twico-ui 1.42.0 → 1.43.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/CHANGELOG.md +34 -0
- package/dist/index.cjs +1341 -962
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +111 -13
- package/dist/index.d.ts +111 -13
- package/dist/index.mjs +1341 -962
- package/dist/index.mjs.map +1 -1
- package/llms.txt +35 -12
- package/package.json +7 -4
- package/styles/fonts/JetBrainsMono-Variable.woff2 +0 -0
- package/styles/fonts/PlusJakartaSans-Italic-Variable.woff2 +0 -0
- package/styles/fonts/PlusJakartaSans-Variable.woff2 +0 -0
- package/styles/twico-ui.css +95 -11
- package/styles/fonts/JetBrainsMono-Variable.ttf +0 -0
- package/styles/fonts/PlusJakartaSans-Italic-Variable.ttf +0 -0
- package/styles/fonts/PlusJakartaSans-Variable.ttf +0 -0
package/llms.txt
CHANGED
|
@@ -234,6 +234,8 @@ Props:
|
|
|
234
234
|
- `type` — `"button" | "submit" | "reset"` · default `"button"` — Native button type — use "submit" to submit a surrounding form.
|
|
235
235
|
- `disabled` — `boolean` · default `false` — Disables the control — no interaction and a dimmed appearance.
|
|
236
236
|
- `autoFocus` — `boolean` · default `false` — Focus the element automatically when it mounts.
|
|
237
|
+
- `id` — `string` — Id applied to <button>, handy for labels and aria wiring.
|
|
238
|
+
- `style` — `React.CSSProperties` — Inline styles merged onto <button> after the component's own.
|
|
237
239
|
|
|
238
240
|
```jsx
|
|
239
241
|
import { Button } from "twico-ui";
|
|
@@ -268,6 +270,8 @@ Props:
|
|
|
268
270
|
- `type` — `"button" | "submit" | "reset"` · default `"button"` — Native button type — use "submit" to submit a surrounding form.
|
|
269
271
|
- `disabled` — `boolean` · default `false` — Disables the control — no interaction and a dimmed appearance.
|
|
270
272
|
- `autoFocus` — `boolean` · default `false` — Focus the element automatically when it mounts.
|
|
273
|
+
- `id` — `string` — Id applied to <button>, handy for labels and aria wiring.
|
|
274
|
+
- `style` — `React.CSSProperties` — Inline styles merged onto <button> after the component's own.
|
|
271
275
|
|
|
272
276
|
```jsx
|
|
273
277
|
import { IconButton } from "twico-ui";
|
|
@@ -424,7 +428,7 @@ Divider is a thin separator rule that visually splits content, either horizontal
|
|
|
424
428
|
Props:
|
|
425
429
|
- `orientation` — `"horizontal" | "vertical"` · default `"horizontal"` — Direction of the separator rule, either horizontal (default) to split stacked content or vertical for inline items.
|
|
426
430
|
- `inset` — `boolean` · default `false` — Indents the start of a horizontal rule to align it with inset content like list item text.
|
|
427
|
-
- `align` — `"left" | "center" | "right" | "start" | "end"` · default `"center"` — Label alignment when children are provided; logical start/end
|
|
431
|
+
- `align` — `"left" | "center" | "right" | "start" | "end"` · default `"center"` — Label alignment when children are provided; prefer the logical "start"/"end" so the label mirrors under dir="rtl" ("left"/"right" still accepted).
|
|
428
432
|
- `children` — `React.ReactNode` — Optional label text rendered within the rule, such as "OR", to break content with a caption.
|
|
429
433
|
|
|
430
434
|
```jsx
|
|
@@ -523,7 +527,7 @@ Heading (h1–h6) with consistent token typography. Use it instead of bare headi
|
|
|
523
527
|
Props:
|
|
524
528
|
- `level` — `1 | 2 | 3 | 4 | 5 | 6` · default `2` — Chooses which h1-h6 tag renders and its default token size, keeping document hierarchy and typography consistent.
|
|
525
529
|
- `size` — `string` — Overrides the font-size token suffix (e.g. "3xl") to decouple visual scale from the semantic heading level.
|
|
526
|
-
- `align` — `string` — Sets the CSS text-align value
|
|
530
|
+
- `align` — `string` — Sets the CSS text-align value; prefer the logical "start"/"end" over "left"/"right" so the heading mirrors under dir="rtl".
|
|
527
531
|
- `as` — `ElementType` — Renders a different tag while preserving the level's size, useful when semantics and visual weight should differ.
|
|
528
532
|
- `sx` — `Sx` — Style escape hatch: flat CSS goes inline (wins over base); nested selectors/at-rules like "&:hover" or "@media …" compile to a scoped stylesheet.
|
|
529
533
|
|
|
@@ -544,7 +548,7 @@ Props:
|
|
|
544
548
|
- `size` — `"xs" | "sm" | "base" | "lg" | "xl"` · default `"base"` — Picks the font-size token from xs to xl, scaling the body text to fit its context, base by default.
|
|
545
549
|
- `tone` — `"default" | "muted" | "subtle" | "primary" | "success" | "warning" | "danger" | "info" | "neutral"` · default `"default"` — Sets the text color — neutral roles (default, muted, subtle) plus the six semantic color intents.
|
|
546
550
|
- `weight` — `string` — Sets the font-weight token suffix like semibold to adjust how heavy the text appears.
|
|
547
|
-
- `align` — `string` — Sets the text-align value,
|
|
551
|
+
- `align` — `string` — Sets the text-align value: "start", "center", "end" or "justify" — prefer the logical start/end so the text mirrors under dir="rtl".
|
|
548
552
|
- `as` — `ElementType` · default `"p"` — Chooses the element or tag rendered, defaulting to p so you can swap in span or other tags.
|
|
549
553
|
- `sx` — `Sx` — Style escape hatch: flat CSS goes inline (wins over base); nested selectors/at-rules like "&:hover" or "@media …" compile to a scoped stylesheet.
|
|
550
554
|
|
|
@@ -581,6 +585,7 @@ Props:
|
|
|
581
585
|
- `readOnly` — `boolean` · default `false` — Makes the field non-editable while still focusable/selectable.
|
|
582
586
|
- `required` — `boolean` · default `false` — Marks the field required for native form validation.
|
|
583
587
|
- `autoComplete` — `string` — Browser autocomplete hint (e.g. "email", "off").
|
|
588
|
+
- `style` — `React.CSSProperties` — Inline styles merged onto <input> after the component's own.
|
|
584
589
|
|
|
585
590
|
```jsx
|
|
586
591
|
import { Checkbox } from "twico-ui";
|
|
@@ -665,6 +670,8 @@ Props:
|
|
|
665
670
|
- `name` — `string` — Form field name submitted with the value.
|
|
666
671
|
- `readOnly` — `boolean` · default `false` — Makes the field non-editable while still focusable/selectable.
|
|
667
672
|
- `autoComplete` — `string` — Browser autocomplete hint (e.g. "email", "off").
|
|
673
|
+
- `id` — `string` — Id applied to <input>, handy for labels and aria wiring.
|
|
674
|
+
- `style` — `React.CSSProperties` — Inline styles merged onto <input> after the component's own.
|
|
668
675
|
|
|
669
676
|
```jsx
|
|
670
677
|
import { Combobox } from "twico-ui";
|
|
@@ -715,6 +722,8 @@ Props:
|
|
|
715
722
|
- `disabled` — `boolean` · default `false` — Disables the control — no interaction and a dimmed appearance.
|
|
716
723
|
- `readOnly` — `boolean` · default `false` — Makes the field non-editable while still focusable/selectable.
|
|
717
724
|
- `autoComplete` — `string` — Browser autocomplete hint (e.g. "email", "off").
|
|
725
|
+
- `id` — `string` — Id applied to <input>, handy for labels and aria wiring.
|
|
726
|
+
- `style` — `React.CSSProperties` — Inline styles merged onto <input> after the component's own.
|
|
718
727
|
|
|
719
728
|
```jsx
|
|
720
729
|
import { Currency } from "twico-ui";
|
|
@@ -753,6 +762,8 @@ Props:
|
|
|
753
762
|
- `disabled` — `boolean` · default `false` — Disables the control — no interaction and a dimmed appearance.
|
|
754
763
|
- `readOnly` — `boolean` · default `false` — Makes the field non-editable while still focusable/selectable.
|
|
755
764
|
- `autoComplete` — `string` — Browser autocomplete hint (e.g. "email", "off").
|
|
765
|
+
- `id` — `string` — Id applied to <input>, handy for labels and aria wiring.
|
|
766
|
+
- `style` — `React.CSSProperties` — Inline styles merged onto <input> after the component's own.
|
|
756
767
|
|
|
757
768
|
```jsx
|
|
758
769
|
import { CurrencyField } from "twico-ui";
|
|
@@ -1030,6 +1041,8 @@ Props:
|
|
|
1030
1041
|
- `disabled` — `boolean` · default `false` — Disables the control — no interaction and a dimmed appearance.
|
|
1031
1042
|
- `readOnly` — `boolean` · default `false` — Makes the field non-editable while still focusable/selectable.
|
|
1032
1043
|
- `autoComplete` — `string` — Browser autocomplete hint (e.g. "email", "off").
|
|
1044
|
+
- `id` — `string` — Id applied to <input>, handy for labels and aria wiring.
|
|
1045
|
+
- `style` — `React.CSSProperties` — Inline styles merged onto <input> after the component's own.
|
|
1033
1046
|
|
|
1034
1047
|
```jsx
|
|
1035
1048
|
import { Input } from "twico-ui";
|
|
@@ -1079,6 +1092,8 @@ Props:
|
|
|
1079
1092
|
- `name` — `string` — Form field name submitted with the value.
|
|
1080
1093
|
- `readOnly` — `boolean` · default `false` — Makes the field non-editable while still focusable/selectable.
|
|
1081
1094
|
- `autoComplete` — `string` — Browser autocomplete hint (e.g. "email", "off").
|
|
1095
|
+
- `id` — `string` — Id applied to <input>, handy for labels and aria wiring.
|
|
1096
|
+
- `style` — `React.CSSProperties` — Inline styles merged onto <input> after the component's own.
|
|
1082
1097
|
|
|
1083
1098
|
```jsx
|
|
1084
1099
|
import { MultiSelect } from "twico-ui";
|
|
@@ -1119,6 +1134,8 @@ Props:
|
|
|
1119
1134
|
- `readOnly` — `boolean` · default `false` — Makes the field non-editable while still focusable/selectable.
|
|
1120
1135
|
- `required` — `boolean` · default `false` — Marks the field required for native form validation.
|
|
1121
1136
|
- `autoComplete` — `string` — Browser autocomplete hint (e.g. "email", "off").
|
|
1137
|
+
- `id` — `string` — Id applied to <input>, handy for labels and aria wiring.
|
|
1138
|
+
- `style` — `React.CSSProperties` — Inline styles merged onto <input> after the component's own.
|
|
1122
1139
|
|
|
1123
1140
|
```jsx
|
|
1124
1141
|
import { Radio } from "twico-ui";
|
|
@@ -1169,7 +1186,7 @@ const [r, setR] = React.useState(0);
|
|
|
1169
1186
|
|
|
1170
1187
|
#### Select
|
|
1171
1188
|
|
|
1172
|
-
A custom select that replaces the native browser dropdown with a rounded, keyboard-navigable popover, supporting grouped options and two-line (title + subtitle) options. Use it when you need a styled single-select with optional in-popover search, grouping, or descriptions.
|
|
1189
|
+
A custom select that replaces the native browser dropdown with a rounded, keyboard-navigable popover, supporting grouped options and two-line (title + subtitle) options. Use it when you need a styled single-select with optional in-popover search, grouping, or descriptions. Its trigger is exposed as the WAI-ARIA select-only combobox (role="combobox" with aria-haspopup="listbox"), as MUI's Select also is, so query it by the combobox role rather than by button — and give it a label, since that role takes its name from the label rather than from the selected value.
|
|
1173
1190
|
|
|
1174
1191
|
`import { Select } from "twico-ui"`
|
|
1175
1192
|
|
|
@@ -1288,6 +1305,8 @@ Props:
|
|
|
1288
1305
|
- `readOnly` — `boolean` · default `false` — Makes the field non-editable while still focusable/selectable.
|
|
1289
1306
|
- `required` — `boolean` · default `false` — Marks the field required for native form validation.
|
|
1290
1307
|
- `autoComplete` — `string` — Browser autocomplete hint (e.g. "email", "off").
|
|
1308
|
+
- `id` — `string` — Id applied to <input>, handy for labels and aria wiring.
|
|
1309
|
+
- `style` — `React.CSSProperties` — Inline styles merged onto <input> after the component's own.
|
|
1291
1310
|
|
|
1292
1311
|
```jsx
|
|
1293
1312
|
import { Switch } from "twico-ui";
|
|
@@ -1326,6 +1345,8 @@ Props:
|
|
|
1326
1345
|
- `rows` — `number` — Visible number of text rows.
|
|
1327
1346
|
- `disabled` — `boolean` · default `false` — Disables the control — no interaction and a dimmed appearance.
|
|
1328
1347
|
- `readOnly` — `boolean` · default `false` — Makes the field non-editable while still focusable/selectable.
|
|
1348
|
+
- `id` — `string` — Id applied to <textarea>, handy for labels and aria wiring.
|
|
1349
|
+
- `style` — `React.CSSProperties` — Inline styles merged onto <textarea> after the component's own.
|
|
1329
1350
|
|
|
1330
1351
|
```jsx
|
|
1331
1352
|
import { Textarea } from "twico-ui";
|
|
@@ -2671,6 +2692,8 @@ Props:
|
|
|
2671
2692
|
- `open` — `string[]` — Controlled open panel values; pair with onOpenChange. When set, internal state is bypassed and defaultOpen is ignored.
|
|
2672
2693
|
- `onOpenChange` — `(values: string[]) => void` — Called with the next open values whenever a panel trigger is toggled (fires in both controlled and uncontrolled modes).
|
|
2673
2694
|
- `headingLevel` — `1 | 2 | 3 | 4 | 5 | 6` · default `3` — Heading level wrapping each trigger button (document-outline semantics).
|
|
2695
|
+
- `mountOnOpen` — `boolean` · default `false` — Render each panel's content only after its first open, then keep it mounted - cuts the DOM and hook cost of a page full of collapsed panels.
|
|
2696
|
+
- `unmountOnClose` — `boolean` · default `false` — Also unmount a panel's content when it closes, waiting out the collapse animation first. Implies mountOnOpen.
|
|
2674
2697
|
|
|
2675
2698
|
```jsx
|
|
2676
2699
|
import { Accordion } from "twico-ui";
|
|
@@ -2741,7 +2764,7 @@ Props:
|
|
|
2741
2764
|
import { Navbar } from "twico-ui";
|
|
2742
2765
|
|
|
2743
2766
|
<Navbar
|
|
2744
|
-
brand={<>Twico <span style={{ color: "var(--color-primary)" }}>UI</span></>}
|
|
2767
|
+
brand={<>Twico <span style={{ color: "var(--color-primary-subtle-fg)" }}>UI</span></>}
|
|
2745
2768
|
links={[
|
|
2746
2769
|
{ label: "Dashboard", active: true },
|
|
2747
2770
|
{ label: "Projects" },
|
|
@@ -2779,7 +2802,7 @@ const MailIcon = () => (<svg width="18" height="18" viewBox="0 0 24 24" fill="no
|
|
|
2779
2802
|
const CogIcon = () => (<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><circle cx="12" cy="12" r="3" /><path d="M12 3v3M12 18v3M3 12h3M18 12h3" /></svg>);
|
|
2780
2803
|
|
|
2781
2804
|
<Sidebar
|
|
2782
|
-
brand={<>Twico <span style={{ color: "var(--color-primary)" }}>UI</span></>}
|
|
2805
|
+
brand={<>Twico <span style={{ color: "var(--color-primary-subtle-fg)" }}>UI</span></>}
|
|
2783
2806
|
items={[
|
|
2784
2807
|
{ section: "Main" },
|
|
2785
2808
|
{ label: "Dashboard", icon: <HomeIcon />, active: true },
|
|
@@ -3018,7 +3041,7 @@ Menu is a portaled dropdown menu that takes a clickable trigger and an array of
|
|
|
3018
3041
|
`import { Menu } from "twico-ui"`
|
|
3019
3042
|
|
|
3020
3043
|
Props:
|
|
3021
|
-
- `trigger` — `React.ReactNode` · **required** — Defines the clickable element that opens the menu, typically a Button or IconButton the dropdown anchors to.
|
|
3044
|
+
- `trigger` — `React.ReactNode` · **required** — Defines the clickable element that opens the menu, typically a Button or IconButton the dropdown anchors to. Pass a single focusable control (a Button/IconButton): the element is cloned to carry tabIndex/aria-expanded, which are only valid on a control, and wrapping the real button to overlay a badge gives two tab stops - put the decoration outside. A wrapping Tooltip goes outside this component.
|
|
3022
3045
|
- `items` — `MenuItemDef[]` · **required** — Lists the menu entries, where each can be an action item, a separator, or a section heading.
|
|
3023
3046
|
- `align` — `"start" | "end"` · default `"start"` — Aligns the menu horizontally to the trigger's start or end edge so it sits flush in tight layouts; defaults to start.
|
|
3024
3047
|
- `header` — `React.ReactNode` — Renders an optional rich node above the items, handy for surfacing user info or context at the top of the menu.
|
|
@@ -3050,7 +3073,7 @@ Popover is a click-triggered floating panel anchored to a trigger element, rende
|
|
|
3050
3073
|
`import { Popover } from "twico-ui"`
|
|
3051
3074
|
|
|
3052
3075
|
Props:
|
|
3053
|
-
- `trigger` — `React.ReactNode` · **required** — The clickable element the panel anchors to; clicking it toggles the popover open and closed.
|
|
3076
|
+
- `trigger` — `React.ReactNode` · **required** — The clickable element the panel anchors to; clicking it toggles the popover open and closed. Pass a single focusable control (a Button/IconButton): the element is cloned to carry tabIndex/aria-expanded, which are only valid on a control, and wrapping the real button to overlay a badge gives two tab stops - put the decoration outside. A wrapping Tooltip goes outside this component.
|
|
3054
3077
|
- `title` — `React.ReactNode` — Optional bold heading rendered at the top of the panel to introduce its interactive content.
|
|
3055
3078
|
- `placement` — `"top" | "bottom" | "left" | "right"` · default `"bottom"` — Which side of the trigger the panel opens toward (top, bottom, left, or right), auto-flipping near viewport edges.
|
|
3056
3079
|
- `align` — `"start" | "center" | "end"` · default `"center"` — Cross-axis alignment (start, center, or end) of the panel relative to the trigger for top and bottom placements.
|
|
@@ -3384,10 +3407,10 @@ export function useKeyPress( key: string | string[], handler: (event: KeyboardEv
|
|
|
3384
3407
|
|
|
3385
3408
|
### useLocalStorage
|
|
3386
3409
|
|
|
3387
|
-
State persisted to localStorage (JSON-serialized), SSR-safe.
|
|
3410
|
+
State persisted to localStorage (JSON-serialized), SSR-safe: returns `initialValue` on the server AND on the first client render, then reads storage in a layout effect before paint (#466).
|
|
3388
3411
|
|
|
3389
3412
|
```ts
|
|
3390
|
-
export function useLocalStorage<T>( key: string, initialValue: T ): [T, (value: T | ((prev: T) => T)) => void];
|
|
3413
|
+
export function useLocalStorage<T>( key: string, initialValue: T, options?: UseLocalStorageOptions ): [T, (value: T | ((prev: T) => T)) => void];
|
|
3391
3414
|
```
|
|
3392
3415
|
|
|
3393
3416
|
### useCopyToClipboard
|
|
@@ -3432,10 +3455,10 @@ export function useTimeout(callback: () => void, delay: number | null): void;
|
|
|
3432
3455
|
|
|
3433
3456
|
### useWindowSize
|
|
3434
3457
|
|
|
3435
|
-
The current window dimensions
|
|
3458
|
+
The current window dimensions. 0×0 on the server AND on the first client render, then measured in a layout effect before paint (#466) — so hydration never mismatches.
|
|
3436
3459
|
|
|
3437
3460
|
```ts
|
|
3438
|
-
export function useWindowSize(): { width: number; height: number };
|
|
3461
|
+
export function useWindowSize(options?: UseWindowSizeOptions): { width: number; height: number };
|
|
3439
3462
|
```
|
|
3440
3463
|
|
|
3441
3464
|
### useHover
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "twico-ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.43.0",
|
|
4
4
|
"description": "Twico UI — a free, modern, themeable React + Tailwind-friendly component library. 61 components with dark mode, motion, and accessibility built in.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Twico UI",
|
|
@@ -78,6 +78,8 @@
|
|
|
78
78
|
"build": "tsup",
|
|
79
79
|
"build:css": "node scripts/build-css.mjs",
|
|
80
80
|
"build:css:check": "node scripts/build-css.mjs --check",
|
|
81
|
+
"build:fonts": "node scripts/build-fonts.mjs",
|
|
82
|
+
"build:fonts:check": "node scripts/build-fonts.mjs --check",
|
|
81
83
|
"verify:palette": "node scripts/verify-palette.mjs",
|
|
82
84
|
"gen:llms": "node scripts/gen-llms.mjs",
|
|
83
85
|
"gen:llms:check": "node scripts/gen-llms.mjs --check",
|
|
@@ -108,7 +110,7 @@
|
|
|
108
110
|
"@arethetypeswrong/cli": "^0.18.5",
|
|
109
111
|
"@semantic-release/changelog": "^7.0.0",
|
|
110
112
|
"@semantic-release/git": "^11.0.1",
|
|
111
|
-
"@size-limit/preset-small-lib": "^
|
|
113
|
+
"@size-limit/preset-small-lib": "^14.0.0",
|
|
112
114
|
"@testing-library/jest-dom": "^7.0.1",
|
|
113
115
|
"@testing-library/react": "^16.1.0",
|
|
114
116
|
"@testing-library/user-event": "^14.6.3",
|
|
@@ -117,10 +119,11 @@
|
|
|
117
119
|
"jsdom": "^30.0.1",
|
|
118
120
|
"lucide-react": "^1.31.0",
|
|
119
121
|
"semantic-release": "^25.0.9",
|
|
120
|
-
"size-limit": "^
|
|
122
|
+
"size-limit": "^14.0.0",
|
|
121
123
|
"tsup": "^8.3.5",
|
|
122
124
|
"typescript": "^5.9.3",
|
|
123
|
-
"vitest": "^5.0.0"
|
|
125
|
+
"vitest": "^5.0.0",
|
|
126
|
+
"wawoff2": "^2.0.1"
|
|
124
127
|
},
|
|
125
128
|
"size-limit": [
|
|
126
129
|
{
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/styles/twico-ui.css
CHANGED
|
@@ -13,11 +13,13 @@
|
|
|
13
13
|
Twico UI — Webfonts (self-hosted, OFL licensed)
|
|
14
14
|
Plus Jakarta Sans (UI) + JetBrains Mono (code).
|
|
15
15
|
Variable fonts: one file covers weights 200–800.
|
|
16
|
+
#450: shipped as WOFF2 - brotli-compressed inside the container, so the saving no longer
|
|
17
|
+
depends on the host compressing font/ttf. Generated by `npm run build:fonts` (committed).
|
|
16
18
|
============================================================ */
|
|
17
19
|
|
|
18
20
|
@font-face {
|
|
19
21
|
font-family: "Plus Jakarta Sans";
|
|
20
|
-
src: url("./fonts/PlusJakartaSans-Variable.
|
|
22
|
+
src: url("./fonts/PlusJakartaSans-Variable.woff2") format("woff2");
|
|
21
23
|
font-weight: 200 800;
|
|
22
24
|
font-style: normal;
|
|
23
25
|
font-display: swap;
|
|
@@ -25,7 +27,7 @@
|
|
|
25
27
|
|
|
26
28
|
@font-face {
|
|
27
29
|
font-family: "Plus Jakarta Sans";
|
|
28
|
-
src: url("./fonts/PlusJakartaSans-Italic-Variable.
|
|
30
|
+
src: url("./fonts/PlusJakartaSans-Italic-Variable.woff2") format("woff2");
|
|
29
31
|
font-weight: 200 800;
|
|
30
32
|
font-style: italic;
|
|
31
33
|
font-display: swap;
|
|
@@ -33,7 +35,7 @@
|
|
|
33
35
|
|
|
34
36
|
@font-face {
|
|
35
37
|
font-family: "JetBrains Mono";
|
|
36
|
-
src: url("./fonts/JetBrainsMono-Variable.
|
|
38
|
+
src: url("./fonts/JetBrainsMono-Variable.woff2") format("woff2");
|
|
37
39
|
font-weight: 100 800;
|
|
38
40
|
font-style: normal;
|
|
39
41
|
font-display: swap;
|
|
@@ -152,16 +154,38 @@
|
|
|
152
154
|
/* Borders & dividers */
|
|
153
155
|
--color-border: var(--slate-200);
|
|
154
156
|
--color-border-strong: var(--slate-300);
|
|
157
|
+
/* #454: the unchecked boundary of Checkbox/Radio/Switch is the ONLY indication the control
|
|
158
|
+
exists, so SC 1.4.11 requires 3:1 against the surface. border-strong is 1.49:1. This step
|
|
159
|
+
clears it in both themes (4.76:1 on white, 6.96:1 on the dark surface) without touching
|
|
160
|
+
card/divider borders. */
|
|
161
|
+
--color-control-border: var(--slate-500);
|
|
162
|
+
/* #454 (review): a Switch track is NOT the same problem as a checkbox border. Its white thumb is
|
|
163
|
+
what identifies the control - except in light mode, where a white thumb on a white surface is
|
|
164
|
+
invisible and the track has to carry it. So light needs a dark track (4.76:1 on the surface, and
|
|
165
|
+
4.76:1 against the thumb)... */
|
|
166
|
+
--color-control-track: var(--slate-500);
|
|
167
|
+
/* #454 (review): the OFF thumb, deliberately STATIC in both themes (like --color-chart-on-fill).
|
|
168
|
+
It used to be --_accent-fg, i.e. the tone's ON-state ink - which is designed to sit on the tone
|
|
169
|
+
FILL, not on a neutral track. For five of the six tones that ink is near-black (success #052e1d,
|
|
170
|
+
info sky-950, warning amber-950, danger's dark variant, and neutral = --color-surface), so on the
|
|
171
|
+
dark track nothing in the control cleared 3:1 and an unchecked success Switch simply vanished -
|
|
172
|
+
the very SC 1.4.11 failure #454 was filed for, reintroduced for 5/6 tones while fixing primary.
|
|
173
|
+
A fixed light thumb resolves against BOTH tracks (4.76:1 on slate-500, 10.35:1 on slate-700) for
|
|
174
|
+
every tone, and the ON state keeps --_accent-fg, which is token-paired with its own fill. */
|
|
175
|
+
--color-control-thumb: #ffffff;
|
|
155
176
|
--color-divider: var(--slate-200);
|
|
156
177
|
|
|
157
178
|
/* Text */
|
|
158
179
|
--color-text: var(--slate-900);
|
|
159
180
|
--color-text-muted: var(--slate-600);
|
|
160
|
-
--color-text-subtle: var(--slate-
|
|
181
|
+
--color-text-subtle: var(--slate-500);
|
|
161
182
|
--color-text-inverted: #ffffff;
|
|
162
183
|
|
|
163
184
|
/* Data labels painted ON coloured chart marks (pie/donut slices, treemap tiles,
|
|
164
|
-
funnel stages).
|
|
185
|
+
funnel stages). #455 made the mark fills theme-aware (--color-chart-1..7), but these two stay
|
|
186
|
+
static on purpose: the fills still span a wide lightness range in BOTH themes, so a theme-aware
|
|
187
|
+
label colour would wash out on the light ones and invert on the dark ones. Historically the
|
|
188
|
+
comment here said the fills were fixed -500 primitives that DON'T flip with
|
|
165
189
|
theme, so these must stay static too (they are intentionally NOT re-declared in
|
|
166
190
|
.dark): a light fill + a translucent dark halo — applied via `paint-order:
|
|
167
191
|
stroke` — keeps the text legible on any slice colour, including light ones like
|
|
@@ -186,26 +210,51 @@
|
|
|
186
210
|
--color-success: var(--emerald-600);
|
|
187
211
|
--color-success-fg: #ffffff;
|
|
188
212
|
--color-success-subtle: var(--emerald-50);
|
|
189
|
-
--color-success-subtle-fg: var(--emerald-
|
|
213
|
+
--color-success-subtle-fg: var(--emerald-700);
|
|
190
214
|
|
|
191
215
|
/* Warning */
|
|
192
216
|
--color-warning: var(--amber-500);
|
|
193
217
|
--color-warning-fg: var(--amber-950); /* dark ink on amber-500 = 6.97:1 (white was 2.15:1) */
|
|
194
218
|
--color-warning-subtle: var(--amber-50);
|
|
195
|
-
--color-warning-subtle-fg: var(--amber-
|
|
219
|
+
--color-warning-subtle-fg: var(--amber-700);
|
|
196
220
|
|
|
197
221
|
/* Danger */
|
|
198
222
|
--color-danger: var(--rose-500);
|
|
199
223
|
--color-danger-hover: var(--rose-600);
|
|
200
224
|
--color-danger-fg: #ffffff;
|
|
201
225
|
--color-danger-subtle: var(--rose-50);
|
|
202
|
-
--color-danger-subtle-fg: var(--rose-
|
|
226
|
+
--color-danger-subtle-fg: var(--rose-700);
|
|
203
227
|
|
|
204
228
|
/* Info */
|
|
205
229
|
--color-info: var(--sky-500);
|
|
206
230
|
--color-info-fg: var(--sky-950); /* dark ink on sky-500 (white was 2.77:1) */
|
|
207
231
|
--color-info-subtle: var(--sky-50);
|
|
208
|
-
--color-info-subtle-fg: var(--sky-
|
|
232
|
+
--color-info-subtle-fg: var(--sky-700);
|
|
233
|
+
|
|
234
|
+
/* #455: GRAPHIC tone colours — for a fill or stroke that is itself the information (a Progress
|
|
235
|
+
bar, a Toast edge stripe, a status icon). SC 1.4.11 wants 3:1 for those, and the light-mode
|
|
236
|
+
tone colours miss it: amber-500 is 1.96:1 on surface-sunken and sky-500 2.53:1. These steps
|
|
237
|
+
clear 3:1 on BOTH --color-surface (#fff) and --color-surface-sunken (slate-100) with margin
|
|
238
|
+
— 4.1:1 at worst — and keep the five tones at a consistent lightness so a tone switch does
|
|
239
|
+
not change the weight of the control. Use the plain tone for fills that carry text on top
|
|
240
|
+
(they are paired with --color-*-fg); use these when the colour stands alone. */
|
|
241
|
+
--color-primary-graphic: var(--brand-500); /* 4.47 / 4.08 — unchanged, listed for symmetry */
|
|
242
|
+
--color-success-graphic: var(--emerald-700); /* 5.48 / 5.01 */
|
|
243
|
+
--color-warning-graphic: var(--amber-700); /* 5.02 / 4.58 */
|
|
244
|
+
--color-danger-graphic: var(--rose-600); /* 4.70 / 4.29 */
|
|
245
|
+
--color-info-graphic: var(--sky-600); /* 4.10 / 3.74 */
|
|
246
|
+
|
|
247
|
+
/* #455: the chart series ramp. Was seven primitives inlined in _chart.js, where slots 1 and 6
|
|
248
|
+
were BOTH indigo-500 (--brand-500 aliases it) — two series rendered identically, 1.00:1. As
|
|
249
|
+
tokens they also flip per theme, so a series fill is never below 3:1 on its own surface:
|
|
250
|
+
light bottoms out at 4.08:1, and the closest pair is 23.8 ΔE76 apart. */
|
|
251
|
+
--color-chart-1: var(--indigo-500);
|
|
252
|
+
--color-chart-2: var(--sky-700);
|
|
253
|
+
--color-chart-3: var(--emerald-700);
|
|
254
|
+
--color-chart-4: var(--amber-700);
|
|
255
|
+
--color-chart-5: var(--rose-600);
|
|
256
|
+
--color-chart-6: var(--indigo-900);
|
|
257
|
+
--color-chart-7: var(--slate-500);
|
|
209
258
|
}
|
|
210
259
|
|
|
211
260
|
/* ============================================================
|
|
@@ -224,11 +273,19 @@
|
|
|
224
273
|
|
|
225
274
|
--color-border: #25324a;
|
|
226
275
|
--color-border-strong: var(--slate-700);
|
|
276
|
+
--color-control-border: var(--slate-400);
|
|
277
|
+
/* ...while dark must go the OTHER way: on a dark surface the white thumb already reads at 10.35:1
|
|
278
|
+
against this track and ~14:1 against the surface, so the control is unmistakable, and lightening
|
|
279
|
+
the track to match --color-control-border would have dropped thumb-vs-track to 2.56:1 - trading
|
|
280
|
+
one 1.4.11 failure for another. On/off is carried by thumb POSITION, so SC 1.4.1 is satisfied
|
|
281
|
+
without colour either way. */
|
|
282
|
+
--color-control-track: var(--slate-700);
|
|
283
|
+
--color-control-thumb: #ffffff; /* static: see the :root note */
|
|
227
284
|
--color-divider: #1c2840;
|
|
228
285
|
|
|
229
286
|
--color-text: var(--slate-50);
|
|
230
287
|
--color-text-muted: var(--slate-300);
|
|
231
|
-
--color-text-subtle: var(--slate-
|
|
288
|
+
--color-text-subtle: var(--slate-400);
|
|
232
289
|
--color-text-inverted: var(--slate-900);
|
|
233
290
|
|
|
234
291
|
--color-primary: var(--brand-500);
|
|
@@ -261,6 +318,33 @@
|
|
|
261
318
|
--color-info-fg: #04212f;
|
|
262
319
|
--color-info-subtle: rgb(14 165 233 / 0.15);
|
|
263
320
|
--color-info-subtle-fg: var(--sky-400);
|
|
321
|
+
|
|
322
|
+
/* #455: dark already clears 3:1 for every tone on slate-900 (6.4:1 and up), so these are the tone
|
|
323
|
+
values themselves - but written as PRIMITIVES, not as var(--color-warning).
|
|
324
|
+
#455 (review): aliasing the tone here while light named a primitive made the family behave
|
|
325
|
+
differently per theme - a consumer overriding --color-warning saw the Progress bar follow in dark
|
|
326
|
+
and not in light. Naming primitives in both scopes puts -graphic on exactly the same footing as
|
|
327
|
+
-fg / -subtle / -subtle-fg / -border: one more member of the per-tone derivative family that a
|
|
328
|
+
re-skin overrides together (which is what the docs-site Theme builder demonstrates). */
|
|
329
|
+
--color-primary-graphic: var(--brand-500);
|
|
330
|
+
--color-success-graphic: var(--emerald-500);
|
|
331
|
+
--color-warning-graphic: var(--amber-500);
|
|
332
|
+
--color-danger-graphic: var(--rose-500);
|
|
333
|
+
--color-info-graphic: var(--sky-500);
|
|
334
|
+
|
|
335
|
+
/* #455: dark keeps the ORIGINAL 500 steps. Dark mode never had the contrast problem (3.07:1 at
|
|
336
|
+
worst against surface-raised, 6.4:1+ on the surface itself), and the on-slice data labels in
|
|
337
|
+
PieChart/DonutChart/Treemap/FunnelChart are a static white fill + dark halo tuned against these
|
|
338
|
+
exact fills (see docs/charts.md) - lightening them would weaken that for no gain. Only slot 6
|
|
339
|
+
changes, from the indigo-500 that duplicated slot 1 to indigo-300: 25.7 ΔE76 from slot 1, and a
|
|
340
|
+
white-on-slice ratio in line with the amber-500 slice the label design already handles. */
|
|
341
|
+
--color-chart-1: var(--indigo-500);
|
|
342
|
+
--color-chart-2: var(--sky-500);
|
|
343
|
+
--color-chart-3: var(--emerald-500);
|
|
344
|
+
--color-chart-4: var(--amber-500);
|
|
345
|
+
--color-chart-5: var(--rose-500);
|
|
346
|
+
--color-chart-6: var(--indigo-300);
|
|
347
|
+
--color-chart-7: var(--slate-500);
|
|
264
348
|
}
|
|
265
349
|
|
|
266
350
|
/* ===== tokens/typography.css ===== */
|
|
@@ -552,7 +636,7 @@ h1, h2, h3, h4, h5, h6 {
|
|
|
552
636
|
p { margin: 0; }
|
|
553
637
|
|
|
554
638
|
a {
|
|
555
|
-
color: var(--color-primary);
|
|
639
|
+
color: var(--color-primary-subtle-fg);
|
|
556
640
|
text-decoration: none;
|
|
557
641
|
transition: color var(--duration-fast) var(--ease-standard);
|
|
558
642
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|