@vertesia/ui 1.5.0-dev.20260901.045442Z → 1.5.0-dev.20260905.011013Z

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 (139) hide show
  1. package/lib/features/agent/chat/AgentRightPanel.d.ts +2 -3
  2. package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
  3. package/lib/features/agent/chat/AgentRightPanel.js +3 -3
  4. package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
  5. package/lib/features/agent/chat/DocumentPanel.d.ts +7 -7
  6. package/lib/features/agent/chat/DocumentPanel.d.ts.map +1 -1
  7. package/lib/features/agent/chat/DocumentPanel.js +6 -12
  8. package/lib/features/agent/chat/DocumentPanel.js.map +1 -1
  9. package/lib/features/agent/chat/DocumentsTab.d.ts +15 -0
  10. package/lib/features/agent/chat/DocumentsTab.d.ts.map +1 -0
  11. package/lib/features/agent/chat/DocumentsTab.js +33 -0
  12. package/lib/features/agent/chat/DocumentsTab.js.map +1 -0
  13. package/lib/features/agent/chat/ModernAgentConversation.js +2 -2
  14. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  15. package/lib/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
  16. package/lib/features/agent/chat/ModernAgentOutput/Header.js +15 -10
  17. package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  18. package/lib/features/agent/chat/hooks/useDocumentPanel.d.ts +2 -2
  19. package/lib/features/agent/chat/hooks/useDocumentPanel.d.ts.map +1 -1
  20. package/lib/features/agent/chat/hooks/useDocumentPanel.js +0 -18
  21. package/lib/features/agent/chat/hooks/useDocumentPanel.js.map +1 -1
  22. package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -1
  23. package/lib/features/oauth/McpConnectionsButton.js +4 -1
  24. package/lib/features/oauth/McpConnectionsButton.js.map +1 -1
  25. package/lib/features/oauth/McpConnectionsDialog.d.ts.map +1 -1
  26. package/lib/features/oauth/McpConnectionsDialog.js +3 -2
  27. package/lib/features/oauth/McpConnectionsDialog.js.map +1 -1
  28. package/lib/features/oauth/useMcpConnections.d.ts +6 -7
  29. package/lib/features/oauth/useMcpConnections.d.ts.map +1 -1
  30. package/lib/features/oauth/useMcpConnections.js +27 -20
  31. package/lib/features/oauth/useMcpConnections.js.map +1 -1
  32. package/lib/features/store/types/TypeRegistry.d.ts +10 -5
  33. package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
  34. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +10 -5
  35. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
  36. package/lib/i18n/locales/ar.json +10 -0
  37. package/lib/i18n/locales/de.json +6 -0
  38. package/lib/i18n/locales/en.json +6 -0
  39. package/lib/i18n/locales/es.json +6 -0
  40. package/lib/i18n/locales/fr.json +6 -0
  41. package/lib/i18n/locales/it.json +6 -0
  42. package/lib/i18n/locales/ja.json +6 -0
  43. package/lib/i18n/locales/ko.json +6 -0
  44. package/lib/i18n/locales/pt.json +6 -0
  45. package/lib/i18n/locales/ru.json +8 -0
  46. package/lib/i18n/locales/tr.json +6 -0
  47. package/lib/i18n/locales/zh-TW.json +6 -0
  48. package/lib/i18n/locales/zh.json +6 -0
  49. package/lib/router/NestedNavigationContext.d.ts +3 -1
  50. package/lib/router/NestedNavigationContext.d.ts.map +1 -1
  51. package/lib/router/NestedNavigationContext.js +2 -2
  52. package/lib/router/NestedNavigationContext.js.map +1 -1
  53. package/lib/vertesia-ui-features.js +14 -14
  54. package/lib/vertesia-ui-features.js.map +1 -1
  55. package/lib/vertesia-ui-i18n.3yHWompP.chunk.js +5 -0
  56. package/lib/vertesia-ui-i18n.3yHWompP.chunk.js.map +1 -0
  57. package/lib/vertesia-ui-i18n.4XKCcnL0.chunk.js +5 -0
  58. package/lib/vertesia-ui-i18n.4XKCcnL0.chunk.js.map +1 -0
  59. package/lib/vertesia-ui-i18n.78KG4J25.chunk.js +5 -0
  60. package/lib/vertesia-ui-i18n.78KG4J25.chunk.js.map +1 -0
  61. package/lib/vertesia-ui-i18n.BN06mpp1.chunk.js +5 -0
  62. package/lib/vertesia-ui-i18n.BN06mpp1.chunk.js.map +1 -0
  63. package/lib/vertesia-ui-i18n.CSzKLlHJ.chunk.js +5 -0
  64. package/lib/vertesia-ui-i18n.CSzKLlHJ.chunk.js.map +1 -0
  65. package/lib/vertesia-ui-i18n.Ccus7aRh.chunk.js +5 -0
  66. package/lib/vertesia-ui-i18n.Ccus7aRh.chunk.js.map +1 -0
  67. package/lib/vertesia-ui-i18n.D9j3c6gI.chunk.js +5 -0
  68. package/lib/vertesia-ui-i18n.D9j3c6gI.chunk.js.map +1 -0
  69. package/lib/vertesia-ui-i18n.DAUg4rrI.chunk.js +5 -0
  70. package/lib/vertesia-ui-i18n.DAUg4rrI.chunk.js.map +1 -0
  71. package/lib/vertesia-ui-i18n.DSxVZKXy.chunk.js +5 -0
  72. package/lib/vertesia-ui-i18n.DSxVZKXy.chunk.js.map +1 -0
  73. package/lib/vertesia-ui-i18n.aahVhHvR.chunk.js +5 -0
  74. package/lib/vertesia-ui-i18n.aahVhHvR.chunk.js.map +1 -0
  75. package/lib/vertesia-ui-i18n.js +2 -2
  76. package/lib/vertesia-ui-i18n.nZ3xJ26v.chunk.js +5 -0
  77. package/lib/vertesia-ui-i18n.nZ3xJ26v.chunk.js.map +1 -0
  78. package/lib/vertesia-ui-i18n.xPYbuFzT.chunk.js +5 -0
  79. package/lib/vertesia-ui-i18n.xPYbuFzT.chunk.js.map +1 -0
  80. package/lib/vertesia-ui-router.js +1 -1
  81. package/lib/vertesia-ui-router.js.map +1 -1
  82. package/package.json +7 -7
  83. package/src/features/agent/chat/AgentRightPanel.tsx +4 -8
  84. package/src/features/agent/chat/DocumentPanel.tsx +39 -48
  85. package/src/features/agent/chat/DocumentsTab.test.tsx +87 -0
  86. package/src/features/agent/chat/DocumentsTab.tsx +124 -0
  87. package/src/features/agent/chat/ModernAgentConversation.test.tsx +0 -1
  88. package/src/features/agent/chat/ModernAgentConversation.tsx +0 -2
  89. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +27 -14
  90. package/src/features/agent/chat/hooks/useDocumentPanel.test.tsx +33 -0
  91. package/src/features/agent/chat/hooks/useDocumentPanel.ts +3 -20
  92. package/src/features/oauth/McpConnectionsButton.test.tsx +79 -8
  93. package/src/features/oauth/McpConnectionsButton.tsx +6 -3
  94. package/src/features/oauth/McpConnectionsDialog.tsx +9 -3
  95. package/src/features/oauth/useMcpConnections.ts +33 -27
  96. package/src/i18n/locales/ar.json +10 -0
  97. package/src/i18n/locales/de.json +6 -0
  98. package/src/i18n/locales/en.json +6 -0
  99. package/src/i18n/locales/es.json +6 -0
  100. package/src/i18n/locales/fr.json +6 -0
  101. package/src/i18n/locales/it.json +6 -0
  102. package/src/i18n/locales/ja.json +6 -0
  103. package/src/i18n/locales/ko.json +6 -0
  104. package/src/i18n/locales/pt.json +6 -0
  105. package/src/i18n/locales/ru.json +8 -0
  106. package/src/i18n/locales/tr.json +6 -0
  107. package/src/i18n/locales/zh-TW.json +6 -0
  108. package/src/i18n/locales/zh.json +6 -0
  109. package/src/router/NestedNavigationContext.test.tsx +54 -0
  110. package/src/router/NestedNavigationContext.tsx +9 -2
  111. package/lib/features/agent/chat/DocumentTabBar.d.ts +0 -9
  112. package/lib/features/agent/chat/DocumentTabBar.d.ts.map +0 -1
  113. package/lib/features/agent/chat/DocumentTabBar.js +0 -9
  114. package/lib/features/agent/chat/DocumentTabBar.js.map +0 -1
  115. package/lib/vertesia-ui-i18n.BJBGsq-8.chunk.js +0 -5
  116. package/lib/vertesia-ui-i18n.BJBGsq-8.chunk.js.map +0 -1
  117. package/lib/vertesia-ui-i18n.BY5YG5cX.chunk.js +0 -5
  118. package/lib/vertesia-ui-i18n.BY5YG5cX.chunk.js.map +0 -1
  119. package/lib/vertesia-ui-i18n.Bd5_1BXO.chunk.js +0 -5
  120. package/lib/vertesia-ui-i18n.Bd5_1BXO.chunk.js.map +0 -1
  121. package/lib/vertesia-ui-i18n.Bvwej2HH.chunk.js +0 -5
  122. package/lib/vertesia-ui-i18n.Bvwej2HH.chunk.js.map +0 -1
  123. package/lib/vertesia-ui-i18n.CMT3f4gf.chunk.js +0 -5
  124. package/lib/vertesia-ui-i18n.CMT3f4gf.chunk.js.map +0 -1
  125. package/lib/vertesia-ui-i18n.D56DNPJW.chunk.js +0 -5
  126. package/lib/vertesia-ui-i18n.D56DNPJW.chunk.js.map +0 -1
  127. package/lib/vertesia-ui-i18n.DDzKLNx6.chunk.js +0 -5
  128. package/lib/vertesia-ui-i18n.DDzKLNx6.chunk.js.map +0 -1
  129. package/lib/vertesia-ui-i18n.D_Am1LpF.chunk.js +0 -5
  130. package/lib/vertesia-ui-i18n.D_Am1LpF.chunk.js.map +0 -1
  131. package/lib/vertesia-ui-i18n.DrZizgGV.chunk.js +0 -5
  132. package/lib/vertesia-ui-i18n.DrZizgGV.chunk.js.map +0 -1
  133. package/lib/vertesia-ui-i18n.DwHsq86z.chunk.js +0 -5
  134. package/lib/vertesia-ui-i18n.DwHsq86z.chunk.js.map +0 -1
  135. package/lib/vertesia-ui-i18n.PLpo0Bbz.chunk.js +0 -5
  136. package/lib/vertesia-ui-i18n.PLpo0Bbz.chunk.js.map +0 -1
  137. package/lib/vertesia-ui-i18n.xVbXALqz.chunk.js +0 -5
  138. package/lib/vertesia-ui-i18n.xVbXALqz.chunk.js.map +0 -1
  139. package/src/features/agent/chat/DocumentTabBar.tsx +0 -41
@@ -1 +1 @@
1
- {"version":3,"file":"vertesia-ui-router.js","names":["_jsx","_jsx","_jsx","_jsx","_jsxs","_jsx","_jsx","_jsx","_jsx"],"sources":["router/PathWithParams.js","router/path.js","router/HistoryNavigator.js","router/FixLinks.js","router/PathMatcher.js","router/Router.js","router/Nav.js","router/RouteComponent.js","router/NestedNavigationContext.js","router/Route404.js","router/NestedRouterProvider.js","router/Redirect.js","router/RouterProvider.js"],"sourcesContent":["export class PathWithParams {\n path;\n params;\n hash;\n constructor(path) {\n let i = path.lastIndexOf('#');\n if (i > -1) {\n this.hash = path.substring(i);\n path = path.substring(0, i);\n }\n else {\n this.hash = '';\n }\n i = path.indexOf('?');\n if (i > -1) {\n this.path = path.substring(0, i);\n this.params = new URLSearchParams(path.substring(i + 1));\n }\n else {\n this.path = path;\n this.params = new URLSearchParams();\n }\n }\n add(params) {\n for (const [key, value] of Object.entries(params)) {\n this.params.set(key, value);\n }\n return this;\n }\n toString() {\n return `${this.path}?${this.params.toString()}${this.hash}`;\n }\n}\n//# sourceMappingURL=PathWithParams.js.map","export function isRootPath(path) {\n return path === '/' || path === '';\n}\nexport function joinPath(path1, path2) {\n if (path1.endsWith('/') && path2.startsWith('/')) {\n path2 = path1 + path2.substring(1);\n }\n else if (path1.endsWith('/')) {\n path2 = path1 + path2;\n }\n else if (path2.startsWith('/')) {\n path2 = path1 + path2;\n }\n else {\n path2 = `${path1}/${path2}`;\n }\n return path2;\n}\n/**\n * The mount base path from an explicit `<base href>` element, or `''` when there is none.\n *\n * Apps served under a deep gateway mount carry `<base href=\"/tenants/.../app/\">`, injected at serve\n * time. The router otherwise resolves absolute routes against the origin, which collapses the URL\n * off the mount (and breaks in-app links). This returns the base pathname without a trailing slash\n * so {@link withMountBasename} can keep navigation under the mount and {@link stripMountBasename}\n * can match routes app-relative. The Studio UI has no `<base>` element, so this returns `''` and\n * every caller becomes a no-op there.\n */\nexport function getMountBasename() {\n if (typeof document === 'undefined')\n return '';\n const base = document.querySelector('base[href]');\n if (!base)\n return '';\n try {\n return new URL(base.href, document.URL).pathname.replace(/\\/+$/, '');\n }\n catch {\n return '';\n }\n}\n/** Prepend the mount basename to an absolute app path (no-op when no mount, path is relative, or already prefixed). */\nexport function withMountBasename(path) {\n const base = getMountBasename();\n if (!base || !path.startsWith('/'))\n return path;\n if (path === base || path.startsWith(`${base}/`))\n return path;\n return joinPath(base, path);\n}\n/** Strip the mount basename from a browser path so route patterns match app-relative (no-op when no mount). */\nexport function stripMountBasename(path) {\n const base = getMountBasename();\n if (!base)\n return path;\n if (path === base)\n return '/';\n if (path.startsWith(`${base}/`))\n return path.slice(base.length) || '/';\n return path;\n}\nexport function getPathSegments(path) {\n if (path === '') {\n return [];\n }\n if (path === '/') {\n return [''];\n }\n let s = 0, e = path.length;\n if (path.startsWith('./')) {\n s = 2;\n }\n else if (path.startsWith('/')) {\n s = 1;\n }\n if (path.endsWith('/')) {\n e = path.length - 1;\n }\n return (s > 0 || e < path.length ? path.substring(s, e) : path).split('/');\n}\nexport function toSegments(path) {\n if (typeof path === 'string') {\n return getPathSegments(path);\n }\n else if (Array.isArray(path)) {\n return path;\n }\n else {\n throw new Error(`Unsupported path object: ${path}`);\n }\n}\n// export class Path {\n// static parse(path: string, abs = false) {\n// if (abs !== undefined) {\n// abs = path.startsWith('/');\n// }\n// return new Path(getPathSegments(path), abs);\n// }\n// constructor(public segments: string[], public isAbsolute = false) {\n// }\n// getParameters() {\n// const out = [];\n// for (const segment of this.segments) {\n// if (segment[0] === ':') {\n// out.push(segment.substring(1));\n// }\n// }\n// if (this.segments[this.segments.length - 1] === '*') {\n// out.push('_');\n// }\n// return out;\n// }\n// resolveParameters(path: string) {\n// const params: PathMatchParams = {};\n// const resolvedSegments = getPathSegments(path);\n// if (resolvedSegments.length < this.segments.length) {\n// return null;\n// }\n// const segments = this.segments;\n// for (let i = 0, l = segments.length; i < l; i++) {\n// const seg = segments[i];\n// if (seg[0] === ':') {\n// params[seg.substring(1)] = resolvedSegments[i];\n// }\n// }\n// if (resolvedSegments.length - this.segments.length) {\n// params._ = resolvedSegments.slice(this.segments.length);\n// }\n// return params;\n// }\n// match(path: string | string[] | Path) {\n// const segments = toSegments(path);\n// if (segments.length < this.segments.length) {\n// return false;\n// }\n// let params: PathMatchParams | undefined;\n// const mySegments = this.segments;\n// for (let i = 0, l = mySegments.length; i < l; i++) {\n// const segment = mySegments[i];\n// if (segment === ':') {\n// if (!params) params = {};\n// params[segment.substring(1)] = segment;\n// } else if (segment !== segments[i]) {\n// if (i === l - 1 && segment === '*') {\n// if (!params) params = {};\n// params._ = segments.slice(i);\n// return params;\n// }\n// return false;\n// }\n// }\n// return params ? params : false;\n// }\n// join(path: Path | string | string[]) {\n// const segments = toSegments(path);\n// return new Path(this.segments.concat(segments), this.isAbsolute);\n// }\n// getRelativePath(path: Path | string | string[], asAbsolute: boolean = false) {\n// const segments = toSegments(path);\n// const extraSegmentsCount = segments.length - this.segments.length;\n// if (extraSegmentsCount <= 0) {\n// return null;\n// }\n// return new Path(segments.slice(this.segments.length), asAbsolute);\n// }\n// prependSegments(segments: string[]) {\n// this.segments = segments.concat(this.segments);\n// }\n// appendSegments(segments: string[]) {\n// this.segments = this.segments.concat(segments);\n// }\n// toAbsolutePath() {\n// return '/' + this.segments.join('/');\n// }\n// toRelativePath() {\n// return this.segments.join('/');\n// }\n// toString() {\n// const path = this.segments.join('/');\n// return this.isAbsolute ? '/' + path : path;\n// }\n// }\n//# sourceMappingURL=path.js.map","import { PathWithParams } from './PathWithParams';\nimport { joinPath, withMountBasename } from './path';\nconst BASE_PATH = Symbol('BASE_PATH');\nexport { BASE_PATH };\nexport class LocationChangeEvent {\n name;\n type;\n location;\n state;\n _canceled = false;\n constructor(name, type, location, state) {\n this.name = name;\n this.type = type;\n this.location = location;\n this.state = state;\n }\n get isPageLoad() {\n return this.type === 'initial';\n }\n get isBackForward() {\n return this.type === 'popState';\n }\n get isLinkClick() {\n return this.type === 'linkClick';\n }\n get isNavigation() {\n return this.type === 'navigate';\n }\n get isCancelable() {\n return this.name === 'beforeChange';\n }\n cancel() {\n if (this.name === 'afterChange') {\n throw new Error('Cannot cancel afterChange event');\n }\n this._canceled = true;\n }\n}\nexport class BeforeLocationChangeEvent extends LocationChangeEvent {\n constructor(type, location, state) {\n super('beforeChange', type, location, state);\n }\n}\nexport class AfterLocationChangeEvent extends LocationChangeEvent {\n constructor(type, location, state) {\n super('afterChange', type, location, state);\n }\n}\nfunction getClosestAnchor(target) {\n if (!(target instanceof Element)) {\n return null;\n }\n return target.closest('a[href]');\n}\nfunction getElementHrefAsUrl(elem) {\n const href = elem.href.trim();\n return href.length > 0 ? new URL(href) : null;\n}\nexport class HistoryNavigator {\n // params to preserve in the query string when navigating\n stickyParams;\n _popStateListener;\n _linkNavListener;\n _listeners = [];\n addListener(listener) {\n this._listeners.push(listener);\n }\n fireLocationChange(event) {\n for (const listener of this._listeners) {\n listener(event);\n }\n }\n /**\n * Should be called when the page is first loaded.\n * It will fire a location change event with type `initial` and the current window.location as the location\n */\n firePageLoad() {\n this.fireLocationChange(new AfterLocationChangeEvent('initial', new URL(window.location.href)));\n }\n addStickyParams(path) {\n if (this.stickyParams) {\n return new PathWithParams(path).add(this.stickyParams).toString();\n }\n return path;\n }\n /**\n * Rewrite the current browser URL in place so that the sticky params are present, without\n * navigating. Used on load / when the params first become known so the address bar reflects\n * the active account/project before the first navigation.\n *\n * Idempotent and side-effect-light: only calls replaceState when the URL would actually\n * change, preserves the existing history state, and never fires a location-change event\n * (so there is no route re-match or component remount).\n */\n normalizeCurrentUrl() {\n if (typeof window === 'undefined' || !this.stickyParams) {\n return;\n }\n const current = window.location.pathname + window.location.search + window.location.hash;\n const normalized = this.addStickyParams(current);\n if (normalized !== current) {\n const to = new URL(normalized, window.location.href);\n window.history.replaceState(window.history.state, '', to.href);\n }\n }\n navigate(to, options = {}) {\n if (options.stepsBack && options.stepsBack > 0) {\n this.stepBack(options.stepsBack, options);\n return;\n }\n if (options.basePath) {\n let basePath = options.basePath;\n if (!basePath.startsWith('/')) {\n basePath = `/${basePath}`;\n }\n to = joinPath(basePath, to);\n }\n to = this.addStickyParams(to);\n // Keep absolute app routes under the served `<base href>` mount instead of resolving them\n // against the bare origin (which collapses the URL off the mount). No-op when origin-served.\n to = withMountBasename(to);\n this._navigate(new URL(to, window.location.href), 'navigate', options);\n }\n stepBack(steps, options = {}) {\n const historyChain = window.history.state.historyChain || [];\n const to = historyChain.length >= steps\n ? new URL(historyChain[historyChain.length - steps].href, window.location.href)\n : new URL(window.location.origin, window.location.href);\n this._navigate(to, 'popState', options);\n const stateToStore = {\n from: window.location.href,\n historyChain: historyChain.slice(0, -steps),\n data: options.state || undefined,\n title: options.title || document.title,\n };\n window.history.replaceState(stateToStore, '', to.href);\n this.fireLocationChange(new AfterLocationChangeEvent('popState', to, options.state));\n }\n _navigate(to, type, options) {\n const beforeEvent = new BeforeLocationChangeEvent(type, to, options.state);\n this.fireLocationChange(beforeEvent);\n if (beforeEvent._canceled) {\n return;\n }\n // Build navigation chain by preserving previous history\n const currentState = window.history.state;\n const currentTitle = options.title || document.title;\n // Create new history chain entry\n const newChainEntry = {\n title: currentTitle,\n href: window.location.pathname + window.location.search + window.location.hash,\n };\n // Build the history chain - clear if using replace\n let historyChain = [];\n if (!options.replace && currentState?.historyChain) {\n historyChain = [...currentState.historyChain];\n }\n // Only add to chain if not replacing\n if (!options.replace) {\n historyChain.push(newChainEntry);\n // Limit chain length to prevent memory issues (keep last 10 entries)\n if (historyChain.length > 10) {\n historyChain = historyChain.slice(-10);\n }\n }\n const stateToStore = {\n from: window.location.href,\n historyChain: historyChain,\n data: options.state || undefined,\n title: options.title || document.title,\n };\n window.history[options.replace ? 'replaceState' : 'pushState'](stateToStore, '', to.href);\n this.fireLocationChange(new AfterLocationChangeEvent(type, to, options.state));\n }\n start() {\n if (typeof window === 'undefined') {\n return;\n }\n const _popStateListener = (ev) => {\n let type;\n const to = new URL(window.location.href);\n let state;\n if (ev.state) {\n type = 'popState';\n state = ev.state.data;\n }\n else {\n type = 'linkClick';\n }\n this.fireLocationChange(new AfterLocationChangeEvent(type, to, state));\n };\n const _linkNavListener = (ev) => {\n // Let the browser handle modifier / non-primary clicks natively (open in new tab/window,\n // download). Intercepting them here would preventDefault those affordances.\n if (ev.defaultPrevented || ev.metaKey || ev.altKey || ev.ctrlKey || ev.shiftKey || ev.button !== 0) {\n return;\n }\n const anchor = getClosestAnchor(ev.target);\n if (!anchor) {\n return;\n }\n const anchorTarget = anchor.getAttribute('target');\n // Downloads, blob URLs, and explicitly targeted links require native browser navigation.\n if (anchor.hasAttribute('download') ||\n anchor.href.startsWith('blob:') ||\n (!!anchorTarget && anchorTarget.toLowerCase() !== '_self')) {\n return;\n }\n const url = getElementHrefAsUrl(anchor);\n if (url && url.origin === window.location.origin) {\n ev.preventDefault();\n const to = new URL(this.addStickyParams(url.href));\n const basePath = ev[BASE_PATH] ||\n ev.target[BASE_PATH];\n if (basePath) {\n to.pathname = joinPath(basePath, to.pathname);\n }\n this._navigate(to, 'linkClick', {});\n }\n };\n this._popStateListener = _popStateListener;\n this._linkNavListener = _linkNavListener;\n window.addEventListener('popstate', _popStateListener);\n document.body.addEventListener('click', this._linkNavListener);\n }\n stop() {\n if (this._popStateListener)\n window.removeEventListener('popstate', this._popStateListener);\n if (this._linkNavListener)\n document.body.removeEventListener('click', this._linkNavListener);\n }\n}\n//# sourceMappingURL=HistoryNavigator.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { useEffect, useRef } from 'react';\nimport { BASE_PATH } from './HistoryNavigator';\nexport function FixLinks({ basePath, children }) {\n const ref = useRef(null);\n useEffect(() => {\n if (ref.current) {\n const divElem = ref.current;\n const listener = (ev) => {\n const elem = ev.target;\n if (elem.tagName.toLowerCase() === 'a') {\n ev[BASE_PATH] = basePath;\n }\n };\n divElem.addEventListener('click', listener);\n return () => {\n divElem.removeEventListener('click', listener);\n };\n }\n }, [basePath]);\n return (_jsx(\"div\", { ref: ref, className: \"h-full w-full\", children: children }));\n}\n//# sourceMappingURL=FixLinks.js.map","import { getPathSegments, toSegments } from './path';\n/**\n * Path matcher which support :param and *wildcard segments.\n * The wildcard segment is only supported as the last segment\n */\nexport class PathMatcher {\n tree = new RootSegmentNode();\n loadMapping(mapping) {\n for (const [key, value] of Object.entries(mapping)) {\n this.addSegments(getPathSegments(key), value);\n }\n }\n addPath(path, value) {\n this.addSegments(getPathSegments(path), value);\n }\n addSegments(segments, value) {\n let node = this.tree;\n for (let i = 0, l = segments.length; i < l; i++) {\n const segment = segments[i];\n if (segment[0] === ':') {\n let childNode = node.wildcard;\n if (!childNode) {\n childNode = new VariableSegmentNode(segment);\n node.wildcard = childNode;\n }\n else if (!(childNode instanceof VariableSegmentNode)) {\n throw new Error(`Failed to index path segments: ${segments.join('/')}. A wildcard \":\" segment will overwrite an existing wildcard segment at path: ${`/${segments.slice(0, i).join('/')}`}`);\n }\n node = childNode;\n }\n else if (segment === '*') {\n if (node.wildcard) {\n throw new Error(`Failed to index path segments: ${segments.join('/')}. A wildcard \"*\" segment already exists at path: ${`/${segments.slice(0, i).join('/')}`}`);\n }\n node.wildcard = new WildcardSegmentNode(segment, value);\n if (i < l - 1) {\n throw new Error(`Failed to index path segments: ${segments.join('/')}. A wildcard segment must be the last segment`);\n }\n return;\n }\n else {\n let childNode = node.children[segment];\n if (!childNode) {\n childNode = new LiteralSegmentNode(segment);\n node.children[segment] = childNode;\n } // else // a literal segment already exists\n node = childNode;\n }\n }\n if (node.value !== undefined) {\n throw new Error(`Failed to index path segments: ${segments.join('/')}. A value already exists at path: ${`/${segments.join('/')}`}`);\n }\n node.value = value;\n }\n match(path) {\n const segments = toSegments(path);\n if (segments.length === 0) {\n return null;\n }\n const params = {};\n let node = this.tree;\n for (const segment of segments) {\n const match = node.match(segment, params);\n if (match) {\n node = match;\n }\n else {\n return null;\n }\n }\n if (!node.value) {\n // not a leaf node (partial match)\n if (node instanceof ParentSegmentNode) {\n if (node.wildcard instanceof WildcardSegmentNode) {\n node = node.wildcard.match('', params);\n if (!node.value) {\n throw new Error('Wildcard segment node `*` must have a value');\n }\n }\n }\n if (!node.value)\n return null; // not a leaf node, neither a trailing wildcard (partial match)\n }\n let matchedSegments, remainingSegments;\n if (params._ && params._.length > 0) {\n matchedSegments = segments.slice(0, -params._.length);\n remainingSegments = params._;\n }\n else {\n matchedSegments = segments;\n }\n return { params, matchedSegments, remainingSegments, value: node.value };\n }\n}\nclass ParentSegmentNode {\n name;\n value;\n children = {};\n wildcard;\n constructor(name, value) {\n this.name = name;\n this.value = value;\n }\n match(segment, params) {\n const node = this.children[segment];\n if (node) {\n return node;\n }\n else if (this.wildcard) {\n if (this.wildcard instanceof WildcardSegmentNode) {\n return this.wildcard.match(segment, params);\n }\n else if (this.wildcard instanceof VariableSegmentNode) {\n params[this.wildcard.paramName] = segment;\n return this.wildcard;\n }\n else {\n throw new Error(`Unknown wildcard segment node type: ${this.wildcard.constructor.name}`);\n }\n }\n else {\n return null;\n }\n }\n}\nclass RootSegmentNode extends ParentSegmentNode {\n constructor() {\n super('#root');\n }\n}\nclass LiteralSegmentNode extends ParentSegmentNode {\n}\nclass VariableSegmentNode extends ParentSegmentNode {\n paramName;\n constructor(name, value) {\n super(name, value);\n this.paramName = name.substring(1);\n }\n}\nclass WildcardSegmentNode {\n name;\n value;\n constructor(name, value) {\n this.name = name;\n this.value = value;\n }\n match(segment, params) {\n if (!params._) {\n params._ = segment ? [segment] : [];\n }\n else {\n if (segment)\n params._.push(segment);\n }\n return this;\n }\n}\n//# sourceMappingURL=PathMatcher.js.map","import { createContext, useContext, useEffect } from 'react';\nimport { HistoryNavigator } from './HistoryNavigator';\nimport { PathMatcher } from './PathMatcher';\nimport { getMountBasename, isRootPath, joinPath, stripMountBasename } from './path';\nexport class BaseRouter {\n // the path to use when navigating to the root of the router\n index;\n matcher = new PathMatcher();\n constructor(routes, index) {\n this.index = index;\n for (const route of routes) {\n this.matcher.addPath(route.path, route);\n }\n }\n match(path) {\n const useIndex = isRootPath(path) && this.index;\n return this.matcher.match(useIndex || path);\n }\n}\nexport class Router extends BaseRouter {\n prompt;\n observer;\n navigator = new HistoryNavigator();\n constructor(routes, updateState) {\n super(routes);\n this.navigator.addListener((event) => {\n if (event.isCancelable && this.prompt?.when) {\n if (!window.confirm(this.prompt.message))\n return;\n }\n if (this.observer) {\n this.observer(event);\n }\n // only process afterChange events\n if (event.name === 'afterChange') {\n // Match app-relative: strip the served `<base href>` mount prefix (no-op when origin-served).\n const match = this.match(stripMountBasename(event.location.pathname));\n if (match?.value) {\n updateState({\n ...match,\n state: event.state,\n });\n }\n else {\n updateState(null);\n }\n }\n });\n }\n getTopRouter() {\n return this;\n }\n /**\n * Subsequent navigations will preserve the given params in the query string.\n * Use null to clear the sticky params.\n * @param params\n */\n setStickyParams(params) {\n this.navigator.stickyParams = params != null ? params : undefined;\n // Reflect the params in the current URL immediately, so the address bar is correct on\n // load (not only after the first navigation).\n this.navigator.normalizeCurrentUrl();\n }\n withObserver(observer) {\n this.observer = observer;\n return this;\n }\n start() {\n this.navigator.start();\n // initialize with the current location\n this.navigator.firePageLoad();\n }\n stop() {\n this.navigator.stop();\n }\n navigate(path, options) {\n this.navigator.navigate(path, options);\n }\n}\nexport class NestedRouter extends BaseRouter {\n parent;\n basePath;\n constructor(parent, basePath, routes) {\n super(routes);\n this.parent = parent;\n this.basePath = basePath;\n }\n getTopRouter() {\n if (this.parent instanceof Router) {\n return this.parent;\n }\n else {\n return this.parent.getTopRouter();\n }\n }\n navigate(path, options) {\n // base path is nested by default in a NestedRouter unless explicitly set to false by caller\n const isBasePathNested = options?.isBasePathNested ?? true;\n let basePath;\n if (isBasePathNested) {\n const childBasePath = options?.basePath;\n // e.g. \"/store\" + \"/objects/123\" => \"/store/objects/123\"\n basePath = childBasePath ? joinPath(this.basePath, childBasePath) : this.basePath;\n this.parent.navigate(path, {\n ...options,\n basePath,\n });\n }\n else {\n // isBasePathNested === false: navigate to an absolute path without adding this router's basePath\n // Pass through to parent without adding our basePath prefix\n this.parent.navigate(path, {\n ...options,\n basePath: options?.basePath,\n });\n }\n }\n}\nconst ReactRouterContext = createContext(undefined);\nexport { ReactRouterContext };\nexport function useRouterContext() {\n const ctx = useContext(ReactRouterContext);\n if (!ctx) {\n throw new Error('useRouter must be used within a RouterProvider');\n }\n return ctx;\n}\nexport function useNavigate() {\n const { navigate } = useRouterContext();\n return navigate;\n}\nexport function useRouterBasePath() {\n const { router } = useRouterContext();\n // The base path apps prepend to build absolute in-app links (e.g. `${base}/items/${id}`). It MUST\n // include the served `<base href>` mount so links stay on the mount and match the full\n // `useLocation().pathname` (which carries the mount). `getMountBasename()` is '' for the\n // origin-served Studio UI and the mount (no trailing slash) for gateway-served apps.\n const mount = getMountBasename();\n if (router instanceof NestedRouter) {\n // NestedRouter.basePath is relative to the parent router, which sits at the mount, so it must\n // be mount-prefixed too. A bare nested base of '/' (an app whose NestedRouterProvider has no\n // basePath) would otherwise make `${base}/items` resolve to `//items` — a protocol-relative\n // URL that escapes the app. Origin-served Studio (mount '') keeps the raw nested basePath.\n if (!mount)\n return router.basePath;\n return router.basePath === '/' ? mount : joinPath(mount, router.basePath);\n }\n return mount;\n}\nexport function useParams(arg) {\n const { params } = useRouterContext();\n if (arg) {\n return params[arg];\n }\n else {\n return params;\n }\n}\nexport function useLocation() {\n const { location } = useRouterContext();\n return location;\n}\nexport function usePageTitle(title) {\n useEffect(() => {\n const prev = document.title;\n document.title = title;\n return () => {\n document.title = prev;\n };\n }, [title]);\n}\nexport function useNavigationPrompt(prompt) {\n const { router } = useRouterContext();\n const topRouter = router.getTopRouter();\n useEffect(() => {\n topRouter.prompt = prompt;\n return () => {\n topRouter.prompt = undefined;\n };\n }, [prompt, topRouter]);\n useEffect(() => {\n if (prompt.when) {\n const doBlock = prompt.when;\n const listener = (ev) => {\n if (doBlock) {\n ev.preventDefault();\n ev.returnValue = '';\n }\n };\n window.addEventListener('beforeunload', listener);\n return () => {\n window.removeEventListener('beforeunload', listener);\n };\n }\n }, [prompt.when]);\n}\n//# sourceMappingURL=Router.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { withMountBasename } from './path';\nimport { useNavigate, useRouterContext } from './Router';\n/**\n * True when the click carries a modifier the browser uses for alternate link behavior\n * (open in new tab/window, download) or is not a primary-button click. Such clicks must fall\n * through to the native anchor so the browser can handle them instead of the SPA router.\n */\nfunction isModifiedClick(ev) {\n return ev.metaKey || ev.altKey || ev.ctrlKey || ev.shiftKey || ev.button !== 0;\n}\nexport function Nav({ children, to, onClick, replace = true }) {\n const navigate = useNavigate();\n const _onClick = (ev) => {\n const link = ev.target.closest('a');\n const rawHref = link?.getAttribute('href');\n const target = to ?? rawHref;\n if (link && target) {\n ev.stopPropagation();\n ev.preventDefault();\n navigate(target, { replace });\n onClick?.(ev);\n }\n };\n return (_jsx(\"span\", { onClick: _onClick, children: children }));\n}\nexport function NavLink({ children, href, className, target, topLevelNav, clearBreadcrumbs = false, replace, skipStickyParams, }) {\n const { router } = useRouterContext();\n // Resolve internal URLs even when a target makes navigation native. New-tab links still need\n // the mount path and tenant sticky params, but must not be intercepted by the SPA router.\n const isAnchorOrEmpty = !href || href.startsWith('#');\n const isExternalUrl = /^[a-z][a-z0-9+.-]*:/i.test(href) || href.startsWith('//');\n const isInternalUrl = !isAnchorOrEmpty && !isExternalUrl;\n const isNativeNavigation = !!target && target !== '_self';\n // Keep the rendered href under the served `<base href>` mount (correct middle-click / hover /\n // open-in-new-tab); the onClick navigates via the router which applies the same rule. No-op when\n // origin-served (Studio UI). Click handler below passes the raw `href` — navigate() re-bases it.\n const resolvedHref = isInternalUrl\n ? withMountBasename(!skipStickyParams ? router.getTopRouter().navigator.addStickyParams(href) : href)\n : href;\n const _onClick = (ev) => {\n if (ev.defaultPrevented || !isInternalUrl || isNativeNavigation || isModifiedClick(ev)) {\n return;\n }\n ev.stopPropagation();\n ev.preventDefault();\n const actualRouter = topLevelNav ? router.getTopRouter() : router;\n actualRouter.navigate(href, { replace: replace ?? clearBreadcrumbs });\n };\n return (_jsx(\"a\", { href: resolvedHref, className: className, target: target, onClick: _onClick, children: children }));\n}\n//# sourceMappingURL=Nav.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { useEffect, useState } from 'react';\nimport { useRouterContext, } from './Router';\n// Resolved lazy modules, keyed by the route's LazyComponent function (a stable identity: route\n// tables are declared once). A revisited lazy route renders synchronously from this cache instead\n// of unmounting to the spinner for the async import() round-trip — without it, every navigation\n// between two lazy routes blanks the page for at least a frame, even when the module is loaded.\nconst resolvedComponents = new Map();\nfunction resolveLazyRoute(route) {\n return route.LazyComponent().then((module) => {\n if (!module.default) {\n throw new Error(`Lazy module for ${route.path} does not have a default export`);\n }\n resolvedComponents.set(route.LazyComponent, module.default);\n return module.default;\n });\n}\n/**\n * Start loading the given routes' lazy modules ahead of navigation (non-lazy routes are ignored).\n * Call it during idle time after first paint: the first navigation to a prefetched route then\n * renders synchronously instead of flashing the spinner while its chunk downloads. Failures are\n * swallowed — navigation retries the import and reports the error the normal way.\n */\nexport function prefetchLazyRoutes(routes) {\n return Promise.allSettled(routes\n .filter((route) => !!route.LazyComponent)\n .map((route) => resolveLazyRoute(route)));\n}\nexport function RouteComponent({ spinner }) {\n const ctx = useRouterContext();\n const route = ctx.route;\n if (route.Component) {\n const Component = route.Component;\n return _jsx(Component, { ...ctx.params });\n }\n else if (route.LazyComponent) {\n // Keyed per path so navigating between two lazy routes remounts: a reused instance would\n // keep rendering the previous route's component while the next import resolves.\n return _jsx(LazyRouteComponent, { route: route, spinner: spinner }, route.path);\n }\n else {\n throw new Error(`Invalid route for ${route.path}. Either Component or LazyCOmponent must be specified.`);\n }\n}\nfunction LazyRouteComponent({ route, spinner }) {\n const [Component, setComponent] = useState(() => resolvedComponents.get(route.LazyComponent) ?? null);\n useEffect(() => {\n // A slow import must not land after this instance moved on (unmount, or a route object\n // swap without a path change): the stale module would overwrite the current one.\n let stale = false;\n void resolveLazyRoute(route).then((component) => {\n if (!stale) {\n // we need to wrap the component type in an arrow function\n // otherwise the setState function will execute the function as a state update function\n setComponent(() => component);\n }\n });\n return () => {\n stale = true;\n };\n }, [route]);\n return Component ? _jsx(Component, {}) : spinner || null;\n}\n//# sourceMappingURL=RouteComponent.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { FixLinks } from './FixLinks';\nimport { joinPath } from './path';\nimport { RouteComponent } from './RouteComponent';\nimport { ReactRouterContext, useRouterContext } from './Router';\nexport function NestedNavigationContext({ basePath, fixLinks = false, children }) {\n const ctx = useRouterContext();\n const wrapWithFixLinks = fixLinks\n ? (elem) => _jsx(FixLinks, { basePath: ctx.matchedRoutePath, children: elem })\n : (elem) => elem;\n return (_jsx(ReactRouterContext.Provider, { value: {\n ...ctx,\n navigate: (to, options) => {\n if (options?.isBasePathNested === false) {\n // Navigate to an absolute path without adding this context's basePath\n return ctx.navigate(to, options);\n }\n const actualBasePath = options?.basePath ? joinPath(basePath, options.basePath) : basePath;\n return ctx.navigate(to, { ...options, basePath: actualBasePath });\n },\n }, children: wrapWithFixLinks(children ? children : _jsx(RouteComponent, {})) }));\n}\n//# sourceMappingURL=NestedNavigationContext.js.map","import { jsx as _jsx, jsxs as _jsxs } from \"react/jsx-runtime\";\nimport { useRouterContext } from './Router';\nexport function Route404Component() {\n const ctx = useRouterContext();\n return _jsxs(\"div\", { children: [\"Route not found for path \", ctx.matchedRoutePath] });\n}\nexport function createRoute404() {\n return {\n params: {},\n matchedSegments: [],\n state: null,\n value: {\n path: 'virtual:404',\n Component: () => _jsx(Route404Component, {}),\n },\n };\n}\n//# sourceMappingURL=Route404.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { useMemo, useRef } from 'react';\nimport { FixLinks } from './FixLinks';\nimport { createRoute404 } from './Route404';\nimport { RouteComponent } from './RouteComponent';\nimport { NestedRouter, ReactRouterContext, useRouterContext } from './Router';\nexport function NestedRouterProvider({ routes, index, children, fixLinks = false }) {\n const ctx = useRouterContext();\n // Capture basePath once at mount. When the parent router switches to a different\n // top-level route (e.g. /store -> /studio), the lazy loader briefly keeps rendering\n // this (now-stale) module with a new ctx. Keeping basePath stable lets the\n // ctx.matchedRoutePath !== nestedRouter.basePath check below detect the mismatch and\n // skip rendering instead of running match() against the wrong route table.\n const basePathRef = useRef(ctx.matchedRoutePath);\n const nestedRouter = useMemo(() => {\n if (typeof window === 'undefined')\n return null;\n const nestedRouter = new NestedRouter(ctx.router, basePathRef.current, routes);\n nestedRouter.index = index;\n return nestedRouter;\n }, [ctx.router, index, routes]);\n const nestedRouteMatch = useMemo(() => {\n if (!nestedRouter) {\n return undefined;\n }\n if (ctx.matchedRoutePath !== nestedRouter.basePath) {\n // The change belongs to another router level and will be handled there.\n return undefined;\n }\n return nestedRouter.match(ctx.remainingPath || '/') || createRoute404();\n }, [ctx.matchedRoutePath, ctx.remainingPath, nestedRouter]);\n const wrapWithFixLinks = fixLinks\n ? (elem) => _jsx(FixLinks, { basePath: ctx.matchedRoutePath, children: elem })\n : (elem) => elem;\n return (nestedRouter &&\n nestedRouteMatch && (_jsx(ReactRouterContext.Provider, { value: {\n ...ctx,\n router: nestedRouter,\n route: nestedRouteMatch.value,\n params: nestedRouteMatch.params,\n matchedRoutePath: `/${nestedRouteMatch.matchedSegments.join('/')}`,\n remainingPath: nestedRouteMatch.remainingSegments\n ? `/${nestedRouteMatch.remainingSegments.join('/')}`\n : undefined,\n navigate: (to, options) => {\n if (nestedRouter) {\n return nestedRouter.navigate(to, options);\n }\n },\n }, children: wrapWithFixLinks(children ? children : _jsx(RouteComponent, {})) })));\n}\n//# sourceMappingURL=NestedRouterProvider.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { useEffect } from 'react';\nimport { useNavigate } from './Router';\nexport function Redirect({ to, replace = true, state }) {\n const navigate = useNavigate();\n useEffect(() => {\n navigate(to, { replace, state });\n }, [navigate, replace, state, to]);\n return null;\n}\n/**\n * Creates a route component that redirects to another route when rendered.\n * Useful in route tables, for example: `{ path: '/', Component: redirectTo('/content') }`.\n */\nexport function redirectTo(to, options = {}) {\n return function RedirectRoute() {\n return _jsx(Redirect, { to: to, replace: options.replace, state: options.state });\n };\n}\n//# sourceMappingURL=Redirect.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { useSafeLayoutEffect } from '@vertesia/ui/core';\nimport { useMemo, useState } from 'react';\nimport { createRoute404 } from './Route404';\nimport { RouteComponent } from './RouteComponent';\nimport { ReactRouterContext, Router } from './Router';\nexport function RouterProvider({ routes, index, onChange, children }) {\n const [state, setState] = useState(undefined);\n const router = useMemo(() => {\n if (typeof window === 'undefined')\n return null;\n const router = new Router(routes, (match) => {\n if (match === null) {\n match = createRoute404();\n }\n setState({\n location: window.location,\n route: match.value,\n params: match.params,\n state: match.state,\n router: router,\n matchedRoutePath: `/${match.matchedSegments.join('/')}`,\n remainingPath: match.remainingSegments ? `/${match.remainingSegments.join('/')}` : undefined,\n navigate: (to, options) => {\n return router.navigate(to, options);\n },\n });\n }).withObserver(onChange);\n router.index = index;\n return router;\n }, [index, onChange, routes]);\n useSafeLayoutEffect(() => {\n router?.start();\n return () => {\n router?.stop();\n };\n }, [router]);\n return (state && (_jsx(ReactRouterContext.Provider, { value: state, children: children ? children : _jsx(RouteComponent, {}) })));\n}\n//# sourceMappingURL=RouterProvider.js.map"],"mappings":"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"}
1
+ {"version":3,"file":"vertesia-ui-router.js","names":["_jsx","_jsx","_jsx","_jsx","_jsxs","_jsx","_jsx","_jsx","_jsx"],"sources":["router/PathWithParams.js","router/path.js","router/HistoryNavigator.js","router/FixLinks.js","router/PathMatcher.js","router/Router.js","router/Nav.js","router/RouteComponent.js","router/NestedNavigationContext.js","router/Route404.js","router/NestedRouterProvider.js","router/Redirect.js","router/RouterProvider.js"],"sourcesContent":["export class PathWithParams {\n path;\n params;\n hash;\n constructor(path) {\n let i = path.lastIndexOf('#');\n if (i > -1) {\n this.hash = path.substring(i);\n path = path.substring(0, i);\n }\n else {\n this.hash = '';\n }\n i = path.indexOf('?');\n if (i > -1) {\n this.path = path.substring(0, i);\n this.params = new URLSearchParams(path.substring(i + 1));\n }\n else {\n this.path = path;\n this.params = new URLSearchParams();\n }\n }\n add(params) {\n for (const [key, value] of Object.entries(params)) {\n this.params.set(key, value);\n }\n return this;\n }\n toString() {\n return `${this.path}?${this.params.toString()}${this.hash}`;\n }\n}\n//# sourceMappingURL=PathWithParams.js.map","export function isRootPath(path) {\n return path === '/' || path === '';\n}\nexport function joinPath(path1, path2) {\n if (path1.endsWith('/') && path2.startsWith('/')) {\n path2 = path1 + path2.substring(1);\n }\n else if (path1.endsWith('/')) {\n path2 = path1 + path2;\n }\n else if (path2.startsWith('/')) {\n path2 = path1 + path2;\n }\n else {\n path2 = `${path1}/${path2}`;\n }\n return path2;\n}\n/**\n * The mount base path from an explicit `<base href>` element, or `''` when there is none.\n *\n * Apps served under a deep gateway mount carry `<base href=\"/tenants/.../app/\">`, injected at serve\n * time. The router otherwise resolves absolute routes against the origin, which collapses the URL\n * off the mount (and breaks in-app links). This returns the base pathname without a trailing slash\n * so {@link withMountBasename} can keep navigation under the mount and {@link stripMountBasename}\n * can match routes app-relative. The Studio UI has no `<base>` element, so this returns `''` and\n * every caller becomes a no-op there.\n */\nexport function getMountBasename() {\n if (typeof document === 'undefined')\n return '';\n const base = document.querySelector('base[href]');\n if (!base)\n return '';\n try {\n return new URL(base.href, document.URL).pathname.replace(/\\/+$/, '');\n }\n catch {\n return '';\n }\n}\n/** Prepend the mount basename to an absolute app path (no-op when no mount, path is relative, or already prefixed). */\nexport function withMountBasename(path) {\n const base = getMountBasename();\n if (!base || !path.startsWith('/'))\n return path;\n if (path === base || path.startsWith(`${base}/`))\n return path;\n return joinPath(base, path);\n}\n/** Strip the mount basename from a browser path so route patterns match app-relative (no-op when no mount). */\nexport function stripMountBasename(path) {\n const base = getMountBasename();\n if (!base)\n return path;\n if (path === base)\n return '/';\n if (path.startsWith(`${base}/`))\n return path.slice(base.length) || '/';\n return path;\n}\nexport function getPathSegments(path) {\n if (path === '') {\n return [];\n }\n if (path === '/') {\n return [''];\n }\n let s = 0, e = path.length;\n if (path.startsWith('./')) {\n s = 2;\n }\n else if (path.startsWith('/')) {\n s = 1;\n }\n if (path.endsWith('/')) {\n e = path.length - 1;\n }\n return (s > 0 || e < path.length ? path.substring(s, e) : path).split('/');\n}\nexport function toSegments(path) {\n if (typeof path === 'string') {\n return getPathSegments(path);\n }\n else if (Array.isArray(path)) {\n return path;\n }\n else {\n throw new Error(`Unsupported path object: ${path}`);\n }\n}\n// export class Path {\n// static parse(path: string, abs = false) {\n// if (abs !== undefined) {\n// abs = path.startsWith('/');\n// }\n// return new Path(getPathSegments(path), abs);\n// }\n// constructor(public segments: string[], public isAbsolute = false) {\n// }\n// getParameters() {\n// const out = [];\n// for (const segment of this.segments) {\n// if (segment[0] === ':') {\n// out.push(segment.substring(1));\n// }\n// }\n// if (this.segments[this.segments.length - 1] === '*') {\n// out.push('_');\n// }\n// return out;\n// }\n// resolveParameters(path: string) {\n// const params: PathMatchParams = {};\n// const resolvedSegments = getPathSegments(path);\n// if (resolvedSegments.length < this.segments.length) {\n// return null;\n// }\n// const segments = this.segments;\n// for (let i = 0, l = segments.length; i < l; i++) {\n// const seg = segments[i];\n// if (seg[0] === ':') {\n// params[seg.substring(1)] = resolvedSegments[i];\n// }\n// }\n// if (resolvedSegments.length - this.segments.length) {\n// params._ = resolvedSegments.slice(this.segments.length);\n// }\n// return params;\n// }\n// match(path: string | string[] | Path) {\n// const segments = toSegments(path);\n// if (segments.length < this.segments.length) {\n// return false;\n// }\n// let params: PathMatchParams | undefined;\n// const mySegments = this.segments;\n// for (let i = 0, l = mySegments.length; i < l; i++) {\n// const segment = mySegments[i];\n// if (segment === ':') {\n// if (!params) params = {};\n// params[segment.substring(1)] = segment;\n// } else if (segment !== segments[i]) {\n// if (i === l - 1 && segment === '*') {\n// if (!params) params = {};\n// params._ = segments.slice(i);\n// return params;\n// }\n// return false;\n// }\n// }\n// return params ? params : false;\n// }\n// join(path: Path | string | string[]) {\n// const segments = toSegments(path);\n// return new Path(this.segments.concat(segments), this.isAbsolute);\n// }\n// getRelativePath(path: Path | string | string[], asAbsolute: boolean = false) {\n// const segments = toSegments(path);\n// const extraSegmentsCount = segments.length - this.segments.length;\n// if (extraSegmentsCount <= 0) {\n// return null;\n// }\n// return new Path(segments.slice(this.segments.length), asAbsolute);\n// }\n// prependSegments(segments: string[]) {\n// this.segments = segments.concat(this.segments);\n// }\n// appendSegments(segments: string[]) {\n// this.segments = this.segments.concat(segments);\n// }\n// toAbsolutePath() {\n// return '/' + this.segments.join('/');\n// }\n// toRelativePath() {\n// return this.segments.join('/');\n// }\n// toString() {\n// const path = this.segments.join('/');\n// return this.isAbsolute ? '/' + path : path;\n// }\n// }\n//# sourceMappingURL=path.js.map","import { PathWithParams } from './PathWithParams';\nimport { joinPath, withMountBasename } from './path';\nconst BASE_PATH = Symbol('BASE_PATH');\nexport { BASE_PATH };\nexport class LocationChangeEvent {\n name;\n type;\n location;\n state;\n _canceled = false;\n constructor(name, type, location, state) {\n this.name = name;\n this.type = type;\n this.location = location;\n this.state = state;\n }\n get isPageLoad() {\n return this.type === 'initial';\n }\n get isBackForward() {\n return this.type === 'popState';\n }\n get isLinkClick() {\n return this.type === 'linkClick';\n }\n get isNavigation() {\n return this.type === 'navigate';\n }\n get isCancelable() {\n return this.name === 'beforeChange';\n }\n cancel() {\n if (this.name === 'afterChange') {\n throw new Error('Cannot cancel afterChange event');\n }\n this._canceled = true;\n }\n}\nexport class BeforeLocationChangeEvent extends LocationChangeEvent {\n constructor(type, location, state) {\n super('beforeChange', type, location, state);\n }\n}\nexport class AfterLocationChangeEvent extends LocationChangeEvent {\n constructor(type, location, state) {\n super('afterChange', type, location, state);\n }\n}\nfunction getClosestAnchor(target) {\n if (!(target instanceof Element)) {\n return null;\n }\n return target.closest('a[href]');\n}\nfunction getElementHrefAsUrl(elem) {\n const href = elem.href.trim();\n return href.length > 0 ? new URL(href) : null;\n}\nexport class HistoryNavigator {\n // params to preserve in the query string when navigating\n stickyParams;\n _popStateListener;\n _linkNavListener;\n _listeners = [];\n addListener(listener) {\n this._listeners.push(listener);\n }\n fireLocationChange(event) {\n for (const listener of this._listeners) {\n listener(event);\n }\n }\n /**\n * Should be called when the page is first loaded.\n * It will fire a location change event with type `initial` and the current window.location as the location\n */\n firePageLoad() {\n this.fireLocationChange(new AfterLocationChangeEvent('initial', new URL(window.location.href)));\n }\n addStickyParams(path) {\n if (this.stickyParams) {\n return new PathWithParams(path).add(this.stickyParams).toString();\n }\n return path;\n }\n /**\n * Rewrite the current browser URL in place so that the sticky params are present, without\n * navigating. Used on load / when the params first become known so the address bar reflects\n * the active account/project before the first navigation.\n *\n * Idempotent and side-effect-light: only calls replaceState when the URL would actually\n * change, preserves the existing history state, and never fires a location-change event\n * (so there is no route re-match or component remount).\n */\n normalizeCurrentUrl() {\n if (typeof window === 'undefined' || !this.stickyParams) {\n return;\n }\n const current = window.location.pathname + window.location.search + window.location.hash;\n const normalized = this.addStickyParams(current);\n if (normalized !== current) {\n const to = new URL(normalized, window.location.href);\n window.history.replaceState(window.history.state, '', to.href);\n }\n }\n navigate(to, options = {}) {\n if (options.stepsBack && options.stepsBack > 0) {\n this.stepBack(options.stepsBack, options);\n return;\n }\n if (options.basePath) {\n let basePath = options.basePath;\n if (!basePath.startsWith('/')) {\n basePath = `/${basePath}`;\n }\n to = joinPath(basePath, to);\n }\n to = this.addStickyParams(to);\n // Keep absolute app routes under the served `<base href>` mount instead of resolving them\n // against the bare origin (which collapses the URL off the mount). No-op when origin-served.\n to = withMountBasename(to);\n this._navigate(new URL(to, window.location.href), 'navigate', options);\n }\n stepBack(steps, options = {}) {\n const historyChain = window.history.state.historyChain || [];\n const to = historyChain.length >= steps\n ? new URL(historyChain[historyChain.length - steps].href, window.location.href)\n : new URL(window.location.origin, window.location.href);\n this._navigate(to, 'popState', options);\n const stateToStore = {\n from: window.location.href,\n historyChain: historyChain.slice(0, -steps),\n data: options.state || undefined,\n title: options.title || document.title,\n };\n window.history.replaceState(stateToStore, '', to.href);\n this.fireLocationChange(new AfterLocationChangeEvent('popState', to, options.state));\n }\n _navigate(to, type, options) {\n const beforeEvent = new BeforeLocationChangeEvent(type, to, options.state);\n this.fireLocationChange(beforeEvent);\n if (beforeEvent._canceled) {\n return;\n }\n // Build navigation chain by preserving previous history\n const currentState = window.history.state;\n const currentTitle = options.title || document.title;\n // Create new history chain entry\n const newChainEntry = {\n title: currentTitle,\n href: window.location.pathname + window.location.search + window.location.hash,\n };\n // Build the history chain - clear if using replace\n let historyChain = [];\n if (!options.replace && currentState?.historyChain) {\n historyChain = [...currentState.historyChain];\n }\n // Only add to chain if not replacing\n if (!options.replace) {\n historyChain.push(newChainEntry);\n // Limit chain length to prevent memory issues (keep last 10 entries)\n if (historyChain.length > 10) {\n historyChain = historyChain.slice(-10);\n }\n }\n const stateToStore = {\n from: window.location.href,\n historyChain: historyChain,\n data: options.state || undefined,\n title: options.title || document.title,\n };\n window.history[options.replace ? 'replaceState' : 'pushState'](stateToStore, '', to.href);\n this.fireLocationChange(new AfterLocationChangeEvent(type, to, options.state));\n }\n start() {\n if (typeof window === 'undefined') {\n return;\n }\n const _popStateListener = (ev) => {\n let type;\n const to = new URL(window.location.href);\n let state;\n if (ev.state) {\n type = 'popState';\n state = ev.state.data;\n }\n else {\n type = 'linkClick';\n }\n this.fireLocationChange(new AfterLocationChangeEvent(type, to, state));\n };\n const _linkNavListener = (ev) => {\n // Let the browser handle modifier / non-primary clicks natively (open in new tab/window,\n // download). Intercepting them here would preventDefault those affordances.\n if (ev.defaultPrevented || ev.metaKey || ev.altKey || ev.ctrlKey || ev.shiftKey || ev.button !== 0) {\n return;\n }\n const anchor = getClosestAnchor(ev.target);\n if (!anchor) {\n return;\n }\n const anchorTarget = anchor.getAttribute('target');\n // Downloads, blob URLs, and explicitly targeted links require native browser navigation.\n if (anchor.hasAttribute('download') ||\n anchor.href.startsWith('blob:') ||\n (!!anchorTarget && anchorTarget.toLowerCase() !== '_self')) {\n return;\n }\n const url = getElementHrefAsUrl(anchor);\n if (url && url.origin === window.location.origin) {\n ev.preventDefault();\n const to = new URL(this.addStickyParams(url.href));\n const basePath = ev[BASE_PATH] ||\n ev.target[BASE_PATH];\n if (basePath) {\n to.pathname = joinPath(basePath, to.pathname);\n }\n this._navigate(to, 'linkClick', {});\n }\n };\n this._popStateListener = _popStateListener;\n this._linkNavListener = _linkNavListener;\n window.addEventListener('popstate', _popStateListener);\n document.body.addEventListener('click', this._linkNavListener);\n }\n stop() {\n if (this._popStateListener)\n window.removeEventListener('popstate', this._popStateListener);\n if (this._linkNavListener)\n document.body.removeEventListener('click', this._linkNavListener);\n }\n}\n//# sourceMappingURL=HistoryNavigator.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { useEffect, useRef } from 'react';\nimport { BASE_PATH } from './HistoryNavigator';\nexport function FixLinks({ basePath, children }) {\n const ref = useRef(null);\n useEffect(() => {\n if (ref.current) {\n const divElem = ref.current;\n const listener = (ev) => {\n const elem = ev.target;\n if (elem.tagName.toLowerCase() === 'a') {\n ev[BASE_PATH] = basePath;\n }\n };\n divElem.addEventListener('click', listener);\n return () => {\n divElem.removeEventListener('click', listener);\n };\n }\n }, [basePath]);\n return (_jsx(\"div\", { ref: ref, className: \"h-full w-full\", children: children }));\n}\n//# sourceMappingURL=FixLinks.js.map","import { getPathSegments, toSegments } from './path';\n/**\n * Path matcher which support :param and *wildcard segments.\n * The wildcard segment is only supported as the last segment\n */\nexport class PathMatcher {\n tree = new RootSegmentNode();\n loadMapping(mapping) {\n for (const [key, value] of Object.entries(mapping)) {\n this.addSegments(getPathSegments(key), value);\n }\n }\n addPath(path, value) {\n this.addSegments(getPathSegments(path), value);\n }\n addSegments(segments, value) {\n let node = this.tree;\n for (let i = 0, l = segments.length; i < l; i++) {\n const segment = segments[i];\n if (segment[0] === ':') {\n let childNode = node.wildcard;\n if (!childNode) {\n childNode = new VariableSegmentNode(segment);\n node.wildcard = childNode;\n }\n else if (!(childNode instanceof VariableSegmentNode)) {\n throw new Error(`Failed to index path segments: ${segments.join('/')}. A wildcard \":\" segment will overwrite an existing wildcard segment at path: ${`/${segments.slice(0, i).join('/')}`}`);\n }\n node = childNode;\n }\n else if (segment === '*') {\n if (node.wildcard) {\n throw new Error(`Failed to index path segments: ${segments.join('/')}. A wildcard \"*\" segment already exists at path: ${`/${segments.slice(0, i).join('/')}`}`);\n }\n node.wildcard = new WildcardSegmentNode(segment, value);\n if (i < l - 1) {\n throw new Error(`Failed to index path segments: ${segments.join('/')}. A wildcard segment must be the last segment`);\n }\n return;\n }\n else {\n let childNode = node.children[segment];\n if (!childNode) {\n childNode = new LiteralSegmentNode(segment);\n node.children[segment] = childNode;\n } // else // a literal segment already exists\n node = childNode;\n }\n }\n if (node.value !== undefined) {\n throw new Error(`Failed to index path segments: ${segments.join('/')}. A value already exists at path: ${`/${segments.join('/')}`}`);\n }\n node.value = value;\n }\n match(path) {\n const segments = toSegments(path);\n if (segments.length === 0) {\n return null;\n }\n const params = {};\n let node = this.tree;\n for (const segment of segments) {\n const match = node.match(segment, params);\n if (match) {\n node = match;\n }\n else {\n return null;\n }\n }\n if (!node.value) {\n // not a leaf node (partial match)\n if (node instanceof ParentSegmentNode) {\n if (node.wildcard instanceof WildcardSegmentNode) {\n node = node.wildcard.match('', params);\n if (!node.value) {\n throw new Error('Wildcard segment node `*` must have a value');\n }\n }\n }\n if (!node.value)\n return null; // not a leaf node, neither a trailing wildcard (partial match)\n }\n let matchedSegments, remainingSegments;\n if (params._ && params._.length > 0) {\n matchedSegments = segments.slice(0, -params._.length);\n remainingSegments = params._;\n }\n else {\n matchedSegments = segments;\n }\n return { params, matchedSegments, remainingSegments, value: node.value };\n }\n}\nclass ParentSegmentNode {\n name;\n value;\n children = {};\n wildcard;\n constructor(name, value) {\n this.name = name;\n this.value = value;\n }\n match(segment, params) {\n const node = this.children[segment];\n if (node) {\n return node;\n }\n else if (this.wildcard) {\n if (this.wildcard instanceof WildcardSegmentNode) {\n return this.wildcard.match(segment, params);\n }\n else if (this.wildcard instanceof VariableSegmentNode) {\n params[this.wildcard.paramName] = segment;\n return this.wildcard;\n }\n else {\n throw new Error(`Unknown wildcard segment node type: ${this.wildcard.constructor.name}`);\n }\n }\n else {\n return null;\n }\n }\n}\nclass RootSegmentNode extends ParentSegmentNode {\n constructor() {\n super('#root');\n }\n}\nclass LiteralSegmentNode extends ParentSegmentNode {\n}\nclass VariableSegmentNode extends ParentSegmentNode {\n paramName;\n constructor(name, value) {\n super(name, value);\n this.paramName = name.substring(1);\n }\n}\nclass WildcardSegmentNode {\n name;\n value;\n constructor(name, value) {\n this.name = name;\n this.value = value;\n }\n match(segment, params) {\n if (!params._) {\n params._ = segment ? [segment] : [];\n }\n else {\n if (segment)\n params._.push(segment);\n }\n return this;\n }\n}\n//# sourceMappingURL=PathMatcher.js.map","import { createContext, useContext, useEffect } from 'react';\nimport { HistoryNavigator } from './HistoryNavigator';\nimport { PathMatcher } from './PathMatcher';\nimport { getMountBasename, isRootPath, joinPath, stripMountBasename } from './path';\nexport class BaseRouter {\n // the path to use when navigating to the root of the router\n index;\n matcher = new PathMatcher();\n constructor(routes, index) {\n this.index = index;\n for (const route of routes) {\n this.matcher.addPath(route.path, route);\n }\n }\n match(path) {\n const useIndex = isRootPath(path) && this.index;\n return this.matcher.match(useIndex || path);\n }\n}\nexport class Router extends BaseRouter {\n prompt;\n observer;\n navigator = new HistoryNavigator();\n constructor(routes, updateState) {\n super(routes);\n this.navigator.addListener((event) => {\n if (event.isCancelable && this.prompt?.when) {\n if (!window.confirm(this.prompt.message))\n return;\n }\n if (this.observer) {\n this.observer(event);\n }\n // only process afterChange events\n if (event.name === 'afterChange') {\n // Match app-relative: strip the served `<base href>` mount prefix (no-op when origin-served).\n const match = this.match(stripMountBasename(event.location.pathname));\n if (match?.value) {\n updateState({\n ...match,\n state: event.state,\n });\n }\n else {\n updateState(null);\n }\n }\n });\n }\n getTopRouter() {\n return this;\n }\n /**\n * Subsequent navigations will preserve the given params in the query string.\n * Use null to clear the sticky params.\n * @param params\n */\n setStickyParams(params) {\n this.navigator.stickyParams = params != null ? params : undefined;\n // Reflect the params in the current URL immediately, so the address bar is correct on\n // load (not only after the first navigation).\n this.navigator.normalizeCurrentUrl();\n }\n withObserver(observer) {\n this.observer = observer;\n return this;\n }\n start() {\n this.navigator.start();\n // initialize with the current location\n this.navigator.firePageLoad();\n }\n stop() {\n this.navigator.stop();\n }\n navigate(path, options) {\n this.navigator.navigate(path, options);\n }\n}\nexport class NestedRouter extends BaseRouter {\n parent;\n basePath;\n constructor(parent, basePath, routes) {\n super(routes);\n this.parent = parent;\n this.basePath = basePath;\n }\n getTopRouter() {\n if (this.parent instanceof Router) {\n return this.parent;\n }\n else {\n return this.parent.getTopRouter();\n }\n }\n navigate(path, options) {\n // base path is nested by default in a NestedRouter unless explicitly set to false by caller\n const isBasePathNested = options?.isBasePathNested ?? true;\n let basePath;\n if (isBasePathNested) {\n const childBasePath = options?.basePath;\n // e.g. \"/store\" + \"/objects/123\" => \"/store/objects/123\"\n basePath = childBasePath ? joinPath(this.basePath, childBasePath) : this.basePath;\n this.parent.navigate(path, {\n ...options,\n basePath,\n });\n }\n else {\n // isBasePathNested === false: navigate to an absolute path without adding this router's basePath\n // Pass through to parent without adding our basePath prefix\n this.parent.navigate(path, {\n ...options,\n basePath: options?.basePath,\n });\n }\n }\n}\nconst ReactRouterContext = createContext(undefined);\nexport { ReactRouterContext };\nexport function useRouterContext() {\n const ctx = useContext(ReactRouterContext);\n if (!ctx) {\n throw new Error('useRouter must be used within a RouterProvider');\n }\n return ctx;\n}\nexport function useNavigate() {\n const { navigate } = useRouterContext();\n return navigate;\n}\nexport function useRouterBasePath() {\n const { router } = useRouterContext();\n // The base path apps prepend to build absolute in-app links (e.g. `${base}/items/${id}`). It MUST\n // include the served `<base href>` mount so links stay on the mount and match the full\n // `useLocation().pathname` (which carries the mount). `getMountBasename()` is '' for the\n // origin-served Studio UI and the mount (no trailing slash) for gateway-served apps.\n const mount = getMountBasename();\n if (router instanceof NestedRouter) {\n // NestedRouter.basePath is relative to the parent router, which sits at the mount, so it must\n // be mount-prefixed too. A bare nested base of '/' (an app whose NestedRouterProvider has no\n // basePath) would otherwise make `${base}/items` resolve to `//items` — a protocol-relative\n // URL that escapes the app. Origin-served Studio (mount '') keeps the raw nested basePath.\n if (!mount)\n return router.basePath;\n return router.basePath === '/' ? mount : joinPath(mount, router.basePath);\n }\n return mount;\n}\nexport function useParams(arg) {\n const { params } = useRouterContext();\n if (arg) {\n return params[arg];\n }\n else {\n return params;\n }\n}\nexport function useLocation() {\n const { location } = useRouterContext();\n return location;\n}\nexport function usePageTitle(title) {\n useEffect(() => {\n const prev = document.title;\n document.title = title;\n return () => {\n document.title = prev;\n };\n }, [title]);\n}\nexport function useNavigationPrompt(prompt) {\n const { router } = useRouterContext();\n const topRouter = router.getTopRouter();\n useEffect(() => {\n topRouter.prompt = prompt;\n return () => {\n topRouter.prompt = undefined;\n };\n }, [prompt, topRouter]);\n useEffect(() => {\n if (prompt.when) {\n const doBlock = prompt.when;\n const listener = (ev) => {\n if (doBlock) {\n ev.preventDefault();\n ev.returnValue = '';\n }\n };\n window.addEventListener('beforeunload', listener);\n return () => {\n window.removeEventListener('beforeunload', listener);\n };\n }\n }, [prompt.when]);\n}\n//# sourceMappingURL=Router.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { withMountBasename } from './path';\nimport { useNavigate, useRouterContext } from './Router';\n/**\n * True when the click carries a modifier the browser uses for alternate link behavior\n * (open in new tab/window, download) or is not a primary-button click. Such clicks must fall\n * through to the native anchor so the browser can handle them instead of the SPA router.\n */\nfunction isModifiedClick(ev) {\n return ev.metaKey || ev.altKey || ev.ctrlKey || ev.shiftKey || ev.button !== 0;\n}\nexport function Nav({ children, to, onClick, replace = true }) {\n const navigate = useNavigate();\n const _onClick = (ev) => {\n const link = ev.target.closest('a');\n const rawHref = link?.getAttribute('href');\n const target = to ?? rawHref;\n if (link && target) {\n ev.stopPropagation();\n ev.preventDefault();\n navigate(target, { replace });\n onClick?.(ev);\n }\n };\n return (_jsx(\"span\", { onClick: _onClick, children: children }));\n}\nexport function NavLink({ children, href, className, target, topLevelNav, clearBreadcrumbs = false, replace, skipStickyParams, }) {\n const { router } = useRouterContext();\n // Resolve internal URLs even when a target makes navigation native. New-tab links still need\n // the mount path and tenant sticky params, but must not be intercepted by the SPA router.\n const isAnchorOrEmpty = !href || href.startsWith('#');\n const isExternalUrl = /^[a-z][a-z0-9+.-]*:/i.test(href) || href.startsWith('//');\n const isInternalUrl = !isAnchorOrEmpty && !isExternalUrl;\n const isNativeNavigation = !!target && target !== '_self';\n // Keep the rendered href under the served `<base href>` mount (correct middle-click / hover /\n // open-in-new-tab); the onClick navigates via the router which applies the same rule. No-op when\n // origin-served (Studio UI). Click handler below passes the raw `href` — navigate() re-bases it.\n const resolvedHref = isInternalUrl\n ? withMountBasename(!skipStickyParams ? router.getTopRouter().navigator.addStickyParams(href) : href)\n : href;\n const _onClick = (ev) => {\n if (ev.defaultPrevented || !isInternalUrl || isNativeNavigation || isModifiedClick(ev)) {\n return;\n }\n ev.stopPropagation();\n ev.preventDefault();\n const actualRouter = topLevelNav ? router.getTopRouter() : router;\n actualRouter.navigate(href, { replace: replace ?? clearBreadcrumbs });\n };\n return (_jsx(\"a\", { href: resolvedHref, className: className, target: target, onClick: _onClick, children: children }));\n}\n//# sourceMappingURL=Nav.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { useEffect, useState } from 'react';\nimport { useRouterContext, } from './Router';\n// Resolved lazy modules, keyed by the route's LazyComponent function (a stable identity: route\n// tables are declared once). A revisited lazy route renders synchronously from this cache instead\n// of unmounting to the spinner for the async import() round-trip — without it, every navigation\n// between two lazy routes blanks the page for at least a frame, even when the module is loaded.\nconst resolvedComponents = new Map();\nfunction resolveLazyRoute(route) {\n return route.LazyComponent().then((module) => {\n if (!module.default) {\n throw new Error(`Lazy module for ${route.path} does not have a default export`);\n }\n resolvedComponents.set(route.LazyComponent, module.default);\n return module.default;\n });\n}\n/**\n * Start loading the given routes' lazy modules ahead of navigation (non-lazy routes are ignored).\n * Call it during idle time after first paint: the first navigation to a prefetched route then\n * renders synchronously instead of flashing the spinner while its chunk downloads. Failures are\n * swallowed — navigation retries the import and reports the error the normal way.\n */\nexport function prefetchLazyRoutes(routes) {\n return Promise.allSettled(routes\n .filter((route) => !!route.LazyComponent)\n .map((route) => resolveLazyRoute(route)));\n}\nexport function RouteComponent({ spinner }) {\n const ctx = useRouterContext();\n const route = ctx.route;\n if (route.Component) {\n const Component = route.Component;\n return _jsx(Component, { ...ctx.params });\n }\n else if (route.LazyComponent) {\n // Keyed per path so navigating between two lazy routes remounts: a reused instance would\n // keep rendering the previous route's component while the next import resolves.\n return _jsx(LazyRouteComponent, { route: route, spinner: spinner }, route.path);\n }\n else {\n throw new Error(`Invalid route for ${route.path}. Either Component or LazyCOmponent must be specified.`);\n }\n}\nfunction LazyRouteComponent({ route, spinner }) {\n const [Component, setComponent] = useState(() => resolvedComponents.get(route.LazyComponent) ?? null);\n useEffect(() => {\n // A slow import must not land after this instance moved on (unmount, or a route object\n // swap without a path change): the stale module would overwrite the current one.\n let stale = false;\n void resolveLazyRoute(route).then((component) => {\n if (!stale) {\n // we need to wrap the component type in an arrow function\n // otherwise the setState function will execute the function as a state update function\n setComponent(() => component);\n }\n });\n return () => {\n stale = true;\n };\n }, [route]);\n return Component ? _jsx(Component, {}) : spinner || null;\n}\n//# sourceMappingURL=RouteComponent.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { FixLinks } from './FixLinks';\nimport { joinPath } from './path';\nimport { RouteComponent } from './RouteComponent';\nimport { ReactRouterContext, useRouterContext } from './Router';\nexport function NestedNavigationContext({ basePath, isBasePathNested = true, fixLinks = false, children, }) {\n const ctx = useRouterContext();\n const wrapWithFixLinks = fixLinks\n ? (elem) => _jsx(FixLinks, { basePath: ctx.matchedRoutePath, children: elem })\n : (elem) => elem;\n return (_jsx(ReactRouterContext.Provider, { value: {\n ...ctx,\n navigate: (to, options) => {\n if (options?.isBasePathNested === false) {\n // Navigate to an absolute path without adding this context's basePath\n return ctx.navigate(to, options);\n }\n const actualBasePath = options?.basePath ? joinPath(basePath, options.basePath) : basePath;\n return ctx.navigate(to, { ...options, basePath: actualBasePath, isBasePathNested });\n },\n }, children: wrapWithFixLinks(children ? children : _jsx(RouteComponent, {})) }));\n}\n//# sourceMappingURL=NestedNavigationContext.js.map","import { jsx as _jsx, jsxs as _jsxs } from \"react/jsx-runtime\";\nimport { useRouterContext } from './Router';\nexport function Route404Component() {\n const ctx = useRouterContext();\n return _jsxs(\"div\", { children: [\"Route not found for path \", ctx.matchedRoutePath] });\n}\nexport function createRoute404() {\n return {\n params: {},\n matchedSegments: [],\n state: null,\n value: {\n path: 'virtual:404',\n Component: () => _jsx(Route404Component, {}),\n },\n };\n}\n//# sourceMappingURL=Route404.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { useMemo, useRef } from 'react';\nimport { FixLinks } from './FixLinks';\nimport { createRoute404 } from './Route404';\nimport { RouteComponent } from './RouteComponent';\nimport { NestedRouter, ReactRouterContext, useRouterContext } from './Router';\nexport function NestedRouterProvider({ routes, index, children, fixLinks = false }) {\n const ctx = useRouterContext();\n // Capture basePath once at mount. When the parent router switches to a different\n // top-level route (e.g. /store -> /studio), the lazy loader briefly keeps rendering\n // this (now-stale) module with a new ctx. Keeping basePath stable lets the\n // ctx.matchedRoutePath !== nestedRouter.basePath check below detect the mismatch and\n // skip rendering instead of running match() against the wrong route table.\n const basePathRef = useRef(ctx.matchedRoutePath);\n const nestedRouter = useMemo(() => {\n if (typeof window === 'undefined')\n return null;\n const nestedRouter = new NestedRouter(ctx.router, basePathRef.current, routes);\n nestedRouter.index = index;\n return nestedRouter;\n }, [ctx.router, index, routes]);\n const nestedRouteMatch = useMemo(() => {\n if (!nestedRouter) {\n return undefined;\n }\n if (ctx.matchedRoutePath !== nestedRouter.basePath) {\n // The change belongs to another router level and will be handled there.\n return undefined;\n }\n return nestedRouter.match(ctx.remainingPath || '/') || createRoute404();\n }, [ctx.matchedRoutePath, ctx.remainingPath, nestedRouter]);\n const wrapWithFixLinks = fixLinks\n ? (elem) => _jsx(FixLinks, { basePath: ctx.matchedRoutePath, children: elem })\n : (elem) => elem;\n return (nestedRouter &&\n nestedRouteMatch && (_jsx(ReactRouterContext.Provider, { value: {\n ...ctx,\n router: nestedRouter,\n route: nestedRouteMatch.value,\n params: nestedRouteMatch.params,\n matchedRoutePath: `/${nestedRouteMatch.matchedSegments.join('/')}`,\n remainingPath: nestedRouteMatch.remainingSegments\n ? `/${nestedRouteMatch.remainingSegments.join('/')}`\n : undefined,\n navigate: (to, options) => {\n if (nestedRouter) {\n return nestedRouter.navigate(to, options);\n }\n },\n }, children: wrapWithFixLinks(children ? children : _jsx(RouteComponent, {})) })));\n}\n//# sourceMappingURL=NestedRouterProvider.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { useEffect } from 'react';\nimport { useNavigate } from './Router';\nexport function Redirect({ to, replace = true, state }) {\n const navigate = useNavigate();\n useEffect(() => {\n navigate(to, { replace, state });\n }, [navigate, replace, state, to]);\n return null;\n}\n/**\n * Creates a route component that redirects to another route when rendered.\n * Useful in route tables, for example: `{ path: '/', Component: redirectTo('/content') }`.\n */\nexport function redirectTo(to, options = {}) {\n return function RedirectRoute() {\n return _jsx(Redirect, { to: to, replace: options.replace, state: options.state });\n };\n}\n//# sourceMappingURL=Redirect.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\nimport { useSafeLayoutEffect } from '@vertesia/ui/core';\nimport { useMemo, useState } from 'react';\nimport { createRoute404 } from './Route404';\nimport { RouteComponent } from './RouteComponent';\nimport { ReactRouterContext, Router } from './Router';\nexport function RouterProvider({ routes, index, onChange, children }) {\n const [state, setState] = useState(undefined);\n const router = useMemo(() => {\n if (typeof window === 'undefined')\n return null;\n const router = new Router(routes, (match) => {\n if (match === null) {\n match = createRoute404();\n }\n setState({\n location: window.location,\n route: match.value,\n params: match.params,\n state: match.state,\n router: router,\n matchedRoutePath: `/${match.matchedSegments.join('/')}`,\n remainingPath: match.remainingSegments ? `/${match.remainingSegments.join('/')}` : undefined,\n navigate: (to, options) => {\n return router.navigate(to, options);\n },\n });\n }).withObserver(onChange);\n router.index = index;\n return router;\n }, [index, onChange, routes]);\n useSafeLayoutEffect(() => {\n router?.start();\n return () => {\n router?.stop();\n };\n }, [router]);\n return (state && (_jsx(ReactRouterContext.Provider, { value: state, children: children ? children : _jsx(RouteComponent, {}) })));\n}\n//# sourceMappingURL=RouterProvider.js.map"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertesia/ui",
3
- "version": "1.5.0-dev.20260901.045442Z",
3
+ "version": "1.5.0-dev.20260905.011013Z",
4
4
  "description": "Vertesia UI components and and hooks",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -92,11 +92,11 @@
92
92
  "vega": "^6.3.1",
93
93
  "vega-embed": "^7.1.0",
94
94
  "vega-lite": "^6.4.3",
95
- "@vertesia/client": "1.5.0-dev.20260901.045442Z",
96
- "@vertesia/common": "1.5.0-dev.20260901.045442Z",
97
- "@vertesia/fusion-ux": "1.5.0-dev.20260901.045442Z",
98
- "@vertesia/rich-text": "1.5.0-dev.20260901.045442Z",
99
- "@vertesia/json": "1.5.0-dev.20260901.045442Z"
95
+ "@vertesia/client": "1.5.0-dev.20260905.011013Z",
96
+ "@vertesia/common": "1.5.0-dev.20260905.011013Z",
97
+ "@vertesia/fusion-ux": "1.5.0-dev.20260905.011013Z",
98
+ "@vertesia/rich-text": "1.5.0-dev.20260905.011013Z",
99
+ "@vertesia/json": "1.5.0-dev.20260905.011013Z"
100
100
  },
101
101
  "devDependencies": {
102
102
  "@testing-library/react": "^16.3.2",
@@ -179,7 +179,7 @@
179
179
  "url": "https://github.com/vertesia/composableai.git",
180
180
  "directory": "packages/ui"
181
181
  },
182
- "gitHead": "52481a0537557578febbaf2494b9af5c023ccc70",
182
+ "gitHead": "ea74a29f6885cec132eec4b6b319e40137df3b40",
183
183
  "scripts": {
184
184
  "clean:lib": "rimraf ./lib ./tsconfig.tsbuildinfo",
185
185
  "clean": "rimraf ./node_modules ./lib ./tsconfig.tsbuildinfo",
@@ -26,7 +26,7 @@ import {
26
26
  import React, { useCallback, useMemo, useState } from 'react';
27
27
  import { ArtifactsTab } from './ArtifactsTab.js';
28
28
  import { BrowserUseWidget, getLatestBrowserUseByWorkstream } from './BrowserUseWidget.js';
29
- import { DocumentPanel } from './DocumentPanel.js';
29
+ import { DocumentsTab } from './DocumentsTab.js';
30
30
  import InlineSlidingPlanPanel from './ModernAgentOutput/InlineSlidingPlanPanel';
31
31
  import { getConversationUrl } from './ModernAgentOutput/utils.js';
32
32
  import type { OpenDocument } from './types/document.js';
@@ -370,8 +370,7 @@ export interface AgentRightPanelProps {
370
370
  // Documents
371
371
  openDocuments?: OpenDocument[];
372
372
  activeDocumentId?: string | null;
373
- onSelectDocument?: (id: string) => void;
374
- onCloseDocument?: (id: string) => void;
373
+ onSelectDocument?: (id: string | null) => void;
375
374
  onUpdateDocumentTitle?: (id: string, title: string) => void;
376
375
  docRefreshKey?: number;
377
376
  runId?: string;
@@ -415,7 +414,6 @@ function AgentRightPanelComponent({
415
414
  openDocuments = [],
416
415
  activeDocumentId,
417
416
  onSelectDocument,
418
- onCloseDocument,
419
417
  onUpdateDocumentTitle,
420
418
  docRefreshKey = 0,
421
419
  runId,
@@ -533,13 +531,11 @@ function AgentRightPanelComponent({
533
531
  ),
534
532
  content: withTabBoundary(
535
533
  t('agent.documents'),
536
- openDocuments.length > 0 && onSelectDocument && onCloseDocument ? (
537
- <DocumentPanel
538
- isOpen={true}
534
+ openDocuments.length > 0 && onSelectDocument ? (
535
+ <DocumentsTab
539
536
  documents={openDocuments}
540
537
  activeDocumentId={activeDocumentId ?? null}
541
538
  onSelectDocument={onSelectDocument}
542
- onCloseDocument={onCloseDocument}
543
539
  onUpdateDocumentTitle={onUpdateDocumentTitle}
544
540
  refreshKey={docRefreshKey}
545
541
  runId={runId}
@@ -3,28 +3,25 @@ import { useUITranslation } from '@vertesia/ui/i18n';
3
3
  import { NavLink } from '@vertesia/ui/router';
4
4
  import { useUserSession } from '@vertesia/ui/session';
5
5
  import { MarkdownRenderer } from '@vertesia/ui/widgets';
6
- import { ExternalLinkIcon, FileTextIcon, Loader2Icon, X } from 'lucide-react';
6
+ import { ArrowLeftIcon, ExternalLinkIcon, FileTextIcon, Loader2Icon } from 'lucide-react';
7
7
  import React, { useCallback, useEffect, useState } from 'react';
8
- import { DocumentTabBar } from './DocumentTabBar.js';
9
- import type { OpenDocument } from './types/document.js';
10
8
 
11
9
  interface DocumentPanelProps {
12
- isOpen: boolean;
13
- documents: OpenDocument[];
14
- activeDocumentId: string | null;
15
- onSelectDocument: (id: string) => void;
16
- onCloseDocument: (id: string) => void;
10
+ /** Document currently displayed. */
11
+ documentId: string;
12
+ /** Title known by the list, shown until the document itself is loaded. */
13
+ title?: string;
14
+ /** Return to the document list. */
15
+ onBack: () => void;
17
16
  onUpdateDocumentTitle?: (id: string, title: string) => void;
18
17
  refreshKey: number;
19
18
  runId?: string;
20
19
  }
21
20
 
22
21
  function DocumentPanelComponent({
23
- isOpen,
24
- documents,
25
- activeDocumentId,
26
- onSelectDocument,
27
- onCloseDocument,
22
+ documentId,
23
+ title,
24
+ onBack,
28
25
  onUpdateDocumentTitle,
29
26
  refreshKey,
30
27
  runId,
@@ -60,48 +57,42 @@ function DocumentPanelComponent({
60
57
  [client, onUpdateDocumentTitle, t],
61
58
  );
62
59
 
63
- // Fetch content when active document changes or refreshKey bumps
60
+ // Fetch content when the displayed document changes or refreshKey bumps
64
61
  useEffect(() => {
65
62
  void refreshKey;
66
- if (activeDocumentId && isOpen) {
67
- void fetchContent(activeDocumentId);
68
- }
69
- }, [activeDocumentId, refreshKey, isOpen, fetchContent]);
70
-
71
- if (!isOpen || documents.length === 0) {
72
- return null;
73
- }
63
+ void fetchContent(documentId);
64
+ }, [documentId, refreshKey, fetchContent]);
74
65
 
75
66
  return (
76
- <div className="h-full shadow-xl border border-muted/20 overflow-hidden flex flex-col">
67
+ <div className="h-full overflow-hidden flex flex-col">
77
68
  {/* Header */}
78
- <div className="flex items-center justify-between px-3 py-2 border-b border-muted/20 shrink-0">
79
- <div className="flex items-center gap-2 min-w-0">
69
+ <div className="flex items-center justify-between gap-1 px-2 py-1 border-b border-border/60 shrink-0">
70
+ <Button
71
+ variant="ghost"
72
+ size="sm"
73
+ className="size-8 shrink-0 rounded-md p-0"
74
+ onClick={onBack}
75
+ aria-label={t('agent.backToDocuments')}
76
+ title={t('agent.backToDocuments')}
77
+ >
78
+ <ArrowLeftIcon className="size-4 cn-rtl-flip" />
79
+ </Button>
80
+ <div className="flex items-center gap-1.5 min-w-0 flex-1">
80
81
  <FileTextIcon className="size-4 text-muted shrink-0" />
81
- <h3 className="font-bold text-sm truncate">{docName || t('agent.document')}</h3>
82
- </div>
83
- <div className="flex items-center gap-1">
84
- <DocumentTabBar documents={documents} activeId={activeDocumentId} onSelect={onSelectDocument} />
85
- {activeDocumentId && (
86
- <NavLink
87
- href={`/store/objects/${activeDocumentId}#overview`}
88
- topLevelNav
89
- className="inline-flex items-center justify-center rounded-md text-sm font-medium h-8 w-8 hover:bg-muted/20 text-muted hover:text-foreground"
90
- >
91
- <VTooltip description={t('agent.openDocument')} placement="top" size="xs">
92
- <ExternalLinkIcon className="size-4" />
93
- </VTooltip>
94
- </NavLink>
95
- )}
96
- <Button
97
- variant="ghost"
98
- size="sm"
99
- onClick={() => activeDocumentId && onCloseDocument(activeDocumentId)}
100
- title={t('agent.close')}
101
- >
102
- <X className="size-4" />
103
- </Button>
82
+ <span className="truncate text-sm font-medium" title={docName || title}>
83
+ {docName || title || t('agent.document')}
84
+ </span>
104
85
  </div>
86
+ <NavLink
87
+ href={`/store/objects/${documentId}#overview`}
88
+ topLevelNav
89
+ className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-muted hover:bg-muted/20 hover:text-foreground"
90
+ >
91
+ <VTooltip description={t('agent.openDocument')} placement="top" size="xs" asChild>
92
+ <ExternalLinkIcon className="size-4" aria-hidden="true" />
93
+ </VTooltip>
94
+ <span className="sr-only">{t('agent.openDocument')}</span>
95
+ </NavLink>
105
96
  </div>
106
97
 
107
98
  {/* Content area */}
@@ -0,0 +1,87 @@
1
+ /** @vitest-environment jsdom */
2
+
3
+ import { cleanup, fireEvent, render, screen } from '@testing-library/react';
4
+ import type { ComponentProps } from 'react';
5
+ import { afterEach, describe, expect, it, vi } from 'vitest';
6
+ import { I18nProvider } from '../../../i18n/index.js';
7
+ import { DocumentsTab } from './DocumentsTab.js';
8
+
9
+ vi.mock('@vertesia/ui/session', () => ({
10
+ useUserSession: () => ({
11
+ client: {
12
+ store: {
13
+ objects: {
14
+ getObjectText: vi.fn().mockResolvedValue({ text: 'Brief body' }),
15
+ retrieve: vi.fn().mockResolvedValue({ name: 'Brief' }),
16
+ },
17
+ },
18
+ },
19
+ }),
20
+ }));
21
+
22
+ vi.mock('@vertesia/ui/router', () => ({
23
+ NavLink: ({ href, children }: { href: string; children: React.ReactNode }) => <a href={href}>{children}</a>,
24
+ }));
25
+
26
+ vi.mock('@vertesia/ui/widgets', () => ({
27
+ MarkdownRenderer: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
28
+ }));
29
+
30
+ afterEach(cleanup);
31
+
32
+ const documents = [
33
+ { id: 'doc-1', title: 'Brief' },
34
+ { id: 'doc-2', title: 'Summary' },
35
+ ];
36
+
37
+ function renderDocumentsTab(props?: Partial<ComponentProps<typeof DocumentsTab>>) {
38
+ const onSelectDocument = vi.fn();
39
+ render(
40
+ <I18nProvider lng="en">
41
+ <DocumentsTab
42
+ documents={documents}
43
+ activeDocumentId={null}
44
+ onSelectDocument={onSelectDocument}
45
+ refreshKey={0}
46
+ {...props}
47
+ />
48
+ </I18nProvider>,
49
+ );
50
+ return { onSelectDocument };
51
+ }
52
+
53
+ describe('DocumentsTab', () => {
54
+ it('lists the open documents when none is selected', () => {
55
+ renderDocumentsTab();
56
+
57
+ expect(screen.getByText('2 documents')).toBeTruthy();
58
+ expect(screen.getByRole('button', { name: 'Brief' })).toBeTruthy();
59
+ expect(screen.getByRole('button', { name: 'Summary' })).toBeTruthy();
60
+ });
61
+
62
+ it('links each list entry to its document page', () => {
63
+ renderDocumentsTab();
64
+
65
+ const links = screen.getAllByRole('link', { name: 'Open document' });
66
+ expect(links.map((link) => link.getAttribute('href'))).toEqual([
67
+ '/store/objects/doc-1#overview',
68
+ '/store/objects/doc-2#overview',
69
+ ]);
70
+ });
71
+
72
+ it('selects a document when its list entry is clicked', () => {
73
+ const { onSelectDocument } = renderDocumentsTab();
74
+
75
+ fireEvent.click(screen.getByRole('button', { name: 'Brief' }));
76
+
77
+ expect(onSelectDocument).toHaveBeenCalledWith('doc-1');
78
+ });
79
+
80
+ it('goes back to the list from the selected document', () => {
81
+ const { onSelectDocument } = renderDocumentsTab({ activeDocumentId: 'doc-1' });
82
+
83
+ fireEvent.click(screen.getByRole('button', { name: 'Back to documents' }));
84
+
85
+ expect(onSelectDocument).toHaveBeenCalledWith(null);
86
+ });
87
+ });