@mitcsutt/kiln-ui 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/display/CodeBlock/CodeBlock.d.ts +5 -4
- package/dist/components/display/CodeBlock/CodeBlock.js.map +1 -1
- package/dist/components/display/CodeBlock/CodeBlock.module.js.map +1 -1
- package/dist/components/display/TreeTable/TreeTable.d.ts +69 -0
- package/dist/components/display/TreeTable/TreeTable.js +152 -0
- package/dist/components/display/TreeTable/TreeTable.js.map +1 -0
- package/dist/components/display/TreeTable/TreeTable.module.js +12 -0
- package/dist/components/display/TreeTable/TreeTable.module.js.map +1 -0
- package/dist/components/display/TreeTable/index.d.ts +2 -0
- package/dist/components/inputs/Checkbox/Checkbox.module.js.map +1 -1
- package/dist/components/inputs/Combobox/Combobox.module.js.map +1 -1
- package/dist/components/inputs/DateRangeField/DateRangeField.module.js.map +1 -1
- package/dist/components/inputs/FileDrop/FileDrop.module.js.map +1 -1
- package/dist/components/inputs/TagsInput/TagsInput.module.js.map +1 -1
- package/dist/components/inputs/internal/messages.module.js.map +1 -1
- package/dist/components/overlays/CommandPalette/CommandPalette.module.js.map +1 -1
- package/dist/components/typography/Link/Link.module.js.map +1 -1
- package/dist/highlight/index.d.ts +1 -1
- package/dist/highlight/index.js +26 -3
- package/dist/highlight/index.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +31 -30
- package/dist/styles.css +1 -1
- package/package.json +2 -1
- package/skills/design-rules/SKILL.md +2 -2
|
@@ -40,14 +40,15 @@ export interface CodeBlockProps extends Omit<HTMLAttributes<HTMLElement>, 'title
|
|
|
40
40
|
* @remarks
|
|
41
41
|
* `CodeBlock` shows code: a snippet in an article, a command, a config example. It's a plain
|
|
42
42
|
* surface with an optional title bar, never fake window chrome. It's plain unless you pass
|
|
43
|
-
* `tokens`: `highlight` from `@mitcsutt/kiln-ui/highlight` turns JavaScript, JSX, TypeScript
|
|
44
|
-
* TSX into tokens, coloured from the theme. Every code sample in these docs is a `CodeBlock`.
|
|
43
|
+
* `tokens`: `highlight` from `@mitcsutt/kiln-ui/highlight` turns JavaScript, JSX, TypeScript,
|
|
44
|
+
* TSX, shell, JSON, YAML and diffs into tokens, coloured from the theme. Every code sample in these docs is a `CodeBlock`.
|
|
45
45
|
*
|
|
46
46
|
* ## Highlighting
|
|
47
47
|
*
|
|
48
48
|
* `highlight(code, language)` resolves to the tokens for `code`, or to `undefined` for a language
|
|
49
|
-
*
|
|
50
|
-
*
|
|
49
|
+
* it doesn't know, which `CodeBlock` shows as plain code. It knows `js`, `jsx`, `ts` and `tsx`
|
|
50
|
+
* (or `javascript` and `typescript`), `bash` (or `sh`, `shell`, `shellscript` and `zsh`), `json`,
|
|
51
|
+
* `yaml` (or `yml`) and `diff`, in any case. It runs [Shiki](https://shiki.style), an optional peer dependency, so
|
|
51
52
|
* install `shiki` to use it. The main `@mitcsutt/kiln-ui` entry never loads it.
|
|
52
53
|
*
|
|
53
54
|
* Keywords and tags take the accent, strings, constants, functions and types take the theme's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeBlock.js","names":["styles","CodeBlock_module_default","CodeBlock","forwardRef","rest","clipboard","useClipboard","copy","captionId","useId","source","trimTrailingNewlines","code","lines","lineTokens","tokens","line","token","i","highlighted","highlightLines","hasHeader","title","language","copyable","cx","className","wrap","showLineNumbers","Button","jsx","CheckIcon","CopyIcon","copyLabel","j"],"sources":["../../../../src/components/display/CodeBlock/CodeBlock.tsx"],"sourcesContent":["import { forwardRef, useId, type HTMLAttributes, type ReactNode } from 'react'\nimport { CheckIcon, CopyIcon } from '#icons'\nimport { Button } from '#components/actions/Button'\nimport { useClipboard } from '#components/actions/CopyButton'\nimport { cx } from '#utils/cx'\nimport { trimTrailingNewlines } from '#utils/newlines'\nimport styles from './CodeBlock.module.css'\n\n/**\n * What a piece of highlighted source is. Each kind is coloured from the theme's own tokens, so\n * highlighted code follows the theme and the colour mode.\n */\nexport type CodeTokenType =\n | 'keyword'\n | 'string'\n | 'comment'\n | 'constant'\n | 'function'\n | 'type'\n | 'tag'\n | 'attribute'\n | 'punctuation'\n\n/** A run of source text and its kind. A token with no `type` is plain text. */\nexport interface CodeToken {\n content: string\n type?: CodeTokenType\n}\n\nexport interface CodeBlockProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {\n /** The source, verbatim. Trailing newlines are trimmed. */\n code: string\n /** Shown as a label (\"TypeScript\", \"bash\"). It doesn't turn on highlighting: `tokens` does. */\n language?: string\n /**\n * Syntax highlighting for `code`: one array of tokens per line, as `highlight` from\n * `@mitcsutt/kiln-ui/highlight` returns them. Without it, or when the tokens don't spell out\n * `code` line for line (say, tokens from a previous `code`), the code is plain.\n */\n tokens?: CodeToken[][]\n /** Filename or caption shown in the header: `src/queries/keys.ts`. */\n title?: ReactNode\n /** Number the lines in a gutter (not copied with a selection). */\n showLineNumbers?: boolean\n /** 1-based line numbers to mark with the theme's highlight colour. */\n highlightLines?: number[]\n /** Show a copy button. Default `true`. */\n copyable?: boolean\n /** Wrap long lines instead of scrolling sideways. */\n wrap?: boolean\n /** Accessible name of the copy button. Default \"Copy code\". */\n copyLabel?: string\n}\n\n/**\n * A block of source with an optional filename bar, line numbers, highlighted lines and a copy\n * button.\n *\n * @remarks\n * `CodeBlock` shows code: a snippet in an article, a command, a config example. It's a plain\n * surface with an optional title bar, never fake window chrome. It's plain unless you pass\n * `tokens`: `highlight` from `@mitcsutt/kiln-ui/highlight` turns JavaScript, JSX, TypeScript
|
|
1
|
+
{"version":3,"file":"CodeBlock.js","names":["styles","CodeBlock_module_default","CodeBlock","forwardRef","rest","clipboard","useClipboard","copy","captionId","useId","source","trimTrailingNewlines","code","lines","lineTokens","tokens","line","token","i","highlighted","highlightLines","hasHeader","title","language","copyable","cx","className","wrap","showLineNumbers","Button","jsx","CheckIcon","CopyIcon","copyLabel","j"],"sources":["../../../../src/components/display/CodeBlock/CodeBlock.tsx"],"sourcesContent":["import { forwardRef, useId, type HTMLAttributes, type ReactNode } from 'react'\nimport { CheckIcon, CopyIcon } from '#icons'\nimport { Button } from '#components/actions/Button'\nimport { useClipboard } from '#components/actions/CopyButton'\nimport { cx } from '#utils/cx'\nimport { trimTrailingNewlines } from '#utils/newlines'\nimport styles from './CodeBlock.module.css'\n\n/**\n * What a piece of highlighted source is. Each kind is coloured from the theme's own tokens, so\n * highlighted code follows the theme and the colour mode.\n */\nexport type CodeTokenType =\n | 'keyword'\n | 'string'\n | 'comment'\n | 'constant'\n | 'function'\n | 'type'\n | 'tag'\n | 'attribute'\n | 'punctuation'\n\n/** A run of source text and its kind. A token with no `type` is plain text. */\nexport interface CodeToken {\n content: string\n type?: CodeTokenType\n}\n\nexport interface CodeBlockProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {\n /** The source, verbatim. Trailing newlines are trimmed. */\n code: string\n /** Shown as a label (\"TypeScript\", \"bash\"). It doesn't turn on highlighting: `tokens` does. */\n language?: string\n /**\n * Syntax highlighting for `code`: one array of tokens per line, as `highlight` from\n * `@mitcsutt/kiln-ui/highlight` returns them. Without it, or when the tokens don't spell out\n * `code` line for line (say, tokens from a previous `code`), the code is plain.\n */\n tokens?: CodeToken[][]\n /** Filename or caption shown in the header: `src/queries/keys.ts`. */\n title?: ReactNode\n /** Number the lines in a gutter (not copied with a selection). */\n showLineNumbers?: boolean\n /** 1-based line numbers to mark with the theme's highlight colour. */\n highlightLines?: number[]\n /** Show a copy button. Default `true`. */\n copyable?: boolean\n /** Wrap long lines instead of scrolling sideways. */\n wrap?: boolean\n /** Accessible name of the copy button. Default \"Copy code\". */\n copyLabel?: string\n}\n\n/**\n * A block of source with an optional filename bar, line numbers, highlighted lines and a copy\n * button.\n *\n * @remarks\n * `CodeBlock` shows code: a snippet in an article, a command, a config example. It's a plain\n * surface with an optional title bar, never fake window chrome. It's plain unless you pass\n * `tokens`: `highlight` from `@mitcsutt/kiln-ui/highlight` turns JavaScript, JSX, TypeScript,\n * TSX, shell, JSON, YAML and diffs into tokens, coloured from the theme. Every code sample in these docs is a `CodeBlock`.\n *\n * ## Highlighting\n *\n * `highlight(code, language)` resolves to the tokens for `code`, or to `undefined` for a language\n * it doesn't know, which `CodeBlock` shows as plain code. It knows `js`, `jsx`, `ts` and `tsx`\n * (or `javascript` and `typescript`), `bash` (or `sh`, `shell`, `shellscript` and `zsh`), `json`,\n * `yaml` (or `yml`) and `diff`, in any case. It runs [Shiki](https://shiki.style), an optional peer dependency, so\n * install `shiki` to use it. The main `@mitcsutt/kiln-ui` entry never loads it.\n *\n * Keywords and tags take the accent, strings, constants, functions and types take the theme's\n * tones, and comments and punctuation are muted. A custom theme needs no code palette of its own.\n *\n * The tokens are plain data, so highlight wherever the code is ready. In a server component or\n * at build time, `await` it and pass the tokens to the client component that renders the\n * `CodeBlock`, and the browser downloads no highlighter. In the browser, call it in an effect, as\n * in the example above: Shiki and the grammar load on the first call.\n *\n * ```tsx\n * import { highlight } from '@mitcsutt/kiln-ui/highlight'\n *\n * export async function Snippet({ source }: { source: string }) {\n * const tokens = await highlight(source, 'tsx')\n * return <SnippetBlock code={source} tokens={tokens} />\n * }\n * ```\n *\n * @privateRemarks\n * A block of source: a snippet in a blog post, a command in a README, a config example.\n * A plain surface with an optional filename bar — no fake window chrome.\n *\n * <CodeBlock title=\"queries/keys.ts\" language=\"TypeScript\" code={source} highlightLines={[3, 4]} />\n */\nexport const CodeBlock = forwardRef<HTMLElement, CodeBlockProps>(function CodeBlock(\n {\n code,\n language,\n tokens,\n title,\n showLineNumbers = false,\n highlightLines,\n copyable = true,\n wrap = false,\n copyLabel = 'Copy code',\n className,\n ...rest\n },\n ref,\n) {\n const clipboard = useClipboard({ timeout: 2000 })\n const copy = clipboard.copied ? 'copied' : clipboard.error ? 'failed' : 'idle'\n const captionId = useId()\n const source = trimTrailingNewlines(code)\n const lines = source.split('\\n')\n const lineTokens =\n tokens?.length === lines.length &&\n tokens.every((line, i) => line.map((token) => token.content).join('') === lines[i])\n ? tokens\n : undefined\n const highlighted = new Set(highlightLines)\n const hasHeader = Boolean(title) || Boolean(language) || copyable\n\n return (\n <figure\n ref={ref}\n className={cx(styles.codeBlock, className)}\n data-kiln-component=\"\"\n data-wrap={wrap || undefined}\n data-line-numbers={showLineNumbers || undefined}\n aria-labelledby={title ? captionId : undefined}\n {...rest}\n >\n {hasHeader ? (\n <figcaption className={styles.header}>\n {title ? (\n <span id={captionId} className={styles.title}>\n {title}\n </span>\n ) : null}\n {language ? <span className={styles.language}>{language}</span> : null}\n {copyable ? (\n <Button\n variant=\"ghost\"\n tone=\"neutral\"\n size=\"sm\"\n className={styles.copy}\n leadingIcon={copy === 'copied' ? <CheckIcon /> : <CopyIcon />}\n aria-label={copyLabel}\n onClick={() => {\n void clipboard.copy(source)\n }}\n data-state={copy}\n >\n {copy === 'copied' ? 'Copied' : copy === 'failed' ? 'Copy failed' : 'Copy'}\n </Button>\n ) : null}\n </figcaption>\n ) : null}\n {/* A scrollable region must be reachable by keyboard. */}\n <pre className={styles.pre} tabIndex={0}>\n <code className={styles.code}>\n {lines.map((line, i) => (\n <span\n key={i}\n className={styles.line}\n data-line={showLineNumbers ? i + 1 : undefined}\n data-highlighted={highlighted.has(i + 1) || undefined}\n >\n {lineTokens?.[i]\n ? lineTokens[i].map((token, j) =>\n token.type ? (\n <span key={j} className={styles.token} data-token={token.type}>\n {token.content}\n </span>\n ) : (\n token.content\n ),\n )\n : line}\n {i < lines.length - 1 ? '\\n' : null}\n </span>\n ))}\n </code>\n </pre>\n {copyable ? (\n <span className={styles.visuallyHidden} role=\"status\" aria-live=\"polite\">\n {copy === 'copied' ? 'Copied to clipboard' : copy === 'failed' ? 'Copy failed' : ''}\n </span>\n ) : null}\n </figure>\n )\n})\n"],"mappings":";;;;;;;;;AA+FA,IAAaE,IAAYC,EAAwC,SAC/D,EACE,SACA,aACA,WACA,UACA,qBAAkB,IAClB,mBACA,cAAW,IACX,UAAO,IACP,eAAY,aACZ,cACA,GAAGC,KAEL,GACA;CACA,IAAMC,IAAYC,EAAa,EAAE,SAAS,IAAK,CAAC,GAC1CC,IAAOF,EAAU,SAAS,WAAWA,EAAU,QAAQ,WAAW,QAClEG,IAAYC,EAAM,GAClBC,IAASC,EAAqBC,CAAI,GAClCC,IAAQH,EAAO,MAAM,IAAI,GACzBI,IACJC,GAAQ,WAAWF,EAAM,UACzBE,EAAO,OAAO,GAAM,MAAMC,EAAK,KAAK,MAAUC,EAAM,OAAO,CAAC,CAAC,KAAK,EAAE,MAAMJ,EAAMK,EAAE,IAC9EH,IACA,KAAA,GACAI,IAAc,IAAI,IAAIC,CAAc,GACpCC,IAAY,EAAQC,KAAU,EAAQC,KAAaC;CAEzD,OACE,kBAAC,UAAD;EACO;EACL,WAAWC,EAAGzB,EAAO,WAAW0B,CAAS;EACzC,uBAAoB;EACpB,aAAWC,KAAQ,KAAA;EACnB,qBAAmBC,KAAmB,KAAA;EACtC,mBAAiBN,IAAQd,IAAY,KAAA;EACrC,GAAIJ;EAPN,UAAA;GASGiB,IACC,kBAAC,cAAD;IAAY,WAAWrB,EAAO;IAA9B,UAAA;KACGsB,IACC,kBAAC,QAAD;MAAM,IAAId;MAAW,WAAWR,EAAO;MACpC,UAAAsB;KACG,CAAA,IACJ;KACHC,IAAW,kBAAC,QAAD;MAAM,WAAWvB,EAAO;MAAW,UAAAuB;KAAe,CAAA,IAAI;KACjEC,IACC,kBAACK,GAAD;MACE,SAAQ;MACR,MAAK;MACL,MAAK;MACL,WAAW7B,EAAO;MAClB,aAAiC8B,EAApBvB,MAAS,WAAYwB,IAAgBC,GAAjB,CAAY,CAAe;MAC5D,cAAYC;MACZ,eAAe;OACb,EAAe,KAAKvB,CAAM;MAC5B;MACA,cAAYH;MAEX,UAAAA,MAAS,WAAW,WAAWA,MAAS,WAAW,gBAAgB;KAC9D,CAAA,IACN;IACM;GACV,CAAA,IAAA;GAEJ,kBAAC,OAAD;IAAK,WAAWP,EAAO;IAAK,UAAU;IACpC,UAAA,kBAAC,QAAD;KAAM,WAAWA,EAAO;KACrB,UAAAa,EAAM,KAAK,GAAM,MAChB,kBAAC,QAAD;MAEE,WAAWb,EAAO;MAClB,aAAW4B,IAAkBV,IAAI,IAAI,KAAA;MACrC,oBAAkBC,EAAY,IAAID,IAAI,CAAC,KAAK,KAAA;MAJ9C,UAAA,CAMGJ,IAAaI,KACVJ,EAAWI,EAAE,CAAC,KAAK,GAAO,MACxBD,EAAM,OACJ,kBAAC,QAAD;OAAc,WAAWjB,EAAO;OAAO,cAAYiB,EAAM;OACtD,UAAAA,EAAM;MACH,GAFKiB,CAEL,IAENjB,EAAM,OAEV,IACAD,GACHE,IAAIL,EAAM,SAAS,IAAI,OAAO,IAC3B;KAjBC,GAAAK,CAiBD,CACP;IACG,CAAA;GACH,CAAA;GACJM,IACC,kBAAC,QAAD;IAAM,WAAWxB,EAAO;IAAgB,MAAK;IAAS,aAAU;IAC7D,UAAAO,MAAS,WAAW,wBAAwBA,MAAS,WAAW,gBAAgB;GAC7E,CAAA,IACJ;EACE;;AAEZ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeBlock.module.js","names":["codeBlock","header","title","language","copy","pre","code","line","token","visuallyHidden","CodeBlock_module_default"],"sources":["../../../../src/components/display/CodeBlock/CodeBlock.module.css"],"sourcesContent":["/*\n * Component tokens (themes may set any of these on [data-theme]):\n * --codeblock-bg default var(--color-surface-sunken)\n * --codeblock-radius default var(--radius-surface)\n * --codeblock-size default var(--text-xs)\n * --codeblock-highlight highlighted line fill, default var(--color-highlight)\n *\n * One edge: a hairline. The header is separated by the same rule, not a fill.\n */\n/* Zero-specificity reset, so a surrounding flow (Prose, Stack) or a className can space it. */\n:where(.codeBlock) {\n margin: 0;\n}\n.codeBlock {\n --_pad: var(--space-4);\n\n display: flex;\n flex-direction: column;\n min-inline-size: 0;\n overflow: hidden;\n border: var(--border-width) solid var(--color-line);\n border-radius: var(--codeblock-radius, var(--radius-surface));\n background: var(--codeblock-bg, var(--color-surface-sunken));\n color: var(--color-ink);\n}\n\n.header {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n min-block-size: calc(var(--control-sm) + var(--space-2));\n padding-inline: var(--_pad) var(--space-2);\n border-block-end: var(--border-width) solid var(--color-line);\n font-family: var(--font-text);\n font-size: var(--text-xs);\n line-height: var(--leading-snug);\n}\n\n.title {\n min-inline-size: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--color-ink);\n font-weight: var(--label-weight);\n}\n\n.language {\n color: var(--color-ink-subtle);\n}\n.title + .language::before {\n content: '·';\n margin-inline-end: var(--space-3);\n}\n\n.copy {\n margin-inline-start: auto;\n color: var(--color-ink-muted);\n}\n.copy[data-state='copied'] {\n color: var(--tone-positive-text);\n}\n.copy[data-state='failed'] {\n color: var(--tone-critical-text);\n}\n\n.pre {\n margin: 0;\n padding-block: var(--space-3);\n overflow-x: auto;\n font-family: var(--font-mono);\n font-stretch: var(--mono-stretch);\n font-size: var(--codeblock-size, var(--text-xs));\n font-variant-ligatures: none;\n line-height: 1.7;\n tab-size: 2;\n white-space: pre;\n scrollbar-width: thin;\n}\n.pre:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: -2px;\n}\n\n.code {\n display: inline-block;\n min-inline-size: 100%;\n font: inherit;\n}\n\n.line {\n display: block;\n position: relative;\n padding-inline: var(--_pad);\n}\n\n.codeBlock[data-line-numbers] .line {\n padding-inline-start: calc(var(--_pad) + 4ch);\n}\n.codeBlock[data-line-numbers] .line::before {\n content: attr(data-line);\n position: absolute;\n inset-inline-start: 0;\n inline-size: calc(var(--_pad) + 2.5ch);\n padding-inline-end: 1ch;\n text-align: end;\n color: var(--color-ink-subtle);\n font-variant-numeric: tabular-nums;\n user-select: none;\n}\n\n/*\n * Highlighted tokens (the `tokens` prop) take the theme's own text colours, so a theme needs no\n * code palette of its own: keywords in the accent, strings, constants and names in the tones.\n */\n.token[data-token='keyword'],\n.token[data-token='tag'] {\n color: var(--color-accent-text);\n}\n.token[data-token='string'] {\n color: var(--tone-positive-text);\n}\n.token[data-token='constant'] {\n color: var(--tone-caution-text);\n}\n.token[data-token='function'],\n.token[data-token='type'] {\n color: var(--tone-info-text);\n}\n.token[data-token='attribute'],\n.token[data-token='punctuation'] {\n color: var(--color-ink-muted);\n}\n.token[data-token='comment'] {\n color: var(--color-ink-subtle);\n}\n\n.line[data-highlighted] {\n background: var(--codeblock-highlight, var(--color-highlight));\n color: var(--color-highlight-ink);\n}\n.line[data-highlighted]::before,\n.line[data-highlighted] .token {\n color: inherit;\n}\n\n.codeBlock[data-wrap] .pre {\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n.codeBlock[data-wrap] .code {\n display: block;\n}\n\n.visuallyHidden {\n position: absolute;\n inline-size: 1px;\n block-size: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"CodeBlock.module.js","names":["codeBlock","header","title","language","copy","pre","code","line","token","visuallyHidden","CodeBlock_module_default"],"sources":["../../../../src/components/display/CodeBlock/CodeBlock.module.css"],"sourcesContent":["/*\n * Component tokens (themes may set any of these on [data-theme]):\n * --codeblock-bg default var(--color-surface-sunken)\n * --codeblock-radius default var(--radius-surface)\n * --codeblock-size default var(--text-xs)\n * --codeblock-highlight highlighted line fill, default var(--color-highlight)\n *\n * One edge: a hairline. The header is separated by the same rule, not a fill.\n */\n/* Zero-specificity reset, so a surrounding flow (Prose, Stack) or a className can space it. */\n:where(.codeBlock) {\n margin: 0;\n}\n.codeBlock {\n --_pad: var(--space-4);\n\n display: flex;\n flex-direction: column;\n min-inline-size: 0;\n overflow: hidden;\n border: var(--border-width) solid var(--color-line);\n border-radius: var(--codeblock-radius, var(--radius-surface));\n background: var(--codeblock-bg, var(--color-surface-sunken));\n color: var(--color-ink);\n}\n\n.header {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n min-block-size: calc(var(--control-sm) + var(--space-2));\n padding-inline: var(--_pad) var(--space-2);\n border-block-end: var(--border-width) solid var(--color-line);\n font-family: var(--font-text);\n font-size: var(--text-xs);\n line-height: var(--leading-snug);\n}\n\n.title {\n min-inline-size: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--color-ink);\n font-weight: var(--label-weight);\n}\n\n.language {\n color: var(--color-ink-subtle);\n}\n.title + .language::before {\n content: '·';\n margin-inline-end: var(--space-3);\n}\n\n/* Scoped under .header so it outranks Button's .button whatever order the CSS chunks load in. */\n.header .copy {\n margin-inline-start: auto;\n color: var(--color-ink-muted);\n}\n.header .copy[data-state='copied'] {\n color: var(--tone-positive-text);\n}\n.header .copy[data-state='failed'] {\n color: var(--tone-critical-text);\n}\n\n.pre {\n margin: 0;\n padding-block: var(--space-3);\n overflow-x: auto;\n font-family: var(--font-mono);\n font-stretch: var(--mono-stretch);\n font-size: var(--codeblock-size, var(--text-xs));\n font-variant-ligatures: none;\n line-height: 1.7;\n tab-size: 2;\n white-space: pre;\n scrollbar-width: thin;\n}\n.pre:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: -2px;\n}\n\n.code {\n display: inline-block;\n min-inline-size: 100%;\n font: inherit;\n}\n\n.line {\n display: block;\n position: relative;\n padding-inline: var(--_pad);\n}\n\n.codeBlock[data-line-numbers] .line {\n padding-inline-start: calc(var(--_pad) + 4ch);\n}\n.codeBlock[data-line-numbers] .line::before {\n content: attr(data-line);\n position: absolute;\n inset-inline-start: 0;\n inline-size: calc(var(--_pad) + 2.5ch);\n padding-inline-end: 1ch;\n text-align: end;\n color: var(--color-ink-subtle);\n font-variant-numeric: tabular-nums;\n user-select: none;\n}\n\n/*\n * Highlighted tokens (the `tokens` prop) take the theme's own text colours, so a theme needs no\n * code palette of its own: keywords in the accent, strings, constants and names in the tones.\n */\n.token[data-token='keyword'],\n.token[data-token='tag'] {\n color: var(--color-accent-text);\n}\n.token[data-token='string'] {\n color: var(--tone-positive-text);\n}\n.token[data-token='constant'] {\n color: var(--tone-caution-text);\n}\n.token[data-token='function'],\n.token[data-token='type'] {\n color: var(--tone-info-text);\n}\n.token[data-token='attribute'],\n.token[data-token='punctuation'] {\n color: var(--color-ink-muted);\n}\n.token[data-token='comment'] {\n color: var(--color-ink-subtle);\n}\n\n.line[data-highlighted] {\n background: var(--codeblock-highlight, var(--color-highlight));\n color: var(--color-highlight-ink);\n}\n.line[data-highlighted]::before,\n.line[data-highlighted] .token {\n color: inherit;\n}\n\n.codeBlock[data-wrap] .pre {\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n.codeBlock[data-wrap] .code {\n display: block;\n}\n\n.visuallyHidden {\n position: absolute;\n inline-size: 1px;\n block-size: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type ReactElement, type ReactNode, type RefAttributes } from 'react';
|
|
2
|
+
import { type TableAlign, type TableColumnWidth, type TableProps } from '../Table/index.js';
|
|
3
|
+
import type { VisibilityProps } from '../../../utils/visibility.js';
|
|
4
|
+
/** One column of a {@link TreeTable}. The first column holds the tree: indent, toggle and the row's name. */
|
|
5
|
+
export interface TreeTableColumn extends VisibilityProps {
|
|
6
|
+
/** Stable key, passed back to `renderCell`. */
|
|
7
|
+
id: string;
|
|
8
|
+
/** The header cell's content. */
|
|
9
|
+
header: ReactNode;
|
|
10
|
+
align?: TableAlign;
|
|
11
|
+
/** Numeric column: right-aligned with tabular figures. */
|
|
12
|
+
numeric?: boolean;
|
|
13
|
+
/** Column sizing: `fill` takes the spare width, `min` shrinks to fit. */
|
|
14
|
+
width?: TableColumnWidth;
|
|
15
|
+
}
|
|
16
|
+
export interface TreeTableProps<T> extends Omit<TableProps, 'children' | 'label' | 'role' | 'onChange' | 'defaultValue'> {
|
|
17
|
+
/** Name for the grid, read by assistive technology. */
|
|
18
|
+
label: string;
|
|
19
|
+
/** The columns, in order. The first holds the tree. */
|
|
20
|
+
columns: readonly TreeTableColumn[];
|
|
21
|
+
/** The top-level rows. */
|
|
22
|
+
rows: readonly T[];
|
|
23
|
+
/** A stable, unique id for a row. It is what `expanded` holds and what keeps focus on a row across renders. */
|
|
24
|
+
getRowId: (row: T) => string;
|
|
25
|
+
/** The row's children, or `undefined` when it has none. */
|
|
26
|
+
getChildren: (row: T) => readonly T[] | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Whether the row can be opened. Defaults to `getChildren(row)` having entries. Return `true` for a
|
|
29
|
+
* row whose children load when it opens.
|
|
30
|
+
*/
|
|
31
|
+
hasChildren?: (row: T) => boolean;
|
|
32
|
+
/** The ids of the open rows (controlled). */
|
|
33
|
+
expanded?: readonly string[];
|
|
34
|
+
/** The ids of the rows that start open (uncontrolled). */
|
|
35
|
+
defaultExpanded?: readonly string[];
|
|
36
|
+
/** Called with the ids of the open rows when one opens or closes. */
|
|
37
|
+
onExpandedChange?: (expanded: string[]) => void;
|
|
38
|
+
/** The content of one cell. The first column's content sits beside the toggle. */
|
|
39
|
+
renderCell: (row: T, column: TreeTableColumn) => ReactNode;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A table of rows in a hierarchy, with a toggle on each parent and keyboard navigation like a file
|
|
43
|
+
* tree.
|
|
44
|
+
*
|
|
45
|
+
* @remarks
|
|
46
|
+
* `TreeTable` is a WAI-ARIA `treegrid` set in `Table`'s styles. Hand it the top-level `rows`, how to
|
|
47
|
+
* find a row's `children`, and `renderCell`; it handles the indent, the toggles, and the
|
|
48
|
+
* `aria-level`, `aria-expanded`, `aria-setsize` and `aria-posinset` on every row.
|
|
49
|
+
*
|
|
50
|
+
* ## Keyboard
|
|
51
|
+
*
|
|
52
|
+
* The grid is one tab stop, and the arrow keys move between rows: Up and Down step by row, Right
|
|
53
|
+
* opens a closed row and then steps into its first child, Left closes an open row and then steps
|
|
54
|
+
* out to its parent, Home and End jump to the first and last visible row, and Enter follows the
|
|
55
|
+
* first link in the row. Links and buttons in a row's cells are reached by Enter, not Tab, so put
|
|
56
|
+
* the row's main link in its first column.
|
|
57
|
+
*
|
|
58
|
+
* ## Open rows
|
|
59
|
+
*
|
|
60
|
+
* `expanded` holds the ids of the open rows, as `getRowId` returns them. Pass it with
|
|
61
|
+
* `onExpandedChange` to control them, for example to keep them in the URL, or `defaultExpanded` to
|
|
62
|
+
* choose which start open. For children that load when a row opens, return `true` from
|
|
63
|
+
* `hasChildren` and give the row a placeholder child while they load.
|
|
64
|
+
*
|
|
65
|
+
* @privateRemarks
|
|
66
|
+
* A separate export, not `Table.Tree`, so a plain `import { Table }` never carries the key handling
|
|
67
|
+
* (docs/adr/0044). Ref and native props go to the `<table>`.
|
|
68
|
+
*/
|
|
69
|
+
export declare const TreeTable: <T>(props: TreeTableProps<T> & RefAttributes<HTMLTableElement>) => ReactElement;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { cx as e } from "../../../utils/cx.js";
|
|
2
|
+
import { ChevronRightIcon as t } from "../../../icons/icons.js";
|
|
3
|
+
import { useLatest as n } from "../../inputs/internal/useLatest.js";
|
|
4
|
+
import { Table as r } from "../Table/Table.js";
|
|
5
|
+
import i from "./TreeTable.module.js";
|
|
6
|
+
import { forwardRef as a, useCallback as o, useLayoutEffect as s, useMemo as c, useRef as l, useState as u } from "react";
|
|
7
|
+
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
8
|
+
//#region src/components/display/TreeTable/TreeTable.tsx
|
|
9
|
+
function p({ label: a, columns: p, rows: m, getRowId: h, getChildren: g, hasChildren: _, expanded: v, defaultExpanded: y, onExpandedChange: b, renderCell: x, className: S, ...C }, w) {
|
|
10
|
+
let [T, E] = u(y ?? []), D = v !== void 0, O = D ? v : T, k = n(b), [A, j] = u(), M = l(/* @__PURE__ */ new Map()), N = l(null), P = c(() => {
|
|
11
|
+
let e = new Set(O), t = [], n = (r, i, a) => {
|
|
12
|
+
r.forEach((o, s) => {
|
|
13
|
+
let c = h(o), l = g(o), u = _ ? _(o) : (l?.length ?? 0) > 0, d = u && e.has(c);
|
|
14
|
+
t.push({
|
|
15
|
+
row: o,
|
|
16
|
+
id: c,
|
|
17
|
+
level: i + 1,
|
|
18
|
+
setSize: r.length,
|
|
19
|
+
posInSet: s + 1,
|
|
20
|
+
parentId: a,
|
|
21
|
+
expandable: u,
|
|
22
|
+
open: d
|
|
23
|
+
}), d && l && n(l, i + 1, c);
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
return n(m, 0, void 0), t;
|
|
27
|
+
}, [
|
|
28
|
+
m,
|
|
29
|
+
O,
|
|
30
|
+
h,
|
|
31
|
+
g,
|
|
32
|
+
_
|
|
33
|
+
]), F = P.some((e) => e.id === A) ? A : P[0]?.id, I = o((e, t) => {
|
|
34
|
+
let n = O.filter((t) => t !== e);
|
|
35
|
+
t && n.push(e), D || E(n), k.current?.(n);
|
|
36
|
+
}, [
|
|
37
|
+
D,
|
|
38
|
+
O,
|
|
39
|
+
k
|
|
40
|
+
]);
|
|
41
|
+
s(() => {
|
|
42
|
+
N.current?.querySelectorAll("a[href], button").forEach((e) => {
|
|
43
|
+
e.setAttribute("tabindex", "-1");
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
let L = (e) => {
|
|
47
|
+
e !== void 0 && (j(e), M.current.get(e)?.focus());
|
|
48
|
+
}, R = (e) => {
|
|
49
|
+
let t = e.target.closest("tr");
|
|
50
|
+
if (e.target !== t || e.altKey || e.ctrlKey || e.metaKey) return;
|
|
51
|
+
let n = P.findIndex((e) => M.current.get(e.id) === t), r = P[n];
|
|
52
|
+
if (!r) return;
|
|
53
|
+
let i = (t) => {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
let r = {
|
|
56
|
+
next: P[n + 1],
|
|
57
|
+
prev: P[n - 1],
|
|
58
|
+
first: P[0],
|
|
59
|
+
last: P[P.length - 1]
|
|
60
|
+
}[t];
|
|
61
|
+
L(r?.id);
|
|
62
|
+
};
|
|
63
|
+
switch (e.key) {
|
|
64
|
+
case "ArrowDown":
|
|
65
|
+
i("next");
|
|
66
|
+
return;
|
|
67
|
+
case "ArrowUp":
|
|
68
|
+
i("prev");
|
|
69
|
+
return;
|
|
70
|
+
case "Home":
|
|
71
|
+
i("first");
|
|
72
|
+
return;
|
|
73
|
+
case "End":
|
|
74
|
+
i("last");
|
|
75
|
+
return;
|
|
76
|
+
case "ArrowRight":
|
|
77
|
+
if (!r.expandable) return;
|
|
78
|
+
e.preventDefault(), r.open ? P[n + 1]?.parentId === r.id && L(P[n + 1]?.id) : I(r.id, !0);
|
|
79
|
+
return;
|
|
80
|
+
case "ArrowLeft":
|
|
81
|
+
r.open ? (e.preventDefault(), I(r.id, !1)) : r.parentId !== void 0 && (e.preventDefault(), L(r.parentId));
|
|
82
|
+
return;
|
|
83
|
+
case "Enter": {
|
|
84
|
+
let n = t.querySelector("a[href]");
|
|
85
|
+
if (!n) return;
|
|
86
|
+
e.preventDefault(), n.click();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}, z = (e) => {
|
|
91
|
+
let t = e.target.closest("tr"), n = P.find((e) => M.current.get(e.id) === t);
|
|
92
|
+
n && j(n.id);
|
|
93
|
+
};
|
|
94
|
+
return /* @__PURE__ */ f(r, {
|
|
95
|
+
ref: w,
|
|
96
|
+
role: "treegrid",
|
|
97
|
+
"aria-label": a,
|
|
98
|
+
className: e(i.treeTable, S),
|
|
99
|
+
...C,
|
|
100
|
+
children: [/* @__PURE__ */ d(r.Head, { children: /* @__PURE__ */ d(r.Row, { children: p.map((e) => /* @__PURE__ */ d(r.HeaderCell, {
|
|
101
|
+
align: e.align,
|
|
102
|
+
numeric: e.numeric,
|
|
103
|
+
width: e.width,
|
|
104
|
+
hideBelow: e.hideBelow,
|
|
105
|
+
hideAbove: e.hideAbove,
|
|
106
|
+
children: e.header
|
|
107
|
+
}, e.id)) }) }), /* @__PURE__ */ d(r.Body, {
|
|
108
|
+
ref: N,
|
|
109
|
+
onKeyDown: R,
|
|
110
|
+
onFocus: z,
|
|
111
|
+
children: P.map((e) => /* @__PURE__ */ d(r.Row, {
|
|
112
|
+
ref: (t) => {
|
|
113
|
+
t ? M.current.set(e.id, t) : M.current.delete(e.id);
|
|
114
|
+
},
|
|
115
|
+
className: i.row,
|
|
116
|
+
interactive: !0,
|
|
117
|
+
tabIndex: e.id === F ? 0 : -1,
|
|
118
|
+
"aria-level": e.level,
|
|
119
|
+
"aria-setsize": e.setSize,
|
|
120
|
+
"aria-posinset": e.posInSet,
|
|
121
|
+
"aria-expanded": e.expandable ? e.open : void 0,
|
|
122
|
+
children: p.map((n, a) => /* @__PURE__ */ d(r.Cell, {
|
|
123
|
+
rowHeader: a === 0,
|
|
124
|
+
align: n.align,
|
|
125
|
+
numeric: n.numeric,
|
|
126
|
+
hideBelow: n.hideBelow,
|
|
127
|
+
hideAbove: n.hideAbove,
|
|
128
|
+
children: a === 0 ? /* @__PURE__ */ f("span", {
|
|
129
|
+
className: i.treeCellContent,
|
|
130
|
+
style: { "--_level": e.level - 1 },
|
|
131
|
+
children: [/* @__PURE__ */ d("button", {
|
|
132
|
+
type: "button",
|
|
133
|
+
className: i.toggle,
|
|
134
|
+
tabIndex: -1,
|
|
135
|
+
"aria-hidden": "true",
|
|
136
|
+
"data-leaf": e.expandable ? void 0 : "",
|
|
137
|
+
onClick: () => {
|
|
138
|
+
L(e.id), I(e.id, !e.open);
|
|
139
|
+
},
|
|
140
|
+
children: /* @__PURE__ */ d(t, { className: i.chevron })
|
|
141
|
+
}), x(e.row, n)]
|
|
142
|
+
}) : x(e.row, n)
|
|
143
|
+
}, n.id))
|
|
144
|
+
}, e.id))
|
|
145
|
+
})]
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
var m = a(p);
|
|
149
|
+
//#endregion
|
|
150
|
+
export { m as TreeTable };
|
|
151
|
+
|
|
152
|
+
//# sourceMappingURL=TreeTable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreeTable.js","names":["styles","TreeTable_module_default","TreeTableInner","expandedProp","rest","inner","setInner","useState","defaultExpanded","controlled","expandedIds","onChange","useLatest","onExpandedChange","activeId","setActiveId","elements","useRef","body","nodes","useMemo","open","out","walk","id","getRowId","row","children","getChildren","expandable","hasChildren","isOpen","level","siblings","index","rows","tabId","node","setExpanded","useCallback","next","existing","moveTo","onKeyDown","rowElement","event","go","target","to","link","onFocus","found","Table","label","cx","className","columns","column","element","columnIndex","ChevronRightIcon","renderCell","TreeTable","forwardRef"],"sources":["../../../../src/components/display/TreeTable/TreeTable.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type FocusEvent,\n type KeyboardEvent,\n type ReactElement,\n type ReactNode,\n type Ref,\n type RefAttributes,\n} from 'react'\nimport {\n Table,\n type TableAlign,\n type TableColumnWidth,\n type TableProps,\n} from '#components/display/Table'\nimport { ChevronRightIcon } from '#icons'\nimport { cx } from '#utils/cx'\nimport type { VisibilityProps } from '#utils/visibility'\nimport { useLatest } from '#components/inputs/internal/useLatest'\nimport styles from './TreeTable.module.css'\n\n/** One column of a {@link TreeTable}. The first column holds the tree: indent, toggle and the row's name. */\nexport interface TreeTableColumn extends VisibilityProps {\n /** Stable key, passed back to `renderCell`. */\n id: string\n /** The header cell's content. */\n header: ReactNode\n align?: TableAlign\n /** Numeric column: right-aligned with tabular figures. */\n numeric?: boolean\n /** Column sizing: `fill` takes the spare width, `min` shrinks to fit. */\n width?: TableColumnWidth\n}\n\nexport interface TreeTableProps<T> extends Omit<\n TableProps,\n 'children' | 'label' | 'role' | 'onChange' | 'defaultValue'\n> {\n /** Name for the grid, read by assistive technology. */\n label: string\n /** The columns, in order. The first holds the tree. */\n columns: readonly TreeTableColumn[]\n /** The top-level rows. */\n rows: readonly T[]\n /** A stable, unique id for a row. It is what `expanded` holds and what keeps focus on a row across renders. */\n getRowId: (row: T) => string\n /** The row's children, or `undefined` when it has none. */\n getChildren: (row: T) => readonly T[] | undefined\n /**\n * Whether the row can be opened. Defaults to `getChildren(row)` having entries. Return `true` for a\n * row whose children load when it opens.\n */\n hasChildren?: (row: T) => boolean\n /** The ids of the open rows (controlled). */\n expanded?: readonly string[]\n /** The ids of the rows that start open (uncontrolled). */\n defaultExpanded?: readonly string[]\n /** Called with the ids of the open rows when one opens or closes. */\n onExpandedChange?: (expanded: string[]) => void\n /** The content of one cell. The first column's content sits beside the toggle. */\n renderCell: (row: T, column: TreeTableColumn) => ReactNode\n}\n\ninterface Node<T> {\n row: T\n id: string\n level: number\n setSize: number\n posInSet: number\n parentId: string | undefined\n expandable: boolean\n open: boolean\n}\n\ntype Dispatch = 'next' | 'prev' | 'first' | 'last'\n\nfunction TreeTableInner<T>(\n {\n label,\n columns,\n rows,\n getRowId,\n getChildren,\n hasChildren,\n expanded: expandedProp,\n defaultExpanded,\n onExpandedChange,\n renderCell,\n className,\n ...rest\n }: TreeTableProps<T>,\n ref: Ref<HTMLTableElement>,\n) {\n const [inner, setInner] = useState<readonly string[]>(defaultExpanded ?? [])\n const controlled = expandedProp !== undefined\n const expandedIds = controlled ? expandedProp : inner\n const onChange = useLatest(onExpandedChange)\n const [activeId, setActiveId] = useState<string>()\n const elements = useRef(new Map<string, HTMLTableRowElement>())\n const body = useRef<HTMLTableSectionElement>(null)\n\n const nodes = useMemo(() => {\n const open = new Set(expandedIds)\n const out: Node<T>[] = []\n const walk = (siblings: readonly T[], level: number, parentId: string | undefined) => {\n siblings.forEach((row, index) => {\n const id = getRowId(row)\n const children = getChildren(row)\n const expandable = hasChildren ? hasChildren(row) : (children?.length ?? 0) > 0\n const isOpen = expandable && open.has(id)\n out.push({\n row,\n id,\n level: level + 1,\n setSize: siblings.length,\n posInSet: index + 1,\n parentId,\n expandable,\n open: isOpen,\n })\n if (isOpen && children) walk(children, level + 1, id)\n })\n }\n walk(rows, 0, undefined)\n return out\n }, [rows, expandedIds, getRowId, getChildren, hasChildren])\n\n const tabId = nodes.some((node) => node.id === activeId) ? activeId : nodes[0]?.id\n\n const setExpanded = useCallback(\n (id: string, open: boolean) => {\n const next = expandedIds.filter((existing) => existing !== id)\n if (open) next.push(id)\n if (!controlled) setInner(next)\n onChange.current?.(next)\n },\n [controlled, expandedIds, onChange],\n )\n\n // Links and buttons inside a row are reached with Enter on the row, so they stay out of the tab\n // order: the grid is one tab stop, however many rows are open.\n useLayoutEffect(() => {\n body.current?.querySelectorAll<HTMLElement>('a[href], button').forEach((element) => {\n element.setAttribute('tabindex', '-1')\n })\n })\n\n const moveTo = (id: string | undefined) => {\n if (id === undefined) return\n setActiveId(id)\n elements.current.get(id)?.focus()\n }\n\n const onKeyDown = (event: KeyboardEvent<HTMLTableSectionElement>) => {\n const rowElement = (event.target as HTMLElement).closest('tr')\n if (event.target !== rowElement || event.altKey || event.ctrlKey || event.metaKey) return\n const index = nodes.findIndex((node) => elements.current.get(node.id) === rowElement)\n const node = nodes[index]\n if (!node) return\n const go = (to: Dispatch) => {\n event.preventDefault()\n const target = {\n next: nodes[index + 1],\n prev: nodes[index - 1],\n first: nodes[0],\n last: nodes[nodes.length - 1],\n }[to]\n moveTo(target?.id)\n }\n switch (event.key) {\n case 'ArrowDown':\n go('next')\n return\n case 'ArrowUp':\n go('prev')\n return\n case 'Home':\n go('first')\n return\n case 'End':\n go('last')\n return\n case 'ArrowRight':\n if (!node.expandable) return\n event.preventDefault()\n if (!node.open) setExpanded(node.id, true)\n else if (nodes[index + 1]?.parentId === node.id) moveTo(nodes[index + 1]?.id)\n return\n case 'ArrowLeft':\n if (node.open) {\n event.preventDefault()\n setExpanded(node.id, false)\n } else if (node.parentId !== undefined) {\n event.preventDefault()\n moveTo(node.parentId)\n }\n return\n case 'Enter': {\n const link = rowElement.querySelector<HTMLElement>('a[href]')\n if (!link) return\n event.preventDefault()\n link.click()\n return\n }\n }\n }\n\n // Clicking inside a row (or focusing a link in it) makes that row the one tab stop.\n const onFocus = (event: FocusEvent<HTMLTableSectionElement>) => {\n const rowElement = (event.target as HTMLElement).closest('tr')\n const found = nodes.find((node) => elements.current.get(node.id) === rowElement)\n if (found) setActiveId(found.id)\n }\n\n return (\n <Table\n ref={ref}\n role=\"treegrid\"\n aria-label={label}\n className={cx(styles.treeTable, className)}\n {...rest}\n >\n <Table.Head>\n <Table.Row>\n {columns.map((column) => (\n <Table.HeaderCell\n key={column.id}\n align={column.align}\n numeric={column.numeric}\n width={column.width}\n hideBelow={column.hideBelow}\n hideAbove={column.hideAbove}\n >\n {column.header}\n </Table.HeaderCell>\n ))}\n </Table.Row>\n </Table.Head>\n <Table.Body ref={body} onKeyDown={onKeyDown} onFocus={onFocus}>\n {nodes.map((node) => (\n <Table.Row\n key={node.id}\n ref={(element) => {\n if (element) elements.current.set(node.id, element)\n else elements.current.delete(node.id)\n }}\n className={styles.row}\n interactive\n tabIndex={node.id === tabId ? 0 : -1}\n aria-level={node.level}\n aria-setsize={node.setSize}\n aria-posinset={node.posInSet}\n aria-expanded={node.expandable ? node.open : undefined}\n >\n {columns.map((column, columnIndex) => {\n return (\n <Table.Cell\n key={column.id}\n rowHeader={columnIndex === 0}\n align={column.align}\n numeric={column.numeric}\n hideBelow={column.hideBelow}\n hideAbove={column.hideAbove}\n >\n {columnIndex === 0 ? (\n <span\n className={styles.treeCellContent}\n style={{ '--_level': node.level - 1 } as CSSProperties}\n >\n <button\n type=\"button\"\n className={styles.toggle}\n tabIndex={-1}\n aria-hidden=\"true\"\n data-leaf={node.expandable ? undefined : ''}\n onClick={() => {\n moveTo(node.id)\n setExpanded(node.id, !node.open)\n }}\n >\n <ChevronRightIcon className={styles.chevron} />\n </button>\n {renderCell(node.row, column)}\n </span>\n ) : (\n renderCell(node.row, column)\n )}\n </Table.Cell>\n )\n })}\n </Table.Row>\n ))}\n </Table.Body>\n </Table>\n )\n}\n\n/**\n * A table of rows in a hierarchy, with a toggle on each parent and keyboard navigation like a file\n * tree.\n *\n * @remarks\n * `TreeTable` is a WAI-ARIA `treegrid` set in `Table`'s styles. Hand it the top-level `rows`, how to\n * find a row's `children`, and `renderCell`; it handles the indent, the toggles, and the\n * `aria-level`, `aria-expanded`, `aria-setsize` and `aria-posinset` on every row.\n *\n * ## Keyboard\n *\n * The grid is one tab stop, and the arrow keys move between rows: Up and Down step by row, Right\n * opens a closed row and then steps into its first child, Left closes an open row and then steps\n * out to its parent, Home and End jump to the first and last visible row, and Enter follows the\n * first link in the row. Links and buttons in a row's cells are reached by Enter, not Tab, so put\n * the row's main link in its first column.\n *\n * ## Open rows\n *\n * `expanded` holds the ids of the open rows, as `getRowId` returns them. Pass it with\n * `onExpandedChange` to control them, for example to keep them in the URL, or `defaultExpanded` to\n * choose which start open. For children that load when a row opens, return `true` from\n * `hasChildren` and give the row a placeholder child while they load.\n *\n * @privateRemarks\n * A separate export, not `Table.Tree`, so a plain `import { Table }` never carries the key handling\n * (docs/adr/0044). Ref and native props go to the `<table>`.\n */\nexport const TreeTable = forwardRef(TreeTableInner) as <T>(\n props: TreeTableProps<T> & RefAttributes<HTMLTableElement>,\n) => ReactElement\n"],"mappings":";;;;;;;;AAkFA,SAASE,EACP,EACE,UACA,YACA,SACA,aACA,gBACA,gBACA,UAAUC,GACV,oBACA,qBACA,eACA,cACA,GAAGC,KAEL,GACA;CACA,IAAM,CAACC,GAAOC,KAAYC,EAA4BC,KAAmB,CAAC,CAAC,GACrEC,IAAaN,MAAiB,KAAA,GAC9BO,IAAcD,IAAaN,IAAeE,GAC1CM,IAAWC,EAAUC,CAAgB,GACrC,CAACC,GAAUC,KAAeR,EAAiB,GAC3CS,IAAWC,kBAAO,IAAI,IAAiC,CAAC,GACxDC,IAAOD,EAAgC,IAAI,GAE3CE,IAAQC,QAAc;EAC1B,IAAMC,IAAO,IAAI,IAAIX,CAAW,GAC1BY,IAAiB,CAAC,GAClBC,KAAQ,GAAwB,GAAe,MAAiC;GACpF,EAAS,SAAS,GAAK,MAAU;IAC/B,IAAMC,IAAKC,EAASC,CAAG,GACjBC,IAAWC,EAAYF,CAAG,GAC1BG,IAAaC,IAAcA,EAAYJ,CAAG,KAAKC,GAAU,UAAU,KAAK,GACxEI,IAASF,KAAcR,EAAK,IAAIG,CAAE;IAWxC,AAVAF,EAAI,KAAK;KACP;KACA;KACA,OAAOU,IAAQ;KACf,SAASC,EAAS;KAClB,UAAUC,IAAQ;KAClB;KACA;KACA,MAAMH;IACR,CAAC,GACGA,KAAUJ,KAAUJ,EAAKI,GAAUK,IAAQ,GAAGR,CAAE;GACtD,CAAC;EACH;EAEA,OADAD,EAAKY,GAAM,GAAG,KAAA,CAAS,GAChBb;CACT,GAAG;EAACa;EAAMzB;EAAae;EAAUG;EAAaE;CAAW,CAAC,GAEpDM,IAAQjB,EAAM,MAAM,MAASkB,EAAK,OAAOvB,CAAQ,IAAIA,IAAWK,EAAM,EAAE,EAAE,IAE1EmB,IAAcC,GACjB,GAAY,MAAkB;EAC7B,IAAMC,IAAO9B,EAAY,QAAQ,MAAa+B,MAAajB,CAAE;EAG7D,AAFIH,KAAMmB,EAAK,KAAKhB,CAAE,GACjBf,KAAYH,EAASkC,CAAI,GAC9B7B,EAAS,UAAU6B,CAAI;CACzB,GACA;EAAC/B;EAAYC;EAAaC;CAAQ,CACpC;CAIA,QAAsB;EACpB,EAAK,SAAS,iBAA8B,iBAAiB,CAAC,CAAC,SAAS,MAAY;GAClF,EAAQ,aAAa,YAAY,IAAI;EACvC,CAAC;CACH,CAAC;CAED,IAAM+B,KAAU,MAA2B;EACzC,AAAIlB,MAAO,KAAA,MACXT,EAAYS,CAAE,GACdR,EAAS,QAAQ,IAAIQ,CAAE,CAAC,EAAE,MAAM;CAClC,GAEMmB,KAAa,MAAkD;EACnE,IAAMC,IAAcC,EAAM,OAAuB,QAAQ,IAAI;EAC7D,IAAIA,EAAM,WAAWD,KAAcC,EAAM,UAAUA,EAAM,WAAWA,EAAM,SAAS;EACnF,IAAMX,IAAQf,EAAM,WAAW,MAASH,EAAS,QAAQ,IAAIqB,EAAK,EAAE,MAAMO,CAAU,GAC9EP,IAAOlB,EAAMe;EACnB,IAAI,CAACG,GAAM;EACX,IAAMS,KAAM,MAAiB;GAC3B,EAAM,eAAe;GACrB,IAAMC,IAAS;IACb,MAAM5B,EAAMe,IAAQ;IACpB,MAAMf,EAAMe,IAAQ;IACpB,OAAOf,EAAM;IACb,MAAMA,EAAMA,EAAM,SAAS;GAC7B,EAAE6B;GACF,EAAOD,GAAQ,EAAE;EACnB;EACA,QAAQF,EAAM,KAAd;GACE,KAAK;IACH,EAAG,MAAM;IACT;GACF,KAAK;IACH,EAAG,MAAM;IACT;GACF,KAAK;IACH,EAAG,OAAO;IACV;GACF,KAAK;IACH,EAAG,MAAM;IACT;GACF,KAAK;IACH,IAAI,CAACR,EAAK,YAAY;IAEtB,AADAQ,EAAM,eAAe,GAChBR,EAAK,OACDlB,EAAMe,IAAQ,EAAE,EAAE,aAAaG,EAAK,MAAIK,EAAOvB,EAAMe,IAAQ,EAAE,EAAE,EAAE,IAD5DI,EAAYD,EAAK,IAAI,EAAI;IAEzC;GACF,KAAK;IACH,AAAIA,EAAK,QACPQ,EAAM,eAAe,GACrBP,EAAYD,EAAK,IAAI,EAAK,KACjBA,EAAK,aAAa,KAAA,MAC3BQ,EAAM,eAAe,GACrBH,EAAOL,EAAK,QAAQ;IAEtB;GACF,KAAK,SAAS;IACZ,IAAMY,IAAOL,EAAW,cAA2B,SAAS;IAC5D,IAAI,CAACK,GAAM;IAEX,AADAJ,EAAM,eAAe,GACrBI,EAAK,MAAM;IACX;GACF;EACF;CACF,GAGMC,KAAW,MAA+C;EAC9D,IAAMN,IAAcC,EAAM,OAAuB,QAAQ,IAAI,GACvDM,IAAQhC,EAAM,MAAM,MAASH,EAAS,QAAQ,IAAIqB,EAAK,EAAE,MAAMO,CAAU;EAC/E,AAAIO,KAAOpC,EAAYoC,EAAM,EAAE;CACjC;CAEA,OACE,kBAACC,GAAD;EACO;EACL,MAAK;EACL,cAAYC;EACZ,WAAWC,EAAGtD,EAAO,WAAWuD,CAAS;EACzC,GAAInD;EALN,UAAA,CAOE,kBAACgD,EAAM,MAAP,EAAA,UACE,kBAACA,EAAM,KAAP,EAAA,UACGI,EAAQ,KAAK,MACZ,kBAACJ,EAAM,YAAP;GAEE,OAAOK,EAAO;GACd,SAASA,EAAO;GAChB,OAAOA,EAAO;GACd,WAAWA,EAAO;GAClB,WAAWA,EAAO;GAEjB,UAAAA,EAAO;EACQ,GARXA,EAAO,EAQI,CACnB,EACQ,CAAA,EACD,CAAA,GACZ,kBAACL,EAAM,MAAP;GAAY,KAAKlC;GAAiB;GAAoB;GACnD,UAAAC,EAAM,KAAK,MACV,kBAACiC,EAAM,KAAP;IAEE,MAAM,MAAY;KAChB,AAAIM,IAAS1C,EAAS,QAAQ,IAAIqB,EAAK,IAAIqB,CAAO,IAC7C1C,EAAS,QAAQ,OAAOqB,EAAK,EAAE;IACtC;IACA,WAAWrC,EAAO;IAClB,aAAA;IACA,UAAUqC,EAAK,OAAOD,IAAQ,IAAI;IAClC,cAAYC,EAAK;IACjB,gBAAcA,EAAK;IACnB,iBAAeA,EAAK;IACpB,iBAAeA,EAAK,aAAaA,EAAK,OAAO,KAAA;IAE5C,UAAAmB,EAAQ,KAAK,GAAQ,MAElB,kBAACJ,EAAM,MAAP;KAEE,WAAWO,MAAgB;KAC3B,OAAOF,EAAO;KACd,SAASA,EAAO;KAChB,WAAWA,EAAO;KAClB,WAAWA,EAAO;KAEjB,UAAAE,MAAgB,IACf,kBAAC,QAAD;MACE,WAAW3D,EAAO;MAClB,OAAO,EAAE,YAAYqC,EAAK,QAAQ,EAAE;MAFtC,UAAA,CAIE,kBAAC,UAAD;OACE,MAAK;OACL,WAAWrC,EAAO;OAClB,UAAU;OACV,eAAY;OACZ,aAAWqC,EAAK,aAAa,KAAA,IAAY;OACzC,eAAe;QAEb,AADAK,EAAOL,EAAK,EAAE,GACdC,EAAYD,EAAK,IAAI,CAACA,EAAK,IAAI;OACjC;OAEA,UAAA,kBAACuB,GAAD,EAAkB,WAAW5D,EAAO,QAAU,CAAA;MACxC,CAAA,GACP6D,EAAWxB,EAAK,KAAKoB,CAAM,CACxB;KAEN,CAAA,IAAAI,EAAWxB,EAAK,KAAKoB,CAAM;IAEnB,GA9BLA,EAAO,EA8BF,CAEf;GACQ,GAjDJpB,EAAK,EAiDD,CACZ;EACS,CAAA,CACP;;AAEX;AA8BA,IAAayB,IAAYC,EAAW7D,CAAc"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/components/display/TreeTable/TreeTable.module.css
|
|
2
|
+
var e = "kiln-TreeTable__treeTable", t = "kiln-TreeTable__row", n = "kiln-TreeTable__treeCellContent", r = "kiln-TreeTable__toggle", i = "kiln-TreeTable__chevron", a = {
|
|
3
|
+
treeTable: e,
|
|
4
|
+
row: t,
|
|
5
|
+
treeCellContent: n,
|
|
6
|
+
toggle: r,
|
|
7
|
+
chevron: i
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { i as chevron, a as default, t as row, r as toggle, n as treeCellContent, e as treeTable };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=TreeTable.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreeTable.module.js","names":["treeTable","row","treeCellContent","toggle","chevron","TreeTable_module_default"],"sources":["../../../../src/components/display/TreeTable/TreeTable.module.css"],"sourcesContent":["/*\n * Component tokens (themes may set any of these on [data-theme]):\n * --tree-table-indent default var(--space-5) — how far each level steps in\n *\n * The table itself is styled by Table; this file adds the indent, the toggle and the row focus.\n */\n.treeTable {\n --_indent: var(--tree-table-indent, var(--space-5));\n}\n\n.row:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: -2px;\n}\n\n.treeCellContent {\n --_level: 0;\n margin-inline-start: calc(var(--_level) * var(--_indent));\n display: inline-flex;\n align-items: baseline;\n gap: var(--space-1);\n min-inline-size: 0;\n}\n\n.toggle {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n inline-size: 1.25rem;\n block-size: 1.25rem;\n padding: 0;\n border: 0;\n background: none;\n color: var(--color-ink-muted);\n cursor: pointer;\n align-self: center;\n}\n\n.toggle[data-leaf] {\n visibility: hidden;\n}\n\n/* Scoped under .toggle so it outranks Icon's .icon whatever order the CSS chunks load in. */\n.toggle .chevron {\n inline-size: 1rem;\n block-size: 1rem;\n transition: transform var(--dur-3) var(--ease-out);\n}\n\n.row[aria-expanded='true'] .chevron {\n transform: rotate(90deg);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .toggle .chevron {\n transition: none;\n }\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.module.js","names":["checkbox","indicator","check","dash","Checkbox_module_default"],"sources":["../../../../src/components/inputs/Checkbox/Checkbox.module.css"],"sourcesContent":["/*\n * Component tokens (themes may set any of these on [data-theme]):\n * --checkbox-radius default calc(var(--radius-field) * 0.4)\n * --control-checked-bg default var(--color-accent) (shared with Radio, Switch)\n * --control-checked-border default var(--color-accent)\n * --control-checked-ink default var(--color-accent-ink)\n * --control-border default var(--color-line-control) (unchecked edge, ≥ 3:1)\n * --control-shadow default var(--shadow-active) — the printed offset in Fiesta, none elsewhere\n */\n.checkbox {\n --_s: calc(var(--control-sm) * 0.5625);\n /* An unchecked box is identified only by its edge, so it needs 3:1 (WCAG 1.4.11):\n line-strong alone is a ~2:1 hairline in the quieter themes. */\n --_border: var(--control-border, var(--color-line-control));\n\n all: unset;\n box-sizing: border-box;\n position: relative;\n display: inline-grid;\n flex: none;\n place-items: center;\n inline-size: var(--_s);\n block-size: var(--_s);\n border: var(--border-width) solid var(--_border);\n border-radius: var(--checkbox-radius, calc(var(--radius-field) * 0.4));\n background-color: var(--color-surface);\n color: var(--control-checked-ink, var(--color-accent-ink));\n box-shadow: var(--control-shadow, var(--shadow-active));\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n transition:\n background-color var(--dur-1) var(--ease-out),\n border-color var(--dur-1) var(--ease-out),\n box-shadow var(--dur-1) var(--ease-out),\n translate var(--dur-1) var(--ease-spring);\n}\n.checkbox[data-size='sm'] {\n --_s: calc(var(--control-sm) * 0.5);\n}\n.checkbox[data-size='lg'] {\n --_s: calc(var(--control-sm) * 0.6875);\n}\n\n/* Bigger hit area than the glyph, without changing layout. */\n.checkbox::before {\n content: '';\n position: absolute;\n inset: calc(var(--space-2) * -1);\n}\n\n@media (hover: hover) {\n .checkbox:hover:not([data-disabled], [data-state='checked'], [data-state='indeterminate']) {\n --_border: color-mix(in oklch, var(--color-line-strong), var(--color-ink) 65%);\n }\n}\n\n.checkbox[data-state='checked'],\n.checkbox[data-state='indeterminate'] {\n --_border: var(--control-checked-border, var(--color-accent));\n background-color: var(--control-checked-bg, var(--color-accent));\n}\n\n.checkbox[data-invalid]:not([data-state='checked']) {\n --_border: var(--tone-critical);\n}\n\n.checkbox:active:not([data-disabled]) {\n translate: var(--active-shift) var(--active-shift);\n box-shadow: none;\n}\n\n.checkbox:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 2px;\n}\n\n.checkbox[data-disabled] {\n cursor: not-allowed;\n opacity: 0.45;\n box-shadow: none;\n}\n\n.indicator {\n display: grid;\n place-items: center;\n inline-size: 100%;\n block-size: 100%;\n animation: tick-in var(--dur-2) var(--ease-spring);\n}\n\n.check,\n.dash {\n grid-area: 1 / 1;\n inline-size: 88%;\n block-size: 88%;\n stroke-width: calc(var(--icon-stroke) * 1.4);\n}\n.indicator[data-state='checked'] .dash,\n.indicator[data-state='indeterminate'] .check {\n display: none;\n}\n\n@keyframes tick-in {\n from {\n opacity: 0;\n scale: 0.5;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .indicator {\n animation: none;\n }\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"Checkbox.module.js","names":["checkbox","indicator","check","dash","Checkbox_module_default"],"sources":["../../../../src/components/inputs/Checkbox/Checkbox.module.css"],"sourcesContent":["/*\n * Component tokens (themes may set any of these on [data-theme]):\n * --checkbox-radius default calc(var(--radius-field) * 0.4)\n * --control-checked-bg default var(--color-accent) (shared with Radio, Switch)\n * --control-checked-border default var(--color-accent)\n * --control-checked-ink default var(--color-accent-ink)\n * --control-border default var(--color-line-control) (unchecked edge, ≥ 3:1)\n * --control-shadow default var(--shadow-active) — the printed offset in Fiesta, none elsewhere\n */\n.checkbox {\n --_s: calc(var(--control-sm) * 0.5625);\n /* An unchecked box is identified only by its edge, so it needs 3:1 (WCAG 1.4.11):\n line-strong alone is a ~2:1 hairline in the quieter themes. */\n --_border: var(--control-border, var(--color-line-control));\n\n all: unset;\n box-sizing: border-box;\n position: relative;\n display: inline-grid;\n flex: none;\n place-items: center;\n inline-size: var(--_s);\n block-size: var(--_s);\n border: var(--border-width) solid var(--_border);\n border-radius: var(--checkbox-radius, calc(var(--radius-field) * 0.4));\n background-color: var(--color-surface);\n color: var(--control-checked-ink, var(--color-accent-ink));\n box-shadow: var(--control-shadow, var(--shadow-active));\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n transition:\n background-color var(--dur-1) var(--ease-out),\n border-color var(--dur-1) var(--ease-out),\n box-shadow var(--dur-1) var(--ease-out),\n translate var(--dur-1) var(--ease-spring);\n}\n.checkbox[data-size='sm'] {\n --_s: calc(var(--control-sm) * 0.5);\n}\n.checkbox[data-size='lg'] {\n --_s: calc(var(--control-sm) * 0.6875);\n}\n\n/* Bigger hit area than the glyph, without changing layout. */\n.checkbox::before {\n content: '';\n position: absolute;\n inset: calc(var(--space-2) * -1);\n}\n\n@media (hover: hover) {\n .checkbox:hover:not([data-disabled], [data-state='checked'], [data-state='indeterminate']) {\n --_border: color-mix(in oklch, var(--color-line-strong), var(--color-ink) 65%);\n }\n}\n\n.checkbox[data-state='checked'],\n.checkbox[data-state='indeterminate'] {\n --_border: var(--control-checked-border, var(--color-accent));\n background-color: var(--control-checked-bg, var(--color-accent));\n}\n\n.checkbox[data-invalid]:not([data-state='checked']) {\n --_border: var(--tone-critical);\n}\n\n.checkbox:active:not([data-disabled]) {\n translate: var(--active-shift) var(--active-shift);\n box-shadow: none;\n}\n\n.checkbox:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 2px;\n}\n\n.checkbox[data-disabled] {\n cursor: not-allowed;\n opacity: 0.45;\n box-shadow: none;\n}\n\n.indicator {\n display: grid;\n place-items: center;\n inline-size: 100%;\n block-size: 100%;\n animation: tick-in var(--dur-2) var(--ease-spring);\n}\n\n/* Scoped under .indicator so it outranks Icon's .icon whatever order the CSS chunks load in. */\n.indicator .check,\n.indicator .dash {\n grid-area: 1 / 1;\n inline-size: 88%;\n block-size: 88%;\n stroke-width: calc(var(--icon-stroke) * 1.4);\n}\n.indicator[data-state='checked'] .dash,\n.indicator[data-state='indeterminate'] .check {\n display: none;\n}\n\n@keyframes tick-in {\n from {\n opacity: 0;\n scale: 0.5;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .indicator {\n animation: none;\n }\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Combobox.module.js","names":["root","values","chips","chip","input","trailing","spinner","clear","chevron","popup","listbox","group","option","groupLabel","optionText","optionLabel","optionDescription","box","check","message","Combobox_module_default"],"sources":["../../../../src/components/inputs/Combobox/Combobox.module.css"],"sourcesContent":["/*\n * The box (border, radius, sizes, states) comes from inputs/internal/control.module.css;\n * this file lays out the chips, the input and the trailing controls inside it, and the\n * floating list.\n *\n * Component tokens (themes may set any of these on [data-theme]):\n * --combobox-list-border default var(--color-line-strong)\n * --combobox-option-highlight default var(--color-surface-sunken) — keyboard/hover row\n * --combobox-option-check default var(--color-accent-text)\n */\n\n/* ── Box ── */\n.root {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n inline-size: 100%;\n padding-inline: var(--_px) calc(var(--_px) * 0.75);\n cursor: text;\n}\n.root[data-multiple] {\n padding-block: calc(var(--space-1) * 0.75);\n}\n.root:focus-within {\n outline: 2px solid var(--color-focus);\n outline-offset: 2px;\n}\n.root[data-disabled] {\n cursor: not-allowed;\n}\n\n.values {\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-1);\n min-inline-size: 0;\n}\n\n.chips {\n display: contents;\n}\n\n.chip {\n max-inline-size: 100%;\n}\n\n.input {\n flex: 1;\n align-self: stretch;\n min-inline-size: 6ch;\n min-block-size: calc(var(--_h) - 2 * var(--border-width));\n margin: 0;\n padding: 0;\n border: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n letter-spacing: inherit;\n text-overflow: ellipsis;\n outline: none;\n}\n.root[data-multiple] .input {\n min-block-size: calc(var(--space-5) * 0.9);\n}\n.input:focus-visible {\n outline: none;\n}\n.input:disabled {\n cursor: not-allowed;\n}\n.input::placeholder {\n color: var(--color-ink-subtle);\n opacity: 1;\n}\n\n.trailing {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: var(--space-1);\n color: var(--color-ink-muted);\n}\n\n.spinner {\n color: var(--color-ink-subtle);\n}\n\n.clear {\n position: relative;\n display: inline-grid;\n place-items: center;\n inline-size: 1.5em;\n block-size: 1.5em;\n padding: 0;\n border: 0;\n border-radius: var(--radius-chip);\n background: transparent;\n color: inherit;\n font-size: inherit;\n cursor: pointer;\n}\n.clear::after {\n content: '';\n position: absolute;\n inset: -0.25em;\n}\n.clear > svg {\n inline-size: 1.1em;\n block-size: 1.1em;\n}\n@media (hover: hover) {\n .clear:hover {\n color: var(--color-ink);\n background: var(--color-surface-sunken);\n }\n}\n.clear:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 1px;\n}\n\n.chevron {\n inline-size: 1.15em;\n block-size: 1.15em;\n transition: rotate var(--dur-2) var(--ease-spring);\n}\n.root[data-state='open'] .chevron {\n rotate: 180deg;\n}\n.root[data-disabled] .trailing {\n color: var(--color-ink-subtle);\n}\n\n/* ── Floating list ── */\n.popup {\n --_pad: var(--space-1);\n --_radius: var(--radius-surface);\n\n z-index: var(--z-popover);\n box-sizing: border-box;\n min-inline-size: var(--radix-popover-trigger-width);\n max-inline-size: min(28rem, calc(100vw - 2 * var(--space-4)));\n max-block-size: min(22rem, var(--radix-popover-content-available-height));\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: var(--_pad);\n border: var(--border-width) solid var(--combobox-list-border, var(--color-line-strong));\n border-radius: var(--_radius);\n background-color: var(--color-surface-raised);\n color: var(--color-ink);\n box-shadow: var(--shadow-float);\n font-family: var(--font-text);\n font-size: var(--text-md);\n line-height: var(--leading-snug);\n scroll-padding-block: var(--_pad);\n transform-origin: var(--radix-popover-content-transform-origin);\n}\n.popup:focus {\n outline: none;\n}\n.popup[data-state='open'] {\n animation: combobox-in var(--dur-2) var(--ease-spring);\n}\n\n@keyframes combobox-in {\n from {\n opacity: 0;\n scale: 0.97;\n translate: 0 calc(var(--space-1) * -1);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .popup[data-state='open'] {\n animation: none;\n }\n .chevron {\n transition: none;\n }\n}\n\n.listbox:empty {\n display: none;\n}\n\n.group {\n display: block;\n}\n.group + .group,\n.option + .group {\n margin-block-start: var(--_pad);\n padding-block-start: var(--_pad);\n border-block-start: var(--border-width) solid var(--color-line);\n}\n\n.groupLabel {\n padding: var(--space-2) var(--space-3) var(--space-1);\n color: var(--color-ink-subtle);\n font-size: var(--text-xs);\n font-weight: var(--label-weight);\n letter-spacing: var(--label-tracking);\n text-transform: var(--label-transform);\n}\n\n/* Nested radius: the row sits inside the list's padding, so it's that much smaller. */\n.option {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n min-block-size: var(--control-sm);\n padding-block: var(--space-1);\n padding-inline: var(--space-3) var(--space-2);\n border-radius: max(2px, calc(var(--_radius) - var(--_pad)));\n cursor: default;\n user-select: none;\n}\n.option[data-active] {\n background-color: var(--combobox-option-highlight, var(--color-surface-sunken));\n}\n.option[data-selected] {\n font-weight: var(--label-weight);\n}\n.option[data-disabled] {\n color: var(--color-ink-subtle);\n opacity: 0.6;\n}\n\n.optionText {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-inline-size: 0;\n}\n\n.optionLabel {\n overflow-wrap: anywhere;\n}\n\n.optionDescription {\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n font-weight: normal;\n}\n\n/* Multiple: a checkbox-like square, filled when chosen. */\n.box {\n display: inline-grid;\n flex: none;\n place-items: center;\n inline-size: 1.1em;\n block-size: 1.1em;\n border: var(--border-width) solid var(--color-line-control);\n border-radius: var(--radius-chip);\n color: var(--color-accent-ink);\n}\n.option[data-selected] .box {\n border-color: var(--color-accent);\n background-color: var(--color-accent);\n}\n.box > svg {\n inline-size: 0.9em;\n block-size: 0.9em;\n}\n\n.check {\n flex: none;\n inline-size: 1.1em;\n block-size: 1.1em;\n color: var(--combobox-option-check, var(--color-accent-text));\n}\n\n.message {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n padding: var(--space-2) var(--space-3);\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"Combobox.module.js","names":["root","values","chips","chip","input","trailing","spinner","clear","chevron","popup","listbox","group","option","groupLabel","optionText","optionLabel","optionDescription","box","check","message","Combobox_module_default"],"sources":["../../../../src/components/inputs/Combobox/Combobox.module.css"],"sourcesContent":["/*\n * The box (border, radius, sizes, states) comes from inputs/internal/control.module.css;\n * this file lays out the chips, the input and the trailing controls inside it, and the\n * floating list.\n *\n * Component tokens (themes may set any of these on [data-theme]):\n * --combobox-list-border default var(--color-line-strong)\n * --combobox-option-highlight default var(--color-surface-sunken) — keyboard/hover row\n * --combobox-option-check default var(--color-accent-text)\n */\n\n/* ── Box ── */\n.root {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n inline-size: 100%;\n padding-inline: var(--_px) calc(var(--_px) * 0.75);\n cursor: text;\n}\n.root[data-multiple] {\n padding-block: calc(var(--space-1) * 0.75);\n}\n.root:focus-within {\n outline: 2px solid var(--color-focus);\n outline-offset: 2px;\n}\n.root[data-disabled] {\n cursor: not-allowed;\n}\n\n.values {\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-1);\n min-inline-size: 0;\n}\n\n/* Scoped under .values so it outranks TagList's .list whatever order the CSS chunks load in. */\n.values .chips {\n display: contents;\n}\n\n.chip {\n max-inline-size: 100%;\n}\n\n.input {\n flex: 1;\n align-self: stretch;\n min-inline-size: 6ch;\n min-block-size: calc(var(--_h) - 2 * var(--border-width));\n margin: 0;\n padding: 0;\n border: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n letter-spacing: inherit;\n text-overflow: ellipsis;\n outline: none;\n}\n.root[data-multiple] .input {\n min-block-size: calc(var(--space-5) * 0.9);\n}\n.input:focus-visible {\n outline: none;\n}\n.input:disabled {\n cursor: not-allowed;\n}\n.input::placeholder {\n color: var(--color-ink-subtle);\n opacity: 1;\n}\n\n.trailing {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: var(--space-1);\n color: var(--color-ink-muted);\n}\n\n/* Scoped under .trailing so it outranks Spinner's .root whatever order the CSS chunks load in. */\n.trailing .spinner {\n color: var(--color-ink-subtle);\n}\n\n.clear {\n position: relative;\n display: inline-grid;\n place-items: center;\n inline-size: 1.5em;\n block-size: 1.5em;\n padding: 0;\n border: 0;\n border-radius: var(--radius-chip);\n background: transparent;\n color: inherit;\n font-size: inherit;\n cursor: pointer;\n}\n.clear::after {\n content: '';\n position: absolute;\n inset: -0.25em;\n}\n.clear > svg {\n inline-size: 1.1em;\n block-size: 1.1em;\n}\n@media (hover: hover) {\n .clear:hover {\n color: var(--color-ink);\n background: var(--color-surface-sunken);\n }\n}\n.clear:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 1px;\n}\n\n/* Scoped under .trailing so it outranks Icon's .icon whatever order the CSS chunks load in. */\n.trailing .chevron {\n inline-size: 1.15em;\n block-size: 1.15em;\n transition: rotate var(--dur-2) var(--ease-spring);\n}\n.root[data-state='open'] .chevron {\n rotate: 180deg;\n}\n.root[data-disabled] .trailing {\n color: var(--color-ink-subtle);\n}\n\n/* ── Floating list ── */\n.popup {\n --_pad: var(--space-1);\n --_radius: var(--radius-surface);\n\n z-index: var(--z-popover);\n box-sizing: border-box;\n min-inline-size: var(--radix-popover-trigger-width);\n max-inline-size: min(28rem, calc(100vw - 2 * var(--space-4)));\n max-block-size: min(22rem, var(--radix-popover-content-available-height));\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: var(--_pad);\n border: var(--border-width) solid var(--combobox-list-border, var(--color-line-strong));\n border-radius: var(--_radius);\n background-color: var(--color-surface-raised);\n color: var(--color-ink);\n box-shadow: var(--shadow-float);\n font-family: var(--font-text);\n font-size: var(--text-md);\n line-height: var(--leading-snug);\n scroll-padding-block: var(--_pad);\n transform-origin: var(--radix-popover-content-transform-origin);\n}\n.popup:focus {\n outline: none;\n}\n.popup[data-state='open'] {\n animation: combobox-in var(--dur-2) var(--ease-spring);\n}\n\n@keyframes combobox-in {\n from {\n opacity: 0;\n scale: 0.97;\n translate: 0 calc(var(--space-1) * -1);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .popup[data-state='open'] {\n animation: none;\n }\n .trailing .chevron {\n transition: none;\n }\n}\n\n.listbox:empty {\n display: none;\n}\n\n.group {\n display: block;\n}\n.group + .group,\n.option + .group {\n margin-block-start: var(--_pad);\n padding-block-start: var(--_pad);\n border-block-start: var(--border-width) solid var(--color-line);\n}\n\n.groupLabel {\n padding: var(--space-2) var(--space-3) var(--space-1);\n color: var(--color-ink-subtle);\n font-size: var(--text-xs);\n font-weight: var(--label-weight);\n letter-spacing: var(--label-tracking);\n text-transform: var(--label-transform);\n}\n\n/* Nested radius: the row sits inside the list's padding, so it's that much smaller. */\n.option {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n min-block-size: var(--control-sm);\n padding-block: var(--space-1);\n padding-inline: var(--space-3) var(--space-2);\n border-radius: max(2px, calc(var(--_radius) - var(--_pad)));\n cursor: default;\n user-select: none;\n}\n.option[data-active] {\n background-color: var(--combobox-option-highlight, var(--color-surface-sunken));\n}\n.option[data-selected] {\n font-weight: var(--label-weight);\n}\n.option[data-disabled] {\n color: var(--color-ink-subtle);\n opacity: 0.6;\n}\n\n.optionText {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-inline-size: 0;\n}\n\n.optionLabel {\n overflow-wrap: anywhere;\n}\n\n.optionDescription {\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n font-weight: normal;\n}\n\n/* Multiple: a checkbox-like square, filled when chosen. */\n.box {\n display: inline-grid;\n flex: none;\n place-items: center;\n inline-size: 1.1em;\n block-size: 1.1em;\n border: var(--border-width) solid var(--color-line-control);\n border-radius: var(--radius-chip);\n color: var(--color-accent-ink);\n}\n.option[data-selected] .box {\n border-color: var(--color-accent);\n background-color: var(--color-accent);\n}\n.box > svg {\n inline-size: 0.9em;\n block-size: 0.9em;\n}\n\n/* Scoped under .option so it outranks Icon's .icon whatever order the CSS chunks load in. */\n.option .check {\n flex: none;\n inline-size: 1.1em;\n block-size: 1.1em;\n color: var(--combobox-option-check, var(--color-accent-text));\n}\n\n.message {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n padding: var(--space-2) var(--space-3);\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateRangeField.module.js","names":["root","parts","part","trigger","panel","presets","preset","times","DateRangeField_module_default"],"sources":["../../../../src/components/inputs/DateRangeField/DateRangeField.module.css"],"sourcesContent":["/*\n * Start and end side by side, each at least --space-11 wide, wrapping to a stack when the\n * column is narrower than both.\n */\n.root {\n min-inline-size: 0;\n}\n\n.parts {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-3);\n}\n\n.part {\n flex: 1 1 var(--space-11);\n min-inline-size: 0;\n}\n\n/* Calendar picker: one calendar button after the two ends, level with their boxes. */\n.trigger {\n flex: none;\n align-self: flex-end;\n}\n\n.panel {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-4);\n}\n\n.presets {\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n min-inline-size: 9rem;\n padding-inline-end: var(--space-4);\n border-inline-end: var(--border-width) solid var(--color-line);\n}\n\n.preset {\n justify-content: flex-start;\n}\n.preset[aria-pressed='true'] {\n background-color: var(--color-accent-soft);\n}\n\n.times {\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"DateRangeField.module.js","names":["root","parts","part","trigger","panel","presets","preset","times","DateRangeField_module_default"],"sources":["../../../../src/components/inputs/DateRangeField/DateRangeField.module.css"],"sourcesContent":["/*\n * Start and end side by side, each at least --space-11 wide, wrapping to a stack when the\n * column is narrower than both.\n */\n.root {\n min-inline-size: 0;\n}\n\n.parts {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-3);\n}\n\n.part {\n flex: 1 1 var(--space-11);\n min-inline-size: 0;\n}\n\n/* Calendar picker: one calendar button after the two ends, level with their boxes. */\n.trigger {\n flex: none;\n align-self: flex-end;\n}\n\n.panel {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-4);\n}\n\n.presets {\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n min-inline-size: 9rem;\n padding-inline-end: var(--space-4);\n border-inline-end: var(--border-width) solid var(--color-line);\n}\n\n/* Scoped under .presets so it outranks Button's .button whatever order the CSS chunks load in. */\n.presets .preset {\n justify-content: flex-start;\n}\n.preset[aria-pressed='true'] {\n background-color: var(--color-accent-soft);\n}\n\n.times {\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileDrop.module.js","names":["root","zone","input","icon","browse","list","item","thumb","image","ext","meta","name","size","remove","FileDrop_module_default"],"sources":["../../../../src/components/inputs/FileDrop/FileDrop.module.css"],"sourcesContent":["/*\n * A dashed drop zone above the chosen files. The real control is the visually hidden\n * file input inside the zone; the zone draws its focus ring.\n *\n * Component tokens (themes may set any of these on [data-theme]):\n * --file-drop-radius default var(--field-radius, var(--radius-field))\n * --file-drop-bg default var(--field-bg, var(--color-surface))\n * --file-drop-border default var(--field-border, var(--color-line-control))\n * --file-drop-active-bg default var(--color-surface-sunken) — while dragging over\n */\n.root {\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n inline-size: 100%;\n font-family: var(--font-text);\n}\n\n/* ── Zone ── */\n.zone {\n --_border: var(--file-drop-border, var(--field-border, var(--color-line-control)));\n\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: center;\n gap: var(--space-2);\n box-sizing: border-box;\n min-block-size: calc(var(--control-lg) * 2);\n padding: var(--space-4);\n border: var(--border-width) dashed var(--_border);\n border-radius: var(--file-drop-radius, var(--field-radius, var(--radius-field)));\n background-color: var(--file-drop-bg, var(--field-bg, var(--color-surface)));\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n line-height: var(--leading-snug);\n text-align: center;\n cursor: pointer;\n transition:\n border-color var(--dur-1) var(--ease-out),\n background-color var(--dur-1) var(--ease-out);\n}\n\n@media (hover: hover) {\n .zone:hover:not([data-disabled], [data-readonly], [data-invalid]) {\n --_border: color-mix(\n in oklab,\n var(--file-drop-border, var(--field-border, var(--color-line-control))),\n var(--color-ink) 35%\n );\n }\n}\n\n/* Focus is on the hidden input; the zone shows the neutral ring. */\n.zone:has(.input:focus-visible) {\n outline: 2px solid var(--color-focus);\n outline-offset: 2px;\n}\n\n.zone[data-dragging] {\n --_border: var(--color-ink);\n border-style: solid;\n background-color: var(--file-drop-active-bg, var(--color-surface-sunken));\n color: var(--color-ink);\n}\n\n.zone[data-invalid] {\n --_border: var(--tone-critical);\n}\n\n.zone[data-readonly] {\n background-color: var(--color-surface-sunken);\n cursor: default;\n}\n\n.zone[data-disabled] {\n --_border: var(--color-line);\n background-color: var(--color-surface-sunken);\n color: var(--color-ink-subtle);\n cursor: not-allowed;\n}\n\n.icon {\n flex: none;\n inline-size: 1.25em;\n block-size: 1.25em;\n}\n\n.browse {\n color: var(--color-ink);\n font-weight: var(--label-weight);\n text-decoration: underline;\n text-decoration-thickness: var(--border-width);\n text-underline-offset: 0.2em;\n}\n.zone[data-disabled] .browse {\n color: inherit;\n}\n\n.input {\n /* visually hidden comes from messages.module.css; this keeps it out of hit-testing. */\n pointer-events: none;\n}\n\n/* ── Files ── */\n.list {\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.list[data-preview='thumbnails'] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));\n gap: var(--space-2);\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n min-block-size: var(--control-md);\n padding-inline: var(--space-3) var(--space-1);\n border: var(--border-width) solid var(--color-line);\n border-radius: var(--file-drop-radius, var(--field-radius, var(--radius-field)));\n background-color: var(--color-surface);\n color: var(--color-ink);\n font-size: var(--text-sm);\n}\n.list[data-preview='thumbnails'] .item {\n position: relative;\n flex-direction: column;\n align-items: stretch;\n gap: var(--space-1);\n padding: var(--space-1) var(--space-1) var(--space-2);\n}\n\n.thumb {\n display: grid;\n place-items: center;\n aspect-ratio: 4 / 3;\n overflow: hidden;\n border-radius: max(2px, calc(var(--field-radius, var(--radius-field)) - var(--space-1)));\n background-color: var(--color-surface-sunken);\n}\n\n.image {\n inline-size: 100%;\n block-size: 100%;\n object-fit: cover;\n}\n\n.ext {\n color: var(--color-ink-subtle);\n font-family: var(--font-numeric);\n font-size: var(--text-xs);\n font-weight: var(--label-weight);\n letter-spacing: var(--label-tracking);\n}\n\n.meta {\n display: flex;\n flex: 1;\n align-items: baseline;\n gap: var(--space-2);\n min-inline-size: 0;\n}\n.list[data-preview='thumbnails'] .meta {\n flex-direction: column;\n gap: 0;\n padding-inline: var(--space-1);\n}\n\n.name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.list[data-preview='thumbnails'] .name {\n max-inline-size: 100%;\n}\n\n.size {\n flex: none;\n color: var(--color-ink-subtle);\n font-family: var(--font-numeric);\n font-stretch: var(--numeric-stretch);\n font-variant-numeric: tabular-nums lining-nums;\n}\n\n.remove {\n position: relative;\n display: inline-grid;\n flex: none;\n place-items: center;\n inline-size: var(--control-sm);\n block-size: var(--control-sm);\n padding: 0;\n border: 0;\n border-radius: var(--radius-chip);\n background: transparent;\n color: var(--color-ink-muted);\n cursor: pointer;\n}\n.list[data-preview='thumbnails'] .remove {\n position: absolute;\n inset-block-start: var(--space-2);\n inset-inline-end: var(--space-2);\n background-color: var(--color-surface-raised);\n box-shadow: var(--shadow-float);\n}\n.remove > svg {\n inline-size: 1.1em;\n block-size: 1.1em;\n}\n@media (hover: hover) {\n .remove:hover {\n color: var(--color-ink);\n background-color: var(--color-surface-sunken);\n }\n}\n.remove:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 1px;\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"FileDrop.module.js","names":["root","zone","input","icon","browse","list","item","thumb","image","ext","meta","name","size","remove","FileDrop_module_default"],"sources":["../../../../src/components/inputs/FileDrop/FileDrop.module.css"],"sourcesContent":["/*\n * A dashed drop zone above the chosen files. The real control is the visually hidden\n * file input inside the zone; the zone draws its focus ring.\n *\n * Component tokens (themes may set any of these on [data-theme]):\n * --file-drop-radius default var(--field-radius, var(--radius-field))\n * --file-drop-bg default var(--field-bg, var(--color-surface))\n * --file-drop-border default var(--field-border, var(--color-line-control))\n * --file-drop-active-bg default var(--color-surface-sunken) — while dragging over\n */\n.root {\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n inline-size: 100%;\n font-family: var(--font-text);\n}\n\n/* ── Zone ── */\n.zone {\n --_border: var(--file-drop-border, var(--field-border, var(--color-line-control)));\n\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: center;\n gap: var(--space-2);\n box-sizing: border-box;\n min-block-size: calc(var(--control-lg) * 2);\n padding: var(--space-4);\n border: var(--border-width) dashed var(--_border);\n border-radius: var(--file-drop-radius, var(--field-radius, var(--radius-field)));\n background-color: var(--file-drop-bg, var(--field-bg, var(--color-surface)));\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n line-height: var(--leading-snug);\n text-align: center;\n cursor: pointer;\n transition:\n border-color var(--dur-1) var(--ease-out),\n background-color var(--dur-1) var(--ease-out);\n}\n\n@media (hover: hover) {\n .zone:hover:not([data-disabled], [data-readonly], [data-invalid]) {\n --_border: color-mix(\n in oklab,\n var(--file-drop-border, var(--field-border, var(--color-line-control))),\n var(--color-ink) 35%\n );\n }\n}\n\n/* Focus is on the hidden input; the zone shows the neutral ring. */\n.zone:has(.input:focus-visible) {\n outline: 2px solid var(--color-focus);\n outline-offset: 2px;\n}\n\n.zone[data-dragging] {\n --_border: var(--color-ink);\n border-style: solid;\n background-color: var(--file-drop-active-bg, var(--color-surface-sunken));\n color: var(--color-ink);\n}\n\n.zone[data-invalid] {\n --_border: var(--tone-critical);\n}\n\n.zone[data-readonly] {\n background-color: var(--color-surface-sunken);\n cursor: default;\n}\n\n.zone[data-disabled] {\n --_border: var(--color-line);\n background-color: var(--color-surface-sunken);\n color: var(--color-ink-subtle);\n cursor: not-allowed;\n}\n\n/* Scoped under .zone so it outranks Icon's .icon whatever order the CSS chunks load in. */\n.zone .icon {\n flex: none;\n inline-size: 1.25em;\n block-size: 1.25em;\n}\n\n.browse {\n color: var(--color-ink);\n font-weight: var(--label-weight);\n text-decoration: underline;\n text-decoration-thickness: var(--border-width);\n text-underline-offset: 0.2em;\n}\n.zone[data-disabled] .browse {\n color: inherit;\n}\n\n.input {\n /* visually hidden comes from messages.module.css; this keeps it out of hit-testing. */\n pointer-events: none;\n}\n\n/* ── Files ── */\n.list {\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.list[data-preview='thumbnails'] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));\n gap: var(--space-2);\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n min-block-size: var(--control-md);\n padding-inline: var(--space-3) var(--space-1);\n border: var(--border-width) solid var(--color-line);\n border-radius: var(--file-drop-radius, var(--field-radius, var(--radius-field)));\n background-color: var(--color-surface);\n color: var(--color-ink);\n font-size: var(--text-sm);\n}\n.list[data-preview='thumbnails'] .item {\n position: relative;\n flex-direction: column;\n align-items: stretch;\n gap: var(--space-1);\n padding: var(--space-1) var(--space-1) var(--space-2);\n}\n\n.thumb {\n display: grid;\n place-items: center;\n aspect-ratio: 4 / 3;\n overflow: hidden;\n border-radius: max(2px, calc(var(--field-radius, var(--radius-field)) - var(--space-1)));\n background-color: var(--color-surface-sunken);\n}\n\n.image {\n inline-size: 100%;\n block-size: 100%;\n object-fit: cover;\n}\n\n.ext {\n color: var(--color-ink-subtle);\n font-family: var(--font-numeric);\n font-size: var(--text-xs);\n font-weight: var(--label-weight);\n letter-spacing: var(--label-tracking);\n}\n\n.meta {\n display: flex;\n flex: 1;\n align-items: baseline;\n gap: var(--space-2);\n min-inline-size: 0;\n}\n.list[data-preview='thumbnails'] .meta {\n flex-direction: column;\n gap: 0;\n padding-inline: var(--space-1);\n}\n\n.name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.list[data-preview='thumbnails'] .name {\n max-inline-size: 100%;\n}\n\n.size {\n flex: none;\n color: var(--color-ink-subtle);\n font-family: var(--font-numeric);\n font-stretch: var(--numeric-stretch);\n font-variant-numeric: tabular-nums lining-nums;\n}\n\n.remove {\n position: relative;\n display: inline-grid;\n flex: none;\n place-items: center;\n inline-size: var(--control-sm);\n block-size: var(--control-sm);\n padding: 0;\n border: 0;\n border-radius: var(--radius-chip);\n background: transparent;\n color: var(--color-ink-muted);\n cursor: pointer;\n}\n.list[data-preview='thumbnails'] .remove {\n position: absolute;\n inset-block-start: var(--space-2);\n inset-inline-end: var(--space-2);\n background-color: var(--color-surface-raised);\n box-shadow: var(--shadow-float);\n}\n.remove > svg {\n inline-size: 1.1em;\n block-size: 1.1em;\n}\n@media (hover: hover) {\n .remove:hover {\n color: var(--color-ink);\n background-color: var(--color-surface-sunken);\n }\n}\n.remove:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 1px;\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TagsInput.module.js","names":["root","values","chips","chip","input","adornment","TagsInput_module_default"],"sources":["../../../../src/components/inputs/TagsInput/TagsInput.module.css"],"sourcesContent":["/*\n * The box (border, radius, sizes, states) comes from inputs/internal/control.module.css;\n * this file lays out the chips and the text input inside it. Chips are `Tag`s, so they\n * follow `--tag-radius`.\n */\n.root {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n inline-size: 100%;\n padding-block: calc(var(--space-1) * 0.75);\n padding-inline: var(--_px);\n cursor: text;\n}\n.root:focus-within {\n outline: 2px solid var(--color-focus);\n outline-offset: 2px;\n}\n.root[data-disabled] {\n cursor: not-allowed;\n}\n\n.values {\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-1);\n min-inline-size: 0;\n}\n\n.chips {\n display: contents;\n}\n\n.chip {\n max-inline-size: 100%;\n}\n\n.input {\n flex: 1;\n min-inline-size: 8ch;\n min-block-size: calc(var(--space-5) * 0.9);\n margin: 0;\n padding: 0;\n border: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n letter-spacing: inherit;\n outline: none;\n}\n.input:focus-visible {\n outline: none;\n}\n.input:disabled {\n cursor: not-allowed;\n}\n.input::placeholder {\n color: var(--color-ink-subtle);\n opacity: 1;\n}\n\n.adornment {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: var(--space-1);\n color: var(--color-ink-subtle);\n font-size: 0.875em;\n white-space: nowrap;\n user-select: none;\n}\n.adornment > svg {\n inline-size: 1.15em;\n block-size: 1.15em;\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"TagsInput.module.js","names":["root","values","chips","chip","input","adornment","TagsInput_module_default"],"sources":["../../../../src/components/inputs/TagsInput/TagsInput.module.css"],"sourcesContent":["/*\n * The box (border, radius, sizes, states) comes from inputs/internal/control.module.css;\n * this file lays out the chips and the text input inside it. Chips are `Tag`s, so they\n * follow `--tag-radius`.\n */\n.root {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n inline-size: 100%;\n padding-block: calc(var(--space-1) * 0.75);\n padding-inline: var(--_px);\n cursor: text;\n}\n.root:focus-within {\n outline: 2px solid var(--color-focus);\n outline-offset: 2px;\n}\n.root[data-disabled] {\n cursor: not-allowed;\n}\n\n.values {\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-1);\n min-inline-size: 0;\n}\n\n/* Scoped under .values so it outranks TagList's .list whatever order the CSS chunks load in. */\n.values .chips {\n display: contents;\n}\n\n.chip {\n max-inline-size: 100%;\n}\n\n.input {\n flex: 1;\n min-inline-size: 8ch;\n min-block-size: calc(var(--space-5) * 0.9);\n margin: 0;\n padding: 0;\n border: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n letter-spacing: inherit;\n outline: none;\n}\n.input:focus-visible {\n outline: none;\n}\n.input:disabled {\n cursor: not-allowed;\n}\n.input::placeholder {\n color: var(--color-ink-subtle);\n opacity: 1;\n}\n\n.adornment {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: var(--space-1);\n color: var(--color-ink-subtle);\n font-size: 0.875em;\n white-space: nowrap;\n user-select: none;\n}\n.adornment > svg {\n inline-size: 1.15em;\n block-size: 1.15em;\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.module.js","names":["label","required","optional","description","error","errorIcon","warning","warningIcon","busy","count","visuallyHidden","messages_module_default"],"sources":["../../../../src/components/inputs/internal/messages.module.css"],"sourcesContent":["/*\n * Shared field text: label, description and error. Used by Field, Fieldset,\n * CheckboxField and RadioGroup items so every label in a form reads the same.\n *\n * Component tokens:\n * --field-label-size default var(--text-sm)\n * --field-description-size default var(--text-sm)\n */\n.label {\n display: inline-flex;\n flex-wrap: wrap;\n align-items: baseline;\n column-gap: 0.35em;\n padding: 0;\n font-family: var(--font-text);\n font-size: var(--field-label-size, var(--text-sm));\n font-weight: var(--label-weight);\n letter-spacing: var(--label-tracking);\n text-transform: var(--label-transform);\n line-height: var(--leading-snug);\n color: var(--color-ink);\n}\n\n/* Visual only — the control carries aria-required. Muted ink: required isn't an error. */\n.required {\n color: var(--color-ink-muted);\n font-weight: var(--label-weight);\n}\n\n.optional {\n color: var(--color-ink-subtle);\n font-weight: normal;\n letter-spacing: 0;\n text-transform: none;\n}\n\n.description {\n max-inline-size: 64ch;\n font-size: var(--field-description-size, var(--text-sm));\n line-height: var(--leading-snug);\n color: var(--color-ink-muted);\n text-wrap: pretty;\n}\n\n.error {\n display: flex;\n align-items: flex-start;\n gap: 0.4em;\n max-inline-size: 64ch;\n font-size: var(--field-description-size, var(--text-sm));\n font-weight: var(--label-weight);\n line-height: var(--leading-snug);\n color: var(--tone-critical-text);\n text-wrap: pretty;\n}\n\n/* Glyph sits on the first line's centre, not the block's. */\n.errorIcon {\n flex: none;\n block-size: 1lh;\n inline-size: 1.1em;\n}\n\n/* Non-blocking advice — same shape as .error, caution tone instead of critical. */\n.warning {\n display: flex;\n align-items: flex-start;\n gap: 0.4em;\n max-inline-size: 64ch;\n font-size: var(--field-description-size, var(--text-sm));\n line-height: var(--leading-snug);\n color: var(--tone-caution-text);\n text-wrap: pretty;\n}\n\n.warningIcon {\n flex: none;\n block-size: 1lh;\n inline-size: 1.1em;\n}\n\n/* validating spinner after the label text */\n.busy {\n flex: none;\n color: var(--color-ink-subtle);\n}\n\n/* maxLength counter under the control */\n.count {\n font-size: var(--field-description-size, var(--text-sm));\n color: var(--color-ink-subtle);\n font-variant-numeric: tabular-nums lining-nums;\n text-align: end;\n}\n\n.visuallyHidden {\n position: absolute;\n inline-size: 1px;\n block-size: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n}\n\n[data-disabled] > .label,\n[data-disabled] > * > .label,\n.label[data-disabled] {\n color: var(--color-ink-subtle);\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"messages.module.js","names":["label","required","optional","description","error","errorIcon","warning","warningIcon","busy","count","visuallyHidden","messages_module_default"],"sources":["../../../../src/components/inputs/internal/messages.module.css"],"sourcesContent":["/*\n * Shared field text: label, description and error. Used by Field, Fieldset,\n * CheckboxField and RadioGroup items so every label in a form reads the same.\n *\n * Component tokens:\n * --field-label-size default var(--text-sm)\n * --field-description-size default var(--text-sm)\n */\n.label {\n display: inline-flex;\n flex-wrap: wrap;\n align-items: baseline;\n column-gap: 0.35em;\n padding: 0;\n font-family: var(--font-text);\n font-size: var(--field-label-size, var(--text-sm));\n font-weight: var(--label-weight);\n letter-spacing: var(--label-tracking);\n text-transform: var(--label-transform);\n line-height: var(--leading-snug);\n color: var(--color-ink);\n}\n\n/* Visual only — the control carries aria-required. Muted ink: required isn't an error. */\n.required {\n color: var(--color-ink-muted);\n font-weight: var(--label-weight);\n}\n\n.optional {\n color: var(--color-ink-subtle);\n font-weight: normal;\n letter-spacing: 0;\n text-transform: none;\n}\n\n.description {\n max-inline-size: 64ch;\n font-size: var(--field-description-size, var(--text-sm));\n line-height: var(--leading-snug);\n color: var(--color-ink-muted);\n text-wrap: pretty;\n}\n\n.error {\n display: flex;\n align-items: flex-start;\n gap: 0.4em;\n max-inline-size: 64ch;\n font-size: var(--field-description-size, var(--text-sm));\n font-weight: var(--label-weight);\n line-height: var(--leading-snug);\n color: var(--tone-critical-text);\n text-wrap: pretty;\n}\n\n/* Glyph sits on the first line's centre, not the block's. */\n/* Scoped under .error so it outranks Icon's .icon whatever order the CSS chunks load in. */\n.error .errorIcon {\n flex: none;\n block-size: 1lh;\n inline-size: 1.1em;\n}\n\n/* Non-blocking advice — same shape as .error, caution tone instead of critical. */\n.warning {\n display: flex;\n align-items: flex-start;\n gap: 0.4em;\n max-inline-size: 64ch;\n font-size: var(--field-description-size, var(--text-sm));\n line-height: var(--leading-snug);\n color: var(--tone-caution-text);\n text-wrap: pretty;\n}\n\n/* Scoped under .warning so it outranks Icon's .icon whatever order the CSS chunks load in. */\n.warning .warningIcon {\n flex: none;\n block-size: 1lh;\n inline-size: 1.1em;\n}\n\n/* validating spinner after the label text */\n/* Doubled so it outranks Spinner's .root whatever order the CSS chunks load in: the label\n around it belongs to whichever field renders it. */\n.busy.busy {\n flex: none;\n color: var(--color-ink-subtle);\n}\n\n/* maxLength counter under the control */\n.count {\n font-size: var(--field-description-size, var(--text-sm));\n color: var(--color-ink-subtle);\n font-variant-numeric: tabular-nums lining-nums;\n text-align: end;\n}\n\n.visuallyHidden {\n position: absolute;\n inline-size: 1px;\n block-size: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n}\n\n[data-disabled] > .label,\n[data-disabled] > * > .label,\n.label[data-disabled] {\n color: var(--color-ink-subtle);\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommandPalette.module.js","names":["overlay","content","search","searchIcon","back","crumb","input","spinner","body","listbox","group","option","groupLabel","icon","text","label","match","description","shortcut","chevron","message","CommandPalette_module_default"],"sources":["../../../../src/components/overlays/CommandPalette/CommandPalette.module.css"],"sourcesContent":["/*\n * Component tokens (themes may set any of these on [data-theme]):\n * --command-palette-radius default var(--radius-surface)\n * --command-palette-shadow default var(--shadow-overlay)\n * --command-palette-border default var(--color-line-strong)\n * --command-palette-surface default var(--color-surface-raised)\n * --command-palette-highlight default var(--color-surface-sunken) — keyboard/hover row\n * --command-palette-match default var(--color-accent) — underline under the matched text\n *\n * The panel hangs from the top third of the screen rather than the middle, so it stays put\n * while the results grow and shrink under the search box.\n */\n\n.overlay {\n position: fixed;\n inset: 0;\n z-index: var(--z-overlay);\n background: var(--color-scrim);\n}\n.overlay[data-state='open'] {\n animation: fade-in var(--dur-2) var(--ease-out);\n}\n.overlay[data-state='closed'] {\n animation: fade-out var(--dur-1) var(--ease-out);\n}\n\n.content {\n --_radius: var(--command-palette-radius, var(--radius-surface));\n --_pad: var(--space-1);\n\n position: fixed;\n inset-block-start: clamp(var(--space-4), 12vh, var(--space-9));\n inset-inline: 0;\n z-index: var(--z-overlay);\n display: flex;\n flex-direction: column;\n inline-size: min(var(--width-text), calc(100% - 2 * var(--space-4)));\n max-block-size: calc(100% - clamp(var(--space-4), 12vh, var(--space-9)) - var(--space-4));\n margin-inline: auto;\n overflow: hidden;\n border: var(--border-width) solid var(--command-palette-border, var(--color-line-strong));\n border-radius: var(--_radius);\n background: var(--command-palette-surface, var(--color-surface-raised));\n box-shadow: var(--command-palette-shadow, var(--shadow-overlay));\n color: var(--color-ink);\n font-family: var(--font-text);\n font-size: var(--text-md);\n line-height: var(--leading-snug);\n transform-origin: 50% 0;\n}\n.content:focus {\n outline: none;\n}\n.content[data-state='open'] {\n animation: palette-in var(--dur-2) var(--ease-spring);\n}\n.content[data-state='closed'] {\n animation: fade-out var(--dur-1) var(--ease-out);\n}\n\n/* ── Search row ── */\n.search {\n display: flex;\n flex: none;\n align-items: center;\n gap: var(--space-2);\n min-block-size: var(--control-lg);\n padding-inline: var(--space-4);\n border-block-end: var(--border-width) solid var(--color-line);\n color: var(--color-ink-muted);\n}\n.search:focus-within {\n color: var(--color-ink);\n}\n\n.searchIcon {\n flex: none;\n inline-size: 1.15em;\n block-size: 1.15em;\n}\n\n.back {\n position: relative;\n display: inline-grid;\n flex: none;\n place-items: center;\n inline-size: 1.75em;\n block-size: 1.75em;\n margin-inline-start: calc(var(--space-1) * -1);\n padding: 0;\n border: 0;\n border-radius: var(--radius-chip);\n background: transparent;\n color: inherit;\n font-size: inherit;\n cursor: pointer;\n}\n.back > svg {\n inline-size: 1.15em;\n block-size: 1.15em;\n}\n@media (hover: hover) {\n .back:hover {\n background: var(--command-palette-highlight, var(--color-surface-sunken));\n color: var(--color-ink);\n }\n}\n.back:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 1px;\n}\n\n.crumb {\n flex: none;\n max-inline-size: 40%;\n overflow: hidden;\n padding-inline-end: var(--space-2);\n border-inline-end: var(--border-width) solid var(--color-line);\n color: var(--color-ink);\n font-size: var(--text-sm);\n font-weight: var(--label-weight);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.input {\n flex: 1;\n align-self: stretch;\n min-inline-size: 0;\n margin: 0;\n padding: 0;\n border: 0;\n background: transparent;\n color: var(--color-ink);\n font: inherit;\n font-size: var(--text-lg);\n letter-spacing: inherit;\n outline: none;\n}\n.input:focus-visible {\n outline: none;\n}\n.input::placeholder {\n color: var(--color-ink-subtle);\n opacity: 1;\n}\n\n.spinner {\n flex: none;\n color: var(--color-ink-subtle);\n}\n\n/* ── Results ── */\n.body {\n flex: 1 1 auto;\n max-block-size: min(26rem, 60vh);\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: var(--_pad);\n scroll-padding-block: var(--_pad);\n}\n\n.listbox:empty {\n display: none;\n}\n\n.group {\n display: block;\n}\n.group + .group,\n.option + .group,\n.group + .option {\n margin-block-start: var(--_pad);\n padding-block-start: var(--_pad);\n border-block-start: var(--border-width) solid var(--color-line);\n}\n\n.groupLabel {\n padding: var(--space-2) var(--space-3) var(--space-1);\n color: var(--color-ink-subtle);\n font-size: var(--text-xs);\n font-weight: var(--label-weight);\n letter-spacing: var(--label-tracking);\n text-transform: var(--label-transform);\n}\n\n/* Nested radius: the row sits inside the panel's padding, so it's that much smaller. */\n.option {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n min-block-size: var(--control-md);\n padding-block: var(--space-1);\n padding-inline: var(--space-3);\n border-radius: max(2px, calc(var(--_radius) - var(--_pad)));\n cursor: default;\n user-select: none;\n}\n.option[data-active] {\n background-color: var(--command-palette-highlight, var(--color-surface-sunken));\n}\n.option[data-disabled] {\n color: var(--color-ink-subtle);\n opacity: 0.6;\n}\n\n.icon {\n display: inline-grid;\n flex: none;\n inline-size: 1.15em;\n place-items: center;\n color: var(--color-ink-muted);\n}\n.icon > svg {\n inline-size: 1.15em;\n block-size: 1.15em;\n}\n.option[data-active] .icon {\n color: var(--color-ink);\n}\n\n.text {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-inline-size: 0;\n}\n\n.label {\n overflow-wrap: anywhere;\n}\n\n.match {\n background: transparent;\n color: inherit;\n font-weight: var(--label-weight);\n text-decoration: underline;\n text-decoration-color: var(--command-palette-match, var(--color-accent));\n text-decoration-thickness: 2px;\n text-underline-offset: 0.2em;\n}\n\n.description {\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n}\n\n.shortcut {\n display: inline-flex;\n flex: none;\n gap: var(--space-1);\n}\n\n.chevron {\n flex: none;\n inline-size: 1.1em;\n block-size: 1.1em;\n color: var(--color-ink-subtle);\n}\n\n.message {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n padding: var(--space-4) var(--space-3);\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n}\n\n@keyframes palette-in {\n from {\n opacity: 0;\n scale: 0.98;\n translate: 0 calc(var(--space-2) * -1);\n }\n}\n@keyframes fade-in {\n from {\n opacity: 0;\n }\n}\n@keyframes fade-out {\n to {\n opacity: 0;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .overlay[data-state],\n .content[data-state] {\n animation: none;\n }\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"CommandPalette.module.js","names":["overlay","content","search","searchIcon","back","crumb","input","spinner","body","listbox","group","option","groupLabel","icon","text","label","match","description","shortcut","chevron","message","CommandPalette_module_default"],"sources":["../../../../src/components/overlays/CommandPalette/CommandPalette.module.css"],"sourcesContent":["/*\n * Component tokens (themes may set any of these on [data-theme]):\n * --command-palette-radius default var(--radius-surface)\n * --command-palette-shadow default var(--shadow-overlay)\n * --command-palette-border default var(--color-line-strong)\n * --command-palette-surface default var(--color-surface-raised)\n * --command-palette-highlight default var(--color-surface-sunken) — keyboard/hover row\n * --command-palette-match default var(--color-accent) — underline under the matched text\n *\n * The panel hangs from the top third of the screen rather than the middle, so it stays put\n * while the results grow and shrink under the search box.\n */\n\n.overlay {\n position: fixed;\n inset: 0;\n z-index: var(--z-overlay);\n background: var(--color-scrim);\n}\n.overlay[data-state='open'] {\n animation: fade-in var(--dur-2) var(--ease-out);\n}\n.overlay[data-state='closed'] {\n animation: fade-out var(--dur-1) var(--ease-out);\n}\n\n.content {\n --_radius: var(--command-palette-radius, var(--radius-surface));\n --_pad: var(--space-1);\n\n position: fixed;\n inset-block-start: clamp(var(--space-4), 12vh, var(--space-9));\n inset-inline: 0;\n z-index: var(--z-overlay);\n display: flex;\n flex-direction: column;\n inline-size: min(var(--width-text), calc(100% - 2 * var(--space-4)));\n max-block-size: calc(100% - clamp(var(--space-4), 12vh, var(--space-9)) - var(--space-4));\n margin-inline: auto;\n overflow: hidden;\n border: var(--border-width) solid var(--command-palette-border, var(--color-line-strong));\n border-radius: var(--_radius);\n background: var(--command-palette-surface, var(--color-surface-raised));\n box-shadow: var(--command-palette-shadow, var(--shadow-overlay));\n color: var(--color-ink);\n font-family: var(--font-text);\n font-size: var(--text-md);\n line-height: var(--leading-snug);\n transform-origin: 50% 0;\n}\n.content:focus {\n outline: none;\n}\n.content[data-state='open'] {\n animation: palette-in var(--dur-2) var(--ease-spring);\n}\n.content[data-state='closed'] {\n animation: fade-out var(--dur-1) var(--ease-out);\n}\n\n/* ── Search row ── */\n.search {\n display: flex;\n flex: none;\n align-items: center;\n gap: var(--space-2);\n min-block-size: var(--control-lg);\n padding-inline: var(--space-4);\n border-block-end: var(--border-width) solid var(--color-line);\n color: var(--color-ink-muted);\n}\n.search:focus-within {\n color: var(--color-ink);\n}\n\n/* Scoped under .search so it outranks Icon's .icon whatever order the CSS chunks load in. */\n.search .searchIcon {\n flex: none;\n inline-size: 1.15em;\n block-size: 1.15em;\n}\n\n.back {\n position: relative;\n display: inline-grid;\n flex: none;\n place-items: center;\n inline-size: 1.75em;\n block-size: 1.75em;\n margin-inline-start: calc(var(--space-1) * -1);\n padding: 0;\n border: 0;\n border-radius: var(--radius-chip);\n background: transparent;\n color: inherit;\n font-size: inherit;\n cursor: pointer;\n}\n.back > svg {\n inline-size: 1.15em;\n block-size: 1.15em;\n}\n@media (hover: hover) {\n .back:hover {\n background: var(--command-palette-highlight, var(--color-surface-sunken));\n color: var(--color-ink);\n }\n}\n.back:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 1px;\n}\n\n.crumb {\n flex: none;\n max-inline-size: 40%;\n overflow: hidden;\n padding-inline-end: var(--space-2);\n border-inline-end: var(--border-width) solid var(--color-line);\n color: var(--color-ink);\n font-size: var(--text-sm);\n font-weight: var(--label-weight);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.input {\n flex: 1;\n align-self: stretch;\n min-inline-size: 0;\n margin: 0;\n padding: 0;\n border: 0;\n background: transparent;\n color: var(--color-ink);\n font: inherit;\n font-size: var(--text-lg);\n letter-spacing: inherit;\n outline: none;\n}\n.input:focus-visible {\n outline: none;\n}\n.input::placeholder {\n color: var(--color-ink-subtle);\n opacity: 1;\n}\n\n/* Scoped under .search so it outranks Spinner's .root whatever order the CSS chunks load in. */\n.search .spinner {\n flex: none;\n color: var(--color-ink-subtle);\n}\n\n/* ── Results ── */\n.body {\n flex: 1 1 auto;\n max-block-size: min(26rem, 60vh);\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: var(--_pad);\n scroll-padding-block: var(--_pad);\n}\n\n.listbox:empty {\n display: none;\n}\n\n.group {\n display: block;\n}\n.group + .group,\n.option + .group,\n.group + .option {\n margin-block-start: var(--_pad);\n padding-block-start: var(--_pad);\n border-block-start: var(--border-width) solid var(--color-line);\n}\n\n.groupLabel {\n padding: var(--space-2) var(--space-3) var(--space-1);\n color: var(--color-ink-subtle);\n font-size: var(--text-xs);\n font-weight: var(--label-weight);\n letter-spacing: var(--label-tracking);\n text-transform: var(--label-transform);\n}\n\n/* Nested radius: the row sits inside the panel's padding, so it's that much smaller. */\n.option {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n min-block-size: var(--control-md);\n padding-block: var(--space-1);\n padding-inline: var(--space-3);\n border-radius: max(2px, calc(var(--_radius) - var(--_pad)));\n cursor: default;\n user-select: none;\n}\n.option[data-active] {\n background-color: var(--command-palette-highlight, var(--color-surface-sunken));\n}\n.option[data-disabled] {\n color: var(--color-ink-subtle);\n opacity: 0.6;\n}\n\n.icon {\n display: inline-grid;\n flex: none;\n inline-size: 1.15em;\n place-items: center;\n color: var(--color-ink-muted);\n}\n.icon > svg {\n inline-size: 1.15em;\n block-size: 1.15em;\n}\n.option[data-active] .icon {\n color: var(--color-ink);\n}\n\n.text {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-inline-size: 0;\n}\n\n.label {\n overflow-wrap: anywhere;\n}\n\n.match {\n background: transparent;\n color: inherit;\n font-weight: var(--label-weight);\n text-decoration: underline;\n text-decoration-color: var(--command-palette-match, var(--color-accent));\n text-decoration-thickness: 2px;\n text-underline-offset: 0.2em;\n}\n\n.description {\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n}\n\n.shortcut {\n display: inline-flex;\n flex: none;\n gap: var(--space-1);\n}\n\n/* Scoped under .option so it outranks Icon's .icon whatever order the CSS chunks load in. */\n.option .chevron {\n flex: none;\n inline-size: 1.1em;\n block-size: 1.1em;\n color: var(--color-ink-subtle);\n}\n\n.message {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n padding: var(--space-4) var(--space-3);\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n}\n\n@keyframes palette-in {\n from {\n opacity: 0;\n scale: 0.98;\n translate: 0 calc(var(--space-2) * -1);\n }\n}\n@keyframes fade-in {\n from {\n opacity: 0;\n }\n}\n@keyframes fade-out {\n to {\n opacity: 0;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .overlay[data-state],\n .content[data-state] {\n animation: none;\n }\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Link.module.js","names":["link","iconWrap","icon","srOnly","Link_module_default"],"sources":["../../../../src/components/typography/Link/Link.module.css"],"sourcesContent":["/*\n * Component tokens:\n * --link-thickness resting underline, default max(0.75 × border, 0.065em)\n * --link-thickness-hover default max(border-width, 0.13em)\n * --link-offset default 0.22em\n */\n.link {\n --_ink: var(--color-ink);\n --_ink-hover: var(--_ink);\n --_line: color-mix(in oklch, currentColor 42%, transparent);\n --_line-hover: currentColor;\n\n color: var(--_ink);\n text-decoration-line: underline;\n text-decoration-color: var(--_line);\n text-decoration-thickness: var(--link-thickness, max(calc(var(--border-width) * 0.75), 0.065em));\n text-underline-offset: var(--link-offset, 0.22em);\n text-decoration-skip-ink: auto;\n border-radius: 0.125em;\n cursor: pointer;\n transition:\n color var(--dur-1) var(--ease-out),\n text-decoration-color var(--dur-1) var(--ease-out),\n text-decoration-thickness var(--dur-1) var(--ease-out),\n text-underline-offset var(--dur-1) var(--ease-out);\n}\n\n.link[data-tone='accent'] {\n --_ink: var(--color-accent-text);\n}\n.link[data-tone='muted'] {\n --_ink: var(--color-ink-muted);\n --_ink-hover: var(--color-ink);\n}\n\n.link[data-underline='hover'] {\n text-decoration-color: transparent;\n}\n\n@media (hover: hover) {\n .link:hover {\n color: var(--_ink-hover);\n text-decoration-color: var(--_line-hover);\n text-decoration-thickness: var(--link-thickness-hover, max(var(--border-width), 0.13em));\n }\n}\n\n.link:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 2px;\n text-decoration-color: var(--_line-hover);\n}\n\n/* The arrow hugs the last word (no wrap point before it) and sits a touch high.\n The glyph's own side-bearing is the gap, so no extra margin. */\n.iconWrap {\n white-space: nowrap;\n}\n.icon {\n display: inline-block;\n inline-size: 0.85em;\n block-size: 0.85em;\n margin-inline: -0.04em -0.12em;\n vertical-align: 0;\n transition: translate var(--dur-1) var(--ease-spring);\n}\n@media (hover: hover) {\n .link:hover .icon {\n translate: 0.08em -0.08em;\n }\n}\n\n.srOnly {\n position: absolute;\n inline-size: 1px;\n block-size: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"Link.module.js","names":["link","iconWrap","icon","srOnly","Link_module_default"],"sources":["../../../../src/components/typography/Link/Link.module.css"],"sourcesContent":["/*\n * Component tokens:\n * --link-thickness resting underline, default max(0.75 × border, 0.065em)\n * --link-thickness-hover default max(border-width, 0.13em)\n * --link-offset default 0.22em\n */\n.link {\n --_ink: var(--color-ink);\n --_ink-hover: var(--_ink);\n --_line: color-mix(in oklch, currentColor 42%, transparent);\n --_line-hover: currentColor;\n\n color: var(--_ink);\n text-decoration-line: underline;\n text-decoration-color: var(--_line);\n text-decoration-thickness: var(--link-thickness, max(calc(var(--border-width) * 0.75), 0.065em));\n text-underline-offset: var(--link-offset, 0.22em);\n text-decoration-skip-ink: auto;\n border-radius: 0.125em;\n cursor: pointer;\n transition:\n color var(--dur-1) var(--ease-out),\n text-decoration-color var(--dur-1) var(--ease-out),\n text-decoration-thickness var(--dur-1) var(--ease-out),\n text-underline-offset var(--dur-1) var(--ease-out);\n}\n\n.link[data-tone='accent'] {\n --_ink: var(--color-accent-text);\n}\n.link[data-tone='muted'] {\n --_ink: var(--color-ink-muted);\n --_ink-hover: var(--color-ink);\n}\n\n.link[data-underline='hover'] {\n text-decoration-color: transparent;\n}\n\n@media (hover: hover) {\n .link:hover {\n color: var(--_ink-hover);\n text-decoration-color: var(--_line-hover);\n text-decoration-thickness: var(--link-thickness-hover, max(var(--border-width), 0.13em));\n }\n}\n\n.link:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 2px;\n text-decoration-color: var(--_line-hover);\n}\n\n/* The arrow hugs the last word (no wrap point before it) and sits a touch high.\n The glyph's own side-bearing is the gap, so no extra margin. */\n.iconWrap {\n white-space: nowrap;\n}\n/* Scoped under .iconWrap so it outranks Icon's .icon whatever order the CSS chunks load in. */\n.iconWrap .icon {\n display: inline-block;\n inline-size: 0.85em;\n block-size: 0.85em;\n margin-inline: -0.04em -0.12em;\n vertical-align: 0;\n transition: translate var(--dur-1) var(--ease-spring);\n}\n@media (hover: hover) {\n .link:hover .icon {\n translate: 0.08em -0.08em;\n }\n}\n\n.srOnly {\n position: absolute;\n inline-size: 1px;\n block-size: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n}\n"],"mappings":""}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CodeToken } from '../components/display/CodeBlock/index.js';
|
|
2
2
|
/** The languages `highlight` understands, with their usual aliases. */
|
|
3
|
-
export type HighlightLanguage = 'js' | 'javascript' | 'jsx' | 'ts' | 'typescript' | 'tsx';
|
|
3
|
+
export type HighlightLanguage = 'js' | 'javascript' | 'jsx' | 'ts' | 'typescript' | 'tsx' | 'bash' | 'sh' | 'shell' | 'shellscript' | 'zsh' | 'json' | 'yaml' | 'yml' | 'diff';
|
|
4
4
|
/**
|
|
5
5
|
* Tokens for `CodeBlock`'s `tokens` prop: one array per line of `code`, each token tagged with
|
|
6
6
|
* what it is (keyword, string, comment…) so the theme colours it. Resolves to `undefined` for a
|