@ciridae/ui 1.0.3 → 1.0.4
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/chat/conversation-source.d.ts +15 -1
- package/dist/chat/describe-tool-call.d.ts +3 -3
- package/dist/chat/describe-tool-call.js +3 -3
- package/dist/chat/message-text.js +2 -2
- package/dist/ciridae.css +16 -4
- package/dist/components/activity-feed.d.ts +1 -0
- package/dist/components/activity-feed.js +1 -0
- package/dist/components/app-frame.d.ts +13 -1
- package/dist/components/app-frame.js +45 -3
- package/dist/components/app-navigation.d.ts +28 -1
- package/dist/components/app-navigation.js +105 -14
- package/dist/components/badge.d.ts +29 -4
- package/dist/components/badge.js +134 -15
- package/dist/components/bulk-action-bar.js +3 -3
- package/dist/components/button.d.ts +10 -3
- package/dist/components/button.js +77 -44
- package/dist/components/calendar.js +44 -17
- package/dist/components/centered-page.js +2 -2
- package/dist/components/chart.d.ts +1 -1
- package/dist/components/chart.js +16 -11
- package/dist/components/chat-client-source.js +47 -6
- package/dist/components/chat-sheet-controller.d.ts +1 -0
- package/dist/components/chat-sheet-controller.js +1 -0
- package/dist/components/chat-sheet.d.ts +10 -2
- package/dist/components/chat-sheet.js +76 -39
- package/dist/components/chat.d.ts +90 -14
- package/dist/components/chat.js +402 -101
- package/dist/components/checkbox-item.d.ts +5 -2
- package/dist/components/checkbox-item.js +9 -5
- package/dist/components/chip.d.ts +5 -0
- package/dist/components/chip.js +27 -1
- package/dist/components/column-settings.js +1 -1
- package/dist/components/command-menu.d.ts +5 -1
- package/dist/components/command-menu.js +98 -32
- package/dist/components/command-palette.d.ts +6 -2
- package/dist/components/command-palette.js +20 -10
- package/dist/components/data-display.d.ts +35 -4
- package/dist/components/data-display.js +138 -19
- package/dist/components/data-grid.d.ts +14 -2
- package/dist/components/data-grid.js +61 -26
- package/dist/components/date-range-picker.js +9 -20
- package/dist/components/drawer.d.ts +5 -0
- package/dist/components/drawer.js +91 -54
- package/dist/components/editable-field.d.ts +12 -3
- package/dist/components/editable-field.js +57 -27
- package/dist/components/email-input.js +6 -5
- package/dist/components/environment-frame.d.ts +1 -1
- package/dist/components/environment-frame.js +37 -6
- package/dist/components/filter-bar.js +39 -28
- package/dist/components/form-controls.d.ts +9 -0
- package/dist/components/form-controls.js +46 -22
- package/dist/components/form-layout.d.ts +7 -3
- package/dist/components/form-layout.js +68 -23
- package/dist/components/glass-menu.d.ts +3 -0
- package/dist/components/glass-menu.js +63 -0
- package/dist/components/gradient-edge.d.ts +9 -0
- package/dist/components/gradient-edge.js +31 -0
- package/dist/components/input.d.ts +4 -2
- package/dist/components/input.js +26 -15
- package/dist/components/keycap.d.ts +9 -5
- package/dist/components/keycap.js +57 -19
- package/dist/components/lightbox.js +2 -1
- package/dist/components/locale.d.ts +10 -0
- package/dist/components/locale.js +18 -2
- package/dist/components/log-entry.d.ts +40 -0
- package/dist/components/log-entry.js +146 -0
- package/dist/components/mention-input.js +4 -3
- package/dist/components/menu.d.ts +6 -2
- package/dist/components/menu.js +34 -37
- package/dist/components/meter.d.ts +9 -1
- package/dist/components/meter.js +64 -6
- package/dist/components/navigation.d.ts +21 -4
- package/dist/components/navigation.js +84 -19
- package/dist/components/notification-tray.js +5 -4
- package/dist/components/overlays.d.ts +3 -1
- package/dist/components/overlays.js +69 -40
- package/dist/components/page-frame.js +1 -1
- package/dist/components/panel.d.ts +1 -1
- package/dist/components/panel.js +18 -12
- package/dist/components/radio-card.js +10 -9
- package/dist/components/record.d.ts +25 -1
- package/dist/components/record.js +147 -18
- package/dist/components/segmented-bar.d.ts +3 -1
- package/dist/components/segmented-bar.js +16 -6
- package/dist/components/select.d.ts +5 -2
- package/dist/components/select.js +103 -127
- package/dist/components/shell-skeleton.js +1 -1
- package/dist/components/shell.d.ts +2 -2
- package/dist/components/shell.js +43 -45
- package/dist/components/sidebar.d.ts +7 -2
- package/dist/components/sidebar.js +55 -27
- package/dist/components/single-line-text.d.ts +2 -0
- package/dist/components/single-line-text.js +16 -0
- package/dist/components/site-banner.d.ts +5 -2
- package/dist/components/site-banner.js +17 -6
- package/dist/components/skeleton.d.ts +7 -6
- package/dist/components/skeleton.js +28 -16
- package/dist/components/skeletons.d.ts +12 -0
- package/dist/components/skeletons.js +71 -8
- package/dist/components/stages.d.ts +78 -6
- package/dist/components/stages.js +512 -156
- package/dist/components/stat-card.d.ts +10 -2
- package/dist/components/stat-card.js +92 -37
- package/dist/components/status-banner.js +1 -1
- package/dist/components/tabs.js +26 -13
- package/dist/components/theme-toggle.d.ts +4 -0
- package/dist/components/theme-toggle.js +67 -0
- package/dist/components/toast.d.ts +9 -2
- package/dist/components/toast.js +78 -29
- package/dist/preset.js +289 -33
- package/dist/styled-system/styles.css +3115 -1044
- package/dist/styled-system/tokens/index.mjs +598 -22
- package/dist/styled-system/tokens/tokens.d.ts +11 -11
- package/dist/styled-system/types/prop-type.d.ts +2 -2
- package/dist/styles.css +16 -4
- package/dist/theme/color.d.ts +3 -0
- package/dist/theme/color.js +5 -0
- package/dist/theme/derive.d.ts +9 -2
- package/dist/theme/derive.js +72 -12
- package/dist/theme/palettes.d.ts +49 -6
- package/dist/theme/palettes.js +84 -15
- package/dist/theme/tokens.d.ts +3 -3
- package/dist/theme/tokens.js +107 -32
- package/package.json +9 -1
|
@@ -11,14 +11,16 @@ import { useCiridaeLocale } from "./locale.js";
|
|
|
11
11
|
import { Popover } from "./overlays.js";
|
|
12
12
|
const root = css({ display: "flex", flexDirection: "column", gap: "layout.sectionGap" });
|
|
13
13
|
const bar = css({ display: "flex", gap: "layout.tightGap", height: "8px" });
|
|
14
|
+
// The chart's data marks, so a segment and its swatch match the series in a chart.
|
|
14
15
|
const toneColor = cva({
|
|
15
16
|
variants: {
|
|
16
17
|
tone: {
|
|
17
|
-
neutral: { background: "
|
|
18
|
-
info: { background: "
|
|
19
|
-
success: { background: "
|
|
20
|
-
warning: { background: "
|
|
21
|
-
|
|
18
|
+
neutral: { background: "chart.neutral" },
|
|
19
|
+
info: { background: "chart.trend" },
|
|
20
|
+
success: { background: "chart.category2" },
|
|
21
|
+
warning: { background: "chart.category1" },
|
|
22
|
+
indigo: { background: "chart.category3" },
|
|
23
|
+
danger: { background: "chart.category4" },
|
|
22
24
|
},
|
|
23
25
|
},
|
|
24
26
|
});
|
|
@@ -42,7 +44,15 @@ const legendRow = css({
|
|
|
42
44
|
paddingTop: "panel.comfortable",
|
|
43
45
|
borderTop: "1px solid token(colors.border.panel)",
|
|
44
46
|
});
|
|
45
|
-
const legendItem = css({
|
|
47
|
+
const legendItem = css({
|
|
48
|
+
display: "inline-flex",
|
|
49
|
+
alignItems: "center",
|
|
50
|
+
gap: "layout.contentGap",
|
|
51
|
+
color: "fg.primary",
|
|
52
|
+
fontSize: "body",
|
|
53
|
+
fontWeight: "medium",
|
|
54
|
+
lineHeight: "tight",
|
|
55
|
+
});
|
|
46
56
|
const legendKey = css({
|
|
47
57
|
display: "inline-flex",
|
|
48
58
|
alignItems: "center",
|
|
@@ -18,8 +18,11 @@ export type SelectProps = {
|
|
|
18
18
|
label?: string;
|
|
19
19
|
/** `medium` is the Round 2 field height; `small` is the pill beside other filters. */
|
|
20
20
|
size?: ControlSize;
|
|
21
|
-
/**
|
|
22
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Defaults to the flat `field` at medium and the glass `raised` face when small. `underline` is
|
|
23
|
+
* a 34px row control at the body size, such as a table footer's rows per page, whatever `size`.
|
|
24
|
+
*/
|
|
25
|
+
variant?: "field" | "raised" | "underline";
|
|
23
26
|
/** Submits the value with an enclosing form under this name. */
|
|
24
27
|
name?: string;
|
|
25
28
|
/** Blocks the enclosing form's submission until a value is chosen. */
|
|
@@ -1,51 +1,24 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Combobox as BaseCombobox } from "@base-ui/react/combobox";
|
|
3
3
|
import { Select as BaseSelect } from "@base-ui/react/select";
|
|
4
|
-
import { CaretDownIcon,
|
|
4
|
+
import { CaretDownIcon, CheckIcon, FunnelSimpleIcon } from "@phosphor-icons/react";
|
|
5
5
|
import { useDebouncedCallback } from "@tanstack/react-pacer";
|
|
6
6
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
7
|
-
import {
|
|
7
|
+
import { useEffect, useRef, useState } from "react";
|
|
8
8
|
import { css, cva, cx } from "#primitives/css";
|
|
9
9
|
import { Button } from "./button.js";
|
|
10
10
|
import { useFieldControl, useInField } from "./field-context.js";
|
|
11
|
+
import { glassMenuDivider, glassMenuRow, glassMenuSurface } from "./glass-menu.js";
|
|
12
|
+
import { faceEdge } from "./gradient-edge.js";
|
|
11
13
|
import { HotkeyLayer } from "./hotkeys.js";
|
|
12
14
|
import { icon, Spinner } from "./icon.js";
|
|
13
15
|
import { useCiridaeLocale } from "./locale.js";
|
|
14
16
|
import { Popover } from "./overlays.js";
|
|
15
|
-
/*
|
|
16
|
-
* Open, a trigger and its menu read as one control: the menu sits flush on the trigger's edge, and
|
|
17
|
-
* the corners and border where they meet go square and quiet, on whichever side the menu opened.
|
|
18
|
-
*/
|
|
19
|
-
const attachedTrigger = {
|
|
20
|
-
"&[data-popup-open][data-popup-side=bottom]": {
|
|
21
|
-
borderBottomLeftRadius: "0",
|
|
22
|
-
borderBottomRightRadius: "0",
|
|
23
|
-
borderBottomColor: "border.subtle",
|
|
24
|
-
},
|
|
25
|
-
"&[data-popup-open][data-popup-side=top]": {
|
|
26
|
-
borderTopLeftRadius: "0",
|
|
27
|
-
borderTopRightRadius: "0",
|
|
28
|
-
borderTopColor: "border.subtle",
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
/** Which side of its trigger the open popup sits on, read from the popup's own `data-side`. */
|
|
32
|
-
function usePopupSide() {
|
|
33
|
-
const [side, setSide] = useState(null);
|
|
34
|
-
const popupRef = useCallback((popup) => {
|
|
35
|
-
if (!popup)
|
|
36
|
-
return;
|
|
37
|
-
const read = () => setSide(popup.getAttribute("data-side"));
|
|
38
|
-
read();
|
|
39
|
-
const observer = new MutationObserver(read);
|
|
40
|
-
observer.observe(popup, { attributes: true, attributeFilter: ["data-side"] });
|
|
41
|
-
return () => observer.disconnect();
|
|
42
|
-
}, []);
|
|
43
|
-
return { side: side ?? undefined, popupRef };
|
|
44
|
-
}
|
|
45
17
|
/*
|
|
46
18
|
* Round 2 draws three select triggers. `field` is the input's flat well, for a form. `raised` is
|
|
47
|
-
* the glass face of a toolbar control; at the compact size it is a pill.
|
|
48
|
-
* control
|
|
19
|
+
* the glass face of a toolbar control; at the compact size it is a pill. `underline` has no face,
|
|
20
|
+
* only a bottom hairline, for a control set in a row such as a table footer. Open, every one draws
|
|
21
|
+
* its edge in the text color, and its menu floats just below it.
|
|
49
22
|
*/
|
|
50
23
|
const trigger = cva({
|
|
51
24
|
base: {
|
|
@@ -64,19 +37,40 @@ const trigger = cva({
|
|
|
64
37
|
cursor: "pointer",
|
|
65
38
|
transitionProperty: "background, border-color",
|
|
66
39
|
transitionDuration: "fast",
|
|
67
|
-
"&[data-popup-open]": { borderColor: "
|
|
68
|
-
...attachedTrigger,
|
|
40
|
+
"&[data-popup-open]": { borderColor: "fg.primary" },
|
|
69
41
|
_focusVisible: { focusRing: "outer" },
|
|
70
42
|
"&:disabled, &[data-disabled]": { opacity: "disabled", cursor: "not-allowed" },
|
|
71
43
|
},
|
|
72
44
|
variants: {
|
|
73
45
|
variant: {
|
|
74
|
-
|
|
75
|
-
|
|
46
|
+
// Hovered, the well darkens by the control hover layer, in light only.
|
|
47
|
+
field: {
|
|
48
|
+
background: "bg.formField",
|
|
49
|
+
borderColor: "border.control",
|
|
50
|
+
_hover: {
|
|
51
|
+
background: "linear-gradient(token(colors.bg.controlHover), token(colors.bg.controlHover)), token(colors.bg.formField)",
|
|
52
|
+
},
|
|
53
|
+
// Open, the well rests under the pointer too; only the edge changes.
|
|
54
|
+
"&[data-popup-open]:hover": { background: "bg.formField" },
|
|
55
|
+
},
|
|
56
|
+
/*
|
|
57
|
+
* The hairline is `toolbarEdge` on the trigger; the border stays clear for it. The face is
|
|
58
|
+
* the selected tint, and hovers to the raised face.
|
|
59
|
+
*/
|
|
76
60
|
raised: {
|
|
77
|
-
background: "
|
|
61
|
+
background: "token(gradients.selected)",
|
|
78
62
|
borderColor: "transparent",
|
|
79
|
-
_hover: { background: "
|
|
63
|
+
_hover: { background: "token(gradients.raisedHover)" },
|
|
64
|
+
// Open, the face rests under the pointer too; only the edge changes.
|
|
65
|
+
"&[data-popup-open]:hover": { background: "token(gradients.selected)" },
|
|
66
|
+
},
|
|
67
|
+
// The caret takes the secondary ink beside the value.
|
|
68
|
+
underline: {
|
|
69
|
+
borderWidth: "0 0 1px",
|
|
70
|
+
borderColor: "border.control",
|
|
71
|
+
borderRadius: "0",
|
|
72
|
+
background: "transparent",
|
|
73
|
+
"& svg": { color: "fg.muted" },
|
|
80
74
|
},
|
|
81
75
|
},
|
|
82
76
|
size: {
|
|
@@ -90,83 +84,69 @@ const trigger = cva({
|
|
|
90
84
|
},
|
|
91
85
|
},
|
|
92
86
|
compoundVariants: [
|
|
93
|
-
{ variant: "raised", size: "compact", css: { borderRadius: "
|
|
87
|
+
{ variant: "raised", size: "compact", css: { borderRadius: "pill" } },
|
|
94
88
|
{ variant: "raised", size: "regular", css: { gap: "layout.controlGap" } },
|
|
89
|
+
// A row's height at the body size, sized to its value.
|
|
90
|
+
{
|
|
91
|
+
variant: "underline",
|
|
92
|
+
size: "regular",
|
|
93
|
+
css: {
|
|
94
|
+
minWidth: "auto",
|
|
95
|
+
height: "control.row",
|
|
96
|
+
paddingInline: "layout.tightGap",
|
|
97
|
+
gap: "layout.controlGap",
|
|
98
|
+
},
|
|
99
|
+
},
|
|
95
100
|
],
|
|
96
101
|
defaultVariants: { variant: "field", size: "regular" },
|
|
97
102
|
});
|
|
103
|
+
const toolbarEdge = faceEdge("toolbar");
|
|
98
104
|
/** The positioner is the positioned element, so it carries the stacking order. */
|
|
99
105
|
const positioner = css({ zIndex: "popover" });
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
/** How far a menu floats from its trigger, in px. */
|
|
107
|
+
const menuGap = 4;
|
|
108
|
+
/* The menu floats on the glass sheet just below its trigger, at least the trigger's width. A
|
|
109
|
+
compact trigger is sized to its value, so its menu may run wider to keep every option whole. A
|
|
102
110
|
long list stops at `overlay.menuList`, or the room left in the viewport, and scrolls inside. */
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
maxHeight: "min(token(sizes.overlay.menuList), var(--available-height))",
|
|
109
|
-
padding: "none",
|
|
110
|
-
overflow: "hidden",
|
|
111
|
-
border: "1px solid token(colors.border.control)",
|
|
112
|
-
background: "bg.card",
|
|
113
|
-
boxShadow: "card",
|
|
114
|
-
"&[data-side=bottom]": { borderTop: "0", borderTopLeftRadius: "0", borderTopRightRadius: "0" },
|
|
115
|
-
"&[data-side=top]": {
|
|
116
|
-
borderBottom: "0",
|
|
117
|
-
borderBottomLeftRadius: "0",
|
|
118
|
-
borderBottomRightRadius: "0",
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
// The trigger's own corners: a field's near-square ones, a compact pill's rounder ones. A compact
|
|
122
|
-
// trigger is sized to its value, so its menu may run wider to keep every option whole.
|
|
123
|
-
variants: {
|
|
124
|
-
size: {
|
|
125
|
-
regular: { borderRadius: "control" },
|
|
126
|
-
compact: { borderRadius: "action", width: "max-content", minWidth: "var(--anchor-width)" },
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
defaultVariants: { size: "regular" },
|
|
111
|
+
const popupStyle = css.raw(glassMenuSurface, {
|
|
112
|
+
display: "flex",
|
|
113
|
+
flexDirection: "column",
|
|
114
|
+
width: "var(--anchor-width)",
|
|
115
|
+
maxHeight: "min(token(sizes.overlay.menuList), var(--available-height))",
|
|
130
116
|
});
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
cursor: "pointer",
|
|
142
|
-
_highlighted: { background: "bg.rowHover", color: "fg.primary" },
|
|
143
|
-
"&[data-selected]": { color: "fg.primary" },
|
|
144
|
-
// The menu is only as wide as its trigger, so a long option truncates rather than widening it.
|
|
145
|
-
"& > :first-child": { minWidth: "0", overflow: "hidden", textOverflow: "ellipsis" },
|
|
146
|
-
whiteSpace: "nowrap",
|
|
147
|
-
},
|
|
148
|
-
// A compact trigger's menu reads at the trigger's own text size.
|
|
149
|
-
variants: {
|
|
150
|
-
size: { regular: {}, compact: { height: "select.compactItem" } },
|
|
151
|
-
},
|
|
152
|
-
defaultVariants: { size: "compact" },
|
|
117
|
+
const compactPopupStyle = css.raw({ width: "max-content", minWidth: "var(--anchor-width)" });
|
|
118
|
+
const popup = {
|
|
119
|
+
regular: css(popupStyle),
|
|
120
|
+
compact: css(popupStyle, compactPopupStyle),
|
|
121
|
+
};
|
|
122
|
+
const itemStyle = css.raw(glassMenuRow, {
|
|
123
|
+
justifyContent: "space-between",
|
|
124
|
+
// The menu is only as wide as its trigger, so a long option truncates rather than widening it.
|
|
125
|
+
"& > :first-child": { minWidth: "0", overflow: "hidden", textOverflow: "ellipsis" },
|
|
126
|
+
whiteSpace: "nowrap",
|
|
153
127
|
});
|
|
128
|
+
// A compact trigger's menu reads at the trigger's own text size.
|
|
129
|
+
const item = {
|
|
130
|
+
regular: css(itemStyle),
|
|
131
|
+
compact: css(itemStyle, { fontSize: "caption" }),
|
|
132
|
+
};
|
|
154
133
|
const itemIndicator = css({ display: "inline-flex", flexShrink: "0" });
|
|
155
134
|
/** Scrolls inside the capped popup; opening scrolls the chosen option into view. */
|
|
156
|
-
const list = css({ overflowY: "auto", overscrollBehavior: "contain" });
|
|
135
|
+
const list = css({ overflowY: "auto", overscrollBehavior: "contain", ringRoom: true });
|
|
157
136
|
function density(size) {
|
|
158
137
|
return size === "small" ? "compact" : "regular";
|
|
159
138
|
}
|
|
160
|
-
function SelectMenu({ options,
|
|
161
|
-
return (_jsx(BaseSelect.Portal, { children: _jsx(HotkeyLayer, { children: _jsx(BaseSelect.Positioner, { className: positioner, sideOffset:
|
|
139
|
+
function SelectMenu({ options, popupClassName, itemClassName, }) {
|
|
140
|
+
return (_jsx(BaseSelect.Portal, { children: _jsx(HotkeyLayer, { children: _jsx(BaseSelect.Positioner, { className: positioner, sideOffset: menuGap, align: "start", alignItemWithTrigger: false, children: _jsx(BaseSelect.Popup, { className: popupClassName, "data-ciridae-ui": "", children: _jsx(BaseSelect.List, { className: list, children: options.map((option) => (_jsxs(BaseSelect.Item, { className: itemClassName, value: option.value, children: [_jsx(BaseSelect.ItemText, { children: option.label }), _jsx(BaseSelect.ItemIndicator, { className: itemIndicator, children: _jsx(CheckIcon, { className: icon({ size: "small" }) }) })] }, option.value))) }) }) }) }) }));
|
|
162
141
|
}
|
|
163
142
|
export function Select({ options, value, onValueChange, placeholder, label, size: controlSize = "small", variant = controlSize === "small" ? "raised" : "field", name, required, disabled, }) {
|
|
164
|
-
const { side, popupRef } = usePopupSide();
|
|
165
143
|
const { labels } = useCiridaeLocale();
|
|
166
144
|
const fieldIds = useFieldControl({});
|
|
167
145
|
const inField = useInField();
|
|
168
|
-
const
|
|
169
|
-
|
|
146
|
+
const underline = variant === "underline";
|
|
147
|
+
// An underline trigger is sized to its value, so its menu may run wider, at its body text.
|
|
148
|
+
const size = underline ? "regular" : density(controlSize);
|
|
149
|
+
return (_jsxs(BaseSelect.Root, { items: options, value: value, onValueChange: onValueChange, name: name, required: required, disabled: disabled, children: [_jsxs(BaseSelect.Trigger, { ...fieldIds, className: cx(trigger({ variant, size }), variant === "raised" && toolbarEdge.className), "aria-label": label ?? (inField ? undefined : labels.select.label), "data-ciridae-ui": "", "data-edge": variant === "raised" ? toolbarEdge["data-edge"] : undefined, children: [_jsx(BaseSelect.Value, { placeholder: placeholder ?? labels.select.placeholder }), _jsx(BaseSelect.Icon, { children: _jsx(CaretDownIcon, { className: icon({ size: "small" }) }) })] }), _jsx(SelectMenu, { options: options, popupClassName: underline ? popup.compact : popup[size], itemClassName: item[size] })] }));
|
|
170
150
|
}
|
|
171
151
|
/*
|
|
172
152
|
* A slicer is a filter's pill: the dimension it cuts by, then the value chosen, then the caret.
|
|
@@ -174,11 +154,10 @@ export function Select({ options, value, onValueChange, placeholder, label, size
|
|
|
174
154
|
*/
|
|
175
155
|
const slicerTrigger = css({
|
|
176
156
|
height: "control.compact",
|
|
177
|
-
borderRadius: "action",
|
|
178
157
|
fontSize: "caption",
|
|
179
158
|
justifyContent: "flex-start",
|
|
180
159
|
});
|
|
181
|
-
const slicerLabel = css({ color: "fg.muted" });
|
|
160
|
+
const slicerLabel = css({ color: "fg.muted", _light: { color: "fg.secondary" } });
|
|
182
161
|
const slicerValue = css({ flex: "1", textAlign: "start" });
|
|
183
162
|
/** A combobox role takes no name from its content, so a slicer names its dimension and value. */
|
|
184
163
|
function slicerName(label, options, value) {
|
|
@@ -186,12 +165,11 @@ function slicerName(label, options, value) {
|
|
|
186
165
|
return chosen ? `${label}: ${chosen.label}` : label;
|
|
187
166
|
}
|
|
188
167
|
export function Slicer({ options, value, onValueChange, label, name, required, disabled, }) {
|
|
189
|
-
|
|
190
|
-
return (_jsxs(BaseSelect.Root, { items: options, value: value, onValueChange: onValueChange, name: name, required: required, disabled: disabled, children: [_jsxs(BaseSelect.Trigger, { className: cx(trigger({ variant: "raised", size: "compact" }), slicerTrigger), "aria-label": slicerName(label, options, value), "data-ciridae-ui": "", "data-edge": "toolbar", "data-popup-side": side, children: [_jsx("span", { className: slicerLabel, "data-slicer-label": "", children: label }), _jsx(BaseSelect.Value, { className: slicerValue }), _jsx(BaseSelect.Icon, { children: _jsx(CaretDownIcon, { className: icon({ size: "small" }) }) })] }), _jsx(SelectMenu, { options: options, size: "compact", popupRef: popupRef })] }));
|
|
168
|
+
return (_jsxs(BaseSelect.Root, { items: options, value: value, onValueChange: onValueChange, name: name, required: required, disabled: disabled, children: [_jsxs(BaseSelect.Trigger, { className: cx(trigger({ variant: "raised", size: "compact" }), slicerTrigger, toolbarEdge.className), "aria-label": slicerName(label, options, value), "data-ciridae-ui": "", "data-edge": toolbarEdge["data-edge"], children: [_jsx("span", { className: slicerLabel, "data-slicer-label": "", children: label }), _jsx(BaseSelect.Value, { className: slicerValue }), _jsx(BaseSelect.Icon, { children: _jsx(CaretDownIcon, { className: icon({ size: "small" }) }) })] }), _jsx(SelectMenu, { options: options, popupClassName: popup.compact, itemClassName: item.compact })] }));
|
|
191
169
|
}
|
|
192
|
-
/* A regular combobox is a field: the well holds the typed query and a caret, and open,
|
|
193
|
-
|
|
194
|
-
the focus. */
|
|
170
|
+
/* A regular combobox is a field: the well holds the typed query and a caret, and open, its edge
|
|
171
|
+
goes to the text color as a `Select`'s does. The ring shows only while closed, since open the
|
|
172
|
+
menu is the focus. */
|
|
195
173
|
const comboboxField = css({
|
|
196
174
|
display: "flex",
|
|
197
175
|
alignItems: "center",
|
|
@@ -200,8 +178,8 @@ const comboboxField = css({
|
|
|
200
178
|
height: "control.default",
|
|
201
179
|
border: "1px solid token(colors.border.control)",
|
|
202
180
|
borderRadius: "control",
|
|
203
|
-
background: "bg.
|
|
204
|
-
|
|
181
|
+
background: "bg.formField",
|
|
182
|
+
"&[data-popup-open]": { borderColor: "fg.primary" },
|
|
205
183
|
"&:has(input:focus-visible):not([data-popup-open])": { focusRing: "outer" },
|
|
206
184
|
"&[data-disabled]": { opacity: "disabled", cursor: "not-allowed" },
|
|
207
185
|
});
|
|
@@ -234,22 +212,19 @@ const comboboxCaret = css({
|
|
|
234
212
|
"&:disabled": { cursor: "not-allowed" },
|
|
235
213
|
});
|
|
236
214
|
/* A compact combobox is a slicer that searches: the same pill, with the query typed in a row at
|
|
237
|
-
the top of its menu. The menu keeps one width while typing narrows it. */
|
|
238
|
-
const comboboxPopup =
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
},
|
|
245
|
-
});
|
|
215
|
+
the top of its menu over a divider. The menu keeps one width while typing narrows it. */
|
|
216
|
+
const comboboxPopup = {
|
|
217
|
+
regular: popup.regular,
|
|
218
|
+
compact: css(popupStyle, compactPopupStyle, {
|
|
219
|
+
width: "max(var(--anchor-width), token(sizes.overlay.menu))",
|
|
220
|
+
}),
|
|
221
|
+
};
|
|
246
222
|
const comboboxSearch = css({
|
|
247
223
|
flexShrink: "0",
|
|
248
224
|
width: "100%",
|
|
249
|
-
height: "
|
|
250
|
-
paddingInline: "
|
|
225
|
+
height: "control.compact",
|
|
226
|
+
paddingInline: "search.inline",
|
|
251
227
|
border: "0",
|
|
252
|
-
borderBottom: "1px solid token(colors.border.subtle)",
|
|
253
228
|
background: "transparent",
|
|
254
229
|
color: "fg.primary",
|
|
255
230
|
fontFamily: "sans",
|
|
@@ -268,9 +243,10 @@ const optionContent = css({
|
|
|
268
243
|
overflow: "hidden",
|
|
269
244
|
textOverflow: "ellipsis",
|
|
270
245
|
});
|
|
246
|
+
const searchDivider = css(glassMenuDivider);
|
|
271
247
|
const emptyMessageStyle = css({
|
|
272
248
|
paddingBlock: "control.compactBlock",
|
|
273
|
-
paddingInline: "
|
|
249
|
+
paddingInline: "menu.itemInline",
|
|
274
250
|
color: "fg.muted",
|
|
275
251
|
fontSize: "caption",
|
|
276
252
|
// Base UI keeps the empty slot mounted while options are listed.
|
|
@@ -313,12 +289,12 @@ export function Combobox({ options, value, onValueChange, placeholder: ownPlaceh
|
|
|
313
289
|
if (details.reason === "input-change" || details.reason === "input-clear")
|
|
314
290
|
search(input);
|
|
315
291
|
},
|
|
316
|
-
}), children: [size === "compact" ? (_jsxs(BaseCombobox.Trigger, { className: cx(trigger({ variant: "raised", size: "compact" }), slicerTrigger), "aria-label": slicerName(label, options, value), "data-ciridae-ui": "", "data-edge": "
|
|
292
|
+
}), children: [size === "compact" ? (_jsxs(BaseCombobox.Trigger, { className: cx(trigger({ variant: "raised", size: "compact" }), slicerTrigger, toolbarEdge.className), "aria-label": slicerName(label, options, value), "data-ciridae-ui": "", "data-edge": toolbarEdge["data-edge"], children: [_jsx("span", { className: slicerLabel, "data-slicer-label": "", children: label }), _jsx("span", { className: slicerValue, children: selected?.label }), _jsx(CaretDownIcon, { className: icon({ size: "small" }) })] })) : (_jsxs(BaseCombobox.InputGroup, { className: comboboxField, "data-ciridae-ui": "", children: [_jsx(BaseCombobox.Input, { ...fieldIds, className: comboboxInput, "aria-label": inputLabel, placeholder: placeholder, autoFocus: autoFocus }), _jsx(BaseCombobox.Trigger, { className: comboboxCaret, "aria-label": label, tabIndex: -1, children: _jsx(CaretDownIcon, { className: icon({ size: "small" }) }) })] })), _jsx(BaseCombobox.Portal, { children: _jsx(HotkeyLayer, { children: _jsx(BaseCombobox.Positioner, { className: positioner, sideOffset: menuGap, align: "start", children: _jsxs(BaseCombobox.Popup, { className: comboboxPopup[size], "data-ciridae-ui": "", children: [size === "compact" && (_jsxs(_Fragment, { children: [_jsx(BaseCombobox.Input, { className: comboboxSearch, "aria-label": label, placeholder: placeholder }), _jsx("div", { className: searchDivider })] })), loading ? (_jsx("div", { className: emptyMessageStyle, children: _jsx(Spinner, { size: "compact" }) })) : (_jsx(BaseCombobox.Empty, { className: emptyMessageStyle, children: emptyMessage ?? labels.common.noResults })), virtualized ? (_jsx(VirtualOptions, { size: size, renderOption: renderOption, scrollToOption: scrollToOption })) : (_jsx(BaseCombobox.List, { className: list, children: (option) => (_jsxs(BaseCombobox.Item, { className: item[size], value: option, children: [_jsx("span", { className: optionContent, children: renderOption ? renderOption(option) : option.label }), _jsx(BaseCombobox.ItemIndicator, { className: itemIndicator, children: _jsx(CheckIcon, { className: icon({ size: "small" }) }) })] }, option.value)) }))] }) }) }) })] }));
|
|
317
293
|
}
|
|
318
294
|
/** Past this many options a combobox draws only those near the view. */
|
|
319
295
|
const virtualizeOptionsPast = 50;
|
|
320
|
-
/** An option row's height before it is measured. */
|
|
321
|
-
const
|
|
296
|
+
/** An option row's height before it is measured, in px. */
|
|
297
|
+
const optionHeight = 32;
|
|
322
298
|
// The options lie over a box as tall as all of them, each moved down to its place.
|
|
323
299
|
const virtualOptions = css({
|
|
324
300
|
position: "relative",
|
|
@@ -331,7 +307,7 @@ function VirtualOptions({ size, renderOption, scrollToOption, }) {
|
|
|
331
307
|
const virtualizer = useVirtualizer({
|
|
332
308
|
count: shown.length,
|
|
333
309
|
getScrollElement: () => listElement,
|
|
334
|
-
estimateSize: () =>
|
|
310
|
+
estimateSize: () => optionHeight,
|
|
335
311
|
getItemKey: (index) => shown[index]?.value ?? index,
|
|
336
312
|
overscan: 8,
|
|
337
313
|
});
|
|
@@ -343,7 +319,7 @@ function VirtualOptions({ size, renderOption, scrollToOption, }) {
|
|
|
343
319
|
}, [scrollToOption, virtualizer]);
|
|
344
320
|
return (_jsx(BaseCombobox.List, { ref: setListElement, className: list, children: _jsx("div", { className: virtualOptions, style: { height: virtualizer.getTotalSize() }, children: virtualizer.getVirtualItems().map((virtualItem) => {
|
|
345
321
|
const option = shown[virtualItem.index];
|
|
346
|
-
return (option && (_jsxs(BaseCombobox.Item, { ref: virtualizer.measureElement, "data-index": virtualItem.index, index: virtualItem.index, value: option, className: item
|
|
322
|
+
return (option && (_jsxs(BaseCombobox.Item, { ref: virtualizer.measureElement, "data-index": virtualItem.index, index: virtualItem.index, value: option, className: item[size], style: { transform: `translateY(${virtualItem.start}px)` }, children: [_jsx("span", { className: optionContent, children: renderOption ? renderOption(option) : option.label }), _jsx(BaseCombobox.ItemIndicator, { className: itemIndicator, children: _jsx(CheckIcon, { className: icon({ size: "small" }) }) })] }, option.value)));
|
|
347
323
|
}) }) }));
|
|
348
324
|
}
|
|
349
325
|
/*
|
|
@@ -370,5 +346,5 @@ const filterStack = css({
|
|
|
370
346
|
});
|
|
371
347
|
export function FilterPopover({ label, count = 0, open, onOpenChange, onClear, children, }) {
|
|
372
348
|
const { labels } = useCiridaeLocale();
|
|
373
|
-
return (_jsx(Popover, { open: open, onOpenChange: onOpenChange && ((next) => onOpenChange(next)), density: "compact", trigger: _jsxs("button", { type: "button", className: cx(trigger({ variant: "raised", size: "compact" }), slicerTrigger), "data-ciridae-ui": "", "data-edge": "
|
|
349
|
+
return (_jsx(Popover, { open: open, onOpenChange: onOpenChange && ((next) => onOpenChange(next)), density: "compact", trigger: _jsxs("button", { type: "button", className: cx(trigger({ variant: "raised", size: "compact" }), slicerTrigger, toolbarEdge.className), "data-ciridae-ui": "", "data-edge": toolbarEdge["data-edge"], children: [_jsx(FunnelSimpleIcon, { className: icon({ size: "small" }) }), label ?? labels.select.filters, count > 0 && _jsx("span", { className: filterCount, children: count })] }), children: _jsxs("div", { className: filterStack, children: [children, onClear && count > 0 && (_jsx(Button, { variant: "ghost", className: css({ justifySelf: "start" }), onClick: onClear, children: labels.filters.clearAll }))] }) }));
|
|
374
350
|
}
|
|
@@ -11,5 +11,5 @@ import { PanelSkeleton, SidebarRowsSkeleton } from "./skeletons.js";
|
|
|
11
11
|
/** Names itself for assistive tech with the locale's "Loading" unless given an `aria-label`. */
|
|
12
12
|
export function ShellSkeleton({ children, ...props }) {
|
|
13
13
|
const { labels } = useCiridaeLocale();
|
|
14
|
-
return (_jsxs(AppShell, { "aria-busy": "true", "aria-label": labels.common.loading, ...props, children: [_jsxs(AppSidebar, { children: [_jsxs(AppSidebarGroup, { children: [_jsx(Skeleton, { height: "control" }), _jsx(Skeleton, { height: "control" })] }), _jsxs(AppSidebarRail, { children: [_jsx(Skeleton, { shape: "circle" }), _jsx(Skeleton, { shape: "circle" })] }), _jsx(AppSidebarNav, { children: _jsx(SidebarRowsSkeleton, {}) }), _jsx(AppSidebarFooter, { children: _jsx(Skeleton, { shape: "text", width: "70%" }) })] }), _jsxs(AppMain, { children: [_jsx(AppHeader, { children: _jsx(Skeleton, { shape: "text", width: "medium" }) }), _jsx(AppContent, { children: children ?? _jsx(PanelSkeleton, { rows: 6 }) })] })] }));
|
|
14
|
+
return (_jsxs(AppShell, { "aria-busy": "true", "aria-label": labels.common.loading, ...props, children: [_jsxs(AppSidebar, { children: [_jsxs(AppSidebarGroup, { children: [_jsx(Skeleton, { height: "control" }), _jsx(Skeleton, { height: "control" })] }), _jsxs(AppSidebarRail, { children: [_jsx(Skeleton, { shape: "circle", style: { width: 32 } }), _jsx(Skeleton, { shape: "circle", style: { width: 32 } })] }), _jsx(AppSidebarNav, { children: _jsx(SidebarRowsSkeleton, {}) }), _jsx(AppSidebarFooter, { children: _jsx(Skeleton, { shape: "text", width: "70%" }) })] }), _jsxs(AppMain, { children: [_jsx(AppHeader, { children: _jsx(Skeleton, { shape: "text", width: "medium" }) }), _jsx(AppContent, { children: children ?? _jsx(PanelSkeleton, { rows: 6 }) })] })] }));
|
|
15
15
|
}
|
|
@@ -50,8 +50,8 @@ export type AppBreadcrumbButtonProps = useRender.ComponentProps<"button"> & {
|
|
|
50
50
|
*/
|
|
51
51
|
export declare function AppBreadcrumbButton({ className, render, href, ...props }: AppBreadcrumbButtonProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
52
52
|
/**
|
|
53
|
-
* The signed-in account as a menu trigger: avatar, name, and a detail line, or with
|
|
54
|
-
* avatar alone.
|
|
53
|
+
* The signed-in account as a menu trigger: avatar, name, and a detail line if given, or with
|
|
54
|
+
* `compact` the avatar alone.
|
|
55
55
|
*/
|
|
56
56
|
export declare function AppAccountButton({ avatar, name, detail, trailing, compact, className, ...props }: ComponentProps<"button"> & {
|
|
57
57
|
avatar: ReactNode;
|