hlmnhkl-ui 0.15.0 → 0.17.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/README.md +1 -1
- package/package.json +1 -1
- package/scripts/pro-components.json +1 -0
- package/src/components/Checkbox/Checkbox.module.css +3 -2
- package/src/components/CopyButton/CopyButton.module.css +3 -2
- package/src/components/PasswordInput/PasswordInput.module.css +3 -2
- package/src/components/SegmentedControl/SegmentedControl.module.css +1 -1
- package/src/components/Skeleton/Skeleton.module.css +21 -0
- package/src/components/Skeleton/Skeleton.tsx +6 -3
- package/src/components/Slider/Slider.module.css +2 -2
- package/src/components/Table/Table.module.css +32 -3
- package/src/components/Table/Table.tsx +74 -35
- package/src/components/Tabs/Tabs.module.css +6 -0
- package/src/tokens.css +12 -4
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ Using Next.js or React Router? The [installation guide](https://ui.hlmnhkl.my/in
|
|
|
49
49
|
|
|
50
50
|
## Pro
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
54 more components (such as Calendar, Chart, KanbanBoard, Combobox and Route), page blocks, full templates and brand themes are coming as hlmnhkl/ui Pro. You can see them on the [docs site](https://ui.hlmnhkl.my).
|
|
53
53
|
|
|
54
54
|
## Licence
|
|
55
55
|
|
package/package.json
CHANGED
|
@@ -71,8 +71,9 @@
|
|
|
71
71
|
|
|
72
72
|
.tick,
|
|
73
73
|
.dash {
|
|
74
|
-
|
|
75
|
-
stroke-
|
|
74
|
+
/* Hidden just before the path starts. A zero-length dash would leave its round ends as a dot in Safari. */
|
|
75
|
+
stroke-dasharray: 1 2;
|
|
76
|
+
stroke-dashoffset: 1.01;
|
|
76
77
|
transition: stroke-dashoffset var(--hl-motion-base) var(--hl-ease-out);
|
|
77
78
|
}
|
|
78
79
|
|
|
@@ -62,8 +62,9 @@
|
|
|
62
62
|
stroke-width: 2.25;
|
|
63
63
|
stroke-linecap: round;
|
|
64
64
|
stroke-linejoin: round;
|
|
65
|
-
|
|
66
|
-
stroke-
|
|
65
|
+
/* Hidden just before the path starts. A zero-length dash would leave its round ends as a dot in Safari. */
|
|
66
|
+
stroke-dasharray: 1 2;
|
|
67
|
+
stroke-dashoffset: 1.01;
|
|
67
68
|
transition: stroke-dashoffset var(--hl-motion-base) var(--hl-ease-in);
|
|
68
69
|
}
|
|
69
70
|
|
|
@@ -55,8 +55,9 @@
|
|
|
55
55
|
.eye[data-open] .pupil { transform: scale(0.8); }
|
|
56
56
|
|
|
57
57
|
.slash {
|
|
58
|
-
|
|
59
|
-
stroke-
|
|
58
|
+
/* Hidden just before the path starts. A zero-length dash would leave its round ends as a dot in Safari. */
|
|
59
|
+
stroke-dasharray: 1 2;
|
|
60
|
+
stroke-dashoffset: 1.01;
|
|
60
61
|
transition: stroke-dashoffset var(--hl-motion-base) var(--hl-ease-out);
|
|
61
62
|
}
|
|
62
63
|
|
|
@@ -26,10 +26,31 @@
|
|
|
26
26
|
.rect { width: 100%; height: var(--hl-skeleton-block); border-radius: var(--hl-radius-md); }
|
|
27
27
|
.circle { width: var(--hl-skeleton-avatar); height: var(--hl-skeleton-avatar); border-radius: var(--hl-radius-full); }
|
|
28
28
|
|
|
29
|
+
/* A sketch: the shapes as dashed pencil outlines, no fill. Text becomes dashed baselines. The lines
|
|
30
|
+
themselves fade gently instead of a shimmer, which would light up the empty box behind them. */
|
|
31
|
+
.sketch {
|
|
32
|
+
background: none;
|
|
33
|
+
border: var(--hl-line) dashed var(--hl-color-border-strong);
|
|
34
|
+
animation: sketching var(--hl-motion-shimmer) var(--hl-ease-in-out) infinite alternate;
|
|
35
|
+
animation-delay: calc(var(--i, 0) * var(--hl-motion-stagger) * 3);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.sketch::after { display: none; }
|
|
39
|
+
|
|
40
|
+
.sketch.text {
|
|
41
|
+
border-width: 0 0 var(--hl-line);
|
|
42
|
+
border-radius: 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@keyframes sketching {
|
|
46
|
+
from { border-color: var(--hl-color-border); }
|
|
47
|
+
}
|
|
48
|
+
|
|
29
49
|
@keyframes shimmer {
|
|
30
50
|
to { transform: translateX(100%); }
|
|
31
51
|
}
|
|
32
52
|
|
|
33
53
|
@media (prefers-reduced-motion: reduce) {
|
|
34
54
|
.bone::after { animation: none; display: none; }
|
|
55
|
+
.sketch { animation: none; }
|
|
35
56
|
}
|
|
@@ -11,24 +11,27 @@ export type SkeletonProps = {
|
|
|
11
11
|
height?: CSSProperties['height']
|
|
12
12
|
/** For text: number of lines. The last one is shorter, like real text. */
|
|
13
13
|
lines?: number
|
|
14
|
+
/** Solid grey shapes, or a sketch: the same shapes as dashed outlines, like a pencil layout. */
|
|
15
|
+
variant?: 'solid' | 'sketch'
|
|
14
16
|
/** Extra class for the root element. */
|
|
15
17
|
className?: string
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
// Decorative only. Mark the loading container with aria-busy and a label instead.
|
|
19
|
-
export function Skeleton({ shape = 'rect', width, height, lines = 1, className }: SkeletonProps) {
|
|
21
|
+
export function Skeleton({ shape = 'rect', width, height, lines = 1, variant = 'solid', className }: SkeletonProps) {
|
|
22
|
+
const look = variant === 'sketch' && styles.sketch
|
|
20
23
|
if (shape === 'text') {
|
|
21
24
|
return (
|
|
22
25
|
<span className={cx(styles.lines, className)} style={{ width }} aria-hidden="true">
|
|
23
26
|
{Array.from({ length: lines }, (_, i) => (
|
|
24
27
|
<span
|
|
25
28
|
key={i}
|
|
26
|
-
className={cx(styles.bone, styles.text)}
|
|
29
|
+
className={cx(styles.bone, styles.text, look)}
|
|
27
30
|
style={{ width: lines > 1 && i === lines - 1 ? '62%' : '100%', ['--i' as string]: i }}
|
|
28
31
|
/>
|
|
29
32
|
))}
|
|
30
33
|
</span>
|
|
31
34
|
)
|
|
32
35
|
}
|
|
33
|
-
return <span className={cx(styles.bone, styles[shape], className)} style={{ width, height }} aria-hidden="true" />
|
|
36
|
+
return <span className={cx(styles.bone, styles[shape], look, className)} style={{ width, height }} aria-hidden="true" />
|
|
34
37
|
}
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
margin-top: calc((var(--hl-track-h) - var(--thumb)) / 2);
|
|
74
74
|
border: var(--hl-line-thick) solid var(--hl-color-accent);
|
|
75
75
|
border-radius: var(--hl-radius-full);
|
|
76
|
-
background: var(--hl-color-surface);
|
|
76
|
+
background: var(--hl-color-surface-raised);
|
|
77
77
|
box-shadow: var(--hl-shadow-2);
|
|
78
78
|
transition:
|
|
79
79
|
transform var(--hl-motion-slow) var(--hl-ease-spring),
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
box-sizing: border-box;
|
|
87
87
|
border: var(--hl-line-thick) solid var(--hl-color-accent);
|
|
88
88
|
border-radius: var(--hl-radius-full);
|
|
89
|
-
background: var(--hl-color-surface);
|
|
89
|
+
background: var(--hl-color-surface-raised);
|
|
90
90
|
box-shadow: var(--hl-shadow-2);
|
|
91
91
|
transition:
|
|
92
92
|
transform var(--hl-motion-slow) var(--hl-ease-spring),
|
|
@@ -131,6 +131,33 @@
|
|
|
131
131
|
text-align: left;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/* A group's header: its name and how many rows it holds, on a quiet band that opens a gap above it,
|
|
135
|
+
so the groups read as pieces the table split into. */
|
|
136
|
+
.groupHead {
|
|
137
|
+
padding: var(--hl-space-6) var(--hl-space-5) var(--hl-space-2);
|
|
138
|
+
border-top: var(--hl-line) solid var(--hl-color-border);
|
|
139
|
+
background: var(--hl-color-surface-sunken);
|
|
140
|
+
font-size: var(--hl-text-sm);
|
|
141
|
+
font-weight: var(--hl-weight-semibold);
|
|
142
|
+
text-align: left;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.group:first-of-type .groupHead { padding-top: var(--hl-space-3); }
|
|
146
|
+
|
|
147
|
+
.groupCount {
|
|
148
|
+
margin-left: var(--hl-space-3);
|
|
149
|
+
font-size: var(--hl-text-xs);
|
|
150
|
+
font-weight: var(--hl-weight-regular);
|
|
151
|
+
color: var(--hl-color-fg-muted);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* A new group's header settles in while its rows glide into place below it. */
|
|
155
|
+
.groupRow { animation: groupIn var(--hl-motion-slow) var(--hl-ease-out) both; }
|
|
156
|
+
|
|
157
|
+
@keyframes groupIn {
|
|
158
|
+
from { opacity: 0; transform: translateY(calc(var(--hl-shift-sm) * -1)); }
|
|
159
|
+
}
|
|
160
|
+
|
|
134
161
|
.empty {
|
|
135
162
|
padding: var(--hl-space-9) var(--hl-space-5);
|
|
136
163
|
border-top: var(--hl-line) solid var(--hl-color-border);
|
|
@@ -193,8 +220,9 @@
|
|
|
193
220
|
|
|
194
221
|
.tick,
|
|
195
222
|
.dash {
|
|
196
|
-
|
|
197
|
-
stroke-
|
|
223
|
+
/* Hidden just before the path starts. A zero-length dash would leave its round ends as a dot in Safari. */
|
|
224
|
+
stroke-dasharray: 1 2;
|
|
225
|
+
stroke-dashoffset: 1.01;
|
|
198
226
|
transition: stroke-dashoffset var(--hl-motion-base) var(--hl-ease-out);
|
|
199
227
|
}
|
|
200
228
|
|
|
@@ -215,7 +243,8 @@
|
|
|
215
243
|
[data-layout="stack"] .table,
|
|
216
244
|
[data-layout="stack"] .table tbody,
|
|
217
245
|
[data-layout="stack"] .table tr,
|
|
218
|
-
[data-layout="stack"] .table td
|
|
246
|
+
[data-layout="stack"] .table td,
|
|
247
|
+
[data-layout="stack"] .table .groupHead { display: block; }
|
|
219
248
|
|
|
220
249
|
[data-layout="stack"] .head { display: block; }
|
|
221
250
|
|
|
@@ -31,6 +31,8 @@ export type TableLabels = {
|
|
|
31
31
|
sortedBy: (column: string, direction: TableSort['direction']) => string
|
|
32
32
|
/** Spoken when a third press turns the sort off. */
|
|
33
33
|
unsorted: (column: string) => string
|
|
34
|
+
/** The row count beside each group's name. */
|
|
35
|
+
groupCount: (count: number) => string
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
const defaultLabels: TableLabels = {
|
|
@@ -38,6 +40,7 @@ const defaultLabels: TableLabels = {
|
|
|
38
40
|
selectRow: (name) => `Select ${name}`,
|
|
39
41
|
sortedBy: (column, direction) => `Sorted by ${column}, ${direction}`,
|
|
40
42
|
unsorted: (column) => `No longer sorted by ${column}`,
|
|
43
|
+
groupCount: (count) => `${count} ${count === 1 ? 'row' : 'rows'}`,
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
export type TableProps<T> = {
|
|
@@ -57,6 +60,9 @@ export type TableProps<T> = {
|
|
|
57
60
|
defaultSort?: TableSort | null
|
|
58
61
|
/** Called with the new sort when a header is pressed: ascending, descending, then null. */
|
|
59
62
|
onSortChange?: (sort: TableSort | null) => void
|
|
63
|
+
/** Gathers rows under a header per group, such as each row's status. Groups keep the order they first
|
|
64
|
+
* appear in; the sort applies inside each group. Rows glide to their group when it changes. */
|
|
65
|
+
groupBy?: (row: T) => string
|
|
60
66
|
/** Adds a checkbox column. */
|
|
61
67
|
selectable?: boolean
|
|
62
68
|
/** Ids of the selected rows, when you control it. */
|
|
@@ -109,6 +115,7 @@ export function Table<T>({
|
|
|
109
115
|
sort: sortProp,
|
|
110
116
|
defaultSort = null,
|
|
111
117
|
onSortChange,
|
|
118
|
+
groupBy,
|
|
112
119
|
selectable,
|
|
113
120
|
selected: selectedProp,
|
|
114
121
|
defaultSelected = [],
|
|
@@ -143,8 +150,10 @@ export function Table<T>({
|
|
|
143
150
|
const [sort, setSort] = useControllable<TableSort | null>(sortProp, defaultSort, onSortChange)
|
|
144
151
|
const [selected, setSelected] = useControllable(selectedProp, defaultSelected, onSelectedChange)
|
|
145
152
|
const [announce, setAnnounce] = useState('')
|
|
146
|
-
const
|
|
153
|
+
const tableRef = useRef<HTMLTableElement>(null)
|
|
147
154
|
const lastTops = useRef(new Map<string, number>())
|
|
155
|
+
const lastShape = useRef('')
|
|
156
|
+
const groupOrder = useRef<string[]>([])
|
|
148
157
|
|
|
149
158
|
const sorted = useMemo(() => {
|
|
150
159
|
if (!sort) return rows
|
|
@@ -161,16 +170,26 @@ export function Table<T>({
|
|
|
161
170
|
return out
|
|
162
171
|
}, [rows, columns, sort])
|
|
163
172
|
|
|
164
|
-
|
|
173
|
+
// Groups take the order they first appear in, and keep it: a sort, or a row moving to another group,
|
|
174
|
+
// never shuffles the groups themselves. A group seen for the first time joins at the end.
|
|
175
|
+
let groups: Array<{ key: string; rows: T[] }> | null = null
|
|
176
|
+
if (groupBy) {
|
|
177
|
+
for (const key of new Set(rows.map(groupBy))) if (!groupOrder.current.includes(key)) groupOrder.current.push(key)
|
|
178
|
+
groups = groupOrder.current.map((key) => ({ key, rows: sorted.filter((r) => groupBy(r) === key) })).filter((g) => g.rows.length)
|
|
179
|
+
}
|
|
180
|
+
const shape = groups ? groups.map((g) => g.key).join('|') : ''
|
|
181
|
+
const order = groups ? groups.map((g) => `${g.key}:${g.rows.map(getRowId).join(',')}`).join('|') : sorted.map(getRowId).join('|')
|
|
165
182
|
|
|
166
|
-
// FLIP: rows glide to their new place after a sort
|
|
183
|
+
// FLIP: rows glide to their new place after a sort. When the groups themselves change, they snap
|
|
184
|
+
// there with the spring, so the table visibly splits apart and closes up again.
|
|
167
185
|
useLayoutEffect(() => {
|
|
168
|
-
const
|
|
169
|
-
if (!
|
|
186
|
+
const table = tableRef.current
|
|
187
|
+
if (!table) return
|
|
170
188
|
const duration = motionMs('slow')
|
|
171
|
-
const ease = easing('out')
|
|
189
|
+
const ease = easing(shape !== lastShape.current ? 'spring' : 'out')
|
|
190
|
+
lastShape.current = shape
|
|
172
191
|
const now = new Map<string, number>()
|
|
173
|
-
|
|
192
|
+
table.querySelectorAll<HTMLElement>('tbody [data-row-id]').forEach((tr) => {
|
|
174
193
|
const rid = tr.dataset.rowId!
|
|
175
194
|
const top = tr.offsetTop
|
|
176
195
|
now.set(rid, top)
|
|
@@ -204,11 +223,35 @@ export function Table<T>({
|
|
|
204
223
|
const scrollable = Boolean(maxHeight) || more.start || more.end
|
|
205
224
|
const nameOf = (row: T) => (rowLabel ? rowLabel(row) : String(read(row, columns[0]?.key ?? '') ?? getRowId(row)))
|
|
206
225
|
|
|
226
|
+
const colCount = columns.length + (selectable ? 1 : 0)
|
|
227
|
+
// Keeps the entrance stagger going across groups.
|
|
228
|
+
let rowIndex = 0
|
|
229
|
+
const renderRow = (row: T) => {
|
|
230
|
+
const ri = rowIndex++
|
|
231
|
+
const rid = getRowId(row)
|
|
232
|
+
const on = selectedSet.has(rid)
|
|
233
|
+
return (
|
|
234
|
+
<tr key={rid} role="row" data-row-id={rid} className={styles.row} data-selected={on || undefined} style={{ ['--i' as string]: Math.min(ri, 12) }}>
|
|
235
|
+
{selectable && (
|
|
236
|
+
<td role="cell" className={styles.checkCell}>
|
|
237
|
+
<Check checked={on} label={labels.selectRow(nameOf(row))} onChange={(v) => setSelected(v ? [...selected, rid] : selected.filter((s) => s !== rid))} />
|
|
238
|
+
</td>
|
|
239
|
+
)}
|
|
240
|
+
{columns.map((c) => (
|
|
241
|
+
<td key={c.key} role="cell" className={styles.td} data-align={c.align ?? 'start'} data-label={labelOf(c)}>
|
|
242
|
+
{/* One wrapper, so the card layout always gets a label and a value */}
|
|
243
|
+
<span>{c.cell ? c.cell(row) : String(read(row, c.key) ?? '')}</span>
|
|
244
|
+
</td>
|
|
245
|
+
))}
|
|
246
|
+
</tr>
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
|
|
207
250
|
return (
|
|
208
251
|
<div className={cx(styles.root, className)} data-layout={layout} data-more-start={more.start || undefined} data-more-end={more.end || undefined}>
|
|
209
252
|
<div ref={scrollRef} onScroll={measure} className={styles.scroll} style={{ maxHeight }} tabIndex={scrollable ? 0 : undefined} role={scrollable ? 'region' : undefined} aria-labelledby={scrollable ? `${id}-cap` : undefined}>
|
|
210
253
|
{/* Explicit roles keep table semantics when rows restyle as cards (layout="stack") */}
|
|
211
|
-
<table role="table" className={styles.table} aria-labelledby={`${id}-cap`}>
|
|
254
|
+
<table ref={tableRef} role="table" className={styles.table} aria-labelledby={`${id}-cap`}>
|
|
212
255
|
<caption id={`${id}-cap`} className={cx(styles.caption, hideCaption && styles.srOnly)}>
|
|
213
256
|
{caption}
|
|
214
257
|
</caption>
|
|
@@ -253,34 +296,30 @@ export function Table<T>({
|
|
|
253
296
|
})}
|
|
254
297
|
</tr>
|
|
255
298
|
</thead>
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
299
|
+
{groups && groups.length > 0 ? (
|
|
300
|
+
groups.map((g) => (
|
|
301
|
+
<tbody key={g.key} role="rowgroup" className={styles.group}>
|
|
302
|
+
<tr role="row" data-row-id={`group:${g.key}`} className={styles.groupRow}>
|
|
303
|
+
<th role="rowheader" scope="rowgroup" colSpan={colCount} className={styles.groupHead}>
|
|
304
|
+
<span>{g.key}</span>{' '}
|
|
305
|
+
<span className={styles.groupCount}>{labels.groupCount(g.rows.length)}</span>
|
|
306
|
+
</th>
|
|
307
|
+
</tr>
|
|
308
|
+
{g.rows.map(renderRow)}
|
|
309
|
+
</tbody>
|
|
310
|
+
))
|
|
311
|
+
) : (
|
|
312
|
+
<tbody role="rowgroup">
|
|
313
|
+
{sorted.map(renderRow)}
|
|
314
|
+
{sorted.length === 0 && (
|
|
315
|
+
<tr role="row">
|
|
316
|
+
<td role="cell" colSpan={colCount} className={styles.empty}>
|
|
317
|
+
{emptyText}
|
|
318
|
+
</td>
|
|
273
319
|
</tr>
|
|
274
|
-
)
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
<tr role="row">
|
|
278
|
-
<td role="cell" colSpan={columns.length + (selectable ? 1 : 0)} className={styles.empty}>
|
|
279
|
-
{emptyText}
|
|
280
|
-
</td>
|
|
281
|
-
</tr>
|
|
282
|
-
)}
|
|
283
|
-
</tbody>
|
|
320
|
+
)}
|
|
321
|
+
</tbody>
|
|
322
|
+
)}
|
|
284
323
|
</table>
|
|
285
324
|
</div>
|
|
286
325
|
<p className={styles.srOnly} role="status">{announce}</p>
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
.tab {
|
|
24
24
|
position: relative;
|
|
25
|
+
min-width: var(--hl-hit-min);
|
|
25
26
|
min-height: var(--hl-hit-min);
|
|
26
27
|
padding: 0 var(--hl-space-4);
|
|
27
28
|
border: 0;
|
|
@@ -36,6 +37,11 @@
|
|
|
36
37
|
transition: color var(--hl-motion-base) var(--hl-ease-out), background-color var(--hl-motion-fast) var(--hl-ease-out);
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
/* Narrow screens: a little less room around each tab, so a short row fits instead of scrolling. */
|
|
41
|
+
@media (max-width: 479px) {
|
|
42
|
+
.tab { padding: 0 var(--hl-space-3); }
|
|
43
|
+
}
|
|
44
|
+
|
|
39
45
|
@media (hover: hover) {
|
|
40
46
|
.tab:hover:not(:disabled) { color: var(--hl-color-fg); background: var(--hl-color-surface-hover); }
|
|
41
47
|
}
|
package/src/tokens.css
CHANGED
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
--hl-color-surface-sunken: var(--hl-gray-100);
|
|
24
24
|
--hl-color-surface-hover: var(--hl-gray-150);
|
|
25
25
|
--hl-color-surface-active: var(--hl-gray-200);
|
|
26
|
+
/* Something that sits on a track, such as a sliding pill or a slider thumb. */
|
|
27
|
+
--hl-color-surface-raised: var(--hl-color-surface);
|
|
26
28
|
--hl-color-overlay: rgb(10 10 10 / 0.32);
|
|
27
29
|
--hl-color-fg: var(--hl-gray-950);
|
|
28
30
|
--hl-color-fg-muted: var(--hl-gray-600);
|
|
@@ -212,6 +214,7 @@
|
|
|
212
214
|
--hl-color-surface-sunken: #121212;
|
|
213
215
|
--hl-color-surface-hover: #262626;
|
|
214
216
|
--hl-color-surface-active: #2e2e2e;
|
|
217
|
+
--hl-color-surface-raised: #2c2c2c;
|
|
215
218
|
--hl-color-overlay: rgb(0 0 0 / 0.6);
|
|
216
219
|
--hl-color-fg: #ececec;
|
|
217
220
|
--hl-color-fg-muted: #ababab;
|
|
@@ -232,8 +235,9 @@
|
|
|
232
235
|
--hl-color-danger-solid: #d63a2e;
|
|
233
236
|
/* Darker on hover: a lighter red drops white text under 4.5:1 */
|
|
234
237
|
--hl-color-danger-solid-hover: #b8302a;
|
|
235
|
-
|
|
236
|
-
--hl-shadow-
|
|
238
|
+
/* Faint: in the dark, height shows as a lighter surface, not a deep shadow. */
|
|
239
|
+
--hl-shadow-1: 0 1px 2px rgb(0 0 0 / 0.2);
|
|
240
|
+
--hl-shadow-2: 0 1px 2px rgb(0 0 0 / 0.2), 0 4px 12px rgb(0 0 0 / 0.15);
|
|
237
241
|
--hl-shadow-3: 0 2px 4px rgb(0 0 0 / 0.4), 0 12px 32px rgb(0 0 0 / 0.5);
|
|
238
242
|
--hl-shadow-4: 0 4px 8px rgb(0 0 0 / 0.4), 0 24px 64px rgb(0 0 0 / 0.6);
|
|
239
243
|
color-scheme: dark;
|
|
@@ -248,6 +252,7 @@
|
|
|
248
252
|
--hl-color-surface-sunken: #121212;
|
|
249
253
|
--hl-color-surface-hover: #262626;
|
|
250
254
|
--hl-color-surface-active: #2e2e2e;
|
|
255
|
+
--hl-color-surface-raised: #2c2c2c;
|
|
251
256
|
--hl-color-overlay: rgb(0 0 0 / 0.6);
|
|
252
257
|
--hl-color-fg: #ececec;
|
|
253
258
|
--hl-color-fg-muted: #ababab;
|
|
@@ -268,8 +273,9 @@
|
|
|
268
273
|
--hl-color-danger-solid: #d63a2e;
|
|
269
274
|
/* Darker on hover: a lighter red drops white text under 4.5:1 */
|
|
270
275
|
--hl-color-danger-solid-hover: #b8302a;
|
|
271
|
-
|
|
272
|
-
--hl-shadow-
|
|
276
|
+
/* Faint: in the dark, height shows as a lighter surface, not a deep shadow. */
|
|
277
|
+
--hl-shadow-1: 0 1px 2px rgb(0 0 0 / 0.2);
|
|
278
|
+
--hl-shadow-2: 0 1px 2px rgb(0 0 0 / 0.2), 0 4px 12px rgb(0 0 0 / 0.15);
|
|
273
279
|
--hl-shadow-3: 0 2px 4px rgb(0 0 0 / 0.4), 0 12px 32px rgb(0 0 0 / 0.5);
|
|
274
280
|
--hl-shadow-4: 0 4px 8px rgb(0 0 0 / 0.4), 0 24px 64px rgb(0 0 0 / 0.6);
|
|
275
281
|
color-scheme: dark;
|
|
@@ -303,6 +309,8 @@
|
|
|
303
309
|
--hl-day-mark: 4px;
|
|
304
310
|
--hl-calendar-gap: 32px;
|
|
305
311
|
--hl-wheel-rows: 5;
|
|
312
|
+
/* How far each row tilts per row away from the middle, so a wheel reads as a drum. */
|
|
313
|
+
--hl-wheel-tilt: 18deg;
|
|
306
314
|
--hl-wheel-w: 64px;
|
|
307
315
|
|
|
308
316
|
/* Smarter inputs */
|