@almadar/ui 4.50.15 → 4.50.17

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.
@@ -24937,7 +24937,18 @@ function useDataDnd(args) {
24937
24937
  });
24938
24938
  }, []);
24939
24939
  const sharedOptimistic = isRoot ? optimisticOrders : parentRoot?.optimisticOrders ?? /* @__PURE__ */ new Map();
24940
- const orderedItems = sharedOptimistic.get(ownGroup) ?? items;
24940
+ const optimisticEntry = sharedOptimistic.get(ownGroup);
24941
+ const orderedItems = optimisticEntry ?? items;
24942
+ if (isZone && enabled) {
24943
+ dndLog.debug("hook:render", {
24944
+ group: ownGroup,
24945
+ isRoot,
24946
+ itemsLen: items.length,
24947
+ optimisticEntryLen: optimisticEntry ? optimisticEntry.length : null,
24948
+ orderedLen: orderedItems.length,
24949
+ sharedKeys: Array.from(sharedOptimistic.keys())
24950
+ });
24951
+ }
24941
24952
  const itemIdsSignature = orderedItems.map((it, idx) => {
24942
24953
  const raw = it[dndItemIdField];
24943
24954
  return String(raw ?? `__idx_${idx}`);
@@ -58394,6 +58405,74 @@ function ServerBridgeProvider({
58394
58405
  return /* @__PURE__ */ jsxRuntime.jsx(ServerBridgeContext.Provider, { value: { connected, sendEvent }, children });
58395
58406
  }
58396
58407
 
58408
+ // context/OrbitalThemeProvider.tsx
58409
+ init_ThemeContext();
58410
+
58411
+ // context/themeTokens.ts
58412
+ function themeTokensToCssVars(tokens, mode = "light", darkVariant) {
58413
+ const vars = {};
58414
+ const isDark = mode === "dark";
58415
+ const pickColors = isDark && darkVariant?.colors ? darkVariant.colors : tokens.colors;
58416
+ if (pickColors) {
58417
+ for (const [key, value] of Object.entries(pickColors)) {
58418
+ vars[`--color-${key}`] = value;
58419
+ }
58420
+ if (isDark && darkVariant?.colors && tokens.colors) {
58421
+ for (const [key, value] of Object.entries(tokens.colors)) {
58422
+ const varName = `--color-${key}`;
58423
+ if (!(varName in vars)) vars[varName] = value;
58424
+ }
58425
+ }
58426
+ }
58427
+ const pickRadii = isDark && darkVariant?.radii ? darkVariant.radii : tokens.radii;
58428
+ if (pickRadii) {
58429
+ for (const [key, value] of Object.entries(pickRadii)) {
58430
+ vars[`--radius-${key}`] = value;
58431
+ }
58432
+ }
58433
+ const pickSpacing = isDark && darkVariant?.spacing ? darkVariant.spacing : tokens.spacing;
58434
+ if (pickSpacing) {
58435
+ for (const [key, value] of Object.entries(pickSpacing)) {
58436
+ vars[`--space-${key}`] = value;
58437
+ }
58438
+ }
58439
+ const pickTypography = isDark && darkVariant?.typography ? darkVariant.typography : tokens.typography;
58440
+ if (pickTypography) {
58441
+ for (const [key, value] of Object.entries(pickTypography)) {
58442
+ vars[`--${key}`] = value;
58443
+ }
58444
+ }
58445
+ const pickShadows = isDark && darkVariant?.shadows ? darkVariant.shadows : tokens.shadows;
58446
+ if (pickShadows) {
58447
+ for (const [key, value] of Object.entries(pickShadows)) {
58448
+ vars[`--shadow-${key}`] = value;
58449
+ }
58450
+ }
58451
+ return vars;
58452
+ }
58453
+ function resolveThemeForRuntime(theme) {
58454
+ if (theme === void 0) return void 0;
58455
+ if (typeof theme === "string") return void 0;
58456
+ return theme;
58457
+ }
58458
+ function OrbitalThemeProvider({ theme, children }) {
58459
+ const resolved = resolveThemeForRuntime(theme);
58460
+ const { resolvedMode } = useTheme();
58461
+ if (!resolved) {
58462
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
58463
+ }
58464
+ const vars = themeTokensToCssVars(resolved.tokens, resolvedMode, resolved.variants?.dark);
58465
+ return /* @__PURE__ */ jsxRuntime.jsx(
58466
+ "div",
58467
+ {
58468
+ "data-orbital-theme": resolved.name,
58469
+ style: { display: "contents", ...vars },
58470
+ children
58471
+ }
58472
+ );
58473
+ }
58474
+ OrbitalThemeProvider.displayName = "OrbitalThemeProvider";
58475
+
58397
58476
  // runtime/OrbPreview.tsx
58398
58477
  init_navigation();
58399
58478
  init_verificationRegistry();
@@ -58805,6 +58884,19 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
58805
58884
  });
58806
58885
  return set;
58807
58886
  }, [schema, pageName]);
58887
+ const activeOrbitalTheme = React93.useMemo(() => {
58888
+ const parsed = schema;
58889
+ if (!parsed?.orbitals?.length) return void 0;
58890
+ if (pageName) {
58891
+ for (const orb of parsed.orbitals) {
58892
+ for (const pageRef of orb.pages ?? []) {
58893
+ const name = typeof pageRef === "object" && pageRef !== null ? pageRef.name : void 0;
58894
+ if (name === pageName) return orb.theme;
58895
+ }
58896
+ }
58897
+ }
58898
+ return parsed.orbitals[0]?.theme;
58899
+ }, [schema, pageName]);
58808
58900
  const inner = /* @__PURE__ */ jsxRuntime.jsx(VerificationProvider, { enabled: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
58809
58901
  EntitySchemaProvider,
58810
58902
  {
@@ -58825,7 +58917,7 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
58825
58917
  persistence
58826
58918
  }
58827
58919
  ),
58828
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "h-full p-4", children: /* @__PURE__ */ jsxRuntime.jsx(UISlotRenderer, { includeHud: true, hudMode: "inline", includeFloating: true }) })
58920
+ /* @__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 }) }) })
58829
58921
  ]
58830
58922
  }
58831
58923
  ) });
package/dist/avl/index.js CHANGED
@@ -24891,7 +24891,18 @@ function useDataDnd(args) {
24891
24891
  });
24892
24892
  }, []);
24893
24893
  const sharedOptimistic = isRoot ? optimisticOrders : parentRoot?.optimisticOrders ?? /* @__PURE__ */ new Map();
24894
- const orderedItems = sharedOptimistic.get(ownGroup) ?? items;
24894
+ const optimisticEntry = sharedOptimistic.get(ownGroup);
24895
+ const orderedItems = optimisticEntry ?? items;
24896
+ if (isZone && enabled) {
24897
+ dndLog.debug("hook:render", {
24898
+ group: ownGroup,
24899
+ isRoot,
24900
+ itemsLen: items.length,
24901
+ optimisticEntryLen: optimisticEntry ? optimisticEntry.length : null,
24902
+ orderedLen: orderedItems.length,
24903
+ sharedKeys: Array.from(sharedOptimistic.keys())
24904
+ });
24905
+ }
24895
24906
  const itemIdsSignature = orderedItems.map((it, idx) => {
24896
24907
  const raw = it[dndItemIdField];
24897
24908
  return String(raw ?? `__idx_${idx}`);
@@ -58348,6 +58359,74 @@ function ServerBridgeProvider({
58348
58359
  return /* @__PURE__ */ jsx(ServerBridgeContext.Provider, { value: { connected, sendEvent }, children });
58349
58360
  }
58350
58361
 
58362
+ // context/OrbitalThemeProvider.tsx
58363
+ init_ThemeContext();
58364
+
58365
+ // context/themeTokens.ts
58366
+ function themeTokensToCssVars(tokens, mode = "light", darkVariant) {
58367
+ const vars = {};
58368
+ const isDark = mode === "dark";
58369
+ const pickColors = isDark && darkVariant?.colors ? darkVariant.colors : tokens.colors;
58370
+ if (pickColors) {
58371
+ for (const [key, value] of Object.entries(pickColors)) {
58372
+ vars[`--color-${key}`] = value;
58373
+ }
58374
+ if (isDark && darkVariant?.colors && tokens.colors) {
58375
+ for (const [key, value] of Object.entries(tokens.colors)) {
58376
+ const varName = `--color-${key}`;
58377
+ if (!(varName in vars)) vars[varName] = value;
58378
+ }
58379
+ }
58380
+ }
58381
+ const pickRadii = isDark && darkVariant?.radii ? darkVariant.radii : tokens.radii;
58382
+ if (pickRadii) {
58383
+ for (const [key, value] of Object.entries(pickRadii)) {
58384
+ vars[`--radius-${key}`] = value;
58385
+ }
58386
+ }
58387
+ const pickSpacing = isDark && darkVariant?.spacing ? darkVariant.spacing : tokens.spacing;
58388
+ if (pickSpacing) {
58389
+ for (const [key, value] of Object.entries(pickSpacing)) {
58390
+ vars[`--space-${key}`] = value;
58391
+ }
58392
+ }
58393
+ const pickTypography = isDark && darkVariant?.typography ? darkVariant.typography : tokens.typography;
58394
+ if (pickTypography) {
58395
+ for (const [key, value] of Object.entries(pickTypography)) {
58396
+ vars[`--${key}`] = value;
58397
+ }
58398
+ }
58399
+ const pickShadows = isDark && darkVariant?.shadows ? darkVariant.shadows : tokens.shadows;
58400
+ if (pickShadows) {
58401
+ for (const [key, value] of Object.entries(pickShadows)) {
58402
+ vars[`--shadow-${key}`] = value;
58403
+ }
58404
+ }
58405
+ return vars;
58406
+ }
58407
+ function resolveThemeForRuntime(theme) {
58408
+ if (theme === void 0) return void 0;
58409
+ if (typeof theme === "string") return void 0;
58410
+ return theme;
58411
+ }
58412
+ function OrbitalThemeProvider({ theme, children }) {
58413
+ const resolved = resolveThemeForRuntime(theme);
58414
+ const { resolvedMode } = useTheme();
58415
+ if (!resolved) {
58416
+ return /* @__PURE__ */ jsx(Fragment, { children });
58417
+ }
58418
+ const vars = themeTokensToCssVars(resolved.tokens, resolvedMode, resolved.variants?.dark);
58419
+ return /* @__PURE__ */ jsx(
58420
+ "div",
58421
+ {
58422
+ "data-orbital-theme": resolved.name,
58423
+ style: { display: "contents", ...vars },
58424
+ children
58425
+ }
58426
+ );
58427
+ }
58428
+ OrbitalThemeProvider.displayName = "OrbitalThemeProvider";
58429
+
58351
58430
  // runtime/OrbPreview.tsx
58352
58431
  init_navigation();
58353
58432
  init_verificationRegistry();
@@ -58759,6 +58838,19 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
58759
58838
  });
58760
58839
  return set;
58761
58840
  }, [schema, pageName]);
58841
+ const activeOrbitalTheme = useMemo(() => {
58842
+ const parsed = schema;
58843
+ if (!parsed?.orbitals?.length) return void 0;
58844
+ if (pageName) {
58845
+ for (const orb of parsed.orbitals) {
58846
+ for (const pageRef of orb.pages ?? []) {
58847
+ const name = typeof pageRef === "object" && pageRef !== null ? pageRef.name : void 0;
58848
+ if (name === pageName) return orb.theme;
58849
+ }
58850
+ }
58851
+ }
58852
+ return parsed.orbitals[0]?.theme;
58853
+ }, [schema, pageName]);
58762
58854
  const inner = /* @__PURE__ */ jsx(VerificationProvider, { enabled: true, children: /* @__PURE__ */ jsxs(
58763
58855
  EntitySchemaProvider,
58764
58856
  {
@@ -58779,7 +58871,7 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
58779
58871
  persistence
58780
58872
  }
58781
58873
  ),
58782
- /* @__PURE__ */ jsx(Box, { className: "h-full p-4", children: /* @__PURE__ */ jsx(UISlotRenderer, { includeHud: true, hudMode: "inline", includeFloating: true }) })
58874
+ /* @__PURE__ */ jsx(OrbitalThemeProvider, { theme: activeOrbitalTheme, children: /* @__PURE__ */ jsx(Box, { className: "h-full p-4", children: /* @__PURE__ */ jsx(UISlotRenderer, { includeHud: true, hudMode: "inline", includeFloating: true }) }) })
58783
58875
  ]
58784
58876
  }
58785
58877
  ) });
@@ -20104,7 +20104,18 @@ function useDataDnd(args) {
20104
20104
  });
20105
20105
  }, []);
20106
20106
  const sharedOptimistic = isRoot ? optimisticOrders : parentRoot?.optimisticOrders ?? /* @__PURE__ */ new Map();
20107
- const orderedItems = sharedOptimistic.get(ownGroup) ?? items;
20107
+ const optimisticEntry = sharedOptimistic.get(ownGroup);
20108
+ const orderedItems = optimisticEntry ?? items;
20109
+ if (isZone && enabled) {
20110
+ dndLog.debug("hook:render", {
20111
+ group: ownGroup,
20112
+ isRoot,
20113
+ itemsLen: items.length,
20114
+ optimisticEntryLen: optimisticEntry ? optimisticEntry.length : null,
20115
+ orderedLen: orderedItems.length,
20116
+ sharedKeys: Array.from(sharedOptimistic.keys())
20117
+ });
20118
+ }
20108
20119
  const itemIdsSignature = orderedItems.map((it, idx) => {
20109
20120
  const raw = it[dndItemIdField];
20110
20121
  return String(raw ?? `__idx_${idx}`);
@@ -20058,7 +20058,18 @@ function useDataDnd(args) {
20058
20058
  });
20059
20059
  }, []);
20060
20060
  const sharedOptimistic = isRoot ? optimisticOrders : parentRoot?.optimisticOrders ?? /* @__PURE__ */ new Map();
20061
- const orderedItems = sharedOptimistic.get(ownGroup) ?? items;
20061
+ const optimisticEntry = sharedOptimistic.get(ownGroup);
20062
+ const orderedItems = optimisticEntry ?? items;
20063
+ if (isZone && enabled) {
20064
+ dndLog.debug("hook:render", {
20065
+ group: ownGroup,
20066
+ isRoot,
20067
+ itemsLen: items.length,
20068
+ optimisticEntryLen: optimisticEntry ? optimisticEntry.length : null,
20069
+ orderedLen: orderedItems.length,
20070
+ sharedKeys: Array.from(sharedOptimistic.keys())
20071
+ });
20072
+ }
20062
20073
  const itemIdsSignature = orderedItems.map((it, idx) => {
20063
20074
  const raw = it[dndItemIdField];
20064
20075
  return String(raw ?? `__idx_${idx}`);
@@ -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
+ }
@@ -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;
@@ -21349,7 +21349,18 @@ function useDataDnd(args) {
21349
21349
  });
21350
21350
  }, []);
21351
21351
  const sharedOptimistic = isRoot ? optimisticOrders : parentRoot?.optimisticOrders ?? /* @__PURE__ */ new Map();
21352
- const orderedItems = sharedOptimistic.get(ownGroup) ?? items;
21352
+ const optimisticEntry = sharedOptimistic.get(ownGroup);
21353
+ const orderedItems = optimisticEntry ?? items;
21354
+ if (isZone && enabled) {
21355
+ dndLog.debug("hook:render", {
21356
+ group: ownGroup,
21357
+ isRoot,
21358
+ itemsLen: items.length,
21359
+ optimisticEntryLen: optimisticEntry ? optimisticEntry.length : null,
21360
+ orderedLen: orderedItems.length,
21361
+ sharedKeys: Array.from(sharedOptimistic.keys())
21362
+ });
21363
+ }
21353
21364
  const itemIdsSignature = orderedItems.map((it, idx) => {
21354
21365
  const raw = it[dndItemIdField];
21355
21366
  return String(raw ?? `__idx_${idx}`);
@@ -21303,7 +21303,18 @@ function useDataDnd(args) {
21303
21303
  });
21304
21304
  }, []);
21305
21305
  const sharedOptimistic = isRoot ? optimisticOrders : parentRoot?.optimisticOrders ?? /* @__PURE__ */ new Map();
21306
- const orderedItems = sharedOptimistic.get(ownGroup) ?? items;
21306
+ const optimisticEntry = sharedOptimistic.get(ownGroup);
21307
+ const orderedItems = optimisticEntry ?? items;
21308
+ if (isZone && enabled) {
21309
+ dndLog.debug("hook:render", {
21310
+ group: ownGroup,
21311
+ isRoot,
21312
+ itemsLen: items.length,
21313
+ optimisticEntryLen: optimisticEntry ? optimisticEntry.length : null,
21314
+ orderedLen: orderedItems.length,
21315
+ sharedKeys: Array.from(sharedOptimistic.keys())
21316
+ });
21317
+ }
21307
21318
  const itemIdsSignature = orderedItems.map((it, idx) => {
21308
21319
  const raw = it[dndItemIdField];
21309
21320
  return String(raw ?? `__idx_${idx}`);
@@ -21118,7 +21118,18 @@ function useDataDnd(args) {
21118
21118
  });
21119
21119
  }, []);
21120
21120
  const sharedOptimistic = isRoot ? optimisticOrders : parentRoot?.optimisticOrders ?? /* @__PURE__ */ new Map();
21121
- const orderedItems = sharedOptimistic.get(ownGroup) ?? items;
21121
+ const optimisticEntry = sharedOptimistic.get(ownGroup);
21122
+ const orderedItems = optimisticEntry ?? items;
21123
+ if (isZone && enabled) {
21124
+ dndLog.debug("hook:render", {
21125
+ group: ownGroup,
21126
+ isRoot,
21127
+ itemsLen: items.length,
21128
+ optimisticEntryLen: optimisticEntry ? optimisticEntry.length : null,
21129
+ orderedLen: orderedItems.length,
21130
+ sharedKeys: Array.from(sharedOptimistic.keys())
21131
+ });
21132
+ }
21122
21133
  const itemIdsSignature = orderedItems.map((it, idx) => {
21123
21134
  const raw = it[dndItemIdField];
21124
21135
  return String(raw ?? `__idx_${idx}`);
@@ -46187,6 +46198,74 @@ function ServerBridgeProvider({
46187
46198
  return /* @__PURE__ */ jsxRuntime.jsx(ServerBridgeContext.Provider, { value: { connected, sendEvent }, children });
46188
46199
  }
46189
46200
 
46201
+ // context/OrbitalThemeProvider.tsx
46202
+ init_ThemeContext();
46203
+
46204
+ // context/themeTokens.ts
46205
+ function themeTokensToCssVars(tokens, mode = "light", darkVariant) {
46206
+ const vars = {};
46207
+ const isDark = mode === "dark";
46208
+ const pickColors = isDark && darkVariant?.colors ? darkVariant.colors : tokens.colors;
46209
+ if (pickColors) {
46210
+ for (const [key, value] of Object.entries(pickColors)) {
46211
+ vars[`--color-${key}`] = value;
46212
+ }
46213
+ if (isDark && darkVariant?.colors && tokens.colors) {
46214
+ for (const [key, value] of Object.entries(tokens.colors)) {
46215
+ const varName = `--color-${key}`;
46216
+ if (!(varName in vars)) vars[varName] = value;
46217
+ }
46218
+ }
46219
+ }
46220
+ const pickRadii = isDark && darkVariant?.radii ? darkVariant.radii : tokens.radii;
46221
+ if (pickRadii) {
46222
+ for (const [key, value] of Object.entries(pickRadii)) {
46223
+ vars[`--radius-${key}`] = value;
46224
+ }
46225
+ }
46226
+ const pickSpacing = isDark && darkVariant?.spacing ? darkVariant.spacing : tokens.spacing;
46227
+ if (pickSpacing) {
46228
+ for (const [key, value] of Object.entries(pickSpacing)) {
46229
+ vars[`--space-${key}`] = value;
46230
+ }
46231
+ }
46232
+ const pickTypography = isDark && darkVariant?.typography ? darkVariant.typography : tokens.typography;
46233
+ if (pickTypography) {
46234
+ for (const [key, value] of Object.entries(pickTypography)) {
46235
+ vars[`--${key}`] = value;
46236
+ }
46237
+ }
46238
+ const pickShadows = isDark && darkVariant?.shadows ? darkVariant.shadows : tokens.shadows;
46239
+ if (pickShadows) {
46240
+ for (const [key, value] of Object.entries(pickShadows)) {
46241
+ vars[`--shadow-${key}`] = value;
46242
+ }
46243
+ }
46244
+ return vars;
46245
+ }
46246
+ function resolveThemeForRuntime(theme) {
46247
+ if (theme === void 0) return void 0;
46248
+ if (typeof theme === "string") return void 0;
46249
+ return theme;
46250
+ }
46251
+ function OrbitalThemeProvider({ theme, children }) {
46252
+ const resolved = resolveThemeForRuntime(theme);
46253
+ const { resolvedMode } = useTheme();
46254
+ if (!resolved) {
46255
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
46256
+ }
46257
+ const vars = themeTokensToCssVars(resolved.tokens, resolvedMode, resolved.variants?.dark);
46258
+ return /* @__PURE__ */ jsxRuntime.jsx(
46259
+ "div",
46260
+ {
46261
+ "data-orbital-theme": resolved.name,
46262
+ style: { display: "contents", ...vars },
46263
+ children
46264
+ }
46265
+ );
46266
+ }
46267
+ OrbitalThemeProvider.displayName = "OrbitalThemeProvider";
46268
+
46190
46269
  // runtime/OrbPreview.tsx
46191
46270
  init_navigation();
46192
46271
  init_verificationRegistry();
@@ -46635,6 +46714,19 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
46635
46714
  });
46636
46715
  return set;
46637
46716
  }, [schema, pageName]);
46717
+ const activeOrbitalTheme = React80.useMemo(() => {
46718
+ const parsed = schema;
46719
+ if (!parsed?.orbitals?.length) return void 0;
46720
+ if (pageName) {
46721
+ for (const orb of parsed.orbitals) {
46722
+ for (const pageRef of orb.pages ?? []) {
46723
+ const name = typeof pageRef === "object" && pageRef !== null ? pageRef.name : void 0;
46724
+ if (name === pageName) return orb.theme;
46725
+ }
46726
+ }
46727
+ }
46728
+ return parsed.orbitals[0]?.theme;
46729
+ }, [schema, pageName]);
46638
46730
  const inner = /* @__PURE__ */ jsxRuntime.jsx(providers.VerificationProvider, { enabled: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
46639
46731
  EntitySchemaProvider,
46640
46732
  {
@@ -46655,7 +46747,7 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
46655
46747
  persistence
46656
46748
  }
46657
46749
  ),
46658
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "h-full p-4", children: /* @__PURE__ */ jsxRuntime.jsx(UISlotRenderer, { includeHud: true, hudMode: "inline", includeFloating: true }) })
46750
+ /* @__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 }) }) })
46659
46751
  ]
46660
46752
  }
46661
46753
  ) });
@@ -21072,7 +21072,18 @@ function useDataDnd(args) {
21072
21072
  });
21073
21073
  }, []);
21074
21074
  const sharedOptimistic = isRoot ? optimisticOrders : parentRoot?.optimisticOrders ?? /* @__PURE__ */ new Map();
21075
- const orderedItems = sharedOptimistic.get(ownGroup) ?? items;
21075
+ const optimisticEntry = sharedOptimistic.get(ownGroup);
21076
+ const orderedItems = optimisticEntry ?? items;
21077
+ if (isZone && enabled) {
21078
+ dndLog.debug("hook:render", {
21079
+ group: ownGroup,
21080
+ isRoot,
21081
+ itemsLen: items.length,
21082
+ optimisticEntryLen: optimisticEntry ? optimisticEntry.length : null,
21083
+ orderedLen: orderedItems.length,
21084
+ sharedKeys: Array.from(sharedOptimistic.keys())
21085
+ });
21086
+ }
21076
21087
  const itemIdsSignature = orderedItems.map((it, idx) => {
21077
21088
  const raw = it[dndItemIdField];
21078
21089
  return String(raw ?? `__idx_${idx}`);
@@ -46141,6 +46152,74 @@ function ServerBridgeProvider({
46141
46152
  return /* @__PURE__ */ jsx(ServerBridgeContext.Provider, { value: { connected, sendEvent }, children });
46142
46153
  }
46143
46154
 
46155
+ // context/OrbitalThemeProvider.tsx
46156
+ init_ThemeContext();
46157
+
46158
+ // context/themeTokens.ts
46159
+ function themeTokensToCssVars(tokens, mode = "light", darkVariant) {
46160
+ const vars = {};
46161
+ const isDark = mode === "dark";
46162
+ const pickColors = isDark && darkVariant?.colors ? darkVariant.colors : tokens.colors;
46163
+ if (pickColors) {
46164
+ for (const [key, value] of Object.entries(pickColors)) {
46165
+ vars[`--color-${key}`] = value;
46166
+ }
46167
+ if (isDark && darkVariant?.colors && tokens.colors) {
46168
+ for (const [key, value] of Object.entries(tokens.colors)) {
46169
+ const varName = `--color-${key}`;
46170
+ if (!(varName in vars)) vars[varName] = value;
46171
+ }
46172
+ }
46173
+ }
46174
+ const pickRadii = isDark && darkVariant?.radii ? darkVariant.radii : tokens.radii;
46175
+ if (pickRadii) {
46176
+ for (const [key, value] of Object.entries(pickRadii)) {
46177
+ vars[`--radius-${key}`] = value;
46178
+ }
46179
+ }
46180
+ const pickSpacing = isDark && darkVariant?.spacing ? darkVariant.spacing : tokens.spacing;
46181
+ if (pickSpacing) {
46182
+ for (const [key, value] of Object.entries(pickSpacing)) {
46183
+ vars[`--space-${key}`] = value;
46184
+ }
46185
+ }
46186
+ const pickTypography = isDark && darkVariant?.typography ? darkVariant.typography : tokens.typography;
46187
+ if (pickTypography) {
46188
+ for (const [key, value] of Object.entries(pickTypography)) {
46189
+ vars[`--${key}`] = value;
46190
+ }
46191
+ }
46192
+ const pickShadows = isDark && darkVariant?.shadows ? darkVariant.shadows : tokens.shadows;
46193
+ if (pickShadows) {
46194
+ for (const [key, value] of Object.entries(pickShadows)) {
46195
+ vars[`--shadow-${key}`] = value;
46196
+ }
46197
+ }
46198
+ return vars;
46199
+ }
46200
+ function resolveThemeForRuntime(theme) {
46201
+ if (theme === void 0) return void 0;
46202
+ if (typeof theme === "string") return void 0;
46203
+ return theme;
46204
+ }
46205
+ function OrbitalThemeProvider({ theme, children }) {
46206
+ const resolved = resolveThemeForRuntime(theme);
46207
+ const { resolvedMode } = useTheme();
46208
+ if (!resolved) {
46209
+ return /* @__PURE__ */ jsx(Fragment, { children });
46210
+ }
46211
+ const vars = themeTokensToCssVars(resolved.tokens, resolvedMode, resolved.variants?.dark);
46212
+ return /* @__PURE__ */ jsx(
46213
+ "div",
46214
+ {
46215
+ "data-orbital-theme": resolved.name,
46216
+ style: { display: "contents", ...vars },
46217
+ children
46218
+ }
46219
+ );
46220
+ }
46221
+ OrbitalThemeProvider.displayName = "OrbitalThemeProvider";
46222
+
46144
46223
  // runtime/OrbPreview.tsx
46145
46224
  init_navigation();
46146
46225
  init_verificationRegistry();
@@ -46589,6 +46668,19 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
46589
46668
  });
46590
46669
  return set;
46591
46670
  }, [schema, pageName]);
46671
+ const activeOrbitalTheme = useMemo(() => {
46672
+ const parsed = schema;
46673
+ if (!parsed?.orbitals?.length) return void 0;
46674
+ if (pageName) {
46675
+ for (const orb of parsed.orbitals) {
46676
+ for (const pageRef of orb.pages ?? []) {
46677
+ const name = typeof pageRef === "object" && pageRef !== null ? pageRef.name : void 0;
46678
+ if (name === pageName) return orb.theme;
46679
+ }
46680
+ }
46681
+ }
46682
+ return parsed.orbitals[0]?.theme;
46683
+ }, [schema, pageName]);
46592
46684
  const inner = /* @__PURE__ */ jsx(VerificationProvider, { enabled: true, children: /* @__PURE__ */ jsxs(
46593
46685
  EntitySchemaProvider,
46594
46686
  {
@@ -46609,7 +46701,7 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
46609
46701
  persistence
46610
46702
  }
46611
46703
  ),
46612
- /* @__PURE__ */ jsx(Box, { className: "h-full p-4", children: /* @__PURE__ */ jsx(UISlotRenderer, { includeHud: true, hudMode: "inline", includeFloating: true }) })
46704
+ /* @__PURE__ */ jsx(OrbitalThemeProvider, { theme: activeOrbitalTheme, children: /* @__PURE__ */ jsx(Box, { className: "h-full p-4", children: /* @__PURE__ */ jsx(UISlotRenderer, { includeHud: true, hudMode: "inline", includeFloating: true }) }) })
46613
46705
  ]
46614
46706
  }
46615
46707
  ) });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "4.50.15",
3
+ "version": "4.50.17",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [