gridsmith-ui 0.7.0 → 0.8.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.
@@ -0,0 +1,89 @@
1
+ import { useBreakpoint } from './chunk-CRQ6KCRD.js';
2
+ import { Icon } from './chunk-X4CNZFWC.js';
3
+ import { cn } from './chunk-4KVFH5KC.js';
4
+ import { Group, Panel, Separator } from 'react-resizable-panels';
5
+ import { createContext, useContext } from 'react';
6
+ import { jsx } from 'react/jsx-runtime';
7
+
8
+ var DirectionCtx = createContext("horizontal");
9
+ var MobileCtx = createContext(false);
10
+ function ResizablePanelGroup({
11
+ className,
12
+ direction = "horizontal",
13
+ stackOnMobile = true,
14
+ ...props
15
+ }) {
16
+ const isMobile = useBreakpoint("sm");
17
+ const shouldStack = stackOnMobile && isMobile && direction === "horizontal";
18
+ const effectiveDirection = shouldStack ? "vertical" : direction;
19
+ return /* @__PURE__ */ jsx(DirectionCtx.Provider, { value: effectiveDirection, children: /* @__PURE__ */ jsx(MobileCtx.Provider, { value: isMobile, children: /* @__PURE__ */ jsx(
20
+ Group,
21
+ {
22
+ className: cn(
23
+ "flex h-full w-full",
24
+ effectiveDirection === "vertical" && "flex-col",
25
+ className
26
+ ),
27
+ orientation: effectiveDirection,
28
+ ...props
29
+ }
30
+ ) }) });
31
+ }
32
+ function ResizablePanel({ className, ...props }) {
33
+ return /* @__PURE__ */ jsx(Panel, { className: cn("", className), ...props });
34
+ }
35
+ function ResizableHandle({
36
+ withHandle,
37
+ className,
38
+ ...props
39
+ }) {
40
+ const direction = useContext(DirectionCtx);
41
+ const isMobile = useContext(MobileCtx);
42
+ const isVertical = direction === "vertical";
43
+ return /* @__PURE__ */ jsx(
44
+ Separator,
45
+ {
46
+ className: cn(
47
+ "relative flex items-center justify-center bg-[var(--ds-border-default)]",
48
+ isVertical ? cn(
49
+ "h-[var(--ds-border-width)] w-full after:absolute after:left-0 after:right-0 after:content-['']",
50
+ isMobile ? "after:-top-3 after:-bottom-3" : "after:-top-1 after:-bottom-1"
51
+ ) : cn(
52
+ "w-[var(--ds-border-width)] after:absolute after:inset-y-0 after:content-['']",
53
+ isMobile ? "after:-left-3 after:-right-3" : "after:-left-1 after:-right-1"
54
+ ),
55
+ "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
56
+ "[&[data-resize-handle-state=drag]]:bg-[var(--ds-accent-primary)]",
57
+ "[&[data-resize-handle-state=hover]]:bg-[var(--ds-accent-primary)]",
58
+ className
59
+ ),
60
+ ...props,
61
+ children: withHandle && /* @__PURE__ */ jsx(
62
+ "div",
63
+ {
64
+ className: cn(
65
+ "z-10 flex items-center justify-center rounded-[var(--ds-radius-sm)]",
66
+ "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
67
+ "bg-[var(--ds-bg-surface)]",
68
+ isVertical ? isMobile ? "h-4 w-8" : "h-3 w-4" : isMobile ? "h-8 w-4" : "h-4 w-3"
69
+ ),
70
+ children: /* @__PURE__ */ jsx(
71
+ Icon,
72
+ {
73
+ name: "grip-vertical",
74
+ size: isMobile ? 12 : 10,
75
+ className: cn(
76
+ "text-[var(--ds-text-muted)]",
77
+ isVertical && "rotate-90"
78
+ )
79
+ }
80
+ )
81
+ }
82
+ )
83
+ }
84
+ );
85
+ }
86
+
87
+ export { ResizableHandle, ResizablePanel, ResizablePanelGroup };
88
+ //# sourceMappingURL=chunk-5B2ZFL2H.js.map
89
+ //# sourceMappingURL=chunk-5B2ZFL2H.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../showcase/src/components/ResizablePanels.tsx"],"names":["PanelGroup","PanelResizeHandle"],"mappings":";;;;;;;AAaA,IAAM,YAAA,GAAe,cAAyB,YAAY,CAAA;AAC1D,IAAM,SAAA,GAAY,cAAc,KAAK,CAAA;AAa9B,SAAS,mBAAA,CAAoB;AAAA,EAClC,SAAA;AAAA,EACA,SAAA,GAAY,YAAA;AAAA,EACZ,aAAA,GAAgB,IAAA;AAAA,EAChB,GAAG;AACL,CAAA,EAA6B;AAC3B,EAAA,MAAM,QAAA,GAAW,cAAc,IAAI,CAAA;AACnC,EAAA,MAAM,WAAA,GAAc,aAAA,IAAiB,QAAA,IAAY,SAAA,KAAc,YAAA;AAC/D,EAAA,MAAM,kBAAA,GAAqB,cAAc,UAAA,GAAa,SAAA;AAEtD,EAAA,uBACE,GAAA,CAAC,YAAA,CAAa,QAAA,EAAb,EAAsB,KAAA,EAAO,kBAAA,EAC5B,QAAA,kBAAA,GAAA,CAAC,SAAA,CAAU,QAAA,EAAV,EAAmB,KAAA,EAAO,QAAA,EACzB,QAAA,kBAAA,GAAA;AAAA,IAACA,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA;AAAA,QACT,oBAAA;AAAA,QACA,uBAAuB,UAAA,IAAc,UAAA;AAAA,QACrC;AAAA,OACF;AAAA,MACA,WAAA,EAAa,kBAAA;AAAA,MACZ,GAAG;AAAA;AAAA,KAER,CAAA,EACF,CAAA;AAEJ;AAcO,SAAS,cAAA,CAAe,EAAE,SAAA,EAAW,GAAG,OAAM,EAAwB;AAC3E,EAAA,uBAAO,GAAA,CAAC,SAAM,SAAA,EAAW,EAAA,CAAG,IAAI,SAAS,CAAA,EAAI,GAAG,KAAA,EAAO,CAAA;AACzD;AAUO,SAAS,eAAA,CAAgB;AAAA,EAC9B,UAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAyB;AACvB,EAAA,MAAM,SAAA,GAAY,WAAW,YAAY,CAAA;AACzC,EAAA,MAAM,QAAA,GAAW,WAAW,SAAS,CAAA;AACrC,EAAA,MAAM,aAAa,SAAA,KAAc,UAAA;AAEjC,EAAA,uBACE,GAAA;AAAA,IAACC,SAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA;AAAA,QACT,yEAAA;AAAA,QACA,UAAA,GACI,EAAA;AAAA,UACE,gGAAA;AAAA,UACA,WAAW,8BAAA,GAAiC;AAAA,SAC9C,GACA,EAAA;AAAA,UACE,8EAAA;AAAA,UACA,WAAW,8BAAA,GAAiC;AAAA,SAC9C;AAAA,QACJ,0EAAA;AAAA,QACA,kEAAA;AAAA,QACA,mEAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG,KAAA;AAAA,MAEH,QAAA,EAAA,UAAA,oBACC,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAW,EAAA;AAAA,YACT,qEAAA;AAAA,YACA,0EAAA;AAAA,YACA,2BAAA;AAAA,YACA,UAAA,GACK,QAAA,GAAW,SAAA,GAAY,SAAA,GACvB,WAAW,SAAA,GAAY;AAAA,WAC9B;AAAA,UAEA,QAAA,kBAAA,GAAA;AAAA,YAAC,IAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,eAAA;AAAA,cACL,IAAA,EAAM,WAAW,EAAA,GAAK,EAAA;AAAA,cACtB,SAAA,EAAW,EAAA;AAAA,gBACT,6BAAA;AAAA,gBACA,UAAA,IAAc;AAAA;AAChB;AAAA;AACF;AAAA;AACF;AAAA,GAEJ;AAEJ","file":"chunk-5B2ZFL2H.js","sourcesContent":["import {\n Panel,\n Group as PanelGroup,\n Separator as PanelResizeHandle,\n} from \"react-resizable-panels\";\nimport { createContext, useContext, type ComponentProps } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useBreakpoint } from \"../lib/use-breakpoint\";\nimport { Icon } from \"../lib/icons\";\n\ntype PanelGroupProps = ComponentProps<typeof PanelGroup>;\n\ntype Direction = \"horizontal\" | \"vertical\";\nconst DirectionCtx = createContext<Direction>(\"horizontal\");\nconst MobileCtx = createContext(false);\n\nexport interface ResizablePanelGroupProps\n extends Omit<PanelGroupProps, \"className\" | \"orientation\"> {\n direction?: Direction;\n stackOnMobile?: boolean;\n className?: string;\n /** Map of panel id → percentage (0–100). Must be an object, never an array. Panels need matching id props. */\n defaultLayout?: { [panelId: string]: number };\n /** Called after resize ends. Receives { [panelId]: number }, not number[]. */\n onLayoutChanged?: (layout: { [panelId: string]: number }) => void;\n}\n\nexport function ResizablePanelGroup({\n className,\n direction = \"horizontal\",\n stackOnMobile = true,\n ...props\n}: ResizablePanelGroupProps) {\n const isMobile = useBreakpoint(\"sm\");\n const shouldStack = stackOnMobile && isMobile && direction === \"horizontal\";\n const effectiveDirection = shouldStack ? \"vertical\" : direction;\n\n return (\n <DirectionCtx.Provider value={effectiveDirection}>\n <MobileCtx.Provider value={isMobile}>\n <PanelGroup\n className={cn(\n \"flex h-full w-full\",\n effectiveDirection === \"vertical\" && \"flex-col\",\n className,\n )}\n orientation={effectiveDirection}\n {...props}\n />\n </MobileCtx.Provider>\n </DirectionCtx.Provider>\n );\n}\n\ntype PanelProps = ComponentProps<typeof Panel>;\n\nexport interface ResizablePanelProps extends Omit<PanelProps, \"className\"> {\n className?: string;\n id?: string;\n /** number = px. \"30%\" or \"30\" = percent. \"28rem\" / \"400px\" also valid. */\n defaultSize?: number | string;\n minSize?: number | string;\n maxSize?: number | string;\n collapsible?: boolean;\n}\n\nexport function ResizablePanel({ className, ...props }: ResizablePanelProps) {\n return <Panel className={cn(\"\", className)} {...props} />;\n}\n\ntype PanelResizeHandleProps = ComponentProps<typeof PanelResizeHandle>;\n\nexport interface ResizableHandleProps\n extends Omit<PanelResizeHandleProps, \"className\"> {\n withHandle?: boolean;\n className?: string;\n}\n\nexport function ResizableHandle({\n withHandle,\n className,\n ...props\n}: ResizableHandleProps) {\n const direction = useContext(DirectionCtx);\n const isMobile = useContext(MobileCtx);\n const isVertical = direction === \"vertical\";\n\n return (\n <PanelResizeHandle\n className={cn(\n \"relative flex items-center justify-center bg-[var(--ds-border-default)]\",\n isVertical\n ? cn(\n \"h-[var(--ds-border-width)] w-full after:absolute after:left-0 after:right-0 after:content-['']\",\n isMobile ? \"after:-top-3 after:-bottom-3\" : \"after:-top-1 after:-bottom-1\"\n )\n : cn(\n \"w-[var(--ds-border-width)] after:absolute after:inset-y-0 after:content-['']\",\n isMobile ? \"after:-left-3 after:-right-3\" : \"after:-left-1 after:-right-1\"\n ),\n \"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]\",\n \"[&[data-resize-handle-state=drag]]:bg-[var(--ds-accent-primary)]\",\n \"[&[data-resize-handle-state=hover]]:bg-[var(--ds-accent-primary)]\",\n className,\n )}\n {...props}\n >\n {withHandle && (\n <div\n className={cn(\n \"z-10 flex items-center justify-center rounded-[var(--ds-radius-sm)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\",\n \"bg-[var(--ds-bg-surface)]\",\n isVertical\n ? (isMobile ? \"h-4 w-8\" : \"h-3 w-4\")\n : (isMobile ? \"h-8 w-4\" : \"h-4 w-3\"),\n )}\n >\n <Icon\n name=\"grip-vertical\"\n size={isMobile ? 12 : 10}\n className={cn(\n \"text-[var(--ds-text-muted)]\",\n isVertical && \"rotate-90\",\n )}\n />\n </div>\n )}\n </PanelResizeHandle>\n );\n}\n"]}
@@ -6,7 +6,7 @@ var BreakpointWidthCtx = createContext(null);
6
6
  function BreakpointWidthProvider({ width, children }) {
7
7
  return createElement(BreakpointWidthCtx, { value: width }, children);
8
8
  }
9
- function readBpFromCSS(key) {
9
+ function readBreakpointPx(key) {
10
10
  if (typeof window === "undefined") return DEFAULT_BREAKPOINTS[key];
11
11
  const raw = getComputedStyle(document.documentElement).getPropertyValue(`--ds-bp-${key}`).trim();
12
12
  const px = parseInt(raw, 10);
@@ -17,7 +17,7 @@ var noopSubscribe = () => () => {
17
17
  var serverSnapshot = () => false;
18
18
  function useBreakpoint(key) {
19
19
  const overrideWidth = useContext(BreakpointWidthCtx);
20
- const px = useMemo(() => readBpFromCSS(key), [key]);
20
+ const px = useMemo(() => readBreakpointPx(key), [key]);
21
21
  const mediaQuery = `(max-width: ${px}px)`;
22
22
  const subscribe = useCallback((onChange) => {
23
23
  if (overrideWidth !== null || typeof window === "undefined") return noopSubscribe();
@@ -34,6 +34,6 @@ function useBreakpoint(key) {
34
34
  return matches;
35
35
  }
36
36
 
37
- export { BreakpointWidthProvider, useBreakpoint };
38
- //# sourceMappingURL=chunk-EKQHHP72.js.map
39
- //# sourceMappingURL=chunk-EKQHHP72.js.map
37
+ export { BreakpointWidthProvider, readBreakpointPx, useBreakpoint };
38
+ //# sourceMappingURL=chunk-CRQ6KCRD.js.map
39
+ //# sourceMappingURL=chunk-CRQ6KCRD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../showcase/src/lib/use-breakpoint.ts"],"names":[],"mappings":";;;AAEA,IAAM,mBAAA,GAAsB,EAAE,EAAA,EAAI,GAAA,EAAK,IAAI,GAAA,EAAK,EAAA,EAAI,IAAA,EAAM,EAAA,EAAI,IAAA,EAAK;AAInE,IAAM,kBAAA,GAAqB,cAA6B,IAAI,CAAA;AAOrD,SAAS,uBAAA,CAAwB,EAAE,KAAA,EAAO,QAAA,EAAS,EAAkD;AAC1G,EAAA,OAAO,cAAc,kBAAA,EAAoB,EAAE,KAAA,EAAO,KAAA,IAAS,QAAQ,CAAA;AACrE;AAGO,SAAS,iBAAiB,GAAA,EAA4B;AAC3D,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,oBAAoB,GAAG,CAAA;AACjE,EAAA,MAAM,GAAA,GAAM,gBAAA,CAAiB,QAAA,CAAS,eAAe,CAAA,CAClD,iBAAiB,CAAA,QAAA,EAAW,GAAG,CAAA,CAAE,CAAA,CACjC,IAAA,EAAK;AACR,EAAA,MAAM,EAAA,GAAK,QAAA,CAAS,GAAA,EAAK,EAAE,CAAA;AAC3B,EAAA,OAAO,KAAA,CAAM,EAAE,CAAA,GAAI,mBAAA,CAAoB,GAAG,CAAA,GAAI,EAAA;AAChD;AAEA,IAAM,aAAA,GAAgB,MAAM,MAAM;AAAC,CAAA;AACnC,IAAM,iBAAiB,MAAM,KAAA;AAatB,SAAS,cAAc,GAAA,EAA6B;AACzD,EAAA,MAAM,aAAA,GAAgB,WAAW,kBAAkB,CAAA;AACnD,EAAA,MAAM,EAAA,GAAK,QAAQ,MAAM,gBAAA,CAAiB,GAAG,CAAA,EAAG,CAAC,GAAG,CAAC,CAAA;AACrD,EAAA,MAAM,UAAA,GAAa,eAAe,EAAE,CAAA,GAAA,CAAA;AAEpC,EAAA,MAAM,SAAA,GAAY,WAAA,CAAY,CAAC,QAAA,KAAyB;AACtD,IAAA,IAAI,kBAAkB,IAAA,IAAQ,OAAO,MAAA,KAAW,WAAA,SAAoB,aAAA,EAAc;AAClF,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,UAAA,CAAW,UAAU,CAAA;AACxC,IAAA,GAAA,CAAI,gBAAA,CAAiB,UAAU,QAAQ,CAAA;AACvC,IAAA,OAAO,MAAM,GAAA,CAAI,mBAAA,CAAoB,QAAA,EAAU,QAAQ,CAAA;AAAA,EACzD,CAAA,EAAG,CAAC,UAAA,EAAY,aAAa,CAAC,CAAA;AAE9B,EAAA,MAAM,OAAA,GAAU,oBAAA;AAAA,IACd,SAAA;AAAA,IACA,MAAO,OAAO,MAAA,KAAW,WAAA,GAAc,OAAO,UAAA,CAAW,UAAU,EAAE,OAAA,GAAU,KAAA;AAAA,IAC/E;AAAA,GACF;AAEA,EAAA,IAAI,aAAA,KAAkB,IAAA,EAAM,OAAO,aAAA,IAAiB,EAAA;AACpD,EAAA,OAAO,OAAA;AACT","file":"chunk-CRQ6KCRD.js","sourcesContent":["import { useCallback, useMemo, useSyncExternalStore, createContext, useContext, createElement, type ReactNode } from \"react\";\n\nconst DEFAULT_BREAKPOINTS = { sm: 640, md: 768, lg: 1024, xl: 1280 } as const;\n\nexport type BreakpointKey = keyof typeof DEFAULT_BREAKPOINTS;\n\nconst BreakpointWidthCtx = createContext<number | null>(null);\n\n/**\n * Provides an override container width for all `useBreakpoint` calls within\n * this subtree. Used by the builder's viewport preview to make components\n * respond to the constrained canvas width instead of the browser viewport.\n */\nexport function BreakpointWidthProvider({ width, children }: { width: number | null; children: ReactNode }) {\n return createElement(BreakpointWidthCtx, { value: width }, children);\n}\n\n/** The `--ds-bp-*` breakpoint in px (the token, else the default). */\nexport function readBreakpointPx(key: BreakpointKey): number {\n if (typeof window === \"undefined\") return DEFAULT_BREAKPOINTS[key];\n const raw = getComputedStyle(document.documentElement)\n .getPropertyValue(`--ds-bp-${key}`)\n .trim();\n const px = parseInt(raw, 10);\n return isNaN(px) ? DEFAULT_BREAKPOINTS[key] : px;\n}\n\nconst noopSubscribe = () => () => {};\nconst serverSnapshot = () => false;\n\n/**\n * Reactive breakpoint check that reads `--ds-bp-*` CSS variables.\n * Returns true when the viewport (or override container) is at or below the\n * named breakpoint.\n *\n * Implemented with useSyncExternalStore so the first render already reflects\n * the media query and a change between render and subscribe cannot be missed.\n *\n * @example\n * const isMobile = useBreakpoint(\"md\"); // true when ≤768px\n */\nexport function useBreakpoint(key: BreakpointKey): boolean {\n const overrideWidth = useContext(BreakpointWidthCtx);\n const px = useMemo(() => readBreakpointPx(key), [key]);\n const mediaQuery = `(max-width: ${px}px)`;\n\n const subscribe = useCallback((onChange: () => void) => {\n if (overrideWidth !== null || typeof window === \"undefined\") return noopSubscribe();\n const mql = window.matchMedia(mediaQuery);\n mql.addEventListener(\"change\", onChange);\n return () => mql.removeEventListener(\"change\", onChange);\n }, [mediaQuery, overrideWidth]);\n\n const matches = useSyncExternalStore(\n subscribe,\n () => (typeof window !== \"undefined\" ? window.matchMedia(mediaQuery).matches : false),\n serverSnapshot,\n );\n\n if (overrideWidth !== null) return overrideWidth <= px;\n return matches;\n}\n"]}
@@ -8,6 +8,7 @@ function CodeBlock({
8
8
  code,
9
9
  language,
10
10
  showLineNumbers = false,
11
+ wrap,
11
12
  className
12
13
  }) {
13
14
  const [copied, setCopied] = useState(false);
@@ -20,6 +21,7 @@ function CodeBlock({
20
21
  }
21
22
  }, [code]);
22
23
  const lines = code.split("\n");
24
+ const wraps = wrap ?? lines.length === 1;
23
25
  const gutterWidth = showLineNumbers ? `${String(lines.length).length + 1}ch` : void 0;
24
26
  return /* @__PURE__ */ jsxs(
25
27
  "div",
@@ -57,17 +59,20 @@ function CodeBlock({
57
59
  }
58
60
  )
59
61
  ] }),
60
- /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsx("pre", { className: "p-ds-4 text-sm leading-relaxed font-[family-name:var(--ds-font-mono)]", children: /* @__PURE__ */ jsx("code", { children: lines.map((line, i) => /* @__PURE__ */ jsxs("span", { className: "block", children: [
61
- showLineNumbers && /* @__PURE__ */ jsx(
62
- "span",
63
- {
64
- className: "inline-block text-right text-[var(--ds-text-muted)] select-none mr-ds-4 opacity-50",
65
- style: { width: gutterWidth },
66
- children: i + 1
67
- }
68
- ),
69
- line || " "
70
- ] }, i)) }) }) })
62
+ /* @__PURE__ */ jsx("div", { className: wraps ? void 0 : "overflow-x-auto", "data-wrap": wraps ? "true" : void 0, children: /* @__PURE__ */ jsx("pre", { className: cn("p-ds-4 text-sm leading-relaxed font-[family-name:var(--ds-font-mono)]", wraps && "whitespace-pre-wrap break-words"), children: /* @__PURE__ */ jsx("code", { children: lines.map((line, i) => (
63
+ // with line numbers each line is a two-column row, so a wrapped line continues under its text, not under the gutter
64
+ /* @__PURE__ */ jsxs("span", { className: showLineNumbers ? "grid grid-cols-[max-content_1fr]" : "block", children: [
65
+ showLineNumbers && /* @__PURE__ */ jsx(
66
+ "span",
67
+ {
68
+ className: "text-right text-[var(--ds-text-muted)] select-none mr-ds-4 opacity-50",
69
+ style: { width: gutterWidth },
70
+ children: i + 1
71
+ }
72
+ ),
73
+ /* @__PURE__ */ jsx("span", { className: "min-w-0", children: line || " " })
74
+ ] }, i)
75
+ )) }) }) })
71
76
  ]
72
77
  }
73
78
  );
@@ -152,5 +157,5 @@ function Divider({
152
157
  }
153
158
 
154
159
  export { CodeBlock, Divider, Link };
155
- //# sourceMappingURL=chunk-G6KC5YNY.js.map
156
- //# sourceMappingURL=chunk-G6KC5YNY.js.map
160
+ //# sourceMappingURL=chunk-VXKSQ56H.js.map
161
+ //# sourceMappingURL=chunk-VXKSQ56H.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../showcase/src/components/CodeBlock.tsx","../../../showcase/src/components/Link.tsx","../../../showcase/src/components/Divider.tsx"],"names":["Link","jsxs","jsx"],"mappings":";;;;;;AAcO,SAAS,SAAA,CAAU;AAAA,EACxB,IAAA;AAAA,EACA,QAAA;AAAA,EACA,eAAA,GAAkB,KAAA;AAAA,EAClB,IAAA;AAAA,EACA;AACF,CAAA,EAAmB;AACjB,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAS,KAAK,CAAA;AAE1C,EAAA,MAAM,UAAA,GAAa,YAAY,YAAY;AACzC,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,CAAU,SAAA,CAAU,SAAA,CAAU,IAAI,CAAA;AACxC,MAAA,SAAA,CAAU,IAAI,CAAA;AACd,MAAA,UAAA,CAAW,MAAM,SAAA,CAAU,KAAK,CAAA,EAAG,GAAI,CAAA;AAAA,IACzC,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAC7B,EAAA,MAAM,KAAA,GAAQ,IAAA,IAAQ,KAAA,CAAM,MAAA,KAAW,CAAA;AACvC,EAAA,MAAM,WAAA,GAAc,kBAAkB,CAAA,EAAG,MAAA,CAAO,MAAM,MAAM,CAAA,CAAE,MAAA,GAAS,CAAC,CAAA,EAAA,CAAA,GAAO,MAAA;AAE/E,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA;AAAA,QACT,gBAAA;AAAA,QACA,yDAAA;AAAA,QACA,yEAAA;AAAA,QACA,+BAAA;AAAA,QACA,8BAAA;AAAA,QACA,iBAAA;AAAA,QACA;AAAA,OACF;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,qJAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4BAAA,EACZ,QAAA,EAAA,QAAA,oBAAY,GAAA,CAAC,KAAA,EAAA,EAAM,OAAA,EAAQ,SAAA,EAAU,IAAA,EAAK,IAAA,EAAM,QAAA,EAAA,QAAA,EAAS,CAAA,EAC5D,CAAA;AAAA,0BACA,IAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,OAAA,EAAS,UAAA;AAAA,cACT,SAAA,EAAW,EAAA;AAAA,gBACT,wFAAA;AAAA,gBACA,iEAAA;AAAA,gBACA,+BAAA;AAAA,gBACA,iCAAA;AAAA,gBACA,mBAAA;AAAA,gBACA;AAAA,eACF;AAAA,cACA,YAAA,EAAY,SAAS,QAAA,GAAW,WAAA;AAAA,cAEhC,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,QAAK,IAAA,EAAM,MAAA,GAAS,OAAA,GAAU,QAAA,EAAU,MAAM,EAAA,EAAI,CAAA;AAAA,gBAClD,SAAS,QAAA,GAAW;AAAA;AAAA;AAAA;AACvB,SAAA,EACF,CAAA;AAAA,wBAEA,GAAA,CAAC,SAAI,SAAA,EAAW,KAAA,GAAQ,SAAY,iBAAA,EAAmB,WAAA,EAAW,KAAA,GAAQ,MAAA,GAAS,MAAA,EACjF,QAAA,kBAAA,GAAA,CAAC,SAAI,SAAA,EAAW,EAAA,CAAG,uEAAA,EAAyE,KAAA,IAAS,iCAAiC,CAAA,EACpI,8BAAC,MAAA,EAAA,EACE,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,EAAM,CAAA;AAAA;AAAA,0BAEhB,IAAA,CAAC,MAAA,EAAA,EAAa,SAAA,EAAW,eAAA,GAAkB,qCAAqC,OAAA,EAC7E,QAAA,EAAA;AAAA,YAAA,eAAA,oBACC,GAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAU,uEAAA;AAAA,gBACV,KAAA,EAAO,EAAE,KAAA,EAAO,WAAA,EAAY;AAAA,gBAE3B,QAAA,EAAA,CAAA,GAAI;AAAA;AAAA,aACP;AAAA,4BAEF,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAW,kBAAQ,GAAA,EAAI;AAAA,WAAA,EAAA,EAT9B,CAUX;AAAA,SACD,CAAA,EACH,GACF,CAAA,EACF;AAAA;AAAA;AAAA,GACF;AAEJ;ACnEA,IAAM,UAAA,GAAuC;AAAA,EAC3C,MAAA,EAAQ,2HAAA;AAAA,EACR,KAAA,EAAO,qEAAA;AAAA,EACP,OAAA,EAAS;AACX,CAAA;AAEA,IAAM,eAAA,GAAiD;AAAA,EACrD,KAAA,EAAO,8BAAA;AAAA,EACP,MAAA,EAAQ,8BAAA;AAAA,EACR,IAAA,EAAM;AACR,CAAA;AAWO,IAAM,IAAA,GAAO,WAAyC,SAASA,KAAAA,CACpE,EAAE,IAAA,EAAM,QAAA,EAAU,SAAA,GAAY,OAAA,EAAS,IAAA,GAAO,QAAA,EAAU,WAAW,KAAA,EAAO,SAAA,EAAW,SAAA,EAAW,QAAA,EAAU,SAAA,EAAW,SAAA,EAAW,QAAQ,GAAA,EAAK,GAAG,KAAA,EAAM,EACtJ,GAAA,EACA;AACA,EAAA,MAAM,OAAA,GAAU,EAAA;AAAA,IACd,8DAAA;AAAA,IACA,yDAAA;AAAA,IACA,uIAAA;AAAA,IACA,WAAW,IAAI,CAAA;AAAA,IACf,gBAAgB,SAAS,CAAA;AAAA,IACzB;AAAA,GACF;AACA,EAAA,MAAM,cAAA,GAAiB,WAAW,QAAA,GAAW,MAAA;AAC7C,EAAA,MAAM,WAAA,GAAc,QAAA,GAAW,EAAA,CAAG,qBAAA,EAAuB,GAAG,CAAA,GAAI,GAAA;AAChE,EAAA,MAAM,OAAA,mBACJC,IAAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,IAAA,QAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GAAA,EACH,CAAA;AAGF,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,uBACEC,GAAAA,CAAC,SAAA,EAAA,EAAU,GAAA,EAAU,MAAY,EAAA,EAAI,IAAA,EAAM,SAAA,EAAW,OAAA,EAAS,QAAQ,cAAA,EAAgB,GAAA,EAAK,WAAA,EAAc,GAAG,OAC1G,QAAA,EAAA,OAAA,EACH,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACEA,GAAAA,CAAC,GAAA,EAAA,EAAE,GAAA,EAAU,IAAA,EAAY,SAAA,EAAW,OAAA,EAAS,MAAA,EAAQ,cAAA,EAAgB,GAAA,EAAK,WAAA,EAAc,GAAG,OACxF,QAAA,EAAA,OAAA,EACH,CAAA;AAEJ,CAAC;ACvEM,SAAS,OAAA,CAAQ;AAAA,EACtB,WAAA,GAAc,YAAA;AAAA,EACd,KAAA;AAAA,EACA;AACF,CAAA,EAAiB;AACf,EAAA,IAAI,gBAAgB,UAAA,EAAY;AAC9B,IAAA,uBACEA,GAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,WAAA;AAAA,QACL,kBAAA,EAAiB,UAAA;AAAA,QACjB,SAAA,EAAW,EAAA;AAAA,UACT,uCAAA;AAAA,UACA,6BAAA;AAAA,UACA,+BAAA;AAAA,UACA;AAAA;AACF;AAAA,KACF;AAAA,EAEJ;AAEA,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,uBACED,IAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,WAAA;AAAA,QACL,SAAA,EAAW,EAAA,CAAG,4BAAA,EAA8B,SAAS,CAAA;AAAA,QAErD,QAAA,EAAA;AAAA,0BAAAC,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kEAAA,EAAmE,CAAA;AAAA,0BACnFA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,4DACb,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,0BACAA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kEAAA,EAAmE;AAAA;AAAA;AAAA,KACrF;AAAA,EAEJ;AAEA,EAAA,uBACEA,GAAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,WAAA;AAAA,MACL,SAAA,EAAW,EAAA;AAAA,QACT,oBAAA;AAAA,QACA,6BAAA;AAAA,QACA,+BAAA;AAAA,QACA;AAAA;AACF;AAAA,GACF;AAEJ","file":"chunk-VXKSQ56H.js","sourcesContent":["import { useState, useCallback } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"../lib/icons\";\nimport { Badge } from \"./Badge\";\n\ninterface CodeBlockProps {\n code: string;\n language?: string;\n showLineNumbers?: boolean;\n /** Wrap long lines instead of scrolling sideways. Default: on for a single-line snippet (a tracking tag, a command), off for multi-line code. */\n wrap?: boolean;\n className?: string;\n}\n\nexport function CodeBlock({\n code,\n language,\n showLineNumbers = false,\n wrap,\n className,\n}: CodeBlockProps) {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch {\n /* clipboard not available */\n }\n }, [code]);\n\n const lines = code.split(\"\\n\");\n const wraps = wrap ?? lines.length === 1;\n const gutterWidth = showLineNumbers ? `${String(lines.length).length + 1}ch` : undefined;\n\n return (\n <div\n className={cn(\n \"relative group\",\n \"bg-[var(--ds-bg-surface)] text-[var(--ds-text-primary)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"rounded-[var(--ds-radius-md)]\",\n \"shadow-[var(--ds-shadow-sm)]\",\n \"overflow-hidden\",\n className,\n )}\n >\n <div className=\"flex items-center justify-between px-ds-4 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] bg-[var(--ds-bg-muted)]\">\n <div className=\"flex items-center gap-ds-2\">\n {language && <Badge variant=\"outline\" size=\"sm\">{language}</Badge>}\n </div>\n <button\n type=\"button\"\n onClick={handleCopy}\n className={cn(\n \"inline-flex items-center gap-ds-1.5 px-ds-2 py-ds-1 text-xs font-medium cursor-pointer\",\n \"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]\",\n \"rounded-[var(--ds-radius-sm)]\",\n \"hover:bg-[var(--ds-bg-surface)]\",\n \"transition-colors\",\n \"focus-visible:shadow-[var(--ds-shadow-focus)] outline-none\",\n )}\n aria-label={copied ? \"Copied\" : \"Copy code\"}\n >\n <Icon name={copied ? \"check\" : \"folder\"} size={14} />\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n </div>\n\n <div className={wraps ? undefined : \"overflow-x-auto\"} data-wrap={wraps ? \"true\" : undefined}>\n <pre className={cn(\"p-ds-4 text-sm leading-relaxed font-[family-name:var(--ds-font-mono)]\", wraps && \"whitespace-pre-wrap break-words\")}>\n <code>\n {lines.map((line, i) => (\n // with line numbers each line is a two-column row, so a wrapped line continues under its text, not under the gutter\n <span key={i} className={showLineNumbers ? \"grid grid-cols-[max-content_1fr]\" : \"block\"}>\n {showLineNumbers && (\n <span\n className=\"text-right text-[var(--ds-text-muted)] select-none mr-ds-4 opacity-50\"\n style={{ width: gutterWidth }}\n >\n {i + 1}\n </span>\n )}\n <span className=\"min-w-0\">{line || \" \"}</span>\n </span>\n ))}\n </code>\n </pre>\n </div>\n </div>\n );\n}\n","import { forwardRef, type AnchorHTMLAttributes, type ComponentType, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\n\ntype LinkUnderline = \"hover\" | \"always\" | \"none\";\ntype LinkTone = \"accent\" | \"muted\" | \"inherit\";\n\nexport interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n href: string;\n children: ReactNode;\n /** When to show the underline. Default \"hover\". */\n underline?: LinkUnderline;\n /** Colour: accent (default), muted for secondary links, inherit to match surrounding text. */\n tone?: LinkTone;\n /** Opens in a new tab with rel=\"noopener noreferrer\". Default false. */\n external?: boolean;\n /**\n * Render through a router link component instead of a plain anchor\n * (e.g. `component={RouterLink}` from react-router or next/link). The\n * component receives the same props; `href` is also passed as `to` for\n * react-router compatibility.\n */\n component?: ComponentType<Record<string, unknown>>;\n iconLeft?: ReactNode;\n iconRight?: ReactNode;\n}\n\nconst toneStyles: Record<LinkTone, string> = {\n accent: \"text-[var(--ds-accent-primary)] hover:text-[var(--ds-accent-primary-hover)] active:text-[var(--ds-accent-primary-active)]\",\n muted: \"text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)]\",\n inherit: \"text-inherit hover:text-[var(--ds-accent-primary)]\",\n};\n\nconst underlineStyles: Record<LinkUnderline, string> = {\n hover: \"no-underline hover:underline\",\n always: \"underline underline-offset-2\",\n none: \"no-underline\",\n};\n\n/**\n * Navigation link. Renders a real <a> (or a router link via `component`) so\n * middle-click, open-in-new-tab, right-click \"copy link\" and screen readers\n * all behave correctly. Visually identical to Button variant=\"link\".\n *\n * Use Link for NAVIGATION (to a page or URL). Use Button variant=\"link\" for an\n * ACTION that should look like a link (show more, resend code). Never use a\n * ghost Button for inline text — its padding breaks the line.\n */\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(function Link(\n { href, children, underline = \"hover\", tone = \"accent\", external = false, component: Component, iconLeft, iconRight, className, target, rel, ...props },\n ref,\n) {\n const classes = cn(\n \"inline-flex items-center gap-ds-1 font-medium cursor-pointer\",\n \"transition-colors duration-[var(--ds-transition-speed)]\",\n \"focus-visible:outline-2 focus-visible:outline-[var(--ds-accent-primary)] focus-visible:outline-offset-2 rounded-[var(--ds-radius-sm)]\",\n toneStyles[tone],\n underlineStyles[underline],\n className,\n );\n const resolvedTarget = external ? \"_blank\" : target;\n const resolvedRel = external ? cn(\"noopener noreferrer\", rel) : rel;\n const content = (\n <>\n {iconLeft}\n {children}\n {iconRight}\n </>\n );\n\n if (Component) {\n return (\n <Component ref={ref} href={href} to={href} className={classes} target={resolvedTarget} rel={resolvedRel} {...props}>\n {content}\n </Component>\n );\n }\n\n return (\n <a ref={ref} href={href} className={classes} target={resolvedTarget} rel={resolvedRel} {...props}>\n {content}\n </a>\n );\n});\n","import { cn } from \"../lib/utils\";\nimport type { ReactNode } from \"react\";\n\ntype Orientation = \"horizontal\" | \"vertical\";\n\ninterface DividerProps {\n orientation?: Orientation;\n label?: ReactNode;\n className?: string;\n}\n\nexport function Divider({\n orientation = \"horizontal\",\n label,\n className,\n}: DividerProps) {\n if (orientation === \"vertical\") {\n return (\n <div\n role=\"separator\"\n aria-orientation=\"vertical\"\n className={cn(\n \"inline-block self-stretch min-h-[1em]\",\n \"w-[var(--ds-divider-width)]\",\n \"bg-[var(--ds-border-default)]\",\n className,\n )}\n />\n );\n }\n\n if (label) {\n return (\n <div\n role=\"separator\"\n className={cn(\"flex items-center gap-ds-3\", className)}\n >\n <span className=\"flex-1 h-[var(--ds-divider-width)] bg-[var(--ds-border-default)]\" />\n <span className=\"text-xs font-medium text-[var(--ds-text-muted)] shrink-0\">\n {label}\n </span>\n <span className=\"flex-1 h-[var(--ds-divider-width)] bg-[var(--ds-border-default)]\" />\n </div>\n );\n }\n\n return (\n <hr\n role=\"separator\"\n className={cn(\n \"border-none w-full\",\n \"h-[var(--ds-divider-width)]\",\n \"bg-[var(--ds-border-default)]\",\n className,\n )}\n />\n );\n}\n"]}
package/dist/data-grid.js CHANGED
@@ -1,4 +1,4 @@
1
- import { useBreakpoint } from './chunk-EKQHHP72.js';
1
+ import { useBreakpoint } from './chunk-CRQ6KCRD.js';
2
2
  import { useTextOverflow, Tooltip } from './chunk-RLNIRPOH.js';
3
3
  import './chunk-WH2FUFAC.js';
4
4
  import { Icon } from './chunk-X4CNZFWC.js';
package/dist/editor.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { useOverlayLayer } from './chunk-RLUK575N.js';
2
- import { useBreakpoint } from './chunk-EKQHHP72.js';
2
+ import { useBreakpoint } from './chunk-CRQ6KCRD.js';
3
3
  import './chunk-WH2FUFAC.js';
4
4
  import { Icon } from './chunk-X4CNZFWC.js';
5
5
  import { cn, ACTIVE_RING, FOCUS_RING } from './chunk-4KVFH5KC.js';
package/dist/index.d.ts CHANGED
@@ -411,14 +411,33 @@ interface FormContextValue {
411
411
  submitted: boolean;
412
412
  }
413
413
  declare function useFormContext(): FormContextValue;
414
+ /** An invalid field as the form finds it in its own DOM after a submit. */
415
+ interface FormFieldError {
416
+ id: string;
417
+ label: string;
418
+ message: string;
419
+ }
414
420
  interface FormWrapperProps {
415
421
  onSubmit: (errors: FormErrors) => void;
416
422
  validationMode?: ValidationMode;
417
423
  children: ReactNode;
424
+ /**
425
+ * The buttons row (submit, cancel) with a clear gap above the last field — never a hand-rolled flex row under it
426
+ * (bench round 3, R12). Right-aligned like CardFooter and the overlay footers; `actionsAlign="start"` for a narrow form.
427
+ */
428
+ actions?: ReactNode;
429
+ actionsAlign?: "start" | "end";
430
+ /** After a failed submit, scroll to and focus the first invalid field (default on). */
431
+ focusFirstError?: boolean;
432
+ /**
433
+ * When two or more fields are invalid after a submit, an error summary above the form links to each (default on).
434
+ * A function renders your own from the list.
435
+ */
436
+ errorSummary?: boolean | ((errors: FormFieldError[]) => ReactNode);
418
437
  className?: string;
419
438
  ref?: React.Ref<HTMLFormElement>;
420
439
  }
421
- declare function FormWrapper({ onSubmit, validationMode, children, className, ref }: FormWrapperProps): react_jsx_runtime.JSX.Element;
440
+ declare function FormWrapper({ onSubmit, validationMode, children, actions, actionsAlign, focusFirstError, errorSummary, className, ref }: FormWrapperProps): react_jsx_runtime.JSX.Element;
422
441
 
423
442
  interface TransferItem {
424
443
  id: string;
@@ -476,7 +495,11 @@ interface CardHeaderProps extends HTMLAttributes<HTMLDivElement> {
476
495
  menuItems?: DropdownMenuEntry[];
477
496
  }
478
497
  declare const CardHeader: react.ForwardRefExoticComponent<CardHeaderProps & react.RefAttributes<HTMLDivElement>>;
479
- declare const CardTitle: react.ForwardRefExoticComponent<HTMLAttributes<HTMLHeadingElement> & react.RefAttributes<HTMLHeadingElement>>;
498
+ interface CardTitleProps extends HTMLAttributes<HTMLHeadingElement> {
499
+ /** Max lines before clamping (with the full title on hover). Default 2, like CardDescription; 1 truncates on one line; 0 = no limit. */
500
+ lines?: number;
501
+ }
502
+ declare const CardTitle: react.ForwardRefExoticComponent<CardTitleProps & react.RefAttributes<HTMLHeadingElement>>;
480
503
  interface CardDescriptionProps extends HTMLAttributes<HTMLParagraphElement> {
481
504
  /** Max lines before clamping. Default 2. Set to 0 for no limit. */
482
505
  lines?: number;
@@ -488,6 +511,8 @@ declare const CardFooter: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDiv
488
511
  interface Trend {
489
512
  direction: "up" | "down" | "flat";
490
513
  value: string;
514
+ /** Whether the change is good news. Default: up = positive, down = negative, flat = neutral. Pass "positive" for a falling cost or overdue count, "negative" for rising churn or errors. */
515
+ sentiment?: "positive" | "negative" | "neutral";
491
516
  }
492
517
  interface StatsCardProps {
493
518
  value: string | number;
@@ -528,7 +553,8 @@ interface DescriptionListProps {
528
553
  columns?: 1 | 2 | 3 | 4;
529
554
  size?: DescriptionListSize;
530
555
  dividers?: boolean;
531
- stackBelow?: "sm" | "md" | "lg";
556
+ /** Below this breakpoint a multi-column list becomes one column. Default "sm" when columns > 1 (a phone never shows two columns of pairs); "none" keeps the columns at every width. */
557
+ stackBelow?: "sm" | "md" | "lg" | "none";
532
558
  className?: string;
533
559
  }
534
560
  declare const DescriptionList: react.ForwardRefExoticComponent<DescriptionListProps & react.RefAttributes<HTMLDListElement>>;
@@ -812,19 +838,24 @@ interface TimelineItem {
812
838
  }
813
839
  interface TimelineProps {
814
840
  items: TimelineItem[];
841
+ /** "responsive" lays the items out horizontally only when they fit at minItemWidth each, else vertically. */
815
842
  orientation?: "vertical" | "horizontal" | "responsive";
843
+ /** The least width a horizontal item gets before the row scrolls (a structural size, not a design value). */
844
+ minItemWidth?: number;
816
845
  className?: string;
817
846
  ref?: Ref<HTMLDivElement>;
818
847
  }
819
- declare function Timeline({ items, orientation, className, ref }: TimelineProps): react_jsx_runtime.JSX.Element;
848
+ declare function Timeline({ items, orientation, minItemWidth, className, ref }: TimelineProps): react_jsx_runtime.JSX.Element;
820
849
 
821
850
  interface CodeBlockProps {
822
851
  code: string;
823
852
  language?: string;
824
853
  showLineNumbers?: boolean;
854
+ /** Wrap long lines instead of scrolling sideways. Default: on for a single-line snippet (a tracking tag, a command), off for multi-line code. */
855
+ wrap?: boolean;
825
856
  className?: string;
826
857
  }
827
- declare function CodeBlock({ code, language, showLineNumbers, className, }: CodeBlockProps): react_jsx_runtime.JSX.Element;
858
+ declare function CodeBlock({ code, language, showLineNumbers, wrap, className, }: CodeBlockProps): react_jsx_runtime.JSX.Element;
828
859
 
829
860
  interface CollapsibleProps {
830
861
  open?: boolean;
@@ -1115,6 +1146,8 @@ interface StackedListProps {
1115
1146
  flush?: boolean;
1116
1147
  /** The current row in a master-detail list. Its treatment follows the theme's in-page vertical active style (rail, tint or pill), like Tabs. */
1117
1148
  selectedId?: string | number;
1149
+ /** How an interactive row answers the pointer: "tint" (default) shades the row; "title" colours the title, for article lists (a knowledge base, a changelog). */
1150
+ hover?: "tint" | "title";
1118
1151
  className?: string;
1119
1152
  }
1120
1153
  declare const StackedList: react.ForwardRefExoticComponent<StackedListProps & react.RefAttributes<HTMLUListElement>>;
@@ -1253,6 +1286,137 @@ declare const Tabs: typeof TabsRoot & {
1253
1286
  Content: typeof TabsContent;
1254
1287
  };
1255
1288
 
1289
+ /**
1290
+ * The theme's shell-level decisions, carried once by AppShell so that
1291
+ * PageHeader and PageContainer can render a page the way the builder preview
1292
+ * renders it without the page passing a single flag (Sprint 25, 14 Sep 2026).
1293
+ *
1294
+ * The generated shell passes the object the template emits; the builder
1295
+ * preview passes the same values from the theme state. Every field is
1296
+ * optional: a page's own props always win over the theme, and a header
1297
+ * outside any shell falls back to the component defaults it always had.
1298
+ */
1299
+ type ChromePosition = "flush" | "floating";
1300
+ type ThemePageHeaderVariant = "default" | "colourful" | "minimal" | "tabs-integrated";
1301
+ type ThemePageHeaderBehavior = "static" | "snapping";
1302
+ type ThemePageHeaderIntensity = "subtle" | "bold";
1303
+ type ThemeBreadcrumbPosition = "inline" | "contained";
1304
+ type ThemeBreadcrumbStyle = "default" | "pill";
1305
+ type ThemeBreadcrumbSeparator = "chevron" | "slash" | "dot" | "arrow";
1306
+ type ThemeSettingsLayout = "sidebar" | "tabs";
1307
+ interface AppShellTheme {
1308
+ /** Where the navbar sits; a floating navbar's gutter is the gap above a floating header. Confirmed by the rendered Navbar. */
1309
+ navbarPosition?: ChromePosition;
1310
+ /** Where the sidebar sits; a floating sidebar's gutter is the gap beside a floating header. Confirmed by the rendered Sidebar. */
1311
+ sidebarPosition?: ChromePosition;
1312
+ pageHeader?: {
1313
+ variant?: ThemePageHeaderVariant;
1314
+ behavior?: ThemePageHeaderBehavior;
1315
+ position?: ChromePosition;
1316
+ /** Colourful only. */
1317
+ intensity?: ThemePageHeaderIntensity;
1318
+ /** Colourful on the home page only; other pages take `otherPagesVariant`. The shell decides which page is home. */
1319
+ colourfulHomeOnly?: boolean;
1320
+ otherPagesVariant?: "default" | "minimal";
1321
+ };
1322
+ breadcrumbs?: {
1323
+ /** Inline in the header, or a contained strip the container renders above it. */
1324
+ position?: ThemeBreadcrumbPosition;
1325
+ style?: ThemeBreadcrumbStyle;
1326
+ separator?: ThemeBreadcrumbSeparator;
1327
+ };
1328
+ /** The customer's settings.layout preference: a rail of sections beside the panel, or horizontal tabs above it. SettingsLayout reads it. */
1329
+ settingsLayout?: ThemeSettingsLayout;
1330
+ }
1331
+
1332
+ interface SettingsSection {
1333
+ id: string;
1334
+ label: string;
1335
+ icon?: IconName;
1336
+ /** Heading above this section in the rail; the option group in the collapsed Dropdown. */
1337
+ group?: string;
1338
+ disabled?: boolean;
1339
+ }
1340
+ interface SettingsLayoutProps {
1341
+ sections: SettingsSection[];
1342
+ /** The selected section id. */
1343
+ value: string;
1344
+ onChange: (id: string) => void;
1345
+ /**
1346
+ * 'sidebar': a rail of sections beside the panel; 'tabs': horizontal tabs above it.
1347
+ * Default: the shell theme's settings.layout preference, else 'sidebar'. A page passes nothing.
1348
+ */
1349
+ layout?: ThemeSettingsLayout;
1350
+ /** Width of the rail in px (sidebar layout). */
1351
+ railWidth?: number;
1352
+ /**
1353
+ * Below this width of the layout itself (not the viewport) the rail becomes a Dropdown. Default: the rail plus a
1354
+ * usable panel (railWidth + 480). Measured on the layout, so a narrow PageContainer or a sidebar shell counts.
1355
+ */
1356
+ collapseBelow?: number;
1357
+ /** Accessible name of the section navigation. */
1358
+ "aria-label"?: string;
1359
+ /** The panel: the selected section's content. */
1360
+ children: ReactNode;
1361
+ className?: string;
1362
+ }
1363
+ /**
1364
+ * The settings page composition (Sprint 25.2, R8): a rail of sections beside
1365
+ * the panel, sticky while the page scrolls, or horizontal tabs above it — the
1366
+ * customer's settings.layout preference decides which, the component decides
1367
+ * the breakpoints. The collapse is measured on the layout's own width (a narrow
1368
+ * PageContainer, a sidebar shell): when the rail would leave too little for the
1369
+ * panel it becomes a Dropdown above the panel; a vertical rail never sits above
1370
+ * the content (settings#10).
1371
+ *
1372
+ * The rail is a Tabs (vertical) styled by the theme's in-page vertical style;
1373
+ * the page assembles the sections' contents and nothing else.
1374
+ */
1375
+ declare function SettingsLayout({ sections, value, onChange, layout: layoutProp, railWidth, collapseBelow, "aria-label": ariaLabel, children, className, }: SettingsLayoutProps): react_jsx_runtime.JSX.Element;
1376
+
1377
+ interface SplitViewProps {
1378
+ /** The list (an inbox, a queue): it scrolls on its own. */
1379
+ list: ReactNode;
1380
+ /** The selected item (a thread, a record): it fills the height and scrolls on its own. */
1381
+ detail: ReactNode;
1382
+ /** Context beside the detail (a contact, properties). Collapses to a toggle that opens it in a Drawer when the layout is narrower than `asideCollapseBelow`. */
1383
+ aside?: ReactNode;
1384
+ /** Names the aside's toggle and Drawer. */
1385
+ asideTitle?: string;
1386
+ /**
1387
+ * Below `collapseBelow` the list shows alone; with `detailOpen` the detail replaces it, with a Back button that calls
1388
+ * `onDetailClose` (detailMode "stack"). The page owns the selection, so it owns this flag.
1389
+ */
1390
+ detailOpen?: boolean;
1391
+ onDetailClose?: () => void;
1392
+ /** "stack" (default): the detail stacks over the list below the collapse width. "route": the app navigates to the detail's own route instead, and this renders the list alone there. */
1393
+ detailMode?: "stack" | "route";
1394
+ backLabel?: string;
1395
+ /** Percent of the width the list takes; the divider is draggable. */
1396
+ listWidth?: number;
1397
+ listMinWidth?: number;
1398
+ asideWidth?: number;
1399
+ /** Below this width of the layout itself (px) the list and detail stop sitting side by side. */
1400
+ collapseBelow?: number;
1401
+ /** Below this width of the layout itself (px) the aside becomes a toggle. */
1402
+ asideCollapseBelow?: number;
1403
+ /** A bordered, rounded surface (inside a page with padding) instead of edge to edge (filling <main>). */
1404
+ bordered?: boolean;
1405
+ "aria-label"?: string;
1406
+ className?: string;
1407
+ }
1408
+ /**
1409
+ * The reading-pane composition (Sprint 25.2, R3): one surface with dividers —
1410
+ * list, detail and an optional aside — that fills the height it is given (an
1411
+ * AppShell's <main> already gives it) and never three cards with gaps. The
1412
+ * panels compose ResizablePanelGroup, so the dividers drag. Below the collapse
1413
+ * width, measured on the layout itself, the list shows alone and the detail
1414
+ * stacks over it (or the app routes to it); the aside collapses to a toggle.
1415
+ * The page owns the selection and assembles the contents; keyboard movement
1416
+ * through the list is the list's job (StackedList selectedId).
1417
+ */
1418
+ declare function SplitView({ list, detail, aside, asideTitle, detailOpen, onDetailClose, detailMode, backLabel, listWidth, listMinWidth, asideWidth, collapseBelow, asideCollapseBelow, bordered, "aria-label": ariaLabel, className, }: SplitViewProps): react_jsx_runtime.JSX.Element;
1419
+
1256
1420
  interface BreadcrumbItem$1 {
1257
1421
  label: string;
1258
1422
  href?: string;
@@ -1408,8 +1572,13 @@ interface SegmentedControlProps {
1408
1572
  className?: string;
1409
1573
  /** Accessible name for the radiogroup, for when there is no visible label (e.g. in a toolbar). */
1410
1574
  "aria-label"?: string;
1575
+ /**
1576
+ * Above this many options the control renders a Dropdown with the same value, onChange and options — a row of
1577
+ * eleven segments runs off the page (bench round 3). Default 6; raise it only where the row is known to fit.
1578
+ */
1579
+ maxOptions?: number;
1411
1580
  }
1412
- declare function SegmentedControl({ value, onChange, options, size, variant, fullWidth, onHoverChange, className, "aria-label": ariaLabel, }: SegmentedControlProps): react_jsx_runtime.JSX.Element;
1581
+ declare function SegmentedControl({ value, onChange, options, size, variant, fullWidth, onHoverChange, className, "aria-label": ariaLabel, maxOptions, }: SegmentedControlProps): react_jsx_runtime.JSX.Element;
1413
1582
 
1414
1583
  interface BottomNavItem {
1415
1584
  label: string;
@@ -1454,7 +1623,7 @@ interface PageHeaderProps {
1454
1623
  intensity?: PageHeaderIntensity;
1455
1624
  /** Colourful: background image URL — overlaid with accent colour */
1456
1625
  backgroundImage?: string;
1457
- /** Colourful: extra bottom padding (px) for content overlap. Content below should use -mt-[value] to pull up. */
1626
+ /** Colourful: extra bottom padding (px) for content overlap. PageContainer pulls the content up by the same amount; the page adds no negative margin. */
1458
1627
  overlapHeight?: number;
1459
1628
  /** Snapping: content shown only when expanded */
1460
1629
  expandedContent?: ReactNode;
@@ -1593,6 +1762,10 @@ interface DialogProps {
1593
1762
  description?: string;
1594
1763
  children?: ReactNode;
1595
1764
  footer?: ReactNode;
1765
+ /** The content has unsaved changes: Escape, the backdrop and the close control ask before discarding, inside the dialog (Sprint 25.2, C1). */
1766
+ dirty?: boolean;
1767
+ /** Called when the user chooses to discard, before onClose. */
1768
+ onDiscard?: () => void;
1596
1769
  variant?: "default" | "destructive";
1597
1770
  size?: DialogSize;
1598
1771
  alert?: boolean;
@@ -1608,7 +1781,7 @@ interface DialogProps {
1608
1781
  */
1609
1782
  onSubmit?: () => void;
1610
1783
  }
1611
- declare function Dialog({ open, onClose, title, description, children, footer, variant, size, alert, container, onSubmit }: DialogProps): react.ReactPortal | null;
1784
+ declare function Dialog({ open, onClose: onCloseProp, title, description, children, footer, variant, size, alert, container, onSubmit, dirty, onDiscard }: DialogProps): react.ReactPortal | null;
1612
1785
 
1613
1786
  interface DrawerProps {
1614
1787
  open: boolean;
@@ -1658,6 +1831,10 @@ interface DrawerProps {
1658
1831
  */
1659
1832
  resizable?: boolean;
1660
1833
  maxWidth?: string;
1834
+ /** The content has unsaved changes: every close path asks before discarding, inside the drawer (Sprint 25.2, C1). */
1835
+ dirty?: boolean;
1836
+ /** Called when the user chooses to discard, before onClose. */
1837
+ onDiscard?: () => void;
1661
1838
  }
1662
1839
  declare function Drawer(props: DrawerProps): react_jsx_runtime.JSX.Element;
1663
1840
 
@@ -1746,6 +1923,8 @@ interface SheetProps {
1746
1923
  title?: ReactNode;
1747
1924
  children: ReactNode;
1748
1925
  footer?: ReactNode;
1926
+ /** A strip between the content and the footer (the Drawer's unsaved-changes question). */
1927
+ confirm?: ReactNode;
1749
1928
  /** Heights the sheet snaps to, as fractions of the viewport (or container). Default [0.5, 0.92]. */
1750
1929
  snapPoints?: number[];
1751
1930
  /** Render inside this element (absolute positioning, no body scroll lock) instead of document.body. */
@@ -1759,7 +1938,7 @@ interface SheetProps {
1759
1938
  /** id of the element that names the dialog when no title is rendered. */
1760
1939
  labelledBy?: string;
1761
1940
  }
1762
- declare function Sheet({ open, onClose, title, children, footer, snapPoints, container, flush, keepMounted, id, labelledBy }: SheetProps): react.ReactPortal | null;
1941
+ declare function Sheet({ open, onClose, title, children, footer, confirm, snapPoints, container, flush, keepMounted, id, labelledBy }: SheetProps): react.ReactPortal | null;
1763
1942
 
1764
1943
  interface Notification {
1765
1944
  id: string;
@@ -1943,46 +2122,6 @@ interface ScrollAreaProps {
1943
2122
  }
1944
2123
  declare function ScrollArea({ children, className, orientation, maxHeight, maxWidth, }: ScrollAreaProps): react_jsx_runtime.JSX.Element;
1945
2124
 
1946
- /**
1947
- * The theme's shell-level decisions, carried once by AppShell so that
1948
- * PageHeader and PageContainer can render a page the way the builder preview
1949
- * renders it without the page passing a single flag (Sprint 25, 14 Sep 2026).
1950
- *
1951
- * The generated shell passes the object the template emits; the builder
1952
- * preview passes the same values from the theme state. Every field is
1953
- * optional: a page's own props always win over the theme, and a header
1954
- * outside any shell falls back to the component defaults it always had.
1955
- */
1956
- type ChromePosition = "flush" | "floating";
1957
- type ThemePageHeaderVariant = "default" | "colourful" | "minimal" | "tabs-integrated";
1958
- type ThemePageHeaderBehavior = "static" | "snapping";
1959
- type ThemePageHeaderIntensity = "subtle" | "bold";
1960
- type ThemeBreadcrumbPosition = "inline" | "contained";
1961
- type ThemeBreadcrumbStyle = "default" | "pill";
1962
- type ThemeBreadcrumbSeparator = "chevron" | "slash" | "dot" | "arrow";
1963
- interface AppShellTheme {
1964
- /** Where the navbar sits; a floating navbar's gutter is the gap above a floating header. Confirmed by the rendered Navbar. */
1965
- navbarPosition?: ChromePosition;
1966
- /** Where the sidebar sits; a floating sidebar's gutter is the gap beside a floating header. Confirmed by the rendered Sidebar. */
1967
- sidebarPosition?: ChromePosition;
1968
- pageHeader?: {
1969
- variant?: ThemePageHeaderVariant;
1970
- behavior?: ThemePageHeaderBehavior;
1971
- position?: ChromePosition;
1972
- /** Colourful only. */
1973
- intensity?: ThemePageHeaderIntensity;
1974
- /** Colourful on the home page only; other pages take `otherPagesVariant`. The shell decides which page is home. */
1975
- colourfulHomeOnly?: boolean;
1976
- otherPagesVariant?: "default" | "minimal";
1977
- };
1978
- breadcrumbs?: {
1979
- /** Inline in the header, or a contained strip the container renders above it. */
1980
- position?: ThemeBreadcrumbPosition;
1981
- style?: ThemeBreadcrumbStyle;
1982
- separator?: ThemeBreadcrumbSeparator;
1983
- };
1984
- }
1985
-
1986
2125
  interface AppShellContextValue {
1987
2126
  hasSidebar: boolean;
1988
2127
  hasMobileMenu: boolean;
@@ -2179,4 +2318,4 @@ interface UseTextOverflowResult {
2179
2318
  */
2180
2319
  declare function useTextOverflow(options?: UseTextOverflowOptions): UseTextOverflowResult;
2181
2320
 
2182
- export { Accordion, ActionPanel, ActionPanelGroup, Alert, type AlertPlacement, AppShell, type AppShellContextValue, type AppShellTheme, AsidePanel, type AsidePanelProps, type AsidePanelSide, Avatar, AvatarGroup, type AvatarGroupItem, type AvatarGroupProps, type AvatarStatus, Badge, type BadgePaletteColor, type BadgeSize, type BadgeVariant, BottomNav, type BottomNavItem, type BreadcrumbItem$1 as BreadcrumbItem, Breadcrumbs, type BreadcrumbsSeparator, type BreadcrumbsSize, type BreadcrumbsVariant, BreakpointKey, BulkActionBar, Button, ButtonSizeContext, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, type CardSelectType, CardTitle, type CardVariant, Carousel, type ChatMessage, type ChatMessageAction, type ChatMessageLayout, ChatMessageList, type ChatMessageSender, type ChatMessageSource, type ChatMessageStatus, ChatPanel, type ChatPanelProps, type ChatPanelStatusTone, Checkbox, CheckboxGroup, CheckboxGroupItem, CodeBlock, Collapsible, ColorPicker, type Column, Combobox, CommandPalette, ContextMenu, CornerPanel, type CornerPanelEdge, type CornerPanelProps, DEFAULT_DATE_RANGE_PRESETS, DataList, DatePicker, type DateRange, DateRangePicker, type DateRangePickerProps, type DateRangePreset, type DescriptionItem, DescriptionList, type DescriptionListOrientation, type DescriptionListSize, Dialog, Divider, Dock, Drawer, Dropdown, DropdownMenu, type DropdownMenuDivider, type DropdownMenuEntry, type DropdownMenuItem, EmptyState, Field, type FieldControlProps, type FieldProps, FileUpload, FormWrapper, HoverCard, InlineFieldError, Input, Kbd, Label, Launcher, type LauncherEdge, type LauncherProps, type LauncherVariant, type LauncherWhenOpen, Link, type LinkProps, MentionInput, MobileHeaderMenu, type MobileHeaderMenuItemData, type MobileHeaderMenuType, NavItem, type NavItemProps, type NavItemType, NavMenu, type NavMenuItem, Navbar, type NavbarSize, type NavbarType, type NavbarVariant, NotificationCenter, NumberInput, PageContainer, type PageContainerWidth, PageHeader, type PageHeaderBehavior, type PageHeaderIntensity, type PageHeaderProps, type PageHeaderVariant, Pagination, PinInput, Popover, Progress, type PromiseToastMessages, RadioGroup, Rating, ScrollArea, SectionHeading, SegmentedControl, Sheet, Sidebar, type SidebarContextValue, type SidebarItem, SidebarNav, type SidebarNavSize, type SidebarPosition, type SidebarSection, type SidebarType, Skeleton, SkipLink, SliderRange, Spinner, StackedList, StatsCard, StatusDot, type StatusDotVariant, Stepper, type Tab, Table, type TableDensity, type TableProps, TableToolbar, type TableToolbarActiveFilter, type TableToolbarFilterOption, Tabs, Tag, TagInput, type TagPaletteColor, type TagVariant, TextOverflow, type TextOverflowProps, Textarea, TimePicker, Timeline, Toast, type ToastAction, type ToastApi, type ToastOptions, type ToastPosition, ToastProvider, type ToastVariant, Toggle, Tooltip, Tour, TransferList, TreeView, type UseTextOverflowOptions, type UseTextOverflowResult, useAppShell, useFormContext, useSidebar, useTextOverflow, useToast };
2321
+ export { Accordion, ActionPanel, ActionPanelGroup, Alert, type AlertPlacement, AppShell, type AppShellContextValue, type AppShellTheme, AsidePanel, type AsidePanelProps, type AsidePanelSide, Avatar, AvatarGroup, type AvatarGroupItem, type AvatarGroupProps, type AvatarStatus, Badge, type BadgePaletteColor, type BadgeSize, type BadgeVariant, BottomNav, type BottomNavItem, type BreadcrumbItem$1 as BreadcrumbItem, Breadcrumbs, type BreadcrumbsSeparator, type BreadcrumbsSize, type BreadcrumbsVariant, BreakpointKey, BulkActionBar, Button, ButtonSizeContext, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, type CardSelectType, CardTitle, type CardVariant, Carousel, type ChatMessage, type ChatMessageAction, type ChatMessageLayout, ChatMessageList, type ChatMessageSender, type ChatMessageSource, type ChatMessageStatus, ChatPanel, type ChatPanelProps, type ChatPanelStatusTone, Checkbox, CheckboxGroup, CheckboxGroupItem, CodeBlock, Collapsible, ColorPicker, type Column, Combobox, CommandPalette, ContextMenu, CornerPanel, type CornerPanelEdge, type CornerPanelProps, DEFAULT_DATE_RANGE_PRESETS, DataList, DatePicker, type DateRange, DateRangePicker, type DateRangePickerProps, type DateRangePreset, type DescriptionItem, DescriptionList, type DescriptionListOrientation, type DescriptionListSize, Dialog, Divider, Dock, Drawer, Dropdown, DropdownMenu, type DropdownMenuDivider, type DropdownMenuEntry, type DropdownMenuItem, EmptyState, Field, type FieldControlProps, type FieldProps, FileUpload, FormWrapper, HoverCard, InlineFieldError, Input, Kbd, Label, Launcher, type LauncherEdge, type LauncherProps, type LauncherVariant, type LauncherWhenOpen, Link, type LinkProps, MentionInput, MobileHeaderMenu, type MobileHeaderMenuItemData, type MobileHeaderMenuType, NavItem, type NavItemProps, type NavItemType, NavMenu, type NavMenuItem, Navbar, type NavbarSize, type NavbarType, type NavbarVariant, NotificationCenter, NumberInput, PageContainer, type PageContainerWidth, PageHeader, type PageHeaderBehavior, type PageHeaderIntensity, type PageHeaderProps, type PageHeaderVariant, Pagination, PinInput, Popover, Progress, type PromiseToastMessages, RadioGroup, Rating, ScrollArea, SectionHeading, SegmentedControl, SettingsLayout, type SettingsLayoutProps, type SettingsSection, Sheet, Sidebar, type SidebarContextValue, type SidebarItem, SidebarNav, type SidebarNavSize, type SidebarPosition, type SidebarSection, type SidebarType, Skeleton, SkipLink, SliderRange, Spinner, SplitView, type SplitViewProps, StackedList, StatsCard, StatusDot, type StatusDotVariant, Stepper, type Tab, Table, type TableDensity, type TableProps, TableToolbar, type TableToolbarActiveFilter, type TableToolbarFilterOption, Tabs, Tag, TagInput, type TagPaletteColor, type TagVariant, TextOverflow, type TextOverflowProps, Textarea, TimePicker, Timeline, Toast, type ToastAction, type ToastApi, type ToastOptions, type ToastPosition, ToastProvider, type ToastVariant, Toggle, Tooltip, Tour, TransferList, TreeView, type Trend, type UseTextOverflowOptions, type UseTextOverflowResult, useAppShell, useFormContext, useSidebar, useTextOverflow, useToast };