u2ui 1.5.3 → 1.5.7

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 (146) hide show
  1. package/el/ico/ico.js +5 -5
  2. package/el/rte/README.md +53 -13
  3. package/el/rte/manifest.json +19 -4
  4. package/el/rte/rte.css +31 -6
  5. package/el/rte/rte.js +174 -44
  6. package/el/rte0/README.md +37 -0
  7. package/el/rte0/manifest.json +33 -0
  8. package/el/rte0/rte0.css +9 -0
  9. package/el/rte0/rte0.js +56 -0
  10. package/el/system/styler.js +2 -0
  11. package/el/tooltip/tooltip.css +2 -2
  12. package/js/Placer/Placer.js +2 -1
  13. package/js/rte/AGENTS.md +142 -0
  14. package/js/rte/PLAN.md +487 -0
  15. package/js/rte/README.md +319 -25
  16. package/js/rte/blocks.js +7 -0
  17. package/js/rte/breaks.js +6 -0
  18. package/js/rte/classes.js +7 -0
  19. package/js/rte/docs/usage.md +845 -0
  20. package/js/rte/images.js +7 -0
  21. package/js/rte/link.js +8 -0
  22. package/js/rte/playground/README.md +95 -0
  23. package/js/rte/playground/hosts.html +553 -0
  24. package/js/rte/playground/index.html +835 -0
  25. package/js/rte/rte.js +56 -5
  26. package/js/rte/run.out +17 -0
  27. package/js/rte/source.js +12 -0
  28. package/js/rte/src/browser/README.md +40 -0
  29. package/js/rte/src/browser/interactive.js +17 -0
  30. package/js/rte/src/browser/range-rect.js +82 -0
  31. package/js/rte/src/client/README.md +385 -0
  32. package/js/rte/src/client/blocks.js +38 -0
  33. package/js/rte/src/client/breaks.js +212 -0
  34. package/js/rte/src/client/classes.js +48 -0
  35. package/js/rte/src/client/editor.js +472 -0
  36. package/js/rte/src/client/external-input.js +47 -0
  37. package/js/rte/src/client/history.js +13 -0
  38. package/js/rte/src/client/images.js +285 -0
  39. package/js/rte/src/client/link.js +567 -0
  40. package/js/rte/src/client/marks.js +25 -0
  41. package/js/rte/src/client/source.js +182 -0
  42. package/js/rte/src/client/structure.js +27 -0
  43. package/js/rte/src/client/tables.js +165 -0
  44. package/js/rte/src/client/unstyle.js +32 -0
  45. package/js/rte/src/command/README.md +520 -0
  46. package/js/rte/src/command/block-boundary.js +43 -0
  47. package/js/rte/src/command/block-style.js +120 -0
  48. package/js/rte/src/command/commands.js +159 -0
  49. package/js/rte/src/command/delete.js +119 -0
  50. package/js/rte/src/command/edit.js +78 -0
  51. package/js/rte/src/command/element.js +45 -0
  52. package/js/rte/src/command/enter.js +175 -0
  53. package/js/rte/src/command/fragment.js +76 -0
  54. package/js/rte/src/command/insert.js +52 -0
  55. package/js/rte/src/command/list.js +284 -0
  56. package/js/rte/src/command/mark.js +583 -0
  57. package/js/rte/src/command/pending-marks.js +216 -0
  58. package/js/rte/src/command/table.js +207 -0
  59. package/js/rte/src/command/unstyle.js +248 -0
  60. package/js/rte/src/config/README.md +96 -0
  61. package/js/rte/src/config/config.js +134 -0
  62. package/js/rte/src/core/README.md +63 -0
  63. package/js/rte/src/core/core.js +247 -0
  64. package/js/rte/src/history/README.md +83 -0
  65. package/js/rte/src/history/history.js +283 -0
  66. package/js/rte/src/input/README.md +173 -0
  67. package/js/rte/src/input/external-input.js +130 -0
  68. package/js/rte/src/input/input-pipeline.js +459 -0
  69. package/js/rte/src/mark/README.md +219 -0
  70. package/js/rte/src/mark/dom-adapter.js +100 -0
  71. package/js/rte/src/mark/mark.js +133 -0
  72. package/js/rte/src/mark/standard.js +76 -0
  73. package/js/rte/src/model/README.md +71 -0
  74. package/js/rte/src/model/content-model.js +213 -0
  75. package/js/rte/src/model/html/README.md +51 -0
  76. package/js/rte/src/model/html/html-model.js +90 -0
  77. package/js/rte/src/normalize/execute/README.md +33 -0
  78. package/js/rte/src/normalize/execute/repair-executor.js +129 -0
  79. package/js/rte/src/normalize/normalizer/README.md +48 -0
  80. package/js/rte/src/normalize/normalizer/normalizer.js +141 -0
  81. package/js/rte/src/normalize/repair/README.md +70 -0
  82. package/js/rte/src/normalize/repair/repair-planner.js +208 -0
  83. package/js/rte/src/sanitize/README.md +108 -0
  84. package/js/rte/src/sanitize/native.js +43 -0
  85. package/js/rte/src/sanitize/policy.js +206 -0
  86. package/js/rte/src/selection/README.md +39 -0
  87. package/js/rte/src/selection/map/README.md +53 -0
  88. package/js/rte/src/selection/map/point-map.js +307 -0
  89. package/js/rte/src/selection/ownership/README.md +32 -0
  90. package/js/rte/src/selection/ownership/ownership.js +42 -0
  91. package/js/rte/src/selection/point/README.md +34 -0
  92. package/js/rte/src/selection/point/point.js +83 -0
  93. package/js/rte/src/selection/range/README.md +38 -0
  94. package/js/rte/src/selection/range/edit-range.js +223 -0
  95. package/js/rte/src/selection/snapshot.js +64 -0
  96. package/js/rte/src/source/README.md +64 -0
  97. package/js/rte/src/source/source.js +193 -0
  98. package/js/rte/src/surface/README.md +36 -0
  99. package/js/rte/src/surface/content.js +16 -0
  100. package/js/rte/src/surface/surface.js +87 -0
  101. package/js/rte/src/transaction/README.md +35 -0
  102. package/js/rte/src/transaction/transaction.js +56 -0
  103. package/js/rte/src/ui/README.md +271 -0
  104. package/js/rte/src/ui/caret.js +17 -0
  105. package/js/rte/src/ui/chrome.js +214 -0
  106. package/js/rte/src/ui/handles.js +179 -0
  107. package/js/rte/src/ui/highlight.js +86 -0
  108. package/js/rte/src/ui/place.js +25 -0
  109. package/js/rte/src/ui/toolbar.js +258 -0
  110. package/js/rte/src/unstyle/README.md +103 -0
  111. package/js/rte/src/unstyle/unstyle.js +140 -0
  112. package/js/rte/tables.js +7 -0
  113. package/js/rte/unstyle.js +8 -0
  114. package/js/rte0/README.md +37 -0
  115. package/js/rte0/rte.js +7 -0
  116. package/js/{rte → rte0}/src/behavior.js +0 -1
  117. package/js/{rte → rte0}/src/events.js +0 -1
  118. package/js/{rte → rte0}/src/range.js +0 -2
  119. package/js/{rte → rte0}/src/ui.items.js +0 -2
  120. package/js/{rte → rte0}/src/ui.js +0 -1
  121. package/package.json +1 -1
  122. package/u2/Element.js +2 -2
  123. package/u2/plan-scoped-refactoring.md +133 -303
  124. package/u2/projects.json +18 -2
  125. package/u2/tools/update.repos.json.js +1 -1
  126. package/el/qrcode/package.json +0 -22
  127. /package/js/{rte → rte0}/old/NodeCleaner.js +0 -0
  128. /package/js/{rte → rte0}/old/Rte/Rte.mjs +0 -0
  129. /package/js/{rte → rte0}/old/Rte/Rte.ui.items.mjs +0 -0
  130. /package/js/{rte → rte0}/old/Rte/Rte.ui.mjs +0 -0
  131. /package/js/{rte → rte0}/old/Rte/crossbrowser.mjs +0 -0
  132. /package/js/{rte → rte0}/old/Rte/font/tinymce.svg +0 -0
  133. /package/js/{rte → rte0}/old/Rte/font/tinymce.woff +0 -0
  134. /package/js/{rte → rte0}/old/Rte/helpers.mjs +0 -0
  135. /package/js/{rte → rte0}/old/Rte/htmlparser.mjs +0 -0
  136. /package/js/{rte → rte0}/old/Rte/index.mjs +0 -0
  137. /package/js/{rte → rte0}/old/Rte/main.css +0 -0
  138. /package/js/{rte → rte0}/old/old.rte.js +0 -0
  139. /package/js/{rte → rte0}/old/range-selection.old.js +0 -0
  140. /package/js/{rte → rte0}/src/fixes.js +0 -0
  141. /package/js/{rte → rte0}/src/rte.js +0 -0
  142. /package/js/{rte → rte0}/src/ui/items/ai.js +0 -0
  143. /package/js/{rte → rte0}/src/ui/items/code.js +0 -0
  144. /package/js/{rte → rte0}/src/ui/items/undo.js +0 -0
  145. /package/js/{rte → rte0}/src/util/htmlparser.js +0 -0
  146. /package/js/{rte → rte0}/src/util/indentHtml.js +0 -0
@@ -1,336 +1,166 @@
1
- # Scoped-Refactoring: isolierte u2-Instanzen (z.B. CMS-Panel)
2
-
3
- ## Ziel
4
-
5
- Eine u2-Instanz **isoliert** in einem Shadow-DOM betreiben — konkreter Anwendungsfall: das CMS-Panel
6
- soll seine **eigene** u2-Version laden, ohne `window.customElements` zu verschmutzen
7
- oder mit der u2-Version der Host-Seite zu kollidieren.
8
-
9
- Dazu müssen zwei Dinge zusammenkommen:
10
-
11
- 1. Element-Dateien registrieren sich **nicht mehr selbst global** (kein
12
- `customElements.define(...)` als Import-Side-Effect).
13
- 2. Registrierung läuft über eine **austauschbare Registry** — global
14
- (`window.customElements`) oder scoped (`new CustomElementRegistry()`), gebunden
15
- an einen ShadowRoot.
16
-
17
- ## Ausgangslage
18
-
19
- - `el/{name}/{name}.js` definiert am Datei-Ende `customElements.define('u2-{name}', …)`
20
- als Side-Effect.
21
- - [`u2/auto.js`](auto.js) beobachtet das DOM per `MutationObserver`, importiert bei
22
- Gebrauch das passende Modul und verlässt sich darauf, dass **der Import** das Element
23
- global registriert.
24
- - **43 von 44** Element-Dateien sind bereits 1:1 `el/{name}/{name}.js` → `u2-{name}`
25
- und exportieren `export default class`.
26
- - Sonderfälle:
27
- - [`el/calendar/calendar.js`](../el/calendar/calendar.js) definiert **zwei** Elemente
28
- (`u2-calendar` + `u2-calendaritem`); `U2CalendarItem` ist aktuell **nicht** exportiert.
29
- - [`el/system/styler.js`](../el/system/styler.js) → `u2-system-styler` (Tag ≠ Ordnername,
30
- wird nicht über auto.js geladen).
31
- - Einige Elemente rendern **andere** u2-Elemente in ihr eigenes Shadow-DOM und
32
- verlassen sich auf den globalen Side-Effect, z.B.
33
- [`el/accordion/accordion.js`](../el/accordion/accordion.js) → `import('../ico/ico.js')`,
34
- ebenso `buttongroup`→`focusgroup`, `fields`→`responsive`, `rating`→`ico`.
35
-
36
- ## Zielarchitektur
37
-
38
- ### `U2Auto` — Factory statt globalem Modul-Side-Effect
39
-
40
- Der MutationObserver-Mechanismus aus [`u2/auto.js`](auto.js) wird zu einer Klasse,
41
- die eine **Registry** und einen **Root** kapselt. Beim Erkennen eines Elements
42
- importiert sie das Modul und registriert es **selbst** aus den Exports — statt sich auf
43
- den Side-Effect zu verlassen.
1
+ # Scoped u2: mehrere u2-Versionen auf einer Seite
44
2
 
45
- ```js
46
- class U2Auto {
47
- // registry defaults to the shadow's own registry, else the global one
48
- constructor(root, registry = root.registry ?? customElements) {
49
- this.root = root;
50
- this.registry = registry;
51
- this.mo = new MutationObserver(entries => {
52
- for (const entry of entries)
53
- for (const node of entry.addedNodes) this._newNodeRoot(node);
54
- });
55
- this.mo.observe(root, { childList: true, subtree: true });
56
- this._newNodeRoot(root);
57
- }
58
-
59
- async _loadEl(name) {
60
- const tag = 'u2-' + name;
61
- if (this.registry.get(tag)) return;
62
- const mod = await import(rootUrl + 'el/' + name + '/' + name + '.js');
63
- if (!this.registry.get(tag)) this.registry.define(tag, mod.default);
64
- for (const [t, cls] of Object.entries(mod.extraElements ?? {}))
65
- if (!this.registry.get(t)) this.registry.define(t, cls);
66
- }
67
- // … _newNode / _newNodeRoot / class + attr handling wie bisher
68
- }
69
- ```
3
+ **Ziel:** Ein CMS-Panel (oder jedes andere eingebettete UI) läuft mit *seiner* u2-Version in
4
+ *seinem* Shadow-Root, unabhängig davon, welche u2-Version die Kundenseite lädt. Grundlage sind
5
+ Scoped Custom Element Registries — Chrome/Edge 146+, Safari 26+, Firefox noch nicht.
70
6
 
71
- - **Global** (heutiges Verhalten): beim Laden von `auto.js` wird automatisch
72
- `new U2Auto(document.documentElement)` erzeugt → Registry = `customElements`.
73
- - **Scoped**: `new U2Auto(shadowRoot, scopedRegistry)` → registriert **nur** in dieses
74
- Shadow, `window.customElements` bleibt unberührt.
7
+ ---
75
8
 
76
- ### Warum die Registry ein Parameter bleibt (nicht lazy ableitbar)
9
+ ## Stand (1.5.3)
77
10
 
78
- Eine scoped Registry wird **bei `attachShadow({ registry })` gebunden** und lässt sich
79
- danach nicht mehr an einen bestehenden ShadowRoot hängen. Wenn U2Auto den ShadowRoot
80
- bekommt, ist es zum *Erzeugen* der Registry längst zu spät.
11
+ **Funktioniert.** Das Panel kann u2-Elemente benutzen, ohne dass auf der Kundenseite etwas kaputt
12
+ geht — auch wenn beide eine andere u2-Version fahren.
81
13
 
82
- - **Zurücklesen** geht über den nativen Getter `ShadowRoot.prototype.registry` → daher
83
- der Default `registry = root.registry ?? customElements`.
84
- - Aber der Aufrufer muss die Registry **vorher** erzeugt und beim `attachShadow`
85
- mitgegeben haben. `el.shadowRoot ? new CustomElementRegistry() : customElements` wäre
86
- **falsch**: die dort neu erzeugte Registry ist mit nichts verdrahtet.
87
- - Root-Typ-Check: `root instanceof ShadowRoot` (nicht `el.shadowRoot`, denn U2Auto
88
- bekommt den Root selbst, nicht den Host).
14
+ | Datei | Rolle |
15
+ |---|---|
16
+ | [`u2/enhance.js`](enhance.js) | scannt einen Root, lädt Elemente/Klassen/Attribute nach, registriert sie in **dessen** Registry. `attachShadow(host, opts)` als Convenience. Ein `MutationObserver` hält es aktuell — dieselbe Mechanik wie `auto.js`, nur ohne globale Nebenwirkungen. |
17
+ | [`u2/Element.js`](Element.js) | Basisklasse. `attachShadow()` belegt `customElementRegistry` vor, `useEl`/`useClass`/`useAttr` holen Kinder samt CSS ins eigene Shadow. Hängt an nichts. |
18
+ | [`u2/auto.js`](auto.js) | unverändert im Verhalten, benutzt intern `enhance` |
19
+ | [`u2/tests/enhance.test.html`](tests/enhance.test.html) | Browser-Test, 35 grün, 1 bekannte Lücke |
89
20
 
90
- ### Convenience-Helper zum Attachen
21
+ `enhance` bindet `css/norm/norm.css` und `css/base/base.css` automatisch ein. Elemente definieren
22
+ sich weiterhin selbst global, aber mit Guard (`customElements.get(tag) || define(...)`) — deshalb
23
+ wirft eine zweite u2-Version nicht mehr.
91
24
 
92
- Da Registry-Erzeugung und `attachShadow` zusammengehören:
25
+ ### Zwei Regeln, die daraus folgen
93
26
 
94
- ```js
95
- function attachU2Shadow(host, opts = {}) {
96
- const registry = new CustomElementRegistry();
97
- const shadow = host.attachShadow({ mode: 'open', ...opts, registry });
98
- new U2Auto(shadow, registry);
99
- return shadow;
100
- }
101
- ```
27
+ **1. Wer ein u2-Element in sein eigenes Shadow rendert, erbt von `U2Element`.** Das ist keine
28
+ Migration — von 41 Elementen tun das genau sechs: `alert`, `accordion`, `calendar`, `rating`
29
+ (je `ico`), `input` (`ico`, `bytes`, `badge`) und `fields` (`responsive`). Die übrigen 35 öffnen
30
+ entweder kein Shadow oder rendern nichts von u2 hinein.
31
+
32
+ **2. Kind-CSS gehört in den Root, in dem das Kind steht.** u2-Elemente haben meist *kein* eigenes
33
+ Shadow — `ico` schreibt sein SVG ins Light DOM, und `ico.css` stylt `u2-ico { … }` von aussen. Ein
34
+ Kind kann sich nicht selbst stylen, der Vater muss die CSS holen. Das macht jetzt `use*()`.
35
+
36
+ ### Warum keine Deklaration am Element
37
+
38
+ Ein `static hasCss` müsste erst per JS geladen werden, bevor die CSS überhaupt startet — es macht
39
+ den wichtigeren Request garantiert langsamer. `projects.json` wäre ebenfalls erst ein Fetch (und ist
40
+ Enhance-Territorium). Also beides parallel und bedingungslos; die Defaults kommen aus der Kategorie:
41
+
42
+ | | js | css | Dateien im Repo |
43
+ |---|---|---|---|
44
+ | `el` | ja | ja | js 41/41, css 37/41 |
45
+ | `class` | **nein** | ja | js 0/8, css 8/8 |
46
+ | `attr` | ja | **nein** | js 15/16, css 1/16 |
47
+
48
+ Ausreisser gehören an die Aufrufstelle, nicht als Feld an alle 41 Elemente:
49
+ `useAttr('skin', {css:true, js:false})`. `skin` bleibt dauerhaft ein Attribut, weil es einen Wert
50
+ trägt — als Klasse ginge das erst mit einem Selektor wie `.u2-class-*`.
51
+
52
+ `v1.5.3` ist veröffentlicht; qino zeigt darauf — beide Pins,
53
+ [`qino/deno.json`](../../qinojs/qino/deno.json) und `core/lib/util.ts`, ein Test wacht über den
54
+ Gleichlauf. `deno check --all qino/` ist grün.
55
+
56
+ ---
57
+
58
+ ## Offen
102
59
 
103
- ### `define()`-Helper — der zentrale Seam
60
+ ### 1. Attribute — der eigentlich ungelöste Teil
104
61
 
105
- Statt roher `customElements.define(...)`-Aufrufe eine geführte, idempotente Funktion:
62
+ Elemente sind isoliert, Attribute nicht. Ein Attribut-Modul hängt beim Auswerten Listener ans
63
+ `document`:
106
64
 
107
65
  ```js
108
- // u2/define.js
109
- export function define(tag, cls, registry = customElements) {
110
- if (!registry.get(tag)) registry.define(tag, cls);
111
- }
66
+ document.addEventListener('click', e => { … e.composedPath()[0].closest('[u2-confirm]') … });
112
67
  ```
113
68
 
114
- Der Guard macht Doppel-Registrierung harmlos (wichtig für die Übergangsphase, in der
115
- sowohl U2Auto als auch der Datei-Side-Effect definieren können).
116
-
117
- ## Firefox / Scoped Custom Element Registries
118
-
119
- - Native `attachShadow({ registry })`, `new CustomElementRegistry()` und der Getter
120
- `ShadowRoot.prototype.registry`: **Chrome/Safari ja, Firefox noch nicht.**
121
- - Lösung: der offizielle Polyfill
122
- **`@webcomponents/scoped-custom-element-registry`**.
123
- - **Wichtig:** der Polyfill **behält den Tag-Namen** bei (`u2-foo` bleibt `u2-foo`).
124
- Er renamed nicht, sondern patcht `attachShadow`, den `innerHTML`-Setter,
125
- `createElement`, `importNode` etc. und wendet im jeweiligen Scope den richtigen
126
- Konstruktor auf denselben Tag an.
127
- → **CSS `u2-foo {}` matcht weiterhin**, Shadow-`<style>` sowieso.
128
- - Der „Name ändert sich / CSS bricht"-Fall gilt nur bei selbstgebautem Poor-man's-Scoping
129
- (`u2-foo-v2` pro Scope) — das machen wir **nicht**.
130
- - Realkosten des Polyfills:
131
- - muss **vor** dem ersten scoped ShadowRoot geladen sein,
132
- - etwas Laufzeit-Overhead,
133
- - wenige Edge-Cases (`el.constructor`).
134
- - **Namen (recherchiert, nicht `registry` — das war ein Entwurfsname):**
135
- `host.attachShadow({ customElementRegistry })`, Rücklesen über
136
- `root.customElementRegistry`, programmatisch
137
- `document.createElement(tag, { customElementRegistry })`, nachträglich
138
- `registry.initialize(root)`. Chrome/Edge 146+, Safari 26+, Firefox noch nicht.
139
- - Feature-Detection:
140
- ```js
141
- if (!('customElementRegistry' in ShadowRoot.prototype))
142
- await import('.../scoped-custom-element-registry.min.js');
143
- ```
144
- Einmal am Anfang laden, danach funktioniert scoped überall gleich.
145
-
146
- ## CSS-Anmerkung
147
-
148
- Komponenten-CSS liegt teils im Shadow des Elements (accordion importiert `ico.css` in sein
149
- eigenes Shadow), teils stylt es das Element **von aussen**: `ico.css` setzt
150
- `u2-ico { --size }` und `u2-ico > svg { height }`. Solches CSS muss in den
151
- **konsumierenden** Root — ohne es hat `u2-ico` dort keine Grösse. `U2Auto` lädt Element-CSS
152
- deshalb in seinen Root, nicht ins Dokument.
153
-
154
- Das globale `impCss` (classless/utilities/base) bleibt davon unberührt; ob es zusätzlich ins
155
- Panel-Shadow soll, entscheidet man separat.
156
-
157
- **Was in einen Root gehört und was nicht** — die Trennlinie verläuft nach Selektor-Reichweite,
158
- nicht nach Datei:
159
-
160
- | | |
161
- |---|---|
162
- | vererbend (Tokens, `line-height`, `hyphens`, `font-family`) | kommt durch die Grenze — **nicht** in `:host` setzen, das wäre ein Zurücksetzen |
163
- | Element-/Universalselektoren (`*{box-sizing}`, `input{font:inherit}`, `img{max-inline-size}`, `table`, `a`, `h1`) | hält an der Grenze — **nur dafür** adoptiert man ein Sheet |
164
- | Host-Kasten (`block-size`, `overflow-y`, `scrollbar-gutter`) | gehört gar nicht auf `:host` |
69
+ Der Radius ist enger als es klingt: ein Attribut wirkt nur auf Elemente, die seinen Namen tragen.
70
+ Hat die Kundenseite kein `u2-confirm`, merkt sie von der Panel-Nutzung nichts. Drei echte Risiken,
71
+ nach Schwere:
165
72
 
166
- `input, textarea, select, button { font: inherit }` ist der wichtigste: es *stellt* Vererbung
167
- erst her, die UA-Styles brechen. Ohne diese Regel erbt ein Formularfeld im Root nichts.
73
+ **a) `draghandle` verändert die Kundenseite bedingungslos.** [`attr/draghandle/draghandle.js:1`](../attr/draghandle/draghandle.js)
74
+ importiert statisch einen Fremd-Polyfill von `bernardo-castilho.github.io` — ein Drittanbieter-Script
75
+ auf einer fremden Seite, plus CSP-Problem. Das CSS daneben ist harmlos, es hängt an
76
+ `[u2-draghandle]`. **Im Panel bis auf Weiteres meiden.**
168
77
 
169
- Wer in einem Root wirklich neu beginnen will, setzt die Werte selbst — die Sheets tun es nicht
170
- für ihn.
78
+ **b) Doppelinstallation.** Lädt die Kundenseite dasselbe Attribut aus ihrer Version, hängen zwei
79
+ Listener-Sätze am Dokument → doppelte Confirm-Dialoge, doppelte Drops. Der realistische Alltagsfall.
171
80
 
172
- ## Interne Element-Deps (der harte Teil)
81
+ **c) Version-Hijack.** Wer zuerst lädt, gewinnt — wie bei Elementen vor Phase 3.
173
82
 
174
- Elemente, die andere u2-Elemente in ihr **eigenes** Shadow rendern, dürfen sich nicht mehr
175
- auf den globalen Side-Effect verlassen. In einer scoped Registry ist `u2-ico` sonst nicht
176
- sichtbar.
83
+ **Billiger Zwischenschritt (nicht breaking, ~16 Einzeiler):** ein Idempotenz-Guard pro Attribut, das
84
+ Gegenstück zu `customElements.get()` — ein Symbol am `document`, die zweite Kopie installiert nicht.
85
+ Erledigt (b) vollständig; aus „zwei kaputte Kopien" wird „eine funktionierende". (c) bleibt.
177
86
 
178
- **Gemessen** ([u2/tests/enhance.test.html](tests/enhance.test.html), Chrome nativ):
87
+ **Richtige Lösung (1.6.0):** Attribute exportieren `install(root)` statt sich selbst zu installieren,
88
+ `useAttr` installiert in den Root. **Der Haken:** fünf von ihnen — `confirm`, `dropzone`,
89
+ `draghandle`, `movable`, `selectable` — benutzen `composedPath()` *absichtlich*, um über
90
+ Shadow-Grenzen hinweg zu arbeiten. Für die ist „der Root" nicht die richtige Grenze. Das geht Modul
91
+ für Modul und ist eine Design-, keine Fleissarbeit.
179
92
 
180
- - Ein im scoped Root geparstes Element trägt die Registry: `el.customElementRegistry === outer`.
181
- - Aber `el.attachShadow({mode})` **ohne** die Option bekommt `window.customElements` — die
182
- Vererbung passiert *nicht* automatisch. **Isolation komponiert nicht von selbst.**
183
- - Dieselbe Klasse darf in **mehreren** Registries definiert werden. Ein Element braucht darum
184
- keine Singleton zu importieren, es folgt seinem Root.
93
+ **Nebenbefund, unabhängig davon:** manche Attribute funktionieren im Shadow-DOM *heute schon* nicht
94
+ sauber. `dropzone` sucht seine Zonen per [`document.querySelectorAll('[u2-dropzone]')`](../attr/dropzone/dropzone.js#L17),
95
+ was in einen Shadow-Root nicht hineinsieht — die Events kommen per `composedPath` an, die
96
+ Buchhaltung nicht.
185
97
 
186
- Ein Element muss seine Registry deshalb aktiv weiterreichen, und zwar an beiden Stellen:
98
+ ### 2. Phase 3 — Selbstregistrierung entfernen (die letzte Lücke)
187
99
 
188
- ```js
189
- const registry = this.customElementRegistry ?? customElements;
190
- this.attachShadow({ mode: 'open', customElementRegistry: registry });
100
+ Die eine verbleibende rote Zeile im Browser-Test: `el/ico/ico.js` registriert sich weiterhin in
101
+ `window.customElements`.
102
+
103
+ **Was es bringt:** Ladereihenfolge wird egal. Heute gilt: lädt das **Panel zuerst**, definiert es
104
+ `u2-ico` aus seiner Version global; danach sieht das u2 der Kundenseite den Namen belegt,
105
+ überspringt still — und **die Kundenseite bekommt die Panel-Version**. Kein Fehler, kein Hinweis.
106
+ Umgekehrt (Kunde zuerst) ist alles korrekt.
107
+
108
+ **Was es kostet:** nicht die 16 Repo-Seiten, die ein Element-JS direkt per Script-Tag laden
109
+ (98 weitere gehen über `auto.js` und wären unberührt), sondern dass
191
110
 
192
- import U2Ico from '../ico/ico.js';
193
- registry.define('u2-ico', U2Ico); // nicht global
111
+ ```html
112
+ <script src="…/el/buttongroup/buttongroup.js" type=module async></script>
194
113
  ```
195
114
 
196
- Betroffen: `accordion`→`ico`, `alert`→`ico`, `calendar`→`ico`, `rating`→`ico`,
197
- `input`→`ico`+`bytes`, `fields`→`responsive`.
198
-
199
- > Ohne diesen Schritt ist die Isolation genau eine Ebene tief: das Panel-Root benutzt seine
200
- > Version, alles was ein Element in sein *eigenes* Shadow rendert, kommt aus der globalen —
201
- > also aus der Version der Host-Seite. `enhance` kann das nicht beheben, sein
202
- > MutationObserver endet an jeder Shadow-Grenze.
203
-
204
- ## Migrationsplan (phasenweise)
205
-
206
- ### Phase 1 — Additive Vorbereitung (non-breaking)
207
-
208
- Ziel: alles vorbereiten, ohne bestehendes Verhalten zu ändern.
209
-
210
- 1. **`export default` überall garantieren** (fehlt nur in 3 Dateien).
211
- Sekundär-Klassen mit exportieren:
212
- ```js
213
- // el/calendar/calendar.js
214
- export const extraElements = { 'u2-calendaritem': U2CalendarItem };
215
- ```
216
- 2. **`u2/define.js`** anlegen (siehe oben).
217
- 3. **Datei-Enden umstellen**: `customElements.define('u2-foo', U2Foo)` → `define('u2-foo', U2Foo)`.
218
- Verhalten identisch (global), aber Registrierung läuft durch den Seam.
219
- → Codemod über die 44 Dateien.
220
- 4. **Interne Deps entkoppeln**: Side-Effect-Importe zwischen Elementen auf
221
- `import Cls; define('u2-x', Cls)` umstellen. Dank Guard harmlos-redundant, aber schon
222
- registry-agnostisch.
223
- 5. **`U2Auto`-Klasse** einführen; `auto.js` erzeugt die globale Default-Instanz
224
- (`new U2Auto(document.documentElement)`) und registriert aus den Exports statt aus dem
225
- Side-Effect.
226
-
227
- Nach Phase 1: global unverändert, aber die gesamte Plumbing für scoped ist vorhanden.
228
-
229
- ### Phase 2 — Scoped-Betrieb ermöglichen
230
-
231
- 6. **Polyfill-Loader** + Feature-Detection einbauen.
232
- 7. **`attachU2Shadow(host)`** exportieren.
233
- 8. CMS-Panel: eigenes Shadow via `attachU2Shadow` erzeugen und dort die isolierte
234
- u2-Instanz laufen lassen. Scoped werden nur die `u2-*`-Elemente; die eigenen Elemente
235
- des Konsumenten bleiben global — sie haben eindeutige Namen, existieren in einer
236
- Version, und der Host muss von aussen auffindbar bleiben.
237
-
238
- ### Phase 3 — Isolation scharf schalten (der einzige echte Break)
239
-
240
- 9. **Self-`define()` am Datei-Ende entfernen**, sodass ein direktes `import 'foo.js'`
241
- nicht mehr registriert. Erst dann leakt nichts mehr global.
242
- → Ein-Zeilen-Codemod pro Datei; auto.js/U2Auto definieren zu dem Zeitpunkt längst selbst.
243
-
244
- > **Ehrlicher Haken:** *volle* Isolation im Panel gibt es erst mit Phase 3. Solange die
245
- > Dateien sich selbst global definieren, leakt jedes im Panel geladene Element in
246
- > `window.customElements`. Phase 2 lässt sich aber komplett fertig testen; nur die
247
- > Leak-Freiheit kommt zuletzt.
248
-
249
- ## Breaking Changes & Migrationsanweisungen
250
-
251
- Erst ab **Phase 3** relevant:
252
-
253
- 1. **`import 'u2/el/foo/foo.js'` definiert das Element nicht mehr** — nur noch der Export
254
- existiert. Grösster Bruch.
255
- - *Migration:* entweder auto.js verwenden (keine Änderung nötig), oder manuell:
256
- ```js
257
- import U2Foo from 'u2/el/foo/foo.js';
258
- customElements.define('u2-foo', U2Foo); // bzw. define(...) aus u2/define.js
259
- ```
260
- 2. **Inter-Element-Side-Effect-Importe** greifen nicht mehr (bereits in Phase 1 auf
261
- explizites `define()` umgestellt → kein Bruch, wenn Phase 1 gemacht wurde).
262
- 3. **`extraElements`** (calendaritem) muss explizit registriert werden (macht U2Auto).
263
-
264
- ## Offen / später
265
-
266
- - **Attribute sind kein Registry-Problem.** Sie kollidieren nicht über Namen, sie
267
- *installieren sich doppelt*, wenn zwei u2-Kopien laufen. Alle 10 hängen ihre Listener an
268
- `document`, vier davon (`confirm`, `dropzone`, `draghandle`, `movable`) benutzen
269
- `composedPath()` — sie arbeiten absichtlich über Shadow-Grenzen hinweg, und sie an einen
270
- Scope zu binden würde sie kaputtmachen.
271
- Zu klären ist deshalb nicht „wie scopen wir", sondern zweierlei: **einmal pro Dokument**
272
- installieren, und **pro Modul** entscheiden, welche Wirkung wirklich subtree-lokal ist.
273
-
274
- ## Erledigt in 1.5.2 — `U2Element`
275
-
276
- [`u2/Element.js`](Element.js): Basisklasse, die den Elementen die Registry-Arbeit abnimmt.
277
- `attachShadow()` belegt `customElementRegistry: this.customElementRegistry` vor — alle
278
- Aufrufstellen bleiben dadurch **wortgleich wie vorher**. `this.useEl(name)` importiert
279
- `el/<name>/<name>.js` und definiert die Klasse in die eigene Registry (`?? customElements`).
280
- Async ist unkritisch: ein Element upgraded auch, wenn es erst nach dem `innerHTML` definiert wird.
281
-
282
- Dazu `useClass(name)` und `useAttr(name)`. Alle drei holen ausserdem die **CSS ins eigene Shadow** —
283
- u2-Elemente haben meist kein eigenes Shadow (`ico` schreibt sein SVG ins Light DOM, `ico.css` stylt
284
- `u2-ico { … }` von aussen), CSS gehört deshalb immer dem Root, in dem das Kind steht. Der Vater
285
- musste sie bisher von Hand per `@import` holen, und `fields` vergass `responsive.css` dabei.
286
-
287
- **Keine Deklaration am Kind.** Ein `static hasCss` müsste erst per JS geladen werden, bevor die CSS
288
- überhaupt startet — es macht den wichtigeren Request garantiert langsamer. `projects.json` wäre
289
- ebenfalls erst ein Fetch (und ist Enhance-Territorium). Also beides parallel, bedingungslos, und die
290
- Defaults kommen aus der Kategorie — dieselben wie in `enhance`:
291
-
292
- | | js | css | Dateien |
293
- |---|---|---|---|
294
- | `el` | ja | ja | js 41/41, css 37/41 |
295
- | `class` | **nein** | ja | js 0/8, css 8/8 |
296
- | `attr` | ja | **nein** | js 15/16, css 1/16 |
115
+ das **dokumentierte Installations-Snippet** ist — [`u2/tools/update.repos.json.js:159`](tools/update.repos.json.js#L159)
116
+ generiert es in jedes README. Neu wäre:
297
117
 
298
- Die Ausreisser gehören an die *Aufrufstelle*, nicht als Feld an alle 41 Elemente:
299
- `useAttr('skin', {css:true})`. `skin` bleibt dauerhaft ein Attribut, weil es einen Wert trägt —
300
- als Klasse ginge das erst mit einem Selektor wie `.u2-class-*`.
118
+ ```html
119
+ <link href="…/el/buttongroup/buttongroup.css" rel=stylesheet>
120
+ <script type=module>
121
+ import U2Buttongroup from '…/el/buttongroup/buttongroup.js';
122
+ customElements.define('u2-buttongroup', U2Buttongroup);
123
+ </script>
124
+ ```
301
125
 
302
- **Reihenfolge:** adoptierte Sheets kommen *nach* den Tree-Styles, die Kind-CSS würde also die
303
- Overrides des Vaters schlagen. `use()` macht darum `unshift`, nicht `push` — sobald der `<style>`
304
- eines Vaters auch mal adoptiert wird, steht er hinter den Kindern, unabhängig davon, wann deren
305
- Sheet eintrifft. Solange der Vater ein Tree-`<style>` hat, muss er die Kind-Regeln
306
- **überspezifizieren**. Ein echter Fall bestand: `fields` überschrieb `u2-responsive {display:block}`
307
- mit `u2-responsive {display:grid}` — Gleichstand, jetzt `#container`.
126
+ Das ist der geplante 1.6.0-Break: 41 Dateien, plus READMEs und SKILL.md neu generieren.
308
127
 
309
- `U2Element` ist keine Migration, sondern eine Regel: **wer ein u2-Element in sein eigenes Shadow
310
- rendert, erbt davon.** Das sind heute genau diese sechs — die übrigen 35 öffnen entweder kein
311
- Shadow oder rendern nichts von u2 hinein und brauchen die Basisklasse nicht.
128
+ ### 3. CSS-Reihenfolge — zwei Wege, der zweite ist besser
312
129
 
313
- | Modul | Kind |
314
- |---|---|
315
- | `alert`, `accordion`, `calendar`, `rating` | `ico` |
316
- | `input` | `ico`, `bytes` |
317
- | `fields` | `responsive` |
130
+ Adoptierte Sheets kommen **nach** den Tree-Styles. `use()` macht darum `unshift` statt `push` — der
131
+ Kind-Sheet landet vorne, egal wann er eintrifft. Solange ein Vater sein CSS aber als Tree-`<style>`
132
+ im `innerHTML` hat, gewinnt die Kind-CSS bei Gleichstand trotzdem.
318
133
 
319
- ```js
320
- export default class U2Alert extends U2Element {
321
- constructor() {
322
- super();
323
- this.attachShadow({mode: 'open'}); // erbt die Registry
324
- this.useEl('ico'); // Klasse in die Registry + ico.css ins Shadow
325
- this.useAttr('focusgroup'); // nur js
326
- ```
134
+ Ein echter Fall bestand: `fields` überschrieb `u2-responsive {display:block}` mit `display:grid`,
135
+ Gleichstand — jetzt `#container`. Bei `alert` und `accordion` war die Eltern-Regel höher
136
+ spezifiziert, dort war nichts zu tun.
137
+
138
+ **Weg A — die sechs `<style>`-Blöcke adoptieren.** Dann bestimmt die Array-Reihenfolge
139
+ `[kind, eltern]` das Ergebnis statt der Spezifität. Zweiter Gewinn: ein Sheet auf Modulebene wird
140
+ einmal geparst statt einmal pro Instanz — heute parst ein `u2-alert` seinen Style-Block bei jeder
141
+ Instanz neu. Mechanisch, sechs Dateien, jede optisch nachzuprüfen.
142
+
143
+ **Weg B — Element-CSS in einen Layer legen.** `@layer u2.el { … }` in `ico.css` & Co. Ungelayerte
144
+ Regeln schlagen gelayerte **immer**, unabhängig von Spezifität und Reihenfolge. Damit gewinnt jeder
145
+ Vater automatisch, ohne `unshift`, ohne Umbau der sechs, ohne Spezifitäts-Nachrechnen — und
146
+ Anwender-Overrides werden allgemein einfacher statt schwerer. Bestehende Overrides brechen nicht:
147
+ sie sind heute ungelayert und werden dadurch stärker, nie schwächer.
148
+
149
+ Der Haken, den es wirklich gibt: **die Layer-Reihenfolge muss einmal deklariert werden.** u2 hat
150
+ schon `@layer normalize` in `base.css`/`norm.css`; kommt `u2.el` dazu, entscheidet die
151
+ Erstbegegnung — und `enhance` adoptiert asynchron. Die Antwort ist billig: `enhance` adoptiert als
152
+ allererstes ein Mini-Sheet mit `@layer u2.norm, u2.base, u2.el, u2.class;`. Danach ist die Ordnung
153
+ in jedem Root festgelegt, egal in welcher Reihenfolge die Sheets eintreffen.
154
+
155
+ Zweiter Haken, kleiner: `!important` kehrt die Layer-Reihenfolge um, und Anwender, deren *eigenes*
156
+ CSS gelayert ist, konkurrieren dann nach Layer-Ordnung statt nach „ungelayert schlägt gelayert".
157
+ Beides selten, beides dokumentierbar.
327
158
 
328
- Ausserhalb eines scoped Roots ist `this.customElementRegistry` `undefined`, die Option gilt als
329
- abwesend und `useEl()` fällt auf `customElements` zurück — Verhalten unverändert.
159
+ **Weg B macht Weg A überflüssig** — bis auf den Parse-Gewinn, der ein eigener, unabhängiger
160
+ Optimierungsschritt bleibt.
330
161
 
331
- Nicht betroffen, bewusst: **Attribute** (`focusgroup`, `draghandle`, `dropzone`, …) sind kein
332
- Registry-Thema; `table` erzeugt sein `u2-ico` im **Light DOM**, wo `enhance` es ohnehin sieht;
333
- `input`s `u2-badge` ist eine *Klasse*, kein Tag; `tree`s `u2-ico` ist auskommentiert.
334
- `U2CalendarItem` erbt `U2Element` mit, obwohl sein Shadow heute keine Custom Elements enthält.
162
+ ### 4. Firefox
335
163
 
336
- - Scoped-Verkettung von Kind-Elementen in die Eltern-Registry (siehe „Interne Deps").
164
+ Ohne Scoped Registries fällt `enhance` auf `customElements` zurück und alles verhält sich wie
165
+ bisher — kein Fehler, aber auch keine Isolation. Fürs CMS-Panel bewusst als Voraussetzung gesetzt.
166
+ Wenn Firefox nachzieht, ist nichts zu tun.
package/u2/projects.json CHANGED
@@ -196,6 +196,14 @@
196
196
  }
197
197
  },
198
198
  "el": {
199
+ "rte0": {
200
+ "name": "rte0",
201
+ "description": "\"Rich\" Rich Text Editor (alpha)",
202
+ "beta": false,
203
+ "deprecated": false,
204
+ "css": true,
205
+ "js": true
206
+ },
199
207
  "tabs": {
200
208
  "name": "tabs",
201
209
  "description": "Turns HTML structures with headings into an interactive, tabbed interface, using the content between headings as each tab’s content.",
@@ -278,7 +286,7 @@
278
286
  },
279
287
  "rte": {
280
288
  "name": "rte",
281
- "description": "\"Rich\" Rich Text Editor (alpha)",
289
+ "description": "Progressively enhances one native textarea with the RTE rich-text editor",
282
290
  "beta": false,
283
291
  "deprecated": false,
284
292
  "css": true,
@@ -560,6 +568,14 @@
560
568
  }
561
569
  },
562
570
  "js": {
571
+ "rte0": {
572
+ "name": "rte0",
573
+ "description": "Easily Make Elements Editable with Intuitive Controls",
574
+ "beta": false,
575
+ "deprecated": false,
576
+ "css": false,
577
+ "js": false
578
+ },
563
579
  "serviceWorker": {
564
580
  "name": "serviceWorker",
565
581
  "description": "",
@@ -586,7 +602,7 @@
586
602
  },
587
603
  "rte": {
588
604
  "name": "rte",
589
- "description": "Easily Make Elements Editable with Intuitive Controls",
605
+ "description": "A modular rich-text editing engine for current browsers",
590
606
  "beta": false,
591
607
  "deprecated": false,
592
608
  "css": false,
@@ -124,7 +124,7 @@ async function UsagePart(category, entry){
124
124
  content += '```js\n'+dedent(js).trim()+'\n```\n\n';
125
125
  }
126
126
 
127
- let html = code.split(/<section[^>]*>/)[1].split('<\/section>')[0];
127
+ let html = code.split(/<section[^>]*>/)?.[1]?.split?.('<\/section>')?.[0];
128
128
  if (html) {
129
129
  html = dedent(html);
130
130
  content += '```html\n'+html+'\n```\n\n';
@@ -1,22 +0,0 @@
1
- {
2
- "name": "u2-qrcode.el",
3
- "version": "2.0.2",
4
- "description": "qr-code element",
5
- "main": "qrcode.js",
6
- "author": "Tobias Buschor",
7
- "license": "MIT",
8
- "repository": {
9
- "type": "git",
10
- "url": "git+https://github.com/u2ui/qrcode.el.git"
11
- },
12
- "keywords": [
13
- "ui",
14
- ],
15
- "bugs": {
16
- "url": "https://github.com/u2ui/qrcode.el/issues"
17
- },
18
- "homepage": "https://github.com/u2ui/qrcode.el#readme",
19
- "scripts": {
20
- "test": "echo \"Error: no test specified\" && exit 1"
21
- }
22
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes