sibujs 4.5.0 → 4.6.0

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 (109) hide show
  1. package/dist/browser.cjs +309 -129
  2. package/dist/browser.d.cts +46 -14
  3. package/dist/browser.d.ts +46 -14
  4. package/dist/browser.js +8 -6
  5. package/dist/build.cjs +184 -72
  6. package/dist/build.js +15 -16
  7. package/dist/cdn.dev.global.js +12 -12
  8. package/dist/cdn.full.dev.global.js +11 -11
  9. package/dist/cdn.full.global.js +10 -10
  10. package/dist/cdn.global.js +12 -12
  11. package/dist/{chunk-IXKSNWV5.js → chunk-2INLLLMZ.js} +1 -1
  12. package/dist/chunk-3ISI6ACU.js +44 -0
  13. package/dist/{chunk-ONOHFDLG.js → chunk-47M47FOM.js} +3 -3
  14. package/dist/chunk-5HZXGZ6T.js +24 -0
  15. package/dist/{chunk-KKLW7YWL.js → chunk-5MT6SJ3P.js} +275 -144
  16. package/dist/{chunk-UGRX3S57.js → chunk-5Q4R7HCL.js} +12 -3
  17. package/dist/{chunk-S373NSMK.js → chunk-7GQCWFOE.js} +150 -59
  18. package/dist/{chunk-FTIR4QW2.js → chunk-7NCARGJW.js} +6 -8
  19. package/dist/{chunk-5DXA2J44.js → chunk-7XHATCIH.js} +5 -2
  20. package/dist/{chunk-VZKNK2V7.js → chunk-AIF3Z2T7.js} +296 -38
  21. package/dist/{chunk-4PMLNECI.js → chunk-BAAG6ZTI.js} +98 -29
  22. package/dist/{chunk-XZZOBQAY.js → chunk-D33YTSX5.js} +2 -2
  23. package/dist/{chunk-TBYTO6BS.js → chunk-DKGBBKOF.js} +136 -80
  24. package/dist/{chunk-NIOYEGBQ.js → chunk-HURREPU2.js} +27 -13
  25. package/dist/{chunk-GW3SCCZG.js → chunk-HYXDKS4N.js} +153 -110
  26. package/dist/chunk-J6FW5TV6.js +233 -0
  27. package/dist/{chunk-PCT43HW3.js → chunk-JSXPZCET.js} +1 -1
  28. package/dist/chunk-NYNYSPK7.js +318 -0
  29. package/dist/{chunk-RJE2BNI4.js → chunk-ORMZXBKQ.js} +108 -45
  30. package/dist/{chunk-OMJJM3KM.js → chunk-OXUY2A6L.js} +287 -130
  31. package/dist/{chunk-3JZ4L5TJ.js → chunk-PK6FK2G2.js} +181 -66
  32. package/dist/{chunk-RBTPLM32.js → chunk-QE4TTDU3.js} +2 -2
  33. package/dist/{chunk-2DCGACUU.js → chunk-SXXVZMKZ.js} +251 -66
  34. package/dist/{chunk-R25EFXXC.js → chunk-TUCPL2HB.js} +3 -3
  35. package/dist/{chunk-7LN645I6.js → chunk-UZQ6ALFS.js} +3 -3
  36. package/dist/{chunk-KEISJXBU.js → chunk-VVWPJ543.js} +6 -8
  37. package/dist/{chunk-RIXRAYIU.js → chunk-XC4MEKGA.js} +3 -3
  38. package/dist/{chunk-B3WHI2QA.js → chunk-XRRZKZYX.js} +55 -31
  39. package/dist/{contracts-DBdg9J_a.d.cts → contracts-DRIuclVT.d.cts} +10 -2
  40. package/dist/{contracts-DBdg9J_a.d.ts → contracts-DRIuclVT.d.ts} +10 -2
  41. package/dist/{customElement-OB9CIsc5.d.cts → customElement-MmInOW1U.d.cts} +21 -0
  42. package/dist/{customElement-OB9CIsc5.d.ts → customElement-MmInOW1U.d.ts} +21 -0
  43. package/dist/data.cjs +213 -117
  44. package/dist/data.d.cts +47 -9
  45. package/dist/data.d.ts +47 -9
  46. package/dist/data.js +12 -9
  47. package/dist/devtools.cjs +81 -57
  48. package/dist/devtools.js +7 -8
  49. package/dist/dispose-GEIG2KOF.js +28 -0
  50. package/dist/ecosystem.cjs +309 -104
  51. package/dist/ecosystem.d.cts +19 -3
  52. package/dist/ecosystem.d.ts +19 -3
  53. package/dist/ecosystem.js +12 -12
  54. package/dist/extras.cjs +2133 -863
  55. package/dist/extras.d.cts +10 -9
  56. package/dist/extras.d.ts +10 -9
  57. package/dist/extras.js +39 -28
  58. package/dist/index.cjs +184 -72
  59. package/dist/index.d.cts +22 -5
  60. package/dist/index.d.ts +22 -5
  61. package/dist/index.js +24 -27
  62. package/dist/motion.cjs +107 -41
  63. package/dist/motion.js +5 -5
  64. package/dist/patterns.cjs +317 -39
  65. package/dist/patterns.d.cts +27 -9
  66. package/dist/patterns.d.ts +27 -9
  67. package/dist/patterns.js +8 -8
  68. package/dist/performance.cjs +308 -216
  69. package/dist/performance.d.cts +2 -2
  70. package/dist/performance.d.ts +2 -2
  71. package/dist/performance.js +8 -9
  72. package/dist/plugin-DVgSnTfK.d.cts +112 -0
  73. package/dist/plugin-DVgSnTfK.d.ts +112 -0
  74. package/dist/plugins.cjs +549 -202
  75. package/dist/plugins.d.cts +3 -3
  76. package/dist/plugins.d.ts +3 -3
  77. package/dist/plugins.js +35 -23
  78. package/dist/signal-EotCj4hS.d.cts +110 -0
  79. package/dist/signal-EotCj4hS.d.ts +110 -0
  80. package/dist/{ssr-BiPRdZ6n.d.cts → ssr-Bli9XRW5.d.cts} +5 -0
  81. package/dist/{ssr-BiPRdZ6n.d.ts → ssr-Bli9XRW5.d.ts} +5 -0
  82. package/dist/{ssr-Y7XOEPEN.js → ssr-XOTUASDO.js} +4 -5
  83. package/dist/ssr.cjs +176 -72
  84. package/dist/ssr.d.cts +9 -3
  85. package/dist/ssr.d.ts +9 -3
  86. package/dist/ssr.js +11 -12
  87. package/dist/{startup-BMpaiMhP.d.ts → startup-BLfSeL15.d.cts} +73 -22
  88. package/dist/{startup-BMpaiMhP.d.cts → startup-BLfSeL15.d.ts} +73 -22
  89. package/dist/{tagFactory-DVoDpHye.d.ts → tagFactory-DFstCLQV.d.cts} +2 -100
  90. package/dist/{tagFactory-DVoDpHye.d.cts → tagFactory-DkaNVUNV.d.ts} +2 -100
  91. package/dist/testing.cjs +2484 -2185
  92. package/dist/testing.d.cts +56 -5
  93. package/dist/testing.d.ts +56 -5
  94. package/dist/testing.js +580 -307
  95. package/dist/ui.cjs +707 -317
  96. package/dist/ui.d.cts +40 -7
  97. package/dist/ui.d.ts +40 -7
  98. package/dist/ui.js +151 -56
  99. package/dist/widgets.cjs +246 -278
  100. package/dist/widgets.js +9 -10
  101. package/package.json +1 -1
  102. package/dist/chunk-2WLZ6757.js +0 -149
  103. package/dist/chunk-CCSJMTRN.js +0 -15
  104. package/dist/chunk-QKRPLZ2V.js +0 -108
  105. package/dist/chunk-VUF4ALSW.js +0 -60
  106. package/dist/chunk-WWV3SJ3L.js +0 -131
  107. package/dist/dispose-46BOMMQJ.js +0 -19
  108. package/dist/plugin-D30wlGW5.d.cts +0 -71
  109. package/dist/plugin-D30wlGW5.d.ts +0 -71
@@ -141,6 +141,90 @@ function reportError(error, context) {
141
141
  });
142
142
  }
143
143
 
144
+ // src/core/rendering/dispose.ts
145
+ var elementDisposers = /* @__PURE__ */ new WeakMap();
146
+ var MAX_DRAIN_TEARDOWNS = 1e4;
147
+ function reportDrainRunaway(label, executed, remaining) {
148
+ if (typeof console === "undefined") return;
149
+ console.error(
150
+ `[SibuJS ${label}] runaway cleanup: stopped after running ${executed} teardowns with ${remaining} still queued. Cleanup production did not stabilize before the teardown safety ceiling was reached \u2014 the remaining work was NOT run.`,
151
+ { executed, remaining }
152
+ );
153
+ }
154
+ var activeBindingCount = 0;
155
+ function resolveCapture(capture) {
156
+ let frame = capture;
157
+ while (frame?.closed) frame = frame.forwardTo;
158
+ return frame ?? null;
159
+ }
160
+ var registrationCaptures = [];
161
+ function currentDisposerCapture() {
162
+ return resolveCapture(registrationCaptures[registrationCaptures.length - 1]);
163
+ }
164
+ function beginDisposerCapture(capture) {
165
+ if (capture === null && registrationCaptures.length === 0) return false;
166
+ registrationCaptures.push(resolveCapture(capture));
167
+ return true;
168
+ }
169
+ function endDisposerCapture() {
170
+ registrationCaptures.pop();
171
+ }
172
+ function registerDisposer(node, teardown) {
173
+ let disposers = elementDisposers.get(node);
174
+ if (!disposers) {
175
+ disposers = [];
176
+ elementDisposers.set(node, disposers);
177
+ }
178
+ disposers.push(teardown);
179
+ if (DEV) activeBindingCount++;
180
+ const capture = resolveCapture(registrationCaptures[registrationCaptures.length - 1]);
181
+ if (capture) capture.entries.push([node, teardown]);
182
+ }
183
+ function dispose(node) {
184
+ const stack = [node];
185
+ const order = [];
186
+ while (stack.length > 0) {
187
+ const current = stack.pop();
188
+ order.push(current);
189
+ const children = Array.from(current.childNodes);
190
+ for (let i = 0; i < children.length; i++) {
191
+ stack.push(children[i]);
192
+ }
193
+ }
194
+ for (let i = order.length - 1; i >= 0; i--) {
195
+ disposeNodeOwn(order[i]);
196
+ }
197
+ }
198
+ function disposeNodeOwn(node) {
199
+ if (!elementDisposers.has(node)) return;
200
+ let executed = 0;
201
+ let runaway = false;
202
+ while (!runaway) {
203
+ const pending = elementDisposers.get(node);
204
+ if (!pending || pending.length === 0) break;
205
+ const snapshot = pending.slice();
206
+ elementDisposers.delete(node);
207
+ if (DEV) activeBindingCount -= snapshot.length;
208
+ for (let i = 0; i < snapshot.length; i++) {
209
+ if (executed >= MAX_DRAIN_TEARDOWNS) {
210
+ const rest = snapshot.slice(i);
211
+ const added = elementDisposers.get(node);
212
+ elementDisposers.set(node, added ? rest.concat(added) : rest);
213
+ if (DEV) activeBindingCount += rest.length;
214
+ reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
215
+ runaway = true;
216
+ break;
217
+ }
218
+ executed++;
219
+ try {
220
+ snapshot[i]();
221
+ } catch (err) {
222
+ reportError(err, { phase: "cleanup", name: "disposer" });
223
+ }
224
+ }
225
+ }
226
+ }
227
+
144
228
  // src/reactivity/track-core.ts
145
229
  var POOL_MAX = 4096;
146
230
  var nodePool = [];
@@ -299,6 +383,7 @@ function retrack(effectFn, subscriber) {
299
383
  }
300
384
  currentSubscriber = subscriber;
301
385
  const sub = subscriber;
386
+ if (sub._cap === void 0) sub._cap = currentDisposerCapture();
302
387
  const epoch = ++subscriberEpochCounter;
303
388
  sub._epoch = epoch;
304
389
  sub._structDirty = false;
@@ -490,7 +575,12 @@ function drainQueue() {
490
575
  quarantined.add(sub);
491
576
  continue;
492
577
  }
493
- safeInvoke(sub);
578
+ const pushed = beginDisposerCapture(sub._cap ?? null);
579
+ try {
580
+ safeInvoke(sub);
581
+ } finally {
582
+ if (pushed) endDisposerCapture();
583
+ }
494
584
  }
495
585
  }
496
586
  function drainNotificationQueue() {
@@ -626,7 +716,7 @@ function forEachSubscriber(signal2, visit) {
626
716
  }
627
717
 
628
718
  // src/reactivity/track.ts
629
- var _runtimeVersion = true ? "4.5.0" : "dev";
719
+ var _runtimeVersion = true ? "4.6.0" : "dev";
630
720
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
631
721
  function resolveReactiveApi() {
632
722
  const g = globalThis;
@@ -966,6 +1056,27 @@ function signal(initial, options) {
966
1056
  return [get, set];
967
1057
  }
968
1058
 
1059
+ // src/utils/adoptThenable.ts
1060
+ function adoptThenable(value) {
1061
+ if (value === null || typeof value !== "object" && typeof value !== "function") return null;
1062
+ let then;
1063
+ try {
1064
+ then = value.then;
1065
+ } catch (error) {
1066
+ return Promise.reject(error);
1067
+ }
1068
+ if (typeof then !== "function") return null;
1069
+ return new Promise((resolve, reject) => {
1070
+ queueMicrotask(() => {
1071
+ try {
1072
+ Reflect.apply(then, value, [resolve, reject]);
1073
+ } catch (error) {
1074
+ reject(error);
1075
+ }
1076
+ });
1077
+ });
1078
+ }
1079
+
969
1080
  // src/utils/globalSingleton.ts
970
1081
  function globalSingleton(key, create) {
971
1082
  const g = globalThis;
@@ -973,37 +1084,127 @@ function globalSingleton(key, create) {
973
1084
  }
974
1085
 
975
1086
  // src/plugins/plugin.ts
1087
+ var CANCELLED_BRAND = /* @__PURE__ */ Symbol.for("sibujs.plugins.installCancelled.v1");
1088
+ var _a;
1089
+ var PluginInstallCancelledError = class extends Error {
1090
+ constructor(pluginName) {
1091
+ super(`[Plugin] Installation of "${pluginName}" was cancelled before it was committed (registry reset).`);
1092
+ /**
1093
+ * Brand, not identity: the default registry is shared across duplicate copies
1094
+ * of this module, so the error a caller receives may come from another copy's
1095
+ * constructor. `instanceof` is taught to recognise the brand instead.
1096
+ */
1097
+ this[_a] = true;
1098
+ this.name = "PluginInstallCancelledError";
1099
+ this.pluginName = pluginName;
1100
+ }
1101
+ static [(_a = CANCELLED_BRAND, Symbol.hasInstance)](value) {
1102
+ return isPluginInstallCancelledError(value);
1103
+ }
1104
+ };
1105
+ function isPluginInstallCancelledError(value) {
1106
+ return typeof value === "object" && value !== null && value[CANCELLED_BRAND] === true;
1107
+ }
976
1108
  function createPluginRegistry() {
977
1109
  const installedPlugins = /* @__PURE__ */ new Set();
978
1110
  const hooks = { init: [], mount: [], unmount: [], error: [] };
979
1111
  const provided = /* @__PURE__ */ new Map();
1112
+ const installStack = /* @__PURE__ */ new Set();
1113
+ const pendingInstalls = /* @__PURE__ */ new Map();
1114
+ let generation = 0;
980
1115
  const registry = {
981
1116
  installedPlugins,
982
1117
  hooks,
983
1118
  provided,
1119
+ /**
1120
+ * Install a plugin as a transaction.
1121
+ *
1122
+ * Hooks and providers registered through `ctx` are staged and committed
1123
+ * only if `install()` returns; a throwing install leaves the registry
1124
+ * exactly as it found it (and can simply be retried). The plugin is marked
1125
+ * installed at commit, before its init hooks run.
1126
+ *
1127
+ * Each `plugin()` call is its own transaction: a dependency installed by a
1128
+ * nested `plugin()` call commits on its own and stays installed even if the
1129
+ * outer installation later fails.
1130
+ */
984
1131
  plugin(p, options) {
985
1132
  if (installedPlugins.has(p.name)) {
986
1133
  console.warn(`[Plugin] "${p.name}" is already installed.`);
987
1134
  return;
988
1135
  }
1136
+ if (installStack.has(p.name)) {
1137
+ throw new Error(`[Plugin] "${p.name}" is already being installed (recursive installation).`);
1138
+ }
1139
+ if (pendingInstalls.has(p.name)) {
1140
+ throw new Error(`[Plugin] "${p.name}" is already being installed (asynchronous installation in flight).`);
1141
+ }
1142
+ const staged = { init: [], mount: [], unmount: [], error: [] };
1143
+ const stagedProvided = /* @__PURE__ */ new Map();
1144
+ let committed = false;
1145
+ const myGeneration = generation;
1146
+ const stale = () => {
1147
+ if (myGeneration === generation) return false;
1148
+ if (DEV) devWarn(`plugin: "${p.name}" registered after the registry was reset; the registration was ignored.`);
1149
+ return true;
1150
+ };
1151
+ const target = () => stale() ? null : committed ? hooks : staged;
989
1152
  const ctx = {
990
- onInit: (cb) => hooks.init.push(cb),
991
- onMount: (cb) => hooks.mount.push(cb),
992
- onUnmount: (cb) => hooks.unmount.push(cb),
993
- onError: (cb) => hooks.error.push(cb),
994
- provide: (key, value) => provided.set(key, value)
1153
+ onInit: (cb) => void target()?.init.push(cb),
1154
+ onMount: (cb) => void target()?.mount.push(cb),
1155
+ onUnmount: (cb) => void target()?.unmount.push(cb),
1156
+ onError: (cb) => void target()?.error.push(cb),
1157
+ provide: (key, value) => {
1158
+ if (stale()) return;
1159
+ (committed ? provided : stagedProvided).set(key, value);
1160
+ }
995
1161
  };
996
- const initHooksBefore = hooks.init.length;
997
- p.install(ctx, options);
998
- installedPlugins.add(p.name);
999
- const justAdded = hooks.init.slice(initHooksBefore);
1000
- for (const cb of justAdded) {
1001
- try {
1002
- cb();
1003
- } catch (e) {
1004
- console.error(`[Plugin] "${p.name}" init error:`, e);
1162
+ const commit = () => {
1163
+ if (myGeneration !== generation) return false;
1164
+ hooks.init.push(...staged.init);
1165
+ hooks.mount.push(...staged.mount);
1166
+ hooks.unmount.push(...staged.unmount);
1167
+ hooks.error.push(...staged.error);
1168
+ for (const [key, value] of stagedProvided) provided.set(key, value);
1169
+ installedPlugins.add(p.name);
1170
+ committed = true;
1171
+ if (pendingInstalls.get(p.name) === myGeneration) pendingInstalls.delete(p.name);
1172
+ for (const cb of staged.init.slice()) {
1173
+ try {
1174
+ cb();
1175
+ } catch (e) {
1176
+ console.error(`[Plugin] "${p.name}" init error:`, e);
1177
+ }
1005
1178
  }
1179
+ return true;
1180
+ };
1181
+ installStack.add(p.name);
1182
+ let pending;
1183
+ try {
1184
+ pending = adoptThenable(p.install(ctx, options));
1185
+ } finally {
1186
+ installStack.delete(p.name);
1006
1187
  }
1188
+ if (!pending) {
1189
+ if (!commit()) throw new PluginInstallCancelledError(p.name);
1190
+ return;
1191
+ }
1192
+ if (myGeneration === generation) pendingInstalls.set(p.name, myGeneration);
1193
+ const settled = pending.then(
1194
+ () => {
1195
+ if (commit()) return;
1196
+ if (pendingInstalls.get(p.name) === myGeneration) pendingInstalls.delete(p.name);
1197
+ throw new PluginInstallCancelledError(p.name);
1198
+ },
1199
+ (err) => {
1200
+ if (pendingInstalls.get(p.name) === myGeneration) pendingInstalls.delete(p.name);
1201
+ reportError(err, { phase: "async", name: `plugin(${p.name})` });
1202
+ throw err;
1203
+ }
1204
+ );
1205
+ settled.catch(() => {
1206
+ });
1207
+ return settled;
1007
1208
  },
1008
1209
  inject(key, defaultValue) {
1009
1210
  if (provided.has(key)) return provided.get(key);
@@ -1041,6 +1242,8 @@ function createPluginRegistry() {
1041
1242
  }
1042
1243
  },
1043
1244
  reset() {
1245
+ generation++;
1246
+ pendingInstalls.clear();
1044
1247
  installedPlugins.clear();
1045
1248
  hooks.init.length = 0;
1046
1249
  hooks.mount.length = 0;
@@ -1581,70 +1784,6 @@ function bindAttribute(el, attr, getter) {
1581
1784
  return reactiveBinding2(commit, el);
1582
1785
  }
1583
1786
 
1584
- // src/core/rendering/dispose.ts
1585
- var elementDisposers = /* @__PURE__ */ new WeakMap();
1586
- var MAX_DRAIN_TEARDOWNS = 1e4;
1587
- function reportDrainRunaway(label, executed, remaining) {
1588
- if (typeof console === "undefined") return;
1589
- console.error(
1590
- `[SibuJS ${label}] runaway cleanup: stopped after running ${executed} teardowns with ${remaining} still queued. Cleanup production did not stabilize before the teardown safety ceiling was reached \u2014 the remaining work was NOT run.`,
1591
- { executed, remaining }
1592
- );
1593
- }
1594
- var activeBindingCount = 0;
1595
- function registerDisposer(node, teardown) {
1596
- let disposers = elementDisposers.get(node);
1597
- if (!disposers) {
1598
- disposers = [];
1599
- elementDisposers.set(node, disposers);
1600
- }
1601
- disposers.push(teardown);
1602
- if (DEV) activeBindingCount++;
1603
- }
1604
- function dispose(node) {
1605
- const stack = [node];
1606
- const order = [];
1607
- while (stack.length > 0) {
1608
- const current = stack.pop();
1609
- order.push(current);
1610
- const children = Array.from(current.childNodes);
1611
- for (let i = 0; i < children.length; i++) {
1612
- stack.push(children[i]);
1613
- }
1614
- }
1615
- for (let i = order.length - 1; i >= 0; i--) {
1616
- const current = order[i];
1617
- if (elementDisposers.has(current)) {
1618
- let executed = 0;
1619
- let runaway = false;
1620
- while (!runaway) {
1621
- const pending = elementDisposers.get(current);
1622
- if (!pending || pending.length === 0) break;
1623
- const snapshot = pending.slice();
1624
- elementDisposers.delete(current);
1625
- if (DEV) activeBindingCount -= snapshot.length;
1626
- for (let i2 = 0; i2 < snapshot.length; i2++) {
1627
- if (executed >= MAX_DRAIN_TEARDOWNS) {
1628
- const rest = snapshot.slice(i2);
1629
- const added = elementDisposers.get(current);
1630
- elementDisposers.set(current, added ? rest.concat(added) : rest);
1631
- if (DEV) activeBindingCount += rest.length;
1632
- reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
1633
- runaway = true;
1634
- break;
1635
- }
1636
- executed++;
1637
- try {
1638
- snapshot[i2]();
1639
- } catch (err) {
1640
- reportError(err, { phase: "cleanup", name: "disposer" });
1641
- }
1642
- }
1643
- }
1644
- }
1645
- }
1646
- }
1647
-
1648
1787
  // src/core/rendering/focusPreservation.ts
1649
1788
  var IDENTITY_ATTRS = ["data-focus-key", "id", "name"];
1650
1789
  var SELECTABLE_TYPES = /* @__PURE__ */ new Set(["text", "search", "url", "tel", "password", ""]);
@@ -2065,53 +2204,119 @@ var tagFactory = (tag, ns) => {
2065
2204
  };
2066
2205
 
2067
2206
  // src/ecosystem/ui/componentAdapter.ts
2207
+ var _themeLayers = globalSingleton(
2208
+ /* @__PURE__ */ Symbol.for("sibujs.themeLayers.v1"),
2209
+ () => /* @__PURE__ */ new WeakMap()
2210
+ );
2211
+ function commitThemeProperty(root, name, record) {
2212
+ const top = record.layers[record.layers.length - 1];
2213
+ if (top) {
2214
+ root.style.setProperty(name, top.value);
2215
+ return;
2216
+ }
2217
+ _themeLayers.get(root)?.delete(name);
2218
+ if (record.original.value === "") root.style.removeProperty(name);
2219
+ else root.style.setProperty(name, record.original.value, record.original.priority);
2220
+ }
2221
+ function setThemeLayer(root, name, handle, value) {
2222
+ let properties = _themeLayers.get(root);
2223
+ if (!properties) _themeLayers.set(root, properties = /* @__PURE__ */ new Map());
2224
+ let record = properties.get(name);
2225
+ if (!record) {
2226
+ record = {
2227
+ original: { value: root.style.getPropertyValue(name), priority: root.style.getPropertyPriority(name) },
2228
+ layers: []
2229
+ };
2230
+ properties.set(name, record);
2231
+ }
2232
+ const layer = record.layers.find((l) => l.handle === handle);
2233
+ if (layer) layer.value = value;
2234
+ else record.layers.push({ handle, value });
2235
+ commitThemeProperty(root, name, record);
2236
+ }
2237
+ function removeThemeLayer(root, name, handle) {
2238
+ const record = _themeLayers.get(root)?.get(name);
2239
+ if (!record) return;
2240
+ const index = record.layers.findIndex((l) => l.handle === handle);
2241
+ if (index === -1) return;
2242
+ record.layers.splice(index, 1);
2243
+ commitThemeProperty(root, name, record);
2244
+ }
2245
+ function ownString(map, key) {
2246
+ if (!map || key === void 0 || !Object.hasOwn(map, key)) return void 0;
2247
+ const value = map[key];
2248
+ return typeof value === "string" ? value : void 0;
2249
+ }
2068
2250
  function createTheme(initial) {
2069
2251
  const [getConfig, setConfig] = signal(initial);
2070
2252
  function resolveClass(component, variant) {
2071
2253
  const config = getConfig();
2072
2254
  const overrideKey = variant ? `${component}-${variant}` : component;
2073
- if (config.classOverrides?.[overrideKey]) {
2074
- return config.classOverrides[overrideKey];
2075
- }
2255
+ const override = ownString(config.classOverrides, overrideKey);
2256
+ if (override) return override;
2076
2257
  const base = `${config.prefix}-${component}`;
2077
2258
  return variant ? `${base} ${config.prefix}-${component}--${variant}` : base;
2078
2259
  }
2079
2260
  function setTheme(partial) {
2080
2261
  setConfig((prev) => ({ ...prev, ...partial }));
2081
2262
  }
2082
- return { config: getConfig, setTheme, resolveClass };
2263
+ function applyTo(root) {
2264
+ const handle = {};
2265
+ let applied = /* @__PURE__ */ new Set();
2266
+ const stop = effect(() => {
2267
+ const variables = getConfig().variables ?? {};
2268
+ const next = new Set(Object.keys(variables));
2269
+ for (const name of applied) {
2270
+ if (!next.has(name)) removeThemeLayer(root, name, handle);
2271
+ }
2272
+ for (const [name, value] of Object.entries(variables)) setThemeLayer(root, name, handle, value);
2273
+ applied = next;
2274
+ });
2275
+ let released = false;
2276
+ return () => {
2277
+ if (released) return;
2278
+ released = true;
2279
+ stop();
2280
+ for (const name of applied) removeThemeLayer(root, name, handle);
2281
+ applied.clear();
2282
+ };
2283
+ }
2284
+ return { config: getConfig, setTheme, resolveClass, applyTo };
2083
2285
  }
2084
2286
  function componentAdapter(config) {
2085
2287
  const theme = createTheme({ prefix: config.prefix });
2288
+ const reprefix = (cls, prefix) => prefix !== config.prefix && cls.startsWith(`${config.prefix}-`) ? `${prefix}-${cls.slice(config.prefix.length + 1)}` : cls;
2086
2289
  const components = {};
2087
2290
  for (const [name, mapping] of Object.entries(config.components)) {
2088
2291
  const factory = tagFactory(mapping.tag || "div");
2089
- components[name] = (props = {}) => {
2292
+ components[name] = (props = {}, children) => {
2090
2293
  const { variant, size, class: userClass, ...rest } = props;
2091
- const classes = [mapping.baseClass];
2092
- if (variant && mapping.variants?.[variant]) {
2093
- classes.push(mapping.variants[variant]);
2094
- }
2095
- if (size && mapping.sizes?.[size]) {
2096
- classes.push(mapping.sizes[size]);
2097
- }
2098
- let finalClass;
2099
- if (typeof userClass === "function") {
2100
- finalClass = () => {
2101
- const extra = userClass();
2102
- return extra ? `${classes.join(" ")} ${extra}` : classes.join(" ");
2103
- };
2104
- } else if (typeof userClass === "string" && userClass) {
2105
- finalClass = `${classes.join(" ")} ${userClass}`;
2106
- } else {
2107
- finalClass = classes.join(" ");
2108
- }
2294
+ const themeClasses = () => {
2295
+ const current = theme.config();
2296
+ const overrides = current.classOverrides ?? {};
2297
+ const pick = (key, fallback) => Object.hasOwn(overrides, key) ? overrides[key] : reprefix(fallback, current.prefix);
2298
+ const classes = [pick(name, mapping.baseClass)];
2299
+ const variantClass = ownString(mapping.variants, variant);
2300
+ if (variant && variantClass) {
2301
+ classes.push(pick(`${name}-${variant}`, variantClass));
2302
+ }
2303
+ const sizeClass = ownString(mapping.sizes, size);
2304
+ if (size && sizeClass) {
2305
+ classes.push(pick(`${name}-${size}`, sizeClass));
2306
+ }
2307
+ return classes.filter(Boolean).join(" ");
2308
+ };
2309
+ const finalClass = () => {
2310
+ const base = themeClasses();
2311
+ const extra = typeof userClass === "function" ? userClass() : userClass;
2312
+ return typeof extra === "string" && extra ? `${base} ${extra}` : base;
2313
+ };
2109
2314
  const mergedProps = {
2110
2315
  ...mapping.defaultProps,
2111
2316
  ...rest,
2112
2317
  class: finalClass
2113
2318
  };
2114
- return factory(mergedProps);
2319
+ return children === void 0 ? factory(mergedProps) : factory(mergedProps, children);
2115
2320
  };
2116
2321
  }
2117
2322
  return { name: config.name, components, theme };
@@ -1,5 +1,6 @@
1
- import { S as SibuPlugin } from './plugin-D30wlGW5.cjs';
2
- import { D as DerivedAccessor, T as TagProps } from './tagFactory-DVoDpHye.cjs';
1
+ import { S as SibuPlugin } from './plugin-DVgSnTfK.cjs';
2
+ import { D as DerivedAccessor, T as TagProps, a as NodeChildren } from './tagFactory-DFstCLQV.cjs';
3
+ import './signal-EotCj4hS.cjs';
3
4
 
4
5
  /** MobX autorun disposer function type. */
5
6
  type MobXReactionDisposer = () => void;
@@ -163,6 +164,16 @@ interface ThemeAPI {
163
164
  setTheme: (config: Partial<ThemeConfig>) => void;
164
165
  /** Resolve a component class name using prefix and overrides */
165
166
  resolveClass: (component: string, variant?: string) => string;
167
+ /**
168
+ * Install the theme's CSS variables on `root` (the theme root — typically the
169
+ * app container) and keep them in sync: variables added, changed or removed by
170
+ * `setTheme()` are reflected, and custom properties the theme never set are left
171
+ * alone. Handles may overlap on one root and be released in any order: the
172
+ * most recently applied live handle's value wins, and when no handle sets a
173
+ * property any more, the value and priority it had before are restored.
174
+ * Returns a function that stops syncing and releases this handle.
175
+ */
176
+ applyTo: (root: HTMLElement) => () => void;
166
177
  }
167
178
  /**
168
179
  * Creates a reactive theme for a UI component library adapter.
@@ -194,7 +205,12 @@ interface AdaptedComponentProps extends TagProps {
194
205
  /** Component size (e.g., "sm", "md", "lg") */
195
206
  size?: string;
196
207
  }
197
- type AdaptedComponent = (props?: AdaptedComponentProps) => Element;
208
+ /**
209
+ * A component produced by {@link componentAdapter}. Children may be passed
210
+ * positionally, exactly like a tag factory: `Button({ variant: "primary" }, "Save")`.
211
+ * Positional children take precedence over a `nodes` prop.
212
+ */
213
+ type AdaptedComponent = (props?: AdaptedComponentProps, children?: NodeChildren) => Element;
198
214
  /**
199
215
  * Creates a set of SibuJS components from a CSS framework's class mappings.
200
216
  *
@@ -1,5 +1,6 @@
1
- import { S as SibuPlugin } from './plugin-D30wlGW5.js';
2
- import { D as DerivedAccessor, T as TagProps } from './tagFactory-DVoDpHye.js';
1
+ import { S as SibuPlugin } from './plugin-DVgSnTfK.js';
2
+ import { D as DerivedAccessor, T as TagProps, a as NodeChildren } from './tagFactory-DkaNVUNV.js';
3
+ import './signal-EotCj4hS.js';
3
4
 
4
5
  /** MobX autorun disposer function type. */
5
6
  type MobXReactionDisposer = () => void;
@@ -163,6 +164,16 @@ interface ThemeAPI {
163
164
  setTheme: (config: Partial<ThemeConfig>) => void;
164
165
  /** Resolve a component class name using prefix and overrides */
165
166
  resolveClass: (component: string, variant?: string) => string;
167
+ /**
168
+ * Install the theme's CSS variables on `root` (the theme root — typically the
169
+ * app container) and keep them in sync: variables added, changed or removed by
170
+ * `setTheme()` are reflected, and custom properties the theme never set are left
171
+ * alone. Handles may overlap on one root and be released in any order: the
172
+ * most recently applied live handle's value wins, and when no handle sets a
173
+ * property any more, the value and priority it had before are restored.
174
+ * Returns a function that stops syncing and releases this handle.
175
+ */
176
+ applyTo: (root: HTMLElement) => () => void;
166
177
  }
167
178
  /**
168
179
  * Creates a reactive theme for a UI component library adapter.
@@ -194,7 +205,12 @@ interface AdaptedComponentProps extends TagProps {
194
205
  /** Component size (e.g., "sm", "md", "lg") */
195
206
  size?: string;
196
207
  }
197
- type AdaptedComponent = (props?: AdaptedComponentProps) => Element;
208
+ /**
209
+ * A component produced by {@link componentAdapter}. Children may be passed
210
+ * positionally, exactly like a tag factory: `Button({ variant: "primary" }, "Save")`.
211
+ * Positional children take precedence over a `nodes` prop.
212
+ */
213
+ type AdaptedComponent = (props?: AdaptedComponentProps, children?: NodeChildren) => Element;
198
214
  /**
199
215
  * Creates a set of SibuJS components from a CSS framework's class mappings.
200
216
  *
package/dist/ecosystem.js CHANGED
@@ -7,19 +7,19 @@ import {
7
7
  mobXAdapter,
8
8
  reduxAdapter,
9
9
  zustandAdapter
10
- } from "./chunk-4PMLNECI.js";
11
- import "./chunk-WWV3SJ3L.js";
12
- import "./chunk-KEISJXBU.js";
13
- import "./chunk-ONOHFDLG.js";
14
- import "./chunk-RBTPLM32.js";
15
- import "./chunk-IXKSNWV5.js";
10
+ } from "./chunk-BAAG6ZTI.js";
11
+ import "./chunk-J6FW5TV6.js";
12
+ import "./chunk-VVWPJ543.js";
13
+ import "./chunk-47M47FOM.js";
14
+ import "./chunk-QE4TTDU3.js";
15
+ import "./chunk-2INLLLMZ.js";
16
16
  import "./chunk-7ZHH77QA.js";
17
- import "./chunk-RIXRAYIU.js";
18
- import "./chunk-5DXA2J44.js";
19
- import "./chunk-QKRPLZ2V.js";
20
- import "./chunk-XZZOBQAY.js";
21
- import "./chunk-UGRX3S57.js";
22
- import "./chunk-2WLZ6757.js";
17
+ import "./chunk-XC4MEKGA.js";
18
+ import "./chunk-7XHATCIH.js";
19
+ import "./chunk-5HZXGZ6T.js";
20
+ import "./chunk-D33YTSX5.js";
21
+ import "./chunk-5Q4R7HCL.js";
22
+ import "./chunk-NYNYSPK7.js";
23
23
  export {
24
24
  antdAdapter,
25
25
  chakraAdapter,