@mitcsutt/kiln-ui 0.3.0 → 0.4.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.
Files changed (100) hide show
  1. package/dist/components/actions/Button/Button.module.js.map +1 -1
  2. package/dist/components/actions/ToggleChip/ToggleChip.d.ts +5 -0
  3. package/dist/components/actions/ToggleChip/ToggleChip.js +10 -6
  4. package/dist/components/actions/ToggleChip/ToggleChip.js.map +1 -1
  5. package/dist/components/actions/ToggleChip/chip.module.js +4 -3
  6. package/dist/components/actions/ToggleChip/chip.module.js.map +1 -1
  7. package/dist/components/display/AvatarGroup/AvatarGroup.d.ts +2 -2
  8. package/dist/components/display/AvatarGroup/AvatarGroup.js +1 -1
  9. package/dist/components/display/AvatarGroup/AvatarGroup.js.map +1 -1
  10. package/dist/components/display/Card/Card.d.ts +7 -4
  11. package/dist/components/display/Card/Card.js +8 -7
  12. package/dist/components/display/Card/Card.js.map +1 -1
  13. package/dist/components/display/Card/Card.module.js.map +1 -1
  14. package/dist/components/display/List/List.d.ts +10 -5
  15. package/dist/components/display/List/List.js +49 -40
  16. package/dist/components/display/List/List.js.map +1 -1
  17. package/dist/components/display/List/List.module.js.map +1 -1
  18. package/dist/components/display/Marquee/Marquee.js +1 -1
  19. package/dist/components/display/Marquee/Marquee.js.map +1 -1
  20. package/dist/components/display/Media/Media.d.ts +13 -0
  21. package/dist/components/display/Media/Media.js +23 -19
  22. package/dist/components/display/Media/Media.js.map +1 -1
  23. package/dist/components/display/Media/Media.module.js.map +1 -1
  24. package/dist/components/display/Media/index.d.ts +1 -1
  25. package/dist/components/display/Stat/Stat.module.js.map +1 -1
  26. package/dist/components/display/Table/Table.d.ts +6 -1
  27. package/dist/components/display/Table/Table.js +6 -4
  28. package/dist/components/display/Table/Table.js.map +1 -1
  29. package/dist/components/display/Table/Table.module.js.map +1 -1
  30. package/dist/components/display/Tag/Tag.d.ts +3 -0
  31. package/dist/components/display/Tag/Tag.js +11 -10
  32. package/dist/components/display/Tag/Tag.js.map +1 -1
  33. package/dist/components/display/Tag/Tag.module.js.map +1 -1
  34. package/dist/components/display/Tag/index.d.ts +1 -1
  35. package/dist/components/feedback/Flash/Flash.d.ts +47 -0
  36. package/dist/components/feedback/Flash/Flash.js +36 -0
  37. package/dist/components/feedback/Flash/Flash.js.map +1 -0
  38. package/dist/components/feedback/Flash/Flash.module.js +10 -0
  39. package/dist/components/feedback/Flash/Flash.module.js.map +1 -0
  40. package/dist/components/feedback/Flash/index.d.ts +2 -0
  41. package/dist/components/feedback/RelativeTime/RelativeTime.d.ts +7 -0
  42. package/dist/components/feedback/RelativeTime/RelativeTime.js +11 -11
  43. package/dist/components/feedback/RelativeTime/RelativeTime.js.map +1 -1
  44. package/dist/components/feedback/StatusDot/StatusDot.d.ts +1 -1
  45. package/dist/components/feedback/StatusDot/StatusDot.js.map +1 -1
  46. package/dist/components/inputs/ChoiceCards/ChoiceCards.js +9 -9
  47. package/dist/components/inputs/Combobox/Combobox.js +5 -5
  48. package/dist/components/inputs/PasswordInput/PasswordInput.js +4 -4
  49. package/dist/components/layout/AppShell/AppShell.d.ts +4 -1
  50. package/dist/components/layout/AppShell/AppShell.js +58 -44
  51. package/dist/components/layout/AppShell/AppShell.js.map +1 -1
  52. package/dist/components/layout/AppShell/AppShell.module.js.map +1 -1
  53. package/dist/components/layout/Box/Box.d.ts +6 -3
  54. package/dist/components/layout/Box/Box.js.map +1 -1
  55. package/dist/components/layout/Box/Box.module.js.map +1 -1
  56. package/dist/components/layout/Divider/Divider.d.ts +7 -1
  57. package/dist/components/layout/Divider/Divider.js +18 -20
  58. package/dist/components/layout/Divider/Divider.js.map +1 -1
  59. package/dist/components/layout/Section/Section.d.ts +8 -6
  60. package/dist/components/layout/Section/Section.js.map +1 -1
  61. package/dist/components/layout/Section/Section.module.js.map +1 -1
  62. package/dist/components/navigation/Accordion/Accordion.d.ts +6 -1
  63. package/dist/components/navigation/Accordion/Accordion.js +19 -11
  64. package/dist/components/navigation/Accordion/Accordion.js.map +1 -1
  65. package/dist/components/navigation/Accordion/Accordion.module.js +7 -6
  66. package/dist/components/navigation/Accordion/Accordion.module.js.map +1 -1
  67. package/dist/components/navigation/NavLinks/NavLinks.d.ts +4 -1
  68. package/dist/components/navigation/NavLinks/NavLinks.js.map +1 -1
  69. package/dist/components/navigation/NavLinks/NavLinks.module.js.map +1 -1
  70. package/dist/components/overlays/Tooltip/Tooltip.d.ts +23 -0
  71. package/dist/components/overlays/Tooltip/Tooltip.js +77 -31
  72. package/dist/components/overlays/Tooltip/Tooltip.js.map +1 -1
  73. package/dist/components/typography/Numeral/Numeral.d.ts +26 -2
  74. package/dist/components/typography/Numeral/Numeral.js +25 -21
  75. package/dist/components/typography/Numeral/Numeral.js.map +1 -1
  76. package/dist/components/typography/Numeral/Numeral.module.js +4 -3
  77. package/dist/components/typography/Numeral/Numeral.module.js.map +1 -1
  78. package/dist/components/typography/Text/Text.d.ts +5 -2
  79. package/dist/components/typography/Text/Text.js.map +1 -1
  80. package/dist/components/typography/Text/Text.module.js.map +1 -1
  81. package/dist/icons/Icon.js +1 -0
  82. package/dist/icons/Icon.js.map +1 -1
  83. package/dist/icons/icons.d.ts +12 -0
  84. package/dist/icons/icons.js +63 -13
  85. package/dist/icons/icons.js.map +1 -1
  86. package/dist/index.d.ts +16 -23
  87. package/dist/index.js +113 -112
  88. package/dist/styles.css +1 -1
  89. package/dist/themes/fiesta.css +1 -1
  90. package/dist/utils/tokens.d.ts +2 -0
  91. package/dist/utils/tokens.js.map +1 -1
  92. package/package.json +2 -2
  93. package/skills/custom-theme/SKILL.md +1 -1
  94. package/skills/design-rules/SKILL.md +7 -4
  95. package/skills/layout-composition/references/app-shell.md +2 -2
  96. package/skills/layout-composition/references/box.md +1 -1
  97. package/skills/layout-composition/references/divider.md +30 -1
  98. package/skills/layout-composition/references/section.md +23 -2
  99. package/skills/setup-and-theming/SKILL.md +3 -3
  100. package/skills/setup-and-theming/references/fiesta.md +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Flash.module.js","names":["flash","Flash_module_default"],"sources":["../../../../src/components/feedback/Flash/Flash.module.css"],"sourcesContent":["/*\n * Component tokens (themes may set any of these on [data-theme]):\n * --flash-color default var(--color-accent) — live state is the accent's job\n * --flash-duration default 1.6s — how long the mark stays. Not a motion token: those\n * collapse under reduced motion, and the mark must still be seen there.\n *\n * An outline, so it never moves layout and shows over any fill. Two keyframe names alternate\n * (data-flash odd/even) so a second change restarts the animation.\n */\n.flash {\n --_c: var(--flash-color, var(--color-accent));\n --_d: var(--flash-duration, 1.6s);\n}\n\n.flash:target,\n.flash[data-flash='odd'] {\n animation: flash-odd var(--_d) var(--ease-out);\n}\n.flash[data-flash='even'] {\n animation: flash-even var(--_d) var(--ease-out);\n}\n\n@keyframes flash-odd {\n from {\n outline: 3px solid var(--_c);\n outline-offset: 2px;\n }\n to {\n outline: 3px solid transparent;\n outline-offset: 2px;\n }\n}\n@keyframes flash-even {\n from {\n outline: 3px solid var(--_c);\n outline-offset: 2px;\n }\n to {\n outline: 3px solid transparent;\n outline-offset: 2px;\n }\n}\n\n/* Reduced motion: no fade. The mark shows, holds for the same time, and goes. */\n@media (prefers-reduced-motion: reduce) {\n .flash:target,\n .flash[data-flash] {\n animation-timing-function: steps(1, end);\n }\n}\n"],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export { Flash } from './Flash.js';
2
+ export type { FlashProps } from './Flash.js';
@@ -11,6 +11,13 @@ export interface RelativeTimeProps extends Omit<TimeHTMLAttributes<HTMLTimeEleme
11
11
  updateInterval?: number;
12
12
  /** Text before the time, e.g. "Updated". A space is added for you. */
13
13
  prefix?: ReactNode;
14
+ /**
15
+ * Seconds either side of now that read as `justNowLabel` instead of `Intl`'s "now" or
16
+ * "in 30 sec". Default `0`, which leaves the wording to `Intl`.
17
+ */
18
+ justNowWithin?: number;
19
+ /** What a moment within `justNowWithin` reads as. Default "just now". */
20
+ justNowLabel?: string;
14
21
  }
15
22
  /**
16
23
  * How long ago, or how long until. A time element that keeps itself current and renders safely on
@@ -3,32 +3,32 @@ import r from "./RelativeTime.module.js";
3
3
  import { forwardRef as i, useEffect as a, useState as o } from "react";
4
4
  import { jsx as s, jsxs as c } from "react/jsx-runtime";
5
5
  //#region src/components/feedback/RelativeTime/RelativeTime.tsx
6
- var l = i(function({ date: i, locale: l = "en-AU", format: u = "short", updateInterval: d = 3e4, prefix: f, title: p, className: m, ...h }, g) {
7
- let [_, v] = o(null);
6
+ var l = i(function({ date: i, locale: l = "en-AU", format: u = "short", updateInterval: d = 3e4, prefix: f, justNowWithin: p = 0, justNowLabel: m = "just now", title: h, className: g, ..._ }, v) {
7
+ let [y, b] = o(null);
8
8
  a(() => {
9
- if (v(Date.now()), !d) return;
9
+ if (b(Date.now()), !d) return;
10
10
  let e = setInterval(() => {
11
- v(Date.now());
11
+ b(Date.now());
12
12
  }, d);
13
13
  return () => {
14
14
  clearInterval(e);
15
15
  };
16
16
  }, [d]);
17
- let y = n(i), b = !Number.isNaN(y.getTime()), x = b ? e(y, l) : "", S = b ? _ === null ? x : t(y, _, l, u) : "";
17
+ let x = n(i), S = !Number.isNaN(x.getTime()), C = S ? e(x, l) : "", w = S ? y === null ? C : Math.abs(x.getTime() - y) < p * 1e3 ? m : t(x, y, l, u) : "";
18
18
  return /* @__PURE__ */ c("time", {
19
- ref: g,
20
- dateTime: b ? y.toISOString() : void 0,
21
- title: p ?? x,
22
- className: m,
19
+ ref: v,
20
+ dateTime: S ? x.toISOString() : void 0,
21
+ title: h ?? C,
22
+ className: g,
23
23
  suppressHydrationWarning: !0,
24
- ...h,
24
+ ..._,
25
25
  children: [f ? /* @__PURE__ */ c("span", {
26
26
  className: r.prefix,
27
27
  children: [f, " "]
28
28
  }) : null, /* @__PURE__ */ s("span", {
29
29
  className: r.value,
30
30
  suppressHydrationWarning: !0,
31
- children: S
31
+ children: w
32
32
  })]
33
33
  });
34
34
  });
@@ -1 +1 @@
1
- {"version":3,"file":"RelativeTime.js","names":["styles","RelativeTime_module_default","RelativeTime","forwardRef","rest","now","setNow","useState","updateInterval","id","d","toDate","date","valid","absolute","formatAbsoluteTime","locale","text","formatRelativeTime","format","title","prefix"],"sources":["../../../../src/components/feedback/RelativeTime/RelativeTime.tsx"],"sourcesContent":["import { forwardRef, useEffect, useState, type ReactNode, type TimeHTMLAttributes } from 'react'\nimport { formatAbsoluteTime, formatRelativeTime, toDate, type RelativeTimeStyle } from './format'\nimport styles from './RelativeTime.module.css'\n\nexport interface RelativeTimeProps extends Omit<\n TimeHTMLAttributes<HTMLTimeElement>,\n 'dateTime' | 'children' | 'prefix'\n> {\n /** The moment to describe. Anything `new Date()` accepts. */\n date: Date | string | number\n /** BCP 47 locale. Default `en-AU`. */\n locale?: string\n /** Wording length: \"3 minutes ago\" (`long`), \"3 mins ago\" (`short`, default), `narrow`. */\n format?: RelativeTimeStyle\n /** Re-render every N ms so the text stays true. `0` disables. Default 30 000. */\n updateInterval?: number\n /** Text before the time, e.g. \"Updated\". A space is added for you. */\n prefix?: ReactNode\n}\n\n/**\n * How long ago, or how long until. A time element that keeps itself current and renders safely on\n * the server.\n *\n * @remarks\n * `RelativeTime` renders a `<time>` that reads \"3 mins ago\" or \"in 2 hours\", and updates itself\n * (every 30 seconds by default). The full date is always in its `title`.\n *\n * @privateRemarks\n * A `<time>` that says how long ago (or until) something happened, and keeps itself current.\n *\n * SSR: the server and the first client render show the absolute date (no clock is read\n * during render, so hydration can't disagree about \"now\"); the relative wording appears\n * once mounted. The absolute date stays available as the `title`.\n *\n * <RelativeTime date={fetchedAt} prefix=\"Updated\" />\n */\nexport const RelativeTime = forwardRef<HTMLTimeElement, RelativeTimeProps>(function RelativeTime(\n {\n date,\n locale = 'en-AU',\n format = 'short',\n updateInterval = 30_000,\n prefix,\n title,\n className,\n ...rest\n },\n ref,\n) {\n const [now, setNow] = useState<number | null>(null)\n\n useEffect(() => {\n setNow(Date.now())\n if (!updateInterval) return\n const id = setInterval(() => {\n setNow(Date.now())\n }, updateInterval)\n return () => {\n clearInterval(id)\n }\n }, [updateInterval])\n\n const d = toDate(date)\n const valid = !Number.isNaN(d.getTime())\n const absolute = valid ? formatAbsoluteTime(d, locale) : ''\n const text = !valid ? '' : now === null ? absolute : formatRelativeTime(d, now, locale, format)\n\n return (\n <time\n ref={ref}\n dateTime={valid ? d.toISOString() : undefined}\n title={title ?? absolute}\n className={className}\n suppressHydrationWarning\n {...rest}\n >\n {prefix ? <span className={styles.prefix}>{prefix} </span> : null}\n {/* Server renders the absolute date in its timezone; the client re-renders relative text on mount. */}\n <span className={styles.value} suppressHydrationWarning>\n {text}\n </span>\n </time>\n )\n})\n"],"mappings":";;;;;AAqCA,IAAaE,IAAeC,EAA+C,SACzE,EACE,SACA,YAAS,SACT,YAAS,SACT,oBAAiB,KACjB,WACA,UACA,cACA,GAAGC,KAEL,GACA;CACA,IAAM,CAACC,GAAKC,KAAUC,EAAwB,IAAI;CAElD,QAAgB;EAEd,IADAD,EAAO,KAAK,IAAI,CAAC,GACb,CAACE,GAAgB;EACrB,IAAMC,IAAK,kBAAkB;GAC3B,EAAO,KAAK,IAAI,CAAC;EACnB,GAAGD,CAAc;EACjB,aAAa;GACX,cAAcC,CAAE;EAClB;CACF,GAAG,CAACD,CAAc,CAAC;CAEnB,IAAME,IAAIC,EAAOC,CAAI,GACfC,IAAQ,CAAC,OAAO,MAAMH,EAAE,QAAQ,CAAC,GACjCI,IAAWD,IAAQE,EAAmBL,GAAGM,CAAM,IAAI,IACnDC,IAAQJ,IAAaR,MAAQ,OAAOS,IAAWI,EAAmBR,GAAGL,GAAKW,GAAQG,CAAM,IAAxE;CAEtB,OACE,kBAAC,QAAD;EACO;EACL,UAAUN,IAAQH,EAAE,YAAY,IAAI,KAAA;EACpC,OAAOU,KAASN;EACL;EACX,0BAAA;EACA,GAAIV;EANN,UAAA,CAQGiB,IAAS,kBAAC,QAAD;GAAM,WAAWrB,EAAO;GAAxB,UAAA,CAAiCqB,GAAO,GAAO;EAAI,CAAA,IAAA,MAE7D,kBAAC,QAAD;GAAM,WAAWrB,EAAO;GAAO,0BAAA;GAC5B,UAAAiB;EACG,CAAA,CACF;;AAEV,CAAC"}
1
+ {"version":3,"file":"RelativeTime.js","names":["styles","RelativeTime_module_default","RelativeTime","forwardRef","rest","now","setNow","useState","updateInterval","id","d","toDate","date","valid","absolute","formatAbsoluteTime","locale","text","justNowWithin","justNowLabel","formatRelativeTime","format","title","prefix"],"sources":["../../../../src/components/feedback/RelativeTime/RelativeTime.tsx"],"sourcesContent":["import { forwardRef, useEffect, useState, type ReactNode, type TimeHTMLAttributes } from 'react'\nimport { formatAbsoluteTime, formatRelativeTime, toDate, type RelativeTimeStyle } from './format'\nimport styles from './RelativeTime.module.css'\n\nexport interface RelativeTimeProps extends Omit<\n TimeHTMLAttributes<HTMLTimeElement>,\n 'dateTime' | 'children' | 'prefix'\n> {\n /** The moment to describe. Anything `new Date()` accepts. */\n date: Date | string | number\n /** BCP 47 locale. Default `en-AU`. */\n locale?: string\n /** Wording length: \"3 minutes ago\" (`long`), \"3 mins ago\" (`short`, default), `narrow`. */\n format?: RelativeTimeStyle\n /** Re-render every N ms so the text stays true. `0` disables. Default 30 000. */\n updateInterval?: number\n /** Text before the time, e.g. \"Updated\". A space is added for you. */\n prefix?: ReactNode\n /**\n * Seconds either side of now that read as `justNowLabel` instead of `Intl`'s \"now\" or\n * \"in 30 sec\". Default `0`, which leaves the wording to `Intl`.\n */\n justNowWithin?: number\n /** What a moment within `justNowWithin` reads as. Default \"just now\". */\n justNowLabel?: string\n}\n\n/**\n * How long ago, or how long until. A time element that keeps itself current and renders safely on\n * the server.\n *\n * @remarks\n * `RelativeTime` renders a `<time>` that reads \"3 mins ago\" or \"in 2 hours\", and updates itself\n * (every 30 seconds by default). The full date is always in its `title`.\n *\n * @privateRemarks\n * A `<time>` that says how long ago (or until) something happened, and keeps itself current.\n *\n * SSR: the server and the first client render show the absolute date (no clock is read\n * during render, so hydration can't disagree about \"now\"); the relative wording appears\n * once mounted. The absolute date stays available as the `title`.\n *\n * <RelativeTime date={fetchedAt} prefix=\"Updated\" />\n */\nexport const RelativeTime = forwardRef<HTMLTimeElement, RelativeTimeProps>(function RelativeTime(\n {\n date,\n locale = 'en-AU',\n format = 'short',\n updateInterval = 30_000,\n prefix,\n justNowWithin = 0,\n justNowLabel = 'just now',\n title,\n className,\n ...rest\n },\n ref,\n) {\n const [now, setNow] = useState<number | null>(null)\n\n useEffect(() => {\n setNow(Date.now())\n if (!updateInterval) return\n const id = setInterval(() => {\n setNow(Date.now())\n }, updateInterval)\n return () => {\n clearInterval(id)\n }\n }, [updateInterval])\n\n const d = toDate(date)\n const valid = !Number.isNaN(d.getTime())\n const absolute = valid ? formatAbsoluteTime(d, locale) : ''\n const text = !valid\n ? ''\n : now === null\n ? absolute\n : Math.abs(d.getTime() - now) < justNowWithin * 1000\n ? justNowLabel\n : formatRelativeTime(d, now, locale, format)\n\n return (\n <time\n ref={ref}\n dateTime={valid ? d.toISOString() : undefined}\n title={title ?? absolute}\n className={className}\n suppressHydrationWarning\n {...rest}\n >\n {prefix ? <span className={styles.prefix}>{prefix} </span> : null}\n {/* Server renders the absolute date in its timezone; the client re-renders relative text on mount. */}\n <span className={styles.value} suppressHydrationWarning>\n {text}\n </span>\n </time>\n )\n})\n"],"mappings":";;;;;AA4CA,IAAaE,IAAeC,EAA+C,SACzE,EACE,SACA,YAAS,SACT,YAAS,SACT,oBAAiB,KACjB,WACA,mBAAgB,GAChB,kBAAe,YACf,UACA,cACA,GAAGC,KAEL,GACA;CACA,IAAM,CAACC,GAAKC,KAAUC,EAAwB,IAAI;CAElD,QAAgB;EAEd,IADAD,EAAO,KAAK,IAAI,CAAC,GACb,CAACE,GAAgB;EACrB,IAAMC,IAAK,kBAAkB;GAC3B,EAAO,KAAK,IAAI,CAAC;EACnB,GAAGD,CAAc;EACjB,aAAa;GACX,cAAcC,CAAE;EAClB;CACF,GAAG,CAACD,CAAc,CAAC;CAEnB,IAAME,IAAIC,EAAOC,CAAI,GACfC,IAAQ,CAAC,OAAO,MAAMH,EAAE,QAAQ,CAAC,GACjCI,IAAWD,IAAQE,EAAmBL,GAAGM,CAAM,IAAI,IACnDC,IAAQJ,IAEVR,MAAQ,OACNS,IACA,KAAK,IAAIJ,EAAE,QAAQ,IAAIL,CAAG,IAAIa,IAAgB,MAC5CC,IACAC,EAAmBV,GAAGL,GAAKW,GAAQK,CAAM,IAL7C;CAOJ,OACE,kBAAC,QAAD;EACO;EACL,UAAUR,IAAQH,EAAE,YAAY,IAAI,KAAA;EACpC,OAAOY,KAASR;EACL;EACX,0BAAA;EACA,GAAIV;EANN,UAAA,CAQGmB,IAAS,kBAAC,QAAD;GAAM,WAAWvB,EAAO;GAAxB,UAAA,CAAiCuB,GAAO,GAAO;EAAI,CAAA,IAAA,MAE7D,kBAAC,QAAD;GAAM,WAAWvB,EAAO;GAAO,0BAAA;GAC5B,UAAAiB;EACG,CAAA,CACF;;AAEV,CAAC"}
@@ -3,7 +3,7 @@ import type { Tone } from '../../../utils/tokens.js';
3
3
  export interface StatusDotProps extends HTMLAttributes<HTMLSpanElement> {
4
4
  /** State colour. Default `neutral`. */
5
5
  tone?: Tone;
6
- /** What the colour means: "Paid", "Through to the round of 32", "Deploying". Always required — colour alone is not information. */
6
+ /** What the colour means: "Paid", "Awaiting approval", "Deploying". Always required — colour alone is not information. */
7
7
  label: ReactNode;
8
8
  /** Keep the label for screen readers only (e.g. in a dense table with a legend). */
9
9
  labelHidden?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"StatusDot.js","names":["styles","StatusDot_module_default","StatusDot","forwardRef","rest","cx","className","tone","size","labelHidden","label"],"sources":["../../../../src/components/feedback/StatusDot/StatusDot.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes, type ReactNode } from 'react'\nimport { cx } from '#utils/cx'\nimport type { Tone } from '#utils/tokens'\nimport styles from './StatusDot.module.css'\n\nexport interface StatusDotProps extends HTMLAttributes<HTMLSpanElement> {\n /** State colour. Default `neutral`. */\n tone?: Tone\n /** What the colour means: \"Paid\", \"Through to the round of 32\", \"Deploying\". Always required — colour alone is not information. */\n label: ReactNode\n /** Keep the label for screen readers only (e.g. in a dense table with a legend). */\n labelHidden?: boolean\n size?: 'sm' | 'md'\n}\n\n/**\n * A small static dot and a label, for states that sit still.\n *\n * @remarks\n * `StatusDot` pairs a tone with a word, so status never depends on colour alone. For \"happening\n * now\", use a {@link LiveIndicator | LiveIndicator}.\n *\n * @privateRemarks\n * A small static dot plus a label. For states that sit still; for \"happening now\" use LiveIndicator.\n */\nexport const StatusDot = forwardRef<HTMLSpanElement, StatusDotProps>(function StatusDot(\n { tone = 'neutral', label, labelHidden = false, size = 'md', className, ...rest },\n ref,\n) {\n return (\n <span\n ref={ref}\n className={cx(styles.status, className)}\n data-tone={tone}\n data-size={size}\n data-label-hidden={labelHidden || undefined}\n {...rest}\n >\n <span className={styles.dot} aria-hidden=\"true\" />\n <span className={labelHidden ? styles.hidden : styles.label}>{label}</span>\n </span>\n )\n})\n"],"mappings":";;;;;AAyBA,IAAaE,IAAYC,EAA4C,SACnE,EAAE,UAAO,WAAW,UAAO,iBAAc,IAAO,UAAO,MAAM,cAAW,GAAGC,KAC3E,GACA;CACA,OACE,kBAAC,QAAD;EACO;EACL,WAAWC,EAAGL,EAAO,QAAQM,CAAS;EACtC,aAAWC;EACX,aAAWC;EACX,qBAAmBC,KAAe,KAAA;EAClC,GAAIL;EANN,UAAA,CAQE,kBAAC,QAAD;GAAM,WAAWJ,EAAO;GAAK,eAAY;EAAQ,CAAA,GACjD,kBAAC,QAAD;GAAM,WAAWS,IAAcT,EAAO,SAASA,EAAO;GAAQ,UAAAU;EAAY,CAAA,CACtE;;AAEV,CAAC"}
1
+ {"version":3,"file":"StatusDot.js","names":["styles","StatusDot_module_default","StatusDot","forwardRef","rest","cx","className","tone","size","labelHidden","label"],"sources":["../../../../src/components/feedback/StatusDot/StatusDot.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes, type ReactNode } from 'react'\nimport { cx } from '#utils/cx'\nimport type { Tone } from '#utils/tokens'\nimport styles from './StatusDot.module.css'\n\nexport interface StatusDotProps extends HTMLAttributes<HTMLSpanElement> {\n /** State colour. Default `neutral`. */\n tone?: Tone\n /** What the colour means: \"Paid\", \"Awaiting approval\", \"Deploying\". Always required — colour alone is not information. */\n label: ReactNode\n /** Keep the label for screen readers only (e.g. in a dense table with a legend). */\n labelHidden?: boolean\n size?: 'sm' | 'md'\n}\n\n/**\n * A small static dot and a label, for states that sit still.\n *\n * @remarks\n * `StatusDot` pairs a tone with a word, so status never depends on colour alone. For \"happening\n * now\", use a {@link LiveIndicator | LiveIndicator}.\n *\n * @privateRemarks\n * A small static dot plus a label. For states that sit still; for \"happening now\" use LiveIndicator.\n */\nexport const StatusDot = forwardRef<HTMLSpanElement, StatusDotProps>(function StatusDot(\n { tone = 'neutral', label, labelHidden = false, size = 'md', className, ...rest },\n ref,\n) {\n return (\n <span\n ref={ref}\n className={cx(styles.status, className)}\n data-tone={tone}\n data-size={size}\n data-label-hidden={labelHidden || undefined}\n {...rest}\n >\n <span className={styles.dot} aria-hidden=\"true\" />\n <span className={labelHidden ? styles.hidden : styles.label}>{label}</span>\n </span>\n )\n})\n"],"mappings":";;;;;AAyBA,IAAaE,IAAYC,EAA4C,SACnE,EAAE,UAAO,WAAW,UAAO,iBAAc,IAAO,UAAO,MAAM,cAAW,GAAGC,KAC3E,GACA;CACA,OACE,kBAAC,QAAD;EACO;EACL,WAAWC,EAAGL,EAAO,QAAQM,CAAS;EACtC,aAAWC;EACX,aAAWC;EACX,qBAAmBC,KAAe,KAAA;EAClC,GAAIL;EANN,UAAA,CAQE,kBAAC,QAAD;GAAM,WAAWJ,EAAO;GAAK,eAAY;EAAQ,CAAA,GACjD,kBAAC,QAAD;GAAM,WAAWS,IAAcT,EAAO,SAASA,EAAO;GAAQ,UAAAU;EAAY,CAAA,CACtE;;AAEV,CAAC"}
@@ -1,8 +1,8 @@
1
1
  import { cx as e } from "../../../utils/cx.js";
2
2
  import { CheckIcon as t } from "../../../icons/icons.js";
3
3
  import { mergeStyles as n, responsiveVars as r } from "../../../utils/responsive.js";
4
- import { hiddenInputs as i, useControllableValue as a, useFocusLeave as o } from "../CheckboxGroup/choice.js";
5
- import { joinIds as s } from "../internal/refs.js";
4
+ import { joinIds as i } from "../internal/refs.js";
5
+ import { hiddenInputs as a, useControllableValue as o, useFocusLeave as s } from "../CheckboxGroup/choice.js";
6
6
  import { markFieldAware as c, useResolvedField as l } from "../internal/FieldContext.js";
7
7
  import u from "./ChoiceCards.module.js";
8
8
  import { forwardRef as d, useId as f } from "react";
@@ -47,10 +47,10 @@ function x(e, t) {
47
47
  function S(e, t) {
48
48
  return {
49
49
  "aria-labelledby": t.label,
50
- "aria-describedby": s(e.description != null && t.description, e.meta != null && t.meta)
50
+ "aria-describedby": i(e.description != null && t.description, e.meta != null && t.meta)
51
51
  };
52
52
  }
53
- var C = c(d(function(t, s) {
53
+ var C = c(d(function(t, i) {
54
54
  let { type: c, value: d, defaultValue: p, onValueChange: C, options: w, columns: T, name: E, disabled: D, readOnly: O, invalid: k, id: A, className: j, style: M, onBlur: N, "aria-describedby": P, "aria-invalid": F, "aria-labelledby": I, ...L } = t, R = f(), z = l({
55
55
  id: A,
56
56
  describedBy: P,
@@ -58,10 +58,10 @@ var C = c(d(function(t, s) {
58
58
  ariaInvalid: F,
59
59
  disabled: D,
60
60
  readOnly: O
61
- }), B = o(N), V = (e) => e === void 0 ? void 0 : typeof e == "string" ? e ? [e] : v : e, H = C ? (e) => {
61
+ }), B = s(N), V = (e) => e === void 0 ? void 0 : typeof e == "string" ? e ? [e] : v : e, H = C ? (e) => {
62
62
  C(c === "single" ? e[0] ?? "" : [...e]);
63
- } : void 0, [U, W] = a(V(d), V(p) ?? v, H, z.readOnly), G = {
64
- ref: s,
63
+ } : void 0, [U, W] = o(V(d), V(p) ?? v, H, z.readOnly), G = {
64
+ ref: i,
65
65
  id: z.id,
66
66
  className: e(u.cards, j),
67
67
  style: n(r("choice-cards-columns", T, y), M),
@@ -99,7 +99,7 @@ var C = c(d(function(t, s) {
99
99
  kind: "radio"
100
100
  })
101
101
  }, e.value);
102
- }), i(E, U, z.disabled)]
102
+ }), a(E, U, z.disabled)]
103
103
  }) : /* @__PURE__ */ h("div", {
104
104
  role: "group",
105
105
  ...G,
@@ -121,7 +121,7 @@ var C = c(d(function(t, s) {
121
121
  kind: "checkbox"
122
122
  })
123
123
  }, e.value);
124
- }), i(E, U, z.disabled)]
124
+ }), a(E, U, z.disabled)]
125
125
  });
126
126
  }));
127
127
  //#endregion
@@ -1,7 +1,7 @@
1
1
  import { cx as e } from "../../../utils/cx.js";
2
2
  import { CheckIcon as t, ChevronDownIcon as n, CloseIcon as r } from "../../../icons/icons.js";
3
- import { Spinner as i } from "../../feedback/Spinner/Spinner.js";
4
- import { useMergedRefs as a } from "../internal/refs.js";
3
+ import { useMergedRefs as i } from "../internal/refs.js";
4
+ import { Spinner as a } from "../../feedback/Spinner/Spinner.js";
5
5
  import { markFieldAware as o, useResolvedField as ee } from "../internal/FieldContext.js";
6
6
  import te from "../internal/messages.module.js";
7
7
  import ne from "../internal/control.module.js";
@@ -94,7 +94,7 @@ var me = u(function({ children: e, onInteractOutside: t }, n) {
94
94
  required: ke,
95
95
  disabled: Oe,
96
96
  readOnly: Ae
97
- }), Ge = ce(), T = w.id ?? `${Ge}combobox`, Ke = `${T}-listbox`, qe = `${T}-status`, E = !w.disabled && !w.readOnly, D = p(null), O = p(null), Je = a(oe, D), k = p(/* @__PURE__ */ new Map());
97
+ }), Ge = ce(), T = w.id ?? `${Ge}combobox`, Ke = `${T}-listbox`, qe = `${T}-status`, E = !w.disabled && !w.readOnly, D = p(null), O = p(null), Je = i(oe, D), k = p(/* @__PURE__ */ new Map());
98
98
  for (let e of v) k.current.set(e.value, e.label);
99
99
  let A = d((e) => v.find((t) => t.value === e)?.label ?? k.current.get(e) ?? e, [v]), [j, M] = c(u.value, u.defaultValue, u.emit), N = !C && j[0] !== void 0 ? A(j[0]) : "", [P, Ye] = c(he, ge ?? (C || u.defaultValue[0] === void 0 ? "" : A(u.defaultValue[0])), _e), Xe = p(P);
100
100
  Xe.current = P;
@@ -306,7 +306,7 @@ var me = u(function({ children: e, onInteractOutside: t }, n) {
306
306
  /* @__PURE__ */ g("span", {
307
307
  className: l.trailing,
308
308
  children: [
309
- y ? /* @__PURE__ */ h(i, {
309
+ y ? /* @__PURE__ */ h(a, {
310
310
  size: "sm",
311
311
  label: null,
312
312
  className: l.spinner
@@ -373,7 +373,7 @@ var me = u(function({ children: e, onInteractOutside: t }, n) {
373
373
  }),
374
374
  y && U.length === 0 ? /* @__PURE__ */ g("div", {
375
375
  className: l.message,
376
- children: [/* @__PURE__ */ h(i, {
376
+ children: [/* @__PURE__ */ h(a, {
377
377
  size: "sm",
378
378
  label: null
379
379
  }), /* @__PURE__ */ h("span", { children: ye })]
@@ -1,6 +1,6 @@
1
1
  import { EyeIcon as e, EyeOffIcon as t } from "../../../icons/icons.js";
2
- import { IconButton as n } from "../../actions/IconButton/IconButton.js";
3
- import { useMergedRefs as r } from "../internal/refs.js";
2
+ import { useMergedRefs as n } from "../internal/refs.js";
3
+ import { IconButton as r } from "../../actions/IconButton/IconButton.js";
4
4
  import { markFieldAware as i, useResolvedField as a } from "../internal/FieldContext.js";
5
5
  import { Input as o } from "../Input/Input.js";
6
6
  import s from "./PasswordInput.module.js";
@@ -12,7 +12,7 @@ var h = i(c(function({ autoComplete: i, visible: c, defaultVisible: h = !1, onVi
12
12
  let T = a({
13
13
  id: b,
14
14
  disabled: x
15
- }), E = u(), D = T.id ?? `${E}password`, O = d(null), k = r(w, O), [A, j] = f(h), M = c ?? A, N = (e) => {
15
+ }), E = u(), D = T.id ?? `${E}password`, O = d(null), k = n(w, O), [A, j] = f(h), M = c ?? A, N = (e) => {
16
16
  c === void 0 && j(e), e !== M && g?.(e);
17
17
  }, P = d(N);
18
18
  P.current = N, l(() => {
@@ -56,7 +56,7 @@ var h = i(c(function({ autoComplete: i, visible: c, defaultVisible: h = !1, onVi
56
56
  id: `${D}-toggle`,
57
57
  "aria-controls": D,
58
58
  "aria-label": M ? v : _,
59
- children: /* @__PURE__ */ p(n, {
59
+ children: /* @__PURE__ */ p(r, {
60
60
  className: s.toggle,
61
61
  size: "sm",
62
62
  label: M ? v : _,
@@ -14,7 +14,10 @@ export interface AppShellProps extends HTMLAttributes<HTMLDivElement> {
14
14
  mainId?: string;
15
15
  }
16
16
  export interface AppShellHeaderProps extends HTMLAttributes<HTMLElement> {
17
- /** Stick to the top of the viewport while scrolling. Default `true`. */
17
+ /**
18
+ * Stick to the top of the viewport while scrolling. Default `true`. While it sticks, in-page
19
+ * links and `scrollIntoView` land below it, however tall it grows.
20
+ */
18
21
  sticky?: boolean;
19
22
  }
20
23
  export type AppShellMainProps = Omit<HTMLAttributes<HTMLElement>, 'id'>;
@@ -1,70 +1,84 @@
1
1
  import { cx as e } from "../../../utils/cx.js";
2
- import { VisuallyHidden as t } from "../VisuallyHidden/VisuallyHidden.js";
3
- import n from "./AppShell.module.js";
4
- import { createContext as r, forwardRef as i, useContext as a, useId as o } from "react";
5
- import { jsx as s, jsxs as c } from "react/jsx-runtime";
2
+ import { useMergedRefs as t } from "../../inputs/internal/refs.js";
3
+ import { VisuallyHidden as n } from "../VisuallyHidden/VisuallyHidden.js";
4
+ import r from "./AppShell.module.js";
5
+ import { createContext as i, forwardRef as a, useContext as o, useEffect as s, useId as c, useRef as l } from "react";
6
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
6
7
  //#region src/components/layout/AppShell/AppShell.tsx
7
- var l = r(null), u = i(function({ skipLinkLabel: r = "Skip to content", mainId: i, navBreakpoint: a = "lg", className: u, children: d, ...f }, p) {
8
- let m = `app-main-${o().replace(/[^\w-]/g, "")}`, h = i ?? m;
9
- return /* @__PURE__ */ s(l.Provider, {
8
+ var f = i(null), p = a(function({ skipLinkLabel: t = "Skip to content", mainId: i, navBreakpoint: a = "lg", className: o, children: s, ...l }, p) {
9
+ let m = `app-main-${c().replace(/[^\w-]/g, "")}`, h = i ?? m;
10
+ return /* @__PURE__ */ u(f.Provider, {
10
11
  value: { mainId: h },
11
- children: /* @__PURE__ */ c("div", {
12
+ children: /* @__PURE__ */ d("div", {
12
13
  ref: p,
13
- className: e(n.shell, u),
14
+ className: e(r.shell, o),
14
15
  "data-nav-breakpoint": a,
15
- ...f,
16
- children: [/* @__PURE__ */ s(t, {
16
+ ...l,
17
+ children: [/* @__PURE__ */ u(n, {
17
18
  as: "a",
18
19
  href: `#${h}`,
19
20
  focusable: !0,
20
- className: n.skip,
21
- children: r
22
- }), d]
21
+ className: r.skip,
22
+ children: t
23
+ }), s]
23
24
  })
24
25
  });
25
- }), d = i(function({ sticky: t = !0, className: r, ...i }, a) {
26
- return /* @__PURE__ */ s("header", {
27
- ref: a,
28
- className: e(n.header, r),
29
- "data-sticky": t || void 0,
30
- ...i
26
+ }), m = a(function({ sticky: n = !0, className: i, ...a }, o) {
27
+ let c = l(null);
28
+ return s(() => {
29
+ let e = c.current, t = e?.parentElement;
30
+ if (!n || !e || !t) return;
31
+ let r = e.ownerDocument.documentElement, i = r.style.scrollPaddingBlockStart, a = () => {
32
+ let n = `${String(e.getBoundingClientRect().height)}px`;
33
+ t.style.setProperty("--app-shell-header-size", n), r.style.scrollPaddingBlockStart = n;
34
+ };
35
+ a();
36
+ let o = typeof ResizeObserver > "u" ? null : new ResizeObserver(a);
37
+ return o?.observe(e), () => {
38
+ o?.disconnect(), t.style.removeProperty("--app-shell-header-size"), r.style.scrollPaddingBlockStart = i;
39
+ };
40
+ }, [n]), /* @__PURE__ */ u("header", {
41
+ ref: t(o, c),
42
+ className: e(r.header, i),
43
+ "data-sticky": n || void 0,
44
+ ...a
31
45
  });
32
- }), f = i(function({ className: t, ...r }, i) {
33
- let o = a(l);
34
- return /* @__PURE__ */ s("main", {
46
+ }), h = a(function({ className: t, ...n }, i) {
47
+ let a = o(f);
48
+ return /* @__PURE__ */ u("main", {
35
49
  ref: i,
36
- id: o?.mainId,
50
+ id: a?.mainId,
37
51
  tabIndex: -1,
38
- className: e(n.main, t),
39
- ...r
52
+ className: e(r.main, t),
53
+ ...n
40
54
  });
41
- }), p = i(function({ side: t = "start", className: r, ...i }, a) {
42
- return /* @__PURE__ */ s("aside", {
55
+ }), g = a(function({ side: t = "start", className: n, ...i }, a) {
56
+ return /* @__PURE__ */ u("aside", {
43
57
  ref: a,
44
- className: e(n.sidebar, r),
58
+ className: e(r.sidebar, n),
45
59
  "data-side": t,
46
60
  ...i
47
61
  });
48
- }), m = i(function({ className: t, ...r }, i) {
49
- return /* @__PURE__ */ s("footer", {
62
+ }), _ = a(function({ className: t, ...n }, i) {
63
+ return /* @__PURE__ */ u("footer", {
50
64
  ref: i,
51
- className: e(n.footer, t),
52
- ...r
65
+ className: e(r.footer, t),
66
+ ...n
53
67
  });
54
- }), h = i(function({ className: t, ...r }, i) {
55
- return /* @__PURE__ */ s("div", {
68
+ }), v = a(function({ className: t, ...n }, i) {
69
+ return /* @__PURE__ */ u("div", {
56
70
  ref: i,
57
- className: e(n.bottomBar, t),
58
- ...r
71
+ className: e(r.bottomBar, t),
72
+ ...n
59
73
  });
60
- }), g = Object.assign(u, {
61
- Header: d,
62
- Main: f,
63
- Sidebar: p,
64
- Footer: m,
65
- BottomBar: h
74
+ }), y = Object.assign(p, {
75
+ Header: m,
76
+ Main: h,
77
+ Sidebar: g,
78
+ Footer: _,
79
+ BottomBar: v
66
80
  });
67
81
  //#endregion
68
- export { g as AppShell };
82
+ export { y as AppShell };
69
83
 
70
84
  //# sourceMappingURL=AppShell.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AppShell.js","names":["styles","AppShell_module_default","ShellContext","createContext","AppShellRoot","forwardRef","rest","generated","useId","id","mainId","cx","className","navBreakpoint","VisuallyHidden","skipLinkLabel","children","Header","sticky","Main","ctx","useContext","Sidebar","side","Footer","BottomBar","AppShell"],"sources":["../../../../src/components/layout/AppShell/AppShell.tsx"],"sourcesContent":["import { createContext, forwardRef, useContext, useId, type HTMLAttributes } from 'react'\nimport { cx } from '#utils/cx'\nimport { VisuallyHidden } from '#components/layout/VisuallyHidden'\nimport styles from './AppShell.module.css'\n\nconst ShellContext = createContext<{ mainId: string } | null>(null)\n\nexport type AppShellNavBreakpoint = 'md' | 'lg'\n\nexport interface AppShellProps extends HTMLAttributes<HTMLDivElement> {\n /** Text of the skip link rendered before everything else. Default \"Skip to content\". */\n skipLinkLabel?: string\n /**\n * Where navigation hands over from phone to desktop: from this breakpoint up the\n * `Sidebar` appears and the `BottomBar` is removed, so there is never a width with\n * neither. `md` (48em) or `lg` (64em, default). Pair it with the same value on\n * `BottomNav hideAbove` and header `NavLinks hideBelow`.\n */\n navBreakpoint?: AppShellNavBreakpoint\n /** Id given to `AppShell.Main` (the skip link target). Generated when omitted. */\n mainId?: string\n}\n\n/**\n * The frame of an app screen. A header, an optional sidebar, the main region, a footer and a\n * phone-only bottom bar.\n *\n * @remarks\n * `AppShell` is the outermost frame of an app: landmarks in the right order, a skip link, a sticky\n * header, and a hand-over between a phone's bottom bar and a desktop's sidebar or header nav.\n * These docs are an `AppShell`.\n *\n * ## Slots\n *\n * `AppShell.Header`, `AppShell.Sidebar`, `AppShell.Main`, `AppShell.Footer` and\n * `AppShell.BottomBar` place themselves, so their order in JSX doesn't affect the layout. Keep it\n * the same as the reading order anyway: header, sidebar, main, footer, bottom bar.\n *\n * - **Header** is sticky by default (`sticky={false}` to scroll it away). Put a `Container` and an\n * `Inline` inside.\n * - **Sidebar** appears from `navBreakpoint` up. It sits at the start of the main region\n * (`side=\"end\"` for the other side), scrolls on its own, and stays below the header.\n * - **Main** is the `<main>` landmark and the skip link's target.\n * - **BottomBar** is pinned to the bottom of the viewport below `navBreakpoint`, and pads for the\n * phone's home indicator.\n *\n * ## Navigation hand-over\n *\n * `navBreakpoint` (`md` or `lg`, default `lg`) is the one width where phone navigation gives way\n * to desktop navigation, so there's never a width with neither. Pair it with the same value on\n * `BottomNav hideAbove` and the header's `NavLinks hideBelow`.\n *\n * @privateRemarks\n * The frame of an app screen: header, optional sidebar, main, footer, and a\n * mobile-only bottom bar. Slots place themselves; order in JSX doesn't matter,\n * but keep DOM order = reading order (Header, Sidebar, Main, Footer, BottomBar).\n * `navBreakpoint` decides where the bottom bar gives way to the sidebar / header nav.\n *\n * <AppShell navBreakpoint=\"md\">\n * <AppShell.Header>… <NavLinks hideBelow=\"md\">…</NavLinks></AppShell.Header>\n * <AppShell.Main>…</AppShell.Main>\n * <AppShell.BottomBar><BottomNav position=\"static\" hideAbove=\"md\">…</BottomNav></AppShell.BottomBar>\n * </AppShell>\n */\nconst AppShellRoot = forwardRef<HTMLDivElement, AppShellProps>(function AppShell(\n { skipLinkLabel = 'Skip to content', mainId, navBreakpoint = 'lg', className, children, ...rest },\n ref,\n) {\n const generated = `app-main-${useId().replace(/[^\\w-]/g, '')}`\n const id = mainId ?? generated\n return (\n <ShellContext.Provider value={{ mainId: id }}>\n <div\n ref={ref}\n className={cx(styles.shell, className)}\n data-nav-breakpoint={navBreakpoint}\n {...rest}\n >\n <VisuallyHidden as=\"a\" href={`#${id}`} focusable className={styles.skip}>\n {skipLinkLabel}\n </VisuallyHidden>\n {children}\n </div>\n </ShellContext.Provider>\n )\n})\n\nexport interface AppShellHeaderProps extends HTMLAttributes<HTMLElement> {\n /** Stick to the top of the viewport while scrolling. Default `true`. */\n sticky?: boolean\n}\n\n/** The top bar: canvas-coloured, hairline below. Put a `Container` + `Inline` inside. */\nconst Header = forwardRef<HTMLElement, AppShellHeaderProps>(function AppShellHeader(\n { sticky = true, className, ...rest },\n ref,\n) {\n return (\n <header\n ref={ref}\n className={cx(styles.header, className)}\n data-sticky={sticky || undefined}\n {...rest}\n />\n )\n})\n\nexport type AppShellMainProps = Omit<HTMLAttributes<HTMLElement>, 'id'>\n\n/** The page's `<main>` landmark and the skip link's target. Its id comes from `AppShell`. */\nconst Main = forwardRef<HTMLElement, AppShellMainProps>(function AppShellMain(\n { className, ...rest },\n ref,\n) {\n const ctx = useContext(ShellContext)\n return (\n <main\n ref={ref}\n id={ctx?.mainId}\n tabIndex={-1}\n className={cx(styles.main, className)}\n {...rest}\n />\n )\n})\n\nexport interface AppShellSidebarProps extends HTMLAttributes<HTMLElement> {\n /** Which side of Main it sits on. Logical, so it follows writing direction. Default `start`. */\n side?: 'start' | 'end'\n}\n\n/** Navigation or context beside Main. Shown from the shell's `navBreakpoint` up only (default `lg`, 64em). */\nconst Sidebar = forwardRef<HTMLElement, AppShellSidebarProps>(function AppShellSidebar(\n { side = 'start', className, ...rest },\n ref,\n) {\n return <aside ref={ref} className={cx(styles.sidebar, className)} data-side={side} {...rest} />\n})\n\nexport type AppShellFooterProps = HTMLAttributes<HTMLElement>\n\n/** The page footer: a hairline above, quieter ink. */\nconst Footer = forwardRef<HTMLElement, AppShellFooterProps>(function AppShellFooter(\n { className, ...rest },\n ref,\n) {\n return <footer ref={ref} className={cx(styles.footer, className)} {...rest} />\n})\n\nexport type AppShellBottomBarProps = HTMLAttributes<HTMLDivElement>\n\n/**\n * A region pinned to the bottom of the viewport on small screens and removed from the\n * shell's `navBreakpoint` up (default `lg`, 64em). Pads for the home indicator (`safe-area-inset-bottom`). Holds a\n * `BottomNav` or a single primary action.\n */\nconst BottomBar = forwardRef<HTMLDivElement, AppShellBottomBarProps>(function AppShellBottomBar(\n { className, ...rest },\n ref,\n) {\n return <div ref={ref} className={cx(styles.bottomBar, className)} {...rest} />\n})\n\nexport const AppShell = Object.assign(AppShellRoot, { Header, Main, Sidebar, Footer, BottomBar })\n"],"mappings":";;;;;;AAKA,IAAME,IAAeC,EAAyC,IAAI,GA2D5DC,IAAeC,EAA0C,SAC7D,EAAE,mBAAgB,mBAAmB,WAAQ,mBAAgB,MAAM,cAAW,aAAU,GAAGC,KAC3F,GACA;CACA,IAAMC,IAAY,YAAYC,EAAM,CAAC,CAAC,QAAQ,WAAW,EAAE,KACrDC,IAAKC,KAAUH;CACrB,OACE,kBAACL,EAAa,UAAd;EAAuB,OAAO,EAAE,QAAQO,EAAG;EACzC,UAAA,kBAAC,OAAD;GACO;GACL,WAAWE,EAAGX,EAAO,OAAOY,CAAS;GACrC,uBAAqBC;GACrB,GAAIP;GAJN,UAAA,CAME,kBAACQ,GAAD;IAAgB,IAAG;IAAI,MAAM,IAAIL;IAAM,WAAA;IAAU,WAAWT,EAAO;IAChE,UAAAe;GACa,CAAA,GACfC,CACE;;CACgB,CAAA;AAE3B,CAAC,GAQKC,IAASZ,EAA6C,SAC1D,EAAE,YAAS,IAAM,cAAW,GAAGC,KAC/B,GACA;CACA,OACE,kBAAC,UAAD;EACO;EACL,WAAWK,EAAGX,EAAO,QAAQY,CAAS;EACtC,eAAaM,KAAU,KAAA;EACvB,GAAIZ;CACL,CAAA;AAEL,CAAC,GAKKa,IAAOd,EAA2C,SACtD,EAAE,cAAW,GAAGC,KAChB,GACA;CACA,IAAMc,IAAMC,EAAWnB,CAAY;CACnC,OACE,kBAAC,QAAD;EACO;EACL,IAAIkB,GAAK;EACT,UAAU;EACV,WAAWT,EAAGX,EAAO,MAAMY,CAAS;EACpC,GAAIN;CACL,CAAA;AAEL,CAAC,GAQKgB,IAAUjB,EAA8C,SAC5D,EAAE,UAAO,SAAS,cAAW,GAAGC,KAChC,GACA;CACA,OAAO,kBAAC,SAAD;EAAY;EAAK,WAAWK,EAAGX,EAAO,SAASY,CAAS;EAAG,aAAWW;EAAM,GAAIjB;CAAO,CAAA;AAChG,CAAC,GAKKkB,IAASnB,EAA6C,SAC1D,EAAE,cAAW,GAAGC,KAChB,GACA;CACA,OAAO,kBAAC,UAAD;EAAa;EAAK,WAAWK,EAAGX,EAAO,QAAQY,CAAS;EAAG,GAAIN;CAAO,CAAA;AAC/E,CAAC,GASKmB,IAAYpB,EAAmD,SACnE,EAAE,cAAW,GAAGC,KAChB,GACA;CACA,OAAO,kBAAC,OAAD;EAAU;EAAK,WAAWK,EAAGX,EAAO,WAAWY,CAAS;EAAG,GAAIN;CAAO,CAAA;AAC/E,CAAC,GAEYoB,IAAW,OAAO,OAAOtB,GAAc;CAAE;CAAQ;CAAM;CAAS;CAAQ;AAAU,CAAC"}
1
+ {"version":3,"file":"AppShell.js","names":["styles","AppShell_module_default","ShellContext","createContext","AppShellRoot","forwardRef","rest","generated","useId","id","mainId","cx","className","navBreakpoint","VisuallyHidden","skipLinkLabel","children","Header","header","useRef","useEffect","el","shell","sticky","root","previous","measure","size","observer","useMergedRefs","ref","Main","ctx","useContext","Sidebar","side","Footer","BottomBar","AppShell"],"sources":["../../../../src/components/layout/AppShell/AppShell.tsx"],"sourcesContent":["import {\n createContext,\n forwardRef,\n useContext,\n useEffect,\n useId,\n useRef,\n type HTMLAttributes,\n} from 'react'\nimport { cx } from '#utils/cx'\nimport { useMergedRefs } from '#components/inputs/internal/refs'\nimport { VisuallyHidden } from '#components/layout/VisuallyHidden'\nimport styles from './AppShell.module.css'\n\nconst ShellContext = createContext<{ mainId: string } | null>(null)\n\nexport type AppShellNavBreakpoint = 'md' | 'lg'\n\nexport interface AppShellProps extends HTMLAttributes<HTMLDivElement> {\n /** Text of the skip link rendered before everything else. Default \"Skip to content\". */\n skipLinkLabel?: string\n /**\n * Where navigation hands over from phone to desktop: from this breakpoint up the\n * `Sidebar` appears and the `BottomBar` is removed, so there is never a width with\n * neither. `md` (48em) or `lg` (64em, default). Pair it with the same value on\n * `BottomNav hideAbove` and header `NavLinks hideBelow`.\n */\n navBreakpoint?: AppShellNavBreakpoint\n /** Id given to `AppShell.Main` (the skip link target). Generated when omitted. */\n mainId?: string\n}\n\n/**\n * The frame of an app screen. A header, an optional sidebar, the main region, a footer and a\n * phone-only bottom bar.\n *\n * @remarks\n * `AppShell` is the outermost frame of an app: landmarks in the right order, a skip link, a sticky\n * header, and a hand-over between a phone's bottom bar and a desktop's sidebar or header nav.\n * These docs are an `AppShell`.\n *\n * ## Slots\n *\n * `AppShell.Header`, `AppShell.Sidebar`, `AppShell.Main`, `AppShell.Footer` and\n * `AppShell.BottomBar` place themselves, so their order in JSX doesn't affect the layout. Keep it\n * the same as the reading order anyway: header, sidebar, main, footer, bottom bar.\n *\n * - **Header** is sticky by default (`sticky={false}` to scroll it away). While it sticks, in-page\n * links and `scrollIntoView` land just below it, whatever its height. Put a `Container` and an\n * `Inline` inside.\n * - **Sidebar** appears from `navBreakpoint` up. It sits at the start of the main region\n * (`side=\"end\"` for the other side), scrolls on its own, and stays below the header.\n * - **Main** is the `<main>` landmark and the skip link's target.\n * - **BottomBar** is pinned to the bottom of the viewport below `navBreakpoint`, and pads for the\n * phone's home indicator.\n *\n * ## Navigation hand-over\n *\n * `navBreakpoint` (`md` or `lg`, default `lg`) is the one width where phone navigation gives way\n * to desktop navigation, so there's never a width with neither. Pair it with the same value on\n * `BottomNav hideAbove` and the header's `NavLinks hideBelow`.\n *\n * @privateRemarks\n * The frame of an app screen: header, optional sidebar, main, footer, and a\n * mobile-only bottom bar. Slots place themselves; order in JSX doesn't matter,\n * but keep DOM order = reading order (Header, Sidebar, Main, Footer, BottomBar).\n * `navBreakpoint` decides where the bottom bar gives way to the sidebar / header nav.\n *\n * <AppShell navBreakpoint=\"md\">\n * <AppShell.Header>… <NavLinks hideBelow=\"md\">…</NavLinks></AppShell.Header>\n * <AppShell.Main>…</AppShell.Main>\n * <AppShell.BottomBar><BottomNav position=\"static\" hideAbove=\"md\">…</BottomNav></AppShell.BottomBar>\n * </AppShell>\n */\nconst AppShellRoot = forwardRef<HTMLDivElement, AppShellProps>(function AppShell(\n { skipLinkLabel = 'Skip to content', mainId, navBreakpoint = 'lg', className, children, ...rest },\n ref,\n) {\n const generated = `app-main-${useId().replace(/[^\\w-]/g, '')}`\n const id = mainId ?? generated\n return (\n <ShellContext.Provider value={{ mainId: id }}>\n <div\n ref={ref}\n className={cx(styles.shell, className)}\n data-nav-breakpoint={navBreakpoint}\n {...rest}\n >\n <VisuallyHidden as=\"a\" href={`#${id}`} focusable className={styles.skip}>\n {skipLinkLabel}\n </VisuallyHidden>\n {children}\n </div>\n </ShellContext.Provider>\n )\n})\n\nexport interface AppShellHeaderProps extends HTMLAttributes<HTMLElement> {\n /**\n * Stick to the top of the viewport while scrolling. Default `true`. While it sticks, in-page\n * links and `scrollIntoView` land below it, however tall it grows.\n */\n sticky?: boolean\n}\n\n/** The top bar: canvas-coloured, hairline below. Put a `Container` + `Inline` inside. */\nconst Header = forwardRef<HTMLElement, AppShellHeaderProps>(function AppShellHeader(\n { sticky = true, className, ...rest },\n ref,\n) {\n const header = useRef<HTMLElement>(null)\n // While it sticks, keep two things in step with its height: the document's\n // scroll-padding-block-start, so anchor jumps land below it, and the shell's\n // --app-shell-header-size, which the sticky offset reads. Both are undone when it stops.\n useEffect(() => {\n const el = header.current\n const shell = el?.parentElement\n if (!sticky || !el || !shell) return\n const root = el.ownerDocument.documentElement\n const previous = root.style.scrollPaddingBlockStart\n const measure = () => {\n const size = `${String(el.getBoundingClientRect().height)}px`\n shell.style.setProperty('--app-shell-header-size', size)\n root.style.scrollPaddingBlockStart = size\n }\n measure()\n const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(measure)\n observer?.observe(el)\n return () => {\n observer?.disconnect()\n shell.style.removeProperty('--app-shell-header-size')\n root.style.scrollPaddingBlockStart = previous\n }\n }, [sticky])\n return (\n <header\n ref={useMergedRefs(ref, header)}\n className={cx(styles.header, className)}\n data-sticky={sticky || undefined}\n {...rest}\n />\n )\n})\n\nexport type AppShellMainProps = Omit<HTMLAttributes<HTMLElement>, 'id'>\n\n/** The page's `<main>` landmark and the skip link's target. Its id comes from `AppShell`. */\nconst Main = forwardRef<HTMLElement, AppShellMainProps>(function AppShellMain(\n { className, ...rest },\n ref,\n) {\n const ctx = useContext(ShellContext)\n return (\n <main\n ref={ref}\n id={ctx?.mainId}\n tabIndex={-1}\n className={cx(styles.main, className)}\n {...rest}\n />\n )\n})\n\nexport interface AppShellSidebarProps extends HTMLAttributes<HTMLElement> {\n /** Which side of Main it sits on. Logical, so it follows writing direction. Default `start`. */\n side?: 'start' | 'end'\n}\n\n/** Navigation or context beside Main. Shown from the shell's `navBreakpoint` up only (default `lg`, 64em). */\nconst Sidebar = forwardRef<HTMLElement, AppShellSidebarProps>(function AppShellSidebar(\n { side = 'start', className, ...rest },\n ref,\n) {\n return <aside ref={ref} className={cx(styles.sidebar, className)} data-side={side} {...rest} />\n})\n\nexport type AppShellFooterProps = HTMLAttributes<HTMLElement>\n\n/** The page footer: a hairline above, quieter ink. */\nconst Footer = forwardRef<HTMLElement, AppShellFooterProps>(function AppShellFooter(\n { className, ...rest },\n ref,\n) {\n return <footer ref={ref} className={cx(styles.footer, className)} {...rest} />\n})\n\nexport type AppShellBottomBarProps = HTMLAttributes<HTMLDivElement>\n\n/**\n * A region pinned to the bottom of the viewport on small screens and removed from the\n * shell's `navBreakpoint` up (default `lg`, 64em). Pads for the home indicator (`safe-area-inset-bottom`). Holds a\n * `BottomNav` or a single primary action.\n */\nconst BottomBar = forwardRef<HTMLDivElement, AppShellBottomBarProps>(function AppShellBottomBar(\n { className, ...rest },\n ref,\n) {\n return <div ref={ref} className={cx(styles.bottomBar, className)} {...rest} />\n})\n\nexport const AppShell = Object.assign(AppShellRoot, { Header, Main, Sidebar, Footer, BottomBar })\n"],"mappings":";;;;;;;AAcA,IAAME,IAAeC,EAAyC,IAAI,GA4D5DC,IAAeC,EAA0C,SAC7D,EAAE,mBAAgB,mBAAmB,WAAQ,mBAAgB,MAAM,cAAW,aAAU,GAAGC,KAC3F,GACA;CACA,IAAMC,IAAY,YAAYC,EAAM,CAAC,CAAC,QAAQ,WAAW,EAAE,KACrDC,IAAKC,KAAUH;CACrB,OACE,kBAACL,EAAa,UAAd;EAAuB,OAAO,EAAE,QAAQO,EAAG;EACzC,UAAA,kBAAC,OAAD;GACO;GACL,WAAWE,EAAGX,EAAO,OAAOY,CAAS;GACrC,uBAAqBC;GACrB,GAAIP;GAJN,UAAA,CAME,kBAACQ,GAAD;IAAgB,IAAG;IAAI,MAAM,IAAIL;IAAM,WAAA;IAAU,WAAWT,EAAO;IAChE,UAAAe;GACa,CAAA,GACfC,CACE;;CACgB,CAAA;AAE3B,CAAC,GAWKC,IAASZ,EAA6C,SAC1D,EAAE,YAAS,IAAM,cAAW,GAAGC,KAC/B,GACA;CACA,IAAMY,IAASC,EAAoB,IAAI;CAwBvC,OApBAC,QAAgB;EACd,IAAMC,IAAKH,EAAO,SACZI,IAAQD,GAAI;EAClB,IAAI,CAACE,KAAU,CAACF,KAAM,CAACC,GAAO;EAC9B,IAAME,IAAOH,EAAG,cAAc,iBACxBI,IAAWD,EAAK,MAAM,yBACtBE,UAAgB;GACpB,IAAMC,IAAO,GAAG,OAAON,EAAG,sBAAsB,CAAC,CAAC,MAAM,EAAE;GAE1D,AADAC,EAAM,MAAM,YAAY,2BAA2BK,CAAI,GACvD,EAAK,MAAM,0BAA0BA;EACvC;EACA,EAAQ;EACR,IAAMC,IAAW,OAAO,iBAAmB,MAAc,OAAO,IAAI,eAAeF,CAAO;EAE1F,OADAE,GAAU,QAAQP,CAAE,SACP;GAGX,AAFAO,GAAU,WAAW,GACrBN,EAAM,MAAM,eAAe,yBAAyB,GACpD,EAAK,MAAM,0BAA0BG;EACvC;CACF,GAAG,CAACF,CAAM,CAAC,GAET,kBAAC,UAAD;EACE,KAAKM,EAAcC,GAAKZ,CAAM;EAC9B,WAAWP,EAAGX,EAAO,QAAQY,CAAS;EACtC,eAAaW,KAAU,KAAA;EACvB,GAAIjB;CACL,CAAA;AAEL,CAAC,GAKKyB,IAAO1B,EAA2C,SACtD,EAAE,cAAW,GAAGC,KAChB,GACA;CACA,IAAM0B,IAAMC,EAAW/B,CAAY;CACnC,OACE,kBAAC,QAAD;EACO;EACL,IAAI8B,GAAK;EACT,UAAU;EACV,WAAWrB,EAAGX,EAAO,MAAMY,CAAS;EACpC,GAAIN;CACL,CAAA;AAEL,CAAC,GAQK4B,IAAU7B,EAA8C,SAC5D,EAAE,UAAO,SAAS,cAAW,GAAGC,KAChC,GACA;CACA,OAAO,kBAAC,SAAD;EAAY;EAAK,WAAWK,EAAGX,EAAO,SAASY,CAAS;EAAG,aAAWuB;EAAM,GAAI7B;CAAO,CAAA;AAChG,CAAC,GAKK8B,IAAS/B,EAA6C,SAC1D,EAAE,cAAW,GAAGC,KAChB,GACA;CACA,OAAO,kBAAC,UAAD;EAAa;EAAK,WAAWK,EAAGX,EAAO,QAAQY,CAAS;EAAG,GAAIN;CAAO,CAAA;AAC/E,CAAC,GASK+B,IAAYhC,EAAmD,SACnE,EAAE,cAAW,GAAGC,KAChB,GACA;CACA,OAAO,kBAAC,OAAD;EAAU;EAAK,WAAWK,EAAGX,EAAO,WAAWY,CAAS;EAAG,GAAIN;CAAO,CAAA;AAC/E,CAAC,GAEYgC,IAAW,OAAO,OAAOlC,GAAc;CAAE;CAAQ;CAAM;CAAS;CAAQ;AAAU,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"AppShell.module.js","names":["shell","header","skip","main","sidebar","footer","bottomBar","AppShell_module_default"],"sources":["../../../../src/components/layout/AppShell/AppShell.module.css"],"sourcesContent":["/*\n * Component tokens:\n * --app-shell-header-height minimum header height, also the sidebar's sticky offset\n * (default: control-lg + space-4)\n * --app-shell-sidebar-width default 16rem\n * --app-shell-header-bg default var(--color-canvas) — opaque, never glass\n * --app-shell-bar-rule rule under the header / above the bottom bar\n * (default var(--color-line-strong): these are the frame's edges)\n *\n * The bottom bar is `position: sticky` as the grid's last row rather than `fixed`, so\n * nothing needs a magic padding to stop it covering the end of Main.\n */\n.shell {\n --app-shell-sticky-offset: 0px;\n\n position: relative;\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n grid-template-rows: auto 1fr auto auto;\n grid-template-areas:\n 'header'\n 'main'\n 'footer'\n 'bottombar';\n min-block-size: 100dvh;\n}\n\n.shell:has(> .header[data-sticky]) {\n --app-shell-sticky-offset: var(\n --app-shell-header-height,\n calc(var(--control-lg) + var(--space-4))\n );\n}\n\n/* Skip link: clipped until focused, then a pill in the top corner above everything. */\n.skip {\n position: absolute;\n inset-block-start: var(--space-3);\n inset-inline-start: var(--space-3);\n z-index: var(--z-toast);\n padding: var(--space-2) var(--space-4);\n border: var(--border-width) solid var(--color-line-strong);\n border-radius: var(--radius-action);\n background: var(--color-surface-raised);\n box-shadow: var(--shadow-float);\n color: var(--color-ink);\n font-size: var(--text-sm);\n font-weight: var(--label-weight);\n text-decoration: none;\n}\n\n.header {\n grid-area: header;\n display: flex;\n align-items: center;\n min-block-size: var(--app-shell-header-height, calc(var(--control-lg) + var(--space-4)));\n min-inline-size: 0;\n padding-block: var(--space-2);\n border-block-end: var(--border-width) solid var(--app-shell-bar-rule, var(--color-line-strong));\n background-color: var(--app-shell-header-bg, var(--color-canvas));\n background-image: var(--canvas-image);\n background-size: var(--canvas-image-size);\n color: var(--color-ink);\n}\n.header > * {\n flex: 1 1 auto;\n min-inline-size: 0;\n}\n.header[data-sticky] {\n position: sticky;\n inset-block-start: 0;\n z-index: var(--z-sticky);\n}\n\n.main {\n grid-area: main;\n min-inline-size: 0;\n}\n.main:focus {\n outline: none;\n}\n\n.sidebar {\n grid-area: sidebar;\n display: none;\n min-inline-size: 0;\n}\n\n.footer {\n grid-area: footer;\n min-inline-size: 0;\n padding-block: var(--space-6);\n border-block-start: var(--border-width) solid var(--color-line);\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n}\n\n.bottomBar {\n grid-area: bottombar;\n position: sticky;\n inset-block-end: 0;\n z-index: var(--z-sticky);\n min-inline-size: 0;\n padding-block-end: env(safe-area-inset-bottom, 0px);\n border-block-start: var(--border-width) solid var(--app-shell-bar-rule, var(--color-line-strong));\n background-color: var(--app-shell-header-bg, var(--color-canvas));\n background-image: var(--canvas-image);\n background-size: var(--canvas-image-size);\n}\n\n/*\n * Nav hand-over. `data-nav-breakpoint` (md | lg) on the shell decides where the bottom\n * bar goes and the sidebar arrives — one breakpoint for both, so no width has neither.\n */\n.sidebar {\n position: sticky;\n inset-block-start: var(--app-shell-sticky-offset);\n align-self: start;\n block-size: calc(100dvh - var(--app-shell-sticky-offset));\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: var(--space-5) var(--space-4);\n}\n.sidebar[data-side='start'] {\n border-inline-end: var(--border-width) solid var(--color-line);\n}\n.sidebar[data-side='end'] {\n border-inline-start: var(--border-width) solid var(--color-line);\n}\n\n@media (min-width: 48em) {\n .shell[data-nav-breakpoint='md'] > .bottomBar {\n display: none;\n }\n .shell[data-nav-breakpoint='md'] > .sidebar {\n display: block;\n }\n .shell[data-nav-breakpoint='md']:has(> .sidebar) {\n grid-template-columns: var(--app-shell-sidebar-width, 16rem) minmax(0, 1fr);\n grid-template-areas:\n 'header header'\n 'sidebar main'\n 'sidebar footer'\n 'bottombar bottombar';\n }\n .shell[data-nav-breakpoint='md']:has(> .sidebar[data-side='end']) {\n grid-template-columns: minmax(0, 1fr) var(--app-shell-sidebar-width, 16rem);\n grid-template-areas:\n 'header header'\n 'main sidebar'\n 'footer sidebar'\n 'bottombar bottombar';\n }\n}\n\n@media (min-width: 64em) {\n .shell[data-nav-breakpoint='lg'] > .bottomBar {\n display: none;\n }\n .shell[data-nav-breakpoint='lg'] > .sidebar {\n display: block;\n }\n .shell[data-nav-breakpoint='lg']:has(> .sidebar) {\n grid-template-columns: var(--app-shell-sidebar-width, 16rem) minmax(0, 1fr);\n grid-template-areas:\n 'header header'\n 'sidebar main'\n 'sidebar footer'\n 'bottombar bottombar';\n }\n .shell[data-nav-breakpoint='lg']:has(> .sidebar[data-side='end']) {\n grid-template-columns: minmax(0, 1fr) var(--app-shell-sidebar-width, 16rem);\n grid-template-areas:\n 'header header'\n 'main sidebar'\n 'footer sidebar'\n 'bottombar bottombar';\n }\n}\n\n/* `hidden` wins over the display above (author CSS otherwise beats the UA [hidden] rule). */\n.shell[hidden] {\n display: none;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"AppShell.module.js","names":["shell","header","skip","main","sidebar","footer","bottomBar","AppShell_module_default"],"sources":["../../../../src/components/layout/AppShell/AppShell.module.css"],"sourcesContent":["/*\n * Component tokens:\n * --app-shell-header-height minimum header height, also the sidebar's sticky offset\n * (default: control-lg + space-4)\n * --app-shell-sidebar-width default 16rem\n * --app-shell-header-bg default var(--color-canvas) — opaque, never glass\n * --app-shell-bar-rule rule under the header / above the bottom bar\n * (default var(--color-line-strong): these are the frame's edges)\n *\n * Set by the component, not a theme:\n * --app-shell-header-size the sticky header's measured height, on the shell; the sticky\n * offset reads it before --app-shell-header-height\n *\n * The bottom bar is `position: sticky` as the grid's last row rather than `fixed`, so\n * nothing needs a magic padding to stop it covering the end of Main.\n */\n.shell {\n --app-shell-sticky-offset: 0px;\n\n position: relative;\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n grid-template-rows: auto 1fr auto auto;\n grid-template-areas:\n 'header'\n 'main'\n 'footer'\n 'bottombar';\n min-block-size: 100dvh;\n}\n\n.shell:has(> .header[data-sticky]) {\n --app-shell-sticky-offset: var(\n --app-shell-header-size,\n var(--app-shell-header-height, calc(var(--control-lg) + var(--space-4)))\n );\n}\n\n/* Skip link: clipped until focused, then a pill in the top corner above everything. */\n.skip {\n position: absolute;\n inset-block-start: var(--space-3);\n inset-inline-start: var(--space-3);\n z-index: var(--z-toast);\n padding: var(--space-2) var(--space-4);\n border: var(--border-width) solid var(--color-line-strong);\n border-radius: var(--radius-action);\n background: var(--color-surface-raised);\n box-shadow: var(--shadow-float);\n color: var(--color-ink);\n font-size: var(--text-sm);\n font-weight: var(--label-weight);\n text-decoration: none;\n}\n\n.header {\n grid-area: header;\n display: flex;\n align-items: center;\n min-block-size: var(--app-shell-header-height, calc(var(--control-lg) + var(--space-4)));\n min-inline-size: 0;\n padding-block: var(--space-2);\n border-block-end: var(--border-width) solid var(--app-shell-bar-rule, var(--color-line-strong));\n background-color: var(--app-shell-header-bg, var(--color-canvas));\n background-image: var(--canvas-image);\n background-size: var(--canvas-image-size);\n color: var(--color-ink);\n}\n.header > * {\n flex: 1 1 auto;\n min-inline-size: 0;\n}\n.header[data-sticky] {\n position: sticky;\n inset-block-start: 0;\n z-index: var(--z-sticky);\n}\n\n.main {\n grid-area: main;\n min-inline-size: 0;\n}\n.main:focus {\n outline: none;\n}\n\n.sidebar {\n grid-area: sidebar;\n display: none;\n min-inline-size: 0;\n}\n\n.footer {\n grid-area: footer;\n min-inline-size: 0;\n padding-block: var(--space-6);\n border-block-start: var(--border-width) solid var(--color-line);\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n}\n\n.bottomBar {\n grid-area: bottombar;\n position: sticky;\n inset-block-end: 0;\n z-index: var(--z-sticky);\n min-inline-size: 0;\n padding-block-end: env(safe-area-inset-bottom, 0px);\n border-block-start: var(--border-width) solid var(--app-shell-bar-rule, var(--color-line-strong));\n background-color: var(--app-shell-header-bg, var(--color-canvas));\n background-image: var(--canvas-image);\n background-size: var(--canvas-image-size);\n}\n\n/*\n * Nav hand-over. `data-nav-breakpoint` (md | lg) on the shell decides where the bottom\n * bar goes and the sidebar arrives — one breakpoint for both, so no width has neither.\n */\n.sidebar {\n position: sticky;\n inset-block-start: var(--app-shell-sticky-offset);\n align-self: start;\n block-size: calc(100dvh - var(--app-shell-sticky-offset));\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: var(--space-5) var(--space-4);\n}\n.sidebar[data-side='start'] {\n border-inline-end: var(--border-width) solid var(--color-line);\n}\n.sidebar[data-side='end'] {\n border-inline-start: var(--border-width) solid var(--color-line);\n}\n\n@media (min-width: 48em) {\n .shell[data-nav-breakpoint='md'] > .bottomBar {\n display: none;\n }\n .shell[data-nav-breakpoint='md'] > .sidebar {\n display: block;\n }\n .shell[data-nav-breakpoint='md']:has(> .sidebar) {\n grid-template-columns: var(--app-shell-sidebar-width, 16rem) minmax(0, 1fr);\n grid-template-areas:\n 'header header'\n 'sidebar main'\n 'sidebar footer'\n 'bottombar bottombar';\n }\n .shell[data-nav-breakpoint='md']:has(> .sidebar[data-side='end']) {\n grid-template-columns: minmax(0, 1fr) var(--app-shell-sidebar-width, 16rem);\n grid-template-areas:\n 'header header'\n 'main sidebar'\n 'footer sidebar'\n 'bottombar bottombar';\n }\n}\n\n@media (min-width: 64em) {\n .shell[data-nav-breakpoint='lg'] > .bottomBar {\n display: none;\n }\n .shell[data-nav-breakpoint='lg'] > .sidebar {\n display: block;\n }\n .shell[data-nav-breakpoint='lg']:has(> .sidebar) {\n grid-template-columns: var(--app-shell-sidebar-width, 16rem) minmax(0, 1fr);\n grid-template-areas:\n 'header header'\n 'sidebar main'\n 'sidebar footer'\n 'bottombar bottombar';\n }\n .shell[data-nav-breakpoint='lg']:has(> .sidebar[data-side='end']) {\n grid-template-columns: minmax(0, 1fr) var(--app-shell-sidebar-width, 16rem);\n grid-template-areas:\n 'header header'\n 'main sidebar'\n 'footer sidebar'\n 'bottombar bottombar';\n }\n}\n\n/* `hidden` wins over the display above (author CSS otherwise beats the UA [hidden] rule). */\n.shell[hidden] {\n display: none;\n}\n"],"mappings":""}
@@ -1,9 +1,9 @@
1
1
  import { type HTMLAttributes } from 'react';
2
2
  import { type Responsive } from '../../../utils/responsive.js';
3
- import { type Space } from '../../../utils/tokens.js';
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';
6
+ export type BoxSurface = 'none' | 'canvas' | 'surface' | 'sunken' | 'raised' | 'inverse' | `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. */
@@ -12,7 +12,10 @@ export interface BoxProps extends HTMLAttributes<HTMLElement>, VisibilityProps {
12
12
  paddingX?: Responsive<Space>;
13
13
  /** Block (top/bottom) padding; overrides `padding` on that axis. Responsive. */
14
14
  paddingY?: Responsive<Space>;
15
- /** Background fill. `inverse` also re-points ink and line colours for its children. */
15
+ /**
16
+ * Background fill. `inverse` and the categorical `cat-1` to `cat-8` (one person's or team's
17
+ * colour, matching their `Tag`) also re-point ink and line colours for its children.
18
+ */
16
19
  surface?: BoxSurface;
17
20
  /** Hairline border in `--color-line`. One edge treatment per element — a border *or* a fill. */
18
21
  border?: boolean;
@@ -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 } 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 = 'none' | 'canvas' | 'surface' | 'sunken' | 'raised' | 'inverse'\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 /** Background fill. `inverse` also re-points ink and line colours for its children. */\n surface?: BoxSurface\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 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-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":";;;;;;;;AA0CA,IAAaE,IAAMC,EAAkC,SACnD,EACE,YACA,aACA,aACA,aAAU,QACV,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,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,GAAIb;CACL,CAAA;AAEL,CAAC"}
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' | 'canvas' | 'surface' | 'sunken' | 'raised' | 'inverse' | `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` and the categorical `cat-1` to `cat-8` (one person's or team's\n * colour, matching their `Tag`) also re-point ink and line colours for its children.\n */\n surface?: BoxSurface\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 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-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":";;;;;;;;AA8CA,IAAaE,IAAMC,EAAkC,SACnD,EACE,YACA,aACA,aACA,aAAU,QACV,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,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,GAAIb;CACL,CAAA;AAEL,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Box.module.js","names":["box","Box_module_default"],"sources":["../../../../src/components/layout/Box/Box.module.css"],"sourcesContent":["/*\n * Responsive pattern: see layout/Stack/Stack.module.css. Axis padding (--box-px/-py)\n * falls back to the all-sides value (--box-p) per breakpoint.\n *\n * --box-fill / --box-on (read-only): the fill and ink of an `inverse` Box.\n */\n.box {\n --_p: var(--box-p-base, 0px);\n --_px: var(--box-px-base, var(--_p));\n --_py: var(--box-py-base, var(--_p));\n\n display: block;\n min-inline-size: 0;\n padding-block: var(--_py);\n padding-inline: var(--_px);\n}\n\n@media (min-width: 40em) {\n .box {\n --_p: var(--box-p-sm, 0px);\n --_px: var(--box-px-sm, var(--_p));\n --_py: var(--box-py-sm, var(--_p));\n }\n}\n@media (min-width: 48em) {\n .box {\n --_p: var(--box-p-md, 0px);\n --_px: var(--box-px-md, var(--_p));\n --_py: var(--box-py-md, var(--_p));\n }\n}\n@media (min-width: 64em) {\n .box {\n --_p: var(--box-p-lg, 0px);\n --_px: var(--box-px-lg, var(--_p));\n --_py: var(--box-py-lg, var(--_p));\n }\n}\n@media (min-width: 80em) {\n .box {\n --_p: var(--box-p-xl, 0px);\n --_px: var(--box-px-xl, var(--_p));\n --_py: var(--box-py-xl, var(--_p));\n }\n}\n\n/* Surfaces */\n.box[data-surface='canvas'] {\n background-color: var(--color-canvas);\n background-image: var(--canvas-image);\n background-size: var(--canvas-image-size);\n color: var(--color-ink);\n}\n.box[data-surface='surface'] {\n background-color: var(--color-surface);\n color: var(--color-ink);\n}\n.box[data-surface='sunken'] {\n background-color: var(--color-surface-sunken);\n color: var(--color-ink);\n}\n.box[data-surface='raised'] {\n background-color: var(--color-surface-raised);\n color: var(--color-ink);\n}\n/* Inverse re-points the colour roles for descendants — same approach as Section. */\n.box[data-surface='inverse'] {\n --box-fill: var(--color-surface-inverse);\n --box-on: var(--color-ink-inverse);\n --color-ink: var(--box-on);\n --color-ink-muted: color-mix(in oklab, var(--box-on) 76%, var(--box-fill));\n --color-ink-subtle: color-mix(in oklab, var(--box-on) 60%, var(--box-fill));\n --color-line: color-mix(in oklab, var(--box-on) 22%, var(--box-fill));\n --color-line-strong: color-mix(in oklab, var(--box-on) 45%, var(--box-fill));\n --color-canvas: var(--box-fill);\n --color-surface: color-mix(in oklab, var(--box-on) 7%, var(--box-fill));\n --color-surface-sunken: color-mix(in oklab, var(--box-on) 12%, var(--box-fill));\n --color-surface-raised: color-mix(in oklab, var(--box-on) 4%, var(--box-fill));\n --color-focus: var(--box-on);\n --color-accent-text: var(--box-on);\n --canvas-image: none;\n\n background-color: var(--box-fill);\n color: var(--box-on);\n}\n.box[data-surface='inverse'] > * {\n --color-surface-inverse: var(--box-on);\n --color-ink-inverse: var(--box-fill);\n}\n\n.box[data-border] {\n border: var(--border-width) solid var(--color-line);\n}\n\n.box[data-radius='field'] {\n border-radius: var(--radius-field);\n}\n.box[data-radius='surface'] {\n border-radius: var(--radius-surface);\n}\n.box[data-radius='media'] {\n border-radius: var(--radius-media);\n}\n\n/* `hidden` wins over the display above (author CSS otherwise beats the UA [hidden] rule). */\n.box[hidden] {\n display: none;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"Box.module.js","names":["box","Box_module_default"],"sources":["../../../../src/components/layout/Box/Box.module.css"],"sourcesContent":["/*\n * Responsive pattern: see layout/Stack/Stack.module.css. Axis padding (--box-px/-py)\n * falls back to the all-sides value (--box-p) per breakpoint.\n *\n * --box-fill / --box-on (read-only): the fill and ink of an `inverse` Box.\n */\n.box {\n --_p: var(--box-p-base, 0px);\n --_px: var(--box-px-base, var(--_p));\n --_py: var(--box-py-base, var(--_p));\n\n display: block;\n min-inline-size: 0;\n padding-block: var(--_py);\n padding-inline: var(--_px);\n}\n\n@media (min-width: 40em) {\n .box {\n --_p: var(--box-p-sm, 0px);\n --_px: var(--box-px-sm, var(--_p));\n --_py: var(--box-py-sm, var(--_p));\n }\n}\n@media (min-width: 48em) {\n .box {\n --_p: var(--box-p-md, 0px);\n --_px: var(--box-px-md, var(--_p));\n --_py: var(--box-py-md, var(--_p));\n }\n}\n@media (min-width: 64em) {\n .box {\n --_p: var(--box-p-lg, 0px);\n --_px: var(--box-px-lg, var(--_p));\n --_py: var(--box-py-lg, var(--_p));\n }\n}\n@media (min-width: 80em) {\n .box {\n --_p: var(--box-p-xl, 0px);\n --_px: var(--box-px-xl, var(--_p));\n --_py: var(--box-py-xl, var(--_p));\n }\n}\n\n/* Surfaces */\n.box[data-surface='canvas'] {\n background-color: var(--color-canvas);\n background-image: var(--canvas-image);\n background-size: var(--canvas-image-size);\n color: var(--color-ink);\n}\n.box[data-surface='surface'] {\n background-color: var(--color-surface);\n color: var(--color-ink);\n}\n.box[data-surface='sunken'] {\n background-color: var(--color-surface-sunken);\n color: var(--color-ink);\n}\n.box[data-surface='raised'] {\n background-color: var(--color-surface-raised);\n color: var(--color-ink);\n}\n/* Inverse and categorical fills re-point the colour roles for descendants — same approach as Section. */\n.box[data-surface='inverse'] {\n --box-fill: var(--color-surface-inverse);\n --box-on: var(--color-ink-inverse);\n}\n.box[data-surface='cat-1'] {\n --box-fill: var(--color-cat-1);\n}\n.box[data-surface='cat-2'] {\n --box-fill: var(--color-cat-2);\n}\n.box[data-surface='cat-3'] {\n --box-fill: var(--color-cat-3);\n}\n.box[data-surface='cat-4'] {\n --box-fill: var(--color-cat-4);\n}\n.box[data-surface='cat-5'] {\n --box-fill: var(--color-cat-5);\n}\n.box[data-surface='cat-6'] {\n --box-fill: var(--color-cat-6);\n}\n.box[data-surface='cat-7'] {\n --box-fill: var(--color-cat-7);\n}\n.box[data-surface='cat-8'] {\n --box-fill: var(--color-cat-8);\n}\n.box[data-surface^='cat-'] {\n --box-on: var(--color-cat-ink);\n}\n.box:is([data-surface='inverse'], [data-surface^='cat-']) {\n --color-ink: var(--box-on);\n --color-ink-muted: color-mix(in oklab, var(--box-on) 76%, var(--box-fill));\n --color-ink-subtle: color-mix(in oklab, var(--box-on) 60%, var(--box-fill));\n --color-line: color-mix(in oklab, var(--box-on) 22%, var(--box-fill));\n --color-line-strong: color-mix(in oklab, var(--box-on) 45%, var(--box-fill));\n --color-canvas: var(--box-fill);\n --color-surface: color-mix(in oklab, var(--box-on) 7%, var(--box-fill));\n --color-surface-sunken: color-mix(in oklab, var(--box-on) 12%, var(--box-fill));\n --color-surface-raised: color-mix(in oklab, var(--box-on) 4%, var(--box-fill));\n --color-focus: var(--box-on);\n --color-accent-text: var(--box-on);\n --canvas-image: none;\n\n background-color: var(--box-fill);\n color: var(--box-on);\n}\n/* A categorical fill only clears AA against its own ink: no headroom for muted steps. */\n.box[data-surface^='cat-'] {\n --color-ink-muted: var(--box-on);\n --color-ink-subtle: var(--box-on);\n --color-surface: var(--box-fill);\n --color-surface-sunken: var(--box-fill);\n --color-surface-raised: var(--box-fill);\n}\n.box:is([data-surface='inverse'], [data-surface^='cat-']) > * {\n --color-surface-inverse: var(--box-on);\n --color-ink-inverse: var(--box-fill);\n}\n\n.box[data-border] {\n border: var(--border-width) solid var(--color-line);\n}\n\n.box[data-radius='field'] {\n border-radius: var(--radius-field);\n}\n.box[data-radius='surface'] {\n border-radius: var(--radius-surface);\n}\n.box[data-radius='media'] {\n border-radius: var(--radius-media);\n}\n\n/* `hidden` wins over the display above (author CSS otherwise beats the UA [hidden] rule). */\n.box[hidden] {\n display: none;\n}\n"],"mappings":""}
@@ -7,7 +7,10 @@ export interface DividerProps extends Omit<HTMLAttributes<HTMLDivElement>, 'chil
7
7
  orientation?: DividerOrientation;
8
8
  /** Heavier rule in `--color-line-strong` at `--border-width-strong`. */
9
9
  strong?: boolean;
10
- /** Text set into a horizontal rule, e.g. "Earlier this week". It also names the separator. */
10
+ /**
11
+ * Content set into a horizontal rule, e.g. "Earlier this week". It's real content, read like
12
+ * any text, and may be a block (a `Stack` of lines); the rules either side are decorative.
13
+ */
11
14
  label?: ReactNode;
12
15
  /** Where the label sits. Default `start` (left-aligned by default); `center` for a lone break. */
13
16
  labelPosition?: 'start' | 'center';
@@ -26,6 +29,9 @@ export interface DividerProps extends Omit<HTMLAttributes<HTMLDivElement>, 'chil
26
29
  * `Divider` separates groups. For a rule between every item of a list, use `Stack dividers`
27
30
  * instead, which spaces the rules for you.
28
31
  *
32
+ * A labelled divider is a band rather than a separator: its label is content that screen readers
33
+ * read in place, and the rules either side of it are decorative.
34
+ *
29
35
  * @privateRemarks
30
36
  * A hairline rule between groups of content. Prefer `Stack dividers` for rules
31
37
  * between every item of a list.