@mindlogic-ai/logician-ui 5.0.0-alpha.2 → 5.0.0-alpha.4
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/Badge/Badge.d.ts.map +1 -1
- package/dist/components/Badge/Badge.js +5 -3
- package/dist/components/Badge/Badge.js.map +1 -1
- package/dist/components/Badge/Badge.mjs +5 -3
- package/dist/components/Badge/Badge.mjs.map +1 -1
- package/dist/components/Badge/Badge.types.d.ts +7 -5
- package/dist/components/Badge/Badge.types.d.ts.map +1 -1
- package/dist/components/Banner/Banner.types.d.ts +24 -1
- package/dist/components/Banner/Banner.types.d.ts.map +1 -1
- package/dist/components/Card/Card.types.d.ts +12 -0
- package/dist/components/Card/Card.types.d.ts.map +1 -1
- package/dist/components/ColorMode/ColorModeToggle.d.ts +7 -2
- package/dist/components/ColorMode/ColorModeToggle.d.ts.map +1 -1
- package/dist/components/ColorMode/ColorModeToggle.js +8 -3
- package/dist/components/ColorMode/ColorModeToggle.js.map +1 -1
- package/dist/components/ColorMode/ColorModeToggle.mjs +8 -3
- package/dist/components/ColorMode/ColorModeToggle.mjs.map +1 -1
- package/dist/components/Confetti/Confetti.types.d.ts +5 -1
- package/dist/components/Confetti/Confetti.types.d.ts.map +1 -1
- package/dist/components/Confetti/confettiColors.d.ts +5 -5
- package/dist/components/Confetti/confettiColors.js +5 -5
- package/dist/components/Confetti/confettiColors.mjs +5 -5
- package/dist/components/ErrorFallback/ErrorFallback.types.d.ts +6 -0
- package/dist/components/ErrorFallback/ErrorFallback.types.d.ts.map +1 -1
- package/dist/components/Form/FormModalFooter/FormModalFooter.types.d.ts +4 -1
- package/dist/components/Form/FormModalFooter/FormModalFooter.types.d.ts.map +1 -1
- package/dist/components/LineGraph/LineGraph.d.ts.map +1 -1
- package/dist/components/LineGraph/LineGraph.js +4 -5
- package/dist/components/LineGraph/LineGraph.js.map +1 -1
- package/dist/components/LineGraph/LineGraph.mjs +5 -6
- package/dist/components/LineGraph/LineGraph.mjs.map +1 -1
- package/dist/components/LineGraph/LineGraph.types.d.ts +12 -2
- package/dist/components/LineGraph/LineGraph.types.d.ts.map +1 -1
- package/dist/components/LineGraph/seriesColors.d.ts +12 -8
- package/dist/components/LineGraph/seriesColors.d.ts.map +1 -1
- package/dist/components/LineGraph/seriesColors.js +8 -7
- package/dist/components/LineGraph/seriesColors.js.map +1 -1
- package/dist/components/LineGraph/seriesColors.mjs +8 -7
- package/dist/components/LineGraph/seriesColors.mjs.map +1 -1
- package/dist/components/Masonry/Masonry.types.d.ts +8 -3
- package/dist/components/Masonry/Masonry.types.d.ts.map +1 -1
- package/dist/components/Menu/MenuItem.types.d.ts +8 -0
- package/dist/components/Menu/MenuItem.types.d.ts.map +1 -1
- package/dist/components/Modal/ModalCloseButton.d.ts +1 -1
- package/dist/components/Modal/ModalCloseButton.js +1 -1
- package/dist/components/Modal/ModalCloseButton.mjs +1 -1
- package/dist/components/Pagination/Pagination.d.ts +11 -10
- package/dist/components/Pagination/Pagination.d.ts.map +1 -1
- package/dist/components/Pagination/Pagination.js +11 -10
- package/dist/components/Pagination/Pagination.js.map +1 -1
- package/dist/components/Pagination/Pagination.mjs +11 -10
- package/dist/components/Pagination/Pagination.mjs.map +1 -1
- package/dist/components/ProgressBar/ProgressBar.types.d.ts +9 -0
- package/dist/components/ProgressBar/ProgressBar.types.d.ts.map +1 -1
- package/dist/components/RadialProgress/RadialProgress.types.d.ts +21 -1
- package/dist/components/RadialProgress/RadialProgress.types.d.ts.map +1 -1
- package/dist/components/SeeMoreButton/SeeMoreButton.types.d.ts +8 -0
- package/dist/components/SeeMoreButton/SeeMoreButton.types.d.ts.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.js +6 -7
- package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.mjs +6 -7
- package/dist/components/SegmentedControl/SegmentedControl.mjs.map +1 -1
- package/dist/components/SegmentedProgressBar/SegmentedProgressBar.types.d.ts +2 -0
- package/dist/components/SegmentedProgressBar/SegmentedProgressBar.types.d.ts.map +1 -1
- package/dist/components/Toast/Toast.styles.d.ts +6 -2
- package/dist/components/Toast/Toast.styles.d.ts.map +1 -1
- package/dist/components/Toast/Toast.styles.js +18 -10
- package/dist/components/Toast/Toast.styles.js.map +1 -1
- package/dist/components/Toast/Toast.styles.mjs +18 -10
- package/dist/components/Toast/Toast.styles.mjs.map +1 -1
- package/dist/theme/colors.d.ts +2 -2
- package/dist/theme/colors.d.ts.map +1 -1
- package/dist/theme/colors.js +22 -2
- package/dist/theme/colors.js.map +1 -1
- package/dist/theme/colors.mjs +23 -3
- package/dist/theme/colors.mjs.map +1 -1
- package/dist/theme/palette.generated.d.ts +98 -0
- package/dist/theme/palette.generated.d.ts.map +1 -1
- package/dist/theme/palette.generated.js +99 -0
- package/dist/theme/palette.generated.js.map +1 -1
- package/dist/theme/palette.generated.mjs +99 -1
- package/dist/theme/palette.generated.mjs.map +1 -1
- package/dist/theme/paletteSwatches.d.ts +20 -0
- package/dist/theme/paletteSwatches.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/Accordion/Accordion.stories.tsx +85 -0
- package/src/components/Accordion/Accordion.usage.mdx +200 -0
- package/src/components/Appear/Appear.usage.mdx +107 -0
- package/src/components/Avatar/Avatar.stories.tsx +71 -1
- package/src/components/Avatar/Avatar.usage.mdx +166 -0
- package/src/components/Badge/Badge.stories.tsx +193 -3
- package/src/components/Badge/Badge.tsx +5 -3
- package/src/components/Badge/Badge.types.ts +7 -5
- package/src/components/Badge/Badge.usage.mdx +265 -0
- package/src/components/Banner/Banner.stories.tsx +152 -2
- package/src/components/Banner/Banner.types.ts +30 -1
- package/src/components/Banner/Banner.usage.mdx +233 -0
- package/src/components/BottomSheet/BottomSheet.stories.tsx +168 -1
- package/src/components/BottomSheet/BottomSheet.usage.mdx +216 -0
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +59 -0
- package/src/components/Breadcrumb/Breadcrumb.usage.mdx +181 -0
- package/src/components/Button/Button.stories.tsx +263 -3
- package/src/components/Button/Button.usage.mdx +342 -0
- package/src/components/Card/Card.stories.tsx +106 -0
- package/src/components/Card/Card.types.ts +12 -0
- package/src/components/Card/Card.usage.mdx +216 -0
- package/src/components/Checkbox/Checkbox.stories.tsx +140 -13
- package/src/components/Checkbox/Checkbox.usage.mdx +214 -0
- package/src/components/Chip/Chip.usage.mdx +78 -0
- package/src/components/Code/Code.stories.tsx +60 -0
- package/src/components/Code/Code.usage.mdx +187 -0
- package/src/components/CodeTabs/CodeTabs.stories.tsx +53 -0
- package/src/components/CodeTabs/CodeTabs.usage.mdx +176 -0
- package/src/components/Collapsible/Collapsible.stories.tsx +58 -0
- package/src/components/Collapsible/Collapsible.usage.mdx +173 -0
- package/src/components/ColorMode/ColorMode.stories.tsx +50 -0
- package/src/components/ColorMode/ColorMode.usage.mdx +135 -0
- package/src/components/ColorMode/ColorModeToggle.tsx +10 -3
- package/src/components/Confetti/Confetti.types.ts +5 -1
- package/src/components/Confetti/Confetti.usage.mdx +111 -0
- package/src/components/Confetti/confettiColors.ts +5 -5
- package/src/components/Container/Container.stories.tsx +32 -0
- package/src/components/Container/Container.usage.mdx +130 -0
- package/src/components/CopyableCode/CopyableCode.stories.tsx +62 -0
- package/src/components/CopyableCode/CopyableCode.usage.mdx +168 -0
- package/src/components/CountBadge/CountBadge.stories.tsx +69 -0
- package/src/components/CountBadge/CountBadge.usage.mdx +215 -0
- package/src/components/CountUp/CountUp.usage.mdx +107 -0
- package/src/components/DatePicker/DatePicker.usage.mdx +177 -0
- package/src/components/DatePicker/RangeDatePicker.stories.tsx +87 -3
- package/src/components/ErrorFallback/ErrorFallback.types.ts +6 -0
- package/src/components/ErrorFallback/ErrorFallback.usage.mdx +127 -0
- package/src/components/ExpandableText/ExpandableText.stories.tsx +55 -0
- package/src/components/ExpandableText/ExpandableText.usage.mdx +176 -0
- package/src/components/FileInput/FileInput.stories.tsx +38 -1
- package/src/components/FileInput/FileInput.usage.mdx +178 -0
- package/src/components/FileItem/FileItem.stories.tsx +71 -0
- package/src/components/FileItem/FileItem.usage.mdx +180 -0
- package/src/components/FileList/FileList.stories.tsx +25 -0
- package/src/components/FileList/FileList.usage.mdx +165 -0
- package/src/components/FlyTo/FlyTo.usage.mdx +99 -0
- package/src/components/Form/Form.stories.tsx +149 -0
- package/src/components/Form/Form.usage.mdx +201 -0
- package/src/components/Form/FormModalFooter/FormModalFooter.types.ts +4 -1
- package/src/components/FormControl/FormControl.stories.tsx +35 -0
- package/src/components/FormControl/FormControl.usage.mdx +128 -0
- package/src/components/FormIntegration/FormIntegration.usage.mdx +158 -0
- package/src/components/FormLabel/FormLabel.stories.tsx +71 -0
- package/src/components/FormLabel/FormLabel.usage.mdx +125 -0
- package/src/components/Icon/Icon.stories.tsx +61 -1
- package/src/components/Icon/Icon.usage.mdx +158 -0
- package/src/components/IconButton/IconButton.stories.tsx +209 -5
- package/src/components/IconButton/IconButton.usage.mdx +273 -0
- package/src/components/InfoSprinkle/InfoSprinkle.stories.tsx +77 -1
- package/src/components/InfoSprinkle/InfoSprinkle.usage.mdx +189 -0
- package/src/components/InlineCode/InlineCode.stories.tsx +75 -0
- package/src/components/InlineCode/InlineCode.usage.mdx +142 -0
- package/src/components/Input/Input.stories.tsx +180 -0
- package/src/components/Input/Input.usage.mdx +278 -0
- package/src/components/LineGraph/LineGraph.stories.tsx +112 -0
- package/src/components/LineGraph/LineGraph.tsx +4 -5
- package/src/components/LineGraph/LineGraph.types.ts +12 -2
- package/src/components/LineGraph/LineGraph.usage.mdx +186 -0
- package/src/components/LineGraph/seriesColors.test.ts +11 -10
- package/src/components/LineGraph/seriesColors.ts +18 -16
- package/src/components/Loaders/Loaders.stories.tsx +93 -0
- package/src/components/Loaders/Loaders.usage.mdx +180 -0
- package/src/components/LogicianProvider/LogicianProvider.usage.mdx +98 -0
- package/src/components/Markdown/Markdown.stories.tsx +53 -0
- package/src/components/Markdown/Markdown.usage.mdx +182 -0
- package/src/components/Masonry/Masonry.stories.tsx +63 -1
- package/src/components/Masonry/Masonry.types.ts +8 -3
- package/src/components/Masonry/Masonry.usage.mdx +142 -0
- package/src/components/MaxLengthIndicator/MaxLengthIndicator.stories.tsx +57 -0
- package/src/components/MaxLengthIndicator/MaxLengthIndicator.usage.mdx +125 -0
- package/src/components/Menu/Menu.stories.tsx +146 -2
- package/src/components/Menu/Menu.usage.mdx +230 -0
- package/src/components/Menu/MenuItem.types.ts +8 -0
- package/src/components/Modal/Modal.stories.tsx +177 -1
- package/src/components/Modal/Modal.usage.mdx +262 -0
- package/src/components/Modal/ModalCloseButton.tsx +1 -1
- package/src/components/MonthPicker/MonthPicker.stories.tsx +30 -0
- package/src/components/MonthPicker/MonthPicker.usage.mdx +191 -0
- package/src/components/Pagination/Pagination.stories.tsx +90 -1
- package/src/components/Pagination/Pagination.tsx +11 -10
- package/src/components/Pagination/Pagination.usage.mdx +186 -0
- package/src/components/PasswordInput/PasswordInput.stories.tsx +51 -0
- package/src/components/PasswordInput/PasswordInput.usage.mdx +193 -0
- package/src/components/PinInput/PinInput.stories.tsx +91 -0
- package/src/components/PinInput/PinInput.usage.mdx +194 -0
- package/src/components/Popover/Popover.stories.tsx +104 -1
- package/src/components/Popover/Popover.usage.mdx +197 -0
- package/src/components/ProgressBar/ProgressBar.stories.tsx +92 -1
- package/src/components/ProgressBar/ProgressBar.types.ts +9 -0
- package/src/components/ProgressBar/ProgressBar.usage.mdx +210 -0
- package/src/components/Pulse/Pulse.usage.mdx +102 -0
- package/src/components/RadialProgress/RadialProgress.stories.tsx +74 -1
- package/src/components/RadialProgress/RadialProgress.types.ts +21 -1
- package/src/components/RadialProgress/RadialProgress.usage.mdx +153 -0
- package/src/components/Radio/Radio.stories.tsx +119 -0
- package/src/components/Radio/Radio.usage.mdx +187 -0
- package/src/components/Reveal/Reveal.usage.mdx +105 -0
- package/src/components/ScaledContext/ScaledContext.usage.mdx +111 -0
- package/src/components/SeeMoreButton/SeeMoreButton.stories.tsx +146 -2
- package/src/components/SeeMoreButton/SeeMoreButton.types.ts +8 -0
- package/src/components/SeeMoreButton/SeeMoreButton.usage.mdx +213 -0
- package/src/components/SegmentedControl/SegmentedControl.stories.tsx +69 -0
- package/src/components/SegmentedControl/SegmentedControl.tsx +6 -7
- package/src/components/SegmentedControl/SegmentedControl.usage.mdx +209 -0
- package/src/components/SegmentedProgressBar/SegmentedProgressBar.stories.tsx +54 -0
- package/src/components/SegmentedProgressBar/SegmentedProgressBar.types.ts +2 -0
- package/src/components/SegmentedProgressBar/SegmentedProgressBar.usage.mdx +145 -0
- package/src/components/Select/Select.stories.tsx +209 -1
- package/src/components/Select/Select.usage.mdx +278 -0
- package/src/components/Shake/Shake.usage.mdx +107 -0
- package/src/components/Slider/Slider.stories.tsx +116 -0
- package/src/components/Slider/Slider.usage.mdx +179 -0
- package/src/components/Spinner/Spinner.stories.tsx +64 -0
- package/src/components/Spinner/Spinner.usage.mdx +136 -0
- package/src/components/SwapTransition/SwapTransition.usage.mdx +102 -0
- package/src/components/Switch/Switch.stories.tsx +131 -6
- package/src/components/Switch/Switch.usage.mdx +199 -0
- package/src/components/Table/Table.stories.tsx +159 -1
- package/src/components/Table/Table.usage.mdx +235 -0
- package/src/components/Tabs/Tabs.stories.tsx +86 -0
- package/src/components/Tabs/Tabs.usage.mdx +219 -0
- package/src/components/Tag/Tag.stories.tsx +181 -4
- package/src/components/Tag/Tag.usage.mdx +257 -0
- package/src/components/Textarea/Textarea.stories.tsx +113 -0
- package/src/components/Textarea/Textarea.usage.mdx +186 -0
- package/src/components/Toast/Toast.stories.tsx +185 -3
- package/src/components/Toast/Toast.styles.ts +18 -10
- package/src/components/Toast/Toast.usage.mdx +265 -0
- package/src/components/Tooltip/Tooltip.stories.tsx +86 -1
- package/src/components/Tooltip/Tooltip.usage.mdx +211 -0
- package/src/components/Tree/Tree.stories.tsx +89 -0
- package/src/components/Tree/Tree.usage.mdx +207 -0
- package/src/components/Typography/Typography.stories.tsx +117 -0
- package/src/components/Typography/Typography.usage.mdx +251 -0
- package/src/components/Workflow/Workflow.usage.mdx +199 -0
- package/src/components/noRawScales.test.ts +5 -1
- package/src/foundations/BrandColour.mdx +364 -0
- package/src/foundations/BrandColour.stories.tsx +334 -0
- package/src/guidelines/ComponentPageTemplate.mdx +84 -0
- package/src/guidelines/FeedbackActions.mdx +162 -23
- package/src/guidelines/_components/Lang.tsx +175 -0
- package/src/guidelines/_components/TokenTable.tsx +136 -0
- package/src/theme/BazePalette.stories.tsx +111 -1
- package/src/theme/Palette.stories.tsx +2 -2
- package/src/theme/SemanticTokens.mdx +75 -16
- package/src/theme/claude.md +15 -9
- package/src/theme/colors.ts +33 -3
- package/src/theme/contrast.test.ts +32 -0
- package/src/theme/palette.generated.ts +99 -0
- package/src/theme/paletteSwatches.ts +35 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doc-only language switch for the Storybook guideline pages.
|
|
3
|
+
*
|
|
4
|
+
* One MDX file carries both languages: wrap each block in `<En>` / `<Ko>` and
|
|
5
|
+
* put `<LangToggle />` at the top of the page. The choice is kept in
|
|
6
|
+
* localStorage (default English) and every block on the page — and on every
|
|
7
|
+
* other guideline page — follows it.
|
|
8
|
+
*
|
|
9
|
+
* Not part of the published library: nothing in `src/index.ts` imports it,
|
|
10
|
+
* `check-component-exports.js` only scans `src/components`, and the rollup
|
|
11
|
+
* build excludes `src/guidelines/**`.
|
|
12
|
+
*/
|
|
13
|
+
import { ReactNode, useSyncExternalStore } from 'react';
|
|
14
|
+
|
|
15
|
+
type DocLang = 'en' | 'ko';
|
|
16
|
+
|
|
17
|
+
const STORAGE_KEY = 'logician-ui:docs-lang';
|
|
18
|
+
const listeners = new Set<() => void>();
|
|
19
|
+
let current: DocLang | undefined;
|
|
20
|
+
|
|
21
|
+
const read = (): DocLang => {
|
|
22
|
+
try {
|
|
23
|
+
return window.localStorage.getItem(STORAGE_KEY) === 'ko' ? 'ko' : 'en';
|
|
24
|
+
} catch {
|
|
25
|
+
return 'en';
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const write = (lang: DocLang) => {
|
|
30
|
+
try {
|
|
31
|
+
window.localStorage.setItem(STORAGE_KEY, lang);
|
|
32
|
+
} catch {
|
|
33
|
+
// Storage blocked (private mode): the switch still works for this page.
|
|
34
|
+
}
|
|
35
|
+
current = lang;
|
|
36
|
+
listeners.forEach((notify) => notify());
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const snapshot = (): DocLang => (current ??= read());
|
|
40
|
+
|
|
41
|
+
// Another tab changed it: one listener for the whole page, not one per block.
|
|
42
|
+
const onStorage = (event: StorageEvent) => {
|
|
43
|
+
if (event.key !== STORAGE_KEY) return;
|
|
44
|
+
current = read();
|
|
45
|
+
listeners.forEach((notify) => notify());
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const subscribe = (notify: () => void) => {
|
|
49
|
+
if (listeners.size === 0) window.addEventListener('storage', onStorage);
|
|
50
|
+
listeners.add(notify);
|
|
51
|
+
return () => {
|
|
52
|
+
listeners.delete(notify);
|
|
53
|
+
if (listeners.size === 0) window.removeEventListener('storage', onStorage);
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/** The language the reader picked; `'en'` until they pick one. */
|
|
58
|
+
const useDocLang = (): DocLang =>
|
|
59
|
+
useSyncExternalStore(subscribe, snapshot, () => 'en');
|
|
60
|
+
|
|
61
|
+
const pick = <V,>(lang: DocLang, en: V, ko: V) => (lang === 'ko' ? ko : en);
|
|
62
|
+
|
|
63
|
+
const Block = ({ lang, children }: { lang: DocLang; children: ReactNode }) =>
|
|
64
|
+
useDocLang() === lang ? <div lang={lang}>{children}</div> : null;
|
|
65
|
+
|
|
66
|
+
/** English block. Leave a blank line after the opening tag so Markdown parses. */
|
|
67
|
+
export const En = ({ children }: { children: ReactNode }) => (
|
|
68
|
+
<Block lang="en">{children}</Block>
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
/** Korean block. Leave a blank line after the opening tag so Markdown parses. */
|
|
72
|
+
export const Ko = ({ children }: { children: ReactNode }) => (
|
|
73
|
+
<Block lang="ko">{children}</Block>
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
/** Inline text in the reader's language, for captions and table cells. */
|
|
77
|
+
export const T = ({ en, ko }: { en: ReactNode; ko: ReactNode }) => {
|
|
78
|
+
const lang = useDocLang();
|
|
79
|
+
return <span lang={lang}>{pick(lang, en, ko)}</span>;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const OPTIONS: { value: DocLang; label: string }[] = [
|
|
83
|
+
{ value: 'en', label: 'English' },
|
|
84
|
+
{ value: 'ko', label: '한국어' },
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
/** Top-of-page switch. Renders as a two-button segmented control. */
|
|
88
|
+
export const LangToggle = () => {
|
|
89
|
+
const lang = useDocLang();
|
|
90
|
+
return (
|
|
91
|
+
<div
|
|
92
|
+
role="group"
|
|
93
|
+
aria-label="Language / 언어"
|
|
94
|
+
style={{
|
|
95
|
+
display: 'inline-flex',
|
|
96
|
+
border: '1px solid #D8D2CA',
|
|
97
|
+
borderRadius: 8,
|
|
98
|
+
overflow: 'hidden',
|
|
99
|
+
margin: '0 0 16px',
|
|
100
|
+
fontSize: 13,
|
|
101
|
+
}}
|
|
102
|
+
>
|
|
103
|
+
{OPTIONS.map((option) => {
|
|
104
|
+
const active = option.value === lang;
|
|
105
|
+
return (
|
|
106
|
+
<button
|
|
107
|
+
key={option.value}
|
|
108
|
+
type="button"
|
|
109
|
+
lang={option.value}
|
|
110
|
+
aria-pressed={active}
|
|
111
|
+
onClick={() => write(option.value)}
|
|
112
|
+
style={{
|
|
113
|
+
padding: '6px 14px',
|
|
114
|
+
border: 0,
|
|
115
|
+
cursor: 'pointer',
|
|
116
|
+
fontWeight: active ? 700 : 400,
|
|
117
|
+
background: active ? '#252525' : 'transparent',
|
|
118
|
+
color: active ? '#F5EDE0' : '#252525',
|
|
119
|
+
}}
|
|
120
|
+
>
|
|
121
|
+
{option.label}
|
|
122
|
+
</button>
|
|
123
|
+
);
|
|
124
|
+
})}
|
|
125
|
+
</div>
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const VERDICT = {
|
|
130
|
+
do: {
|
|
131
|
+
mark: '✓',
|
|
132
|
+
en: 'Do',
|
|
133
|
+
ko: '이렇게 하세요',
|
|
134
|
+
rule: '#5E7A37',
|
|
135
|
+
ink: '#425C17',
|
|
136
|
+
},
|
|
137
|
+
dont: {
|
|
138
|
+
mark: '×',
|
|
139
|
+
en: "Don't",
|
|
140
|
+
ko: '이렇게 하지 마세요',
|
|
141
|
+
rule: '#A02525',
|
|
142
|
+
ink: '#A02525',
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/** Do / Don't caption under a `<Canvas>` specimen. */
|
|
147
|
+
export const Verdict = ({
|
|
148
|
+
kind,
|
|
149
|
+
en,
|
|
150
|
+
ko,
|
|
151
|
+
}: {
|
|
152
|
+
kind: 'do' | 'dont';
|
|
153
|
+
en: ReactNode;
|
|
154
|
+
ko: ReactNode;
|
|
155
|
+
}) => {
|
|
156
|
+
const lang = useDocLang();
|
|
157
|
+
const v = VERDICT[kind];
|
|
158
|
+
return (
|
|
159
|
+
<p
|
|
160
|
+
lang={lang}
|
|
161
|
+
style={{
|
|
162
|
+
margin: '-12px 0 28px',
|
|
163
|
+
paddingLeft: 12,
|
|
164
|
+
borderLeft: `3px solid ${v.rule}`,
|
|
165
|
+
fontSize: 14,
|
|
166
|
+
lineHeight: 1.6,
|
|
167
|
+
}}
|
|
168
|
+
>
|
|
169
|
+
<strong style={{ color: v.ink }}>
|
|
170
|
+
{v.mark} {pick(lang, v.en, v.ko)}.
|
|
171
|
+
</strong>{' '}
|
|
172
|
+
{pick(lang, en, ko)}
|
|
173
|
+
</p>
|
|
174
|
+
);
|
|
175
|
+
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doc-only token table for guideline pages: one row per semantic token, with
|
|
3
|
+
* its light and dark value resolved from the shipped theme
|
|
4
|
+
* (`getSwatchGroups` in `src/theme/paletteSwatches.ts`). No hex is written by
|
|
5
|
+
* hand, so a palette change shows up here on the next build.
|
|
6
|
+
*
|
|
7
|
+
* Render it inside a story (it uses Chakra), then pull the story into MDX with
|
|
8
|
+
* `<Canvas of={…} />` or `<Story of={…} />`. Not exported from the library.
|
|
9
|
+
*/
|
|
10
|
+
import type { ReactNode } from 'react';
|
|
11
|
+
import { Box, Grid } from '@chakra-ui/react';
|
|
12
|
+
import { readableColor } from 'polished';
|
|
13
|
+
|
|
14
|
+
import { getSwatchGroups, Swatch } from '../../theme/paletteSwatches';
|
|
15
|
+
import { T } from './Lang';
|
|
16
|
+
|
|
17
|
+
const SWATCHES: ReadonlyMap<string, Swatch> = new Map(
|
|
18
|
+
getSwatchGroups().flatMap(([, swatches]) =>
|
|
19
|
+
swatches.map((swatch) => [swatch.path, swatch] as const)
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
/** Light and dark hex of a public semantic token. Throws on an unknown name. */
|
|
24
|
+
const resolveToken = (path: string): Swatch => {
|
|
25
|
+
const swatch = SWATCHES.get(path);
|
|
26
|
+
if (!swatch) throw new Error(`Unknown semantic colour token: ${path}`);
|
|
27
|
+
return swatch;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/** Label colour for a chip: brand black or white, whichever reads on it. */
|
|
31
|
+
const labelOn = (hex: string) =>
|
|
32
|
+
readableColor(hex, '#252525', '#FFFFFF', false);
|
|
33
|
+
|
|
34
|
+
const Chip = ({ hex }: { hex: string }) => {
|
|
35
|
+
const transparent = !/^#/.test(hex);
|
|
36
|
+
return (
|
|
37
|
+
<Box
|
|
38
|
+
// Literal values, not tokens: the chip shows one fixed mode's value
|
|
39
|
+
// whatever mode the page is in.
|
|
40
|
+
style={{
|
|
41
|
+
background: transparent ? undefined : hex,
|
|
42
|
+
color: transparent ? undefined : labelOn(hex),
|
|
43
|
+
}}
|
|
44
|
+
borderWidth="1px"
|
|
45
|
+
borderColor="border.subtle"
|
|
46
|
+
borderStyle={transparent ? 'dashed' : 'solid'}
|
|
47
|
+
borderRadius="sm"
|
|
48
|
+
px={2}
|
|
49
|
+
py={1.5}
|
|
50
|
+
fontFamily="mono"
|
|
51
|
+
fontSize="11px"
|
|
52
|
+
minW="88px"
|
|
53
|
+
>
|
|
54
|
+
{hex.replace('#', '')}
|
|
55
|
+
</Box>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
type TokenRow = {
|
|
60
|
+
/** Semantic token path, e.g. `primary.main`. */
|
|
61
|
+
token: string;
|
|
62
|
+
/** What the token is for, in the reader's language. */
|
|
63
|
+
use?: ReactNode;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const HEADERS: ReactNode[] = [
|
|
67
|
+
<T key="token" en="Token" ko="토큰" />,
|
|
68
|
+
<T key="light" en="Light" ko="라이트" />,
|
|
69
|
+
<T key="dark" en="Dark" ko="다크" />,
|
|
70
|
+
<T key="use" en="Use" ko="쓰는 곳" />,
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Token | light | dark | use. Pass `rows` as token names or `{ token, use }`;
|
|
75
|
+
* `use` is usually a `<T en ko />` so it follows the page language.
|
|
76
|
+
*/
|
|
77
|
+
export const TokenTable = ({ rows }: { rows: (string | TokenRow)[] }) => {
|
|
78
|
+
const normalised = rows.map((row) =>
|
|
79
|
+
typeof row === 'string' ? { token: row } : row
|
|
80
|
+
);
|
|
81
|
+
const hasUse = normalised.some((row) => row.use);
|
|
82
|
+
return (
|
|
83
|
+
<Grid
|
|
84
|
+
templateColumns={{
|
|
85
|
+
base: 'minmax(0,1fr) auto auto',
|
|
86
|
+
md: hasUse
|
|
87
|
+
? 'minmax(160px,auto) auto auto minmax(0,1fr)'
|
|
88
|
+
: 'minmax(160px,auto) auto auto',
|
|
89
|
+
}}
|
|
90
|
+
columnGap={3}
|
|
91
|
+
rowGap={1.5}
|
|
92
|
+
alignItems="center"
|
|
93
|
+
justifyContent="start"
|
|
94
|
+
fontSize="13px"
|
|
95
|
+
color="fg.default"
|
|
96
|
+
maxW="100%"
|
|
97
|
+
>
|
|
98
|
+
{HEADERS.slice(0, hasUse ? 4 : 3).map((header, i) => (
|
|
99
|
+
<Box
|
|
100
|
+
key={i}
|
|
101
|
+
fontWeight="bold"
|
|
102
|
+
color="fg.subtle"
|
|
103
|
+
display={i === 3 ? { base: 'none', md: 'block' } : undefined}
|
|
104
|
+
>
|
|
105
|
+
{header}
|
|
106
|
+
</Box>
|
|
107
|
+
))}
|
|
108
|
+
{normalised.map(({ token, use }) => {
|
|
109
|
+
const { light, dark } = resolveToken(token);
|
|
110
|
+
return (
|
|
111
|
+
<Box key={token} display="contents">
|
|
112
|
+
<Box fontFamily="mono" fontSize="12px" wordBreak="break-all">
|
|
113
|
+
{token}
|
|
114
|
+
{use && (
|
|
115
|
+
<Box
|
|
116
|
+
display={{ base: 'block', md: 'none' }}
|
|
117
|
+
fontFamily="body"
|
|
118
|
+
color="fg.subtle"
|
|
119
|
+
>
|
|
120
|
+
{use}
|
|
121
|
+
</Box>
|
|
122
|
+
)}
|
|
123
|
+
</Box>
|
|
124
|
+
<Chip hex={light} />
|
|
125
|
+
<Chip hex={dark} />
|
|
126
|
+
{hasUse && (
|
|
127
|
+
<Box display={{ base: 'none', md: 'block' }} color="fg.muted">
|
|
128
|
+
{use}
|
|
129
|
+
</Box>
|
|
130
|
+
)}
|
|
131
|
+
</Box>
|
|
132
|
+
);
|
|
133
|
+
})}
|
|
134
|
+
</Grid>
|
|
135
|
+
);
|
|
136
|
+
};
|
|
@@ -7,7 +7,19 @@ import {
|
|
|
7
7
|
ROLE_TOKEN_PATHS,
|
|
8
8
|
SYSTEM_HUE_NAMES,
|
|
9
9
|
} from './colors';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
CORAL,
|
|
12
|
+
DATAVIZ,
|
|
13
|
+
RAMPS,
|
|
14
|
+
SCHEMES,
|
|
15
|
+
SYSTEM_HUES,
|
|
16
|
+
} from './palette.generated';
|
|
17
|
+
import {
|
|
18
|
+
DATA_VIZ_LABEL_TOKEN,
|
|
19
|
+
DATA_VIZ_LABELS,
|
|
20
|
+
type DataVizKey,
|
|
21
|
+
resolveColor,
|
|
22
|
+
} from './paletteSwatches';
|
|
11
23
|
|
|
12
24
|
/**
|
|
13
25
|
* logician-ui 5.0 BAZE palette — the three token layers.
|
|
@@ -104,6 +116,12 @@ export const RawScales: Story = {
|
|
|
104
116
|
<Chip key={k} hex={hex} label={k} />
|
|
105
117
|
))}
|
|
106
118
|
</Flex>
|
|
119
|
+
<H4>dataviz</H4>
|
|
120
|
+
<Flex gap={2} wrap="wrap">
|
|
121
|
+
{Object.entries(DATAVIZ).map(([k, hex]) => (
|
|
122
|
+
<Chip key={k} hex={hex} label={k} />
|
|
123
|
+
))}
|
|
124
|
+
</Flex>
|
|
107
125
|
<H4>system hues</H4>
|
|
108
126
|
<Grid templateColumns="120px repeat(8, 1fr)" gap={1} fontSize="11px">
|
|
109
127
|
<span />
|
|
@@ -157,6 +175,98 @@ export const RoleTokens: Story = {
|
|
|
157
175
|
),
|
|
158
176
|
};
|
|
159
177
|
|
|
178
|
+
const DATA_STEPS = (Object.keys(DATA_VIZ_LABELS) as DataVizKey[]).filter((k) =>
|
|
179
|
+
k.startsWith('data-')
|
|
180
|
+
);
|
|
181
|
+
/** Display order: far below → baseline → far above. */
|
|
182
|
+
const DIVERGING_STEPS: DataVizKey[] = [
|
|
183
|
+
'diverging-neg-3',
|
|
184
|
+
'diverging-neg-2',
|
|
185
|
+
'diverging-neg-1',
|
|
186
|
+
'diverging-mid',
|
|
187
|
+
'diverging-pos-1',
|
|
188
|
+
'diverging-pos-2',
|
|
189
|
+
'diverging-pos-3',
|
|
190
|
+
];
|
|
191
|
+
|
|
192
|
+
/** A fill with the in-cell label `DATA_VIZ_LABELS` gives it (or none). */
|
|
193
|
+
const DataCell = ({
|
|
194
|
+
flat,
|
|
195
|
+
hex,
|
|
196
|
+
mode,
|
|
197
|
+
}: {
|
|
198
|
+
flat: DataVizKey;
|
|
199
|
+
hex: string;
|
|
200
|
+
mode: 'light' | 'dark';
|
|
201
|
+
}) => {
|
|
202
|
+
const label = DATA_VIZ_LABELS[flat][mode];
|
|
203
|
+
const labelHex =
|
|
204
|
+
label && resolveColor(`{colors.${DATA_VIZ_LABEL_TOKEN[label]}}`, mode);
|
|
205
|
+
return (
|
|
206
|
+
<Stack gap={1}>
|
|
207
|
+
<Flex
|
|
208
|
+
bg={hex}
|
|
209
|
+
color={labelHex || undefined}
|
|
210
|
+
h="56px"
|
|
211
|
+
align="center"
|
|
212
|
+
justify="center"
|
|
213
|
+
fontSize="13px"
|
|
214
|
+
fontWeight="bold"
|
|
215
|
+
borderRadius="sm"
|
|
216
|
+
>
|
|
217
|
+
{labelHex && '42%'}
|
|
218
|
+
</Flex>
|
|
219
|
+
{/* Plain boxes: the panel paints its own mode, so text inherits its colour. */}
|
|
220
|
+
<Box fontFamily="mono" fontSize="11px">
|
|
221
|
+
{ROLE_TOKEN_PATHS[flat]}
|
|
222
|
+
</Box>
|
|
223
|
+
<Box fontSize="10px">
|
|
224
|
+
{hex} ·{' '}
|
|
225
|
+
{labelHex
|
|
226
|
+
? `${label} label ${ratio(hex, labelHex).toFixed(2)}`
|
|
227
|
+
: 'no in-cell label'}
|
|
228
|
+
</Box>
|
|
229
|
+
</Stack>
|
|
230
|
+
);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Data-visualisation fills — `data.1–4` (single measure, 4 = largest) and
|
|
235
|
+
* `diverging.*` (blue above the baseline, orange below, `diverging.mid` at it)
|
|
236
|
+
* — in light and dark, each with the in-cell label it can carry.
|
|
237
|
+
*/
|
|
238
|
+
export const DataViz: Story = {
|
|
239
|
+
render: () => (
|
|
240
|
+
<Stack gap={6} maxW="1100px">
|
|
241
|
+
{(['light', 'dark'] as const).map((mode) => {
|
|
242
|
+
const table = SCHEMES.ink[mode] as Record<string, string>;
|
|
243
|
+
return (
|
|
244
|
+
<Stack
|
|
245
|
+
key={mode}
|
|
246
|
+
gap={4}
|
|
247
|
+
p={4}
|
|
248
|
+
borderRadius="md"
|
|
249
|
+
bg={table['bg-canvas']}
|
|
250
|
+
color={table['fg-default']}
|
|
251
|
+
>
|
|
252
|
+
<Box fontWeight="bold">{mode}</Box>
|
|
253
|
+
<Grid templateColumns="repeat(4, 1fr)" gap={2}>
|
|
254
|
+
{DATA_STEPS.map((k) => (
|
|
255
|
+
<DataCell key={k} flat={k} hex={table[k]} mode={mode} />
|
|
256
|
+
))}
|
|
257
|
+
</Grid>
|
|
258
|
+
<Grid templateColumns="repeat(7, 1fr)" gap={2}>
|
|
259
|
+
{DIVERGING_STEPS.map((k) => (
|
|
260
|
+
<DataCell key={k} flat={k} hex={table[k]} mode={mode} />
|
|
261
|
+
))}
|
|
262
|
+
</Grid>
|
|
263
|
+
</Stack>
|
|
264
|
+
);
|
|
265
|
+
})}
|
|
266
|
+
</Stack>
|
|
267
|
+
),
|
|
268
|
+
};
|
|
269
|
+
|
|
160
270
|
/** Live tokens on this page's colour mode — flip the toolbar to check dark. */
|
|
161
271
|
export const Category: Story = {
|
|
162
272
|
render: () => (
|
|
@@ -30,9 +30,9 @@ const meta = {
|
|
|
30
30
|
|
|
31
31
|
Three layers; components read only the last one.
|
|
32
32
|
|
|
33
|
-
1. **Raw scales** — \`ink\` / \`inkDark\`, \`sand\` / \`sandDark\`, \`slate\` / \`slateDark\` (1–12), \`coral\`,
|
|
33
|
+
1. **Raw scales** — \`ink\` / \`inkDark\`, \`sand\` / \`sandDark\`, \`slate\` / \`slateDark\` (1–12), \`coral\`, 12 system hues, and \`dataviz\`. Values come from \`scripts/palette/generate.mjs\`.
|
|
34
34
|
2. **Semantic steps** — \`neutral.1–12\` and \`secondary.1–12\`, filled by the theme option: \`createLogicianTheme({ neutral: 'ink' | 'slate', secondary: 'sand' })\` (or \`<LogicianProvider theme={…}>\`).
|
|
35
|
-
3. **Role tokens** — \`bg.*\`, \`layer.*\`, \`fg.*\`, \`border.*\`, \`primary.*\`, \`action.*\`, status \`{bg,border,fg,solid,onSolid}\`, \`category.*\` …
|
|
35
|
+
3. **Role tokens** — \`bg.*\`, \`layer.*\`, \`fg.*\`, \`border.*\`, \`primary.*\`, \`action.*\`, status \`{bg,border,fg,solid,onSolid}\`, \`category.*\`, data-viz fills \`data.*\` / \`diverging.*\` …
|
|
36
36
|
|
|
37
37
|
Every value below is shown in light and dark. Contrast is audited in CI (\`contrast.test.ts\`) in light, dark and both high-contrast modes. The 4.x names still resolve as aliases until 6.0 and are listed at the bottom, not in the grid. Setup/Theme/BAZE Palette shows the raw scales and every role in all four modes.
|
|
38
38
|
`,
|
|
@@ -15,7 +15,7 @@ Values and contrast for every token: **Setup/Theme/BAZE Palette**.
|
|
|
15
15
|
| --- | --- | --- |
|
|
16
16
|
| Raw scale (colour names) | `ink.1–12`, `inkDark.1–12`, `sand.*`, `slate.*`, `coral.*`, `red.base` … | never in components |
|
|
17
17
|
| Semantic step (role names) | `neutral.1–12`, `secondary.1–12` | a specific neutral step no role names |
|
|
18
|
-
| Semantic role | `bg.*`, `layer.*`, `fg.*`, `border.*`, `primary.*`, `secondary.*`, `action.*`, `send.*`, `count.*`, `disabled.*`, `focus.ring`, status, `tooltip.*`, `category.*` | everything else |
|
|
18
|
+
| Semantic role | `bg.*`, `layer.*`, `fg.*`, `border.*`, `primary.*`, `secondary.*`, `action.*`, `send.*`, `count.*`, `disabled.*`, `focus.ring`, status, `tooltip.*`, `category.*`, `data.*`, `diverging.*` | everything else |
|
|
19
19
|
|
|
20
20
|
```ts
|
|
21
21
|
createLogicianTheme() // BAZE: { neutral: 'ink', secondary: 'sand' }
|
|
@@ -45,6 +45,8 @@ createLogicianTheme({ neutral: 'slate' }) // cool gray — app code unchanged
|
|
|
45
45
|
| Disabled (no opacity) | `disabled.bg` / `disabled.fg` |
|
|
46
46
|
| Status | `danger` · `success` · `warning` · `info` → `.bg` `.border` `.fg` `.solid` `.onSolid` |
|
|
47
47
|
| Decorative category (tiles, avatars, tags, charts) | `category.{hue}.surface` / `.fg` |
|
|
48
|
+
| Single-measure chart, usage bar, map, heatmap fill | `data.1`–`data.4` (4 = largest) |
|
|
49
|
+
| Chart fill above / below a real baseline (vs plan, vs average) | `diverging.pos.1–3` / `diverging.neg.1–3`, `diverging.mid` at the baseline |
|
|
48
50
|
|
|
49
51
|
Emphasis is weight, not colour: headings use `fg.default`, never `primary.*`.
|
|
50
52
|
Status colours mean status — don't borrow `success`/`warning` for decoration;
|
|
@@ -57,25 +59,82 @@ Use it for both, and for nothing decorative.
|
|
|
57
59
|
|
|
58
60
|
- **Links** — `fg.link` / `fg.linkHover` (blue ink, #48607A / #AFC7E1), in chat
|
|
59
61
|
messages, markdown and app copy alike. Never ink-black or coral for a link.
|
|
60
|
-
- **Data visualisation** — usage/share bars, single-measure bar
|
|
61
|
-
|
|
62
|
-
rainbow and never a grey ramp. Steps differ in lightness only (the
|
|
63
|
-
`blue.base` is left out)
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
- **Data visualisation** — usage/share bars, single-measure bar charts, maps,
|
|
63
|
+
heatmaps, progress-by-share: the `data.*` ramp, a **blue monochrome ramp**,
|
|
64
|
+
never a rainbow and never a grey ramp. Steps differ in lightness only (the
|
|
65
|
+
saturated `blue.base` is left out). **The higher number is the larger value**:
|
|
66
|
+
`data.4` is the strongest step in both modes (dark mode flips the lightness,
|
|
67
|
+
so `data.4` is the lightest blue there).
|
|
68
|
+
- **Lines** — a single-measure line chart, and series 1 of a multi-series one,
|
|
69
|
+
stroke in `blue.base` (`#4674A4` / `#6892BD`, ≥ 4.5:1). A 2px line is not a
|
|
70
|
+
filled area: the ramp's darkest step `blue.ink` reads as slate grey at that
|
|
71
|
+
width, so lines take the saturated blue the ramp leaves out.
|
|
72
|
+
|
|
73
|
+
| Token | Light | Dark |
|
|
66
74
|
| --- | --- | --- |
|
|
67
|
-
|
|
|
68
|
-
|
|
|
69
|
-
|
|
|
70
|
-
|
|
|
71
|
-
|
|
72
|
-
Pick each label by measured contrast (≥ 4.5:1), not by step number.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
| `data.4` (largest) | `#48607A` (`blue.ink`) · white label | `#AFC7E1` (`blue.inkDark`) · ink label |
|
|
76
|
+
| `data.3` | `#7492B3` (`dataviz.blueMid`) · ink label | `#7492B3` · ink label |
|
|
77
|
+
| `data.2` | `#AFC7E1` (`blue.inkDark`) · ink label | `#48607A` (`blue.ink`) · white label |
|
|
78
|
+
| `data.1` (smallest) | `#DFEBF9` (`blue.surface`) · ink label | `#232F3D` (`blue.surfaceDark`) · white label |
|
|
79
|
+
|
|
80
|
+
Pick each label by measured contrast (≥ 4.5:1), not by step number. Ink is
|
|
81
|
+
`#252525`, white is `#FFFFFF`, in either mode; `contrast.test.ts` re-measures
|
|
82
|
+
every label in this section, including the diverging table below.
|
|
83
|
+
|
|
84
|
+
A chart that must tell several *categories* apart (multi-series lines) starts
|
|
85
|
+
with the same data blue (`blue.base`) and then cycles `CHART_SERIES_HUES` in
|
|
86
|
+
`LineGraph/seriesColors.ts` (teal, pink, indigo, purple, brown, …), which
|
|
87
|
+
leaves red, yellow and green out so no series reads as a status.
|
|
76
88
|
`info` is also blue; status always comes with an icon and words, so a blue
|
|
77
89
|
chart is never mistaken for an info notice.
|
|
78
90
|
|
|
91
|
+
### Diverging: above and below a baseline
|
|
92
|
+
|
|
93
|
+
When the value has a **real zero or baseline** and both directions mean
|
|
94
|
+
something — actual vs plan, this month vs the average, change since last
|
|
95
|
+
week — use the `diverging.*` ramp. A one-sided value (a count, a share, a
|
|
96
|
+
usage total) keeps `data.*`, even if some bars are small.
|
|
97
|
+
|
|
98
|
+
- **Blue is above the baseline, orange is below** (`diverging.pos.*` /
|
|
99
|
+
`diverging.neg.*`). `3` is the largest distance from the baseline on either
|
|
100
|
+
side, and the two sides share their lightness per step, so the same
|
|
101
|
+
distance looks the same size in both directions.
|
|
102
|
+
- **The baseline itself is `diverging.mid`** (neutral step 3, so it follows
|
|
103
|
+
the neutral scheme). Never white or `bg.canvas`: a "no change" cell must
|
|
104
|
+
still read as a cell.
|
|
105
|
+
- **Never red and green for direction.** Above/below is not good/bad. When a
|
|
106
|
+
direction is good or bad, that is a status: say it with an icon and words,
|
|
107
|
+
as everywhere else.
|
|
108
|
+
- **Orange is for fills only** — bars, cells, areas. Never orange text or
|
|
109
|
+
icons; labels and axis text stay `fg.*`. Lines keep the stroke rules
|
|
110
|
+
above.
|
|
111
|
+
- **The legend names the direction in words** ("above plan" / "below plan"),
|
|
112
|
+
not only with the two colours.
|
|
113
|
+
|
|
114
|
+
| Token | Light | Dark |
|
|
115
|
+
| --- | --- | --- |
|
|
116
|
+
| `diverging.pos.3` (far above) | `#2C5D91` · white label | `#A9C7EB` · ink label |
|
|
117
|
+
| `diverging.pos.2` | `#5890CD` · ink label | `#5890CD` · ink label |
|
|
118
|
+
| `diverging.pos.1` (just above) | `#A9C7EB` · ink label | `#2C5D91` · white label |
|
|
119
|
+
| `diverging.mid` (at the baseline) | `#EDE9E2` (`neutral.3`) · ink label | `#38332E` (`neutral.3`) · white label |
|
|
120
|
+
| `diverging.neg.1` (just below) | `#E4BBA0` · ink label | `#85491A` · white label |
|
|
121
|
+
| `diverging.neg.2` | `#BF7946` · **no in-cell label**; label outside the mark | `#BF7946` · **no in-cell label**; label outside the mark |
|
|
122
|
+
| `diverging.neg.3` (far below) | `#85491A` · white label | `#E4BBA0` · ink label |
|
|
123
|
+
|
|
124
|
+
`diverging.neg.2` clears neither label (ink 4.41:1, white 3.48:1), so values
|
|
125
|
+
for that step go beside or above the bar, not inside it. The `diverging.mid`
|
|
126
|
+
values shown are the `ink` scheme; with `neutral: 'slate'` it is slate step 3.
|
|
127
|
+
|
|
128
|
+
The diverging ramp is a dedicated data-viz ramp (OKLCH chroma ≈ 0.10–0.11 at
|
|
129
|
+
steps 2–3, 0.06 at step 1, the same on both sides): paired with the dusty
|
|
130
|
+
`data.*` blue (≈ 0.05), any warm hue reads as brown. Blue ↔ orange
|
|
131
|
+
also keeps the widest colour-blind separation of the pairs considered; gold
|
|
132
|
+
reads as a warning and purple collapses into blue for deuteranopes.
|
|
133
|
+
|
|
134
|
+
`data.*` and `diverging.*` are fills: under high contrast they keep their
|
|
135
|
+
value (like `bg.track`), and in-cell labels are audited at 4.5:1 in light and
|
|
136
|
+
dark.
|
|
137
|
+
|
|
79
138
|
## Modes
|
|
80
139
|
|
|
81
140
|
Every role flips with the colour mode (`_light` / `_dark`) and has a
|
package/src/theme/claude.md
CHANGED
|
@@ -143,11 +143,11 @@ is the maintainer's view.
|
|
|
143
143
|
|
|
144
144
|
### Layers and files
|
|
145
145
|
|
|
146
|
-
| Layer
|
|
147
|
-
|
|
|
148
|
-
| Raw scales `ink`/`inkDark`, `sand`/`sandDark`, `slate`/`slateDark` (1–12), `coral`, 12 system hues `{base, baseDark, hc, hcDark, surface, ink, surfaceDark, inkDark}`
|
|
149
|
-
| Semantic steps `neutral.1–12`, `secondary.1–12`
|
|
150
|
-
| Roles (`bg.*`, `layer.*`, `fg.*`, `border.*`, `primary.*`, `secondary.*`, `action.*`, `send.*`, `count.*`, `disabled.*`, `focus.ring`, status, `tooltip.*`, `category.*`) | `ROLE_TOKEN_PATHS` + `createSemanticColors()` | The only colours a component reads |
|
|
146
|
+
| Layer | Where | Rule |
|
|
147
|
+
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------- |
|
|
148
|
+
| Raw scales `ink`/`inkDark`, `sand`/`sandDark`, `slate`/`slateDark` (1–12), `coral`, 12 system hues `{base, baseDark, hc, hcDark, surface, ink, surfaceDark, inkDark}`, `dataviz` | `palette.generated.ts` → `colors` in `colors.ts` | Components and recipes **never** read them |
|
|
149
|
+
| Semantic steps `neutral.1–12`, `secondary.1–12` | `createSemanticColors()` | Filled by the theme option (`neutral: 'ink' \| 'slate'`, `secondary: 'sand'`) |
|
|
150
|
+
| Roles (`bg.*`, `layer.*`, `fg.*`, `border.*`, `primary.*`, `secondary.*`, `action.*`, `send.*`, `count.*`, `disabled.*`, `focus.ring`, status, `tooltip.*`, `category.*`, `data.*`, `diverging.*`) | `ROLE_TOKEN_PATHS` + `createSemanticColors()` | The only colours a component reads |
|
|
151
151
|
|
|
152
152
|
- **Values come from the generator.** `scripts/palette/generate.mjs` ports the
|
|
153
153
|
designer prototype (OKLCH, contrast-targeted steps) and `--check`s it against
|
|
@@ -166,8 +166,9 @@ _moreContrast }`) because Chakra cannot nest `_dark` inside `_moreContrast`
|
|
|
166
166
|
### Adding or changing a token
|
|
167
167
|
|
|
168
168
|
1. Add it to the generator (`buildScheme`) and to `PATHS` in `colors.ts`.
|
|
169
|
-
2. Register its contrast pair(s) in `contrast.test.ts` (`PAIRS`, `SEP
|
|
170
|
-
|
|
169
|
+
2. Register its contrast pair(s) in `contrast.test.ts` (`PAIRS`, `SEP`; a
|
|
170
|
+
data-viz fill goes in `DATA_VIZ_LABELS` (`paletteSwatches.ts`) with its in-cell label), or a reason in
|
|
171
|
+
`NO_PAIR`. The registry test fails until you do; the audit runs
|
|
171
172
|
light / dark / hcLight / hcDark for every neutral scheme.
|
|
172
173
|
3. Add it to `SemanticColorToken` and to SemanticTokens.mdx.
|
|
173
174
|
|
|
@@ -250,8 +251,13 @@ follow the scheme and high contrast. Base font size is 14px.
|
|
|
250
251
|
badges/tags, the modal header band), never rows or panels.
|
|
251
252
|
5. Disabled = `disabled.*`, not opacity. Focus = `focusRing`.
|
|
252
253
|
6. Blue means data and links: links are `fg.link`; data visualisation
|
|
253
|
-
(usage bars, single-measure charts, maps)
|
|
254
|
-
rainbow or grey ramp
|
|
254
|
+
(usage bars, single-measure bar charts, maps) fills with `data.1–4` (4 =
|
|
255
|
+
largest), never a rainbow or grey ramp; line strokes (single-measure, and
|
|
256
|
+
series 1) use `blue.base`. Values against a real baseline (vs plan, vs
|
|
257
|
+
average) fill with `diverging.pos.1–3` (above, blue) / `diverging.neg.1–3`
|
|
258
|
+
(below, orange) and `diverging.mid` at the baseline — never red/green for
|
|
259
|
+
direction, never orange text or icons. Values and labels:
|
|
260
|
+
SemanticTokens.mdx → "Blue means data and links".
|
|
255
261
|
|
|
256
262
|
## Extending the Theme
|
|
257
263
|
|