@psnext/design-system 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/DESIGN.md +2 -2
  2. package/dist/Header.cjs +63 -88
  3. package/dist/Header.cjs.map +1 -1
  4. package/dist/Header.js +64 -89
  5. package/dist/Header.js.map +1 -1
  6. package/dist/index.d.cts +5 -5
  7. package/dist/index.d.ts +5 -5
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index10.d.cts +6 -6
  10. package/dist/index10.d.ts +7 -7
  11. package/dist/index10.d.ts.map +1 -1
  12. package/dist/index11.d.cts +3 -3
  13. package/dist/index11.d.ts +3 -3
  14. package/dist/index11.d.ts.map +1 -1
  15. package/dist/index12.d.cts +12 -12
  16. package/dist/index12.d.cts.map +1 -1
  17. package/dist/index12.d.ts +12 -12
  18. package/dist/index12.d.ts.map +1 -1
  19. package/dist/index13.d.cts +6 -6
  20. package/dist/index13.d.ts +6 -6
  21. package/dist/index14.d.cts +5 -5
  22. package/dist/index14.d.cts.map +1 -1
  23. package/dist/index14.d.ts +5 -5
  24. package/dist/index15.d.cts +3 -3
  25. package/dist/index15.d.cts.map +1 -1
  26. package/dist/index15.d.ts +3 -3
  27. package/dist/index16.d.cts +2 -2
  28. package/dist/index16.d.cts.map +1 -1
  29. package/dist/index16.d.ts +2 -2
  30. package/dist/index17.d.cts +4 -4
  31. package/dist/index17.d.cts.map +1 -1
  32. package/dist/index17.d.ts +4 -4
  33. package/dist/index18.d.cts +11 -11
  34. package/dist/index18.d.cts.map +1 -1
  35. package/dist/index18.d.ts +11 -11
  36. package/dist/index19.d.cts +10 -10
  37. package/dist/index19.d.ts +10 -10
  38. package/dist/index2.d.cts +8 -8
  39. package/dist/index2.d.ts +8 -8
  40. package/dist/index2.d.ts.map +1 -1
  41. package/dist/index20.d.cts +16 -16
  42. package/dist/index20.d.ts +16 -16
  43. package/dist/index21.d.cts +4 -4
  44. package/dist/index21.d.ts +4 -4
  45. package/dist/index22.d.cts +11 -11
  46. package/dist/index22.d.ts +11 -11
  47. package/dist/index23.d.cts +16 -16
  48. package/dist/index23.d.ts +16 -16
  49. package/dist/index24.d.cts +10 -10
  50. package/dist/index24.d.cts.map +1 -1
  51. package/dist/index24.d.ts +10 -10
  52. package/dist/index25.d.cts +2 -2
  53. package/dist/index25.d.cts.map +1 -1
  54. package/dist/index25.d.ts +2 -2
  55. package/dist/index26.d.cts +13 -13
  56. package/dist/index26.d.cts.map +1 -1
  57. package/dist/index26.d.ts +14 -14
  58. package/dist/index26.d.ts.map +1 -1
  59. package/dist/index27.d.cts +7 -7
  60. package/dist/index27.d.ts +7 -7
  61. package/dist/index28.d.cts +6 -6
  62. package/dist/index28.d.cts.map +1 -1
  63. package/dist/index28.d.ts +5 -5
  64. package/dist/index29.d.cts +4 -4
  65. package/dist/index29.d.cts.map +1 -1
  66. package/dist/index29.d.ts +4 -4
  67. package/dist/index3.d.cts +13 -13
  68. package/dist/index3.d.cts.map +1 -1
  69. package/dist/index3.d.ts +13 -13
  70. package/dist/index30.d.cts +6 -6
  71. package/dist/index30.d.cts.map +1 -1
  72. package/dist/index30.d.ts +6 -6
  73. package/dist/index31.d.cts +4 -4
  74. package/dist/index31.d.ts +5 -5
  75. package/dist/index32.d.cts +6 -6
  76. package/dist/index32.d.cts.map +1 -1
  77. package/dist/index32.d.ts +5 -5
  78. package/dist/index33.d.cts +11 -11
  79. package/dist/index33.d.ts +11 -11
  80. package/dist/index34.d.cts +5 -5
  81. package/dist/index34.d.cts.map +1 -1
  82. package/dist/index34.d.ts +5 -5
  83. package/dist/index35.d.cts +15 -15
  84. package/dist/index35.d.cts.map +1 -1
  85. package/dist/index35.d.ts +15 -15
  86. package/dist/index35.d.ts.map +1 -1
  87. package/dist/index36.d.cts +3 -3
  88. package/dist/index36.d.cts.map +1 -1
  89. package/dist/index36.d.ts +3 -3
  90. package/dist/index37.d.cts +4 -4
  91. package/dist/index37.d.ts +5 -5
  92. package/dist/index38.d.cts +2 -2
  93. package/dist/index38.d.cts.map +1 -1
  94. package/dist/index38.d.ts +2 -2
  95. package/dist/index39.d.cts +17 -17
  96. package/dist/index39.d.cts.map +1 -1
  97. package/dist/index39.d.ts +17 -17
  98. package/dist/index4.d.cts +2 -2
  99. package/dist/index4.d.ts +2 -2
  100. package/dist/index4.d.ts.map +1 -1
  101. package/dist/index40.d.cts +5 -5
  102. package/dist/index40.d.cts.map +1 -1
  103. package/dist/index40.d.ts +5 -5
  104. package/dist/index41.d.cts +11 -11
  105. package/dist/index41.d.cts.map +1 -1
  106. package/dist/index41.d.ts +11 -11
  107. package/dist/index41.d.ts.map +1 -1
  108. package/dist/index42.d.cts +8 -8
  109. package/dist/index42.d.ts +8 -8
  110. package/dist/index42.d.ts.map +1 -1
  111. package/dist/index43.d.cts +9 -9
  112. package/dist/index43.d.ts +9 -9
  113. package/dist/index43.d.ts.map +1 -1
  114. package/dist/index45.d.cts +8 -8
  115. package/dist/index45.d.ts +8 -8
  116. package/dist/index45.d.ts.map +1 -1
  117. package/dist/index46.d.cts +2 -2
  118. package/dist/index46.d.ts +2 -2
  119. package/dist/index47.d.ts +4 -4
  120. package/dist/index48.d.cts +4 -4
  121. package/dist/index48.d.cts.map +1 -1
  122. package/dist/index48.d.ts +4 -4
  123. package/dist/index49.d.cts +3 -3
  124. package/dist/index49.d.ts +3 -3
  125. package/dist/index5.d.cts +7 -7
  126. package/dist/index5.d.ts +7 -7
  127. package/dist/index5.d.ts.map +1 -1
  128. package/dist/index50.d.cts +11 -11
  129. package/dist/index50.d.cts.map +1 -1
  130. package/dist/index50.d.ts +11 -11
  131. package/dist/index51.d.cts +9 -9
  132. package/dist/index51.d.ts +9 -9
  133. package/dist/index52.d.cts +5 -5
  134. package/dist/index52.d.ts +5 -5
  135. package/dist/index53.d.cts +27 -27
  136. package/dist/index53.d.cts.map +1 -1
  137. package/dist/index53.d.ts +27 -27
  138. package/dist/index53.d.ts.map +1 -1
  139. package/dist/index54.d.cts +5 -5
  140. package/dist/index54.d.ts +5 -5
  141. package/dist/index55.d.cts +2 -2
  142. package/dist/index55.d.ts +2 -2
  143. package/dist/index55.d.ts.map +1 -1
  144. package/dist/index56.d.cts +2 -2
  145. package/dist/index56.d.ts +2 -2
  146. package/dist/index57.d.cts +2 -2
  147. package/dist/index57.d.cts.map +1 -1
  148. package/dist/index57.d.ts +2 -2
  149. package/dist/index58.d.cts +4 -4
  150. package/dist/index58.d.cts.map +1 -1
  151. package/dist/index58.d.ts +4 -4
  152. package/dist/index59.d.cts +9 -9
  153. package/dist/index59.d.ts +9 -9
  154. package/dist/index59.d.ts.map +1 -1
  155. package/dist/index6.d.cts +6 -6
  156. package/dist/index6.d.ts +5 -5
  157. package/dist/index6.d.ts.map +1 -1
  158. package/dist/index60.d.cts +9 -9
  159. package/dist/index60.d.cts.map +1 -1
  160. package/dist/index60.d.ts +13 -13
  161. package/dist/index60.d.ts.map +1 -1
  162. package/dist/index61.d.cts +8 -8
  163. package/dist/index61.d.cts.map +1 -1
  164. package/dist/index61.d.ts +7 -7
  165. package/dist/index61.d.ts.map +1 -1
  166. package/dist/index62.d.cts +5 -5
  167. package/dist/index62.d.cts.map +1 -1
  168. package/dist/index62.d.ts +4 -4
  169. package/dist/index62.d.ts.map +1 -1
  170. package/dist/index63.d.cts +2 -2
  171. package/dist/index63.d.cts.map +1 -1
  172. package/dist/index63.d.ts +2 -2
  173. package/dist/index63.d.ts.map +1 -1
  174. package/dist/index64.d.cts +6 -6
  175. package/dist/index64.d.cts.map +1 -1
  176. package/dist/index64.d.ts +6 -6
  177. package/dist/index64.d.ts.map +1 -1
  178. package/dist/index65.d.cts +3 -3
  179. package/dist/index65.d.ts +3 -3
  180. package/dist/index65.d.ts.map +1 -1
  181. package/dist/index66.d.cts +4 -4
  182. package/dist/index66.d.cts.map +1 -1
  183. package/dist/index66.d.ts +5 -5
  184. package/dist/index66.d.ts.map +1 -1
  185. package/dist/index67.d.cts +2 -2
  186. package/dist/index67.d.ts +2 -2
  187. package/dist/index67.d.ts.map +1 -1
  188. package/dist/index68.d.cts +7 -7
  189. package/dist/index68.d.cts.map +1 -1
  190. package/dist/index68.d.ts +8 -8
  191. package/dist/index68.d.ts.map +1 -1
  192. package/dist/index69.d.cts +7 -7
  193. package/dist/index69.d.ts +7 -7
  194. package/dist/index69.d.ts.map +1 -1
  195. package/dist/index7.d.cts +8 -8
  196. package/dist/index7.d.ts +8 -8
  197. package/dist/index7.d.ts.map +1 -1
  198. package/dist/index71.d.cts +19 -17
  199. package/dist/index71.d.cts.map +1 -1
  200. package/dist/index71.d.ts +19 -17
  201. package/dist/index71.d.ts.map +1 -1
  202. package/dist/index8.d.cts +5 -5
  203. package/dist/index8.d.cts.map +1 -1
  204. package/dist/index8.d.ts +4 -4
  205. package/dist/index8.d.ts.map +1 -1
  206. package/dist/index9.d.cts +2 -2
  207. package/dist/index9.d.ts +2 -2
  208. package/dist/index9.d.ts.map +1 -1
  209. package/dist/patterns/DataTable/index.d.cts +3 -3
  210. package/dist/patterns/DataTable/index.d.cts.map +1 -1
  211. package/dist/patterns/DataTable/index.d.ts +3 -3
  212. package/dist/patterns/DataTable/index.d.ts.map +1 -1
  213. package/dist/patterns/Footer/index.d.cts +7 -7
  214. package/dist/patterns/Footer/index.d.ts +7 -7
  215. package/dist/patterns/Footer/index.d.ts.map +1 -1
  216. package/dist/patterns/MediaObject/index.d.cts +11 -11
  217. package/dist/patterns/MediaObject/index.d.ts +13 -13
  218. package/dist/patterns/SectionCard/index.d.cts +2 -2
  219. package/dist/patterns/SectionCard/index.d.ts +2 -2
  220. package/dist/patterns/SectionCard/index.d.ts.map +1 -1
  221. package/dist/patterns/SectionHeading/index.d.cts +2 -2
  222. package/dist/patterns/SectionHeading/index.d.ts +2 -2
  223. package/dist/patterns/SectionHeading/index.d.ts.map +1 -1
  224. package/package.json +1 -1
package/dist/Header.js CHANGED
@@ -9,7 +9,7 @@ import { Popover, PopoverContent, PopoverTrigger } from "./primitives/Popover/in
9
9
  import { Skeleton } from "./primitives/Skeleton/index.js";
10
10
  import { useTheme } from "./primitives/ThemeProvider/index.js";
11
11
  import * as React from "react";
12
- import { Check, ChevronDown, ChevronRight, FolderOpen, LogOut, MessageSquareShare, Moon, Search, Sun, X } from "lucide-react";
12
+ import { Check, ChevronDown, ChevronRight, LogOut, MessageSquareShare, Moon, Search, Sun } from "lucide-react";
13
13
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
14
14
  import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
15
15
  //#region src/patterns/Header/project-tree.ts
@@ -25,6 +25,14 @@ function findProjectName(tree, id) {
25
25
  if (found) return found;
26
26
  }
27
27
  }
28
+ /** First selectable node in the tree (depth-first, skipping context-only ancestors). */
29
+ function firstSelectableProject(tree) {
30
+ for (const node of tree) {
31
+ if (!node.isContextOnly) return node;
32
+ const found = firstSelectableProject(node.children);
33
+ if (found) return found;
34
+ }
35
+ }
28
36
  /** Filter the tree to nodes matching `term`, preserving ancestors of matches. */
29
37
  function filterTree(nodes, term) {
30
38
  if (!term) return nodes;
@@ -176,16 +184,14 @@ const DEFAULT_LABELS = {
176
184
  searchPlaceholder: "Search project",
177
185
  emptyStateText: "No projects found",
178
186
  profileMenuLabel: "Profile menu",
179
- logoutLabel: "Logout",
180
- overlayTitle: "Select a Project",
181
- overlayDescription: "Choose a project to get started. You can change it anytime from the header."
187
+ logoutLabel: "Logout"
182
188
  };
183
189
  //#endregion
184
190
  //#region src/patterns/Header/api.ts
185
191
  const PATHS = {
186
192
  token: "/api/v1/studio-auth/sessions/token",
187
193
  logout: "/api/v1/studio-auth/sessions/logout",
188
- projects: (clientId) => `/api/v1/onboarding/organization/${clientId}/projects`,
194
+ projects: (clientId) => `/api/v1/client-projects/getAllProjects?limit=50&page=1&sort=name&sortOrder=ASC&clientId=${encodeURIComponent(clientId)}&metaData=true`,
189
195
  credits: "/save/api/v1/users"
190
196
  };
191
197
  /** Join a base URL and path without doubling slashes. */
@@ -239,6 +245,7 @@ async function callLogout(endpoints, fetcher) {
239
245
  //#endregion
240
246
  //#region src/patterns/Header/storage.ts
241
247
  const PROJECT_KEY = "ds-header-project";
248
+ const LAST_PROJECT_KEY = "lastSelectedProject";
242
249
  function getStoredProject() {
243
250
  try {
244
251
  const raw = sessionStorage.getItem(PROJECT_KEY);
@@ -257,6 +264,20 @@ function clearStoredProject() {
257
264
  sessionStorage.removeItem(PROJECT_KEY);
258
265
  } catch {}
259
266
  }
267
+ /** The project the user last explicitly selected, in any tab (localStorage). */
268
+ function getLastSelectedProject() {
269
+ try {
270
+ const raw = localStorage.getItem(LAST_PROJECT_KEY);
271
+ return raw ? JSON.parse(raw) : null;
272
+ } catch {
273
+ return null;
274
+ }
275
+ }
276
+ function setLastSelectedProject(project) {
277
+ try {
278
+ localStorage.setItem(LAST_PROJECT_KEY, JSON.stringify(project));
279
+ } catch {}
280
+ }
260
281
  //#endregion
261
282
  //#region src/patterns/Header/header-store.ts
262
283
  function initialState() {
@@ -292,14 +313,22 @@ const headerStore = {
292
313
  getServerSnapshot() {
293
314
  return SERVER_SNAPSHOT;
294
315
  },
295
- /** Set the selected project. `name` is best-effort; the Header backfills it from the tree. */
296
- setProject(id, name = "", clientId) {
297
- if (id) setStoredProject({
298
- id,
299
- name,
300
- clientId: clientId ?? state.clientId
301
- });
302
- else clearStoredProject();
316
+ /**
317
+ * Set the selected project. `name` is best-effort; the Header backfills it from
318
+ * the tree. Explicit selections are also remembered in localStorage as the
319
+ * cross-tab default; pass `remember: false` for internal backfill/auto-select
320
+ * writes so they don't overwrite the user's last explicit choice.
321
+ */
322
+ setProject(id, name = "", clientId, { remember = true } = {}) {
323
+ if (id) {
324
+ const project = {
325
+ id,
326
+ name,
327
+ clientId: clientId ?? state.clientId
328
+ };
329
+ setStoredProject(project);
330
+ if (remember) setLastSelectedProject(project);
331
+ } else clearStoredProject();
303
332
  state = {
304
333
  ...state,
305
334
  selectedProjectId: id,
@@ -484,6 +513,10 @@ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInje
484
513
  }
485
514
  }, [apiBaseUrl]);
486
515
  const selection = useHeaderStore();
516
+ const onProjectChangeRef = React.useRef(onProjectChange);
517
+ React.useEffect(() => {
518
+ onProjectChangeRef.current = onProjectChange;
519
+ });
487
520
  React.useEffect(() => {
488
521
  if (effectiveClientId) headerStore.reconcileClient(effectiveClientId);
489
522
  }, [effectiveClientId]);
@@ -491,10 +524,19 @@ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInje
491
524
  if (!projectsQuery.data) return;
492
525
  const tree = projectsQuery.data.projectsTree;
493
526
  const id = headerStore.getSnapshot().selectedProjectId;
494
- if (id && !nodeExistsInTree(tree, id)) headerStore.clearProject();
495
- else if (id) {
527
+ if (id && nodeExistsInTree(tree, id)) {
496
528
  const name = findProjectName(tree, id);
497
- if (name && name !== headerStore.getSnapshot().selectedProjectName) headerStore.setProject(id, name, effectiveClientId);
529
+ if (name && name !== headerStore.getSnapshot().selectedProjectName) headerStore.setProject(id, name, effectiveClientId, { remember: false });
530
+ } else {
531
+ const last = getLastSelectedProject();
532
+ const fallback = last && nodeExistsInTree(tree, last.id) ? {
533
+ id: last.id,
534
+ name: findProjectName(tree, last.id) ?? last.name
535
+ } : firstSelectableProject(tree);
536
+ if (fallback) {
537
+ headerStore.setProject(fallback.id, fallback.name, effectiveClientId, { remember: false });
538
+ onProjectChangeRef.current?.(fallback.id);
539
+ } else if (id) headerStore.clearProject();
498
540
  }
499
541
  headerStore.setOrganization(projectsQuery.data.organizationName, effectiveClientId);
500
542
  }, [projectsQuery.data, effectiveClientId]);
@@ -532,7 +574,6 @@ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInje
532
574
  credits: selection.credits,
533
575
  creditsHref,
534
576
  projectDropdownVisible,
535
- showOverlay: isAuthenticated && projectDropdownVisible && !selection.selectedProjectId,
536
577
  selectProject,
537
578
  logout
538
579
  };
@@ -644,7 +685,7 @@ function Header(props) {
644
685
  children: /* @__PURE__ */ jsx(HeaderInner, { ...props })
645
686
  });
646
687
  }
647
- function HeaderInner({ logoType, logoHref, showOrg = false, showProjectDropdown = false, showProfile = false, showThemeSwitcher = false, showCredits = false, pageTitle, feedbackUrl, logoAddon, className, onCloseProjectOverlay, ...rest }) {
688
+ function HeaderInner({ logoType, logoHref, showOrg = false, showProjectDropdown = false, showProfile = false, showThemeSwitcher = false, showCredits = false, pageTitle, feedbackUrl, logoAddon, actionsStart, actionsEnd, className, ...rest }) {
648
689
  const { product } = useTheme();
649
690
  const brand = logoType ?? product;
650
691
  const state = useGlobalHeader({
@@ -658,8 +699,8 @@ function HeaderInner({ logoType, logoHref, showOrg = false, showProjectDropdown
658
699
  const showOrgUi = showOrg && state.isAuthenticated;
659
700
  const showProfileUi = showProfile && state.isAuthenticated;
660
701
  const showCreditsUi = showCredits && state.isAuthenticated && state.credits !== void 0;
661
- const showActions = showThemeSwitcher || showProfileUi || showCreditsUi || !!feedbackUrl;
662
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(HeaderBar, {
702
+ const showActions = showThemeSwitcher || showProfileUi || showCreditsUi || !!feedbackUrl || !!actionsStart || !!actionsEnd;
703
+ return /* @__PURE__ */ jsxs(HeaderBar, {
663
704
  className,
664
705
  children: [
665
706
  /* @__PURE__ */ jsx(HeaderLogo, {
@@ -693,6 +734,7 @@ function HeaderInner({ logoType, logoHref, showOrg = false, showProjectDropdown
693
734
  showActions && /* @__PURE__ */ jsxs("div", {
694
735
  className: "ml-auto flex items-center gap-2",
695
736
  children: [
737
+ actionsStart,
696
738
  feedbackUrl && /* @__PURE__ */ jsx(Button, {
697
739
  variant: "ghost",
698
740
  size: "icon",
@@ -715,78 +757,11 @@ function HeaderInner({ logoType, logoHref, showOrg = false, showProjectDropdown
715
757
  showProfileUi && /* @__PURE__ */ jsx(ProfileMenu, {
716
758
  email: state.userEmail,
717
759
  onLogout: state.logout
718
- })
760
+ }),
761
+ actionsEnd
719
762
  ]
720
763
  })
721
764
  ]
722
- }), showProjectUi && state.showOverlay && /* @__PURE__ */ jsx(ProjectOverlay, {
723
- organizationName: state.organizationName,
724
- projectsTree: state.projectsTree,
725
- selectedProjectId: state.selectedProjectId,
726
- onSelect: state.selectProject,
727
- isLoading: state.isProjectsLoading,
728
- onClose: onCloseProjectOverlay
729
- })] });
730
- }
731
- function ProjectOverlay({ organizationName, projectsTree, selectedProjectId, onSelect, isLoading, onClose }) {
732
- return /* @__PURE__ */ jsx("div", {
733
- role: "dialog",
734
- "aria-modal": "true",
735
- "aria-label": DEFAULT_LABELS.overlayTitle,
736
- className: "fixed inset-0 z-50 flex items-center justify-center bg-primary-bg/80 backdrop-blur-sm",
737
- children: /* @__PURE__ */ jsxs("div", {
738
- className: "relative mx-1 flex w-full max-w-md flex-col items-center gap-6 rounded-16 border bg-glass-none-bg p-2 text-primary-txt shadow-xl",
739
- children: [
740
- /* @__PURE__ */ jsx(Button, {
741
- variant: "ghost",
742
- size: "icon",
743
- onClick: onClose ?? (() => window.history.back()),
744
- className: "absolute top-4 right-4",
745
- "aria-label": "Close",
746
- children: /* @__PURE__ */ jsx(X, { className: "size-5" })
747
- }),
748
- /* @__PURE__ */ jsxs("div", {
749
- className: "flex flex-col items-center gap-3 text-center",
750
- children: [
751
- /* @__PURE__ */ jsx("div", {
752
- className: "rounded-full bg-primary/10 p-4",
753
- children: /* @__PURE__ */ jsx(FolderOpen, { className: "size-8 text-primary" })
754
- }),
755
- /* @__PURE__ */ jsx("h2", {
756
- className: "font-semibold text-primary-txt text-xl",
757
- children: DEFAULT_LABELS.overlayTitle
758
- }),
759
- /* @__PURE__ */ jsx("p", {
760
- className: "text-muted-txt text-sm",
761
- children: DEFAULT_LABELS.overlayDescription
762
- })
763
- ]
764
- }),
765
- /* @__PURE__ */ jsxs("div", {
766
- className: "flex w-full justify-center gap-2",
767
- children: [organizationName && /* @__PURE__ */ jsxs("div", {
768
- className: cn(PILL, "select-none"),
769
- title: organizationName,
770
- children: [/* @__PURE__ */ jsxs("span", {
771
- className: "shrink-0 text-muted-txt",
772
- children: [DEFAULT_LABELS.orgLabel, ":"]
773
- }), /* @__PURE__ */ jsx("span", {
774
- className: "max-w-52 truncate font-medium",
775
- children: organizationName
776
- })]
777
- }), /* @__PURE__ */ jsx(ProjectPicker, {
778
- projectsTree,
779
- selectedProjectId,
780
- onSelect,
781
- projectLabel: DEFAULT_LABELS.projectLabel,
782
- projectPlaceholder: DEFAULT_LABELS.projectPlaceholder,
783
- searchPlaceholder: DEFAULT_LABELS.searchPlaceholder,
784
- emptyStateText: DEFAULT_LABELS.emptyStateText,
785
- isLoading
786
- })]
787
- })
788
- ]
789
- })
790
765
  });
791
766
  }
792
767
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"Header.js","names":["PILL"],"sources":["../src/patterns/Header/project-tree.ts","../src/patterns/Header/ProjectPicker.tsx","../src/patterns/Header/labels.ts","../src/patterns/Header/api.ts","../src/patterns/Header/storage.ts","../src/patterns/Header/header-store.ts","../src/patterns/Header/session.ts","../src/patterns/Header/use-global-header.ts","../src/patterns/Header/Header.tsx"],"sourcesContent":["import type { ProjectNode } from \"./types\";\n\n/** True when a node with the given id exists anywhere in the tree. */\nexport function nodeExistsInTree(tree: ProjectNode[], id: string): boolean {\n return tree.some((node) => node.id === id || nodeExistsInTree(node.children, id));\n}\n\n/** Name of the node with the given id, or undefined. */\nexport function findProjectName(tree: ProjectNode[], id: string): string | undefined {\n for (const node of tree) {\n if (node.id === id) return node.name;\n const found = findProjectName(node.children, id);\n if (found) return found;\n }\n return undefined;\n}\n\n/** Filter the tree to nodes matching `term`, preserving ancestors of matches. */\nexport function filterTree(nodes: ProjectNode[], term: string): ProjectNode[] {\n if (!term) return nodes;\n const lower = term.toLowerCase();\n return nodes.flatMap((node) => {\n if (node.name.toLowerCase().includes(lower)) return [node];\n const children = filterTree(node.children, term);\n return children.length > 0 ? [{ ...node, children }] : [];\n });\n}\n","\"use client\";\n\nimport { Check, ChevronDown, ChevronRight, Search } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { Input } from \"@/primitives/Input\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/primitives/Popover\";\nimport { Skeleton } from \"@/primitives/Skeleton\";\nimport { cn } from \"@/utils\";\nimport { filterTree, findProjectName } from \"./project-tree\";\nimport type { ProjectNode } from \"./types\";\n\ninterface ProjectPickerProps {\n projectsTree: ProjectNode[];\n selectedProjectId: string;\n selectedProjectName?: string;\n onSelect: (id: string) => void;\n projectLabel: string;\n projectPlaceholder: string;\n searchPlaceholder: string;\n emptyStateText: string;\n isLoading?: boolean;\n}\n\n// Pill shared by the trigger and the org pill — keeps the header lockup consistent.\nconst PILL =\n \"flex min-h-8 items-center gap-1 rounded-12 border border-primary-border bg-input-bg px-3 py-1 text-xs leading-4\";\n\nexport function ProjectPicker({\n projectsTree,\n selectedProjectId,\n selectedProjectName,\n onSelect,\n projectLabel,\n projectPlaceholder,\n searchPlaceholder,\n emptyStateText,\n isLoading = false,\n}: Readonly<ProjectPickerProps>) {\n const [open, setOpen] = React.useState(false);\n const [searchTerm, setSearchTerm] = React.useState(\"\");\n const [collapsedIds, setCollapsedIds] = React.useState<Set<string>>(new Set());\n\n const toggleCollapse = (id: string) =>\n setCollapsedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n\n const handleSelect = (id: string) => {\n onSelect(id);\n setOpen(false);\n };\n\n const selectedName = selectedProjectId\n ? (findProjectName(projectsTree, selectedProjectId) ?? selectedProjectName)\n : undefined;\n\n const filteredTree = filterTree(projectsTree, searchTerm);\n\n if (isLoading) {\n return (\n <div data-slot=\"header-project-picker\" className={cn(PILL, \"min-w-44\")}>\n <span className=\"shrink-0 text-muted-txt\">{projectLabel}:</span>\n <Skeleton className=\"h-3 flex-1\" />\n <ChevronDown className=\"size-4 shrink-0 text-muted-txt opacity-40\" />\n </div>\n );\n }\n\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setSearchTerm(\"\");\n }}\n >\n <PopoverTrigger\n data-slot=\"header-project-picker\"\n className={cn(PILL, \"text-left transition-colors hover:border-focus/60\")}\n >\n <span className=\"shrink-0 text-muted-txt\">{projectLabel}:</span>\n <span className={cn(\"max-w-36 truncate\", selectedName ? \"font-medium\" : \"text-muted-txt\")}>\n {selectedName ?? projectPlaceholder}\n </span>\n <ChevronDown className=\"ml-1 size-4 shrink-0 text-muted-txt\" />\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-64 p-0\" role=\"tree\" aria-label={projectLabel}>\n <div className=\"border-b p-2\">\n <div className=\"relative\">\n <Search className=\"absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-txt\" />\n <Input\n size=\"sm\"\n className=\"pl-8\"\n placeholder={searchPlaceholder}\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n />\n </div>\n </div>\n <div className=\"max-h-64 overflow-y-auto py-1\">\n {filteredTree.length === 0 ? (\n <p className=\"px-1 py-0.5 text-sm text-muted-txt\">{emptyStateText}</p>\n ) : (\n filteredTree.map((node) => (\n <TreeNode\n key={node.id}\n node={node}\n depth={0}\n selectedId={selectedProjectId}\n onSelect={handleSelect}\n collapsedIds={collapsedIds}\n onToggleCollapse={toggleCollapse}\n />\n ))\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\ninterface TreeNodeProps {\n node: ProjectNode;\n depth: number;\n selectedId: string;\n onSelect: (id: string) => void;\n collapsedIds: Set<string>;\n onToggleCollapse: (id: string) => void;\n}\n\nfunction TreeNode({\n node,\n depth,\n selectedId,\n onSelect,\n collapsedIds,\n onToggleCollapse,\n}: Readonly<TreeNodeProps>) {\n const isSelected = !node.isContextOnly && selectedId === node.id;\n const isCollapsed = collapsedIds.has(node.id);\n const hasChildren = node.children.length > 0;\n\n return (\n <div\n role=\"treeitem\"\n aria-selected={node.isContextOnly ? undefined : isSelected}\n aria-expanded={hasChildren ? !isCollapsed : undefined}\n >\n <div\n style={{ paddingLeft: `${0.75 + depth}rem` }}\n className={cn(\n \"flex items-center gap-1 py-2 pr-3 text-sm transition-colors\",\n node.isContextOnly\n ? \"cursor-default text-muted-txt\"\n : \"cursor-pointer hover:bg-ghost-hover-bg\",\n isSelected && \"bg-secondary-bg font-medium\",\n )}\n >\n {hasChildren ? (\n <button\n type=\"button\"\n aria-label={isCollapsed ? `Expand ${node.name}` : `Collapse ${node.name}`}\n onClick={() => onToggleCollapse(node.id)}\n className=\"shrink-0 text-muted-txt hover:text-primary-txt\"\n >\n {isCollapsed ? (\n <ChevronRight className=\"size-3.5\" />\n ) : (\n <ChevronDown className=\"size-3.5\" />\n )}\n </button>\n ) : (\n <span className=\"inline-block w-3.5 shrink-0\" />\n )}\n\n {node.isContextOnly ? (\n <span className=\"flex-1 text-left\">{node.name}</span>\n ) : (\n <button type=\"button\" onClick={() => onSelect(node.id)} className=\"flex-1 text-left\">\n {node.name}\n </button>\n )}\n\n {isSelected && <Check className=\"ml-auto size-3.5 shrink-0 text-primary\" />}\n </div>\n {!isCollapsed && hasChildren && (\n <div role=\"group\">\n {node.children.map((child) => (\n <TreeNode\n key={child.id}\n node={child}\n depth={depth + 1}\n selectedId={selectedId}\n onSelect={onSelect}\n collapsedIds={collapsedIds}\n onToggleCollapse={onToggleCollapse}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n","/** Default UI strings. Spread-override via the Header `labels` prop if needed. */\nexport const DEFAULT_LABELS = {\n orgLabel: \"Org\",\n projectLabel: \"Project\",\n projectPlaceholder: \"Select project...\",\n searchPlaceholder: \"Search project\",\n emptyStateText: \"No projects found\",\n profileMenuLabel: \"Profile menu\",\n logoutLabel: \"Logout\",\n overlayTitle: \"Select a Project\",\n overlayDescription: \"Choose a project to get started. You can change it anytime from the header.\",\n} as const;\n\nexport type Labels = typeof DEFAULT_LABELS;\n","import type { Fetcher, HeaderEndpoints, HeaderProps, ProjectNode } from \"./types\";\n\n// Studio-auth API. Endpoints are built from the host-provided `apiBaseUrl` (full\n// domain) so the same header works across environments/subdomains. All requests\n// send cookies (`credentials: 'include'`); the parent-domain session cookie is\n// readable cross-subdomain.\n\nconst PATHS = {\n token: \"/api/v1/studio-auth/sessions/token\",\n logout: \"/api/v1/studio-auth/sessions/logout\",\n projects: (clientId: string) => `/api/v1/onboarding/organization/${clientId}/projects`,\n credits: \"/save/api/v1/users\",\n};\n\n/** Join a base URL and path without doubling slashes. */\nfunction join(baseUrl: string, path: string): string {\n return `${baseUrl.replace(/\\/$/, \"\")}${path}`;\n}\n\nexport function buildEndpoints(\n apiBaseUrl: string,\n overrides?: HeaderProps[\"endpoints\"],\n): HeaderEndpoints {\n return {\n token: overrides?.token ?? join(apiBaseUrl, PATHS.token),\n logout: overrides?.logout ?? join(apiBaseUrl, PATHS.logout),\n projects:\n overrides?.projects ?? ((clientId: string) => join(apiBaseUrl, PATHS.projects(clientId))),\n credits: overrides?.credits ?? join(apiBaseUrl, PATHS.credits),\n };\n}\n\ntype ApiEnvelope<T> = { response?: { data?: T } };\n\nexport async function fetchToken(endpoints: HeaderEndpoints, fetcher: Fetcher): Promise<string> {\n const res = await fetcher(endpoints.token, { credentials: \"include\" });\n if (!res.ok) throw new Error(`token request failed: ${res.status}`);\n const { accessToken } = (await res.json()) as { accessToken: string };\n return accessToken;\n}\n\nexport async function fetchProjects(\n endpoints: HeaderEndpoints,\n clientId: string,\n accessToken: string,\n fetcher: Fetcher,\n): Promise<{ projectsTree: ProjectNode[]; organizationName: string | undefined }> {\n const res = await fetcher(endpoints.projects(clientId), {\n credentials: \"include\",\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (!res.ok) throw new Error(`projects request failed: ${res.status}`);\n const data = (await res.json()) as ApiEnvelope<{\n projectsTree?: ProjectNode[];\n organization?: { name?: string };\n }>;\n return {\n projectsTree: data.response?.data?.projectsTree ?? [],\n organizationName: data.response?.data?.organization?.name,\n };\n}\n\nexport async function fetchCredits(\n endpoints: HeaderEndpoints,\n accessToken: string,\n fetcher: Fetcher,\n): Promise<number | undefined> {\n const res = await fetcher(endpoints.credits, {\n credentials: \"include\",\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (!res.ok) throw new Error(`credits request failed: ${res.status}`);\n const data = (await res.json()) as { remainingCredits?: number };\n return data.remainingCredits;\n}\n\nexport async function callLogout(endpoints: HeaderEndpoints, fetcher: Fetcher): Promise<void> {\n try {\n await fetcher(endpoints.logout, { method: \"POST\", credentials: \"include\" });\n } finally {\n if (typeof window !== \"undefined\") window.location.href = \"/\";\n }\n}\n","// Persists the user's project selection across reloads (sessionStorage), tagged\n// with the client it belongs to so a stale selection from a different org is\n// discarded on re-login.\n\nconst PROJECT_KEY = \"ds-header-project\";\n\nexport interface StoredProject {\n id: string;\n name: string;\n clientId?: string;\n}\n\nexport function getStoredProject(): StoredProject | null {\n try {\n const raw = sessionStorage.getItem(PROJECT_KEY);\n return raw ? (JSON.parse(raw) as StoredProject) : null;\n } catch {\n return null;\n }\n}\n\nexport function setStoredProject(project: StoredProject): void {\n try {\n sessionStorage.setItem(PROJECT_KEY, JSON.stringify(project));\n } catch {\n // sessionStorage unavailable — degrade silently\n }\n}\n\nexport function clearStoredProject(): void {\n try {\n sessionStorage.removeItem(PROJECT_KEY);\n } catch {\n // noop\n }\n}\n","\"use client\";\n\nimport * as React from \"react\";\n\nimport { clearStoredProject, getStoredProject, setStoredProject } from \"./storage\";\n\n// Module-level store for the current project/org selection. Module scope (not\n// React context) so a host app can read and change the selection from anywhere —\n// including components rendered outside the <Header> subtree. The Header is one\n// writer/reader; `useHeaderProject()` gives apps the same access.\n\nexport interface HeaderSelection {\n selectedProjectId: string;\n selectedProjectName: string;\n organizationName: string | undefined;\n /** Remaining credits for the logged-in user (read-only here; set by the Header). */\n credits: number | undefined;\n /** Client/org the current selection + org belong to (for cross-org invalidation). */\n clientId: string | undefined;\n}\n\nfunction initialState(): HeaderSelection {\n const stored = typeof window !== \"undefined\" ? getStoredProject() : null;\n return {\n selectedProjectId: stored?.id ?? \"\",\n selectedProjectName: stored?.name ?? \"\",\n organizationName: undefined,\n credits: undefined,\n clientId: stored?.clientId,\n };\n}\n\nlet state: HeaderSelection = initialState();\n// Stable reference for SSR / first server render.\nconst SERVER_SNAPSHOT: HeaderSelection = Object.freeze({\n selectedProjectId: \"\",\n selectedProjectName: \"\",\n organizationName: undefined,\n credits: undefined,\n clientId: undefined,\n});\n\nconst listeners = new Set<() => void>();\nfunction emit() {\n for (const listener of listeners) listener();\n}\n\nexport const headerStore = {\n subscribe(listener: () => void) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n getSnapshot(): HeaderSelection {\n return state;\n },\n getServerSnapshot(): HeaderSelection {\n return SERVER_SNAPSHOT;\n },\n\n /** Set the selected project. `name` is best-effort; the Header backfills it from the tree. */\n setProject(id: string, name = \"\", clientId?: string) {\n if (id) setStoredProject({ id, name, clientId: clientId ?? state.clientId });\n else clearStoredProject();\n state = {\n ...state,\n selectedProjectId: id,\n selectedProjectName: name,\n clientId: clientId ?? state.clientId,\n };\n emit();\n },\n\n clearProject() {\n clearStoredProject();\n state = { ...state, selectedProjectId: \"\", selectedProjectName: \"\" };\n emit();\n },\n\n setOrganization(name: string | undefined, clientId?: string) {\n state = { ...state, organizationName: name, clientId: clientId ?? state.clientId };\n emit();\n },\n\n setCredits(credits: number | undefined) {\n if (state.credits === credits) return;\n state = { ...state, credits };\n emit();\n },\n\n /** When the active client changes, drop a selection/org from the previous one. */\n reconcileClient(clientId: string) {\n if (state.clientId === clientId) return;\n if (state.clientId && state.clientId !== clientId) {\n clearStoredProject();\n state = {\n selectedProjectId: \"\",\n selectedProjectName: \"\",\n organizationName: undefined,\n credits: state.credits, // user-level — survives org switches\n clientId,\n };\n } else {\n state = { ...state, clientId };\n }\n emit();\n },\n};\n\n/** Internal: subscribe a component to the selection store. */\nexport function useHeaderStore(): HeaderSelection {\n return React.useSyncExternalStore(\n headerStore.subscribe,\n headerStore.getSnapshot,\n headerStore.getServerSnapshot,\n );\n}\n\nexport interface UseHeaderProjectResult {\n selectedProjectId: string;\n selectedProjectName: string | undefined;\n organizationName: string | undefined;\n /** Set the active project from outside the Header (by id). */\n setProject: (id: string) => void;\n /** Clear the active project (e.g. to re-prompt selection). */\n clearProject: () => void;\n}\n\n/**\n * Read the current project/org and change the project from anywhere in the app —\n * no need to be inside the <Header>. Reflects user selections made in the header\n * and updates the header when changed here.\n */\nexport function useHeaderProject(): UseHeaderProjectResult {\n const snapshot = useHeaderStore();\n return {\n selectedProjectId: snapshot.selectedProjectId,\n selectedProjectName: snapshot.selectedProjectName || undefined,\n organizationName: snapshot.organizationName,\n setProject: React.useCallback((id: string) => headerStore.setProject(id), []),\n clearProject: React.useCallback(() => headerStore.clearProject(), []),\n };\n}\n\n/** Read the logged-in user's remaining credits (read-only; the Header owns it). */\nexport function useHeaderCredits(): number | undefined {\n return useHeaderStore().credits;\n}\n","// Client-side session detection. The auth system writes a JS-readable cookie\n// `{environmentId}-sessionId` (a JWT) on the shared parent domain. We decode it\n// and check its expiry to know whether the user is logged in — no network call.\n\ninterface JwtPayload {\n exp?: number;\n [key: string]: unknown;\n}\n\n/** Read the raw session JWT from the `{environmentId}-sessionId` cookie. */\nexport function getSessionToken(environmentId: string): string | null {\n if (typeof document === \"undefined\") return null;\n const name = `${environmentId}-sessionId`;\n for (const part of document.cookie.split(\";\")) {\n const [key, ...rest] = part.trim().split(\"=\");\n if (key === name) return decodeURIComponent(rest.join(\"=\"));\n }\n return null;\n}\n\n/** Decode a JWT payload without verifying the signature (display/expiry only). */\nexport function decodeJwt(token: string): JwtPayload | null {\n try {\n const payload = token.split(\".\")[1];\n if (!payload) return null;\n const base64 = payload.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const json = atob(base64);\n return JSON.parse(json) as JwtPayload;\n } catch {\n return null;\n }\n}\n\n/** User/session claims carried in the session JWT (the subset the header uses). */\nexport interface SessionClaims {\n email?: string;\n name?: string;\n userId?: string;\n /** Active organisation id (`client_id` claim). */\n clientId?: string;\n exp?: number;\n}\n\n/**\n * Decode the user claims from the session cookie's JWT — no network call.\n * Returns null when the cookie is absent or undecodable.\n */\nexport function getSessionClaims(environmentId: string): SessionClaims | null {\n const token = getSessionToken(environmentId);\n if (!token) return null;\n const payload = decodeJwt(token);\n if (!payload) return null;\n const str = (v: unknown) => (typeof v === \"string\" ? v : undefined);\n return {\n email: str(payload.email),\n name: str(payload.name),\n userId: str(payload.user_id),\n clientId: str(payload.client_id),\n exp: typeof payload.exp === \"number\" ? payload.exp : undefined,\n };\n}\n\n/** True when a valid, unexpired session cookie exists for the environment. */\nexport function isSessionValid(environmentId: string): boolean {\n const token = getSessionToken(environmentId);\n if (!token) return false;\n const payload = decodeJwt(token);\n if (!payload) return false;\n // No exp claim → treat as a non-expiring session.\n if (typeof payload.exp !== \"number\") return true;\n return payload.exp * 1000 > Date.now();\n}\n","\"use client\";\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport * as React from \"react\";\n\nimport { buildEndpoints, callLogout, fetchCredits, fetchProjects, fetchToken } from \"./api\";\nimport { headerStore, useHeaderStore } from \"./header-store\";\nimport { findProjectName, nodeExistsInTree } from \"./project-tree\";\nimport { getSessionClaims, isSessionValid } from \"./session\";\nimport type { HeaderProps, ProjectNode } from \"./types\";\n\n/** Window event other modules can dispatch to show/hide the project dropdown. */\nexport const TOGGLE_PROJECT_DROPDOWN_EVENT = \"toggle-project-dropdown\";\nexport interface ToggleProjectDropdownDetail {\n show: boolean;\n}\n\nconst DEFAULT_STALE_TIME = 5 * 60_000;\nconst DEFAULT_GC_TIME = 10 * 60_000;\n\nexport interface GlobalHeaderState {\n /** Whether a valid session cookie exists — when false, hide all user content. */\n isAuthenticated: boolean;\n userEmail: string | undefined;\n organizationName: string | undefined;\n projectsTree: ProjectNode[];\n selectedProjectId: string;\n selectedProjectName: string | undefined;\n isProjectsLoading: boolean;\n isOrgLoading: boolean;\n /** Remaining credits for the user (undefined until loaded / when disabled). */\n credits: number | undefined;\n /** Where the credits pill links to (studio-auth `/user/activity`). */\n creditsHref: string;\n projectDropdownVisible: boolean;\n /** True when the dropdown is on, the user is in, but no project is chosen yet. */\n showOverlay: boolean;\n selectProject: (id: string) => void;\n logout: () => void;\n}\n\ntype UseGlobalHeaderArgs = Pick<\n HeaderProps,\n | \"apiBaseUrl\"\n | \"environmentId\"\n | \"clientId\"\n | \"_dangerouslyInjectAccessToken\"\n | \"showProjectDropdown\"\n | \"showProfile\"\n | \"showOrg\"\n | \"showCredits\"\n | \"endpoints\"\n | \"fetcher\"\n | \"staleTime\"\n | \"gcTime\"\n | \"onProjectChange\"\n>;\n\nexport function useGlobalHeader({\n apiBaseUrl,\n environmentId,\n clientId,\n _dangerouslyInjectAccessToken: injectedToken,\n showProjectDropdown = false,\n showProfile = false,\n showOrg = false,\n showCredits = false,\n endpoints: endpointOverrides,\n fetcher: fetcherProp,\n staleTime = DEFAULT_STALE_TIME,\n gcTime = DEFAULT_GC_TIME,\n onProjectChange,\n}: UseGlobalHeaderArgs): GlobalHeaderState {\n const fetcher = React.useMemo(\n () => fetcherProp ?? ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, init)),\n [fetcherProp],\n );\n const endpoints = React.useMemo(\n () => buildEndpoints(apiBaseUrl, endpointOverrides),\n [apiBaseUrl, endpointOverrides],\n );\n\n // Read the session cookie each render (cheap); gates every network call.\n // User identity (email, client id) comes from the JWT claims — no /me call.\n const isAuthenticated = isSessionValid(environmentId);\n const claims = getSessionClaims(environmentId);\n\n // token → projects, enabled only when the previous resolved.\n const tokenQuery = useQuery({\n queryKey: [\"ds-header\", \"token\", endpoints.token],\n queryFn: () => fetchToken(endpoints, fetcher),\n enabled: isAuthenticated && !injectedToken,\n staleTime,\n gcTime,\n });\n const token = injectedToken ?? tokenQuery.data;\n\n const effectiveClientId = clientId ?? claims?.clientId;\n const wantsProjects = showProjectDropdown || showOrg;\n const projectsQuery = useQuery({\n queryKey: [\"ds-header\", \"projects\", effectiveClientId, token],\n queryFn: () => fetchProjects(endpoints, effectiveClientId as string, token as string, fetcher),\n enabled: isAuthenticated && !!token && !!effectiveClientId && wantsProjects,\n staleTime,\n gcTime,\n });\n\n // Credits — only needs the token. Always refetched on mount (staleTime 0) so a\n // page refresh shows the current balance.\n const creditsQuery = useQuery({\n queryKey: [\"ds-header\", \"credits\", endpoints.credits, token],\n queryFn: () => fetchCredits(endpoints, token as string, fetcher),\n enabled: isAuthenticated && !!token && showCredits,\n staleTime: 0,\n gcTime,\n });\n\n const projectsTree = projectsQuery.data?.projectsTree ?? [];\n const userEmail = showProfile ? claims?.email : undefined;\n const creditsHref = React.useMemo(() => {\n try {\n return new URL(\"/user/activity\", apiBaseUrl).toString();\n } catch {\n return \"/user/activity\";\n }\n }, [apiBaseUrl]);\n\n // Selection + org live in a module store so host apps can read/change them\n // from outside the header (see useHeaderProject).\n const selection = useHeaderStore();\n\n // Once the client id resolves, drop a selection/org from a different client.\n React.useEffect(() => {\n if (effectiveClientId) headerStore.reconcileClient(effectiveClientId);\n }, [effectiveClientId]);\n\n // Once projects load: publish the org name and validate/backfill the selection\n // (drop one that no longer exists; fill in its name from the tree).\n React.useEffect(() => {\n if (!projectsQuery.data) return;\n const tree = projectsQuery.data.projectsTree;\n const id = headerStore.getSnapshot().selectedProjectId;\n if (id && !nodeExistsInTree(tree, id)) {\n headerStore.clearProject();\n } else if (id) {\n const name = findProjectName(tree, id);\n if (name && name !== headerStore.getSnapshot().selectedProjectName) {\n headerStore.setProject(id, name, effectiveClientId);\n }\n }\n headerStore.setOrganization(projectsQuery.data.organizationName, effectiveClientId);\n }, [projectsQuery.data, effectiveClientId]);\n\n // Publish credits to the store so host apps can read them via useHeaderCredits.\n React.useEffect(() => {\n if (creditsQuery.data !== undefined) headerStore.setCredits(creditsQuery.data);\n }, [creditsQuery.data]);\n\n const selectProject = (id: string) => {\n const name = findProjectName(projectsTree, id) ?? \"\";\n headerStore.setProject(id, name, effectiveClientId);\n onProjectChange?.(id);\n };\n\n const logout = () => {\n headerStore.clearProject();\n void callLogout(endpoints, fetcher);\n };\n\n // Visibility: declarative from the prop, overridable at runtime via the event.\n const [projectDropdownVisible, setProjectDropdownVisible] = React.useState(showProjectDropdown);\n React.useEffect(() => setProjectDropdownVisible(showProjectDropdown), [showProjectDropdown]);\n React.useEffect(() => {\n const handler = (e: Event) => {\n setProjectDropdownVisible((e as CustomEvent<ToggleProjectDropdownDetail>).detail.show);\n };\n window.addEventListener(TOGGLE_PROJECT_DROPDOWN_EVENT, handler);\n return () => window.removeEventListener(TOGGLE_PROJECT_DROPDOWN_EVENT, handler);\n }, []);\n\n const isProjectsLoading = projectsQuery.isFetching && !projectsQuery.data;\n\n return {\n isAuthenticated,\n userEmail,\n organizationName: selection.organizationName,\n projectsTree,\n selectedProjectId: selection.selectedProjectId,\n selectedProjectName: selection.selectedProjectName || undefined,\n isProjectsLoading,\n isOrgLoading: showOrg && isProjectsLoading,\n credits: selection.credits,\n creditsHref,\n projectDropdownVisible,\n showOverlay: isAuthenticated && projectDropdownVisible && !selection.selectedProjectId,\n selectProject,\n logout,\n };\n}\n","\"use client\";\n\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { FolderOpen, LogOut, MessageSquareShare, Moon, Sun, X } from \"lucide-react\";\nimport type * as React from \"react\";\n\nimport { Avatar, AvatarFallback } from \"@/primitives/Avatar\";\nimport { Button } from \"@/primitives/Button\";\nimport { Credits } from \"@/primitives/Credits\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/primitives/DropdownMenu\";\nimport { Logo } from \"@/primitives/Logo\";\nimport { Skeleton } from \"@/primitives/Skeleton\";\nimport { type ThemeProduct, useTheme } from \"@/primitives/ThemeProvider\";\nimport { cn } from \"@/utils\";\nimport { ProjectPicker } from \"./ProjectPicker\";\nimport { DEFAULT_LABELS } from \"./labels\";\nimport type { HeaderProps, ProjectNode } from \"./types\";\nimport { useGlobalHeader } from \"./use-global-header\";\n\n// Fallback logo destinations when the host doesn't pass `logoHref`.\nconst LOGO_HREF: Record<ThemeProduct, string> = {\n psai: \"https://sapientaiproducts.com/\",\n slingshot: \"https://sapientaiproducts.com/slingshot\",\n sustain: \"https://www.publicissapient.com/\",\n bodhi: \"https://sapientaiproducts.com/bodhi\",\n};\n\nconst PILL =\n \"flex min-h-8 items-center gap-1 rounded-12 border border-primary-border bg-input-bg px-3 py-1 text-xs leading-4\";\n\n// ── Presentational parts (props-driven; Storybook/VR-able) ──────────────────\n\n/** The header bar shell — a sticky glass strip. */\nfunction HeaderBar({ className, ...props }: React.ComponentProps<\"header\">) {\n return (\n <header\n data-slot=\"header\"\n className={cn(\n \"sticky top-1 z-10 mt-1 flex h-15 items-center gap-5 rounded-16 px-3 py-2\",\n \"bg-glass-60-bg backdrop-blur-glass\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/** Product logo linking to its home, with a Suspense-safe fallback. */\nfunction HeaderLogo({ brand, href }: { brand: ThemeProduct; href?: string }) {\n return (\n <a href={href ?? LOGO_HREF[brand]} aria-label=\"Go to product home\" data-slot=\"header-logo\">\n <Logo brand={brand} className=\"h-8 w-auto\" />\n </a>\n );\n}\n\n/** Read-only organisation pill. */\nfunction OrgPill({ name, loading }: { name?: string; loading?: boolean }) {\n if (loading && !name) {\n return (\n <div className={cn(PILL, \"ml-3\")} data-slot=\"header-org\">\n <span className=\"shrink-0 text-muted-txt\">{DEFAULT_LABELS.orgLabel}:</span>\n <Skeleton className=\"h-4 w-24\" />\n </div>\n );\n }\n if (!name) return null;\n return (\n <div className={cn(PILL, \"ml-3 select-none\")} title={name} data-slot=\"header-org\">\n <span className=\"shrink-0 text-muted-txt\">{DEFAULT_LABELS.orgLabel}:</span>\n <span className=\"max-w-36 truncate text-primary-txt\">{name}</span>\n </div>\n );\n}\n\n/** Light/dark toggle — defers to ThemeProvider. */\nfunction ThemeToggle() {\n const { theme, toggleTheme } = useTheme();\n return (\n <Button variant=\"ghost\" size=\"icon\" onClick={toggleTheme} aria-label=\"Toggle theme\">\n {theme === \"light\" ? <Moon className=\"size-4\" /> : <Sun className=\"size-4\" />}\n </Button>\n );\n}\n\n/** Profile menu — avatar trigger with email + logout. */\nfunction ProfileMenu({ email, onLogout }: { email?: string; onLogout: () => void }) {\n const initial = email?.trim().charAt(0).toUpperCase() || \"?\";\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" aria-label={DEFAULT_LABELS.profileMenuLabel}>\n <Avatar className=\"size-7\">\n <AvatarFallback>{initial}</AvatarFallback>\n </Avatar>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" sideOffset={8} className=\"min-w-44\">\n {email && (\n <>\n <DropdownMenuLabel className=\"truncate font-normal text-muted-txt\">\n {email}\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n </>\n )}\n <DropdownMenuItem onSelect={onLogout} variant=\"destructive\">\n <LogOut />\n {DEFAULT_LABELS.logoutLabel}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport { HeaderBar, HeaderLogo, OrgPill, ThemeToggle, ProfileMenu };\n\n// ── Wired Header ─────────────────────────────────────────────────────────────\n\n// Internal singleton client so the header is drop-in (no app setup) while still\n// sharing its cache across mounts/navigation.\nlet sharedClient: QueryClient | undefined;\nfunction getQueryClient(): QueryClient {\n sharedClient ??= new QueryClient({\n defaultOptions: { queries: { retry: 1, refetchOnWindowFocus: false } },\n });\n return sharedClient;\n}\n\n/** Drop-in global header. Must be rendered inside a <ThemeProvider>. */\nexport function Header(props: HeaderProps) {\n return (\n <QueryClientProvider client={getQueryClient()}>\n <HeaderInner {...props} />\n </QueryClientProvider>\n );\n}\n\nfunction HeaderInner({\n logoType,\n logoHref,\n showOrg = false,\n showProjectDropdown = false,\n showProfile = false,\n showThemeSwitcher = false,\n showCredits = false,\n pageTitle,\n feedbackUrl,\n logoAddon,\n className,\n onCloseProjectOverlay,\n ...rest\n}: HeaderProps) {\n const { product } = useTheme();\n const brand = logoType ?? product;\n const state = useGlobalHeader({\n showOrg,\n showProjectDropdown,\n showProfile,\n showCredits,\n ...rest,\n });\n\n // Logged-out users see no user content (project/org/profile/credits).\n const showProjectUi = showProjectDropdown && state.isAuthenticated;\n const showOrgUi = showOrg && state.isAuthenticated;\n const showProfileUi = showProfile && state.isAuthenticated;\n const showCreditsUi = showCredits && state.isAuthenticated && state.credits !== undefined;\n const showActions = showThemeSwitcher || showProfileUi || showCreditsUi || !!feedbackUrl;\n\n return (\n <>\n <HeaderBar className={className}>\n <HeaderLogo brand={brand} href={logoHref} />\n {/* Page title — 20px (gap-5) from the logo. */}\n {pageTitle && (\n <span data-slot=\"header-title\" className=\"ml-5 font-semibold text-primary-txt text-sm\">\n {pageTitle}\n </span>\n )}\n {logoAddon}\n\n {showOrgUi && <OrgPill name={state.organizationName} loading={state.isOrgLoading} />}\n\n {showProjectUi && state.projectDropdownVisible && (\n <div className=\"ml-2\">\n <ProjectPicker\n projectsTree={state.projectsTree}\n selectedProjectId={state.selectedProjectId}\n selectedProjectName={state.selectedProjectName}\n onSelect={state.selectProject}\n projectLabel={DEFAULT_LABELS.projectLabel}\n projectPlaceholder={DEFAULT_LABELS.projectPlaceholder}\n searchPlaceholder={DEFAULT_LABELS.searchPlaceholder}\n emptyStateText={DEFAULT_LABELS.emptyStateText}\n isLoading={state.isProjectsLoading}\n />\n </div>\n )}\n\n {showActions && (\n <div className=\"ml-auto flex items-center gap-2\">\n {feedbackUrl && (\n <Button variant=\"ghost\" size=\"icon\" asChild>\n <a\n href={feedbackUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label=\"Share feedback\"\n >\n <MessageSquareShare className=\"size-4\" />\n </a>\n </Button>\n )}\n {showThemeSwitcher && <ThemeToggle />}\n {showCreditsUi && state.credits !== undefined && (\n <a\n href={state.creditsHref}\n aria-label=\"View credit activity\"\n className=\"rounded-full outline-none focus-visible:ring-3 focus-visible:ring-focus\"\n >\n <Credits value={state.credits} />\n </a>\n )}\n {showProfileUi && <ProfileMenu email={state.userEmail} onLogout={state.logout} />}\n </div>\n )}\n </HeaderBar>\n\n {showProjectUi && state.showOverlay && (\n <ProjectOverlay\n organizationName={state.organizationName}\n projectsTree={state.projectsTree}\n selectedProjectId={state.selectedProjectId}\n onSelect={state.selectProject}\n isLoading={state.isProjectsLoading}\n onClose={onCloseProjectOverlay}\n />\n )}\n </>\n );\n}\n\n// First-run blocking overlay prompting a project selection.\nfunction ProjectOverlay({\n organizationName,\n projectsTree,\n selectedProjectId,\n onSelect,\n isLoading,\n onClose,\n}: {\n organizationName?: string;\n projectsTree: ProjectNode[];\n selectedProjectId: string;\n onSelect: (id: string) => void;\n isLoading: boolean;\n onClose?: () => void;\n}) {\n return (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={DEFAULT_LABELS.overlayTitle}\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-primary-bg/80 backdrop-blur-sm\"\n >\n <div className=\"relative mx-1 flex w-full max-w-md flex-col items-center gap-6 rounded-16 border bg-glass-none-bg p-2 text-primary-txt shadow-xl\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={onClose ?? (() => window.history.back())}\n className=\"absolute top-4 right-4\"\n aria-label=\"Close\"\n >\n <X className=\"size-5\" />\n </Button>\n <div className=\"flex flex-col items-center gap-3 text-center\">\n <div className=\"rounded-full bg-primary/10 p-4\">\n <FolderOpen className=\"size-8 text-primary\" />\n </div>\n <h2 className=\"font-semibold text-primary-txt text-xl\">{DEFAULT_LABELS.overlayTitle}</h2>\n <p className=\"text-muted-txt text-sm\">{DEFAULT_LABELS.overlayDescription}</p>\n </div>\n <div className=\"flex w-full justify-center gap-2\">\n {organizationName && (\n <div className={cn(PILL, \"select-none\")} title={organizationName}>\n <span className=\"shrink-0 text-muted-txt\">{DEFAULT_LABELS.orgLabel}:</span>\n <span className=\"max-w-52 truncate font-medium\">{organizationName}</span>\n </div>\n )}\n <ProjectPicker\n projectsTree={projectsTree}\n selectedProjectId={selectedProjectId}\n onSelect={onSelect}\n projectLabel={DEFAULT_LABELS.projectLabel}\n projectPlaceholder={DEFAULT_LABELS.projectPlaceholder}\n searchPlaceholder={DEFAULT_LABELS.searchPlaceholder}\n emptyStateText={DEFAULT_LABELS.emptyStateText}\n isLoading={isLoading}\n />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Header.js","names":["PILL"],"sources":["../src/patterns/Header/project-tree.ts","../src/patterns/Header/ProjectPicker.tsx","../src/patterns/Header/labels.ts","../src/patterns/Header/api.ts","../src/patterns/Header/storage.ts","../src/patterns/Header/header-store.ts","../src/patterns/Header/session.ts","../src/patterns/Header/use-global-header.ts","../src/patterns/Header/Header.tsx"],"sourcesContent":["import type { ProjectNode } from \"./types\";\n\n/** True when a node with the given id exists anywhere in the tree. */\nexport function nodeExistsInTree(tree: ProjectNode[], id: string): boolean {\n return tree.some((node) => node.id === id || nodeExistsInTree(node.children, id));\n}\n\n/** Name of the node with the given id, or undefined. */\nexport function findProjectName(tree: ProjectNode[], id: string): string | undefined {\n for (const node of tree) {\n if (node.id === id) return node.name;\n const found = findProjectName(node.children, id);\n if (found) return found;\n }\n return undefined;\n}\n\n/** First selectable node in the tree (depth-first, skipping context-only ancestors). */\nexport function firstSelectableProject(tree: ProjectNode[]): ProjectNode | undefined {\n for (const node of tree) {\n if (!node.isContextOnly) return node;\n const found = firstSelectableProject(node.children);\n if (found) return found;\n }\n return undefined;\n}\n\n/** Filter the tree to nodes matching `term`, preserving ancestors of matches. */\nexport function filterTree(nodes: ProjectNode[], term: string): ProjectNode[] {\n if (!term) return nodes;\n const lower = term.toLowerCase();\n return nodes.flatMap((node) => {\n if (node.name.toLowerCase().includes(lower)) return [node];\n const children = filterTree(node.children, term);\n return children.length > 0 ? [{ ...node, children }] : [];\n });\n}\n","\"use client\";\n\nimport { Check, ChevronDown, ChevronRight, Search } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { Input } from \"@/primitives/Input\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/primitives/Popover\";\nimport { Skeleton } from \"@/primitives/Skeleton\";\nimport { cn } from \"@/utils\";\nimport { filterTree, findProjectName } from \"./project-tree\";\nimport type { ProjectNode } from \"./types\";\n\ninterface ProjectPickerProps {\n projectsTree: ProjectNode[];\n selectedProjectId: string;\n selectedProjectName?: string;\n onSelect: (id: string) => void;\n projectLabel: string;\n projectPlaceholder: string;\n searchPlaceholder: string;\n emptyStateText: string;\n isLoading?: boolean;\n}\n\n// Pill shared by the trigger and the org pill — keeps the header lockup consistent.\nconst PILL =\n \"flex min-h-8 items-center gap-1 rounded-12 border border-primary-border bg-input-bg px-3 py-1 text-xs leading-4\";\n\nexport function ProjectPicker({\n projectsTree,\n selectedProjectId,\n selectedProjectName,\n onSelect,\n projectLabel,\n projectPlaceholder,\n searchPlaceholder,\n emptyStateText,\n isLoading = false,\n}: Readonly<ProjectPickerProps>) {\n const [open, setOpen] = React.useState(false);\n const [searchTerm, setSearchTerm] = React.useState(\"\");\n const [collapsedIds, setCollapsedIds] = React.useState<Set<string>>(new Set());\n\n const toggleCollapse = (id: string) =>\n setCollapsedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n\n const handleSelect = (id: string) => {\n onSelect(id);\n setOpen(false);\n };\n\n const selectedName = selectedProjectId\n ? (findProjectName(projectsTree, selectedProjectId) ?? selectedProjectName)\n : undefined;\n\n const filteredTree = filterTree(projectsTree, searchTerm);\n\n if (isLoading) {\n return (\n <div data-slot=\"header-project-picker\" className={cn(PILL, \"min-w-44\")}>\n <span className=\"shrink-0 text-muted-txt\">{projectLabel}:</span>\n <Skeleton className=\"h-3 flex-1\" />\n <ChevronDown className=\"size-4 shrink-0 text-muted-txt opacity-40\" />\n </div>\n );\n }\n\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setSearchTerm(\"\");\n }}\n >\n <PopoverTrigger\n data-slot=\"header-project-picker\"\n className={cn(PILL, \"text-left transition-colors hover:border-focus/60\")}\n >\n <span className=\"shrink-0 text-muted-txt\">{projectLabel}:</span>\n <span className={cn(\"max-w-36 truncate\", selectedName ? \"font-medium\" : \"text-muted-txt\")}>\n {selectedName ?? projectPlaceholder}\n </span>\n <ChevronDown className=\"ml-1 size-4 shrink-0 text-muted-txt\" />\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-64 p-0\" role=\"tree\" aria-label={projectLabel}>\n <div className=\"border-b p-2\">\n <div className=\"relative\">\n <Search className=\"absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-txt\" />\n <Input\n size=\"sm\"\n className=\"pl-8\"\n placeholder={searchPlaceholder}\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n />\n </div>\n </div>\n <div className=\"max-h-64 overflow-y-auto py-1\">\n {filteredTree.length === 0 ? (\n <p className=\"px-1 py-0.5 text-sm text-muted-txt\">{emptyStateText}</p>\n ) : (\n filteredTree.map((node) => (\n <TreeNode\n key={node.id}\n node={node}\n depth={0}\n selectedId={selectedProjectId}\n onSelect={handleSelect}\n collapsedIds={collapsedIds}\n onToggleCollapse={toggleCollapse}\n />\n ))\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\ninterface TreeNodeProps {\n node: ProjectNode;\n depth: number;\n selectedId: string;\n onSelect: (id: string) => void;\n collapsedIds: Set<string>;\n onToggleCollapse: (id: string) => void;\n}\n\nfunction TreeNode({\n node,\n depth,\n selectedId,\n onSelect,\n collapsedIds,\n onToggleCollapse,\n}: Readonly<TreeNodeProps>) {\n const isSelected = !node.isContextOnly && selectedId === node.id;\n const isCollapsed = collapsedIds.has(node.id);\n const hasChildren = node.children.length > 0;\n\n return (\n <div\n role=\"treeitem\"\n aria-selected={node.isContextOnly ? undefined : isSelected}\n aria-expanded={hasChildren ? !isCollapsed : undefined}\n >\n <div\n style={{ paddingLeft: `${0.75 + depth}rem` }}\n className={cn(\n \"flex items-center gap-1 py-2 pr-3 text-sm transition-colors\",\n node.isContextOnly\n ? \"cursor-default text-muted-txt\"\n : \"cursor-pointer hover:bg-ghost-hover-bg\",\n isSelected && \"bg-secondary-bg font-medium\",\n )}\n >\n {hasChildren ? (\n <button\n type=\"button\"\n aria-label={isCollapsed ? `Expand ${node.name}` : `Collapse ${node.name}`}\n onClick={() => onToggleCollapse(node.id)}\n className=\"shrink-0 text-muted-txt hover:text-primary-txt\"\n >\n {isCollapsed ? (\n <ChevronRight className=\"size-3.5\" />\n ) : (\n <ChevronDown className=\"size-3.5\" />\n )}\n </button>\n ) : (\n <span className=\"inline-block w-3.5 shrink-0\" />\n )}\n\n {node.isContextOnly ? (\n <span className=\"flex-1 text-left\">{node.name}</span>\n ) : (\n <button type=\"button\" onClick={() => onSelect(node.id)} className=\"flex-1 text-left\">\n {node.name}\n </button>\n )}\n\n {isSelected && <Check className=\"ml-auto size-3.5 shrink-0 text-primary\" />}\n </div>\n {!isCollapsed && hasChildren && (\n <div role=\"group\">\n {node.children.map((child) => (\n <TreeNode\n key={child.id}\n node={child}\n depth={depth + 1}\n selectedId={selectedId}\n onSelect={onSelect}\n collapsedIds={collapsedIds}\n onToggleCollapse={onToggleCollapse}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n","/** Default UI strings. Spread-override via the Header `labels` prop if needed. */\nexport const DEFAULT_LABELS = {\n orgLabel: \"Org\",\n projectLabel: \"Project\",\n projectPlaceholder: \"Select project...\",\n searchPlaceholder: \"Search project\",\n emptyStateText: \"No projects found\",\n profileMenuLabel: \"Profile menu\",\n logoutLabel: \"Logout\",\n} as const;\n\nexport type Labels = typeof DEFAULT_LABELS;\n","import type { Fetcher, HeaderEndpoints, HeaderProps, ProjectNode } from \"./types\";\n\n// Studio-auth API. Endpoints are built from the host-provided `apiBaseUrl` (full\n// domain) so the same header works across environments/subdomains. All requests\n// send cookies (`credentials: 'include'`); the parent-domain session cookie is\n// readable cross-subdomain.\n\nconst PATHS = {\n token: \"/api/v1/studio-auth/sessions/token\",\n logout: \"/api/v1/studio-auth/sessions/logout\",\n projects: (clientId: string) =>\n `/api/v1/client-projects/getAllProjects?limit=50&page=1&sort=name&sortOrder=ASC&clientId=${encodeURIComponent(clientId)}&metaData=true`,\n credits: \"/save/api/v1/users\",\n};\n\n/** Join a base URL and path without doubling slashes. */\nfunction join(baseUrl: string, path: string): string {\n return `${baseUrl.replace(/\\/$/, \"\")}${path}`;\n}\n\nexport function buildEndpoints(\n apiBaseUrl: string,\n overrides?: HeaderProps[\"endpoints\"],\n): HeaderEndpoints {\n return {\n token: overrides?.token ?? join(apiBaseUrl, PATHS.token),\n logout: overrides?.logout ?? join(apiBaseUrl, PATHS.logout),\n projects:\n overrides?.projects ?? ((clientId: string) => join(apiBaseUrl, PATHS.projects(clientId))),\n credits: overrides?.credits ?? join(apiBaseUrl, PATHS.credits),\n };\n}\n\ntype ApiEnvelope<T> = { response?: { data?: T } };\n\nexport async function fetchToken(endpoints: HeaderEndpoints, fetcher: Fetcher): Promise<string> {\n const res = await fetcher(endpoints.token, { credentials: \"include\" });\n if (!res.ok) throw new Error(`token request failed: ${res.status}`);\n const { accessToken } = (await res.json()) as { accessToken: string };\n return accessToken;\n}\n\nexport async function fetchProjects(\n endpoints: HeaderEndpoints,\n clientId: string,\n accessToken: string,\n fetcher: Fetcher,\n): Promise<{ projectsTree: ProjectNode[]; organizationName: string | undefined }> {\n const res = await fetcher(endpoints.projects(clientId), {\n credentials: \"include\",\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (!res.ok) throw new Error(`projects request failed: ${res.status}`);\n const data = (await res.json()) as ApiEnvelope<{\n projectsTree?: ProjectNode[];\n organization?: { name?: string };\n }>;\n return {\n projectsTree: data.response?.data?.projectsTree ?? [],\n organizationName: data.response?.data?.organization?.name,\n };\n}\n\nexport async function fetchCredits(\n endpoints: HeaderEndpoints,\n accessToken: string,\n fetcher: Fetcher,\n): Promise<number | undefined> {\n const res = await fetcher(endpoints.credits, {\n credentials: \"include\",\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (!res.ok) throw new Error(`credits request failed: ${res.status}`);\n const data = (await res.json()) as { remainingCredits?: number };\n return data.remainingCredits;\n}\n\nexport async function callLogout(endpoints: HeaderEndpoints, fetcher: Fetcher): Promise<void> {\n try {\n await fetcher(endpoints.logout, { method: \"POST\", credentials: \"include\" });\n } finally {\n if (typeof window !== \"undefined\") window.location.href = \"/\";\n }\n}\n","// Persists the user's project selection across reloads (sessionStorage), tagged\n// with the client it belongs to so a stale selection from a different org is\n// discarded on re-login. Explicit selections are additionally remembered in\n// localStorage (`lastSelectedProject`) so new tabs default to the project the\n// user picked last — while each tab keeps its own per-tab selection.\n\nconst PROJECT_KEY = \"ds-header-project\";\nconst LAST_PROJECT_KEY = \"lastSelectedProject\";\n\nexport interface StoredProject {\n id: string;\n name: string;\n clientId?: string;\n}\n\nexport function getStoredProject(): StoredProject | null {\n try {\n const raw = sessionStorage.getItem(PROJECT_KEY);\n return raw ? (JSON.parse(raw) as StoredProject) : null;\n } catch {\n return null;\n }\n}\n\nexport function setStoredProject(project: StoredProject): void {\n try {\n sessionStorage.setItem(PROJECT_KEY, JSON.stringify(project));\n } catch {\n // sessionStorage unavailable — degrade silently\n }\n}\n\nexport function clearStoredProject(): void {\n try {\n sessionStorage.removeItem(PROJECT_KEY);\n } catch {\n // noop\n }\n}\n\n/** The project the user last explicitly selected, in any tab (localStorage). */\nexport function getLastSelectedProject(): StoredProject | null {\n try {\n const raw = localStorage.getItem(LAST_PROJECT_KEY);\n return raw ? (JSON.parse(raw) as StoredProject) : null;\n } catch {\n return null;\n }\n}\n\nexport function setLastSelectedProject(project: StoredProject): void {\n try {\n localStorage.setItem(LAST_PROJECT_KEY, JSON.stringify(project));\n } catch {\n // localStorage unavailable — degrade silently\n }\n}\n","\"use client\";\n\nimport * as React from \"react\";\n\nimport {\n clearStoredProject,\n getStoredProject,\n setLastSelectedProject,\n setStoredProject,\n} from \"./storage\";\n\n// Module-level store for the current project/org selection. Module scope (not\n// React context) so a host app can read and change the selection from anywhere —\n// including components rendered outside the <Header> subtree. The Header is one\n// writer/reader; `useHeaderProject()` gives apps the same access.\n\nexport interface HeaderSelection {\n selectedProjectId: string;\n selectedProjectName: string;\n organizationName: string | undefined;\n /** Remaining credits for the logged-in user (read-only here; set by the Header). */\n credits: number | undefined;\n /** Client/org the current selection + org belong to (for cross-org invalidation). */\n clientId: string | undefined;\n}\n\nfunction initialState(): HeaderSelection {\n const stored = typeof window !== \"undefined\" ? getStoredProject() : null;\n return {\n selectedProjectId: stored?.id ?? \"\",\n selectedProjectName: stored?.name ?? \"\",\n organizationName: undefined,\n credits: undefined,\n clientId: stored?.clientId,\n };\n}\n\nlet state: HeaderSelection = initialState();\n// Stable reference for SSR / first server render.\nconst SERVER_SNAPSHOT: HeaderSelection = Object.freeze({\n selectedProjectId: \"\",\n selectedProjectName: \"\",\n organizationName: undefined,\n credits: undefined,\n clientId: undefined,\n});\n\nconst listeners = new Set<() => void>();\nfunction emit() {\n for (const listener of listeners) listener();\n}\n\nexport const headerStore = {\n subscribe(listener: () => void) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n getSnapshot(): HeaderSelection {\n return state;\n },\n getServerSnapshot(): HeaderSelection {\n return SERVER_SNAPSHOT;\n },\n\n /**\n * Set the selected project. `name` is best-effort; the Header backfills it from\n * the tree. Explicit selections are also remembered in localStorage as the\n * cross-tab default; pass `remember: false` for internal backfill/auto-select\n * writes so they don't overwrite the user's last explicit choice.\n */\n setProject(id: string, name = \"\", clientId?: string, { remember = true } = {}) {\n if (id) {\n const project = { id, name, clientId: clientId ?? state.clientId };\n setStoredProject(project);\n if (remember) setLastSelectedProject(project);\n } else clearStoredProject();\n state = {\n ...state,\n selectedProjectId: id,\n selectedProjectName: name,\n clientId: clientId ?? state.clientId,\n };\n emit();\n },\n\n clearProject() {\n clearStoredProject();\n state = { ...state, selectedProjectId: \"\", selectedProjectName: \"\" };\n emit();\n },\n\n setOrganization(name: string | undefined, clientId?: string) {\n state = { ...state, organizationName: name, clientId: clientId ?? state.clientId };\n emit();\n },\n\n setCredits(credits: number | undefined) {\n if (state.credits === credits) return;\n state = { ...state, credits };\n emit();\n },\n\n /** When the active client changes, drop a selection/org from the previous one. */\n reconcileClient(clientId: string) {\n if (state.clientId === clientId) return;\n if (state.clientId && state.clientId !== clientId) {\n clearStoredProject();\n state = {\n selectedProjectId: \"\",\n selectedProjectName: \"\",\n organizationName: undefined,\n credits: state.credits, // user-level — survives org switches\n clientId,\n };\n } else {\n state = { ...state, clientId };\n }\n emit();\n },\n};\n\n/** Internal: subscribe a component to the selection store. */\nexport function useHeaderStore(): HeaderSelection {\n return React.useSyncExternalStore(\n headerStore.subscribe,\n headerStore.getSnapshot,\n headerStore.getServerSnapshot,\n );\n}\n\nexport interface UseHeaderProjectResult {\n selectedProjectId: string;\n selectedProjectName: string | undefined;\n organizationName: string | undefined;\n /** Set the active project from outside the Header (by id). */\n setProject: (id: string) => void;\n /** Clear this tab's active project (the header re-defaults on next projects load). */\n clearProject: () => void;\n}\n\n/**\n * Read the current project/org and change the project from anywhere in the app —\n * no need to be inside the <Header>. Reflects user selections made in the header\n * and updates the header when changed here.\n */\nexport function useHeaderProject(): UseHeaderProjectResult {\n const snapshot = useHeaderStore();\n return {\n selectedProjectId: snapshot.selectedProjectId,\n selectedProjectName: snapshot.selectedProjectName || undefined,\n organizationName: snapshot.organizationName,\n setProject: React.useCallback((id: string) => headerStore.setProject(id), []),\n clearProject: React.useCallback(() => headerStore.clearProject(), []),\n };\n}\n\n/** Read the logged-in user's remaining credits (read-only; the Header owns it). */\nexport function useHeaderCredits(): number | undefined {\n return useHeaderStore().credits;\n}\n","// Client-side session detection. The auth system writes a JS-readable cookie\n// `{environmentId}-sessionId` (a JWT) on the shared parent domain. We decode it\n// and check its expiry to know whether the user is logged in — no network call.\n\ninterface JwtPayload {\n exp?: number;\n [key: string]: unknown;\n}\n\n/** Read the raw session JWT from the `{environmentId}-sessionId` cookie. */\nexport function getSessionToken(environmentId: string): string | null {\n if (typeof document === \"undefined\") return null;\n const name = `${environmentId}-sessionId`;\n for (const part of document.cookie.split(\";\")) {\n const [key, ...rest] = part.trim().split(\"=\");\n if (key === name) return decodeURIComponent(rest.join(\"=\"));\n }\n return null;\n}\n\n/** Decode a JWT payload without verifying the signature (display/expiry only). */\nexport function decodeJwt(token: string): JwtPayload | null {\n try {\n const payload = token.split(\".\")[1];\n if (!payload) return null;\n const base64 = payload.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const json = atob(base64);\n return JSON.parse(json) as JwtPayload;\n } catch {\n return null;\n }\n}\n\n/** User/session claims carried in the session JWT (the subset the header uses). */\nexport interface SessionClaims {\n email?: string;\n name?: string;\n userId?: string;\n /** Active organisation id (`client_id` claim). */\n clientId?: string;\n exp?: number;\n}\n\n/**\n * Decode the user claims from the session cookie's JWT — no network call.\n * Returns null when the cookie is absent or undecodable.\n */\nexport function getSessionClaims(environmentId: string): SessionClaims | null {\n const token = getSessionToken(environmentId);\n if (!token) return null;\n const payload = decodeJwt(token);\n if (!payload) return null;\n const str = (v: unknown) => (typeof v === \"string\" ? v : undefined);\n return {\n email: str(payload.email),\n name: str(payload.name),\n userId: str(payload.user_id),\n clientId: str(payload.client_id),\n exp: typeof payload.exp === \"number\" ? payload.exp : undefined,\n };\n}\n\n/** True when a valid, unexpired session cookie exists for the environment. */\nexport function isSessionValid(environmentId: string): boolean {\n const token = getSessionToken(environmentId);\n if (!token) return false;\n const payload = decodeJwt(token);\n if (!payload) return false;\n // No exp claim → treat as a non-expiring session.\n if (typeof payload.exp !== \"number\") return true;\n return payload.exp * 1000 > Date.now();\n}\n","\"use client\";\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport * as React from \"react\";\n\nimport { buildEndpoints, callLogout, fetchCredits, fetchProjects, fetchToken } from \"./api\";\nimport { headerStore, useHeaderStore } from \"./header-store\";\nimport { findProjectName, firstSelectableProject, nodeExistsInTree } from \"./project-tree\";\nimport { getSessionClaims, isSessionValid } from \"./session\";\nimport { getLastSelectedProject } from \"./storage\";\nimport type { HeaderProps, ProjectNode } from \"./types\";\n\n/** Window event other modules can dispatch to show/hide the project dropdown. */\nexport const TOGGLE_PROJECT_DROPDOWN_EVENT = \"toggle-project-dropdown\";\nexport interface ToggleProjectDropdownDetail {\n show: boolean;\n}\n\nconst DEFAULT_STALE_TIME = 5 * 60_000;\nconst DEFAULT_GC_TIME = 10 * 60_000;\n\nexport interface GlobalHeaderState {\n /** Whether a valid session cookie exists — when false, hide all user content. */\n isAuthenticated: boolean;\n userEmail: string | undefined;\n organizationName: string | undefined;\n projectsTree: ProjectNode[];\n selectedProjectId: string;\n selectedProjectName: string | undefined;\n isProjectsLoading: boolean;\n isOrgLoading: boolean;\n /** Remaining credits for the user (undefined until loaded / when disabled). */\n credits: number | undefined;\n /** Where the credits pill links to (studio-auth `/user/activity`). */\n creditsHref: string;\n projectDropdownVisible: boolean;\n selectProject: (id: string) => void;\n logout: () => void;\n}\n\ntype UseGlobalHeaderArgs = Pick<\n HeaderProps,\n | \"apiBaseUrl\"\n | \"environmentId\"\n | \"clientId\"\n | \"_dangerouslyInjectAccessToken\"\n | \"showProjectDropdown\"\n | \"showProfile\"\n | \"showOrg\"\n | \"showCredits\"\n | \"endpoints\"\n | \"fetcher\"\n | \"staleTime\"\n | \"gcTime\"\n | \"onProjectChange\"\n>;\n\nexport function useGlobalHeader({\n apiBaseUrl,\n environmentId,\n clientId,\n _dangerouslyInjectAccessToken: injectedToken,\n showProjectDropdown = false,\n showProfile = false,\n showOrg = false,\n showCredits = false,\n endpoints: endpointOverrides,\n fetcher: fetcherProp,\n staleTime = DEFAULT_STALE_TIME,\n gcTime = DEFAULT_GC_TIME,\n onProjectChange,\n}: UseGlobalHeaderArgs): GlobalHeaderState {\n const fetcher = React.useMemo(\n () => fetcherProp ?? ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, init)),\n [fetcherProp],\n );\n const endpoints = React.useMemo(\n () => buildEndpoints(apiBaseUrl, endpointOverrides),\n [apiBaseUrl, endpointOverrides],\n );\n\n // Read the session cookie each render (cheap); gates every network call.\n // User identity (email, client id) comes from the JWT claims — no /me call.\n const isAuthenticated = isSessionValid(environmentId);\n const claims = getSessionClaims(environmentId);\n\n // token → projects, enabled only when the previous resolved.\n const tokenQuery = useQuery({\n queryKey: [\"ds-header\", \"token\", endpoints.token],\n queryFn: () => fetchToken(endpoints, fetcher),\n enabled: isAuthenticated && !injectedToken,\n staleTime,\n gcTime,\n });\n const token = injectedToken ?? tokenQuery.data;\n\n const effectiveClientId = clientId ?? claims?.clientId;\n const wantsProjects = showProjectDropdown || showOrg;\n const projectsQuery = useQuery({\n queryKey: [\"ds-header\", \"projects\", effectiveClientId, token],\n queryFn: () => fetchProjects(endpoints, effectiveClientId as string, token as string, fetcher),\n enabled: isAuthenticated && !!token && !!effectiveClientId && wantsProjects,\n staleTime,\n gcTime,\n });\n\n // Credits — only needs the token. Always refetched on mount (staleTime 0) so a\n // page refresh shows the current balance.\n const creditsQuery = useQuery({\n queryKey: [\"ds-header\", \"credits\", endpoints.credits, token],\n queryFn: () => fetchCredits(endpoints, token as string, fetcher),\n enabled: isAuthenticated && !!token && showCredits,\n staleTime: 0,\n gcTime,\n });\n\n const projectsTree = projectsQuery.data?.projectsTree ?? [];\n const userEmail = showProfile ? claims?.email : undefined;\n const creditsHref = React.useMemo(() => {\n try {\n return new URL(\"/user/activity\", apiBaseUrl).toString();\n } catch {\n return \"/user/activity\";\n }\n }, [apiBaseUrl]);\n\n // Selection + org live in a module store so host apps can read/change them\n // from outside the header (see useHeaderProject).\n const selection = useHeaderStore();\n\n // Ref so the auto-select effect sees the latest callback without re-running.\n const onProjectChangeRef = React.useRef(onProjectChange);\n React.useEffect(() => {\n onProjectChangeRef.current = onProjectChange;\n });\n\n // Once the client id resolves, drop a selection/org from a different client.\n React.useEffect(() => {\n if (effectiveClientId) headerStore.reconcileClient(effectiveClientId);\n }, [effectiveClientId]);\n\n // Once projects load: publish the org name and validate/backfill the selection.\n // A tab with no valid selection defaults to the user's last explicitly selected\n // project (localStorage `lastSelectedProject`) when it still exists in the\n // tree, else the first selectable project — no selection prompt.\n React.useEffect(() => {\n if (!projectsQuery.data) return;\n const tree = projectsQuery.data.projectsTree;\n const id = headerStore.getSnapshot().selectedProjectId;\n if (id && nodeExistsInTree(tree, id)) {\n const name = findProjectName(tree, id);\n if (name && name !== headerStore.getSnapshot().selectedProjectName) {\n headerStore.setProject(id, name, effectiveClientId, { remember: false });\n }\n } else {\n const last = getLastSelectedProject();\n const fallback =\n last && nodeExistsInTree(tree, last.id)\n ? { id: last.id, name: findProjectName(tree, last.id) ?? last.name }\n : firstSelectableProject(tree);\n if (fallback) {\n headerStore.setProject(fallback.id, fallback.name, effectiveClientId, {\n remember: false,\n });\n onProjectChangeRef.current?.(fallback.id);\n } else if (id) {\n headerStore.clearProject();\n }\n }\n headerStore.setOrganization(projectsQuery.data.organizationName, effectiveClientId);\n }, [projectsQuery.data, effectiveClientId]);\n\n // Publish credits to the store so host apps can read them via useHeaderCredits.\n React.useEffect(() => {\n if (creditsQuery.data !== undefined) headerStore.setCredits(creditsQuery.data);\n }, [creditsQuery.data]);\n\n const selectProject = (id: string) => {\n const name = findProjectName(projectsTree, id) ?? \"\";\n headerStore.setProject(id, name, effectiveClientId);\n onProjectChange?.(id);\n };\n\n const logout = () => {\n headerStore.clearProject();\n void callLogout(endpoints, fetcher);\n };\n\n // Visibility: declarative from the prop, overridable at runtime via the event.\n const [projectDropdownVisible, setProjectDropdownVisible] = React.useState(showProjectDropdown);\n React.useEffect(() => setProjectDropdownVisible(showProjectDropdown), [showProjectDropdown]);\n React.useEffect(() => {\n const handler = (e: Event) => {\n setProjectDropdownVisible((e as CustomEvent<ToggleProjectDropdownDetail>).detail.show);\n };\n window.addEventListener(TOGGLE_PROJECT_DROPDOWN_EVENT, handler);\n return () => window.removeEventListener(TOGGLE_PROJECT_DROPDOWN_EVENT, handler);\n }, []);\n\n const isProjectsLoading = projectsQuery.isFetching && !projectsQuery.data;\n\n return {\n isAuthenticated,\n userEmail,\n organizationName: selection.organizationName,\n projectsTree,\n selectedProjectId: selection.selectedProjectId,\n selectedProjectName: selection.selectedProjectName || undefined,\n isProjectsLoading,\n isOrgLoading: showOrg && isProjectsLoading,\n credits: selection.credits,\n creditsHref,\n projectDropdownVisible,\n selectProject,\n logout,\n };\n}\n","\"use client\";\n\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { LogOut, MessageSquareShare, Moon, Sun } from \"lucide-react\";\nimport type * as React from \"react\";\n\nimport { Avatar, AvatarFallback } from \"@/primitives/Avatar\";\nimport { Button } from \"@/primitives/Button\";\nimport { Credits } from \"@/primitives/Credits\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/primitives/DropdownMenu\";\nimport { Logo } from \"@/primitives/Logo\";\nimport { Skeleton } from \"@/primitives/Skeleton\";\nimport { type ThemeProduct, useTheme } from \"@/primitives/ThemeProvider\";\nimport { cn } from \"@/utils\";\nimport { ProjectPicker } from \"./ProjectPicker\";\nimport { DEFAULT_LABELS } from \"./labels\";\nimport type { HeaderProps } from \"./types\";\nimport { useGlobalHeader } from \"./use-global-header\";\n\n// Fallback logo destinations when the host doesn't pass `logoHref`.\nconst LOGO_HREF: Record<ThemeProduct, string> = {\n psai: \"https://sapientaiproducts.com/\",\n slingshot: \"https://sapientaiproducts.com/slingshot\",\n sustain: \"https://www.publicissapient.com/\",\n bodhi: \"https://sapientaiproducts.com/bodhi\",\n};\n\nconst PILL =\n \"flex min-h-8 items-center gap-1 rounded-12 border border-primary-border bg-input-bg px-3 py-1 text-xs leading-4\";\n\n// ── Presentational parts (props-driven; Storybook/VR-able) ──────────────────\n\n/** The header bar shell — a sticky glass strip. */\nfunction HeaderBar({ className, ...props }: React.ComponentProps<\"header\">) {\n return (\n <header\n data-slot=\"header\"\n className={cn(\n \"sticky top-1 z-10 mt-1 flex h-15 items-center gap-5 rounded-16 px-3 py-2\",\n \"bg-glass-60-bg backdrop-blur-glass\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/** Product logo linking to its home, with a Suspense-safe fallback. */\nfunction HeaderLogo({ brand, href }: { brand: ThemeProduct; href?: string }) {\n return (\n <a href={href ?? LOGO_HREF[brand]} aria-label=\"Go to product home\" data-slot=\"header-logo\">\n <Logo brand={brand} className=\"h-8 w-auto\" />\n </a>\n );\n}\n\n/** Read-only organisation pill. */\nfunction OrgPill({ name, loading }: { name?: string; loading?: boolean }) {\n if (loading && !name) {\n return (\n <div className={cn(PILL, \"ml-3\")} data-slot=\"header-org\">\n <span className=\"shrink-0 text-muted-txt\">{DEFAULT_LABELS.orgLabel}:</span>\n <Skeleton className=\"h-4 w-24\" />\n </div>\n );\n }\n if (!name) return null;\n return (\n <div className={cn(PILL, \"ml-3 select-none\")} title={name} data-slot=\"header-org\">\n <span className=\"shrink-0 text-muted-txt\">{DEFAULT_LABELS.orgLabel}:</span>\n <span className=\"max-w-36 truncate text-primary-txt\">{name}</span>\n </div>\n );\n}\n\n/** Light/dark toggle — defers to ThemeProvider. */\nfunction ThemeToggle() {\n const { theme, toggleTheme } = useTheme();\n return (\n <Button variant=\"ghost\" size=\"icon\" onClick={toggleTheme} aria-label=\"Toggle theme\">\n {theme === \"light\" ? <Moon className=\"size-4\" /> : <Sun className=\"size-4\" />}\n </Button>\n );\n}\n\n/** Profile menu — avatar trigger with email + logout. */\nfunction ProfileMenu({ email, onLogout }: { email?: string; onLogout: () => void }) {\n const initial = email?.trim().charAt(0).toUpperCase() || \"?\";\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" aria-label={DEFAULT_LABELS.profileMenuLabel}>\n <Avatar className=\"size-7\">\n <AvatarFallback>{initial}</AvatarFallback>\n </Avatar>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" sideOffset={8} className=\"min-w-44\">\n {email && (\n <>\n <DropdownMenuLabel className=\"truncate font-normal text-muted-txt\">\n {email}\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n </>\n )}\n <DropdownMenuItem onSelect={onLogout} variant=\"destructive\">\n <LogOut />\n {DEFAULT_LABELS.logoutLabel}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport { HeaderBar, HeaderLogo, OrgPill, ThemeToggle, ProfileMenu };\n\n// ── Wired Header ─────────────────────────────────────────────────────────────\n\n// Internal singleton client so the header is drop-in (no app setup) while still\n// sharing its cache across mounts/navigation.\nlet sharedClient: QueryClient | undefined;\nfunction getQueryClient(): QueryClient {\n sharedClient ??= new QueryClient({\n defaultOptions: { queries: { retry: 1, refetchOnWindowFocus: false } },\n });\n return sharedClient;\n}\n\n/** Drop-in global header. Must be rendered inside a <ThemeProvider>. */\nexport function Header(props: HeaderProps) {\n return (\n <QueryClientProvider client={getQueryClient()}>\n <HeaderInner {...props} />\n </QueryClientProvider>\n );\n}\n\nfunction HeaderInner({\n logoType,\n logoHref,\n showOrg = false,\n showProjectDropdown = false,\n showProfile = false,\n showThemeSwitcher = false,\n showCredits = false,\n pageTitle,\n feedbackUrl,\n logoAddon,\n actionsStart,\n actionsEnd,\n className,\n ...rest\n}: HeaderProps) {\n const { product } = useTheme();\n const brand = logoType ?? product;\n const state = useGlobalHeader({\n showOrg,\n showProjectDropdown,\n showProfile,\n showCredits,\n ...rest,\n });\n\n // Logged-out users see no user content (project/org/profile/credits).\n const showProjectUi = showProjectDropdown && state.isAuthenticated;\n const showOrgUi = showOrg && state.isAuthenticated;\n const showProfileUi = showProfile && state.isAuthenticated;\n const showCreditsUi = showCredits && state.isAuthenticated && state.credits !== undefined;\n const showActions =\n showThemeSwitcher ||\n showProfileUi ||\n showCreditsUi ||\n !!feedbackUrl ||\n !!actionsStart ||\n !!actionsEnd;\n\n return (\n <HeaderBar className={className}>\n <HeaderLogo brand={brand} href={logoHref} />\n {/* Page title — 20px (gap-5) from the logo. */}\n {pageTitle && (\n <span data-slot=\"header-title\" className=\"ml-5 font-semibold text-primary-txt text-sm\">\n {pageTitle}\n </span>\n )}\n {logoAddon}\n\n {showOrgUi && <OrgPill name={state.organizationName} loading={state.isOrgLoading} />}\n\n {showProjectUi && state.projectDropdownVisible && (\n <div className=\"ml-2\">\n <ProjectPicker\n projectsTree={state.projectsTree}\n selectedProjectId={state.selectedProjectId}\n selectedProjectName={state.selectedProjectName}\n onSelect={state.selectProject}\n projectLabel={DEFAULT_LABELS.projectLabel}\n projectPlaceholder={DEFAULT_LABELS.projectPlaceholder}\n searchPlaceholder={DEFAULT_LABELS.searchPlaceholder}\n emptyStateText={DEFAULT_LABELS.emptyStateText}\n isLoading={state.isProjectsLoading}\n />\n </div>\n )}\n\n {showActions && (\n <div className=\"ml-auto flex items-center gap-2\">\n {actionsStart}\n {feedbackUrl && (\n <Button variant=\"ghost\" size=\"icon\" asChild>\n <a\n href={feedbackUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label=\"Share feedback\"\n >\n <MessageSquareShare className=\"size-4\" />\n </a>\n </Button>\n )}\n {showThemeSwitcher && <ThemeToggle />}\n {showCreditsUi && state.credits !== undefined && (\n <a\n href={state.creditsHref}\n aria-label=\"View credit activity\"\n className=\"rounded-full outline-none focus-visible:ring-3 focus-visible:ring-focus\"\n >\n <Credits value={state.credits} />\n </a>\n )}\n {showProfileUi && <ProfileMenu email={state.userEmail} onLogout={state.logout} />}\n {actionsEnd}\n </div>\n )}\n </HeaderBar>\n );\n}\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime266 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime232 from "react/jsx-runtime";
2
2
  import { Accordion } from "radix-ui";
3
3
 
4
4
  //#region src/primitives/Accordion/Accordion.d.ts
@@ -10,24 +10,24 @@ declare function Accordion$1({
10
10
  }: React.ComponentProps<typeof Accordion.Root> & {
11
11
  /** Visual style: `line` (divider rows) or `bordered` (rounded border with inset rows). */
12
12
  variant?: "line" | "bordered";
13
- }): react_jsx_runtime266.JSX.Element;
13
+ }): react_jsx_runtime232.JSX.Element;
14
14
  /** A single collapsible section; identified by its required `value`. */
15
15
  declare function AccordionItem({
16
16
  className,
17
17
  ...props
18
- }: React.ComponentProps<typeof Accordion.Item>): react_jsx_runtime266.JSX.Element;
18
+ }: React.ComponentProps<typeof Accordion.Item>): react_jsx_runtime232.JSX.Element;
19
19
  /** The clickable header that toggles its section open or closed. */
20
20
  declare function AccordionTrigger({
21
21
  className,
22
22
  children,
23
23
  ...props
24
- }: React.ComponentProps<typeof Accordion.Trigger>): react_jsx_runtime266.JSX.Element;
24
+ }: React.ComponentProps<typeof Accordion.Trigger>): react_jsx_runtime232.JSX.Element;
25
25
  /** The animated collapsible panel revealed when its section is open. */
26
26
  declare function AccordionContent({
27
27
  className,
28
28
  children,
29
29
  ...props
30
- }: React.ComponentProps<typeof Accordion.Content>): react_jsx_runtime266.JSX.Element;
30
+ }: React.ComponentProps<typeof Accordion.Content>): react_jsx_runtime232.JSX.Element;
31
31
  //#endregion
32
32
  export { AccordionTrigger as i, AccordionContent as n, AccordionItem as r, Accordion$1 as t };
33
33
  //# sourceMappingURL=index.d.cts.map
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Accordion } from "radix-ui";
2
- import * as react_jsx_runtime23 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime307 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/primitives/Accordion/Accordion.d.ts
5
5
  /** A vertically stacked set of collapsible sections built on Radix Accordion. */
@@ -10,24 +10,24 @@ declare function Accordion$1({
10
10
  }: React.ComponentProps<typeof Accordion.Root> & {
11
11
  /** Visual style: `line` (divider rows) or `bordered` (rounded border with inset rows). */
12
12
  variant?: "line" | "bordered";
13
- }): react_jsx_runtime23.JSX.Element;
13
+ }): react_jsx_runtime307.JSX.Element;
14
14
  /** A single collapsible section; identified by its required `value`. */
15
15
  declare function AccordionItem({
16
16
  className,
17
17
  ...props
18
- }: React.ComponentProps<typeof Accordion.Item>): react_jsx_runtime23.JSX.Element;
18
+ }: React.ComponentProps<typeof Accordion.Item>): react_jsx_runtime307.JSX.Element;
19
19
  /** The clickable header that toggles its section open or closed. */
20
20
  declare function AccordionTrigger({
21
21
  className,
22
22
  children,
23
23
  ...props
24
- }: React.ComponentProps<typeof Accordion.Trigger>): react_jsx_runtime23.JSX.Element;
24
+ }: React.ComponentProps<typeof Accordion.Trigger>): react_jsx_runtime307.JSX.Element;
25
25
  /** The animated collapsible panel revealed when its section is open. */
26
26
  declare function AccordionContent({
27
27
  className,
28
28
  children,
29
29
  ...props
30
- }: React.ComponentProps<typeof Accordion.Content>): react_jsx_runtime23.JSX.Element;
30
+ }: React.ComponentProps<typeof Accordion.Content>): react_jsx_runtime307.JSX.Element;
31
31
  //#endregion
32
32
  export { AccordionTrigger as i, AccordionContent as n, AccordionItem as r, Accordion$1 as t };
33
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/primitives/Accordion/Accordion.tsx"],"mappings":";;;;;iBAKS,WAAA;;;;GAIN,KAAA,CAAM,sBAAsB,SAAA,CAAmB;;EAJzC,OAAA,CAAA,EAAA,MAAS,GAAA,UAAA;CAAA,CAAA,EAOjB,mBAAA,CAAA,GAAA,CAAA,OAPiB;;iBAyBT,aAAA,CAvBP;EAAA,SAAA;EAAA,GAAA;AAAA,CAAA,EA0BC,KAAA,CAAM,cA1BP,CAAA,OA0B6B,SAAA,CAAmB,IA1BhD,CAAA,CAAA,EA0BqD,mBAAA,CAAA,GAAA,CAAA,OA1BrD;;iBAwCO,gBAAA,CAtCA;EAAA,SAAA;EAAA,QAAA;EAAA,GAAA;AAAA,CAAA,EA0CN,KAAA,CAAM,cA1CA,CAAA,OA0CsB,SAAA,CAAmB,OA1CzC,CAAA,CAAA,EA0CiD,mBAAA,CAAA,GAAA,CAAA,OA1CjD;;AAGR,iBA2DQ,gBAAA,CA3DR;EAAA,SAAA;EAAA,QAAA;EAAA,GAAA;AAAA,CAAA,EA+DE,KAAA,CAAM,cA/DR,CAAA,OA+D8B,SAAA,CAAmB,OA/DjD,CAAA,CAAA,EA+DyD,mBAAA,CAAA,GAAA,CAAA,OA/DzD"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/primitives/Accordion/Accordion.tsx"],"mappings":";;;;;iBAKS,WAAA;;;;GAIN,KAAA,CAAM,sBAAsB,SAAA,CAAmB;;EAJzC,OAAA,CAAA,EAAA,MAAS,GAAA,UAAA;CAAA,CAAA,EAOjB,oBAAA,CAAA,GAAA,CAAA,OAPiB;;iBAyBT,aAAA,CAvBP;EAAA,SAAA;EAAA,GAAA;AAAA,CAAA,EA0BC,KAAA,CAAM,cA1BP,CAAA,OA0B6B,SAAA,CAAmB,IA1BhD,CAAA,CAAA,EA0BqD,oBAAA,CAAA,GAAA,CAAA,OA1BrD;;iBAwCO,gBAAA,CAtCA;EAAA,SAAA;EAAA,QAAA;EAAA,GAAA;AAAA,CAAA,EA0CN,KAAA,CAAM,cA1CA,CAAA,OA0CsB,SAAA,CAAmB,OA1CzC,CAAA,CAAA,EA0CiD,oBAAA,CAAA,GAAA,CAAA,OA1CjD;;AAGR,iBA2DQ,gBAAA,CA3DR;EAAA,SAAA;EAAA,QAAA;EAAA,GAAA;AAAA,CAAA,EA+DE,KAAA,CAAM,cA/DR,CAAA,OA+D8B,SAAA,CAAmB,OA/DjD,CAAA,CAAA,EA+DyD,oBAAA,CAAA,GAAA,CAAA,OA/DzD"}