@mitcsutt/kiln-ui 0.3.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/actions/Button/Button.module.js.map +1 -1
- package/dist/components/actions/ToggleChip/ToggleChip.d.ts +5 -0
- package/dist/components/actions/ToggleChip/ToggleChip.js +10 -6
- package/dist/components/actions/ToggleChip/ToggleChip.js.map +1 -1
- package/dist/components/actions/ToggleChip/chip.module.js +4 -3
- package/dist/components/actions/ToggleChip/chip.module.js.map +1 -1
- package/dist/components/display/AvatarGroup/AvatarGroup.d.ts +2 -2
- package/dist/components/display/AvatarGroup/AvatarGroup.js +1 -1
- package/dist/components/display/AvatarGroup/AvatarGroup.js.map +1 -1
- package/dist/components/display/Card/Card.d.ts +7 -4
- package/dist/components/display/Card/Card.js +8 -7
- package/dist/components/display/Card/Card.js.map +1 -1
- package/dist/components/display/Card/Card.module.js.map +1 -1
- package/dist/components/display/List/List.d.ts +18 -5
- package/dist/components/display/List/List.js +53 -43
- 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/Marquee/Marquee.js +1 -1
- package/dist/components/display/Marquee/Marquee.js.map +1 -1
- package/dist/components/display/Media/Media.d.ts +15 -0
- package/dist/components/display/Media/Media.js +43 -23
- package/dist/components/display/Media/Media.js.map +1 -1
- package/dist/components/display/Media/Media.module.js.map +1 -1
- package/dist/components/display/Media/index.d.ts +1 -1
- package/dist/components/display/Stat/Stat.module.js.map +1 -1
- package/dist/components/display/Table/Table.d.ts +23 -1
- package/dist/components/display/Table/Table.js +19 -14
- 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/display/Tag/Tag.d.ts +3 -0
- package/dist/components/display/Tag/Tag.js +11 -10
- package/dist/components/display/Tag/Tag.js.map +1 -1
- package/dist/components/display/Tag/Tag.module.js.map +1 -1
- package/dist/components/display/Tag/index.d.ts +1 -1
- package/dist/components/feedback/Flash/Flash.d.ts +47 -0
- package/dist/components/feedback/Flash/Flash.js +36 -0
- package/dist/components/feedback/Flash/Flash.js.map +1 -0
- package/dist/components/feedback/Flash/Flash.module.js +10 -0
- package/dist/components/feedback/Flash/Flash.module.js.map +1 -0
- package/dist/components/feedback/Flash/index.d.ts +2 -0
- package/dist/components/feedback/RelativeTime/RelativeTime.d.ts +7 -0
- package/dist/components/feedback/RelativeTime/RelativeTime.js +11 -11
- package/dist/components/feedback/RelativeTime/RelativeTime.js.map +1 -1
- package/dist/components/feedback/StatusDot/StatusDot.d.ts +1 -1
- package/dist/components/feedback/StatusDot/StatusDot.js.map +1 -1
- package/dist/components/inputs/ChoiceCards/ChoiceCards.js +9 -9
- package/dist/components/inputs/Combobox/Combobox.js +5 -5
- package/dist/components/inputs/PasswordInput/PasswordInput.js +4 -4
- package/dist/components/layout/AppShell/AppShell.d.ts +4 -1
- package/dist/components/layout/AppShell/AppShell.js +58 -44
- package/dist/components/layout/AppShell/AppShell.js.map +1 -1
- package/dist/components/layout/AppShell/AppShell.module.js.map +1 -1
- package/dist/components/layout/Box/Box.d.ts +15 -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/Divider/Divider.d.ts +7 -1
- package/dist/components/layout/Divider/Divider.js +18 -20
- package/dist/components/layout/Divider/Divider.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 +18 -7
- 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/components/navigation/Accordion/Accordion.d.ts +6 -1
- package/dist/components/navigation/Accordion/Accordion.js +19 -11
- package/dist/components/navigation/Accordion/Accordion.js.map +1 -1
- package/dist/components/navigation/Accordion/Accordion.module.js +7 -6
- package/dist/components/navigation/Accordion/Accordion.module.js.map +1 -1
- package/dist/components/navigation/NavLinks/NavLinks.d.ts +4 -1
- package/dist/components/navigation/NavLinks/NavLinks.js.map +1 -1
- package/dist/components/navigation/NavLinks/NavLinks.module.js.map +1 -1
- package/dist/components/overlays/Tooltip/Tooltip.d.ts +23 -0
- package/dist/components/overlays/Tooltip/Tooltip.js +77 -31
- package/dist/components/overlays/Tooltip/Tooltip.js.map +1 -1
- package/dist/components/typography/Numeral/Numeral.d.ts +26 -2
- package/dist/components/typography/Numeral/Numeral.js +25 -21
- package/dist/components/typography/Numeral/Numeral.js.map +1 -1
- package/dist/components/typography/Numeral/Numeral.module.js +4 -3
- package/dist/components/typography/Numeral/Numeral.module.js.map +1 -1
- package/dist/components/typography/Text/Text.d.ts +5 -2
- package/dist/components/typography/Text/Text.js.map +1 -1
- package/dist/components/typography/Text/Text.module.js.map +1 -1
- package/dist/icons/Icon.js +1 -0
- package/dist/icons/Icon.js.map +1 -1
- package/dist/icons/icons.d.ts +12 -0
- package/dist/icons/icons.js +63 -13
- package/dist/icons/icons.js.map +1 -1
- package/dist/index.d.ts +19 -24
- package/dist/index.js +114 -112
- package/dist/styles.css +1 -1
- package/dist/themes/fiesta.css +1 -1
- package/dist/utils/tokens.d.ts +2 -0
- package/dist/utils/tokens.js.map +1 -1
- package/package.json +2 -2
- package/skills/custom-theme/SKILL.md +1 -1
- package/skills/design-rules/SKILL.md +8 -4
- package/skills/layout-composition/SKILL.md +2 -0
- package/skills/layout-composition/references/app-shell.md +2 -2
- package/skills/layout-composition/references/box.md +21 -1
- package/skills/layout-composition/references/divider.md +30 -1
- package/skills/layout-composition/references/scroll-area.md +68 -0
- package/skills/layout-composition/references/section.md +24 -2
- package/skills/setup-and-theming/SKILL.md +3 -3
- package/skills/setup-and-theming/references/fiesta.md +1 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactElement } from 'react';
|
|
2
|
+
export interface FlashProps extends HTMLAttributes<HTMLElement> {
|
|
3
|
+
/**
|
|
4
|
+
* Flashes each time this changes after the first render: a score, a count, an updated-at
|
|
5
|
+
* time. Compared with `Object.is`.
|
|
6
|
+
*/
|
|
7
|
+
value?: unknown;
|
|
8
|
+
/**
|
|
9
|
+
* Flash once when the element mounts, for something that's new because of a change: the row
|
|
10
|
+
* a new goal adds. It doesn't flash during the page's first render. Pass it only to elements
|
|
11
|
+
* that are new, not to every row of a list that loads.
|
|
12
|
+
*/
|
|
13
|
+
appear?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Flash when this turns `true`: the element is the place a link just opened on. For routers
|
|
16
|
+
* that change the URL without the browser updating `:target` (most client-side routers).
|
|
17
|
+
* Plain `#hash` links and `hashchange`/`popstate` navigation are caught without it.
|
|
18
|
+
*/
|
|
19
|
+
target?: boolean;
|
|
20
|
+
/** The one element to flash. It receives the class, data attribute and ref. */
|
|
21
|
+
children: ReactElement;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Draws brief attention to an element that just changed, or that a link just jumped to.
|
|
25
|
+
*
|
|
26
|
+
* @remarks
|
|
27
|
+
* `Flash` wraps any single element, a list row, a card, a figure, and gives it a short outline
|
|
28
|
+
* in the accent that fades away. It adds no element of its own. It flashes:
|
|
29
|
+
*
|
|
30
|
+
* - each time `value` changes after the first render;
|
|
31
|
+
* - once on mount with `appear`, for an element that's new because of a change;
|
|
32
|
+
* - when the element is the URL's `#target`, on a page load, a `#hash` link or back and forward;
|
|
33
|
+
* - when `target` turns `true`, for a client-side router, which changes the URL without
|
|
34
|
+
* updating `:target`: `target={location.hash === '#match-123'}`.
|
|
35
|
+
*
|
|
36
|
+
* With reduced motion the outline doesn't fade: it shows, holds, and goes. The colour and how
|
|
37
|
+
* long it stays are the `--flash-color` and `--flash-duration` tokens.
|
|
38
|
+
*
|
|
39
|
+
* @privateRemarks
|
|
40
|
+
* One primitive for "this just changed / you were sent here" instead of a flash prop on every
|
|
41
|
+
* component (DESIGN.md §2 Motion: motion that shows a state change). An outline, so it never
|
|
42
|
+
* shifts layout and works over any background. Two keyframe names alternate so each change
|
|
43
|
+
* restarts the animation.
|
|
44
|
+
*
|
|
45
|
+
* <Flash value={goals}><List.Item>…</List.Item></Flash>
|
|
46
|
+
*/
|
|
47
|
+
export declare const Flash: import("react").ForwardRefExoticComponent<FlashProps & import("react").RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { cx as e } from "../../../utils/cx.js";
|
|
2
|
+
import { useMergedRefs as t } from "../../inputs/internal/refs.js";
|
|
3
|
+
import n from "./Flash.module.js";
|
|
4
|
+
import { forwardRef as r, useEffect as i, useRef as a, useState as o, useSyncExternalStore as s } from "react";
|
|
5
|
+
import { jsx as c } from "react/jsx-runtime";
|
|
6
|
+
import { Slot as l } from "radix-ui";
|
|
7
|
+
//#region src/components/feedback/Flash/Flash.tsx
|
|
8
|
+
var u = !1, d = () => () => void 0, f = r(function({ value: r, appear: f = !1, target: p = !1, className: m, children: h, ...g }, _) {
|
|
9
|
+
let v = a(null), y = s(d, () => u, () => !1), [b, x] = o(f && y || p ? 1 : 0), [S, C] = o({
|
|
10
|
+
value: r,
|
|
11
|
+
target: p
|
|
12
|
+
});
|
|
13
|
+
return (!Object.is(S.value, r) || S.target !== p) && (C({
|
|
14
|
+
value: r,
|
|
15
|
+
target: p
|
|
16
|
+
}), (!Object.is(S.value, r) || p && !S.target) && x(b + 1)), i(() => {
|
|
17
|
+
u = !0;
|
|
18
|
+
let e = () => {
|
|
19
|
+
let e = v.current?.id;
|
|
20
|
+
e && window.location.hash === `#${e}` && x((e) => e + 1);
|
|
21
|
+
};
|
|
22
|
+
return window.addEventListener("hashchange", e), window.addEventListener("popstate", e), () => {
|
|
23
|
+
window.removeEventListener("hashchange", e), window.removeEventListener("popstate", e);
|
|
24
|
+
};
|
|
25
|
+
}, []), /* @__PURE__ */ c(l.Root, {
|
|
26
|
+
ref: t(_, v),
|
|
27
|
+
className: e(n.flash, m),
|
|
28
|
+
"data-flash": b === 0 ? void 0 : b % 2 ? "odd" : "even",
|
|
29
|
+
...g,
|
|
30
|
+
children: h
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
//#endregion
|
|
34
|
+
export { f as Flash };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=Flash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Flash.js","names":["styles","Flash_module_default","pageRendered","subscribe","Flash","forwardRef","rest","element","useRef","pageWasRendered","useSyncExternalStore","count","setCount","useState","appear","target","seen","setSeen","value","useEffect","check","id","n","Slot","useMergedRefs","ref","cx","className"],"sources":["../../../../src/components/feedback/Flash/Flash.tsx"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useRef,\n useState,\n useSyncExternalStore,\n type HTMLAttributes,\n type ReactElement,\n} from 'react'\nimport { Slot } from 'radix-ui'\nimport { cx } from '#utils/cx'\nimport { useMergedRefs } from '#components/inputs/internal/refs'\nimport styles from './Flash.module.css'\n\n/**\n * Whether any Flash has committed yet. Elements present at the first commit (the server render\n * and its hydration included) never flash on `appear`, so a page doesn't light up as it loads.\n */\nlet pageRendered = false\n\n/** Nothing to subscribe to: the snapshot only tells hydration (`false`) from a later mount. */\nconst subscribe = () => () => undefined\n\nexport interface FlashProps extends HTMLAttributes<HTMLElement> {\n /**\n * Flashes each time this changes after the first render: a score, a count, an updated-at\n * time. Compared with `Object.is`.\n */\n value?: unknown\n /**\n * Flash once when the element mounts, for something that's new because of a change: the row\n * a new goal adds. It doesn't flash during the page's first render. Pass it only to elements\n * that are new, not to every row of a list that loads.\n */\n appear?: boolean\n /**\n * Flash when this turns `true`: the element is the place a link just opened on. For routers\n * that change the URL without the browser updating `:target` (most client-side routers).\n * Plain `#hash` links and `hashchange`/`popstate` navigation are caught without it.\n */\n target?: boolean\n /** The one element to flash. It receives the class, data attribute and ref. */\n children: ReactElement\n}\n\n/**\n * Draws brief attention to an element that just changed, or that a link just jumped to.\n *\n * @remarks\n * `Flash` wraps any single element, a list row, a card, a figure, and gives it a short outline\n * in the accent that fades away. It adds no element of its own. It flashes:\n *\n * - each time `value` changes after the first render;\n * - once on mount with `appear`, for an element that's new because of a change;\n * - when the element is the URL's `#target`, on a page load, a `#hash` link or back and forward;\n * - when `target` turns `true`, for a client-side router, which changes the URL without\n * updating `:target`: `target={location.hash === '#match-123'}`.\n *\n * With reduced motion the outline doesn't fade: it shows, holds, and goes. The colour and how\n * long it stays are the `--flash-color` and `--flash-duration` tokens.\n *\n * @privateRemarks\n * One primitive for \"this just changed / you were sent here\" instead of a flash prop on every\n * component (DESIGN.md §2 Motion: motion that shows a state change). An outline, so it never\n * shifts layout and works over any background. Two keyframe names alternate so each change\n * restarts the animation.\n *\n * <Flash value={goals}><List.Item>…</List.Item></Flash>\n */\nexport const Flash = forwardRef<HTMLElement, FlashProps>(function Flash(\n { value, appear = false, target = false, className, children, ...rest },\n ref,\n) {\n const element = useRef<HTMLElement>(null)\n const pageWasRendered = useSyncExternalStore(\n subscribe,\n () => pageRendered,\n () => false,\n )\n const [count, setCount] = useState((appear && pageWasRendered) || target ? 1 : 0)\n const [seen, setSeen] = useState({ value, target })\n if (!Object.is(seen.value, value) || seen.target !== target) {\n setSeen({ value, target })\n if (!Object.is(seen.value, value) || (target && !seen.target)) setCount(count + 1)\n }\n\n useEffect(() => {\n pageRendered = true\n // `:target` covers page loads; these cover hash links and history moves after it.\n const check = () => {\n const id = element.current?.id\n if (id && window.location.hash === `#${id}`) setCount((n) => n + 1)\n }\n window.addEventListener('hashchange', check)\n window.addEventListener('popstate', check)\n return () => {\n window.removeEventListener('hashchange', check)\n window.removeEventListener('popstate', check)\n }\n }, [])\n\n return (\n <Slot.Root\n ref={useMergedRefs(ref, element)}\n className={cx(styles.flash, className)}\n data-flash={count === 0 ? undefined : count % 2 ? 'odd' : 'even'}\n {...rest}\n >\n {children}\n </Slot.Root>\n )\n})\n"],"mappings":";;;;;;;AAkBA,IAAIE,IAAe,IAGbC,gBAAwB,KAAA,GAgDjBC,IAAQC,EAAoC,SACvD,EAAE,UAAO,YAAS,IAAO,YAAS,IAAO,cAAW,aAAU,GAAGC,KACjE,GACA;CACA,IAAMC,IAAUC,EAAoB,IAAI,GAClCC,IAAkBC,EACtBP,SACMD,SACA,EACR,GACM,CAACS,GAAOC,KAAYC,EAAUC,KAAUL,KAAoBM,IAAS,IAAI,CAAC,GAC1E,CAACC,GAAMC,KAAWJ,EAAS;EAAE;EAAO;CAAO,CAAC;CAqBlD,QApBI,CAAC,OAAO,GAAGG,EAAK,OAAOE,CAAK,KAAKF,EAAK,WAAWD,OACnDE,EAAQ;EAAE;EAAO;CAAO,CAAC,IACrB,CAAC,OAAO,GAAGD,EAAK,OAAOE,CAAK,KAAMH,KAAU,CAACC,EAAK,WAASJ,EAASD,IAAQ,CAAC,IAGnFQ,QAAgB;EACd,IAAe;EAEf,IAAMC,UAAc;GAClB,IAAMC,IAAKd,EAAQ,SAAS;GAC5B,AAAIc,KAAM,OAAO,SAAS,SAAS,IAAIA,OAAMT,GAAU,MAAMU,IAAI,CAAC;EACpE;EAGA,OAFA,OAAO,iBAAiB,cAAcF,CAAK,GAC3C,OAAO,iBAAiB,YAAYA,CAAK,SAC5B;GAEX,AADA,OAAO,oBAAoB,cAAcA,CAAK,GAC9C,OAAO,oBAAoB,YAAYA,CAAK;EAC9C;CACF,GAAG,CAAC,CAAC,GAGH,kBAACG,EAAK,MAAN;EACE,KAAKC,EAAcC,GAAKlB,CAAO;EAC/B,WAAWmB,EAAG1B,EAAO,OAAO2B,CAAS;EACrC,cAAYhB,MAAU,IAAI,KAAA,IAAYA,IAAQ,IAAI,QAAQ;EAC1D,GAAIL;EAEH;CACQ,CAAA;AAEf,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/components/feedback/Flash/Flash.module.css
|
|
2
|
+
var e = "kiln-Flash__flash", t = {
|
|
3
|
+
flash: e,
|
|
4
|
+
"flash-odd": "kiln-Flash__flash-odd",
|
|
5
|
+
"flash-even": "kiln-Flash__flash-even"
|
|
6
|
+
};
|
|
7
|
+
//#endregion
|
|
8
|
+
export { t as default, e as flash };
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=Flash.module.js.map
|
|
@@ -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":""}
|
|
@@ -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,
|
|
7
|
-
let [
|
|
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 (
|
|
9
|
+
if (b(Date.now()), !d) return;
|
|
10
10
|
let e = setInterval(() => {
|
|
11
|
-
|
|
11
|
+
b(Date.now());
|
|
12
12
|
}, d);
|
|
13
13
|
return () => {
|
|
14
14
|
clearInterval(e);
|
|
15
15
|
};
|
|
16
16
|
}, [d]);
|
|
17
|
-
let
|
|
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:
|
|
20
|
-
dateTime:
|
|
21
|
-
title:
|
|
22
|
-
className:
|
|
19
|
+
ref: v,
|
|
20
|
+
dateTime: S ? x.toISOString() : void 0,
|
|
21
|
+
title: h ?? C,
|
|
22
|
+
className: g,
|
|
23
23
|
suppressHydrationWarning: !0,
|
|
24
|
-
...
|
|
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:
|
|
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
|
|
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", "
|
|
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\", \"
|
|
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 {
|
|
5
|
-
import {
|
|
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":
|
|
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,
|
|
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 =
|
|
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] =
|
|
64
|
-
ref:
|
|
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
|
-
}),
|
|
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
|
-
}),
|
|
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 {
|
|
4
|
-
import {
|
|
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 =
|
|
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(
|
|
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(
|
|
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 {
|
|
3
|
-
import {
|
|
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 =
|
|
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(
|
|
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
|
-
/**
|
|
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 {
|
|
3
|
-
import n from "
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
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
|
|
8
|
-
let m = `app-main-${
|
|
9
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
12
|
+
children: /* @__PURE__ */ d("div", {
|
|
12
13
|
ref: p,
|
|
13
|
-
className: e(
|
|
14
|
+
className: e(r.shell, o),
|
|
14
15
|
"data-nav-breakpoint": a,
|
|
15
|
-
...
|
|
16
|
-
children: [/* @__PURE__ */
|
|
16
|
+
...l,
|
|
17
|
+
children: [/* @__PURE__ */ u(n, {
|
|
17
18
|
as: "a",
|
|
18
19
|
href: `#${h}`,
|
|
19
20
|
focusable: !0,
|
|
20
|
-
className:
|
|
21
|
-
children:
|
|
22
|
-
}),
|
|
21
|
+
className: r.skip,
|
|
22
|
+
children: t
|
|
23
|
+
}), s]
|
|
23
24
|
})
|
|
24
25
|
});
|
|
25
|
-
}),
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
}),
|
|
33
|
-
let
|
|
34
|
-
return /* @__PURE__ */
|
|
46
|
+
}), h = a(function({ className: t, ...n }, i) {
|
|
47
|
+
let a = o(f);
|
|
48
|
+
return /* @__PURE__ */ u("main", {
|
|
35
49
|
ref: i,
|
|
36
|
-
id:
|
|
50
|
+
id: a?.mainId,
|
|
37
51
|
tabIndex: -1,
|
|
38
|
-
className: e(
|
|
39
|
-
...
|
|
52
|
+
className: e(r.main, t),
|
|
53
|
+
...n
|
|
40
54
|
});
|
|
41
|
-
}),
|
|
42
|
-
return /* @__PURE__ */
|
|
55
|
+
}), g = a(function({ side: t = "start", className: n, ...i }, a) {
|
|
56
|
+
return /* @__PURE__ */ u("aside", {
|
|
43
57
|
ref: a,
|
|
44
|
-
className: e(
|
|
58
|
+
className: e(r.sidebar, n),
|
|
45
59
|
"data-side": t,
|
|
46
60
|
...i
|
|
47
61
|
});
|
|
48
|
-
}),
|
|
49
|
-
return /* @__PURE__ */
|
|
62
|
+
}), _ = a(function({ className: t, ...n }, i) {
|
|
63
|
+
return /* @__PURE__ */ u("footer", {
|
|
50
64
|
ref: i,
|
|
51
|
-
className: e(
|
|
52
|
-
...
|
|
65
|
+
className: e(r.footer, t),
|
|
66
|
+
...n
|
|
53
67
|
});
|
|
54
|
-
}),
|
|
55
|
-
return /* @__PURE__ */
|
|
68
|
+
}), v = a(function({ className: t, ...n }, i) {
|
|
69
|
+
return /* @__PURE__ */ u("div", {
|
|
56
70
|
ref: i,
|
|
57
|
-
className: e(
|
|
58
|
-
...
|
|
71
|
+
className: e(r.bottomBar, t),
|
|
72
|
+
...n
|
|
59
73
|
});
|
|
60
|
-
}),
|
|
61
|
-
Header:
|
|
62
|
-
Main:
|
|
63
|
-
Sidebar:
|
|
64
|
-
Footer:
|
|
65
|
-
BottomBar:
|
|
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 {
|
|
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-
|
|
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' | '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. */
|
|
@@ -12,8 +12,20 @@ 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
|
-
/**
|
|
15
|
+
/**
|
|
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.
|
|
19
|
+
*/
|
|
16
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;
|
|
17
29
|
/** Hairline border in `--color-line`. One edge treatment per element — a border *or* a fill. */
|
|
18
30
|
border?: boolean;
|
|
19
31
|
/** Corner radius, by role. */
|