u2ui 1.5.0 → 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.
Files changed (47) hide show
  1. package/el/accordion/accordion.js +4 -6
  2. package/el/alert/alert.js +5 -8
  3. package/el/breadcrumb/breadcrumb.js +1 -1
  4. package/el/buttongroup/buttongroup.js +1 -1
  5. package/el/bytes/bytes.js +1 -1
  6. package/el/calendar/calendar.js +6 -7
  7. package/el/carousel/carousel.js +1 -1
  8. package/el/carousel-nav/carousel-nav.js +1 -1
  9. package/el/chart/chart.js +1 -1
  10. package/el/code/code.js +1 -1
  11. package/el/cookiebanner/cookiebanner.js +1 -1
  12. package/el/copy/copy.js +1 -1
  13. package/el/counter/counter.js +1 -1
  14. package/el/drawer/drawer.js +1 -1
  15. package/el/fields/fields.js +5 -4
  16. package/el/ico/ico.js +1 -1
  17. package/el/input/input.js +6 -7
  18. package/el/maintitlebar/maintitlebar.js +1 -1
  19. package/el/masonry/masonry.js +1 -1
  20. package/el/menubutton/menubutton.js +1 -1
  21. package/el/number/number.js +1 -1
  22. package/el/out/out.js +1 -1
  23. package/el/pagination/pagination.js +1 -1
  24. package/el/parallax-bg/parallax-bg.js +1 -1
  25. package/el/qrcode/qrcode.js +1 -1
  26. package/el/rating/rating.js +4 -6
  27. package/el/responsive/responsive.js +1 -1
  28. package/el/rte/rte.js +1 -1
  29. package/el/skeleton/skeleton.js +1 -1
  30. package/el/splitpanel/splitpanel.js +1 -1
  31. package/el/spot/spot.js +1 -1
  32. package/el/system/styler.js +1 -1
  33. package/el/system/system.js +1 -1
  34. package/el/table/table.js +1 -1
  35. package/el/tabs/tabs.js +1 -1
  36. package/el/textfit/textfit.js +1 -1
  37. package/el/time/time.js +1 -1
  38. package/el/toc/toc.js +1 -1
  39. package/el/tooltip/tooltip.js +1 -1
  40. package/el/tree/tree.js +1 -1
  41. package/el/typewriter/typewriter.js +1 -1
  42. package/el/video/video.js +1 -1
  43. package/package.json +1 -1
  44. package/u2/Element.js +37 -0
  45. package/u2/enhance.js +1 -12
  46. package/u2/plan-scoped-refactoring.md +64 -8
  47. 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 HTMLElement {
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;
@@ -208,4 +206,4 @@ export default class U2Accordion extends HTMLElement {
208
206
  }
209
207
  }
210
208
 
211
- customElements.define('u2-accordion', U2Accordion);
209
+ customElements.get('u2-accordion') || customElements.define('u2-accordion', U2Accordion);
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 HTMLElement {
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>
@@ -163,7 +160,7 @@ const variantData = {
163
160
  }
164
161
  };
165
162
 
166
- customElements.define('u2-alert', U2Alert);
163
+ customElements.get('u2-alert') || customElements.define('u2-alert', U2Alert);
167
164
 
168
165
  function alert(message, variant, options={}) {
169
166
  const el = document.createElement('u2-alert');
@@ -116,4 +116,4 @@ export default class U2Breadcrumb extends HTMLElement {
116
116
  }
117
117
  }
118
118
 
119
- customElements.define('u2-breadcrumb', U2Breadcrumb);
119
+ customElements.get('u2-breadcrumb') || customElements.define('u2-breadcrumb', U2Breadcrumb);
@@ -65,4 +65,4 @@ export default class U2Buttongroup extends HTMLElement {
65
65
  }
66
66
 
67
67
  }
68
- customElements.define('u2-buttongroup', U2Buttongroup);
68
+ customElements.get('u2-buttongroup') || customElements.define('u2-buttongroup', U2Buttongroup);
package/el/bytes/bytes.js CHANGED
@@ -54,7 +54,7 @@ export default class U2Bytes extends HTMLElement {
54
54
  }
55
55
  }
56
56
 
57
- customElements.define('u2-bytes', U2Bytes);
57
+ customElements.get('u2-bytes') || customElements.define('u2-bytes', U2Bytes);
58
58
 
59
59
 
60
60
  function localesFromElement(el) {
@@ -1,5 +1,6 @@
1
+ import U2Element from '../../u2/Element.js';
1
2
 
2
- export default class U2Calendar extends HTMLElement {
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
- import('../ico/ico.js');
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 HTMLElement {
297
+ class U2CalendarItem extends U2Element {
299
298
  static observedAttributes = ['start', 'end'];
300
299
 
301
300
  constructor() {
@@ -387,5 +386,5 @@ function getTimeFormatter(localeTag, options = { hour: '2-digit', minute: '2-dig
387
386
  }
388
387
 
389
388
 
390
- customElements.define('u2-calendar', U2Calendar);
391
- customElements.define('u2-calendaritem', U2CalendarItem);
389
+ customElements.get('u2-calendar') || customElements.define('u2-calendar', U2Calendar);
390
+ customElements.get('u2-calendaritem') || customElements.define('u2-calendaritem', U2CalendarItem);
@@ -321,7 +321,7 @@ U2Carousel.mode.fade = {
321
321
  }
322
322
 
323
323
 
324
- customElements.define('u2-carousel', U2Carousel)
324
+ customElements.get('u2-carousel') || customElements.define('u2-carousel', U2Carousel)
325
325
 
326
326
 
327
327
  // slide on target
@@ -71,4 +71,4 @@ export default class U2CarouselNav extends HTMLElement {
71
71
  })
72
72
  }
73
73
  }
74
- customElements.define('u2-carousel-nav', U2CarouselNav)
74
+ customElements.get('u2-carousel-nav') || customElements.define('u2-carousel-nav', U2CarouselNav)
package/el/chart/chart.js CHANGED
@@ -185,4 +185,4 @@ function getHSLofElement(el) {
185
185
  }
186
186
 
187
187
 
188
- customElements.define('u2-chart', U2Chart);
188
+ customElements.get('u2-chart') || customElements.define('u2-chart', U2Chart);
package/el/code/code.js CHANGED
@@ -197,7 +197,7 @@ export default class U2Code extends HTMLElement {
197
197
 
198
198
  }
199
199
 
200
- customElements.define('u2-code', U2Code);
200
+ customElements.get('u2-code') || customElements.define('u2-code', U2Code);
201
201
 
202
202
 
203
203
  function trimCode(value){
@@ -55,7 +55,7 @@ function getCookie() {
55
55
  }
56
56
  }
57
57
 
58
- customElements.define('u2-cookiebanner', U2Cookiebanner);
58
+ customElements.get('u2-cookiebanner') || customElements.define('u2-cookiebanner', U2Cookiebanner);
59
59
 
60
60
 
61
61
 
package/el/copy/copy.js CHANGED
@@ -87,4 +87,4 @@ export default class U2Copy extends HTMLElement {
87
87
  }
88
88
  }
89
89
 
90
- customElements.define('u2-copy', U2Copy);
90
+ customElements.get('u2-copy') || customElements.define('u2-copy', U2Copy);
@@ -93,4 +93,4 @@ function format(el, val){
93
93
  }).format(val);
94
94
  }
95
95
 
96
- customElements.define('u2-counter', U2Counter)
96
+ customElements.get('u2-counter') || customElements.define('u2-counter', U2Counter)
@@ -163,4 +163,4 @@ export default class U2Drawer extends HTMLElement {
163
163
  }
164
164
 
165
165
  // Register custom element
166
- customElements.define('u2-drawer', U2Drawer);
166
+ customElements.get('u2-drawer') || customElements.define('u2-drawer', U2Drawer);
@@ -1,8 +1,9 @@
1
- export default class U2Fields extends HTMLElement {
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
- import('../responsive/responsive.js');
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
- u2-responsive {
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;
@@ -130,4 +131,4 @@ export default class U2Fields extends HTMLElement {
130
131
 
131
132
  }
132
133
 
133
- customElements.define('u2-fields', U2Fields);
134
+ customElements.get('u2-fields') || customElements.define('u2-fields', U2Fields);
package/el/ico/ico.js CHANGED
@@ -160,4 +160,4 @@ async function loadCached(url) {
160
160
  }
161
161
 
162
162
 
163
- customElements.define('u2-ico', U2Ico);
163
+ customElements.get('u2-ico') || customElements.define('u2-ico', U2Ico);
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
- import('../bytes/bytes.js');
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 HTMLElement {
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;
@@ -665,7 +664,7 @@ export default class U2Input extends HTMLElement {
665
664
  $(selector) { return this.shadowRoot.querySelector(selector); }
666
665
 
667
666
  }
668
- customElements.define('u2-input', U2Input);
667
+ customElements.get('u2-input') || customElements.define('u2-input', U2Input);
669
668
 
670
669
  // Globales File-Drag-Feedback
671
670
  document.addEventListener('dragenter', e => {
@@ -14,4 +14,4 @@ export default class U2Maintitlebar extends HTMLElement {
14
14
  navigator.windowControlsOverlay?.removeEventListener('geometrychange', this._check);
15
15
  }
16
16
  }
17
- customElements.define('u2-maintitlebar', U2Maintitlebar);
17
+ customElements.get('u2-maintitlebar') || customElements.define('u2-maintitlebar', U2Maintitlebar);
@@ -44,7 +44,7 @@ export default class U2Masonry extends HTMLElement{
44
44
  }
45
45
  }
46
46
 
47
- customElements.define('u2-masonry', U2Masonry);
47
+ customElements.get('u2-masonry') || customElements.define('u2-masonry', U2Masonry);
48
48
 
49
49
 
50
50
  function sortByHeight(a, b){
@@ -73,7 +73,7 @@ export default class U2Menubutton extends HTMLElement {
73
73
  });
74
74
  }
75
75
  }
76
- customElements.define('u2-menubutton', U2Menubutton);
76
+ customElements.get('u2-menubutton') || customElements.define('u2-menubutton', U2Menubutton);
77
77
 
78
78
 
79
79
  function nextFocusable(root) {
@@ -58,7 +58,7 @@ export default class U2Number extends HTMLElement {
58
58
  }
59
59
  }
60
60
 
61
- customElements.define('u2-number', U2Number);
61
+ customElements.get('u2-number') || customElements.define('u2-number', U2Number);
62
62
 
63
63
  function localesFromElement(el) {
64
64
  let langEl = el.closest('[lang]')||document.documentElement;
package/el/out/out.js CHANGED
@@ -39,4 +39,4 @@ export default class U2Out extends HTMLElement {
39
39
 
40
40
  }
41
41
 
42
- customElements.define('u2-out', U2Out);
42
+ customElements.get('u2-out') || customElements.define('u2-out', U2Out);
@@ -144,4 +144,4 @@ export default class U2Pagination extends HTMLElement {
144
144
  }
145
145
  }
146
146
 
147
- customElements.define('u2-pagination', U2Pagination);
147
+ customElements.get('u2-pagination') || customElements.define('u2-pagination', U2Pagination);
@@ -194,4 +194,4 @@ export default class U2ParallaxBg extends HTMLElement {
194
194
  }
195
195
  }
196
196
 
197
- customElements.define('u2-parallax-bg', U2ParallaxBg)
197
+ customElements.get('u2-parallax-bg') || customElements.define('u2-parallax-bg', U2ParallaxBg)
@@ -35,7 +35,7 @@ export default class U2Qrcode extends HTMLElement {
35
35
  }
36
36
 
37
37
  }
38
- customElements.define('u2-qrcode', U2Qrcode);
38
+ customElements.get('u2-qrcode') || customElements.define('u2-qrcode', U2Qrcode);
39
39
 
40
40
  function toSvgString(qr) {
41
41
  const border = 0;
@@ -1,7 +1,6 @@
1
- const icoCssUrl = import.meta.resolve('../../el/ico/ico.css');
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 HTMLElement {
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>
@@ -145,4 +143,4 @@ function translate(text) {
145
143
  return texts[text][lang] ?? texts[text].en;
146
144
  }
147
145
 
148
- customElements.define('u2-rating', U2Rating);
146
+ customElements.get('u2-rating') || customElements.define('u2-rating', U2Rating);
@@ -123,7 +123,7 @@ export default class U2Responsive extends HTMLElement {
123
123
  }
124
124
  }
125
125
 
126
- customElements.define('u2-responsive', U2Responsive);
126
+ customElements.get('u2-responsive') || customElements.define('u2-responsive', U2Responsive);
127
127
 
128
128
 
129
129
 
package/el/rte/rte.js CHANGED
@@ -44,7 +44,7 @@ export default class U2Rte extends HTMLElement {
44
44
  }
45
45
  }
46
46
 
47
- customElements.define('u2-rte', U2Rte);
47
+ customElements.get('u2-rte') || customElements.define('u2-rte', U2Rte);
48
48
 
49
49
 
50
50
  // import Showdown from 'https://cdn.skypack.dev/showdown';
@@ -21,7 +21,7 @@ export default class U2Skeleton extends HTMLElement {
21
21
  }
22
22
  }
23
23
 
24
- customElements.define('u2-skeleton', U2Skeleton);
24
+ customElements.get('u2-skeleton') || customElements.define('u2-skeleton', U2Skeleton);
25
25
 
26
26
 
27
27
 
@@ -114,4 +114,4 @@ export default class U2Splitpanel extends HTMLElement {
114
114
  }
115
115
  }
116
116
 
117
- customElements.define('u2-splitpanel', U2Splitpanel);
117
+ customElements.get('u2-splitpanel') || customElements.define('u2-splitpanel', U2Splitpanel);
package/el/spot/spot.js CHANGED
@@ -103,4 +103,4 @@ export default class U2Spot extends HTMLElement {
103
103
  }
104
104
  }
105
105
 
106
- customElements.define('u2-spot', U2Spot);
106
+ customElements.get('u2-spot') || customElements.define('u2-spot', U2Spot);
@@ -572,7 +572,7 @@ class ColorSystemStyler extends HTMLElement {
572
572
  }
573
573
  }
574
574
 
575
- customElements.define('u2-system-styler', ColorSystemStyler);
575
+ customElements.get('u2-system-styler') || customElements.define('u2-system-styler', ColorSystemStyler);
576
576
 
577
577
 
578
578
 
@@ -68,7 +68,7 @@ export default class U2System extends HTMLElement {
68
68
 
69
69
  }
70
70
 
71
- customElements.define('u2-system', U2System);
71
+ customElements.get('u2-system') || customElements.define('u2-system', U2System);
72
72
 
73
73
  addEventListener('keydown', (e) => {
74
74
  if (e.target.form !== undefined) return;
package/el/table/table.js CHANGED
@@ -465,4 +465,4 @@ class Column {
465
465
  }
466
466
  }
467
467
 
468
- customElements.define('u2-table', U2Table);
468
+ customElements.get('u2-table') || customElements.define('u2-table', U2Table);
package/el/tabs/tabs.js CHANGED
@@ -162,7 +162,7 @@ export default class U2Tabs extends HTMLElement {
162
162
  }
163
163
 
164
164
  }
165
- customElements.define('u2-tabs', U2Tabs);
165
+ customElements.get('u2-tabs') || customElements.define('u2-tabs', U2Tabs);
166
166
 
167
167
  // beta, does not work if initial u2-target is already fired
168
168
  // problem: sometimes, on initial load, the event is fired before the listener is added
@@ -77,4 +77,4 @@ export default class U2Textfit extends HTMLElement {
77
77
  }
78
78
  }
79
79
 
80
- customElements.define('u2-textfit', U2Textfit);
80
+ customElements.get('u2-textfit') || customElements.define('u2-textfit', U2Textfit);
package/el/time/time.js CHANGED
@@ -176,4 +176,4 @@ const ensureOption = (val, ...options) => {
176
176
  return options[0];
177
177
  }
178
178
 
179
- customElements.define('u2-time', U2Time);
179
+ customElements.get('u2-time') || customElements.define('u2-time', U2Time);
package/el/toc/toc.js CHANGED
@@ -84,4 +84,4 @@ export default class U2Toc extends HTMLElement {
84
84
  }
85
85
  }
86
86
 
87
- customElements.define('u2-toc', U2Toc);
87
+ customElements.get('u2-toc') || customElements.define('u2-toc', U2Toc);
@@ -67,7 +67,7 @@ export default class U2Tooltip extends HTMLElement {
67
67
  }
68
68
  static observedAttributes = ['position'];
69
69
  }
70
- customElements.define('u2-tooltip', U2Tooltip);
70
+ customElements.get('u2-tooltip') || customElements.define('u2-tooltip', U2Tooltip);
71
71
 
72
72
 
73
73
  document.addEventListener('mouseenter',function(e){
package/el/tree/tree.js CHANGED
@@ -233,4 +233,4 @@ export default class U2Tree extends HTMLElement {
233
233
  }
234
234
  }
235
235
 
236
- customElements.define('u2-tree', U2Tree);
236
+ customElements.get('u2-tree') || customElements.define('u2-tree', U2Tree);
@@ -100,7 +100,7 @@ export default class U2Typewriter extends HTMLElement {
100
100
  }
101
101
 
102
102
  }
103
- customElements.define('u2-typewriter', U2Typewriter);
103
+ customElements.get('u2-typewriter') || customElements.define('u2-typewriter', U2Typewriter);
104
104
 
105
105
 
106
106
  // find the next Char in children or sibling of the node but not outside the root
package/el/video/video.js CHANGED
@@ -483,7 +483,7 @@ const svg = {
483
483
  fastRewind: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M11 16.07V7.93c0-.81-.91-1.28-1.58-.82l-5.77 4.07c-.56.4-.56 1.24 0 1.63l5.77 4.07c.67.47 1.58 0 1.58-.81zm1.66-3.25l5.77 4.07c.66.47 1.58-.01 1.58-.82V7.93c0-.81-.91-1.28-1.58-.82l-5.77 4.07a1 1 0 0 0 0 1.64z"></path></svg>',
484
484
  }
485
485
 
486
- customElements.define('u2-video', U2Video);
486
+ customElements.get('u2-video') || customElements.define('u2-video', U2Video);
487
487
 
488
488
 
489
489
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "u2ui",
3
- "version": "1.5.0",
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
- - **`U2Element` als Basisklasse** (wenn sie kommt) nimmt den Elementen die Registry-Arbeit ab:
267
- `attachShadow(options)` überschreiben und `customElementRegistry: this.customElementRegistry`
268
- vorbelegen — dann bleiben alle Aufrufstellen wie heute. Dazu ein Einzeiler für Kind-Elemente,
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
+ }