@apliteni/apliteni-ui 0.105.0 → 0.107.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/package.json +1 -1
- package/react/dist/index.d.ts +3 -1
- package/react/dist/index.js +7 -4
- package/src/components/dropdown.js +20 -1
- package/src/styles/dropdown.css +27 -1
- package/src/styles/topbar.css +2 -2
package/package.json
CHANGED
package/react/dist/index.d.ts
CHANGED
|
@@ -469,6 +469,8 @@ type DropdownProps = {
|
|
|
469
469
|
/** Replaces the trigger's label/value pair. With `ariaLabel`, names the trigger. */
|
|
470
470
|
triggerContent?: ReactNode;
|
|
471
471
|
triggerClass?: string;
|
|
472
|
+
/** The trigger is off: no stop, no panel, the kit's unavailable paint. #580 */
|
|
473
|
+
disabled?: boolean;
|
|
472
474
|
chevron?: boolean;
|
|
473
475
|
/** The edge the panel hugs. */
|
|
474
476
|
align?: 'start' | 'end';
|
|
@@ -490,7 +492,7 @@ type DropdownProps = {
|
|
|
490
492
|
/** Draw the row yourself. `props` is everything the row needs; spread it. */
|
|
491
493
|
row?: (item: DropdownItem, props: DropdownRowProps) => ReactNode;
|
|
492
494
|
};
|
|
493
|
-
declare function Dropdown({ label, value, placeholder, variant, items, sections, header, footer, triggerContent, triggerClass, chevron, align, direction, scroll, search, ariaLabel, id, panelClass, open: openProp, defaultOpen, onOpenChange, onSelect, row, }: DropdownProps): react.JSX.Element;
|
|
495
|
+
declare function Dropdown({ label, value, placeholder, variant, items, sections, header, footer, triggerContent, triggerClass, disabled, chevron, align, direction, scroll, search, ariaLabel, id, panelClass, open: openProp, defaultOpen, onOpenChange, onSelect, row, }: DropdownProps): react.JSX.Element;
|
|
494
496
|
|
|
495
497
|
type BackLinkOwnProps = {
|
|
496
498
|
/** The address. No address, or a `javascript:` one, and nothing is rendered. */
|
package/react/dist/index.js
CHANGED
|
@@ -1939,6 +1939,7 @@ function Dropdown({
|
|
|
1939
1939
|
footer,
|
|
1940
1940
|
triggerContent,
|
|
1941
1941
|
triggerClass = "",
|
|
1942
|
+
disabled = false,
|
|
1942
1943
|
chevron = true,
|
|
1943
1944
|
align = "start",
|
|
1944
1945
|
direction = "down",
|
|
@@ -2235,6 +2236,7 @@ function Dropdown({
|
|
|
2235
2236
|
trigger.current?.focus();
|
|
2236
2237
|
};
|
|
2237
2238
|
const onKeyDown = (e) => {
|
|
2239
|
+
if (disabled && !open) return;
|
|
2238
2240
|
const onTrigger = e.target === trigger.current;
|
|
2239
2241
|
const onField = e.target === field.current;
|
|
2240
2242
|
if (onField && composing(e)) return;
|
|
@@ -2299,14 +2301,14 @@ function Dropdown({
|
|
|
2299
2301
|
if (!isRow(entry)) {
|
|
2300
2302
|
return /* @__PURE__ */ jsx20("div", { className: "ui-dropdown__sep", role: "separator", hidden: filtering || void 0 }, key);
|
|
2301
2303
|
}
|
|
2302
|
-
const
|
|
2304
|
+
const disabled2 = !!entry.disabled;
|
|
2303
2305
|
const selected = selectedOf(entry);
|
|
2304
|
-
const asLink = !!entry.href && !
|
|
2306
|
+
const asLink = !!entry.href && !disabled2 && !asOption;
|
|
2305
2307
|
const props = {
|
|
2306
2308
|
className: cx6(
|
|
2307
2309
|
"ui-dropdown__item",
|
|
2308
2310
|
selected && "is-selected",
|
|
2309
|
-
|
|
2311
|
+
disabled2 && "is-disabled",
|
|
2310
2312
|
entry.danger && "is-danger",
|
|
2311
2313
|
Boolean(sx) && open && entry === active && "is-active"
|
|
2312
2314
|
),
|
|
@@ -2315,7 +2317,7 @@ function Dropdown({
|
|
|
2315
2317
|
tabIndex: -1,
|
|
2316
2318
|
...entry.value != null ? { "data-value": String(entry.value) } : null,
|
|
2317
2319
|
...asOption ? { "aria-selected": selected } : null,
|
|
2318
|
-
...
|
|
2320
|
+
...disabled2 ? { "aria-disabled": true } : null,
|
|
2319
2321
|
...asLink ? { href: entry.href, ...entry.target ? { target: entry.target } : null } : null,
|
|
2320
2322
|
...sx ? { id: rowIds.get(entry), hidden: hiddenBy(entry) || void 0 } : null,
|
|
2321
2323
|
onClick: (e) => choose(entry, e),
|
|
@@ -2362,6 +2364,7 @@ function Dropdown({
|
|
|
2362
2364
|
type: "button",
|
|
2363
2365
|
className: cx6("ui-dropdown__trigger", triggerClass),
|
|
2364
2366
|
"data-dropdown-trigger": "",
|
|
2367
|
+
disabled: disabled || void 0,
|
|
2365
2368
|
"aria-haspopup": sx ? "dialog" : listRole,
|
|
2366
2369
|
"aria-expanded": open,
|
|
2367
2370
|
"aria-label": ariaLabel && triggerContent != null ? ariaLabel : void 0,
|
|
@@ -157,6 +157,8 @@ function ddSearchBody({ items, sections }, sx, name, scroll) {
|
|
|
157
157
|
* @param {boolean} [o.portal] mount the panel on <body>, for a clipping or sticky ancestor
|
|
158
158
|
* @param {boolean|number} [o.scroll] true, or a maxHeight in px, to cap and scroll
|
|
159
159
|
* @param {boolean} [o.open] render already-open (handy for screenshots)
|
|
160
|
+
* @param {boolean} [o.disabled] the trigger is off: no stop, no panel, the kit's
|
|
161
|
+
* unavailable paint. #580
|
|
160
162
|
* @param {string} [o.ariaLabel] accessible name for the panel and trigger
|
|
161
163
|
* @param {boolean|object} [o.search] true, or { placeholder, label, empty, hint, query } —
|
|
162
164
|
* a field above the rows that filters them; `empty` may carry {q}
|
|
@@ -166,7 +168,7 @@ export function dropdown({
|
|
|
166
168
|
label, value, placeholder = 'Select…', variant, items, sections,
|
|
167
169
|
foot = '', header = '', footer = '', triggerContent, triggerClass = '', chevron = true,
|
|
168
170
|
align = 'start', direction = 'down', portal = false,
|
|
169
|
-
scroll = false, open = false, ariaLabel, id, panelClass = '', search = false,
|
|
171
|
+
scroll = false, open = false, disabled = false, ariaLabel, id, panelClass = '', search = false,
|
|
170
172
|
} = {}) {
|
|
171
173
|
const flat = sections ? sections.flatMap((s) => s.items || []) : (items || []);
|
|
172
174
|
const isSelect = variant === 'select' || (variant == null && flat.some((it) => it && (it.selected || it.value != null)));
|
|
@@ -185,6 +187,9 @@ export function dropdown({
|
|
|
185
187
|
'data-dropdown-trigger',
|
|
186
188
|
`aria-haspopup="${sx ? 'dialog' : listRole}"`,
|
|
187
189
|
`aria-expanded="${open ? 'true' : 'false'}"`,
|
|
190
|
+
// The attribute, not aria-disabled: a dropdown's trigger carries no message a
|
|
191
|
+
// reader has to stop on, so it leaves the tab order the way .ui-btn's does.
|
|
192
|
+
disabled ? 'disabled' : '',
|
|
188
193
|
ariaLabel && triggerContent != null ? `aria-label="${esc(ariaLabel)}"` : '',
|
|
189
194
|
].filter(Boolean).join(' ');
|
|
190
195
|
|
|
@@ -269,6 +274,17 @@ const DD_GAP = 9;
|
|
|
269
274
|
// below asks the container for its panel rather than querying inside it.
|
|
270
275
|
const ddPanelOf = (dd) => dd.__ddPanel || dd.querySelector('[data-dropdown-panel]');
|
|
271
276
|
|
|
277
|
+
// A trigger the sheet paints off. The kit paints both spellings unavailable, so
|
|
278
|
+
// the wiring refuses both: the native attribute keeps the browser from
|
|
279
|
+
// dispatching anything, but an aria-disabled trigger is still a keyboard stop,
|
|
280
|
+
// and a click or an Enter on it reached openDropdown() until #580's round two.
|
|
281
|
+
// ddItemsOf() above refuses an aria-disabled ROW the same way.
|
|
282
|
+
// why: docs/foundations.md#colour-and-contrast
|
|
283
|
+
const ddTriggerOff = (dd) => {
|
|
284
|
+
const trigger = dd.querySelector('[data-dropdown-trigger]');
|
|
285
|
+
return !!trigger && (trigger.disabled === true || trigger.getAttribute('aria-disabled') === 'true');
|
|
286
|
+
};
|
|
287
|
+
|
|
272
288
|
function ddGap(panel) {
|
|
273
289
|
const declared = parseFloat(ddViewOf(panel).getComputedStyle(panel).getPropertyValue('--ui-dropdown-gap'));
|
|
274
290
|
return Number.isFinite(declared) ? declared : DD_GAP;
|
|
@@ -836,6 +852,9 @@ function closeAllDropdowns(except) {
|
|
|
836
852
|
}
|
|
837
853
|
|
|
838
854
|
function openDropdown(dd, focusIdx) {
|
|
855
|
+
// Every way in goes through here — the trigger's click, the Enter the browser
|
|
856
|
+
// turns into one, and the arrows — so one refusal covers them all. #580
|
|
857
|
+
if (ddTriggerOff(dd)) return;
|
|
839
858
|
closeAllDropdowns(dd);
|
|
840
859
|
const panel = ddPanelOf(dd);
|
|
841
860
|
const search = ddSearchOf(dd);
|
package/src/styles/dropdown.css
CHANGED
|
@@ -18,7 +18,11 @@
|
|
|
18
18
|
font-weight: 500;
|
|
19
19
|
color: var(--text);
|
|
20
20
|
background: var(--surface); /* code-bg: inherit — control paint; the containing surface is the ground, for a chip and for a band alike. */
|
|
21
|
-
|
|
21
|
+
/* The kit's live control edge, the one .ui-btn takes on the same fill. --border
|
|
22
|
+
is what --disabled-border resolves to in LIGHT, so a live trigger used to draw
|
|
23
|
+
the exact line the kit paints an unavailable control with. #580
|
|
24
|
+
why: docs/foundations.md#colour-and-contrast */
|
|
25
|
+
border: 1px solid var(--control-edge);
|
|
22
26
|
border-radius: var(--radius-pill);
|
|
23
27
|
padding: 7px 11px 7px 13px;
|
|
24
28
|
transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
|
|
@@ -29,6 +33,28 @@
|
|
|
29
33
|
what the kit's rows already chose. why: docs/foundations.md#the-focus-ring */
|
|
30
34
|
.ui-dropdown__trigger:hover:not(:focus-visible) { border-color: var(--accent); }
|
|
31
35
|
.ui-dropdown__trigger:focus-visible { outline: var(--ring); outline-offset: var(--ring-offset); }
|
|
36
|
+
/* Off. The off hover-not-focus selectors are (0,4,0), above live hover's (0,3,0).
|
|
37
|
+
A pointer over a dead control changes nothing while an aria-disabled one keeps its stop and the ring.
|
|
38
|
+
No fill: --disabled-surface IS this control's --surface, in both themes. The
|
|
39
|
+
activation is refused in ddTriggerOff(), not with pointer-events, which would
|
|
40
|
+
take that stop away. #580 why: docs/foundations.md#colour-and-contrast */
|
|
41
|
+
.ui-dropdown__trigger:disabled,
|
|
42
|
+
.ui-dropdown__trigger:disabled:hover,
|
|
43
|
+
.ui-dropdown__trigger:disabled:hover:not(:focus-visible),
|
|
44
|
+
.ui-dropdown__trigger:disabled:focus-visible,
|
|
45
|
+
.ui-dropdown__trigger[aria-disabled="true"]:hover,
|
|
46
|
+
.ui-dropdown__trigger[aria-disabled="true"]:hover:not(:focus-visible),
|
|
47
|
+
.ui-dropdown__trigger[aria-disabled="true"]:focus-visible,
|
|
48
|
+
.ui-dropdown__trigger[aria-disabled="true"] {
|
|
49
|
+
border-color: var(--disabled-border);
|
|
50
|
+
/* muted-ink: state — unavailable control */ color: var(--disabled-ink);
|
|
51
|
+
cursor: not-allowed;
|
|
52
|
+
}
|
|
53
|
+
/* The prefix and the value carry inks of their own, so they take the state's. */
|
|
54
|
+
.ui-dropdown__trigger:disabled .ui-dropdown__pre,
|
|
55
|
+
.ui-dropdown__trigger:disabled .ui-dropdown__value,
|
|
56
|
+
.ui-dropdown__trigger[aria-disabled="true"] .ui-dropdown__pre,
|
|
57
|
+
.ui-dropdown__trigger[aria-disabled="true"] .ui-dropdown__value { color: inherit; }
|
|
32
58
|
.ui-dropdown__pre { color: var(--text); }
|
|
33
59
|
.ui-dropdown__value { color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
|
|
34
60
|
|
package/src/styles/topbar.css
CHANGED
|
@@ -206,10 +206,10 @@
|
|
|
206
206
|
transition: background var(--dur-fast) var(--ease);
|
|
207
207
|
}
|
|
208
208
|
/* Menu rows use the reading surface and an edge on hover — see
|
|
209
|
-
src/styles/dropdown.css:
|
|
209
|
+
src/styles/dropdown.css:271 `.ui-dropdown__item:hover`.
|
|
210
210
|
why: docs/foundations.md#elevation */
|
|
211
211
|
.vopt:hover { outline: 1px solid var(--control-edge); outline-offset: -1px; background: var(--surface); /* code-bg: inherit — control paint; the containing surface is the ground, for a chip and for a band alike. */ }
|
|
212
|
-
/* The row is a keyboard stop: src/components/dropdown.js:
|
|
212
|
+
/* The row is a keyboard stop: src/components/dropdown.js:1107
|
|
213
213
|
`items[next < 0 ? 0 : next]?.focus()` moves focus onto a `[data-dd-item]` with
|
|
214
214
|
the arrow keys, and this is one. It takes the ring on its own 10px radius, the
|
|
215
215
|
same way `.amenu a` above does. #482 */
|