@parallelworks/ui 0.45.0 → 0.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -5
- package/dist/ai/agent/permissions.d.ts +1 -1
- package/dist/ai/agent/permissions.js +1 -1
- package/dist/ai/ai.css +4 -4
- package/dist/ai/components/ChatInput.js +1 -1
- package/dist/ai/components/ChatStage.d.ts +1 -1
- package/dist/ai/components/ChatStage.js +1 -1
- package/dist/ai/core/pasteLanguage.d.ts +1 -1
- package/dist/ai/core/pasteLanguage.js +1 -1
- package/dist/brandIcons.js +1 -1
- package/dist/components/ColorInput.d.ts +36 -0
- package/dist/components/ColorInput.js +82 -0
- package/dist/components/Combobox.d.ts +5 -2
- package/dist/components/Combobox.js +12 -11
- package/dist/components/CreateModal.js +2 -2
- package/dist/components/DatePicker.d.ts +5 -1
- package/dist/components/DatePicker.js +7 -7
- package/dist/components/Field.d.ts +19 -5
- package/dist/components/Field.js +21 -4
- package/dist/components/Input.d.ts +11 -1
- package/dist/components/Input.js +9 -6
- package/dist/components/Loader.d.ts +1 -1
- package/dist/components/MenuEntries.js +1 -1
- package/dist/components/NumberInput.d.ts +1 -0
- package/dist/components/OneTimeCodeInput.d.ts +23 -0
- package/dist/components/OneTimeCodeInput.js +39 -0
- package/dist/components/Provider.d.ts +15 -6
- package/dist/components/Provider.js +17 -5
- package/dist/components/SearchInput.d.ts +1 -0
- package/dist/components/Section.d.ts +7 -2
- package/dist/components/Section.js +58 -39
- package/dist/components/SegmentedControl.d.ts +4 -2
- package/dist/components/SegmentedControl.js +4 -2
- package/dist/components/Select.d.ts +2 -1
- package/dist/components/Select.js +1 -1
- package/dist/components/StatusBadge.d.ts +2 -2
- package/dist/components/StatusBadge.js +1 -1
- package/dist/components/Tabs.js +1 -0
- package/dist/components/ThemeEditor.js +15 -52
- package/dist/components/Toast.js +1 -1
- package/dist/components/ToggleGroup.d.ts +42 -0
- package/dist/components/ToggleGroup.js +69 -0
- package/dist/components/comboboxItems.d.ts +1 -1
- package/dist/components/fieldBox.js +1 -1
- package/dist/components/tone.d.ts +1 -1
- package/dist/editing.d.ts +1 -1
- package/dist/file-explorer/FileExplorerContext.js +11 -11
- package/dist/file-explorer/FilePreview/useObjectBlobUrl.js +4 -4
- package/dist/file-explorer/FilePreview/useObjectText.js +4 -4
- package/dist/file-explorer/FilePreview/usePresignedUrl.js +4 -4
- package/dist/file-explorer/lib/types.d.ts +2 -2
- package/dist/file-explorer/toasts.js +9 -9
- package/dist/form/Fields/BooleanField.js +1 -1
- package/dist/form/Fields/ColorField.js +6 -10
- package/dist/form/Fields/DropdownField.js +1 -1
- package/dist/form/Fields/DurationField.js +1 -1
- package/dist/form/Fields/MultiDropdownField.js +1 -1
- package/dist/form/Fields/StringField.js +1 -1
- package/dist/form/Fields/TextAreaField.js +1 -1
- package/dist/form/Form.js +1 -1
- package/dist/form/utils/fieldItems.d.ts +1 -1
- package/dist/graph/GraphEditorDialogs.js +1 -1
- package/dist/graph/InputDialog.js +2 -2
- package/dist/graph/SuggestionInput.d.ts +1 -1
- package/dist/graph/SuggestionInput.js +1 -1
- package/dist/graph/WorkflowSettingsDialog.js +1 -1
- package/dist/graph/editorFields.js +2 -2
- package/dist/graph/editorPrimitives.d.ts +2 -2
- package/dist/graph/editorPrimitives.js +1 -1
- package/dist/graph/editorStrings.d.ts +2 -2
- package/dist/graph/editorStrings.js +4 -4
- package/dist/graph/inputRefs.js +2 -2
- package/dist/graph/stepWith.js +1 -1
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +14 -10
- package/dist/list/ListViewControls.js +1 -1
- package/dist/list/listSearch.js +1 -1
- package/dist/logviewer/segments.d.ts +1 -1
- package/dist/logviewer/segments.js +1 -1
- package/dist/styles/theme.css +1 -1
- package/dist/styles.css +1 -1
- package/dist/theme/derive.d.ts +3 -0
- package/dist/theme/derive.js +11 -7
- package/package.json +1 -1
package/dist/components/Input.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
|
-
import { fieldBox } from "./fieldBox.js";
|
|
3
2
|
import { Field, RevealToggle } from "./Field.js";
|
|
3
|
+
import { fieldBox } from "./fieldBox.js";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { forwardRef, useState } from "react";
|
|
6
6
|
//#region src/components/Input.tsx
|
|
@@ -19,7 +19,7 @@ function framed({ label, hint, description, error }, { id, required, disabled },
|
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
21
|
/** A single-line text field. `type="password"` adds a button that shows what was typed. */
|
|
22
|
-
var Input = forwardRef(({ label, hint, description, error, className, mono, type, ...props }, ref) => {
|
|
22
|
+
var Input = forwardRef(({ label, hint, description, error, className, mono, size, type, ...props }, ref) => {
|
|
23
23
|
const [revealed, setRevealed] = useState(false);
|
|
24
24
|
const secret = type === "password";
|
|
25
25
|
return framed({
|
|
@@ -35,7 +35,7 @@ var Input = forwardRef(({ label, hint, description, error, className, mono, type
|
|
|
35
35
|
"aria-invalid": control["aria-invalid"] ?? props["aria-invalid"],
|
|
36
36
|
"aria-describedby": [props["aria-describedby"], control["aria-describedby"]].filter(Boolean).join(" ") || void 0,
|
|
37
37
|
type: secret && revealed ? "text" : type,
|
|
38
|
-
className: cx(fieldBox(), mono && "font-mono", secret && "pr-9", className)
|
|
38
|
+
className: cx(fieldBox({ size }), mono && "font-mono", secret && "pr-9", className)
|
|
39
39
|
});
|
|
40
40
|
return secret ? /* @__PURE__ */ jsxs("div", {
|
|
41
41
|
className: "relative w-full",
|
|
@@ -49,7 +49,7 @@ var Input = forwardRef(({ label, hint, description, error, className, mono, type
|
|
|
49
49
|
});
|
|
50
50
|
Input.displayName = "Input";
|
|
51
51
|
/** A multi-line text field that grows by hand. */
|
|
52
|
-
var Textarea = forwardRef(({ label, hint, description, error, className, mono, ...props }, ref) => framed({
|
|
52
|
+
var Textarea = forwardRef(({ label, hint, description, error, className, mono, size, ...props }, ref) => framed({
|
|
53
53
|
label,
|
|
54
54
|
hint,
|
|
55
55
|
description,
|
|
@@ -60,8 +60,11 @@ var Textarea = forwardRef(({ label, hint, description, error, className, mono, .
|
|
|
60
60
|
...control,
|
|
61
61
|
"aria-invalid": control["aria-invalid"] ?? props["aria-invalid"],
|
|
62
62
|
"aria-describedby": [props["aria-describedby"], control["aria-describedby"]].filter(Boolean).join(" ") || void 0,
|
|
63
|
-
className: cx(fieldBox({
|
|
63
|
+
className: cx(fieldBox({
|
|
64
|
+
size,
|
|
65
|
+
multiline: true
|
|
66
|
+
}), size === "sm" ? "min-h-16" : "min-h-24", "resize-y", mono && "font-mono", className)
|
|
64
67
|
})));
|
|
65
68
|
Textarea.displayName = "Textarea";
|
|
66
69
|
//#endregion
|
|
67
|
-
export { Input, Textarea };
|
|
70
|
+
export { Input, Textarea, framed };
|
|
@@ -5,7 +5,7 @@ export interface LoaderProps {
|
|
|
5
5
|
* loader is named with the provider's `loading` string. */
|
|
6
6
|
label?: string | undefined;
|
|
7
7
|
variant?: 'spinner' | 'logo';
|
|
8
|
-
/** Sits in a line of text or a button instead of
|
|
8
|
+
/** Sits in a line of text or a button instead of centering in its own row. */
|
|
9
9
|
inline?: boolean;
|
|
10
10
|
/** The spinner's color, such as `currentColor` inside a button. */
|
|
11
11
|
color?: string | undefined;
|
|
@@ -38,7 +38,7 @@ function MenuEntries({ entries, search, query = "" }) {
|
|
|
38
38
|
children: /* @__PURE__ */ jsx(Menu.Input, {
|
|
39
39
|
"aria-label": search.placeholder,
|
|
40
40
|
placeholder: search.placeholder,
|
|
41
|
-
className: "w-full rounded-md border border-(--theme-border) bg-(--theme-muted-panel-bg) px-2 py-1 text-[13px] text-(--theme-app) outline-none placeholder:text-(--theme-
|
|
41
|
+
className: "w-full rounded-md border border-(--theme-border) bg-(--theme-muted-panel-bg) px-2 py-1 text-[13px] text-(--theme-app) outline-none placeholder:text-(--theme-placeholder) focus:border-(--theme-accent)"
|
|
42
42
|
})
|
|
43
43
|
}),
|
|
44
44
|
/* @__PURE__ */ jsx(Menu.List, { children: /* @__PURE__ */ jsx(EntryRows, { entries: shown }) }),
|
|
@@ -15,6 +15,7 @@ export interface NumberInputProps extends Omit<NumberField.Root.Props, 'classNam
|
|
|
15
15
|
'aria-invalid'?: boolean | undefined;
|
|
16
16
|
/** Marks the field required for assistive technology without the native check `required` adds. */
|
|
17
17
|
'aria-required'?: boolean | undefined;
|
|
18
|
+
/** `sm` for dense places such as toolbars and table cells. */
|
|
18
19
|
size?: FieldBoxSize | undefined;
|
|
19
20
|
/** Applied to the box around the input and its steppers, such as a width. */
|
|
20
21
|
className?: string | undefined;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { OTPField } from '@base-ui/react/otp-field';
|
|
2
|
+
import { type FieldBoxSize } from './fieldBox.js';
|
|
3
|
+
export interface OneTimeCodeInputProps extends Omit<OTPField.Root.Props, 'className' | 'render' | 'children' | 'length' | 'style'> {
|
|
4
|
+
/** How many characters the code has. */
|
|
5
|
+
length?: number | undefined;
|
|
6
|
+
/** `sm` for dense places such as toolbars and table cells. */
|
|
7
|
+
size?: FieldBoxSize | undefined;
|
|
8
|
+
'aria-invalid'?: boolean | undefined;
|
|
9
|
+
'aria-required'?: boolean | undefined;
|
|
10
|
+
/** On the row of boxes: its margin or gap. */
|
|
11
|
+
className?: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A one-time code, such as the six digits of a sign-in check, typed one character to a box. It
|
|
15
|
+
* fills from the browser's or phone's code autofill (`autocomplete="one-time-code"`) and from a
|
|
16
|
+
* paste of the whole code, moves on as each character is typed and back on Backspace, and opens a
|
|
17
|
+
* number pad for a numeric code. The value is the code as one string; `onValueComplete` fires once
|
|
18
|
+
* every box is filled, and `autoSubmit` submits the form then.
|
|
19
|
+
*
|
|
20
|
+
* Name it with a Field or a `<label>` for its `id`, which is the first box's, or with
|
|
21
|
+
* `aria-label`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function OneTimeCodeInput({ length, size, className, 'aria-label': ariaLabel, 'aria-invalid': ariaInvalid, 'aria-required': ariaRequired, ...rootProps }: OneTimeCodeInputProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { cx } from "../cx.js";
|
|
2
|
+
import { useStrings } from "./Provider.js";
|
|
3
|
+
import { fieldBox } from "./fieldBox.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { useId } from "react";
|
|
6
|
+
import { OTPField } from "@base-ui/react/otp-field";
|
|
7
|
+
//#region src/components/OneTimeCodeInput.tsx
|
|
8
|
+
/**
|
|
9
|
+
* A one-time code, such as the six digits of a sign-in check, typed one character to a box. It
|
|
10
|
+
* fills from the browser's or phone's code autofill (`autocomplete="one-time-code"`) and from a
|
|
11
|
+
* paste of the whole code, moves on as each character is typed and back on Backspace, and opens a
|
|
12
|
+
* number pad for a numeric code. The value is the code as one string; `onValueComplete` fires once
|
|
13
|
+
* every box is filled, and `autoSubmit` submits the form then.
|
|
14
|
+
*
|
|
15
|
+
* Name it with a Field or a `<label>` for its `id`, which is the first box's, or with
|
|
16
|
+
* `aria-label`.
|
|
17
|
+
*/
|
|
18
|
+
function OneTimeCodeInput({ length = 6, size = "md", className, "aria-label": ariaLabel, "aria-invalid": ariaInvalid, "aria-required": ariaRequired, ...rootProps }) {
|
|
19
|
+
const t = useStrings().oneTimeCode;
|
|
20
|
+
const labelId = useId();
|
|
21
|
+
return /* @__PURE__ */ jsxs(OTPField.Root, {
|
|
22
|
+
length,
|
|
23
|
+
"aria-label": ariaLabel,
|
|
24
|
+
...rootProps,
|
|
25
|
+
className: cx("flex items-center", size === "sm" ? "gap-1" : "gap-2", className),
|
|
26
|
+
children: [ariaLabel && /* @__PURE__ */ jsx("span", {
|
|
27
|
+
id: labelId,
|
|
28
|
+
hidden: true,
|
|
29
|
+
children: ariaLabel
|
|
30
|
+
}), Array.from({ length }, (_, index) => /* @__PURE__ */ jsx(OTPField.Input, {
|
|
31
|
+
...index > 0 ? { "aria-label": t.character(index + 1, length) } : ariaLabel ? { "aria-labelledby": labelId } : {},
|
|
32
|
+
...ariaInvalid && { "aria-invalid": true },
|
|
33
|
+
...ariaRequired && { "aria-required": true },
|
|
34
|
+
className: cx(fieldBox({ size }), "px-0 text-center font-mono tabular-nums", size === "sm" ? "w-7" : "w-9 text-base")
|
|
35
|
+
}, index))]
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { OneTimeCodeInput };
|
|
@@ -30,6 +30,8 @@ export interface UIStrings {
|
|
|
30
30
|
share: string;
|
|
31
31
|
send: string;
|
|
32
32
|
filter: string;
|
|
33
|
+
/** A filter's choice that turns it off, showing everything. */
|
|
34
|
+
all: string;
|
|
33
35
|
loading: string;
|
|
34
36
|
loadMore: string;
|
|
35
37
|
showMore: string;
|
|
@@ -110,6 +112,16 @@ export interface UIStrings {
|
|
|
110
112
|
previousMonth: string;
|
|
111
113
|
nextMonth: string;
|
|
112
114
|
};
|
|
115
|
+
colorInput: {
|
|
116
|
+
/** Names the picker beside the hex field: the field's name, or none when it has no plain one. */
|
|
117
|
+
pick: (name?: string) => string;
|
|
118
|
+
/** Under the hex field while what is typed isn't a color. */
|
|
119
|
+
invalid: string;
|
|
120
|
+
};
|
|
121
|
+
oneTimeCode: {
|
|
122
|
+
/** Names each box after the first, which the field's label names. */
|
|
123
|
+
character: (position: number, length: number) => string;
|
|
124
|
+
};
|
|
113
125
|
theme: {
|
|
114
126
|
/** Names the light, dark or system choice. */
|
|
115
127
|
appearance: string;
|
|
@@ -131,9 +143,6 @@ export interface UIStrings {
|
|
|
131
143
|
sidebarAccent: string;
|
|
132
144
|
code: string;
|
|
133
145
|
codeStyle: (style: 'balanced' | 'vivid' | 'muted' | 'mono') => string;
|
|
134
|
-
/** Names a color input's picker, beside its hex field. */
|
|
135
|
-
pick: (name: string) => string;
|
|
136
|
-
invalidColor: string;
|
|
137
146
|
copy: string;
|
|
138
147
|
/** The thing a copy toast names. */
|
|
139
148
|
copied: string;
|
|
@@ -406,7 +415,7 @@ export interface UIStrings {
|
|
|
406
415
|
failedTitle: string;
|
|
407
416
|
unknownTitle: string;
|
|
408
417
|
unknownShort: string;
|
|
409
|
-
|
|
418
|
+
canceled: string;
|
|
410
419
|
completed: string;
|
|
411
420
|
failed: string;
|
|
412
421
|
totalSize: string;
|
|
@@ -417,9 +426,9 @@ export interface UIStrings {
|
|
|
417
426
|
expandDetails: string;
|
|
418
427
|
minimizeDetails: string;
|
|
419
428
|
sessionNotQueued: (id: string, status: string) => string;
|
|
420
|
-
|
|
429
|
+
allCanceled: (count: number) => string;
|
|
421
430
|
someUploaded: (count: number) => string;
|
|
422
|
-
|
|
431
|
+
someCanceled: (count: number) => string;
|
|
423
432
|
allUploaded: string;
|
|
424
433
|
failedSummary: (failed: number, total: number) => string;
|
|
425
434
|
failReasonGeneric: string;
|
|
@@ -45,6 +45,7 @@ var DEFAULTS = {
|
|
|
45
45
|
share: "Share",
|
|
46
46
|
send: "Send",
|
|
47
47
|
filter: "Filter",
|
|
48
|
+
all: "All",
|
|
48
49
|
loading: "Loading…",
|
|
49
50
|
loadMore: "Load more",
|
|
50
51
|
showMore: "Show more",
|
|
@@ -112,6 +113,11 @@ var DEFAULTS = {
|
|
|
112
113
|
previousMonth: "Previous month",
|
|
113
114
|
nextMonth: "Next month"
|
|
114
115
|
},
|
|
116
|
+
colorInput: {
|
|
117
|
+
pick: (name) => name ? `Pick ${name.toLowerCase()}` : "Pick a color",
|
|
118
|
+
invalid: "Enter a hex color, such as #1f6feb."
|
|
119
|
+
},
|
|
120
|
+
oneTimeCode: { character: (position, length) => `Character ${position} of ${length}` },
|
|
115
121
|
theme: {
|
|
116
122
|
appearance: "Appearance",
|
|
117
123
|
light: "Light",
|
|
@@ -133,8 +139,6 @@ var DEFAULTS = {
|
|
|
133
139
|
muted: "Muted",
|
|
134
140
|
mono: "Monochrome"
|
|
135
141
|
})[style],
|
|
136
|
-
pick: (name) => `Pick ${name.toLowerCase()}`,
|
|
137
|
-
invalidColor: "Enter a hex color, such as #1f6feb.",
|
|
138
142
|
copy: "Copy theme",
|
|
139
143
|
copied: "theme",
|
|
140
144
|
import: "Import theme",
|
|
@@ -404,7 +408,7 @@ var DEFAULTS = {
|
|
|
404
408
|
failedTitle: "Upload Failed",
|
|
405
409
|
unknownTitle: "Unknown Status",
|
|
406
410
|
unknownShort: "Unknown",
|
|
407
|
-
|
|
411
|
+
canceled: "Canceled",
|
|
408
412
|
completed: "Completed",
|
|
409
413
|
failed: "Failed",
|
|
410
414
|
totalSize: "Total size:",
|
|
@@ -414,9 +418,9 @@ var DEFAULTS = {
|
|
|
414
418
|
expandDetails: "Expand details",
|
|
415
419
|
minimizeDetails: "Minimize details",
|
|
416
420
|
sessionNotQueued: (id, status) => `Upload session with ID ${id} is not queued, current status is ${status}`,
|
|
417
|
-
|
|
421
|
+
allCanceled: (count) => `All ${count} file(s) were canceled by user.`,
|
|
418
422
|
someUploaded: (count) => `${count} file(s) uploaded successfully!`,
|
|
419
|
-
|
|
423
|
+
someCanceled: (count) => `${count} file(s) canceled by user.`,
|
|
420
424
|
allUploaded: "Upload file(s) successfully!",
|
|
421
425
|
failedSummary: (failed, total) => `${failed}/${total} files failed to upload:`,
|
|
422
426
|
failReasonGeneric: "The file(s) may be too large or the connection may have been interrupted.",
|
|
@@ -632,6 +636,14 @@ function UIProvider({ strings, navigation, data, slots, engine, children }) {
|
|
|
632
636
|
...DEFAULTS.strings.datePicker,
|
|
633
637
|
...strings?.datePicker
|
|
634
638
|
},
|
|
639
|
+
colorInput: {
|
|
640
|
+
...DEFAULTS.strings.colorInput,
|
|
641
|
+
...strings?.colorInput
|
|
642
|
+
},
|
|
643
|
+
oneTimeCode: {
|
|
644
|
+
...DEFAULTS.strings.oneTimeCode,
|
|
645
|
+
...strings?.oneTimeCode
|
|
646
|
+
},
|
|
635
647
|
theme: {
|
|
636
648
|
...DEFAULTS.strings.theme,
|
|
637
649
|
...strings?.theme
|
|
@@ -5,6 +5,7 @@ export interface SearchInputProps extends Omit<InputHTMLAttributes<HTMLInputElem
|
|
|
5
5
|
onValueChange: (value: string) => void;
|
|
6
6
|
/** Names the box, and is its placeholder unless `placeholder` says otherwise. */
|
|
7
7
|
label?: string | undefined;
|
|
8
|
+
/** `sm` for dense places such as toolbars and table cells. */
|
|
8
9
|
size?: FieldBoxSize | undefined;
|
|
9
10
|
/** On the wrapper: its width or margin. */
|
|
10
11
|
className?: string | undefined;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
2
|
export type SectionVariant = 'plain' | 'card';
|
|
3
3
|
export interface SectionProps {
|
|
4
4
|
title: ReactNode;
|
|
5
|
+
/** Under the title in muted text, saying what the section holds; it describes
|
|
6
|
+
* the section, and its toggle, to assistive technology. */
|
|
7
|
+
description?: ReactNode;
|
|
5
8
|
/** Beside the title, outside the toggle, such as an info tip or a count. */
|
|
6
9
|
beside?: ReactNode;
|
|
7
10
|
/** At the header's far end, such as an add button or a range picker. */
|
|
@@ -18,6 +21,8 @@ export interface SectionProps {
|
|
|
18
21
|
defaultOpen?: boolean | undefined;
|
|
19
22
|
/** The heading level the title sits at in the page's outline. */
|
|
20
23
|
headingLevel?: 2 | 3 | 4 | undefined;
|
|
24
|
+
/** On the section, so a link or a scroll can target it. */
|
|
25
|
+
id?: string | undefined;
|
|
21
26
|
className?: string | undefined;
|
|
22
27
|
children: ReactNode;
|
|
23
28
|
}
|
|
@@ -25,4 +30,4 @@ export interface SectionProps {
|
|
|
25
30
|
* that can fold away. Folding keeps the content mounted, so fields hold their
|
|
26
31
|
* values and validation while closed. For a line inside content that reveals
|
|
27
32
|
* more detail, use Disclosure. */
|
|
28
|
-
export declare function Section({ title, beside, actions, variant, collapsible, open, onOpenChange, defaultOpen, headingLevel, className, children, }: SectionProps): import("react").JSX.Element;
|
|
33
|
+
export declare function Section({ title, description, beside, actions, variant, collapsible, open, onOpenChange, defaultOpen, headingLevel, id, className, children, }: SectionProps): import("react").JSX.Element;
|
|
@@ -2,73 +2,92 @@ import { cx } from "../cx.js";
|
|
|
2
2
|
import { ChevronRightIcon } from "../icons.js";
|
|
3
3
|
import { collapsePanelClassName } from "./Disclosure.js";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { useId } from "react";
|
|
5
6
|
import { Collapsible } from "@base-ui/react/collapsible";
|
|
6
7
|
//#region src/components/Section.tsx
|
|
7
8
|
var rootClasses = {
|
|
8
9
|
plain: "flex w-full flex-col",
|
|
9
|
-
card: "
|
|
10
|
+
card: "panel mb-1 flex w-full flex-col"
|
|
10
11
|
};
|
|
11
12
|
var headerClasses = {
|
|
12
13
|
plain: "mb-2 flex w-full items-center gap-2 border-b border-(--theme-border) pb-1",
|
|
13
|
-
card: "flex w-full items-center gap-2 px-
|
|
14
|
+
card: "flex w-full items-center gap-2 px-3 py-3"
|
|
14
15
|
};
|
|
16
|
+
var cardBodyClassName = "px-3 pb-3";
|
|
15
17
|
var titleClasses = {
|
|
16
18
|
plain: "text-lg font-semibold",
|
|
17
|
-
card: "text-sm font-bold
|
|
19
|
+
card: "text-sm font-bold"
|
|
18
20
|
};
|
|
21
|
+
var foldedTitleClasses = {
|
|
22
|
+
plain: "",
|
|
23
|
+
card: "not-data-panel-open:text-(--theme-muted-text-color)"
|
|
24
|
+
};
|
|
25
|
+
var chevronIndent = "pl-6";
|
|
19
26
|
/** A titled part of a page or form, its title a heading in the page's outline,
|
|
20
27
|
* that can fold away. Folding keeps the content mounted, so fields hold their
|
|
21
28
|
* values and validation while closed. For a line inside content that reveals
|
|
22
29
|
* more detail, use Disclosure. */
|
|
23
|
-
function Section({ title, beside, actions, variant = "plain", collapsible = true, open, onOpenChange, defaultOpen = true, headingLevel = 3, className, children }) {
|
|
30
|
+
function Section({ title, description, beside, actions, variant = "plain", collapsible = true, open, onOpenChange, defaultOpen = true, headingLevel = 3, id, className, children }) {
|
|
24
31
|
const Heading = `h${headingLevel}`;
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
children: actions
|
|
28
|
-
});
|
|
32
|
+
const descriptionId = useId();
|
|
33
|
+
const describedBy = description ? descriptionId : void 0;
|
|
29
34
|
const titleProps = { "data-section-title": "" };
|
|
30
35
|
const fill = !beside && !actions;
|
|
36
|
+
const header = (heading) => /* @__PURE__ */ jsxs("div", {
|
|
37
|
+
className: headerClasses[variant],
|
|
38
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
39
|
+
className: "flex min-w-0 flex-1 flex-col gap-0.5",
|
|
40
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
41
|
+
className: "flex min-w-0 items-center gap-2",
|
|
42
|
+
children: [heading, beside]
|
|
43
|
+
}), description && /* @__PURE__ */ jsx("p", {
|
|
44
|
+
id: descriptionId,
|
|
45
|
+
className: cx("text-sm theme-muted-text", collapsible && chevronIndent),
|
|
46
|
+
children: description
|
|
47
|
+
})]
|
|
48
|
+
}), actions && /* @__PURE__ */ jsx("div", {
|
|
49
|
+
className: "flex shrink-0 items-center gap-2",
|
|
50
|
+
children: actions
|
|
51
|
+
})]
|
|
52
|
+
});
|
|
31
53
|
if (!collapsible) return /* @__PURE__ */ jsxs("section", {
|
|
54
|
+
id,
|
|
55
|
+
"aria-describedby": describedBy,
|
|
32
56
|
className: cx(rootClasses[variant], className),
|
|
33
|
-
children: [/* @__PURE__ */
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
beside,
|
|
42
|
-
end
|
|
43
|
-
]
|
|
44
|
-
}), children]
|
|
57
|
+
children: [header(/* @__PURE__ */ jsx(Heading, {
|
|
58
|
+
...titleProps,
|
|
59
|
+
className: cx("flex items-center", titleClasses[variant]),
|
|
60
|
+
children: title
|
|
61
|
+
})), variant === "card" ? /* @__PURE__ */ jsx("div", {
|
|
62
|
+
className: cardBodyClassName,
|
|
63
|
+
children
|
|
64
|
+
}) : children]
|
|
45
65
|
});
|
|
46
66
|
return /* @__PURE__ */ jsxs(Collapsible.Root, {
|
|
67
|
+
id,
|
|
68
|
+
"aria-describedby": describedBy,
|
|
47
69
|
open,
|
|
48
70
|
onOpenChange: (next) => onOpenChange?.(next),
|
|
49
71
|
defaultOpen,
|
|
50
72
|
className: cx(rootClasses[variant], className),
|
|
51
|
-
children: [/* @__PURE__ */
|
|
52
|
-
className:
|
|
53
|
-
children:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
})
|
|
64
|
-
}),
|
|
65
|
-
beside,
|
|
66
|
-
end
|
|
67
|
-
]
|
|
68
|
-
}), /* @__PURE__ */ jsx(Collapsible.Panel, {
|
|
73
|
+
children: [header(/* @__PURE__ */ jsx(Heading, {
|
|
74
|
+
className: cx("flex min-w-0", fill && "flex-1"),
|
|
75
|
+
children: /* @__PURE__ */ jsxs(Collapsible.Trigger, {
|
|
76
|
+
...titleProps,
|
|
77
|
+
"aria-describedby": describedBy,
|
|
78
|
+
className: cx("group flex min-w-0 cursor-pointer items-center gap-1 text-left", fill && "w-full", titleClasses[variant], foldedTitleClasses[variant]),
|
|
79
|
+
children: [/* @__PURE__ */ jsx(ChevronRightIcon, {
|
|
80
|
+
"aria-hidden": "true",
|
|
81
|
+
className: cx("shrink-0 transition-transform group-data-panel-open:rotate-90 motion-reduce:transition-none", "px-1 text-[1.25rem]")
|
|
82
|
+
}), title]
|
|
83
|
+
})
|
|
84
|
+
})), /* @__PURE__ */ jsx(Collapsible.Panel, {
|
|
69
85
|
keepMounted: true,
|
|
70
86
|
className: collapsePanelClassName,
|
|
71
|
-
children
|
|
87
|
+
children: variant === "card" ? /* @__PURE__ */ jsx("div", {
|
|
88
|
+
className: cardBodyClassName,
|
|
89
|
+
children
|
|
90
|
+
}) : children
|
|
72
91
|
})]
|
|
73
92
|
});
|
|
74
93
|
}
|
|
@@ -10,8 +10,10 @@ export interface SegmentedOption<T extends string> {
|
|
|
10
10
|
}
|
|
11
11
|
/** A few mutually exclusive choices side by side, one always current, such as
|
|
12
12
|
* a time range or what to group by. To move between views or pages, use
|
|
13
|
-
* `Tabs` with `variant="segmented"`, which looks the same.
|
|
14
|
-
*
|
|
13
|
+
* `Tabs` with `variant="segmented"`, which looks the same. To filter a list
|
|
14
|
+
* by values that may all be off, or several at once, use `ToggleGroup`. Name
|
|
15
|
+
* it with `label`, or leave that out inside a `Field group`, whose legend
|
|
16
|
+
* names it. */
|
|
15
17
|
export declare function SegmentedControl<T extends string>({ label, options, value, onValueChange, fill, iconOnly, testId, }: SegmentLayout & {
|
|
16
18
|
label?: string | undefined;
|
|
17
19
|
options: SegmentedOption<T>[];
|
|
@@ -6,8 +6,10 @@ import { ToggleGroup } from "@base-ui/react/toggle-group";
|
|
|
6
6
|
//#region src/components/SegmentedControl.tsx
|
|
7
7
|
/** A few mutually exclusive choices side by side, one always current, such as
|
|
8
8
|
* a time range or what to group by. To move between views or pages, use
|
|
9
|
-
* `Tabs` with `variant="segmented"`, which looks the same.
|
|
10
|
-
*
|
|
9
|
+
* `Tabs` with `variant="segmented"`, which looks the same. To filter a list
|
|
10
|
+
* by values that may all be off, or several at once, use `ToggleGroup`. Name
|
|
11
|
+
* it with `label`, or leave that out inside a `Field group`, whose legend
|
|
12
|
+
* names it. */
|
|
11
13
|
function SegmentedControl({ label, options, value, onValueChange, fill = false, iconOnly = false, testId }) {
|
|
12
14
|
const layout = {
|
|
13
15
|
fill,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Select as BaseSelect } from '@base-ui/react/select';
|
|
2
2
|
import type { ReactElement, ReactNode } from 'react';
|
|
3
|
+
import { type FieldBoxSize } from './fieldBox.js';
|
|
3
4
|
export interface SelectItem<Value> {
|
|
4
5
|
value: Value;
|
|
5
6
|
label: string;
|
|
@@ -24,7 +25,7 @@ export type SelectProps<Value, Multiple extends boolean | undefined = false> = O
|
|
|
24
25
|
/** A hint on the trigger button. */
|
|
25
26
|
triggerTooltip?: ReactNode;
|
|
26
27
|
/** `sm` for dense places such as toolbars and table cells. */
|
|
27
|
-
size?:
|
|
28
|
+
size?: FieldBoxSize | undefined;
|
|
28
29
|
/** The item a person is on as they move through the open list, then undefined once it
|
|
29
30
|
* closes, such as to preview a theme before it is chosen. */
|
|
30
31
|
onItemHighlighted?: ((value: Value | undefined) => void) | undefined;
|
|
@@ -36,7 +36,7 @@ function Select$1({ items, placeholder, className, "aria-label": ariaLabel, "ari
|
|
|
36
36
|
className: cx(fieldBox({ size }), triggerClassName, className),
|
|
37
37
|
children: [/* @__PURE__ */ jsx(Select.Value, {
|
|
38
38
|
placeholder,
|
|
39
|
-
className: "truncate data-placeholder:text-(--theme-
|
|
39
|
+
className: "truncate data-placeholder:text-(--theme-placeholder)",
|
|
40
40
|
children: rootProps.multiple ? (values) => values.length > 0 ? values.map(labelOf).join(", ") : placeholder : void 0
|
|
41
41
|
}), /* @__PURE__ */ jsx(Select.Icon, {
|
|
42
42
|
className: "shrink-0 text-(--theme-muted-text-color)",
|
|
@@ -9,14 +9,14 @@ interface StatusBadgeProps {
|
|
|
9
9
|
variant?: BadgeVariant;
|
|
10
10
|
/** Show animated pulse indicator */
|
|
11
11
|
pulse?: boolean;
|
|
12
|
-
/** Show a still indicator in the variant's
|
|
12
|
+
/** Show a still indicator in the variant's color */
|
|
13
13
|
dot?: boolean;
|
|
14
14
|
/** Size */
|
|
15
15
|
size?: 'sm' | 'md';
|
|
16
16
|
/** Additional class */
|
|
17
17
|
className?: string;
|
|
18
18
|
}
|
|
19
|
-
/** A line of text in a variant's
|
|
19
|
+
/** A line of text in a variant's color, for a status that stands beside a
|
|
20
20
|
* dot rather than inside a badge. */
|
|
21
21
|
export declare function statusTextClass(variant: BadgeVariant): string;
|
|
22
22
|
export declare function StatusBadge({ children, variant, pulse, dot, size, className, }: StatusBadgeProps): import("react").JSX.Element;
|
|
@@ -2,7 +2,7 @@ import { cx } from "../cx.js";
|
|
|
2
2
|
import { toneFill, toneSurface, toneText } from "./tone.js";
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
//#region src/components/StatusBadge.tsx
|
|
5
|
-
/** A line of text in a variant's
|
|
5
|
+
/** A line of text in a variant's color, for a status that stands beside a
|
|
6
6
|
* dot rather than inside a badge. */
|
|
7
7
|
function statusTextClass(variant) {
|
|
8
8
|
return toneText[variant];
|
package/dist/components/Tabs.js
CHANGED
|
@@ -52,6 +52,7 @@ function Tabs$1({ label, items, value, defaultValue, onValueChange, variant = "l
|
|
|
52
52
|
},
|
|
53
53
|
orientation: layout.iconOnly ? "vertical" : "horizontal",
|
|
54
54
|
"data-testid": testId,
|
|
55
|
+
className: children ? void 0 : "contents",
|
|
55
56
|
children: [showRow && /* @__PURE__ */ jsxs("div", {
|
|
56
57
|
className: cx("flex items-center justify-between gap-2", !segmented && "border-b border-(--theme-border)", sticky && stickyClasses[sticky], className),
|
|
57
58
|
children: [/* @__PURE__ */ jsxs(Tabs.List, {
|
|
@@ -2,18 +2,19 @@ import { cx } from "../cx.js";
|
|
|
2
2
|
import { useStrings } from "./Provider.js";
|
|
3
3
|
import { useCopy } from "./useCopy.js";
|
|
4
4
|
import { Button } from "./Button.js";
|
|
5
|
+
import { parseColor, toHex } from "../theme/color.js";
|
|
6
|
+
import { CODE_STYLES, DEFAULT_THEME, THEME_PRESETS, modeOf, parseTheme, schemeFor, serializeTheme } from "../theme/model.js";
|
|
7
|
+
import { deriveTheme, generateTheme } from "../theme/derive.js";
|
|
8
|
+
import { prefersWideGamut } from "../theme/index.js";
|
|
9
|
+
import { Field } from "./Field.js";
|
|
5
10
|
import { fieldBox } from "./fieldBox.js";
|
|
11
|
+
import { Textarea } from "./Input.js";
|
|
12
|
+
import { ColorInput } from "./ColorInput.js";
|
|
6
13
|
import { Disclosure } from "./Disclosure.js";
|
|
7
14
|
import { Switch } from "./Switch.js";
|
|
8
|
-
import { Field } from "./Field.js";
|
|
9
|
-
import { Textarea } from "./Input.js";
|
|
10
15
|
import { Select } from "./Select.js";
|
|
11
16
|
import { SegmentedControl } from "./SegmentedControl.js";
|
|
12
17
|
import { Slider } from "./Slider.js";
|
|
13
|
-
import { parseColor, toHex } from "../theme/color.js";
|
|
14
|
-
import { CODE_STYLES, DEFAULT_THEME, THEME_PRESETS, modeOf, parseTheme, schemeFor, serializeTheme } from "../theme/model.js";
|
|
15
|
-
import { deriveTheme, generateTheme } from "../theme/derive.js";
|
|
16
|
-
import { prefersWideGamut } from "../theme/index.js";
|
|
17
18
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
18
19
|
import { useId, useMemo, useState } from "react";
|
|
19
20
|
//#region src/components/ThemeEditor.tsx
|
|
@@ -101,15 +102,15 @@ function ThemeEditor({ value, onChange, mode, onModeChange, preference, onPrefer
|
|
|
101
102
|
onValueChange: setEditing
|
|
102
103
|
})
|
|
103
104
|
}),
|
|
104
|
-
/* @__PURE__ */ jsx(
|
|
105
|
+
/* @__PURE__ */ jsx(ColorInput, {
|
|
105
106
|
label: t.base,
|
|
106
107
|
value: seed.base,
|
|
107
|
-
|
|
108
|
+
onValueChange: (base) => setSeed({ base })
|
|
108
109
|
}),
|
|
109
|
-
/* @__PURE__ */ jsx(
|
|
110
|
+
/* @__PURE__ */ jsx(ColorInput, {
|
|
110
111
|
label: t.accent,
|
|
111
112
|
value: seed.accent,
|
|
112
|
-
|
|
113
|
+
onValueChange: (accent) => setSeed({ accent })
|
|
113
114
|
}),
|
|
114
115
|
/* @__PURE__ */ jsx(Field, {
|
|
115
116
|
label: t.contrast,
|
|
@@ -141,20 +142,20 @@ function ThemeEditor({ value, onChange, mode, onModeChange, preference, onPrefer
|
|
|
141
142
|
}),
|
|
142
143
|
scheme.sidebar && /* @__PURE__ */ jsxs("div", {
|
|
143
144
|
className: "flex flex-col gap-5 border-l-2 border-(--theme-border) pl-4",
|
|
144
|
-
children: [/* @__PURE__ */ jsx(
|
|
145
|
+
children: [/* @__PURE__ */ jsx(ColorInput, {
|
|
145
146
|
label: t.sidebarBase,
|
|
146
147
|
value: scheme.sidebar.base ?? derived["--theme-sidebar-bg"],
|
|
147
|
-
|
|
148
|
+
onValueChange: (base) => update({
|
|
148
149
|
...scheme,
|
|
149
150
|
sidebar: {
|
|
150
151
|
...scheme.sidebar,
|
|
151
152
|
base
|
|
152
153
|
}
|
|
153
154
|
})
|
|
154
|
-
}), /* @__PURE__ */ jsx(
|
|
155
|
+
}), /* @__PURE__ */ jsx(ColorInput, {
|
|
155
156
|
label: t.sidebarAccent,
|
|
156
157
|
value: scheme.sidebar.accent ?? seed.accent,
|
|
157
|
-
|
|
158
|
+
onValueChange: (accent) => update({
|
|
158
159
|
...scheme,
|
|
159
160
|
sidebar: {
|
|
160
161
|
...scheme.sidebar,
|
|
@@ -214,44 +215,6 @@ function Swatch({ colors }) {
|
|
|
214
215
|
}, i))
|
|
215
216
|
});
|
|
216
217
|
}
|
|
217
|
-
/** A color as a picker beside a hex field. A half-typed hex stays in the field, marked, until it parses. */
|
|
218
|
-
function ColorField({ label, value, onChange }) {
|
|
219
|
-
const { theme: t } = useStrings();
|
|
220
|
-
const [draft, setDraft] = useState(null);
|
|
221
|
-
const parsed = parseColor(value);
|
|
222
|
-
const hex = parsed ? toHex(parsed) : "#000000";
|
|
223
|
-
const invalid = draft !== null && parseColor(draft) === null;
|
|
224
|
-
return /* @__PURE__ */ jsx(Field, {
|
|
225
|
-
label,
|
|
226
|
-
error: invalid ? t.invalidColor : void 0,
|
|
227
|
-
children: (control) => /* @__PURE__ */ jsxs("div", {
|
|
228
|
-
className: "flex items-center gap-2",
|
|
229
|
-
children: [/* @__PURE__ */ jsx("input", {
|
|
230
|
-
type: "color",
|
|
231
|
-
"aria-label": t.pick(label),
|
|
232
|
-
value: hex,
|
|
233
|
-
onChange: (e) => {
|
|
234
|
-
setDraft(null);
|
|
235
|
-
onChange(e.target.value);
|
|
236
|
-
},
|
|
237
|
-
className: "h-8 w-10 shrink-0 cursor-pointer rounded-md border border-(--theme-border) bg-transparent p-0.5"
|
|
238
|
-
}), /* @__PURE__ */ jsx("input", {
|
|
239
|
-
...control,
|
|
240
|
-
className: fieldBox({ size: "sm" }),
|
|
241
|
-
spellCheck: false,
|
|
242
|
-
value: draft ?? value,
|
|
243
|
-
onChange: (e) => {
|
|
244
|
-
const text = e.target.value;
|
|
245
|
-
if (parseColor(text)) {
|
|
246
|
-
setDraft(null);
|
|
247
|
-
onChange(text.trim().toLowerCase());
|
|
248
|
-
} else setDraft(text);
|
|
249
|
-
},
|
|
250
|
-
onBlur: () => setDraft(null)
|
|
251
|
-
})]
|
|
252
|
-
})
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
218
|
function ImportTheme({ onImport }) {
|
|
256
219
|
const { theme: t } = useStrings();
|
|
257
220
|
const [open, setOpen] = useState(false);
|