u2ui 1.5.1 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/el/accordion/accordion.js +3 -5
- package/el/alert/alert.js +4 -7
- package/el/calendar/calendar.js +4 -5
- package/el/fields/fields.js +4 -3
- package/el/input/input.js +5 -6
- package/el/rating/rating.js +3 -5
- package/package.json +1 -1
- package/u2/Element.js +37 -0
- package/u2/enhance.js +1 -12
- package/u2/plan-scoped-refactoring.md +64 -8
- package/u2/utils.js +17 -0
|
@@ -1,17 +1,15 @@
|
|
|
1
|
+
import U2Element from '../../u2/Element.js';
|
|
1
2
|
|
|
2
|
-
const icoCssUrl = import.meta.resolve('../../el/ico/ico.css');
|
|
3
3
|
|
|
4
|
-
export default class U2Accordion extends
|
|
4
|
+
export default class U2Accordion extends U2Element {
|
|
5
5
|
|
|
6
6
|
constructor() {
|
|
7
7
|
super();
|
|
8
8
|
|
|
9
|
-
import('../ico/ico.js');
|
|
10
|
-
|
|
11
9
|
let shadowRoot = this.attachShadow({ mode: 'open', slotAssignment: 'manual' });
|
|
10
|
+
this.useEl('ico');
|
|
12
11
|
shadowRoot.innerHTML = `
|
|
13
12
|
<style>
|
|
14
|
-
@import url('${icoCssUrl}');
|
|
15
13
|
:host {
|
|
16
14
|
display:block;
|
|
17
15
|
gap:.5em;
|
package/el/alert/alert.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
const icoCssUrl = import.meta.resolve('../../el/ico/ico.css');
|
|
1
|
+
import U2Element from '../../u2/Element.js';
|
|
3
2
|
|
|
4
3
|
const style = `
|
|
5
|
-
@import url('${icoCssUrl}');
|
|
6
4
|
:host(:not([dismissable]))::part(close) { display:none; } /* TODO: does not work in chrome */
|
|
7
5
|
:host {
|
|
8
6
|
--u2-ico-dir:var(--u2-ico-dir-material);
|
|
@@ -80,14 +78,13 @@ slot[name=icon] {
|
|
|
80
78
|
/* slot[name=action]:empty-slot { display:none; } not possible */`;
|
|
81
79
|
|
|
82
80
|
|
|
83
|
-
export default class U2Alert extends
|
|
81
|
+
export default class U2Alert extends U2Element {
|
|
84
82
|
constructor() {
|
|
85
83
|
super();
|
|
86
84
|
|
|
87
|
-
import('../../attr/focusgroup/focusgroup.js');
|
|
88
|
-
import('../ico/ico.js');
|
|
89
|
-
|
|
90
85
|
this.attachShadow({mode: 'open'});
|
|
86
|
+
this.useEl('ico');
|
|
87
|
+
this.useAttr('focusgroup');
|
|
91
88
|
this.shadowRoot.innerHTML = `
|
|
92
89
|
<style>${style}</style>
|
|
93
90
|
<div id=container>
|
package/el/calendar/calendar.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import U2Element from '../../u2/Element.js';
|
|
1
2
|
|
|
2
|
-
export default class U2Calendar extends
|
|
3
|
+
export default class U2Calendar extends U2Element {
|
|
3
4
|
static observedAttributes = ['view', 'date', 'lang'];
|
|
4
5
|
|
|
5
6
|
constructor() {
|
|
@@ -8,12 +9,10 @@ export default class U2Calendar extends HTMLElement {
|
|
|
8
9
|
this._currentDate = new Date();
|
|
9
10
|
this._locale = null;
|
|
10
11
|
this._weekStart = 0; // 0 = Sunday .. 6 = Saturday
|
|
11
|
-
|
|
12
|
-
const icoCssUrl = import.meta.resolve('../ico/ico.css');
|
|
12
|
+
this.useEl('ico');
|
|
13
13
|
|
|
14
14
|
this.shadowRoot.innerHTML = `
|
|
15
15
|
<style>
|
|
16
|
-
@import url('${icoCssUrl}');
|
|
17
16
|
:host {
|
|
18
17
|
display: flex;
|
|
19
18
|
flex-direction: column;
|
|
@@ -295,7 +294,7 @@ export default class U2Calendar extends HTMLElement {
|
|
|
295
294
|
|
|
296
295
|
|
|
297
296
|
|
|
298
|
-
class U2CalendarItem extends
|
|
297
|
+
class U2CalendarItem extends U2Element {
|
|
299
298
|
static observedAttributes = ['start', 'end'];
|
|
300
299
|
|
|
301
300
|
constructor() {
|
package/el/fields/fields.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import U2Element from '../../u2/Element.js';
|
|
2
|
+
export default class U2Fields extends U2Element {
|
|
2
3
|
constructor() {
|
|
3
4
|
super();
|
|
4
5
|
this.attachShadow({ mode: 'open', slotAssignment: 'manual' });
|
|
5
|
-
|
|
6
|
+
this.useEl('responsive');
|
|
6
7
|
|
|
7
8
|
this.shadowRoot.innerHTML = `
|
|
8
9
|
<style>
|
|
@@ -11,7 +12,7 @@ export default class U2Fields extends HTMLElement {
|
|
|
11
12
|
margin-block:.5rem;
|
|
12
13
|
white-space:nowrap;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
+
#container { /* out-specify responsive.css, which useEl now adopts */
|
|
15
16
|
display: grid;
|
|
16
17
|
align-items:baseline;
|
|
17
18
|
grid-template-columns: auto 1fr;
|
package/el/input/input.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import U2Element from '../../u2/Element.js';
|
|
1
2
|
// Type-Handler mit Lifecycle
|
|
2
3
|
class TypeHandler {
|
|
3
4
|
constructor(element, shadow) {
|
|
@@ -288,7 +289,6 @@ class FileHandler extends TypeHandler {
|
|
|
288
289
|
}
|
|
289
290
|
get css() {
|
|
290
291
|
return `
|
|
291
|
-
@import url('${import.meta.resolve('../../class/badge/badge.css')}');
|
|
292
292
|
:host { vertical-align: top; }
|
|
293
293
|
#droparea {
|
|
294
294
|
flex: 1 1 auto;
|
|
@@ -334,7 +334,8 @@ class FileHandler extends TypeHandler {
|
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
init() {
|
|
337
|
-
|
|
337
|
+
this.element.useEl('bytes');
|
|
338
|
+
this.element.useClass('badge');
|
|
338
339
|
|
|
339
340
|
const browse = this.shadow.getElementById('browse');
|
|
340
341
|
|
|
@@ -433,15 +434,13 @@ const TYPE_REGISTRY = {
|
|
|
433
434
|
};
|
|
434
435
|
|
|
435
436
|
// Custom Element
|
|
436
|
-
export default class U2Input extends
|
|
437
|
+
export default class U2Input extends U2Element {
|
|
437
438
|
constructor() {
|
|
438
439
|
super();
|
|
439
|
-
import('../ico/ico.js');
|
|
440
|
-
|
|
441
440
|
const shadow = this.attachShadow({ mode: 'open', delegatesFocus: true });
|
|
441
|
+
this.useEl('ico');
|
|
442
442
|
shadow.innerHTML = `
|
|
443
443
|
<style>
|
|
444
|
-
@import url('${import.meta.resolve('../ico/ico.css')}');
|
|
445
444
|
|
|
446
445
|
:host {
|
|
447
446
|
display: inline-block;
|
package/el/rating/rating.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import U2Element from '../../u2/Element.js';
|
|
2
2
|
|
|
3
3
|
const style = `
|
|
4
|
-
@import url('${icoCssUrl}');
|
|
5
4
|
:host {
|
|
6
5
|
--u2-ico-dir: var(--u2-ico-dir-material);
|
|
7
6
|
--color-inactive:#ccc;
|
|
@@ -25,15 +24,14 @@ const style = `
|
|
|
25
24
|
}
|
|
26
25
|
`;
|
|
27
26
|
|
|
28
|
-
export default class U2Rating extends
|
|
27
|
+
export default class U2Rating extends U2Element {
|
|
29
28
|
static formAssociated = true;
|
|
30
29
|
#value = null;
|
|
31
30
|
constructor() {
|
|
32
31
|
super();
|
|
33
32
|
|
|
34
|
-
import('../ico/ico.js');
|
|
35
|
-
|
|
36
33
|
this.attachShadow({mode: 'open'});
|
|
34
|
+
this.useEl('ico');
|
|
37
35
|
this.shadowRoot.innerHTML = `
|
|
38
36
|
<style>${style}</style>
|
|
39
37
|
<div id=stars></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "u2ui",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "HTML Advanced: More Capabilities, Same Feel, Same Simplicity",
|
|
5
5
|
"keywords": ["web-components","pattern-library","component-library","ui-toolkit","design-system"],
|
|
6
6
|
"author": "Tobias Buschor",
|
package/u2/Element.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { sheet } from './utils.js';
|
|
2
|
+
|
|
3
|
+
const base = new URL('../', import.meta.url).href; // this copy of u2
|
|
4
|
+
|
|
5
|
+
/** Base class for u2 elements — keeps a subtree on one u2 version.
|
|
6
|
+
A scoped shadow root only resolves tags its own registry knows, and a shadow opened
|
|
7
|
+
without the option silently falls back to the global one. Inheriting it instead means
|
|
8
|
+
nesting composes: whatever version enhanced the root stays the version all the way down. */
|
|
9
|
+
export default class U2Element extends HTMLElement {
|
|
10
|
+
|
|
11
|
+
attachShadow(options) {
|
|
12
|
+
return super.attachShadow({customElementRegistry: this.customElementRegistry, ...options});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
useEl(name, options) { return use(this, 'el', name, options); }
|
|
16
|
+
useClass(name, options) { return use(this, 'class', name, options); }
|
|
17
|
+
useAttr(name, options) { return use(this, 'attr', name, options); }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Bring what a child needs into this element's shadow. Both start at once — the css is the
|
|
21
|
+
part that shows, it must not wait for a module. Defaults follow the category: an el has
|
|
22
|
+
both, a class is css only, an attr is js only — `u2-skin` is the attr that styles, and it
|
|
23
|
+
stays an attr because it carries a value: useAttr('skin', {css:true}). */
|
|
24
|
+
function use(el, category, name, {css = category !== 'attr', js = category !== 'class'} = {}) {
|
|
25
|
+
const path = `${base}${category}/${name}/${name}`;
|
|
26
|
+
const warn = err => console.warn('u2: could not load', category + '/' + name, err);
|
|
27
|
+
// unshift, not push: the element's own styles are adopted after these and have to keep
|
|
28
|
+
// winning ties, no matter when the child's sheet arrives.
|
|
29
|
+
if (css) sheet(path + '.css').then(s => el.shadowRoot.adoptedStyleSheets.unshift(s), warn);
|
|
30
|
+
if (!js) return;
|
|
31
|
+
return import(path + '.js').then(mod => {
|
|
32
|
+
if (category !== 'el') return; // a class has no js, an attr installs itself
|
|
33
|
+
const registry = el.customElementRegistry ?? customElements;
|
|
34
|
+
const tag = 'u2-' + name;
|
|
35
|
+
registry.get(tag) || registry.define(tag, mod.default);
|
|
36
|
+
}, warn);
|
|
37
|
+
}
|
package/u2/enhance.js
CHANGED
|
@@ -9,29 +9,18 @@ document it stays a <link>, so the page keeps its say over u2's own rules.
|
|
|
9
9
|
See ./plan-scoped-refactoring.md */
|
|
10
10
|
|
|
11
11
|
import { repos } from './u2.js';
|
|
12
|
-
import { importCss } from './utils.js';
|
|
12
|
+
import { importCss, sheet } from './utils.js';
|
|
13
13
|
|
|
14
14
|
const base = new URL('../', import.meta.url).href; // this copy of u2 — another root may run another
|
|
15
15
|
const scoped = 'customElementRegistry' in ShadowRoot.prototype;
|
|
16
16
|
// The default scope: module identity gives one per u2 version, so a caller who does not care
|
|
17
17
|
// gets isolation for free. A caller who brings its own wins, and the elements follow the root.
|
|
18
18
|
const versionRegistry = scoped ? new CustomElementRegistry() : undefined;
|
|
19
|
-
const sheets = new Map(); // url -> Promise<CSSStyleSheet>, shared across roots
|
|
20
19
|
|
|
21
20
|
// the manifest is wanted by every load, so fetch it on import and keep the resolved map
|
|
22
21
|
let projects = null;
|
|
23
22
|
repos().then(map => projects = map);
|
|
24
23
|
|
|
25
|
-
function sheet(url) {
|
|
26
|
-
if (!sheets.has(url)) {
|
|
27
|
-
sheets.set(url, fetch(url).then(r => r.text()).then(css => {
|
|
28
|
-
const s = new CSSStyleSheet();
|
|
29
|
-
s.replaceSync(css); // u2 css has no relative url() and no @import
|
|
30
|
-
return s;
|
|
31
|
-
}));
|
|
32
|
-
}
|
|
33
|
-
return sheets.get(url);
|
|
34
|
-
}
|
|
35
24
|
|
|
36
25
|
/** Attach a shadow root that runs its own u2. Same signature as the native method. */
|
|
37
26
|
export function attachShadow(host, options = {}) {
|
|
@@ -263,14 +263,9 @@ Erst ab **Phase 3** relevant:
|
|
|
263
263
|
|
|
264
264
|
## Offen / später
|
|
265
265
|
|
|
266
|
-
-
|
|
267
|
-
`
|
|
268
|
-
|
|
269
|
-
etwa `this.registerElement('ico')`: importiert die Klasse, definiert sie in die eigene
|
|
270
|
-
Registry **und adoptiert `ico.css` ins eigene Shadow**. Beides steht heute von Hand in jedem
|
|
271
|
-
Modul, und `fields` vergisst die CSS von `responsive` bereits. Async ist unkritisch — ein
|
|
272
|
-
Element upgraded auch, wenn es erst nach dem `innerHTML` definiert wird.
|
|
273
|
-
Ein `createElement`-Helper lohnt nicht: `innerHTML` benutzt ohnehin die Registry des Shadows.
|
|
266
|
+
- **Die übrigen 36 Elemente auf `U2Element`.** Solange eines `extends HTMLElement` bleibt, fällt
|
|
267
|
+
sein Shadow auf `window.customElements` zurück, sobald es doch mal ein u2-Element rendert.
|
|
268
|
+
Mechanisch, aber 36 Dateien.
|
|
274
269
|
- **Attribute sind kein Registry-Problem.** Sie kollidieren nicht über Namen, sie
|
|
275
270
|
*installieren sich doppelt*, wenn zwei u2-Kopien laufen. Alle 10 hängen ihre Listener an
|
|
276
271
|
`document`, vier davon (`confirm`, `dropzone`, `draghandle`, `movable`) benutzen
|
|
@@ -278,4 +273,65 @@ Erst ab **Phase 3** relevant:
|
|
|
278
273
|
Scope zu binden würde sie kaputtmachen.
|
|
279
274
|
Zu klären ist deshalb nicht „wie scopen wir", sondern zweierlei: **einmal pro Dokument**
|
|
280
275
|
installieren, und **pro Modul** entscheiden, welche Wirkung wirklich subtree-lokal ist.
|
|
276
|
+
|
|
277
|
+
## Erledigt in 1.5.2 — `U2Element`
|
|
278
|
+
|
|
279
|
+
[`u2/Element.js`](Element.js): Basisklasse, die den Elementen die Registry-Arbeit abnimmt.
|
|
280
|
+
`attachShadow()` belegt `customElementRegistry: this.customElementRegistry` vor — alle
|
|
281
|
+
Aufrufstellen bleiben dadurch **wortgleich wie vorher**. `this.useEl(name)` importiert
|
|
282
|
+
`el/<name>/<name>.js` und definiert die Klasse in die eigene Registry (`?? customElements`).
|
|
283
|
+
Async ist unkritisch: ein Element upgraded auch, wenn es erst nach dem `innerHTML` definiert wird.
|
|
284
|
+
|
|
285
|
+
Dazu `useClass(name)` und `useAttr(name)`. Alle drei holen ausserdem die **CSS ins eigene Shadow** —
|
|
286
|
+
u2-Elemente haben meist kein eigenes Shadow (`ico` schreibt sein SVG ins Light DOM, `ico.css` stylt
|
|
287
|
+
`u2-ico { … }` von aussen), CSS gehört deshalb immer dem Root, in dem das Kind steht. Der Vater
|
|
288
|
+
musste sie bisher von Hand per `@import` holen, und `fields` vergass `responsive.css` dabei.
|
|
289
|
+
|
|
290
|
+
**Keine Deklaration am Kind.** Ein `static hasCss` müsste erst per JS geladen werden, bevor die CSS
|
|
291
|
+
überhaupt startet — es macht den wichtigeren Request garantiert langsamer. `projects.json` wäre
|
|
292
|
+
ebenfalls erst ein Fetch (und ist Enhance-Territorium). Also beides parallel, bedingungslos, und die
|
|
293
|
+
Defaults kommen aus der Kategorie — dieselben wie in `enhance`:
|
|
294
|
+
|
|
295
|
+
| | js | css | Dateien |
|
|
296
|
+
|---|---|---|---|
|
|
297
|
+
| `el` | ja | ja | js 41/41, css 37/41 |
|
|
298
|
+
| `class` | **nein** | ja | js 0/8, css 8/8 |
|
|
299
|
+
| `attr` | ja | **nein** | js 15/16, css 1/16 |
|
|
300
|
+
|
|
301
|
+
Die Ausreisser gehören an die *Aufrufstelle*, nicht als Feld an alle 41 Elemente:
|
|
302
|
+
`useAttr('skin', {css:true})`. `skin` bleibt dauerhaft ein Attribut, weil es einen Wert trägt —
|
|
303
|
+
als Klasse ginge das erst mit einem Selektor wie `.u2-class-*`.
|
|
304
|
+
|
|
305
|
+
**Reihenfolge:** adoptierte Sheets kommen *nach* den Tree-Styles, die Kind-CSS würde also die
|
|
306
|
+
Overrides des Vaters schlagen. `use()` macht darum `unshift`, nicht `push` — sobald der `<style>`
|
|
307
|
+
eines Vaters auch mal adoptiert wird, steht er hinter den Kindern, unabhängig davon, wann deren
|
|
308
|
+
Sheet eintrifft. Solange der Vater ein Tree-`<style>` hat, muss er die Kind-Regeln
|
|
309
|
+
**überspezifizieren**. Ein echter Fall bestand: `fields` überschrieb `u2-responsive {display:block}`
|
|
310
|
+
mit `u2-responsive {display:grid}` — Gleichstand, jetzt `#container`.
|
|
311
|
+
|
|
312
|
+
Die sechs Module, die u2-Elemente in ihr *eigenes* Shadow rendern:
|
|
313
|
+
|
|
314
|
+
| Modul | Kind |
|
|
315
|
+
|---|---|
|
|
316
|
+
| `alert`, `accordion`, `calendar`, `rating` | `ico` |
|
|
317
|
+
| `input` | `ico`, `bytes` |
|
|
318
|
+
| `fields` | `responsive` |
|
|
319
|
+
|
|
320
|
+
```js
|
|
321
|
+
export default class U2Alert extends U2Element {
|
|
322
|
+
constructor() {
|
|
323
|
+
super();
|
|
324
|
+
this.attachShadow({mode: 'open'}); // erbt die Registry
|
|
325
|
+
this.useEl('ico'); // Klasse in die Registry + ico.css ins Shadow
|
|
326
|
+
this.useAttr('focusgroup'); // nur js
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Ausserhalb eines scoped Roots ist `this.customElementRegistry` `undefined`, die Option gilt als
|
|
330
|
+
abwesend und `useEl()` fällt auf `customElements` zurück — Verhalten unverändert.
|
|
331
|
+
|
|
332
|
+
Nicht betroffen, bewusst: **Attribute** (`focusgroup`, `draghandle`, `dropzone`, …) sind kein
|
|
333
|
+
Registry-Thema; `table` erzeugt sein `u2-ico` im **Light DOM**, wo `enhance` es ohnehin sieht;
|
|
334
|
+
`input`s `u2-badge` ist eine *Klasse*, kein Tag; `tree`s `u2-ico` ist auskommentiert.
|
|
335
|
+
`U2CalendarItem` erbt `U2Element` mit, obwohl sein Shadow heute keine Custom Elements enthält.
|
|
336
|
+
|
|
281
337
|
- Scoped-Verkettung von Kind-Elementen in die Eltern-Registry (siehe „Interne Deps").
|
package/u2/utils.js
CHANGED
|
@@ -59,3 +59,20 @@ function rootGetStyleWrapper(root) {
|
|
|
59
59
|
}
|
|
60
60
|
return styleWrapper;
|
|
61
61
|
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
///////////////////////////
|
|
65
|
+
// stylesheets
|
|
66
|
+
|
|
67
|
+
const sheets = new Map();
|
|
68
|
+
/** One parsed CSSStyleSheet per url, shared by every root that adopts it. */
|
|
69
|
+
export function sheet(url) {
|
|
70
|
+
if (!sheets.has(url)) {
|
|
71
|
+
sheets.set(url, fetch(url).then(r => r.text()).then(css => {
|
|
72
|
+
const s = new CSSStyleSheet();
|
|
73
|
+
s.replaceSync(css); // u2 css has no relative url() and no @import
|
|
74
|
+
return s;
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
return sheets.get(url);
|
|
78
|
+
}
|