Skip to content

Commit 5dbd4f6

Browse files
committed
feat(slot mixin): adds helpers for working with slots
Also organized the files to clearly identify what is private to the component and public to the world.
1 parent a8aaf84 commit 5dbd4f6

File tree

11 files changed

+227
-133
lines changed

11 files changed

+227
-133
lines changed

README.md

+68-47
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,37 @@ Our consumable web components are prefixed with "**rb-**"
88
example [rb-button](https://rapid-build-ui.io/components/rb-button).
99

1010

11+
1112
## Installation
1213
```bash
13-
$ npm install @rapid-build-ui/rb-base
14+
$ yarn add @rapid-build-ui/rb-base
1415
```
1516

1617

18+
1719
## What's Included
1820
* Web component library [SkateJS](http://skatejs.netlify.com/).
19-
* The view rendering engine [lit-html](https://polymer.github.io/lit-html/).
20-
* Imports:
21-
* guid-service.js
22-
* type-service.js
23-
* view-directives.js
21+
* The view rendering engine [lit-html](https://lit-html.polymer-project.org/).
22+
* API (creates this.rb object that contains a set of common helper objects):
23+
* [this.rb.elms](#thisrbelms)
24+
* [this.rb.events](#thisrbevents)
25+
* [this.rb.view](#thisrbevents)
2426
* Callbacks:
25-
* viewReady()
26-
* Creates this.rb object that contains a set of common helper objects:
27-
* this.rb.elms
28-
* this.rb.events
29-
* this.rb.view
27+
* [viewReady()](#viewready)
28+
* Imports:
29+
* [guid service](#guid-service)
30+
* [type service](#type-service)
31+
* [view directives](#view-directives)
32+
3033

3134

3235
## How To Use
3336
```js
3437
/* Example
3538
**********/
36-
import { props, html, RbBase } from '../../rb-base/scripts/rb-base.js';
37-
import view from '../../rb-base/scripts/view-directives.js';
38-
import template from '../views/rb-popover.html';
39+
import { RbBase, props, html } from '../../rb-base/scripts/rb-base.js';
40+
import view from '../../rb-base/scripts/public/view/directives.js';
41+
import template from '../views/rb-popover.html';
3942

4043
export class RbPopover extends RbBase() {
4144
// Lifecycle
@@ -49,36 +52,71 @@ export class RbPopover extends RbBase() {
4952
this.showPopover = !this.showPopover;
5053
}
5154
// Template
52-
render({ props }) { // :string
55+
render({ props, state }) { // :string
5356
return html template;
5457
}
5558
}
5659
```
5760

5861

62+
63+
## API
64+
65+
### this.rb.elms
66+
* An object/hashmap to store component elements.
67+
* *See [how to use...](#how-to-use)*
68+
69+
70+
### this.rb.events
71+
* Properties
72+
* events :object (readonly, hashmap of active events)
73+
* Methods
74+
* add(elm(s), 'space separated events', callback[, opts]) :void
75+
* events are automatically removed in disconnectedCallback()
76+
* meaning, you don't have to call remove() or removeAll()
77+
* opts :{}
78+
* [default options](https://goo.gl/f3kP5A)
79+
* opts.bind (custom):
80+
* undefined (binds to component, default)
81+
* false | null (binds to target elm)
82+
* elm (binds to supplied elm)
83+
* emit(elm, 'event' [, { detail: any } ]) :boolean
84+
* remove(elm(s), 'space separated events', callback) :void
85+
* removeAll([opts]) :void
86+
* opts :{}
87+
* opts.force (internal option) :boolean
88+
* forces events to be set to empty {}
89+
90+
91+
### this.rb.view
92+
* Properties
93+
* isReady :boolean (readonly, will be true when view is ready)
94+
95+
96+
5997
## Callbacks (optional)
6098

6199
### viewReady()
62-
*See "How To Use"*
100+
*See [how to use...](#how-to-use)*
63101
Executed once when view is ready and all its rb sub components views are ready.
64102
Use when you need to make sure elements are accessible in the shadow dom.
65103

66104

67105

68106
## Imports (optional)
69107

70-
### guid-service.js
108+
### guid service
71109
* Methods
72110
* create(maxLength = 12) :string (sometimes returns maxLength - 1 chars)
73111

74112
```js
75113
// Example
76-
import Guid from '../../rb-base/scripts/guid-service.js';
114+
import Guid from '../../rb-base/scripts/public/services/guid.js';
77115
const guid = Guid.create();
78116
```
79117

80118

81-
### type-service.js
119+
### type service
82120
* Methods (**is.methods() :boolean**)
83121
* get(val) :string (returns val type)
84122
* is.array(val)
@@ -95,17 +133,22 @@ const guid = Guid.create();
95133

96134
```js
97135
// Example
98-
import Type from '../../rb-base/scripts/type-service.js';
136+
import Type from '../../rb-base/scripts/public/services/type.js';
99137
const isString = Type.is.string('rapid');
100138
```
101139

102140

103-
### view-directives.js
104-
Returns object of
105-
[lit-html](https://polymer.github.io/lit-html/guide/writing-templates.html#directives)
106-
[directives](https://github.com/rapid-build-ui/rb-base/blob/master/src/client/scripts/view-directives.js)
141+
### view directives
142+
Returns an object of
143+
[lit-html](https://lit-html.polymer-project.org/guide/template-reference#built-in-directives)
144+
[directives](https://github.com/rapid-build-ui/rb-base/blob/master/src/client/scripts/public/view/directives.js)
107145
to be used in view.
108146

147+
```js
148+
// Example
149+
import view from '../../rb-base/scripts/public/view/directives.js';
150+
```
151+
109152
```html
110153
<!-- Example (import view object in js, see "How To Use"): -->
111154
<ul>
@@ -114,26 +157,4 @@ to be used in view.
114157
(hero, i) => html`<li>${i} ${hero}</li>`
115158
)}
116159
</ul>
117-
```
118-
119-
120-
## API
121-
122-
### this.rb.elms
123-
*See "How To Use"*
124-
This is object/hashmap to store component elements.
125-
126-
127-
### this.rb.events
128-
* Properties
129-
* events :object (readonly, hashmap of active events)
130-
* Methods
131-
* add(elm, 'space separated events', callback[, opts]) :void
132-
* remove(elm, 'space separated events', callback) :void
133-
* removeAll([opts]) :void
134-
* emit(elm, 'event' [, { detail: any } ]) :boolean
135-
136-
137-
### this.rb.view
138-
* Properties
139-
* isReady :boolean (readonly, will be true when view is ready)
160+
```

rapid-build.cson

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ common:
1414
from:
1515
minFile:
1616
scripts: [
17-
'scripts/!(rb-*.js)'
17+
'scripts/**/*.js'
1818
]
1919

2020
extra:
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*************************************
2+
* BASE MIXIN (for all rb-components)
3+
*************************************/
4+
import { props, withComponent } from '../../../../../skatejs/dist/esnext/index.js';
5+
import { html, render } from '../../../../../lit-html/lit-html.js';
6+
import EventService from '../../private/services/event.js';
7+
import ViewService from '../../private/services/view.js';
8+
9+
const Base = (BaseElm = HTMLElement) => class extends withComponent(BaseElm) {
10+
/* Lifecycle
11+
************/
12+
constructor() { // :void
13+
super();
14+
this.rb = {
15+
elms: {},
16+
events: EventService.call(this),
17+
view: ViewService.call(this)
18+
}
19+
}
20+
disconnectedCallback() { // :void
21+
super.disconnectedCallback && super.disconnectedCallback();
22+
this.rb.events.removeAll({ force: true });
23+
// console.log(`${this.localName} disconnected:`, this.rb.events.events);
24+
}
25+
26+
/* @skatejs/renderer-lit-html
27+
*****************************/
28+
async renderer(root, call) { // :void
29+
render(call(), root);
30+
if (this.rb.view.isReady) return;
31+
// console.log(`${this.localName} view ready:`, this.rb.view.isReady);
32+
await this.rb.view.readyCallback(); // called once when rb view is ready
33+
}
34+
}
35+
36+
/* Export it!
37+
*************/
38+
export { Base, html, props };
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/***************************************
2+
* SLOT MIXIN
3+
* ------------------------------------
4+
* Adds helpers for working with slots.
5+
***************************************/
6+
const Slot = BaseElm => class extends BaseElm {
7+
/* Lifecycle
8+
************/
9+
constructor() {
10+
super();
11+
this.state = {
12+
...super.state,
13+
slots: {} // :{ [slotName]: boolean }
14+
};
15+
}
16+
17+
/* Getters
18+
**********/
19+
get _hasLightDom() { // :boolean
20+
this._cleanLightDomWhitespace();
21+
return !!this.childNodes.length;
22+
}
23+
24+
get _lightDomSlotNames() { // :{ [slotName]: boolean }
25+
const names = {};
26+
for (const child of this.childNodes) {
27+
if (![1,3].includes(child.nodeType)) continue; // only text or elm
28+
// text
29+
if (child.nodeType === 3) { names['default'] = true; continue; }
30+
// elms (child.slot :string)
31+
const name = child.slot.trim().toLowerCase() || 'default';
32+
names[name] = true;
33+
}
34+
return names;
35+
}
36+
37+
/* Methods
38+
**********/
39+
_cleanLightDomWhitespace() { // :void (mutator: this.childNodes)
40+
for (const child of this.childNodes) {
41+
if (child.nodeType !== 3) continue;
42+
if (child.textContent.trim().length) continue;
43+
child.remove(); // remove empty text nodes
44+
}
45+
}
46+
47+
_setSlotStates(slotNames={}) { // :void (mutator: this.state.slots)
48+
if (!Object.keys(slotNames).length) return;
49+
Object.assign(this.state.slots, slotNames);
50+
this.triggerUpdate();
51+
}
52+
53+
_initSlotStates() { // :void (run in viewReady())
54+
if (!this._hasLightDom) return;
55+
this._setSlotStates(this._lightDomSlotNames);
56+
}
57+
}
58+
59+
/* Export it!
60+
*************/
61+
export default Slot;

src/client/scripts/event-service.js src/client/scripts/private/services/event.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/********************************************************************************
22
* EVENT SERVICE
3-
********************************************************************************
3+
* -----------------------------------------------------------------------------
44
* HOW TO USE
5-
- import EventService from './event-service.js';
5+
- import EventService from './event.js';
66
- this.rb.events = EventService.call(this); :object (set in constructor)
77
* API
88
- this.rb.events.events; :object (readonly: hashmap of events)
@@ -11,8 +11,8 @@
1111
- this.rb.events.removeAll([options]); :void
1212
- this.rb.events.emit(elm, 'event' [, { detail: any } ]); :boolean
1313
********************************************************************************/
14-
import { emit } from '../../../skatejs/dist/esnext/emit.js';
15-
import Guid from './guid-service.js';
14+
import { emit } from '../../../../../skatejs/dist/esnext/emit.js';
15+
import Guid from '../../public/services/guid.js';
1616

1717
/* Event Helpers
1818
****************/

src/client/scripts/view-service.js src/client/scripts/private/services/view.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/********************************************************************
22
* VIEW SERVICE
3-
********************************************************************
3+
* -----------------------------------------------------------------
44
* HOW TO USE
5-
- import View from './view-service.js';
5+
- import ViewService from './view.js';
66
- this.rb.view = View.call(this); :object (set in constructor)
77
* API
88
- this.rb.view.isReady; :boolean (readonly: set in readyCallback())

src/client/scripts/guid-service.js src/client/scripts/public/services/guid.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
/****************************************
1+
/***************************************
22
* GUID SERVICE
3-
****************************************
3+
* ------------------------------------
44
* HOW TO USE
5-
- import Guid from './guid-service.js';
5+
- import Guid from './guid.js';
66
* API
77
- Guid.create(maxLength = 12); :string
8-
****************************************/
8+
***************************************/
99
const GuidService = {
1010
create(maxLength = 12) { // :string (sometimes returns maxLength - 1 chars)
1111
return Math.round((Math.random() * 36 ** maxLength)).toString(36);

src/client/scripts/type-service.js src/client/scripts/public/services/type.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
/****************************************
1+
/********************************
22
* TYPE SERVICE
3-
****************************************
3+
* -----------------------------
44
* HOW TO USE
5-
- import Type from './type-service.js';
5+
- import Type from './type.js';
66
- Type = TypeService; :object
7-
****************************************/
7+
********************************/
88
const TypeService = {
99
/* Return Type as String
1010
************************/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*********************************************
2+
* VIEW DIRECTIVES (from lit-html >= v0.14.0)
3+
*********************************************/
4+
import { directive } from '../../../../../lit-html/lit-html.js';
5+
import { asyncAppend } from '../../../../../lit-html/directives/async-append.js';
6+
import { asyncReplace } from '../../../../../lit-html/directives/async-replace.js';
7+
import { cache } from '../../../../../lit-html/directives/cache.js';
8+
import { classMap } from '../../../../../lit-html/directives/class-map.js';
9+
import { guard } from '../../../../../lit-html/directives/guard.js';
10+
import { ifDefined } from '../../../../../lit-html/directives/if-defined.js';
11+
import { repeat } from '../../../../../lit-html/directives/repeat.js';
12+
import { styleMap } from '../../../../../lit-html/directives/style-map.js';
13+
import { unsafeHTML } from '../../../../../lit-html/directives/unsafe-html.js';
14+
import { until } from '../../../../../lit-html/directives/until.js';
15+
16+
/* View Directives
17+
******************/
18+
const ViewDirectives = {
19+
asyncAppend,
20+
asyncReplace,
21+
cache,
22+
classMap,
23+
directive,
24+
guard,
25+
ifDefined,
26+
repeat,
27+
styleMap,
28+
unsafeHTML,
29+
until
30+
}
31+
32+
/* Export it!
33+
*************/
34+
export default ViewDirectives;
35+

0 commit comments

Comments
 (0)