@mitcsutt/kiln-ui 0.4.0 → 0.5.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/List/List.d.ts +8 -0
- package/dist/components/display/List/List.js +5 -4
- package/dist/components/display/List/List.js.map +1 -1
- package/dist/components/display/List/List.module.js.map +1 -1
- package/dist/components/display/List/index.d.ts +1 -1
- package/dist/components/display/Media/Media.d.ts +2 -0
- package/dist/components/display/Media/Media.js +41 -25
- package/dist/components/display/Media/Media.js.map +1 -1
- package/dist/components/display/Table/Table.d.ts +17 -0
- package/dist/components/display/Table/Table.js +13 -10
- package/dist/components/display/Table/Table.js.map +1 -1
- package/dist/components/display/Table/Table.module.js.map +1 -1
- package/dist/components/display/Table/index.d.ts +1 -1
- package/dist/components/layout/Box/Box.d.ts +12 -3
- package/dist/components/layout/Box/Box.js +11 -10
- package/dist/components/layout/Box/Box.js.map +1 -1
- package/dist/components/layout/Box/Box.module.js.map +1 -1
- package/dist/components/layout/ScrollArea/ScrollArea.d.ts +36 -0
- package/dist/components/layout/ScrollArea/ScrollArea.js +25 -0
- package/dist/components/layout/ScrollArea/ScrollArea.js.map +1 -0
- package/dist/components/layout/ScrollArea/ScrollArea.module.js +6 -0
- package/dist/components/layout/ScrollArea/ScrollArea.module.js.map +1 -0
- package/dist/components/layout/ScrollArea/index.d.ts +2 -0
- package/dist/components/layout/Section/Section.d.ts +11 -2
- package/dist/components/layout/Section/Section.js +10 -9
- package/dist/components/layout/Section/Section.js.map +1 -1
- package/dist/components/layout/Section/Section.module.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +102 -101
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/skills/design-rules/SKILL.md +1 -0
- package/skills/layout-composition/SKILL.md +2 -0
- package/skills/layout-composition/references/box.md +21 -1
- package/skills/layout-composition/references/scroll-area.md +68 -0
- package/skills/layout-composition/references/section.md +2 -1
|
@@ -2,6 +2,8 @@ import { type HTMLAttributes, type LiHTMLAttributes, type ReactNode } from 'reac
|
|
|
2
2
|
import type { CategoryColor } from '../../../utils/tokens.js';
|
|
3
3
|
export type ListDensity = 'compact' | 'regular';
|
|
4
4
|
export type ListElement = 'ul' | 'ol';
|
|
5
|
+
/** `surface` and `raised` set the list on one sheet, like `Card`'s `outline` and `raised`. */
|
|
6
|
+
export type ListSurface = 'none' | 'surface' | 'raised';
|
|
5
7
|
export interface ListProps extends HTMLAttributes<HTMLUListElement> {
|
|
6
8
|
/** Hairline rules between rows. Default `true`. */
|
|
7
9
|
divided?: boolean;
|
|
@@ -9,6 +11,12 @@ export interface ListProps extends HTMLAttributes<HTMLUListElement> {
|
|
|
9
11
|
density?: ListDensity;
|
|
10
12
|
/** `ol` when order is the content (a leaderboard). Default `ul`. */
|
|
11
13
|
as?: ListElement;
|
|
14
|
+
/**
|
|
15
|
+
* Set the rows on a sheet so they read as rows, not text on the page: `surface` is the
|
|
16
|
+
* surface fill inside a hairline edge, `raised` stands on the theme's surface shadow. Rows run
|
|
17
|
+
* edge to edge, clipped to the sheet's corners. Default `none`.
|
|
18
|
+
*/
|
|
19
|
+
surface?: ListSurface;
|
|
12
20
|
}
|
|
13
21
|
export interface ListItemProps extends Omit<LiHTMLAttributes<HTMLLIElement>, 'color'> {
|
|
14
22
|
/** Hover affordance. Implied by `asChild`. */
|
|
@@ -4,14 +4,15 @@ import { createContext as n, forwardRef as r, useContext as i } from "react";
|
|
|
4
4
|
import { jsx as a } from "react/jsx-runtime";
|
|
5
5
|
import { Slot as o } from "radix-ui";
|
|
6
6
|
//#region src/components/display/List/List.tsx
|
|
7
|
-
var s = r(function({ divided: n = !0, density: r = "regular", as: i = "ul",
|
|
7
|
+
var s = r(function({ divided: n = !0, density: r = "regular", as: i = "ul", surface: o = "none", className: s, ...c }, l) {
|
|
8
8
|
return /* @__PURE__ */ a(i, {
|
|
9
|
-
ref:
|
|
9
|
+
ref: l,
|
|
10
10
|
role: "list",
|
|
11
|
-
className: e(t.list,
|
|
11
|
+
className: e(t.list, s),
|
|
12
12
|
"data-divided": n || void 0,
|
|
13
13
|
"data-density": r,
|
|
14
|
-
|
|
14
|
+
"data-surface": o === "none" ? void 0 : o,
|
|
15
|
+
...c
|
|
15
16
|
});
|
|
16
17
|
}), c = n(!1), l = r(function({ interactive: n = !1, asChild: r = !1, selected: i = !1, highlighted: s = !1, muted: l = !1, color: u, className: d, children: f, ...p }, m) {
|
|
17
18
|
let h = r ? o.Root : "div";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"List.js","names":["styles","List_module_default","ListRoot","forwardRef","Comp","rest","cx","className","divided","density","RowIsControl","createContext","ListItem","Row","asChild","Slot","interactive","selected","highlighted","muted","color","ListLeading","useContext","ListContent","ListDescription","ListTrailing","List"],"sources":["../../../../src/components/display/List/List.tsx"],"sourcesContent":["import {\n createContext,\n forwardRef,\n useContext,\n type HTMLAttributes,\n type LiHTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { Slot } from 'radix-ui'\nimport { cx } from '#utils/cx'\nimport type { CategoryColor } from '#utils/tokens'\nimport styles from './List.module.css'\n\nexport type ListDensity = 'compact' | 'regular'\nexport type ListElement = 'ul' | 'ol'\n\nexport interface ListProps extends HTMLAttributes<HTMLUListElement> {\n /** Hairline rules between rows. Default `true`. */\n divided?: boolean\n /** Row height. Default `regular`. */\n density?: ListDensity\n /** `ol` when order is the content (a leaderboard). Default `ul`. */\n as?: ListElement\n}\n\n/**\n * The workhorse row list. Leading, content and trailing slots, divided by hairlines, never boxed\n * in cards.\n *\n * @remarks\n * `List` is for rows of similar things: trips, people, invoices, recent activity. Each row has up\n * to three slots: `List.Leading` (an avatar, an icon, a rank), `List.Content` (a title and\n * `List.Description`), and `List.Trailing` (an amount, a time, an action). Rows are divided by\n * hairlines.\n *\n * @privateRemarks\n * The workhorse row list: leaderboards, team members, invoices, recent work. Rows are\n * `Leading · Content · Trailing`, divided by hairlines, never boxed in cards.\n *\n * <List><List.Item><List.Leading>1</List.Leading><List.Content>…</List.Content></List.Item></List>\n */\nconst ListRoot = forwardRef<HTMLUListElement, ListProps>(function List(\n { divided = true, density = 'regular', as: Comp = 'ul', className, ...rest },\n ref,\n) {\n return (\n <Comp\n // @ts-expect-error — ul/ol share HTMLOListElement-compatible attributes; ref type differs only nominally\n ref={ref}\n role=\"list\"\n className={cx(styles.list, className)}\n data-divided={divided || undefined}\n data-density={density}\n {...rest}\n />\n )\n})\n\n/**\n * Whether the row is the asChild link or button. Its slots are then spans, the only content a\n * button may hold; elsewhere they're divs, so block components (Stat, Stack) fit in them.\n */\nconst RowIsControl = createContext(false)\n\nexport interface ListItemProps extends Omit<LiHTMLAttributes<HTMLLIElement>, 'color'> {\n /** Hover affordance. Implied by `asChild`. */\n interactive?: boolean\n /**\n * Make the whole row one link or button: the single child becomes the row, so there\n * is exactly one interactive element and no nested anchors.\n * `<List.Item asChild><a href=\"/projects/atlas\">…slots…</a></List.Item>`\n */\n asChild?: boolean\n /** The current item (accent-soft fill) — e.g. the open page in a list of links. */\n selected?: boolean\n /** Draw attention to a row with `--color-highlight` — typically \"you\". */\n highlighted?: boolean\n /** Out of play (eliminated, archived, past): every ink drops to the muted step, which still reads. */\n muted?: boolean\n /** A categorical colour drawn as a rail at the row's start: whose row it is, matching their `Tag`. */\n color?: CategoryColor\n children?: ReactNode\n}\n\nconst ListItem = forwardRef<HTMLLIElement, ListItemProps>(function ListItem(\n {\n interactive = false,\n asChild = false,\n selected = false,\n highlighted = false,\n muted = false,\n color,\n className,\n children,\n ...rest\n },\n ref,\n) {\n const Row = asChild ? Slot.Root : 'div'\n return (\n <li\n ref={ref}\n className={cx(styles.item, className)}\n data-interactive={interactive || asChild || undefined}\n data-selected={selected || undefined}\n data-highlighted={highlighted || undefined}\n data-muted={muted || undefined}\n data-color={color}\n {...rest}\n >\n <RowIsControl.Provider value={asChild}>\n <Row className={styles.row}>{children}</Row>\n </RowIsControl.Provider>\n </li>\n )\n})\n\n/** Rank, avatar or icon at the start of the row. Numbers are tabular and right-aligned. */\nconst ListLeading = forwardRef<HTMLElement, HTMLAttributes<HTMLElement>>(function ListLeading(\n { className, ...rest },\n ref,\n) {\n const Comp = useContext(RowIsControl) ? 'span' : 'div'\n // @ts-expect-error — polymorphic ref across span/div is safe here\n return <Comp ref={ref} className={cx(styles.leading, className)} {...rest} />\n})\n\n/** Title (the direct text) and an optional `List.Description` below it. */\nconst ListContent = forwardRef<HTMLElement, HTMLAttributes<HTMLElement>>(function ListContent(\n { className, ...rest },\n ref,\n) {\n const Comp = useContext(RowIsControl) ? 'span' : 'div'\n // @ts-expect-error — polymorphic ref across span/div is safe here\n return <Comp ref={ref} className={cx(styles.content, className)} {...rest} />\n})\n\nconst ListDescription = forwardRef<HTMLElement, HTMLAttributes<HTMLElement>>(\n function ListDescription({ className, ...rest }, ref) {\n const Comp = useContext(RowIsControl) ? 'span' : 'div'\n // @ts-expect-error — polymorphic ref across span/div is safe here\n return <Comp ref={ref} className={cx(styles.description, className)} {...rest} />\n },\n)\n\n/** Value, meta or actions at the end of the row. Numbers are tabular. */\nconst ListTrailing = forwardRef<HTMLElement, HTMLAttributes<HTMLElement>>(function ListTrailing(\n { className, ...rest },\n ref,\n) {\n const Comp = useContext(RowIsControl) ? 'span' : 'div'\n // @ts-expect-error — polymorphic ref across span/div is safe here\n return <Comp ref={ref} className={cx(styles.trailing, className)} {...rest} />\n})\n\nexport const List = Object.assign(ListRoot, {\n Item: ListItem,\n Leading: ListLeading,\n Content: ListContent,\n Description: ListDescription,\n Trailing: ListTrailing,\n})\n"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"List.js","names":["styles","List_module_default","ListRoot","forwardRef","Comp","rest","cx","className","divided","density","surface","RowIsControl","createContext","ListItem","Row","asChild","Slot","interactive","selected","highlighted","muted","color","ListLeading","useContext","ListContent","ListDescription","ListTrailing","List"],"sources":["../../../../src/components/display/List/List.tsx"],"sourcesContent":["import {\n createContext,\n forwardRef,\n useContext,\n type HTMLAttributes,\n type LiHTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { Slot } from 'radix-ui'\nimport { cx } from '#utils/cx'\nimport type { CategoryColor } from '#utils/tokens'\nimport styles from './List.module.css'\n\nexport type ListDensity = 'compact' | 'regular'\nexport type ListElement = 'ul' | 'ol'\n/** `surface` and `raised` set the list on one sheet, like `Card`'s `outline` and `raised`. */\nexport type ListSurface = 'none' | 'surface' | 'raised'\n\nexport interface ListProps extends HTMLAttributes<HTMLUListElement> {\n /** Hairline rules between rows. Default `true`. */\n divided?: boolean\n /** Row height. Default `regular`. */\n density?: ListDensity\n /** `ol` when order is the content (a leaderboard). Default `ul`. */\n as?: ListElement\n /**\n * Set the rows on a sheet so they read as rows, not text on the page: `surface` is the\n * surface fill inside a hairline edge, `raised` stands on the theme's surface shadow. Rows run\n * edge to edge, clipped to the sheet's corners. Default `none`.\n */\n surface?: ListSurface\n}\n\n/**\n * The workhorse row list. Leading, content and trailing slots, divided by hairlines, never boxed\n * in cards.\n *\n * @remarks\n * `List` is for rows of similar things: trips, people, invoices, recent activity. Each row has up\n * to three slots: `List.Leading` (an avatar, an icon, a rank), `List.Content` (a title and\n * `List.Description`), and `List.Trailing` (an amount, a time, an action). Rows are divided by\n * hairlines.\n *\n * ## On a surface\n *\n * On a busy page, or a theme whose canvas has a texture, `surface=\"surface\"` sets the whole list\n * on one sheet, and `surface=\"raised\"` stands it on the theme's surface shadow. The rows stay rows\n * on it and run edge to edge: a highlighted, selected or hovered row is a band across the sheet,\n * and a categorical rail is the row's edge, following the sheet's corners at either end.\n *\n * @privateRemarks\n * The workhorse row list: leaderboards, team members, invoices, recent work. Rows are\n * `Leading · Content · Trailing`, divided by hairlines, never boxed in cards.\n *\n * <List><List.Item><List.Leading>1</List.Leading><List.Content>…</List.Content></List.Item></List>\n */\nconst ListRoot = forwardRef<HTMLUListElement, ListProps>(function List(\n { divided = true, density = 'regular', as: Comp = 'ul', surface = 'none', className, ...rest },\n ref,\n) {\n return (\n <Comp\n // @ts-expect-error — ul/ol share HTMLOListElement-compatible attributes; ref type differs only nominally\n ref={ref}\n role=\"list\"\n className={cx(styles.list, className)}\n data-divided={divided || undefined}\n data-density={density}\n data-surface={surface === 'none' ? undefined : surface}\n {...rest}\n />\n )\n})\n\n/**\n * Whether the row is the asChild link or button. Its slots are then spans, the only content a\n * button may hold; elsewhere they're divs, so block components (Stat, Stack) fit in them.\n */\nconst RowIsControl = createContext(false)\n\nexport interface ListItemProps extends Omit<LiHTMLAttributes<HTMLLIElement>, 'color'> {\n /** Hover affordance. Implied by `asChild`. */\n interactive?: boolean\n /**\n * Make the whole row one link or button: the single child becomes the row, so there\n * is exactly one interactive element and no nested anchors.\n * `<List.Item asChild><a href=\"/projects/atlas\">…slots…</a></List.Item>`\n */\n asChild?: boolean\n /** The current item (accent-soft fill) — e.g. the open page in a list of links. */\n selected?: boolean\n /** Draw attention to a row with `--color-highlight` — typically \"you\". */\n highlighted?: boolean\n /** Out of play (eliminated, archived, past): every ink drops to the muted step, which still reads. */\n muted?: boolean\n /** A categorical colour drawn as a rail at the row's start: whose row it is, matching their `Tag`. */\n color?: CategoryColor\n children?: ReactNode\n}\n\nconst ListItem = forwardRef<HTMLLIElement, ListItemProps>(function ListItem(\n {\n interactive = false,\n asChild = false,\n selected = false,\n highlighted = false,\n muted = false,\n color,\n className,\n children,\n ...rest\n },\n ref,\n) {\n const Row = asChild ? Slot.Root : 'div'\n return (\n <li\n ref={ref}\n className={cx(styles.item, className)}\n data-interactive={interactive || asChild || undefined}\n data-selected={selected || undefined}\n data-highlighted={highlighted || undefined}\n data-muted={muted || undefined}\n data-color={color}\n {...rest}\n >\n <RowIsControl.Provider value={asChild}>\n <Row className={styles.row}>{children}</Row>\n </RowIsControl.Provider>\n </li>\n )\n})\n\n/** Rank, avatar or icon at the start of the row. Numbers are tabular and right-aligned. */\nconst ListLeading = forwardRef<HTMLElement, HTMLAttributes<HTMLElement>>(function ListLeading(\n { className, ...rest },\n ref,\n) {\n const Comp = useContext(RowIsControl) ? 'span' : 'div'\n // @ts-expect-error — polymorphic ref across span/div is safe here\n return <Comp ref={ref} className={cx(styles.leading, className)} {...rest} />\n})\n\n/** Title (the direct text) and an optional `List.Description` below it. */\nconst ListContent = forwardRef<HTMLElement, HTMLAttributes<HTMLElement>>(function ListContent(\n { className, ...rest },\n ref,\n) {\n const Comp = useContext(RowIsControl) ? 'span' : 'div'\n // @ts-expect-error — polymorphic ref across span/div is safe here\n return <Comp ref={ref} className={cx(styles.content, className)} {...rest} />\n})\n\nconst ListDescription = forwardRef<HTMLElement, HTMLAttributes<HTMLElement>>(\n function ListDescription({ className, ...rest }, ref) {\n const Comp = useContext(RowIsControl) ? 'span' : 'div'\n // @ts-expect-error — polymorphic ref across span/div is safe here\n return <Comp ref={ref} className={cx(styles.description, className)} {...rest} />\n },\n)\n\n/** Value, meta or actions at the end of the row. Numbers are tabular. */\nconst ListTrailing = forwardRef<HTMLElement, HTMLAttributes<HTMLElement>>(function ListTrailing(\n { className, ...rest },\n ref,\n) {\n const Comp = useContext(RowIsControl) ? 'span' : 'div'\n // @ts-expect-error — polymorphic ref across span/div is safe here\n return <Comp ref={ref} className={cx(styles.trailing, className)} {...rest} />\n})\n\nexport const List = Object.assign(ListRoot, {\n Item: ListItem,\n Leading: ListLeading,\n Content: ListContent,\n Description: ListDescription,\n Trailing: ListTrailing,\n})\n"],"mappings":";;;;;;AAwDA,IAAME,IAAWC,EAAwC,SACvD,EAAE,aAAU,IAAM,aAAU,WAAW,IAAIC,IAAO,MAAM,aAAU,QAAQ,cAAW,GAAGC,KACxF,GACA;CACA,OACE,kBAACD,GAAD;EAEO;EACL,MAAK;EACL,WAAWE,EAAGN,EAAO,MAAMO,CAAS;EACpC,gBAAcC,KAAW,KAAA;EACzB,gBAAcC;EACd,gBAAcC,MAAY,SAAS,KAAA,IAAYA;EAC/C,GAAIL;CACL,CAAA;AAEL,CAAC,GAMKM,IAAeC,EAAc,EAAK,GAsBlCC,IAAWV,EAAyC,SACxD,EACE,iBAAc,IACd,aAAU,IACV,cAAW,IACX,iBAAc,IACd,WAAQ,IACR,UACA,cACA,aACA,GAAGE,KAEL,GACA;CACA,IAAMS,IAAMC,IAAUC,EAAK,OAAO;CAClC,OACE,kBAAC,MAAD;EACO;EACL,WAAWV,EAAGN,EAAO,MAAMO,CAAS;EACpC,oBAAkBU,KAAeF,KAAW,KAAA;EAC5C,iBAAeG,KAAY,KAAA;EAC3B,oBAAkBC,KAAe,KAAA;EACjC,cAAYC,KAAS,KAAA;EACrB,cAAYC;EACZ,GAAIhB;EAEJ,UAAA,kBAACM,EAAa,UAAd;GAAuB,OAAOI;GAC5B,UAAA,kBAACD,GAAD;IAAK,WAAWd,EAAO;IAAM;GAAc,CAAA;EACtB,CAAA;CACrB,CAAA;AAER,CAAC,GAGKsB,IAAcnB,EAAqD,SACvE,EAAE,cAAW,GAAGE,KAChB,GACA;CACA,IAAMD,IAAOmB,EAAWZ,CAAY,IAAI,SAAS;CAEjD,OAAO,kBAACP,GAAD;EAAW;EAAK,WAAWE,EAAGN,EAAO,SAASO,CAAS;EAAG,GAAIF;CAAO,CAAA;AAC9E,CAAC,GAGKmB,IAAcrB,EAAqD,SACvE,EAAE,cAAW,GAAGE,KAChB,GACA;CACA,IAAMD,IAAOmB,EAAWZ,CAAY,IAAI,SAAS;CAEjD,OAAO,kBAACP,GAAD;EAAW;EAAK,WAAWE,EAAGN,EAAO,SAASO,CAAS;EAAG,GAAIF;CAAO,CAAA;AAC9E,CAAC,GAEKoB,IAAkBtB,EACtB,SAAyB,EAAE,cAAW,GAAGE,KAAQ,GAAK;CACpD,IAAMD,IAAOmB,EAAWZ,CAAY,IAAI,SAAS;CAEjD,OAAO,kBAACP,GAAD;EAAW;EAAK,WAAWE,EAAGN,EAAO,aAAaO,CAAS;EAAG,GAAIF;CAAO,CAAA;AAClF,CACF,GAGMqB,IAAevB,EAAqD,SACxE,EAAE,cAAW,GAAGE,KAChB,GACA;CACA,IAAMD,IAAOmB,EAAWZ,CAAY,IAAI,SAAS;CAEjD,OAAO,kBAACP,GAAD;EAAW;EAAK,WAAWE,EAAGN,EAAO,UAAUO,CAAS;EAAG,GAAIF;CAAO,CAAA;AAC/E,CAAC,GAEYsB,IAAO,OAAO,OAAOzB,GAAU;CAC1C,MAAMW;CACN,SAASS;CACT,SAASE;CACT,aAAaC;CACb,UAAUC;AACZ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"List.module.js","names":["list","item","row","leading","content","description","trailing","List_module_default"],"sources":["../../../../src/components/display/List/List.module.css"],"sourcesContent":["/*\n * Component tokens (themes may set any of these on [data-theme]):\n * --list-inset default var(--space-2) — row padding-inline
|
|
1
|
+
{"version":3,"file":"List.module.js","names":["list","item","row","leading","content","description","trailing","List_module_default"],"sources":["../../../../src/components/display/List/List.module.css"],"sourcesContent":["/*\n * Component tokens (themes may set any of these on [data-theme]):\n * --list-inset default var(--space-2), var(--space-4) on a surface — row padding-inline\n * --list-row-radius default var(--radius-field), square on a surface — row fills\n * --list-trailing-size default: the row's text size (same as the title)\n * --list-rail-width default var(--space-1) — the categorical rail of a `color` row\n * --list-surface-bg default var(--color-surface), var(--color-surface-raised) when `raised`\n * --list-surface-radius default var(--radius-surface) — the sheet of a `surface` list\n * --highlight-tone-{positive,caution,critical,info}-text, --highlight-accent-text\n * tone text inside a highlighted row (shared with Table)\n *\n * Structure: li.item > .row (a div, or the asChild link/button) > slots. The row carries\n * padding, hover and focus so a linked row is one target edge to edge. Slots are divs, so\n * block components (Stat, Stack, a sized Media) fit in them, and spans inside an asChild row,\n * the only content a button may hold.\n */\n.list {\n --_inset: var(--space-2);\n --_row-radius: var(--radius-field);\n\n display: flex;\n flex-direction: column;\n margin: 0;\n padding: 0;\n list-style: none;\n font-family: var(--font-text);\n color: var(--color-ink);\n}\n\n/*\n * On a surface: the whole list on one sheet, with Card's edges (`outline` for surface,\n * `raised` for raised), so rows read as rows on a textured or busy canvas. Rows run edge to\n * edge and the sheet clips them to its radius, so a fill is a band across the sheet, and a\n * categorical rail sits flush with the sheet's inner edge and follows its corners on the\n * first and last rows. Rows take a wider inset so text clears the edge.\n */\n.list[data-surface] {\n --_inset: var(--space-4);\n --_row-radius: 0px;\n\n overflow: hidden;\n border: var(--border-width) solid var(--color-line);\n border-radius: var(--list-surface-radius, var(--radius-surface));\n background: var(--list-surface-bg, var(--color-surface));\n}\n.list[data-surface='raised'] {\n border-color: var(--color-line-strong);\n background: var(--list-surface-bg, var(--color-surface-raised));\n box-shadow: var(--shadow-surface);\n}\n\n.item {\n --_py: var(--space-3);\n --_fill: transparent;\n --_fill-ink: inherit;\n\n position: relative;\n min-inline-size: 0;\n}\n.list[data-density='compact'] > .item {\n --_py: var(--space-2);\n}\n\n.list[data-divided] > .item + .item {\n border-block-start: var(--border-width) solid var(--color-line);\n}\n/* A filled row doesn't need rules either side — the fill is its edge. */\n.list[data-divided] > .item:is([data-highlighted], [data-selected]),\n.list[data-divided] > .item:is([data-highlighted], [data-selected]) + .item {\n border-block-start-color: transparent;\n}\n\n.row {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n inline-size: 100%;\n min-inline-size: 0;\n margin: 0;\n padding-block: var(--_py);\n padding-inline: var(--list-inset, var(--_inset));\n border: 0;\n border-radius: var(--list-row-radius, var(--_row-radius));\n background: var(--_fill);\n color: var(--_fill-ink);\n font: inherit;\n text-align: start;\n text-decoration: none;\n transition: background-color var(--dur-1) var(--ease-out);\n}\n\n.item[data-selected] {\n --_fill: var(--color-accent-soft);\n --_fill-ink: var(--color-ink);\n}\n.item[data-highlighted] {\n --_fill: var(--color-highlight);\n --_fill-ink: var(--color-highlight-ink);\n --_band-positive: var(\n --highlight-tone-positive-text,\n color-mix(in oklab, var(--tone-positive-text) 75%, var(--color-highlight-ink))\n );\n --_band-caution: var(\n --highlight-tone-caution-text,\n color-mix(in oklab, var(--tone-caution-text) 75%, var(--color-highlight-ink))\n );\n --_band-critical: var(\n --highlight-tone-critical-text,\n color-mix(in oklab, var(--tone-critical-text) 75%, var(--color-highlight-ink))\n );\n --_band-info: var(\n --highlight-tone-info-text,\n color-mix(in oklab, var(--tone-info-text) 75%, var(--color-highlight-ink))\n );\n --_band-accent: var(\n --highlight-accent-text,\n color-mix(in oklab, var(--color-accent-text) 75%, var(--color-highlight-ink))\n );\n}\n\n/*\n * A filled row re-points the colour roles for its content, so a muted description, a\n * tone-coloured Numeral or a LiveIndicator stays legible on the fill (gold in Fiesta\n * night). The item publishes fill/ink under private names and the row swaps the roles —\n * redefining a role from itself on one element would be a var() cycle (see Section).\n */\n.item:is([data-highlighted], [data-selected]) > .row {\n --color-ink: var(--_fill-ink);\n --color-ink-muted: color-mix(in oklab, var(--_fill-ink), var(--_fill) 25%);\n --color-ink-subtle: color-mix(in oklab, var(--_fill-ink), var(--_fill) 35%);\n}\n.item[data-highlighted] > .row {\n --tone-positive-text: var(--_band-positive);\n --tone-caution-text: var(--_band-caution);\n --tone-critical-text: var(--_band-critical);\n --tone-info-text: var(--_band-info);\n --color-accent-text: var(--_band-accent);\n /* Soft fills (a soft Badge or Tag) tint the band, like Section's accent band, so the\n re-pointed tone texts above stay legible on them in every mode. */\n --tone-positive-soft: color-mix(in oklab, var(--_band-positive) 8%, var(--_fill));\n --tone-caution-soft: color-mix(in oklab, var(--_band-caution) 8%, var(--_fill));\n --tone-critical-soft: color-mix(in oklab, var(--_band-critical) 8%, var(--_fill));\n --tone-info-soft: color-mix(in oklab, var(--_band-info) 8%, var(--_fill));\n --color-accent-soft: color-mix(in oklab, var(--_band-accent) 8%, var(--_fill));\n}\n\n.item[data-interactive] > .row {\n cursor: pointer;\n}\n\n/* Muted: out of play. The title drops to the muted step, which still clears AA. */\n.item[data-muted] > .row {\n --color-ink: var(--color-ink-muted);\n\n color: var(--color-ink-muted);\n}\n\n/* A categorical rail in the row's start inset: whose row it is, in their Tag's colour. */\n.item[data-color]::before {\n content: '';\n position: absolute;\n inset-block: var(--space-1);\n inset-inline-start: 0;\n inline-size: var(--list-rail-width, var(--space-1));\n border-radius: var(--radius-chip);\n background: var(--_cat);\n}\n/* On a sheet the rail is an edge of the row: full height, square, and over the rule above it. */\n.list[data-surface] > .item[data-color]::before {\n inset-block: 0;\n border-radius: 0;\n}\n.list[data-surface][data-divided] > .item + .item[data-color]::before {\n inset-block-start: calc(var(--border-width) * -1);\n}\n.item[data-color='1'] {\n --_cat: var(--color-cat-1);\n}\n.item[data-color='2'] {\n --_cat: var(--color-cat-2);\n}\n.item[data-color='3'] {\n --_cat: var(--color-cat-3);\n}\n.item[data-color='4'] {\n --_cat: var(--color-cat-4);\n}\n.item[data-color='5'] {\n --_cat: var(--color-cat-5);\n}\n.item[data-color='6'] {\n --_cat: var(--color-cat-6);\n}\n.item[data-color='7'] {\n --_cat: var(--color-cat-7);\n}\n.item[data-color='8'] {\n --_cat: var(--color-cat-8);\n}\n.item[data-color] > .row {\n padding-inline-start: calc(var(--list-inset, var(--_inset)) + var(--space-2));\n}\n@media (hover: hover) {\n .item[data-interactive]:not([data-highlighted], [data-selected]) > .row:hover {\n background: var(--color-surface-sunken);\n }\n .item[data-interactive]:is([data-highlighted], [data-selected]) > .row:hover {\n background: color-mix(in oklch, var(--_fill) 88%, var(--color-ink));\n }\n}\n.row:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: -2px;\n}\n\n/* ── Slots ───────────────────────────────────────────────────────────────── */\n\n.leading {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: flex-end;\n min-inline-size: 2ch;\n color: var(--color-ink-muted);\n font-family: var(--font-numeric);\n font-stretch: var(--numeric-stretch);\n font-weight: var(--label-weight);\n font-variant-numeric: tabular-nums lining-nums;\n font-size: var(--text-md);\n}\n.item[data-highlighted] .leading {\n color: inherit;\n}\n\n.content {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: calc(var(--space-1) / 2);\n min-inline-size: 0;\n font-size: var(--text-md);\n font-weight: var(--label-weight);\n line-height: var(--leading-snug);\n /* Wrap between words; break inside one only when a single word can't fit the column. */\n overflow-wrap: break-word;\n}\n\n.description {\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n font-weight: 400;\n}\n\n.trailing {\n --stat-align: end;\n --stat-container-type: normal;\n\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: flex-end;\n gap: var(--space-2);\n margin-inline-start: auto;\n text-align: end;\n /*\n * The row's text face and size, with tabular figures: a bare \"7 tasks\" sits level with the\n * title instead of looming in the numeric face. Put a <Numeral>/<Amount> here for figures\n * that should carry the numeric face (receipt mono in Ledger).\n */\n font-variant-numeric: tabular-nums lining-nums;\n font-size: var(--list-trailing-size, var(--text-md));\n font-weight: var(--label-weight);\n line-height: var(--leading-snug);\n white-space: nowrap;\n}\n"],"mappings":""}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { List } from './List.js';
|
|
2
|
-
export type { ListProps, ListItemProps, ListDensity, ListElement } from './List.js';
|
|
2
|
+
export type { ListProps, ListItemProps, ListDensity, ListElement, ListSurface } from './List.js';
|
|
@@ -17,6 +17,8 @@ export interface MediaProps extends Omit<HTMLAttributes<HTMLElement>, 'children'
|
|
|
17
17
|
/**
|
|
18
18
|
* A fixed height, for a small image that sits inline beside text (a flag by a name, a logo
|
|
19
19
|
* in a row). The width follows `ratio`, or the image's own ratio when `ratio` is `auto`.
|
|
20
|
+
* With a fixed `ratio`, the image also gets `width` and `height` attributes, so its box is
|
|
21
|
+
* known before it loads; with `auto`, pass them in `imgProps`.
|
|
20
22
|
* Default: none, so the frame fills its container.
|
|
21
23
|
*/
|
|
22
24
|
size?: MediaSize;
|
|
@@ -3,49 +3,65 @@ import t from "./Media.module.js";
|
|
|
3
3
|
import { forwardRef as n, useEffect as r, useRef as i, useState as a } from "react";
|
|
4
4
|
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/display/Media/Media.tsx
|
|
6
|
-
var c =
|
|
7
|
-
|
|
6
|
+
var c = {
|
|
7
|
+
xs: 16,
|
|
8
|
+
sm: 20,
|
|
9
|
+
md: 24,
|
|
10
|
+
lg: 32,
|
|
11
|
+
xl: 96
|
|
12
|
+
};
|
|
13
|
+
function l(e, t) {
|
|
14
|
+
if (e === void 0 || t === "auto") return {};
|
|
15
|
+
let [n, r] = t.split("/").map(Number), i = c[e];
|
|
16
|
+
return {
|
|
17
|
+
width: Math.round(i * n / r),
|
|
18
|
+
height: i
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
var u = n(function({ src: n, alt: c, ratio: u = "auto", fit: d = "cover", radius: f = "media", size: p, dimmed: m = !1, caption: h, fallback: g, loading: _ = "lazy", imgProps: v, className: y, ...b }, x) {
|
|
22
|
+
let [S, C] = a(!1), w = i(null);
|
|
8
23
|
r(() => {
|
|
9
|
-
let e =
|
|
10
|
-
|
|
24
|
+
let e = w.current;
|
|
25
|
+
C(!!(e?.complete && e.naturalWidth === 0 && typeof e.currentSrc == "string" && e.currentSrc !== ""));
|
|
11
26
|
}, [n]);
|
|
12
|
-
let
|
|
13
|
-
return /* @__PURE__ */ s(
|
|
14
|
-
ref:
|
|
15
|
-
className: e(t.media,
|
|
16
|
-
"data-ratio":
|
|
17
|
-
"data-fit":
|
|
18
|
-
"data-radius":
|
|
19
|
-
"data-size":
|
|
20
|
-
"data-dimmed":
|
|
21
|
-
"data-failed":
|
|
22
|
-
...
|
|
23
|
-
children: [/* @__PURE__ */ o(
|
|
27
|
+
let T = h === void 0 ? p ? "span" : "div" : "figure", E = p ? "span" : "div";
|
|
28
|
+
return /* @__PURE__ */ s(T, {
|
|
29
|
+
ref: x,
|
|
30
|
+
className: e(t.media, y),
|
|
31
|
+
"data-ratio": u,
|
|
32
|
+
"data-fit": d,
|
|
33
|
+
"data-radius": f,
|
|
34
|
+
"data-size": p,
|
|
35
|
+
"data-dimmed": m || void 0,
|
|
36
|
+
"data-failed": S || void 0,
|
|
37
|
+
...b,
|
|
38
|
+
children: [/* @__PURE__ */ o(E, {
|
|
24
39
|
className: t.frame,
|
|
25
|
-
children:
|
|
40
|
+
children: S ? /* @__PURE__ */ o(E, {
|
|
26
41
|
className: t.fallback,
|
|
27
42
|
role: c ? "img" : void 0,
|
|
28
43
|
"aria-label": c || void 0,
|
|
29
|
-
children:
|
|
44
|
+
children: g
|
|
30
45
|
}) : /* @__PURE__ */ o("img", {
|
|
31
|
-
ref:
|
|
46
|
+
ref: w,
|
|
32
47
|
className: t.image,
|
|
33
48
|
src: n,
|
|
34
49
|
alt: c,
|
|
35
|
-
loading:
|
|
50
|
+
loading: _,
|
|
36
51
|
decoding: "async",
|
|
37
52
|
onError: () => {
|
|
38
|
-
|
|
53
|
+
C(!0);
|
|
39
54
|
},
|
|
40
|
-
...
|
|
55
|
+
...l(p, u),
|
|
56
|
+
...v
|
|
41
57
|
})
|
|
42
|
-
}),
|
|
58
|
+
}), h === void 0 ? null : /* @__PURE__ */ o("figcaption", {
|
|
43
59
|
className: t.caption,
|
|
44
|
-
children:
|
|
60
|
+
children: h
|
|
45
61
|
})]
|
|
46
62
|
});
|
|
47
63
|
});
|
|
48
64
|
//#endregion
|
|
49
|
-
export {
|
|
65
|
+
export { u as Media };
|
|
50
66
|
|
|
51
67
|
//# sourceMappingURL=Media.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Media.js","names":["styles","Media_module_default","Media","forwardRef","rest","failed","setFailed","useState","imgRef","useRef","img","src","Root","caption","
|
|
1
|
+
{"version":3,"file":"Media.js","names":["styles","Media_module_default","SIZE_PX","sizeHints","size","ratio","w","h","height","Media","forwardRef","rest","failed","setFailed","useState","imgRef","useRef","img","src","Root","caption","Box","cx","className","fit","radius","dimmed","alt","fallback","imgProps"],"sources":["../../../../src/components/display/Media/Media.tsx"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useRef,\n useState,\n type HTMLAttributes,\n type ImgHTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { cx } from '#utils/cx'\nimport styles from './Media.module.css'\n\nexport type MediaRatio = '1/1' | '4/3' | '3/2' | '16/9' | '21/9' | '3/4' | '2/3' | 'auto'\nexport type MediaFit = 'cover' | 'contain'\nexport type MediaRadius = 'none' | 'media' | 'surface'\n/** Fixed heights for inline thumbnails: about 16, 20, 24, 32 and 96px. */\nexport type MediaSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\n/** Nominal heights in px, for the image's width/height hints; the CSS sets the real size. */\nconst SIZE_PX: Record<MediaSize, number> = { xs: 16, sm: 20, md: 24, lg: 32, xl: 96 }\n\n/**\n * The width and height attributes a sized image carries, so the browser knows its box before it\n * loads (and audits don't flag it). Only known with a fixed ratio: an `auto` frame takes the\n * image's own ratio, so pass `imgProps.width`/`height` there.\n */\nfunction sizeHints(size: MediaSize | undefined, ratio: MediaRatio) {\n if (size === undefined || ratio === 'auto') return {}\n const [w, h] = ratio.split('/').map(Number) as [number, number]\n const height = SIZE_PX[size]\n return { width: Math.round((height * w) / h), height }\n}\n\nexport interface MediaProps extends Omit<HTMLAttributes<HTMLElement>, 'children'> {\n src: string\n /** Required. Describe the image; pass `\"\"` only when it's purely decorative. */\n alt: string\n /** Frame ratio. The image is fitted inside. Default `auto` (the image's own ratio). */\n ratio?: MediaRatio\n /** Default `cover`. Use `contain` for logos, diagrams and screenshots that must not crop. */\n fit?: MediaFit\n /** Corner role. Default `media`. */\n radius?: MediaRadius\n /**\n * A fixed height, for a small image that sits inline beside text (a flag by a name, a logo\n * in a row). The width follows `ratio`, or the image's own ratio when `ratio` is `auto`.\n * With a fixed `ratio`, the image also gets `width` and `height` attributes, so its box is\n * known before it loads; with `auto`, pass them in `imgProps`.\n * Default: none, so the frame fills its container.\n */\n size?: MediaSize\n /**\n * Out of play: the image fades toward grey but stays recognisable, like a knocked-out\n * team's flag or a past event's photo. Pair it with a muted `List.Item` or `Table.Row`.\n */\n dimmed?: boolean\n /** Renders a `<figure>` with this as its `<figcaption>`. */\n caption?: ReactNode\n /** Shown inside the frame if the image fails to load. Default: an empty sunken frame. */\n fallback?: ReactNode\n /** Default `lazy`. Use `eager` for the image above the fold. */\n loading?: 'lazy' | 'eager'\n /** Extra attributes for the `<img>` (srcSet, sizes, width/height, fetchPriority). */\n imgProps?: Omit<ImgHTMLAttributes<HTMLImageElement>, 'src' | 'alt' | 'loading'>\n}\n\n/**\n * A framed image with a fixed ratio, lazy loading, a caption, and a calm failure state.\n *\n * @remarks\n * `Media` frames an image: it holds a ratio while loading, fits the image, loads lazily, and when\n * the image fails it keeps its shape and shows a quiet fallback instead of a broken-image icon.\n *\n * @privateRemarks\n * A framed image: fixed ratio, fitted, lazy by default, with a caption and a graceful\n * failure state. Screenshots, company logos, scanned documents.\n *\n * <Media src=\"/images/dashboard.png\" alt=\"Revenue dashboard, September\" ratio=\"16/9\" caption=\"Dashboard, 2026\" />\n */\nexport const Media = forwardRef<HTMLElement, MediaProps>(function Media(\n {\n src,\n alt,\n ratio = 'auto',\n fit = 'cover',\n radius = 'media',\n size,\n dimmed = false,\n caption,\n fallback,\n loading = 'lazy',\n imgProps,\n className,\n ...rest\n },\n ref,\n) {\n const [failed, setFailed] = useState(false)\n const imgRef = useRef<HTMLImageElement>(null)\n\n // Reset when the source changes; also catch an error that fired before hydration.\n useEffect(() => {\n const img = imgRef.current\n setFailed(\n Boolean(\n img?.complete &&\n img.naturalWidth === 0 &&\n typeof img.currentSrc === 'string' &&\n img.currentSrc !== '',\n ),\n )\n }, [src])\n\n // A sized thumbnail is phrasing content (spans), so it can sit in a button or a line of text.\n const Root = caption !== undefined ? 'figure' : size ? 'span' : 'div'\n const Box = size ? 'span' : 'div'\n return (\n <Root\n // @ts-expect-error — polymorphic ref across figure/div is safe here\n ref={ref}\n className={cx(styles.media, className)}\n data-ratio={ratio}\n data-fit={fit}\n data-radius={radius}\n data-size={size}\n data-dimmed={dimmed || undefined}\n data-failed={failed || undefined}\n {...rest}\n >\n <Box className={styles.frame}>\n {failed ? (\n <Box\n className={styles.fallback}\n role={alt ? 'img' : undefined}\n aria-label={alt || undefined}\n >\n {fallback}\n </Box>\n ) : (\n <img\n ref={imgRef}\n className={styles.image}\n src={src}\n alt={alt}\n loading={loading}\n decoding=\"async\"\n onError={() => {\n setFailed(true)\n }}\n {...sizeHints(size, ratio)}\n {...imgProps}\n />\n )}\n </Box>\n {caption !== undefined ? <figcaption className={styles.caption}>{caption}</figcaption> : null}\n </Root>\n )\n})\n"],"mappings":";;;;;AAmBA,IAAME,IAAqC;CAAE,IAAI;CAAI,IAAI;CAAI,IAAI;CAAI,IAAI;CAAI,IAAI;AAAG;AAOpF,SAASC,EAAU,GAA6B,GAAmB;CACjE,IAAIC,MAAS,KAAA,KAAaC,MAAU,QAAQ,OAAO,CAAC;CACpD,IAAM,CAACC,GAAGC,KAAKF,EAAM,MAAM,GAAG,CAAC,CAAC,IAAI,MAAM,GACpCG,IAASN,EAAQE;CACvB,OAAO;EAAE,OAAO,KAAK,MAAOI,IAASF,IAAKC,CAAC;EAAG;CAAO;AACvD;AAgDA,IAAaE,IAAQC,EAAoC,SACvD,EACE,QACA,QACA,WAAQ,QACR,SAAM,SACN,YAAS,SACT,SACA,YAAS,IACT,YACA,aACA,aAAU,QACV,aACA,cACA,GAAGC,KAEL,GACA;CACA,IAAM,CAACC,GAAQC,KAAaC,EAAS,EAAK,GACpCC,IAASC,EAAyB,IAAI;CAG5C,QAAgB;EACd,IAAMC,IAAMF,EAAO;EACnB,EACE,GACEE,GAAK,YACLA,EAAI,iBAAiB,KACrB,OAAOA,EAAI,cAAe,YAC1BA,EAAI,eAAe,GAEvB;CACF,GAAG,CAACC,CAAG,CAAC;CAGR,IAAMC,IAAOC,MAAY,KAAA,IAAuBhB,IAAO,SAAS,QAA3B,UAC/BiB,IAAMjB,IAAO,SAAS;CAC5B,OACE,kBAACe,GAAD;EAEO;EACL,WAAWG,EAAGtB,EAAO,OAAOuB,CAAS;EACrC,cAAYlB;EACZ,YAAUmB;EACV,eAAaC;EACb,aAAWrB;EACX,eAAasB,KAAU,KAAA;EACvB,eAAad,KAAU,KAAA;EACvB,GAAID;EAVN,UAAA,CAYE,kBAACU,GAAD;GAAK,WAAWrB,EAAO;GACpB,UAAAY,IACC,kBAACS,GAAD;IACE,WAAWrB,EAAO;IAClB,MAAM2B,IAAM,QAAQ,KAAA;IACpB,cAAYA,KAAO,KAAA;IAElB,UAAAC;GACE,CAAA,IAEL,kBAAC,OAAD;IACE,KAAKb;IACL,WAAWf,EAAO;IACb;IACA;IACI;IACT,UAAS;IACT,eAAe;KACb,EAAU,EAAI;IAChB;IACA,GAAIG,EAAUC,GAAMC,CAAK;IACzB,GAAIwB;GACL,CAAA;EAEA,CAAA,GACJT,MAAY,KAAA,IAA4E,OAAhE,kBAAC,cAAD;GAAY,WAAWpB,EAAO;GAAU,UAAAoB;EAAoB,CAAA,CACjF;;AAEV,CAAC"}
|
|
@@ -3,7 +3,11 @@ import type { CategoryColor } from '../../../utils/tokens.js';
|
|
|
3
3
|
import { type VisibilityProps } from '../../../utils/visibility.js';
|
|
4
4
|
export type TableDensity = 'compact' | 'regular';
|
|
5
5
|
export type TableVariant = 'rules' | 'plain';
|
|
6
|
+
/** `surface` and `raised` set the table on one sheet, like `Card`'s `outline` and `raised`. */
|
|
7
|
+
export type TableSurface = 'none' | 'surface' | 'raised';
|
|
6
8
|
export type TableAlign = 'start' | 'center' | 'end';
|
|
9
|
+
/** Where body and footer cells sit in a row taller than their content. */
|
|
10
|
+
export type TableVerticalAlign = 'middle' | 'baseline' | 'top';
|
|
7
11
|
export type TableSort = 'asc' | 'desc' | 'none';
|
|
8
12
|
/** `fill` takes the spare width (the name column); `min` shrinks to its content. */
|
|
9
13
|
export type TableColumnWidth = 'fill' | 'min';
|
|
@@ -12,8 +16,21 @@ export interface TableProps extends TableHTMLAttributes<HTMLTableElement> {
|
|
|
12
16
|
density?: TableDensity;
|
|
13
17
|
/** `rules` (default): a hairline under every row. `plain`: only the header rule. */
|
|
14
18
|
variant?: TableVariant;
|
|
19
|
+
/**
|
|
20
|
+
* Where cell content sits when a row's cells differ in height (a flag and a tag beside plain
|
|
21
|
+
* figures). `baseline` (the default) lines up the first line of text across the row;
|
|
22
|
+
* `middle` centres every cell, so figures sit level with a name that has a flag or a tag beside
|
|
23
|
+
* or under it; `top` pins each cell to the row's top. Header cells always sit on the header rule.
|
|
24
|
+
*/
|
|
25
|
+
valign?: TableVerticalAlign;
|
|
15
26
|
/** Alternate row fills. Off by default — rules usually read better. */
|
|
16
27
|
striped?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Set the table on a sheet so its rows read as rows, not text on the page: `surface` is the
|
|
30
|
+
* surface fill inside a hairline edge, `raised` stands on the theme's surface shadow. Rows run
|
|
31
|
+
* edge to edge, clipped to the sheet's corners, with a little more air. Default `none`.
|
|
32
|
+
*/
|
|
33
|
+
surface?: TableSurface;
|
|
17
34
|
/**
|
|
18
35
|
* Keep the header visible while rows scroll. The wrapper becomes the scroll container
|
|
19
36
|
* (capped by `--table-max-height`, default 70vh), since a horizontally scrolling wrapper
|
|
@@ -5,22 +5,25 @@ import i from "./Table.module.js";
|
|
|
5
5
|
import { forwardRef as a } from "react";
|
|
6
6
|
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
7
7
|
//#region src/components/display/Table/Table.tsx
|
|
8
|
-
var c = a(function({ density: t = "regular", variant: n = "rules",
|
|
8
|
+
var c = a(function({ density: t = "regular", variant: n = "rules", valign: r = "baseline", striped: a = !1, surface: s = "none", stickyHeader: c = !1, label: l, className: u, ...d }, f) {
|
|
9
9
|
return /* @__PURE__ */ o("div", {
|
|
10
10
|
className: i.scroll,
|
|
11
11
|
"data-kiln-component": "",
|
|
12
|
-
"data-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
|
|
12
|
+
"data-surface": s === "none" ? void 0 : s,
|
|
13
|
+
"data-sticky-header": c || void 0,
|
|
14
|
+
role: l ? "region" : void 0,
|
|
15
|
+
"aria-label": l,
|
|
16
|
+
tabIndex: l ? 0 : void 0,
|
|
16
17
|
children: /* @__PURE__ */ o("table", {
|
|
17
|
-
ref:
|
|
18
|
-
className: e(i.table,
|
|
18
|
+
ref: f,
|
|
19
|
+
className: e(i.table, u),
|
|
19
20
|
"data-density": t,
|
|
20
21
|
"data-variant": n,
|
|
21
|
-
"data-
|
|
22
|
-
"data-
|
|
23
|
-
|
|
22
|
+
"data-valign": r,
|
|
23
|
+
"data-striped": a || void 0,
|
|
24
|
+
"data-surface": s === "none" ? void 0 : s,
|
|
25
|
+
"data-sticky-header": c || void 0,
|
|
26
|
+
...d
|
|
24
27
|
})
|
|
25
28
|
});
|
|
26
29
|
}), l = a(function({ className: t, ...n }, r) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.js","names":["styles","Table_module_default","TableRoot","forwardRef","rest","stickyHeader","label","cx","className","density","variant","striped","TableHead","TableBody","TableFoot","TableRow","highlighted","interactive","muted","color","ARIA_SORT","TableHeaderCell","sortable","sort","onSort","visibilityClass","align","numeric","width","children","jsx","ChevronUpIcon","ChevronDownIcon","TableCell","shared","rowHeader","thRest","TableCaption","Table"],"sources":["../../../../src/components/display/Table/Table.tsx"],"sourcesContent":["import {\n forwardRef,\n type HTMLAttributes,\n type TableHTMLAttributes,\n type TdHTMLAttributes,\n type ThHTMLAttributes,\n} from 'react'\nimport { cx } from '#utils/cx'\nimport type { CategoryColor } from '#utils/tokens'\nimport { visibilityClass, type VisibilityProps } from '#utils/visibility'\nimport { ChevronDownIcon, ChevronUpIcon } from '#icons'\nimport styles from './Table.module.css'\n\nexport type TableDensity = 'compact' | 'regular'\nexport type TableVariant = 'rules' | 'plain'\nexport type TableAlign = 'start' | 'center' | 'end'\nexport type TableSort = 'asc' | 'desc' | 'none'\n/** `fill` takes the spare width (the name column); `min` shrinks to its content. */\nexport type TableColumnWidth = 'fill' | 'min'\n\nexport interface TableProps extends TableHTMLAttributes<HTMLTableElement> {\n /** Row height. Default `regular`. */\n density?: TableDensity\n /** `rules` (default): a hairline under every row. `plain`: only the header rule. */\n variant?: TableVariant\n /** Alternate row fills. Off by default — rules usually read better. */\n striped?: boolean\n /**\n * Keep the header visible while rows scroll. The wrapper becomes the scroll container\n * (capped by `--table-max-height`, default 70vh), since a horizontally scrolling wrapper\n * would otherwise trap a page-sticky header.\n */\n stickyHeader?: boolean\n /**\n * Name for the scroll container. When set, the wrapper becomes a focusable, labelled\n * region so keyboard users can scroll a wide table.\n */\n label?: string\n}\n\n/**\n * A semantic data table with numeric columns that line up, sortable headers and a footer for\n * totals.\n *\n * @remarks\n * `Table` is a real `<table>` with Kiln's styles: rules between rows, numeric columns in tabular\n * figures, and a wrapper that scrolls sideways on narrow screens instead of breaking the layout.\n *\n * ## Density, stripes and sticky headers\n *\n * `density=\"compact\"` for dense data, `striped` for alternating fills (rules usually read better),\n * and `stickyHeader` to keep the header in view while the rows scroll inside the table.\n *\n * @privateRemarks\n * A semantic, styled data table: project boards, ledgers, audit logs. The wrapper scrolls\n * horizontally on narrow screens; `ref` and native props go to the `<table>`.\n *\n * <Table><Table.Head><Table.Row><Table.HeaderCell>Project</Table.HeaderCell>…</Table.Row></Table.Head>…</Table>\n */\nconst TableRoot = forwardRef<HTMLTableElement, TableProps>(function Table(\n {\n density = 'regular',\n variant = 'rules',\n striped = false,\n stickyHeader = false,\n label,\n className,\n ...rest\n },\n ref,\n) {\n return (\n <div\n className={styles.scroll}\n data-kiln-component=\"\"\n data-sticky-header={stickyHeader || undefined}\n role={label ? 'region' : undefined}\n aria-label={label}\n tabIndex={label ? 0 : undefined}\n >\n <table\n ref={ref}\n className={cx(styles.table, className)}\n data-density={density}\n data-variant={variant}\n data-striped={striped || undefined}\n data-sticky-header={stickyHeader || undefined}\n {...rest}\n />\n </div>\n )\n})\n\nconst TableHead = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n function TableHead({ className, ...rest }, ref) {\n return <thead ref={ref} className={cx(styles.head, className)} {...rest} />\n },\n)\n\nconst TableBody = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n function TableBody({ className, ...rest }, ref) {\n return <tbody ref={ref} className={cx(styles.body, className)} {...rest} />\n },\n)\n\n/** Totals row(s). Set above a strong rule. */\nconst TableFoot = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n function TableFoot({ className, ...rest }, ref) {\n return <tfoot ref={ref} className={cx(styles.foot, className)} {...rest} />\n },\n)\n\nexport interface TableRowProps extends Omit<HTMLAttributes<HTMLTableRowElement>, 'color'> {\n /** `--color-highlight` fill — \"you\", your project, the circled line. */\n highlighted?: boolean\n /** Hover fill for rows that respond to clicks (put the real link in a cell). */\n interactive?: boolean\n /** Out of play (eliminated, archived, past): every ink drops to the muted step, which still reads. */\n muted?: boolean\n /** A categorical colour drawn as a rail at the row's start: whose row it is, matching their `Tag`. */\n color?: CategoryColor\n}\n\nconst TableRow = forwardRef<HTMLTableRowElement, TableRowProps>(function TableRow(\n { highlighted = false, interactive = false, muted = false, color, className, ...rest },\n ref,\n) {\n return (\n <tr\n ref={ref}\n className={cx(styles.row, className)}\n data-highlighted={highlighted || undefined}\n data-interactive={interactive || undefined}\n data-muted={muted || undefined}\n data-color={color}\n {...rest}\n />\n )\n})\n\nexport interface TableHeaderCellProps\n extends Omit<ThHTMLAttributes<HTMLTableCellElement>, 'align' | 'width'>, VisibilityProps {\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. Default: automatic. */\n width?: TableColumnWidth\n /** Current sort of this column. With `onSort`, the label becomes a button and `aria-sort` is set. */\n sort?: TableSort\n /** Called when the sort button is pressed. Decide the next direction yourself. */\n onSort?: () => void\n}\n\nconst ARIA_SORT = { asc: 'ascending', desc: 'descending', none: 'none' } as const\n\nconst TableHeaderCell = forwardRef<HTMLTableCellElement, TableHeaderCellProps>(\n function TableHeaderCell(\n {\n align,\n numeric = false,\n width,\n sort,\n onSort,\n hideBelow,\n hideAbove,\n scope = 'col',\n className,\n children,\n ...rest\n },\n ref,\n ) {\n const sortable = sort !== undefined && onSort !== undefined\n return (\n <th\n ref={ref}\n scope={scope}\n className={cx(styles.headerCell, visibilityClass({ hideBelow, hideAbove }), className)}\n data-align={align ?? (numeric ? 'end' : undefined)}\n data-numeric={numeric || undefined}\n data-width={width}\n data-sort={sortable ? sort : undefined}\n aria-sort={sort !== undefined ? ARIA_SORT[sort] : undefined}\n {...rest}\n >\n {sortable ? (\n <button type=\"button\" className={styles.sortButton} onClick={onSort}>\n {children}\n <span className={styles.sortGlyph} aria-hidden=\"true\">\n {sort === 'asc' ? <ChevronUpIcon /> : <ChevronDownIcon />}\n </span>\n </button>\n ) : (\n children\n )}\n </th>\n )\n },\n)\n\n/**\n * Hide a column on small screens: put the same `hideBelow` on its HeaderCell and on\n * every Cell in that column (cells are `display: none`, so the columns stay aligned).\n */\nexport interface TableCellProps\n extends Omit<TdHTMLAttributes<HTMLTableCellElement>, 'align'>, VisibilityProps {\n align?: TableAlign\n /** Figures: right-aligned, tabular, in the theme's numeric face (mono in Ledger). */\n numeric?: boolean\n /** Render as `<th scope=\"row\">` — the cell that names the row (project, client). */\n rowHeader?: boolean\n}\n\nconst TableCell = forwardRef<HTMLTableCellElement, TableCellProps>(function TableCell(\n { align, numeric = false, rowHeader = false, hideBelow, hideAbove, className, ...rest },\n ref,\n) {\n const shared = {\n className: cx(styles.cell, visibilityClass({ hideBelow, hideAbove }), className),\n 'data-align': align ?? (numeric ? 'end' : undefined),\n 'data-numeric': numeric || undefined,\n 'data-row-header': rowHeader || undefined,\n }\n if (rowHeader) {\n const { scope = 'row', ...thRest } = rest as ThHTMLAttributes<HTMLTableCellElement>\n return <th ref={ref} scope={scope} {...shared} {...thRest} />\n }\n return <td ref={ref} {...shared} {...rest} />\n})\n\nconst TableCaption = forwardRef<HTMLTableCaptionElement, HTMLAttributes<HTMLTableCaptionElement>>(\n function TableCaption({ className, ...rest }, ref) {\n return <caption ref={ref} className={cx(styles.caption, className)} {...rest} />\n },\n)\n\nexport const Table = Object.assign(TableRoot, {\n Head: TableHead,\n Body: TableBody,\n Foot: TableFoot,\n Row: TableRow,\n HeaderCell: TableHeaderCell,\n Cell: TableCell,\n Caption: TableCaption,\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Table.js","names":["styles","Table_module_default","TableRoot","forwardRef","rest","surface","stickyHeader","label","cx","className","density","variant","valign","striped","TableHead","TableBody","TableFoot","TableRow","highlighted","interactive","muted","color","ARIA_SORT","TableHeaderCell","sortable","sort","onSort","visibilityClass","align","numeric","width","children","jsx","ChevronUpIcon","ChevronDownIcon","TableCell","shared","rowHeader","thRest","TableCaption","Table"],"sources":["../../../../src/components/display/Table/Table.tsx"],"sourcesContent":["import {\n forwardRef,\n type HTMLAttributes,\n type TableHTMLAttributes,\n type TdHTMLAttributes,\n type ThHTMLAttributes,\n} from 'react'\nimport { cx } from '#utils/cx'\nimport type { CategoryColor } from '#utils/tokens'\nimport { visibilityClass, type VisibilityProps } from '#utils/visibility'\nimport { ChevronDownIcon, ChevronUpIcon } from '#icons'\nimport styles from './Table.module.css'\n\nexport type TableDensity = 'compact' | 'regular'\nexport type TableVariant = 'rules' | 'plain'\n/** `surface` and `raised` set the table on one sheet, like `Card`'s `outline` and `raised`. */\nexport type TableSurface = 'none' | 'surface' | 'raised'\nexport type TableAlign = 'start' | 'center' | 'end'\n/** Where body and footer cells sit in a row taller than their content. */\nexport type TableVerticalAlign = 'middle' | 'baseline' | 'top'\nexport type TableSort = 'asc' | 'desc' | 'none'\n/** `fill` takes the spare width (the name column); `min` shrinks to its content. */\nexport type TableColumnWidth = 'fill' | 'min'\n\nexport interface TableProps extends TableHTMLAttributes<HTMLTableElement> {\n /** Row height. Default `regular`. */\n density?: TableDensity\n /** `rules` (default): a hairline under every row. `plain`: only the header rule. */\n variant?: TableVariant\n /**\n * Where cell content sits when a row's cells differ in height (a flag and a tag beside plain\n * figures). `baseline` (the default) lines up the first line of text across the row;\n * `middle` centres every cell, so figures sit level with a name that has a flag or a tag beside\n * or under it; `top` pins each cell to the row's top. Header cells always sit on the header rule.\n */\n valign?: TableVerticalAlign\n /** Alternate row fills. Off by default — rules usually read better. */\n striped?: boolean\n /**\n * Set the table on a sheet so its rows read as rows, not text on the page: `surface` is the\n * surface fill inside a hairline edge, `raised` stands on the theme's surface shadow. Rows run\n * edge to edge, clipped to the sheet's corners, with a little more air. Default `none`.\n */\n surface?: TableSurface\n /**\n * Keep the header visible while rows scroll. The wrapper becomes the scroll container\n * (capped by `--table-max-height`, default 70vh), since a horizontally scrolling wrapper\n * would otherwise trap a page-sticky header.\n */\n stickyHeader?: boolean\n /**\n * Name for the scroll container. When set, the wrapper becomes a focusable, labelled\n * region so keyboard users can scroll a wide table.\n */\n label?: string\n}\n\n/**\n * A semantic data table with numeric columns that line up, sortable headers and a footer for\n * totals.\n *\n * @remarks\n * `Table` is a real `<table>` with Kiln's styles: rules between rows, numeric columns in tabular\n * figures, and a wrapper that scrolls sideways on narrow screens instead of breaking the layout.\n *\n * ## Density, stripes and sticky headers\n *\n * `density=\"compact\"` for dense data, `striped` for alternating fills (rules usually read better),\n * and `stickyHeader` to keep the header in view while the rows scroll inside the table.\n *\n * ## On a surface\n *\n * On a busy page, or a theme whose canvas has a texture, `surface=\"surface\"` sets the table on one\n * sheet, and `surface=\"raised\"` stands it on the theme's surface shadow. Rows run edge to edge and\n * get a little more air: a highlighted row is a band across the sheet, a categorical rail is the\n * row's edge, and the sheet scrolls sideways with the table.\n *\n * @privateRemarks\n * A semantic, styled data table: project boards, ledgers, audit logs. The wrapper scrolls\n * horizontally on narrow screens; `ref` and native props go to the `<table>`.\n *\n * <Table><Table.Head><Table.Row><Table.HeaderCell>Project</Table.HeaderCell>…</Table.Row></Table.Head>…</Table>\n */\nconst TableRoot = forwardRef<HTMLTableElement, TableProps>(function Table(\n {\n density = 'regular',\n variant = 'rules',\n valign = 'baseline',\n striped = false,\n surface = 'none',\n stickyHeader = false,\n label,\n className,\n ...rest\n },\n ref,\n) {\n return (\n <div\n className={styles.scroll}\n data-kiln-component=\"\"\n data-surface={surface === 'none' ? undefined : surface}\n data-sticky-header={stickyHeader || undefined}\n role={label ? 'region' : undefined}\n aria-label={label}\n tabIndex={label ? 0 : undefined}\n >\n <table\n ref={ref}\n className={cx(styles.table, className)}\n data-density={density}\n data-variant={variant}\n data-valign={valign}\n data-striped={striped || undefined}\n data-surface={surface === 'none' ? undefined : surface}\n data-sticky-header={stickyHeader || undefined}\n {...rest}\n />\n </div>\n )\n})\n\nconst TableHead = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n function TableHead({ className, ...rest }, ref) {\n return <thead ref={ref} className={cx(styles.head, className)} {...rest} />\n },\n)\n\nconst TableBody = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n function TableBody({ className, ...rest }, ref) {\n return <tbody ref={ref} className={cx(styles.body, className)} {...rest} />\n },\n)\n\n/** Totals row(s). Set above a strong rule. */\nconst TableFoot = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n function TableFoot({ className, ...rest }, ref) {\n return <tfoot ref={ref} className={cx(styles.foot, className)} {...rest} />\n },\n)\n\nexport interface TableRowProps extends Omit<HTMLAttributes<HTMLTableRowElement>, 'color'> {\n /** `--color-highlight` fill — \"you\", your project, the circled line. */\n highlighted?: boolean\n /** Hover fill for rows that respond to clicks (put the real link in a cell). */\n interactive?: boolean\n /** Out of play (eliminated, archived, past): every ink drops to the muted step, which still reads. */\n muted?: boolean\n /** A categorical colour drawn as a rail at the row's start: whose row it is, matching their `Tag`. */\n color?: CategoryColor\n}\n\nconst TableRow = forwardRef<HTMLTableRowElement, TableRowProps>(function TableRow(\n { highlighted = false, interactive = false, muted = false, color, className, ...rest },\n ref,\n) {\n return (\n <tr\n ref={ref}\n className={cx(styles.row, className)}\n data-highlighted={highlighted || undefined}\n data-interactive={interactive || undefined}\n data-muted={muted || undefined}\n data-color={color}\n {...rest}\n />\n )\n})\n\nexport interface TableHeaderCellProps\n extends Omit<ThHTMLAttributes<HTMLTableCellElement>, 'align' | 'width'>, VisibilityProps {\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. Default: automatic. */\n width?: TableColumnWidth\n /** Current sort of this column. With `onSort`, the label becomes a button and `aria-sort` is set. */\n sort?: TableSort\n /** Called when the sort button is pressed. Decide the next direction yourself. */\n onSort?: () => void\n}\n\nconst ARIA_SORT = { asc: 'ascending', desc: 'descending', none: 'none' } as const\n\nconst TableHeaderCell = forwardRef<HTMLTableCellElement, TableHeaderCellProps>(\n function TableHeaderCell(\n {\n align,\n numeric = false,\n width,\n sort,\n onSort,\n hideBelow,\n hideAbove,\n scope = 'col',\n className,\n children,\n ...rest\n },\n ref,\n ) {\n const sortable = sort !== undefined && onSort !== undefined\n return (\n <th\n ref={ref}\n scope={scope}\n className={cx(styles.headerCell, visibilityClass({ hideBelow, hideAbove }), className)}\n data-align={align ?? (numeric ? 'end' : undefined)}\n data-numeric={numeric || undefined}\n data-width={width}\n data-sort={sortable ? sort : undefined}\n aria-sort={sort !== undefined ? ARIA_SORT[sort] : undefined}\n {...rest}\n >\n {sortable ? (\n <button type=\"button\" className={styles.sortButton} onClick={onSort}>\n {children}\n <span className={styles.sortGlyph} aria-hidden=\"true\">\n {sort === 'asc' ? <ChevronUpIcon /> : <ChevronDownIcon />}\n </span>\n </button>\n ) : (\n children\n )}\n </th>\n )\n },\n)\n\n/**\n * Hide a column on small screens: put the same `hideBelow` on its HeaderCell and on\n * every Cell in that column (cells are `display: none`, so the columns stay aligned).\n */\nexport interface TableCellProps\n extends Omit<TdHTMLAttributes<HTMLTableCellElement>, 'align'>, VisibilityProps {\n align?: TableAlign\n /** Figures: right-aligned, tabular, in the theme's numeric face (mono in Ledger). */\n numeric?: boolean\n /** Render as `<th scope=\"row\">` — the cell that names the row (project, client). */\n rowHeader?: boolean\n}\n\nconst TableCell = forwardRef<HTMLTableCellElement, TableCellProps>(function TableCell(\n { align, numeric = false, rowHeader = false, hideBelow, hideAbove, className, ...rest },\n ref,\n) {\n const shared = {\n className: cx(styles.cell, visibilityClass({ hideBelow, hideAbove }), className),\n 'data-align': align ?? (numeric ? 'end' : undefined),\n 'data-numeric': numeric || undefined,\n 'data-row-header': rowHeader || undefined,\n }\n if (rowHeader) {\n const { scope = 'row', ...thRest } = rest as ThHTMLAttributes<HTMLTableCellElement>\n return <th ref={ref} scope={scope} {...shared} {...thRest} />\n }\n return <td ref={ref} {...shared} {...rest} />\n})\n\nconst TableCaption = forwardRef<HTMLTableCaptionElement, HTMLAttributes<HTMLTableCaptionElement>>(\n function TableCaption({ className, ...rest }, ref) {\n return <caption ref={ref} className={cx(styles.caption, className)} {...rest} />\n },\n)\n\nexport const Table = Object.assign(TableRoot, {\n Head: TableHead,\n Body: TableBody,\n Foot: TableFoot,\n Row: TableRow,\n HeaderCell: TableHeaderCell,\n Cell: TableCell,\n Caption: TableCaption,\n})\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.module.js","names":["scroll","table","caption","headerCell","cell","body","row","foot","head","sortButton","sortGlyph","Table_module_default"],"sources":["../../../../src/components/display/Table/Table.module.css"],"sourcesContent":["/*\n * Component tokens (themes may set any of these on [data-theme]):\n * --table-head-font default var(--font-text) — Fiesta sets its display caps\n * --table-head-numeric-font numeric header cells, default var(--table-head-font, var(--font-text))\n * --table-head-size default var(--text-sm)\n * --table-head-weight default var(--label-weight)\n * --table-head-transform default var(--heading-transform)\n * --table-head-bg default var(--color-canvas) — only painted when stickyHeader\n * --table-max-height default 70vh — scroll height when stickyHeader\n * --table-rail-width default var(--space-1) — the categorical rail of a `color` row\n * --table-foot-rule the rule over totals, default var(--border-width-strong) solid\n * var(--color-line-strong) — Ledger draws the accountant's double rule\n * --highlight-tone-{positive,caution,critical,info}-text, --highlight-accent-text\n * tone text inside a highlighted row (shared with List). Default:\n * the tone text mixed 25% toward --color-highlight-ink.\n *\n * Headers are labels, so they're set in the text face (monospace as decoration for small\n * labels is banned in DESIGN §2); figures below them carry the numeric face.\n */\n.scroll {\n inline-size: 100%;\n min-inline-size: 0;\n overflow-x: auto;\n overscroll-behavior-x: contain;\n}\n.scroll[data-sticky-header] {\n overflow: auto;\n max-block-size: var(--table-max-height, 70vh);\n}\n.scroll:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 2px;\n}\n\n.table {\n --_py: var(--space-2);\n --_px: var(--space-3);\n\n inline-size: 100%;\n border-collapse: separate;\n border-spacing: 0;\n font-family: var(--font-text);\n font-size: var(--text-sm);\n line-height: var(--leading-snug);\n color: var(--color-ink);\n}\n.table[data-density='compact'] {\n --_py: var(--space-1);\n --_px: var(--space-2);\n}\n\n.caption {\n caption-side: top;\n padding-block-end: var(--space-3);\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n text-align: start;\n}\n\n/* ── Cells ─────────────────────────────────────────────────────────────── */\n\n.headerCell,\n.cell {\n padding: var(--_py) var(--_px);\n text-align: start;\n vertical-align: baseline;\n}\n.headerCell:first-child,\n.cell:first-child {\n padding-inline-start: var(--space-2);\n}\n.headerCell:last-child,\n.cell:last-child {\n padding-inline-end: var(--space-2);\n}\n/* Figure columns are narrow; tighter gutters keep a 10-column figures table on a phone. */\n:is(.headerCell, .cell)[data-numeric] {\n padding-inline: var(--space-2);\n}\n.headerCell abbr {\n text-decoration: none;\n cursor: help;\n}\n:is(.headerCell, .cell)[data-align='center'] {\n text-align: center;\n}\n:is(.headerCell, .cell)[data-align='end'] {\n text-align: end;\n}\n\n.headerCell {\n padding-block: var(--_py);\n color: var(--color-ink-muted);\n font-family: var(--table-head-font, var(--font-text));\n font-size: var(--table-head-size, var(--text-sm));\n font-weight: var(--table-head-weight, var(--label-weight));\n letter-spacing: var(--label-tracking);\n text-transform: var(--table-head-transform, var(--heading-transform));\n white-space: nowrap;\n vertical-align: bottom;\n border-block-end: var(--border-width-strong) solid var(--color-line-strong);\n}\n\n.headerCell[data-numeric] {\n font-family: var(--table-head-numeric-font, var(--table-head-font, var(--font-text)));\n font-variant-numeric: tabular-nums lining-nums;\n}\n.headerCell[data-width='fill'] {\n inline-size: 100%;\n}\n.headerCell[data-width='min'] {\n inline-size: 1%;\n}\n\n.cell[data-numeric] {\n font-family: var(--font-numeric);\n font-stretch: var(--numeric-stretch);\n font-variant-numeric: tabular-nums lining-nums;\n white-space: nowrap;\n}\n.cell[data-row-header] {\n font-weight: var(--label-weight);\n}\n\n/* ── Rows ──────────────────────────────────────────────────────────────── */\n\n.table[data-variant='rules'] .body .cell {\n border-block-end: var(--border-width) solid var(--color-line);\n}\n.table[data-variant='rules'] .body > .row:last-child > .cell {\n border-block-end-color: var(--color-line-strong);\n}\n\n.table[data-striped] .body > .row:nth-child(even) > .cell {\n background: var(--color-surface-sunken);\n}\n\n/*\n * A highlighted row re-points the colour roles for its cells' content, so a muted date,\n * a tone-coloured Numeral or a LiveIndicator stays legible on the highlight fill (gold in\n * Fiesta night, where the ordinary tone texts are pale). Same approach as Section's\n * inverse band: the row publishes its fill/ink and tone texts under private names, and\n * the cells swap the roles — setting e.g. --tone-positive-text from itself on one element\n * would be a var() cycle.\n */\n.row[data-highlighted] {\n --_band-fill: var(--color-highlight);\n --_band-ink: var(--color-highlight-ink);\n --_band-positive: var(\n --highlight-tone-positive-text,\n color-mix(in oklab, var(--tone-positive-text) 75%, var(--color-highlight-ink))\n );\n --_band-caution: var(\n --highlight-tone-caution-text,\n color-mix(in oklab, var(--tone-caution-text) 75%, var(--color-highlight-ink))\n );\n --_band-critical: var(\n --highlight-tone-critical-text,\n color-mix(in oklab, var(--tone-critical-text) 75%, var(--color-highlight-ink))\n );\n --_band-info: var(\n --highlight-tone-info-text,\n color-mix(in oklab, var(--tone-info-text) 75%, var(--color-highlight-ink))\n );\n --_band-accent: var(\n --highlight-accent-text,\n color-mix(in oklab, var(--color-accent-text) 75%, var(--color-highlight-ink))\n );\n}\n.row[data-highlighted] > .cell {\n --color-ink: var(--_band-ink);\n --color-ink-muted: color-mix(in oklab, var(--_band-ink), var(--_band-fill) 25%);\n --color-ink-subtle: color-mix(in oklab, var(--_band-ink), var(--_band-fill) 35%);\n --tone-positive-text: var(--_band-positive);\n --tone-caution-text: var(--_band-caution);\n --tone-critical-text: var(--_band-critical);\n --tone-info-text: var(--_band-info);\n --color-accent-text: var(--_band-accent);\n /* Soft fills (a soft Badge or Tag) tint the band, like Section's accent band, so the\n re-pointed tone texts above stay legible on them in every mode. */\n --tone-positive-soft: color-mix(in oklab, var(--_band-positive) 8%, var(--_band-fill));\n --tone-caution-soft: color-mix(in oklab, var(--_band-caution) 8%, var(--_band-fill));\n --tone-critical-soft: color-mix(in oklab, var(--_band-critical) 8%, var(--_band-fill));\n --tone-info-soft: color-mix(in oklab, var(--_band-info) 8%, var(--_band-fill));\n --color-accent-soft: color-mix(in oklab, var(--_band-accent) 8%, var(--_band-fill));\n\n background: var(--_band-fill);\n color: var(--_band-ink);\n}\n/* Round the ends of a highlighted row so the fill reads as a marker, not a stripe. */\n.row[data-highlighted] > .cell:first-child {\n border-start-start-radius: var(--radius-field);\n border-end-start-radius: var(--radius-field);\n}\n.row[data-highlighted] > .cell:last-child {\n border-start-end-radius: var(--radius-field);\n border-end-end-radius: var(--radius-field);\n}\n\n.row[data-interactive] {\n cursor: pointer;\n}\n\n/* Muted: out of play. Every ink drops to the muted step, which still clears AA. */\n.row[data-muted] > .cell {\n --color-ink: var(--color-ink-muted);\n\n color: var(--color-ink-muted);\n}\n\n/* A categorical rail at the row's start: whose row it is, in their Tag's colour. */\n.row[data-color] > .cell:first-child {\n position: relative;\n padding-inline-start: calc(var(--space-2) + var(--space-2));\n}\n.row[data-color] > .cell:first-child::before {\n content: '';\n position: absolute;\n inset-block: var(--space-1);\n inset-inline-start: 0;\n inline-size: var(--table-rail-width, var(--space-1));\n border-radius: var(--radius-chip);\n background: var(--_cat);\n}\n.row[data-color='1'] {\n --_cat: var(--color-cat-1);\n}\n.row[data-color='2'] {\n --_cat: var(--color-cat-2);\n}\n.row[data-color='3'] {\n --_cat: var(--color-cat-3);\n}\n.row[data-color='4'] {\n --_cat: var(--color-cat-4);\n}\n.row[data-color='5'] {\n --_cat: var(--color-cat-5);\n}\n.row[data-color='6'] {\n --_cat: var(--color-cat-6);\n}\n.row[data-color='7'] {\n --_cat: var(--color-cat-7);\n}\n.row[data-color='8'] {\n --_cat: var(--color-cat-8);\n}\n.row > .cell {\n transition: background-color var(--dur-1) var(--ease-out);\n}\n@media (hover: hover) {\n .row[data-interactive]:not([data-highlighted]):hover > .cell {\n background: var(--color-surface-sunken);\n }\n}\n\n.foot > :first-child > .cell {\n border-block-start: var(\n --table-foot-rule,\n var(--border-width-strong) solid var(--color-line-strong)\n );\n}\n.foot .cell {\n font-weight: var(--label-weight);\n}\n/* The totals rule replaces the last row's hairline rather than stacking under it. */\n.table[data-variant='rules'] .body:has(+ .foot) > .row:last-child > .cell {\n border-block-end-width: 0;\n}\n\n/* ── Sticky header ─────────────────────────────────────────────────────── */\n\n.table[data-sticky-header] .head .headerCell {\n position: sticky;\n inset-block-start: 0;\n z-index: 1;\n background: var(--table-head-bg, var(--color-canvas));\n}\n\n/* ── Sort button ───────────────────────────────────────────────────────── */\n\n.sortButton {\n display: inline-flex;\n align-items: center;\n gap: 0.25em;\n margin: calc(var(--space-1) * -1);\n padding: var(--space-1);\n border: 0;\n border-radius: var(--radius-field);\n background: transparent;\n color: inherit;\n font: inherit;\n letter-spacing: inherit;\n text-transform: inherit;\n cursor: pointer;\n transition: color var(--dur-1) var(--ease-out);\n}\n.headerCell[data-align='end'] .sortButton {\n flex-direction: row-reverse;\n}\n@media (hover: hover) {\n .sortButton:hover {\n color: var(--color-ink);\n }\n}\n.sortButton:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 0;\n}\n.sortGlyph {\n display: inline-flex;\n font-size: 1.1em;\n opacity: 0;\n transition: opacity var(--dur-1) var(--ease-out);\n}\n.headerCell:is([data-sort='asc'], [data-sort='desc']) {\n color: var(--color-ink);\n}\n.headerCell:is([data-sort='asc'], [data-sort='desc']) .sortGlyph,\n.sortButton:hover .sortGlyph,\n.sortButton:focus-visible .sortGlyph {\n opacity: 1;\n}\n.headerCell[data-sort='none'] .sortButton:is(:hover, :focus-visible) .sortGlyph {\n opacity: 0.45;\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"Table.module.js","names":["scroll","table","caption","headerCell","cell","body","row","foot","head","sortButton","sortGlyph","Table_module_default"],"sources":["../../../../src/components/display/Table/Table.module.css"],"sourcesContent":["/*\n * Component tokens (themes may set any of these on [data-theme]):\n * --table-head-font default var(--font-text) — Fiesta sets its display caps\n * --table-head-numeric-font numeric header cells, default var(--table-head-font, var(--font-text))\n * --table-head-size default var(--text-sm)\n * --table-head-weight default var(--label-weight)\n * --table-head-transform default var(--heading-transform)\n * --table-head-bg default var(--color-canvas), the sheet's fill on a `surface`\n * table — only painted when stickyHeader\n * --table-max-height default 70vh — scroll height when stickyHeader\n * --table-rail-width default var(--space-1) — the categorical rail of a `color` row\n * --table-surface-bg default var(--color-surface), var(--color-surface-raised) when `raised`\n * --table-surface-radius default var(--radius-surface) — the sheet of a `surface` table\n * --table-foot-rule the rule over totals, default var(--border-width-strong) solid\n * var(--color-line-strong) — Ledger draws the accountant's double rule\n * --highlight-tone-{positive,caution,critical,info}-text, --highlight-accent-text\n * tone text inside a highlighted row (shared with List). Default:\n * the tone text mixed 25% toward --color-highlight-ink.\n *\n * Headers are labels, so they're set in the text face (monospace as decoration for small\n * labels is banned in DESIGN §2); figures below them carry the numeric face.\n */\n.scroll {\n inline-size: 100%;\n min-inline-size: 0;\n overflow-x: auto;\n overscroll-behavior-x: contain;\n}\n.scroll[data-sticky-header] {\n overflow: auto;\n max-block-size: var(--table-max-height, 70vh);\n}\n/*\n * On a surface: the wrapper is the sheet, with Card's edges (`outline` for surface, `raised`\n * for raised), so it scrolls sideways with the table and rows read as rows on a textured or\n * busy canvas. Rows run edge to edge and the scroll container clips them to its radius, so a\n * highlighted row is a band across the sheet and a categorical rail sits flush with the\n * sheet's inner edge, following its corners on the first and last rows.\n */\n.scroll[data-surface] {\n --_sheet-bg: var(--table-surface-bg, var(--color-surface));\n\n border: var(--border-width) solid var(--color-line);\n border-radius: var(--table-surface-radius, var(--radius-surface));\n background: var(--_sheet-bg);\n}\n.scroll[data-surface='raised'] {\n --_sheet-bg: var(--table-surface-bg, var(--color-surface-raised));\n\n border-color: var(--color-line-strong);\n box-shadow: var(--shadow-surface);\n}\n.scroll:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 2px;\n}\n\n.table {\n --_py: var(--space-2);\n --_px: var(--space-3);\n --_edge: var(--space-2);\n --_row-radius: var(--radius-field);\n --_valign: baseline;\n\n inline-size: 100%;\n border-collapse: separate;\n border-spacing: 0;\n font-family: var(--font-text);\n font-size: var(--text-sm);\n line-height: var(--leading-snug);\n color: var(--color-ink);\n}\n.table[data-valign='middle'] {\n --_valign: middle;\n}\n.table[data-valign='top'] {\n --_valign: top;\n}\n.table[data-density='compact'] {\n --_py: var(--space-1);\n --_px: var(--space-2);\n}\n/* On a sheet rows get more air, and the end cells a wider inset so text clears the edge. */\n.table[data-surface] {\n --_py: var(--space-3);\n --_edge: var(--space-4);\n --_row-radius: 0px;\n}\n.table[data-surface][data-density='compact'] {\n --_py: var(--space-2);\n}\n\n.caption {\n caption-side: top;\n padding-block-end: var(--space-3);\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n text-align: start;\n}\n/* On a sheet the caption lines up with the first column instead of the sheet's edge. */\n.table[data-surface] > .caption {\n padding-block-start: var(--space-3);\n padding-inline: var(--_edge);\n}\n\n/* ── Cells ─────────────────────────────────────────────────────────────── */\n\n.headerCell,\n.cell {\n padding: var(--_py) var(--_px);\n text-align: start;\n vertical-align: var(--_valign);\n}\n.headerCell:first-child,\n.cell:first-child {\n padding-inline-start: var(--_edge);\n}\n.headerCell:last-child,\n.cell:last-child {\n padding-inline-end: var(--_edge);\n}\n/* Figure columns are narrow; tighter gutters keep a 10-column figures table on a phone. */\n:is(.headerCell, .cell)[data-numeric] {\n padding-inline: var(--space-2);\n}\n.headerCell abbr {\n text-decoration: none;\n cursor: help;\n}\n:is(.headerCell, .cell)[data-align='center'] {\n text-align: center;\n}\n:is(.headerCell, .cell)[data-align='end'] {\n text-align: end;\n}\n\n.headerCell {\n padding-block: var(--_py);\n color: var(--color-ink-muted);\n font-family: var(--table-head-font, var(--font-text));\n font-size: var(--table-head-size, var(--text-sm));\n font-weight: var(--table-head-weight, var(--label-weight));\n letter-spacing: var(--label-tracking);\n text-transform: var(--table-head-transform, var(--heading-transform));\n white-space: nowrap;\n vertical-align: bottom;\n border-block-end: var(--border-width-strong) solid var(--color-line-strong);\n}\n\n.headerCell[data-numeric] {\n font-family: var(--table-head-numeric-font, var(--table-head-font, var(--font-text)));\n font-variant-numeric: tabular-nums lining-nums;\n}\n.headerCell[data-width='fill'] {\n inline-size: 100%;\n}\n.headerCell[data-width='min'] {\n inline-size: 1%;\n}\n\n.cell[data-numeric] {\n font-family: var(--font-numeric);\n font-stretch: var(--numeric-stretch);\n font-variant-numeric: tabular-nums lining-nums;\n white-space: nowrap;\n}\n.cell[data-row-header] {\n font-weight: var(--label-weight);\n}\n\n/* ── Rows ──────────────────────────────────────────────────────────────── */\n\n.table[data-variant='rules'] .body .cell {\n border-block-end: var(--border-width) solid var(--color-line);\n}\n.table[data-variant='rules'] .body > .row:last-child > .cell {\n border-block-end-color: var(--color-line-strong);\n}\n/* On a sheet, its edge closes the table: no closing rule just inside it. */\n.table[data-surface][data-variant='rules'] .body:last-child > .row:last-child > .cell {\n border-block-end-color: transparent;\n}\n\n.table[data-striped] .body > .row:nth-child(even) > .cell {\n background: var(--color-surface-sunken);\n}\n\n/*\n * A highlighted row re-points the colour roles for its cells' content, so a muted date,\n * a tone-coloured Numeral or a LiveIndicator stays legible on the highlight fill (gold in\n * Fiesta night, where the ordinary tone texts are pale). Same approach as Section's\n * inverse band: the row publishes its fill/ink and tone texts under private names, and\n * the cells swap the roles — setting e.g. --tone-positive-text from itself on one element\n * would be a var() cycle.\n */\n.row[data-highlighted] {\n --_band-fill: var(--color-highlight);\n --_band-ink: var(--color-highlight-ink);\n --_band-positive: var(\n --highlight-tone-positive-text,\n color-mix(in oklab, var(--tone-positive-text) 75%, var(--color-highlight-ink))\n );\n --_band-caution: var(\n --highlight-tone-caution-text,\n color-mix(in oklab, var(--tone-caution-text) 75%, var(--color-highlight-ink))\n );\n --_band-critical: var(\n --highlight-tone-critical-text,\n color-mix(in oklab, var(--tone-critical-text) 75%, var(--color-highlight-ink))\n );\n --_band-info: var(\n --highlight-tone-info-text,\n color-mix(in oklab, var(--tone-info-text) 75%, var(--color-highlight-ink))\n );\n --_band-accent: var(\n --highlight-accent-text,\n color-mix(in oklab, var(--color-accent-text) 75%, var(--color-highlight-ink))\n );\n}\n.row[data-highlighted] > .cell {\n --color-ink: var(--_band-ink);\n --color-ink-muted: color-mix(in oklab, var(--_band-ink), var(--_band-fill) 25%);\n --color-ink-subtle: color-mix(in oklab, var(--_band-ink), var(--_band-fill) 35%);\n --tone-positive-text: var(--_band-positive);\n --tone-caution-text: var(--_band-caution);\n --tone-critical-text: var(--_band-critical);\n --tone-info-text: var(--_band-info);\n --color-accent-text: var(--_band-accent);\n /* Soft fills (a soft Badge or Tag) tint the band, like Section's accent band, so the\n re-pointed tone texts above stay legible on them in every mode. */\n --tone-positive-soft: color-mix(in oklab, var(--_band-positive) 8%, var(--_band-fill));\n --tone-caution-soft: color-mix(in oklab, var(--_band-caution) 8%, var(--_band-fill));\n --tone-critical-soft: color-mix(in oklab, var(--_band-critical) 8%, var(--_band-fill));\n --tone-info-soft: color-mix(in oklab, var(--_band-info) 8%, var(--_band-fill));\n --color-accent-soft: color-mix(in oklab, var(--_band-accent) 8%, var(--_band-fill));\n\n background: var(--_band-fill);\n color: var(--_band-ink);\n}\n/* Round the ends of a highlighted row so the fill reads as a marker, not a stripe. */\n.row[data-highlighted] > .cell:first-child {\n border-start-start-radius: var(--_row-radius);\n border-end-start-radius: var(--_row-radius);\n}\n.row[data-highlighted] > .cell:last-child {\n border-start-end-radius: var(--_row-radius);\n border-end-end-radius: var(--_row-radius);\n}\n\n.row[data-interactive] {\n cursor: pointer;\n}\n\n/* Muted: out of play. Every ink drops to the muted step, which still clears AA. */\n.row[data-muted] > .cell {\n --color-ink: var(--color-ink-muted);\n\n color: var(--color-ink-muted);\n}\n\n/* A categorical rail at the row's start: whose row it is, in their Tag's colour. */\n.row[data-color] > .cell:first-child {\n position: relative;\n padding-inline-start: calc(var(--_edge) + var(--space-2));\n}\n.row[data-color] > .cell:first-child::before {\n content: '';\n position: absolute;\n inset-block: var(--space-1);\n inset-inline-start: 0;\n inline-size: var(--table-rail-width, var(--space-1));\n border-radius: var(--radius-chip);\n background: var(--_cat);\n}\n/* On a sheet the rail is an edge of the row: full height, square, and over the rule below it. */\n.table[data-surface] .row[data-color] > .cell:first-child::before {\n inset-block: 0;\n border-radius: 0;\n}\n.table[data-surface][data-variant='rules'] .body .row[data-color] > .cell:first-child::before {\n inset-block-end: calc(var(--border-width) * -1);\n}\n.row[data-color='1'] {\n --_cat: var(--color-cat-1);\n}\n.row[data-color='2'] {\n --_cat: var(--color-cat-2);\n}\n.row[data-color='3'] {\n --_cat: var(--color-cat-3);\n}\n.row[data-color='4'] {\n --_cat: var(--color-cat-4);\n}\n.row[data-color='5'] {\n --_cat: var(--color-cat-5);\n}\n.row[data-color='6'] {\n --_cat: var(--color-cat-6);\n}\n.row[data-color='7'] {\n --_cat: var(--color-cat-7);\n}\n.row[data-color='8'] {\n --_cat: var(--color-cat-8);\n}\n.row > .cell {\n transition: background-color var(--dur-1) var(--ease-out);\n}\n@media (hover: hover) {\n .row[data-interactive]:not([data-highlighted]):hover > .cell {\n background: var(--color-surface-sunken);\n }\n}\n\n.foot > :first-child > .cell {\n border-block-start: var(\n --table-foot-rule,\n var(--border-width-strong) solid var(--color-line-strong)\n );\n}\n.foot .cell {\n font-weight: var(--label-weight);\n}\n/* The totals rule replaces the last row's hairline rather than stacking under it. */\n.table[data-variant='rules'] .body:has(+ .foot) > .row:last-child > .cell {\n border-block-end-width: 0;\n}\n\n/* ── Sticky header ─────────────────────────────────────────────────────── */\n\n.table[data-sticky-header] .head .headerCell {\n position: sticky;\n inset-block-start: 0;\n z-index: 1;\n background: var(--table-head-bg, var(--color-canvas));\n}\n.table[data-surface][data-sticky-header] .head .headerCell {\n background: var(--table-head-bg, var(--_sheet-bg));\n}\n\n/* ── Sort button ───────────────────────────────────────────────────────── */\n\n.sortButton {\n display: inline-flex;\n align-items: center;\n gap: 0.25em;\n margin: calc(var(--space-1) * -1);\n padding: var(--space-1);\n border: 0;\n border-radius: var(--radius-field);\n background: transparent;\n color: inherit;\n font: inherit;\n letter-spacing: inherit;\n text-transform: inherit;\n cursor: pointer;\n transition: color var(--dur-1) var(--ease-out);\n}\n.headerCell[data-align='end'] .sortButton {\n flex-direction: row-reverse;\n}\n@media (hover: hover) {\n .sortButton:hover {\n color: var(--color-ink);\n }\n}\n.sortButton:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 0;\n}\n.sortGlyph {\n display: inline-flex;\n font-size: 1.1em;\n opacity: 0;\n transition: opacity var(--dur-1) var(--ease-out);\n}\n.headerCell:is([data-sort='asc'], [data-sort='desc']) {\n color: var(--color-ink);\n}\n.headerCell:is([data-sort='asc'], [data-sort='desc']) .sortGlyph,\n.sortButton:hover .sortGlyph,\n.sortButton:focus-visible .sortGlyph {\n opacity: 1;\n}\n.headerCell[data-sort='none'] .sortButton:is(:hover, :focus-visible) .sortGlyph {\n opacity: 0.45;\n}\n"],"mappings":""}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Table } from './Table.js';
|
|
2
|
-
export type { TableProps, TableDensity, TableVariant, TableAlign, TableSort, TableColumnWidth, TableRowProps, TableHeaderCellProps, TableCellProps, } from './Table.js';
|
|
2
|
+
export type { TableProps, TableDensity, TableVariant, TableSurface, TableAlign, TableVerticalAlign, TableSort, TableColumnWidth, TableRowProps, TableHeaderCellProps, TableCellProps, } from './Table.js';
|
|
@@ -3,7 +3,7 @@ import { type Responsive } from '../../../utils/responsive.js';
|
|
|
3
3
|
import { type Space, type CategoryColor } from '../../../utils/tokens.js';
|
|
4
4
|
import { type VisibilityProps } from '../../../utils/visibility.js';
|
|
5
5
|
export type BoxElement = 'div' | 'span' | 'section' | 'article' | 'aside' | 'header' | 'footer' | 'li';
|
|
6
|
-
export type BoxSurface = 'none' | 'canvas' | 'surface' | 'sunken' | 'raised' | 'inverse' | `cat-${CategoryColor}`;
|
|
6
|
+
export type BoxSurface = 'none' | 'canvas' | 'surface' | 'sunken' | 'raised' | 'inverse' | 'accent' | `cat-${CategoryColor}`;
|
|
7
7
|
export type BoxRadius = 'none' | 'field' | 'surface' | 'media';
|
|
8
8
|
export interface BoxProps extends HTMLAttributes<HTMLElement>, VisibilityProps {
|
|
9
9
|
/** Padding on every side. Responsive. */
|
|
@@ -13,10 +13,19 @@ export interface BoxProps extends HTMLAttributes<HTMLElement>, VisibilityProps {
|
|
|
13
13
|
/** Block (top/bottom) padding; overrides `padding` on that axis. Responsive. */
|
|
14
14
|
paddingY?: Responsive<Space>;
|
|
15
15
|
/**
|
|
16
|
-
* Background fill. `inverse` and the categorical `cat-1` to `cat-8` (one person's or
|
|
17
|
-
* colour, matching their `Tag`) also re-point ink and
|
|
16
|
+
* Background fill. `inverse`, `accent` and the categorical `cat-1` to `cat-8` (one person's or
|
|
17
|
+
* team's colour, matching their `Tag`) also re-point ink, line and accent colours for its
|
|
18
|
+
* children, so they stay legible on the fill.
|
|
18
19
|
*/
|
|
19
20
|
surface?: BoxSurface;
|
|
21
|
+
/**
|
|
22
|
+
* On an `inverse`, `accent` or categorical fill, re-point the status tones too, so tone text
|
|
23
|
+
* and soft tone fills (a `Stat` delta, a toned `Numeral` or `Text`, a soft `Badge`) stay AA on
|
|
24
|
+
* the fill. On `accent` and categorical fills tone text becomes the fill's ink, so the sign,
|
|
25
|
+
* glyph or label carries the status; on `inverse` each tone keeps its hue. Off by default, so
|
|
26
|
+
* tones keep the page's colours. No effect on other surfaces.
|
|
27
|
+
*/
|
|
28
|
+
adaptTones?: boolean;
|
|
20
29
|
/** Hairline border in `--color-line`. One edge treatment per element — a border *or* a fill. */
|
|
21
30
|
border?: boolean;
|
|
22
31
|
/** Corner radius, by role. */
|
|
@@ -6,18 +6,19 @@ import a from "./Box.module.js";
|
|
|
6
6
|
import { forwardRef as o } from "react";
|
|
7
7
|
import { jsx as s } from "react/jsx-runtime";
|
|
8
8
|
//#region src/components/layout/Box/Box.tsx
|
|
9
|
-
var c = o(function({ padding: o, paddingX: c, paddingY: l, surface: u = "none",
|
|
10
|
-
return /* @__PURE__ */ s(
|
|
11
|
-
ref:
|
|
9
|
+
var c = o(function({ padding: o, paddingX: c, paddingY: l, surface: u = "none", adaptTones: d = !1, border: f = !1, radius: p = "none", as: m = "div", hideBelow: h, hideAbove: g, className: _, style: v, ...y }, b) {
|
|
10
|
+
return /* @__PURE__ */ s(m, {
|
|
11
|
+
ref: b,
|
|
12
12
|
className: e(a.box, i({
|
|
13
|
-
hideBelow:
|
|
14
|
-
hideAbove:
|
|
15
|
-
}),
|
|
13
|
+
hideBelow: h,
|
|
14
|
+
hideAbove: g
|
|
15
|
+
}), _),
|
|
16
16
|
"data-surface": u === "none" ? void 0 : u,
|
|
17
|
-
"data-
|
|
18
|
-
"data-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
"data-adapt-tones": d || void 0,
|
|
18
|
+
"data-border": f || void 0,
|
|
19
|
+
"data-radius": p === "none" ? void 0 : p,
|
|
20
|
+
style: t(n("box-p", o, r), n("box-px", c, r), n("box-py", l, r), v),
|
|
21
|
+
...y
|
|
21
22
|
});
|
|
22
23
|
});
|
|
23
24
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Box.js","names":["styles","Box_module_default","Box","forwardRef","Comp","rest","cx","visibilityClass","className","surface","border","radius","mergeStyles","responsiveVars","padding","space","paddingX","paddingY","style"],"sources":["../../../../src/components/layout/Box/Box.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes } from 'react'\nimport { cx } from '#utils/cx'\nimport { mergeStyles, responsiveVars, type Responsive } from '#utils/responsive'\nimport { space, type Space, type CategoryColor } from '#utils/tokens'\nimport styles from './Box.module.css'\nimport { visibilityClass, type VisibilityProps } from '#utils/visibility'\n\nexport type BoxElement =\n 'div' | 'span' | 'section' | 'article' | 'aside' | 'header' | 'footer' | 'li'\nexport type BoxSurface =\n 'none'
|
|
1
|
+
{"version":3,"file":"Box.js","names":["styles","Box_module_default","Box","forwardRef","Comp","rest","cx","visibilityClass","className","surface","adaptTones","border","radius","mergeStyles","responsiveVars","padding","space","paddingX","paddingY","style"],"sources":["../../../../src/components/layout/Box/Box.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes } from 'react'\nimport { cx } from '#utils/cx'\nimport { mergeStyles, responsiveVars, type Responsive } from '#utils/responsive'\nimport { space, type Space, type CategoryColor } from '#utils/tokens'\nimport styles from './Box.module.css'\nimport { visibilityClass, type VisibilityProps } from '#utils/visibility'\n\nexport type BoxElement =\n 'div' | 'span' | 'section' | 'article' | 'aside' | 'header' | 'footer' | 'li'\nexport type BoxSurface =\n | 'none'\n | 'canvas'\n | 'surface'\n | 'sunken'\n | 'raised'\n | 'inverse'\n | 'accent'\n | `cat-${CategoryColor}`\nexport type BoxRadius = 'none' | 'field' | 'surface' | 'media'\n\nexport interface BoxProps extends HTMLAttributes<HTMLElement>, VisibilityProps {\n /** Padding on every side. Responsive. */\n padding?: Responsive<Space>\n /** Inline (left/right) padding; overrides `padding` on that axis. Responsive. */\n paddingX?: Responsive<Space>\n /** Block (top/bottom) padding; overrides `padding` on that axis. Responsive. */\n paddingY?: Responsive<Space>\n /**\n * Background fill. `inverse`, `accent` and the categorical `cat-1` to `cat-8` (one person's or\n * team's colour, matching their `Tag`) also re-point ink, line and accent colours for its\n * children, so they stay legible on the fill.\n */\n surface?: BoxSurface\n /**\n * On an `inverse`, `accent` or categorical fill, re-point the status tones too, so tone text\n * and soft tone fills (a `Stat` delta, a toned `Numeral` or `Text`, a soft `Badge`) stay AA on\n * the fill. On `accent` and categorical fills tone text becomes the fill's ink, so the sign,\n * glyph or label carries the status; on `inverse` each tone keeps its hue. Off by default, so\n * tones keep the page's colours. No effect on other surfaces.\n */\n adaptTones?: boolean\n /** Hairline border in `--color-line`. One edge treatment per element — a border *or* a fill. */\n border?: boolean\n /** Corner radius, by role. */\n radius?: BoxRadius\n as?: BoxElement\n}\n\n/**\n * Padding, a surface and an edge, and nothing else. The escape hatch when no other layout fits.\n *\n * @remarks\n * `Box` adds padding, a background surface, a border and a radius to its content. Reach for\n * `Stack`, `Inline` or `Grid` to arrange things, and for `Card` when something is a self-contained\n * object. `Box` is for the wells and frames left over.\n *\n * @privateRemarks\n * The escape hatch: padding, a surface and an edge — nothing else. Reach for\n * Stack/Inline/Grid for arrangement and Card for self-contained objects first.\n *\n * <Box padding={{ base: 4, md: 5 }} surface=\"sunken\" radius=\"surface\">…</Box>\n */\nexport const Box = forwardRef<HTMLElement, BoxProps>(function Box(\n {\n padding,\n paddingX,\n paddingY,\n surface = 'none',\n adaptTones = false,\n border = false,\n radius = 'none',\n as: Comp = 'div',\n hideBelow,\n hideAbove,\n className,\n style,\n ...rest\n },\n ref,\n) {\n return (\n <Comp\n // @ts-expect-error — polymorphic ref across a union of intrinsic elements is safe here\n ref={ref}\n className={cx(styles.box, visibilityClass({ hideBelow, hideAbove }), className)}\n data-surface={surface === 'none' ? undefined : surface}\n data-adapt-tones={adaptTones || undefined}\n data-border={border || undefined}\n data-radius={radius === 'none' ? undefined : radius}\n style={mergeStyles(\n responsiveVars('box-p', padding, space),\n responsiveVars('box-px', paddingX, space),\n responsiveVars('box-py', paddingY, space),\n style,\n )}\n {...rest}\n />\n )\n})\n"],"mappings":";;;;;;;;AA8DA,IAAaE,IAAMC,EAAkC,SACnD,EACE,YACA,aACA,aACA,aAAU,QACV,gBAAa,IACb,YAAS,IACT,YAAS,QACT,IAAIC,IAAO,OACX,cACA,cACA,cACA,UACA,GAAGC,KAEL,GACA;CACA,OACE,kBAACD,GAAD;EAEO;EACL,WAAWE,EAAGN,EAAO,KAAKO,EAAgB;GAAE;GAAW;EAAU,CAAC,GAAGC,CAAS;EAC9E,gBAAcC,MAAY,SAAS,KAAA,IAAYA;EAC/C,oBAAkBC,KAAc,KAAA;EAChC,eAAaC,KAAU,KAAA;EACvB,eAAaC,MAAW,SAAS,KAAA,IAAYA;EAC7C,OAAOC,EACLC,EAAe,SAASC,GAASC,CAAK,GACtCF,EAAe,UAAUG,GAAUD,CAAK,GACxCF,EAAe,UAAUI,GAAUF,CAAK,GACxCG,CACF;EACA,GAAId;CACL,CAAA;AAEL,CAAC"}
|