@rebasepro/ui 0.24.0 → 0.24.1-canary.gcb918fc
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/components/Alert.d.ts +6 -0
- package/dist/components/Alert.es.js +82 -0
- package/dist/components/Alert.es.js.map +1 -0
- package/dist/components/Autocomplete.es.js +53 -0
- package/dist/components/Autocomplete.es.js.map +1 -0
- package/dist/components/Avatar.d.ts +3 -1
- package/dist/components/Avatar.es.js +37 -0
- package/dist/components/Avatar.es.js.map +1 -0
- package/dist/components/Badge.es.js +27 -0
- package/dist/components/Badge.es.js.map +1 -0
- package/dist/components/BooleanSwitch.es.js +75 -0
- package/dist/components/BooleanSwitch.es.js.map +1 -0
- package/dist/components/BooleanSwitchWithLabel.es.js +55 -0
- package/dist/components/BooleanSwitchWithLabel.es.js.map +1 -0
- package/dist/components/Button.es.js +58 -0
- package/dist/components/Button.es.js.map +1 -0
- package/dist/components/Card.es.js +26 -0
- package/dist/components/Card.es.js.map +1 -0
- package/dist/components/CenteredView.es.js +23 -0
- package/dist/components/CenteredView.es.js.map +1 -0
- package/dist/components/Checkbox.es.js +62 -0
- package/dist/components/Checkbox.es.js.map +1 -0
- package/dist/components/Chip.es.js +72 -0
- package/dist/components/Chip.es.js.map +1 -0
- package/dist/components/CircularProgress.es.js +28 -0
- package/dist/components/CircularProgress.es.js.map +1 -0
- package/dist/components/CircularProgressCenter.es.js +30 -0
- package/dist/components/CircularProgressCenter.es.js.map +1 -0
- package/dist/components/Collapse.es.js +57 -0
- package/dist/components/Collapse.es.js.map +1 -0
- package/dist/components/ColorPicker.es.js +89 -0
- package/dist/components/ColorPicker.es.js.map +1 -0
- package/dist/components/Container.es.js +31 -0
- package/dist/components/Container.es.js.map +1 -0
- package/dist/components/DateTimeField.d.ts +11 -1
- package/dist/components/DateTimeField.es.js +253 -0
- package/dist/components/DateTimeField.es.js.map +1 -0
- package/dist/components/DebouncedTextField.es.js +93 -0
- package/dist/components/DebouncedTextField.es.js.map +1 -0
- package/dist/components/Dialog.es.js +98 -0
- package/dist/components/Dialog.es.js.map +1 -0
- package/dist/components/DialogActions.es.js +15 -0
- package/dist/components/DialogActions.es.js.map +1 -0
- package/dist/components/DialogContent.es.js +18 -0
- package/dist/components/DialogContent.es.js.map +1 -0
- package/dist/components/DialogTitle.es.js +26 -0
- package/dist/components/DialogTitle.es.js.map +1 -0
- package/dist/components/ErrorBoundary.es.js +158 -0
- package/dist/components/ErrorBoundary.es.js.map +1 -0
- package/dist/components/ExpandablePanel.es.js +91 -0
- package/dist/components/ExpandablePanel.es.js.map +1 -0
- package/dist/components/FileUpload.es.js +58 -0
- package/dist/components/FileUpload.es.js.map +1 -0
- package/dist/components/FilterChip.es.js +31 -0
- package/dist/components/FilterChip.es.js.map +1 -0
- package/dist/components/IconButton.es.js +52 -0
- package/dist/components/IconButton.es.js.map +1 -0
- package/dist/components/InfoLabel.es.js +18 -0
- package/dist/components/InfoLabel.es.js.map +1 -0
- package/dist/components/InputLabel.es.js +27 -0
- package/dist/components/InputLabel.es.js.map +1 -0
- package/dist/components/Label.es.js +18 -0
- package/dist/components/Label.es.js.map +1 -0
- package/dist/components/LoadingButton.es.js +21 -0
- package/dist/components/LoadingButton.es.js.map +1 -0
- package/dist/components/Markdown.es.js +88 -0
- package/dist/components/Markdown.es.js.map +1 -0
- package/dist/components/Menu.es.js +46 -0
- package/dist/components/Menu.es.js.map +1 -0
- package/dist/components/Menubar.es.js +142 -0
- package/dist/components/Menubar.es.js.map +1 -0
- package/dist/components/MultiSelect.d.ts +1 -7
- package/dist/components/MultiSelect.es.js +271 -0
- package/dist/components/MultiSelect.es.js.map +1 -0
- package/dist/components/Paper.es.js +16 -0
- package/dist/components/Paper.es.js.map +1 -0
- package/dist/components/Popover.es.js +113 -0
- package/dist/components/Popover.es.js.map +1 -0
- package/dist/components/RadioGroup.es.js +30 -0
- package/dist/components/RadioGroup.es.js.map +1 -0
- package/dist/components/ResizablePanels.d.ts +3 -1
- package/dist/components/ResizablePanels.es.js +137 -0
- package/dist/components/ResizablePanels.es.js.map +1 -0
- package/dist/components/SearchBar.es.js +82 -0
- package/dist/components/SearchBar.es.js.map +1 -0
- package/dist/components/Select.d.ts +8 -1
- package/dist/components/Select.es.js +300 -0
- package/dist/components/Select.es.js.map +1 -0
- package/dist/components/Separator.es.js +20 -0
- package/dist/components/Separator.es.js.map +1 -0
- package/dist/components/Sheet.es.js +73 -0
- package/dist/components/Sheet.es.js.map +1 -0
- package/dist/components/Skeleton.es.js +33 -0
- package/dist/components/Skeleton.es.js.map +1 -0
- package/dist/components/Slider.es.js +56 -0
- package/dist/components/Slider.es.js.map +1 -0
- package/dist/components/Table.d.ts +18 -3
- package/dist/components/Table.es.js +69 -0
- package/dist/components/Table.es.js.map +1 -0
- package/dist/components/Tabs.es.js +101 -0
- package/dist/components/Tabs.es.js.map +1 -0
- package/dist/components/TextField.d.ts +0 -8
- package/dist/components/TextField.es.js +111 -0
- package/dist/components/TextField.es.js.map +1 -0
- package/dist/components/TextareaAutosize.es.js +187 -0
- package/dist/components/TextareaAutosize.es.js.map +1 -0
- package/dist/components/ToggleButtonGroup.d.ts +6 -1
- package/dist/components/ToggleButtonGroup.es.js +35 -0
- package/dist/components/ToggleButtonGroup.es.js.map +1 -0
- package/dist/components/Tooltip.d.ts +24 -0
- package/dist/components/Tooltip.es.js +165 -0
- package/dist/components/Tooltip.es.js.map +1 -0
- package/dist/components/Typography.es.js +85 -0
- package/dist/components/Typography.es.js.map +1 -0
- package/dist/components/VirtualTable/VirtualTable.es.js +516 -0
- package/dist/components/VirtualTable/VirtualTable.es.js.map +1 -0
- package/dist/components/VirtualTable/VirtualTableCell.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTableCell.es.js +40 -0
- package/dist/components/VirtualTable/VirtualTableCell.es.js.map +1 -0
- package/dist/components/VirtualTable/VirtualTableHeader.es.js +209 -0
- package/dist/components/VirtualTable/VirtualTableHeader.es.js.map +1 -0
- package/dist/components/VirtualTable/VirtualTableHeaderRow.es.js +166 -0
- package/dist/components/VirtualTable/VirtualTableHeaderRow.es.js.map +1 -0
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +13 -2
- package/dist/components/VirtualTable/VirtualTableRow.d.ts +6 -7
- package/dist/components/VirtualTable/VirtualTableRow.es.js +41 -0
- package/dist/components/VirtualTable/VirtualTableRow.es.js.map +1 -0
- package/dist/components/VirtualTable/fields/VirtualTableDateField.d.ts +2 -1
- package/dist/components/VirtualTable/fields/VirtualTableDateField.es.js +71 -0
- package/dist/components/VirtualTable/fields/VirtualTableDateField.es.js.map +1 -0
- package/dist/components/VirtualTable/fields/VirtualTableInput.es.js +73 -0
- package/dist/components/VirtualTable/fields/VirtualTableInput.es.js.map +1 -0
- package/dist/components/VirtualTable/fields/VirtualTableNumberInput.es.js +47 -0
- package/dist/components/VirtualTable/fields/VirtualTableNumberInput.es.js.map +1 -0
- package/dist/components/VirtualTable/fields/VirtualTableSelect.es.js +83 -0
- package/dist/components/VirtualTable/fields/VirtualTableSelect.es.js.map +1 -0
- package/dist/components/VirtualTable/fields/VirtualTableSwitch.es.js +22 -0
- package/dist/components/VirtualTable/fields/VirtualTableSwitch.es.js.map +1 -0
- package/dist/components/VirtualTable/selection/SelectionContext.es.js +23 -0
- package/dist/components/VirtualTable/selection/SelectionContext.es.js.map +1 -0
- package/dist/components/VirtualTable/selection/SelectionStore.es.js +43 -0
- package/dist/components/VirtualTable/selection/SelectionStore.es.js.map +1 -0
- package/dist/components/VirtualTable/types.d.ts +1 -1
- package/dist/components/common/SelectInputLabel.es.js +28 -0
- package/dist/components/common/SelectInputLabel.es.js.map +1 -0
- package/dist/components/index.es.js +64 -0
- package/dist/hooks/PortalContainerContext.es.js +40 -0
- package/dist/hooks/PortalContainerContext.es.js.map +1 -0
- package/dist/hooks/UiLabelsContext.d.ts +63 -0
- package/dist/hooks/UiLabelsContext.es.js +59 -0
- package/dist/hooks/UiLabelsContext.es.js.map +1 -0
- package/dist/hooks/useDebounceCallback.es.js +15 -0
- package/dist/hooks/useDebounceCallback.es.js.map +1 -0
- package/dist/hooks/useDebounceValue.es.js +19 -0
- package/dist/hooks/useDebounceValue.es.js.map +1 -0
- package/dist/hooks/useDebouncedCallback.es.js +36 -0
- package/dist/hooks/useDebouncedCallback.es.js.map +1 -0
- package/dist/hooks/useInjectStyles.es.js +27 -0
- package/dist/hooks/useInjectStyles.es.js.map +1 -0
- package/dist/hooks/useIsDarkMode.es.js +61 -0
- package/dist/hooks/useIsDarkMode.es.js.map +1 -0
- package/dist/hooks/useModalFocus.es.js +81 -0
- package/dist/hooks/useModalFocus.es.js.map +1 -0
- package/dist/hooks/useOutsideAlerter.es.js +41 -0
- package/dist/hooks/useOutsideAlerter.es.js.map +1 -0
- package/dist/hooks/useRestoreInterruptedFocus.es.js +61 -0
- package/dist/hooks/useRestoreInterruptedFocus.es.js.map +1 -0
- package/dist/icons/GitHubIcon.es.js +23 -0
- package/dist/icons/GitHubIcon.es.js.map +1 -0
- package/dist/icons/HandleIcon.es.js +60 -0
- package/dist/icons/HandleIcon.es.js.map +1 -0
- package/dist/icons/Icon.es.js +25 -0
- package/dist/icons/Icon.es.js.map +1 -0
- package/dist/icons/LucideIconByName.d.ts +12 -9
- package/dist/icons/LucideIconByName.es.js +83 -0
- package/dist/icons/LucideIconByName.es.js.map +1 -0
- package/dist/icons/cool_icon_keys.es.js +55 -0
- package/dist/icons/cool_icon_keys.es.js.map +1 -0
- package/dist/icons/icon_keys.es.js +1941 -0
- package/dist/icons/icon_keys.es.js.map +1 -0
- package/dist/icons/index.d.ts +4 -3
- package/dist/icons/index.es.js +8 -0
- package/dist/icons/lucide_icon_map.d.ts +12 -0
- package/dist/icons/lucide_icon_map.es.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.es.js +87 -9563
- package/dist/styles.es.js +158 -0
- package/dist/styles.es.js.map +1 -0
- package/dist/util/chip_colors.es.js +290 -0
- package/dist/util/chip_colors.es.js.map +1 -0
- package/dist/util/cls.es.js +10 -0
- package/dist/util/cls.es.js.map +1 -0
- package/dist/util/debounce.es.js +22 -0
- package/dist/util/debounce.es.js.map +1 -0
- package/dist/util/hash.es.js +16 -0
- package/dist/util/hash.es.js.map +1 -0
- package/dist/util/keys.es.js +37 -0
- package/dist/util/keys.es.js.map +1 -0
- package/dist/util/lazy_chunk.es.js +96 -0
- package/dist/util/lazy_chunk.es.js.map +1 -0
- package/dist/views/CardView.d.ts +26 -2
- package/dist/views/CardView.es.js +435 -0
- package/dist/views/CardView.es.js.map +1 -0
- package/dist/views/CollectionView/CollectionCardView.es.js +179 -0
- package/dist/views/CollectionView/CollectionCardView.es.js.map +1 -0
- package/dist/views/CollectionView/CollectionKanbanView.es.js +172 -0
- package/dist/views/CollectionView/CollectionKanbanView.es.js.map +1 -0
- package/dist/views/CollectionView/CollectionListView.es.js +156 -0
- package/dist/views/CollectionView/CollectionListView.es.js.map +1 -0
- package/dist/views/CollectionView/CollectionTableView.es.js +149 -0
- package/dist/views/CollectionView/CollectionTableView.es.js.map +1 -0
- package/dist/views/CollectionView/CollectionView.es.js +197 -0
- package/dist/views/CollectionView/CollectionView.es.js.map +1 -0
- package/dist/views/CollectionView/CollectionViewToolbar.es.js +155 -0
- package/dist/views/CollectionView/CollectionViewToolbar.es.js.map +1 -0
- package/dist/views/CollectionView/DefaultCellRenderer.es.js +302 -0
- package/dist/views/CollectionView/DefaultCellRenderer.es.js.map +1 -0
- package/dist/views/CollectionView/resolveTitleProperty.es.js +56 -0
- package/dist/views/CollectionView/resolveTitleProperty.es.js.map +1 -0
- package/dist/views/CollectionView/utils.es.js +19 -0
- package/dist/views/CollectionView/utils.es.js.map +1 -0
- package/dist/views/Kanban/Board.es.js +237 -0
- package/dist/views/Kanban/Board.es.js.map +1 -0
- package/dist/views/Kanban/BoardColumn.es.js +81 -0
- package/dist/views/Kanban/BoardColumn.es.js.map +1 -0
- package/dist/views/Kanban/BoardColumnTitle.es.js +27 -0
- package/dist/views/Kanban/BoardColumnTitle.es.js.map +1 -0
- package/dist/views/Kanban/BoardSortableList.es.js +98 -0
- package/dist/views/Kanban/BoardSortableList.es.js.map +1 -0
- package/dist/views/Kanban/placement.es.js +27 -0
- package/dist/views/Kanban/placement.es.js.map +1 -0
- package/dist/views/KanbanView.es.js +11 -0
- package/dist/views/KanbanView.es.js.map +1 -0
- package/dist/views/ListView.d.ts +15 -2
- package/dist/views/ListView.es.js +245 -0
- package/dist/views/ListView.es.js.map +1 -0
- package/dist/views/useScrollParentRestoration.d.ts +8 -1
- package/dist/views/useScrollParentRestoration.es.js +75 -0
- package/dist/views/useScrollParentRestoration.es.js.map +1 -0
- package/package.json +2 -2
- package/dist/index.es.js.map +0 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
//#region src/styles.ts
|
|
2
|
+
var CONTROL_HEIGHT = {
|
|
3
|
+
smallest: 28,
|
|
4
|
+
small: 32,
|
|
5
|
+
medium: 40,
|
|
6
|
+
large: 48,
|
|
7
|
+
xl: 56,
|
|
8
|
+
"2xl": 64
|
|
9
|
+
};
|
|
10
|
+
/** Tailwind min-height class per control size. Keep in sync with CONTROL_HEIGHT. */
|
|
11
|
+
var controlHeightMixin = {
|
|
12
|
+
smallest: "min-h-[28px]",
|
|
13
|
+
small: "min-h-[32px]",
|
|
14
|
+
medium: "min-h-[40px]",
|
|
15
|
+
large: "min-h-[48px]",
|
|
16
|
+
xl: "min-h-[56px]",
|
|
17
|
+
"2xl": "min-h-[64px]"
|
|
18
|
+
};
|
|
19
|
+
/** Horizontal padding paired with each size, so gutters scale with height. */
|
|
20
|
+
var controlPaddingMixin = {
|
|
21
|
+
smallest: "px-2",
|
|
22
|
+
small: "px-2",
|
|
23
|
+
medium: "px-3",
|
|
24
|
+
large: "px-4",
|
|
25
|
+
xl: "px-6",
|
|
26
|
+
"2xl": "px-10"
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Suppress the focus ring on a surface that is focusable but is not a control —
|
|
30
|
+
* a popover panel, a menu container, a bare cell input inside a table that
|
|
31
|
+
* indicates focus by other means.
|
|
32
|
+
*
|
|
33
|
+
* Still expressed as `ring-0`, and that is why the default ring in
|
|
34
|
+
* `index.css` overrides `--tw-ring-shadow` rather than switching to
|
|
35
|
+
* `inset-ring-*`: `inset-ring` is a different variable, which this would not
|
|
36
|
+
* have silenced, and every surface that had opted out would have got a ring
|
|
37
|
+
* back.
|
|
38
|
+
*/
|
|
39
|
+
var focusedDisabled = "focus-visible:ring-0 focus-visible:ring-offset-0";
|
|
40
|
+
var focusedInvisibleMixin = "focus:bg-surface-field-hover";
|
|
41
|
+
/**
|
|
42
|
+
* The focus ring, drawn OUTSIDE the element, for a control that opts into it.
|
|
43
|
+
*
|
|
44
|
+
* The product's default ring is the `:focus-visible` rule in `index.css`, and
|
|
45
|
+
* that one is drawn *inside* the border box: an outset ring is paint beyond the
|
|
46
|
+
* box, and any ancestor that clips — a scroller, a truncating cell, a
|
|
47
|
+
* max-height collapse — cuts it. This one is still outset because its only
|
|
48
|
+
* caller is a whole field row sitting inside `p-4`/`p-6` of card padding, where
|
|
49
|
+
* there is room around it and nothing clipping within 16px. Reach for it only
|
|
50
|
+
* where that is true; anywhere else, let the default apply.
|
|
51
|
+
*
|
|
52
|
+
* Three dead declarations were removed rather than reshuffled:
|
|
53
|
+
* `outline-hidden` + `outline-none` — the same instruction twice.
|
|
54
|
+
* `ring-primary` + `ring-primary/50` — the first could never win.
|
|
55
|
+
* `ring-opacity-50` — Tailwind v3 syntax. v4 expresses
|
|
56
|
+
* opacity with the `/50` slash form, so
|
|
57
|
+
* this generated nothing at all.
|
|
58
|
+
*
|
|
59
|
+
* What is left is the ring that was actually rendering, at 60% rather than 50%:
|
|
60
|
+
* on `surface-900` the old value sat close enough to the field's own border to
|
|
61
|
+
* be missed at a glance, which is the one thing a focus ring may not be.
|
|
62
|
+
* `ring-offset-0` + a transparent offset stay — without them the ring draws a
|
|
63
|
+
* white halo on dark surfaces.
|
|
64
|
+
*/
|
|
65
|
+
var focusedClasses = "z-30 outline-none ring-2 ring-primary/60 ring-offset-0 ring-offset-transparent";
|
|
66
|
+
/**
|
|
67
|
+
* Field surfaces.
|
|
68
|
+
*
|
|
69
|
+
* A field is the one surface that goes the other way: it is INSET into
|
|
70
|
+
* whatever holds it, so `surface-field` is an alpha fill rather than a solid,
|
|
71
|
+
* and it composes over a card, the sheet or a dialog alike. It also carries
|
|
72
|
+
* the hairline: a field is an object (DESIGN.md rule 2), and without the line
|
|
73
|
+
* a 4% fill on a card reads as a soft slab rather than a control — measured on
|
|
74
|
+
* the product form, eight of them in a row looked like a wall. The reference
|
|
75
|
+
* draws every input with its 1px edge, on both themes.
|
|
76
|
+
*
|
|
77
|
+
* The 1px inset top highlight that used to sit here was the recessed-edge
|
|
78
|
+
* device from before the field had a border; with a real hairline above it
|
|
79
|
+
* the two stacked into a doubled top edge. The border does its work now.
|
|
80
|
+
*
|
|
81
|
+
* Exactly one element carries this mixin per field — the box, never the
|
|
82
|
+
* input inside it — so the alpha fill and its hover composite once.
|
|
83
|
+
*/
|
|
84
|
+
var fieldBackgroundMixin = "bg-surface-field border border-hairline";
|
|
85
|
+
var fieldBackgroundInvisibleMixin = "bg-transparent";
|
|
86
|
+
var fieldBackgroundDisabledMixin = "bg-surface-field/60";
|
|
87
|
+
/**
|
|
88
|
+
* `transition-colors` here, because every other interactive surface in the kit
|
|
89
|
+
* has it and fields did not — `cardClickableMixin` eases, a TextField snapped.
|
|
90
|
+
* On a form of eight fields that difference is the whole feel of the screen.
|
|
91
|
+
*/
|
|
92
|
+
var fieldBackgroundHoverMixin = "transition-colors duration-150 hover:bg-surface-field-hover";
|
|
93
|
+
/**
|
|
94
|
+
* The hairline. One value per theme (`--hairline` in theme.css), and where it
|
|
95
|
+
* goes matters more than what it is: a line marks an OBJECT — a card on the
|
|
96
|
+
* sheet, a field, a floating surface. It does not mark a region: a tile inside
|
|
97
|
+
* a card, a row, a segmented track, a button, a chip are fills, and the
|
|
98
|
+
* lightness step between them is the whole separation. One exception, and it
|
|
99
|
+
* is the sheet's own edge against the frame: that step is about 3 L* on both
|
|
100
|
+
* themes and did not read on a real screen, so the Scaffold draws this line
|
|
101
|
+
* there. Measured before this existed, the panel drew the same line on every
|
|
102
|
+
* card and every tile as well, and with only two surface values available the
|
|
103
|
+
* line was doing the work a step should have done.
|
|
104
|
+
*/
|
|
105
|
+
var defaultBorderMixin = "border-hairline";
|
|
106
|
+
var paperMixin = "bg-surface-card rounded-lg border border-hairline-strong";
|
|
107
|
+
var cardMixin = "bg-surface-card rounded-xl border border-hairline";
|
|
108
|
+
/**
|
|
109
|
+
* An inset well: code, a query, a log tail, a connection string.
|
|
110
|
+
*
|
|
111
|
+
* It must read as *recessed into* the surface holding it, which means darker
|
|
112
|
+
* than that surface in dark mode. Cards now sit at `surface-card` (#181818),
|
|
113
|
+
* so #0a0a0a is already fourteen units below and reads as a well; #000 was
|
|
114
|
+
* tuned for the old #0a card and is now harsher than it needs to be. That value
|
|
115
|
+
* is the `surface-well` role (theme.css), the one surface that goes DOWN the
|
|
116
|
+
* ladder on purpose. Pair with `font-mono`; this mixin carries the surface
|
|
117
|
+
* only.
|
|
118
|
+
*/
|
|
119
|
+
var codeSurfaceMixin = "bg-surface-well rounded-md";
|
|
120
|
+
/**
|
|
121
|
+
* The accent, used as TEXT.
|
|
122
|
+
*
|
|
123
|
+
* `--color-primary` (#0070F4) is tuned to be a fill — white text on it, it on
|
|
124
|
+
* white. Read as text on our dark surfaces it lands at **4.36:1 on a
|
|
125
|
+
* `surface-900` card** (measured), which is below AA for body-sized text, and
|
|
126
|
+
* every accent link in the product sits on exactly that surface. On the page's
|
|
127
|
+
* `surface-950` it only reaches 4.62:1, so the margin was never real.
|
|
128
|
+
*
|
|
129
|
+
* `--color-primary-light` is the same hue lifted 0.15 in OKLCH lightness and
|
|
130
|
+
* measures **7.34:1** on the same card. It is indistinguishable as "the blue"
|
|
131
|
+
* and comfortably legible, so dark mode swaps to it for text.
|
|
132
|
+
*
|
|
133
|
+
* Use this for links, accent labels and any accent-coloured type. It is NOT for
|
|
134
|
+
* fills — a filled button keeps `bg-primary`, where the contrast question runs
|
|
135
|
+
* the other way and #0070F4 is already correct.
|
|
136
|
+
*/
|
|
137
|
+
var accentTextMixin = "text-primary dark:text-primary-light";
|
|
138
|
+
/**
|
|
139
|
+
* Hover on a SOLID surface goes one step lighter, and it stays neutral. The
|
|
140
|
+
* previous `hover:bg-primary/5` tinted every clickable card blue, which spent
|
|
141
|
+
* the brand colour on a state that carries no meaning; on the dark ladder it
|
|
142
|
+
* also read as a hue shift rather than a lift.
|
|
143
|
+
*/
|
|
144
|
+
var cardClickableMixin = "hover:bg-surface-card-hover cursor-pointer transition-colors duration-150";
|
|
145
|
+
var cardSelectedMixin = "bg-primary-bg/30 dark:bg-primary-bg/10 ring-1 ring-primary/75";
|
|
146
|
+
/**
|
|
147
|
+
* Hover on a TRANSPARENT ground — a nav item, a menu item, a list row, a tree
|
|
148
|
+
* row. `surface-hover` is an alpha fill, so it lifts whatever it lands on by
|
|
149
|
+
* the same amount, and `surface-active` is the same idea one step further for
|
|
150
|
+
* the selected row when no hue is wanted. Do not use these on a solid card:
|
|
151
|
+
* an alpha fill REPLACES a solid background rather than tinting it.
|
|
152
|
+
*/
|
|
153
|
+
var surfaceHoverMixin = "hover:bg-surface-hover transition-colors duration-150";
|
|
154
|
+
var surfaceActiveMixin = "bg-surface-active";
|
|
155
|
+
//#endregion
|
|
156
|
+
export { CONTROL_HEIGHT, accentTextMixin, cardClickableMixin, cardMixin, cardSelectedMixin, codeSurfaceMixin, controlHeightMixin, controlPaddingMixin, defaultBorderMixin, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, fieldBackgroundInvisibleMixin, fieldBackgroundMixin, focusedClasses, focusedDisabled, focusedInvisibleMixin, paperMixin, surfaceActiveMixin, surfaceHoverMixin };
|
|
157
|
+
|
|
158
|
+
//# sourceMappingURL=styles.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.es.js","names":[],"sources":["../src/styles.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Control size scale — the single source of truth for how tall an inline\n// control is.\n//\n// Every control that sits on a line with another control (buttons, text\n// fields, selects, search bars, date fields, icon buttons, checkboxes) resolves\n// its height from this map, so a Button and a TextField at the same `size` are\n// pixel-identical and share a baseline. Before this existed each component\n// carried its own map and `size=\"large\"` meant 42px on a Button and 64px on a\n// TextField.\n//\n// The scale is 28/32/40/48 — the rhythm IconButton and Checkbox already used.\n// `xl`/`2xl` continue above it and are button-only.\n// ---------------------------------------------------------------------------\n\nexport type ControlSize = \"smallest\" | \"small\" | \"medium\" | \"large\";\nexport type ButtonSize = ControlSize | \"xl\" | \"2xl\";\n\nexport const CONTROL_HEIGHT = {\n smallest: 28,\n small: 32,\n medium: 40,\n large: 48,\n xl: 56,\n \"2xl\": 64\n} as const satisfies Record<ButtonSize, number>;\n\n/** Tailwind min-height class per control size. Keep in sync with CONTROL_HEIGHT. */\nexport const controlHeightMixin = {\n smallest: \"min-h-[28px]\",\n small: \"min-h-[32px]\",\n medium: \"min-h-[40px]\",\n large: \"min-h-[48px]\",\n xl: \"min-h-[56px]\",\n \"2xl\": \"min-h-[64px]\"\n} as const satisfies Record<ButtonSize, string>;\n\n/** Horizontal padding paired with each size, so gutters scale with height. */\nexport const controlPaddingMixin = {\n smallest: \"px-2\",\n small: \"px-2\",\n medium: \"px-3\",\n large: \"px-4\",\n xl: \"px-6\",\n \"2xl\": \"px-10\"\n} as const satisfies Record<ButtonSize, string>;\n\n/**\n * Suppress the focus ring on a surface that is focusable but is not a control —\n * a popover panel, a menu container, a bare cell input inside a table that\n * indicates focus by other means.\n *\n * Still expressed as `ring-0`, and that is why the default ring in\n * `index.css` overrides `--tw-ring-shadow` rather than switching to\n * `inset-ring-*`: `inset-ring` is a different variable, which this would not\n * have silenced, and every surface that had opted out would have got a ring\n * back.\n */\nexport const focusedDisabled = \"focus-visible:ring-0 focus-visible:ring-offset-0\";\nexport const focusedInvisibleMixin = \"focus:bg-surface-field-hover\";\n\n/**\n * The focus ring, drawn OUTSIDE the element, for a control that opts into it.\n *\n * The product's default ring is the `:focus-visible` rule in `index.css`, and\n * that one is drawn *inside* the border box: an outset ring is paint beyond the\n * box, and any ancestor that clips — a scroller, a truncating cell, a\n * max-height collapse — cuts it. This one is still outset because its only\n * caller is a whole field row sitting inside `p-4`/`p-6` of card padding, where\n * there is room around it and nothing clipping within 16px. Reach for it only\n * where that is true; anywhere else, let the default apply.\n *\n * Three dead declarations were removed rather than reshuffled:\n * `outline-hidden` + `outline-none` — the same instruction twice.\n * `ring-primary` + `ring-primary/50` — the first could never win.\n * `ring-opacity-50` — Tailwind v3 syntax. v4 expresses\n * opacity with the `/50` slash form, so\n * this generated nothing at all.\n *\n * What is left is the ring that was actually rendering, at 60% rather than 50%:\n * on `surface-900` the old value sat close enough to the field's own border to\n * be missed at a glance, which is the one thing a focus ring may not be.\n * `ring-offset-0` + a transparent offset stay — without them the ring draws a\n * white halo on dark surfaces.\n */\nexport const focusedClasses = \"z-30 outline-none ring-2 ring-primary/60 ring-offset-0 ring-offset-transparent\";\n\n/**\n * Field surfaces.\n *\n * A field is the one surface that goes the other way: it is INSET into\n * whatever holds it, so `surface-field` is an alpha fill rather than a solid,\n * and it composes over a card, the sheet or a dialog alike. It also carries\n * the hairline: a field is an object (DESIGN.md rule 2), and without the line\n * a 4% fill on a card reads as a soft slab rather than a control — measured on\n * the product form, eight of them in a row looked like a wall. The reference\n * draws every input with its 1px edge, on both themes.\n *\n * The 1px inset top highlight that used to sit here was the recessed-edge\n * device from before the field had a border; with a real hairline above it\n * the two stacked into a doubled top edge. The border does its work now.\n *\n * Exactly one element carries this mixin per field — the box, never the\n * input inside it — so the alpha fill and its hover composite once.\n */\nexport const fieldBackgroundMixin = \"bg-surface-field border border-hairline\";\nexport const fieldBackgroundInvisibleMixin = \"bg-transparent\";\nexport const fieldBackgroundDisabledMixin = \"bg-surface-field/60\";\n\n/**\n * `transition-colors` here, because every other interactive surface in the kit\n * has it and fields did not — `cardClickableMixin` eases, a TextField snapped.\n * On a form of eight fields that difference is the whole feel of the screen.\n */\nexport const fieldBackgroundHoverMixin = \"transition-colors duration-150 hover:bg-surface-field-hover\";\n\n/**\n * The hairline. One value per theme (`--hairline` in theme.css), and where it\n * goes matters more than what it is: a line marks an OBJECT — a card on the\n * sheet, a field, a floating surface. It does not mark a region: a tile inside\n * a card, a row, a segmented track, a button, a chip are fills, and the\n * lightness step between them is the whole separation. One exception, and it\n * is the sheet's own edge against the frame: that step is about 3 L* on both\n * themes and did not read on a real screen, so the Scaffold draws this line\n * there. Measured before this existed, the panel drew the same line on every\n * card and every tile as well, and with only two surface values available the\n * line was doing the work a step should have done.\n */\nexport const defaultBorderMixin = \"border-hairline\";\n\n// ---------------------------------------------------------------------------\n// Surfaces are named by ROLE (see theme.css) and the theme decides the value.\n// Every nested surface is one step lifted from the surface it sits on, on both\n// themes. The rules are in packages/ui/DESIGN.md (Surfaces); the measurements\n// behind the ladder are in docs/design/instatic-distilled.html.\n//\n// Two kinds of card, and the difference is what the border is for.\n//\n// A **floating** surface — a menu, a dialog, a popover — sits OVER the page. It\n// has to be legible against whatever happens to be underneath it, so its edge\n// is definite: `hairline-strong`. That is `paperMixin`.\n//\n// A **page** surface — a card in the document flow — sits ON the sheet, and it\n// is already one step lighter than the sheet. It keeps a plain hairline, which\n// is all a card on the sheet needs; once the step is there the line is close\n// to optional, and a stronger one reads as a box drawn around content.\n// ---------------------------------------------------------------------------\nexport const paperMixin = \"bg-surface-card rounded-lg border border-hairline-strong\";\nexport const cardMixin = \"bg-surface-card rounded-xl border border-hairline\";\n\n/**\n * An inset well: code, a query, a log tail, a connection string.\n *\n * It must read as *recessed into* the surface holding it, which means darker\n * than that surface in dark mode. Cards now sit at `surface-card` (#181818),\n * so #0a0a0a is already fourteen units below and reads as a well; #000 was\n * tuned for the old #0a card and is now harsher than it needs to be. That value\n * is the `surface-well` role (theme.css), the one surface that goes DOWN the\n * ladder on purpose. Pair with `font-mono`; this mixin carries the surface\n * only.\n */\nexport const codeSurfaceMixin = \"bg-surface-well rounded-md\";\n\n/**\n * The accent, used as TEXT.\n *\n * `--color-primary` (#0070F4) is tuned to be a fill — white text on it, it on\n * white. Read as text on our dark surfaces it lands at **4.36:1 on a\n * `surface-900` card** (measured), which is below AA for body-sized text, and\n * every accent link in the product sits on exactly that surface. On the page's\n * `surface-950` it only reaches 4.62:1, so the margin was never real.\n *\n * `--color-primary-light` is the same hue lifted 0.15 in OKLCH lightness and\n * measures **7.34:1** on the same card. It is indistinguishable as \"the blue\"\n * and comfortably legible, so dark mode swaps to it for text.\n *\n * Use this for links, accent labels and any accent-coloured type. It is NOT for\n * fills — a filled button keeps `bg-primary`, where the contrast question runs\n * the other way and #0070F4 is already correct.\n */\nexport const accentTextMixin = \"text-primary dark:text-primary-light\";\n\n/**\n * Hover on a SOLID surface goes one step lighter, and it stays neutral. The\n * previous `hover:bg-primary/5` tinted every clickable card blue, which spent\n * the brand colour on a state that carries no meaning; on the dark ladder it\n * also read as a hue shift rather than a lift.\n */\nexport const cardClickableMixin = \"hover:bg-surface-card-hover cursor-pointer transition-colors duration-150\";\nexport const cardSelectedMixin = \"bg-primary-bg/30 dark:bg-primary-bg/10 ring-1 ring-primary/75\";\n\n/**\n * Hover on a TRANSPARENT ground — a nav item, a menu item, a list row, a tree\n * row. `surface-hover` is an alpha fill, so it lifts whatever it lands on by\n * the same amount, and `surface-active` is the same idea one step further for\n * the selected row when no hue is wanted. Do not use these on a solid card:\n * an alpha fill REPLACES a solid background rather than tinting it.\n */\nexport const surfaceHoverMixin = \"hover:bg-surface-hover transition-colors duration-150\";\nexport const surfaceActiveMixin = \"bg-surface-active\";\n"],"mappings":";AAkBA,IAAa,iBAAiB;CAC1B,UAAU;CACV,OAAO;CACP,QAAQ;CACR,OAAO;CACP,IAAI;CACJ,OAAO;AACX;;AAGA,IAAa,qBAAqB;CAC9B,UAAU;CACV,OAAO;CACP,QAAQ;CACR,OAAO;CACP,IAAI;CACJ,OAAO;AACX;;AAGA,IAAa,sBAAsB;CAC/B,UAAU;CACV,OAAO;CACP,QAAQ;CACR,OAAO;CACP,IAAI;CACJ,OAAO;AACX;;;;;;;;;;;;AAaA,IAAa,kBAAkB;AAC/B,IAAa,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;AA0BrC,IAAa,iBAAiB;;;;;;;;;;;;;;;;;;;AAoB9B,IAAa,uBAAuB;AACpC,IAAa,gCAAgC;AAC7C,IAAa,+BAA+B;;;;;;AAO5C,IAAa,4BAA4B;;;;;;;;;;;;;AAczC,IAAa,qBAAqB;AAmBlC,IAAa,aAAa;AAC1B,IAAa,YAAY;;;;;;;;;;;;AAazB,IAAa,mBAAmB;;;;;;;;;;;;;;;;;;AAmBhC,IAAa,kBAAkB;;;;;;;AAQ/B,IAAa,qBAAqB;AAClC,IAAa,oBAAoB;;;;;;;;AASjC,IAAa,oBAAoB;AACjC,IAAa,qBAAqB"}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { hashString } from "./hash.es.js";
|
|
2
|
+
//#region src/util/chip_colors.ts
|
|
3
|
+
/** WCAG floor, plus a little margin so rounding cannot drop a pair below 4.5. */
|
|
4
|
+
var CONTRAST_TARGET = 4.6;
|
|
5
|
+
/** Page backgrounds the outlined variant sits on: `bg-white` and `surface-950`. */
|
|
6
|
+
var PAGE_LIGHT = "#ffffff";
|
|
7
|
+
var PAGE_DARK = "#181818";
|
|
8
|
+
function toRgb(hex) {
|
|
9
|
+
let h = hex.replace("#", "");
|
|
10
|
+
if (h.length === 3) h = h.split("").map((c) => c + c).join("");
|
|
11
|
+
return [
|
|
12
|
+
0,
|
|
13
|
+
2,
|
|
14
|
+
4
|
|
15
|
+
].map((i) => parseInt(h.slice(i, i + 2), 16));
|
|
16
|
+
}
|
|
17
|
+
function toHex(rgb) {
|
|
18
|
+
return "#" + rgb.map((v) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, "0")).join("");
|
|
19
|
+
}
|
|
20
|
+
function toRgba(hex, alpha) {
|
|
21
|
+
const [r, g, b] = toRgb(hex);
|
|
22
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* What a translucent colour reads as over an opaque one: a per-channel sRGB
|
|
26
|
+
* mix, which is how the browser composites it. The tint ink is pushed against
|
|
27
|
+
* this, never against the page alone — a 16% wash of the hue moves the
|
|
28
|
+
* background a long way toward the ink, and an ink that only cleared AA on
|
|
29
|
+
* the bare page lands near 3.5:1 on its own tint.
|
|
30
|
+
*/
|
|
31
|
+
function compositeOver(fgHex, alpha, bgHex) {
|
|
32
|
+
const fg = toRgb(fgHex);
|
|
33
|
+
const bg = toRgb(bgHex);
|
|
34
|
+
return toHex(fg.map((c, i) => alpha * c + (1 - alpha) * bg[i]));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Tint alpha by tone, light then dark. The tones keep meaning something in the
|
|
38
|
+
* tinted variant — a `Darker` chip is a heavier wash, not a different hue —
|
|
39
|
+
* and dark mode runs four points higher because the same alpha of a bright
|
|
40
|
+
* hue reads fainter over near-black than over white.
|
|
41
|
+
*/
|
|
42
|
+
var TINT_ALPHA = {
|
|
43
|
+
Lighter: [.1, .14],
|
|
44
|
+
Light: [.14, .18],
|
|
45
|
+
Dark: [.18, .22],
|
|
46
|
+
Darker: [.22, .26]
|
|
47
|
+
};
|
|
48
|
+
function relativeLuminance(hex) {
|
|
49
|
+
const [r, g, b] = toRgb(hex).map((v) => {
|
|
50
|
+
const c = v / 255;
|
|
51
|
+
return c <= .03928 ? c / 12.92 : Math.pow((c + .055) / 1.055, 2.4);
|
|
52
|
+
});
|
|
53
|
+
return .2126 * r + .7152 * g + .0722 * b;
|
|
54
|
+
}
|
|
55
|
+
function contrastRatio(a, b) {
|
|
56
|
+
const x = relativeLuminance(a);
|
|
57
|
+
const y = relativeLuminance(b);
|
|
58
|
+
const [hi, lo] = x > y ? [x, y] : [y, x];
|
|
59
|
+
return (hi + .05) / (lo + .05);
|
|
60
|
+
}
|
|
61
|
+
function mixHex(from, to, t) {
|
|
62
|
+
const A = toRgb(from);
|
|
63
|
+
const B = toRgb(to);
|
|
64
|
+
return toHex([
|
|
65
|
+
0,
|
|
66
|
+
1,
|
|
67
|
+
2
|
|
68
|
+
].map((i) => A[i] + (B[i] - A[i]) * t));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Walk a tinted ink toward black or white until it clears the floor on `bg`.
|
|
72
|
+
*
|
|
73
|
+
* Stops at the first passing step rather than going all the way, so the ink
|
|
74
|
+
* keeps as much of its hue as legibility allows.
|
|
75
|
+
*/
|
|
76
|
+
function push(base, toward, bg) {
|
|
77
|
+
for (let t = 0; t <= 1.0001; t += .02) {
|
|
78
|
+
const candidate = mixHex(base, toward, t);
|
|
79
|
+
if (contrastRatio(candidate, bg) >= CONTRAST_TARGET) return candidate;
|
|
80
|
+
}
|
|
81
|
+
return toward;
|
|
82
|
+
}
|
|
83
|
+
/** The ink for a chip filled with `bg`: whichever direction has more headroom. */
|
|
84
|
+
function inkOn(stops, bg) {
|
|
85
|
+
const dark = push(stops.text, "#000000", bg);
|
|
86
|
+
const light = push(stops.onDeep ?? stops.pale, "#ffffff", bg);
|
|
87
|
+
return contrastRatio(dark, bg) >= contrastRatio(light, bg) ? dark : light;
|
|
88
|
+
}
|
|
89
|
+
var CHIP_HUES = [
|
|
90
|
+
"blue",
|
|
91
|
+
"cyan",
|
|
92
|
+
"teal",
|
|
93
|
+
"green",
|
|
94
|
+
"yellow",
|
|
95
|
+
"orange",
|
|
96
|
+
"red",
|
|
97
|
+
"pink",
|
|
98
|
+
"purple",
|
|
99
|
+
"gray",
|
|
100
|
+
"indigo",
|
|
101
|
+
"violet",
|
|
102
|
+
"fuchsia",
|
|
103
|
+
"rose",
|
|
104
|
+
"emerald"
|
|
105
|
+
];
|
|
106
|
+
var HUE_STOPS = {
|
|
107
|
+
blue: {
|
|
108
|
+
pale: "#cfdfff",
|
|
109
|
+
mid: "#9cc7ff",
|
|
110
|
+
solid: "#2d7ff9",
|
|
111
|
+
deep: "#2750ae",
|
|
112
|
+
text: "#102046"
|
|
113
|
+
},
|
|
114
|
+
cyan: {
|
|
115
|
+
pale: "#d0f0fd",
|
|
116
|
+
mid: "#77d1f3",
|
|
117
|
+
solid: "#18bfff",
|
|
118
|
+
deep: "#0b76b7",
|
|
119
|
+
text: "#04283f"
|
|
120
|
+
},
|
|
121
|
+
teal: {
|
|
122
|
+
pale: "#c2f5e9",
|
|
123
|
+
mid: "#72ddc3",
|
|
124
|
+
solid: "#20d9d2",
|
|
125
|
+
deep: "#06a09b",
|
|
126
|
+
text: "#012524",
|
|
127
|
+
onDeep: "#daf3e9"
|
|
128
|
+
},
|
|
129
|
+
green: {
|
|
130
|
+
pale: "#d1f7c4",
|
|
131
|
+
mid: "#93e088",
|
|
132
|
+
solid: "#20c933",
|
|
133
|
+
deep: "#338a17",
|
|
134
|
+
text: "#0b1d05"
|
|
135
|
+
},
|
|
136
|
+
yellow: {
|
|
137
|
+
pale: "#ffeab6",
|
|
138
|
+
mid: "#ffd66e",
|
|
139
|
+
solid: "#fcb400",
|
|
140
|
+
deep: "#b87503",
|
|
141
|
+
text: "#3b2501"
|
|
142
|
+
},
|
|
143
|
+
orange: {
|
|
144
|
+
pale: "#fee2d5",
|
|
145
|
+
mid: "#ffa981",
|
|
146
|
+
solid: "#ff6f2c",
|
|
147
|
+
deep: "#d74d26",
|
|
148
|
+
text: "#6b2613"
|
|
149
|
+
},
|
|
150
|
+
red: {
|
|
151
|
+
pale: "#ffdce5",
|
|
152
|
+
mid: "#ff9eb7",
|
|
153
|
+
solid: "#f82b60",
|
|
154
|
+
deep: "#ba1e45",
|
|
155
|
+
text: "#4c0c1c"
|
|
156
|
+
},
|
|
157
|
+
pink: {
|
|
158
|
+
pale: "#ffdaf6",
|
|
159
|
+
mid: "#f99de2",
|
|
160
|
+
solid: "#ff08c2",
|
|
161
|
+
deep: "#b2158b",
|
|
162
|
+
text: "#400832"
|
|
163
|
+
},
|
|
164
|
+
purple: {
|
|
165
|
+
pale: "#ede2fe",
|
|
166
|
+
mid: "#cdb0ff",
|
|
167
|
+
solid: "#8b46ff",
|
|
168
|
+
deep: "#6b1cb0",
|
|
169
|
+
text: "#280b42"
|
|
170
|
+
},
|
|
171
|
+
gray: {
|
|
172
|
+
pale: "#eeeeee",
|
|
173
|
+
mid: "#cccccc",
|
|
174
|
+
solid: "#666666",
|
|
175
|
+
deep: "#444444",
|
|
176
|
+
text: "#040404"
|
|
177
|
+
},
|
|
178
|
+
indigo: {
|
|
179
|
+
pale: "#e0e7ff",
|
|
180
|
+
mid: "#a5b4fc",
|
|
181
|
+
solid: "#6366f1",
|
|
182
|
+
deep: "#4f46e5",
|
|
183
|
+
text: "#312e81"
|
|
184
|
+
},
|
|
185
|
+
violet: {
|
|
186
|
+
pale: "#ede9fe",
|
|
187
|
+
mid: "#c4b5fd",
|
|
188
|
+
solid: "#8b5cf6",
|
|
189
|
+
deep: "#7c3aed",
|
|
190
|
+
text: "#4c1d95"
|
|
191
|
+
},
|
|
192
|
+
fuchsia: {
|
|
193
|
+
pale: "#fae8ff",
|
|
194
|
+
mid: "#f0abfc",
|
|
195
|
+
solid: "#d946ef",
|
|
196
|
+
deep: "#c026d3",
|
|
197
|
+
text: "#701a75"
|
|
198
|
+
},
|
|
199
|
+
rose: {
|
|
200
|
+
pale: "#ffe4e6",
|
|
201
|
+
mid: "#fda4af",
|
|
202
|
+
solid: "#f43f5e",
|
|
203
|
+
deep: "#e11d48",
|
|
204
|
+
text: "#881337"
|
|
205
|
+
},
|
|
206
|
+
emerald: {
|
|
207
|
+
pale: "#d1fae5",
|
|
208
|
+
mid: "#6ee7b7",
|
|
209
|
+
solid: "#10b981",
|
|
210
|
+
deep: "#059669",
|
|
211
|
+
text: "#064e3b"
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* One tone of one hue.
|
|
216
|
+
*
|
|
217
|
+
* Backgrounds are the palette's, unchanged — the stops were not the problem and
|
|
218
|
+
* moving them would have restyled every chip in the product. Only the ink moved,
|
|
219
|
+
* and it moved to wherever the measurement says it has to be.
|
|
220
|
+
*/
|
|
221
|
+
function tone(stops, chipTone) {
|
|
222
|
+
const outline = {
|
|
223
|
+
outlineText: push(stops.text, "#000000", PAGE_LIGHT),
|
|
224
|
+
darkOutlineText: push(stops.onDeep ?? stops.pale, "#ffffff", PAGE_DARK)
|
|
225
|
+
};
|
|
226
|
+
const [alphaLight, alphaDark] = TINT_ALPHA[chipTone];
|
|
227
|
+
const tint = {
|
|
228
|
+
tintColor: toRgba(stops.solid, alphaLight),
|
|
229
|
+
tintText: push(stops.deep, "#000000", compositeOver(stops.solid, alphaLight, PAGE_LIGHT)),
|
|
230
|
+
darkTintColor: toRgba(stops.solid, alphaDark),
|
|
231
|
+
darkTintText: push(stops.mid, "#ffffff", compositeOver(stops.solid, alphaDark, PAGE_DARK))
|
|
232
|
+
};
|
|
233
|
+
const filled = (light, dark) => ({
|
|
234
|
+
color: light,
|
|
235
|
+
text: inkOn(stops, light),
|
|
236
|
+
darkColor: dark,
|
|
237
|
+
darkText: inkOn(stops, dark),
|
|
238
|
+
...outline,
|
|
239
|
+
...tint
|
|
240
|
+
});
|
|
241
|
+
switch (chipTone) {
|
|
242
|
+
case "Light": return filled(stops.mid, stops.solid);
|
|
243
|
+
case "Dark": return filled(stops.solid, stops.solid);
|
|
244
|
+
case "Darker": return filled(stops.deep, stops.deep);
|
|
245
|
+
default: return filled(stops.pale, stops.deep);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
var CHIP_TONES = [
|
|
249
|
+
"Lighter",
|
|
250
|
+
"Light",
|
|
251
|
+
"Dark",
|
|
252
|
+
"Darker"
|
|
253
|
+
];
|
|
254
|
+
function buildChipColors() {
|
|
255
|
+
const colors = {};
|
|
256
|
+
for (const hue of CHIP_HUES) {
|
|
257
|
+
const stops = HUE_STOPS[hue];
|
|
258
|
+
for (const chipTone of CHIP_TONES) colors[`${hue}${chipTone}`] = tone(stops, chipTone);
|
|
259
|
+
colors[hue] = tone(stops, "Lighter");
|
|
260
|
+
}
|
|
261
|
+
return colors;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Every chip scheme, keyed by hue and tone.
|
|
265
|
+
*
|
|
266
|
+
* This table used to hold four tones per hue and was flattened to one, which
|
|
267
|
+
* left `blueDark`, `redDarker` and friends resolving to `undefined` — a chip
|
|
268
|
+
* with a colour in its config rendering with no colour at all — and left seeded
|
|
269
|
+
* chips picking from ten schemes, so a five-value enum routinely drew the same
|
|
270
|
+
* background three times. The tones are generated from {@link HUE_STOPS} now,
|
|
271
|
+
* so a new hue brings its whole family with it.
|
|
272
|
+
*/
|
|
273
|
+
var CHIP_COLORS = buildChipColors();
|
|
274
|
+
/**
|
|
275
|
+
* The keys a seeded chip may be assigned, in a stable order.
|
|
276
|
+
*
|
|
277
|
+
* The bare-hue aliases are excluded: they are the same scheme as `<hue>Lighter`
|
|
278
|
+
* and would make the palest tone twice as likely as any other.
|
|
279
|
+
*/
|
|
280
|
+
var CHIP_SEED_KEYS = CHIP_HUES.flatMap((hue) => CHIP_TONES.map((chipTone) => `${hue}${chipTone}`));
|
|
281
|
+
function getColorSchemeForKey(key) {
|
|
282
|
+
return CHIP_COLORS[key] ?? getColorSchemeForSeed(String(key));
|
|
283
|
+
}
|
|
284
|
+
function getColorSchemeForSeed(seed) {
|
|
285
|
+
return CHIP_COLORS[CHIP_SEED_KEYS[hashString(seed) % CHIP_SEED_KEYS.length]];
|
|
286
|
+
}
|
|
287
|
+
//#endregion
|
|
288
|
+
export { CHIP_COLORS, CHIP_HUES, CHIP_SEED_KEYS, compositeOver, contrastRatio, getColorSchemeForKey, getColorSchemeForSeed };
|
|
289
|
+
|
|
290
|
+
//# sourceMappingURL=chip_colors.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chip_colors.es.js","names":[],"sources":["../../src/util/chip_colors.ts"],"sourcesContent":["import { hashString } from \"./hash\";\n\nexport type ChipColorScheme = {\n color: string;\n text: string;\n /** Background color override for dark mode */\n darkColor?: string;\n /** Text color override for dark mode */\n darkText?: string;\n /**\n * Ink for the `outlined` variant, which has no fill of its own.\n *\n * `text`/`darkText` are the ink ON the chip's own background. An outlined\n * chip drops that background and sits on the PAGE, so the same value is\n * being asked to be legible against two different surfaces at once — and\n * for most hues it cannot be. Splitting the roles is what lets the filled\n * ink follow its fill (often dark ink on a bright chip) without dragging\n * the outlined variant down with it.\n */\n outlineText?: string;\n /** Outlined-variant ink in dark mode. */\n darkOutlineText?: string;\n /**\n * The `tinted` variant: the hue's solid stop at low alpha, as an `rgba()`\n * string so it composes over a card, the sheet or a dialog alike, and an\n * ink MEASURED on what that tint reads as over the page. A tint is the\n * reference's rule for hue in the chrome — a 12–16% wash behind hue-coloured\n * text — and it is what a status or enum chip paints by default now; the\n * saturated `color` stop is the `filled` variant, kept for swatches.\n */\n tintColor?: string;\n tintText?: string;\n darkTintColor?: string;\n darkTintText?: string;\n}\n\n/* ────────────────────────────────────────────────────────────────────────────\n Contrast\n ────────────────────────────────────────────────────────────────────────────\n\n Chip ink is DERIVED, not hand-picked. It used to be written down per tone —\n `\"#fff\"` on every `solid` background, the hue's `pale` on every `deep` one —\n and an audit of all 120 hue/tone/mode pairs found **63 of them below WCAG AA**.\n The worst was white on `teal.solid` at **1.76:1**, which is not a near miss;\n it is unreadable. The palette is an Airtable-style one whose mid stops are\n bright enough to need dark ink, and hardcoding light ink ignored that.\n\n So the ink is measured against the background it will actually sit on, and\n pushed toward black or white only as far as it must go to clear the floor.\n Starting from the hue's own dark/light tints rather than from flat `#000`\n and `#fff` keeps the family looking like a family: `blue.solid` gets a very\n dark navy, not black.\n\n Deriving it also means a new hue cannot be added below AA — there is no\n per-tone ink to forget to check. */\n\n/** WCAG floor, plus a little margin so rounding cannot drop a pair below 4.5. */\nconst CONTRAST_TARGET = 4.6;\n\n/** Page backgrounds the outlined variant sits on: `bg-white` and `surface-950`. */\nconst PAGE_LIGHT = \"#ffffff\";\nconst PAGE_DARK = \"#181818\";\n\nfunction toRgb(hex: string): [number, number, number] {\n let h = hex.replace(\"#\", \"\");\n if (h.length === 3) h = h.split(\"\").map(c => c + c).join(\"\");\n return [0, 2, 4].map(i => parseInt(h.slice(i, i + 2), 16)) as [number, number, number];\n}\n\nfunction toHex(rgb: number[]): string {\n return \"#\" + rgb.map(v => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nfunction toRgba(hex: string, alpha: number): string {\n const [r, g, b] = toRgb(hex);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\n/**\n * What a translucent colour reads as over an opaque one: a per-channel sRGB\n * mix, which is how the browser composites it. The tint ink is pushed against\n * this, never against the page alone — a 16% wash of the hue moves the\n * background a long way toward the ink, and an ink that only cleared AA on\n * the bare page lands near 3.5:1 on its own tint.\n */\nexport function compositeOver(fgHex: string, alpha: number, bgHex: string): string {\n const fg = toRgb(fgHex);\n const bg = toRgb(bgHex);\n return toHex(fg.map((c, i) => alpha * c + (1 - alpha) * bg[i]));\n}\n\n/** Read an `rgba(r, g, b, a)` string back as what it composites to over `bgHex`. */\nexport function tintOnPage(rgba: string, bgHex: string): string {\n const m = rgba.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*([\\d.]+))?\\)/);\n if (!m) return rgba;\n const fg = toHex([Number(m[1]), Number(m[2]), Number(m[3])]);\n return compositeOver(fg, m[4] === undefined ? 1 : Number(m[4]), bgHex);\n}\n\n/**\n * Tint alpha by tone, light then dark. The tones keep meaning something in the\n * tinted variant — a `Darker` chip is a heavier wash, not a different hue —\n * and dark mode runs four points higher because the same alpha of a bright\n * hue reads fainter over near-black than over white.\n */\nconst TINT_ALPHA: Record<ChipTone, [light: number, dark: number]> = {\n Lighter: [0.10, 0.14],\n Light: [0.14, 0.18],\n Dark: [0.18, 0.22],\n Darker: [0.22, 0.26]\n};\n\nfunction relativeLuminance(hex: string): number {\n const [r, g, b] = toRgb(hex).map(v => {\n const c = v / 255;\n return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n });\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\nexport function contrastRatio(a: string, b: string): number {\n const x = relativeLuminance(a);\n const y = relativeLuminance(b);\n const [hi, lo] = x > y ? [x, y] : [y, x];\n return (hi + 0.05) / (lo + 0.05);\n}\n\nfunction mixHex(from: string, to: string, t: number): string {\n const A = toRgb(from);\n const B = toRgb(to);\n return toHex([0, 1, 2].map(i => A[i] + (B[i] - A[i]) * t));\n}\n\n/**\n * Walk a tinted ink toward black or white until it clears the floor on `bg`.\n *\n * Stops at the first passing step rather than going all the way, so the ink\n * keeps as much of its hue as legibility allows.\n */\nfunction push(base: string, toward: string, bg: string): string {\n for (let t = 0; t <= 1.0001; t += 0.02) {\n const candidate = mixHex(base, toward, t);\n if (contrastRatio(candidate, bg) >= CONTRAST_TARGET) return candidate;\n }\n return toward;\n}\n\n/** The ink for a chip filled with `bg`: whichever direction has more headroom. */\nfunction inkOn(stops: HueStops, bg: string): string {\n const dark = push(stops.text, \"#000000\", bg);\n const light = push(stops.onDeep ?? stops.pale, \"#ffffff\", bg);\n return contrastRatio(dark, bg) >= contrastRatio(light, bg) ? dark : light;\n}\n\n/**\n * The hues a chip can take, and the four stops each one is built from.\n *\n * `pale` and `mid` are backgrounds for dark text; `solid` and `deep` are\n * backgrounds for light text. `text` is the dark ink used on the two pale\n * stops, and `onDeep` the light ink on `deep` — it defaults to `pale`, and is\n * only set where a hue needs a tint of its own to stay legible.\n */\ntype HueStops = {\n pale: string;\n mid: string;\n solid: string;\n deep: string;\n text: string;\n onDeep?: string;\n}\n\nexport const CHIP_HUES = [\n \"blue\", \"cyan\", \"teal\", \"green\", \"yellow\", \"orange\", \"red\", \"pink\", \"purple\", \"gray\",\n \"indigo\", \"violet\", \"fuchsia\", \"rose\", \"emerald\"\n] as const;\n\nexport type ChipHue = typeof CHIP_HUES[number];\n\n/**\n * How light or saturated a chip of a given hue is.\n *\n * A hue on its own (`\"blue\"`) means `Lighter` — the tone the picker offers and\n * the one seeded chips used to be limited to.\n */\nexport type ChipTone = \"Lighter\" | \"Light\" | \"Dark\" | \"Darker\";\n\nexport type ChipColorKey = ChipHue | `${ChipHue}${ChipTone}`;\n\nconst HUE_STOPS: Record<ChipHue, HueStops> = {\n blue: { pale: \"#cfdfff\", mid: \"#9cc7ff\", solid: \"#2d7ff9\", deep: \"#2750ae\", text: \"#102046\" },\n cyan: { pale: \"#d0f0fd\", mid: \"#77d1f3\", solid: \"#18bfff\", deep: \"#0b76b7\", text: \"#04283f\" },\n teal: { pale: \"#c2f5e9\", mid: \"#72ddc3\", solid: \"#20d9d2\", deep: \"#06a09b\", text: \"#012524\", onDeep: \"#daf3e9\" },\n green: { pale: \"#d1f7c4\", mid: \"#93e088\", solid: \"#20c933\", deep: \"#338a17\", text: \"#0b1d05\" },\n yellow: { pale: \"#ffeab6\", mid: \"#ffd66e\", solid: \"#fcb400\", deep: \"#b87503\", text: \"#3b2501\" },\n orange: { pale: \"#fee2d5\", mid: \"#ffa981\", solid: \"#ff6f2c\", deep: \"#d74d26\", text: \"#6b2613\" },\n red: { pale: \"#ffdce5\", mid: \"#ff9eb7\", solid: \"#f82b60\", deep: \"#ba1e45\", text: \"#4c0c1c\" },\n pink: { pale: \"#ffdaf6\", mid: \"#f99de2\", solid: \"#ff08c2\", deep: \"#b2158b\", text: \"#400832\" },\n purple: { pale: \"#ede2fe\", mid: \"#cdb0ff\", solid: \"#8b46ff\", deep: \"#6b1cb0\", text: \"#280b42\" },\n gray: { pale: \"#eeeeee\", mid: \"#cccccc\", solid: \"#666666\", deep: \"#444444\", text: \"#040404\" },\n indigo: { pale: \"#e0e7ff\", mid: \"#a5b4fc\", solid: \"#6366f1\", deep: \"#4f46e5\", text: \"#312e81\" },\n violet: { pale: \"#ede9fe\", mid: \"#c4b5fd\", solid: \"#8b5cf6\", deep: \"#7c3aed\", text: \"#4c1d95\" },\n fuchsia: { pale: \"#fae8ff\", mid: \"#f0abfc\", solid: \"#d946ef\", deep: \"#c026d3\", text: \"#701a75\" },\n rose: { pale: \"#ffe4e6\", mid: \"#fda4af\", solid: \"#f43f5e\", deep: \"#e11d48\", text: \"#881337\" },\n emerald: { pale: \"#d1fae5\", mid: \"#6ee7b7\", solid: \"#10b981\", deep: \"#059669\", text: \"#064e3b\" }\n};\n\n/**\n * One tone of one hue.\n *\n * Backgrounds are the palette's, unchanged — the stops were not the problem and\n * moving them would have restyled every chip in the product. Only the ink moved,\n * and it moved to wherever the measurement says it has to be.\n */\nfunction tone(stops: HueStops, chipTone: ChipTone): ChipColorScheme {\n // The outlined variant is a property of the HUE, not of the tone: it has no\n // fill, so every tone of a hue sits on the same page background and wants\n // the same ink.\n const outline = {\n outlineText: push(stops.text, \"#000000\", PAGE_LIGHT),\n darkOutlineText: push(stops.onDeep ?? stops.pale, \"#ffffff\", PAGE_DARK)\n };\n\n // The tint is the SOLID stop washed out, on both themes, so a hue keeps\n // its identity across the two — a pale-stop tint of blue reads as grey.\n // Light ink starts from `deep` and dark ink from `mid`: the saturated end\n // that already sits on the right side of the composite, pushed only as\n // far as the measurement says.\n const [alphaLight, alphaDark] = TINT_ALPHA[chipTone];\n const tint = {\n tintColor: toRgba(stops.solid, alphaLight),\n tintText: push(stops.deep, \"#000000\", compositeOver(stops.solid, alphaLight, PAGE_LIGHT)),\n darkTintColor: toRgba(stops.solid, alphaDark),\n darkTintText: push(stops.mid, \"#ffffff\", compositeOver(stops.solid, alphaDark, PAGE_DARK))\n };\n\n const filled = (light: string, dark: string): ChipColorScheme => ({\n color: light,\n text: inkOn(stops, light),\n darkColor: dark,\n darkText: inkOn(stops, dark),\n ...outline,\n ...tint\n });\n\n switch (chipTone) {\n case \"Light\":\n return filled(stops.mid, stops.solid);\n case \"Dark\":\n return filled(stops.solid, stops.solid);\n case \"Darker\":\n return filled(stops.deep, stops.deep);\n case \"Lighter\":\n default:\n return filled(stops.pale, stops.deep);\n }\n}\n\nconst CHIP_TONES: ChipTone[] = [\"Lighter\", \"Light\", \"Dark\", \"Darker\"];\n\nfunction buildChipColors(): Record<ChipColorKey, ChipColorScheme> {\n const colors = {} as Record<ChipColorKey, ChipColorScheme>;\n for (const hue of CHIP_HUES) {\n const stops = HUE_STOPS[hue];\n for (const chipTone of CHIP_TONES) {\n colors[`${hue}${chipTone}` as ChipColorKey] = tone(stops, chipTone);\n }\n // The bare hue is the lightest tone, which is what every existing\n // `color: \"blue\"` in a collection config already means.\n colors[hue] = tone(stops, \"Lighter\");\n }\n return colors;\n}\n\n/**\n * Every chip scheme, keyed by hue and tone.\n *\n * This table used to hold four tones per hue and was flattened to one, which\n * left `blueDark`, `redDarker` and friends resolving to `undefined` — a chip\n * with a colour in its config rendering with no colour at all — and left seeded\n * chips picking from ten schemes, so a five-value enum routinely drew the same\n * background three times. The tones are generated from {@link HUE_STOPS} now,\n * so a new hue brings its whole family with it.\n */\nexport const CHIP_COLORS: Record<ChipColorKey, ChipColorScheme> = buildChipColors();\n\n/**\n * The keys a seeded chip may be assigned, in a stable order.\n *\n * The bare-hue aliases are excluded: they are the same scheme as `<hue>Lighter`\n * and would make the palest tone twice as likely as any other.\n */\nexport const CHIP_SEED_KEYS: ChipColorKey[] = CHIP_HUES.flatMap(\n hue => CHIP_TONES.map(chipTone => `${hue}${chipTone}` as ChipColorKey));\n\n// `string & {}` keeps the known keys in autocomplete while still accepting the\n// arbitrary column colours a board hands over.\nexport function getColorSchemeForKey(key: ChipColorKey | (string & {})): ChipColorScheme {\n // An unknown key is a config that names a colour this build does not have —\n // a renamed hue, or a value typed by hand. Seeding from the key keeps it\n // coloured and keeps it stable, rather than dropping it to no colour.\n return CHIP_COLORS[key as ChipColorKey] ?? getColorSchemeForSeed(String(key));\n}\n\nexport function getColorSchemeForSeed(seed: string): ChipColorScheme {\n const hash: number = hashString(seed);\n return CHIP_COLORS[CHIP_SEED_KEYS[hash % CHIP_SEED_KEYS.length]];\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cls.es.js","names":[],"sources":["../../src/util/cls.ts"],"sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cls(...classes: ClassValue[]) {\n return twMerge(clsx(classes));\n}\n\n\n"],"mappings":";;;AAGA,SAAgB,IAAI,GAAG,SAAuB;CAC1C,OAAO,QAAQ,KAAK,OAAO,CAAC;AAChC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/util/debounce.ts
|
|
2
|
+
/**
|
|
3
|
+
* @ignore
|
|
4
|
+
*/
|
|
5
|
+
function debounce(func, wait = 166) {
|
|
6
|
+
let timeout;
|
|
7
|
+
function debounced(...args) {
|
|
8
|
+
const later = () => {
|
|
9
|
+
func.apply(this, args);
|
|
10
|
+
};
|
|
11
|
+
clearTimeout(timeout);
|
|
12
|
+
timeout = setTimeout(later, wait);
|
|
13
|
+
}
|
|
14
|
+
debounced.clear = () => {
|
|
15
|
+
clearTimeout(timeout);
|
|
16
|
+
};
|
|
17
|
+
return debounced;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { debounce };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=debounce.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debounce.es.js","names":[],"sources":["../../src/util/debounce.ts"],"sourcesContent":["/**\n * @ignore\n */\n\nexport function debounce<T extends (...args: any[]) => unknown>(func: T, wait = 166) {\n let timeout: ReturnType<typeof setTimeout>;\n\n function debounced(this: unknown, ...args: Parameters<T>) {\n const later = () => {\n func.apply(this, args);\n };\n clearTimeout(timeout);\n timeout = setTimeout(later, wait);\n }\n\n debounced.clear = () => {\n clearTimeout(timeout);\n };\n\n return debounced as T & Cancelable;\n}\n\n/**\n * @ignore\n */\nexport interface Cancelable {\n clear(): void;\n}\n"],"mappings":";;;;AAIA,SAAgB,SAAgD,MAAS,OAAO,KAAK;CACjF,IAAI;CAEJ,SAAS,UAAyB,GAAG,MAAqB;EACtD,MAAM,cAAc;GAChB,KAAK,MAAM,MAAM,IAAI;EACzB;EACA,aAAa,OAAO;EACpB,UAAU,WAAW,OAAO,IAAI;CACpC;CAEA,UAAU,cAAc;EACpB,aAAa,OAAO;CACxB;CAEA,OAAO;AACX"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/util/hash.ts
|
|
2
|
+
function hashString(str) {
|
|
3
|
+
let hash = 0;
|
|
4
|
+
let i;
|
|
5
|
+
let chr;
|
|
6
|
+
for (i = 0; i < str.length; i++) {
|
|
7
|
+
chr = str.charCodeAt(i);
|
|
8
|
+
hash = (hash << 5) - hash + chr;
|
|
9
|
+
hash |= 0;
|
|
10
|
+
}
|
|
11
|
+
return Math.abs(hash);
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { hashString };
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=hash.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.es.js","names":[],"sources":["../../src/util/hash.ts"],"sourcesContent":["export function hashString(str: string): number {\n let hash = 0;\n let i;\n let chr;\n for (i = 0; i < str.length; i++) {\n chr = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + chr;\n hash |= 0; // Convert to 32bit integer\n }\n return Math.abs(hash);\n}\n"],"mappings":";AAAA,SAAgB,WAAW,KAAqB;CAC5C,IAAI,OAAO;CACX,IAAI;CACJ,IAAI;CACJ,KAAK,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;EAC7B,MAAM,IAAI,WAAW,CAAC;EACtB,QAAS,QAAQ,KAAK,OAAQ;EAC9B,QAAQ;CACZ;CACA,OAAO,KAAK,IAAI,IAAI;AACxB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/util/keys.ts
|
|
2
|
+
/**
|
|
3
|
+
* Whether a key event has already been handled by something above you — the
|
|
4
|
+
* one question every global key handler (a `keydown` listener on `window` or
|
|
5
|
+
* `document`) must ask before acting.
|
|
6
|
+
*
|
|
7
|
+
* The rule: **a handler that acts on a key calls `event.preventDefault()`;
|
|
8
|
+
* a global handler that finds the event already handled does nothing.** Every
|
|
9
|
+
* kit overlay follows it for free — `Dialog`, `Sheet`, `Popover`, `Menu`,
|
|
10
|
+
* `Select`, `MultiSelect`, `Tooltip` are Radix layers, and a Radix layer calls
|
|
11
|
+
* `preventDefault()` on the Escape it consumes to close itself. So Escape
|
|
12
|
+
* pressed in an open dropdown closes the dropdown, and the record panel's
|
|
13
|
+
* Escape handler underneath sees it handled and leaves the record open.
|
|
14
|
+
*
|
|
15
|
+
* Two conditions make it hold:
|
|
16
|
+
*
|
|
17
|
+
* - **Listen in the bubble phase.** A Radix layer listens on `document` in
|
|
18
|
+
* the capture phase, so it has run before any bubble listener — on the
|
|
19
|
+
* target, on `document` or on `window` — whatever order they were added in.
|
|
20
|
+
* A capture listener added before the layer opened runs *before* it and
|
|
21
|
+
* cannot see its claim. Only a layer of your own, one that sits above
|
|
22
|
+
* everything else while it is open, belongs in the capture phase, and it
|
|
23
|
+
* must call `preventDefault()` when it acts.
|
|
24
|
+
* - **Do not ask the DOM instead.** `document.querySelector('[role="dialog"]')`
|
|
25
|
+
* misses every layer that is not a dialog (a menu is `role="menu"`, a select
|
|
26
|
+
* list `role="listbox"`), and the list of roles is never finished.
|
|
27
|
+
*
|
|
28
|
+
* An IME composition counts as handled too: Escape while composing Japanese or
|
|
29
|
+
* Chinese text cancels the composition, and must not close a panel.
|
|
30
|
+
*/
|
|
31
|
+
function isKeyHandled(event) {
|
|
32
|
+
return event.defaultPrevented || event.isComposing;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { isKeyHandled };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=keys.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.es.js","names":[],"sources":["../../src/util/keys.ts"],"sourcesContent":["/**\n * Whether a key event has already been handled by something above you — the\n * one question every global key handler (a `keydown` listener on `window` or\n * `document`) must ask before acting.\n *\n * The rule: **a handler that acts on a key calls `event.preventDefault()`;\n * a global handler that finds the event already handled does nothing.** Every\n * kit overlay follows it for free — `Dialog`, `Sheet`, `Popover`, `Menu`,\n * `Select`, `MultiSelect`, `Tooltip` are Radix layers, and a Radix layer calls\n * `preventDefault()` on the Escape it consumes to close itself. So Escape\n * pressed in an open dropdown closes the dropdown, and the record panel's\n * Escape handler underneath sees it handled and leaves the record open.\n *\n * Two conditions make it hold:\n *\n * - **Listen in the bubble phase.** A Radix layer listens on `document` in\n * the capture phase, so it has run before any bubble listener — on the\n * target, on `document` or on `window` — whatever order they were added in.\n * A capture listener added before the layer opened runs *before* it and\n * cannot see its claim. Only a layer of your own, one that sits above\n * everything else while it is open, belongs in the capture phase, and it\n * must call `preventDefault()` when it acts.\n * - **Do not ask the DOM instead.** `document.querySelector('[role=\"dialog\"]')`\n * misses every layer that is not a dialog (a menu is `role=\"menu\"`, a select\n * list `role=\"listbox\"`), and the list of roles is never finished.\n *\n * An IME composition counts as handled too: Escape while composing Japanese or\n * Chinese text cancels the composition, and must not close a panel.\n */\nexport function isKeyHandled(event: KeyboardEvent): boolean {\n return event.defaultPrevented || event.isComposing;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgB,aAAa,OAA+B;CACxD,OAAO,MAAM,oBAAoB,MAAM;AAC3C"}
|