@sovereignfs/ui 0.21.3 → 0.33.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/Button.module.css +75 -8
- package/dist/Calendar.module.css +126 -0
- package/dist/Card.module.css +4 -2
- package/dist/Checkbox.module.css +109 -0
- package/dist/CodeTextarea.module.css +53 -0
- package/dist/ConfirmDialog.module.css +109 -0
- package/dist/DatePicker.module.css +57 -0
- package/dist/Dialog.module.css +73 -46
- package/dist/DragHandleRow.module.css +57 -0
- package/dist/Drawer.module.css +61 -0
- package/dist/FormField.module.css +5 -0
- package/dist/Icon.module.css +5 -0
- package/dist/Input.module.css +10 -0
- package/dist/Menu.module.css +82 -0
- package/dist/NavTabs.module.css +4 -2
- package/dist/OverlayHeader.module.css +98 -0
- package/dist/Popover.module.css +31 -1
- package/dist/SegmentedControl.module.css +4 -2
- package/dist/Select.module.css +9 -0
- package/dist/Sheet.module.css +55 -0
- package/dist/SplitPane.module.css +85 -0
- package/dist/StatusBadge.module.css +59 -0
- package/dist/SystemBanner.module.css +4 -2
- package/dist/Tabs.module.css +4 -2
- package/dist/TagInput.module.css +141 -0
- package/dist/Textarea.module.css +39 -0
- package/dist/Toast.module.css +7 -5
- package/dist/Toggle.module.css +1 -1
- package/dist/Tooltip.module.css +6 -1
- package/dist/index.d.ts +549 -20
- package/dist/index.js +1496 -193
- package/dist/tokens/primitives.css +19 -0
- package/dist/tokens/semantic.css +19 -0
- package/package.json +1 -1
- package/src/__tests__/motion.test.tsx +105 -0
- package/src/components/Button/Button.module.css +75 -8
- package/src/components/Button/Button.stories.tsx +6 -0
- package/src/components/Button/Button.tsx +17 -1
- package/src/components/Button/__tests__/Button.test.tsx +19 -0
- package/src/components/Calendar/Calendar.module.css +126 -0
- package/src/components/Calendar/Calendar.tsx +213 -0
- package/src/components/Calendar/__tests__/Calendar.test.tsx +98 -0
- package/src/components/Calendar/dateUtils.ts +97 -0
- package/src/components/Card/Card.module.css +4 -2
- package/src/components/Checkbox/Checkbox.module.css +109 -0
- package/src/components/Checkbox/Checkbox.tsx +78 -0
- package/src/components/CodeTextarea/CodeTextarea.module.css +53 -0
- package/src/components/CodeTextarea/CodeTextarea.stories.tsx +77 -0
- package/src/components/CodeTextarea/CodeTextarea.tsx +36 -0
- package/src/components/ConfirmDialog/ConfirmDialog.module.css +109 -0
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +124 -0
- package/src/components/ConfirmDialog/__tests__/ConfirmDialog.test.tsx +146 -0
- package/src/components/DatePicker/DatePicker.module.css +57 -0
- package/src/components/DatePicker/DatePicker.tsx +103 -0
- package/src/components/DatePicker/__tests__/DatePicker.test.tsx +89 -0
- package/src/components/Dialog/Dialog.module.css +73 -46
- package/src/components/Dialog/Dialog.stories.tsx +51 -1
- package/src/components/Dialog/Dialog.tsx +86 -22
- package/src/components/Dialog/__tests__/Dialog.test.tsx +67 -3
- package/src/components/DragHandleRow/DragHandleRow.module.css +57 -0
- package/src/components/DragHandleRow/DragHandleRow.tsx +61 -0
- package/src/components/Drawer/Drawer.module.css +61 -0
- package/src/components/Drawer/Drawer.tsx +117 -13
- package/src/components/Drawer/__tests__/Drawer.test.tsx +123 -2
- package/src/components/FormField/FormField.module.css +5 -0
- package/src/components/FormField/FormField.tsx +36 -11
- package/src/components/FormField/__tests__/FormField.test.tsx +83 -0
- package/src/components/Icon/Icon.module.css +5 -0
- package/src/components/Icon/Icon.stories.tsx +4 -3
- package/src/components/Icon/Icon.tsx +1 -1
- package/src/components/Icon/icons/calendar.tsx +23 -0
- package/src/components/Icon/icons/ellipsis-vertical.tsx +22 -0
- package/src/components/Icon/icons/index.ts +8 -4
- package/src/components/Icon/icons/sliders-horizontal.tsx +9 -9
- package/src/components/Input/Input.module.css +10 -0
- package/src/components/Menu/Menu.module.css +82 -0
- package/src/components/Menu/Menu.tsx +137 -0
- package/src/components/Menu/__tests__/Menu.test.tsx +197 -0
- package/src/components/NavTabs/NavTabs.module.css +4 -2
- package/src/components/OverlayHeader/OverlayHeader.module.css +98 -0
- package/src/components/OverlayHeader/OverlayHeader.tsx +62 -0
- package/src/components/OverlayHeader/__tests__/OverlayHeader.test.tsx +51 -0
- package/src/components/Popover/Popover.module.css +31 -1
- package/src/components/Popover/Popover.stories.tsx +126 -1
- package/src/components/Popover/Popover.tsx +140 -7
- package/src/components/SegmentedControl/SegmentedControl.module.css +4 -2
- package/src/components/Select/Select.module.css +9 -0
- package/src/components/Select/Select.tsx +10 -2
- package/src/components/Sheet/Sheet.module.css +55 -0
- package/src/components/Sheet/Sheet.tsx +151 -0
- package/src/components/Sheet/__tests__/Sheet.test.tsx +99 -0
- package/src/components/SplitPane/SplitPane.module.css +85 -0
- package/src/components/SplitPane/SplitPane.stories.tsx +160 -0
- package/src/components/SplitPane/SplitPane.tsx +149 -0
- package/src/components/SplitPane/__tests__/SplitPane.test.tsx +51 -0
- package/src/components/StatusBadge/StatusBadge.module.css +59 -0
- package/src/components/StatusBadge/StatusBadge.stories.tsx +74 -0
- package/src/components/StatusBadge/StatusBadge.tsx +65 -0
- package/src/components/SystemBanner/SystemBanner.module.css +4 -2
- package/src/components/Tabs/Tabs.module.css +4 -2
- package/src/components/TagInput/TagInput.module.css +141 -0
- package/src/components/TagInput/TagInput.stories.tsx +109 -0
- package/src/components/TagInput/TagInput.tsx +174 -0
- package/src/components/TagInput/__tests__/TagInput.test.tsx +69 -0
- package/src/components/Textarea/Textarea.module.css +39 -0
- package/src/components/Textarea/Textarea.tsx +15 -0
- package/src/components/Textarea/__tests__/Textarea.test.tsx +29 -0
- package/src/components/Toast/Toast.module.css +7 -5
- package/src/components/Toggle/Toggle.module.css +1 -1
- package/src/components/Tooltip/Tooltip.module.css +6 -1
- package/src/hooks/__tests__/useDoubleTap.test.tsx +117 -0
- package/src/hooks/__tests__/useIsMobile.test.tsx +80 -0
- package/src/hooks/__tests__/useLongPress.test.tsx +158 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useDoubleTap.ts +91 -0
- package/src/hooks/useIsMobile.ts +33 -0
- package/src/hooks/useLongPress.ts +185 -0
- package/src/index.ts +37 -2
- package/src/motion.ts +78 -0
- package/src/stories/Checkbox.stories.tsx +45 -0
- package/src/stories/DesignSystemOverview.stories.tsx +354 -8
- package/src/stories/DragHandleRow.stories.tsx +41 -0
- package/src/stories/FormField.stories.tsx +8 -8
- package/src/stories/InteractionHooks.stories.tsx +388 -0
- package/src/stories/MobilePatterns.stories.tsx +4 -4
- package/src/stories/Textarea.stories.tsx +51 -0
- package/src/stories/TokenGallery.stories.tsx +87 -1
- package/src/tokens/primitives.css +19 -0
- package/src/tokens/semantic.css +19 -0
- package/src/components/Icon/icons/terminal.tsx +0 -19
package/dist/Button.module.css
CHANGED
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
font-weight: var(--sv-font-weight-medium);
|
|
10
10
|
line-height: 1;
|
|
11
11
|
cursor: pointer;
|
|
12
|
+
/* Removes the ~300ms double-tap-to-zoom delay on touch — this is a tap
|
|
13
|
+
target, never a pinch-zoom surface. */
|
|
14
|
+
touch-action: manipulation;
|
|
12
15
|
transition:
|
|
13
16
|
background-color 0.15s ease,
|
|
14
17
|
border-color 0.15s ease,
|
|
@@ -25,6 +28,15 @@
|
|
|
25
28
|
cursor: not-allowed;
|
|
26
29
|
}
|
|
27
30
|
|
|
31
|
+
/* Touch target: gated to (pointer: coarse) — the *primary* pointer, not
|
|
32
|
+
(any-pointer: coarse) — so a touchscreen laptop with mouse/trackpad as
|
|
33
|
+
primary keeps desktop density (see mobile design-system plan, Part 4 #5). */
|
|
34
|
+
@media (pointer: coarse) {
|
|
35
|
+
.button {
|
|
36
|
+
min-height: var(--sv-touch-target-min, 44px);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
28
40
|
/* Sizes */
|
|
29
41
|
.sm {
|
|
30
42
|
padding: var(--sv-space-1) var(--sv-space-3);
|
|
@@ -37,14 +49,51 @@
|
|
|
37
49
|
font-weight: var(--sv-font-weight-semibold);
|
|
38
50
|
}
|
|
39
51
|
|
|
52
|
+
/* Loading spinner — a self-contained token-only spinner rather than reusing
|
|
53
|
+
the Spinner component: Spinner's border colors are semantic-fixed
|
|
54
|
+
(`--sv-color-accent`), which would be invisible against a primary button's
|
|
55
|
+
accent background, and overriding a second CSS module's rule on the same
|
|
56
|
+
element is a cross-module cascade-order gamble (see ConfirmDialog's
|
|
57
|
+
`.destructiveConfirm` comment for the same tradeoff). `currentColor` picks
|
|
58
|
+
up each variant's own text color for free. */
|
|
59
|
+
.spinner {
|
|
60
|
+
display: inline-block;
|
|
61
|
+
width: var(--sv-icon-size-sm);
|
|
62
|
+
height: var(--sv-icon-size-sm);
|
|
63
|
+
flex-shrink: 0;
|
|
64
|
+
border: 2px solid currentColor;
|
|
65
|
+
border-top-color: transparent;
|
|
66
|
+
border-radius: var(--sv-radius-full);
|
|
67
|
+
opacity: 0.7;
|
|
68
|
+
animation: button-spin 0.7s linear infinite;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@keyframes button-spin {
|
|
72
|
+
to {
|
|
73
|
+
transform: rotate(360deg);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@media (prefers-reduced-motion: reduce) {
|
|
78
|
+
.spinner {
|
|
79
|
+
animation-play-state: paused;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
40
83
|
/* Variants */
|
|
41
84
|
.primary {
|
|
42
85
|
background-color: var(--sv-color-accent);
|
|
43
86
|
color: var(--sv-color-text-on-accent);
|
|
44
87
|
}
|
|
45
88
|
|
|
46
|
-
|
|
47
|
-
|
|
89
|
+
@media (hover: hover) {
|
|
90
|
+
.primary:hover:not(:disabled) {
|
|
91
|
+
background-color: var(--sv-color-accent-hover);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.primary:active:not(:disabled) {
|
|
96
|
+
background-color: color-mix(in srgb, var(--sv-color-accent) 80%, black);
|
|
48
97
|
}
|
|
49
98
|
|
|
50
99
|
.secondary {
|
|
@@ -53,8 +102,14 @@
|
|
|
53
102
|
border-color: var(--sv-color-border-strong);
|
|
54
103
|
}
|
|
55
104
|
|
|
56
|
-
|
|
57
|
-
|
|
105
|
+
@media (hover: hover) {
|
|
106
|
+
.secondary:hover:not(:disabled) {
|
|
107
|
+
background-color: var(--sv-color-surface-sunken);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.secondary:active:not(:disabled) {
|
|
112
|
+
background-color: color-mix(in srgb, var(--sv-color-surface-sunken) 85%, black);
|
|
58
113
|
}
|
|
59
114
|
|
|
60
115
|
.ghost {
|
|
@@ -62,8 +117,14 @@
|
|
|
62
117
|
color: var(--sv-color-text-primary);
|
|
63
118
|
}
|
|
64
119
|
|
|
65
|
-
|
|
66
|
-
|
|
120
|
+
@media (hover: hover) {
|
|
121
|
+
.ghost:hover:not(:disabled) {
|
|
122
|
+
background-color: var(--sv-color-surface-sunken);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.ghost:active:not(:disabled) {
|
|
127
|
+
background-color: color-mix(in srgb, var(--sv-color-surface-sunken) 85%, black);
|
|
67
128
|
}
|
|
68
129
|
|
|
69
130
|
.destructive {
|
|
@@ -72,6 +133,12 @@
|
|
|
72
133
|
border-color: var(--sv-color-error-border);
|
|
73
134
|
}
|
|
74
135
|
|
|
75
|
-
|
|
76
|
-
|
|
136
|
+
@media (hover: hover) {
|
|
137
|
+
.destructive:hover:not(:disabled) {
|
|
138
|
+
background-color: var(--sv-color-error-surface);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.destructive:active:not(:disabled) {
|
|
143
|
+
background-color: color-mix(in srgb, var(--sv-color-error-surface) 85%, black);
|
|
77
144
|
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/* Calendar — month grid. Tokens only. Grid columns are equal-width via
|
|
2
|
+
* `1fr` repeated 7 times rather than a fixed px size, so the component
|
|
3
|
+
* scales cleanly inside both a Popover panel (desktop) and a full-width
|
|
4
|
+
* Drawer sheet (mobile). */
|
|
5
|
+
|
|
6
|
+
.calendar {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
gap: var(--sv-space-3);
|
|
10
|
+
font-family: var(--sv-font-family);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.header {
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: space-between;
|
|
17
|
+
gap: var(--sv-space-2);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.navButton {
|
|
21
|
+
display: inline-flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
width: var(--sv-touch-target-min, 44px);
|
|
25
|
+
height: var(--sv-touch-target-min, 44px);
|
|
26
|
+
flex-shrink: 0;
|
|
27
|
+
border: none;
|
|
28
|
+
border-radius: var(--sv-radius-md);
|
|
29
|
+
background: transparent;
|
|
30
|
+
color: var(--sv-color-text-muted);
|
|
31
|
+
cursor: pointer;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@media (hover: hover) {
|
|
35
|
+
.navButton:hover {
|
|
36
|
+
background: var(--sv-color-surface-sunken);
|
|
37
|
+
color: var(--sv-color-text-primary);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.navButton:focus-visible {
|
|
42
|
+
outline: 2px solid var(--sv-color-focus-ring);
|
|
43
|
+
outline-offset: -2px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.monthLabel {
|
|
47
|
+
font-size: var(--sv-font-size-sm);
|
|
48
|
+
font-weight: var(--sv-font-weight-semibold);
|
|
49
|
+
color: var(--sv-color-text-primary);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.grid {
|
|
53
|
+
display: flex;
|
|
54
|
+
flex-direction: column;
|
|
55
|
+
gap: var(--sv-space-1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.weekdayRow,
|
|
59
|
+
.week {
|
|
60
|
+
display: grid;
|
|
61
|
+
grid-template-columns: repeat(7, 1fr);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.weekday {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
justify-content: center;
|
|
68
|
+
height: var(--sv-space-6);
|
|
69
|
+
font-size: var(--sv-font-size-xs);
|
|
70
|
+
font-weight: var(--sv-font-weight-medium);
|
|
71
|
+
color: var(--sv-color-text-subtle);
|
|
72
|
+
text-transform: uppercase;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.day {
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
justify-content: center;
|
|
79
|
+
width: 100%;
|
|
80
|
+
/* Square-ish cell that also clears the touch-target minimum — height
|
|
81
|
+
drives the grid's row size; width fills its 1fr column. */
|
|
82
|
+
min-height: var(--sv-touch-target-min, 44px);
|
|
83
|
+
border: none;
|
|
84
|
+
border-radius: var(--sv-radius-md);
|
|
85
|
+
background: transparent;
|
|
86
|
+
color: var(--sv-color-text-primary);
|
|
87
|
+
font-size: var(--sv-font-size-sm);
|
|
88
|
+
cursor: pointer;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@media (hover: hover) {
|
|
92
|
+
.day:hover:not(:disabled) {
|
|
93
|
+
background: var(--sv-color-surface-sunken);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.day:focus-visible {
|
|
98
|
+
outline: 2px solid var(--sv-color-focus-ring);
|
|
99
|
+
outline-offset: -2px;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.day:disabled {
|
|
103
|
+
color: var(--sv-color-text-subtle);
|
|
104
|
+
cursor: not-allowed;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.dayOutside {
|
|
108
|
+
color: var(--sv-color-text-subtle);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.dayToday {
|
|
112
|
+
font-weight: var(--sv-font-weight-semibold);
|
|
113
|
+
box-shadow: inset 0 0 0 1px var(--sv-color-border-strong);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.daySelected,
|
|
117
|
+
.daySelected:disabled {
|
|
118
|
+
background: var(--sv-color-accent);
|
|
119
|
+
color: var(--sv-color-text-on-accent);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@media (hover: hover) {
|
|
123
|
+
.daySelected:hover:not(:disabled) {
|
|
124
|
+
background: var(--sv-color-accent-hover);
|
|
125
|
+
}
|
|
126
|
+
}
|
package/dist/Card.module.css
CHANGED
|
@@ -24,8 +24,10 @@
|
|
|
24
24
|
transition: border-color 0.15s ease;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
@media (hover: hover) {
|
|
28
|
+
.interactive:hover {
|
|
29
|
+
border-color: var(--sv-color-border-strong);
|
|
30
|
+
}
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
.interactive:focus-visible {
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
.root {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
gap: var(--sv-space-2);
|
|
5
|
+
cursor: pointer;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/* The visual box */
|
|
9
|
+
.box {
|
|
10
|
+
--checkbox-box-size: 18px;
|
|
11
|
+
position: relative;
|
|
12
|
+
flex-shrink: 0;
|
|
13
|
+
width: var(--checkbox-box-size);
|
|
14
|
+
height: var(--checkbox-box-size);
|
|
15
|
+
border-radius: var(--sv-radius-sm);
|
|
16
|
+
border: 1.5px solid var(--sv-color-border-strong);
|
|
17
|
+
background: var(--sv-color-surface);
|
|
18
|
+
transition:
|
|
19
|
+
background-color 0.15s ease,
|
|
20
|
+
border-color 0.15s ease;
|
|
21
|
+
display: flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.checked {
|
|
27
|
+
background-color: var(--sv-color-accent);
|
|
28
|
+
border-color: var(--sv-color-accent);
|
|
29
|
+
color: var(--sv-white);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* Hide the native input visually but keep it accessible */
|
|
33
|
+
.input {
|
|
34
|
+
position: absolute;
|
|
35
|
+
inset: 0;
|
|
36
|
+
opacity: 0;
|
|
37
|
+
margin: 0;
|
|
38
|
+
width: 100%;
|
|
39
|
+
height: 100%;
|
|
40
|
+
cursor: pointer;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.input:disabled {
|
|
44
|
+
cursor: not-allowed;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Expand the tappable region to the platform's minimum touch target without
|
|
48
|
+
growing the visible box — consumers (e.g. task rows) align the box to the
|
|
49
|
+
pixel against header icons, so its visual footprint and layout must stay
|
|
50
|
+
identical. Gated to (pointer: coarse), the *primary* pointer, so a
|
|
51
|
+
touchscreen laptop with mouse/trackpad as primary keeps desktop density. */
|
|
52
|
+
@media (pointer: coarse) {
|
|
53
|
+
.input {
|
|
54
|
+
inset: calc((var(--checkbox-box-size) - var(--sv-touch-target-min, 44px)) / 2);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.input:focus-visible + .tick,
|
|
59
|
+
.input:focus-visible {
|
|
60
|
+
outline: none;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.box:has(.input:focus-visible) {
|
|
64
|
+
outline: 2px solid var(--sv-color-focus-ring);
|
|
65
|
+
outline-offset: 2px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.tick {
|
|
69
|
+
width: 10px;
|
|
70
|
+
height: 8px;
|
|
71
|
+
pointer-events: none;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Label */
|
|
75
|
+
.label {
|
|
76
|
+
font-size: var(--sv-font-size-sm);
|
|
77
|
+
color: var(--sv-color-text-primary);
|
|
78
|
+
cursor: pointer;
|
|
79
|
+
user-select: none;
|
|
80
|
+
transition: color 0.15s ease;
|
|
81
|
+
/* Strike-through animates via clip-path on a pseudo-element */
|
|
82
|
+
position: relative;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.label::after {
|
|
86
|
+
content: '';
|
|
87
|
+
position: absolute;
|
|
88
|
+
left: 0;
|
|
89
|
+
top: 50%;
|
|
90
|
+
width: 100%;
|
|
91
|
+
height: 1.5px;
|
|
92
|
+
background: var(--sv-color-text-muted);
|
|
93
|
+
transform: scaleX(0);
|
|
94
|
+
transform-origin: left center;
|
|
95
|
+
transition: transform 0.2s ease;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.struck {
|
|
99
|
+
color: var(--sv-color-text-muted);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.struck::after {
|
|
103
|
+
transform: scaleX(1);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.disabled {
|
|
107
|
+
opacity: 0.5;
|
|
108
|
+
cursor: not-allowed;
|
|
109
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
.textarea {
|
|
2
|
+
display: block;
|
|
3
|
+
width: 100%;
|
|
4
|
+
min-height: 180px;
|
|
5
|
+
max-height: min(70vh, 720px);
|
|
6
|
+
padding: var(--sv-space-3);
|
|
7
|
+
font-family: var(--sv-font-family-mono);
|
|
8
|
+
font-size: var(--sv-font-size-sm);
|
|
9
|
+
line-height: 1.6;
|
|
10
|
+
color: var(--sv-color-text-primary);
|
|
11
|
+
tab-size: 2;
|
|
12
|
+
white-space: pre;
|
|
13
|
+
overflow: auto;
|
|
14
|
+
resize: vertical;
|
|
15
|
+
background: var(--sv-color-surface);
|
|
16
|
+
border: 1px solid var(--sv-color-border-strong);
|
|
17
|
+
border-radius: var(--sv-radius-md);
|
|
18
|
+
transition:
|
|
19
|
+
border-color 0.15s ease,
|
|
20
|
+
box-shadow 0.15s ease;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.textarea::placeholder {
|
|
24
|
+
color: var(--sv-color-text-muted);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.textarea:focus-visible {
|
|
28
|
+
outline: none;
|
|
29
|
+
border-color: var(--sv-color-accent);
|
|
30
|
+
box-shadow: 0 0 0 2px var(--sv-color-focus-ring);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.textarea:read-only {
|
|
34
|
+
color: var(--sv-color-text-muted);
|
|
35
|
+
background: var(--sv-color-surface-sunken);
|
|
36
|
+
border-color: var(--sv-color-border);
|
|
37
|
+
cursor: default;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.textarea:disabled {
|
|
41
|
+
opacity: 0.5;
|
|
42
|
+
cursor: not-allowed;
|
|
43
|
+
resize: none;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.invalid {
|
|
47
|
+
border-color: var(--sv-color-error-border);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.invalid:focus-visible {
|
|
51
|
+
border-color: var(--sv-color-error-border);
|
|
52
|
+
box-shadow: 0 0 0 2px var(--sv-color-error-border);
|
|
53
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/* ConfirmDialog — built on the native <dialog> element (see the component's
|
|
2
|
+
* own doc comment for why: content-sized, top-layer stacking, ::backdrop for
|
|
3
|
+
* free). Tokens only. */
|
|
4
|
+
|
|
5
|
+
.dialog {
|
|
6
|
+
border: none;
|
|
7
|
+
border-radius: var(--sv-radius-lg);
|
|
8
|
+
background: var(--sv-color-surface);
|
|
9
|
+
box-shadow: var(--sv-shadow-overlay);
|
|
10
|
+
padding: 0;
|
|
11
|
+
width: 22rem;
|
|
12
|
+
max-width: calc(100vw - var(--sv-space-8));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.dialog::backdrop {
|
|
16
|
+
background: var(--sv-color-scrim);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.body {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
gap: var(--sv-space-4);
|
|
23
|
+
padding: var(--sv-space-6);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.title {
|
|
27
|
+
margin: 0;
|
|
28
|
+
font-size: var(--sv-font-size-lg);
|
|
29
|
+
font-weight: var(--sv-font-weight-semibold);
|
|
30
|
+
color: var(--sv-color-text-primary);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.message {
|
|
34
|
+
margin: 0;
|
|
35
|
+
font-size: var(--sv-font-size-sm);
|
|
36
|
+
color: var(--sv-color-text-muted);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.error {
|
|
40
|
+
margin: 0;
|
|
41
|
+
font-size: var(--sv-font-size-xs);
|
|
42
|
+
color: var(--sv-color-error-text);
|
|
43
|
+
padding: var(--sv-space-2) var(--sv-space-3);
|
|
44
|
+
border: 1px solid var(--sv-color-error-border);
|
|
45
|
+
border-radius: var(--sv-radius-sm);
|
|
46
|
+
background-color: var(--sv-color-error-surface);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.actions {
|
|
50
|
+
display: flex;
|
|
51
|
+
gap: var(--sv-space-3);
|
|
52
|
+
justify-content: flex-end;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Matches Button's own .button + .md structural rules exactly (padding,
|
|
56
|
+
* radius, font weight, focus-visible ring, disabled state, touch target,
|
|
57
|
+
* hover guard, active/pressed state) so it reads as the same control family
|
|
58
|
+
* — only the color scheme differs. Not built as an override of Button's own
|
|
59
|
+
* CSS module: cross-module class-order in the cascade isn't guaranteed, and
|
|
60
|
+
* an inline-style override would defeat Button's own :hover rule (inline
|
|
61
|
+
* styles always win over an external stylesheet, hover or not). A plain
|
|
62
|
+
* button with its own tokens sidesteps both problems. */
|
|
63
|
+
.destructiveConfirm {
|
|
64
|
+
display: inline-flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
justify-content: center;
|
|
67
|
+
gap: var(--sv-space-2);
|
|
68
|
+
padding: 13px var(--sv-space-4);
|
|
69
|
+
border: 1px solid transparent;
|
|
70
|
+
border-radius: var(--sv-radius-md);
|
|
71
|
+
font-family: var(--sv-font-family);
|
|
72
|
+
font-size: var(--sv-font-size-sm);
|
|
73
|
+
font-weight: var(--sv-font-weight-semibold);
|
|
74
|
+
line-height: 1;
|
|
75
|
+
cursor: pointer;
|
|
76
|
+
touch-action: manipulation;
|
|
77
|
+
background-color: var(--sv-color-error-solid);
|
|
78
|
+
color: var(--sv-color-text-on-error);
|
|
79
|
+
transition: background-color 0.15s ease;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@media (pointer: coarse) {
|
|
83
|
+
.destructiveConfirm {
|
|
84
|
+
min-height: var(--sv-touch-target-min, 44px);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Derived via color-mix from the semantic token, not a raw --sv-red-800
|
|
89
|
+
primitive (the original .dangerButton pattern this replaces did reference
|
|
90
|
+
the primitive directly — fixed here, not carried forward). */
|
|
91
|
+
@media (hover: hover) {
|
|
92
|
+
.destructiveConfirm:hover:not(:disabled) {
|
|
93
|
+
background-color: color-mix(in srgb, var(--sv-color-error-solid) 85%, black);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.destructiveConfirm:active:not(:disabled) {
|
|
98
|
+
background-color: color-mix(in srgb, var(--sv-color-error-solid) 80%, black);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.destructiveConfirm:focus-visible {
|
|
102
|
+
outline: 2px solid var(--sv-color-focus-ring);
|
|
103
|
+
outline-offset: 2px;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.destructiveConfirm:disabled {
|
|
107
|
+
opacity: 0.5;
|
|
108
|
+
cursor: not-allowed;
|
|
109
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/* DatePicker — trigger styled to match Input's height/border/radius/focus
|
|
2
|
+
* ring for visual consistency as a form field. */
|
|
3
|
+
|
|
4
|
+
.trigger {
|
|
5
|
+
display: flex;
|
|
6
|
+
align-items: center;
|
|
7
|
+
justify-content: space-between;
|
|
8
|
+
gap: var(--sv-space-2);
|
|
9
|
+
width: 100%;
|
|
10
|
+
padding: var(--sv-space-2) var(--sv-space-3);
|
|
11
|
+
font-family: var(--sv-font-family);
|
|
12
|
+
font-size: var(--sv-font-size-sm);
|
|
13
|
+
line-height: 1.5;
|
|
14
|
+
color: var(--sv-color-text-primary);
|
|
15
|
+
background-color: var(--sv-color-surface);
|
|
16
|
+
border: 1px solid var(--sv-color-border-strong);
|
|
17
|
+
border-radius: var(--sv-radius-md);
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
transition:
|
|
20
|
+
border-color 0.15s ease,
|
|
21
|
+
box-shadow 0.15s ease;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* Same iOS auto-zoom fix as Input — see its own module.css for why. */
|
|
25
|
+
@media (pointer: coarse) {
|
|
26
|
+
.trigger {
|
|
27
|
+
font-size: var(--sv-font-size-md);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.trigger:focus-visible {
|
|
32
|
+
outline: none;
|
|
33
|
+
border-color: var(--sv-color-accent);
|
|
34
|
+
box-shadow: 0 0 0 2px var(--sv-color-focus-ring);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.trigger:disabled {
|
|
38
|
+
opacity: 0.5;
|
|
39
|
+
cursor: not-allowed;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.triggerValue {
|
|
43
|
+
color: var(--sv-color-text-primary);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.triggerPlaceholder {
|
|
47
|
+
color: var(--sv-color-text-muted);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.popoverBody {
|
|
51
|
+
padding: var(--sv-space-3);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.drawerBody {
|
|
55
|
+
padding: var(--sv-space-4);
|
|
56
|
+
padding-bottom: max(var(--sv-space-4), env(safe-area-inset-bottom));
|
|
57
|
+
}
|