@jonmilner/ui 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_NOTICES.md +51 -0
- package/dist/AlertDialog/index.d.mts +21 -0
- package/dist/AlertDialog/index.mjs +29 -0
- package/dist/Badge/Badge.css +2 -0
- package/dist/Badge/Badge.css.mjs +24 -0
- package/dist/Badge/index.d.mts +11 -0
- package/dist/Badge/index.mjs +54 -0
- package/dist/Box/Box.css +2 -0
- package/dist/Box/Box.css.mjs +8 -0
- package/dist/Box/index.d.mts +8 -0
- package/dist/Box/index.mjs +15 -0
- package/dist/Button/Button.css +2 -0
- package/dist/Button/Button.css.mjs +25 -0
- package/dist/Button/index.d.mts +18 -0
- package/dist/Button/index.mjs +97 -0
- package/dist/Checkbox/Checkbox.css +2 -0
- package/dist/Checkbox/Checkbox.css.mjs +8 -0
- package/dist/Checkbox/index.d.mts +6 -0
- package/dist/Checkbox/index.mjs +45 -0
- package/dist/Chip/Chip.css +2 -0
- package/dist/Chip/Chip.css.mjs +17 -0
- package/dist/Chip/index.d.mts +13 -0
- package/dist/Chip/index.mjs +73 -0
- package/dist/Clickable/Clickable.css +2 -0
- package/dist/Clickable/Clickable.css.mjs +8 -0
- package/dist/Clickable/index.d.mts +11 -0
- package/dist/Clickable/index.mjs +28 -0
- package/dist/Dialog/Dialog.css +2 -0
- package/dist/Dialog/Dialog.css.d.mts +3 -0
- package/dist/Dialog/Dialog.css.mjs +12 -0
- package/dist/Dialog/client.d.mts +12 -0
- package/dist/Dialog/client.mjs +31 -0
- package/dist/Dialog/index.d.mts +30 -0
- package/dist/Dialog/index.mjs +85 -0
- package/dist/Field/Field.css +2 -0
- package/dist/Field/Field.css.mjs +8 -0
- package/dist/Field/client.mjs +26 -0
- package/dist/Field/index.d.mts +20 -0
- package/dist/Field/index.mjs +88 -0
- package/dist/Heading/Heading.css +2 -0
- package/dist/Heading/Heading.css.mjs +8 -0
- package/dist/Heading/index.d.mts +9 -0
- package/dist/Heading/index.mjs +27 -0
- package/dist/Icon/Icon.css +2 -0
- package/dist/Icon/Icon.css.mjs +17 -0
- package/dist/Icon/index.d.mts +12 -0
- package/dist/Icon/index.mjs +24 -0
- package/dist/IconButton/IconButton.css +2 -0
- package/dist/IconButton/IconButton.css.mjs +24 -0
- package/dist/IconButton/index.d.mts +15 -0
- package/dist/IconButton/index.mjs +25 -0
- package/dist/Inline/Inline.css +2 -0
- package/dist/Inline/Inline.css.mjs +8 -0
- package/dist/Inline/index.d.mts +14 -0
- package/dist/Inline/index.mjs +17 -0
- package/dist/Menu/Menu.css +2 -0
- package/dist/Menu/Menu.css.mjs +8 -0
- package/dist/Menu/client.d.mts +9 -0
- package/dist/Menu/client.mjs +27 -0
- package/dist/Menu/index.d.mts +34 -0
- package/dist/Menu/index.mjs +107 -0
- package/dist/MultiSelect/MultiSelect.css +2 -0
- package/dist/MultiSelect/MultiSelect.css.mjs +8 -0
- package/dist/MultiSelect/client.d.mts +8 -0
- package/dist/MultiSelect/client.mjs +93 -0
- package/dist/MultiSelect/index.d.mts +23 -0
- package/dist/MultiSelect/index.mjs +75 -0
- package/dist/SearchField/SearchField.css +2 -0
- package/dist/SearchField/SearchField.css.mjs +27 -0
- package/dist/SearchField/client.d.mts +5 -0
- package/dist/SearchField/client.mjs +74 -0
- package/dist/SearchField/index.d.mts +25 -0
- package/dist/SearchField/index.mjs +36 -0
- package/dist/Stack/Stack.css +2 -0
- package/dist/Stack/Stack.css.mjs +8 -0
- package/dist/Stack/index.d.mts +14 -0
- package/dist/Stack/index.mjs +15 -0
- package/dist/Tabs/Tabs.css +2 -0
- package/dist/Tabs/Tabs.css.mjs +8 -0
- package/dist/Tabs/index.d.mts +20 -0
- package/dist/Tabs/index.mjs +88 -0
- package/dist/Tag/Tag.css +2 -0
- package/dist/Tag/Tag.css.mjs +17 -0
- package/dist/Tag/index.d.mts +13 -0
- package/dist/Tag/index.mjs +82 -0
- package/dist/Text/Text.css +2 -0
- package/dist/Text/Text.css.mjs +32 -0
- package/dist/Text/index.d.mts +16 -0
- package/dist/Text/index.mjs +25 -0
- package/dist/Toast/Toast.css +2 -0
- package/dist/Toast/Toast.css.mjs +18 -0
- package/dist/Toast/client.d.mts +46 -0
- package/dist/Toast/client.mjs +219 -0
- package/dist/Toast/index.d.mts +7 -0
- package/dist/Toast/index.mjs +5 -0
- package/dist/base.css +6 -0
- package/dist/brands/brand.d.mts +9 -0
- package/dist/brands/brand.mjs +4 -0
- package/dist/brands/check-fonts.mjs +15 -0
- package/dist/brands/default.d.mts +4 -0
- package/dist/brands/default.mjs +74 -0
- package/dist/brands/font.d.mts +17 -0
- package/dist/brands/font.mjs +35 -0
- package/dist/brands/forced-colors.mjs +18 -0
- package/dist/brands/index.d.mts +8 -0
- package/dist/brands/index.mjs +5 -0
- package/dist/brands/metrics.mjs +40 -0
- package/dist/contrast/color.d.mts +3 -0
- package/dist/contrast/color.mjs +222 -0
- package/dist/contrast/contrast.d.mts +18 -0
- package/dist/contrast/contrast.mjs +52 -0
- package/dist/contrast/mixes.mjs +33 -0
- package/dist/docs/AlertDialog.md +113 -0
- package/dist/docs/Badge.md +76 -0
- package/dist/docs/Box.md +87 -0
- package/dist/docs/Button.md +98 -0
- package/dist/docs/Checkbox.md +107 -0
- package/dist/docs/Chip.md +92 -0
- package/dist/docs/Clickable.md +82 -0
- package/dist/docs/Dialog.md +166 -0
- package/dist/docs/Field.md +143 -0
- package/dist/docs/Heading.md +69 -0
- package/dist/docs/Icon.md +116 -0
- package/dist/docs/IconButton.md +83 -0
- package/dist/docs/Inline.md +79 -0
- package/dist/docs/Menu.md +181 -0
- package/dist/docs/MultiSelect.md +120 -0
- package/dist/docs/SearchField.md +127 -0
- package/dist/docs/Stack.md +79 -0
- package/dist/docs/Tabs.md +130 -0
- package/dist/docs/Tag.md +97 -0
- package/dist/docs/Text.md +90 -0
- package/dist/docs/Toast.md +115 -0
- package/dist/docs/llms.txt +33 -0
- package/dist/docs/manifest.json +2649 -0
- package/dist/docs/manifest.schema.json +96 -0
- package/dist/docs/migrations/README.md +27 -0
- package/dist/docs/theming.md +59 -0
- package/dist/icons/ArrowLeftIcon.d.mts +4 -0
- package/dist/icons/ArrowLeftIcon.mjs +11 -0
- package/dist/icons/ArrowRightIcon.d.mts +4 -0
- package/dist/icons/ArrowRightIcon.mjs +11 -0
- package/dist/icons/CheckIcon.d.mts +4 -0
- package/dist/icons/CheckIcon.mjs +11 -0
- package/dist/icons/ChevronDownIcon.d.mts +4 -0
- package/dist/icons/ChevronDownIcon.mjs +11 -0
- package/dist/icons/ChevronRightIcon.d.mts +4 -0
- package/dist/icons/ChevronRightIcon.mjs +11 -0
- package/dist/icons/CircleAlertIcon.d.mts +4 -0
- package/dist/icons/CircleAlertIcon.mjs +15 -0
- package/dist/icons/CircleCheckIcon.d.mts +4 -0
- package/dist/icons/CircleCheckIcon.mjs +15 -0
- package/dist/icons/CircleDotIcon.d.mts +4 -0
- package/dist/icons/CircleDotIcon.mjs +19 -0
- package/dist/icons/CircleSlashIcon.d.mts +4 -0
- package/dist/icons/CircleSlashIcon.mjs +15 -0
- package/dist/icons/GitMergeIcon.d.mts +4 -0
- package/dist/icons/GitMergeIcon.mjs +23 -0
- package/dist/icons/GitPullRequestClosedIcon.d.mts +4 -0
- package/dist/icons/GitPullRequestClosedIcon.mjs +23 -0
- package/dist/icons/GitPullRequestDraftIcon.d.mts +4 -0
- package/dist/icons/GitPullRequestDraftIcon.mjs +23 -0
- package/dist/icons/GitPullRequestIcon.d.mts +4 -0
- package/dist/icons/GitPullRequestIcon.mjs +23 -0
- package/dist/icons/InboxIcon.d.mts +4 -0
- package/dist/icons/InboxIcon.mjs +11 -0
- package/dist/icons/InfoIcon.d.mts +4 -0
- package/dist/icons/InfoIcon.mjs +15 -0
- package/dist/icons/LoaderCircleIcon.d.mts +4 -0
- package/dist/icons/LoaderCircleIcon.mjs +11 -0
- package/dist/icons/RefreshCwIcon.d.mts +4 -0
- package/dist/icons/RefreshCwIcon.mjs +15 -0
- package/dist/icons/SearchIcon.d.mts +4 -0
- package/dist/icons/SearchIcon.mjs +15 -0
- package/dist/icons/SettingsIcon.d.mts +4 -0
- package/dist/icons/SettingsIcon.mjs +15 -0
- package/dist/icons/XIcon.d.mts +4 -0
- package/dist/icons/XIcon.mjs +11 -0
- package/dist/icons/index.d.mts +25 -0
- package/dist/icons/index.mjs +45 -0
- package/dist/index.d.mts +28 -0
- package/dist/index.mjs +25 -0
- package/dist/popup/client.d.mts +9 -0
- package/dist/popup/client.mjs +31 -0
- package/dist/styles/atoms.css +2 -0
- package/dist/styles/atoms.css.d.mts +219 -0
- package/dist/styles/atoms.css.mjs +2669 -0
- package/dist/styles/button-fills.mjs +17 -0
- package/dist/styles/highlight.mjs +8 -0
- package/dist/styles/hover-tint.mjs +4 -0
- package/dist/styles/join.mjs +4 -0
- package/dist/styles/layers.css +2 -0
- package/dist/styles/part-props.d.mts +8 -0
- package/dist/styles/split-style-props.mjs +9 -0
- package/dist/testing/index.d.mts +4 -0
- package/dist/testing/index.mjs +3 -0
- package/dist/testing/motion.d.mts +22 -0
- package/dist/testing/motion.mjs +49 -0
- package/dist/theme/FontCheck.mjs +11 -0
- package/dist/theme/ThemeProvider.d.mts +15 -0
- package/dist/theme/ThemeProvider.mjs +23 -0
- package/dist/theme/define-theme.d.mts +9 -0
- package/dist/theme/define-theme.mjs +84 -0
- package/dist/theme/use-theme-container.mjs +15 -0
- package/dist/tokens/contract.d.mts +110 -0
- package/dist/tokens/contract.mjs +17 -0
- package/dist/tokens/index.d.mts +2 -0
- package/dist/tokens/index.mjs +1 -0
- package/dist/tokens/roles.d.mts +6 -0
- package/dist/tokens/roles.mjs +24 -0
- package/dist/tokens/scales.d.mts +100 -0
- package/dist/tokens/scales.mjs +103 -0
- package/dist/types.d.mts +7 -0
- package/package.json +159 -3
- package/README.md +0 -3
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/styles/button-fills.ts
|
|
2
|
+
var e = {
|
|
3
|
+
primary: {
|
|
4
|
+
backgroundColor: "accent",
|
|
5
|
+
color: "accentFg"
|
|
6
|
+
},
|
|
7
|
+
secondary: {
|
|
8
|
+
backgroundColor: "bg",
|
|
9
|
+
color: "fg"
|
|
10
|
+
},
|
|
11
|
+
danger: {
|
|
12
|
+
backgroundColor: "danger",
|
|
13
|
+
color: "dangerFg"
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
export { e as fills };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
@layer tokens, reset, atoms, components.box, components.checkbox, components.clickable, components.icon, components.icon-button, components.inline, components.stack, components.text, components.badge, components.button, components.chip, components.field, components.heading, components.dialog, components.alert-dialog, components.menu, components.multiselect, components.search-field, components.tabs, components.tag, components.toast;
|
|
2
|
+
@layer tokens,reset,atoms,components;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { StyleProps } from "../Box/index.mjs";
|
|
2
|
+
import { CSSProperties } from "react";
|
|
3
|
+
//#region src/styles/part-props.d.ts
|
|
4
|
+
export type PartProps<P> = StyleProps & Omit<P, "render" | "className" | "style" | keyof StyleProps> & {
|
|
5
|
+
className?: string;
|
|
6
|
+
style?: CSSProperties;
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { sprinkles as e } from "./atoms.css.mjs";
|
|
2
|
+
//#region src/styles/split-style-props.ts
|
|
3
|
+
function t(t) {
|
|
4
|
+
let n = {}, r = {};
|
|
5
|
+
for (let [i, a] of Object.entries(t)) (e.properties.has(i) ? n : r)[i] = a;
|
|
6
|
+
return [n, r];
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { t as splitStyleProps };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Mode } from "../contrast/color.mjs";
|
|
2
|
+
import { ContrastFailure, ContrastPair, checkContrast, contrastPairs, contrastRatio } from "../contrast/contrast.mjs";
|
|
3
|
+
import { MediaEmulator, MotionLocator, MotionStyle, MotionTarget, emulateReducedMotion, expectCrossfadeOnly, expectNoMotion, readMotionStyle } from "./motion.mjs";
|
|
4
|
+
export { type ContrastFailure, type ContrastPair, type MediaEmulator, type Mode, type MotionLocator, type MotionStyle, type MotionTarget, checkContrast, contrastPairs, contrastRatio, emulateReducedMotion, expectCrossfadeOnly, expectNoMotion, readMotionStyle };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { checkContrast as e, contrastPairs as t, contrastRatio as n } from "../contrast/contrast.mjs";
|
|
2
|
+
import { emulateReducedMotion as r, expectCrossfadeOnly as i, expectNoMotion as a, readMotionStyle as o } from "./motion.mjs";
|
|
3
|
+
export { e as checkContrast, t as contrastPairs, n as contrastRatio, r as emulateReducedMotion, i as expectCrossfadeOnly, a as expectNoMotion, o as readMotionStyle };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/testing/motion.d.ts
|
|
2
|
+
export interface MediaEmulator {
|
|
3
|
+
emulateMedia(options: {
|
|
4
|
+
reducedMotion: "reduce" | "no-preference" | null;
|
|
5
|
+
}): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export interface MotionLocator {
|
|
8
|
+
evaluate<R>(fn: (el: Element) => R): Promise<R>;
|
|
9
|
+
}
|
|
10
|
+
export type MotionTarget = Element | MotionLocator;
|
|
11
|
+
export interface MotionStyle {
|
|
12
|
+
displaced: string[];
|
|
13
|
+
transitions: {
|
|
14
|
+
ms: number;
|
|
15
|
+
property: string;
|
|
16
|
+
}[];
|
|
17
|
+
}
|
|
18
|
+
export declare function emulateReducedMotion(page: MediaEmulator): Promise<() => Promise<void>>;
|
|
19
|
+
export declare const readMotionStyle: (el: Element) => MotionStyle;
|
|
20
|
+
export declare function expectNoMotion(target: MotionTarget): Promise<void>;
|
|
21
|
+
export declare function expectCrossfadeOnly(target: MotionTarget): Promise<void>;
|
|
22
|
+
//#endregion
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//#region src/testing/motion.ts
|
|
2
|
+
async function e(e) {
|
|
3
|
+
return await e.emulateMedia({ reducedMotion: "reduce" }), () => e.emulateMedia({ reducedMotion: null });
|
|
4
|
+
}
|
|
5
|
+
var t = (e) => {
|
|
6
|
+
let t = getComputedStyle(e), n = (e) => (e.match(/-?[\d.]+(?:e[-+]?\d+)?/g) ?? []).map(Number), r = (e, t) => Math.abs(e - t) < 1e-6, i = Object.entries({
|
|
7
|
+
translate: (e) => n(e.replace(/-?[\d.]+%/g, "")).every((e) => r(e, 0)),
|
|
8
|
+
scale: (e) => n(e).every((e) => r(e, 1)),
|
|
9
|
+
rotate: (e) => r(n(e).at(-1) ?? 0, 0),
|
|
10
|
+
transform: (e) => {
|
|
11
|
+
let t = n(e.replace(/^matrix(3d)?/, "")), i = t.length === 16 ? [
|
|
12
|
+
0,
|
|
13
|
+
5,
|
|
14
|
+
10,
|
|
15
|
+
15
|
|
16
|
+
] : [0, 3];
|
|
17
|
+
return t.every((e, t) => r(e, +!!i.includes(t)));
|
|
18
|
+
}
|
|
19
|
+
}).map(([e, n]) => [
|
|
20
|
+
e,
|
|
21
|
+
t.getPropertyValue(e),
|
|
22
|
+
n
|
|
23
|
+
]).filter(([, e, t]) => e !== "none" && !t(e)).map(([e, t]) => `${e}: ${t}`), a = (e) => parseFloat(e) * (e.endsWith("ms") ? 1 : 1e3), o = t.transitionProperty.split(",").map((e) => e.trim()), s = t.transitionDuration.split(",").map((e) => a(e.trim()));
|
|
24
|
+
return {
|
|
25
|
+
displaced: i,
|
|
26
|
+
transitions: o.map((e, t) => ({
|
|
27
|
+
property: e,
|
|
28
|
+
ms: s[t % s.length] ?? 0
|
|
29
|
+
}))
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
function n(e) {
|
|
33
|
+
return "evaluate" in e ? e.evaluate(t) : Promise.resolve(t(e));
|
|
34
|
+
}
|
|
35
|
+
function r({ displaced: e }) {
|
|
36
|
+
if (e.length > 0) throw Error(`Expected no motion, got ${e.join("; ")}`);
|
|
37
|
+
}
|
|
38
|
+
async function i(e) {
|
|
39
|
+
r(await n(e));
|
|
40
|
+
}
|
|
41
|
+
async function a(e) {
|
|
42
|
+
let t = await n(e);
|
|
43
|
+
if (r(t), !t.transitions.some(({ property: e, ms: t }) => (e === "opacity" || e === "all") && t > 0)) {
|
|
44
|
+
let e = t.transitions.map(({ property: e, ms: t }) => `${e} ${t}ms`).join(", ");
|
|
45
|
+
throw Error(`Expected an opacity transition over 0ms, got ${e}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { e as emulateReducedMotion, a as expectCrossfadeOnly, i as expectNoMotion, t as readMotionStyle };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { checkFonts as e } from "../brands/check-fonts.mjs";
|
|
3
|
+
import { useEffect as t } from "react";
|
|
4
|
+
//#region src/theme/FontCheck.tsx
|
|
5
|
+
function n({ font: n }) {
|
|
6
|
+
return t(() => {
|
|
7
|
+
e({ font: n });
|
|
8
|
+
}, [n]), null;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { n as FontCheck };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { presets } from "../brands/index.mjs";
|
|
2
|
+
import { Theme } from "./define-theme.mjs";
|
|
3
|
+
import { ComponentPropsWithRef } from "react";
|
|
4
|
+
//#region src/theme/ThemeProvider.d.ts
|
|
5
|
+
export type ThemeProviderProps = ComponentPropsWithRef<"div"> & {
|
|
6
|
+
mode?: "light" | "dark" | "system";
|
|
7
|
+
} & ({
|
|
8
|
+
brand?: keyof typeof presets;
|
|
9
|
+
theme?: undefined;
|
|
10
|
+
} | {
|
|
11
|
+
brand?: undefined;
|
|
12
|
+
theme: Theme;
|
|
13
|
+
});
|
|
14
|
+
export declare function ThemeProvider({ brand, mode, theme, children, ...props }: ThemeProviderProps): import("react").JSX.Element;
|
|
15
|
+
//#endregion
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { presets as e } from "../brands/index.mjs";
|
|
2
|
+
import { FontCheck as t } from "./FontCheck.mjs";
|
|
3
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
|
+
//#region src/theme/ThemeProvider.tsx
|
|
5
|
+
function i({ brand: i = "default", mode: a = "system", theme: o, children: s, ...c }) {
|
|
6
|
+
let l = o?.brand.name ?? i, u = o?.brand ?? e[i];
|
|
7
|
+
return /* @__PURE__ */ r("div", {
|
|
8
|
+
...c,
|
|
9
|
+
"data-brand": l,
|
|
10
|
+
"data-mode": a,
|
|
11
|
+
children: [
|
|
12
|
+
o && /* @__PURE__ */ n("style", {
|
|
13
|
+
href: o.href,
|
|
14
|
+
precedence: "ui-theme",
|
|
15
|
+
children: o.css
|
|
16
|
+
}),
|
|
17
|
+
process.env.NODE_ENV !== "production" && u && /* @__PURE__ */ n(t, { font: u.font }),
|
|
18
|
+
s
|
|
19
|
+
]
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { i as ThemeProvider };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Brand } from "../brands/brand.mjs";
|
|
2
|
+
//#region src/theme/define-theme.d.ts
|
|
3
|
+
export interface Theme {
|
|
4
|
+
readonly brand: Brand;
|
|
5
|
+
readonly href: string;
|
|
6
|
+
readonly css: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function defineTheme(brand: Brand): Theme;
|
|
9
|
+
//#endregion
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { fallbackFaces as e, fallbackFamily as t, fontStack as n, fontTrim as r } from "../brands/font.mjs";
|
|
2
|
+
import { forcedColors as i } from "../brands/forced-colors.mjs";
|
|
3
|
+
import { presets as a } from "../brands/index.mjs";
|
|
4
|
+
import { resolveColor as o } from "../contrast/color.mjs";
|
|
5
|
+
import { checkContrast as s, contrastPairs as c } from "../contrast/contrast.mjs";
|
|
6
|
+
import { checkMixes as l, contrastMixes as u } from "../contrast/mixes.mjs";
|
|
7
|
+
import { colorRoles as d, fontRoles as f } from "../tokens/roles.mjs";
|
|
8
|
+
import { vars as p } from "../tokens/contract.mjs";
|
|
9
|
+
//#region src/theme/define-theme.ts
|
|
10
|
+
var m = (e) => e.slice(4, -1), h = (e) => e.replace(/[A-Z]/g, (e) => `-${e.toLowerCase()}`), g = (e, t) => `${e} {\n${t.map(([e, t]) => ` ${e}: ${t};\n`).join("")}}`;
|
|
11
|
+
function _(o) {
|
|
12
|
+
let s = (e) => {
|
|
13
|
+
throw Error(`defineTheme("${o.name}"): ${e}`);
|
|
14
|
+
};
|
|
15
|
+
/^[a-z][\w-]*$/i.test(o.name) || s("the name must be a CSS identifier");
|
|
16
|
+
for (let [e, t] of Object.entries(o.color)) v.test(t) && s(`color.${e} must be a single color value`);
|
|
17
|
+
for (let [e, { metrics: t, fallback: n }] of Object.entries(o.font)) for (let r of [t, n].flatMap((e) => [
|
|
18
|
+
e.familyName,
|
|
19
|
+
e.fullName,
|
|
20
|
+
e.postscriptName
|
|
21
|
+
])) r !== void 0 && (v.test(r) || /["'\n]/.test(r)) && s(`font.${e} has a font name with quotes or CSS syntax: ${r}`);
|
|
22
|
+
process.env.NODE_ENV !== "production" && C(o, s);
|
|
23
|
+
let c = `[data-brand="${o.name}"]`, l = Object.values(o.font), u = Object.values(a).flatMap((e) => Object.values(e.font)), _;
|
|
24
|
+
try {
|
|
25
|
+
_ = e([...u, ...l]);
|
|
26
|
+
} catch (e) {
|
|
27
|
+
return s(e.message);
|
|
28
|
+
}
|
|
29
|
+
let b = new Set(l.map(t));
|
|
30
|
+
for (let e of u) b.delete(t(e));
|
|
31
|
+
let x = [
|
|
32
|
+
...[..._].filter(([e]) => b.has(e)).map(([e, t]) => g("@font-face", [["font-family", `"${e}"`], ...Object.entries(t).map(([e, t]) => [h(e), t])])),
|
|
33
|
+
g(c, [...d.map((e) => [m(p.color[e]), o.color[e]]), ...f.flatMap((e) => {
|
|
34
|
+
let t = r(o.font[e].metrics);
|
|
35
|
+
return [
|
|
36
|
+
[m(p.font[e]), n(o.font[e])],
|
|
37
|
+
[m(p.fontTrim[e].cap), t.cap],
|
|
38
|
+
[m(p.fontTrim[e].baseline), t.baseline]
|
|
39
|
+
];
|
|
40
|
+
})]),
|
|
41
|
+
`@media (forced-colors: active) {\n${g(c, d.map((e) => [m(p.color[e]), i[e]])).split("\n").map((e) => ` ${e}`).join("\n")}\n}`
|
|
42
|
+
].join("\n");
|
|
43
|
+
return {
|
|
44
|
+
brand: o,
|
|
45
|
+
href: `ui-theme-${o.name}-${y(x)}`,
|
|
46
|
+
css: x
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
var v = /[;{}<>\\!]|\/\*/;
|
|
50
|
+
function y(e) {
|
|
51
|
+
let t = 2166136261;
|
|
52
|
+
for (let n = 0; n < e.length; n++) t = Math.imul(t ^ e.charCodeAt(n), 16777619);
|
|
53
|
+
return (t >>> 0).toString(36);
|
|
54
|
+
}
|
|
55
|
+
var b = /var\(\s*--color-([a-z-]+)\s*\)/g, x = new Map(d.map((e) => [h(e), e])), S = new Set(c.map((e) => e.bg));
|
|
56
|
+
function C(e, t) {
|
|
57
|
+
let n = (r, i = []) => (i.includes(r) && t(`color.${r} references itself through var()`), e.color[r].replace(b, (e, t) => {
|
|
58
|
+
let a = x.get(t);
|
|
59
|
+
return a ? n(a, [...i, r]) : e;
|
|
60
|
+
})), r = Object.fromEntries(d.map((e) => [e, n(e)]));
|
|
61
|
+
for (let n of d) {
|
|
62
|
+
r[n].includes("var(") && t(`color.${n} is ${e.color[n]}: the contrast check needs literal colors, so use var() only to reference another color role`);
|
|
63
|
+
for (let i of ["light", "dark"]) {
|
|
64
|
+
let a;
|
|
65
|
+
try {
|
|
66
|
+
({alpha: a} = o(r[n], i));
|
|
67
|
+
} catch (r) {
|
|
68
|
+
return t(`color.${n} is ${e.color[n]}, which the contrast check cannot resolve (${r.message}). Use hex, rgb(), oklab(), oklch(), color-mix() or light-dark(); named colors other than white, black and transparent are not supported`);
|
|
69
|
+
}
|
|
70
|
+
a < 1 && S.has(n) && t(`color.${n} is translucent in ${i} mode, but it is a background in a contrast pair and must be opaque`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
for (let { name: e, fill: n } of u) for (let i of ["light", "dark"]) o(n(r), i).alpha < 1 && t(`the ${e} is translucent in ${i} mode: the roles it mixes must be opaque`);
|
|
74
|
+
let i = {
|
|
75
|
+
...e,
|
|
76
|
+
color: r
|
|
77
|
+
}, a = s(i), c = [...a, ...l(i).filter((e) => !a.some((t) => t.fg === e.fg && t.mode === e.mode && t.ratio === e.ratio)).map(({ mix: e, ...t }) => ({
|
|
78
|
+
...t,
|
|
79
|
+
bg: `the ${e}`
|
|
80
|
+
}))].toSorted((e, t) => e.mode === t.mode ? 0 : e.mode === "light" ? -1 : 1);
|
|
81
|
+
c.length > 0 && t(`fails WCAG AA contrast:\n${c.map(({ fg: e, bg: t, mode: n, ratio: r, min: i }) => ` ${e} on ${t} (${n}): ${r.toFixed(2)}, needs ${i}`).join("\n")}`);
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
export { _ as defineTheme };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useCallback as e, useMemo as t, useRef as n } from "react";
|
|
2
|
+
//#region src/theme/use-theme-container.ts
|
|
3
|
+
function r() {
|
|
4
|
+
let r = n(null), i = e((e) => {
|
|
5
|
+
r.current = e;
|
|
6
|
+
}, []);
|
|
7
|
+
return t(() => ({
|
|
8
|
+
container: { get current() {
|
|
9
|
+
return r.current?.closest("[data-brand]") ?? null;
|
|
10
|
+
} },
|
|
11
|
+
ref: i
|
|
12
|
+
}), [i]);
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { r as useThemeContainer };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
//#region src/tokens/contract.d.ts
|
|
2
|
+
type CssVar = `var(--${string})`;
|
|
3
|
+
export type Contract<T> = { readonly [K in keyof T]: T[K] extends string ? CssVar : Contract<T[K]>; };
|
|
4
|
+
export declare const contract: {
|
|
5
|
+
space: {
|
|
6
|
+
0: string;
|
|
7
|
+
1: string;
|
|
8
|
+
12: string;
|
|
9
|
+
16: string;
|
|
10
|
+
2: string;
|
|
11
|
+
20: string;
|
|
12
|
+
24: string;
|
|
13
|
+
32: string;
|
|
14
|
+
4: string;
|
|
15
|
+
40: string;
|
|
16
|
+
48: string;
|
|
17
|
+
6: string;
|
|
18
|
+
64: string;
|
|
19
|
+
8: string;
|
|
20
|
+
80: string;
|
|
21
|
+
96: string;
|
|
22
|
+
};
|
|
23
|
+
size: {
|
|
24
|
+
xs: string;
|
|
25
|
+
sm: string;
|
|
26
|
+
med: string;
|
|
27
|
+
lg: string;
|
|
28
|
+
xl: string;
|
|
29
|
+
};
|
|
30
|
+
container: {
|
|
31
|
+
prose: string;
|
|
32
|
+
page: string;
|
|
33
|
+
wide: string;
|
|
34
|
+
};
|
|
35
|
+
radius: {
|
|
36
|
+
none: string;
|
|
37
|
+
sm: string;
|
|
38
|
+
med: string;
|
|
39
|
+
lg: string;
|
|
40
|
+
xl: string;
|
|
41
|
+
full: string;
|
|
42
|
+
};
|
|
43
|
+
fontSize: {
|
|
44
|
+
xs: string;
|
|
45
|
+
sm: string;
|
|
46
|
+
med: string;
|
|
47
|
+
lg: string;
|
|
48
|
+
xl: string;
|
|
49
|
+
"2xl": string;
|
|
50
|
+
"3xl": string;
|
|
51
|
+
"4xl": string;
|
|
52
|
+
};
|
|
53
|
+
fontWeight: {
|
|
54
|
+
regular: string;
|
|
55
|
+
medium: string;
|
|
56
|
+
semibold: string;
|
|
57
|
+
bold: string;
|
|
58
|
+
};
|
|
59
|
+
lineHeight: {
|
|
60
|
+
sm: string;
|
|
61
|
+
med: string;
|
|
62
|
+
lg: string;
|
|
63
|
+
};
|
|
64
|
+
zIndex: {
|
|
65
|
+
base: string;
|
|
66
|
+
raised: string;
|
|
67
|
+
dropdown: string;
|
|
68
|
+
sticky: string;
|
|
69
|
+
overlay: string;
|
|
70
|
+
modal: string;
|
|
71
|
+
popover: string;
|
|
72
|
+
toast: string;
|
|
73
|
+
tooltip: string;
|
|
74
|
+
};
|
|
75
|
+
duration: {
|
|
76
|
+
fast: string;
|
|
77
|
+
med: string;
|
|
78
|
+
slow: string;
|
|
79
|
+
};
|
|
80
|
+
easing: {
|
|
81
|
+
standard: string;
|
|
82
|
+
enter: string;
|
|
83
|
+
exit: string;
|
|
84
|
+
};
|
|
85
|
+
distance: {
|
|
86
|
+
sm: string;
|
|
87
|
+
med: string;
|
|
88
|
+
lg: string;
|
|
89
|
+
};
|
|
90
|
+
scale: {
|
|
91
|
+
sm: string;
|
|
92
|
+
med: string;
|
|
93
|
+
lg: string;
|
|
94
|
+
};
|
|
95
|
+
dir: string;
|
|
96
|
+
shadow: {
|
|
97
|
+
sm: string;
|
|
98
|
+
med: string;
|
|
99
|
+
lg: string;
|
|
100
|
+
};
|
|
101
|
+
color: Record<"accent" | "accentFg" | "bg" | "bgMuted" | "bgRaised" | "border" | "borderStrong" | "danger" | "dangerFg" | "fg" | "fgMuted" | "focus" | "shadow", string>;
|
|
102
|
+
font: Record<"body" | "display" | "heading" | "label" | "mono", string>;
|
|
103
|
+
fontTrim: Record<"body" | "display" | "heading" | "label" | "mono", {
|
|
104
|
+
cap: string;
|
|
105
|
+
baseline: string;
|
|
106
|
+
}>;
|
|
107
|
+
};
|
|
108
|
+
export declare const vars: Contract<typeof contract>;
|
|
109
|
+
//#endregion
|
|
110
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { tokens as e } from "./scales.mjs";
|
|
2
|
+
import { colorRoles as t, fontRoles as n } from "./roles.mjs";
|
|
3
|
+
//#region src/tokens/contract.ts
|
|
4
|
+
function r(e, t) {
|
|
5
|
+
return typeof e == "string" ? `var(--${t.join("-").replace(/[A-Z]/g, (e) => `-${e.toLowerCase()}`)})` : Object.fromEntries(Object.entries(e).map(([e, n]) => [e, r(n, [...t, e])]));
|
|
6
|
+
}
|
|
7
|
+
var i = (e, t) => Object.fromEntries(e.map((e) => [e, t])), a = {
|
|
8
|
+
...e,
|
|
9
|
+
color: i(t, ""),
|
|
10
|
+
font: i(n, ""),
|
|
11
|
+
fontTrim: i(n, {
|
|
12
|
+
cap: "",
|
|
13
|
+
baseline: ""
|
|
14
|
+
})
|
|
15
|
+
}, o = r(a, []);
|
|
16
|
+
//#endregion
|
|
17
|
+
export { a as contract, o as vars };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { vars } from "./contract.mjs";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region src/tokens/roles.d.ts
|
|
2
|
+
export declare const colorRoles: readonly ["bg", "bgMuted", "bgRaised", "fg", "fgMuted", "border", "borderStrong", "accent", "accentFg", "danger", "dangerFg", "focus", "shadow"];
|
|
3
|
+
export type ColorRole = (typeof colorRoles)[number];
|
|
4
|
+
export declare const fontRoles: readonly ["body", "heading", "display", "label", "mono"];
|
|
5
|
+
export type FontRole = (typeof fontRoles)[number];
|
|
6
|
+
//#endregion
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/tokens/roles.ts
|
|
2
|
+
var e = [
|
|
3
|
+
"bg",
|
|
4
|
+
"bgMuted",
|
|
5
|
+
"bgRaised",
|
|
6
|
+
"fg",
|
|
7
|
+
"fgMuted",
|
|
8
|
+
"border",
|
|
9
|
+
"borderStrong",
|
|
10
|
+
"accent",
|
|
11
|
+
"accentFg",
|
|
12
|
+
"danger",
|
|
13
|
+
"dangerFg",
|
|
14
|
+
"focus",
|
|
15
|
+
"shadow"
|
|
16
|
+
], t = [
|
|
17
|
+
"body",
|
|
18
|
+
"heading",
|
|
19
|
+
"display",
|
|
20
|
+
"label",
|
|
21
|
+
"mono"
|
|
22
|
+
];
|
|
23
|
+
//#endregion
|
|
24
|
+
export { e as colorRoles, t as fontRoles };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
//#region src/tokens/scales.d.ts
|
|
2
|
+
export declare const tokens: {
|
|
3
|
+
space: {
|
|
4
|
+
0: string;
|
|
5
|
+
1: string;
|
|
6
|
+
12: string;
|
|
7
|
+
16: string;
|
|
8
|
+
2: string;
|
|
9
|
+
20: string;
|
|
10
|
+
24: string;
|
|
11
|
+
32: string;
|
|
12
|
+
4: string;
|
|
13
|
+
40: string;
|
|
14
|
+
48: string;
|
|
15
|
+
6: string;
|
|
16
|
+
64: string;
|
|
17
|
+
8: string;
|
|
18
|
+
80: string;
|
|
19
|
+
96: string;
|
|
20
|
+
};
|
|
21
|
+
size: {
|
|
22
|
+
xs: string;
|
|
23
|
+
sm: string;
|
|
24
|
+
med: string;
|
|
25
|
+
lg: string;
|
|
26
|
+
xl: string;
|
|
27
|
+
};
|
|
28
|
+
container: {
|
|
29
|
+
prose: string;
|
|
30
|
+
page: string;
|
|
31
|
+
wide: string;
|
|
32
|
+
};
|
|
33
|
+
radius: {
|
|
34
|
+
none: string;
|
|
35
|
+
sm: string;
|
|
36
|
+
med: string;
|
|
37
|
+
lg: string;
|
|
38
|
+
xl: string;
|
|
39
|
+
full: string;
|
|
40
|
+
};
|
|
41
|
+
fontSize: {
|
|
42
|
+
xs: string;
|
|
43
|
+
sm: string;
|
|
44
|
+
med: string;
|
|
45
|
+
lg: string;
|
|
46
|
+
xl: string;
|
|
47
|
+
"2xl": string;
|
|
48
|
+
"3xl": string;
|
|
49
|
+
"4xl": string;
|
|
50
|
+
};
|
|
51
|
+
fontWeight: {
|
|
52
|
+
regular: string;
|
|
53
|
+
medium: string;
|
|
54
|
+
semibold: string;
|
|
55
|
+
bold: string;
|
|
56
|
+
};
|
|
57
|
+
lineHeight: {
|
|
58
|
+
sm: string;
|
|
59
|
+
med: string;
|
|
60
|
+
lg: string;
|
|
61
|
+
};
|
|
62
|
+
zIndex: {
|
|
63
|
+
base: string;
|
|
64
|
+
raised: string;
|
|
65
|
+
dropdown: string;
|
|
66
|
+
sticky: string;
|
|
67
|
+
overlay: string;
|
|
68
|
+
modal: string;
|
|
69
|
+
popover: string;
|
|
70
|
+
toast: string;
|
|
71
|
+
tooltip: string;
|
|
72
|
+
};
|
|
73
|
+
duration: {
|
|
74
|
+
fast: string;
|
|
75
|
+
med: string;
|
|
76
|
+
slow: string;
|
|
77
|
+
};
|
|
78
|
+
easing: {
|
|
79
|
+
standard: string;
|
|
80
|
+
enter: string;
|
|
81
|
+
exit: string;
|
|
82
|
+
};
|
|
83
|
+
distance: {
|
|
84
|
+
sm: string;
|
|
85
|
+
med: string;
|
|
86
|
+
lg: string;
|
|
87
|
+
};
|
|
88
|
+
scale: {
|
|
89
|
+
sm: string;
|
|
90
|
+
med: string;
|
|
91
|
+
lg: string;
|
|
92
|
+
};
|
|
93
|
+
dir: string;
|
|
94
|
+
shadow: {
|
|
95
|
+
sm: string;
|
|
96
|
+
med: string;
|
|
97
|
+
lg: string;
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
//#endregion
|