gridsmith-ui 0.29.0 → 0.29.1
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/CHANGELOG.md +25 -0
- package/dist/charts.d.ts +5 -0
- package/dist/charts.js +2 -2
- package/dist/charts.js.map +1 -1
- package/dist/chat.js +5 -5
- package/dist/{chunk-GXMTS3YD.js → chunk-37WOC7F7.js} +29 -12
- package/dist/chunk-37WOC7F7.js.map +1 -0
- package/dist/{chunk-OPFJEL3Z.js → chunk-4TUJXDRU.js} +96 -15
- package/dist/chunk-4TUJXDRU.js.map +1 -0
- package/dist/{chunk-EIWXVICU.js → chunk-6A5RHW2W.js} +3 -3
- package/dist/{chunk-EIWXVICU.js.map → chunk-6A5RHW2W.js.map} +1 -1
- package/dist/{chunk-XVB55M3N.js → chunk-72SDAX54.js} +2 -2
- package/dist/chunk-72SDAX54.js.map +1 -0
- package/dist/{chunk-YUTF2X6B.js → chunk-FUKSLQ77.js} +8 -8
- package/dist/{chunk-YUTF2X6B.js.map → chunk-FUKSLQ77.js.map} +1 -1
- package/dist/{chunk-DQCHCLEJ.js → chunk-I3MTQ3CS.js} +5 -5
- package/dist/{chunk-DQCHCLEJ.js.map → chunk-I3MTQ3CS.js.map} +1 -1
- package/dist/{chunk-66JJCQU3.js → chunk-JTU7OBYJ.js} +5 -3
- package/dist/chunk-JTU7OBYJ.js.map +1 -0
- package/dist/{chunk-2ROVDVLZ.js → chunk-MFAWJSMJ.js} +3 -3
- package/dist/{chunk-2ROVDVLZ.js.map → chunk-MFAWJSMJ.js.map} +1 -1
- package/dist/{chunk-TJEV7YAY.js → chunk-MKFWHWBK.js} +2 -2
- package/dist/{chunk-TJEV7YAY.js.map → chunk-MKFWHWBK.js.map} +1 -1
- package/dist/{chunk-BRAXJEEP.js → chunk-QNHVPE2B.js} +4 -4
- package/dist/{chunk-BRAXJEEP.js.map → chunk-QNHVPE2B.js.map} +1 -1
- package/dist/{chunk-TRDXWHD2.js → chunk-RECCCA7Z.js} +6 -6
- package/dist/chunk-RECCCA7Z.js.map +1 -0
- package/dist/{chunk-R4GXKH4U.js → chunk-RJEUQ7RL.js} +10 -8
- package/dist/chunk-RJEUQ7RL.js.map +1 -0
- package/dist/{chunk-CRQ6KCRD.js → chunk-ZHUVLBCC.js} +7 -4
- package/dist/chunk-ZHUVLBCC.js.map +1 -0
- package/dist/data-grid.d.ts +2 -2
- package/dist/data-grid.js +9 -9
- package/dist/data-grid.js.map +1 -1
- package/dist/editor-mentions.js +2 -2
- package/dist/editor.js +4 -4
- package/dist/icons.d.ts +9 -0
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +38 -13
- package/dist/index.js +135 -148
- package/dist/index.js.map +1 -1
- package/dist/kanban.js +6 -6
- package/dist/kanban.js.map +1 -1
- package/dist/resizable.js +7 -7
- package/dist/roots.css +2 -0
- package/dist/{table-utils-BkjNEWts.d.ts → table-utils-CxnpFHRF.d.ts} +5 -4
- package/dist/{use-pagination-BxcRlNQG.d.ts → use-pagination-QykGSREv.d.ts} +7 -0
- package/dist/utils.js.map +1 -1
- package/dist/virtualized.d.ts +1 -1
- package/dist/virtualized.js +6 -6
- package/package.json +1 -1
- package/dist/chunk-66JJCQU3.js.map +0 -1
- package/dist/chunk-CRQ6KCRD.js.map +0 -1
- package/dist/chunk-GXMTS3YD.js.map +0 -1
- package/dist/chunk-OPFJEL3Z.js.map +0 -1
- package/dist/chunk-R4GXKH4U.js.map +0 -1
- package/dist/chunk-TRDXWHD2.js.map +0 -1
- package/dist/chunk-XVB55M3N.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { Badge } from './chunk-
|
|
3
|
-
import { slotIcon, Icon } from './chunk-
|
|
4
|
-
import { cn, FOCUS_RING } from './chunk-
|
|
2
|
+
import { Badge } from './chunk-RECCCA7Z.js';
|
|
3
|
+
import { slotIcon, Icon } from './chunk-MKFWHWBK.js';
|
|
4
|
+
import { cn, FOCUS_RING } from './chunk-JTU7OBYJ.js';
|
|
5
5
|
import { forwardRef, useState, useCallback } from 'react';
|
|
6
6
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
7
7
|
|
|
@@ -159,5 +159,5 @@ function Divider({
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
export { CodeBlock, Divider, Link };
|
|
162
|
-
//# sourceMappingURL=chunk-
|
|
163
|
-
//# sourceMappingURL=chunk-
|
|
162
|
+
//# sourceMappingURL=chunk-I3MTQ3CS.js.map
|
|
163
|
+
//# sourceMappingURL=chunk-I3MTQ3CS.js.map
|
|
@@ -1 +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-DQCHCLEJ.js","sourcesContent":["import { useState, useCallback } from \"react\";\nimport { cn, FOCUS_RING } 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_RING,\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 ElementType, type ReactNode } from \"react\";\nimport { cn, FOCUS_RING } from \"../lib/utils\";\nimport { slotIcon, type IconSlot } from \"../lib/icons\";\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. Any element type: a router's Link requires\n * its own props (react-router's `to`), which a narrower type refused under\n * strict TypeScript (Sprint 25.16 A19).\n */\n component?: ElementType;\n /** An icon name (\"info\"), drawn as the theme's icon at 14 px, or an element. Not text: use children. */\n iconLeft?: IconSlot;\n /** As iconLeft, after the label. */\n iconRight?: IconSlot;\n}\n\nconst toneStyles: Record<LinkTone, string> = {\n accent: \"text-[var(--ds-accent-ink)] 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-ink)]\",\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_RING,\n \"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 {slotIcon(iconLeft, 14, \"Link's iconLeft\")}\n {children}\n {slotIcon(iconRight, 14, \"Link's 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
|
+
{"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-I3MTQ3CS.js","sourcesContent":["import { useState, useCallback } from \"react\";\nimport { cn, FOCUS_RING } 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_RING,\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 ElementType, type ReactNode } from \"react\";\nimport { cn, FOCUS_RING } from \"../lib/utils\";\nimport { slotIcon, type IconSlot } from \"../lib/icons\";\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. Any element type: a router's Link requires\n * its own props (react-router's `to`), which a narrower type refused under\n * strict TypeScript (Sprint 25.16 A19).\n */\n component?: ElementType;\n /** An icon name (\"info\"), drawn as the theme's icon at 14 px, or an element. Not text: use children. */\n iconLeft?: IconSlot;\n /** As iconLeft, after the label. */\n iconRight?: IconSlot;\n}\n\nconst toneStyles: Record<LinkTone, string> = {\n accent: \"text-[var(--ds-accent-ink)] 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-ink)]\",\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_RING,\n \"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 {slotIcon(iconLeft, 14, \"Link's iconLeft\")}\n {children}\n {slotIcon(iconRight, 14, \"Link's 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"]}
|
|
@@ -15,6 +15,8 @@ var FOCUS_RING = "focus-visible:outline-2 focus-visible:outline-solid focus-visi
|
|
|
15
15
|
var PEER_FOCUS_RING = "peer-focus-visible:outline-2 peer-focus-visible:outline-solid peer-focus-visible:outline-offset-2 peer-focus-visible:outline-[var(--ds-focus)] peer-focus-visible:shadow-none";
|
|
16
16
|
var GROUP_FOCUS_RING = "group-focus-visible:outline-2 group-focus-visible:outline-solid group-focus-visible:outline-offset-2 group-focus-visible:outline-[var(--ds-focus)] group-focus-visible:shadow-none";
|
|
17
17
|
var FOCUS_INSET = "focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-[var(--ds-focus-inset)] focus-visible:outline-[var(--ds-focus)]";
|
|
18
|
+
var FOCUS_ROOM = 4;
|
|
19
|
+
var atLeastFocusRoom = (length) => `max(${length}, ${FOCUS_ROOM}px)`;
|
|
18
20
|
var FIELD_FOCUS_RING = "focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-[var(--ds-focus)] focus-visible:border-[var(--ds-focus)] [[data-input-modality=pointer]_&]:focus-visible:outline-none [[data-input-modality=pointer]_&]:focus-visible:border-[var(--ds-accent-ink)] [[data-input-modality=pointer]_&]:focus-visible:ring-2 [[data-input-modality=pointer]_&]:focus-visible:ring-[var(--ds-ring-active)]";
|
|
19
21
|
var FIELD_FOCUS_WITHIN_RING = "has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-2 has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-solid has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-offset-2 has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-[var(--ds-focus)] has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:border-[var(--ds-focus)] [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-none [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:border-[var(--ds-accent-ink)] [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:ring-2 [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:ring-[var(--ds-ring-active)]";
|
|
20
22
|
var FIELD_HAS_FOCUS_RING = "has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-2 has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-solid has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-offset-2 has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-[var(--ds-focus)] has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:border-[var(--ds-focus)] [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-none [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:border-[var(--ds-accent-ink)] [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:ring-2 [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:ring-[var(--ds-ring-active)]";
|
|
@@ -41,6 +43,6 @@ function unlockBodyScroll() {
|
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
export { ACTIVE_RING, ERROR_ACTIVE_RING, ERROR_FOCUS_RING, ERROR_FOCUS_WITHIN_RING, ERROR_HAS_FOCUS_RING, FIELD_FOCUS_RING, FIELD_FOCUS_WITHIN_RING, FIELD_HAS_FOCUS_RING, FOCUS_INSET, FOCUS_RING, GLASS_BACKDROP, GLASS_DROPDOWN, GLASS_OVERLAY, GLASS_SURFACE, GROUP_FOCUS_RING, OVERLAY_SURFACE, PEER_FOCUS_RING, cn, lockBodyScroll, unlockBodyScroll };
|
|
45
|
-
//# sourceMappingURL=chunk-
|
|
46
|
-
//# sourceMappingURL=chunk-
|
|
46
|
+
export { ACTIVE_RING, ERROR_ACTIVE_RING, ERROR_FOCUS_RING, ERROR_FOCUS_WITHIN_RING, ERROR_HAS_FOCUS_RING, FIELD_FOCUS_RING, FIELD_FOCUS_WITHIN_RING, FIELD_HAS_FOCUS_RING, FOCUS_INSET, FOCUS_RING, FOCUS_ROOM, GLASS_BACKDROP, GLASS_DROPDOWN, GLASS_OVERLAY, GLASS_SURFACE, GROUP_FOCUS_RING, OVERLAY_SURFACE, PEER_FOCUS_RING, atLeastFocusRoom, cn, lockBodyScroll, unlockBodyScroll };
|
|
47
|
+
//# sourceMappingURL=chunk-JTU7OBYJ.js.map
|
|
48
|
+
//# sourceMappingURL=chunk-JTU7OBYJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/lib/utils.ts"],"names":[],"mappings":";;;;;AAGO,SAAS,MAAM,MAAA,EAA8B;AAClD,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;AAEO,IAAM,cAAA,GAAiB;AAEvB,IAAM,aAAA,GAAgB,GAAG,cAAc,CAAA,qDAAA;AAEvC,IAAM,aAAA,GAAgB,GAAG,cAAc,CAAA,sDAAA;AAavC,IAAM,eAAA,GAAkB;AAExB,IAAM,cAAA,GAAiB,GAAG,cAAc,CAAA,yDAAA;AAWxC,IAAM,UAAA,GAAa;AAgBnB,IAAM,eAAA,GAAkB;AAExB,IAAM,gBAAA,GAAmB;AAUzB,IAAM,WAAA,GAAc;AAOpB,IAAM,UAAA,GAAa;AAGnB,IAAM,mBAAmB,CAAC,MAAA,KAAmB,CAAA,IAAA,EAAO,MAAM,KAAK,UAAU,CAAA,GAAA;AAgBzE,IAAM,gBAAA,GAAmB;AAEzB,IAAM,uBAAA,GAA0B;AAEhC,IAAM,oBAAA,GAAuB;AAG7B,IAAM,gBAAA,GAAmB;AAEzB,IAAM,uBAAA,GAA0B;AAEhC,IAAM,oBAAA,GAAuB;AAK7B,IAAM,WAAA,GAAc;AAEpB,IAAM,iBAAA,GAAoB;AAMjC,IAAI,eAAA,GAAkB,CAAA;AACtB,IAAI,0BAAA,GAA6B,EAAA;AAE1B,SAAS,cAAA,GAAiB;AAC/B,EAAA,IAAI,oBAAoB,CAAA,EAAG;AACzB,IAAA,0BAAA,GAA6B,QAAA,CAAS,KAAK,KAAA,CAAM,QAAA;AACjD,IAAA,QAAA,CAAS,IAAA,CAAK,MAAM,QAAA,GAAW,QAAA;AAAA,EACjC;AACA,EAAA,eAAA,EAAA;AACF;AAEO,SAAS,gBAAA,GAAmB;AACjC,EAAA,IAAI,oBAAoB,CAAA,EAAG;AAC3B,EAAA,eAAA,EAAA;AACA,EAAA,IAAI,oBAAoB,CAAA,EAAG;AACzB,IAAA,QAAA,CAAS,IAAA,CAAK,MAAM,QAAA,GAAW,0BAAA;AAC/B,IAAA,0BAAA,GAA6B,EAAA;AAAA,EAC/B;AACF","file":"chunk-JTU7OBYJ.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n\nexport const GLASS_BACKDROP = \"[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]\";\n\nexport const GLASS_SURFACE = `${GLASS_BACKDROP} shadow-[var(--ds-shadow-card),var(--ds-glass-inset)]`;\n\nexport const GLASS_OVERLAY = `${GLASS_BACKDROP} shadow-[var(--ds-shadow-modal),var(--ds-glass-inset)]`;\n\n/**\n * A modal surface (Dialog, Drawer, Sheet, CommandPalette, GlobalSearch): the theme's surface, never less than 85% opaque.\n * A glass theme's surface is see-through by design, which suits a card on the canvas; over an overlay's scrim the same\n * glass reads as grey mud, and the page shows through (round 27, R27-17, the owner picked 85% from a mock-up). An opaque\n * theme keeps its surface as it is: the alpha only rises, through CSS relative colour, in every mode and scope.\n *\n * The theme's surface comes first, for a browser without relative colour (Chrome before 119, Firefox before 128,\n * Safari before 16.4): a value holding var() is only found invalid once computed, which drops the background to\n * transparent rather than to an earlier declaration, so the raised one applies only where @supports says it can (the\n * round 27 review). A surface with no colour at all (fully transparent) stays so: raising it would paint it black.\n */\nexport const OVERLAY_SURFACE = \"bg-[var(--ds-bg-surface)] supports-[color:oklch(from_red_l_c_h)]:bg-[oklch(from_var(--ds-bg-surface)_l_c_h_/_max(alpha,min(1,alpha*1000)*0.85))]\";\n\nexport const GLASS_DROPDOWN = `${GLASS_BACKDROP} shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]`;\n\n// Keyboard focus (Sprint 30, the owner's D1 and D6): where Tab has landed. A solid outline in the theme's focus colour\n// (--ds-focus, derived to 3:1 on every ground), 2 px, with a 2 px gap between it and the element. The gap shows what the\n// element sits on, so one colour reads beside any fill, and while the outline shows, the element's own shadow steps\n// aside (D7, P12): shadow-none drops its --tw-shadow and keeps any ring. Every part is prefixed: an unprefixed\n// outline-solid draws an outline at rest. And outline-solid is required: in Tailwind 4, outline-none (which many\n// components set at rest) sets --tw-outline-style: none, which outline-2 reads, so without it no outline draws. These\n// draw no border (a button that uses one, the Launcher, gets the outline alone); a field takes FIELD_FOCUS_RING. `cn()`\n// keeps only the last of outline-none and outline-solid in one variant, so a component's own focus-visible:outline-none\n// after a utility would remove the outline: none may follow one.\nexport const FOCUS_RING = \"focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-[var(--ds-focus)] focus-visible:shadow-none\";\n\n/**\n * On a wrapper that shows focus for a control inside it: HAS_FOCUS_RING, from the keyboard only (`:has(:focus-visible)`).\n * FOCUS_WITHIN_RING shows it on any focus inside, a click's too, since `:focus-within` has no keyboard-only form: kept\n * for code that uses it, and a new wrapper takes HAS_FOCUS_RING (D6: keyboard focus shows only from the keyboard).\n */\nexport const FOCUS_WITHIN_RING = \"focus-within:outline-2 focus-within:outline-solid focus-within:outline-offset-2 focus-within:outline-[var(--ds-focus)] focus-within:shadow-none\";\n\nexport const HAS_FOCUS_RING = \"has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-solid has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-[var(--ds-focus)] has-[:focus-visible]:shadow-none\";\n\n/**\n * The outline on a drawn child, where the element that takes focus is hidden or wraps it: a checkbox's box beside its\n * input (`peer`), a radio's circle inside its button, a separator's grip, a Gantt milestone's diamond (`group`). The\n * same outline, gap and shadow rule.\n */\nexport const PEER_FOCUS_RING = \"peer-focus-visible:outline-2 peer-focus-visible:outline-solid peer-focus-visible:outline-offset-2 peer-focus-visible:outline-[var(--ds-focus)] peer-focus-visible:shadow-none\";\n\nexport const GROUP_FOCUS_RING = \"group-focus-visible:outline-2 group-focus-visible:outline-solid group-focus-visible:outline-offset-2 group-focus-visible:outline-[var(--ds-focus)] group-focus-visible:shadow-none\";\n\n/**\n * The same outline drawn inside the element's edge, for edge-to-edge rows, cells and scroll regions only (the plan's\n * P3): elements that are never filled solid, since inside the edge there is no gap to keep one colour readable on a fill.\n * It sits `--ds-focus-inset` in: 5 px, deeper where the theme's corners are rounder, so it clears a table's rounded\n * corners (D8, the owner's decision A); what such an element holds keeps 1 px more clear of its edge. Anywhere else the\n * outline stays outside, with room made for it. Moved here from use-keyboard-scroll.ts (Sprint 30) so the server-safe\n * `gridsmith-ui/utils` can export it.\n */\nexport const FOCUS_INSET = \"focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-[var(--ds-focus-inset)] focus-visible:outline-[var(--ds-focus)]\";\n\n/**\n * The room FOCUS_RING's outline takes outside its element, in px: its 2 px gap and 2 px line (Sprint 30, P3). Where a\n * container clips, what sits beside its edge keeps this much clear of it: a fixed size, never a theme space. Internal,\n * as is the one below (exports/utils.ts exports by name).\n */\nexport const FOCUS_ROOM = 4;\n\n/** A theme's length that sets how far something sits from a clipping edge, never under FOCUS_ROOM (Sprint 25.27). */\nexport const atLeastFocusRoom = (length: string) => `max(${length}, ${FOCUS_ROOM}px)`;\n\n/**\n * A field (D6, P4, P13). Reached with Tab: the keyboard's outline, and its border in the focus colour, as GOV.UK turns a\n * focused input's border: it is where you type. Clicked into: the active look instead, the accent border and its soft\n * halo (`ring-2` in --ds-ring-active, laid over the field's own shadow), and no outline. A browser matches :focus-visible\n * on a text field either way, so lib/input-modality.ts notes on <html> whether a pointer moved focus last; with no note\n * yet, the outline. The field keeps its own (inset) shadow in both: no shadow-none here.\n *\n * The wrapper forms (_WITHIN_ and _HAS_, for a box round the part you type in) show it while that part has focus, and\n * not while a control of the field's own does: a button, a select, a link, a checkbox, a radio or a switch inside it (a\n * tag's remove, a picker's chevron, a composer's Send, an editor's toolbar or a task's checkbox), or anything in a popup\n * inside the box (a dialog of its own; a field that is itself in a dialog still shows it). That control shows its own outline, so there is one focus point, never\n * two (P11). _WITHIN_ reads :focus, as a click on a date's segment isn't :focus-visible; _HAS_ reads :focus-visible.\n * Either outranks the field's hover border, so hovering keeps the look.\n */\nexport const FIELD_FOCUS_RING = \"focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-[var(--ds-focus)] focus-visible:border-[var(--ds-focus)] [[data-input-modality=pointer]_&]:focus-visible:outline-none [[data-input-modality=pointer]_&]:focus-visible:border-[var(--ds-accent-ink)] [[data-input-modality=pointer]_&]:focus-visible:ring-2 [[data-input-modality=pointer]_&]:focus-visible:ring-[var(--ds-ring-active)]\";\n\nexport const FIELD_FOCUS_WITHIN_RING = \"has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-2 has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-solid has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-offset-2 has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-[var(--ds-focus)] has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:border-[var(--ds-focus)] [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-none [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:border-[var(--ds-accent-ink)] [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:ring-2 [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:ring-[var(--ds-ring-active)]\";\n\nexport const FIELD_HAS_FOCUS_RING = \"has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-2 has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-solid has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-offset-2 has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-[var(--ds-focus)] has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:border-[var(--ds-focus)] [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-none [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:border-[var(--ds-accent-ink)] [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:ring-2 [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:ring-[var(--ds-ring-active)]\";\n\n// A field with an error: the same, its red border kept, and the red halo when clicked into.\nexport const ERROR_FOCUS_RING = \"focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-[var(--ds-focus)] focus-visible:border-[var(--ds-status-error)] [[data-input-modality=pointer]_&]:focus-visible:outline-none [[data-input-modality=pointer]_&]:focus-visible:ring-2 [[data-input-modality=pointer]_&]:focus-visible:ring-[var(--ds-ring-error)]\";\n\nexport const ERROR_FOCUS_WITHIN_RING = \"has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-2 has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-solid has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-offset-2 has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-[var(--ds-focus)] has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:border-[var(--ds-status-error)] [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:outline-none [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:ring-2 [[data-input-modality=pointer]_&]:has-[:focus:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus))]:ring-[var(--ds-ring-error)]\";\n\nexport const ERROR_HAS_FOCUS_RING = \"has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-2 has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-solid has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-offset-2 has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-[var(--ds-focus)] has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:border-[var(--ds-status-error)] [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:outline-none [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:ring-2 [[data-input-modality=pointer]_&]:has-[:focus-visible:not(button,select,a,[role=button],input[type=checkbox],input[type=radio],[role=checkbox],[role=radio],[role=switch])]:[&:not(:has([role=dialog]_:focus-visible))]:ring-[var(--ds-ring-error)]\";\n\n// Active (D6): a field clicked into, or a dropdown or picker that's open, is its accent border (--ds-accent-ink, P8) with\n// the soft halo beyond it; on a field with an error, red with the red halo. Never an outline: that is keyboard focus's.\n// Choices (a selected card, row or swatch, the Stepper's current step) draw their own selected look, not this (D2).\nexport const ACTIVE_RING = \"border-[var(--ds-accent-ink)] ring-2 ring-[var(--ds-ring-active)]\";\n\nexport const ERROR_ACTIVE_RING = \"border-[var(--ds-status-error)] ring-2 ring-[var(--ds-ring-error)]\";\n\n// Body scroll lock is reference-counted so stacked overlays (a Dialog opened\n// from a Drawer, for example) only restore scrolling when the LAST one\n// closes. The original overflow value is captured on the first lock and put\n// back on the last unlock; an unbalanced unlock is clamped at zero.\nlet scrollLockCount = 0;\nlet scrollLockPreviousOverflow = \"\";\n\nexport function lockBodyScroll() {\n if (scrollLockCount === 0) {\n scrollLockPreviousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n }\n scrollLockCount++;\n}\n\nexport function unlockBodyScroll() {\n if (scrollLockCount === 0) return;\n scrollLockCount--;\n if (scrollLockCount === 0) {\n document.body.style.overflow = scrollLockPreviousOverflow;\n scrollLockPreviousOverflow = \"\";\n }\n}\n\n/** Test-only: current number of active locks. */\nexport function getBodyScrollLockCount() {\n return scrollLockCount;\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { FIXED_FORM, localeFor, browserLanguages, formatLocale } from './chunk-OYNUU346.js';
|
|
3
|
-
import { cn } from './chunk-
|
|
3
|
+
import { cn } from './chunk-JTU7OBYJ.js';
|
|
4
4
|
import { createContext, useSyncExternalStore, useContext } from 'react';
|
|
5
5
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
6
|
|
|
@@ -61,5 +61,5 @@ function Skeleton({ variant = "text", lines = 3, width, height, className }) {
|
|
|
61
61
|
var TITLE_TEXT = "font-[family-name:var(--ds-font-display)] text-lg font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)] break-words";
|
|
62
62
|
|
|
63
63
|
export { LocaleContext, Skeleton, TITLE_TEXT, useFormatLocale, useHydrated, useToday };
|
|
64
|
-
//# sourceMappingURL=chunk-
|
|
65
|
-
//# sourceMappingURL=chunk-
|
|
64
|
+
//# sourceMappingURL=chunk-MFAWJSMJ.js.map
|
|
65
|
+
//# sourceMappingURL=chunk-MFAWJSMJ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../showcase/src/lib/hydrated.ts","../../../showcase/src/lib/locale.ts","../../../showcase/src/components/Skeleton.tsx","../../../showcase/src/lib/title-text.ts"],"names":[],"mappings":"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","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/lib/hydrated.ts","../../../showcase/src/lib/locale.ts","../../../showcase/src/components/Skeleton.tsx","../../../showcase/src/lib/title-text.ts"],"names":[],"mappings":"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","file":"chunk-MFAWJSMJ.js","sourcesContent":["import { useSyncExternalStore } from \"react\";\n\nconst noSubscription = () => () => {};\nconst inBrowser = () => true;\nconst onServer = () => false;\n\n/**\n * Whether the browser has taken the page over (Sprint 25.20 D3): false on a server, and in the render that hydrates the\n * server's HTML (it must draw what the server drew), true straight after. A render with no server HTML (a Vite app, a\n * component mounted later) is true from its first render. What depends on the visitor's clock or time zone, which no\n * server knows, waits for it.\n */\nexport function useHydrated(): boolean {\n return useSyncExternalStore(noSubscription, inBrowser, onServer);\n}\n\n/**\n * Today on the visitor's device, once the browser has the page (null on a server and while hydrating): the day a date\n * grid marks and starts its keyboard on. Read on each render, so a grid drawn again after midnight marks the new day.\n */\nexport function useToday(): Date | null {\n return useHydrated() ? new Date() : null;\n}\n","import { createContext, useContext } from \"react\";\nimport { browserLanguages, formatLocale, localeFor, FIXED_FORM, type LocaleChoice } from \"./format-locale\";\nimport { useHydrated } from \"./hydrated\";\n\n// the choice itself needs no React, so server code can make it too (Sprint 25.22's review: requestLocale, on utils)\nexport { localeChoice, FIXED_FORM, type LocaleChoice } from \"./format-locale\";\n\nexport const LocaleContext = createContext<LocaleChoice | null>(null);\n\n/**\n * The locale a component writes its dates and numbers in (Sprint 25.20 L1). On a server, and while the browser hydrates\n * the server's HTML, the one the server chose: LocaleProvider's (the visitor's form of the page's language, from the\n * request), else \"en\", never a machine's own default, so both sides write the same. Once the page has loaded, the\n * browser's own reading (the visitor's form of the page's `lang`, as formatLocale() reads it), usually the same. A render\n * with no server HTML reads the browser's from its first render. Undefined is the browser's own language.\n */\nexport function useFormatLocale(): string | undefined {\n const choice = useContext(LocaleContext);\n const hydrated = useHydrated();\n if (!hydrated) return choice ? choice.server : FIXED_FORM;\n return choice ? localeFor(choice.lang, browserLanguages()) ?? choice.server : formatLocale();\n}\n","import { cn } from \"../lib/utils\";\n\ninterface SkeletonProps {\n variant?: \"text\" | \"avatar\" | \"card\" | \"table-row\" | \"custom\";\n lines?: number;\n width?: string;\n height?: string;\n className?: string;\n}\n\nfunction Bone({ className, style, \"data-gs\": marker }: { className?: string; style?: React.CSSProperties; \"data-gs\"?: string }) {\n return (\n <div\n data-gs={marker}\n className={cn(\"rounded-[var(--ds-radius-sm)] bg-[var(--ds-bg-emphasis)] animate-pulse\", className)}\n style={style}\n />\n );\n}\n\nexport function Skeleton({ variant = \"text\", lines = 3, width, height, className }: SkeletonProps) {\n if (variant === \"custom\") {\n return <Bone data-gs=\"skeleton\" className={className} style={{ width, height }} />;\n }\n\n if (variant === \"avatar\") {\n return <Bone data-gs=\"skeleton\" className={cn(\"h-10 w-10 rounded-[var(--ds-radius-full)]\", className)} />;\n }\n\n if (variant === \"card\") {\n return (\n <div data-gs=\"skeleton\" className={cn(\"space-y-ds-3\", className)}>\n <Bone className=\"h-32 w-full rounded-[var(--ds-radius-md)]\" />\n <Bone className=\"h-4 w-3/4\" />\n <Bone className=\"h-4 w-1/2\" />\n </div>\n );\n }\n\n if (variant === \"table-row\") {\n return (\n <div data-gs=\"skeleton\" className={cn(\"flex gap-ds-4\", className)}>\n <Bone className=\"h-4 flex-[3]\" />\n <Bone className=\"h-4 flex-[2]\" />\n <Bone className=\"h-4 flex-1\" />\n <Bone className=\"h-4 flex-1\" />\n </div>\n );\n }\n\n // text variant\n const widths = [\"w-3/4\", \"w-1/2\", \"w-5/6\", \"w-2/3\", \"w-4/5\"];\n return (\n <div data-gs=\"skeleton\" className={cn(\"space-y-ds-3\", className)}>\n {Array.from({ length: lines }, (_, i) => (\n <Bone key={i} className={cn(\"h-4\", widths[i % widths.length])} />\n ))}\n </div>\n );\n}\n","/**\n * A title's text classes: CardTitle's, which a titled Table's band and a ChartContainer's title share (Sprint 25.9, A1),\n * one definition so they cannot drift. A word or a name longer than its line breaks at the line's edge (round 27,\n * R27-16: run 70's \"primary-logo-navy.svg\" ran out of its card); break-word, not anywhere, so a title's words still\n * set its minimum and the actions beside it wrap under it before a word is broken (HEADER_LAYOUT.floor).\n */\nexport const TITLE_TEXT = \"font-[family-name:var(--ds-font-display)] text-lg font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)] break-words\";\n"]}
|
|
@@ -205,5 +205,5 @@ function NotAnIcon({ text, from }) {
|
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
export { Icon, IconProvider, preloadPack, registerIconPack, slotDraws, slotIcon, warnOnce };
|
|
208
|
-
//# sourceMappingURL=chunk-
|
|
209
|
-
//# sourceMappingURL=chunk-
|
|
208
|
+
//# sourceMappingURL=chunk-MKFWHWBK.js.map
|
|
209
|
+
//# sourceMappingURL=chunk-MKFWHWBK.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../showcase/src/lib/dev-warn.ts","../../../showcase/src/lib/icon-pack-imports.ts","../../../showcase/src/lib/icons.tsx"],"names":[],"mappings":"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","file":"chunk-TJEV7YAY.js","sourcesContent":["// Bundlers set process.env.NODE_ENV. Where none did (a page with no build step), reading it throws and warnings stay off.\ndeclare const process: { env: { NODE_ENV?: string } };\nconst warned = new Set<string>();\n\n/** A mistake in a component's props, told to the developer once a page, in a development build. */\nexport function warnOnce(component: string, message: string): void {\n let dev = false;\n try {\n dev = process.env.NODE_ENV !== \"production\";\n } catch {\n dev = false;\n }\n const text = `${component}: ${message}`;\n if (!dev || warned.has(text)) return;\n warned.add(text);\n console.warn(text);\n}\n","/**\n * The import each icon pack takes, as an app writes it when it registers its theme's pack (Sprint 25.21 P1:\n * `registerIconPack('feather', () => import('react-icons/fi'))`). One table for the library's warning, the shells\n * `get_app_shell` writes and the engine's fix. Lucide is the library's own: every app installs it, as the fallback.\n * No React here, so the platform reads it as it reads the other showcase modules.\n */\nexport const ICON_PACK_IMPORTS = {\n feather: \"react-icons/fi\",\n heroicons: \"@heroicons/react/24/outline\",\n phosphor: \"@phosphor-icons/react\",\n tabler: \"@tabler/icons-react\",\n} as const;\n\n/** A pack an app registers: every pack but Lucide. */\nexport type RegisteredIconPack = keyof typeof ICON_PACK_IMPORTS;\n\n/** The two lines that register a pack, at the top of an app's shell, before any preloadPack. */\nexport function iconPackRegistration(pack: RegisteredIconPack): { importLine: string; call: string } {\n return {\n importLine: \"import { registerIconPack } from 'gridsmith-ui/icons'\",\n call: `registerIconPack('${pack}', () => import('${ICON_PACK_IMPORTS[pack]}'))`,\n };\n}\n","import { createContext, useContext, useEffect, useSyncExternalStore, type ReactElement, type ReactNode, type ComponentType } from \"react\";\nimport { warnOnce } from \"./dev-warn\";\nimport { iconPackRegistration, type RegisteredIconPack } from \"./icon-pack-imports\";\nimport type { PackLoad } from \"./icon-packs/types\";\n\n/* ── Types ────────────────────────────────────────────────────── */\n\n/**\n * Runtime list of curated icon names. The CuratedIconName type derives from\n * this array, so adding a name here extends autocomplete automatically.\n * Every name must have an alias (or auto-kebab match) in ALL five packs —\n * icon-completeness.test.tsx enforces this.\n */\nexport const CURATED_ICON_NAMES = [\n \"home\", \"folder\", \"chart\", \"settings\",\n \"chevron-right\", \"close\", \"plus\", \"search\",\n \"bell\", \"user\", \"check\", \"warning\", \"info\", \"error\",\n \"clock\", \"calendar\",\n \"bold\", \"italic\", \"underline\", \"strikethrough\",\n \"align-left\", \"align-center\", \"align-right\",\n \"list\", \"list-ordered\", \"list-checks\",\n \"link\", \"image\", \"table\", \"code\", \"quote\", \"minus\",\n \"superscript\", \"subscript\", \"highlight\", \"type\",\n \"chevron-up\", \"chevron-down\", \"chevron-left\", \"trash\",\n \"undo\", \"redo\",\n \"arrow-left\", \"grip-vertical\",\n \"mic\", \"paperclip\", \"send\",\n \"log-out\", \"edit\", \"menu\", \"more-horizontal\",\n \"star\", \"bookmark\", \"download\", \"upload\", \"sparkles\",\n \"file\", \"file-text\", \"eye\", \"eye-off\", \"copy\", \"external-link\", \"filter\", \"lock\",\n \"map-pin\",\n] as const;\n\ntype CuratedIconName = (typeof CURATED_ICON_NAMES)[number];\n\n/**\n * Curated names provide autocomplete and work identically across all 5 packs.\n * Any kebab-case string is also accepted — it resolves directly against the\n * active pack's native exports (e.g. \"clipboard-copy\" → Lucide's ClipboardCopy).\n */\nexport type IconName = CuratedIconName | (string & {});\n\nexport type IconPack = \"lucide\" | \"phosphor\" | \"heroicons\" | \"tabler\" | \"feather\";\n\ntype IconComponent = ComponentType<Record<string, unknown>>;\ntype IconMap = Record<string, IconComponent>;\n\n/* ── External store ──────────────────────────────────────────── */\n\ntype Subscriber = () => void;\nconst subscribers = new Set<Subscriber>();\nfunction notifySubscribers() {\n subscribers.forEach((fn) => fn());\n}\nfunction subscribe(cb: Subscriber): () => void {\n subscribers.add(cb);\n return () => { subscribers.delete(cb); };\n}\n\nconst curatedCache = new Map<IconPack, IconMap>();\nconst extendedCache = new Map<IconPack, IconMap>();\n\nfunction useCuratedMap(pack: IconPack): IconMap | null {\n return useSyncExternalStore(\n subscribe,\n () => curatedCache.get(pack) ?? null,\n () => null,\n );\n}\n\nfunction useExtendedMap(pack: IconPack): IconMap | null {\n return useSyncExternalStore(\n subscribe,\n () => extendedCache.get(pack) ?? null,\n () => null,\n );\n}\n\n/* ── Pack loading ────────────────────────────────────────────────\n Each pack is isolated in its own file under ./icon-packs/, and reads\n its package through an import handed to it: the app's own for its\n theme's pack (registerIconPack, Sprint 25.21 P1), the library's own\n for Lucide. No file the library publishes names a pack the app may\n not have installed, so no bundler looks for one: Next.js's webpack\n resolved every pack the library named, and failed the build.\n\n Loading is two-phase:\n 1. Curated map (50 static named imports) — available as soon as\n the pack chunk loads, cached and notified immediately.\n 2. Extended map (full barrel import + kebab-case iteration) —\n loaded in the background, cached and notified when ready. */\n\nconst loadingPacks = new Set<IconPack>();\nconst failedPacks = new Set<IconPack>();\n\ntype PackModule = {\n loadCurated(load: PackLoad): Promise<IconMap>;\n loadExtended(load: PackLoad): Promise<IconMap>;\n};\n\n/** Each pack's import: Lucide's is the library's own (every app installs it); the others are the app's, registered. */\nconst packImports = new Map<IconPack, PackLoad>([[\"lucide\", () => import(\"lucide-react\")]]);\n\n/**\n * The theme's icon pack, as the app's own import (Sprint 25.21 P1): `registerIconPack('feather', () =>\n * import('react-icons/fi'))` at the top of the shell, before any preloadPack. The library names no pack itself, so an\n * app's bundler only ever meets the pack the app installed. A pack drawn before it is registered draws Lucide's icons,\n * and draws its own once registered. Lucide needs no line.\n */\nexport function registerIconPack(pack: RegisteredIconPack, load: PackLoad): void {\n packImports.set(pack, load);\n // a draw that met the pack unregistered loads it now: its icons redraw once the pack's map arrives (a notice alone\n // changes no snapshot, so nothing would redraw to ask)\n if (failedPacks.delete(pack)) void loadPack(pack);\n}\n\n/** The npm package each pack needs — named in the error when a pack is missing. */\nconst PEER_PACKAGE: Record<IconPack, string> = {\n lucide: \"lucide-react\",\n phosphor: \"@phosphor-icons/react\",\n heroicons: \"@heroicons/react\",\n tabler: \"@tabler/icons-react\",\n feather: \"react-icons\",\n};\n\nasync function loadPack(pack: IconPack): Promise<void> {\n if (curatedCache.has(pack) || loadingPacks.has(pack) || failedPacks.has(pack)) return;\n loadingPacks.add(pack);\n\n // Each pack module reaches its package only through the import handed to it\n // (see icon-packs/*.ts), so the chunk import below always succeeds and it is\n // loadCurated() that rejects when the package is not installed.\n const load = packImports.get(pack);\n if (!load) {\n // not registered: Lucide's icons stand in (Icon's third tier), and the developer is told the line to add\n failedPacks.add(pack);\n loadingPacks.delete(pack);\n const lines = iconPackRegistration(pack as RegisteredIconPack);\n warnOnce(\"IconProvider\", `the ${pack} icon pack isn't registered, so its icons are drawn from Lucide. At the top of the shell, before any preloadPack: ${lines.importLine}; ${lines.call}`);\n return;\n }\n let mod: PackModule;\n let curated: IconMap;\n try {\n switch (pack) {\n case \"lucide\": mod = await import(\"./icon-packs/lucide\"); break;\n case \"phosphor\": mod = await import(\"./icon-packs/phosphor\"); break;\n case \"heroicons\": mod = await import(\"./icon-packs/heroicons\"); break;\n case \"tabler\": mod = await import(\"./icon-packs/tabler\"); break;\n case \"feather\": mod = await import(\"./icon-packs/feather\"); break;\n }\n curated = await mod!.loadCurated(load);\n } catch {\n loadingPacks.delete(pack);\n failedPacks.add(pack);\n console.error(`gridsmith-ui: ${PEER_PACKAGE[pack]} is not installed. Run: npm install ${PEER_PACKAGE[pack]}`);\n return;\n }\n\n curatedCache.set(pack, curated);\n notifySubscribers();\n\n mod!.loadExtended(load).then((extended) => {\n extendedCache.set(pack, extended);\n notifySubscribers();\n }).catch(() => {\n // Extended map failed (e.g. network error loading the full barrel).\n // Curated icons still work; extended names will not resolve.\n });\n}\n\n/** A pack's registered import, for the tests that load the packs directly; they register them first. */\nfunction importOf(pack: IconPack): PackLoad {\n const load = packImports.get(pack);\n if (!load) throw new Error(`gridsmith-ui: register the ${pack} icon pack first (registerIconPack)`);\n return load;\n}\n\n/** Exported for the icon-completeness test — not part of the public API. */\nexport const packLoaders: Record<IconPack, {\n curated: () => Promise<IconMap>;\n extended: () => Promise<IconMap>;\n}> = {\n lucide: { curated: () => import(\"./icon-packs/lucide\").then((m) => m.loadCurated(importOf(\"lucide\"))), extended: () => import(\"./icon-packs/lucide\").then((m) => m.loadExtended(importOf(\"lucide\"))) },\n phosphor: { curated: () => import(\"./icon-packs/phosphor\").then((m) => m.loadCurated(importOf(\"phosphor\"))), extended: () => import(\"./icon-packs/phosphor\").then((m) => m.loadExtended(importOf(\"phosphor\"))) },\n heroicons: { curated: () => import(\"./icon-packs/heroicons\").then((m) => m.loadCurated(importOf(\"heroicons\"))), extended: () => import(\"./icon-packs/heroicons\").then((m) => m.loadExtended(importOf(\"heroicons\"))) },\n tabler: { curated: () => import(\"./icon-packs/tabler\").then((m) => m.loadCurated(importOf(\"tabler\"))), extended: () => import(\"./icon-packs/tabler\").then((m) => m.loadExtended(importOf(\"tabler\"))) },\n feather: { curated: () => import(\"./icon-packs/feather\").then((m) => m.loadCurated(importOf(\"feather\"))), extended: () => import(\"./icon-packs/feather\").then((m) => m.loadExtended(importOf(\"feather\"))) },\n};\n\n/* ── Context ──────────────────────────────────────────────────── */\n\ninterface IconContextValue {\n pack: IconPack;\n weight: number;\n}\n\nconst IconCtx = createContext<IconContextValue>({ pack: \"lucide\", weight: 1.5 });\n\nexport function IconProvider({ pack, weight, children }: { pack: IconPack; weight: number; children: ReactNode }) {\n useEffect(() => {\n loadPack(pack);\n if (pack !== \"lucide\") loadPack(\"lucide\");\n }, [pack]);\n\n return <IconCtx.Provider value={{ pack, weight }}>{children}</IconCtx.Provider>;\n}\n\n/**\n * Start loading a pack's icon chunk before React mounts. Call this in your\n * app's entry point or shell for the fastest possible cold start, after the\n * pack is registered (every pack but Lucide, Sprint 25.21 P1):\n *\n * import { preloadPack, registerIconPack } from 'gridsmith-ui/icons'\n * registerIconPack('feather', () => import('react-icons/fi'))\n * preloadPack('feather')\n */\nexport function preloadPack(pack: IconPack): void {\n loadPack(pack);\n}\n\n/* ── Phosphor weight mapping ──────────────────────────────────── */\n\n/**\n * A stroke weight maps to a stroke weight only. `fill` and `duotone` change the\n * glyph itself (Phosphor's filled Check is a check inside a filled square), so\n * a theme's heaviest stroke must never reach them — the Sprint 22 bench found\n * every tick on a 2.5-weight theme rendered as a filled box (14 Sep 2026).\n */\nexport function getPhosphorWeight(numericWeight: number): \"thin\" | \"light\" | \"regular\" | \"bold\" {\n if (numericWeight <= 0.75) return \"thin\";\n if (numericWeight <= 1.25) return \"light\";\n if (numericWeight <= 1.75) return \"regular\";\n return \"bold\";\n}\n\n/* ── Icon component ───────────────────────────────────────────── */\n\n/**\n * `from`: the component slot that drew the icon (\"Button's iconLeft\"), named in the development warning when the theme's\n * pack has no icon by that name. A name no pack has draws nothing (Sprint 25.17 A26: an arrow or a word passed as an\n * icon was printed as text before slots took names).\n */\n/**\n * Whether a map holds an icon of its own by this name, never one its prototype lends: a slot now takes any string, and\n * \"constructor\", \"toString\" or \"__proto__\" read off a plain object drew junk or threw (Sprint 25.17's review). The icon\n * is then read off the map itself, so the compiler sees a component the map holds, not one made while rendering.\n */\nfunction owns(map: Record<string, IconComponent> | null | undefined, name: string): map is Record<string, IconComponent> {\n return !!map && Object.prototype.hasOwnProperty.call(map, name);\n}\n\nexport function Icon({ name, size = 16, className, from }: { name: IconName; size?: number; className?: string; from?: string }) {\n const { pack, weight } = useContext(IconCtx);\n\n const curatedMap = useCuratedMap(pack);\n const extendedMap = useExtendedMap(pack);\n const lucideCurated = useCuratedMap(\"lucide\");\n const lucideExtended = useExtendedMap(\"lucide\");\n\n // Ensure the active pack is loading (covers cases where Icon mounts\n // before IconProvider's useEffect fires, e.g. during SSR hydration)\n if (!curatedCache.has(pack) && !loadingPacks.has(pack)) {\n loadPack(pack);\n }\n\n let Comp: IconComponent | undefined | null = null;\n let renderPack: IconPack = pack;\n\n // Tier 1: curated map (available once pack chunk has loaded)\n if (owns(curatedMap, name)) {\n Comp = curatedMap[name];\n }\n\n // Tier 2: extended map (available after barrel import completes)\n if (!Comp && owns(extendedMap, name)) {\n Comp = extendedMap[name];\n }\n\n // Tier 3: lucide fallback (curated first, then extended)\n if (!Comp && pack !== \"lucide\") {\n const fallback = owns(lucideCurated, name) ? lucideCurated[name] : owns(lucideExtended, name) ? lucideExtended[name] : undefined;\n if (fallback) {\n Comp = fallback;\n renderPack = \"lucide\";\n }\n }\n\n const allMapsLoaded = !!(curatedMap && extendedMap && (pack === \"lucide\" || (lucideCurated && lucideExtended)));\n const missing = !Comp && allMapsLoaded;\n useEffect(() => {\n if (missing) warnOnce(\"Icon\", `\"${name}\" is not an icon name in the ${pack} pack${pack === \"lucide\" ? \"\" : \" or Lucide\"}, so ${from ?? \"it\"} draws nothing. Pass an icon name, or an element.`);\n }, [missing, name, pack, from]);\n\n if (!Comp) {\n if (allMapsLoaded) return null;\n return <span style={{ display: \"inline-block\", width: size, height: size }} className={className} />;\n }\n\n if (renderPack === \"phosphor\") {\n return <Comp size={size} weight={getPhosphorWeight(weight)} className={className} />;\n }\n\n if (renderPack === \"heroicons\") {\n return <Comp className={className} style={{ width: size, height: size, strokeWidth: weight }} />;\n }\n\n if (renderPack === \"tabler\") {\n return <Comp size={size} stroke={weight} className={className} />;\n }\n\n if (renderPack === \"feather\") {\n return <Comp size={size} className={className} strokeWidth={weight} />;\n }\n\n return <Comp size={size} strokeWidth={weight} className={className} />;\n}\n\n/* ── Icon slots ───────────────────────────────────────────────── */\n\n/**\n * What an icon slot takes (Sprint 25.17 A26): an icon name, drawn as the theme's icon at the slot's size, or an element,\n * drawn as given. `IconName` accepts any string, so text type-checks: in development a name the theme's pack lacks warns,\n * naming the slot, and draws nothing; the engine flags a literal that is no icon name (gs:icon-slot-not-an-icon).\n */\nexport type IconSlot = IconName | ReactElement | false | null | undefined;\n\n/** What an icon slot holds, drawn: a name as the theme's icon at `size`, anything else as given. */\nexport function slotIcon(icon: IconSlot | ReactNode, size: number, from: string): ReactNode {\n if (typeof icon === \"string\") {\n // \"\" is no icon (`saved ? \"check\" : \"\"`): nothing drawn, nothing warned\n if (!icon) return null;\n return ICON_NAME_SHAPE.test(icon) ? <Icon name={icon} size={size} from={from} /> : <NotAnIcon text={icon} from={from} />;\n }\n return icon;\n}\n\n/** The shape of an icon name: kebab case, as every pack's names are written (\"arrow-right\", \"file-text\"). */\nconst ICON_NAME_SHAPE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\n/**\n * Whether a slot draws something: an element, or a string shaped as an icon name. Text (\"→\", \"Save\") draws nothing, so\n * a button keeps its even padding for it (Sprint 25.17's review); a name the pack lacks still warns, once its maps load.\n */\nexport function slotDraws(icon: IconSlot | ReactNode): boolean {\n if (typeof icon === \"string\") return ICON_NAME_SHAPE.test(icon);\n return icon != null && icon !== false && icon !== true;\n}\n\n/** Text given to an icon slot: it draws nothing, and says so in development, naming the slot. */\nfunction NotAnIcon({ text, from }: { text: string; from: string }) {\n useEffect(() => {\n warnOnce(\"Icon\", `\"${text}\" is not an icon name, so ${from} draws nothing. Words go in the label; pass an icon name, or an element.`);\n }, [text, from]);\n return null;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/lib/dev-warn.ts","../../../showcase/src/lib/icon-pack-imports.ts","../../../showcase/src/lib/icons.tsx"],"names":[],"mappings":"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","file":"chunk-MKFWHWBK.js","sourcesContent":["// Bundlers set process.env.NODE_ENV. Where none did (a page with no build step), reading it throws and warnings stay off.\ndeclare const process: { env: { NODE_ENV?: string } };\nconst warned = new Set<string>();\n\n/** A mistake in a component's props, told to the developer once a page, in a development build. */\nexport function warnOnce(component: string, message: string): void {\n let dev = false;\n try {\n dev = process.env.NODE_ENV !== \"production\";\n } catch {\n dev = false;\n }\n const text = `${component}: ${message}`;\n if (!dev || warned.has(text)) return;\n warned.add(text);\n console.warn(text);\n}\n","/**\n * The import each icon pack takes, as an app writes it when it registers its theme's pack (Sprint 25.21 P1:\n * `registerIconPack('feather', () => import('react-icons/fi'))`). One table for the library's warning, the shells\n * `get_app_shell` writes and the engine's fix. Lucide is the library's own: every app installs it, as the fallback.\n * No React here, so the platform reads it as it reads the other showcase modules.\n */\nexport const ICON_PACK_IMPORTS = {\n feather: \"react-icons/fi\",\n heroicons: \"@heroicons/react/24/outline\",\n phosphor: \"@phosphor-icons/react\",\n tabler: \"@tabler/icons-react\",\n} as const;\n\n/** A pack an app registers: every pack but Lucide. */\nexport type RegisteredIconPack = keyof typeof ICON_PACK_IMPORTS;\n\n/** The two lines that register a pack, at the top of an app's shell, before any preloadPack. */\nexport function iconPackRegistration(pack: RegisteredIconPack): { importLine: string; call: string } {\n return {\n importLine: \"import { registerIconPack } from 'gridsmith-ui/icons'\",\n call: `registerIconPack('${pack}', () => import('${ICON_PACK_IMPORTS[pack]}'))`,\n };\n}\n","import { createContext, useContext, useEffect, useSyncExternalStore, type ReactElement, type ReactNode, type ComponentType } from \"react\";\nimport { warnOnce } from \"./dev-warn\";\nimport { iconPackRegistration, type RegisteredIconPack } from \"./icon-pack-imports\";\nimport type { PackLoad } from \"./icon-packs/types\";\n\n/* ── Types ────────────────────────────────────────────────────── */\n\n/**\n * Runtime list of curated icon names. The CuratedIconName type derives from\n * this array, so adding a name here extends autocomplete automatically.\n * Every name must have an alias (or auto-kebab match) in ALL five packs —\n * icon-completeness.test.tsx enforces this.\n */\nexport const CURATED_ICON_NAMES = [\n \"home\", \"folder\", \"chart\", \"settings\",\n \"chevron-right\", \"close\", \"plus\", \"search\",\n \"bell\", \"user\", \"check\", \"warning\", \"info\", \"error\",\n \"clock\", \"calendar\",\n \"bold\", \"italic\", \"underline\", \"strikethrough\",\n \"align-left\", \"align-center\", \"align-right\",\n \"list\", \"list-ordered\", \"list-checks\",\n \"link\", \"image\", \"table\", \"code\", \"quote\", \"minus\",\n \"superscript\", \"subscript\", \"highlight\", \"type\",\n \"chevron-up\", \"chevron-down\", \"chevron-left\", \"trash\",\n \"undo\", \"redo\",\n \"arrow-left\", \"grip-vertical\",\n \"mic\", \"paperclip\", \"send\",\n \"log-out\", \"edit\", \"menu\", \"more-horizontal\",\n \"star\", \"bookmark\", \"download\", \"upload\", \"sparkles\",\n \"file\", \"file-text\", \"eye\", \"eye-off\", \"copy\", \"external-link\", \"filter\", \"lock\",\n \"map-pin\",\n] as const;\n\ntype CuratedIconName = (typeof CURATED_ICON_NAMES)[number];\n\n/**\n * Curated names provide autocomplete and work identically across all 5 packs.\n * Any kebab-case string is also accepted — it resolves directly against the\n * active pack's native exports (e.g. \"clipboard-copy\" → Lucide's ClipboardCopy).\n */\nexport type IconName = CuratedIconName | (string & {});\n\nexport type IconPack = \"lucide\" | \"phosphor\" | \"heroicons\" | \"tabler\" | \"feather\";\n\ntype IconComponent = ComponentType<Record<string, unknown>>;\ntype IconMap = Record<string, IconComponent>;\n\n/* ── External store ──────────────────────────────────────────── */\n\ntype Subscriber = () => void;\nconst subscribers = new Set<Subscriber>();\nfunction notifySubscribers() {\n subscribers.forEach((fn) => fn());\n}\nfunction subscribe(cb: Subscriber): () => void {\n subscribers.add(cb);\n return () => { subscribers.delete(cb); };\n}\n\nconst curatedCache = new Map<IconPack, IconMap>();\nconst extendedCache = new Map<IconPack, IconMap>();\n\nfunction useCuratedMap(pack: IconPack): IconMap | null {\n return useSyncExternalStore(\n subscribe,\n () => curatedCache.get(pack) ?? null,\n () => null,\n );\n}\n\nfunction useExtendedMap(pack: IconPack): IconMap | null {\n return useSyncExternalStore(\n subscribe,\n () => extendedCache.get(pack) ?? null,\n () => null,\n );\n}\n\n/* ── Pack loading ────────────────────────────────────────────────\n Each pack is isolated in its own file under ./icon-packs/, and reads\n its package through an import handed to it: the app's own for its\n theme's pack (registerIconPack, Sprint 25.21 P1), the library's own\n for Lucide. No file the library publishes names a pack the app may\n not have installed, so no bundler looks for one: Next.js's webpack\n resolved every pack the library named, and failed the build.\n\n Loading is two-phase:\n 1. Curated map (50 static named imports) — available as soon as\n the pack chunk loads, cached and notified immediately.\n 2. Extended map (full barrel import + kebab-case iteration) —\n loaded in the background, cached and notified when ready. */\n\nconst loadingPacks = new Set<IconPack>();\nconst failedPacks = new Set<IconPack>();\n\ntype PackModule = {\n loadCurated(load: PackLoad): Promise<IconMap>;\n loadExtended(load: PackLoad): Promise<IconMap>;\n};\n\n/** Each pack's import: Lucide's is the library's own (every app installs it); the others are the app's, registered. */\nconst packImports = new Map<IconPack, PackLoad>([[\"lucide\", () => import(\"lucide-react\")]]);\n\n/**\n * The theme's icon pack, as the app's own import (Sprint 25.21 P1): `registerIconPack('feather', () =>\n * import('react-icons/fi'))` at the top of the shell, before any preloadPack. The library names no pack itself, so an\n * app's bundler only ever meets the pack the app installed. A pack drawn before it is registered draws Lucide's icons,\n * and draws its own once registered. Lucide needs no line.\n */\nexport function registerIconPack(pack: RegisteredIconPack, load: PackLoad): void {\n packImports.set(pack, load);\n // a draw that met the pack unregistered loads it now: its icons redraw once the pack's map arrives (a notice alone\n // changes no snapshot, so nothing would redraw to ask)\n if (failedPacks.delete(pack)) void loadPack(pack);\n}\n\n/** The npm package each pack needs — named in the error when a pack is missing. */\nconst PEER_PACKAGE: Record<IconPack, string> = {\n lucide: \"lucide-react\",\n phosphor: \"@phosphor-icons/react\",\n heroicons: \"@heroicons/react\",\n tabler: \"@tabler/icons-react\",\n feather: \"react-icons\",\n};\n\nasync function loadPack(pack: IconPack): Promise<void> {\n if (curatedCache.has(pack) || loadingPacks.has(pack) || failedPacks.has(pack)) return;\n loadingPacks.add(pack);\n\n // Each pack module reaches its package only through the import handed to it\n // (see icon-packs/*.ts), so the chunk import below always succeeds and it is\n // loadCurated() that rejects when the package is not installed.\n const load = packImports.get(pack);\n if (!load) {\n // not registered: Lucide's icons stand in (Icon's third tier), and the developer is told the line to add\n failedPacks.add(pack);\n loadingPacks.delete(pack);\n const lines = iconPackRegistration(pack as RegisteredIconPack);\n warnOnce(\"IconProvider\", `the ${pack} icon pack isn't registered, so its icons are drawn from Lucide. At the top of the shell, before any preloadPack: ${lines.importLine}; ${lines.call}`);\n return;\n }\n let mod: PackModule;\n let curated: IconMap;\n try {\n switch (pack) {\n case \"lucide\": mod = await import(\"./icon-packs/lucide\"); break;\n case \"phosphor\": mod = await import(\"./icon-packs/phosphor\"); break;\n case \"heroicons\": mod = await import(\"./icon-packs/heroicons\"); break;\n case \"tabler\": mod = await import(\"./icon-packs/tabler\"); break;\n case \"feather\": mod = await import(\"./icon-packs/feather\"); break;\n }\n curated = await mod!.loadCurated(load);\n } catch {\n loadingPacks.delete(pack);\n failedPacks.add(pack);\n console.error(`gridsmith-ui: ${PEER_PACKAGE[pack]} is not installed. Run: npm install ${PEER_PACKAGE[pack]}`);\n return;\n }\n\n curatedCache.set(pack, curated);\n notifySubscribers();\n\n mod!.loadExtended(load).then((extended) => {\n extendedCache.set(pack, extended);\n notifySubscribers();\n }).catch(() => {\n // Extended map failed (e.g. network error loading the full barrel).\n // Curated icons still work; extended names will not resolve.\n });\n}\n\n/** A pack's registered import, for the tests that load the packs directly; they register them first. */\nfunction importOf(pack: IconPack): PackLoad {\n const load = packImports.get(pack);\n if (!load) throw new Error(`gridsmith-ui: register the ${pack} icon pack first (registerIconPack)`);\n return load;\n}\n\n/** Exported for the icon-completeness test — not part of the public API. */\nexport const packLoaders: Record<IconPack, {\n curated: () => Promise<IconMap>;\n extended: () => Promise<IconMap>;\n}> = {\n lucide: { curated: () => import(\"./icon-packs/lucide\").then((m) => m.loadCurated(importOf(\"lucide\"))), extended: () => import(\"./icon-packs/lucide\").then((m) => m.loadExtended(importOf(\"lucide\"))) },\n phosphor: { curated: () => import(\"./icon-packs/phosphor\").then((m) => m.loadCurated(importOf(\"phosphor\"))), extended: () => import(\"./icon-packs/phosphor\").then((m) => m.loadExtended(importOf(\"phosphor\"))) },\n heroicons: { curated: () => import(\"./icon-packs/heroicons\").then((m) => m.loadCurated(importOf(\"heroicons\"))), extended: () => import(\"./icon-packs/heroicons\").then((m) => m.loadExtended(importOf(\"heroicons\"))) },\n tabler: { curated: () => import(\"./icon-packs/tabler\").then((m) => m.loadCurated(importOf(\"tabler\"))), extended: () => import(\"./icon-packs/tabler\").then((m) => m.loadExtended(importOf(\"tabler\"))) },\n feather: { curated: () => import(\"./icon-packs/feather\").then((m) => m.loadCurated(importOf(\"feather\"))), extended: () => import(\"./icon-packs/feather\").then((m) => m.loadExtended(importOf(\"feather\"))) },\n};\n\n/* ── Context ──────────────────────────────────────────────────── */\n\ninterface IconContextValue {\n pack: IconPack;\n weight: number;\n}\n\nconst IconCtx = createContext<IconContextValue>({ pack: \"lucide\", weight: 1.5 });\n\n/**\n * Sets the icon pack and stroke weight for every Icon inside it, and starts loading the pack. The app shell's generated\n * code puts it around the app with the theme's pack, so a page doesn't add its own.\n */\nexport function IconProvider({ pack, weight, children }: { pack: IconPack; weight: number; children: ReactNode }) {\n useEffect(() => {\n loadPack(pack);\n if (pack !== \"lucide\") loadPack(\"lucide\");\n }, [pack]);\n\n return <IconCtx.Provider value={{ pack, weight }}>{children}</IconCtx.Provider>;\n}\n\n/**\n * Start loading a pack's icon chunk before React mounts. Call this in your\n * app's entry point or shell for the fastest possible cold start, after the\n * pack is registered (every pack but Lucide, Sprint 25.21 P1):\n *\n * import { preloadPack, registerIconPack } from 'gridsmith-ui/icons'\n * registerIconPack('feather', () => import('react-icons/fi'))\n * preloadPack('feather')\n */\nexport function preloadPack(pack: IconPack): void {\n loadPack(pack);\n}\n\n/* ── Phosphor weight mapping ──────────────────────────────────── */\n\n/**\n * A stroke weight maps to a stroke weight only. `fill` and `duotone` change the\n * glyph itself (Phosphor's filled Check is a check inside a filled square), so\n * a theme's heaviest stroke must never reach them — the Sprint 22 bench found\n * every tick on a 2.5-weight theme rendered as a filled box (14 Sep 2026).\n */\nexport function getPhosphorWeight(numericWeight: number): \"thin\" | \"light\" | \"regular\" | \"bold\" {\n if (numericWeight <= 0.75) return \"thin\";\n if (numericWeight <= 1.25) return \"light\";\n if (numericWeight <= 1.75) return \"regular\";\n return \"bold\";\n}\n\n/* ── Icon component ───────────────────────────────────────────── */\n\n/**\n * `from`: the component slot that drew the icon (\"Button's iconLeft\"), named in the development warning when the theme's\n * pack has no icon by that name. A name no pack has draws nothing (Sprint 25.17 A26: an arrow or a word passed as an\n * icon was printed as text before slots took names).\n */\n/**\n * Whether a map holds an icon of its own by this name, never one its prototype lends: a slot now takes any string, and\n * \"constructor\", \"toString\" or \"__proto__\" read off a plain object drew junk or threw (Sprint 25.17's review). The icon\n * is then read off the map itself, so the compiler sees a component the map holds, not one made while rendering.\n */\nfunction owns(map: Record<string, IconComponent> | null | undefined, name: string): map is Record<string, IconComponent> {\n return !!map && Object.prototype.hasOwnProperty.call(map, name);\n}\n\n/**\n * An icon by name, drawn from the pack the IconProvider around it sets (the theme's, through the app shell), with Lucide\n * as the fallback when the pack lacks the name; `size` in pixels, 16 by default. A name neither has draws nothing and\n * warns once in development, where `from` names the caller.\n */\nexport function Icon({ name, size = 16, className, from }: { name: IconName; size?: number; className?: string; from?: string }) {\n const { pack, weight } = useContext(IconCtx);\n\n const curatedMap = useCuratedMap(pack);\n const extendedMap = useExtendedMap(pack);\n const lucideCurated = useCuratedMap(\"lucide\");\n const lucideExtended = useExtendedMap(\"lucide\");\n\n // Ensure the active pack is loading (covers cases where Icon mounts\n // before IconProvider's useEffect fires, e.g. during SSR hydration)\n if (!curatedCache.has(pack) && !loadingPacks.has(pack)) {\n loadPack(pack);\n }\n\n let Comp: IconComponent | undefined | null = null;\n let renderPack: IconPack = pack;\n\n // Tier 1: curated map (available once pack chunk has loaded)\n if (owns(curatedMap, name)) {\n Comp = curatedMap[name];\n }\n\n // Tier 2: extended map (available after barrel import completes)\n if (!Comp && owns(extendedMap, name)) {\n Comp = extendedMap[name];\n }\n\n // Tier 3: lucide fallback (curated first, then extended)\n if (!Comp && pack !== \"lucide\") {\n const fallback = owns(lucideCurated, name) ? lucideCurated[name] : owns(lucideExtended, name) ? lucideExtended[name] : undefined;\n if (fallback) {\n Comp = fallback;\n renderPack = \"lucide\";\n }\n }\n\n const allMapsLoaded = !!(curatedMap && extendedMap && (pack === \"lucide\" || (lucideCurated && lucideExtended)));\n const missing = !Comp && allMapsLoaded;\n useEffect(() => {\n if (missing) warnOnce(\"Icon\", `\"${name}\" is not an icon name in the ${pack} pack${pack === \"lucide\" ? \"\" : \" or Lucide\"}, so ${from ?? \"it\"} draws nothing. Pass an icon name, or an element.`);\n }, [missing, name, pack, from]);\n\n if (!Comp) {\n if (allMapsLoaded) return null;\n return <span style={{ display: \"inline-block\", width: size, height: size }} className={className} />;\n }\n\n if (renderPack === \"phosphor\") {\n return <Comp size={size} weight={getPhosphorWeight(weight)} className={className} />;\n }\n\n if (renderPack === \"heroicons\") {\n return <Comp className={className} style={{ width: size, height: size, strokeWidth: weight }} />;\n }\n\n if (renderPack === \"tabler\") {\n return <Comp size={size} stroke={weight} className={className} />;\n }\n\n if (renderPack === \"feather\") {\n return <Comp size={size} className={className} strokeWidth={weight} />;\n }\n\n return <Comp size={size} strokeWidth={weight} className={className} />;\n}\n\n/* ── Icon slots ───────────────────────────────────────────────── */\n\n/**\n * What an icon slot takes (Sprint 25.17 A26): an icon name, drawn as the theme's icon at the slot's size, or an element,\n * drawn as given. `IconName` accepts any string, so text type-checks: in development a name the theme's pack lacks warns,\n * naming the slot, and draws nothing; the engine flags a literal that is no icon name (gs:icon-slot-not-an-icon).\n */\nexport type IconSlot = IconName | ReactElement | false | null | undefined;\n\n/** What an icon slot holds, drawn: a name as the theme's icon at `size`, anything else as given. */\nexport function slotIcon(icon: IconSlot | ReactNode, size: number, from: string): ReactNode {\n if (typeof icon === \"string\") {\n // \"\" is no icon (`saved ? \"check\" : \"\"`): nothing drawn, nothing warned\n if (!icon) return null;\n return ICON_NAME_SHAPE.test(icon) ? <Icon name={icon} size={size} from={from} /> : <NotAnIcon text={icon} from={from} />;\n }\n return icon;\n}\n\n/** The shape of an icon name: kebab case, as every pack's names are written (\"arrow-right\", \"file-text\"). */\nconst ICON_NAME_SHAPE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\n/**\n * Whether a slot draws something: an element, or a string shaped as an icon name. Text (\"→\", \"Save\") draws nothing, so\n * a button keeps its even padding for it (Sprint 25.17's review); a name the pack lacks still warns, once its maps load.\n */\nexport function slotDraws(icon: IconSlot | ReactNode): boolean {\n if (typeof icon === \"string\") return ICON_NAME_SHAPE.test(icon);\n return icon != null && icon !== false && icon !== true;\n}\n\n/** Text given to an icon slot: it draws nothing, and says so in development, naming the slot. */\nfunction NotAnIcon({ text, from }: { text: string; from: string }) {\n useEffect(() => {\n warnOnce(\"Icon\", `\"${text}\" is not an icon name, so ${from} draws nothing. Words go in the label; pass an icon name, or an element.`);\n }, [text, from]);\n return null;\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useTextOverflow, Tooltip } from './chunk-
|
|
3
|
-
import { cn } from './chunk-
|
|
2
|
+
import { useTextOverflow, Tooltip } from './chunk-37WOC7F7.js';
|
|
3
|
+
import { cn } from './chunk-JTU7OBYJ.js';
|
|
4
4
|
import { useRef, useState, useLayoutEffect, Fragment } from 'react';
|
|
5
5
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
6
|
|
|
@@ -113,5 +113,5 @@ function useCardsSwitch(narrowScreen, cardsBelow = CARDS_BELOW, remeasure) {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
export { CARDS_BELOW, CardValue, inferColumnKinds, kindOfRenderedText, useCardsSwitch };
|
|
116
|
-
//# sourceMappingURL=chunk-
|
|
117
|
-
//# sourceMappingURL=chunk-
|
|
116
|
+
//# sourceMappingURL=chunk-QNHVPE2B.js.map
|
|
117
|
+
//# sourceMappingURL=chunk-QNHVPE2B.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../showcase/src/lib/table-utils.ts","../../../showcase/src/lib/card-cell.tsx","../../../showcase/src/lib/use-cards-switch.ts"],"names":[],"mappings":"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","file":"chunk-BRAXJEEP.js","sourcesContent":["/** Shared column-kind inference for Table and DataGrid. */\n\n/**\n * What a column holds, which decides how its cells lay out: numbers and dates shrink to their content and stay whole,\n * an identifier (a long run of digits: a barcode, an ID) may wrap anywhere, an email truncates, text wraps at spaces.\n */\nexport type ColumnKind = \"date\" | \"number\" | \"email\" | \"label\" | \"text\" | \"identifier\";\n\nconst DATE_ISO = /^\\d{4}-\\d{2}-\\d{2}$/;\nconst DATE_US = /^\\d{1,2}\\/\\d{1,2}\\/\\d{4}$/;\n// a month's name or its short form, with or without a full stop: \"Jan\", \"Sept\", \"Sep.\", \"September\" (Sprint 25.13 A35)\nconst MONTH = \"[A-Z][a-z]{2,8}\\\\.?\";\nconst DATE_TEXT_MDY = new RegExp(`^${MONTH}\\\\s+\\\\d{1,2},?\\\\s+\\\\d{4}$`); // \"Jan 12, 2024\" or \"Sept 12 2024\"\nconst DATE_TEXT_DMY = new RegExp(`^\\\\d{1,2}\\\\s+${MONTH}\\\\s+\\\\d{4}$`); // \"12 Jan 2024\", \"24 Sept 2026\"\n// a date this year, with no year: \"Sep 16\", \"16 Sept\" (the review of 30 September). Only a month's own name, so \"Room 12\"\n// isn't a date.\nconst MONTH_NAME = \"(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|June?|July?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\\\\.?\";\nconst DATE_TEXT_MD = new RegExp(`^${MONTH_NAME}\\\\s+\\\\d{1,2}$`);\nconst DATE_TEXT_DM = new RegExp(`^\\\\d{1,2}\\\\s+${MONTH_NAME}$`);\n// a number, with a currency before or a unit after it: \"$1,200\", \"12%\", \"18 KB\", \"1.2 MB\", \"250 ms\" (Sprint 25.13 A35)\nconst NUMBER_RE = /^[$€£¥]?\\s?[\\d,]+\\.?\\d*\\s?(?:%|[KMGTP]i?B|B|bytes?|ms|s|sec|min|h|hrs?|kg|g|km|m|°[CF])?$/i;\n// a long run of digits is an identifier, never a quantity: a barcode or an account number (Sprint 25.13 A35)\nconst IDENTIFIER_RE = /^\\d{13,}$/;\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) || DATE_TEXT_MD.test(v) || DATE_TEXT_DM.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 // A long run of digits, as text or as a number too large to be one: an identifier\n if (present.every((v) => (typeof v === \"string\" && IDENTIFIER_RE.test(v)) || (typeof v === \"number\" && Math.abs(v) >= 1e13 && Number.isInteger(v)))) return \"identifier\";\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 * The kind of a column from the words its cells show (Sprint 25.13 A35): a column of elements has no kind from its\n * values, so the Table reads what they render. Only a date or a number counts from rendered text, to keep it whole.\n */\nexport function kindOfRenderedText(texts: string[]): ColumnKind | undefined {\n const kind = detectKind(texts.map((t) => t.trim()).filter(Boolean));\n return kind === \"date\" || kind === \"number\" ? kind : undefined;\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","/**\n * The value cell of a Table or DataGrid in card mode (Sprint 25.4 C-2, C-4).\n *\n * A card row is `label | value`, the value right-aligned. Three things a value must do on a phone:\n * - wrap a long single string at sensible points first (after @, ., /, -) and mid-word only as a last resort\n * (`overflow-wrap: break-word` breaks inside a word only when the word alone cannot fit a line);\n * - clamp after two lines with the full text in a tooltip;\n * - reach the builder's own markup: a nested flex row (icon + name) keeps `min-width: auto` and overflows unless\n * every descendant is told `min-width: 0` and given the same break rule.\n *\n * A cell that holds an Avatar stacks: the avatar above, the primary text, then the secondary, aligned to the value\n * column. The rule is CSS (`:has([data-avatar])`) on the value cell's direct child, so a hand-rolled\n * `<div class=\"flex\"><Avatar/><div>…</div></div>` stacks the same way EntityCell does.\n */\nimport { Fragment, type ReactNode } from \"react\";\nimport { cn } from \"./utils\";\nimport { Tooltip } from \"../components/Tooltip\";\nimport { useTextOverflow } from \"./use-text-overflow\";\n\nexport const CARD_VALUE_CLASS = cn(\n \"min-w-0 text-right text-[var(--ds-text-primary)]\",\n \"[overflow-wrap:break-word] [&_*]:min-w-0 [&_*]:[overflow-wrap:break-word]\",\n // A hand-rolled avatar cell (div > Avatar + text) keeps its row and sits against the value column's right edge,\n // like EntityCell (round 7: the stacked cell was replaced).\n \"[&:has([data-avatar])>*]:flex [&:has([data-avatar])>*]:items-center [&:has([data-avatar])>*]:justify-end [&:has([data-avatar])>*]:text-right\",\n);\n\nconst BREAK_AFTER = /([@./-])/g;\n\n/** The string with a soft break opportunity after each @, ., / and -, so a long email or path wraps there first. */\nexport function breakable(text: string): ReactNode {\n const parts = text.split(BREAK_AFTER);\n if (parts.length === 1) return text;\n return parts.map((part, i) => (\n <Fragment key={i}>{part}{i % 2 === 1 && <wbr />}</Fragment>\n ));\n}\n\n/** A string value: sensible breaks, two lines, the full text as a tooltip once it clamps. */\nexport function CardStringValue({ text }: { text: string }) {\n const { ref, isTruncated } = useTextOverflow({ lines: 2, content: text });\n const el = <span ref={ref} className=\"block line-clamp-2\">{breakable(text)}</span>;\n return isTruncated ? <Tooltip content={text}>{el}</Tooltip> : el;\n}\n\nexport function CardValue({ value, id }: { value: ReactNode; id?: string }) {\n return (\n <span id={id} className={CARD_VALUE_CLASS}>\n {typeof value === \"string\" ? <CardStringValue text={value} /> : value}\n </span>\n );\n}\n","import { useLayoutEffect, useRef, useState } from \"react\";\n\n/**\n * Sprint 25.13 A35: below this width of its own, about a phone's, a table that doesn't fit shows cards; it goes back to\n * a table once it has the room the table needed, or this much more, so a width near the line can't flip it back and\n * forth.\n */\nexport const CARDS_BELOW = 440;\nexport const CARDS_HYSTERESIS = 40;\n\n/**\n * Whether a table (Table, DataGrid) shows cards (Sprint 25.13 A35): on a narrow screen, as before, and anywhere else\n * only when its own width is under `cardsBelow` and the table doesn't fit it — measured on the element `rootRef` holds,\n * never against the screen's breakpoint, so a table in a pane, a drawer or a dialog stays a table and scrolls sideways,\n * and a table that fits stays a table however narrow its box. 0 never switches by width. The root is whichever element\n * renders, so the measure follows the mode and `remeasure` (a titled table's root differs). A width of 0 (not laid out\n * yet, or no layout at all) decides nothing.\n *\n * The review of 30 September: the switch measured the root in both modes, and in a box that sizes to its content (a\n * flex item, an inline-block, a grid item placed at its start) the table's width said cards and the cards' width said\n * table, so it flipped on every commit until React stopped the page. It now decides each way from what the other mode\n * can't change: a table goes to cards when it overflows its frame (a box sized to its content never makes it overflow),\n * and cards go back once the root has the width the table needed then, which the cards can't make it overflow again.\n */\nexport function useCardsSwitch(narrowScreen: boolean, cardsBelow: number = CARDS_BELOW, remeasure?: unknown) {\n const rootRef = useRef<HTMLElement | null>(null);\n const [narrowBox, setNarrowBox] = useState(false);\n // the root's width at which the table fits its frame, read when it went to cards\n const needed = useRef(0);\n const cards = narrowScreen || narrowBox;\n useLayoutEffect(() => {\n const root = rootRef.current;\n if (!root || cardsBelow <= 0) { setNarrowBox(false); return; }\n const measure = () => {\n // the width of the root's place: the cards' list reaches past its box by the room it keeps for a card's keyboard\n // outline, its margins taken back (Sprint 30, P3), which mustn't read as more width than the table had there\n const style = getComputedStyle(root);\n const width = root.getBoundingClientRect().width + (parseFloat(style.marginLeft) || 0) + (parseFloat(style.marginRight) || 0);\n if (width <= 0) return;\n if (narrowBox) {\n if (width >= Math.min(needed.current, cardsBelow + CARDS_HYSTERESIS)) setNarrowBox(false);\n return;\n }\n // cards shown for a narrow screen measure nothing: the table isn't drawn to read\n if (cards) return;\n const frame = root.querySelector<HTMLElement>(\"[data-table-scroll]\") ?? root;\n const over = frame.scrollWidth - frame.clientWidth;\n if (width < cardsBelow && over > 1) {\n needed.current = width + over;\n setNarrowBox(true);\n }\n };\n measure();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(measure);\n observer.observe(root);\n // the table's own width too: rows arriving can make it overflow a frame that keeps its size\n const table = root.querySelector(\"[data-table-scroll] > *\");\n if (table) observer.observe(table);\n return () => observer.disconnect();\n }, [cardsBelow, cards, narrowBox, remeasure]);\n return { cards, rootRef };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/lib/table-utils.ts","../../../showcase/src/lib/card-cell.tsx","../../../showcase/src/lib/use-cards-switch.ts"],"names":[],"mappings":"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","file":"chunk-QNHVPE2B.js","sourcesContent":["/** Shared column-kind inference for Table and DataGrid. */\n\n/**\n * What a column holds, which decides how its cells lay out: numbers and dates shrink to their content and stay whole,\n * an identifier (a long run of digits: a barcode, an ID) may wrap anywhere, an email truncates, text wraps at spaces.\n */\nexport type ColumnKind = \"date\" | \"number\" | \"email\" | \"label\" | \"text\" | \"identifier\";\n\nconst DATE_ISO = /^\\d{4}-\\d{2}-\\d{2}$/;\nconst DATE_US = /^\\d{1,2}\\/\\d{1,2}\\/\\d{4}$/;\n// a month's name or its short form, with or without a full stop: \"Jan\", \"Sept\", \"Sep.\", \"September\" (Sprint 25.13 A35)\nconst MONTH = \"[A-Z][a-z]{2,8}\\\\.?\";\nconst DATE_TEXT_MDY = new RegExp(`^${MONTH}\\\\s+\\\\d{1,2},?\\\\s+\\\\d{4}$`); // \"Jan 12, 2024\" or \"Sept 12 2024\"\nconst DATE_TEXT_DMY = new RegExp(`^\\\\d{1,2}\\\\s+${MONTH}\\\\s+\\\\d{4}$`); // \"12 Jan 2024\", \"24 Sept 2026\"\n// a date this year, with no year: \"Sep 16\", \"16 Sept\" (the review of 30 September). Only a month's own name, so \"Room 12\"\n// isn't a date.\nconst MONTH_NAME = \"(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|June?|July?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\\\\.?\";\nconst DATE_TEXT_MD = new RegExp(`^${MONTH_NAME}\\\\s+\\\\d{1,2}$`);\nconst DATE_TEXT_DM = new RegExp(`^\\\\d{1,2}\\\\s+${MONTH_NAME}$`);\n// a number, with a currency before or a unit after it: \"$1,200\", \"12%\", \"18 KB\", \"1.2 MB\", \"250 ms\" (Sprint 25.13 A35)\nconst NUMBER_RE = /^[$€£¥]?\\s?[\\d,]+\\.?\\d*\\s?(?:%|[KMGTP]i?B|B|bytes?|ms|s|sec|min|h|hrs?|kg|g|km|m|°[CF])?$/i;\n// a long run of digits is an identifier, never a quantity: a barcode or an account number (Sprint 25.13 A35)\nconst IDENTIFIER_RE = /^\\d{13,}$/;\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) || DATE_TEXT_MD.test(v) || DATE_TEXT_DM.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 // A long run of digits, as text or as a number too large to be one: an identifier\n if (present.every((v) => (typeof v === \"string\" && IDENTIFIER_RE.test(v)) || (typeof v === \"number\" && Math.abs(v) >= 1e13 && Number.isInteger(v)))) return \"identifier\";\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 * The kind of a column from the words its cells show (Sprint 25.13 A35): a column of elements has no kind from its\n * values, so the Table reads what they render. Only a date or a number counts from rendered text, to keep it whole.\n */\nexport function kindOfRenderedText(texts: string[]): ColumnKind | undefined {\n const kind = detectKind(texts.map((t) => t.trim()).filter(Boolean));\n return kind === \"date\" || kind === \"number\" ? kind : undefined;\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","/**\n * The value cell of a Table or DataGrid in card mode (Sprint 25.4 C-2, C-4).\n *\n * A card row is `label | value`, the value right-aligned. Three things a value must do on a phone:\n * - wrap a long single string at sensible points first (after @, ., /, -) and mid-word only as a last resort\n * (`overflow-wrap: break-word` breaks inside a word only when the word alone cannot fit a line);\n * - clamp after two lines with the full text in a tooltip;\n * - reach the builder's own markup: a nested flex row (icon + name) keeps `min-width: auto` and overflows unless\n * every descendant is told `min-width: 0` and given the same break rule.\n *\n * A cell that holds an Avatar stacks: the avatar above, the primary text, then the secondary, aligned to the value\n * column. The rule is CSS (`:has([data-avatar])`) on the value cell's direct child, so a hand-rolled\n * `<div class=\"flex\"><Avatar/><div>…</div></div>` stacks the same way EntityCell does.\n */\nimport { Fragment, type ReactNode } from \"react\";\nimport { cn } from \"./utils\";\nimport { Tooltip } from \"../components/Tooltip\";\nimport { useTextOverflow } from \"./use-text-overflow\";\n\nexport const CARD_VALUE_CLASS = cn(\n \"min-w-0 text-right text-[var(--ds-text-primary)]\",\n \"[overflow-wrap:break-word] [&_*]:min-w-0 [&_*]:[overflow-wrap:break-word]\",\n // A hand-rolled avatar cell (div > Avatar + text) keeps its row and sits against the value column's right edge,\n // like EntityCell (round 7: the stacked cell was replaced).\n \"[&:has([data-avatar])>*]:flex [&:has([data-avatar])>*]:items-center [&:has([data-avatar])>*]:justify-end [&:has([data-avatar])>*]:text-right\",\n);\n\nconst BREAK_AFTER = /([@./-])/g;\n\n/** The string with a soft break opportunity after each @, ., / and -, so a long email or path wraps there first. */\nexport function breakable(text: string): ReactNode {\n const parts = text.split(BREAK_AFTER);\n if (parts.length === 1) return text;\n return parts.map((part, i) => (\n <Fragment key={i}>{part}{i % 2 === 1 && <wbr />}</Fragment>\n ));\n}\n\n/** A string value: sensible breaks, two lines, the full text as a tooltip once it clamps. */\nexport function CardStringValue({ text }: { text: string }) {\n const { ref, isTruncated } = useTextOverflow({ lines: 2, content: text });\n const el = <span ref={ref} className=\"block line-clamp-2\">{breakable(text)}</span>;\n return isTruncated ? <Tooltip content={text}>{el}</Tooltip> : el;\n}\n\nexport function CardValue({ value, id }: { value: ReactNode; id?: string }) {\n return (\n <span id={id} className={CARD_VALUE_CLASS}>\n {typeof value === \"string\" ? <CardStringValue text={value} /> : value}\n </span>\n );\n}\n","import { useLayoutEffect, useRef, useState } from \"react\";\n\n/**\n * Sprint 25.13 A35: below this width of its own, about a phone's, a table that doesn't fit shows cards; it goes back to\n * a table once it has the room the table needed, or this much more, so a width near the line can't flip it back and\n * forth.\n */\nexport const CARDS_BELOW = 440;\nexport const CARDS_HYSTERESIS = 40;\n\n/**\n * Whether a table (Table, DataGrid) shows cards (Sprint 25.13 A35): on a narrow screen, as before, and anywhere else\n * only when its own width is under `cardsBelow` and the table doesn't fit it — measured on the element `rootRef` holds,\n * never against the screen's breakpoint, so a table in a pane, a drawer or a dialog stays a table and scrolls sideways,\n * and a table that fits stays a table however narrow its box. 0 never switches by width. The root is whichever element\n * renders, so the measure follows the mode and `remeasure` (a titled table's root differs). A width of 0 (not laid out\n * yet, or no layout at all) decides nothing.\n *\n * The review of 30 September: the switch measured the root in both modes, and in a box that sizes to its content (a\n * flex item, an inline-block, a grid item placed at its start) the table's width said cards and the cards' width said\n * table, so it flipped on every commit until React stopped the page. It now decides each way from what the other mode\n * can't change: a table goes to cards when it overflows its frame (a box sized to its content never makes it overflow),\n * and cards go back once the root has the width the table needed then, which the cards can't make it overflow again.\n */\nexport function useCardsSwitch(narrowScreen: boolean, cardsBelow: number = CARDS_BELOW, remeasure?: unknown) {\n const rootRef = useRef<HTMLElement | null>(null);\n const [narrowBox, setNarrowBox] = useState(false);\n // the root's width at which the table fits its frame, read when it went to cards\n const needed = useRef(0);\n const cards = narrowScreen || narrowBox;\n useLayoutEffect(() => {\n const root = rootRef.current;\n if (!root || cardsBelow <= 0) { setNarrowBox(false); return; }\n const measure = () => {\n // the width of the root's place: the cards' list reaches past its box by the room it keeps for a card's keyboard\n // outline, its margins taken back (Sprint 30, P3), which mustn't read as more width than the table had there\n const style = getComputedStyle(root);\n const width = root.getBoundingClientRect().width + (parseFloat(style.marginLeft) || 0) + (parseFloat(style.marginRight) || 0);\n if (width <= 0) return;\n if (narrowBox) {\n if (width >= Math.min(needed.current, cardsBelow + CARDS_HYSTERESIS)) setNarrowBox(false);\n return;\n }\n // cards shown for a narrow screen measure nothing: the table isn't drawn to read\n if (cards) return;\n const frame = root.querySelector<HTMLElement>(\"[data-table-scroll]\") ?? root;\n const over = frame.scrollWidth - frame.clientWidth;\n if (width < cardsBelow && over > 1) {\n needed.current = width + over;\n setNarrowBox(true);\n }\n };\n measure();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(measure);\n observer.observe(root);\n // the table's own width too: rows arriving can make it overflow a frame that keeps its size\n const table = root.querySelector(\"[data-table-scroll] > *\");\n if (table) observer.observe(table);\n return () => observer.disconnect();\n }, [cardsBelow, cards, narrowBox, remeasure]);\n return { cards, rootRef };\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useTextOverflow,
|
|
3
|
-
import { Icon } from './chunk-
|
|
4
|
-
import { cn } from './chunk-
|
|
2
|
+
import { useTextOverflow, AutoTooltip } from './chunk-37WOC7F7.js';
|
|
3
|
+
import { Icon } from './chunk-MKFWHWBK.js';
|
|
4
|
+
import { cn } from './chunk-JTU7OBYJ.js';
|
|
5
5
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
7
|
var severityToVariant = {
|
|
@@ -93,11 +93,11 @@ function Badge({ variant = "default", severity, size = "md", color, iconLeft, ic
|
|
|
93
93
|
}
|
|
94
94
|
);
|
|
95
95
|
if (isTruncated) {
|
|
96
|
-
return /* @__PURE__ */ jsx(
|
|
96
|
+
return /* @__PURE__ */ jsx(AutoTooltip, { content: children, children: badge });
|
|
97
97
|
}
|
|
98
98
|
return badge;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
export { Badge };
|
|
102
|
-
//# sourceMappingURL=chunk-
|
|
103
|
-
//# sourceMappingURL=chunk-
|
|
102
|
+
//# sourceMappingURL=chunk-RECCCA7Z.js.map
|
|
103
|
+
//# sourceMappingURL=chunk-RECCCA7Z.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/components/Badge.tsx"],"names":[],"mappings":"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","file":"chunk-RECCCA7Z.js","sourcesContent":["import { cn } from \"../lib/utils\";\nimport { Icon, type IconName } from \"../lib/icons\";\nimport { AutoTooltip } 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-text)] 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-text)] 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 // Sprint 25.13 A1: a card header reads this to put a badge in its actions beside the title (D1a), and a card grid\n // to size from what its headers hold (A2)\n data-gs-badge=\"\"\n className={cn(\n \"inline-flex items-center font-medium max-w-full whitespace-nowrap shrink-0\",\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\" from=\"Badge's iconLeft\" />}\n {maxWidth ? (\n <span ref={truncRef} className=\"truncate\">{children}</span>\n ) : (\n children\n )}\n {iconRight && <Icon name={iconRight} size={iconSize} className=\"shrink-0\" from=\"Badge's iconRight\" />}\n </span>\n );\n\n if (isTruncated) {\n return <AutoTooltip content={children}>{badge}</AutoTooltip>;\n }\n return badge;\n}\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { elementType, formatLocale } from './chunk-OYNUU346.js';
|
|
3
|
-
import {
|
|
4
|
-
import { slotDraws, slotIcon, warnOnce } from './chunk-
|
|
5
|
-
import { cn, FOCUS_RING } from './chunk-
|
|
3
|
+
import { AutoTooltip, NATIVE_TITLE } from './chunk-37WOC7F7.js';
|
|
4
|
+
import { slotDraws, slotIcon, warnOnce } from './chunk-MKFWHWBK.js';
|
|
5
|
+
import { cn, FOCUS_RING } from './chunk-JTU7OBYJ.js';
|
|
6
6
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
7
|
import { createContext, forwardRef, useContext, isValidElement, useMemo } from 'react';
|
|
8
8
|
|
|
@@ -89,7 +89,8 @@ var Button = forwardRef(function Button2({ variant = "default", size: sizeProp,
|
|
|
89
89
|
e.preventDefault();
|
|
90
90
|
} : onClick;
|
|
91
91
|
const ariaLabel = props["aria-label"];
|
|
92
|
-
const
|
|
92
|
+
const drawsTooltip = isIconSize && !!ariaLabel;
|
|
93
|
+
const title = props.title;
|
|
93
94
|
const btn = /* @__PURE__ */ jsxs(
|
|
94
95
|
"button",
|
|
95
96
|
{
|
|
@@ -135,11 +136,12 @@ var Button = forwardRef(function Button2({ variant = "default", size: sizeProp,
|
|
|
135
136
|
]
|
|
136
137
|
}
|
|
137
138
|
);
|
|
138
|
-
if (
|
|
139
|
-
return /* @__PURE__ */ jsx(
|
|
139
|
+
if (drawsTooltip) {
|
|
140
|
+
return /* @__PURE__ */ jsx(AutoTooltip, { content: title ?? ariaLabel, children: btn });
|
|
140
141
|
}
|
|
141
142
|
return btn;
|
|
142
143
|
});
|
|
144
|
+
Button[NATIVE_TITLE] = true;
|
|
143
145
|
function getCssPadding(size) {
|
|
144
146
|
switch (size) {
|
|
145
147
|
case "xs":
|
|
@@ -245,5 +247,5 @@ function preferenceActionKey(label) {
|
|
|
245
247
|
}
|
|
246
248
|
|
|
247
249
|
export { Button, ButtonSizeContext, ControlSizeContext, DAY, HOUR, MINUTE, PREFERENCE_HOUSE_DEFAULTS, PreferencesContext, Spinner, formatFullTime, formatRelativeTime, preferenceActionKey, thresholdOf, toMillis, triggerType, usePreferences, useShellPreferences };
|
|
248
|
-
//# sourceMappingURL=chunk-
|
|
249
|
-
//# sourceMappingURL=chunk-
|
|
250
|
+
//# sourceMappingURL=chunk-RJEUQ7RL.js.map
|
|
251
|
+
//# sourceMappingURL=chunk-RJEUQ7RL.js.map
|