@crewlethq/ui 0.3.0 → 0.4.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.
Files changed (47) hide show
  1. package/dist/Card/Card.d.ts +23 -1
  2. package/dist/Card/index.js +1 -1
  3. package/dist/{Card-AHX3Q2JD.css → Card-RLR254LD.css} +22 -0
  4. package/dist/CodeBlock/CodeBlock.d.ts +68 -9
  5. package/dist/CodeBlock/index.js +3 -3
  6. package/dist/{CodeBlock-U2W6NNVC.css → CodeBlock-GYNJ2HI6.css} +50 -15
  7. package/dist/Copyable/CopyButton.d.ts +11 -1
  8. package/dist/Copyable/Copyable.d.ts +9 -1
  9. package/dist/Copyable/index.js +2 -2
  10. package/dist/DataTable/index.js +2 -2
  11. package/dist/DataView/index.js +3 -3
  12. package/dist/FilterChip/FilterChip.d.ts +37 -5
  13. package/dist/FilterChip/index.d.ts +1 -1
  14. package/dist/FilterChip/index.js +1 -1
  15. package/dist/Meter/Meter.d.ts +79 -2
  16. package/dist/Meter/index.d.ts +2 -2
  17. package/dist/Meter/index.js +1 -1
  18. package/dist/SegmentedControl/SegmentedControl.d.ts +36 -3
  19. package/dist/SegmentedControl/index.d.ts +1 -1
  20. package/dist/SegmentedControl/index.js +2 -2
  21. package/dist/Select/Select.d.ts +16 -1
  22. package/dist/Select/index.js +1 -1
  23. package/dist/Tabs/index.js +1 -1
  24. package/dist/Tabs/roving.d.ts +32 -1
  25. package/dist/ThemeSwitcher/index.js +3 -3
  26. package/dist/TimeWindowPicker/index.js +2 -2
  27. package/dist/{chunk-GUIF6Q6N.js → chunk-2HQR4U4D.js} +1 -1
  28. package/dist/{chunk-GHYY2WPF.js → chunk-34VGEDVV.js} +1 -1
  29. package/dist/{chunk-D3OADIM6.js → chunk-3QRYCPXQ.js} +7 -3
  30. package/dist/{chunk-V663QU4R.js → chunk-5VNUYO76.js} +16 -5
  31. package/dist/chunk-6ZFVFA56.js +108 -0
  32. package/dist/{chunk-HTDFCRJZ.js → chunk-D35VTV2Z.js} +20 -6
  33. package/dist/{chunk-T7FKOJKW.js → chunk-NDCATSW7.js} +11 -3
  34. package/dist/{chunk-5IMACPJS.js → chunk-OFHBK7RI.js} +5 -2
  35. package/dist/{chunk-YMWONFSI.js → chunk-QEUY3A5P.js} +19 -3
  36. package/dist/{chunk-G2QFRTJ2.js → chunk-WOYYD2YR.js} +1 -1
  37. package/dist/{chunk-EHMQQHYR.js → chunk-WQX73TWF.js} +1 -1
  38. package/dist/{chunk-LGCPQIOZ.js → chunk-YODNNSZL.js} +23 -9
  39. package/dist/{chunk-EPOOQZYA.js → chunk-ZFATEERP.js} +32 -6
  40. package/dist/generated/index.js +17 -17
  41. package/dist/index.js +17 -17
  42. package/dist/styles.css +74 -17
  43. package/dist/utils/index.d.ts +1 -1
  44. package/dist/utils/index.js +1 -1
  45. package/dist/utils/useClipboard.d.ts +56 -4
  46. package/package.json +3 -3
  47. package/dist/chunk-ARMRX2YV.js +0 -96
@@ -49,6 +49,7 @@ function FilterChip({
49
49
  }
50
50
  );
51
51
  }
52
+ var ACTIVATE_HINT = "Press Enter or Space to apply the filter you land on.";
52
53
  var reachable = (chip) => !chip.disabled && chip.getAttribute("aria-disabled") !== "true";
53
54
  function moveTo(key, from, total) {
54
55
  if (key === "ArrowRight" || key === "ArrowDown") return (from + 1) % total;
@@ -60,6 +61,8 @@ function moveTo(key, from, total) {
60
61
  function FilterChipGroup({
61
62
  label,
62
63
  semantics = "toggle",
64
+ activate = "automatic",
65
+ activateHint,
63
66
  value,
64
67
  onValueChange,
65
68
  allowNone = false,
@@ -69,19 +72,25 @@ function FilterChipGroup({
69
72
  }) {
70
73
  const row = useRef(null);
71
74
  const labelId = useId();
75
+ const hintId = useId();
76
+ const manual = semantics === "radio" && activate === "manual";
77
+ const hint = manual ? activateHint === void 0 ? ACTIVATE_HINT : activateHint : null;
78
+ const landed = useRef(null);
72
79
  const chips = useCallback(
73
80
  () => row.current === null ? [] : [...row.current.querySelectorAll(`[${FILTER_CHIP_ATTRIBUTE}]`)],
74
81
  []
75
82
  );
76
- useLayoutEffect(() => {
83
+ const placeStop = useCallback(() => {
77
84
  if (semantics !== "radio") return;
78
85
  const all = chips();
86
+ const held = manual && landed.current !== null ? all.indexOf(landed.current) : -1;
79
87
  const chosen = all.findIndex((chip) => chip.getAttribute("aria-checked") === "true" && reachable(chip));
80
- const stop = chosen < 0 ? all.findIndex(reachable) : chosen;
88
+ const stop = held >= 0 && reachable(all[held]) ? held : chosen < 0 ? all.findIndex(reachable) : chosen;
81
89
  all.forEach((chip, index) => {
82
90
  chip.tabIndex = index === stop ? 0 : -1;
83
91
  });
84
- });
92
+ }, [chips, manual, semantics]);
93
+ useLayoutEffect(placeStop);
85
94
  const choose = useCallback(
86
95
  (next) => {
87
96
  onValueChange?.(next);
@@ -95,9 +104,23 @@ function FilterChipGroup({
95
104
  if (from < 0 || open.length === 0) return;
96
105
  const to = moveTo(event.key, from, open.length);
97
106
  if (to === null) return;
107
+ const next = open[to];
108
+ if (next === void 0) return;
98
109
  event.preventDefault();
99
- open[to]?.focus();
100
- open[to]?.click();
110
+ next.focus();
111
+ if (manual) {
112
+ landed.current = next;
113
+ placeStop();
114
+ return;
115
+ }
116
+ next.click();
117
+ };
118
+ const onFocus = (event) => {
119
+ if (!manual) return;
120
+ const target = event.target;
121
+ if (!target.hasAttribute(FILTER_CHIP_ATTRIBUTE)) return;
122
+ landed.current = target;
123
+ placeStop();
101
124
  };
102
125
  return /* @__PURE__ */ jsxs(
103
126
  "div",
@@ -105,11 +128,14 @@ function FilterChipGroup({
105
128
  ref: row,
106
129
  role: semantics === "radio" ? "radiogroup" : "group",
107
130
  "aria-labelledby": labelId,
131
+ "aria-describedby": hint ? hintId : void 0,
108
132
  className: cx("crewlet-filter-chip-group", className),
109
133
  onKeyDown,
134
+ onFocus,
110
135
  children: [
111
136
  hideLabel ? /* @__PURE__ */ jsx(VisuallyHidden, { id: labelId, children: label }) : /* @__PURE__ */ jsx("span", { id: labelId, className: "crewlet-filter-chip-group__label", children: label }),
112
- /* @__PURE__ */ jsx(GroupContext.Provider, { value: { semantics, value, choose, allowNone }, children })
137
+ /* @__PURE__ */ jsx(GroupContext.Provider, { value: { semantics, value, choose, allowNone }, children }),
138
+ hint ? /* @__PURE__ */ jsx(VisuallyHidden, { id: hintId, children: hint }) : null
113
139
  ]
114
140
  }
115
141
  );
@@ -2,25 +2,25 @@ import '../chunk-ZCR6YGQ4.js';
2
2
  export { TreeCanvas } from '../chunk-7HPRF5XN.js';
3
3
  import '../chunk-IJ7QXNIJ.js';
4
4
  export { Text } from '../chunk-23DHIMJA.js';
5
- export { DensitySwitcher, ThemeSwitcher, applyDensity, applyStoredPreferences, applyTheme, useDensityPreference, useThemePreference } from '../chunk-GUIF6Q6N.js';
6
- export { DEFAULT_TIME_WINDOW_LABELS, TIME_WINDOW_SPANS, TimeWindowPicker, describeTimeWindow, isTimeWindowSet, parseTimeWindowDuration, resolveTimeWindow, timeWindowMatchesPreset } from '../chunk-G2QFRTJ2.js';
7
- export { ToastProvider, Toaster, useToast } from '../chunk-NPZY6YYL.js';
5
+ export { DensitySwitcher, ThemeSwitcher, applyDensity, applyStoredPreferences, applyTheme, useDensityPreference, useThemePreference } from '../chunk-2HQR4U4D.js';
6
+ export { DEFAULT_TIME_WINDOW_LABELS, TIME_WINDOW_SPANS, TimeWindowPicker, describeTimeWindow, isTimeWindowSet, parseTimeWindowDuration, resolveTimeWindow, timeWindowMatchesPreset } from '../chunk-WOYYD2YR.js';
8
7
  export { Timeline, TimelineItem } from '../chunk-O67VF5MS.js';
8
+ export { ToastProvider, Toaster, useToast } from '../chunk-NPZY6YYL.js';
9
9
  export { Tooltip } from '../chunk-XV6WRMBC.js';
10
- export { StatGroup } from '../chunk-QNCVHRZL.js';
10
+ export { StatCard } from '../chunk-22O7LAW2.js';
11
11
  export { Switch } from '../chunk-EV6IMYJ6.js';
12
12
  export { Table } from '../chunk-FEFTGVMF.js';
13
13
  export { TagGroup } from '../chunk-V2XMNLMS.js';
14
14
  export { TagsInput } from '../chunk-RDGD7Z7I.js';
15
15
  export { SearchTrigger } from '../chunk-Q4ZPPART.js';
16
16
  export { Section } from '../chunk-A2UXBCLO.js';
17
- export { SegmentedControl } from '../chunk-ARMRX2YV.js';
18
- export { TabPanel, Tabs, tabId } from '../chunk-YMWONFSI.js';
19
- export { Select } from '../chunk-5IMACPJS.js';
17
+ export { SegmentedControl } from '../chunk-6ZFVFA56.js';
18
+ export { TabPanel, Tabs, tabId } from '../chunk-QEUY3A5P.js';
19
+ export { Select } from '../chunk-OFHBK7RI.js';
20
20
  export { matchesShortcut, useShortcut } from '../chunk-F6OE5FH3.js';
21
21
  export { NavGroup, NavItem, SidebarNav } from '../chunk-3EYF6HKB.js';
22
22
  export { Skeleton } from '../chunk-W5J7R5EB.js';
23
- export { StatCard } from '../chunk-22O7LAW2.js';
23
+ export { StatGroup } from '../chunk-QNCVHRZL.js';
24
24
  export { OrgNodeDisclosure, OrgNodeLabel, OrgNodeLead } from '../chunk-IAJLHVUA.js';
25
25
  export { OrgTable, OrgTableActions, OrgTableAdd, OrgTableName } from '../chunk-H4FBTAYS.js';
26
26
  export { TreeGrid } from '../chunk-5SDBMKUO.js';
@@ -30,10 +30,10 @@ export { PricingCard } from '../chunk-KLJCCMF3.js';
30
30
  export { Tag } from '../chunk-S2XHHEW4.js';
31
31
  export { StatusDot } from '../chunk-PZSWF74H.js';
32
32
  export { Prose } from '../chunk-JCSA3XVH.js';
33
- export { List, ListItem } from '../chunk-HZ5XZNPS.js';
34
33
  export { Link } from '../chunk-2ZQMA2WB.js';
34
+ export { List, ListItem } from '../chunk-HZ5XZNPS.js';
35
35
  export { ListInput } from '../chunk-EN6K2IFA.js';
36
- export { Meter, meterTone } from '../chunk-LGCPQIOZ.js';
36
+ export { Meter, meterTone, progressTone } from '../chunk-YODNNSZL.js';
37
37
  export { NewItemsNotice } from '../chunk-YLYOWZ4V.js';
38
38
  export { useFullscreen } from '../chunk-XDTYBF2F.js';
39
39
  export { ImageUpload } from '../chunk-5WS6L6FA.js';
@@ -45,15 +45,15 @@ export { EmptyState } from '../chunk-RA2ULG6H.js';
45
45
  export { EntityChip } from '../chunk-QYOFACSP.js';
46
46
  export { ErrorBoundary } from '../chunk-7EM5T4ME.js';
47
47
  export { Eyebrow } from '../chunk-RK4XPHVG.js';
48
- export { FILTER_CHIP_ATTRIBUTE, FilterChip, FilterChipGroup } from '../chunk-EPOOQZYA.js';
48
+ export { FILTER_CHIP_ATTRIBUTE, FilterChip, FilterChipGroup } from '../chunk-ZFATEERP.js';
49
49
  export { CommandPalette } from '../chunk-ESCO4XYW.js';
50
50
  export { Container } from '../chunk-QVE4GJAT.js';
51
- export { DATA_VIEW_TOOLBAR_LABELS, DataView, DataViewToolbar, FILTER_AXIS_LABELS, FilterAxisBar, FilterAxisChip, applyColumnFilters, applyFilters, blankFilterValue, defaultOperator, filterDefsFromColumns, filterHasValue, filterPredicate, formatFilterValue, operatorOf, tableColumns } from '../chunk-GHYY2WPF.js';
51
+ export { DATA_VIEW_TOOLBAR_LABELS, DataView, DataViewToolbar, FILTER_AXIS_LABELS, FilterAxisBar, FilterAxisChip, applyColumnFilters, applyFilters, blankFilterValue, defaultOperator, filterDefsFromColumns, filterHasValue, filterPredicate, formatFilterValue, operatorOf, tableColumns } from '../chunk-34VGEDVV.js';
52
52
  export { Toolbar, ToolbarOverflow, ToolbarWide } from '../chunk-5EKIWVOR.js';
53
53
  export { PageHeader } from '../chunk-HOXGBLEY.js';
54
54
  export { RelativeTime, currentNow, formatElapsed, formatExact, formatRelative, formatUntil, toISO, toInstant, useNow } from '../chunk-3CZ7XAVY.js';
55
55
  export { Kbd, isApplePlatform, keyGlyph } from '../chunk-SFZOKW2G.js';
56
- export { ALL_ITEMS, CopyableCell, DATA_TABLE_LABELS, DataTable, RowActionsMenu } from '../chunk-EHMQQHYR.js';
56
+ export { ALL_ITEMS, CopyableCell, DATA_TABLE_LABELS, DataTable, RowActionsMenu } from '../chunk-WQX73TWF.js';
57
57
  export { Menu } from '../chunk-FBZAKNSX.js';
58
58
  export { EMPTY_VALUE, EmptyValue } from '../chunk-EUCC37WY.js';
59
59
  export { ConfirmModal, Modal } from '../chunk-2EOKFKHX.js';
@@ -64,13 +64,13 @@ export { CalendarGrid, compareDays, daysInMonth, sameDay, shiftDay, shiftMonth,
64
64
  export { Callout } from '../chunk-3ZP55QZE.js';
65
65
  export { CANVAS_COMPOSE_CONTEXT, CANVAS_FIT_MAX_ZOOM, CANVAS_FIT_PADDING, CANVAS_FOCUS_CONTEXT, CANVAS_MAX_ZOOM, CANVAS_MIN_ZOOM, CANVAS_PAN_MARGIN, CANVAS_PAN_STEP, CANVAS_REVEAL_PADDING, CANVAS_TAP_SLOP, CANVAS_WHEEL_LINE_PX, CANVAS_WHEEL_ZOOM_PER_PIXEL, CANVAS_ZOOM_CEILING, CANVAS_ZOOM_LIMITS, CANVAS_ZOOM_STEP, Canvas, IDENTITY_VIEW, anchorView, beyondSlop, clampPan, clampZoom, fitView, panBy, pinchView, regionView, revealView, screenRect, toScreen, toWorld, wheelPixels, wheelZoomFactor, zoomAt, zoomLimits } from '../chunk-CMEE37QJ.js';
66
66
  import '../chunk-53DVJCVW.js';
67
- export { Card } from '../chunk-T7FKOJKW.js';
67
+ export { Card } from '../chunk-NDCATSW7.js';
68
68
  export { useCardHeaderSlot } from '../chunk-AV2DXAEL.js';
69
69
  export { ActivityStrip, BarList, DATA_COLORS, DATA_COLOR_OTHER, Legend, Sparkline, StackedBar, TimeSeries, dataColor } from '../chunk-F4PJZ4ED.js';
70
70
  export { Checkbox } from '../chunk-2PRH365R.js';
71
- export { CodeBlock } from '../chunk-HTDFCRJZ.js';
72
- export { CopyButton, Copyable } from '../chunk-D3OADIM6.js';
73
- export { useClipboard } from '../chunk-V663QU4R.js';
71
+ export { CodeBlock } from '../chunk-D35VTV2Z.js';
72
+ export { CopyButton, Copyable } from '../chunk-3QRYCPXQ.js';
73
+ export { useClipboard, writeClipboard } from '../chunk-5VNUYO76.js';
74
74
  export { Combobox } from '../chunk-UOGSZKLT.js';
75
75
  export { TYPE_AHEAD_WINDOW, useListbox, useOptionKeys } from '../chunk-GTOUGQQK.js';
76
76
  export { FormField, FormRow, FormSection, Input, InputAffix, Label, ReadOnlyField, Textarea } from '../chunk-O6232G37.js';
package/dist/index.js CHANGED
@@ -2,25 +2,25 @@ import './chunk-ZCR6YGQ4.js';
2
2
  export { TreeCanvas } from './chunk-7HPRF5XN.js';
3
3
  import './chunk-IJ7QXNIJ.js';
4
4
  export { Text } from './chunk-23DHIMJA.js';
5
- export { DensitySwitcher, ThemeSwitcher, applyDensity, applyStoredPreferences, applyTheme, useDensityPreference, useThemePreference } from './chunk-GUIF6Q6N.js';
6
- export { DEFAULT_TIME_WINDOW_LABELS, TIME_WINDOW_SPANS, TimeWindowPicker, describeTimeWindow, isTimeWindowSet, parseTimeWindowDuration, resolveTimeWindow, timeWindowMatchesPreset } from './chunk-G2QFRTJ2.js';
7
- export { ToastProvider, Toaster, useToast } from './chunk-NPZY6YYL.js';
5
+ export { DensitySwitcher, ThemeSwitcher, applyDensity, applyStoredPreferences, applyTheme, useDensityPreference, useThemePreference } from './chunk-2HQR4U4D.js';
6
+ export { DEFAULT_TIME_WINDOW_LABELS, TIME_WINDOW_SPANS, TimeWindowPicker, describeTimeWindow, isTimeWindowSet, parseTimeWindowDuration, resolveTimeWindow, timeWindowMatchesPreset } from './chunk-WOYYD2YR.js';
8
7
  export { Timeline, TimelineItem } from './chunk-O67VF5MS.js';
8
+ export { ToastProvider, Toaster, useToast } from './chunk-NPZY6YYL.js';
9
9
  export { Tooltip } from './chunk-XV6WRMBC.js';
10
- export { StatGroup } from './chunk-QNCVHRZL.js';
10
+ export { StatCard } from './chunk-22O7LAW2.js';
11
11
  export { Switch } from './chunk-EV6IMYJ6.js';
12
12
  export { Table } from './chunk-FEFTGVMF.js';
13
13
  export { TagGroup } from './chunk-V2XMNLMS.js';
14
14
  export { TagsInput } from './chunk-RDGD7Z7I.js';
15
15
  export { SearchTrigger } from './chunk-Q4ZPPART.js';
16
16
  export { Section } from './chunk-A2UXBCLO.js';
17
- export { SegmentedControl } from './chunk-ARMRX2YV.js';
18
- export { TabPanel, Tabs, tabId } from './chunk-YMWONFSI.js';
19
- export { Select } from './chunk-5IMACPJS.js';
17
+ export { SegmentedControl } from './chunk-6ZFVFA56.js';
18
+ export { TabPanel, Tabs, tabId } from './chunk-QEUY3A5P.js';
19
+ export { Select } from './chunk-OFHBK7RI.js';
20
20
  export { matchesShortcut, useShortcut } from './chunk-F6OE5FH3.js';
21
21
  export { NavGroup, NavItem, SidebarNav } from './chunk-3EYF6HKB.js';
22
22
  export { Skeleton } from './chunk-W5J7R5EB.js';
23
- export { StatCard } from './chunk-22O7LAW2.js';
23
+ export { StatGroup } from './chunk-QNCVHRZL.js';
24
24
  export { OrgNodeDisclosure, OrgNodeLabel, OrgNodeLead } from './chunk-IAJLHVUA.js';
25
25
  export { OrgTable, OrgTableActions, OrgTableAdd, OrgTableName } from './chunk-H4FBTAYS.js';
26
26
  export { TreeGrid } from './chunk-5SDBMKUO.js';
@@ -30,10 +30,10 @@ export { PricingCard } from './chunk-KLJCCMF3.js';
30
30
  export { Tag } from './chunk-S2XHHEW4.js';
31
31
  export { StatusDot } from './chunk-PZSWF74H.js';
32
32
  export { Prose } from './chunk-JCSA3XVH.js';
33
- export { List, ListItem } from './chunk-HZ5XZNPS.js';
34
33
  export { Link } from './chunk-2ZQMA2WB.js';
34
+ export { List, ListItem } from './chunk-HZ5XZNPS.js';
35
35
  export { ListInput } from './chunk-EN6K2IFA.js';
36
- export { Meter, meterTone } from './chunk-LGCPQIOZ.js';
36
+ export { Meter, meterTone, progressTone } from './chunk-YODNNSZL.js';
37
37
  export { NewItemsNotice } from './chunk-YLYOWZ4V.js';
38
38
  export { useFullscreen } from './chunk-XDTYBF2F.js';
39
39
  export { ImageUpload } from './chunk-5WS6L6FA.js';
@@ -45,15 +45,15 @@ export { EmptyState } from './chunk-RA2ULG6H.js';
45
45
  export { EntityChip } from './chunk-QYOFACSP.js';
46
46
  export { ErrorBoundary } from './chunk-7EM5T4ME.js';
47
47
  export { Eyebrow } from './chunk-RK4XPHVG.js';
48
- export { FILTER_CHIP_ATTRIBUTE, FilterChip, FilterChipGroup } from './chunk-EPOOQZYA.js';
48
+ export { FILTER_CHIP_ATTRIBUTE, FilterChip, FilterChipGroup } from './chunk-ZFATEERP.js';
49
49
  export { CommandPalette } from './chunk-ESCO4XYW.js';
50
50
  export { Container } from './chunk-QVE4GJAT.js';
51
- export { DATA_VIEW_TOOLBAR_LABELS, DataView, DataViewToolbar, FILTER_AXIS_LABELS, FilterAxisBar, FilterAxisChip, applyColumnFilters, applyFilters, blankFilterValue, defaultOperator, filterDefsFromColumns, filterHasValue, filterPredicate, formatFilterValue, operatorOf, tableColumns } from './chunk-GHYY2WPF.js';
51
+ export { DATA_VIEW_TOOLBAR_LABELS, DataView, DataViewToolbar, FILTER_AXIS_LABELS, FilterAxisBar, FilterAxisChip, applyColumnFilters, applyFilters, blankFilterValue, defaultOperator, filterDefsFromColumns, filterHasValue, filterPredicate, formatFilterValue, operatorOf, tableColumns } from './chunk-34VGEDVV.js';
52
52
  export { Toolbar, ToolbarOverflow, ToolbarWide } from './chunk-5EKIWVOR.js';
53
53
  export { PageHeader } from './chunk-HOXGBLEY.js';
54
54
  export { RelativeTime, currentNow, formatElapsed, formatExact, formatRelative, formatUntil, toISO, toInstant, useNow } from './chunk-3CZ7XAVY.js';
55
55
  export { Kbd, isApplePlatform, keyGlyph } from './chunk-SFZOKW2G.js';
56
- export { ALL_ITEMS, CopyableCell, DATA_TABLE_LABELS, DataTable, RowActionsMenu } from './chunk-EHMQQHYR.js';
56
+ export { ALL_ITEMS, CopyableCell, DATA_TABLE_LABELS, DataTable, RowActionsMenu } from './chunk-WQX73TWF.js';
57
57
  export { Menu } from './chunk-FBZAKNSX.js';
58
58
  export { EMPTY_VALUE, EmptyValue } from './chunk-EUCC37WY.js';
59
59
  export { ConfirmModal, Modal } from './chunk-2EOKFKHX.js';
@@ -64,13 +64,13 @@ export { CalendarGrid, compareDays, daysInMonth, sameDay, shiftDay, shiftMonth,
64
64
  export { Callout } from './chunk-3ZP55QZE.js';
65
65
  export { CANVAS_COMPOSE_CONTEXT, CANVAS_FIT_MAX_ZOOM, CANVAS_FIT_PADDING, CANVAS_FOCUS_CONTEXT, CANVAS_MAX_ZOOM, CANVAS_MIN_ZOOM, CANVAS_PAN_MARGIN, CANVAS_PAN_STEP, CANVAS_REVEAL_PADDING, CANVAS_TAP_SLOP, CANVAS_WHEEL_LINE_PX, CANVAS_WHEEL_ZOOM_PER_PIXEL, CANVAS_ZOOM_CEILING, CANVAS_ZOOM_LIMITS, CANVAS_ZOOM_STEP, Canvas, IDENTITY_VIEW, anchorView, beyondSlop, clampPan, clampZoom, fitView, panBy, pinchView, regionView, revealView, screenRect, toScreen, toWorld, wheelPixels, wheelZoomFactor, zoomAt, zoomLimits } from './chunk-CMEE37QJ.js';
66
66
  import './chunk-53DVJCVW.js';
67
- export { Card } from './chunk-T7FKOJKW.js';
67
+ export { Card } from './chunk-NDCATSW7.js';
68
68
  export { useCardHeaderSlot } from './chunk-AV2DXAEL.js';
69
69
  export { ActivityStrip, BarList, DATA_COLORS, DATA_COLOR_OTHER, Legend, Sparkline, StackedBar, TimeSeries, dataColor } from './chunk-F4PJZ4ED.js';
70
70
  export { Checkbox } from './chunk-2PRH365R.js';
71
- export { CodeBlock } from './chunk-HTDFCRJZ.js';
72
- export { CopyButton, Copyable } from './chunk-D3OADIM6.js';
73
- export { useClipboard } from './chunk-V663QU4R.js';
71
+ export { CodeBlock } from './chunk-D35VTV2Z.js';
72
+ export { CopyButton, Copyable } from './chunk-3QRYCPXQ.js';
73
+ export { useClipboard, writeClipboard } from './chunk-5VNUYO76.js';
74
74
  export { Combobox } from './chunk-UOGSZKLT.js';
75
75
  export { TYPE_AHEAD_WINDOW, useListbox, useOptionKeys } from './chunk-GTOUGQQK.js';
76
76
  export { FormField, FormRow, FormSection, Input, InputAffix, Label, ReadOnlyField, Textarea } from './chunk-O6232G37.js';
package/dist/styles.css CHANGED
@@ -2061,7 +2061,7 @@
2061
2061
  }
2062
2062
 
2063
2063
 
2064
- /* Card-AHX3Q2JD.css */
2064
+ /* Card-RLR254LD.css */
2065
2065
  /*
2066
2066
  * Card, THE surface. Everything on a screen is a card, a row inside one, or a
2067
2067
  * control.
@@ -2458,6 +2458,28 @@
2458
2458
  color: var(--color-text-primary);
2459
2459
  }
2460
2460
 
2461
+ /*
2462
+ * A TITLE THAT ENDS RATHER THAN STOPS, where a caller has asked for it.
2463
+ *
2464
+ * The name block clips, which is what keeps the head one line, so a title
2465
+ * wider than the row is cut at the header's edge — mid-word, with nothing to
2466
+ * say a word was lost. `text-overflow` is the rule that says it, and it
2467
+ * applies to a BLOCK container only: on the flex title above it does nothing
2468
+ * at all, and the text it would act on is an anonymous flex item that no
2469
+ * selector here can reach. So the modifier makes the title a block. Its
2470
+ * children are then one line of inline content rather than centred flex items
2471
+ * with a gap between them, which is the whole of what a caller opts into, and
2472
+ * why this is a modifier rather than the base rule.
2473
+ *
2474
+ * `white-space: nowrap` is already the title's own, and `min-width: 0` is what
2475
+ * lets the block shrink below its content inside the name block; both stand.
2476
+ */
2477
+ .crewlet-card__title--truncate {
2478
+ display: block;
2479
+ overflow: hidden;
2480
+ text-overflow: ellipsis;
2481
+ }
2482
+
2461
2483
  /*
2462
2484
  * The subtitle gives up its tail and the title does not: a title is the
2463
2485
  * record's identity and has to be read in full, while a subtitle is context.
@@ -2886,7 +2908,7 @@
2886
2908
  }
2887
2909
 
2888
2910
 
2889
- /* CodeBlock-U2W6NNVC.css */
2911
+ /* CodeBlock-GYNJ2HI6.css */
2890
2912
  /*
2891
2913
  * CodeBlock, a monospace command, config or record surface. One step off the
2892
2914
  * page, with an optional header carrying a filename and the copy control.
@@ -2955,6 +2977,42 @@
2955
2977
  white-space: pre-wrap;
2956
2978
  overflow-wrap: anywhere;
2957
2979
  tab-size: 2;
2980
+ /*
2981
+ * THE CEILING IS A CASCADING ONE, read here and declared nowhere, so the
2982
+ * fallback IS the default: with nothing set the block is unbounded, as it
2983
+ * has always been. `maxHeight` writes the property inline on the block, and
2984
+ * an application that wants one ceiling for every block it renders writes it
2985
+ * once on an ancestor instead — because a ceiling every call site has to
2986
+ * remember is a ceiling somebody forgets, and the right height is a fact
2987
+ * about the SURFACE the block sits on rather than about the component.
2988
+ *
2989
+ * Declared with a fallback rather than seeded on `.crewlet-codeblock`: a
2990
+ * name a component declares on itself stops inheriting, so seeding it would
2991
+ * be the one shape in which an ancestor's value can never arrive.
2992
+ *
2993
+ * ONE DECLARATION, in the rule below. `.crewlet-codeblock--bounded` is still
2994
+ * emitted as the marker that this block set a ceiling of its own — the hook
2995
+ * an application stylesheet and a reader of the DOM key on — but it draws
2996
+ * nothing, because a second rule restating this height is how the two come
2997
+ * to disagree.
2998
+ */
2999
+ }
3000
+
3001
+ /*
3002
+ * The ceiling, at the specificity the rule it replaces already had.
3003
+ *
3004
+ * `.crewlet-codeblock .crewlet-codeblock__pre` rather than
3005
+ * `.crewlet-codeblock__pre`, and the extra class earns its place: the rule
3006
+ * that used to set this was `.crewlet-codeblock--bounded .crewlet-codeblock__pre`
3007
+ * at (0,2,0), and an application overriding it wrote `.crewlet-codeblock__pre
3008
+ * { max-height: … }` at (0,1,0) and expected to LOSE. Declaring it on the
3009
+ * single class drops this to (0,1,0), which turns every one of those
3010
+ * overrides into a tie decided by sheet order — so a consumer who wrote a
3011
+ * losing rule on purpose silently starts winning. Same two-class weight,
3012
+ * same outcome for anybody who already had an opinion.
3013
+ */
3014
+ .crewlet-codeblock .crewlet-codeblock__pre {
3015
+ max-height: var(--crewlet-codeblock-max-height, none);
2958
3016
  }
2959
3017
 
2960
3018
  /*
@@ -2967,21 +3025,20 @@
2967
3025
  }
2968
3026
 
2969
3027
  /*
2970
- * Bounded, with its own scroll. Without a ceiling a long record pushes
2971
- * everything under it off the screen, which on a detail page is every other
2972
- * fact about the thing being read.
2973
- */
2974
- .crewlet-codeblock--bounded .crewlet-codeblock__pre {
2975
- max-height: var(--crewlet-codeblock-max-height);
2976
- }
2977
-
2978
- /*
2979
- * A BLOCK THAT OWNS SELECT-ALL. Select-all is a document verb, so on a screen
2980
- * that is mostly one record it took the nav, the stat row and every card with
2981
- * it. While this block has focus the verb means "this record", which is the
2982
- * only thing anybody was reaching for, and the ring is what says so: a
2983
- * keyboard verb that changes meaning on focus, with no visible focus state, is
2984
- * a secret.
3028
+ * A BLOCK A READER CAN REACH. Two things put the block in the tab order and
3029
+ * the role follows both: `selectable`, and `focusWhenScrollable` on a box that
3030
+ * turned out to scroll.
3031
+ *
3032
+ * On the first, select-all is a document verb, so on a screen that is mostly
3033
+ * one record it took the nav, the stat row and every card with it. While this
3034
+ * block has focus the verb means "this record", which is the only thing
3035
+ * anybody was reaching for, and the ring is what says so: a keyboard verb that
3036
+ * changes meaning on focus, with no visible focus state, is a secret. On the
3037
+ * second the block keeps no keys at all; the ring is there because a scroll
3038
+ * container a reader arrows through has to say where they are.
3039
+ *
3040
+ * The text cursor is right for both, and it is what the caret-shape of a
3041
+ * `pre` full of selectable text should always have been.
2985
3042
  */
2986
3043
  .crewlet-codeblock__pre[role='region'] {
2987
3044
  cursor: text;
@@ -1,5 +1,5 @@
1
1
  export { cx } from './cx.js';
2
- export { useClipboard } from './useClipboard.js';
2
+ export { useClipboard, writeClipboard } from './useClipboard.js';
3
3
  export type { Clipboard, ClipboardOptions, ClipboardState } from './useClipboard.js';
4
4
  export type { PhaseTone, Tone } from './tone.js';
5
5
  export { HeadingLevelProvider, headingTag, nextHeadingLevel, useHeadingLevel } from './headingLevel.js';
@@ -1,4 +1,4 @@
1
1
  import '../chunk-IJ7QXNIJ.js';
2
- export { useClipboard } from '../chunk-V663QU4R.js';
2
+ export { useClipboard, writeClipboard } from '../chunk-5VNUYO76.js';
3
3
  export { HeadingLevelProvider, headingTag, nextHeadingLevel, useHeadingLevel } from '../chunk-PQADV6P6.js';
4
4
  export { cx } from '../chunk-ODEQTPFM.js';
@@ -1,7 +1,35 @@
1
1
  export type ClipboardState = 'idle' | 'copied' | 'failed';
2
2
  export interface ClipboardOptions {
3
- /** How long the copied or failed answer stands before the control settles back. */
4
- resetMs?: number;
3
+ /** How long the copied answer stands before the control settles back. */
4
+ resetMs?: number | undefined;
5
+ /**
6
+ * How long a REFUSAL stands, which is not the same question.
7
+ *
8
+ * Left unset it is `resetMs`, which is what this hook has always done and
9
+ * what every current call site still gets. `null` holds the failed state
10
+ * until the next copy; a number gives it a clock of its own.
11
+ *
12
+ * WHY IT IS A SEPARATE CLOCK. A success confirms something the reader
13
+ * already knows they asked for, so it can go as soon as it has been seen.
14
+ * A refusal is news — usually that the origin is not secure and that NO
15
+ * copy on this page will ever work — and a control that has quietly gone
16
+ * back to offering its action is indistinguishable from one nobody ever
17
+ * pressed, so the reader presses it again and learns nothing a second time.
18
+ * [Toaster] already settled this question for this design system and its
19
+ * `DURATIONS` table is the precedent: `info` and `success` go after 4s,
20
+ * `warning` and `danger` are sticky, because news that removes itself is
21
+ * news somebody misses.
22
+ *
23
+ * `null` rather than Toaster's `0` for sticky, because `resetMs` has
24
+ * shipped with `0` meaning "settle on the next tick" and a second option in
25
+ * the same object reading the same number as its opposite is a trap. `null`
26
+ * collides with nothing.
27
+ *
28
+ * The recommendation is `null`. It is not the DEFAULT only because moving
29
+ * the default is a behaviour change for every call site that never asked
30
+ * for one.
31
+ */
32
+ failedResetMs?: number | null | undefined;
5
33
  }
6
34
  export interface Clipboard {
7
35
  state: ClipboardState;
@@ -10,7 +38,7 @@ export interface Clipboard {
10
38
  /**
11
39
  * Putting text on the clipboard, and saying whether it arrived.
12
40
  *
13
- * TWO THINGS ARE LOAD BEARING, and both were wrong before this existed.
41
+ * THREE THINGS ARE LOAD BEARING, and all three were wrong before this existed.
14
42
  *
15
43
  * 1. THE CLIPBOARD API IS NOT ALWAYS THERE. It is gated on a secure context,
16
44
  * so `navigator.clipboard` is simply undefined on the plain http origin
@@ -22,9 +50,33 @@ export interface Clipboard {
22
50
  * 2. A COPY WITH NO FEEDBACK IS A DEAD BUTTON. The clipboard is invisible;
23
51
  * the only way a reader learns it worked is if the control says so, which
24
52
  * is what `state` is for.
53
+ * 3. THE WRITE OUTLIVES THE SCREEN. `writeText` is held for as long as the
54
+ * browser holds its permission prompt, which is until the reader answers
55
+ * it — and they may navigate instead. The unmount cleanup clears whatever
56
+ * timer exists AT THAT MOMENT, and for a write still in flight that is
57
+ * none: the settle then ran after the cleanup and armed a fresh timer with
58
+ * nothing left alive to clear it, so the hook leaked a timer per abandoned
59
+ * copy and wrote state to a component that was gone. `live` is what the
60
+ * settle is checked against, and it is checked AFTER the await rather than
61
+ * before, because the await is the whole of the gap.
25
62
  *
26
63
  * The text may be a THUNK, resolved on the press. On a live screen the thing
27
64
  * worth copying is assembled from everything on it, so a string prop means
28
65
  * building it again on every push for a control nobody has touched.
29
66
  */
30
- export declare function useClipboard({ resetMs }?: ClipboardOptions): Clipboard;
67
+ export declare function useClipboard({ resetMs, failedResetMs }?: ClipboardOptions): Clipboard;
68
+ /**
69
+ * The write itself, with no state machine around it.
70
+ *
71
+ * Exported because the two halves are independently useful and only one of
72
+ * them is hard: a caller that already owns its feedback — a toast, a form's
73
+ * own status line, a control whose label is driven by something else —
74
+ * wants the secure-context detection, the fallback and the honest boolean,
75
+ * and reimplementing those to get them means reimplementing
76
+ * `execCommandCopy` too, which is the half with the focus restoration in it.
77
+ *
78
+ * Returns whether the text reached the clipboard. It never throws: a refusal
79
+ * is `false`, because a caller that has to tell a refusal from a success is
80
+ * exactly the caller that must not receive one as an exception.
81
+ */
82
+ export declare function writeClipboard(text: string): Promise<boolean>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crewlethq/ui",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Crewlet shared React components built on @crewlethq/tokens and @crewlethq/icons.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -42,8 +42,8 @@
42
42
  "clean": "rm -rf dist src/generated"
43
43
  },
44
44
  "dependencies": {
45
- "@crewlethq/icons": "0.3.0",
46
- "@crewlethq/tokens": "0.3.0"
45
+ "@crewlethq/icons": "0.4.0",
46
+ "@crewlethq/tokens": "0.4.0"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "react": ">=18",
@@ -1,96 +0,0 @@
1
- import { useRoving, tabStop, tabId } from './chunk-YMWONFSI.js';
2
- import { Count } from './chunk-BHHIIK3M.js';
3
- import { cx } from './chunk-ODEQTPFM.js';
4
- import './Tabs-VLICJFVB.css';
5
- import './SegmentedControl-X3BI3XU4.css';
6
- import { jsx, jsxs } from 'react/jsx-runtime';
7
-
8
- function SegmentedControl({
9
- label,
10
- options,
11
- value,
12
- onValueChange,
13
- size = "md",
14
- className = "",
15
- semantics,
16
- panelId
17
- }) {
18
- const radio = semantics === "radio";
19
- const cards = options.some((option) => option.description !== void 0);
20
- const { buttons, onKeyDown } = useRoving(
21
- options.length,
22
- radio ? (index) => onValueChange(options[index].value) : null
23
- );
24
- const selected = tabStop(
25
- options,
26
- Math.max(
27
- 0,
28
- options.findIndex((option) => option.value === value)
29
- )
30
- );
31
- return /* @__PURE__ */ jsx(
32
- "div",
33
- {
34
- className: cx(
35
- "crewlet-tabs",
36
- /*
37
- * THE PILL CHROME IS NOT WORN IN CARDS MODE. A card row is not a chip
38
- * in a tinted container: the pill's own rules set the container's
39
- * background, border, padding and `width: fit-content`, and each
40
- * option's padding, radius and active chip. Left on, every one of
41
- * them still applied (the two stylesheets are single-class rules and
42
- * Tabs.css is bundled last), so the cards were drawn inside a pill
43
- * bar sized to its content, which is what the mode exists to avoid.
44
- */
45
- !cards && "crewlet-tabs--pill",
46
- `crewlet-tabs--${size}`,
47
- "crewlet-segmented",
48
- cards && "crewlet-segmented--cards",
49
- className
50
- ),
51
- role: radio ? "radiogroup" : "tablist",
52
- "aria-label": label,
53
- children: options.map((option, index) => {
54
- const chosen = option.value === value;
55
- const named = option.srLabel ?? (option.label ? void 0 : option.title);
56
- return /* @__PURE__ */ jsxs(
57
- "button",
58
- {
59
- ref: (el) => {
60
- buttons.current[index] = el;
61
- },
62
- type: "button",
63
- role: radio ? "radio" : "tab",
64
- id: radio || !panelId ? void 0 : tabId(panelId, option.value),
65
- "aria-checked": radio ? chosen : void 0,
66
- "aria-selected": radio ? void 0 : chosen,
67
- "aria-controls": radio ? void 0 : panelId,
68
- "aria-label": named,
69
- tabIndex: index === selected ? 0 : -1,
70
- title: option.title,
71
- disabled: option.disabled,
72
- className: cx(
73
- "crewlet-tabs__tab",
74
- "crewlet-segmented__option",
75
- chosen && "is-active",
76
- option.disabled && "is-disabled"
77
- ),
78
- onClick: () => onValueChange(option.value),
79
- onKeyDown: (event) => onKeyDown(event, radio),
80
- children: [
81
- option.icon ? /* @__PURE__ */ jsx("span", { className: "crewlet-tabs__icon", children: option.icon }) : null,
82
- option.label || option.description ? /* @__PURE__ */ jsxs("span", { className: "crewlet-segmented__text", children: [
83
- /* @__PURE__ */ jsx("span", { className: "crewlet-tabs__label", children: option.label }),
84
- option.description ? /* @__PURE__ */ jsx("span", { className: "crewlet-segmented__description", children: option.description }) : null
85
- ] }) : null,
86
- option.count != null ? /* @__PURE__ */ jsx(Count, { value: option.count }) : null
87
- ]
88
- },
89
- option.value
90
- );
91
- })
92
- }
93
- );
94
- }
95
-
96
- export { SegmentedControl };