gridsmith-ui 0.23.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/dist/Breadcrumbs-CGS8GKl-.d.ts +33 -0
- package/dist/MentionList-CoNBRFGR.d.ts +8 -0
- package/dist/charts.d.ts +42 -1
- package/dist/charts.js +320 -89
- package/dist/charts.js.map +1 -1
- package/dist/chat.js +5 -4
- package/dist/chat.js.map +1 -1
- package/dist/chunk-2YSEME33.js +118 -0
- package/dist/chunk-2YSEME33.js.map +1 -0
- package/dist/{chunk-6PL7FXYH.js → chunk-3CUKJ4VP.js} +321 -11
- package/dist/chunk-3CUKJ4VP.js.map +1 -0
- package/dist/{chunk-SBTBMAIU.js → chunk-FHMCAOAH.js} +6 -6
- package/dist/{chunk-SBTBMAIU.js.map → chunk-FHMCAOAH.js.map} +1 -1
- package/dist/chunk-HP7WUZPK.js +80 -0
- package/dist/chunk-HP7WUZPK.js.map +1 -0
- package/dist/{chunk-4LDYR7QP.js → chunk-HYMXAIXN.js} +53 -13
- package/dist/chunk-HYMXAIXN.js.map +1 -0
- package/dist/{chunk-7TOJ4G7S.js → chunk-HZIP4EJI.js} +14 -9
- package/dist/chunk-HZIP4EJI.js.map +1 -0
- package/dist/{chunk-RT7RYGC3.js → chunk-JXANCXK6.js} +4 -39
- package/dist/chunk-JXANCXK6.js.map +1 -0
- package/dist/{chunk-CXMV7SXJ.js → chunk-MD2EFMES.js} +5 -77
- package/dist/chunk-MD2EFMES.js.map +1 -0
- package/dist/{chunk-IVCVNAXG.js → chunk-OTCEJN64.js} +3 -3
- package/dist/{chunk-IVCVNAXG.js.map → chunk-OTCEJN64.js.map} +1 -1
- package/dist/{chunk-EYMGLK4M.js → chunk-QGSCF7PN.js} +7 -7
- package/dist/chunk-QGSCF7PN.js.map +1 -0
- package/dist/{chunk-CKWITUSH.js → chunk-QM4SJKWV.js} +15 -5
- package/dist/chunk-QM4SJKWV.js.map +1 -0
- package/dist/chunk-RWKCAKN3.js +209 -0
- package/dist/chunk-RWKCAKN3.js.map +1 -0
- package/dist/{chunk-ICNWPNMM.js → chunk-W7GCEJEH.js} +11 -23
- package/dist/chunk-W7GCEJEH.js.map +1 -0
- package/dist/chunk-WOVYHFUD.js +50 -0
- package/dist/chunk-WOVYHFUD.js.map +1 -0
- package/dist/{chunk-NCIZQYXQ.js → chunk-X2HEV7FB.js} +33 -3
- package/dist/chunk-X2HEV7FB.js.map +1 -0
- package/dist/chunk-XVB55M3N.js +42 -0
- package/dist/chunk-XVB55M3N.js.map +1 -0
- package/dist/data-grid.d.ts +1 -1
- package/dist/data-grid.js +14 -12
- package/dist/data-grid.js.map +1 -1
- package/dist/editor-mentions.d.ts +30 -0
- package/dist/editor-mentions.js +160 -0
- package/dist/editor-mentions.js.map +1 -0
- package/dist/editor.d.ts +23 -3
- package/dist/editor.js +59 -9
- package/dist/editor.js.map +1 -1
- package/dist/{feather-2JFSFLXN.js → feather-W26ERBQV.js} +11 -3
- package/dist/feather-W26ERBQV.js.map +1 -0
- package/dist/{heroicons-4AQ4YBVG.js → heroicons-MY43466C.js} +21 -7
- package/dist/heroicons-MY43466C.js.map +1 -0
- package/dist/icons.d.ts +11 -4
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +348 -65
- package/dist/index.js +886 -576
- package/dist/index.js.map +1 -1
- package/dist/kanban.js +26 -8
- package/dist/kanban.js.map +1 -1
- package/dist/{lucide-RZC2FEMS.js → lucide-CMPVM3PS.js} +11 -3
- package/dist/lucide-CMPVM3PS.js.map +1 -0
- package/dist/{phosphor-CEN25FLM.js → phosphor-RMHZOW2O.js} +11 -3
- package/dist/phosphor-RMHZOW2O.js.map +1 -0
- package/dist/resizable.d.ts +16 -1
- package/dist/resizable.js +91 -23
- package/dist/resizable.js.map +1 -1
- package/dist/roots.css +15 -0
- package/dist/{tabler-YXXC7Y6B.js → tabler-MJVEYHA5.js} +11 -3
- package/dist/tabler-MJVEYHA5.js.map +1 -0
- package/dist/{use-pagination-DiJo0aW5.d.ts → use-pagination-BnKOnBdz.d.ts} +3 -0
- package/dist/virtualized.d.ts +1 -1
- package/dist/virtualized.js +8 -6
- package/dist/virtualized.js.map +1 -1
- package/package.json +29 -21
- package/dist/chunk-4LDYR7QP.js.map +0 -1
- package/dist/chunk-6PL7FXYH.js.map +0 -1
- package/dist/chunk-7TOJ4G7S.js.map +0 -1
- package/dist/chunk-CKWITUSH.js.map +0 -1
- package/dist/chunk-CXMV7SXJ.js.map +0 -1
- package/dist/chunk-EYMGLK4M.js.map +0 -1
- package/dist/chunk-ICNWPNMM.js.map +0 -1
- package/dist/chunk-NCIZQYXQ.js.map +0 -1
- package/dist/chunk-RT7RYGC3.js.map +0 -1
- package/dist/feather-2JFSFLXN.js.map +0 -1
- package/dist/heroicons-4AQ4YBVG.js.map +0 -1
- package/dist/lucide-RZC2FEMS.js.map +0 -1
- package/dist/phosphor-CEN25FLM.js.map +0 -1
- package/dist/tabler-YXXC7Y6B.js.map +0 -1
package/dist/chat.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Divider, CodeBlock, Link } from './chunk-
|
|
2
|
-
import './chunk-
|
|
3
|
-
import './chunk-
|
|
1
|
+
import { Divider, CodeBlock, Link } from './chunk-QGSCF7PN.js';
|
|
2
|
+
import './chunk-FHMCAOAH.js';
|
|
3
|
+
import './chunk-MD2EFMES.js';
|
|
4
4
|
import './chunk-7Q46JXSK.js';
|
|
5
|
+
import './chunk-HYMXAIXN.js';
|
|
6
|
+
import './chunk-HP7WUZPK.js';
|
|
5
7
|
import './chunk-WH2FUFAC.js';
|
|
6
|
-
import './chunk-4LDYR7QP.js';
|
|
7
8
|
import { cn } from './chunk-M2QRNBDQ.js';
|
|
8
9
|
import { memo, Children, isValidElement } from 'react';
|
|
9
10
|
import Markdown from 'react-markdown';
|
package/dist/chat.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../showcase/src/components/MarkdownContent.tsx"],"names":[],"mappings":"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","file":"chat.js","sourcesContent":["import { memo, Children, isValidElement, type ComponentProps, type ReactElement, type ReactNode } from \"react\";\nimport Markdown, { type Components } from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport { cn } from \"../lib/utils\";\nimport { CodeBlock } from \"./CodeBlock\";\nimport { Link } from \"./Link\";\nimport { Divider } from \"./Divider\";\n\nexport interface MarkdownContentProps {\n /** The markdown source — a model's reply, an API's description. Raw HTML in it is never rendered. */\n children: string;\n /** Show a caret at the end of the last block while the source is still arriving. Pass a message's status === \"streaming\" from ChatMessageList's renderContent. */\n streaming?: boolean;\n className?: string;\n}\n\nconst isExternal = (href: string) => /^(https?:)?\\/\\//i.test(href);\n\n/** Pull the code string and language out of the single <code> child react-markdown gives a <pre>. */\nfunction codeFromPre(children: ReactNode): { code: string; language?: string } {\n const only = Children.toArray(children).find(isValidElement) as ReactElement<{ className?: string; children?: ReactNode }> | undefined;\n const cls = only?.props.className ?? \"\";\n const language = /language-([\\w+-]+)/.exec(cls)?.[1];\n const raw = only ? only.props.children : children;\n const code = Children.toArray(raw)\n .map((c) => (typeof c === \"string\" || typeof c === \"number\" ? String(c) : \"\"))\n .join(\"\")\n .replace(/\\n$/, \"\");\n return { code, language };\n}\n\ntype P<T extends keyof React.JSX.IntrinsicElements> = ComponentProps<T> & { node?: unknown };\n\nconst components: Components = {\n p: ({ node: _n, ...props }: P<\"p\">) => <p {...props} />,\n a: ({ node: _n, href = \"#\", children, ...props }: P<\"a\">) => (\n <Link\n href={href}\n underline=\"always\"\n {...(isExternal(href) ? { target: \"_blank\", rel: \"noopener noreferrer\" } : {})}\n {...(props as Record<string, unknown>)}\n >\n {children}\n </Link>\n ),\n pre: ({ node: _n, children }: P<\"pre\">) => {\n const { code, language } = codeFromPre(children);\n return <CodeBlock code={code} language={language} />;\n },\n code: ({ node: _n, className, children, ...props }: P<\"code\">) => (\n <code\n className={cn(\n \"rounded-[var(--ds-radius-sm)] bg-[var(--ds-bg-muted)] px-ds-1 py-[1px] font-[family-name:var(--ds-font-mono)] text-[0.9em]\",\n className,\n )}\n {...props}\n >\n {children}\n </code>\n ),\n ul: ({ node: _n, ...props }: P<\"ul\">) => <ul className=\"list-disc space-y-ds-1 pl-ds-5\" {...props} />,\n ol: ({ node: _n, ...props }: P<\"ol\">) => <ol className=\"list-decimal space-y-ds-1 pl-ds-5\" {...props} />,\n li: ({ node: _n, ...props }: P<\"li\">) => <li {...props} />,\n h1: ({ node: _n, ...props }: P<\"h1\">) => <h3 className=\"text-base font-semibold text-[var(--ds-text-primary)]\" {...props} />,\n h2: ({ node: _n, ...props }: P<\"h2\">) => <h3 className=\"text-base font-semibold text-[var(--ds-text-primary)]\" {...props} />,\n h3: ({ node: _n, ...props }: P<\"h3\">) => <h4 className=\"text-sm font-semibold text-[var(--ds-text-primary)]\" {...props} />,\n h4: ({ node: _n, ...props }: P<\"h4\">) => <h4 className=\"text-sm font-semibold text-[var(--ds-text-primary)]\" {...props} />,\n h5: ({ node: _n, ...props }: P<\"h5\">) => <h5 className=\"text-sm font-medium text-[var(--ds-text-primary)]\" {...props} />,\n h6: ({ node: _n, ...props }: P<\"h6\">) => <h6 className=\"text-sm font-medium text-[var(--ds-text-secondary)]\" {...props} />,\n blockquote: ({ node: _n, ...props }: P<\"blockquote\">) => (\n <blockquote\n className=\"border-l-[length:calc(var(--ds-border-width)*2)] border-[var(--ds-border-default)] pl-ds-3 text-[var(--ds-text-secondary)]\"\n {...props}\n />\n ),\n hr: () => <Divider />,\n strong: ({ node: _n, ...props }: P<\"strong\">) => <strong className=\"font-semibold\" {...props} />,\n // Wide content scrolls inside its own container; the page never scrolls sideways.\n table: ({ node: _n, ...props }: P<\"table\">) => (\n <div className=\"overflow-x-auto rounded-[var(--ds-radius-md)] border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\">\n <table className=\"w-full border-collapse text-sm\" {...props} />\n </div>\n ),\n thead: ({ node: _n, ...props }: P<\"thead\">) => <thead className=\"bg-[var(--ds-bg-muted)]\" {...props} />,\n th: ({ node: _n, ...props }: P<\"th\">) => (\n <th className=\"px-ds-3 py-ds-2 text-left text-xs font-semibold uppercase tracking-wide text-[var(--ds-text-secondary)]\" {...props} />\n ),\n td: ({ node: _n, ...props }: P<\"td\">) => (\n <td className=\"border-t-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] px-ds-3 py-ds-2 align-top\" {...props} />\n ),\n img: ({ node: _n, alt = \"\", ...props }: P<\"img\">) => <img alt={alt} className=\"max-w-full rounded-[var(--ds-radius-md)]\" {...props} />,\n};\n\n/**\n * Renders markdown (GitHub flavour: tables, task lists, strikethrough) with\n * Gridsmith primitives: fenced code becomes CodeBlock, links become Link,\n * a rule becomes Divider, everything else is token-styled markup. Raw HTML is\n * not rendered — the source is untrusted by default. Memoised: an unchanged\n * message never re-parses; a streaming message re-parses only its own string.\n *\n * Lives on the `gridsmith-ui/chat` entry point (react-markdown and remark-gfm\n * are optional peers), so apps without a chat never load a markdown parser.\n */\n// The caret is a pseudo-element on the last block, so it sits at the end of the\n// last line of text instead of on a line of its own below a block element.\nconst STREAMING_CARET = cn(\n \"[&>:last-child]:after:content-['▍'] [&>:last-child]:after:ml-ds-0.5\",\n \"[&>:last-child]:after:text-[var(--ds-accent-primary)] [&>:last-child]:after:animate-pulse\",\n);\n\nconst Memoised = memo(function MarkdownContentInner({ children, streaming, className }: MarkdownContentProps) {\n return (\n <div\n className={cn(\"space-y-ds-4 text-sm leading-relaxed text-[var(--ds-text-primary)]\", streaming && STREAMING_CARET, className)}\n data-markdown=\"\"\n data-streaming={streaming || undefined}\n >\n <Markdown remarkPlugins={[remarkGfm]} components={components} skipHtml>\n {children}\n </Markdown>\n </div>\n );\n});\n\n// A plain function export so the registry extractor (which reads `export function`)\n// documents it; the memo above still skips re-parsing unchanged sources.\nexport function MarkdownContent(props: MarkdownContentProps) {\n return <Memoised {...props} />;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/components/MarkdownContent.tsx"],"names":[],"mappings":"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","file":"chat.js","sourcesContent":["import { memo, Children, isValidElement, type ComponentProps, type ReactElement, type ReactNode } from \"react\";\nimport Markdown, { type Components } from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport { cn } from \"../lib/utils\";\nimport { CodeBlock } from \"./CodeBlock\";\nimport { Link } from \"./Link\";\nimport { Divider } from \"./Divider\";\n\nexport interface MarkdownContentProps {\n /** The markdown source — a model's reply, an API's description. Raw HTML in it is never rendered. */\n children: string;\n /** Show a caret at the end of the last block while the source is still arriving. Pass a message's status === \"streaming\" from ChatMessageList's renderContent. */\n streaming?: boolean;\n className?: string;\n}\n\nconst isExternal = (href: string) => /^(https?:)?\\/\\//i.test(href);\n\n/** Pull the code string and language out of the single <code> child react-markdown gives a <pre>. */\nfunction codeFromPre(children: ReactNode): { code: string; language?: string } {\n const only = Children.toArray(children).find(isValidElement) as ReactElement<{ className?: string; children?: ReactNode }> | undefined;\n const cls = only?.props.className ?? \"\";\n const language = /language-([\\w+-]+)/.exec(cls)?.[1];\n const raw = only ? only.props.children : children;\n const code = Children.toArray(raw)\n .map((c) => (typeof c === \"string\" || typeof c === \"number\" ? String(c) : \"\"))\n .join(\"\")\n .replace(/\\n$/, \"\");\n return { code, language };\n}\n\ntype P<T extends keyof React.JSX.IntrinsicElements> = ComponentProps<T> & { node?: unknown };\n\nconst components: Components = {\n p: ({ node: _n, ...props }: P<\"p\">) => <p {...props} />,\n a: ({ node: _n, href = \"#\", children, ...props }: P<\"a\">) => (\n <Link\n href={href}\n underline=\"always\"\n {...(isExternal(href) ? { target: \"_blank\", rel: \"noopener noreferrer\" } : {})}\n {...(props as Record<string, unknown>)}\n >\n {children}\n </Link>\n ),\n pre: ({ node: _n, children }: P<\"pre\">) => {\n const { code, language } = codeFromPre(children);\n return <CodeBlock code={code} language={language} />;\n },\n code: ({ node: _n, className, children, ...props }: P<\"code\">) => (\n <code\n className={cn(\n \"rounded-[var(--ds-radius-sm)] bg-[var(--ds-bg-muted)] px-ds-1 py-[1px] font-[family-name:var(--ds-font-mono)] text-[0.9em]\",\n className,\n )}\n {...props}\n >\n {children}\n </code>\n ),\n ul: ({ node: _n, ...props }: P<\"ul\">) => <ul className=\"list-disc space-y-ds-1 pl-ds-5\" {...props} />,\n ol: ({ node: _n, ...props }: P<\"ol\">) => <ol className=\"list-decimal space-y-ds-1 pl-ds-5\" {...props} />,\n li: ({ node: _n, ...props }: P<\"li\">) => <li {...props} />,\n h1: ({ node: _n, ...props }: P<\"h1\">) => <h3 className=\"text-base font-semibold text-[var(--ds-text-primary)]\" {...props} />,\n h2: ({ node: _n, ...props }: P<\"h2\">) => <h3 className=\"text-base font-semibold text-[var(--ds-text-primary)]\" {...props} />,\n h3: ({ node: _n, ...props }: P<\"h3\">) => <h4 className=\"text-sm font-semibold text-[var(--ds-text-primary)]\" {...props} />,\n h4: ({ node: _n, ...props }: P<\"h4\">) => <h4 className=\"text-sm font-semibold text-[var(--ds-text-primary)]\" {...props} />,\n h5: ({ node: _n, ...props }: P<\"h5\">) => <h5 className=\"text-sm font-medium text-[var(--ds-text-primary)]\" {...props} />,\n h6: ({ node: _n, ...props }: P<\"h6\">) => <h6 className=\"text-sm font-medium text-[var(--ds-text-secondary)]\" {...props} />,\n blockquote: ({ node: _n, ...props }: P<\"blockquote\">) => (\n <blockquote\n className=\"border-l-[length:calc(var(--ds-border-width)*2)] border-[var(--ds-border-default)] pl-ds-3 text-[var(--ds-text-secondary)]\"\n {...props}\n />\n ),\n hr: () => <Divider />,\n strong: ({ node: _n, ...props }: P<\"strong\">) => <strong className=\"font-semibold\" {...props} />,\n // Wide content scrolls inside its own container; the page never scrolls sideways.\n table: ({ node: _n, ...props }: P<\"table\">) => (\n <div className=\"overflow-x-auto rounded-[var(--ds-radius-md)] border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\">\n <table className=\"w-full border-collapse text-sm\" {...props} />\n </div>\n ),\n thead: ({ node: _n, ...props }: P<\"thead\">) => <thead className=\"bg-[var(--ds-bg-muted)]\" {...props} />,\n th: ({ node: _n, ...props }: P<\"th\">) => (\n <th className=\"px-ds-3 py-ds-2 text-left text-xs font-semibold uppercase tracking-wide text-[var(--ds-text-secondary)]\" {...props} />\n ),\n td: ({ node: _n, ...props }: P<\"td\">) => (\n <td className=\"border-t-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] px-ds-3 py-ds-2 align-top\" {...props} />\n ),\n img: ({ node: _n, alt = \"\", ...props }: P<\"img\">) => <img alt={alt} className=\"max-w-full rounded-[var(--ds-radius-md)]\" {...props} />,\n};\n\n/**\n * Renders markdown (GitHub flavour: tables, task lists, strikethrough) with\n * Gridsmith primitives: fenced code becomes CodeBlock, links become Link,\n * a rule becomes Divider, everything else is token-styled markup. Raw HTML is\n * not rendered — the source is untrusted by default. Memoised: an unchanged\n * message never re-parses; a streaming message re-parses only its own string.\n *\n * Lives on the `gridsmith-ui/chat` entry point (react-markdown and remark-gfm\n * are optional peers), so apps without a chat never load a markdown parser.\n */\n// The caret is a pseudo-element on the last block, so it sits at the end of the\n// last line of text instead of on a line of its own below a block element.\nconst STREAMING_CARET = cn(\n \"[&>:last-child]:after:content-['▍'] [&>:last-child]:after:ml-ds-0.5\",\n \"[&>:last-child]:after:text-[var(--ds-accent-primary)] [&>:last-child]:after:animate-pulse\",\n);\n\nconst Memoised = memo(function MarkdownContentInner({ children, streaming, className }: MarkdownContentProps) {\n return (\n <div\n className={cn(\"space-y-ds-4 text-sm leading-relaxed text-[var(--ds-text-primary)]\", streaming && STREAMING_CARET, className)}\n data-markdown=\"\"\n data-streaming={streaming || undefined}\n >\n <Markdown remarkPlugins={[remarkGfm]} components={components} skipHtml>\n {children}\n </Markdown>\n </div>\n );\n});\n\n// A plain function export so the registry extractor (which reads `export function`)\n// documents it; the memo above still skips re-parsing unchanged sources.\nexport function MarkdownContent(props: MarkdownContentProps) {\n return <Memoised {...props} />;\n}\n"]}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { createContext, useContext, useState, useLayoutEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
// ../../showcase/src/lib/use-fill-height.ts
|
|
4
|
+
function useFillHeight(ref, enabled = true) {
|
|
5
|
+
const insideFill = useContext(FillContext);
|
|
6
|
+
const active = enabled && !insideFill;
|
|
7
|
+
const [height, setHeight] = useState(null);
|
|
8
|
+
useLayoutEffect(() => {
|
|
9
|
+
const main = ref.current?.closest("main[data-shell-main]");
|
|
10
|
+
if (!active || !main || typeof ResizeObserver === "undefined") {
|
|
11
|
+
setHeight(null);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
let frame = 0;
|
|
15
|
+
const measure = () => {
|
|
16
|
+
frame = 0;
|
|
17
|
+
const el = ref.current;
|
|
18
|
+
setHeight(el && main.contains(el) ? fillHeight(el, main) : null);
|
|
19
|
+
};
|
|
20
|
+
const schedule = () => {
|
|
21
|
+
if (!frame) frame = requestAnimationFrame(measure);
|
|
22
|
+
};
|
|
23
|
+
measure();
|
|
24
|
+
const ro = new ResizeObserver(schedule);
|
|
25
|
+
const watch = (box) => {
|
|
26
|
+
ro.observe(box);
|
|
27
|
+
for (const child of Array.from(box.children)) ro.observe(child);
|
|
28
|
+
};
|
|
29
|
+
const page = main.querySelector("[data-shell-content]");
|
|
30
|
+
watch(main);
|
|
31
|
+
if (page) watch(page);
|
|
32
|
+
const mo = typeof MutationObserver === "undefined" ? null : new MutationObserver((records) => {
|
|
33
|
+
for (const record of records) record.addedNodes.forEach((node) => {
|
|
34
|
+
if (node instanceof Element) ro.observe(node);
|
|
35
|
+
});
|
|
36
|
+
schedule();
|
|
37
|
+
});
|
|
38
|
+
mo?.observe(main, { childList: true });
|
|
39
|
+
if (page) mo?.observe(page, { childList: true });
|
|
40
|
+
return () => {
|
|
41
|
+
ro.disconnect();
|
|
42
|
+
mo?.disconnect();
|
|
43
|
+
if (frame) cancelAnimationFrame(frame);
|
|
44
|
+
};
|
|
45
|
+
}, [ref, active]);
|
|
46
|
+
return active ? height : null;
|
|
47
|
+
}
|
|
48
|
+
var FillContext = createContext(false);
|
|
49
|
+
var MIN_FILL = 240;
|
|
50
|
+
var ROW_MAX = 56;
|
|
51
|
+
function fillHeight(el, main) {
|
|
52
|
+
const page = el.closest("[data-shell-content]") ?? main;
|
|
53
|
+
if (!leadsPage(el, page) || !isLastContent(el, page) || hasOwnHeight(el) || !followsContent(el, main)) return null;
|
|
54
|
+
const mainBox = main.getBoundingClientRect();
|
|
55
|
+
const top = el.getBoundingClientRect().top - mainBox.top - main.clientTop + main.scrollTop;
|
|
56
|
+
const height = Math.floor(main.clientHeight - top - spaceBelow(el, main));
|
|
57
|
+
return height >= MIN_FILL ? height : null;
|
|
58
|
+
}
|
|
59
|
+
function takesRoom(box) {
|
|
60
|
+
const style = getComputedStyle(box);
|
|
61
|
+
if (style.display === "none" || style.position === "absolute" || style.position === "fixed") return false;
|
|
62
|
+
const rect = box.getBoundingClientRect();
|
|
63
|
+
return rect.height > 0 && rect.width > 0;
|
|
64
|
+
}
|
|
65
|
+
var CHROME = '[role="alert"], [role="status"], [role="tablist"], [role="toolbar"], [role="search"]';
|
|
66
|
+
var isChrome = (box) => box.matches(CHROME) || box.children.length > 0 && Array.from(box.children).every((child) => !takesRoom(child) || child.matches(CHROME));
|
|
67
|
+
function leadsPage(el, page) {
|
|
68
|
+
for (let node = el; node && node !== page; node = node.parentElement) {
|
|
69
|
+
for (let prev = node.previousElementSibling; prev; prev = prev.previousElementSibling) {
|
|
70
|
+
if (!takesRoom(prev)) continue;
|
|
71
|
+
if (prev.matches('[data-gs="page-header"]') || prev.querySelector('[data-gs="page-header"], h1')) continue;
|
|
72
|
+
if (isChrome(prev)) continue;
|
|
73
|
+
if (prev.getBoundingClientRect().height > ROW_MAX) return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
function isLastContent(el, page) {
|
|
79
|
+
for (let node = el; node && node !== page; node = node.parentElement) {
|
|
80
|
+
for (let next = node.nextElementSibling; next; next = next.nextElementSibling) {
|
|
81
|
+
if (takesRoom(next)) return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
function hasOwnHeight(el) {
|
|
87
|
+
const inline = el.style.height;
|
|
88
|
+
el.style.height = "";
|
|
89
|
+
const own = el.offsetHeight;
|
|
90
|
+
el.style.height = "auto";
|
|
91
|
+
const natural = el.offsetHeight;
|
|
92
|
+
el.style.height = inline;
|
|
93
|
+
return Math.abs(own - natural) > 1;
|
|
94
|
+
}
|
|
95
|
+
function followsContent(el, main) {
|
|
96
|
+
let top = el;
|
|
97
|
+
while (top.parentElement && top.parentElement !== main) top = top.parentElement;
|
|
98
|
+
const before = top.offsetHeight;
|
|
99
|
+
const inline = el.style.height;
|
|
100
|
+
el.style.height = `${el.offsetHeight + main.clientHeight}px`;
|
|
101
|
+
const grows = top.offsetHeight > before;
|
|
102
|
+
el.style.height = inline;
|
|
103
|
+
return grows;
|
|
104
|
+
}
|
|
105
|
+
function spaceBelow(el, main) {
|
|
106
|
+
const px = (value) => parseFloat(value) || 0;
|
|
107
|
+
let space = px(getComputedStyle(main).paddingBottom);
|
|
108
|
+
for (let node = el; node && node !== main; node = node.parentElement) {
|
|
109
|
+
const style = getComputedStyle(node);
|
|
110
|
+
space += px(style.marginBottom);
|
|
111
|
+
if (node !== el) space += px(style.paddingBottom) + px(style.borderBottomWidth);
|
|
112
|
+
}
|
|
113
|
+
return space;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export { FillContext, useFillHeight };
|
|
117
|
+
//# sourceMappingURL=chunk-2YSEME33.js.map
|
|
118
|
+
//# sourceMappingURL=chunk-2YSEME33.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/lib/use-fill-height.ts"],"names":[],"mappings":"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","file":"chunk-2YSEME33.js","sourcesContent":["import { createContext, useContext, useLayoutEffect, useState, type RefObject } from \"react\";\n\n/**\n * Sprint 25.16 A42 (P31): a page led by a chart, a board or a split view fills the height under its header, and its\n * content scrolls inside it; the page doesn't. SplitView (frame=\"page\"), Gantt and KanbanBoard use this one mechanism.\n *\n * The element takes the rest of the shell's <main> height (main's height less what sits above it and the padding below\n * it) when all of these hold:\n * - it leads the page: above it there is only the page's header, its chrome (notices, tabs, a toolbar, a search or\n * filters row, however tall) and short rows, so a board in a dashboard's last card keeps its own height;\n * - it is the page's last content: nothing after it, up to <main>, takes room, so nothing below it is cut off (the\n * shell's footer is not the page's: it sits below the fold, as it does under a SplitView frame=\"fill\");\n * - its height follows its content: neither its own class nor a box around it gives it one (a fixed height, a flex\n * column that already gives it the rest), and given more, the page grows;\n * - the rest is tall enough to use (a phone on its side keeps the natural height, and the page scrolls).\n * Outside the shell's <main> (AppShell marks it), or inside a view that fills (a Gantt in a SplitView's pane), it keeps\n * its own height. Returns the height in pixels, or null for the natural height.\n */\nexport function useFillHeight(ref: RefObject<HTMLElement | null>, enabled = true): number | null {\n const insideFill = useContext(FillContext);\n const active = enabled && !insideFill;\n const [height, setHeight] = useState<number | null>(null);\n useLayoutEffect(() => {\n const main = ref.current?.closest<HTMLElement>(\"main[data-shell-main]\");\n if (!active || !main || typeof ResizeObserver === \"undefined\") {\n setHeight(null);\n return;\n }\n let frame = 0;\n // the element is read on each measure: a view that changes its layout (stacked or side by side) changes its root\n const measure = () => {\n frame = 0;\n const el = ref.current;\n setHeight(el && main.contains(el) ? fillHeight(el, main) : null);\n };\n const schedule = () => {\n if (!frame) frame = requestAnimationFrame(measure);\n };\n measure();\n // main's height (the window, a phone's toolbar), and what sits above or after the element at the page's top level (a\n // header's actions wrapping, a banner or a note arriving): the boxes there now, and any that arrive\n const ro = new ResizeObserver(schedule);\n const watch = (box: Element) => {\n ro.observe(box);\n for (const child of Array.from(box.children)) ro.observe(child);\n };\n const page = main.querySelector<HTMLElement>(\"[data-shell-content]\");\n watch(main);\n if (page) watch(page);\n const mo = typeof MutationObserver === \"undefined\" ? null : new MutationObserver((records) => {\n for (const record of records) record.addedNodes.forEach((node) => { if (node instanceof Element) ro.observe(node); });\n schedule();\n });\n mo?.observe(main, { childList: true });\n if (page) mo?.observe(page, { childList: true });\n return () => {\n ro.disconnect();\n mo?.disconnect();\n if (frame) cancelAnimationFrame(frame);\n };\n }, [ref, active]);\n return active ? height : null;\n}\n\n/** Content inside a view that fills: it takes the view's height (h-full), never the page's. */\nexport const FillContext = createContext(false);\n\n/** Below this the rest of the screen is too short to scroll inside (about six rows of a chart). */\nconst MIN_FILL = 240;\n/** A row that may sit between the header and the view: tabs, a toolbar, a filters row (PageContainer's ROW_MAX). */\nconst ROW_MAX = 56;\n\nfunction fillHeight(el: HTMLElement, main: HTMLElement): number | null {\n // the page's own content: the shell's wrapper above its footer, else main\n const page = el.closest<HTMLElement>(\"[data-shell-content]\") ?? main;\n if (!leadsPage(el, page) || !isLastContent(el, page) || hasOwnHeight(el) || !followsContent(el, main)) return null;\n const mainBox = main.getBoundingClientRect();\n const top = el.getBoundingClientRect().top - mainBox.top - main.clientTop + main.scrollTop;\n const height = Math.floor(main.clientHeight - top - spaceBelow(el, main));\n return height >= MIN_FILL ? height : null;\n}\n\n/** Whether a box takes room on the page: an overlay, a portal's anchor, a hidden or an empty node doesn't. */\nfunction takesRoom(box: Element): boolean {\n const style = getComputedStyle(box);\n if (style.display === \"none\" || style.position === \"absolute\" || style.position === \"fixed\") return false;\n const rect = box.getBoundingClientRect();\n return rect.height > 0 && rect.width > 0;\n}\n\n/**\n * The page's chrome, at any height: a notice (an Alert, a banner that wraps to two lines on a phone), tabs, a toolbar, a\n * search or filters row (the review of 1 October: a two-line banner turned the fill off). Content of the page's own (a\n * row of stats, cards, text) is not chrome.\n */\nconst CHROME = '[role=\"alert\"], [role=\"status\"], [role=\"tablist\"], [role=\"toolbar\"], [role=\"search\"]';\nconst isChrome = (box: Element) =>\n box.matches(CHROME) || (box.children.length > 0 && Array.from(box.children).every((child) => !takesRoom(child) || child.matches(CHROME)));\n\n/** Above the element, up to the page's root: only the page's header (its title), its chrome, and rows no taller than ROW_MAX. */\nfunction leadsPage(el: HTMLElement, page: HTMLElement): boolean {\n for (let node: HTMLElement | null = el; node && node !== page; node = node.parentElement) {\n for (let prev = node.previousElementSibling; prev; prev = prev.previousElementSibling) {\n if (!takesRoom(prev)) continue;\n if (prev.matches('[data-gs=\"page-header\"]') || prev.querySelector('[data-gs=\"page-header\"], h1')) continue;\n if (isChrome(prev)) continue;\n if (prev.getBoundingClientRect().height > ROW_MAX) return false;\n }\n }\n return true;\n}\n\n/** Nothing after the element, up to the page's root, takes room. */\nfunction isLastContent(el: HTMLElement, page: HTMLElement): boolean {\n for (let node: HTMLElement | null = el; node && node !== page; node = node.parentElement) {\n for (let next = node.nextElementSibling; next; next = next.nextElementSibling) {\n if (takesRoom(next)) return false;\n }\n }\n return true;\n}\n\n/**\n * The element's own CSS gives it a height that isn't its content's: a fixed height of its own (`h-[420px]`), or `h-full`\n * that resolves against a box which already has one. It keeps it. Read with the fill's own height set aside.\n */\nfunction hasOwnHeight(el: HTMLElement): boolean {\n const inline = el.style.height;\n el.style.height = \"\";\n const own = el.offsetHeight;\n el.style.height = \"auto\";\n const natural = el.offsetHeight;\n el.style.height = inline;\n return Math.abs(own - natural) > 1;\n}\n\n/**\n * Given more height, does the page grow? Probed once: the element is made a screen taller and main's top-level box\n * measured. A box of fixed height around it, or a flex column that already gives it its height, absorbs it.\n */\nfunction followsContent(el: HTMLElement, main: HTMLElement): boolean {\n let top: HTMLElement = el;\n while (top.parentElement && top.parentElement !== main) top = top.parentElement;\n const before = top.offsetHeight;\n const inline = el.style.height;\n el.style.height = `${el.offsetHeight + main.clientHeight}px`;\n const grows = top.offsetHeight > before;\n el.style.height = inline;\n return grows;\n}\n\n/** The padding, borders and margins under the element, up to main's own padding: they stay below it. */\nfunction spaceBelow(el: HTMLElement, main: HTMLElement): number {\n const px = (value: string) => parseFloat(value) || 0;\n let space = px(getComputedStyle(main).paddingBottom);\n for (let node: HTMLElement | null = el; node && node !== main; node = node.parentElement) {\n const style = getComputedStyle(node);\n space += px(style.marginBottom);\n if (node !== el) space += px(style.paddingBottom) + px(style.borderBottomWidth);\n }\n return space;\n}\n"]}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { PreferencesContext, Button } from './chunk-
|
|
1
|
+
import { PreferencesContext, Button } from './chunk-HZIP4EJI.js';
|
|
2
2
|
import { useBreakpoint, readBreakpointPx } from './chunk-CRQ6KCRD.js';
|
|
3
|
-
import { FormChangeCtx
|
|
4
|
-
import { SurfaceBoundary } from './chunk-
|
|
5
|
-
import {
|
|
3
|
+
import { FormChangeCtx } from './chunk-XVB55M3N.js';
|
|
4
|
+
import { SurfaceBoundary } from './chunk-QM4SJKWV.js';
|
|
5
|
+
import { usePopupFocus, useOverlayLayer, useReturnFocus, useFocusTrap, focusInitial, useNonModalDialog, OVERLAY_CLOSE_ATTR } from './chunk-JXANCXK6.js';
|
|
6
|
+
import { useTextOverflow, Tooltip } from './chunk-MD2EFMES.js';
|
|
7
|
+
import { Icon } from './chunk-HYMXAIXN.js';
|
|
8
|
+
import { usePosition } from './chunk-HP7WUZPK.js';
|
|
6
9
|
import { useLatest } from './chunk-WH2FUFAC.js';
|
|
7
|
-
import { Icon } from './chunk-4LDYR7QP.js';
|
|
8
10
|
import { cn, lockBodyScroll, unlockBodyScroll, OVERLAY_SURFACE, GLASS_OVERLAY } from './chunk-M2QRNBDQ.js';
|
|
9
11
|
import { createContext, version, forwardRef, useState, useCallback, useRef, useEffect, isValidElement, useContext, useMemo, useId, useLayoutEffect } from 'react';
|
|
10
12
|
import { createPortal } from 'react-dom';
|
|
@@ -564,9 +566,11 @@ function DrawerPanel({ form, open, onClose, position = "right", width = "400px",
|
|
|
564
566
|
"aria-labelledby": title ? titleId : labelledBy,
|
|
565
567
|
style: sheet ? {
|
|
566
568
|
containerType: "inline-size",
|
|
569
|
+
"--ds-form-max": "none",
|
|
567
570
|
height: dragPx ? `calc(${baseHeight}${heightUnit} + ${dragPx}px)` : `${baseHeight}${heightUnit}`
|
|
568
571
|
} : {
|
|
569
572
|
containerType: "inline-size",
|
|
573
|
+
"--ds-form-max": "none",
|
|
570
574
|
width: isHorizontal ? effectiveWidth : void 0,
|
|
571
575
|
maxWidth: isHorizontal ? "100%" : void 0,
|
|
572
576
|
height: isMobile ? "100%" : void 0,
|
|
@@ -728,6 +732,7 @@ var AppShell = forwardRef(function AppShell2({
|
|
|
728
732
|
preferences,
|
|
729
733
|
currentPath,
|
|
730
734
|
homePath = "/",
|
|
735
|
+
navigate,
|
|
731
736
|
focus,
|
|
732
737
|
drawerWidth = "520px"
|
|
733
738
|
}, ref) {
|
|
@@ -755,6 +760,16 @@ var AppShell = forwardRef(function AppShell2({
|
|
|
755
760
|
setUnsavedCount((n) => n - 1);
|
|
756
761
|
};
|
|
757
762
|
}, []);
|
|
763
|
+
const [leftCount, setLeftCount] = useState(0);
|
|
764
|
+
const markFlowLeft = useCallback(() => {
|
|
765
|
+
setLeftCount((n) => n + 1);
|
|
766
|
+
let released = false;
|
|
767
|
+
return () => {
|
|
768
|
+
if (released) return;
|
|
769
|
+
released = true;
|
|
770
|
+
setLeftCount((n) => n - 1);
|
|
771
|
+
};
|
|
772
|
+
}, []);
|
|
758
773
|
const showMobileDrawer = hasMobileMenu && !(isSmallMobile && hasMobileNav);
|
|
759
774
|
const [shellEl, setShellEl] = useState(null);
|
|
760
775
|
const [chrome, setChrome] = useState({});
|
|
@@ -791,12 +806,17 @@ var AppShell = forwardRef(function AppShell2({
|
|
|
791
806
|
return /* @__PURE__ */ jsx(PreferencesContext, { value: preferences ?? null, children: /* @__PURE__ */ jsx(DrawerWidthCtx, { value: drawerWidth, children: /* @__PURE__ */ jsx(
|
|
792
807
|
AppShellContext,
|
|
793
808
|
{
|
|
794
|
-
value: { hasSidebar, hasMobileMenu, hasMobileNav, sidebarOpen, setSidebarOpen, isMobile, isTablet, sidebarCollapsed, setSidebarCollapsed: setUserCollapsed, asideOpen, setAsideOpen, asideSide, asideFloating, setAsideFloating, container: shellEl, theme: theme ?? null, isHome, navbarFloating, sidebarFloating, registerChrome, hasLauncher, launcherCorner, hasFooter, focus: focus ?? null, hasUnsavedChanges: unsavedCount > 0, addUnsavedChanges, drawerWidth },
|
|
809
|
+
value: { hasSidebar, hasMobileMenu, hasMobileNav, sidebarOpen, setSidebarOpen, isMobile, isTablet, sidebarCollapsed, setSidebarCollapsed: setUserCollapsed, asideOpen, setAsideOpen, asideSide, asideFloating, setAsideFloating, container: shellEl, theme: theme ?? null, isHome, navbarFloating, sidebarFloating, registerChrome, hasLauncher, launcherCorner, hasFooter, focus: focus ?? null, hasUnsavedChanges: unsavedCount > 0, addUnsavedChanges, drawerWidth, navigate: navigate ?? null, flowLeft: leftCount > 0, markFlowLeft },
|
|
795
810
|
children: /* @__PURE__ */ jsxs("div", { ref: (el) => {
|
|
796
811
|
setShellEl(el);
|
|
797
812
|
if (typeof ref === "function") ref(el);
|
|
798
813
|
else if (ref) ref.current = el;
|
|
799
|
-
}, className: cn(
|
|
814
|
+
}, className: cn(
|
|
815
|
+
// Sprint 25.16 A42: the dynamic viewport where the browser has it, so nothing hides under a phone browser's
|
|
816
|
+
// toolbar (100vh is the height with the toolbar hidden)
|
|
817
|
+
"relative h-screen supports-[height:100dvh]:h-dvh flex flex-col bg-[var(--ds-bg-canvas)] overflow-hidden",
|
|
818
|
+
className
|
|
819
|
+
), children: [
|
|
800
820
|
skipLink && /* @__PURE__ */ jsx(SkipLink, { href: `#${mainId}` }),
|
|
801
821
|
layout === "sidebar-header" && navbar,
|
|
802
822
|
layout === "multi-column" && navbar,
|
|
@@ -811,6 +831,7 @@ var AppShell = forwardRef(function AppShell2({
|
|
|
811
831
|
{
|
|
812
832
|
ref: mainRef,
|
|
813
833
|
id: mainId,
|
|
834
|
+
"data-shell-main": "",
|
|
814
835
|
tabIndex: -1,
|
|
815
836
|
className: cn(
|
|
816
837
|
"flex-1 min-h-0 focus:outline-none",
|
|
@@ -819,7 +840,7 @@ var AppShell = forwardRef(function AppShell2({
|
|
|
819
840
|
),
|
|
820
841
|
style: { containerType: "inline-size" },
|
|
821
842
|
children: scrollable ? footer ? /* @__PURE__ */ jsxs("div", { className: "min-h-full flex flex-col", children: [
|
|
822
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1", children }),
|
|
843
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1", "data-shell-content": "", children }),
|
|
823
844
|
footer
|
|
824
845
|
] }) : children : /* @__PURE__ */ jsx("div", { className: "absolute inset-0", children })
|
|
825
846
|
}
|
|
@@ -847,6 +868,295 @@ var AppShell = forwardRef(function AppShell2({
|
|
|
847
868
|
}
|
|
848
869
|
) }) });
|
|
849
870
|
});
|
|
871
|
+
function useCrumbFollow() {
|
|
872
|
+
const navigate = useAppShell()?.navigate ?? null;
|
|
873
|
+
return useCallback((e, item) => {
|
|
874
|
+
if (item.href && (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey)) return;
|
|
875
|
+
if (item.onClick) {
|
|
876
|
+
e.preventDefault();
|
|
877
|
+
item.onClick();
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
if (!item.href) {
|
|
881
|
+
e.preventDefault();
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
if (!navigate || e.defaultPrevented || !onThisSite(item.href)) return;
|
|
885
|
+
e.preventDefault();
|
|
886
|
+
navigate(item.href);
|
|
887
|
+
}, [navigate]);
|
|
888
|
+
}
|
|
889
|
+
function onThisSite(href) {
|
|
890
|
+
if (typeof window === "undefined") return false;
|
|
891
|
+
try {
|
|
892
|
+
return new URL(href, window.location.href).origin === window.location.origin;
|
|
893
|
+
} catch {
|
|
894
|
+
return false;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
var crumbGoes = (item) => !!(item.href || item.onClick);
|
|
898
|
+
function SeparatorIcon({ type, size }) {
|
|
899
|
+
const iconSize = size === "sm" ? 10 : 12;
|
|
900
|
+
if (type === "chevron") return /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: iconSize });
|
|
901
|
+
if (type === "arrow") return /* @__PURE__ */ jsx(Icon, { name: "arrow-right", size: iconSize });
|
|
902
|
+
if (type === "dot") return /* @__PURE__ */ jsx("span", { children: "\xB7" });
|
|
903
|
+
return /* @__PURE__ */ jsx("span", { children: "/" });
|
|
904
|
+
}
|
|
905
|
+
var Breadcrumbs = forwardRef(function Breadcrumbs2({
|
|
906
|
+
items,
|
|
907
|
+
separator = "chevron",
|
|
908
|
+
variant = "inline",
|
|
909
|
+
itemVariant,
|
|
910
|
+
size = "md",
|
|
911
|
+
showIcons = false,
|
|
912
|
+
maxItems,
|
|
913
|
+
bleed = false,
|
|
914
|
+
contentMaxWidth,
|
|
915
|
+
className,
|
|
916
|
+
container,
|
|
917
|
+
"aria-label": label = "Breadcrumb"
|
|
918
|
+
}, ref) {
|
|
919
|
+
const [dropdownOpen, setDropdownOpen] = useState(false);
|
|
920
|
+
const follow = useCrumbFollow();
|
|
921
|
+
const [activeIdx, setActiveIdx] = useState(0);
|
|
922
|
+
const ellipsisBtnRef = useRef(null);
|
|
923
|
+
const dropdownRef = useRef(null);
|
|
924
|
+
const closeDropdown = useCallback(() => setDropdownOpen(false), []);
|
|
925
|
+
const { isTop, returnFocus } = usePopupFocus(dropdownOpen, { trigger: ellipsisBtnRef, panel: dropdownRef, close: closeDropdown, tabExits: "any" });
|
|
926
|
+
const pos = usePosition(ellipsisBtnRef, dropdownRef, dropdownOpen, { side: "bottom", align: "start", offset: 4, flip: true });
|
|
927
|
+
const effectiveMaxItems = maxItems ? Math.max(maxItems, 2) : void 0;
|
|
928
|
+
const shouldCollapse = effectiveMaxItems && items.length > effectiveMaxItems;
|
|
929
|
+
const collapsedItems = shouldCollapse ? items.slice(1, -(effectiveMaxItems - 1)) : [];
|
|
930
|
+
const visibleItems = shouldCollapse ? [...items.slice(0, 1), null, ...items.slice(-(effectiveMaxItems - 1))] : items;
|
|
931
|
+
useEffect(() => {
|
|
932
|
+
if (!dropdownOpen) return;
|
|
933
|
+
const handler = (e) => {
|
|
934
|
+
const target = e.target;
|
|
935
|
+
if (ellipsisBtnRef.current?.contains(target) || dropdownRef.current?.contains(target)) return;
|
|
936
|
+
setDropdownOpen(false);
|
|
937
|
+
};
|
|
938
|
+
const onKeyDown = (e) => {
|
|
939
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTop()) return;
|
|
940
|
+
e.preventDefault();
|
|
941
|
+
returnFocus();
|
|
942
|
+
setDropdownOpen(false);
|
|
943
|
+
};
|
|
944
|
+
document.addEventListener("mousedown", handler);
|
|
945
|
+
document.addEventListener("keydown", onKeyDown);
|
|
946
|
+
return () => {
|
|
947
|
+
document.removeEventListener("mousedown", handler);
|
|
948
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
949
|
+
};
|
|
950
|
+
}, [dropdownOpen, isTop, returnFocus]);
|
|
951
|
+
useEffect(() => {
|
|
952
|
+
if (!dropdownOpen) return;
|
|
953
|
+
const id = requestAnimationFrame(() => dropdownRef.current?.querySelector(`[data-index="${activeIdx}"]`)?.focus());
|
|
954
|
+
return () => cancelAnimationFrame(id);
|
|
955
|
+
}, [dropdownOpen, activeIdx]);
|
|
956
|
+
function onMenuKeyDown(e) {
|
|
957
|
+
const last = collapsedItems.length - 1;
|
|
958
|
+
const next = e.key === "ArrowDown" ? activeIdx >= last ? 0 : activeIdx + 1 : e.key === "ArrowUp" ? activeIdx <= 0 ? last : activeIdx - 1 : e.key === "Home" ? 0 : e.key === "End" ? last : null;
|
|
959
|
+
if (next === null) return;
|
|
960
|
+
e.preventDefault();
|
|
961
|
+
setActiveIdx(next);
|
|
962
|
+
}
|
|
963
|
+
const textClass = size === "sm" ? "text-xs" : "text-sm";
|
|
964
|
+
const gapClass = size === "sm" ? "gap-ds-1" : "gap-ds-1.5";
|
|
965
|
+
const iconSize = size === "sm" ? 12 : 14;
|
|
966
|
+
const isContainedBleed = variant === "contained" && bleed;
|
|
967
|
+
const wrapperClasses = cn(
|
|
968
|
+
variant === "contained" && !bleed && cn(
|
|
969
|
+
"bg-[var(--ds-bg-muted)] rounded-[var(--ds-radius-md)]",
|
|
970
|
+
size === "sm" ? "py-ds-1 px-ds-2" : "py-ds-1.5 px-ds-3"
|
|
971
|
+
),
|
|
972
|
+
!isContainedBleed && className
|
|
973
|
+
);
|
|
974
|
+
function renderItem(item, _index, isLast) {
|
|
975
|
+
const isPill = itemVariant === "pill" || variant === "pill" && !itemVariant;
|
|
976
|
+
const insideContained = variant === "contained";
|
|
977
|
+
const pillClasses = isPill ? cn(
|
|
978
|
+
"rounded-[var(--ds-radius-full)]",
|
|
979
|
+
insideContained ? "bg-[var(--ds-bg-surface)]" : "bg-[var(--ds-bg-muted)]",
|
|
980
|
+
size === "sm" ? "px-ds-2 py-[2px]" : "px-ds-2.5 py-ds-0.5"
|
|
981
|
+
) : "";
|
|
982
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
983
|
+
showIcons && item.icon && /* @__PURE__ */ jsx(Icon, { name: item.icon, size: iconSize, className: "shrink-0" }),
|
|
984
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: item.label })
|
|
985
|
+
] });
|
|
986
|
+
if (!crumbGoes(item)) {
|
|
987
|
+
return /* @__PURE__ */ jsx(
|
|
988
|
+
"span",
|
|
989
|
+
{
|
|
990
|
+
"aria-current": isLast ? "page" : void 0,
|
|
991
|
+
className: cn(
|
|
992
|
+
"flex items-center",
|
|
993
|
+
isLast ? "font-medium text-[var(--ds-text-primary)]" : "text-[var(--ds-text-secondary)]",
|
|
994
|
+
gapClass,
|
|
995
|
+
pillClasses
|
|
996
|
+
),
|
|
997
|
+
children: content
|
|
998
|
+
}
|
|
999
|
+
);
|
|
1000
|
+
}
|
|
1001
|
+
return /* @__PURE__ */ jsx(
|
|
1002
|
+
"a",
|
|
1003
|
+
{
|
|
1004
|
+
href: item.href ?? "#",
|
|
1005
|
+
onClick: (e) => follow(e, item),
|
|
1006
|
+
className: cn(
|
|
1007
|
+
"text-[var(--ds-text-secondary)] flex items-center",
|
|
1008
|
+
"hover:text-[var(--ds-text-primary)]",
|
|
1009
|
+
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
1010
|
+
gapClass,
|
|
1011
|
+
pillClasses
|
|
1012
|
+
),
|
|
1013
|
+
children: content
|
|
1014
|
+
}
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
const listContent = /* @__PURE__ */ jsx("ol", { className: cn("flex items-center flex-wrap", gapClass, textClass), children: visibleItems.map((item, i) => {
|
|
1018
|
+
if (item === null) {
|
|
1019
|
+
return /* @__PURE__ */ jsxs("li", { className: cn("flex items-center", gapClass), children: [
|
|
1020
|
+
i > 0 && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "text-[var(--ds-text-secondary)] select-none flex items-center", children: /* @__PURE__ */ jsx(SeparatorIcon, { type: separator, size }) }),
|
|
1021
|
+
/* @__PURE__ */ jsx(
|
|
1022
|
+
"button",
|
|
1023
|
+
{
|
|
1024
|
+
type: "button",
|
|
1025
|
+
ref: ellipsisBtnRef,
|
|
1026
|
+
onClick: () => {
|
|
1027
|
+
if (!dropdownOpen) setActiveIdx(0);
|
|
1028
|
+
setDropdownOpen(!dropdownOpen);
|
|
1029
|
+
},
|
|
1030
|
+
"aria-label": "Show hidden breadcrumbs",
|
|
1031
|
+
"aria-expanded": dropdownOpen,
|
|
1032
|
+
"aria-haspopup": "menu",
|
|
1033
|
+
className: cn(
|
|
1034
|
+
"text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)]",
|
|
1035
|
+
"transition-colors duration-[var(--ds-transition-speed)] cursor-pointer",
|
|
1036
|
+
"flex items-center",
|
|
1037
|
+
(itemVariant === "pill" || variant === "pill" && !itemVariant) && cn(
|
|
1038
|
+
"rounded-[var(--ds-radius-full)]",
|
|
1039
|
+
variant === "contained" ? "bg-[var(--ds-bg-surface)]" : "bg-[var(--ds-bg-muted)]",
|
|
1040
|
+
size === "sm" ? "px-ds-2 py-[2px]" : "px-ds-2.5 py-ds-0.5"
|
|
1041
|
+
)
|
|
1042
|
+
),
|
|
1043
|
+
children: "\xB7\xB7\xB7"
|
|
1044
|
+
}
|
|
1045
|
+
)
|
|
1046
|
+
] }, "__ellipsis");
|
|
1047
|
+
}
|
|
1048
|
+
const isLast = i === visibleItems.length - 1;
|
|
1049
|
+
return /* @__PURE__ */ jsxs("li", { className: cn("flex items-center", gapClass), children: [
|
|
1050
|
+
i > 0 && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "text-[var(--ds-text-secondary)] select-none flex items-center", children: /* @__PURE__ */ jsx(SeparatorIcon, { type: separator, size }) }),
|
|
1051
|
+
renderItem(item, i, isLast)
|
|
1052
|
+
] }, i);
|
|
1053
|
+
}) });
|
|
1054
|
+
const dropdown = dropdownOpen && collapsedItems.length > 0 && createPortal(
|
|
1055
|
+
/* @__PURE__ */ jsx(
|
|
1056
|
+
"div",
|
|
1057
|
+
{
|
|
1058
|
+
ref: dropdownRef,
|
|
1059
|
+
role: "menu",
|
|
1060
|
+
"aria-label": "Hidden breadcrumbs",
|
|
1061
|
+
onKeyDown: onMenuKeyDown,
|
|
1062
|
+
className: cn(
|
|
1063
|
+
"fixed z-[var(--ds-z-popover)] min-w-[160px] max-h-60 overflow-auto",
|
|
1064
|
+
"bg-[var(--ds-bg-surface-elevated)]",
|
|
1065
|
+
"[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
|
|
1066
|
+
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
1067
|
+
"rounded-[var(--ds-radius-md)]",
|
|
1068
|
+
"shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]",
|
|
1069
|
+
"py-ds-1"
|
|
1070
|
+
),
|
|
1071
|
+
style: { top: pos.top, left: pos.left },
|
|
1072
|
+
children: collapsedItems.map((ci, idx) => {
|
|
1073
|
+
const itemClass = cn(
|
|
1074
|
+
"flex items-center w-full text-left text-sm cursor-pointer",
|
|
1075
|
+
"px-ds-3 py-ds-1.5 transition-colors",
|
|
1076
|
+
"text-[var(--ds-text-secondary)]",
|
|
1077
|
+
"hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]",
|
|
1078
|
+
"focus-visible:outline-none focus-visible:bg-[var(--ds-bg-muted)] focus-visible:text-[var(--ds-text-primary)] focus-visible:shadow-[inset_var(--ds-shadow-focus)]",
|
|
1079
|
+
gapClass
|
|
1080
|
+
);
|
|
1081
|
+
const label2 = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1082
|
+
showIcons && ci.icon && /* @__PURE__ */ jsx(Icon, { name: ci.icon, size: iconSize, className: "shrink-0" }),
|
|
1083
|
+
ci.label
|
|
1084
|
+
] });
|
|
1085
|
+
return ci.href && !ci.onClick ? /* @__PURE__ */ jsx(
|
|
1086
|
+
"a",
|
|
1087
|
+
{
|
|
1088
|
+
"data-index": idx,
|
|
1089
|
+
role: "menuitem",
|
|
1090
|
+
href: ci.href,
|
|
1091
|
+
tabIndex: idx === activeIdx ? 0 : -1,
|
|
1092
|
+
className: itemClass,
|
|
1093
|
+
onClick: (e) => {
|
|
1094
|
+
setDropdownOpen(false);
|
|
1095
|
+
follow(e, ci);
|
|
1096
|
+
},
|
|
1097
|
+
onKeyDown: (e) => {
|
|
1098
|
+
if (e.key === " ") {
|
|
1099
|
+
e.preventDefault();
|
|
1100
|
+
e.currentTarget.click();
|
|
1101
|
+
}
|
|
1102
|
+
},
|
|
1103
|
+
children: label2
|
|
1104
|
+
},
|
|
1105
|
+
idx
|
|
1106
|
+
) : /* @__PURE__ */ jsx(
|
|
1107
|
+
"button",
|
|
1108
|
+
{
|
|
1109
|
+
type: "button",
|
|
1110
|
+
"data-index": idx,
|
|
1111
|
+
role: "menuitem",
|
|
1112
|
+
tabIndex: idx === activeIdx ? 0 : -1,
|
|
1113
|
+
"aria-disabled": !crumbGoes(ci) || void 0,
|
|
1114
|
+
className: itemClass,
|
|
1115
|
+
onClick: () => {
|
|
1116
|
+
if (!ci.onClick) return;
|
|
1117
|
+
setDropdownOpen(false);
|
|
1118
|
+
ci.onClick();
|
|
1119
|
+
},
|
|
1120
|
+
children: label2
|
|
1121
|
+
},
|
|
1122
|
+
idx
|
|
1123
|
+
);
|
|
1124
|
+
})
|
|
1125
|
+
}
|
|
1126
|
+
),
|
|
1127
|
+
container ?? document.body
|
|
1128
|
+
);
|
|
1129
|
+
if (isContainedBleed) {
|
|
1130
|
+
return /* @__PURE__ */ jsxs(
|
|
1131
|
+
"nav",
|
|
1132
|
+
{
|
|
1133
|
+
ref,
|
|
1134
|
+
"aria-label": label,
|
|
1135
|
+
className: cn(
|
|
1136
|
+
"w-full bg-[var(--ds-bg-muted)]",
|
|
1137
|
+
// Hairline under the band: it sits within ~1.2:1 of both canvas and a tinted header, so the edge needs a line.
|
|
1138
|
+
"border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
1139
|
+
className
|
|
1140
|
+
),
|
|
1141
|
+
children: [
|
|
1142
|
+
/* @__PURE__ */ jsx(
|
|
1143
|
+
"div",
|
|
1144
|
+
{
|
|
1145
|
+
className: cn("w-full mx-auto px-ds-6", size === "sm" ? "py-ds-1" : "py-ds-1.5"),
|
|
1146
|
+
style: { maxWidth: contentMaxWidth ?? "var(--ds-bp-xl)" },
|
|
1147
|
+
children: listContent
|
|
1148
|
+
}
|
|
1149
|
+
),
|
|
1150
|
+
dropdown
|
|
1151
|
+
]
|
|
1152
|
+
}
|
|
1153
|
+
);
|
|
1154
|
+
}
|
|
1155
|
+
return /* @__PURE__ */ jsxs("nav", { ref, "aria-label": label, className: wrapperClasses, children: [
|
|
1156
|
+
listContent,
|
|
1157
|
+
dropdown
|
|
1158
|
+
] });
|
|
1159
|
+
});
|
|
850
1160
|
function useCompact(ref, breakpoint, band = 0) {
|
|
851
1161
|
const px = typeof breakpoint === "number" ? breakpoint : readBreakpointPx(breakpoint);
|
|
852
1162
|
const width = useElementWidth(ref);
|
|
@@ -874,6 +1184,6 @@ function useElementWidth(ref) {
|
|
|
874
1184
|
return width;
|
|
875
1185
|
}
|
|
876
1186
|
|
|
877
|
-
export { AppShell, DiscardConfirm, Drawer, DrawerFooterCtx, DrawerPanel, OVERLAY_ROOT_ATTR, OverlayCloseCtx, OverlayMarkCtx, OverlayMarkScope, REACT_VERSION_PROBLEM, ResizeEdge, SkipLink, defaultMaxWidth, insetLessScrollbar, pxOf, useAppShell, useBelow, useCloseSettle, useCompact, useDirtyGuard, useElementWidth, useOverlayMark, useRememberedWidth, useScrollbarInset, useUnsavedChanges };
|
|
878
|
-
//# sourceMappingURL=chunk-
|
|
879
|
-
//# sourceMappingURL=chunk-
|
|
1187
|
+
export { AppShell, Breadcrumbs, DiscardConfirm, Drawer, DrawerFooterCtx, DrawerPanel, OVERLAY_ROOT_ATTR, OverlayCloseCtx, OverlayMarkCtx, OverlayMarkScope, REACT_VERSION_PROBLEM, ResizeEdge, SkipLink, crumbGoes, defaultMaxWidth, insetLessScrollbar, pxOf, useAppShell, useBelow, useCloseSettle, useCompact, useCrumbFollow, useDirtyGuard, useElementWidth, useOverlayMark, useRememberedWidth, useScrollbarInset, useUnsavedChanges };
|
|
1188
|
+
//# sourceMappingURL=chunk-3CUKJ4VP.js.map
|
|
1189
|
+
//# sourceMappingURL=chunk-3CUKJ4VP.js.map
|