@almadar/ui 5.127.0 → 5.129.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22068,7 +22068,7 @@ var init_DashboardLayout = __esm({
22068
22068
  ]
22069
22069
  }
22070
22070
  ),
22071
- user && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "relative", children: [
22071
+ user?.name && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "relative", children: [
22072
22072
  /* @__PURE__ */ jsxRuntime.jsxs(
22073
22073
  Button,
22074
22074
  {
@@ -27388,12 +27388,12 @@ var init_MapView = __esm({
27388
27388
  shadowSize: [41, 41]
27389
27389
  });
27390
27390
  L.Marker.prototype.options.icon = defaultIcon;
27391
- const { useEffect: useEffect62, useRef: useRef59, useCallback: useCallback93, useState: useState91 } = React84__namespace.default;
27391
+ const { useEffect: useEffect62, useRef: useRef60, useCallback: useCallback93, useState: useState91 } = React84__namespace.default;
27392
27392
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
27393
27393
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
27394
27394
  function MapUpdater({ centerLat, centerLng, zoom }) {
27395
27395
  const map = useMap();
27396
- const prevRef = useRef59({ centerLat, centerLng, zoom });
27396
+ const prevRef = useRef60({ centerLat, centerLng, zoom });
27397
27397
  useEffect62(() => {
27398
27398
  const prev = prevRef.current;
27399
27399
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
@@ -36583,6 +36583,290 @@ var init_GraphCanvas = __esm({
36583
36583
  GraphCanvas.displayName = "GraphCanvas";
36584
36584
  }
36585
36585
  });
36586
+ var ImportSourcePicker;
36587
+ var init_ImportSourcePicker = __esm({
36588
+ "components/core/molecules/import/ImportSourcePicker.tsx"() {
36589
+ "use client";
36590
+ init_Box();
36591
+ init_Icon();
36592
+ init_Typography();
36593
+ init_cn();
36594
+ ImportSourcePicker = ({
36595
+ sources,
36596
+ onSelect,
36597
+ onFilesSelected,
36598
+ title,
36599
+ moreSources,
36600
+ className
36601
+ }) => {
36602
+ const fileInputRef = React84.useRef(null);
36603
+ const handlePick = (source) => {
36604
+ if (source.disabled) return;
36605
+ if (source.kind === "file") {
36606
+ const input = fileInputRef.current;
36607
+ if (!input) return;
36608
+ input.accept = source.accept ?? "";
36609
+ input.multiple = source.multiple ?? false;
36610
+ input.click();
36611
+ return;
36612
+ }
36613
+ onSelect?.(source.id);
36614
+ };
36615
+ const handleFiles = (event) => {
36616
+ const files = event.target.files ? Array.from(event.target.files) : [];
36617
+ event.target.value = "";
36618
+ if (files.length > 0) onFilesSelected?.(files);
36619
+ };
36620
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("flex flex-col gap-2", className), children: [
36621
+ title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
36622
+ sources.map((source) => /* @__PURE__ */ jsxRuntime.jsxs(
36623
+ Box,
36624
+ {
36625
+ role: "button",
36626
+ tabIndex: source.disabled ? -1 : 0,
36627
+ "aria-disabled": source.disabled,
36628
+ onClick: () => handlePick(source),
36629
+ onKeyDown: (event) => {
36630
+ if (event.key === "Enter" || event.key === " ") {
36631
+ event.preventDefault();
36632
+ handlePick(source);
36633
+ }
36634
+ },
36635
+ className: cn(
36636
+ "flex items-center gap-3 rounded-md border border-border bg-card px-4 py-3 text-left",
36637
+ source.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer hover:bg-accent hover:text-accent-foreground"
36638
+ ),
36639
+ children: [
36640
+ source.icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: source.icon, size: "md" }) : null,
36641
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-col", children: [
36642
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "label", children: source.label }),
36643
+ source.description ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: source.description }) : null
36644
+ ] })
36645
+ ]
36646
+ },
36647
+ source.id
36648
+ )),
36649
+ moreSources,
36650
+ /* @__PURE__ */ jsxRuntime.jsx(
36651
+ "input",
36652
+ {
36653
+ ref: fileInputRef,
36654
+ type: "file",
36655
+ className: "hidden",
36656
+ onChange: handleFiles,
36657
+ "data-testid": "import-source-file-input"
36658
+ }
36659
+ )
36660
+ ] });
36661
+ };
36662
+ }
36663
+ });
36664
+ function formatFieldValue(value) {
36665
+ if (value === null) return "\u2014";
36666
+ if (value instanceof Date) return value.toISOString();
36667
+ if (Array.isArray(value)) return value.map(formatFieldValue).join(", ");
36668
+ if (typeof value === "object") return JSON.stringify(value);
36669
+ return String(value);
36670
+ }
36671
+ function unitTitle(unit) {
36672
+ for (const key of TITLE_KEYS) {
36673
+ const value = unit.fields[key];
36674
+ if (typeof value === "string" && value.length > 0) return value;
36675
+ }
36676
+ return unit.ref;
36677
+ }
36678
+ function fieldSummary(unit) {
36679
+ return Object.entries(unit.fields).filter(([key]) => !TITLE_KEYS.includes(key)).map(([key, value]) => `${key}: ${formatFieldValue(value)}`).join(" \xB7 ");
36680
+ }
36681
+ var TITLE_KEYS, ImportPreviewTree;
36682
+ var init_ImportPreviewTree = __esm({
36683
+ "components/core/molecules/import/ImportPreviewTree.tsx"() {
36684
+ "use client";
36685
+ init_Box();
36686
+ init_Badge();
36687
+ init_Button();
36688
+ init_Icon();
36689
+ init_Typography();
36690
+ init_cn();
36691
+ TITLE_KEYS = ["title", "name", "label"];
36692
+ ImportPreviewTree = ({
36693
+ units,
36694
+ skipped = [],
36695
+ entityDisplay,
36696
+ onConfirm,
36697
+ onCancel,
36698
+ confirmLabel = "Confirm import",
36699
+ cancelLabel = "Cancel",
36700
+ indent = 16,
36701
+ className
36702
+ }) => {
36703
+ const groups = /* @__PURE__ */ new Map();
36704
+ for (const unit of units) {
36705
+ const group = groups.get(unit.targetEntity);
36706
+ if (group) group.push(unit);
36707
+ else groups.set(unit.targetEntity, [unit]);
36708
+ }
36709
+ const renderUnit = (unit, childrenByParent, depth) => {
36710
+ const summary = fieldSummary(unit);
36711
+ const children = childrenByParent.get(unit.ref) ?? [];
36712
+ return /* @__PURE__ */ jsxRuntime.jsxs(React84__namespace.default.Fragment, { children: [
36713
+ /* @__PURE__ */ jsxRuntime.jsxs(
36714
+ Box,
36715
+ {
36716
+ className: "flex flex-col py-1",
36717
+ style: { paddingLeft: depth * indent },
36718
+ "data-testid": `import-preview-unit-${unit.ref}`,
36719
+ children: [
36720
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
36721
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: "file-text", size: "xs", className: "text-muted-foreground" }),
36722
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", children: unitTitle(unit) })
36723
+ ] }),
36724
+ summary ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: summary }) : null
36725
+ ]
36726
+ }
36727
+ ),
36728
+ children.map((child) => renderUnit(child, childrenByParent, depth + 1))
36729
+ ] }, unit.ref);
36730
+ };
36731
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("flex flex-col gap-4", className), children: [
36732
+ units.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: "No units staged." }) : null,
36733
+ Array.from(groups.entries()).map(([entity, groupUnits]) => {
36734
+ const refs = new Set(groupUnits.map((unit) => unit.ref));
36735
+ const childrenByParent = /* @__PURE__ */ new Map();
36736
+ const roots = [];
36737
+ for (const unit of groupUnits) {
36738
+ if (unit.parentRef && refs.has(unit.parentRef)) {
36739
+ const siblings = childrenByParent.get(unit.parentRef);
36740
+ if (siblings) siblings.push(unit);
36741
+ else childrenByParent.set(unit.parentRef, [unit]);
36742
+ } else {
36743
+ roots.push(unit);
36744
+ }
36745
+ }
36746
+ const label = entityDisplay[entity]?.plural ?? entity;
36747
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { border: true, className: "rounded-md border-border bg-card p-3", children: [
36748
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2 pb-2", children: [
36749
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "label", children: label }),
36750
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { amount: groupUnits.length })
36751
+ ] }),
36752
+ roots.map((unit) => renderUnit(unit, childrenByParent, 0))
36753
+ ] }, entity);
36754
+ }),
36755
+ skipped.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(Box, { border: true, className: "rounded-md border-border bg-card p-3", children: [
36756
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2 pb-2", children: [
36757
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "label", children: "Skipped" }),
36758
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { amount: skipped.length })
36759
+ ] }),
36760
+ skipped.map((element) => /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-baseline gap-2 py-1", children: [
36761
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", children: element.ref }),
36762
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: element.reason })
36763
+ ] }, element.ref))
36764
+ ] }) : null,
36765
+ onConfirm || onCancel ? /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center justify-end gap-2", children: [
36766
+ onCancel ? /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "default", label: cancelLabel, onClick: onCancel }) : null,
36767
+ onConfirm ? /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", label: confirmLabel, onClick: onConfirm }) : null
36768
+ ] }) : null
36769
+ ] });
36770
+ };
36771
+ }
36772
+ });
36773
+ var PIPELINE, DEFAULT_LABELS, ImportProgress;
36774
+ var init_ImportProgress = __esm({
36775
+ "components/core/molecules/import/ImportProgress.tsx"() {
36776
+ "use client";
36777
+ init_Box();
36778
+ init_Badge();
36779
+ init_Icon();
36780
+ init_Typography();
36781
+ init_cn();
36782
+ PIPELINE = [
36783
+ "fetching",
36784
+ "mapping",
36785
+ "reviewing",
36786
+ "committing"
36787
+ ];
36788
+ DEFAULT_LABELS = {
36789
+ fetching: "Fetching",
36790
+ mapping: "Mapping",
36791
+ reviewing: "Reviewing",
36792
+ committing: "Committing",
36793
+ done: "Done",
36794
+ failed: "Failed"
36795
+ };
36796
+ ImportProgress = ({
36797
+ step,
36798
+ counts,
36799
+ labels,
36800
+ className
36801
+ }) => {
36802
+ const label = (key) => labels?.[key] ?? DEFAULT_LABELS[key];
36803
+ const currentIndex = step === "done" || step === "failed" ? PIPELINE.length : PIPELINE.indexOf(step);
36804
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("flex flex-col gap-3", className), children: [
36805
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
36806
+ PIPELINE.map((key, index) => {
36807
+ const isComplete = index < currentIndex;
36808
+ const isActive = index === currentIndex;
36809
+ return /* @__PURE__ */ jsxRuntime.jsxs(React84__namespace.default.Fragment, { children: [
36810
+ index > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "h-px w-4 bg-border" }) : null,
36811
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-1", "data-testid": `import-progress-step-${key}`, children: [
36812
+ /* @__PURE__ */ jsxRuntime.jsx(
36813
+ Icon,
36814
+ {
36815
+ icon: isComplete ? "check" : isActive ? "loader" : "circle",
36816
+ size: "sm",
36817
+ className: cn(
36818
+ isComplete ? "text-success" : isActive ? "text-primary" : "text-muted-foreground"
36819
+ )
36820
+ }
36821
+ ),
36822
+ /* @__PURE__ */ jsxRuntime.jsx(
36823
+ Typography,
36824
+ {
36825
+ variant: "caption",
36826
+ className: cn(isActive ? "text-foreground" : "text-muted-foreground"),
36827
+ children: label(key)
36828
+ }
36829
+ )
36830
+ ] })
36831
+ ] }, key);
36832
+ }),
36833
+ step === "done" || step === "failed" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
36834
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "h-px w-4 bg-border" }),
36835
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-1", "data-testid": `import-progress-step-${step}`, children: [
36836
+ /* @__PURE__ */ jsxRuntime.jsx(
36837
+ Icon,
36838
+ {
36839
+ icon: step === "done" ? "check" : "x",
36840
+ size: "sm",
36841
+ className: step === "done" ? "text-success" : "text-error"
36842
+ }
36843
+ ),
36844
+ /* @__PURE__ */ jsxRuntime.jsx(
36845
+ Typography,
36846
+ {
36847
+ variant: "caption",
36848
+ className: step === "done" ? "text-success" : "text-error",
36849
+ children: label(step)
36850
+ }
36851
+ )
36852
+ ] })
36853
+ ] }) : null
36854
+ ] }),
36855
+ counts ? /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
36856
+ counts.staged !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { label: `Staged ${counts.staged}` }) : null,
36857
+ counts.committed !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "success", label: `Committed ${counts.committed}` }) : null,
36858
+ counts.failed !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "danger", label: `Failed ${counts.failed}` }) : null
36859
+ ] }) : null
36860
+ ] });
36861
+ };
36862
+ }
36863
+ });
36864
+
36865
+ // components/core/molecules/import/index.ts
36866
+ var init_import = __esm({
36867
+ "components/core/molecules/import/index.ts"() {
36868
+ }
36869
+ });
36586
36870
  var ReflectionBlock;
36587
36871
  var init_ReflectionBlock = __esm({
36588
36872
  "components/core/molecules/ReflectionBlock.tsx"() {
@@ -36657,6 +36941,7 @@ var init_molecules2 = __esm({
36657
36941
  init_EmptyState();
36658
36942
  init_Pagination();
36659
36943
  init_molecules();
36944
+ init_import();
36660
36945
  }
36661
36946
  });
36662
36947
 
@@ -37137,7 +37422,7 @@ function getBadgeVariant(fieldName, value) {
37137
37422
  function formatFieldLabel(fieldName) {
37138
37423
  return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase());
37139
37424
  }
37140
- function formatFieldValue(value, fieldName) {
37425
+ function formatFieldValue2(value, fieldName) {
37141
37426
  if (typeof value === "number") {
37142
37427
  if (fieldName.toLowerCase().includes("progress") || fieldName.toLowerCase().includes("percent")) {
37143
37428
  return `${value}%`;
@@ -37232,7 +37517,7 @@ function renderRichFieldValue(value, fieldName, fieldType) {
37232
37517
  return str;
37233
37518
  }
37234
37519
  default:
37235
- return formatFieldValue(value, fieldName);
37520
+ return formatFieldValue2(value, fieldName);
37236
37521
  }
37237
37522
  }
37238
37523
  function normalizeFieldDefs(fields) {
@@ -37343,7 +37628,7 @@ var init_DetailPanel = __esm({
37343
37628
  const value = getNestedValue(normalizedData, field);
37344
37629
  return {
37345
37630
  label: labelFor(field),
37346
- value: formatFieldValue(value, field),
37631
+ value: formatFieldValue2(value, field),
37347
37632
  icon: getFieldIcon(field)
37348
37633
  };
37349
37634
  }
@@ -43355,6 +43640,9 @@ var init_component_registry_generated = __esm({
43355
43640
  init_HeroOrganism();
43356
43641
  init_HeroSection();
43357
43642
  init_Icon();
43643
+ init_ImportPreviewTree();
43644
+ init_ImportProgress();
43645
+ init_ImportSourcePicker();
43358
43646
  init_InfiniteScrollSentinel();
43359
43647
  init_Input();
43360
43648
  init_InputGroup();
@@ -43618,6 +43906,9 @@ var init_component_registry_generated = __esm({
43618
43906
  "HeroOrganism": HeroOrganism,
43619
43907
  "HeroSection": HeroSection,
43620
43908
  "Icon": Icon,
43909
+ "ImportPreviewTree": ImportPreviewTree,
43910
+ "ImportProgress": ImportProgress,
43911
+ "ImportSourcePicker": ImportSourcePicker,
43621
43912
  "InfiniteScrollSentinel": InfiniteScrollSentinel,
43622
43913
  "Input": Input,
43623
43914
  "InputGroup": InputGroup,
@@ -45154,6 +45445,96 @@ function VerificationProvider({
45154
45445
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
45155
45446
  }
45156
45447
  VerificationProvider.displayName = "VerificationProvider";
45448
+ var UserContext = React84.createContext(null);
45449
+ function UserProvider({
45450
+ user = null,
45451
+ children
45452
+ }) {
45453
+ const hasRole = React84.useCallback(
45454
+ (role) => {
45455
+ if (!user) return role === "anonymous";
45456
+ return user.role === role;
45457
+ },
45458
+ [user]
45459
+ );
45460
+ const hasPermission = React84.useCallback(
45461
+ (permission) => {
45462
+ if (!user) return false;
45463
+ return user.permissions?.includes(permission) ?? false;
45464
+ },
45465
+ [user]
45466
+ );
45467
+ const hasAnyRole = React84.useCallback(
45468
+ (roles) => {
45469
+ if (!user) return roles.includes("anonymous");
45470
+ return user.role ? roles.includes(user.role) : false;
45471
+ },
45472
+ [user]
45473
+ );
45474
+ const hasAllPermissions = React84.useCallback(
45475
+ (permissions) => {
45476
+ if (!user || !user.permissions) return false;
45477
+ return permissions.every((p) => user.permissions?.includes(p));
45478
+ },
45479
+ [user]
45480
+ );
45481
+ const getUserField = React84.useCallback(
45482
+ (path) => {
45483
+ const viewer = user ?? core.ANONYMOUS_USER;
45484
+ const [first, ...rest] = path.split(".");
45485
+ if (!first) return void 0;
45486
+ let value = viewer[first];
45487
+ for (const segment of rest) {
45488
+ if (value === null || typeof value !== "object" || Array.isArray(value) || value instanceof Date) {
45489
+ return void 0;
45490
+ }
45491
+ value = value[segment];
45492
+ }
45493
+ return value;
45494
+ },
45495
+ [user]
45496
+ );
45497
+ const contextValue = React84.useMemo(
45498
+ () => ({
45499
+ user,
45500
+ isLoggedIn: user !== null,
45501
+ hasRole,
45502
+ hasPermission,
45503
+ hasAnyRole,
45504
+ hasAllPermissions,
45505
+ getUserField
45506
+ }),
45507
+ [user, hasRole, hasPermission, hasAnyRole, hasAllPermissions, getUserField]
45508
+ );
45509
+ return /* @__PURE__ */ jsxRuntime.jsx(UserContext.Provider, { value: contextValue, children });
45510
+ }
45511
+ function useUser() {
45512
+ const context = React84.useContext(UserContext);
45513
+ if (!context) {
45514
+ return {
45515
+ user: null,
45516
+ isLoggedIn: false,
45517
+ hasRole: (role) => role === "anonymous",
45518
+ hasPermission: () => false,
45519
+ hasAnyRole: (roles) => roles.includes("anonymous"),
45520
+ hasAllPermissions: () => false,
45521
+ getUserField: () => void 0
45522
+ };
45523
+ }
45524
+ return context;
45525
+ }
45526
+ function useHasRole(role) {
45527
+ const { hasRole } = useUser();
45528
+ return hasRole(role);
45529
+ }
45530
+ function useHasPermission(permission) {
45531
+ const { hasPermission } = useUser();
45532
+ return hasPermission(permission);
45533
+ }
45534
+ function useUserForEvaluation() {
45535
+ const { user, isLoggedIn } = useUser();
45536
+ return isLoggedIn && user ? user : void 0;
45537
+ }
45157
45538
  function OrbitalProvider({
45158
45539
  children,
45159
45540
  themes,
@@ -45165,13 +45546,14 @@ function OrbitalProvider({
45165
45546
  initialData,
45166
45547
  suspense = false,
45167
45548
  verification,
45168
- isolated = false
45549
+ isolated = false,
45550
+ user = null
45169
45551
  }) {
45170
45552
  const suspenseConfig = React84.useMemo(
45171
45553
  () => ({ enabled: suspense }),
45172
45554
  [suspense]
45173
45555
  );
45174
- const inner = /* @__PURE__ */ jsxRuntime.jsx(EventBusProvider, { debug: debug2, isolated, children: /* @__PURE__ */ jsxRuntime.jsx(VerificationProvider, { enabled: verification, children: /* @__PURE__ */ jsxRuntime.jsx(SelectionProvider, { debug: debug2, children: /* @__PURE__ */ jsxRuntime.jsx(SuspenseConfigProvider, { config: suspenseConfig, children }) }) }) });
45556
+ const inner = /* @__PURE__ */ jsxRuntime.jsx(EventBusProvider, { debug: debug2, isolated, children: /* @__PURE__ */ jsxRuntime.jsx(VerificationProvider, { enabled: verification, children: /* @__PURE__ */ jsxRuntime.jsx(UserProvider, { user, children: /* @__PURE__ */ jsxRuntime.jsx(SelectionProvider, { debug: debug2, children: /* @__PURE__ */ jsxRuntime.jsx(SuspenseConfigProvider, { config: suspenseConfig, children }) }) }) }) });
45175
45557
  if (skipTheme) {
45176
45558
  return inner;
45177
45559
  }
@@ -45427,104 +45809,6 @@ var CurrentPagePathProvider = ({
45427
45809
  }) => /* @__PURE__ */ jsxRuntime.jsx(CurrentPagePathContext.Provider, { value, children });
45428
45810
  CurrentPagePathProvider.displayName = "CurrentPagePathProvider";
45429
45811
  var useCurrentPagePath2 = () => React84.useContext(CurrentPagePathContext);
45430
- var ANONYMOUS_USER = {
45431
- id: "anonymous",
45432
- role: "anonymous",
45433
- permissions: []
45434
- };
45435
- var UserContext = React84.createContext(null);
45436
- function UserProvider({
45437
- user = null,
45438
- children
45439
- }) {
45440
- const hasRole = React84.useCallback(
45441
- (role) => {
45442
- if (!user) return role === "anonymous";
45443
- return user.role === role;
45444
- },
45445
- [user]
45446
- );
45447
- const hasPermission = React84.useCallback(
45448
- (permission) => {
45449
- if (!user) return false;
45450
- return user.permissions?.includes(permission) ?? false;
45451
- },
45452
- [user]
45453
- );
45454
- const hasAnyRole = React84.useCallback(
45455
- (roles) => {
45456
- if (!user) return roles.includes("anonymous");
45457
- return user.role ? roles.includes(user.role) : false;
45458
- },
45459
- [user]
45460
- );
45461
- const hasAllPermissions = React84.useCallback(
45462
- (permissions) => {
45463
- if (!user || !user.permissions) return false;
45464
- return permissions.every((p) => user.permissions?.includes(p));
45465
- },
45466
- [user]
45467
- );
45468
- const getUserField = React84.useCallback(
45469
- (path) => {
45470
- const userData = user ?? ANONYMOUS_USER;
45471
- const parts = path.split(".");
45472
- let value = userData;
45473
- for (const segment of parts) {
45474
- if (value === null || value === void 0) {
45475
- return void 0;
45476
- }
45477
- if (typeof value === "object") {
45478
- value = value[segment];
45479
- } else {
45480
- return void 0;
45481
- }
45482
- }
45483
- return value;
45484
- },
45485
- [user]
45486
- );
45487
- const contextValue = React84.useMemo(
45488
- () => ({
45489
- user,
45490
- isLoggedIn: user !== null,
45491
- hasRole,
45492
- hasPermission,
45493
- hasAnyRole,
45494
- hasAllPermissions,
45495
- getUserField
45496
- }),
45497
- [user, hasRole, hasPermission, hasAnyRole, hasAllPermissions, getUserField]
45498
- );
45499
- return /* @__PURE__ */ jsxRuntime.jsx(UserContext.Provider, { value: contextValue, children });
45500
- }
45501
- function useUser() {
45502
- const context = React84.useContext(UserContext);
45503
- if (!context) {
45504
- return {
45505
- user: null,
45506
- isLoggedIn: false,
45507
- hasRole: (role) => role === "anonymous",
45508
- hasPermission: () => false,
45509
- hasAnyRole: (roles) => roles.includes("anonymous"),
45510
- hasAllPermissions: () => false,
45511
- getUserField: () => void 0
45512
- };
45513
- }
45514
- return context;
45515
- }
45516
- function useHasRole(role) {
45517
- const { hasRole } = useUser();
45518
- return hasRole(role);
45519
- }
45520
- function useHasPermission(permission) {
45521
- const { hasPermission } = useUser();
45522
- return hasPermission(permission);
45523
- }
45524
- function useUserForEvaluation() {
45525
- const { user, isLoggedIn } = useUser();
45526
- return isLoggedIn && user ? user : void 0;
45527
- }
45528
45812
  var EntitySchemaContext = React84.createContext(null);
45529
45813
  function EntitySchemaProvider({
45530
45814
  entities,
@@ -46248,7 +46532,10 @@ Object.defineProperty(exports, "useDesignTheme", {
46248
46532
  enumerable: true,
46249
46533
  get: function () { return context.useDesignTheme; }
46250
46534
  });
46251
- exports.ANONYMOUS_USER = ANONYMOUS_USER;
46535
+ Object.defineProperty(exports, "ANONYMOUS_USER", {
46536
+ enumerable: true,
46537
+ get: function () { return core.ANONYMOUS_USER; }
46538
+ });
46252
46539
  exports.CurrentPagePathContext = CurrentPagePathContext;
46253
46540
  exports.CurrentPagePathProvider = CurrentPagePathProvider;
46254
46541
  exports.EntitySchemaProvider = EntitySchemaProvider;
@@ -1,7 +1,8 @@
1
1
  import React__default, { ReactNode } from 'react';
2
2
  import { EntityRow, FieldValue } from '@almadar/core';
3
- import { U as UIThemeDefinition } from '../UserContext-BKckAUv7.cjs';
4
- export { A as ANONYMOUS_USER, a as CurrentPagePathContext, b as CurrentPagePathProvider, c as CurrentPagePathProviderProps, d as DesignThemeProvider, O as OrbitalThemeProvider, e as OrbitalThemeProviderProps, h as UserContext, i as UserContextValue, j as UserData, k as UserProvider, l as UserProviderProps, u as useCurrentPagePath, m as useDesignTheme, n as useHasPermission, o as useHasRole, q as useUser, r as useUserForEvaluation } from '../UserContext-BKckAUv7.cjs';
3
+ export { ANONYMOUS_USER } from '@almadar/core';
4
+ import { U as UIThemeDefinition, j as UserData } from '../UserContext-g_LcDiGN.cjs';
5
+ export { a as CurrentPagePathContext, b as CurrentPagePathProvider, c as CurrentPagePathProviderProps, d as DesignThemeProvider, O as OrbitalThemeProvider, e as OrbitalThemeProviderProps, h as UserContext, i as UserContextValue, k as UserProvider, l as UserProviderProps, u as useCurrentPagePath, m as useDesignTheme, n as useHasPermission, o as useHasRole, q as useUser, r as useUserForEvaluation } from '../UserContext-g_LcDiGN.cjs';
5
6
  export { E as EntitySchemaContextValue, a as EntitySchemaProvider, b as EntitySchemaProviderProps, S as SendEventResult, c as ServerBridgeContextValue, d as ServerBridgeProvider, e as ServerBridgeProviderProps, f as ServerBridgeTransport, g as ServerClientEffect, h as ServerResponseMeta, T as TraitContext, i as TraitContextValue, j as TraitInstance, k as TraitProvider, l as TraitProviderProps, u as useEntitySchema, m as useEntitySchemaOptional, n as useServerBridge, o as useTrait, p as useTraitContext } from '../TraitProvider-Ch79cUcb.cjs';
6
7
  import { U as UseOfflineExecutorResult, a as UseOfflineExecutorOptions } from '../offline-executor-Qz4b6GpF.cjs';
7
8
  export { N as NavigationContextValue, b as NavigationProvider, c as NavigationProviderProps, d as NavigationState, e as comparePathSpecificity, f as extractRouteParams, g as findPageByName, h as findPageByPath, i as getAllPages, j as getDefaultPage, m as matchPath, k as matchPathAmong, p as pathMatches, u as useActivePage, l as useInitPayload, n as useNavigateTo, o as useNavigation, q as useNavigationId, r as useNavigationState } from '../offline-executor-Qz4b6GpF.cjs';
@@ -145,6 +146,7 @@ declare function useSelectionOptional<T = EntityRow>(): SelectionContextType<T>
145
146
  * - ThemeProvider - Theme and color mode management
146
147
  * - EventBusProvider - Page-scoped event pub/sub
147
148
  * - SelectionProvider - Selected entity tracking
149
+ * - UserProvider - the viewer `@user.x` bindings resolve against
148
150
  *
149
151
  * Entity data flows through props (via enrichFromResponse in ServerBridge),
150
152
  * not through context. FetchedDataProvider has been removed.
@@ -188,6 +190,15 @@ interface OrbitalProviderProps {
188
190
  * preview's events don't clobber the host's global bus). Default false.
189
191
  */
190
192
  isolated?: boolean;
193
+ /**
194
+ * The signed-in viewer. Generated trait hooks read `@user.x` through
195
+ * `useUser()`, so without this every role gate takes its negative branch and
196
+ * every ownership-scoped list renders empty — silently, since `useUser()`
197
+ * falls back to anonymous rather than throwing
198
+ * (U-USERPROVIDER-MOUNTED-NOWHERE). Mounting the provider here means every
199
+ * host that already wraps its app in OrbitalProvider only has to pass the user.
200
+ */
201
+ user?: UserData | null;
191
202
  }
192
203
  /**
193
204
  * OrbitalProvider - Unified context provider for Orbital applications
@@ -236,7 +247,7 @@ interface OrbitalProviderProps {
236
247
  * }
237
248
  * ```
238
249
  */
239
- declare function OrbitalProvider({ children, themes, defaultTheme, defaultMode, targetRef, skipTheme, debug, initialData, suspense, verification, isolated, }: OrbitalProviderProps): React__default.ReactElement;
250
+ declare function OrbitalProvider({ children, themes, defaultTheme, defaultMode, targetRef, skipTheme, debug, initialData, suspense, verification, isolated, user, }: OrbitalProviderProps): React__default.ReactElement;
240
251
  declare namespace OrbitalProvider {
241
252
  var displayName: string;
242
253
  }
@@ -454,4 +465,4 @@ declare function useOfflineMode(): OfflineModeContextValue;
454
465
  */
455
466
  declare function useOptionalOfflineMode(): OfflineModeContextValue | null;
456
467
 
457
- export { EventBusContext, EventBusProvider, type OfflineModeContextValue, OfflineModeProvider, type OfflineModeProviderProps, OrbitalProvider, type OrbitalProviderProps, SelectionContext, type SelectionContextType, SelectionProvider, type TraitScope, TraitScopeProvider, type TraitScopeProviderProps, UIThemeDefinition, VerificationProvider, type VerificationProviderProps, useOfflineMode, useOptionalOfflineMode, useSelection, useSelectionOptional, useTraitScope, useTraitScopeChain };
468
+ export { EventBusContext, EventBusProvider, type OfflineModeContextValue, OfflineModeProvider, type OfflineModeProviderProps, OrbitalProvider, type OrbitalProviderProps, SelectionContext, type SelectionContextType, SelectionProvider, type TraitScope, TraitScopeProvider, type TraitScopeProviderProps, UIThemeDefinition, UserData, VerificationProvider, type VerificationProviderProps, useOfflineMode, useOptionalOfflineMode, useSelection, useSelectionOptional, useTraitScope, useTraitScopeChain };