gridsmith-ui 0.7.0 → 0.9.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/dist/chat.js CHANGED
@@ -1,5 +1,5 @@
1
- import { Divider, CodeBlock, Link } from './chunk-G6KC5YNY.js';
2
- import './chunk-QVNGQ64Q.js';
1
+ import { Divider, CodeBlock, Link } from './chunk-X27PSHOH.js';
2
+ import './chunk-PHQWHAT3.js';
3
3
  import './chunk-RLNIRPOH.js';
4
4
  import './chunk-WH2FUFAC.js';
5
5
  import './chunk-X4CNZFWC.js';
@@ -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"]}
@@ -0,0 +1,38 @@
1
+ // ../../showcase/src/lib/table-utils.ts
2
+ var DATE_ISO = /^\d{4}-\d{2}-\d{2}$/;
3
+ var DATE_US = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
4
+ var DATE_TEXT_MDY = /^[A-Z][a-z]{2}\s+\d{1,2},?\s+\d{4}$/;
5
+ var DATE_TEXT_DMY = /^\d{1,2}\s+[A-Z][a-z]{2}\s+\d{4}$/;
6
+ var NUMBER_RE = /^[$€£¥]?\s?[\d,]+\.?\d*%?$/;
7
+ var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
8
+ function isDate(v) {
9
+ return DATE_ISO.test(v) || DATE_US.test(v) || DATE_TEXT_MDY.test(v) || DATE_TEXT_DMY.test(v);
10
+ }
11
+ function isJsx(v) {
12
+ return typeof v === "object" && v !== null;
13
+ }
14
+ function detectKind(values) {
15
+ const present = values.filter((v) => v != null);
16
+ if (present.length === 0) return void 0;
17
+ if (present.some(isJsx)) return void 0;
18
+ if (present.every((v) => typeof v === "string" && isDate(v))) return "date";
19
+ if (present.every((v) => typeof v === "number")) return "number";
20
+ if (present.every((v) => typeof v === "string" && NUMBER_RE.test(v))) return "number";
21
+ if (present.every((v) => typeof v === "string" && EMAIL_RE.test(v))) return "email";
22
+ if (present.every((v) => typeof v === "string" && v.length <= 20 && !/[\n\r]/.test(v))) return "label";
23
+ return "text";
24
+ }
25
+ function inferColumnKinds(data, columnKeys, maxSample = 50) {
26
+ const sample = data.length > maxSample ? data.slice(0, maxSample) : data;
27
+ const result = /* @__PURE__ */ new Map();
28
+ for (const key of columnKeys) {
29
+ const values = sample.map((row) => row[key]);
30
+ const kind = detectKind(values);
31
+ if (kind) result.set(key, kind);
32
+ }
33
+ return result;
34
+ }
35
+
36
+ export { inferColumnKinds };
37
+ //# sourceMappingURL=chunk-PDZL4A6K.js.map
38
+ //# sourceMappingURL=chunk-PDZL4A6K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../showcase/src/lib/table-utils.ts"],"names":[],"mappings":";AAIA,IAAM,QAAA,GAAW,qBAAA;AACjB,IAAM,OAAA,GAAU,2BAAA;AAChB,IAAM,aAAA,GAAgB,qCAAA;AACtB,IAAM,aAAA,GAAgB,mCAAA;AACtB,IAAM,SAAA,GAAY,4BAAA;AAClB,IAAM,QAAA,GAAW,4BAAA;AAEjB,SAAS,OAAO,CAAA,EAAoB;AAClC,EAAA,OAAO,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,IAAK,QAAQ,IAAA,CAAK,CAAC,CAAA,IAAK,aAAA,CAAc,IAAA,CAAK,CAAC,CAAA,IAAK,aAAA,CAAc,KAAK,CAAC,CAAA;AAC7F;AAEA,SAAS,MAAM,CAAA,EAAqB;AAClC,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,IAAY,CAAA,KAAM,IAAA;AACxC;AAEA,SAAS,WAAW,MAAA,EAA2C;AAE7D,EAAA,MAAM,UAAU,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,KAAM,KAAK,IAAI,CAAA;AAC9C,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAGjC,EAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG,OAAO,MAAA;AAGhC,EAAA,IAAI,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,KAAM,OAAO,CAAA,KAAM,QAAA,IAAY,MAAA,CAAO,CAAC,CAAC,CAAA,EAAG,OAAO,MAAA;AAGrE,EAAA,IAAI,OAAA,CAAQ,MAAM,CAAC,CAAA,KAAM,OAAO,CAAA,KAAM,QAAQ,GAAG,OAAO,QAAA;AACxD,EAAA,IAAI,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,KAAM,OAAO,CAAA,KAAM,QAAA,IAAY,SAAA,CAAU,IAAA,CAAK,CAAC,CAAC,CAAA,EAAG,OAAO,QAAA;AAG7E,EAAA,IAAI,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,KAAM,OAAO,CAAA,KAAM,QAAA,IAAY,QAAA,CAAS,IAAA,CAAK,CAAC,CAAC,CAAA,EAAG,OAAO,OAAA;AAG5E,EAAA,IAAI,QAAQ,KAAA,CAAM,CAAC,CAAA,KAAM,OAAO,MAAM,QAAA,IAAY,CAAA,CAAE,MAAA,IAAU,EAAA,IAAM,CAAC,QAAA,CAAS,IAAA,CAAK,CAAC,CAAC,GAAG,OAAO,OAAA;AAG/F,EAAA,OAAO,MAAA;AACT;AAOO,SAAS,gBAAA,CACd,IAAA,EACA,UAAA,EACA,SAAA,GAAY,EAAA,EACa;AACzB,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,GAAS,SAAA,GAAY,KAAK,KAAA,CAAM,CAAA,EAAG,SAAS,CAAA,GAAI,IAAA;AACpE,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAwB;AAE3C,EAAA,KAAA,MAAW,OAAO,UAAA,EAAY;AAC5B,IAAA,MAAM,SAAS,MAAA,CAAO,GAAA,CAAI,CAAC,GAAA,KAAQ,GAAA,CAAI,GAAG,CAAC,CAAA;AAC3C,IAAA,MAAM,IAAA,GAAO,WAAW,MAAM,CAAA;AAC9B,IAAA,IAAI,IAAA,EAAM,MAAA,CAAO,GAAA,CAAI,GAAA,EAAK,IAAI,CAAA;AAAA,EAChC;AAEA,EAAA,OAAO,MAAA;AACT","file":"chunk-PDZL4A6K.js","sourcesContent":["/** Shared column-kind inference for Table and DataGrid. */\n\nexport type ColumnKind = \"date\" | \"number\" | \"email\" | \"label\" | \"text\";\n\nconst DATE_ISO = /^\\d{4}-\\d{2}-\\d{2}$/;\nconst DATE_US = /^\\d{1,2}\\/\\d{1,2}\\/\\d{4}$/;\nconst DATE_TEXT_MDY = /^[A-Z][a-z]{2}\\s+\\d{1,2},?\\s+\\d{4}$/; // \"Jan 12, 2024\" or \"Jan 12 2024\"\nconst DATE_TEXT_DMY = /^\\d{1,2}\\s+[A-Z][a-z]{2}\\s+\\d{4}$/; // \"12 Jan 2024\"\nconst NUMBER_RE = /^[$€£¥]?\\s?[\\d,]+\\.?\\d*%?$/;\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\nfunction isDate(v: string): boolean {\n return DATE_ISO.test(v) || DATE_US.test(v) || DATE_TEXT_MDY.test(v) || DATE_TEXT_DMY.test(v);\n}\n\nfunction isJsx(v: unknown): boolean {\n return typeof v === \"object\" && v !== null;\n}\n\nfunction detectKind(values: unknown[]): ColumnKind | undefined {\n // Filter out null/undefined\n const present = values.filter((v) => v != null);\n if (present.length === 0) return undefined;\n\n // Any JSX value means no kind\n if (present.some(isJsx)) return undefined;\n\n // Check date (strings only)\n if (present.every((v) => typeof v === \"string\" && isDate(v))) return \"date\";\n\n // Check number: all typeof number, or all strings matching the number pattern\n if (present.every((v) => typeof v === \"number\")) return \"number\";\n if (present.every((v) => typeof v === \"string\" && NUMBER_RE.test(v))) return \"number\";\n\n // Check email\n if (present.every((v) => typeof v === \"string\" && EMAIL_RE.test(v))) return \"email\";\n\n // Check label: strings <= 20 chars, no line breaks\n if (present.every((v) => typeof v === \"string\" && v.length <= 20 && !/[\\n\\r]/.test(v))) return \"label\";\n\n // Fallback\n return \"text\";\n}\n\n/**\n * Sample data rows and infer a ColumnKind for each key.\n * Returns a Map of key -> kind for columns that matched a pattern.\n * Columns with mixed types or JSX values get no entry.\n */\nexport function inferColumnKinds(\n data: Record<string, unknown>[],\n columnKeys: string[],\n maxSample = 50,\n): Map<string, ColumnKind> {\n const sample = data.length > maxSample ? data.slice(0, maxSample) : data;\n const result = new Map<string, ColumnKind>();\n\n for (const key of columnKeys) {\n const values = sample.map((row) => row[key]);\n const kind = detectKind(values);\n if (kind) result.set(key, kind);\n }\n\n return result;\n}\n"]}
@@ -3,6 +3,13 @@ import { Icon } from './chunk-X4CNZFWC.js';
3
3
  import { cn } from './chunk-4KVFH5KC.js';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
5
5
 
6
+ var severityToVariant = {
7
+ info: "neutral",
8
+ low: "success-soft",
9
+ medium: "warning-soft",
10
+ high: "error-soft",
11
+ critical: "error"
12
+ };
6
13
  var variantStyles = {
7
14
  default: "bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] text-[var(--ds-text-on-primary)]",
8
15
  neutral: "bg-[var(--ds-text-muted)]/[0.12] text-[var(--ds-text-secondary)]",
@@ -56,11 +63,12 @@ function getPaletteClasses(color, variant) {
56
63
  const styleFn = paletteByVariant[variant] ?? paletteByVariant.default;
57
64
  return styleFn(color);
58
65
  }
59
- function Badge({ variant = "default", size = "md", color, iconLeft, iconRight, maxWidth, className, children }) {
66
+ function Badge({ variant = "default", severity, size = "md", color, iconLeft, iconRight, maxWidth, className, children }) {
67
+ const resolvedVariant = severity ? severityToVariant[severity] : variant;
60
68
  const { ref: truncRef, isTruncated } = useTextOverflow({ lines: 1, disabled: !maxWidth });
61
69
  const iconSize = iconSizes[size];
62
70
  const isIconOnly = (iconLeft || iconRight) && !children;
63
- const colorClasses = color ? getPaletteClasses(color, variant) : variantStyles[variant];
71
+ const colorClasses = color ? getPaletteClasses(color, resolvedVariant) : variantStyles[resolvedVariant];
64
72
  const badge = /* @__PURE__ */ jsxs(
65
73
  "span",
66
74
  {
@@ -89,5 +97,5 @@ function Badge({ variant = "default", size = "md", color, iconLeft, iconRight, m
89
97
  }
90
98
 
91
99
  export { Badge };
92
- //# sourceMappingURL=chunk-QVNGQ64Q.js.map
93
- //# sourceMappingURL=chunk-QVNGQ64Q.js.map
100
+ //# sourceMappingURL=chunk-PHQWHAT3.js.map
101
+ //# sourceMappingURL=chunk-PHQWHAT3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../showcase/src/components/Badge.tsx"],"names":[],"mappings":"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","file":"chunk-PHQWHAT3.js","sourcesContent":["import { cn } from \"../lib/utils\";\nimport { Icon, type IconName } from \"../lib/icons\";\nimport { Tooltip } from \"./Tooltip\";\nimport { useTextOverflow } from \"../lib/use-text-overflow\";\nimport type { ReactNode } from \"react\";\n\nexport type BadgeVariant =\n | \"default\"\n | \"neutral\"\n | \"subtle\"\n | \"success\"\n | \"success-soft\"\n | \"warning\"\n | \"warning-soft\"\n | \"error\"\n | \"error-soft\"\n | \"outline\";\n\nexport type BadgeSize = \"xs\" | \"sm\" | \"md\";\nexport type BadgePaletteColor = 1 | 2 | 3 | 4 | 5;\nexport type BadgeSeverity = \"info\" | \"low\" | \"medium\" | \"high\" | \"critical\";\n\nconst severityToVariant: Record<BadgeSeverity, BadgeVariant> = {\n info: \"neutral\",\n low: \"success-soft\",\n medium: \"warning-soft\",\n high: \"error-soft\",\n critical: \"error\",\n};\n\nconst variantStyles: Record<BadgeVariant, string> = {\n default: \"bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] text-[var(--ds-text-on-primary)]\",\n neutral: \"bg-[var(--ds-text-muted)]/[0.12] text-[var(--ds-text-secondary)]\",\n subtle: \"bg-[var(--ds-bg-muted)] text-[var(--ds-text-secondary)]\",\n success: \"bg-[var(--ds-status-success)] text-[var(--ds-text-on-success)]\",\n \"success-soft\": \"bg-[var(--ds-status-success-bg)] text-[var(--ds-status-success)] border-[length:var(--ds-border-width)] border-[var(--ds-status-success)]/[0.2]\",\n warning: \"bg-[var(--ds-status-warning)] text-[var(--ds-text-on-warning)]\",\n \"warning-soft\": \"bg-[var(--ds-status-warning-bg)] text-[var(--ds-status-warning-text)] border-[length:var(--ds-border-width)] border-[var(--ds-status-warning)]/[0.2]\",\n error: \"bg-[var(--ds-status-error)] text-[var(--ds-text-on-error)]\",\n \"error-soft\": \"bg-[var(--ds-status-error-bg)] text-[var(--ds-status-error)] border-[length:var(--ds-border-width)] border-[var(--ds-status-error)]/[0.2]\",\n outline: \"bg-transparent text-[var(--ds-text-primary)] border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\",\n};\n\nconst sizeStyles: Record<BadgeSize, string> = {\n xs: \"px-ds-1.5 py-[1px] text-[length:10px] gap-[3px]\",\n sm: \"px-ds-2 py-ds-0.5 text-[length:var(--ds-font-size-xs)] gap-ds-1\",\n md: \"px-ds-2.5 py-ds-0.5 text-[length:var(--ds-font-size-xs)] gap-ds-1\",\n};\n\nconst iconSizes: Record<BadgeSize, number> = {\n xs: 10,\n sm: 12,\n md: 12,\n};\n\ntype PaletteStyleFn = (n: BadgePaletteColor) => string;\n\nconst paletteByVariant: Record<string, PaletteStyleFn> = {\n default: (n) => paletteDefault[n],\n neutral: (n) => paletteSubtle[n],\n subtle: (n) => paletteSubtle[n],\n outline: (n) => paletteOutline[n],\n};\n\nconst paletteDefault: Record<BadgePaletteColor, string> = {\n 1: \"bg-[var(--ds-palette-1-bold)] text-[var(--ds-palette-1-on-bold)]\",\n 2: \"bg-[var(--ds-palette-2-bold)] text-[var(--ds-palette-2-on-bold)]\",\n 3: \"bg-[var(--ds-palette-3-bold)] text-[var(--ds-palette-3-on-bold)]\",\n 4: \"bg-[var(--ds-palette-4-bold)] text-[var(--ds-palette-4-on-bold)]\",\n 5: \"bg-[var(--ds-palette-5-bold)] text-[var(--ds-palette-5-on-bold)]\",\n};\n\nconst paletteSubtle: Record<BadgePaletteColor, string> = {\n 1: \"bg-[var(--ds-palette-1-bg)] text-[var(--ds-palette-1-text)]\",\n 2: \"bg-[var(--ds-palette-2-bg)] text-[var(--ds-palette-2-text)]\",\n 3: \"bg-[var(--ds-palette-3-bg)] text-[var(--ds-palette-3-text)]\",\n 4: \"bg-[var(--ds-palette-4-bg)] text-[var(--ds-palette-4-text)]\",\n 5: \"bg-[var(--ds-palette-5-bg)] text-[var(--ds-palette-5-text)]\",\n};\n\nconst paletteOutline: Record<BadgePaletteColor, string> = {\n 1: \"bg-transparent text-[var(--ds-palette-1-bold)] border-[length:var(--ds-border-width)] border-[var(--ds-palette-1-bold)]\",\n 2: \"bg-transparent text-[var(--ds-palette-2-bold)] border-[length:var(--ds-border-width)] border-[var(--ds-palette-2-bold)]\",\n 3: \"bg-transparent text-[var(--ds-palette-3-bold)] border-[length:var(--ds-border-width)] border-[var(--ds-palette-3-bold)]\",\n 4: \"bg-transparent text-[var(--ds-palette-4-bold)] border-[length:var(--ds-border-width)] border-[var(--ds-palette-4-bold)]\",\n 5: \"bg-transparent text-[var(--ds-palette-5-bold)] border-[length:var(--ds-border-width)] border-[var(--ds-palette-5-bold)]\",\n};\n\nfunction getPaletteClasses(color: BadgePaletteColor, variant: BadgeVariant): string {\n const styleFn = paletteByVariant[variant] ?? paletteByVariant.default;\n return styleFn(color);\n}\n\ninterface BadgeProps {\n variant?: BadgeVariant;\n /** Severity shorthand — maps to a variant. When set, overrides `variant`. */\n severity?: BadgeSeverity;\n size?: BadgeSize;\n /** Palette colour (1-5). Overrides variant colour with decorative palette tokens. */\n color?: BadgePaletteColor;\n /** Icon to show before the label */\n iconLeft?: IconName;\n /** Icon to show after the label */\n iconRight?: IconName;\n /** Max width before truncation (e.g. \"120px\", \"16ch\"). Shows tooltip when truncated. */\n maxWidth?: string;\n className?: string;\n children?: ReactNode;\n}\n\nexport function Badge({ variant = \"default\", severity, size = \"md\", color, iconLeft, iconRight, maxWidth, className, children }: BadgeProps) {\n // severity sets the variant and variant is ignored when both are written\n const resolvedVariant = severity ? severityToVariant[severity] : variant;\n const { ref: truncRef, isTruncated } = useTextOverflow({ lines: 1, disabled: !maxWidth });\n const iconSize = iconSizes[size];\n const isIconOnly = (iconLeft || iconRight) && !children;\n\n const colorClasses = color\n ? getPaletteClasses(color, resolvedVariant)\n : variantStyles[resolvedVariant];\n\n const badge = (\n <span\n className={cn(\n \"inline-flex items-center font-medium max-w-full whitespace-nowrap\",\n \"rounded-[var(--ds-radius-full)]\",\n sizeStyles[size],\n isIconOnly && size === \"xs\" && \"px-[3px]\",\n isIconOnly && size === \"sm\" && \"px-ds-1\",\n isIconOnly && size === \"md\" && \"px-ds-1.5\",\n colorClasses,\n className\n )}\n style={maxWidth ? { maxWidth } : undefined}\n >\n {iconLeft && <Icon name={iconLeft} size={iconSize} className=\"shrink-0\" />}\n {maxWidth ? (\n <span ref={truncRef} className=\"truncate\">{children}</span>\n ) : (\n children\n )}\n {iconRight && <Icon name={iconRight} size={iconSize} className=\"shrink-0\" />}\n </span>\n );\n\n if (isTruncated) {\n return <Tooltip content={children}>{badge}</Tooltip>;\n }\n return badge;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { Badge } from './chunk-QVNGQ64Q.js';
1
+ import { Badge } from './chunk-PHQWHAT3.js';
2
2
  import { Icon } from './chunk-X4CNZFWC.js';
3
3
  import { cn } from './chunk-4KVFH5KC.js';
4
4
  import { forwardRef, useState, useCallback } from 'react';
@@ -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-X27PSHOH.js.map
161
+ //# sourceMappingURL=chunk-X27PSHOH.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":"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","file":"chunk-X27PSHOH.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"]}
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ColumnDef } from '@tanstack/react-table';
3
- import { B as BreakpointKey } from './use-breakpoint-BfKzmkxx.js';
3
+ import { B as BreakpointKey, C as ColumnKind } from './table-utils-GounRE6s.js';
4
4
  import 'react';
5
5
 
6
6
  /** Column meta for opt-in truncation. Set on ColumnDef.meta. */
@@ -11,6 +11,8 @@ interface DataGridColumnMeta {
11
11
  };
12
12
  /** CSS max-width for the column. */
13
13
  maxWidth?: string;
14
+ /** Explicit column kind. When omitted the DataGrid infers it from data values. */
15
+ kind?: ColumnKind;
14
16
  }
15
17
  interface DataGridProps<T> {
16
18
  data: T[];
package/dist/data-grid.js CHANGED
@@ -1,4 +1,5 @@
1
- import { useBreakpoint } from './chunk-EKQHHP72.js';
1
+ import { inferColumnKinds } from './chunk-PDZL4A6K.js';
2
+ import { useBreakpoint } from './chunk-CRQ6KCRD.js';
2
3
  import { useTextOverflow, Tooltip } from './chunk-RLNIRPOH.js';
3
4
  import './chunk-WH2FUFAC.js';
4
5
  import { Icon } from './chunk-X4CNZFWC.js';
@@ -27,6 +28,15 @@ function DataGrid({
27
28
  const [sorting, setSorting] = useState([]);
28
29
  const [editCell, setEditCell] = useState(null);
29
30
  const [editValue, setEditValue] = useState("");
31
+ const columnKeys = useMemo(() => columns.map((c) => c.id ?? ("accessorKey" in c ? String(c.accessorKey) : "")).filter(Boolean), [columns]);
32
+ const inferredKinds = useMemo(
33
+ () => inferColumnKinds(data, columnKeys),
34
+ [data, columnKeys]
35
+ );
36
+ const kindOf = useCallback(
37
+ (colId, meta) => meta?.kind ?? inferredKinds.get(colId),
38
+ [inferredKinds]
39
+ );
30
40
  const tableColumns = useMemo(() => {
31
41
  if (!editable) return columns;
32
42
  return columns.map((col) => ({
@@ -103,8 +113,8 @@ function DataGrid({
103
113
  "p-ds-4 space-y-ds-2"
104
114
  ),
105
115
  children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsxs("div", { className: "flex justify-between gap-ds-2 text-sm", children: [
106
- /* @__PURE__ */ jsx("span", { className: "text-[var(--ds-text-secondary)] font-medium text-xs uppercase tracking-wider", children: typeof cell.column.columnDef.header === "string" ? cell.column.columnDef.header : cell.column.id }),
107
- /* @__PURE__ */ jsx("span", { className: "text-[var(--ds-text-primary)] text-right", children: flexRender(cell.column.columnDef.cell, cell.getContext()) })
116
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[var(--ds-text-secondary)] font-medium text-xs uppercase tracking-wider", children: typeof cell.column.columnDef.header === "string" ? cell.column.columnDef.header : cell.column.id }),
117
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 text-[var(--ds-text-primary)] text-right [overflow-wrap:anywhere]", children: flexRender(cell.column.columnDef.cell, cell.getContext()) })
108
118
  ] }, cell.id))
109
119
  },
110
120
  row.id
@@ -138,17 +148,19 @@ function DataGrid({
138
148
  const canSort = header.column.getCanSort();
139
149
  const sorted = header.column.getIsSorted();
140
150
  const meta = header.column.columnDef.meta;
151
+ const headerKind = kindOf(header.column.id, meta);
141
152
  return /* @__PURE__ */ jsx(
142
153
  "th",
143
154
  {
144
155
  className: cn(
145
- "px-ds-4 py-ds-3 text-left text-xs font-[var(--ds-weight-heading)] uppercase tracking-wider",
156
+ "px-ds-4 py-ds-3 text-xs font-[var(--ds-weight-heading)] uppercase tracking-wider",
157
+ headerKind === "number" ? "text-right" : "text-left",
146
158
  "text-[var(--ds-text-secondary)]",
147
159
  canSort && "cursor-pointer select-none hover:text-[var(--ds-text-primary)]"
148
160
  ),
149
161
  style: meta?.maxWidth ? { maxWidth: meta.maxWidth } : void 0,
150
162
  onClick: canSort ? header.column.getToggleSortingHandler() : void 0,
151
- children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-ds-1", children: [
163
+ children: /* @__PURE__ */ jsxs("span", { className: cn("flex items-center gap-ds-1", headerKind === "number" && "justify-end"), children: [
152
164
  flexRender(header.column.columnDef.header, header.getContext()),
153
165
  canSort && /* @__PURE__ */ jsxs("span", { className: "inline-flex flex-col -space-y-ds-1.5", children: [
154
166
  /* @__PURE__ */ jsx(
@@ -183,13 +195,27 @@ function DataGrid({
183
195
  children: row.getVisibleCells().map((cell) => {
184
196
  const meta = cell.column.columnDef.meta;
185
197
  const truncLines = meta?.truncate === true ? 1 : meta?.truncate ? meta.truncate.lines : 0;
198
+ const kind = kindOf(cell.column.id, meta);
186
199
  const rendered = flexRender(cell.column.columnDef.cell, cell.getContext());
200
+ let inner;
201
+ if (truncLines > 0) {
202
+ inner = /* @__PURE__ */ jsx(TruncCell, { lines: truncLines, children: rendered });
203
+ } else if (kind === "email") {
204
+ inner = /* @__PURE__ */ jsx("span", { className: "max-w-[200px] truncate inline-block", title: typeof cell.getValue() === "string" ? cell.getValue() : void 0, children: rendered });
205
+ } else if (kind === "date" || kind === "number") {
206
+ inner = /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap", children: rendered });
207
+ } else {
208
+ inner = rendered;
209
+ }
187
210
  return /* @__PURE__ */ jsx(
188
211
  "td",
189
212
  {
190
- className: "px-ds-4 py-ds-3 text-[var(--ds-text-primary)]",
213
+ className: cn(
214
+ "px-ds-4 py-ds-3 text-[var(--ds-text-primary)]",
215
+ kind === "number" && "text-right"
216
+ ),
191
217
  style: meta?.maxWidth ? { maxWidth: meta.maxWidth } : void 0,
192
- children: truncLines > 0 ? /* @__PURE__ */ jsx(TruncCell, { lines: truncLines, children: rendered }) : rendered
218
+ children: inner
193
219
  },
194
220
  cell.id
195
221
  );
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../showcase/src/components/DataGrid.tsx"],"names":[],"mappings":"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","file":"data-grid.js","sourcesContent":["import { useState, useCallback, useMemo, type ReactNode } from \"react\";\nimport {\n useReactTable,\n getCoreRowModel,\n getSortedRowModel,\n getPaginationRowModel,\n flexRender,\n type CellContext,\n type ColumnDef,\n type SortingState,\n} from \"@tanstack/react-table\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"../lib/icons\";\nimport { Tooltip } from \"./Tooltip\";\nimport { useTextOverflow } from \"../lib/use-text-overflow\";\nimport { useBreakpoint, type BreakpointKey } from \"../lib/use-breakpoint\";\n\n/** Column meta for opt-in truncation. Set on ColumnDef.meta. */\nexport interface DataGridColumnMeta {\n /** true = single-line, or { lines: N } for multi-line clamp. */\n truncate?: boolean | { lines: number };\n /** CSS max-width for the column. */\n maxWidth?: string;\n}\n\nfunction TruncCell({ children, lines }: { children: ReactNode; lines: number }) {\n const { ref, isTruncated } = useTextOverflow({ lines });\n const clampClass = lines === 1 ? \"truncate\" : `line-clamp-${lines}`;\n const cell = <span ref={ref} className={cn(clampClass, \"block\")}>{children}</span>;\n if (!isTruncated) return cell;\n return <Tooltip content={children}>{cell}</Tooltip>;\n}\n\nexport interface DataGridProps<T> {\n data: T[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- public API: columns may carry any value type\n columns: ColumnDef<T, any>[];\n pageSize?: number;\n editable?: boolean;\n onCellEdit?: (rowIndex: number, columnId: string, value: unknown) => void;\n /** Breakpoint at which the grid switches to card layout. Defaults to \"md\" (768px). */\n mobileBreakpoint?: BreakpointKey;\n className?: string;\n}\n\nexport function DataGrid<T>({\n data,\n columns,\n pageSize = 10,\n editable = false,\n onCellEdit,\n mobileBreakpoint = \"md\",\n className,\n}: DataGridProps<T>) {\n const isMobile = useBreakpoint(mobileBreakpoint);\n const [sorting, setSorting] = useState<SortingState>([]);\n const [editCell, setEditCell] = useState<{ row: number; col: string } | null>(null);\n const [editValue, setEditValue] = useState(\"\");\n\n const tableColumns = useMemo(() => {\n if (!editable) return columns;\n return columns.map((col) => ({\n ...col,\n cell: (info: CellContext<T, unknown>) => {\n const rowIdx = info.row.index;\n const colId = info.column.id;\n const isEditing = editCell?.row === rowIdx && editCell?.col === colId;\n\n if (isEditing) {\n return (\n <input\n autoFocus\n className={cn(\n \"w-full h-full bg-transparent text-sm text-[var(--ds-text-primary)]\",\n \"outline-none border-none px-0\",\n )}\n value={editValue}\n onChange={(e) => setEditValue(e.target.value)}\n onBlur={() => {\n onCellEdit?.(rowIdx, colId, editValue);\n setEditCell(null);\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n onCellEdit?.(rowIdx, colId, editValue);\n setEditCell(null);\n } else if (e.key === \"Escape\") {\n setEditCell(null);\n }\n }}\n />\n );\n }\n\n const rendered = typeof col.cell === \"function\" ? col.cell(info) : info.getValue();\n return (\n <span\n onDoubleClick={() => {\n setEditCell({ row: rowIdx, col: colId });\n setEditValue(String(info.getValue() ?? \"\"));\n }}\n className=\"cursor-default\"\n >\n {rendered as React.ReactNode}\n </span>\n );\n },\n }));\n }, [columns, editable, editCell, editValue, onCellEdit]);\n\n // TanStack Table returns functions the React Compiler cannot memoise; the\n // compiler would skip this component, which is fine — the project does not\n // use it. The note is informational, not a defect.\n // eslint-disable-next-line react-hooks/incompatible-library -- TanStack Table is not compiler-compatible\n const table = useReactTable({\n data,\n columns: tableColumns,\n state: { sorting },\n onSortingChange: setSorting,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n initialState: { pagination: { pageSize } },\n });\n\n const handlePageChange = useCallback(\n (page: number) => table.setPageIndex(page),\n [table],\n );\n\n const pageCount = table.getPageCount();\n const currentPage = table.getState().pagination.pageIndex;\n\n if (isMobile) {\n return (\n <div className={cn(\"space-y-ds-3\", className)}>\n <div className=\"flex flex-col gap-ds-3\">\n {table.getRowModel().rows.map((row) => (\n <div\n key={row.id}\n className={cn(\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)]\",\n \"p-ds-4 space-y-ds-2\",\n )}\n >\n {row.getVisibleCells().map((cell) => (\n <div key={cell.id} className=\"flex justify-between gap-ds-2 text-sm\">\n <span className=\"text-[var(--ds-text-secondary)] font-medium text-xs uppercase tracking-wider\">\n {typeof cell.column.columnDef.header === \"string\"\n ? cell.column.columnDef.header\n : cell.column.id}\n </span>\n <span className=\"text-[var(--ds-text-primary)] text-right\">\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </span>\n </div>\n ))}\n </div>\n ))}\n </div>\n\n {pageCount > 1 && (\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-[var(--ds-text-muted)]\">\n Page {currentPage + 1} of {pageCount}\n </span>\n <div className=\"flex items-center gap-ds-1\">\n <PagerBtn onClick={() => handlePageChange(currentPage - 1)} disabled={currentPage === 0} label=\"Prev\" />\n <PagerBtn onClick={() => handlePageChange(currentPage + 1)} disabled={currentPage >= pageCount - 1} label=\"Next\" />\n </div>\n </div>\n )}\n </div>\n );\n }\n\n return (\n <div className={cn(\"space-y-ds-3\", className)}>\n <div\n className={cn(\n \"w-full overflow-auto rounded-[var(--ds-radius-md)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"shadow-[var(--ds-shadow-card)]\",\n \"bg-[var(--ds-bg-surface)]\",\n )}\n >\n <table className=\"w-full text-sm\">\n <thead className=\"bg-[var(--ds-bg-muted)]\">\n {table.getHeaderGroups().map((hg) => (\n <tr key={hg.id} className=\"border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]\">\n {hg.headers.map((header) => {\n const canSort = header.column.getCanSort();\n const sorted = header.column.getIsSorted();\n const meta = header.column.columnDef.meta as DataGridColumnMeta | undefined;\n return (\n <th\n key={header.id}\n className={cn(\n \"px-ds-4 py-ds-3 text-left text-xs font-[var(--ds-weight-heading)] uppercase tracking-wider\",\n \"text-[var(--ds-text-secondary)]\",\n canSort && \"cursor-pointer select-none hover:text-[var(--ds-text-primary)]\",\n )}\n style={meta?.maxWidth ? { maxWidth: meta.maxWidth } : undefined}\n onClick={canSort ? header.column.getToggleSortingHandler() : undefined}\n >\n <span className=\"flex items-center gap-ds-1\">\n {flexRender(header.column.columnDef.header, header.getContext())}\n {canSort && (\n <span className=\"inline-flex flex-col -space-y-ds-1.5\">\n <Icon\n name=\"chevron-up\"\n size={10}\n className={sorted === \"asc\" ? \"text-[var(--ds-accent-primary)]\" : \"opacity-30\"}\n />\n <Icon\n name=\"chevron-down\"\n size={10}\n className={sorted === \"desc\" ? \"text-[var(--ds-accent-primary)]\" : \"opacity-30\"}\n />\n </span>\n )}\n </span>\n </th>\n );\n })}\n </tr>\n ))}\n </thead>\n <tbody>\n {table.getRowModel().rows.map((row) => (\n <tr\n key={row.id}\n className={cn(\n \"border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] last:border-b-0\",\n \"hover:bg-[var(--ds-bg-muted)] transition-colors\",\n )}\n >\n {row.getVisibleCells().map((cell) => {\n const meta = cell.column.columnDef.meta as DataGridColumnMeta | undefined;\n const truncLines = meta?.truncate === true ? 1 : meta?.truncate ? meta.truncate.lines : 0;\n const rendered = flexRender(cell.column.columnDef.cell, cell.getContext());\n return (\n <td\n key={cell.id}\n className=\"px-ds-4 py-ds-3 text-[var(--ds-text-primary)]\"\n style={meta?.maxWidth ? { maxWidth: meta.maxWidth } : undefined}\n >\n {truncLines > 0 ? <TruncCell lines={truncLines}>{rendered}</TruncCell> : rendered}\n </td>\n );\n })}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n\n {pageCount > 1 && (\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-[var(--ds-text-muted)]\">\n Page {currentPage + 1} of {pageCount}\n </span>\n <div className=\"flex items-center gap-ds-1\">\n <PagerBtn\n onClick={() => handlePageChange(0)}\n disabled={currentPage === 0}\n label=\"First\"\n />\n <PagerBtn\n onClick={() => handlePageChange(currentPage - 1)}\n disabled={currentPage === 0}\n label=\"Prev\"\n />\n {Array.from({ length: Math.min(pageCount, 5) }, (_, i) => {\n let page: number;\n if (pageCount <= 5) {\n page = i;\n } else if (currentPage < 3) {\n page = i;\n } else if (currentPage > pageCount - 4) {\n page = pageCount - 5 + i;\n } else {\n page = currentPage - 2 + i;\n }\n return (\n <PagerBtn\n key={page}\n onClick={() => handlePageChange(page)}\n active={page === currentPage}\n label={String(page + 1)}\n />\n );\n })}\n <PagerBtn\n onClick={() => handlePageChange(currentPage + 1)}\n disabled={currentPage >= pageCount - 1}\n label=\"Next\"\n />\n <PagerBtn\n onClick={() => handlePageChange(pageCount - 1)}\n disabled={currentPage >= pageCount - 1}\n label=\"Last\"\n />\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction PagerBtn({\n onClick,\n disabled,\n active,\n label,\n}: {\n onClick: () => void;\n disabled?: boolean;\n active?: boolean;\n label: string;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n className={cn(\n \"h-8 min-w-[32px] px-ds-2 text-xs font-medium rounded-[var(--ds-radius-sm)]\",\n \"transition-colors duration-[var(--ds-transition-speed)] cursor-pointer\",\n \"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]\",\n \"disabled:opacity-disabled disabled:cursor-not-allowed\",\n active\n ? \"bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]\"\n : \"text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]\",\n )}\n >\n {label}\n </button>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../../showcase/src/components/DataGrid.tsx"],"names":[],"mappings":"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","file":"data-grid.js","sourcesContent":["import { useState, useCallback, useMemo, type ReactNode } from \"react\";\nimport {\n useReactTable,\n getCoreRowModel,\n getSortedRowModel,\n getPaginationRowModel,\n flexRender,\n type CellContext,\n type ColumnDef,\n type SortingState,\n} from \"@tanstack/react-table\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"../lib/icons\";\nimport { Tooltip } from \"./Tooltip\";\nimport { useTextOverflow } from \"../lib/use-text-overflow\";\nimport { useBreakpoint, type BreakpointKey } from \"../lib/use-breakpoint\";\nimport { inferColumnKinds, type ColumnKind } from \"../lib/table-utils\";\n\n/** Column meta for opt-in truncation. Set on ColumnDef.meta. */\nexport interface DataGridColumnMeta {\n /** true = single-line, or { lines: N } for multi-line clamp. */\n truncate?: boolean | { lines: number };\n /** CSS max-width for the column. */\n maxWidth?: string;\n /** Explicit column kind. When omitted the DataGrid infers it from data values. */\n kind?: ColumnKind;\n}\n\nfunction TruncCell({ children, lines }: { children: ReactNode; lines: number }) {\n const { ref, isTruncated } = useTextOverflow({ lines });\n const clampClass = lines === 1 ? \"truncate\" : `line-clamp-${lines}`;\n const cell = <span ref={ref} className={cn(clampClass, \"block\")}>{children}</span>;\n if (!isTruncated) return cell;\n return <Tooltip content={children}>{cell}</Tooltip>;\n}\n\nexport interface DataGridProps<T> {\n data: T[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- public API: columns may carry any value type\n columns: ColumnDef<T, any>[];\n pageSize?: number;\n editable?: boolean;\n onCellEdit?: (rowIndex: number, columnId: string, value: unknown) => void;\n /** Breakpoint at which the grid switches to card layout. Defaults to \"md\" (768px). */\n mobileBreakpoint?: BreakpointKey;\n className?: string;\n}\n\nexport function DataGrid<T>({\n data,\n columns,\n pageSize = 10,\n editable = false,\n onCellEdit,\n mobileBreakpoint = \"md\",\n className,\n}: DataGridProps<T>) {\n const isMobile = useBreakpoint(mobileBreakpoint);\n const [sorting, setSorting] = useState<SortingState>([]);\n const [editCell, setEditCell] = useState<{ row: number; col: string } | null>(null);\n const [editValue, setEditValue] = useState(\"\");\n\n /* ── Column kind inference ─────────────────────────────────────────── */\n const columnKeys = useMemo(() => columns.map((c) => c.id ?? (\"accessorKey\" in c ? String(c.accessorKey) : \"\")).filter(Boolean), [columns]);\n const inferredKinds = useMemo(\n () => inferColumnKinds(data as Record<string, unknown>[], columnKeys),\n [data, columnKeys],\n );\n const kindOf = useCallback(\n (colId: string, meta: DataGridColumnMeta | undefined) => meta?.kind ?? inferredKinds.get(colId),\n [inferredKinds],\n );\n\n const tableColumns = useMemo(() => {\n if (!editable) return columns;\n return columns.map((col) => ({\n ...col,\n cell: (info: CellContext<T, unknown>) => {\n const rowIdx = info.row.index;\n const colId = info.column.id;\n const isEditing = editCell?.row === rowIdx && editCell?.col === colId;\n\n if (isEditing) {\n return (\n <input\n autoFocus\n className={cn(\n \"w-full h-full bg-transparent text-sm text-[var(--ds-text-primary)]\",\n \"outline-none border-none px-0\",\n )}\n value={editValue}\n onChange={(e) => setEditValue(e.target.value)}\n onBlur={() => {\n onCellEdit?.(rowIdx, colId, editValue);\n setEditCell(null);\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n onCellEdit?.(rowIdx, colId, editValue);\n setEditCell(null);\n } else if (e.key === \"Escape\") {\n setEditCell(null);\n }\n }}\n />\n );\n }\n\n const rendered = typeof col.cell === \"function\" ? col.cell(info) : info.getValue();\n return (\n <span\n onDoubleClick={() => {\n setEditCell({ row: rowIdx, col: colId });\n setEditValue(String(info.getValue() ?? \"\"));\n }}\n className=\"cursor-default\"\n >\n {rendered as React.ReactNode}\n </span>\n );\n },\n }));\n }, [columns, editable, editCell, editValue, onCellEdit]);\n\n // TanStack Table returns functions the React Compiler cannot memoise; the\n // compiler would skip this component, which is fine — the project does not\n // use it. The note is informational, not a defect.\n // eslint-disable-next-line react-hooks/incompatible-library -- TanStack Table is not compiler-compatible\n const table = useReactTable({\n data,\n columns: tableColumns,\n state: { sorting },\n onSortingChange: setSorting,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n initialState: { pagination: { pageSize } },\n });\n\n const handlePageChange = useCallback(\n (page: number) => table.setPageIndex(page),\n [table],\n );\n\n const pageCount = table.getPageCount();\n const currentPage = table.getState().pagination.pageIndex;\n\n if (isMobile) {\n return (\n <div className={cn(\"space-y-ds-3\", className)}>\n <div className=\"flex flex-col gap-ds-3\">\n {table.getRowModel().rows.map((row) => (\n <div\n key={row.id}\n className={cn(\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)]\",\n \"p-ds-4 space-y-ds-2\",\n )}\n >\n {row.getVisibleCells().map((cell) => (\n <div key={cell.id} className=\"flex justify-between gap-ds-2 text-sm\">\n <span className=\"shrink-0 text-[var(--ds-text-secondary)] font-medium text-xs uppercase tracking-wider\">\n {typeof cell.column.columnDef.header === \"string\"\n ? cell.column.columnDef.header\n : cell.column.id}\n </span>\n <span className=\"min-w-0 text-[var(--ds-text-primary)] text-right [overflow-wrap:anywhere]\">\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </span>\n </div>\n ))}\n </div>\n ))}\n </div>\n\n {pageCount > 1 && (\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-[var(--ds-text-muted)]\">\n Page {currentPage + 1} of {pageCount}\n </span>\n <div className=\"flex items-center gap-ds-1\">\n <PagerBtn onClick={() => handlePageChange(currentPage - 1)} disabled={currentPage === 0} label=\"Prev\" />\n <PagerBtn onClick={() => handlePageChange(currentPage + 1)} disabled={currentPage >= pageCount - 1} label=\"Next\" />\n </div>\n </div>\n )}\n </div>\n );\n }\n\n return (\n <div className={cn(\"space-y-ds-3\", className)}>\n <div\n className={cn(\n \"w-full overflow-auto rounded-[var(--ds-radius-md)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"shadow-[var(--ds-shadow-card)]\",\n \"bg-[var(--ds-bg-surface)]\",\n )}\n >\n <table className=\"w-full text-sm\">\n <thead className=\"bg-[var(--ds-bg-muted)]\">\n {table.getHeaderGroups().map((hg) => (\n <tr key={hg.id} className=\"border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]\">\n {hg.headers.map((header) => {\n const canSort = header.column.getCanSort();\n const sorted = header.column.getIsSorted();\n const meta = header.column.columnDef.meta as DataGridColumnMeta | undefined;\n const headerKind = kindOf(header.column.id, meta);\n return (\n <th\n key={header.id}\n className={cn(\n \"px-ds-4 py-ds-3 text-xs font-[var(--ds-weight-heading)] uppercase tracking-wider\",\n headerKind === \"number\" ? \"text-right\" : \"text-left\",\n \"text-[var(--ds-text-secondary)]\",\n canSort && \"cursor-pointer select-none hover:text-[var(--ds-text-primary)]\",\n )}\n style={meta?.maxWidth ? { maxWidth: meta.maxWidth } : undefined}\n onClick={canSort ? header.column.getToggleSortingHandler() : undefined}\n >\n <span className={cn(\"flex items-center gap-ds-1\", headerKind === \"number\" && \"justify-end\")}>\n {flexRender(header.column.columnDef.header, header.getContext())}\n {canSort && (\n <span className=\"inline-flex flex-col -space-y-ds-1.5\">\n <Icon\n name=\"chevron-up\"\n size={10}\n className={sorted === \"asc\" ? \"text-[var(--ds-accent-primary)]\" : \"opacity-30\"}\n />\n <Icon\n name=\"chevron-down\"\n size={10}\n className={sorted === \"desc\" ? \"text-[var(--ds-accent-primary)]\" : \"opacity-30\"}\n />\n </span>\n )}\n </span>\n </th>\n );\n })}\n </tr>\n ))}\n </thead>\n <tbody>\n {table.getRowModel().rows.map((row) => (\n <tr\n key={row.id}\n className={cn(\n \"border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] last:border-b-0\",\n \"hover:bg-[var(--ds-bg-muted)] transition-colors\",\n )}\n >\n {row.getVisibleCells().map((cell) => {\n const meta = cell.column.columnDef.meta as DataGridColumnMeta | undefined;\n const truncLines = meta?.truncate === true ? 1 : meta?.truncate ? meta.truncate.lines : 0;\n const kind = kindOf(cell.column.id, meta);\n const rendered = flexRender(cell.column.columnDef.cell, cell.getContext());\n\n let inner: ReactNode;\n if (truncLines > 0) {\n inner = <TruncCell lines={truncLines}>{rendered}</TruncCell>;\n } else if (kind === \"email\") {\n inner = (\n <span className=\"max-w-[200px] truncate inline-block\" title={typeof cell.getValue() === \"string\" ? cell.getValue() as string : undefined}>\n {rendered}\n </span>\n );\n } else if (kind === \"date\" || kind === \"number\") {\n inner = <span className=\"whitespace-nowrap\">{rendered}</span>;\n } else {\n inner = rendered;\n }\n\n return (\n <td\n key={cell.id}\n className={cn(\n \"px-ds-4 py-ds-3 text-[var(--ds-text-primary)]\",\n kind === \"number\" && \"text-right\",\n )}\n style={meta?.maxWidth ? { maxWidth: meta.maxWidth } : undefined}\n >\n {inner}\n </td>\n );\n })}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n\n {pageCount > 1 && (\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-[var(--ds-text-muted)]\">\n Page {currentPage + 1} of {pageCount}\n </span>\n <div className=\"flex items-center gap-ds-1\">\n <PagerBtn\n onClick={() => handlePageChange(0)}\n disabled={currentPage === 0}\n label=\"First\"\n />\n <PagerBtn\n onClick={() => handlePageChange(currentPage - 1)}\n disabled={currentPage === 0}\n label=\"Prev\"\n />\n {Array.from({ length: Math.min(pageCount, 5) }, (_, i) => {\n let page: number;\n if (pageCount <= 5) {\n page = i;\n } else if (currentPage < 3) {\n page = i;\n } else if (currentPage > pageCount - 4) {\n page = pageCount - 5 + i;\n } else {\n page = currentPage - 2 + i;\n }\n return (\n <PagerBtn\n key={page}\n onClick={() => handlePageChange(page)}\n active={page === currentPage}\n label={String(page + 1)}\n />\n );\n })}\n <PagerBtn\n onClick={() => handlePageChange(currentPage + 1)}\n disabled={currentPage >= pageCount - 1}\n label=\"Next\"\n />\n <PagerBtn\n onClick={() => handlePageChange(pageCount - 1)}\n disabled={currentPage >= pageCount - 1}\n label=\"Last\"\n />\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction PagerBtn({\n onClick,\n disabled,\n active,\n label,\n}: {\n onClick: () => void;\n disabled?: boolean;\n active?: boolean;\n label: string;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n className={cn(\n \"h-8 min-w-[32px] px-ds-2 text-xs font-medium rounded-[var(--ds-radius-sm)]\",\n \"transition-colors duration-[var(--ds-transition-speed)] cursor-pointer\",\n \"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]\",\n \"disabled:opacity-disabled disabled:cursor-not-allowed\",\n active\n ? \"bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]\"\n : \"text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]\",\n )}\n >\n {label}\n </button>\n );\n}\n"]}
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';