@ciridae/ui 1.0.2 → 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/app/auth.d.ts +10 -0
- package/dist/app/auth.js +60 -0
- package/dist/app/error-boundary.d.ts +18 -0
- package/dist/app/error-boundary.js +45 -0
- package/dist/app/feedback.d.ts +12 -0
- package/dist/app/feedback.js +128 -0
- package/dist/app/index.d.ts +8 -0
- package/dist/app/index.js +8 -0
- package/dist/app/request-errors.d.ts +63 -0
- package/dist/app/request-errors.js +172 -0
- package/dist/app/sentry.d.ts +18 -0
- package/dist/app/sentry.js +52 -0
- package/dist/app/telemetry.d.ts +7 -0
- package/dist/app/telemetry.js +28 -0
- package/dist/app/trail.d.ts +9 -0
- package/dist/app/trail.js +18 -0
- package/dist/chat/chat-query-keys.d.ts +3 -3
- package/dist/chat/contract.d.ts +15 -15
- package/dist/chat/conversation-items-query-options.d.ts +114 -114
- package/dist/chat/conversation-source.d.ts +89 -0
- package/dist/chat/conversation-source.js +1 -0
- package/dist/chat/describe-tool-call.d.ts +3 -3
- package/dist/chat/describe-tool-call.js +3 -3
- package/dist/chat/message-text.d.ts +1 -1
- package/dist/chat/message-text.js +116 -48
- package/dist/chat/use-conversation-list.d.ts +6 -6
- package/dist/ciridae.css +16 -4
- package/dist/components/activity-feed.d.ts +3 -2
- package/dist/components/activity-feed.js +1 -0
- package/dist/components/agent-work.d.ts +3 -3
- package/dist/components/app-frame.d.ts +91 -0
- package/dist/components/app-frame.js +134 -0
- package/dist/components/app-navigation.d.ts +30 -3
- package/dist/components/app-navigation.js +105 -14
- package/dist/components/badge.d.ts +30 -5
- package/dist/components/badge.js +134 -15
- package/dist/components/brand-icons.d.ts +3 -3
- package/dist/components/bulk-action-bar.d.ts +1 -1
- package/dist/components/bulk-action-bar.js +3 -3
- package/dist/components/button.d.ts +12 -5
- package/dist/components/button.js +77 -44
- package/dist/components/calendar.d.ts +1 -1
- package/dist/components/calendar.js +44 -17
- package/dist/components/centered-page.d.ts +1 -1
- package/dist/components/centered-page.js +2 -2
- package/dist/components/chart.d.ts +22 -2
- package/dist/components/chart.js +251 -51
- package/dist/components/chat-client-source.d.ts +16 -0
- package/dist/components/chat-client-source.js +297 -0
- package/dist/components/chat-page.d.ts +9 -8
- package/dist/components/chat-page.js +7 -11
- package/dist/components/chat-sheet-controller.d.ts +11 -14
- package/dist/components/chat-sheet-controller.js +3 -3
- package/dist/components/chat-sheet.d.ts +18 -11
- package/dist/components/chat-sheet.js +188 -289
- package/dist/components/chat.d.ts +109 -19
- package/dist/components/chat.js +520 -124
- package/dist/components/checkbox-item.d.ts +6 -3
- package/dist/components/checkbox-item.js +9 -5
- package/dist/components/checkbox-list.d.ts +1 -1
- package/dist/components/chip.d.ts +6 -1
- package/dist/components/chip.js +27 -1
- package/dist/components/collapsible.d.ts +1 -1
- package/dist/components/color-theme.d.ts +1 -1
- package/dist/components/column-settings.d.ts +1 -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 +7 -3
- package/dist/components/command-palette.js +20 -11
- package/dist/components/copyable-id.d.ts +22 -5
- package/dist/components/copyable-id.js +46 -6
- package/dist/components/data-display.d.ts +39 -8
- package/dist/components/data-display.js +138 -19
- package/dist/components/data-grid.d.ts +23 -11
- package/dist/components/data-grid.js +61 -26
- package/dist/components/date-range-picker.d.ts +1 -1
- package/dist/components/date-range-picker.js +9 -20
- package/dist/components/date-time.d.ts +1 -1
- package/dist/components/dialog-height-context.d.ts +1 -1
- package/dist/components/document-viewer.d.ts +2 -2
- package/dist/components/drawer.d.ts +11 -6
- package/dist/components/drawer.js +91 -54
- package/dist/components/dropzone.d.ts +4 -4
- package/dist/components/editable-field.d.ts +12 -3
- package/dist/components/editable-field.js +57 -27
- package/dist/components/email-input.d.ts +1 -1
- package/dist/components/email-input.js +6 -5
- package/dist/components/environment-frame.d.ts +2 -2
- package/dist/components/environment-frame.js +37 -6
- package/dist/components/expandable-text.d.ts +1 -1
- package/dist/components/feedback-screenshot.d.ts +1 -1
- package/dist/components/feedback-sheet.d.ts +18 -3
- package/dist/components/feedback-sheet.js +216 -55
- package/dist/components/field-context.d.ts +1 -1
- package/dist/components/filter-bar.d.ts +3 -3
- package/dist/components/filter-bar.js +43 -29
- package/dist/components/form-controls.d.ts +12 -3
- package/dist/components/form-controls.js +46 -22
- package/dist/components/form-layout.d.ts +14 -10
- 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/hotkeys.d.ts +2 -2
- package/dist/components/icon.d.ts +1 -1
- package/dist/components/input.d.ts +7 -5
- package/dist/components/input.js +29 -17
- package/dist/components/keyboard-shortcuts.d.ts +2 -2
- package/dist/components/keycap.d.ts +10 -6
- package/dist/components/keycap.js +57 -19
- package/dist/components/layout.d.ts +13 -13
- package/dist/components/lightbox.d.ts +9 -3
- package/dist/components/lightbox.js +13 -9
- package/dist/components/link.d.ts +1 -1
- package/dist/components/locale.d.ts +42 -2
- package/dist/components/locale.js +43 -3
- package/dist/components/log-entry.d.ts +40 -0
- package/dist/components/log-entry.js +146 -0
- package/dist/components/log-list.d.ts +3 -3
- package/dist/components/mention-input.d.ts +2 -2
- package/dist/components/mention-input.js +4 -3
- package/dist/components/menu.d.ts +7 -3
- package/dist/components/menu.js +34 -37
- package/dist/components/meter.d.ts +10 -2
- 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.d.ts +1 -1
- package/dist/components/notification-tray.js +5 -4
- package/dist/components/overlays.d.ts +6 -4
- package/dist/components/overlays.js +69 -40
- package/dist/components/page-frame.d.ts +4 -4
- package/dist/components/page-frame.js +1 -1
- package/dist/components/panel.d.ts +4 -4
- package/dist/components/panel.js +18 -12
- package/dist/components/profile-header.d.ts +1 -1
- package/dist/components/progress.d.ts +1 -1
- package/dist/components/project-avatar.d.ts +1 -1
- package/dist/components/radio-card.d.ts +2 -2
- package/dist/components/radio-card.js +10 -9
- package/dist/components/record.d.ts +29 -5
- package/dist/components/record.js +147 -18
- package/dist/components/resolved-file-url.d.ts +19 -0
- package/dist/components/resolved-file-url.js +49 -0
- package/dist/components/scroll-area.d.ts +1 -1
- package/dist/components/secret-dialog.d.ts +1 -1
- package/dist/components/segmented-bar.d.ts +4 -2
- package/dist/components/segmented-bar.js +16 -6
- package/dist/components/select.d.ts +9 -6
- package/dist/components/select.js +103 -127
- package/dist/components/settings.d.ts +4 -4
- package/dist/components/shell-skeleton.d.ts +1 -1
- package/dist/components/shell-skeleton.js +1 -1
- package/dist/components/shell.d.ts +21 -21
- package/dist/components/shell.js +43 -43
- package/dist/components/side-panel.d.ts +3 -3
- package/dist/components/sidebar.d.ts +13 -8
- 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 +8 -7
- package/dist/components/skeleton.js +28 -16
- package/dist/components/skeletons.d.ts +17 -5
- package/dist/components/skeletons.js +71 -8
- package/dist/components/stages.d.ts +83 -11
- package/dist/components/stages.js +512 -156
- package/dist/components/stat-card.d.ts +12 -4
- package/dist/components/stat-card.js +92 -37
- package/dist/components/status-banner.d.ts +1 -1
- package/dist/components/status-banner.js +1 -1
- package/dist/components/status.d.ts +2 -2
- package/dist/components/steps.d.ts +1 -1
- package/dist/components/switch.d.ts +1 -1
- package/dist/components/tabs.d.ts +8 -8
- package/dist/components/tabs.js +26 -13
- package/dist/components/theme-customizer.d.ts +2 -2
- package/dist/components/theme-toggle.d.ts +4 -0
- package/dist/components/theme-toggle.js +67 -0
- package/dist/components/toast.d.ts +10 -3
- package/dist/components/toast.js +78 -29
- package/dist/components/use-new-version-available.d.ts +6 -0
- package/dist/components/use-new-version-available.js +29 -0
- package/dist/components/user-chip.d.ts +3 -3
- package/dist/components/wizard.d.ts +2 -2
- package/dist/feedback/contract.d.ts +136 -136
- package/dist/feedback/feedback-controller.d.ts +6 -6
- package/dist/feedback/generated/zod.gen.d.ts +28 -28
- package/dist/feedback/operator-contract.d.ts +11 -11
- package/dist/feedback/operator-controller.d.ts +32 -13
- package/dist/feedback/operator-controller.js +44 -11
- package/dist/preset.js +289 -33
- package/dist/styled-system/styles.css +3294 -1079
- 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 +40 -3
|
@@ -13,7 +13,12 @@ export type ButtonProps = Omit<BaseButtonProps, "className"> & {
|
|
|
13
13
|
/** The hotkey that does what the button does, shown after its label; the host binds it. */
|
|
14
14
|
shortcut?: Hotkey;
|
|
15
15
|
};
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* The size a `Button` takes where it does not set its own, so the container decides: a dialog's
|
|
18
|
+
* footer holds the default 38px buttons, where everywhere else the small one is the everyday.
|
|
19
|
+
*/
|
|
20
|
+
export declare const ButtonSizeContext: import("react").Context<NonNullable<"medium" | "large" | "small" | undefined>>;
|
|
21
|
+
export declare function Button({ className, variant, size: ownSize, fullWidth, loading, icon, shortcut, children, disabled, ...props }: ButtonProps): import("react").JSX.Element;
|
|
17
22
|
export type DataButtonState = "idle" | "pending" | "error" | "success";
|
|
18
23
|
export type DataButtonProps = Omit<ButtonProps, "children" | "icon" | "loading"> & {
|
|
19
24
|
state: DataButtonState;
|
|
@@ -24,19 +29,21 @@ export type DataButtonProps = Omit<ButtonProps, "children" | "icon" | "loading">
|
|
|
24
29
|
icon?: ReactNode;
|
|
25
30
|
};
|
|
26
31
|
/** Async action button with consistent pending, retry, and completion feedback. */
|
|
27
|
-
export declare function DataButton({ state, idleLabel, pendingLabel, errorLabel, successLabel, variant, icon, disabled, ...props }: DataButtonProps): import("
|
|
28
|
-
type IconButtonSize = "compact" | "small" | "medium" | "large";
|
|
32
|
+
export declare function DataButton({ state, idleLabel, pendingLabel, errorLabel, successLabel, variant, icon, disabled, ...props }: DataButtonProps): import("react").JSX.Element;
|
|
33
|
+
type IconButtonSize = "compact" | "send" | "small" | "medium" | "large";
|
|
29
34
|
/**
|
|
30
35
|
* The size an `IconButton` takes where it does not set its own, so the container decides: the
|
|
31
36
|
* sidebar rail's icons are large, and the same icon shown in the phone header matches the header's
|
|
32
37
|
* small buttons.
|
|
33
38
|
*/
|
|
34
|
-
export declare const IconButtonSizeContext: import("
|
|
39
|
+
export declare const IconButtonSizeContext: import("react").Context<IconButtonSize>;
|
|
35
40
|
export type IconButtonProps = Omit<BaseButtonProps, "className" | "aria-label"> & {
|
|
36
41
|
className?: string;
|
|
37
42
|
"aria-label": string;
|
|
38
43
|
size?: IconButtonSize;
|
|
39
44
|
variant?: "raised" | "ghost" | "primary";
|
|
45
|
+
/** `square` is the 8-round square that leads a page title; buttons are otherwise round. */
|
|
46
|
+
shape?: "round" | "square";
|
|
40
47
|
/**
|
|
41
48
|
* `true` marks the button with a dot; a number shows that count, nothing at zero, and joins the
|
|
42
49
|
* button's name so assistive tech hears it too.
|
|
@@ -48,5 +55,5 @@ export type IconButtonProps = Omit<BaseButtonProps, "className" | "aria-label">
|
|
|
48
55
|
*/
|
|
49
56
|
shortcut?: Hotkey;
|
|
50
57
|
};
|
|
51
|
-
export declare function IconButton({ className, size, variant, badge, shortcut, children, "aria-label": label, ...props }: IconButtonProps): import("
|
|
58
|
+
export declare function IconButton({ className, size, variant, shape, badge, shortcut, children, "aria-label": label, ...props }: IconButtonProps): import("react").JSX.Element;
|
|
52
59
|
export {};
|
|
@@ -3,10 +3,14 @@ import { Button as BaseButton } from "@base-ui/react/button";
|
|
|
3
3
|
import { CheckCircleIcon, WarningCircleIcon } from "@phosphor-icons/react";
|
|
4
4
|
import { createContext, useContext } from "react";
|
|
5
5
|
import { css, cva, cx } from "#primitives/css";
|
|
6
|
+
import { faceEdge } from "./gradient-edge.js";
|
|
6
7
|
import { formatForDisplay } from "./hotkeys.js";
|
|
7
8
|
import { icon as iconStyle, Spinner } from "./icon.js";
|
|
8
9
|
import { ShortcutHint } from "./keycap.js";
|
|
9
10
|
import { useCiridaeLocale } from "./locale.js";
|
|
11
|
+
/* The hover wash laid over a gradient face, as the design's state layer sits over it. */
|
|
12
|
+
const raisedHoverLight = "linear-gradient(token(colors.bg.hover), token(colors.bg.hover)), token(gradients.raised)";
|
|
13
|
+
const tintedHover = "linear-gradient(token(colors.bg.hover), token(colors.bg.hover)), token(gradients.tinted)";
|
|
10
14
|
const action = cva({
|
|
11
15
|
base: {
|
|
12
16
|
display: "inline-flex",
|
|
@@ -14,8 +18,10 @@ const action = cva({
|
|
|
14
18
|
alignItems: "center",
|
|
15
19
|
justifyContent: "center",
|
|
16
20
|
gap: "control.iconGap",
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
// The design lays a button's edge over its padding rather than inside it, so no border.
|
|
22
|
+
border: "0",
|
|
23
|
+
// Buttons are pills at both heights.
|
|
24
|
+
borderRadius: "pill",
|
|
19
25
|
height: "control.default",
|
|
20
26
|
paddingInline: "control.inline",
|
|
21
27
|
fontFamily: "sans",
|
|
@@ -36,67 +42,67 @@ const action = cva({
|
|
|
36
42
|
},
|
|
37
43
|
variants: {
|
|
38
44
|
variant: {
|
|
39
|
-
|
|
45
|
+
/*
|
|
46
|
+
* Buttons cast no shadow: each face is told apart by its gradient fill and its gradient
|
|
47
|
+
* edge alone. Light has no hover on the primary face; dark lets a little of the surface
|
|
48
|
+
* through. A raised face takes the hover wash over its gradient in light, and thins in dark.
|
|
49
|
+
*/
|
|
40
50
|
primary: {
|
|
41
|
-
background: "
|
|
51
|
+
background: "token(gradients.primary)",
|
|
42
52
|
color: "bg.canvas",
|
|
43
53
|
_light: { color: "fg.onAccent" },
|
|
44
|
-
|
|
45
|
-
|
|
54
|
+
_hover: {
|
|
55
|
+
background: "bg.primaryHover",
|
|
56
|
+
_light: { background: "token(gradients.primary)" },
|
|
57
|
+
},
|
|
46
58
|
_active: { translate: "0 1px" },
|
|
47
59
|
},
|
|
48
60
|
secondary: {
|
|
49
|
-
background: "
|
|
61
|
+
background: "token(gradients.raised)",
|
|
50
62
|
color: "fg.primary",
|
|
51
|
-
|
|
52
|
-
_hover: { background: "bg.raisedHover" },
|
|
63
|
+
_hover: { background: "bg.raisedHover", _light: { background: raisedHoverLight } },
|
|
53
64
|
_active: { translate: "0 1px" },
|
|
54
65
|
},
|
|
55
66
|
subtle: {
|
|
56
67
|
background: "bg.fill",
|
|
57
68
|
color: "fg.muted",
|
|
58
|
-
borderColor: "transparent",
|
|
59
69
|
_hover: { color: "fg.primary" },
|
|
60
70
|
_active: { translate: "0 1px" },
|
|
61
71
|
},
|
|
62
|
-
// White in dark,
|
|
72
|
+
// White in dark, the secondary grey in light: the one face whose text follows the theme
|
|
73
|
+
// differently.
|
|
63
74
|
ghost: {
|
|
64
75
|
background: "transparent",
|
|
65
76
|
color: "fg.primary",
|
|
66
|
-
_light: { color: "fg.
|
|
67
|
-
borderColor: "transparent",
|
|
77
|
+
_light: { color: "fg.secondary" },
|
|
68
78
|
_hover: { color: "fg.primary", background: "bg.hover" },
|
|
69
79
|
},
|
|
70
80
|
// Warm glass with an amber edge and the warm accent for its text.
|
|
71
81
|
tinted: {
|
|
72
|
-
background: "
|
|
82
|
+
background: "token(gradients.tinted)",
|
|
73
83
|
color: "accent.yellow",
|
|
74
84
|
_light: { color: "accent.bronze" },
|
|
75
|
-
|
|
76
|
-
_hover: { background: "bg.raisedHover" },
|
|
85
|
+
_hover: { background: tintedHover },
|
|
77
86
|
_active: { translate: "0 1px" },
|
|
78
87
|
},
|
|
79
88
|
// The secondary face with red text, for a destructive action that asks for confirmation:
|
|
80
89
|
// it names the risk without being the loudest thing on the page. The confirmation's own
|
|
81
90
|
// button is `danger`.
|
|
82
91
|
secondaryDanger: {
|
|
83
|
-
background: "
|
|
92
|
+
background: "token(gradients.raised)",
|
|
84
93
|
color: "accent.red",
|
|
85
|
-
|
|
86
|
-
_hover: { background: "bg.raisedHover" },
|
|
94
|
+
_hover: { background: "bg.raisedHover", _light: { background: raisedHoverLight } },
|
|
87
95
|
_active: { translate: "0 1px" },
|
|
88
96
|
},
|
|
89
97
|
danger: {
|
|
90
|
-
background: "
|
|
98
|
+
background: "token(gradients.danger)",
|
|
91
99
|
color: "fg.onAccent",
|
|
92
|
-
borderColor: "transparent",
|
|
93
100
|
_hover: { filter: "brightness(1.05)" },
|
|
94
101
|
_active: { translate: "0 1px" },
|
|
95
102
|
},
|
|
96
103
|
success: {
|
|
97
104
|
background: "accent.green",
|
|
98
105
|
color: "bg.canvas",
|
|
99
|
-
borderColor: "transparent",
|
|
100
106
|
_hover: { filter: "brightness(1.05)" },
|
|
101
107
|
_active: { translate: "0 1px" },
|
|
102
108
|
},
|
|
@@ -104,8 +110,6 @@ const action = cva({
|
|
|
104
110
|
link: {
|
|
105
111
|
background: "transparent",
|
|
106
112
|
color: "fg.primary",
|
|
107
|
-
borderColor: "transparent",
|
|
108
|
-
borderWidth: "0",
|
|
109
113
|
fontFamily: "inherit",
|
|
110
114
|
fontWeight: "inherit",
|
|
111
115
|
letterSpacing: "inherit",
|
|
@@ -134,22 +138,30 @@ const action = cva({
|
|
|
134
138
|
// Small is the everyday button; medium and large are for a page's one main action.
|
|
135
139
|
defaultVariants: { variant: "primary", size: "small" },
|
|
136
140
|
});
|
|
137
|
-
//
|
|
141
|
+
// Each gradient face draws its own gradient edge; the flat faces draw a hairline or none.
|
|
138
142
|
const buttonEdges = {
|
|
139
|
-
primary:
|
|
140
|
-
secondary: "
|
|
143
|
+
primary: "primary",
|
|
144
|
+
secondary: "raised",
|
|
141
145
|
subtle: "glass",
|
|
142
146
|
ghost: undefined,
|
|
143
|
-
tinted:
|
|
144
|
-
secondaryDanger: "
|
|
145
|
-
danger:
|
|
147
|
+
tinted: "tinted",
|
|
148
|
+
secondaryDanger: "raised",
|
|
149
|
+
danger: "danger",
|
|
146
150
|
success: undefined,
|
|
147
151
|
link: undefined,
|
|
148
152
|
};
|
|
149
153
|
// In the button's own color, quieter than its label.
|
|
150
154
|
const buttonHint = css({ color: "inherit", opacity: "0.6" });
|
|
151
|
-
|
|
152
|
-
|
|
155
|
+
/**
|
|
156
|
+
* The size a `Button` takes where it does not set its own, so the container decides: a dialog's
|
|
157
|
+
* footer holds the default 38px buttons, where everywhere else the small one is the everyday.
|
|
158
|
+
*/
|
|
159
|
+
export const ButtonSizeContext = createContext("small");
|
|
160
|
+
export function Button({ className, variant = "primary", size: ownSize, fullWidth, loading, icon, shortcut, children, disabled, ...props }) {
|
|
161
|
+
const containerSize = useContext(ButtonSizeContext);
|
|
162
|
+
const size = ownSize ?? containerSize;
|
|
163
|
+
const edge = faceEdge(buttonEdges[variant]);
|
|
164
|
+
return (_jsxs(BaseButton, { ...props, disabled: disabled || loading, "aria-busy": loading || undefined, className: cx(action({ variant, size, fullWidth }), edge.className, className), "data-ciridae-ui": "", "data-edge": edge["data-edge"], children: [loading ? _jsx(Spinner, { "aria-hidden": "true" }) : icon, children, shortcut && _jsx(ShortcutHint, { hotkey: shortcut, className: buttonHint })] }));
|
|
153
165
|
}
|
|
154
166
|
/** Async action button with consistent pending, retry, and completion feedback. */
|
|
155
167
|
export function DataButton({ state, idleLabel, pendingLabel, errorLabel, successLabel, variant = "primary", icon, disabled, ...props }) {
|
|
@@ -183,19 +195,22 @@ const round = cva({
|
|
|
183
195
|
alignItems: "center",
|
|
184
196
|
justifyContent: "center",
|
|
185
197
|
padding: "none",
|
|
198
|
+
// The edge's own 1px, as the design counts it; the bare button has neither.
|
|
186
199
|
border: "1px solid transparent",
|
|
187
200
|
borderRadius: "pill",
|
|
188
201
|
color: "fg.muted",
|
|
189
|
-
background: "
|
|
202
|
+
background: "token(gradients.raised)",
|
|
190
203
|
cursor: "pointer",
|
|
191
204
|
flexShrink: "0",
|
|
192
205
|
transitionProperty: "translate, background, color",
|
|
193
206
|
transitionDuration: "fast",
|
|
194
|
-
|
|
207
|
+
// Hover keeps the face in light and thins it in dark; the icon takes the primary ink.
|
|
208
|
+
_hover: { color: "fg.primary", background: "token(gradients.raisedHover)" },
|
|
195
209
|
_active: { translate: "0 1px" },
|
|
196
210
|
_focusVisible: { focusRing: "outer" },
|
|
211
|
+
// A round face fades further than other controls when it cannot be pressed.
|
|
197
212
|
"&:disabled, &[data-disabled]": {
|
|
198
|
-
opacity: "
|
|
213
|
+
opacity: "disabledRound",
|
|
199
214
|
cursor: "not-allowed",
|
|
200
215
|
translate: "none",
|
|
201
216
|
},
|
|
@@ -203,27 +218,44 @@ const round = cva({
|
|
|
203
218
|
variants: {
|
|
204
219
|
variant: {
|
|
205
220
|
raised: {},
|
|
221
|
+
// The bare icon button: no face until hovered, and disabled it fades as other controls do.
|
|
206
222
|
ghost: {
|
|
223
|
+
border: "0",
|
|
207
224
|
background: "transparent",
|
|
208
|
-
_hover: { background: "bg.hover" },
|
|
225
|
+
_hover: { background: "bg.hover", _light: { background: "bg.hover" } },
|
|
209
226
|
_active: { translate: "none" },
|
|
227
|
+
"&:disabled, &[data-disabled]": { opacity: "disabled" },
|
|
210
228
|
},
|
|
211
229
|
// The primary face as a round button: a composer's send.
|
|
212
230
|
primary: {
|
|
213
|
-
background: "
|
|
231
|
+
background: "token(gradients.primary)",
|
|
214
232
|
color: "bg.canvas",
|
|
215
233
|
_light: { color: "fg.onAccent" },
|
|
216
|
-
_hover: {
|
|
234
|
+
_hover: {
|
|
235
|
+
color: "bg.canvas",
|
|
236
|
+
background: "bg.primaryHover",
|
|
237
|
+
_light: { color: "fg.onAccent", background: "token(gradients.primary)" },
|
|
238
|
+
},
|
|
217
239
|
},
|
|
218
240
|
},
|
|
241
|
+
// 24 is the bare button's in a column or group header; 26 the composer's send on the
|
|
242
|
+
// primary face; the other round faces are 28, 34 and 38.
|
|
219
243
|
size: {
|
|
220
244
|
compact: { width: "control.shortcut", height: "control.shortcut" },
|
|
221
|
-
|
|
222
|
-
|
|
245
|
+
send: { width: "control.send", height: "control.send" },
|
|
246
|
+
small: { width: "control.roundSmall", height: "control.roundSmall" },
|
|
247
|
+
medium: { width: "control.round", height: "control.round" },
|
|
223
248
|
large: { width: "control.default", height: "control.default" },
|
|
224
249
|
},
|
|
250
|
+
// A page's leading icon button is a rounded square rather than a circle.
|
|
251
|
+
shape: { round: {}, square: { borderRadius: "action" } },
|
|
225
252
|
},
|
|
226
|
-
|
|
253
|
+
compoundVariants: [
|
|
254
|
+
// Bare, the button is a rounded square too: 6 round at 24 and 8 round at 28.
|
|
255
|
+
{ variant: "ghost", size: "compact", css: { borderRadius: "keycap" } },
|
|
256
|
+
{ variant: "ghost", size: "small", css: { borderRadius: "action" } },
|
|
257
|
+
],
|
|
258
|
+
defaultVariants: { size: "medium", variant: "raised", shape: "round" },
|
|
227
259
|
});
|
|
228
260
|
const badgeDot = css({
|
|
229
261
|
position: "absolute",
|
|
@@ -263,10 +295,11 @@ const badgeCount = css({
|
|
|
263
295
|
* small buttons.
|
|
264
296
|
*/
|
|
265
297
|
export const IconButtonSizeContext = createContext("medium");
|
|
266
|
-
const iconButtonEdges = { raised: "
|
|
267
|
-
export function IconButton({ className, size, variant = "raised", badge, shortcut, children, "aria-label": label, ...props }) {
|
|
298
|
+
const iconButtonEdges = { raised: "raised", ghost: undefined, primary: "primary" };
|
|
299
|
+
export function IconButton({ className, size, variant = "raised", shape = "round", badge, shortcut, children, "aria-label": label, ...props }) {
|
|
268
300
|
const containerSize = useContext(IconButtonSizeContext);
|
|
269
301
|
const { labels } = useCiridaeLocale();
|
|
270
302
|
const count = typeof badge === "number" && badge > 0 ? badge : 0;
|
|
271
|
-
|
|
303
|
+
const edge = faceEdge(iconButtonEdges[variant]);
|
|
304
|
+
return (_jsxs(BaseButton, { ...props, "aria-label": count > 0 ? labels.common.withCount(label, count) : label, "aria-keyshortcuts": shortcut && formatForDisplay(shortcut, { useSymbols: false }), className: cx(round({ size: size ?? containerSize, variant, shape }), edge.className, className), "data-ciridae-ui": "", "data-edge": edge["data-edge"], children: [children, badge === true && _jsx("span", { className: badgeDot, "aria-hidden": "true" }), count > 0 && (_jsx("span", { className: badgeCount, "aria-hidden": "true", children: count > 99 ? "99+" : count }))] }));
|
|
272
305
|
}
|
|
@@ -10,5 +10,5 @@ export type CalendarProps = {
|
|
|
10
10
|
weekStartsOn?: WeekStartsOn;
|
|
11
11
|
labels?: Partial<CiridaeLabels["calendar"]>;
|
|
12
12
|
};
|
|
13
|
-
export declare function Calendar({ month, selected, onMonthChange, onSelect, locale: ownLocale, weekStartsOn, labels: ownLabels, }: CalendarProps): import("
|
|
13
|
+
export declare function Calendar({ month, selected, onMonthChange, onSelect, locale: ownLocale, weekStartsOn, labels: ownLabels, }: CalendarProps): import("react").JSX.Element;
|
|
14
14
|
export {};
|
|
@@ -5,11 +5,39 @@ import { css, cx } from "#primitives/css";
|
|
|
5
5
|
import { IconButton } from "./button.js";
|
|
6
6
|
import { directional, icon } from "./icon.js";
|
|
7
7
|
import { useCiridaeLocale } from "./locale.js";
|
|
8
|
+
/*
|
|
9
|
+
* The month alone, no face of its own: it sits on the popover or picker that opens it. Seven 32px
|
|
10
|
+
* day columns inside an 8px inset, which with the glass sheet's 4px makes the design's 12px.
|
|
11
|
+
*/
|
|
12
|
+
const calendar = css({
|
|
13
|
+
display: "grid",
|
|
14
|
+
gap: "layout.controlGap",
|
|
15
|
+
width: "calc(7 * token(sizes.control.compact) + 2 * token(spacing.panel.compact))",
|
|
16
|
+
padding: "panel.compact",
|
|
17
|
+
});
|
|
18
|
+
const header = css({
|
|
19
|
+
display: "flex",
|
|
20
|
+
alignItems: "center",
|
|
21
|
+
justifyContent: "space-between",
|
|
22
|
+
fontSize: "caption",
|
|
23
|
+
fontWeight: "medium",
|
|
24
|
+
letterSpacing: "compact",
|
|
25
|
+
});
|
|
8
26
|
const grid = css({
|
|
9
27
|
display: "grid",
|
|
10
28
|
gridTemplateColumns: "repeat(7, minmax(0, 1fr))",
|
|
11
29
|
justifyItems: "center",
|
|
12
|
-
|
|
30
|
+
rowGap: "control.trackInset",
|
|
31
|
+
});
|
|
32
|
+
// The weekdays sit as far above the days as the month sits above them.
|
|
33
|
+
const weekDay = css({
|
|
34
|
+
paddingBlock: "layout.tightGap",
|
|
35
|
+
marginBottom: "control.iconGap",
|
|
36
|
+
textAlign: "center",
|
|
37
|
+
color: "fg.muted",
|
|
38
|
+
fontSize: "code",
|
|
39
|
+
fontWeight: "medium",
|
|
40
|
+
lineHeight: "tight",
|
|
13
41
|
});
|
|
14
42
|
const row = css({
|
|
15
43
|
display: "grid",
|
|
@@ -18,20 +46,29 @@ const row = css({
|
|
|
18
46
|
width: "100%",
|
|
19
47
|
});
|
|
20
48
|
const previousMonthIcon = css({ transform: "rotate(180deg)" });
|
|
49
|
+
// Today wears a hairline ring; the chosen day the primary button's face.
|
|
21
50
|
const day = css({
|
|
22
51
|
width: "control.compact",
|
|
23
52
|
height: "control.compact",
|
|
24
|
-
border: "
|
|
53
|
+
border: "1px solid transparent",
|
|
25
54
|
borderRadius: "round",
|
|
26
55
|
background: "transparent",
|
|
27
56
|
color: "fg.primary",
|
|
57
|
+
fontSize: "caption",
|
|
58
|
+
fontWeight: "medium",
|
|
28
59
|
cursor: "pointer",
|
|
29
60
|
transitionProperty: "background, color",
|
|
30
61
|
transitionDuration: "fast",
|
|
62
|
+
"&[aria-current=date]": { borderColor: "border.control" },
|
|
31
63
|
"&:hover:not(:disabled):not([aria-selected=true])": {
|
|
32
|
-
background: "bg.
|
|
64
|
+
background: "bg.hover",
|
|
65
|
+
},
|
|
66
|
+
"&[aria-selected=true]": {
|
|
67
|
+
borderColor: "transparent",
|
|
68
|
+
background: "token(gradients.primary)",
|
|
69
|
+
color: "bg.canvas",
|
|
70
|
+
_light: { color: "fg.onAccent" },
|
|
33
71
|
},
|
|
34
|
-
"&[aria-selected=true]": { background: "fg.primary", color: "bg.canvas" },
|
|
35
72
|
_disabled: { color: "fg.muted", opacity: "disabled", cursor: "default" },
|
|
36
73
|
_focusVisible: { focusRing: "outer" },
|
|
37
74
|
});
|
|
@@ -135,20 +172,10 @@ export function Calendar({ month, selected, onMonthChange, onSelect, locale: own
|
|
|
135
172
|
});
|
|
136
173
|
const weekDayFormatter = new Intl.DateTimeFormat(locale, { weekday: "narrow" });
|
|
137
174
|
const fullWeekDayFormatter = new Intl.DateTimeFormat(locale, { weekday: "long" });
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
padding: "panel.compact",
|
|
141
|
-
border: "1px solid token(colors.border.control)",
|
|
142
|
-
borderRadius: "inset",
|
|
143
|
-
background: "bg.card",
|
|
144
|
-
}), "data-ciridae-ui": "", children: [_jsxs("header", { className: css({
|
|
145
|
-
display: "flex",
|
|
146
|
-
alignItems: "center",
|
|
147
|
-
justifyContent: "space-between",
|
|
148
|
-
marginBottom: "panel.compact",
|
|
149
|
-
}), children: [_jsx(IconButton, { "aria-label": labels.previousMonth, size: "compact", type: "button", onClick: () => onMonthChange(new Date(month.getFullYear(), month.getMonth() - 1, 1)), children: _jsx(ArrowRightIcon, { className: cx(icon(), directional, previousMonthIcon) }) }), _jsx("strong", { id: monthLabelId, children: monthFormatter.format(month) }), _jsx(IconButton, { "aria-label": labels.nextMonth, size: "compact", type: "button", onClick: () => onMonthChange(new Date(month.getFullYear(), month.getMonth() + 1, 1)), children: _jsx(ArrowRightIcon, { className: cx(icon(), directional) }) })] }), _jsxs("div", { className: grid, role: "grid", "aria-labelledby": monthLabelId, children: [_jsx("div", { className: row, role: "row", children: weekDays.map((date) => (_jsx("span", { "aria-label": fullWeekDayFormatter.format(date), className: css({ textAlign: "center", color: "fg.muted", fontSize: "caption" }), role: "columnheader", children: weekDayFormatter.format(date) }, date.getDay()))) }), Array.from({ length: 6 }, (_, weekIndex) => (_jsx("div", { className: row, role: "row", children: days.slice(weekIndex * 7, weekIndex * 7 + 7).map((date) => {
|
|
175
|
+
const today = new Date();
|
|
176
|
+
return (_jsxs("section", { className: calendar, "data-ciridae-ui": "", children: [_jsxs("header", { className: header, children: [_jsx(IconButton, { "aria-label": labels.previousMonth, size: "compact", variant: "ghost", type: "button", onClick: () => onMonthChange(new Date(month.getFullYear(), month.getMonth() - 1, 1)), children: _jsx(ArrowRightIcon, { className: cx(icon({ size: "small" }), directional, previousMonthIcon) }) }), _jsx("span", { id: monthLabelId, children: monthFormatter.format(month) }), _jsx(IconButton, { "aria-label": labels.nextMonth, size: "compact", variant: "ghost", type: "button", onClick: () => onMonthChange(new Date(month.getFullYear(), month.getMonth() + 1, 1)), children: _jsx(ArrowRightIcon, { className: cx(icon({ size: "small" }), directional) }) })] }), _jsxs("div", { className: grid, role: "grid", "aria-labelledby": monthLabelId, children: [_jsx("div", { className: row, role: "row", children: weekDays.map((date) => (_jsx("span", { "aria-label": fullWeekDayFormatter.format(date), className: weekDay, role: "columnheader", children: weekDayFormatter.format(date) }, date.getDay()))) }), Array.from({ length: 6 }, (_, weekIndex) => (_jsx("div", { className: row, role: "row", children: days.slice(weekIndex * 7, weekIndex * 7 + 7).map((date) => {
|
|
150
177
|
const inCurrentMonth = isSameMonth(date, currentMonth);
|
|
151
|
-
return (_jsx("button", { type: "button", "aria-label": dayFormatter.format(date), "aria-selected": inCurrentMonth && isSameDay(date, selected), className: day, disabled: !inCurrentMonth, onClick: () => onSelect(date), onFocus: () => setFocusedDate(date), onKeyDown: (event) => handleDayKeyDown(event, date), ref: (element) => {
|
|
178
|
+
return (_jsx("button", { type: "button", "aria-label": dayFormatter.format(date), "aria-selected": inCurrentMonth && isSameDay(date, selected), "aria-current": isSameDay(date, today) ? "date" : undefined, className: day, disabled: !inCurrentMonth, onClick: () => onSelect(date), onFocus: () => setFocusedDate(date), onKeyDown: (event) => handleDayKeyDown(event, date), ref: (element) => {
|
|
152
179
|
if (element)
|
|
153
180
|
dayButtons.current.set(dateKey(date), element);
|
|
154
181
|
else
|
|
@@ -18,4 +18,4 @@ export type CenteredPageProps = {
|
|
|
18
18
|
* content. `form` width narrows both for a short form; `wide` suits a card holding a list whose
|
|
19
19
|
* rows carry a label, a detail, and a control.
|
|
20
20
|
*/
|
|
21
|
-
export declare function CenteredPage({ brand, aside, title, description, header, width, children, }: CenteredPageProps): import("
|
|
21
|
+
export declare function CenteredPage({ brand, aside, title, description, header, width, children, }: CenteredPageProps): import("react").JSX.Element;
|
|
@@ -10,7 +10,7 @@ const page = css({
|
|
|
10
10
|
// A phone keeps a thin margin around the card rather than giving its width away.
|
|
11
11
|
padding: "panel.compact",
|
|
12
12
|
"@media(min-width: 640px)": { padding: "page.inline" },
|
|
13
|
-
background: "
|
|
13
|
+
background: "token(gradients.canvas)",
|
|
14
14
|
color: "fg.primary",
|
|
15
15
|
});
|
|
16
16
|
const column = css({
|
|
@@ -31,7 +31,7 @@ const headerRow = css({
|
|
|
31
31
|
paddingInline: "panel.roomy",
|
|
32
32
|
});
|
|
33
33
|
const brandMark = css({ width: "brand.logo", height: "brand.logo", color: "fg.primary" });
|
|
34
|
-
const content = css({ display: "flex", flexDirection: "column", gap: "layout.
|
|
34
|
+
const content = css({ display: "flex", flexDirection: "column", gap: "layout.centeredCardGap" });
|
|
35
35
|
const titleGroup = css({ display: "grid", gap: "layout.tightGap" });
|
|
36
36
|
const titleText = css({ margin: "none", fontSize: "heading.section", fontWeight: "medium" });
|
|
37
37
|
const descriptionText = css({ margin: "none", color: "fg.muted", fontSize: "caption" });
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ComponentProps } from "react";
|
|
2
2
|
/** One line on the chart: a label and its `[unixSeconds, value]` samples. */
|
|
3
3
|
export type TimeSeries = {
|
|
4
4
|
label: string;
|
|
5
5
|
points: readonly (readonly [number, number])[];
|
|
6
6
|
};
|
|
7
|
+
/** One bar or line point per category, such as a month or a team, for a series. */
|
|
8
|
+
export type CategorySeries = {
|
|
9
|
+
label: string;
|
|
10
|
+
/** One value per category, in the categories' order; `null` leaves it out. */
|
|
11
|
+
values: readonly (number | null)[];
|
|
12
|
+
};
|
|
7
13
|
/**
|
|
8
14
|
* Lines over a fixed time window. Samples from different series are joined on their timestamp, so
|
|
9
15
|
* a series missing a sample leaves a gap rather than a line drawn through it.
|
|
@@ -19,4 +25,18 @@ export declare function TimeSeriesChart({ series, start, end, formatValue, forma
|
|
|
19
25
|
height?: number;
|
|
20
26
|
/** Disable fractional axis ticks for discrete counts such as users. */
|
|
21
27
|
allowDecimals?: boolean;
|
|
22
|
-
}): import("
|
|
28
|
+
}): import("react").JSX.Element;
|
|
29
|
+
/**
|
|
30
|
+
* Values by category as bars, side by side per series, or as lines, such as counts per month.
|
|
31
|
+
* Each series takes the next chart colour; a legend names them once there is more than one.
|
|
32
|
+
*/
|
|
33
|
+
export declare function CategoryChart({ categories, series, variant, formatValue, height, allowDecimals, className, ...props }: ComponentProps<"div"> & {
|
|
34
|
+
categories: readonly string[];
|
|
35
|
+
series: readonly CategorySeries[];
|
|
36
|
+
/** `line` joins each series' values across the categories instead. */
|
|
37
|
+
variant?: "bar" | "line";
|
|
38
|
+
formatValue?: (value: number) => string;
|
|
39
|
+
height?: number;
|
|
40
|
+
/** Disable fractional axis ticks for discrete counts such as users. */
|
|
41
|
+
allowDecimals?: boolean;
|
|
42
|
+
}): import("react").JSX.Element;
|