@urbicon-ui/blocks 6.25.0 → 6.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Calendar/calendar.variants.d.ts +63 -63
- package/dist/components/CompositionBar/CompositionBar.svelte +1 -1
- package/dist/i18n/index.d.ts +378 -2
- package/dist/primitives/Alert/alert.variants.d.ts +8 -8
- package/dist/primitives/Alert/alert.variants.js +1 -1
- package/dist/primitives/Badge/badge.variants.js +1 -1
- package/dist/primitives/Button/button.variants.js +2 -2
- package/dist/primitives/Checkbox/checkbox.variants.js +2 -2
- package/dist/primitives/Dialog/Dialog.svelte +5 -0
- package/dist/primitives/Drawer/Drawer.svelte +5 -0
- package/dist/primitives/JourneyTimeline/journey-timeline.variants.d.ts +22 -22
- package/dist/primitives/RadioGroup/radioGroup.variants.js +1 -1
- package/dist/primitives/Spinner/spinner.variants.d.ts +16 -16
- package/dist/primitives/Stepper/stepper.variants.d.ts +11 -11
- package/dist/primitives/Stepper/stepper.variants.js +1 -1
- package/dist/primitives/Toast/toast.variants.d.ts +12 -12
- package/dist/primitives/Tooltip/tooltip.variants.d.ts +3 -3
- package/dist/primitives/Tooltip/tooltip.variants.js +1 -1
- package/dist/style/foundation.css +22 -15
- package/dist/style/semantic.css +21 -9
- package/dist/style/themes/forest.css +3 -1
- package/dist/style/themes/sunset.css +3 -1
- package/dist/utils/figma-token-export.js +5 -1
- package/dist/utils/overlay.js +24 -2
- package/package.json +3 -3
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { type SlotNames, type VariantProps } from '../../utils/variants.js';
|
|
2
2
|
export declare const tooltipVariants: ((props?: {
|
|
3
3
|
open?: boolean | undefined;
|
|
4
|
-
intent?: "
|
|
4
|
+
intent?: "info" | "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
|
|
5
5
|
size?: "sm" | "md" | "lg" | undefined;
|
|
6
6
|
} | undefined) => {
|
|
7
7
|
base: (props?: ({
|
|
8
8
|
open?: boolean | undefined;
|
|
9
|
-
intent?: "
|
|
9
|
+
intent?: "info" | "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
|
|
10
10
|
size?: "sm" | "md" | "lg" | undefined;
|
|
11
11
|
} & {
|
|
12
12
|
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
13
13
|
}) | undefined) => string;
|
|
14
14
|
arrow: (props?: ({
|
|
15
15
|
open?: boolean | undefined;
|
|
16
|
-
intent?: "
|
|
16
|
+
intent?: "info" | "primary" | "secondary" | "success" | "warning" | "danger" | "neutral" | undefined;
|
|
17
17
|
size?: "sm" | "md" | "lg" | undefined;
|
|
18
18
|
} & {
|
|
19
19
|
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
@@ -53,7 +53,7 @@ export const tooltipVariants = tv({
|
|
|
53
53
|
secondary: { base: 'bg-secondary text-text-on-primary' },
|
|
54
54
|
info: { base: 'bg-info text-text-on-primary' },
|
|
55
55
|
success: { base: 'bg-success text-text-on-primary' },
|
|
56
|
-
warning: { base: 'bg-warning text-text-on-
|
|
56
|
+
warning: { base: 'bg-warning text-text-on-warning' },
|
|
57
57
|
danger: { base: 'bg-danger text-text-on-primary' },
|
|
58
58
|
neutral: { base: 'bg-surface-inverted text-text-inverted' }
|
|
59
59
|
},
|
|
@@ -52,20 +52,20 @@
|
|
|
52
52
|
--color-warm-neutral-900: oklch(0.2 0.008 45);
|
|
53
53
|
--color-warm-neutral-950: oklch(0.12 0.006 45);
|
|
54
54
|
|
|
55
|
-
/* Darkened *-500 / *-600 / *-700 so text-on-primary (white
|
|
56
|
-
AA (4.5:1) on the solid intent backgrounds **in light
|
|
57
|
-
--color-<intent> resolves to the -500/-600 shades.
|
|
58
|
-
L=0.65 which produced ~3:1 contrast — below AA.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
55
|
+
/* Darkened *-500 / *-600 / *-700 so text-on-primary (white in light mode)
|
|
56
|
+
passes WCAG AA (4.5:1) on the solid intent backgrounds **in light
|
|
57
|
+
mode**, where --color-<intent> resolves to the -500/-600 shades.
|
|
58
|
+
Previous values had L=0.65 which produced ~3:1 contrast — below AA.
|
|
59
|
+
Warning is the one inverted ramp: its fill stays light in both modes
|
|
60
|
+
(500 keeps its yellow at L=0.75) and pairs with the dark,
|
|
61
|
+
non-mode-aware `text-on-warning` (= warning-950), not white.
|
|
62
|
+
|
|
63
|
+
In dark mode --color-<intent> resolves to the *lighter* -400/-300/-200
|
|
64
|
+
shades and pairs with the dark branch of the mode-aware
|
|
65
|
+
`text-on-primary` (semantic.css, 2026-07-14). Both directions are
|
|
66
|
+
measured across all six themes by style/contrast.test.ts. Do not
|
|
67
|
+
lighten these ramps to "help" dark mode; light mode is the branch
|
|
68
|
+
these stops guarantee. */
|
|
69
69
|
--color-success-50: oklch(0.95 0.03 140);
|
|
70
70
|
--color-success-100: oklch(0.9 0.05 140);
|
|
71
71
|
--color-success-200: oklch(0.82 0.08 140);
|
|
@@ -85,7 +85,14 @@
|
|
|
85
85
|
--color-warning-400: oklch(0.66 0.14 80);
|
|
86
86
|
--color-warning-500: oklch(0.75 0.15 80);
|
|
87
87
|
--color-warning-600: oklch(0.65 0.15 80);
|
|
88
|
-
|
|
88
|
+
/* L=0.59, not the ramp's usual 0.55: warning-700 is the light-mode press
|
|
89
|
+
fill (--color-warning-active) under the dark `text-on-warning`
|
|
90
|
+
(warning-950). Warning's ramp is inverted — pressing moves TOWARD the
|
|
91
|
+
dark label — and at L=0.55 the press state measured 3.90–4.05:1, under
|
|
92
|
+
AA. 0.59 is the lowest 0.01 step at which every themed hue clears
|
|
93
|
+
4.5:1 (0.58 still fails forest's hue 60 at 4.46:1). Mirrored by the
|
|
94
|
+
forest/sunset ramps; guarded by contrast.test.ts. */
|
|
95
|
+
--color-warning-700: oklch(0.59 0.13 80);
|
|
89
96
|
--color-warning-800: oklch(0.45 0.11 80);
|
|
90
97
|
--color-warning-900: oklch(0.25 0.08 80);
|
|
91
98
|
--color-warning-950: oklch(0.15 0.05 80);
|
package/dist/style/semantic.css
CHANGED
|
@@ -54,12 +54,13 @@
|
|
|
54
54
|
--color-text-tertiary: light-dark(var(--color-neutral-600), var(--color-neutral-300));
|
|
55
55
|
--color-text-quaternary: light-dark(var(--color-neutral-500), var(--color-neutral-400));
|
|
56
56
|
--color-text-disabled: light-dark(var(--color-neutral-300), var(--color-neutral-600));
|
|
57
|
-
/* The
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
deliberately NOT aliased to one
|
|
61
|
-
--color-text-on-dark)`), even though
|
|
62
|
-
they answer to different fills and
|
|
57
|
+
/* The on-colors below pair text with a *fill* rather than a surface.
|
|
58
|
+
text-on-dark and text-on-primary answer fills that are dark in light
|
|
59
|
+
mode and light in dark mode, so the label has to travel the opposite
|
|
60
|
+
way — white, then near-black. They are deliberately NOT aliased to one
|
|
61
|
+
another (`text-on-primary: var(--color-text-on-dark)`), even though
|
|
62
|
+
they carry the same value today — they answer to different fills and
|
|
63
|
+
must stay independently overridable:
|
|
63
64
|
|
|
64
65
|
- text-on-dark is the partner of the avatar identity palette, whose 12
|
|
65
66
|
slots hold ONE lightness per mode (0.45 / 0.72) by construction.
|
|
@@ -75,10 +76,21 @@
|
|
|
75
76
|
Material-3 `onPrimary` pattern). White here was unconditional until
|
|
76
77
|
2026-07-14, which put 125 of the 126 dark-mode intent fills under WCAG AA
|
|
77
78
|
— down to 1.51:1, and getting *worse* on press. The mode-aware branch
|
|
78
|
-
clears all 108 fills this token governs; `warning` is not one of them
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
clears all 108 fills this token governs; `warning` is not one of them —
|
|
80
|
+
its fill is light in BOTH modes, so it carries its own non-mode-aware
|
|
81
|
+
on-color below (`--color-text-on-warning`). */
|
|
81
82
|
--color-text-on-primary: light-dark(var(--color-neutral-0), var(--color-neutral-900));
|
|
83
|
+
/* Warning's own on-color. Warning is the one intent whose fill stays a
|
|
84
|
+
light amber in BOTH modes (base/hover/active ride L 0.59–0.82), so unlike
|
|
85
|
+
text-on-primary this token is deliberately NOT mode-aware — the label is
|
|
86
|
+
a warm dark in both modes. It rides the warning ramp's own 950 stop
|
|
87
|
+
rather than a neutral, so theme re-hues (forest 60, sunset 92) flow
|
|
88
|
+
through and the label reads as part of the swatch instead of soot on top
|
|
89
|
+
of it. Until 2026-07-20 filled warning paired with `text-on-surface` — a
|
|
90
|
+
*surface* token that flips light in dark mode — which put all 18
|
|
91
|
+
dark-mode warning fills at 1.51–2.80:1. Measured across every theme ×
|
|
92
|
+
mode × state by style/contrast.test.ts. */
|
|
93
|
+
--color-text-on-warning: var(--color-warning-950);
|
|
82
94
|
--color-text-on-surface: light-dark(var(--color-neutral-900), var(--color-neutral-100));
|
|
83
95
|
|
|
84
96
|
/* === PRIMARY INTENT ===
|
|
@@ -86,7 +86,9 @@
|
|
|
86
86
|
--color-warning-400: oklch(0.66 0.14 60);
|
|
87
87
|
--color-warning-500: oklch(0.75 0.15 60);
|
|
88
88
|
--color-warning-600: oklch(0.65 0.15 60);
|
|
89
|
-
|
|
89
|
+
/* 0.59 mirrors foundation.css: light-mode press fill under the dark
|
|
90
|
+
text-on-warning — hue 60 is the binding case (0.58 = 4.46:1, under AA). */
|
|
91
|
+
--color-warning-700: oklch(0.59 0.13 60);
|
|
90
92
|
--color-warning-800: oklch(0.45 0.11 60);
|
|
91
93
|
--color-warning-900: oklch(0.25 0.08 60);
|
|
92
94
|
--color-warning-950: oklch(0.15 0.05 60);
|
|
@@ -73,7 +73,9 @@
|
|
|
73
73
|
--color-warning-400: oklch(0.66 0.14 92);
|
|
74
74
|
--color-warning-500: oklch(0.75 0.15 92);
|
|
75
75
|
--color-warning-600: oklch(0.65 0.15 92);
|
|
76
|
-
|
|
76
|
+
/* 0.59 mirrors foundation.css: light-mode press fill under the dark
|
|
77
|
+
text-on-warning (AA floor across all themed hues). */
|
|
78
|
+
--color-warning-700: oklch(0.59 0.13 92);
|
|
77
79
|
--color-warning-800: oklch(0.45 0.11 92);
|
|
78
80
|
--color-warning-900: oklch(0.25 0.08 92);
|
|
79
81
|
--color-warning-950: oklch(0.15 0.05 92);
|
|
@@ -99,7 +99,7 @@ const foundationColors = {
|
|
|
99
99
|
'400': 'oklch(0.66 0.14 80)',
|
|
100
100
|
'500': 'oklch(0.75 0.15 80)',
|
|
101
101
|
'600': 'oklch(0.65 0.15 80)',
|
|
102
|
-
'700': 'oklch(0.
|
|
102
|
+
'700': 'oklch(0.59 0.13 80)',
|
|
103
103
|
'800': 'oklch(0.45 0.11 80)',
|
|
104
104
|
'900': 'oklch(0.25 0.08 80)',
|
|
105
105
|
'950': 'oklch(0.15 0.05 80)'
|
|
@@ -155,6 +155,10 @@ const semanticTokens = {
|
|
|
155
155
|
disabled: { value: '{color.neutral.300}', description: 'Disabled text' },
|
|
156
156
|
'on-dark': { value: '{color.neutral.0}', description: 'Text on dark surfaces' },
|
|
157
157
|
'on-primary': { value: '{color.neutral.0}', description: 'Text on primary color bg' },
|
|
158
|
+
'on-warning': {
|
|
159
|
+
value: '{color.warning.950}',
|
|
160
|
+
description: 'Text on the warning fill (warm dark in both modes)'
|
|
161
|
+
},
|
|
158
162
|
'on-surface': { value: '{color.neutral.900}', description: 'Text on tinted surfaces' }
|
|
159
163
|
},
|
|
160
164
|
border: {
|
package/dist/utils/overlay.js
CHANGED
|
@@ -18,8 +18,18 @@ export function trapFocus(event, container) {
|
|
|
18
18
|
if (!isBrowser)
|
|
19
19
|
return;
|
|
20
20
|
const focusable = getFocusableElements(container);
|
|
21
|
-
if (focusable.length === 0)
|
|
21
|
+
if (focusable.length === 0) {
|
|
22
|
+
// Nothing tabbable inside the overlay (untitled Dialog with static
|
|
23
|
+
// children, Drawer with hideCloseButton): park focus on the container —
|
|
24
|
+
// the panel that focusFirstElement's fallback focused via tabindex="-1" —
|
|
25
|
+
// instead of letting Tab walk out of the modal. Browsers with a real top
|
|
26
|
+
// layer get this from `showModal()` inertness; the guard keeps the trap's
|
|
27
|
+
// contract honest everywhere else. `contains` includes the container
|
|
28
|
+
// itself, so focus already parked there stays put.
|
|
29
|
+
if (container?.contains(document.activeElement))
|
|
30
|
+
event.preventDefault();
|
|
22
31
|
return;
|
|
32
|
+
}
|
|
23
33
|
const first = focusable[0];
|
|
24
34
|
const last = focusable[focusable.length - 1];
|
|
25
35
|
if (event.shiftKey) {
|
|
@@ -74,8 +84,20 @@ export function focusFirstElement(container) {
|
|
|
74
84
|
return;
|
|
75
85
|
tick().then(() => {
|
|
76
86
|
const focusable = getFocusableElements(container);
|
|
77
|
-
if (focusable.length > 0)
|
|
87
|
+
if (focusable.length > 0) {
|
|
78
88
|
focusable[0].focus();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// No focusable descendant — e.g. an untitled Dialog whose children are
|
|
92
|
+
// static text (no header, so no close button), or a Drawer with
|
|
93
|
+
// hideCloseButton. Fall back to the container itself, which the overlay
|
|
94
|
+
// panels make programmatically focusable via tabindex="-1" (excluded from
|
|
95
|
+
// getFocusableElements, so it never joins the Tab cycle). Without this,
|
|
96
|
+
// focus stays on <body>: the overlay's element-level keydown never fires,
|
|
97
|
+
// leaving ESC to the window fallback and the Tab trap inert until the
|
|
98
|
+
// user clicks in — a WCAG 2.1.2 problem. Mirrors the native <dialog>
|
|
99
|
+
// focusing steps, which likewise fall back to the dialog element.
|
|
100
|
+
container?.focus();
|
|
79
101
|
});
|
|
80
102
|
}
|
|
81
103
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@urbicon-ui/blocks",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.26.0",
|
|
4
4
|
"description": "Svelte 5 UI component library with Tailwind CSS 4, OKLCH design tokens and zero runtime dependencies",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -91,8 +91,8 @@
|
|
|
91
91
|
"@sveltejs/package": "^2.5.8",
|
|
92
92
|
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
|
93
93
|
"@tailwindcss/vite": "^4.3.1",
|
|
94
|
-
"@urbicon-ui/i18n": "6.
|
|
95
|
-
"@urbicon-ui/shared-types": "6.
|
|
94
|
+
"@urbicon-ui/i18n": "6.26.0",
|
|
95
|
+
"@urbicon-ui/shared-types": "6.26.0",
|
|
96
96
|
"prettier": "^3.8.4",
|
|
97
97
|
"prettier-plugin-svelte": "^4.1.1",
|
|
98
98
|
"prettier-plugin-tailwindcss": "^0.8.0",
|