@kenlo/sds-design-system 0.9.9 → 1.0.1
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 +49 -7
- package/components/Avatar/Avatar.css +22 -0
- package/components/Button/Button.css +95 -8
- package/components/Card/Card.css +16 -6
- package/components/Card/card-variants.js +18 -0
- package/components/Card/card.marko +12 -2
- package/components/Checkbox/Checkbox.css +56 -0
- package/components/ColorPicker/ColorPicker.css +25 -2
- package/components/ColorPicker/color-picker.marko +25 -4
- package/components/DatePicker/DatePicker.css +22 -0
- package/components/Floating/focus-when-ready.js +59 -0
- package/components/Incrementer/Incrementer.css +22 -0
- package/components/Input/Input.css +25 -2
- package/components/Menu/Menu.css +21 -11
- package/components/Menu/menu-variants.js +12 -0
- package/components/Menu/menu.marko +11 -7
- package/components/Pill/Pill.css +46 -0
- package/components/Radio/Radio.css +75 -0
- package/components/Select/Select.css +21 -1
- package/components/Select/select-options.js +10 -1
- package/components/Select/select.marko +112 -5
- package/components/Table/Table.css +73 -2
- package/components/Table/table-column-picker.marko +161 -0
- package/components/Table/table-logic.js +56 -0
- package/components/Table/table.marko +50 -12
- package/components/TextEditor/TextEditor.css +2 -2
- package/components/Toggle/Toggle.css +40 -0
- package/components/Tooltip/Tooltip.css +2 -2
- package/components/Uploader/Uploader.css +23 -0
- package/foundations/custom-scheme.js +128 -10
- package/foundations/fonts/OFL.txt +114 -0
- package/foundations/fonts/fonts.json +152 -0
- package/foundations/fonts/manrope-cyrillic-ext.woff2 +0 -0
- package/foundations/fonts/manrope-cyrillic.woff2 +0 -0
- package/foundations/fonts/manrope-greek.woff2 +0 -0
- package/foundations/fonts/manrope-latin-ext.woff2 +0 -0
- package/foundations/fonts/manrope-latin.woff2 +0 -0
- package/foundations/fonts/manrope-vietnamese.woff2 +0 -0
- package/foundations/tokens.css +1094 -13
- package/icons/generated/fluent-chevron-down-filled.marko +3 -0
- package/icons/generated/fluent-chevron-up-filled.marko +3 -0
- package/icons/generated/fluent-column-triple-regular.marko +3 -0
- package/icons/manifest.json +3 -0
- package/marko.json +3 -0
- package/package.json +4 -3
|
@@ -215,6 +215,36 @@
|
|
|
215
215
|
flex-direction: column;
|
|
216
216
|
margin: -3px 0;
|
|
217
217
|
}
|
|
218
|
+
/* ── sortIndicator="hover" — the pair on an unsorted header is hidden rather than removed.
|
|
219
|
+
|
|
220
|
+
Removed, the header would be narrower until the pointer arrived and then push the header
|
|
221
|
+
beside it sideways; hidden, it keeps its room and nothing moves. The two chevrons also
|
|
222
|
+
overlap into roughly one glyph's height here, so the clean header does not carry a
|
|
223
|
+
column-tall gap where a mark might appear.
|
|
224
|
+
|
|
225
|
+
The hover selector is on the cell and the focus one on the button, because in SDS the
|
|
226
|
+
header's control IS a button inside the cell — KDLS puts tabindex on the cell itself and
|
|
227
|
+
can write both on one selector. ── */
|
|
228
|
+
.sds-table__sort--compact {
|
|
229
|
+
color: var(--color-neutral-40);
|
|
230
|
+
opacity: 0;
|
|
231
|
+
transition: opacity 120ms ease;
|
|
232
|
+
}
|
|
233
|
+
.sds-table__sort--compact .sds-icon + .sds-icon {
|
|
234
|
+
margin-top: calc(-1 * var(--spacing-2));
|
|
235
|
+
}
|
|
236
|
+
.sds-table__col--sortable:hover .sds-table__sort--compact,
|
|
237
|
+
.sds-table__sort-button:focus-visible .sds-table__sort--compact {
|
|
238
|
+
opacity: 1;
|
|
239
|
+
}
|
|
240
|
+
/* ── loading — the rows that are on screen stay there, dimmed, while the next ones come.
|
|
241
|
+
|
|
242
|
+
Not a spinner in their place: a reader who asked for a different sort order would watch
|
|
243
|
+
the list vanish and come back, and lose where they were in it. The header keeps its full
|
|
244
|
+
colour, so the column titles stay readable while the body is provisional. ── */
|
|
245
|
+
.sds-table--loading .sds-table__row:not(.sds-table__row--header) {
|
|
246
|
+
opacity: 0.5;
|
|
247
|
+
}
|
|
218
248
|
/* ── Ellipsis (single-line truncation + Tooltip on hover) ── */
|
|
219
249
|
.sds-table__col--ellipsis .sds-tooltip-wrapper {
|
|
220
250
|
display: flex;
|
|
@@ -254,8 +284,8 @@
|
|
|
254
284
|
}
|
|
255
285
|
|
|
256
286
|
.sds-table__sort-button:focus-visible {
|
|
257
|
-
outline: var(--focus-ring-
|
|
258
|
-
outline-offset:
|
|
287
|
+
outline: var(--focus-ring-outline);
|
|
288
|
+
outline-offset: var(--focus-ring-outline-offset);
|
|
259
289
|
border-radius: var(--radius-xs);
|
|
260
290
|
}
|
|
261
291
|
|
|
@@ -268,3 +298,44 @@
|
|
|
268
298
|
font-family: var(--font-family-base);
|
|
269
299
|
font-size: var(--font-size-body-md);
|
|
270
300
|
}
|
|
301
|
+
|
|
302
|
+
/* ── Column picker ──────────────────────────────────────────────────────
|
|
303
|
+
sds-table-column-picker's panel. Ported from KDLS 2.9.0's Table.css.
|
|
304
|
+
BEM root: .sds-table__column-picker
|
|
305
|
+
─────────────────────────────────────────────────────────────────── */
|
|
306
|
+
.sds-table__column-picker {
|
|
307
|
+
display: flex;
|
|
308
|
+
flex-direction: column;
|
|
309
|
+
gap: var(--spacing-4);
|
|
310
|
+
min-width: 240px;
|
|
311
|
+
}
|
|
312
|
+
/* The rows scroll and nothing else does: the reset link below stays put, and the cap is
|
|
313
|
+
the same seven and a half rows every other list in the system shows. The padding is
|
|
314
|
+
there so a focus ring on the first or last checkbox is not clipped by the scroller, and
|
|
315
|
+
the negative margin takes the space back so the rows still line up with the title. */
|
|
316
|
+
.sds-table__column-picker-list {
|
|
317
|
+
display: flex;
|
|
318
|
+
flex-direction: column;
|
|
319
|
+
gap: var(--spacing-6);
|
|
320
|
+
max-height: var(--menu-max-height);
|
|
321
|
+
overflow-y: auto;
|
|
322
|
+
padding: var(--spacing-1);
|
|
323
|
+
margin: calc(-1 * var(--spacing-1));
|
|
324
|
+
}
|
|
325
|
+
/* A <fieldset>, for the grouping a screen reader needs — and a fieldset arrives with a
|
|
326
|
+
browser border, a browser margin and a browser padding that no design asked for. */
|
|
327
|
+
.sds-table__column-picker-group {
|
|
328
|
+
display: flex;
|
|
329
|
+
flex-direction: column;
|
|
330
|
+
gap: var(--spacing-3);
|
|
331
|
+
min-width: 0;
|
|
332
|
+
margin: 0;
|
|
333
|
+
padding: 0;
|
|
334
|
+
border: 0;
|
|
335
|
+
}
|
|
336
|
+
/* Same reason: a <legend> is laid out as part of the border it no longer has, so without
|
|
337
|
+
this the group title sits indented and cannot be reached by the flex gap above. */
|
|
338
|
+
.sds-table__column-picker-group-title {
|
|
339
|
+
display: contents;
|
|
340
|
+
padding: 0;
|
|
341
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
<!-- sds-table-column-picker — ported from kdls-design-system components/Table/TableColumnPicker.tsx
|
|
2
|
+
(added there in 2.9.0 by Valdir Primo; read at commit 245652b).
|
|
3
|
+
|
|
4
|
+
A pill that opens the table's columns, grouped, one per line, to show or hide. It
|
|
5
|
+
applies on the tick — there is no "Aplicar" button, because a reader who ticks a box
|
|
6
|
+
and watches nothing happen ticks it again.
|
|
7
|
+
|
|
8
|
+
Divergences from KDLS, all of them consequences of how SDS already works:
|
|
9
|
+
|
|
10
|
+
The checkboxes report to ONE listener here, not one handler each. sds-checkbox does not
|
|
11
|
+
hydrate on purpose — it takes no onChange and lets the native change event bubble — so
|
|
12
|
+
the picker listens once on the panel and reads which box fired out of the input's own
|
|
13
|
+
name and value. sds-table does exactly this, for the same reason: a component per
|
|
14
|
+
checkbox is a component serialised per checkbox.
|
|
15
|
+
|
|
16
|
+
The ordering rule lives in table-logic.js as `toggleColumn`, tested without a DOM.
|
|
17
|
+
KDLS writes it inline in the component, where the rule that the caller gets its keys
|
|
18
|
+
back in the groups' order can only be checked by rendering React.
|
|
19
|
+
|
|
20
|
+
KDLS watches the floating portal with a MutationObserver to know when the panel has
|
|
21
|
+
been placed, because a portalled panel is hidden until then and a hidden element drops
|
|
22
|
+
focus(). SDS has no portal — Marko 5 has none — but it has the same wait for a
|
|
23
|
+
different reason: sds-floating renders its panel `visibility: hidden` until it has
|
|
24
|
+
measured and placed it, and focus() on a hidden element does nothing and reports
|
|
25
|
+
nothing. Confirmed in Chromium on 2026-09-17, where opening this picker left the caret
|
|
26
|
+
on `<body>`. The rule and its measurement are in Floating/focus-when-ready.js, shared
|
|
27
|
+
with sds-select, which met it too.
|
|
28
|
+
|
|
29
|
+
Escape is handled twice on purpose: sds-floating already closes on it, and this adds
|
|
30
|
+
the half KDLS also adds — putting focus back on the trigger. Closing a panel while the
|
|
31
|
+
focus stays inside it leaves a keyboard reader standing on nothing. -->
|
|
32
|
+
|
|
33
|
+
import { pickerKeys, toggleColumn } from "./table-logic.js";
|
|
34
|
+
import { focusWhenReady } from "../Floating/focus-when-ready.js";
|
|
35
|
+
import columnTriple from "../../icons/generated/fluent-column-triple-regular.marko";
|
|
36
|
+
|
|
37
|
+
class {
|
|
38
|
+
onCreate() {
|
|
39
|
+
this.state = { open: false };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setOpen(open) {
|
|
43
|
+
this.state.open = open;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Every box in the panel reports here.
|
|
48
|
+
*
|
|
49
|
+
* The name is the picker's own, so a checkbox belonging to something else that happens
|
|
50
|
+
* to sit inside the panel is not mistaken for a column.
|
|
51
|
+
*/
|
|
52
|
+
handleChange(event) {
|
|
53
|
+
const target = event.target;
|
|
54
|
+
if (target.type !== "checkbox" || target.name !== this.checkboxName) return;
|
|
55
|
+
const { groups = [], value = [], onChange } = this.input;
|
|
56
|
+
onChange?.(toggleColumn(groups, value, target.value, target.checked));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get checkboxName() {
|
|
60
|
+
return `sds-table-column-picker-${this.id}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The first column the reader can actually change, so the keyboard lands on a control
|
|
65
|
+
* rather than on the panel — and it keeps asking until the panel can take the caret.
|
|
66
|
+
*/
|
|
67
|
+
focusFirst() {
|
|
68
|
+
focusWhenReady(() => {
|
|
69
|
+
if (!this.state.open) return null;
|
|
70
|
+
const panel = this.getEl("panel");
|
|
71
|
+
return panel && panel.querySelector("input[type=checkbox]:not(:disabled)");
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
handleKey(event) {
|
|
76
|
+
if (event.key !== "Escape") return;
|
|
77
|
+
this.setOpen(false);
|
|
78
|
+
this.getEl("trigger")?.querySelector("button, [role=button]")?.focus();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
onUpdate() {
|
|
82
|
+
if (this.state.open && !this.focused) {
|
|
83
|
+
this.focused = true;
|
|
84
|
+
this.focusFirst();
|
|
85
|
+
}
|
|
86
|
+
if (!this.state.open) this.focused = false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
$ {
|
|
91
|
+
const {
|
|
92
|
+
label = "Colunas",
|
|
93
|
+
groups,
|
|
94
|
+
value = [],
|
|
95
|
+
onReset,
|
|
96
|
+
class: extraClass = "",
|
|
97
|
+
} = input;
|
|
98
|
+
|
|
99
|
+
if (!Array.isArray(groups) || !groups.length) {
|
|
100
|
+
throw new Error("sds-table-column-picker needs `groups`.");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const open = state.open;
|
|
104
|
+
const offered = pickerKeys(groups);
|
|
105
|
+
const name = component.checkboxName;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
<sds-popover
|
|
109
|
+
title=label
|
|
110
|
+
placement="bottomRight"
|
|
111
|
+
trigger="click"
|
|
112
|
+
arrow=false
|
|
113
|
+
open=open
|
|
114
|
+
onOpenChange=(next) => component.setOpen(next)
|
|
115
|
+
class=extraClass
|
|
116
|
+
>
|
|
117
|
+
<@content>
|
|
118
|
+
<div key="panel" class="sds-table__column-picker" on-change("handleChange") on-keydown("handleKey")>
|
|
119
|
+
<!-- The list scrolls, the reset link does not: `--menu-max-height` caps the rows so
|
|
120
|
+
the same seven and a half of them show whether or not there is a link below. -->
|
|
121
|
+
<div class="sds-table__column-picker-list sds-scroll sds-scroll--thin">
|
|
122
|
+
<for|group, index| of=groups>
|
|
123
|
+
<!-- A fieldset, so a screen reader announces the group a box belongs to instead
|
|
124
|
+
of reading fourteen unrelated checkboxes. -->
|
|
125
|
+
<fieldset class="sds-table__column-picker-group">
|
|
126
|
+
<if(group.title)>
|
|
127
|
+
<legend class="sds-table__column-picker-group-title">
|
|
128
|
+
<sds-text as="span" variant="labelSemiBold">${group.title}</sds-text>
|
|
129
|
+
</legend>
|
|
130
|
+
</if>
|
|
131
|
+
<for|column| of=group.columns>
|
|
132
|
+
<sds-checkbox
|
|
133
|
+
label=column.label
|
|
134
|
+
width="fill"
|
|
135
|
+
name=name
|
|
136
|
+
value=column.key
|
|
137
|
+
checked=value.includes(column.key)
|
|
138
|
+
disabled=column.disabled
|
|
139
|
+
hint=column.hint
|
|
140
|
+
/>
|
|
141
|
+
</for>
|
|
142
|
+
</fieldset>
|
|
143
|
+
</for>
|
|
144
|
+
</div>
|
|
145
|
+
<if(onReset)>
|
|
146
|
+
<sds-button variant="link" size="md" label="Restaurar padrão" onClick=() => onReset()/>
|
|
147
|
+
</if>
|
|
148
|
+
</div>
|
|
149
|
+
</@content>
|
|
150
|
+
|
|
151
|
+
<span key="trigger">
|
|
152
|
+
<sds-pill
|
|
153
|
+
label=label
|
|
154
|
+
active=open
|
|
155
|
+
aria-haspopup="dialog"
|
|
156
|
+
aria-expanded=(open ? "true" : "false")
|
|
157
|
+
>
|
|
158
|
+
<@icon-left><${columnTriple}/></@icon-left>
|
|
159
|
+
</sds-pill>
|
|
160
|
+
</span>
|
|
161
|
+
</sds-popover>
|
|
@@ -29,6 +29,28 @@ export const SORT_DIRECTIONS = [
|
|
|
29
29
|
{ label: 'Decrescente', value: 'desc' },
|
|
30
30
|
];
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* How a sortable header wears its sort mark. From KDLS 2.8.0.
|
|
34
|
+
*
|
|
35
|
+
* `always` draws the up/down pair on every sortable header — the reader can see which
|
|
36
|
+
* columns sort before touching any of them, at the cost of a row of chevrons.
|
|
37
|
+
* `hover` keeps the unsorted headers clean and shows the pair only while a header is
|
|
38
|
+
* pointed at or focused, in the room it already occupies so nothing moves; the sorted
|
|
39
|
+
* header gets a single filled chevron instead of a coloured half of a pair.
|
|
40
|
+
*
|
|
41
|
+
* `always` stays the default: it is what the table did before the choice existed, and a
|
|
42
|
+
* new option that changes an existing table's appearance is not an option, it is a change.
|
|
43
|
+
*/
|
|
44
|
+
export const SORT_INDICATORS = ['always', 'hover'];
|
|
45
|
+
|
|
46
|
+
export function assertSortIndicator(value) {
|
|
47
|
+
if (!SORT_INDICATORS.includes(value)) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`Unknown table sortIndicator: "${value}". Allowed: ${SORT_INDICATORS.join(', ')}`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
32
54
|
/**
|
|
33
55
|
* The mobile layout triggers off the table's own width, not the viewport's.
|
|
34
56
|
*
|
|
@@ -127,3 +149,37 @@ export function ariaSortFor(column, sort) {
|
|
|
127
149
|
if (sort?.key !== column.key) return 'none';
|
|
128
150
|
return sort.direction === 'asc' ? 'ascending' : 'descending';
|
|
129
151
|
}
|
|
152
|
+
|
|
153
|
+
/* ── Column picker ──────────────────────────────────────────────────────────
|
|
154
|
+
The arithmetic behind sds-table-column-picker. From KDLS 2.9.0, where it lives inside
|
|
155
|
+
the component; here it is a pair of pure functions so the ordering rule can be tested
|
|
156
|
+
without a DOM, and so the component stays a template. ─────────────────────── */
|
|
157
|
+
|
|
158
|
+
/** Every key the picker offers, in the order the groups list them. */
|
|
159
|
+
export function pickerKeys(groups = []) {
|
|
160
|
+
return groups.flatMap((group) => group.columns.map((column) => column.key));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* The visible columns after one box is ticked or unticked.
|
|
165
|
+
*
|
|
166
|
+
* Two rules, and both matter to what the reader sees:
|
|
167
|
+
*
|
|
168
|
+
* The result comes back in the GROUPS' order, never the order the boxes were clicked. The
|
|
169
|
+
* caller renders the columns in the order it is handed, so appending would let the table's
|
|
170
|
+
* column order depend on the sequence somebody happened to tick things in.
|
|
171
|
+
*
|
|
172
|
+
* A key the caller shows but no group offers is kept, at the end. That is the fixed first
|
|
173
|
+
* column, or an actions column — a column the picker deliberately does not let anyone turn
|
|
174
|
+
* off, and therefore one it must not turn off by omission either.
|
|
175
|
+
*/
|
|
176
|
+
export function toggleColumn(groups, value = [], key, checked) {
|
|
177
|
+
const offered = pickerKeys(groups);
|
|
178
|
+
const next = new Set(value);
|
|
179
|
+
if (checked) next.add(key);
|
|
180
|
+
else next.delete(key);
|
|
181
|
+
return [
|
|
182
|
+
...offered.filter((k) => next.has(k)),
|
|
183
|
+
...value.filter((k) => !offered.includes(k) && next.has(k)),
|
|
184
|
+
];
|
|
185
|
+
}
|
|
@@ -29,11 +29,13 @@
|
|
|
29
29
|
|
|
30
30
|
import {
|
|
31
31
|
gridTemplate, nextSort, sortRows, rowId, toggleId, toggleAll, headerCheckState,
|
|
32
|
-
sortFieldOptions, ariaSortFor, SORT_DIRECTIONS, NONE_SORT,
|
|
33
|
-
SELECT_ALL_NAME, SELECT_ROW_NAME,
|
|
32
|
+
sortFieldOptions, ariaSortFor, assertSortIndicator, SORT_DIRECTIONS, NONE_SORT,
|
|
33
|
+
MOBILE_BREAKPOINT, SELECT_ALL_NAME, SELECT_ROW_NAME,
|
|
34
34
|
} from "./table-logic.js";
|
|
35
35
|
import chevronUp from "../../icons/generated/fluent-chevron-up-regular.marko";
|
|
36
36
|
import chevronDown from "../../icons/generated/fluent-chevron-down-regular.marko";
|
|
37
|
+
import chevronUpFilled from "../../icons/generated/fluent-chevron-up-filled.marko";
|
|
38
|
+
import chevronDownFilled from "../../icons/generated/fluent-chevron-down-filled.marko";
|
|
37
39
|
|
|
38
40
|
class {
|
|
39
41
|
onCreate(input) {
|
|
@@ -132,6 +134,8 @@ $ {
|
|
|
132
134
|
rowSelection = false,
|
|
133
135
|
selectedIds = [],
|
|
134
136
|
onRowClick,
|
|
137
|
+
sortIndicator = "always",
|
|
138
|
+
loading = false,
|
|
135
139
|
pagination,
|
|
136
140
|
emptyMessage = "Nenhum resultado",
|
|
137
141
|
label = "Tabela",
|
|
@@ -142,6 +146,7 @@ $ {
|
|
|
142
146
|
if (variant !== "default" && variant !== "cardLines") {
|
|
143
147
|
throw new Error(`Unknown table variant: "${variant}". Allowed: default, cardLines`);
|
|
144
148
|
}
|
|
149
|
+
assertSortIndicator(sortIndicator);
|
|
145
150
|
|
|
146
151
|
const sort = component.sort;
|
|
147
152
|
const ordered = sortRows(rows, columns, sort);
|
|
@@ -164,11 +169,20 @@ $ {
|
|
|
164
169
|
"sds-table",
|
|
165
170
|
variant !== "default" ? `sds-table--${variant}` : "",
|
|
166
171
|
bordered ? "sds-table--bordered" : "",
|
|
172
|
+
loading ? "sds-table--loading" : "",
|
|
167
173
|
extraClass,
|
|
168
174
|
].filter(Boolean).join(" ");
|
|
169
175
|
}
|
|
170
176
|
|
|
171
|
-
<div
|
|
177
|
+
<div
|
|
178
|
+
key="root"
|
|
179
|
+
class=rootClass
|
|
180
|
+
role="table"
|
|
181
|
+
aria-label=label
|
|
182
|
+
aria-rowcount=String(ordered.length)
|
|
183
|
+
aria-busy=(loading ? "true" : null)
|
|
184
|
+
on-change("handleChange")
|
|
185
|
+
>
|
|
172
186
|
<if(input.header)>
|
|
173
187
|
<${input.header}/>
|
|
174
188
|
</if>
|
|
@@ -245,15 +259,39 @@ $ {
|
|
|
245
259
|
<span class="sds-table__col-title">${column.title ?? ""}</span>
|
|
246
260
|
<!-- Both arrows, with the live one coloured — KDLS's shape, and the
|
|
247
261
|
right one: a single arrow leaves a visitor guessing whether the
|
|
248
|
-
column is sorted at all or just sortable.
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
262
|
+
column is sorted at all or just sortable.
|
|
263
|
+
|
|
264
|
+
Under sortIndicator="hover" the sorted column is the exception: it
|
|
265
|
+
already answers "is it sorted" by being the only marked header, so it
|
|
266
|
+
shows one filled arrow instead of a pair with one half greyed. Every
|
|
267
|
+
other header keeps the pair, hidden by opacity rather than removed —
|
|
268
|
+
taking it out of the DOM would let the header resize when the pointer
|
|
269
|
+
arrives, and a header that grows on hover pushes the one beside it. -->
|
|
270
|
+
<if(sortIndicator === "hover" && sort?.key === column.key)>
|
|
271
|
+
<span class="sds-table__sort" aria-hidden="true">
|
|
272
|
+
<sds-icon size="sm" color="primary">
|
|
273
|
+
<if(sort.direction === "asc")>
|
|
274
|
+
<${chevronUpFilled}/>
|
|
275
|
+
</if>
|
|
276
|
+
<else>
|
|
277
|
+
<${chevronDownFilled}/>
|
|
278
|
+
</else>
|
|
279
|
+
</sds-icon>
|
|
280
|
+
</span>
|
|
281
|
+
</if>
|
|
282
|
+
<else>
|
|
283
|
+
<span
|
|
284
|
+
class=["sds-table__sort", sortIndicator === "hover" ? "sds-table__sort--compact" : ""].filter(Boolean).join(" ")
|
|
285
|
+
aria-hidden="true"
|
|
286
|
+
>
|
|
287
|
+
<sds-icon size="sm" color=(sort?.key === column.key && sort.direction === "asc" ? "primary" : undefined)>
|
|
288
|
+
<${chevronUp}/>
|
|
289
|
+
</sds-icon>
|
|
290
|
+
<sds-icon size="sm" color=(sort?.key === column.key && sort.direction === "desc" ? "primary" : undefined)>
|
|
291
|
+
<${chevronDown}/>
|
|
292
|
+
</sds-icon>
|
|
293
|
+
</span>
|
|
294
|
+
</else>
|
|
257
295
|
</button>
|
|
258
296
|
</if>
|
|
259
297
|
<else>
|
|
@@ -71,8 +71,8 @@
|
|
|
71
71
|
KDLS gives it no focus style: a contenteditable div with no ring is a control a keyboard
|
|
72
72
|
user cannot tell they have reached. */
|
|
73
73
|
.sds-text-editor__body:focus-visible {
|
|
74
|
-
outline: var(--focus-ring-
|
|
75
|
-
outline-offset: -
|
|
74
|
+
outline: var(--focus-ring-outline);
|
|
75
|
+
outline-offset: calc(var(--focus-ring-outline-offset) * -1);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
/* The toolbar's own buttons are sds-icon-button and sds-menu, which carry their own. */
|
|
@@ -167,3 +167,43 @@
|
|
|
167
167
|
box-shadow: var(--focus-ring);
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
/* ── The site's gradient, on the stroke ────────────────────────────────────────
|
|
171
|
+
|
|
172
|
+
`border-color` rejects a gradient, so a stroke normally reads the `-solid` companion —
|
|
173
|
+
the gradient's first stop, flat. These rules paint it properly instead: the gradient on
|
|
174
|
+
`border-box`, the surface colour on `padding-box`, over a transparent border. Only the
|
|
175
|
+
border's own 2px show the gradient, and `border-radius` still works, which is what
|
|
176
|
+
`border-image` would cost.
|
|
177
|
+
|
|
178
|
+
`[data-primary-gradient]` is written by `applyCustomGradient` and removed by
|
|
179
|
+
`applyCustomColor` — a stylesheet cannot ask what a custom property contains, so the
|
|
180
|
+
code that fills the slot says so. KDLS wrote the same rules under
|
|
181
|
+
`[data-color-scheme="lya"]`, its own brand gradient; SDS deleted every `lya` block with
|
|
182
|
+
the brand and these went with them. Keyed on the marker they serve any site's gradient.
|
|
183
|
+
─────────────────────────────────────────────────────────────────────────── */
|
|
184
|
+
|
|
185
|
+
[data-primary-gradient] .sds-toggle:hover:not(.sds-toggle--disabled) {
|
|
186
|
+
background:
|
|
187
|
+
linear-gradient(var(--component-bg-color), var(--component-bg-color)) padding-box,
|
|
188
|
+
var(--color-primary-50) border-box;
|
|
189
|
+
border-color: transparent;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* ── And when the gradient FILLS this, it has no border to fight ──────────────
|
|
193
|
+
|
|
194
|
+
Filled from the slot and ringed with the `-solid` companion: the same colour while the
|
|
195
|
+
slot is solid, and a flat hoop of the first stop once it is a gradient. `border: none`
|
|
196
|
+
because under a gradient the fill IS the whole control.
|
|
197
|
+
|
|
198
|
+
Touched states brighten or darken rather than stepping to tone 60 or 70 — stepping a
|
|
199
|
+
gradient's tone moves every stop at once and reads as a different colour, not as the
|
|
200
|
+
same control being pressed. Same answer as the checked checkbox. ─────────── */
|
|
201
|
+
[data-primary-gradient] .sds-toggle__item--active {
|
|
202
|
+
background: var(--color-primary-50);
|
|
203
|
+
border: none;
|
|
204
|
+
}
|
|
205
|
+
[data-primary-gradient] .sds-toggle__item--active:hover:not(:disabled) {
|
|
206
|
+
background: var(--color-primary-50);
|
|
207
|
+
border: none;
|
|
208
|
+
filter: brightness(1.1);
|
|
209
|
+
}
|
|
@@ -178,3 +178,26 @@ button.sds-uploader {
|
|
|
178
178
|
.sds-uploader__error {
|
|
179
179
|
color: var(--color-error-50);
|
|
180
180
|
}
|
|
181
|
+
|
|
182
|
+
/* ── The site's gradient, on the stroke ────────────────────────────────────────
|
|
183
|
+
|
|
184
|
+
`border-color` rejects a gradient, so a stroke normally reads the `-solid` companion —
|
|
185
|
+
the gradient's first stop, flat. These rules paint it properly instead: the gradient on
|
|
186
|
+
`border-box`, the surface colour on `padding-box`, over a transparent border. Only the
|
|
187
|
+
border's own 2px show the gradient, and `border-radius` still works, which is what
|
|
188
|
+
`border-image` would cost.
|
|
189
|
+
|
|
190
|
+
`[data-primary-gradient]` is written by `applyCustomGradient` and removed by
|
|
191
|
+
`applyCustomColor` — a stylesheet cannot ask what a custom property contains, so the
|
|
192
|
+
code that fills the slot says so. KDLS wrote the same rules under
|
|
193
|
+
`[data-color-scheme="lya"]`, its own brand gradient; SDS deleted every `lya` block with
|
|
194
|
+
the brand and these went with them. Keyed on the marker they serve any site's gradient.
|
|
195
|
+
─────────────────────────────────────────────────────────────────────────── */
|
|
196
|
+
|
|
197
|
+
[data-primary-gradient] .sds-uploader:hover,
|
|
198
|
+
[data-primary-gradient] .sds-uploader--dragging {
|
|
199
|
+
background:
|
|
200
|
+
var(--color-primary-10) padding-box,
|
|
201
|
+
var(--color-primary-50) border-box;
|
|
202
|
+
border-color: transparent;
|
|
203
|
+
}
|