@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.
@@ -622,6 +622,71 @@ function useTheme() {
622
622
  }
623
623
  var ThemeContext_default = ThemeContext;
624
624
 
625
+ // context/themeTokens.ts
626
+ function themeTokensToCssVars(tokens, mode = "light", darkVariant) {
627
+ const vars = {};
628
+ const isDark = mode === "dark";
629
+ const pickColors = isDark && darkVariant?.colors ? darkVariant.colors : tokens.colors;
630
+ if (pickColors) {
631
+ for (const [key, value] of Object.entries(pickColors)) {
632
+ vars[`--color-${key}`] = value;
633
+ }
634
+ if (isDark && darkVariant?.colors && tokens.colors) {
635
+ for (const [key, value] of Object.entries(tokens.colors)) {
636
+ const varName = `--color-${key}`;
637
+ if (!(varName in vars)) vars[varName] = value;
638
+ }
639
+ }
640
+ }
641
+ const pickRadii = isDark && darkVariant?.radii ? darkVariant.radii : tokens.radii;
642
+ if (pickRadii) {
643
+ for (const [key, value] of Object.entries(pickRadii)) {
644
+ vars[`--radius-${key}`] = value;
645
+ }
646
+ }
647
+ const pickSpacing = isDark && darkVariant?.spacing ? darkVariant.spacing : tokens.spacing;
648
+ if (pickSpacing) {
649
+ for (const [key, value] of Object.entries(pickSpacing)) {
650
+ vars[`--space-${key}`] = value;
651
+ }
652
+ }
653
+ const pickTypography = isDark && darkVariant?.typography ? darkVariant.typography : tokens.typography;
654
+ if (pickTypography) {
655
+ for (const [key, value] of Object.entries(pickTypography)) {
656
+ vars[`--${key}`] = value;
657
+ }
658
+ }
659
+ const pickShadows = isDark && darkVariant?.shadows ? darkVariant.shadows : tokens.shadows;
660
+ if (pickShadows) {
661
+ for (const [key, value] of Object.entries(pickShadows)) {
662
+ vars[`--shadow-${key}`] = value;
663
+ }
664
+ }
665
+ return vars;
666
+ }
667
+ function resolveThemeForRuntime(theme) {
668
+ if (theme === void 0) return void 0;
669
+ if (typeof theme === "string") return void 0;
670
+ return theme;
671
+ }
672
+ function OrbitalThemeProvider({ theme, children }) {
673
+ const resolved = resolveThemeForRuntime(theme);
674
+ const { resolvedMode } = useTheme();
675
+ if (!resolved) {
676
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
677
+ }
678
+ const vars = themeTokensToCssVars(resolved.tokens, resolvedMode, resolved.variants?.dark);
679
+ return /* @__PURE__ */ jsxRuntime.jsx(
680
+ "div",
681
+ {
682
+ "data-orbital-theme": resolved.name,
683
+ style: { display: "contents", ...vars },
684
+ children
685
+ }
686
+ );
687
+ }
688
+ OrbitalThemeProvider.displayName = "OrbitalThemeProvider";
689
+
625
690
  // context/DesignThemeContext.tsx
626
691
  var DesignThemeProvider = ThemeProvider;
627
692
  function useDesignTheme() {
@@ -743,12 +808,15 @@ exports.BUILT_IN_THEMES = BUILT_IN_THEMES;
743
808
  exports.CurrentPagePathContext = CurrentPagePathContext;
744
809
  exports.CurrentPagePathProvider = CurrentPagePathProvider;
745
810
  exports.DesignThemeProvider = DesignThemeProvider;
811
+ exports.OrbitalThemeProvider = OrbitalThemeProvider;
746
812
  exports.ThemeContext = ThemeContext_default;
747
813
  exports.ThemeProvider = ThemeProvider;
748
814
  exports.UISlotContext = UISlotContext;
749
815
  exports.UISlotProvider = UISlotProvider;
750
816
  exports.UserContext = UserContext;
751
817
  exports.UserProvider = UserProvider;
818
+ exports.resolveThemeForRuntime = resolveThemeForRuntime;
819
+ exports.themeTokensToCssVars = themeTokensToCssVars;
752
820
  exports.useCurrentPagePath = useCurrentPagePath;
753
821
  exports.useDesignTheme = useDesignTheme;
754
822
  exports.useHasPermission = useHasPermission;
@@ -4,6 +4,8 @@
4
4
  export { UISlotProvider, useUISlots, useSlotContent, useSlotHasContent, UISlotContext, type UISlotManager, type UISlot, type SlotContent, type RenderUIConfig, type SlotAnimation, type SlotChangeCallback, } from "./UISlotContext";
5
5
  export { ThemeProvider, useTheme, BUILT_IN_THEMES, type ThemeDefinition, type ThemeProviderProps, type ColorMode, type ResolvedMode, type DesignTheme, } from "./ThemeContext";
6
6
  export { default as ThemeContext } from "./ThemeContext";
7
+ export { themeTokensToCssVars, resolveThemeForRuntime, type ThemeMode, } from "./themeTokens";
8
+ export { OrbitalThemeProvider, type OrbitalThemeProviderProps, } from "./OrbitalThemeProvider";
7
9
  export { DesignThemeProvider, useDesignTheme } from "./DesignThemeContext";
8
10
  export { CurrentPagePathProvider, CurrentPagePathContext, useCurrentPagePath, type CurrentPagePathProviderProps, } from "./CurrentPagePathContext";
9
11
  export { UserProvider, UserContext, useUser, useHasRole, useHasPermission, useUserForEvaluation, ANONYMOUS_USER, type UserData, type UserContextValue, type UserProviderProps, } from "./UserContext";
@@ -1,6 +1,6 @@
1
1
  import { createContext, useMemo, useContext, useState, useEffect, useCallback, useRef } from 'react';
2
2
  import { createLogger } from '@almadar/logger';
3
- import { jsx } from 'react/jsx-runtime';
3
+ import { jsx, Fragment } from 'react/jsx-runtime';
4
4
 
5
5
  var log = createLogger("almadar:ui:ui-slots");
6
6
  var DEFAULT_SOURCE_KEY = "__default__";
@@ -620,6 +620,71 @@ function useTheme() {
620
620
  }
621
621
  var ThemeContext_default = ThemeContext;
622
622
 
623
+ // context/themeTokens.ts
624
+ function themeTokensToCssVars(tokens, mode = "light", darkVariant) {
625
+ const vars = {};
626
+ const isDark = mode === "dark";
627
+ const pickColors = isDark && darkVariant?.colors ? darkVariant.colors : tokens.colors;
628
+ if (pickColors) {
629
+ for (const [key, value] of Object.entries(pickColors)) {
630
+ vars[`--color-${key}`] = value;
631
+ }
632
+ if (isDark && darkVariant?.colors && tokens.colors) {
633
+ for (const [key, value] of Object.entries(tokens.colors)) {
634
+ const varName = `--color-${key}`;
635
+ if (!(varName in vars)) vars[varName] = value;
636
+ }
637
+ }
638
+ }
639
+ const pickRadii = isDark && darkVariant?.radii ? darkVariant.radii : tokens.radii;
640
+ if (pickRadii) {
641
+ for (const [key, value] of Object.entries(pickRadii)) {
642
+ vars[`--radius-${key}`] = value;
643
+ }
644
+ }
645
+ const pickSpacing = isDark && darkVariant?.spacing ? darkVariant.spacing : tokens.spacing;
646
+ if (pickSpacing) {
647
+ for (const [key, value] of Object.entries(pickSpacing)) {
648
+ vars[`--space-${key}`] = value;
649
+ }
650
+ }
651
+ const pickTypography = isDark && darkVariant?.typography ? darkVariant.typography : tokens.typography;
652
+ if (pickTypography) {
653
+ for (const [key, value] of Object.entries(pickTypography)) {
654
+ vars[`--${key}`] = value;
655
+ }
656
+ }
657
+ const pickShadows = isDark && darkVariant?.shadows ? darkVariant.shadows : tokens.shadows;
658
+ if (pickShadows) {
659
+ for (const [key, value] of Object.entries(pickShadows)) {
660
+ vars[`--shadow-${key}`] = value;
661
+ }
662
+ }
663
+ return vars;
664
+ }
665
+ function resolveThemeForRuntime(theme) {
666
+ if (theme === void 0) return void 0;
667
+ if (typeof theme === "string") return void 0;
668
+ return theme;
669
+ }
670
+ function OrbitalThemeProvider({ theme, children }) {
671
+ const resolved = resolveThemeForRuntime(theme);
672
+ const { resolvedMode } = useTheme();
673
+ if (!resolved) {
674
+ return /* @__PURE__ */ jsx(Fragment, { children });
675
+ }
676
+ const vars = themeTokensToCssVars(resolved.tokens, resolvedMode, resolved.variants?.dark);
677
+ return /* @__PURE__ */ jsx(
678
+ "div",
679
+ {
680
+ "data-orbital-theme": resolved.name,
681
+ style: { display: "contents", ...vars },
682
+ children
683
+ }
684
+ );
685
+ }
686
+ OrbitalThemeProvider.displayName = "OrbitalThemeProvider";
687
+
623
688
  // context/DesignThemeContext.tsx
624
689
  var DesignThemeProvider = ThemeProvider;
625
690
  function useDesignTheme() {
@@ -736,4 +801,4 @@ function useUserForEvaluation() {
736
801
  return isLoggedIn && user ? user : void 0;
737
802
  }
738
803
 
739
- export { ANONYMOUS_USER, BUILT_IN_THEMES, CurrentPagePathContext, CurrentPagePathProvider, DesignThemeProvider, ThemeContext_default as ThemeContext, ThemeProvider, UISlotContext, UISlotProvider, UserContext, UserProvider, useCurrentPagePath, useDesignTheme, useHasPermission, useHasRole, useSlotContent, useSlotHasContent, useTheme, useUISlots, useUser, useUserForEvaluation };
804
+ export { ANONYMOUS_USER, BUILT_IN_THEMES, CurrentPagePathContext, CurrentPagePathProvider, DesignThemeProvider, OrbitalThemeProvider, ThemeContext_default as ThemeContext, ThemeProvider, UISlotContext, UISlotProvider, UserContext, UserProvider, resolveThemeForRuntime, themeTokensToCssVars, useCurrentPagePath, useDesignTheme, useHasPermission, useHasRole, useSlotContent, useSlotHasContent, useTheme, useUISlots, useUser, useUserForEvaluation };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * themeTokens — runtime mirror of the orbital compiler's theme codegen.
3
+ *
4
+ * The compile path (orbital-rust/crates/orbital-shell-typescript/src/codegen/theme.rs)
5
+ * reads `OrbitalDefinition.theme.tokens` and emits CSS custom-property
6
+ * declarations into a `[data-theme="<name>-<mode>"]` block. The runtime
7
+ * does not parse compiled CSS — it reads the same `tokens` object directly
8
+ * and produces the same `{ '--color-primary': '…', '--radius-md': '…' }` map
9
+ * that the compiler emits.
10
+ *
11
+ * Keeping the two paths byte-identical at the variable level is the contract:
12
+ * editing tokens via the Studio Design System tab must produce the exact
13
+ * same rendered result as editing them in source and running `orbital
14
+ * compile`. The mapping rules here mirror `generate_tokens_css` /
15
+ * `generate_tokens_css_dark` (theme.rs:122–351).
16
+ *
17
+ * Compile vs runtime difference (intentional):
18
+ * - Compile emits the FULL set: schema overrides on top of defaults. This is
19
+ * needed because the compiled CSS replaces the theme entirely.
20
+ * - Runtime emits ONLY the keys present in `tokens` (and `variants.dark`).
21
+ * Missing keys cascade from the parent `[data-theme]` rule on the document
22
+ * element. The provider scopes overrides to an orbital subtree without
23
+ * shadowing inherited defaults.
24
+ *
25
+ * @packageDocumentation
26
+ */
27
+ import type { ThemeDefinition, ThemeTokens, ThemeVariant, ThemeRef } from '@almadar/core';
28
+ /** Resolved color mode. Mirrors `ThemeContext.resolvedMode`. */
29
+ export type ThemeMode = 'light' | 'dark';
30
+ /**
31
+ * Convert `ThemeTokens` (+ optional dark variant) into a CSS custom-property
32
+ * map keyed by variable name (e.g. `--color-primary`).
33
+ *
34
+ * Mapping rules (mirror theme.rs):
35
+ * - `tokens.colors.<k>` → `--color-<k>`
36
+ * - `tokens.radii.<k>` → `--radius-<k>`
37
+ * - `tokens.spacing.<k>` → `--space-<k>`
38
+ * - `tokens.typography.<k>` → `--<k>` (keys already include their `font-`/
39
+ * `letter-`/`line-` prefix)
40
+ * - `tokens.shadows.<k>` → `--shadow-<k>` (schema key has no prefix)
41
+ *
42
+ * In `'dark'` mode, the `darkVariant` overrides are merged on top of the
43
+ * base tokens per category — same precedence the Rust compiler uses
44
+ * (`generate_tokens_css_dark`). Categories not present in `darkVariant` fall
45
+ * back to the base tokens.
46
+ */
47
+ export declare function themeTokensToCssVars(tokens: ThemeTokens, mode?: ThemeMode, darkVariant?: ThemeVariant): Record<string, string>;
48
+ /**
49
+ * `ThemeRef` is `ThemeDefinition | string`. When it's a string, it's an
50
+ * unresolved import reference (e.g. `"Ocean.theme"`) that should have been
51
+ * inlined by the compiler's import phase before runtime. If we still see a
52
+ * string here, the upstream resolution path didn't run — return `undefined`
53
+ * rather than guess. `OrbitalThemeProvider` falls through to passthrough.
54
+ */
55
+ export declare function resolveThemeForRuntime(theme: ThemeRef | undefined): ThemeDefinition | undefined;
@@ -21325,6 +21325,7 @@ function useDataDnd(args) {
21325
21325
  sortable: sortable$1,
21326
21326
  dropEvent,
21327
21327
  reorderEvent,
21328
+ positionEvent,
21328
21329
  dndItemIdField = "id",
21329
21330
  dndRoot,
21330
21331
  items,
@@ -21392,8 +21393,8 @@ function useDataDnd(args) {
21392
21393
  const [activeDrag, setActiveDrag] = React81__namespace.default.useState(null);
21393
21394
  const [overZoneGroup, setOverZoneGroup] = React81__namespace.default.useState(null);
21394
21395
  const meta = React81__namespace.default.useMemo(
21395
- () => ({ group: ownGroup, dropEvent, reorderEvent, itemIds, rawItems: items, idField: dndItemIdField }),
21396
- [ownGroup, dropEvent, reorderEvent, itemIds, items, dndItemIdField]
21396
+ () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
21397
+ [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
21397
21398
  );
21398
21399
  React81__namespace.default.useEffect(() => {
21399
21400
  const target = isRoot ? null : parentRoot;
@@ -21479,6 +21480,20 @@ function useDataDnd(args) {
21479
21480
  dndLog.warn("dragEnd:abort:no-zone-resolved", { activeId: active.id, hasSource: !!sourceMeta, hasTarget: !!targetMeta });
21480
21481
  return;
21481
21482
  }
21483
+ const emitPositions = (zoneMeta) => {
21484
+ if (!zoneMeta.positionEvent) {
21485
+ dndLog.debug("dragEnd:positions:no-event", { group: zoneMeta.group });
21486
+ return;
21487
+ }
21488
+ const evt = `UI:${zoneMeta.positionEvent}`;
21489
+ const order = optimisticOrdersRef.current.get(zoneMeta.group) ?? zoneMeta.rawItems;
21490
+ order.forEach((it, idx) => {
21491
+ const id = String(it[zoneMeta.idField]);
21492
+ const position = idx * 1e3;
21493
+ eventBus.emit(evt, { id, position });
21494
+ });
21495
+ dndLog.info("dragEnd:positions:emitted", { event: evt, group: zoneMeta.group, count: order.length });
21496
+ };
21482
21497
  if (sourceMeta.group !== targetMeta.group) {
21483
21498
  if (targetMeta.dropEvent) {
21484
21499
  const evt = `UI:${targetMeta.dropEvent}`;
@@ -21498,6 +21513,8 @@ function useDataDnd(args) {
21498
21513
  } else {
21499
21514
  dndLog.warn("dragEnd:cross-container:no-dropEvent-on-target", { targetGroup: targetMeta.group });
21500
21515
  }
21516
+ emitPositions(sourceMeta);
21517
+ emitPositions(targetMeta);
21501
21518
  return;
21502
21519
  }
21503
21520
  if (oldIndex === newIndex) {
@@ -21520,6 +21537,7 @@ function useDataDnd(args) {
21520
21537
  } else {
21521
21538
  dndLog.debug("dragEnd:reorder:no-reorderEvent", { sourceGroup: sourceMeta.group });
21522
21539
  }
21540
+ emitPositions(sourceMeta);
21523
21541
  },
21524
21542
  [eventBus]
21525
21543
  );
@@ -21824,6 +21842,7 @@ function DataGrid({
21824
21842
  sortable,
21825
21843
  dropEvent,
21826
21844
  reorderEvent,
21845
+ positionEvent,
21827
21846
  dndItemIdField,
21828
21847
  dndRoot
21829
21848
  }) {
@@ -21841,6 +21860,7 @@ function DataGrid({
21841
21860
  sortable,
21842
21861
  dropEvent,
21843
21862
  reorderEvent,
21863
+ positionEvent,
21844
21864
  dndItemIdField,
21845
21865
  dndRoot
21846
21866
  });
@@ -22233,6 +22253,7 @@ function DataList({
22233
22253
  sortable: sortableProp,
22234
22254
  dropEvent,
22235
22255
  reorderEvent: dndReorderEvent,
22256
+ positionEvent,
22236
22257
  dndItemIdField,
22237
22258
  dndRoot
22238
22259
  }) {
@@ -22249,6 +22270,7 @@ function DataList({
22249
22270
  sortable: sortableProp,
22250
22271
  dropEvent,
22251
22272
  reorderEvent: dndReorderEvent,
22273
+ positionEvent,
22252
22274
  dndItemIdField,
22253
22275
  dndRoot
22254
22276
  });
@@ -21279,6 +21279,7 @@ function useDataDnd(args) {
21279
21279
  sortable,
21280
21280
  dropEvent,
21281
21281
  reorderEvent,
21282
+ positionEvent,
21282
21283
  dndItemIdField = "id",
21283
21284
  dndRoot,
21284
21285
  items,
@@ -21346,8 +21347,8 @@ function useDataDnd(args) {
21346
21347
  const [activeDrag, setActiveDrag] = React81__default.useState(null);
21347
21348
  const [overZoneGroup, setOverZoneGroup] = React81__default.useState(null);
21348
21349
  const meta = React81__default.useMemo(
21349
- () => ({ group: ownGroup, dropEvent, reorderEvent, itemIds, rawItems: items, idField: dndItemIdField }),
21350
- [ownGroup, dropEvent, reorderEvent, itemIds, items, dndItemIdField]
21350
+ () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
21351
+ [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
21351
21352
  );
21352
21353
  React81__default.useEffect(() => {
21353
21354
  const target = isRoot ? null : parentRoot;
@@ -21433,6 +21434,20 @@ function useDataDnd(args) {
21433
21434
  dndLog.warn("dragEnd:abort:no-zone-resolved", { activeId: active.id, hasSource: !!sourceMeta, hasTarget: !!targetMeta });
21434
21435
  return;
21435
21436
  }
21437
+ const emitPositions = (zoneMeta) => {
21438
+ if (!zoneMeta.positionEvent) {
21439
+ dndLog.debug("dragEnd:positions:no-event", { group: zoneMeta.group });
21440
+ return;
21441
+ }
21442
+ const evt = `UI:${zoneMeta.positionEvent}`;
21443
+ const order = optimisticOrdersRef.current.get(zoneMeta.group) ?? zoneMeta.rawItems;
21444
+ order.forEach((it, idx) => {
21445
+ const id = String(it[zoneMeta.idField]);
21446
+ const position = idx * 1e3;
21447
+ eventBus.emit(evt, { id, position });
21448
+ });
21449
+ dndLog.info("dragEnd:positions:emitted", { event: evt, group: zoneMeta.group, count: order.length });
21450
+ };
21436
21451
  if (sourceMeta.group !== targetMeta.group) {
21437
21452
  if (targetMeta.dropEvent) {
21438
21453
  const evt = `UI:${targetMeta.dropEvent}`;
@@ -21452,6 +21467,8 @@ function useDataDnd(args) {
21452
21467
  } else {
21453
21468
  dndLog.warn("dragEnd:cross-container:no-dropEvent-on-target", { targetGroup: targetMeta.group });
21454
21469
  }
21470
+ emitPositions(sourceMeta);
21471
+ emitPositions(targetMeta);
21455
21472
  return;
21456
21473
  }
21457
21474
  if (oldIndex === newIndex) {
@@ -21474,6 +21491,7 @@ function useDataDnd(args) {
21474
21491
  } else {
21475
21492
  dndLog.debug("dragEnd:reorder:no-reorderEvent", { sourceGroup: sourceMeta.group });
21476
21493
  }
21494
+ emitPositions(sourceMeta);
21477
21495
  },
21478
21496
  [eventBus]
21479
21497
  );
@@ -21778,6 +21796,7 @@ function DataGrid({
21778
21796
  sortable,
21779
21797
  dropEvent,
21780
21798
  reorderEvent,
21799
+ positionEvent,
21781
21800
  dndItemIdField,
21782
21801
  dndRoot
21783
21802
  }) {
@@ -21795,6 +21814,7 @@ function DataGrid({
21795
21814
  sortable,
21796
21815
  dropEvent,
21797
21816
  reorderEvent,
21817
+ positionEvent,
21798
21818
  dndItemIdField,
21799
21819
  dndRoot
21800
21820
  });
@@ -22187,6 +22207,7 @@ function DataList({
22187
22207
  sortable: sortableProp,
22188
22208
  dropEvent,
22189
22209
  reorderEvent: dndReorderEvent,
22210
+ positionEvent,
22190
22211
  dndItemIdField,
22191
22212
  dndRoot
22192
22213
  }) {
@@ -22203,6 +22224,7 @@ function DataList({
22203
22224
  sortable: sortableProp,
22204
22225
  dropEvent,
22205
22226
  reorderEvent: dndReorderEvent,
22227
+ positionEvent,
22206
22228
  dndItemIdField,
22207
22229
  dndRoot
22208
22230
  });
@@ -21094,6 +21094,7 @@ function useDataDnd(args) {
21094
21094
  sortable: sortable$1,
21095
21095
  dropEvent,
21096
21096
  reorderEvent,
21097
+ positionEvent,
21097
21098
  dndItemIdField = "id",
21098
21099
  dndRoot,
21099
21100
  items,
@@ -21161,8 +21162,8 @@ function useDataDnd(args) {
21161
21162
  const [activeDrag, setActiveDrag] = React80__namespace.default.useState(null);
21162
21163
  const [overZoneGroup, setOverZoneGroup] = React80__namespace.default.useState(null);
21163
21164
  const meta = React80__namespace.default.useMemo(
21164
- () => ({ group: ownGroup, dropEvent, reorderEvent, itemIds, rawItems: items, idField: dndItemIdField }),
21165
- [ownGroup, dropEvent, reorderEvent, itemIds, items, dndItemIdField]
21165
+ () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
21166
+ [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
21166
21167
  );
21167
21168
  React80__namespace.default.useEffect(() => {
21168
21169
  const target = isRoot ? null : parentRoot;
@@ -21248,6 +21249,20 @@ function useDataDnd(args) {
21248
21249
  dndLog.warn("dragEnd:abort:no-zone-resolved", { activeId: active.id, hasSource: !!sourceMeta, hasTarget: !!targetMeta });
21249
21250
  return;
21250
21251
  }
21252
+ const emitPositions = (zoneMeta) => {
21253
+ if (!zoneMeta.positionEvent) {
21254
+ dndLog.debug("dragEnd:positions:no-event", { group: zoneMeta.group });
21255
+ return;
21256
+ }
21257
+ const evt = `UI:${zoneMeta.positionEvent}`;
21258
+ const order = optimisticOrdersRef.current.get(zoneMeta.group) ?? zoneMeta.rawItems;
21259
+ order.forEach((it, idx) => {
21260
+ const id = String(it[zoneMeta.idField]);
21261
+ const position = idx * 1e3;
21262
+ eventBus.emit(evt, { id, position });
21263
+ });
21264
+ dndLog.info("dragEnd:positions:emitted", { event: evt, group: zoneMeta.group, count: order.length });
21265
+ };
21251
21266
  if (sourceMeta.group !== targetMeta.group) {
21252
21267
  if (targetMeta.dropEvent) {
21253
21268
  const evt = `UI:${targetMeta.dropEvent}`;
@@ -21267,6 +21282,8 @@ function useDataDnd(args) {
21267
21282
  } else {
21268
21283
  dndLog.warn("dragEnd:cross-container:no-dropEvent-on-target", { targetGroup: targetMeta.group });
21269
21284
  }
21285
+ emitPositions(sourceMeta);
21286
+ emitPositions(targetMeta);
21270
21287
  return;
21271
21288
  }
21272
21289
  if (oldIndex === newIndex) {
@@ -21289,6 +21306,7 @@ function useDataDnd(args) {
21289
21306
  } else {
21290
21307
  dndLog.debug("dragEnd:reorder:no-reorderEvent", { sourceGroup: sourceMeta.group });
21291
21308
  }
21309
+ emitPositions(sourceMeta);
21292
21310
  },
21293
21311
  [eventBus]
21294
21312
  );
@@ -21593,6 +21611,7 @@ function DataGrid({
21593
21611
  sortable,
21594
21612
  dropEvent,
21595
21613
  reorderEvent,
21614
+ positionEvent,
21596
21615
  dndItemIdField,
21597
21616
  dndRoot
21598
21617
  }) {
@@ -21610,6 +21629,7 @@ function DataGrid({
21610
21629
  sortable,
21611
21630
  dropEvent,
21612
21631
  reorderEvent,
21632
+ positionEvent,
21613
21633
  dndItemIdField,
21614
21634
  dndRoot
21615
21635
  });
@@ -22002,6 +22022,7 @@ function DataList({
22002
22022
  sortable: sortableProp,
22003
22023
  dropEvent,
22004
22024
  reorderEvent: dndReorderEvent,
22025
+ positionEvent,
22005
22026
  dndItemIdField,
22006
22027
  dndRoot
22007
22028
  }) {
@@ -22018,6 +22039,7 @@ function DataList({
22018
22039
  sortable: sortableProp,
22019
22040
  dropEvent,
22020
22041
  reorderEvent: dndReorderEvent,
22042
+ positionEvent,
22021
22043
  dndItemIdField,
22022
22044
  dndRoot
22023
22045
  });
@@ -46198,6 +46220,74 @@ function ServerBridgeProvider({
46198
46220
  return /* @__PURE__ */ jsxRuntime.jsx(ServerBridgeContext.Provider, { value: { connected, sendEvent }, children });
46199
46221
  }
46200
46222
 
46223
+ // context/OrbitalThemeProvider.tsx
46224
+ init_ThemeContext();
46225
+
46226
+ // context/themeTokens.ts
46227
+ function themeTokensToCssVars(tokens, mode = "light", darkVariant) {
46228
+ const vars = {};
46229
+ const isDark = mode === "dark";
46230
+ const pickColors = isDark && darkVariant?.colors ? darkVariant.colors : tokens.colors;
46231
+ if (pickColors) {
46232
+ for (const [key, value] of Object.entries(pickColors)) {
46233
+ vars[`--color-${key}`] = value;
46234
+ }
46235
+ if (isDark && darkVariant?.colors && tokens.colors) {
46236
+ for (const [key, value] of Object.entries(tokens.colors)) {
46237
+ const varName = `--color-${key}`;
46238
+ if (!(varName in vars)) vars[varName] = value;
46239
+ }
46240
+ }
46241
+ }
46242
+ const pickRadii = isDark && darkVariant?.radii ? darkVariant.radii : tokens.radii;
46243
+ if (pickRadii) {
46244
+ for (const [key, value] of Object.entries(pickRadii)) {
46245
+ vars[`--radius-${key}`] = value;
46246
+ }
46247
+ }
46248
+ const pickSpacing = isDark && darkVariant?.spacing ? darkVariant.spacing : tokens.spacing;
46249
+ if (pickSpacing) {
46250
+ for (const [key, value] of Object.entries(pickSpacing)) {
46251
+ vars[`--space-${key}`] = value;
46252
+ }
46253
+ }
46254
+ const pickTypography = isDark && darkVariant?.typography ? darkVariant.typography : tokens.typography;
46255
+ if (pickTypography) {
46256
+ for (const [key, value] of Object.entries(pickTypography)) {
46257
+ vars[`--${key}`] = value;
46258
+ }
46259
+ }
46260
+ const pickShadows = isDark && darkVariant?.shadows ? darkVariant.shadows : tokens.shadows;
46261
+ if (pickShadows) {
46262
+ for (const [key, value] of Object.entries(pickShadows)) {
46263
+ vars[`--shadow-${key}`] = value;
46264
+ }
46265
+ }
46266
+ return vars;
46267
+ }
46268
+ function resolveThemeForRuntime(theme) {
46269
+ if (theme === void 0) return void 0;
46270
+ if (typeof theme === "string") return void 0;
46271
+ return theme;
46272
+ }
46273
+ function OrbitalThemeProvider({ theme, children }) {
46274
+ const resolved = resolveThemeForRuntime(theme);
46275
+ const { resolvedMode } = useTheme();
46276
+ if (!resolved) {
46277
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
46278
+ }
46279
+ const vars = themeTokensToCssVars(resolved.tokens, resolvedMode, resolved.variants?.dark);
46280
+ return /* @__PURE__ */ jsxRuntime.jsx(
46281
+ "div",
46282
+ {
46283
+ "data-orbital-theme": resolved.name,
46284
+ style: { display: "contents", ...vars },
46285
+ children
46286
+ }
46287
+ );
46288
+ }
46289
+ OrbitalThemeProvider.displayName = "OrbitalThemeProvider";
46290
+
46201
46291
  // runtime/OrbPreview.tsx
46202
46292
  init_navigation();
46203
46293
  init_verificationRegistry();
@@ -46646,6 +46736,19 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
46646
46736
  });
46647
46737
  return set;
46648
46738
  }, [schema, pageName]);
46739
+ const activeOrbitalTheme = React80.useMemo(() => {
46740
+ const parsed = schema;
46741
+ if (!parsed?.orbitals?.length) return void 0;
46742
+ if (pageName) {
46743
+ for (const orb of parsed.orbitals) {
46744
+ for (const pageRef of orb.pages ?? []) {
46745
+ const name = typeof pageRef === "object" && pageRef !== null ? pageRef.name : void 0;
46746
+ if (name === pageName) return orb.theme;
46747
+ }
46748
+ }
46749
+ }
46750
+ return parsed.orbitals[0]?.theme;
46751
+ }, [schema, pageName]);
46649
46752
  const inner = /* @__PURE__ */ jsxRuntime.jsx(providers.VerificationProvider, { enabled: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
46650
46753
  EntitySchemaProvider,
46651
46754
  {
@@ -46666,7 +46769,7 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
46666
46769
  persistence
46667
46770
  }
46668
46771
  ),
46669
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "h-full p-4", children: /* @__PURE__ */ jsxRuntime.jsx(UISlotRenderer, { includeHud: true, hudMode: "inline", includeFloating: true }) })
46772
+ /* @__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 }) }) })
46670
46773
  ]
46671
46774
  }
46672
46775
  ) });