basalt-ui 1.40.2 → 1.40.3
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 +9 -0
- package/MIGRATING.md +16 -12
- package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
- package/dist/charts/primitives/HoverOverlay.js +2 -1
- package/dist/commands/shortcut-format.d.ts +9 -4
- package/dist/commands/shortcut-format.d.ts.map +1 -1
- package/dist/commands/shortcut-format.js +35 -5
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +14 -1
- package/dist/theme/segmented-control.module.css +8 -0
- package/dist/tokens/derive.d.ts.map +1 -1
- package/dist/tokens/derive.js +3 -1
- package/dist/tokens.css +1 -1
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/src/charts/primitives/HoverOverlay.tsx +2 -1
- package/src/commands/shortcut-format.ts +49 -10
- package/src/theme/index.ts +17 -1
- package/src/theme/segmented-control.module.css +8 -0
- package/src/tokens/derive.ts +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## [1.40.3](https://github.com/jkrumm/basalt-ui/compare/v1.40.2...v1.40.3) (2026-10-05)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* chart cursor slider always carries aria-valuenow ([e1bce15](https://github.com/jkrumm/basalt-ui/commit/e1bce15e7b280a4f203bb05173d4478c0a64c7f3))
|
|
7
|
+
* light-scheme text, links, errors and badges clear WCAG AA ([bfa4c0e](https://github.com/jkrumm/basalt-ui/commit/bfa4c0e329138daa0f6ffe7d6a9678644a1b0440))
|
|
8
|
+
* shortcut display uses platform glyphs and Title-case words for named keys ([77733e9](https://github.com/jkrumm/basalt-ui/commit/77733e916892138b42b398188f85dae234877181))
|
|
9
|
+
|
|
1
10
|
## [1.40.2](https://github.com/jkrumm/basalt-ui/compare/v1.40.1...v1.40.2) (2026-10-05)
|
|
2
11
|
|
|
3
12
|
|
package/MIGRATING.md
CHANGED
|
@@ -66,18 +66,18 @@ There is one row per SURFACE, not per export, and a surface earns a row once any
|
|
|
66
66
|
shipped lefthook preset both changed in 1.30.0 with no row that owned them — which is how a
|
|
67
67
|
consumer read this index, found nothing, and diffed a KPI row that had silently gone 4-up → 2-up.
|
|
68
68
|
|
|
69
|
-
| Surface | 1.27.0 | 1.28.0 | 1.29.0 | 1.30.0 | 1.30.1 | 1.30.2 | 1.31.0 | 1.32.0 | 1.32.1 | 1.33.0 | 1.34.0 | 1.34.1 | 1.35.0 | 1.36.0 | 1.36.1 | 1.37.0 | 1.37.1 | 1.38.0 | 1.38.1 | 1.39.0 | 1.40.0 | 1.40.1 | 1.40.2 | Unreleased |
|
|
70
|
-
| ----------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------- | ------ | ------ | -------------------------------------------------------------------------------------------- | ------ | ------ | ------ | ------ | ------ | ----------------------------------------------- | ------ | ------ | ------ | ---------- | --- |
|
|
71
|
-
| **tokens** (`./tokens`) | — | `--vx-divider` → `rgba()` on both schemes (§ Shell) | `--vx-space-touch-target` added (§ Additions) | eight spacing numbers (§ Chrome) | — | — | `--vx-hit` replaces the touch vars; `SIZE_CLASSES` (§ 1.31.0) | — | `SIZE_CLASSES`/`CONTAINER_CLASSES` actually exported (§ Fixes) | `CONTAINER_GRID_BREAKPOINTS`; `raw-breakpoint` trusts it (§ 1.33.0) | `CONTAINER_KEYS` (§ 1.34.0) | — | — | — | — | — | — | — | | `appShellInset` 20 → 16 (§ 1.38.1) | — | — | — | — | — |
|
|
72
|
-
| **charts** (`./charts`) | — | phone tier, `curve`, formatters, `state`, log axis (§ preamble) | `ChartState.empty: string`, `AxisBottomNumeric` (§ Additions) | responsive `height`, `legend.maxRows` (§ Charts) | `height` reaches the kinds; `maxRows` beats the `fill` fit (§ Charts) | — | container-class tier + `height` keys (§ 1.31.0) | — | `ResponsiveChartHeight` `sm` → key (§ Container recipes) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
73
|
-
| **shell** (`.`) | — | scrollport, region seams, **the brand left the sidebar** (§§ scrollport, brand, Shell) | `PageTitle`, `BasaltDevDock`, `useBreakpoint` (§ Additions) | More popover, aside pill, the responsive gutter, `useBasaltSpacing` (§ Chrome) | — | — | `theme.breakpoints` derived, `useSizeClass`, `data-basalt-host`, `useBreakpoint` on notice (§ 1.31.0) | `useBreakpoint` removal → 1.33.0; `useSizeClass` is shell-only (§ 1.32.0) | shell-less `shell/` gutter, `AppShell` breakpoints, `useSizeClass` for overlays (§§ Shell-less, `useSizeClass`) | — | `useBreakpoint` removed (§ 1.34.0) | — | — | `useCoarsePointer()` (§ `useCoarsePointer()`) | — | — | — | — | | content gutter 16, block 8 from `sm` (§ 1.38.1) | — | — | — | — | — |
|
|
74
|
-
| **controls** (`./controls`) | `NumberFilter`, `field.number` (§ Controls) | sheet renders panel rows; `PanelRow`, `SliderControl` (§ `basalt-ui/controls`) | — | — | — | — | — | — | — | `NumberFilter clearable`; `createSearchStore` `resets` (§ State and controls) | — | — | — | `FormSection`/`FormRow`/`FormGroup`/`FormActions` move here (§ The form layout moves) | — | — | — | — | — | — | — | — | — | — |
|
|
75
|
-
| **forms** (`./forms`) | — | `field` → `inputProps`, **`inputProps` drops `key`**, the layout tier (§ `inputProps`) | `field` DELETED — and the `--fix` recipe no longer works (§ Consolidation) | — | — | — | — | — | `FormGroup` row no longer stretches (§ Fixes) | — | — | — | — | the layout + `useForm`/`schemaResolver` deprecated, removed 1.37.0 (§ The form layout moves) | — | — | — | — | — | — | — | — | — | — |
|
|
76
|
-
| **data** (`./data/table`) | — | root is a `<div>`, row selection, `getItemKey` required (§ `basalt-ui/data`) | `./data` + `./query` + `./connectivity` dropped (§ Consolidation) | — | — | — | — | — | `renderCard` documented (§ `renderCard`) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
77
|
-
| **dashboard** (`.`) | `StatCard`: `unit`, `breakdown`, delta format (§ `StatCard`) | `StatGroup`, `WidgetGrid`, query-aware `StatCard` — additive | — | **the column law keys on the CONTAINER; `cols={4}` is 2-up at `sm`** (§ Dashboard) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
78
|
-
| **toolchain** (`./configs/*`) | — | — | the shipped lefthook preset's `check-theme` BROKE — the CLI resolver stopped ascending (§ CLI) | the preset's default bin, and the `root:` recipe (§ Toolchain) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
79
|
-
| **CLI** (`basalt-ui`) | — | — | **resolver stops relocating; `doctor` loses 6 of 10 checks** (§ CLI) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
80
|
-
| **guards** | five rules → `error` (§ Guards) | six new ids at `warn` (§ preamble) | `query-dual-import` retired in 1.29.1 (§ Guards) | four rules → `error` (§ Guards) | — | — | — | `raw-breakpoint`: the container-grid answer, `error` at 1.33.0 (§ 1.32.0) | `FormRow`/`FormGroup` homes in both lanes; `basalt-main` dropped (§ Fixes) | C1 + breakpoint pairs → `error`; `unknown-vx-token` `warn` (§ Guards) | — | — | — | `unknown-vx-token` → `error`; the token factories throw (§ Guards) | — | — | — | — | — | — | — | — | — | — |
|
|
69
|
+
| Surface | 1.27.0 | 1.28.0 | 1.29.0 | 1.30.0 | 1.30.1 | 1.30.2 | 1.31.0 | 1.32.0 | 1.32.1 | 1.33.0 | 1.34.0 | 1.34.1 | 1.35.0 | 1.36.0 | 1.36.1 | 1.37.0 | 1.37.1 | 1.38.0 | 1.38.1 | 1.39.0 | 1.40.0 | 1.40.1 | 1.40.2 | 1.40.3 | Unreleased |
|
|
70
|
+
| ----------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------- | ------ | ------ | -------------------------------------------------------------------------------------------- | ------ | ------ | ------ | ------ | ------ | ----------------------------------------------- | ------ | ------ | ------ | ------ | ---------- | --- |
|
|
71
|
+
| **tokens** (`./tokens`) | — | `--vx-divider` → `rgba()` on both schemes (§ Shell) | `--vx-space-touch-target` added (§ Additions) | eight spacing numbers (§ Chrome) | — | — | `--vx-hit` replaces the touch vars; `SIZE_CLASSES` (§ 1.31.0) | — | `SIZE_CLASSES`/`CONTAINER_CLASSES` actually exported (§ Fixes) | `CONTAINER_GRID_BREAKPOINTS`; `raw-breakpoint` trusts it (§ 1.33.0) | `CONTAINER_KEYS` (§ 1.34.0) | — | — | — | — | — | — | — | | `appShellInset` 20 → 16 (§ 1.38.1) | — | — | — | — | — | — |
|
|
72
|
+
| **charts** (`./charts`) | — | phone tier, `curve`, formatters, `state`, log axis (§ preamble) | `ChartState.empty: string`, `AxisBottomNumeric` (§ Additions) | responsive `height`, `legend.maxRows` (§ Charts) | `height` reaches the kinds; `maxRows` beats the `fill` fit (§ Charts) | — | container-class tier + `height` keys (§ 1.31.0) | — | `ResponsiveChartHeight` `sm` → key (§ Container recipes) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
73
|
+
| **shell** (`.`) | — | scrollport, region seams, **the brand left the sidebar** (§§ scrollport, brand, Shell) | `PageTitle`, `BasaltDevDock`, `useBreakpoint` (§ Additions) | More popover, aside pill, the responsive gutter, `useBasaltSpacing` (§ Chrome) | — | — | `theme.breakpoints` derived, `useSizeClass`, `data-basalt-host`, `useBreakpoint` on notice (§ 1.31.0) | `useBreakpoint` removal → 1.33.0; `useSizeClass` is shell-only (§ 1.32.0) | shell-less `shell/` gutter, `AppShell` breakpoints, `useSizeClass` for overlays (§§ Shell-less, `useSizeClass`) | — | `useBreakpoint` removed (§ 1.34.0) | — | — | `useCoarsePointer()` (§ `useCoarsePointer()`) | — | — | — | — | | content gutter 16, block 8 from `sm` (§ 1.38.1) | — | — | — | — | — | — |
|
|
74
|
+
| **controls** (`./controls`) | `NumberFilter`, `field.number` (§ Controls) | sheet renders panel rows; `PanelRow`, `SliderControl` (§ `basalt-ui/controls`) | — | — | — | — | — | — | — | `NumberFilter clearable`; `createSearchStore` `resets` (§ State and controls) | — | — | — | `FormSection`/`FormRow`/`FormGroup`/`FormActions` move here (§ The form layout moves) | — | — | — | — | — | — | — | — | — | — | — |
|
|
75
|
+
| **forms** (`./forms`) | — | `field` → `inputProps`, **`inputProps` drops `key`**, the layout tier (§ `inputProps`) | `field` DELETED — and the `--fix` recipe no longer works (§ Consolidation) | — | — | — | — | — | `FormGroup` row no longer stretches (§ Fixes) | — | — | — | — | the layout + `useForm`/`schemaResolver` deprecated, removed 1.37.0 (§ The form layout moves) | — | — | — | — | — | — | — | — | — | — | — |
|
|
76
|
+
| **data** (`./data/table`) | — | root is a `<div>`, row selection, `getItemKey` required (§ `basalt-ui/data`) | `./data` + `./query` + `./connectivity` dropped (§ Consolidation) | — | — | — | — | — | `renderCard` documented (§ `renderCard`) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
77
|
+
| **dashboard** (`.`) | `StatCard`: `unit`, `breakdown`, delta format (§ `StatCard`) | `StatGroup`, `WidgetGrid`, query-aware `StatCard` — additive | — | **the column law keys on the CONTAINER; `cols={4}` is 2-up at `sm`** (§ Dashboard) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
78
|
+
| **toolchain** (`./configs/*`) | — | — | the shipped lefthook preset's `check-theme` BROKE — the CLI resolver stopped ascending (§ CLI) | the preset's default bin, and the `root:` recipe (§ Toolchain) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
79
|
+
| **CLI** (`basalt-ui`) | — | — | **resolver stops relocating; `doctor` loses 6 of 10 checks** (§ CLI) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
80
|
+
| **guards** | five rules → `error` (§ Guards) | six new ids at `warn` (§ preamble) | `query-dual-import` retired in 1.29.1 (§ Guards) | four rules → `error` (§ Guards) | — | — | — | `raw-breakpoint`: the container-grid answer, `error` at 1.33.0 (§ 1.32.0) | `FormRow`/`FormGroup` homes in both lanes; `basalt-main` dropped (§ Fixes) | C1 + breakpoint pairs → `error`; `unknown-vx-token` `warn` (§ Guards) | — | — | — | `unknown-vx-token` → `error`; the token factories throw (§ Guards) | — | — | — | — | — | — | — | — | — | — | — |
|
|
81
81
|
|
|
82
82
|
---
|
|
83
83
|
|
|
@@ -86,6 +86,10 @@ consumer read this index, found nothing, and diffed a KPI row that had silently
|
|
|
86
86
|
_Nothing yet. Author the next section under this heading as `## Unreleased — <title>`; the
|
|
87
87
|
release renames it and opens a new one here._
|
|
88
88
|
|
|
89
|
+
## 1.40.3
|
|
90
|
+
|
|
91
|
+
_Nothing to migrate in this release._
|
|
92
|
+
|
|
89
93
|
## 1.40.2
|
|
90
94
|
|
|
91
95
|
_Nothing to migrate in this release._
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HoverOverlay.d.ts","sourceRoot":"","sources":["../../../src/charts/primitives/HoverOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAA;AACzF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAG1D,qCAAqC;AACrC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;IAC3C;2FACuF;IACvF,MAAM,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;IAC5C,wEAAwE;IACxE,IAAI,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;IAC1C,OAAO,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;IAC5C,4DAA4D;IAC5D,SAAS,CAAC,EAAE,oBAAoB,CAAC,cAAc,CAAC,CAAA;IAChD,MAAM,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAA;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,MAAM,EACN,MAAM,EACN,MAAM,EACN,IAAI,EACJ,OAAO,EACP,SAAS,EACT,MAAM,EACN,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,SAAS,GACV,EAAE,iBAAiB,+
|
|
1
|
+
{"version":3,"file":"HoverOverlay.d.ts","sourceRoot":"","sources":["../../../src/charts/primitives/HoverOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAA;AACzF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAG1D,qCAAqC;AACrC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;IAC3C;2FACuF;IACvF,MAAM,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;IAC5C,wEAAwE;IACxE,IAAI,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;IAC1C,OAAO,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;IAC5C,4DAA4D;IAC5D,SAAS,CAAC,EAAE,oBAAoB,CAAC,cAAc,CAAC,CAAA;IAChD,MAAM,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAA;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,MAAM,EACN,MAAM,EACN,MAAM,EACN,IAAI,EACJ,OAAO,EACP,SAAS,EACT,MAAM,EACN,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,SAAS,GACV,EAAE,iBAAiB,+BAkCnB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE;IAC1C,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAA;IACtB,IAAI,EAAE,SAAS,CAAC,EAAE,CAAA;IAClB,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACtB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAChC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;CAC9B,GAAG,IAAI,CAAC,iBAAiB,EAAE,OAAO,GAAG,QAAQ,CAAC,CAc9C"}
|
|
@@ -36,7 +36,8 @@ function HoverOverlay({
|
|
|
36
36
|
"aria-orientation": "horizontal",
|
|
37
37
|
"aria-valuemin": 0,
|
|
38
38
|
...valueMax !== void 0 && { "aria-valuemax": valueMax },
|
|
39
|
-
|
|
39
|
+
// `aria-valuenow` is required on a slider: 0 (the first point) until the cursor lands on one.
|
|
40
|
+
"aria-valuenow": valueNow ?? 0,
|
|
40
41
|
...valueText !== void 0 && { "aria-valuetext": valueText },
|
|
41
42
|
onKeyDown,
|
|
42
43
|
...onBlur !== void 0 && { onBlur }
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* parseShortcut('Mod+S', false) // ['Ctrl', 'S']
|
|
10
10
|
*
|
|
11
11
|
* // Single display string for Spotlight description:
|
|
12
|
-
* formatShortcutDisplay('Mod+S', true) // '⌘
|
|
12
|
+
* formatShortcutDisplay('Mod+S', true) // '⌘S' on mac
|
|
13
13
|
* formatShortcutDisplay('Mod+S', false) // 'Ctrl+S' on windows
|
|
14
14
|
*/
|
|
15
15
|
/**
|
|
@@ -22,16 +22,20 @@ export declare function detectMac(): boolean;
|
|
|
22
22
|
* Convert a shortcut string to a list of Kbd-friendly tokens.
|
|
23
23
|
* 'Mod+S' → ['⌘', 'S'] (mac) or ['Ctrl', 'S'] (other).
|
|
24
24
|
* 'Shift+Mod+P' → ['⇧', '⌘', 'P'] (mac) or ['Shift', 'Ctrl', 'P'] (other).
|
|
25
|
+
* Named keys read as glyphs on mac and Title-case words elsewhere:
|
|
26
|
+
* 'Mod+Backspace' → ['⌘', '⌫'] (mac) or ['Ctrl', 'Backspace'] (other).
|
|
25
27
|
* isMac is the post-mount platform flag; defaults false on SSR / first render.
|
|
26
28
|
*
|
|
27
29
|
* @example
|
|
28
30
|
* parseShortcut('Mod+S', true) // ['⌘', 'S']
|
|
29
31
|
* parseShortcut('Shift+Mod+P', false) // ['Shift', 'Ctrl', 'P']
|
|
32
|
+
* parseShortcut('ArrowLeft', true) // ['←']
|
|
30
33
|
*/
|
|
31
34
|
export declare function parseShortcut(shortcut: string, isMac: boolean): string[];
|
|
32
35
|
/**
|
|
33
36
|
* Format a shortcut string for inline display (e.g. Spotlight action description).
|
|
34
|
-
* Returns a compact string like '⌘
|
|
37
|
+
* Returns a compact string like '⌘S' / '⌘⌫' (mac, glyphs with no separator) or 'Ctrl+S' /
|
|
38
|
+
* 'Ctrl+Backspace' (elsewhere, Title-case words joined with '+').
|
|
35
39
|
*
|
|
36
40
|
* isMac is the post-mount platform flag. Pass false on SSR / first client render.
|
|
37
41
|
*
|
|
@@ -40,9 +44,10 @@ export declare function parseShortcut(shortcut: string, isMac: boolean): string[
|
|
|
40
44
|
* always-on and produces the same tokens via parseShortcut.
|
|
41
45
|
*
|
|
42
46
|
* @example
|
|
43
|
-
* formatShortcutDisplay('Mod+S', true)
|
|
47
|
+
* formatShortcutDisplay('Mod+S', true) // '⌘S'
|
|
48
|
+
* formatShortcutDisplay('Mod+Backspace', true) // '⌘⌫'
|
|
44
49
|
* formatShortcutDisplay('Mod+S', false) // 'Ctrl+S'
|
|
45
|
-
* formatShortcutDisplay('Shift+Mod+P', true) // '
|
|
50
|
+
* formatShortcutDisplay('Shift+Mod+P', true) // '⇧⌘P'
|
|
46
51
|
*/
|
|
47
52
|
export declare function formatShortcutDisplay(shortcut: string, isMac: boolean): string;
|
|
48
53
|
//# sourceMappingURL=shortcut-format.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shortcut-format.d.ts","sourceRoot":"","sources":["../../src/commands/shortcut-format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAMnC;
|
|
1
|
+
{"version":3,"file":"shortcut-format.d.ts","sourceRoot":"","sources":["../../src/commands/shortcut-format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAMnC;AAmCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAqBxE;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAG9E"}
|
|
@@ -4,9 +4,36 @@ function detectMac() {
|
|
|
4
4
|
if (uadPlatform !== void 0) return /mac|iphone|ipad/i.test(uadPlatform);
|
|
5
5
|
return /Mac|iPhone|iPad/.test(navigator.userAgent);
|
|
6
6
|
}
|
|
7
|
+
const NAMED_KEYS = {
|
|
8
|
+
backspace: ["\u232B", "Backspace"],
|
|
9
|
+
delete: ["\u2326", "Delete"],
|
|
10
|
+
del: ["\u2326", "Delete"],
|
|
11
|
+
arrowleft: ["\u2190", "Left"],
|
|
12
|
+
arrowright: ["\u2192", "Right"],
|
|
13
|
+
arrowup: ["\u2191", "Up"],
|
|
14
|
+
arrowdown: ["\u2193", "Down"],
|
|
15
|
+
left: ["\u2190", "Left"],
|
|
16
|
+
right: ["\u2192", "Right"],
|
|
17
|
+
up: ["\u2191", "Up"],
|
|
18
|
+
down: ["\u2193", "Down"],
|
|
19
|
+
escape: ["\u238B", "Esc"],
|
|
20
|
+
esc: ["\u238B", "Esc"],
|
|
21
|
+
enter: ["\u21A9", "Enter"],
|
|
22
|
+
return: ["\u21A9", "Enter"],
|
|
23
|
+
tab: ["\u21E5", "Tab"],
|
|
24
|
+
space: ["\u2423", "Space"],
|
|
25
|
+
home: ["\u2196", "Home"],
|
|
26
|
+
end: ["\u2198", "End"],
|
|
27
|
+
pageup: ["\u21DE", "PgUp"],
|
|
28
|
+
pagedown: ["\u21DF", "PgDn"]
|
|
29
|
+
};
|
|
30
|
+
function plainKey(key) {
|
|
31
|
+
return key.length === 1 ? key.toUpperCase() : key.charAt(0).toUpperCase() + key.slice(1);
|
|
32
|
+
}
|
|
7
33
|
function parseShortcut(shortcut, isMac) {
|
|
8
34
|
return shortcut.split("+").map((key) => {
|
|
9
|
-
|
|
35
|
+
const lower = key.toLowerCase();
|
|
36
|
+
switch (lower) {
|
|
10
37
|
case "mod":
|
|
11
38
|
return isMac ? "\u2318" : "Ctrl";
|
|
12
39
|
case "shift":
|
|
@@ -16,15 +43,18 @@ function parseShortcut(shortcut, isMac) {
|
|
|
16
43
|
case "meta":
|
|
17
44
|
return isMac ? "\u2318" : "Meta";
|
|
18
45
|
case "ctrl":
|
|
19
|
-
return isMac ? "
|
|
20
|
-
default:
|
|
21
|
-
|
|
46
|
+
return isMac ? "\u2303" : "Ctrl";
|
|
47
|
+
default: {
|
|
48
|
+
const named = NAMED_KEYS[lower];
|
|
49
|
+
if (named !== void 0) return isMac ? named[0] : named[1];
|
|
50
|
+
return plainKey(key);
|
|
51
|
+
}
|
|
22
52
|
}
|
|
23
53
|
});
|
|
24
54
|
}
|
|
25
55
|
function formatShortcutDisplay(shortcut, isMac) {
|
|
26
56
|
const tokens = parseShortcut(shortcut, isMac);
|
|
27
|
-
return
|
|
57
|
+
return tokens.join(isMac ? "" : "+");
|
|
28
58
|
}
|
|
29
59
|
export {
|
|
30
60
|
detectMac,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAiEA,OAAO,KAAK,EACV,oBAAoB,EAGpB,oBAAoB,EAErB,MAAM,eAAe,CAAA;AAStB,OAAO,KAAK,EAAe,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAGpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAQlD;;;;;GAKG;AACH,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAIlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAMvD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAgBnE,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,iBAAiB;QACzB,YAAY,CAAC,EAAE,YAAY,CAAA;QAC3B,WAAW,CAAC,EAAE,iBAAiB,CAAA;QAC/B,YAAY,CAAC,EAAE,YAAY,CAAA;QAC3B,aAAa,CAAC,EAAE,WAAW,CAAA;KAC5B;CACF;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAiEA,OAAO,KAAK,EACV,oBAAoB,EAGpB,oBAAoB,EAErB,MAAM,eAAe,CAAA;AAStB,OAAO,KAAK,EAAe,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAGpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAQlD;;;;;GAKG;AACH,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAIlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAMvD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAgBnE,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,iBAAiB;QACzB,YAAY,CAAC,EAAE,YAAY,CAAA;QAC3B,WAAW,CAAC,EAAE,iBAAiB,CAAA;QAC/B,YAAY,CAAC,EAAE,YAAY,CAAA;QAC3B,aAAa,CAAC,EAAE,WAAW,CAAA;KAC5B;CACF;AAuiCD;+EAC+E;AAC/E,eAAO,MAAM,SAAS,EAAE,oBAAuD,CAAA;AAkU/E;;8FAE8F;AAC9F,eAAO,MAAM,oBAAoB,EAAE,oBACc,CAAA;AAEjD,kEAAkE;AAClE,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;IAE9B;;;;;;;;;;;;;;;;OAgBG;IACH,KAAK,CAAC,EAAE,iBAAiB,CAAA;IAEzB;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAC7B,CAAA;AA0BD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,aAAa,CAAC,EACrD,OAAO,CAAC,EAAE,wBAAwB,GACjC,oBAAoB,CAmCtB"}
|
package/dist/theme/index.js
CHANGED
|
@@ -156,13 +156,17 @@ const basaltVariantColorResolver = (input) => {
|
|
|
156
156
|
const isDefaultColor = input.color === void 0 || input.color === input.theme.primaryColor;
|
|
157
157
|
return isDefaultColor ? { ...resolved, hover: `color-mix(in srgb, var(--vx-ink) 6%, transparent)` } : resolved;
|
|
158
158
|
}
|
|
159
|
+
if (input.variant === "outline") {
|
|
160
|
+
return { ...resolved, color: `color-mix(in srgb, ${resolved.color} 70%, var(--vx-ink))` };
|
|
161
|
+
}
|
|
159
162
|
if (input.variant !== "light") return resolved;
|
|
160
163
|
const ink = `var(--mantine-color-${colorName}-light-color)`;
|
|
161
164
|
return {
|
|
162
165
|
...resolved,
|
|
163
166
|
background: `color-mix(in srgb, ${ink} 13%, transparent)`,
|
|
164
167
|
hover: `color-mix(in srgb, ${ink} 20%, transparent)`,
|
|
165
|
-
|
|
168
|
+
// Same pull toward ink as `outline`: the saturated tone text sat at 3.2–4.4:1 on its own tint.
|
|
169
|
+
color: `color-mix(in srgb, ${ink} 70%, var(--vx-ink))`,
|
|
166
170
|
border: "none"
|
|
167
171
|
};
|
|
168
172
|
};
|
|
@@ -1003,6 +1007,12 @@ function buildCssVariablesResolver(data) {
|
|
|
1003
1007
|
// secondary / muted text
|
|
1004
1008
|
"--mantine-color-text": `var(--vx-ink, ${INK.ink.light})`,
|
|
1005
1009
|
// primary body/heading text
|
|
1010
|
+
// Field errors: Mantine's own error red measures 1.98:1 (dark) / 4.37:1 (light). The solid status red
|
|
1011
|
+
// pulled toward ink clears AA on every text surface in both schemes.
|
|
1012
|
+
"--mantine-color-error": "color-mix(in srgb, var(--vx-bad-solid) 85%, var(--vx-ink))",
|
|
1013
|
+
// Links: Mantine reads the accent FILL shade (4.38:1 on the light page, under WCAG AA); the hover
|
|
1014
|
+
// accent is the next step darker and clears 4.5:1 on every light text surface.
|
|
1015
|
+
"--mantine-color-anchor": "var(--vx-accent-hover)",
|
|
1006
1016
|
// `--app-shell-border-color` is set by `components.AppShell.extend({ vars })` above — this
|
|
1007
1017
|
// entry was dead (an element-level declaration always beats an inherited `:root` value).
|
|
1008
1018
|
// THE strict-surface lever. Mantine components do NOT chain border/surface colors through
|
|
@@ -1031,6 +1041,9 @@ function buildCssVariablesResolver(data) {
|
|
|
1031
1041
|
"--mantine-color-default-border": "transparent",
|
|
1032
1042
|
"--mantine-color-dimmed": `var(--vx-neutral, ${NEUTRAL.neutral.dark})`,
|
|
1033
1043
|
"--mantine-color-text": `var(--vx-ink, ${INK.ink.dark})`,
|
|
1044
|
+
// Field errors: Mantine's own error red measures 1.98:1 (dark) / 4.37:1 (light). The solid status red
|
|
1045
|
+
// pulled toward ink clears AA on every text surface in both schemes.
|
|
1046
|
+
"--mantine-color-error": "color-mix(in srgb, var(--vx-bad-solid) 85%, var(--vx-ink))",
|
|
1034
1047
|
// See the light block above — `--app-shell-border-color` is set by `AppShell.extend` now.
|
|
1035
1048
|
// Dark components read `--mantine-color-dark-4` (border) raw. `buildDarkTuple` already sets
|
|
1036
1049
|
// dark-4, but to a slightly lighter step than the hairline token, so layout borders read
|
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
font-weight: 600;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/*
|
|
17
|
+
* Inactive labels read ink2, not Mantine's gray-7 (4.0:1 on the light track): the active segment is
|
|
18
|
+
* told apart by the raised pill and weight 600, so the inactive text can stay at full AA contrast.
|
|
19
|
+
*/
|
|
20
|
+
.label:not([data-active], [data-disabled]) {
|
|
21
|
+
color: var(--vx-ink2);
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
/*
|
|
17
25
|
* Mantine's own `.control` ships `flex: 1` with no `min-width` override, so its initial value
|
|
18
26
|
* (`auto`) floors every option at its min-content width — a `fullWidth` track therefore still
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../../src/tokens/derive.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC,MAAM,MAAM,YAAY,GAAG;IACzB;;;;;;;;OAQG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAA;IAC/C;kGAC8F;IAC9F,UAAU,EAAE,MAAM,CAAA;IAClB;mDAC+C;IAC/C,SAAS,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;;OAMG;IACH,gBAAgB,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB,EAAE,YAOnC,CAAA;AAID;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAEjF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAEnE;AAuHD,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,KAAK,GACL,MAAM,GACN,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,QAAQ,GACR,QAAQ,CAAA;AA6DZ,MAAM,MAAM,UAAU,GAClB,IAAI,GACJ,OAAO,GACP,YAAY,GACZ,UAAU,GACV,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,UAAU,CAAA;AA2Bd,MAAM,MAAM,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../../src/tokens/derive.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC,MAAM,MAAM,YAAY,GAAG;IACzB;;;;;;;;OAQG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAA;IAC/C;kGAC8F;IAC9F,UAAU,EAAE,MAAM,CAAA;IAClB;mDAC+C;IAC/C,SAAS,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;;OAMG;IACH,gBAAgB,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB,EAAE,YAOnC,CAAA;AAID;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAEjF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAEnE;AAuHD,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,KAAK,GACL,MAAM,GACN,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,QAAQ,GACR,QAAQ,CAAA;AA6DZ,MAAM,MAAM,UAAU,GAClB,IAAI,GACJ,OAAO,GACP,YAAY,GACZ,UAAU,GACV,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,UAAU,CAAA;AA2Bd,MAAM,MAAM,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAUvD,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAA;AAS/C;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,6FAA6F;IAC7F,UAAU,EAAE,MAAM,CAAA;IAClB,0EAA0E;IAC1E,eAAe,EAAE,MAAM,CAAA;IACvB,6EAA6E;IAC7E,iBAAiB,EAAE,MAAM,CAAA;IACzB,4EAA4E;IAC5E,gBAAgB,EAAE,MAAM,CAAA;CACzB,CAAA;AAED;8BAC8B;AAC9B,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,SAAS,CAAA;IACjB,WAAW,EAAE,SAAS,CAAA;IACtB,UAAU,EAAE,SAAS,CAAA;IACrB,eAAe,EAAE,SAAS,CAAA;IAC1B,QAAQ,EAAE,SAAS,CAAA;IACnB,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IACnC,OAAO,EAAE,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IACtC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IAC9B,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;CACrC,CAAA;AAED;;8DAE8D;AAC9D,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,cAAc,CAQjE;AAED,gGAAgG;AAChG,wBAAgB,eAAe,CAC7B,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,GAAG,SAAS,CAAC,EAChD,MAAM,EAAE,YAAY,GACnB,cAAc,CA+GhB"}
|
package/dist/tokens/derive.js
CHANGED
|
@@ -127,7 +127,9 @@ const SURFACE_TONE = {
|
|
|
127
127
|
}
|
|
128
128
|
};
|
|
129
129
|
const INK_TONE = {
|
|
130
|
-
light
|
|
130
|
+
// light `faint` is tone 44.5 so tertiary text clears WCAG AA (4.5:1) on every text surface
|
|
131
|
+
// (bg / panel / subtle / field); 48.44 landed at 4.23–4.31:1 on bg and subtle.
|
|
132
|
+
light: { ink: 15.16, ink2: 27.09, muted: 34.88, faint: 44.5 },
|
|
131
133
|
dark: { ink: 90.94, ink2: 88.12, muted: 84.91, faint: 66.24 }
|
|
132
134
|
};
|
|
133
135
|
const STATUS_HUE = { good: 151.975, warn: 76.64, bad: 29.905 };
|
package/dist/tokens.css
CHANGED
|
@@ -291,7 +291,7 @@ html[data-mantine-color-scheme='light'] {
|
|
|
291
291
|
--vx-ink: #262629;
|
|
292
292
|
--vx-ink2: #404043;
|
|
293
293
|
--vx-muted: #525255;
|
|
294
|
-
--vx-faint: #
|
|
294
|
+
--vx-faint: #69696c;
|
|
295
295
|
--vx-accent: #4374a6;
|
|
296
296
|
--vx-accent-hover: #3c6895;
|
|
297
297
|
--vx-accent-fill: #4374a6;
|
package/llms.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# basalt-ui v1.40.
|
|
1
|
+
# basalt-ui v1.40.3
|
|
2
2
|
# Opinionated framework for Mantine-based React apps — theme, app shell, visx charts, toolchain presets
|
|
3
3
|
#
|
|
4
4
|
# basalt-ui is an opinionated framework for Mantine-based React apps.
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
# ./tokens.css subpath. Guide: docs/FRAMEWORK-FREE.md in the repo.
|
|
20
20
|
|
|
21
21
|
Package: basalt-ui
|
|
22
|
-
Version: 1.40.
|
|
22
|
+
Version: 1.40.3
|
|
23
23
|
|
|
24
24
|
## basalt-ui
|
|
25
25
|
Import: import { ... } from 'basalt-ui'
|
package/package.json
CHANGED
|
@@ -66,7 +66,8 @@ export function HoverOverlay({
|
|
|
66
66
|
'aria-orientation': 'horizontal' as const,
|
|
67
67
|
'aria-valuemin': 0,
|
|
68
68
|
...(valueMax !== undefined && { 'aria-valuemax': valueMax }),
|
|
69
|
-
|
|
69
|
+
// `aria-valuenow` is required on a slider: 0 (the first point) until the cursor lands on one.
|
|
70
|
+
'aria-valuenow': valueNow ?? 0,
|
|
70
71
|
...(valueText !== undefined && { 'aria-valuetext': valueText }),
|
|
71
72
|
onKeyDown,
|
|
72
73
|
...(onBlur !== undefined && { onBlur }),
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* parseShortcut('Mod+S', false) // ['Ctrl', 'S']
|
|
10
10
|
*
|
|
11
11
|
* // Single display string for Spotlight description:
|
|
12
|
-
* formatShortcutDisplay('Mod+S', true) // '⌘
|
|
12
|
+
* formatShortcutDisplay('Mod+S', true) // '⌘S' on mac
|
|
13
13
|
* formatShortcutDisplay('Mod+S', false) // 'Ctrl+S' on windows
|
|
14
14
|
*/
|
|
15
15
|
|
|
@@ -30,19 +30,54 @@ export function detectMac(): boolean {
|
|
|
30
30
|
|
|
31
31
|
// ── parseShortcut ─────────────────────────────────────────────────────────────
|
|
32
32
|
|
|
33
|
+
/** Named keys → [mac glyph, other-platform word]. Keys are the lower-cased shortcut token. */
|
|
34
|
+
const NAMED_KEYS: Record<string, readonly [mac: string, other: string]> = {
|
|
35
|
+
backspace: ['⌫', 'Backspace'],
|
|
36
|
+
delete: ['⌦', 'Delete'],
|
|
37
|
+
del: ['⌦', 'Delete'],
|
|
38
|
+
arrowleft: ['←', 'Left'],
|
|
39
|
+
arrowright: ['→', 'Right'],
|
|
40
|
+
arrowup: ['↑', 'Up'],
|
|
41
|
+
arrowdown: ['↓', 'Down'],
|
|
42
|
+
left: ['←', 'Left'],
|
|
43
|
+
right: ['→', 'Right'],
|
|
44
|
+
up: ['↑', 'Up'],
|
|
45
|
+
down: ['↓', 'Down'],
|
|
46
|
+
escape: ['⎋', 'Esc'],
|
|
47
|
+
esc: ['⎋', 'Esc'],
|
|
48
|
+
enter: ['↩', 'Enter'],
|
|
49
|
+
return: ['↩', 'Enter'],
|
|
50
|
+
tab: ['⇥', 'Tab'],
|
|
51
|
+
space: ['␣', 'Space'],
|
|
52
|
+
home: ['↖', 'Home'],
|
|
53
|
+
end: ['↘', 'End'],
|
|
54
|
+
pageup: ['⇞', 'PgUp'],
|
|
55
|
+
pagedown: ['⇟', 'PgDn'],
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** A key that is not a modifier or a named key: a single character upper-cases (`s` → `S`), any
|
|
59
|
+
* other word title-cases (`f5` → `F5`, `insert` → `Insert`). */
|
|
60
|
+
function plainKey(key: string): string {
|
|
61
|
+
return key.length === 1 ? key.toUpperCase() : key.charAt(0).toUpperCase() + key.slice(1)
|
|
62
|
+
}
|
|
63
|
+
|
|
33
64
|
/**
|
|
34
65
|
* Convert a shortcut string to a list of Kbd-friendly tokens.
|
|
35
66
|
* 'Mod+S' → ['⌘', 'S'] (mac) or ['Ctrl', 'S'] (other).
|
|
36
67
|
* 'Shift+Mod+P' → ['⇧', '⌘', 'P'] (mac) or ['Shift', 'Ctrl', 'P'] (other).
|
|
68
|
+
* Named keys read as glyphs on mac and Title-case words elsewhere:
|
|
69
|
+
* 'Mod+Backspace' → ['⌘', '⌫'] (mac) or ['Ctrl', 'Backspace'] (other).
|
|
37
70
|
* isMac is the post-mount platform flag; defaults false on SSR / first render.
|
|
38
71
|
*
|
|
39
72
|
* @example
|
|
40
73
|
* parseShortcut('Mod+S', true) // ['⌘', 'S']
|
|
41
74
|
* parseShortcut('Shift+Mod+P', false) // ['Shift', 'Ctrl', 'P']
|
|
75
|
+
* parseShortcut('ArrowLeft', true) // ['←']
|
|
42
76
|
*/
|
|
43
77
|
export function parseShortcut(shortcut: string, isMac: boolean): string[] {
|
|
44
78
|
return shortcut.split('+').map((key) => {
|
|
45
|
-
|
|
79
|
+
const lower = key.toLowerCase()
|
|
80
|
+
switch (lower) {
|
|
46
81
|
case 'mod':
|
|
47
82
|
return isMac ? '⌘' : 'Ctrl'
|
|
48
83
|
case 'shift':
|
|
@@ -52,9 +87,12 @@ export function parseShortcut(shortcut: string, isMac: boolean): string[] {
|
|
|
52
87
|
case 'meta':
|
|
53
88
|
return isMac ? '⌘' : 'Meta'
|
|
54
89
|
case 'ctrl':
|
|
55
|
-
return isMac ? '
|
|
56
|
-
default:
|
|
57
|
-
|
|
90
|
+
return isMac ? '⌃' : 'Ctrl'
|
|
91
|
+
default: {
|
|
92
|
+
const named = NAMED_KEYS[lower]
|
|
93
|
+
if (named !== undefined) return isMac ? named[0] : named[1]
|
|
94
|
+
return plainKey(key)
|
|
95
|
+
}
|
|
58
96
|
}
|
|
59
97
|
})
|
|
60
98
|
}
|
|
@@ -63,7 +101,8 @@ export function parseShortcut(shortcut: string, isMac: boolean): string[] {
|
|
|
63
101
|
|
|
64
102
|
/**
|
|
65
103
|
* Format a shortcut string for inline display (e.g. Spotlight action description).
|
|
66
|
-
* Returns a compact string like '⌘
|
|
104
|
+
* Returns a compact string like '⌘S' / '⌘⌫' (mac, glyphs with no separator) or 'Ctrl+S' /
|
|
105
|
+
* 'Ctrl+Backspace' (elsewhere, Title-case words joined with '+').
|
|
67
106
|
*
|
|
68
107
|
* isMac is the post-mount platform flag. Pass false on SSR / first client render.
|
|
69
108
|
*
|
|
@@ -72,12 +111,12 @@ export function parseShortcut(shortcut: string, isMac: boolean): string[] {
|
|
|
72
111
|
* always-on and produces the same tokens via parseShortcut.
|
|
73
112
|
*
|
|
74
113
|
* @example
|
|
75
|
-
* formatShortcutDisplay('Mod+S', true)
|
|
114
|
+
* formatShortcutDisplay('Mod+S', true) // '⌘S'
|
|
115
|
+
* formatShortcutDisplay('Mod+Backspace', true) // '⌘⌫'
|
|
76
116
|
* formatShortcutDisplay('Mod+S', false) // 'Ctrl+S'
|
|
77
|
-
* formatShortcutDisplay('Shift+Mod+P', true) // '
|
|
117
|
+
* formatShortcutDisplay('Shift+Mod+P', true) // '⇧⌘P'
|
|
78
118
|
*/
|
|
79
119
|
export function formatShortcutDisplay(shortcut: string, isMac: boolean): string {
|
|
80
120
|
const tokens = parseShortcut(shortcut, isMac)
|
|
81
|
-
|
|
82
|
-
return isMac ? tokens.join(' ') : tokens.join('+')
|
|
121
|
+
return tokens.join(isMac ? '' : '+')
|
|
83
122
|
}
|
package/src/theme/index.ts
CHANGED
|
@@ -383,13 +383,20 @@ const basaltVariantColorResolver: VariantColorsResolver = (input) => {
|
|
|
383
383
|
: resolved
|
|
384
384
|
}
|
|
385
385
|
|
|
386
|
+
// `outline`: the tone's own text colour, pulled toward ink so the label keeps its hue at AA
|
|
387
|
+
// (grey outline badges measured 3.9:1 on the light page).
|
|
388
|
+
if (input.variant === 'outline') {
|
|
389
|
+
return { ...resolved, color: `color-mix(in srgb, ${resolved.color} 70%, var(--vx-ink))` }
|
|
390
|
+
}
|
|
391
|
+
|
|
386
392
|
if (input.variant !== 'light') return resolved
|
|
387
393
|
const ink = `var(--mantine-color-${colorName}-light-color)`
|
|
388
394
|
return {
|
|
389
395
|
...resolved,
|
|
390
396
|
background: `color-mix(in srgb, ${ink} 13%, transparent)`,
|
|
391
397
|
hover: `color-mix(in srgb, ${ink} 20%, transparent)`,
|
|
392
|
-
|
|
398
|
+
// Same pull toward ink as `outline`: the saturated tone text sat at 3.2–4.4:1 on its own tint.
|
|
399
|
+
color: `color-mix(in srgb, ${ink} 70%, var(--vx-ink))`,
|
|
393
400
|
border: 'none',
|
|
394
401
|
}
|
|
395
402
|
}
|
|
@@ -1464,6 +1471,12 @@ function buildCssVariablesResolver(data: PaletteData): CSSVariablesResolver {
|
|
|
1464
1471
|
'--mantine-color-default-border': 'transparent',
|
|
1465
1472
|
'--mantine-color-dimmed': `var(--vx-neutral, ${NEUTRAL.neutral.light})`, // secondary / muted text
|
|
1466
1473
|
'--mantine-color-text': `var(--vx-ink, ${INK.ink.light})`, // primary body/heading text
|
|
1474
|
+
// Field errors: Mantine's own error red measures 1.98:1 (dark) / 4.37:1 (light). The solid status red
|
|
1475
|
+
// pulled toward ink clears AA on every text surface in both schemes.
|
|
1476
|
+
'--mantine-color-error': 'color-mix(in srgb, var(--vx-bad-solid) 85%, var(--vx-ink))',
|
|
1477
|
+
// Links: Mantine reads the accent FILL shade (4.38:1 on the light page, under WCAG AA); the hover
|
|
1478
|
+
// accent is the next step darker and clears 4.5:1 on every light text surface.
|
|
1479
|
+
'--mantine-color-anchor': 'var(--vx-accent-hover)',
|
|
1467
1480
|
// `--app-shell-border-color` is set by `components.AppShell.extend({ vars })` above — this
|
|
1468
1481
|
// entry was dead (an element-level declaration always beats an inherited `:root` value).
|
|
1469
1482
|
// THE strict-surface lever. Mantine components do NOT chain border/surface colors through
|
|
@@ -1492,6 +1505,9 @@ function buildCssVariablesResolver(data: PaletteData): CSSVariablesResolver {
|
|
|
1492
1505
|
'--mantine-color-default-border': 'transparent',
|
|
1493
1506
|
'--mantine-color-dimmed': `var(--vx-neutral, ${NEUTRAL.neutral.dark})`,
|
|
1494
1507
|
'--mantine-color-text': `var(--vx-ink, ${INK.ink.dark})`,
|
|
1508
|
+
// Field errors: Mantine's own error red measures 1.98:1 (dark) / 4.37:1 (light). The solid status red
|
|
1509
|
+
// pulled toward ink clears AA on every text surface in both schemes.
|
|
1510
|
+
'--mantine-color-error': 'color-mix(in srgb, var(--vx-bad-solid) 85%, var(--vx-ink))',
|
|
1495
1511
|
// See the light block above — `--app-shell-border-color` is set by `AppShell.extend` now.
|
|
1496
1512
|
// Dark components read `--mantine-color-dark-4` (border) raw. `buildDarkTuple` already sets
|
|
1497
1513
|
// dark-4, but to a slightly lighter step than the hairline token, so layout borders read
|
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
font-weight: 600;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/*
|
|
17
|
+
* Inactive labels read ink2, not Mantine's gray-7 (4.0:1 on the light track): the active segment is
|
|
18
|
+
* told apart by the raised pill and weight 600, so the inactive text can stay at full AA contrast.
|
|
19
|
+
*/
|
|
20
|
+
.label:not([data-active], [data-disabled]) {
|
|
21
|
+
color: var(--vx-ink2);
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
/*
|
|
17
25
|
* Mantine's own `.control` ships `flex: 1` with no `min-width` override, so its initial value
|
|
18
26
|
* (`auto`) floors every option at its min-content width — a `fullWidth` track therefore still
|
package/src/tokens/derive.ts
CHANGED
|
@@ -307,7 +307,9 @@ const SURFACE_TONE: Record<Side, Record<SurfaceKey, number>> = {
|
|
|
307
307
|
export type InkKey = 'ink' | 'ink2' | 'muted' | 'faint'
|
|
308
308
|
|
|
309
309
|
const INK_TONE: Record<Side, Record<InkKey, number>> = {
|
|
310
|
-
light
|
|
310
|
+
// light `faint` is tone 44.5 so tertiary text clears WCAG AA (4.5:1) on every text surface
|
|
311
|
+
// (bg / panel / subtle / field); 48.44 landed at 4.23–4.31:1 on bg and subtle.
|
|
312
|
+
light: { ink: 15.16, ink2: 27.09, muted: 34.88, faint: 44.5 },
|
|
311
313
|
dark: { ink: 90.94, ink2: 88.12, muted: 84.91, faint: 66.24 },
|
|
312
314
|
}
|
|
313
315
|
|