@almadar/ui 4.50.16 → 4.50.18

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.
@@ -24913,6 +24913,7 @@ function useDataDnd(args) {
24913
24913
  sortable: sortable$1,
24914
24914
  dropEvent,
24915
24915
  reorderEvent,
24916
+ positionEvent,
24916
24917
  dndItemIdField = "id",
24917
24918
  dndRoot,
24918
24919
  items,
@@ -24980,8 +24981,8 @@ function useDataDnd(args) {
24980
24981
  const [activeDrag, setActiveDrag] = React93__namespace.default.useState(null);
24981
24982
  const [overZoneGroup, setOverZoneGroup] = React93__namespace.default.useState(null);
24982
24983
  const meta = React93__namespace.default.useMemo(
24983
- () => ({ group: ownGroup, dropEvent, reorderEvent, itemIds, rawItems: items, idField: dndItemIdField }),
24984
- [ownGroup, dropEvent, reorderEvent, itemIds, items, dndItemIdField]
24984
+ () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
24985
+ [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
24985
24986
  );
24986
24987
  React93__namespace.default.useEffect(() => {
24987
24988
  const target = isRoot ? null : parentRoot;
@@ -25067,6 +25068,20 @@ function useDataDnd(args) {
25067
25068
  dndLog.warn("dragEnd:abort:no-zone-resolved", { activeId: active.id, hasSource: !!sourceMeta, hasTarget: !!targetMeta });
25068
25069
  return;
25069
25070
  }
25071
+ const emitPositions = (zoneMeta) => {
25072
+ if (!zoneMeta.positionEvent) {
25073
+ dndLog.debug("dragEnd:positions:no-event", { group: zoneMeta.group });
25074
+ return;
25075
+ }
25076
+ const evt = `UI:${zoneMeta.positionEvent}`;
25077
+ const order = optimisticOrdersRef.current.get(zoneMeta.group) ?? zoneMeta.rawItems;
25078
+ order.forEach((it, idx) => {
25079
+ const id = String(it[zoneMeta.idField]);
25080
+ const position = idx * 1e3;
25081
+ eventBus.emit(evt, { id, position });
25082
+ });
25083
+ dndLog.info("dragEnd:positions:emitted", { event: evt, group: zoneMeta.group, count: order.length });
25084
+ };
25070
25085
  if (sourceMeta.group !== targetMeta.group) {
25071
25086
  if (targetMeta.dropEvent) {
25072
25087
  const evt = `UI:${targetMeta.dropEvent}`;
@@ -25086,6 +25101,8 @@ function useDataDnd(args) {
25086
25101
  } else {
25087
25102
  dndLog.warn("dragEnd:cross-container:no-dropEvent-on-target", { targetGroup: targetMeta.group });
25088
25103
  }
25104
+ emitPositions(sourceMeta);
25105
+ emitPositions(targetMeta);
25089
25106
  return;
25090
25107
  }
25091
25108
  if (oldIndex === newIndex) {
@@ -25108,6 +25125,7 @@ function useDataDnd(args) {
25108
25125
  } else {
25109
25126
  dndLog.debug("dragEnd:reorder:no-reorderEvent", { sourceGroup: sourceMeta.group });
25110
25127
  }
25128
+ emitPositions(sourceMeta);
25111
25129
  },
25112
25130
  [eventBus]
25113
25131
  );
@@ -25412,6 +25430,7 @@ function DataGrid({
25412
25430
  sortable,
25413
25431
  dropEvent,
25414
25432
  reorderEvent,
25433
+ positionEvent,
25415
25434
  dndItemIdField,
25416
25435
  dndRoot
25417
25436
  }) {
@@ -25429,6 +25448,7 @@ function DataGrid({
25429
25448
  sortable,
25430
25449
  dropEvent,
25431
25450
  reorderEvent,
25451
+ positionEvent,
25432
25452
  dndItemIdField,
25433
25453
  dndRoot
25434
25454
  });
@@ -25821,6 +25841,7 @@ function DataList({
25821
25841
  sortable: sortableProp,
25822
25842
  dropEvent,
25823
25843
  reorderEvent: dndReorderEvent,
25844
+ positionEvent,
25824
25845
  dndItemIdField,
25825
25846
  dndRoot
25826
25847
  }) {
@@ -25837,6 +25858,7 @@ function DataList({
25837
25858
  sortable: sortableProp,
25838
25859
  dropEvent,
25839
25860
  reorderEvent: dndReorderEvent,
25861
+ positionEvent,
25840
25862
  dndItemIdField,
25841
25863
  dndRoot
25842
25864
  });
@@ -58405,6 +58427,74 @@ function ServerBridgeProvider({
58405
58427
  return /* @__PURE__ */ jsxRuntime.jsx(ServerBridgeContext.Provider, { value: { connected, sendEvent }, children });
58406
58428
  }
58407
58429
 
58430
+ // context/OrbitalThemeProvider.tsx
58431
+ init_ThemeContext();
58432
+
58433
+ // context/themeTokens.ts
58434
+ function themeTokensToCssVars(tokens, mode = "light", darkVariant) {
58435
+ const vars = {};
58436
+ const isDark = mode === "dark";
58437
+ const pickColors = isDark && darkVariant?.colors ? darkVariant.colors : tokens.colors;
58438
+ if (pickColors) {
58439
+ for (const [key, value] of Object.entries(pickColors)) {
58440
+ vars[`--color-${key}`] = value;
58441
+ }
58442
+ if (isDark && darkVariant?.colors && tokens.colors) {
58443
+ for (const [key, value] of Object.entries(tokens.colors)) {
58444
+ const varName = `--color-${key}`;
58445
+ if (!(varName in vars)) vars[varName] = value;
58446
+ }
58447
+ }
58448
+ }
58449
+ const pickRadii = isDark && darkVariant?.radii ? darkVariant.radii : tokens.radii;
58450
+ if (pickRadii) {
58451
+ for (const [key, value] of Object.entries(pickRadii)) {
58452
+ vars[`--radius-${key}`] = value;
58453
+ }
58454
+ }
58455
+ const pickSpacing = isDark && darkVariant?.spacing ? darkVariant.spacing : tokens.spacing;
58456
+ if (pickSpacing) {
58457
+ for (const [key, value] of Object.entries(pickSpacing)) {
58458
+ vars[`--space-${key}`] = value;
58459
+ }
58460
+ }
58461
+ const pickTypography = isDark && darkVariant?.typography ? darkVariant.typography : tokens.typography;
58462
+ if (pickTypography) {
58463
+ for (const [key, value] of Object.entries(pickTypography)) {
58464
+ vars[`--${key}`] = value;
58465
+ }
58466
+ }
58467
+ const pickShadows = isDark && darkVariant?.shadows ? darkVariant.shadows : tokens.shadows;
58468
+ if (pickShadows) {
58469
+ for (const [key, value] of Object.entries(pickShadows)) {
58470
+ vars[`--shadow-${key}`] = value;
58471
+ }
58472
+ }
58473
+ return vars;
58474
+ }
58475
+ function resolveThemeForRuntime(theme) {
58476
+ if (theme === void 0) return void 0;
58477
+ if (typeof theme === "string") return void 0;
58478
+ return theme;
58479
+ }
58480
+ function OrbitalThemeProvider({ theme, children }) {
58481
+ const resolved = resolveThemeForRuntime(theme);
58482
+ const { resolvedMode } = useTheme();
58483
+ if (!resolved) {
58484
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
58485
+ }
58486
+ const vars = themeTokensToCssVars(resolved.tokens, resolvedMode, resolved.variants?.dark);
58487
+ return /* @__PURE__ */ jsxRuntime.jsx(
58488
+ "div",
58489
+ {
58490
+ "data-orbital-theme": resolved.name,
58491
+ style: { display: "contents", ...vars },
58492
+ children
58493
+ }
58494
+ );
58495
+ }
58496
+ OrbitalThemeProvider.displayName = "OrbitalThemeProvider";
58497
+
58408
58498
  // runtime/OrbPreview.tsx
58409
58499
  init_navigation();
58410
58500
  init_verificationRegistry();
@@ -58816,6 +58906,19 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
58816
58906
  });
58817
58907
  return set;
58818
58908
  }, [schema, pageName]);
58909
+ const activeOrbitalTheme = React93.useMemo(() => {
58910
+ const parsed = schema;
58911
+ if (!parsed?.orbitals?.length) return void 0;
58912
+ if (pageName) {
58913
+ for (const orb of parsed.orbitals) {
58914
+ for (const pageRef of orb.pages ?? []) {
58915
+ const name = typeof pageRef === "object" && pageRef !== null ? pageRef.name : void 0;
58916
+ if (name === pageName) return orb.theme;
58917
+ }
58918
+ }
58919
+ }
58920
+ return parsed.orbitals[0]?.theme;
58921
+ }, [schema, pageName]);
58819
58922
  const inner = /* @__PURE__ */ jsxRuntime.jsx(VerificationProvider, { enabled: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
58820
58923
  EntitySchemaProvider,
58821
58924
  {
@@ -58836,7 +58939,7 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
58836
58939
  persistence
58837
58940
  }
58838
58941
  ),
58839
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "h-full p-4", children: /* @__PURE__ */ jsxRuntime.jsx(UISlotRenderer, { includeHud: true, hudMode: "inline", includeFloating: true }) })
58942
+ /* @__PURE__ */ jsxRuntime.jsx(OrbitalThemeProvider, { theme: activeOrbitalTheme, children: /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "h-full p-4", children: /* @__PURE__ */ jsxRuntime.jsx(UISlotRenderer, { includeHud: true, hudMode: "inline", includeFloating: true }) }) })
58840
58943
  ]
58841
58944
  }
58842
58945
  ) });
package/dist/avl/index.js CHANGED
@@ -24867,6 +24867,7 @@ function useDataDnd(args) {
24867
24867
  sortable,
24868
24868
  dropEvent,
24869
24869
  reorderEvent,
24870
+ positionEvent,
24870
24871
  dndItemIdField = "id",
24871
24872
  dndRoot,
24872
24873
  items,
@@ -24934,8 +24935,8 @@ function useDataDnd(args) {
24934
24935
  const [activeDrag, setActiveDrag] = React93__default.useState(null);
24935
24936
  const [overZoneGroup, setOverZoneGroup] = React93__default.useState(null);
24936
24937
  const meta = React93__default.useMemo(
24937
- () => ({ group: ownGroup, dropEvent, reorderEvent, itemIds, rawItems: items, idField: dndItemIdField }),
24938
- [ownGroup, dropEvent, reorderEvent, itemIds, items, dndItemIdField]
24938
+ () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
24939
+ [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
24939
24940
  );
24940
24941
  React93__default.useEffect(() => {
24941
24942
  const target = isRoot ? null : parentRoot;
@@ -25021,6 +25022,20 @@ function useDataDnd(args) {
25021
25022
  dndLog.warn("dragEnd:abort:no-zone-resolved", { activeId: active.id, hasSource: !!sourceMeta, hasTarget: !!targetMeta });
25022
25023
  return;
25023
25024
  }
25025
+ const emitPositions = (zoneMeta) => {
25026
+ if (!zoneMeta.positionEvent) {
25027
+ dndLog.debug("dragEnd:positions:no-event", { group: zoneMeta.group });
25028
+ return;
25029
+ }
25030
+ const evt = `UI:${zoneMeta.positionEvent}`;
25031
+ const order = optimisticOrdersRef.current.get(zoneMeta.group) ?? zoneMeta.rawItems;
25032
+ order.forEach((it, idx) => {
25033
+ const id = String(it[zoneMeta.idField]);
25034
+ const position = idx * 1e3;
25035
+ eventBus.emit(evt, { id, position });
25036
+ });
25037
+ dndLog.info("dragEnd:positions:emitted", { event: evt, group: zoneMeta.group, count: order.length });
25038
+ };
25024
25039
  if (sourceMeta.group !== targetMeta.group) {
25025
25040
  if (targetMeta.dropEvent) {
25026
25041
  const evt = `UI:${targetMeta.dropEvent}`;
@@ -25040,6 +25055,8 @@ function useDataDnd(args) {
25040
25055
  } else {
25041
25056
  dndLog.warn("dragEnd:cross-container:no-dropEvent-on-target", { targetGroup: targetMeta.group });
25042
25057
  }
25058
+ emitPositions(sourceMeta);
25059
+ emitPositions(targetMeta);
25043
25060
  return;
25044
25061
  }
25045
25062
  if (oldIndex === newIndex) {
@@ -25062,6 +25079,7 @@ function useDataDnd(args) {
25062
25079
  } else {
25063
25080
  dndLog.debug("dragEnd:reorder:no-reorderEvent", { sourceGroup: sourceMeta.group });
25064
25081
  }
25082
+ emitPositions(sourceMeta);
25065
25083
  },
25066
25084
  [eventBus]
25067
25085
  );
@@ -25366,6 +25384,7 @@ function DataGrid({
25366
25384
  sortable,
25367
25385
  dropEvent,
25368
25386
  reorderEvent,
25387
+ positionEvent,
25369
25388
  dndItemIdField,
25370
25389
  dndRoot
25371
25390
  }) {
@@ -25383,6 +25402,7 @@ function DataGrid({
25383
25402
  sortable,
25384
25403
  dropEvent,
25385
25404
  reorderEvent,
25405
+ positionEvent,
25386
25406
  dndItemIdField,
25387
25407
  dndRoot
25388
25408
  });
@@ -25775,6 +25795,7 @@ function DataList({
25775
25795
  sortable: sortableProp,
25776
25796
  dropEvent,
25777
25797
  reorderEvent: dndReorderEvent,
25798
+ positionEvent,
25778
25799
  dndItemIdField,
25779
25800
  dndRoot
25780
25801
  }) {
@@ -25791,6 +25812,7 @@ function DataList({
25791
25812
  sortable: sortableProp,
25792
25813
  dropEvent,
25793
25814
  reorderEvent: dndReorderEvent,
25815
+ positionEvent,
25794
25816
  dndItemIdField,
25795
25817
  dndRoot
25796
25818
  });
@@ -58359,6 +58381,74 @@ function ServerBridgeProvider({
58359
58381
  return /* @__PURE__ */ jsx(ServerBridgeContext.Provider, { value: { connected, sendEvent }, children });
58360
58382
  }
58361
58383
 
58384
+ // context/OrbitalThemeProvider.tsx
58385
+ init_ThemeContext();
58386
+
58387
+ // context/themeTokens.ts
58388
+ function themeTokensToCssVars(tokens, mode = "light", darkVariant) {
58389
+ const vars = {};
58390
+ const isDark = mode === "dark";
58391
+ const pickColors = isDark && darkVariant?.colors ? darkVariant.colors : tokens.colors;
58392
+ if (pickColors) {
58393
+ for (const [key, value] of Object.entries(pickColors)) {
58394
+ vars[`--color-${key}`] = value;
58395
+ }
58396
+ if (isDark && darkVariant?.colors && tokens.colors) {
58397
+ for (const [key, value] of Object.entries(tokens.colors)) {
58398
+ const varName = `--color-${key}`;
58399
+ if (!(varName in vars)) vars[varName] = value;
58400
+ }
58401
+ }
58402
+ }
58403
+ const pickRadii = isDark && darkVariant?.radii ? darkVariant.radii : tokens.radii;
58404
+ if (pickRadii) {
58405
+ for (const [key, value] of Object.entries(pickRadii)) {
58406
+ vars[`--radius-${key}`] = value;
58407
+ }
58408
+ }
58409
+ const pickSpacing = isDark && darkVariant?.spacing ? darkVariant.spacing : tokens.spacing;
58410
+ if (pickSpacing) {
58411
+ for (const [key, value] of Object.entries(pickSpacing)) {
58412
+ vars[`--space-${key}`] = value;
58413
+ }
58414
+ }
58415
+ const pickTypography = isDark && darkVariant?.typography ? darkVariant.typography : tokens.typography;
58416
+ if (pickTypography) {
58417
+ for (const [key, value] of Object.entries(pickTypography)) {
58418
+ vars[`--${key}`] = value;
58419
+ }
58420
+ }
58421
+ const pickShadows = isDark && darkVariant?.shadows ? darkVariant.shadows : tokens.shadows;
58422
+ if (pickShadows) {
58423
+ for (const [key, value] of Object.entries(pickShadows)) {
58424
+ vars[`--shadow-${key}`] = value;
58425
+ }
58426
+ }
58427
+ return vars;
58428
+ }
58429
+ function resolveThemeForRuntime(theme) {
58430
+ if (theme === void 0) return void 0;
58431
+ if (typeof theme === "string") return void 0;
58432
+ return theme;
58433
+ }
58434
+ function OrbitalThemeProvider({ theme, children }) {
58435
+ const resolved = resolveThemeForRuntime(theme);
58436
+ const { resolvedMode } = useTheme();
58437
+ if (!resolved) {
58438
+ return /* @__PURE__ */ jsx(Fragment, { children });
58439
+ }
58440
+ const vars = themeTokensToCssVars(resolved.tokens, resolvedMode, resolved.variants?.dark);
58441
+ return /* @__PURE__ */ jsx(
58442
+ "div",
58443
+ {
58444
+ "data-orbital-theme": resolved.name,
58445
+ style: { display: "contents", ...vars },
58446
+ children
58447
+ }
58448
+ );
58449
+ }
58450
+ OrbitalThemeProvider.displayName = "OrbitalThemeProvider";
58451
+
58362
58452
  // runtime/OrbPreview.tsx
58363
58453
  init_navigation();
58364
58454
  init_verificationRegistry();
@@ -58770,6 +58860,19 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
58770
58860
  });
58771
58861
  return set;
58772
58862
  }, [schema, pageName]);
58863
+ const activeOrbitalTheme = useMemo(() => {
58864
+ const parsed = schema;
58865
+ if (!parsed?.orbitals?.length) return void 0;
58866
+ if (pageName) {
58867
+ for (const orb of parsed.orbitals) {
58868
+ for (const pageRef of orb.pages ?? []) {
58869
+ const name = typeof pageRef === "object" && pageRef !== null ? pageRef.name : void 0;
58870
+ if (name === pageName) return orb.theme;
58871
+ }
58872
+ }
58873
+ }
58874
+ return parsed.orbitals[0]?.theme;
58875
+ }, [schema, pageName]);
58773
58876
  const inner = /* @__PURE__ */ jsx(VerificationProvider, { enabled: true, children: /* @__PURE__ */ jsxs(
58774
58877
  EntitySchemaProvider,
58775
58878
  {
@@ -58790,7 +58893,7 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
58790
58893
  persistence
58791
58894
  }
58792
58895
  ),
58793
- /* @__PURE__ */ jsx(Box, { className: "h-full p-4", children: /* @__PURE__ */ jsx(UISlotRenderer, { includeHud: true, hudMode: "inline", includeFloating: true }) })
58896
+ /* @__PURE__ */ jsx(OrbitalThemeProvider, { theme: activeOrbitalTheme, children: /* @__PURE__ */ jsx(Box, { className: "h-full p-4", children: /* @__PURE__ */ jsx(UISlotRenderer, { includeHud: true, hudMode: "inline", includeFloating: true }) }) })
58794
58897
  ]
58795
58898
  }
58796
58899
  ) });
@@ -20080,6 +20080,7 @@ function useDataDnd(args) {
20080
20080
  sortable: sortable$1,
20081
20081
  dropEvent,
20082
20082
  reorderEvent,
20083
+ positionEvent,
20083
20084
  dndItemIdField = "id",
20084
20085
  dndRoot,
20085
20086
  items,
@@ -20147,8 +20148,8 @@ function useDataDnd(args) {
20147
20148
  const [activeDrag, setActiveDrag] = React75__namespace.default.useState(null);
20148
20149
  const [overZoneGroup, setOverZoneGroup] = React75__namespace.default.useState(null);
20149
20150
  const meta = React75__namespace.default.useMemo(
20150
- () => ({ group: ownGroup, dropEvent, reorderEvent, itemIds, rawItems: items, idField: dndItemIdField }),
20151
- [ownGroup, dropEvent, reorderEvent, itemIds, items, dndItemIdField]
20151
+ () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
20152
+ [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
20152
20153
  );
20153
20154
  React75__namespace.default.useEffect(() => {
20154
20155
  const target = isRoot ? null : parentRoot;
@@ -20234,6 +20235,20 @@ function useDataDnd(args) {
20234
20235
  dndLog.warn("dragEnd:abort:no-zone-resolved", { activeId: active.id, hasSource: !!sourceMeta, hasTarget: !!targetMeta });
20235
20236
  return;
20236
20237
  }
20238
+ const emitPositions = (zoneMeta) => {
20239
+ if (!zoneMeta.positionEvent) {
20240
+ dndLog.debug("dragEnd:positions:no-event", { group: zoneMeta.group });
20241
+ return;
20242
+ }
20243
+ const evt = `UI:${zoneMeta.positionEvent}`;
20244
+ const order = optimisticOrdersRef.current.get(zoneMeta.group) ?? zoneMeta.rawItems;
20245
+ order.forEach((it, idx) => {
20246
+ const id = String(it[zoneMeta.idField]);
20247
+ const position = idx * 1e3;
20248
+ eventBus.emit(evt, { id, position });
20249
+ });
20250
+ dndLog.info("dragEnd:positions:emitted", { event: evt, group: zoneMeta.group, count: order.length });
20251
+ };
20237
20252
  if (sourceMeta.group !== targetMeta.group) {
20238
20253
  if (targetMeta.dropEvent) {
20239
20254
  const evt = `UI:${targetMeta.dropEvent}`;
@@ -20253,6 +20268,8 @@ function useDataDnd(args) {
20253
20268
  } else {
20254
20269
  dndLog.warn("dragEnd:cross-container:no-dropEvent-on-target", { targetGroup: targetMeta.group });
20255
20270
  }
20271
+ emitPositions(sourceMeta);
20272
+ emitPositions(targetMeta);
20256
20273
  return;
20257
20274
  }
20258
20275
  if (oldIndex === newIndex) {
@@ -20275,6 +20292,7 @@ function useDataDnd(args) {
20275
20292
  } else {
20276
20293
  dndLog.debug("dragEnd:reorder:no-reorderEvent", { sourceGroup: sourceMeta.group });
20277
20294
  }
20295
+ emitPositions(sourceMeta);
20278
20296
  },
20279
20297
  [eventBus]
20280
20298
  );
@@ -20579,6 +20597,7 @@ function DataGrid({
20579
20597
  sortable,
20580
20598
  dropEvent,
20581
20599
  reorderEvent,
20600
+ positionEvent,
20582
20601
  dndItemIdField,
20583
20602
  dndRoot
20584
20603
  }) {
@@ -20596,6 +20615,7 @@ function DataGrid({
20596
20615
  sortable,
20597
20616
  dropEvent,
20598
20617
  reorderEvent,
20618
+ positionEvent,
20599
20619
  dndItemIdField,
20600
20620
  dndRoot
20601
20621
  });
@@ -20988,6 +21008,7 @@ function DataList({
20988
21008
  sortable: sortableProp,
20989
21009
  dropEvent,
20990
21010
  reorderEvent: dndReorderEvent,
21011
+ positionEvent,
20991
21012
  dndItemIdField,
20992
21013
  dndRoot
20993
21014
  }) {
@@ -21004,6 +21025,7 @@ function DataList({
21004
21025
  sortable: sortableProp,
21005
21026
  dropEvent,
21006
21027
  reorderEvent: dndReorderEvent,
21028
+ positionEvent,
21007
21029
  dndItemIdField,
21008
21030
  dndRoot
21009
21031
  });
@@ -20034,6 +20034,7 @@ function useDataDnd(args) {
20034
20034
  sortable,
20035
20035
  dropEvent,
20036
20036
  reorderEvent,
20037
+ positionEvent,
20037
20038
  dndItemIdField = "id",
20038
20039
  dndRoot,
20039
20040
  items,
@@ -20101,8 +20102,8 @@ function useDataDnd(args) {
20101
20102
  const [activeDrag, setActiveDrag] = React75__default.useState(null);
20102
20103
  const [overZoneGroup, setOverZoneGroup] = React75__default.useState(null);
20103
20104
  const meta = React75__default.useMemo(
20104
- () => ({ group: ownGroup, dropEvent, reorderEvent, itemIds, rawItems: items, idField: dndItemIdField }),
20105
- [ownGroup, dropEvent, reorderEvent, itemIds, items, dndItemIdField]
20105
+ () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
20106
+ [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
20106
20107
  );
20107
20108
  React75__default.useEffect(() => {
20108
20109
  const target = isRoot ? null : parentRoot;
@@ -20188,6 +20189,20 @@ function useDataDnd(args) {
20188
20189
  dndLog.warn("dragEnd:abort:no-zone-resolved", { activeId: active.id, hasSource: !!sourceMeta, hasTarget: !!targetMeta });
20189
20190
  return;
20190
20191
  }
20192
+ const emitPositions = (zoneMeta) => {
20193
+ if (!zoneMeta.positionEvent) {
20194
+ dndLog.debug("dragEnd:positions:no-event", { group: zoneMeta.group });
20195
+ return;
20196
+ }
20197
+ const evt = `UI:${zoneMeta.positionEvent}`;
20198
+ const order = optimisticOrdersRef.current.get(zoneMeta.group) ?? zoneMeta.rawItems;
20199
+ order.forEach((it, idx) => {
20200
+ const id = String(it[zoneMeta.idField]);
20201
+ const position = idx * 1e3;
20202
+ eventBus.emit(evt, { id, position });
20203
+ });
20204
+ dndLog.info("dragEnd:positions:emitted", { event: evt, group: zoneMeta.group, count: order.length });
20205
+ };
20191
20206
  if (sourceMeta.group !== targetMeta.group) {
20192
20207
  if (targetMeta.dropEvent) {
20193
20208
  const evt = `UI:${targetMeta.dropEvent}`;
@@ -20207,6 +20222,8 @@ function useDataDnd(args) {
20207
20222
  } else {
20208
20223
  dndLog.warn("dragEnd:cross-container:no-dropEvent-on-target", { targetGroup: targetMeta.group });
20209
20224
  }
20225
+ emitPositions(sourceMeta);
20226
+ emitPositions(targetMeta);
20210
20227
  return;
20211
20228
  }
20212
20229
  if (oldIndex === newIndex) {
@@ -20229,6 +20246,7 @@ function useDataDnd(args) {
20229
20246
  } else {
20230
20247
  dndLog.debug("dragEnd:reorder:no-reorderEvent", { sourceGroup: sourceMeta.group });
20231
20248
  }
20249
+ emitPositions(sourceMeta);
20232
20250
  },
20233
20251
  [eventBus]
20234
20252
  );
@@ -20533,6 +20551,7 @@ function DataGrid({
20533
20551
  sortable,
20534
20552
  dropEvent,
20535
20553
  reorderEvent,
20554
+ positionEvent,
20536
20555
  dndItemIdField,
20537
20556
  dndRoot
20538
20557
  }) {
@@ -20550,6 +20569,7 @@ function DataGrid({
20550
20569
  sortable,
20551
20570
  dropEvent,
20552
20571
  reorderEvent,
20572
+ positionEvent,
20553
20573
  dndItemIdField,
20554
20574
  dndRoot
20555
20575
  });
@@ -20942,6 +20962,7 @@ function DataList({
20942
20962
  sortable: sortableProp,
20943
20963
  dropEvent,
20944
20964
  reorderEvent: dndReorderEvent,
20965
+ positionEvent,
20945
20966
  dndItemIdField,
20946
20967
  dndRoot
20947
20968
  }) {
@@ -20958,6 +20979,7 @@ function DataList({
20958
20979
  sortable: sortableProp,
20959
20980
  dropEvent,
20960
20981
  reorderEvent: dndReorderEvent,
20982
+ positionEvent,
20961
20983
  dndItemIdField,
20962
20984
  dndRoot
20963
20985
  });
@@ -103,7 +103,7 @@ export interface DataGridProps<T extends EntityRow = EntityRow> extends DataDndP
103
103
  /** Max items to show before "Show More" button. Defaults to 0 (disabled). */
104
104
  pageSize?: number;
105
105
  }
106
- export declare function DataGrid<T extends EntityRow = EntityRow>({ entity, fields, columns, itemActions, cols, gap, minCardWidth, className, isLoading, error, imageField, selectable, selectionEvent, infiniteScroll, loadMoreEvent, hasMore, children, pageSize, renderItem: schemaRenderItem, dragGroup, accepts, sortable, dropEvent, reorderEvent, dndItemIdField, dndRoot, }: DataGridProps<T>): string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined;
106
+ export declare function DataGrid<T extends EntityRow = EntityRow>({ entity, fields, columns, itemActions, cols, gap, minCardWidth, className, isLoading, error, imageField, selectable, selectionEvent, infiniteScroll, loadMoreEvent, hasMore, children, pageSize, renderItem: schemaRenderItem, dragGroup, accepts, sortable, dropEvent, reorderEvent, positionEvent, dndItemIdField, dndRoot, }: DataGridProps<T>): string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined;
107
107
  export declare namespace DataGrid {
108
108
  var displayName: string;
109
109
  }
@@ -117,7 +117,7 @@ export interface DataListProps<T extends EntityRow = EntityRow> extends DataDndP
117
117
  /** Max items to show before "Show More" button. Defaults to 5. Set to 0 to disable. */
118
118
  pageSize?: number;
119
119
  }
120
- export declare function DataList<T extends EntityRow = EntityRow>({ entity, fields, columns, itemActions, gap, variant, groupBy, senderField, currentUser, className, isLoading, error, reorderable: _reorderable, reorderEvent: _reorderEvent, swipeLeftEvent: _swipeLeftEvent, swipeLeftActions: _swipeLeftActions, swipeRightEvent: _swipeRightEvent, swipeRightActions: _swipeRightActions, longPressEvent: _longPressEvent, infiniteScroll, loadMoreEvent, hasMore, children, pageSize, renderItem: schemaRenderItem, dragGroup, accepts, sortable: sortableProp, dropEvent, reorderEvent: dndReorderEvent, dndItemIdField, dndRoot, }: DataListProps<T>): string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined;
120
+ export declare function DataList<T extends EntityRow = EntityRow>({ entity, fields, columns, itemActions, gap, variant, groupBy, senderField, currentUser, className, isLoading, error, reorderable: _reorderable, reorderEvent: _reorderEvent, swipeLeftEvent: _swipeLeftEvent, swipeLeftActions: _swipeLeftActions, swipeRightEvent: _swipeRightEvent, swipeRightActions: _swipeRightActions, longPressEvent: _longPressEvent, infiniteScroll, loadMoreEvent, hasMore, children, pageSize, renderItem: schemaRenderItem, dragGroup, accepts, sortable: sortableProp, dropEvent, reorderEvent: dndReorderEvent, positionEvent, dndItemIdField, dndRoot, }: DataListProps<T>): string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined;
121
121
  export declare namespace DataList {
122
122
  var displayName: string;
123
123
  }
@@ -20,6 +20,14 @@ import React from 'react';
20
20
  import { type UniqueIdentifier } from '@dnd-kit/core';
21
21
  import type { EntityRow, EventKey } from '@almadar/core';
22
22
  export interface DataDndProps {
23
+ /**
24
+ * Event emitted N times per drop (one per item in each affected zone) so
25
+ * the trait can persist new positions for every item — not just the moved
26
+ * one. Required for stable sort-by-position because setting only the
27
+ * dragged item's position creates collisions with the (unchanged) others.
28
+ * Payload: { id : string, position : number }.
29
+ */
30
+ positionEvent?: EventKey;
23
31
  dragGroup?: string;
24
32
  accepts?: string;
25
33
  sortable?: boolean;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * OrbitalThemeProvider — runtime application of `OrbitalDefinition.theme`.
3
+ *
4
+ * Wraps an orbital's rendered subtree in a wrapping `<div>` that sets the
5
+ * CSS variables derived from `theme.tokens` (and `variants.dark` when the
6
+ * resolved color mode is dark). Inline custom-property declarations on the
7
+ * wrapper override any `[data-theme]` selector rule for the same variable
8
+ * within the subtree, while letting unset variables cascade from the parent.
9
+ *
10
+ * Mapping is delegated to `themeTokensToCssVars`, which mirrors the Rust
11
+ * compiler's `generate_tokens_css`. Compile-time and runtime produce the
12
+ * same CSS variable map for the same `ThemeDefinition` input, so a Studio
13
+ * Design System edit and an `orbital compile` of the same schema render
14
+ * identically.
15
+ *
16
+ * No-op when:
17
+ * - `theme` is `undefined` (orbital declares no theme — parent cascades)
18
+ * - `theme` is a string ref that didn't get inlined upstream
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * <OrbitalThemeProvider theme={orbital.theme}>
23
+ * <UISlotRenderer />
24
+ * </OrbitalThemeProvider>
25
+ * ```
26
+ */
27
+ import { type ReactElement, type ReactNode } from 'react';
28
+ import type { ThemeRef } from '@almadar/core';
29
+ export interface OrbitalThemeProviderProps {
30
+ /** The `OrbitalDefinition.theme` value (inline definition or string ref). */
31
+ theme?: ThemeRef;
32
+ children: ReactNode;
33
+ }
34
+ export declare function OrbitalThemeProvider({ theme, children }: OrbitalThemeProviderProps): ReactElement;
35
+ export declare namespace OrbitalThemeProvider {
36
+ var displayName: string;
37
+ }