@crewlethq/ui 0.3.0 → 0.4.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/dist/Card/Card.d.ts +23 -1
- package/dist/Card/index.js +1 -1
- package/dist/{Card-AHX3Q2JD.css → Card-RLR254LD.css} +22 -0
- package/dist/CodeBlock/CodeBlock.d.ts +68 -9
- package/dist/CodeBlock/index.js +3 -3
- package/dist/{CodeBlock-U2W6NNVC.css → CodeBlock-GYNJ2HI6.css} +50 -15
- package/dist/Copyable/CopyButton.d.ts +11 -1
- package/dist/Copyable/Copyable.d.ts +9 -1
- package/dist/Copyable/index.js +2 -2
- package/dist/DataTable/index.js +2 -2
- package/dist/DataView/index.js +3 -3
- package/dist/FilterChip/FilterChip.d.ts +37 -5
- package/dist/FilterChip/index.d.ts +1 -1
- package/dist/FilterChip/index.js +1 -1
- package/dist/Meter/Meter.d.ts +79 -2
- package/dist/Meter/index.d.ts +2 -2
- package/dist/Meter/index.js +1 -1
- package/dist/SegmentedControl/SegmentedControl.d.ts +36 -3
- package/dist/SegmentedControl/index.d.ts +1 -1
- package/dist/SegmentedControl/index.js +2 -2
- package/dist/Select/Select.d.ts +16 -1
- package/dist/Select/index.js +1 -1
- package/dist/Tabs/index.js +1 -1
- package/dist/Tabs/roving.d.ts +32 -1
- package/dist/ThemeSwitcher/index.js +3 -3
- package/dist/TimeWindowPicker/index.js +2 -2
- package/dist/{chunk-GUIF6Q6N.js → chunk-2HQR4U4D.js} +1 -1
- package/dist/{chunk-GHYY2WPF.js → chunk-34VGEDVV.js} +1 -1
- package/dist/{chunk-D3OADIM6.js → chunk-3QRYCPXQ.js} +7 -3
- package/dist/{chunk-V663QU4R.js → chunk-5VNUYO76.js} +16 -5
- package/dist/chunk-6ZFVFA56.js +108 -0
- package/dist/{chunk-HTDFCRJZ.js → chunk-D35VTV2Z.js} +20 -6
- package/dist/{chunk-T7FKOJKW.js → chunk-NDCATSW7.js} +11 -3
- package/dist/{chunk-5IMACPJS.js → chunk-OFHBK7RI.js} +5 -2
- package/dist/{chunk-YMWONFSI.js → chunk-QEUY3A5P.js} +19 -3
- package/dist/{chunk-G2QFRTJ2.js → chunk-WOYYD2YR.js} +1 -1
- package/dist/{chunk-EHMQQHYR.js → chunk-WQX73TWF.js} +1 -1
- package/dist/{chunk-LGCPQIOZ.js → chunk-YODNNSZL.js} +23 -9
- package/dist/{chunk-EPOOQZYA.js → chunk-ZFATEERP.js} +32 -6
- package/dist/generated/index.js +16 -16
- package/dist/index.js +16 -16
- package/dist/styles.css +74 -17
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/useClipboard.d.ts +56 -4
- package/package.json +3 -3
- package/dist/chunk-ARMRX2YV.js +0 -96
package/dist/Select/Select.d.ts
CHANGED
|
@@ -59,8 +59,23 @@ export interface SelectOption {
|
|
|
59
59
|
* `HTMLSelectElement`, because the element a caller's handler lands on depends
|
|
60
60
|
* on the mode: the listbox's trigger is a button and the native mode's is a
|
|
61
61
|
* `select`. A handler written for the wider type works in both.
|
|
62
|
+
*
|
|
63
|
+
* `required` AND `aria-required` ARE BOTH HERE, and they are not the same
|
|
64
|
+
* fact. `required` is the form constraint: in native mode it is the attribute
|
|
65
|
+
* the browser validates against and refuses a submission on, and it implies
|
|
66
|
+
* the ARIA fact. `aria-required` states that fact ALONE — which is what a form
|
|
67
|
+
* needs where requiredness is the unmarked default and the visible mark beside
|
|
68
|
+
* the label is welded to the constraint flag, so asking for the constraint
|
|
69
|
+
* would mark every field on the screen. Where both are given the explicit one
|
|
70
|
+
* wins, because it is the more specific of the two statements.
|
|
71
|
+
*
|
|
72
|
+
* The rest of the `aria-*` surface is deliberately NOT picked. The listbox
|
|
73
|
+
* mode draws a button, a search box and a portalled panel rather than one
|
|
74
|
+
* element, so each attribute has to be routed to whichever of them is the
|
|
75
|
+
* combobox at the time; widened wholesale, every name nothing routes would be
|
|
76
|
+
* a prop the component accepts and silently ignores.
|
|
62
77
|
*/
|
|
63
|
-
type NativePassthrough = Pick<SelectHTMLAttributes<HTMLSelectElement>, 'autoFocus' | 'name' | 'required' | 'aria-describedby'> & {
|
|
78
|
+
type NativePassthrough = Pick<SelectHTMLAttributes<HTMLSelectElement>, 'autoFocus' | 'name' | 'required' | 'aria-describedby' | 'aria-required'> & {
|
|
64
79
|
onBlur?: FocusEventHandler<HTMLElement> | undefined;
|
|
65
80
|
onFocus?: FocusEventHandler<HTMLElement> | undefined;
|
|
66
81
|
};
|
package/dist/Select/index.js
CHANGED
package/dist/Tabs/index.js
CHANGED
package/dist/Tabs/roving.d.ts
CHANGED
|
@@ -8,10 +8,35 @@ import { type KeyboardEvent } from 'react';
|
|
|
8
8
|
* an element Tab skips, and the keyboard could not enter the row at all. It
|
|
9
9
|
* falls back to the first option that can take focus, and to none where every
|
|
10
10
|
* option is disabled, which is a row with nothing to reach.
|
|
11
|
+
*
|
|
12
|
+
* `selected` is where the stop BELONGS rather than what is chosen: under
|
|
13
|
+
* manual activation that is where focus last was, which is not the chosen
|
|
14
|
+
* option (see [RovingOptions.followFocus]).
|
|
11
15
|
*/
|
|
12
16
|
export declare function tabStop(items: readonly {
|
|
13
17
|
disabled?: boolean | undefined;
|
|
14
18
|
}[], selected: number): number;
|
|
19
|
+
/**
|
|
20
|
+
* How a row places its ONE TAB STOP while focus moves inside it.
|
|
21
|
+
*/
|
|
22
|
+
export interface RovingOptions {
|
|
23
|
+
/**
|
|
24
|
+
* Whether the stop FOLLOWS FOCUS rather than staying on the selection.
|
|
25
|
+
*
|
|
26
|
+
* Off by default, which is the only honest answer for a row that SELECTS AS
|
|
27
|
+
* FOCUS MOVES: there the two are the same element, so the stop needs no
|
|
28
|
+
* state of its own and an arrow key costs the render it was going to cost
|
|
29
|
+
* anyway.
|
|
30
|
+
*
|
|
31
|
+
* On is what a row whose arrows do NOT select has to have. With the stop
|
|
32
|
+
* left on the selection, a reader who arrows three options along without
|
|
33
|
+
* committing, Tabs out of the row and Tabs back is dropped on the option
|
|
34
|
+
* they started from rather than the one they left, and every move they made
|
|
35
|
+
* is gone with nothing said about it. It is half of manual activation, not
|
|
36
|
+
* a refinement of it.
|
|
37
|
+
*/
|
|
38
|
+
followFocus?: boolean | undefined;
|
|
39
|
+
}
|
|
15
40
|
/**
|
|
16
41
|
* Roving focus over a row of buttons: ONE TAB STOP for the row, the arrows to
|
|
17
42
|
* move inside it.
|
|
@@ -26,11 +51,17 @@ export declare function tabStop(items: readonly {
|
|
|
26
51
|
* tab is a section that pushes a history entry, and a row that selected on
|
|
27
52
|
* every arrow press left one entry per keystroke for Back to walk through.
|
|
28
53
|
*
|
|
54
|
+
* THE TWO ARGUMENTS GO TOGETHER. A caller that passes no `select` is a row
|
|
55
|
+
* under manual activation and wants `followFocus`, because the stop and the
|
|
56
|
+
* selection have come apart; a caller that passes one wants neither.
|
|
57
|
+
*
|
|
29
58
|
* A DISABLED BUTTON IS STEPPED OVER rather than focused: a browser refuses it
|
|
30
59
|
* focus, so a move that lands on one drops focus on the page body and the
|
|
31
60
|
* next arrow press does nothing at all.
|
|
32
61
|
*/
|
|
33
|
-
export declare function useRoving(count: number, select: ((index: number) => void) | null): {
|
|
62
|
+
export declare function useRoving(count: number, select: ((index: number) => void) | null, { followFocus }?: RovingOptions): {
|
|
34
63
|
buttons: import("react").RefObject<(HTMLButtonElement | null)[]>;
|
|
35
64
|
onKeyDown: (event: KeyboardEvent<HTMLElement>, vertical: boolean) => void;
|
|
65
|
+
onFocusAt: (index: number) => void;
|
|
66
|
+
focused: number | null;
|
|
36
67
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { DensitySwitcher, ThemeSwitcher, applyDensity, applyStoredPreferences, applyTheme, useDensityPreference, useThemePreference } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
3
|
-
import '../chunk-
|
|
1
|
+
export { DensitySwitcher, ThemeSwitcher, applyDensity, applyStoredPreferences, applyTheme, useDensityPreference, useThemePreference } from '../chunk-2HQR4U4D.js';
|
|
2
|
+
import '../chunk-6ZFVFA56.js';
|
|
3
|
+
import '../chunk-QEUY3A5P.js';
|
|
4
4
|
import '../chunk-BHHIIK3M.js';
|
|
5
5
|
import '../chunk-BZFWDIV6.js';
|
|
6
6
|
import '../chunk-ODEQTPFM.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { DEFAULT_TIME_WINDOW_LABELS, TIME_WINDOW_SPANS, TimeWindowPicker, describeTimeWindow, isTimeWindowSet, parseTimeWindowDuration, resolveTimeWindow, timeWindowMatchesPreset } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
1
|
+
export { DEFAULT_TIME_WINDOW_LABELS, TIME_WINDOW_SPANS, TimeWindowPicker, describeTimeWindow, isTimeWindowSet, parseTimeWindowDuration, resolveTimeWindow, timeWindowMatchesPreset } from '../chunk-WOYYD2YR.js';
|
|
2
|
+
import '../chunk-OFHBK7RI.js';
|
|
3
3
|
import '../chunk-DD5BBGBE.js';
|
|
4
4
|
import '../chunk-GXQ3B46I.js';
|
|
5
5
|
import '../chunk-GTOUGQQK.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SegmentedControl } from './chunk-
|
|
1
|
+
import { SegmentedControl } from './chunk-6ZFVFA56.js';
|
|
2
2
|
import { LightModeGlyph, ComputerGlyph, DarkModeGlyph } from '@crewlethq/icons/glyphs';
|
|
3
3
|
import { useState, useEffect, useCallback } from 'react';
|
|
4
4
|
import { jsx } from 'react/jsx-runtime';
|
|
@@ -2,7 +2,7 @@ import { Toolbar } from './chunk-5EKIWVOR.js';
|
|
|
2
2
|
import { PageHeader } from './chunk-HOXGBLEY.js';
|
|
3
3
|
import { RelativeTime } from './chunk-3CZ7XAVY.js';
|
|
4
4
|
import { Kbd } from './chunk-SFZOKW2G.js';
|
|
5
|
-
import { DataTable } from './chunk-
|
|
5
|
+
import { DataTable } from './chunk-WQX73TWF.js';
|
|
6
6
|
import { Menu } from './chunk-FBZAKNSX.js';
|
|
7
7
|
import { DateTimePicker } from './chunk-UG46QBLT.js';
|
|
8
8
|
import { Popover } from './chunk-DD5BBGBE.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useClipboard } from './chunk-
|
|
1
|
+
import { useClipboard } from './chunk-5VNUYO76.js';
|
|
2
2
|
import { IconButton } from './chunk-F27EPQ7D.js';
|
|
3
3
|
import { Button } from './chunk-BZYDZBAN.js';
|
|
4
4
|
import { VisuallyHidden } from './chunk-BZFWDIV6.js';
|
|
@@ -26,9 +26,11 @@ function CopyButton({
|
|
|
26
26
|
size = "small",
|
|
27
27
|
variant = "tertiary",
|
|
28
28
|
title,
|
|
29
|
+
resetMs,
|
|
30
|
+
failedResetMs,
|
|
29
31
|
className
|
|
30
32
|
}) {
|
|
31
|
-
const { state, copy } = useClipboard();
|
|
33
|
+
const { state, copy } = useClipboard({ resetMs, failedResetMs });
|
|
32
34
|
const onClick = useCallback(() => {
|
|
33
35
|
void copy(text);
|
|
34
36
|
}, [copy, text]);
|
|
@@ -67,10 +69,12 @@ var Copyable = ({
|
|
|
67
69
|
title = "Copy",
|
|
68
70
|
copiedMessage = "copied to the clipboard",
|
|
69
71
|
failedMessage = "the browser refused the clipboard",
|
|
72
|
+
resetMs,
|
|
73
|
+
failedResetMs,
|
|
70
74
|
className
|
|
71
75
|
}) => {
|
|
72
76
|
const text = value === void 0 || value === null ? "" : String(value);
|
|
73
|
-
const { state, copy } = useClipboard();
|
|
77
|
+
const { state, copy } = useClipboard({ resetMs, failedResetMs });
|
|
74
78
|
const onCopy = useCallback(() => {
|
|
75
79
|
void copy(text);
|
|
76
80
|
}, [copy, text]);
|
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
2
2
|
|
|
3
3
|
// src/utils/useClipboard.ts
|
|
4
|
-
function useClipboard({ resetMs = 2e3 } = {}) {
|
|
4
|
+
function useClipboard({ resetMs = 2e3, failedResetMs } = {}) {
|
|
5
5
|
const [state, setState] = useState("idle");
|
|
6
6
|
const timer = useRef(void 0);
|
|
7
|
-
|
|
7
|
+
const live = useRef(true);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
live.current = true;
|
|
10
|
+
return () => {
|
|
11
|
+
live.current = false;
|
|
12
|
+
clearTimeout(timer.current);
|
|
13
|
+
timer.current = void 0;
|
|
14
|
+
};
|
|
15
|
+
}, []);
|
|
8
16
|
const copy = useCallback(
|
|
9
17
|
async (text) => {
|
|
10
18
|
const ok = await writeClipboard(typeof text === "function" ? text() : text);
|
|
19
|
+
if (!live.current) return ok;
|
|
11
20
|
setState(ok ? "copied" : "failed");
|
|
12
21
|
clearTimeout(timer.current);
|
|
13
|
-
timer.current =
|
|
22
|
+
timer.current = void 0;
|
|
23
|
+
const after = ok ? resetMs : failedResetMs === void 0 ? resetMs : failedResetMs;
|
|
24
|
+
if (after !== null) timer.current = setTimeout(() => setState("idle"), after);
|
|
14
25
|
return ok;
|
|
15
26
|
},
|
|
16
|
-
[resetMs]
|
|
27
|
+
[resetMs, failedResetMs]
|
|
17
28
|
);
|
|
18
29
|
return { state, copy };
|
|
19
30
|
}
|
|
@@ -48,4 +59,4 @@ function execCommandCopy(text) {
|
|
|
48
59
|
}
|
|
49
60
|
}
|
|
50
61
|
|
|
51
|
-
export { useClipboard };
|
|
62
|
+
export { useClipboard, writeClipboard };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { useRoving, tabStop, tabId } from './chunk-QEUY3A5P.js';
|
|
2
|
+
import { Count } from './chunk-BHHIIK3M.js';
|
|
3
|
+
import { VisuallyHidden } from './chunk-BZFWDIV6.js';
|
|
4
|
+
import { cx } from './chunk-ODEQTPFM.js';
|
|
5
|
+
import './Tabs-VLICJFVB.css';
|
|
6
|
+
import './SegmentedControl-X3BI3XU4.css';
|
|
7
|
+
import { useId } from 'react';
|
|
8
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
9
|
+
|
|
10
|
+
var ACTIVATE_HINT = "Press Enter or Space to choose the option you land on.";
|
|
11
|
+
function SegmentedControl({
|
|
12
|
+
label,
|
|
13
|
+
options,
|
|
14
|
+
value,
|
|
15
|
+
onValueChange,
|
|
16
|
+
size = "md",
|
|
17
|
+
className = "",
|
|
18
|
+
semantics,
|
|
19
|
+
panelId,
|
|
20
|
+
activate = "automatic",
|
|
21
|
+
activateHint
|
|
22
|
+
}) {
|
|
23
|
+
const radio = semantics === "radio";
|
|
24
|
+
const manual = radio && activate === "manual";
|
|
25
|
+
const cards = options.some((option) => option.description !== void 0);
|
|
26
|
+
const { buttons, onKeyDown, onFocusAt, focused } = useRoving(
|
|
27
|
+
options.length,
|
|
28
|
+
radio && !manual ? (index) => onValueChange(options[index].value) : null,
|
|
29
|
+
{ followFocus: manual }
|
|
30
|
+
);
|
|
31
|
+
const chosenIndex = Math.max(
|
|
32
|
+
0,
|
|
33
|
+
options.findIndex((option) => option.value === value)
|
|
34
|
+
);
|
|
35
|
+
const stop = tabStop(options, focused ?? chosenIndex);
|
|
36
|
+
const hintId = useId();
|
|
37
|
+
const hint = manual ? activateHint === void 0 ? ACTIVATE_HINT : activateHint : null;
|
|
38
|
+
return /* @__PURE__ */ jsxs(
|
|
39
|
+
"div",
|
|
40
|
+
{
|
|
41
|
+
className: cx(
|
|
42
|
+
"crewlet-tabs",
|
|
43
|
+
/*
|
|
44
|
+
* THE PILL CHROME IS NOT WORN IN CARDS MODE. A card row is not a chip
|
|
45
|
+
* in a tinted container: the pill's own rules set the container's
|
|
46
|
+
* background, border, padding and `width: fit-content`, and each
|
|
47
|
+
* option's padding, radius and active chip. Left on, every one of
|
|
48
|
+
* them still applied (the two stylesheets are single-class rules and
|
|
49
|
+
* Tabs.css is bundled last), so the cards were drawn inside a pill
|
|
50
|
+
* bar sized to its content, which is what the mode exists to avoid.
|
|
51
|
+
*/
|
|
52
|
+
!cards && "crewlet-tabs--pill",
|
|
53
|
+
`crewlet-tabs--${size}`,
|
|
54
|
+
"crewlet-segmented",
|
|
55
|
+
cards && "crewlet-segmented--cards",
|
|
56
|
+
className
|
|
57
|
+
),
|
|
58
|
+
role: radio ? "radiogroup" : "tablist",
|
|
59
|
+
"aria-label": label,
|
|
60
|
+
"aria-describedby": hint ? hintId : void 0,
|
|
61
|
+
children: [
|
|
62
|
+
options.map((option, index) => {
|
|
63
|
+
const chosen = option.value === value;
|
|
64
|
+
const named = option.srLabel ?? (option.label ? void 0 : option.title);
|
|
65
|
+
return /* @__PURE__ */ jsxs(
|
|
66
|
+
"button",
|
|
67
|
+
{
|
|
68
|
+
ref: (el) => {
|
|
69
|
+
buttons.current[index] = el;
|
|
70
|
+
},
|
|
71
|
+
type: "button",
|
|
72
|
+
role: radio ? "radio" : "tab",
|
|
73
|
+
id: radio || !panelId ? void 0 : tabId(panelId, option.value),
|
|
74
|
+
"aria-checked": radio ? chosen : void 0,
|
|
75
|
+
"aria-selected": radio ? void 0 : chosen,
|
|
76
|
+
"aria-controls": radio ? void 0 : panelId,
|
|
77
|
+
"aria-label": named,
|
|
78
|
+
tabIndex: index === stop ? 0 : -1,
|
|
79
|
+
title: option.title,
|
|
80
|
+
disabled: option.disabled,
|
|
81
|
+
className: cx(
|
|
82
|
+
"crewlet-tabs__tab",
|
|
83
|
+
"crewlet-segmented__option",
|
|
84
|
+
chosen && "is-active",
|
|
85
|
+
option.disabled && "is-disabled"
|
|
86
|
+
),
|
|
87
|
+
onClick: () => onValueChange(option.value),
|
|
88
|
+
onFocus: () => onFocusAt(index),
|
|
89
|
+
onKeyDown: (event) => onKeyDown(event, radio),
|
|
90
|
+
children: [
|
|
91
|
+
option.icon ? /* @__PURE__ */ jsx("span", { className: "crewlet-tabs__icon", children: option.icon }) : null,
|
|
92
|
+
option.label || option.description ? /* @__PURE__ */ jsxs("span", { className: "crewlet-segmented__text", children: [
|
|
93
|
+
/* @__PURE__ */ jsx("span", { className: "crewlet-tabs__label", children: option.label }),
|
|
94
|
+
option.description ? /* @__PURE__ */ jsx("span", { className: "crewlet-segmented__description", children: option.description }) : null
|
|
95
|
+
] }) : null,
|
|
96
|
+
option.count != null ? /* @__PURE__ */ jsx(Count, { value: option.count }) : null
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
option.value
|
|
100
|
+
);
|
|
101
|
+
}),
|
|
102
|
+
hint ? /* @__PURE__ */ jsx(VisuallyHidden, { id: hintId, children: hint }) : null
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export { SegmentedControl };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { CopyButton } from './chunk-
|
|
1
|
+
import { CopyButton } from './chunk-3QRYCPXQ.js';
|
|
2
2
|
import { cx } from './chunk-ODEQTPFM.js';
|
|
3
|
-
import './CodeBlock-
|
|
4
|
-
import { forwardRef, useRef } from 'react';
|
|
3
|
+
import './CodeBlock-GYNJ2HI6.css';
|
|
4
|
+
import { forwardRef, useRef, useState, useLayoutEffect } from 'react';
|
|
5
5
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
7
|
var CodeBlock = forwardRef(function CodeBlock2({
|
|
@@ -16,6 +16,7 @@ var CodeBlock = forwardRef(function CodeBlock2({
|
|
|
16
16
|
maxHeight,
|
|
17
17
|
plain = false,
|
|
18
18
|
selectable = false,
|
|
19
|
+
focusWhenScrollable = false,
|
|
19
20
|
label,
|
|
20
21
|
className,
|
|
21
22
|
style,
|
|
@@ -25,6 +26,19 @@ var CodeBlock = forwardRef(function CodeBlock2({
|
|
|
25
26
|
const body = code.replace(/\n+$/, "");
|
|
26
27
|
const showHeader = !plain && (filename !== void 0 || language !== void 0 || copyable);
|
|
27
28
|
const perLine = showLineNumbers || prompt !== void 0;
|
|
29
|
+
const [overflows, setOverflows] = useState(false);
|
|
30
|
+
useLayoutEffect(() => {
|
|
31
|
+
if (!focusWhenScrollable) return;
|
|
32
|
+
const node = box.current;
|
|
33
|
+
if (!node) return;
|
|
34
|
+
const measure = () => setOverflows(node.scrollHeight > node.clientHeight || node.scrollWidth > node.clientWidth);
|
|
35
|
+
measure();
|
|
36
|
+
if (typeof ResizeObserver !== "function") return;
|
|
37
|
+
const watch = new ResizeObserver(measure);
|
|
38
|
+
watch.observe(node);
|
|
39
|
+
return () => watch.disconnect();
|
|
40
|
+
}, [focusWhenScrollable, body, wrap, showLineNumbers, prompt, maxHeight]);
|
|
41
|
+
const focusable = selectable || focusWhenScrollable && overflows;
|
|
28
42
|
const onKeyDown = (event) => {
|
|
29
43
|
const isA = event.code === "KeyA" || !event.code && event.key.toLowerCase() === "a";
|
|
30
44
|
if (!isA || event.altKey || event.shiftKey || !(event.metaKey || event.ctrlKey)) return;
|
|
@@ -77,9 +91,9 @@ var CodeBlock = forwardRef(function CodeBlock2({
|
|
|
77
91
|
ref: box,
|
|
78
92
|
className: "crewlet-codeblock__pre",
|
|
79
93
|
"data-language": language,
|
|
80
|
-
tabIndex:
|
|
81
|
-
role:
|
|
82
|
-
"aria-label":
|
|
94
|
+
tabIndex: focusable ? 0 : void 0,
|
|
95
|
+
role: focusable ? "region" : void 0,
|
|
96
|
+
"aria-label": focusable ? label : void 0,
|
|
83
97
|
onKeyDown: selectable ? onKeyDown : void 0,
|
|
84
98
|
children: /* @__PURE__ */ jsx("code", { className: "crewlet-codeblock__code", children: content })
|
|
85
99
|
}
|
|
@@ -2,7 +2,7 @@ import { CardHeaderSlotContext } from './chunk-AV2DXAEL.js';
|
|
|
2
2
|
import { Count } from './chunk-BHHIIK3M.js';
|
|
3
3
|
import { useHeadingLevel, HeadingLevelProvider, nextHeadingLevel, headingTag } from './chunk-PQADV6P6.js';
|
|
4
4
|
import { cx } from './chunk-ODEQTPFM.js';
|
|
5
|
-
import './Card-
|
|
5
|
+
import './Card-RLR254LD.css';
|
|
6
6
|
import { createContext, useId, useState, isValidElement, useRef, useCallback, useMemo, Children, cloneElement, useContext, useEffect, Fragment } from 'react';
|
|
7
7
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
8
8
|
|
|
@@ -198,7 +198,7 @@ var CardFooter = ({ variant = "actions", padding = "sm", className, children, ..
|
|
|
198
198
|
children
|
|
199
199
|
}
|
|
200
200
|
);
|
|
201
|
-
var CardTitle = ({ as, className, children, ...rest }) => {
|
|
201
|
+
var CardTitle = ({ as, truncate = false, className, children, ...rest }) => {
|
|
202
202
|
const card = useContext(CardContext);
|
|
203
203
|
const fallback = useHeadingLevel();
|
|
204
204
|
const Tag = as ?? headingTag(card?.titleLevel ?? fallback);
|
|
@@ -206,7 +206,15 @@ var CardTitle = ({ as, className, children, ...rest }) => {
|
|
|
206
206
|
useEffect(() => {
|
|
207
207
|
register?.();
|
|
208
208
|
}, [register]);
|
|
209
|
-
return /* @__PURE__ */ jsx(
|
|
209
|
+
return /* @__PURE__ */ jsx(
|
|
210
|
+
Tag,
|
|
211
|
+
{
|
|
212
|
+
...rest,
|
|
213
|
+
id: rest.id ?? card?.titleId,
|
|
214
|
+
className: cx("crewlet-card__title", truncate && "crewlet-card__title--truncate", className),
|
|
215
|
+
children
|
|
216
|
+
}
|
|
217
|
+
);
|
|
210
218
|
};
|
|
211
219
|
var CardDescription = ({ className, children, ...rest }) => /* @__PURE__ */ jsx("p", { ...rest, className: cx("crewlet-card__description", className), children });
|
|
212
220
|
var SLOT_TYPES = /* @__PURE__ */ new Set([CardHeader, CardBody, CardFooter]);
|
|
@@ -90,6 +90,7 @@ var Select = forwardRef(function Select2({
|
|
|
90
90
|
emptyMessage,
|
|
91
91
|
describedBy: native["aria-describedby"],
|
|
92
92
|
required: native.required,
|
|
93
|
+
ariaRequired: native["aria-required"],
|
|
93
94
|
focusOnMount: native.autoFocus,
|
|
94
95
|
name: native.name,
|
|
95
96
|
onBlur: native.onBlur,
|
|
@@ -165,6 +166,7 @@ var ListboxSelect = forwardRef(function ListboxSelect2({
|
|
|
165
166
|
emptyMessage,
|
|
166
167
|
describedBy,
|
|
167
168
|
required,
|
|
169
|
+
ariaRequired,
|
|
168
170
|
focusOnMount,
|
|
169
171
|
name,
|
|
170
172
|
onBlur,
|
|
@@ -339,6 +341,7 @@ var ListboxSelect = forwardRef(function ListboxSelect2({
|
|
|
339
341
|
const listId = listbox.listId;
|
|
340
342
|
const activeId = open && flat.length > 0 ? listbox.optionId(listbox.active) : void 0;
|
|
341
343
|
const comboOnTrigger = !searchable;
|
|
344
|
+
const requiredForAria = ariaRequired ?? required;
|
|
342
345
|
let index = -1;
|
|
343
346
|
const rows = groups.map((group, position2) => {
|
|
344
347
|
const items = group.items.map((option) => {
|
|
@@ -414,7 +417,7 @@ var ListboxSelect = forwardRef(function ListboxSelect2({
|
|
|
414
417
|
"aria-controls": listId,
|
|
415
418
|
"aria-activedescendant": activeId,
|
|
416
419
|
"aria-label": searchPlaceholder,
|
|
417
|
-
"aria-required":
|
|
420
|
+
"aria-required": requiredForAria,
|
|
418
421
|
placeholder: searchPlaceholder,
|
|
419
422
|
value: query,
|
|
420
423
|
onChange: (event) => setQuery(event.target.value),
|
|
@@ -474,7 +477,7 @@ var ListboxSelect = forwardRef(function ListboxSelect2({
|
|
|
474
477
|
"aria-label": ariaLabel,
|
|
475
478
|
"aria-describedby": describedBy,
|
|
476
479
|
"aria-invalid": error || void 0,
|
|
477
|
-
"aria-required": comboOnTrigger ?
|
|
480
|
+
"aria-required": comboOnTrigger ? requiredForAria : void 0,
|
|
478
481
|
disabled,
|
|
479
482
|
onBlur,
|
|
480
483
|
onFocus,
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { Count } from './chunk-BHHIIK3M.js';
|
|
2
2
|
import { cx } from './chunk-ODEQTPFM.js';
|
|
3
3
|
import './Tabs-VLICJFVB.css';
|
|
4
|
-
import React, { useRef, useLayoutEffect } from 'react';
|
|
4
|
+
import React, { useRef, useState, useLayoutEffect } from 'react';
|
|
5
5
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
7
|
function tabStop(items, selected) {
|
|
8
8
|
if (selected >= 0 && !items[selected]?.disabled) return selected;
|
|
9
9
|
return items.findIndex((item) => !item.disabled);
|
|
10
10
|
}
|
|
11
|
-
function useRoving(count, select) {
|
|
11
|
+
function useRoving(count, select, { followFocus = false } = {}) {
|
|
12
12
|
const buttons = useRef([]);
|
|
13
|
+
const [landed, setLanded] = useState(null);
|
|
13
14
|
function step(from, by) {
|
|
14
15
|
for (let i = 0; i < count; i += 1) {
|
|
15
16
|
const at = ((from + by * i) % count + count) % count;
|
|
@@ -37,6 +38,9 @@ function useRoving(count, select) {
|
|
|
37
38
|
return null;
|
|
38
39
|
}
|
|
39
40
|
}
|
|
41
|
+
const onFocusAt = (index) => {
|
|
42
|
+
if (followFocus) setLanded(index);
|
|
43
|
+
};
|
|
40
44
|
const onKeyDown = (event, vertical) => {
|
|
41
45
|
const at = buttons.current.findIndex((button) => button === document.activeElement);
|
|
42
46
|
if (at < 0) return;
|
|
@@ -44,9 +48,21 @@ function useRoving(count, select) {
|
|
|
44
48
|
if (next === null) return;
|
|
45
49
|
event.preventDefault();
|
|
46
50
|
buttons.current[next]?.focus();
|
|
51
|
+
onFocusAt(next);
|
|
47
52
|
select?.(next);
|
|
48
53
|
};
|
|
49
|
-
return {
|
|
54
|
+
return {
|
|
55
|
+
buttons,
|
|
56
|
+
onKeyDown,
|
|
57
|
+
onFocusAt,
|
|
58
|
+
/*
|
|
59
|
+
* Where the stop belongs, or null for "on the caller's selection, as
|
|
60
|
+
* ever". Bounded by the CURRENT count, because a row whose options
|
|
61
|
+
* changed under a remembered index would otherwise put its only stop past
|
|
62
|
+
* its own end, where Tab finds nothing at all.
|
|
63
|
+
*/
|
|
64
|
+
focused: followFocus && landed !== null && landed < count ? landed : null
|
|
65
|
+
};
|
|
50
66
|
}
|
|
51
67
|
function tabId(panelId, value) {
|
|
52
68
|
return `${panelId}-tab-${value}`;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Select } from './chunk-
|
|
1
|
+
import { Select } from './chunk-OFHBK7RI.js';
|
|
2
2
|
import { Popover } from './chunk-DD5BBGBE.js';
|
|
3
3
|
import { today, shiftMonth, CalendarGrid, compareDays } from './chunk-GXQ3B46I.js';
|
|
4
4
|
import { Input } from './chunk-O6232G37.js';
|
|
@@ -3,7 +3,7 @@ import { EmptyValue } from './chunk-EUCC37WY.js';
|
|
|
3
3
|
import { Modal } from './chunk-2EOKFKHX.js';
|
|
4
4
|
import { useCardHeaderSlot } from './chunk-AV2DXAEL.js';
|
|
5
5
|
import { Checkbox } from './chunk-2PRH365R.js';
|
|
6
|
-
import { useClipboard } from './chunk-
|
|
6
|
+
import { useClipboard } from './chunk-5VNUYO76.js';
|
|
7
7
|
import { IconButton } from './chunk-F27EPQ7D.js';
|
|
8
8
|
import { Button } from './chunk-BZYDZBAN.js';
|
|
9
9
|
import { VisuallyHidden } from './chunk-BZFWDIV6.js';
|
|
@@ -9,6 +9,13 @@ function meterTone(percent) {
|
|
|
9
9
|
if (percent >= 75) return "warning";
|
|
10
10
|
return "brand";
|
|
11
11
|
}
|
|
12
|
+
function progressTone(percent) {
|
|
13
|
+
return percent >= 100 ? "success" : "brand";
|
|
14
|
+
}
|
|
15
|
+
var RAMPS = {
|
|
16
|
+
spent: meterTone,
|
|
17
|
+
progress: progressTone
|
|
18
|
+
};
|
|
12
19
|
function Meter({
|
|
13
20
|
value,
|
|
14
21
|
max,
|
|
@@ -16,34 +23,41 @@ function Meter({
|
|
|
16
23
|
valueText,
|
|
17
24
|
hint,
|
|
18
25
|
tone,
|
|
26
|
+
polarity = "spent",
|
|
19
27
|
size = "default",
|
|
20
28
|
hideLabel = false,
|
|
21
29
|
className,
|
|
22
30
|
...rest
|
|
23
31
|
}) {
|
|
24
32
|
const labelId = useId();
|
|
25
|
-
const
|
|
26
|
-
const
|
|
33
|
+
const bounded = max > 0;
|
|
34
|
+
const percent = bounded ? Math.min(100, Math.max(0, value / max * 100)) : 0;
|
|
35
|
+
const drawn = tone ?? RAMPS[polarity](percent);
|
|
27
36
|
const trailing = hint ?? valueText;
|
|
37
|
+
const reported = bounded ? Math.min(max, Math.max(0, value)) : value;
|
|
38
|
+
const spoken = bounded ? valueText ?? (reported === value ? void 0 : `${value} of ${max}`) : void 0;
|
|
39
|
+
const unspoken = !bounded && valueText !== void 0 && (hideLabel || hint !== void 0) ? valueText : void 0;
|
|
28
40
|
return /* @__PURE__ */ jsxs("div", { ...rest, className: cx("crewlet-meter", `crewlet-meter--${size}`, className), children: [
|
|
29
41
|
hideLabel ? /* @__PURE__ */ jsx(VisuallyHidden, { id: labelId, children: label }) : /* @__PURE__ */ jsxs("div", { className: "crewlet-meter__legend", children: [
|
|
30
42
|
/* @__PURE__ */ jsx("span", { id: labelId, className: "crewlet-meter__label", children: label }),
|
|
31
43
|
trailing === void 0 ? null : /* @__PURE__ */ jsx("span", { className: "crewlet-meter__hint", children: trailing })
|
|
32
44
|
] }),
|
|
45
|
+
unspoken === void 0 ? null : /* @__PURE__ */ jsx(VisuallyHidden, { children: unspoken }),
|
|
33
46
|
/* @__PURE__ */ jsx(
|
|
34
47
|
"div",
|
|
35
48
|
{
|
|
36
49
|
className: "crewlet-meter__track",
|
|
37
|
-
role: "meter",
|
|
38
|
-
"aria-labelledby": labelId,
|
|
39
|
-
"aria-valuenow":
|
|
40
|
-
"aria-valuemin": 0,
|
|
41
|
-
"aria-valuemax": max,
|
|
42
|
-
"aria-valuetext":
|
|
50
|
+
role: bounded ? "meter" : void 0,
|
|
51
|
+
"aria-labelledby": bounded ? labelId : void 0,
|
|
52
|
+
"aria-valuenow": bounded ? reported : void 0,
|
|
53
|
+
"aria-valuemin": bounded ? 0 : void 0,
|
|
54
|
+
"aria-valuemax": bounded ? max : void 0,
|
|
55
|
+
"aria-valuetext": spoken,
|
|
56
|
+
"aria-hidden": bounded ? void 0 : true,
|
|
43
57
|
children: /* @__PURE__ */ jsx("div", { className: "crewlet-meter__fill", "data-tone": drawn, style: { width: `${percent}%` } })
|
|
44
58
|
}
|
|
45
59
|
)
|
|
46
60
|
] });
|
|
47
61
|
}
|
|
48
62
|
|
|
49
|
-
export { Meter, meterTone };
|
|
63
|
+
export { Meter, meterTone, progressTone };
|