@crewlethq/ui 0.61.0 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +8 -0
  2. package/dist/AgentHandoffPanel/index.js +1 -1
  3. package/dist/AppShell/index.js +1 -1
  4. package/dist/ArtifactBar/index.js +5 -5
  5. package/dist/ArtifactCard/index.js +3 -3
  6. package/dist/AttachmentChip/AttachmentChip.d.ts +37 -0
  7. package/dist/AttachmentChip/index.d.ts +3 -0
  8. package/dist/AttachmentChip/index.js +6 -0
  9. package/dist/AttachmentChip-XF4KPQ3G.css +16 -0
  10. package/dist/AvatarPicker/index.js +6 -6
  11. package/dist/Canvas/index.js +1 -1
  12. package/dist/CanvasBoard/index.js +1 -1
  13. package/dist/CanvasToolbar/index.js +1 -1
  14. package/dist/Combobox/index.js +1 -1
  15. package/dist/CommandPalette/index.js +1 -1
  16. package/dist/CommentThread/index.js +1 -1
  17. package/dist/ContrastBadge/index.js +2 -2
  18. package/dist/ContrastHelp/index.js +3 -3
  19. package/dist/DataTable/index.js +1 -1
  20. package/dist/DataView/index.js +1 -1
  21. package/dist/DateTimePicker/index.js +1 -1
  22. package/dist/DeepWorkCard/DeepWorkCard.d.ts +85 -0
  23. package/dist/DeepWorkCard/index.d.ts +3 -0
  24. package/dist/DeepWorkCard/index.js +17 -0
  25. package/dist/DeepWorkCard-DGHRIQDM.css +80 -0
  26. package/dist/DocTabsEditor/index.js +1 -1
  27. package/dist/DownloadButton/DownloadButton.d.ts +7 -1
  28. package/dist/DownloadButton/index.js +1 -1
  29. package/dist/FileList/FileList.d.ts +42 -0
  30. package/dist/FileList/index.d.ts +3 -0
  31. package/dist/FileList/index.js +3 -0
  32. package/dist/FileList-TGDNV2QS.css +89 -0
  33. package/dist/FollowBanner/index.js +1 -1
  34. package/dist/HuePicker/index.js +5 -5
  35. package/dist/InlineEditor/index.js +1 -1
  36. package/dist/LinkInterstitial/index.js +1 -1
  37. package/dist/ListInput/index.js +1 -1
  38. package/dist/LogoSlot/index.js +3 -3
  39. package/dist/MarkdownEditor/index.js +5 -5
  40. package/dist/Menu/index.js +1 -1
  41. package/dist/MergeConflicts/index.js +5 -5
  42. package/dist/Modal/index.js +1 -1
  43. package/dist/OpenInAppCard/index.js +2 -2
  44. package/dist/PeekRail/index.js +1 -1
  45. package/dist/PresenterView/index.js +1 -1
  46. package/dist/PrincipalPicker/index.js +2 -2
  47. package/dist/ResultTableCard/index.js +3 -3
  48. package/dist/RichEditor/index.js +1 -1
  49. package/dist/SegmentedControl/index.js +4 -4
  50. package/dist/SelectionBar/index.js +1 -1
  51. package/dist/SetupWizard/index.js +2 -2
  52. package/dist/ShareDialog/index.js +1 -1
  53. package/dist/SheetColumnEditor/index.js +6 -6
  54. package/dist/SheetGrid/index.js +3 -3
  55. package/dist/SlideCompare/index.js +1 -1
  56. package/dist/SlideFilmstrip/index.js +1 -1
  57. package/dist/Switcher/index.js +1 -1
  58. package/dist/Tabs/index.js +3 -3
  59. package/dist/ThemeGallery/index.js +1 -1
  60. package/dist/ThemeSwitcher/index.js +5 -5
  61. package/dist/TimeRangePicker/index.js +5 -5
  62. package/dist/TimeWindowPicker/index.js +1 -1
  63. package/dist/TreeCanvas/index.js +1 -1
  64. package/dist/ValueField/ValueField.d.ts +117 -0
  65. package/dist/ValueField/index.d.ts +10 -0
  66. package/dist/ValueField/index.js +15 -0
  67. package/dist/ValueField/references.d.ts +66 -0
  68. package/dist/ValueField-EIBD6RYS.css +13 -0
  69. package/dist/VersionCompare/index.js +5 -5
  70. package/dist/{chunk-53NTMTRM.js → chunk-6IGIYOTV.js} +1 -1
  71. package/dist/chunk-CZXF6EFK.js +52 -0
  72. package/dist/{chunk-5ZGJ22CO.js → chunk-DHIO6Q75.js} +1 -1
  73. package/dist/{chunk-3BQWARG2.js → chunk-F7VBYCW2.js} +1 -1
  74. package/dist/{chunk-5G76O23M.js → chunk-IJIC4COR.js} +1 -1
  75. package/dist/{chunk-RPHQNXE5.js → chunk-IOZFPFQS.js} +1 -1
  76. package/dist/{chunk-NL72YZWF.js → chunk-ISHLFPNN.js} +1 -1
  77. package/dist/{chunk-5KW63GZ3.js → chunk-JAOJLEYB.js} +1 -1
  78. package/dist/{chunk-MOW65OIJ.js → chunk-JPVORBWC.js} +1 -1
  79. package/dist/chunk-KYTOEWJD.js +56 -0
  80. package/dist/chunk-LA4PX7Z6.js +118 -0
  81. package/dist/{chunk-LG6TUGET.js → chunk-NSCYGUDG.js} +2 -0
  82. package/dist/chunk-OD3Z6QKN.js +237 -0
  83. package/dist/{chunk-OM6CPZB7.js → chunk-OIMWGV2N.js} +1 -1
  84. package/dist/{chunk-5PMFRAGL.js → chunk-OU4FLGOZ.js} +1 -1
  85. package/dist/{chunk-5MN2HISF.js → chunk-PHQPQZUX.js} +1 -1
  86. package/dist/{chunk-VC2M2E7N.js → chunk-PK2P2QH6.js} +4 -3
  87. package/dist/{chunk-NRMXUNLR.js → chunk-QCVAVAF6.js} +1 -1
  88. package/dist/{chunk-LND6XSXN.js → chunk-S2VMOITT.js} +1 -1
  89. package/dist/{chunk-VRPDQSXZ.js → chunk-SELUJSTZ.js} +2 -2
  90. package/dist/{chunk-3633T7EJ.js → chunk-WSV3MBOE.js} +1 -1
  91. package/dist/generated/index.d.ts +4 -0
  92. package/dist/generated/index.js +88 -84
  93. package/dist/index.js +88 -84
  94. package/dist/styles.css +210 -0
  95. package/package.json +3 -3
  96. package/dist/{Editor-DM7X24B7.js → Editor-GHHWWXXL.js} +1 -1
  97. package/dist/{chunk-VN3DCUED.js → chunk-27JCHL64.js} +1 -1
  98. package/dist/{chunk-T4THNJ6E.js → chunk-5DCY2QUY.js} +1 -1
  99. package/dist/{chunk-WDRYUMN6.js → chunk-BSAQE7PO.js} +1 -1
  100. package/dist/{chunk-I43D5K6A.js → chunk-CT6I36FH.js} +1 -1
  101. package/dist/{chunk-MHFTG2LO.js → chunk-EBCH3MRX.js} +1 -1
  102. package/dist/{chunk-OXZKRUGM.js → chunk-TXQNWGUD.js} +0 -0
  103. package/dist/{chunk-WXSGCYZO.js → chunk-VVVB3OBW.js} +1 -1
@@ -0,0 +1,117 @@
1
+ import { type ReactNode } from 'react';
2
+ /**
3
+ * What a value field holds, which decides its control and what it does to a
4
+ * value on its way through.
5
+ *
6
+ * - `text`: free text, spaces kept.
7
+ * - `multiline`: prose in a textarea, every space and newline kept, spell check on.
8
+ * - `secret`: a credential, masked unless the value is a whole reference.
9
+ * - `url`: an address, wearing an `https://` affix, whitespace dropped.
10
+ * - `id` and `email`: one token, whitespace dropped.
11
+ * - `choice` and `handle`: one of `choices`, picked from a listbox.
12
+ */
13
+ export type ValueFieldKind = 'text' | 'multiline' | 'secret' | 'url' | 'id' | 'choice' | 'handle' | 'email';
14
+ /** One option of a `choice` or `handle` field. */
15
+ export interface ValueFieldChoice {
16
+ value: string;
17
+ label: string;
18
+ /** A sentence saying what picking this one does: drawn under the option, and on the help line once chosen. */
19
+ hint?: string | undefined;
20
+ }
21
+ /** The words a value field draws itself. */
22
+ export interface ValueFieldLabels {
23
+ /** Names the completion list. "Secrets" by default. */
24
+ references: string;
25
+ /** The choice placeholder while nothing is chosen. "Choose one" by default. */
26
+ choose: string;
27
+ }
28
+ export interface ValueFieldProps {
29
+ label: string;
30
+ /** A mark drawn before the label, such as a third party's own logo. */
31
+ mark?: ReactNode;
32
+ kind?: ValueFieldKind | undefined;
33
+ value: string;
34
+ onChange: (value: string) => void;
35
+ /** Where the value comes from, or what shape it takes. */
36
+ help?: ReactNode;
37
+ /** Why the last value was refused. */
38
+ error?: ReactNode;
39
+ placeholder?: string | undefined;
40
+ /** What a `choice` or `handle` field offers; ignored by every other kind. */
41
+ choices?: readonly ValueFieldChoice[] | undefined;
42
+ disabled?: boolean | undefined;
43
+ /**
44
+ * Whether an answer is required. REQUIRED IS THE UNMARKED DEFAULT: `false`
45
+ * says "(optional)" beside the label, `true` sets `aria-required` and draws
46
+ * nothing unless `markRequired` says the requiredness is news. Most fields
47
+ * on a form are required, and marking them all is noise that teaches a
48
+ * reader to skip the note.
49
+ */
50
+ required?: boolean | undefined;
51
+ /**
52
+ * Says "(required)" beside the label, for a field whose requiredness is
53
+ * NEWS: one that appeared because of an answer above it. Read only with
54
+ * `required`.
55
+ */
56
+ markRequired?: boolean | undefined;
57
+ autoFocus?: boolean | undefined;
58
+ /**
59
+ * The stored entry names offered when somebody types `$`, completed into a
60
+ * whole `${NAME}`. NAMES ONLY: a value never reaches the field, so a list
61
+ * that could not be assembled leaves the field exactly as it was.
62
+ */
63
+ references?: readonly string[] | undefined;
64
+ /**
65
+ * Called as the completion list is about to open, so the caller can make
66
+ * sure the names are current. On the way in only, never per keystroke.
67
+ */
68
+ onReferencesNeeded?: (() => void) | undefined;
69
+ /**
70
+ * Whether a value is exactly one reference, which keeps a `secret` field
71
+ * readable and lets a `url` field's affix step aside. [isWholeReference]
72
+ * by default; a product with its own reference grammar passes it here.
73
+ */
74
+ isReference?: ((value: string) => boolean) | undefined;
75
+ /** How many lines a `multiline` field shows before it scrolls. Three by default. */
76
+ rows?: number | undefined;
77
+ /** Show the help line only while the field has focus. See [FormField]. */
78
+ helperOnFocus?: boolean | undefined;
79
+ labels?: Partial<ValueFieldLabels> | undefined;
80
+ className?: string | undefined;
81
+ }
82
+ /**
83
+ * A labelled value: [FormField] with the control a kind of value needs, and
84
+ * the rules every form holding such values otherwise rewrites.
85
+ *
86
+ * A SECRET FIELD IS A PASSWORD FIELD, and that is not decoration: `type` is
87
+ * what keeps the value out of an autofill store, out of a screenshot and out
88
+ * of the accessibility tree as text.
89
+ *
90
+ * A REFERENCE IS NOT A CREDENTIAL, so it is not masked. A secret whose value
91
+ * is wholly a `${NAME}` holds the NAME of a stored entry, and the reader has
92
+ * to be able to see which entry it points at. Typing over it masks again the
93
+ * moment it stops being a whole reference, so a credential is never on screen.
94
+ *
95
+ * TYPING `$` OFFERS THE STORED ENTRIES, from `references`, ranked closest
96
+ * first and written in as a whole `${NAME}` with the caret after it. Tab and
97
+ * Enter take the highlighted name, Escape closes the list and keeps what was
98
+ * typed, and a press outside closes only the list.
99
+ *
100
+ * A URL FIELD WEARS ITS SCHEME. An `https://` affix sits inside the box, is
101
+ * read once as part of the value, and is written into it. It steps aside for
102
+ * a value that carries `http://` and for one starting with `$` (a reference
103
+ * carries its own scheme once it resolves), and a pasted `https://` is not
104
+ * doubled onto it.
105
+ *
106
+ * A SINGLE TOKEN TAKES NO WHITESPACE. A `url`, `id` or `email` drops it as it
107
+ * is typed or pasted: a space around one is invisible in the box and fatal
108
+ * wherever it is used. No field asserts `type="email"`, because the browser
109
+ * would refuse a reference for having no "@" in it; `inputMode` still offers
110
+ * the right keyboard.
111
+ *
112
+ * A CHOICE IS THE LISTBOX, which can draw each choice's hint under it. The
113
+ * chosen one's hint also joins the help line, and a stored answer the list
114
+ * no longer offers keeps a row of its own rather than vanishing into a
115
+ * different selection.
116
+ */
117
+ export declare function ValueField({ label, mark, kind, value, onChange, help, error, placeholder, choices, disabled, required, markRequired, autoFocus, references, onReferencesNeeded, isReference, rows, helperOnFocus, labels, className, }: ValueFieldProps): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import '../Input/Input.css';
2
+ import '../VisuallyHidden/VisuallyHidden.css';
3
+ import '../HitArea/HitArea.css';
4
+ import '../Combobox/Combobox.css';
5
+ import '../Select/Select.css';
6
+ import './ValueField.css';
7
+ export { ValueField } from './ValueField.js';
8
+ export type { ValueFieldChoice, ValueFieldKind, ValueFieldLabels, ValueFieldProps } from './ValueField.js';
9
+ export { REFERENCE_NAME_PATTERN, completeReference, isWholeReference, rankReferences, referenceAt, urlSchemeOf, } from './references.js';
10
+ export type { ReferenceQuery } from './references.js';
@@ -0,0 +1,15 @@
1
+ export { REFERENCE_NAME_PATTERN, ValueField, completeReference, isWholeReference, rankReferences, referenceAt, urlSchemeOf } from '../chunk-OD3Z6QKN.js';
2
+ import '../chunk-XQZ6EWOE.js';
3
+ import '../chunk-PK2P2QH6.js';
4
+ import '../chunk-7KHM2FZH.js';
5
+ import '../chunk-TLIJG4TP.js';
6
+ import '../chunk-PGCLHYVP.js';
7
+ import '../chunk-PQADV6P6.js';
8
+ import '../chunk-2G355KDJ.js';
9
+ import '../chunk-OMV5W53A.js';
10
+ import '../chunk-2YTOOH3A.js';
11
+ import '../chunk-H5XTJ7GJ.js';
12
+ import '../chunk-2XWFWNDT.js';
13
+ import '../chunk-NUZHC6MM.js';
14
+ import '../chunk-UT6CW3C7.js';
15
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Completing a `${NAME}` reference from a list of stored entry names.
3
+ *
4
+ * A value field takes either a value or a reference to one, and the reference
5
+ * has to be typed exactly: a name off by a character resolves to nothing,
6
+ * which reads as configured on every surface while whatever it feeds refuses
7
+ * every use. These helpers are what lets a field offer the names it knows
8
+ * rather than leaving the reader to copy one across from another screen.
9
+ */
10
+ /** The shape of a reference's name: a letter or underscore, then letters, digits and underscores. */
11
+ export declare const REFERENCE_NAME_PATTERN = "[A-Za-z_][A-Za-z0-9_]*";
12
+ /**
13
+ * Whether a value is exactly one `${NAME}` reference, trimmed first.
14
+ *
15
+ * This is the default a [ValueField] asks when deciding whether a secret's
16
+ * value is a name (readable) or a credential (masked). A product whose
17
+ * reference grammar is stricter passes its own predicate as `isReference`.
18
+ */
19
+ export declare function isWholeReference(value: string): boolean;
20
+ /** Where a reference is being typed, and what has been typed of it. */
21
+ export interface ReferenceQuery {
22
+ /** Index of the `$` that opens it. */
23
+ start: number;
24
+ /** What follows the `$`, with any `{` stripped. */
25
+ query: string;
26
+ }
27
+ /**
28
+ * The `${...}` under the caret, or null.
29
+ *
30
+ * IT SCANS BACK FROM THE CARET rather than matching the whole value, because
31
+ * a field can hold a reference among other text and the one being edited is
32
+ * the one being completed. The scan stops at whitespace and at a `}`: the
33
+ * first because no name contains one, the second because a reference that is
34
+ * already closed is finished, and offering to complete it again would replace
35
+ * a name somebody had chosen.
36
+ */
37
+ export declare function referenceAt(value: string, caret: number): ReferenceQuery | null;
38
+ /**
39
+ * The names ordered by how closely they match what has been typed.
40
+ *
41
+ * Three tiers, in the order somebody means them: a name that STARTS with the
42
+ * query, then one that CONTAINS it, then one whose letters appear in order.
43
+ * Case is ignored, because a name is upper snake case and nobody holds shift
44
+ * to filter a list. An empty query keeps every name in the order given: the
45
+ * point of typing `$` alone is to see what there is.
46
+ */
47
+ export declare function rankReferences(names: readonly string[], query: string): string[];
48
+ /**
49
+ * The value with the chosen name written in as a whole `${NAME}`, and where
50
+ * the caret goes.
51
+ *
52
+ * CLOSED BRACES, always, and the caret lands after them: a reference resolves
53
+ * only when it is whole, and a half-written one is a literal that reaches its
54
+ * destination as the characters somebody typed.
55
+ */
56
+ export declare function completeReference(value: string, caret: number, at: ReferenceQuery, name: string): {
57
+ value: string;
58
+ caret: number;
59
+ };
60
+ /**
61
+ * The scheme a value already carries, `https://`, `http://` or empty.
62
+ *
63
+ * Matched without regard to case, because a pasted address is whatever the
64
+ * address bar had.
65
+ */
66
+ export declare function urlSchemeOf(value: string): '' | 'https://' | 'http://';
@@ -0,0 +1,13 @@
1
+ /*
2
+ * ValueField: a labelled value with the control its kind needs.
3
+ *
4
+ * The row is FormField's and every control is the package's own; what is
5
+ * drawn here is the mark a label may carry, such as a third party's logo,
6
+ * set on the label's line ahead of its words.
7
+ */
8
+
9
+ .crewlet-value-field__label {
10
+ display: inline-flex;
11
+ align-items: center;
12
+ gap: var(--spacing-1);
13
+ }
@@ -1,18 +1,18 @@
1
- export { VERSION_COMPARE_LABELS, VERSION_COMPARE_LENSES, VersionCompare } from '../chunk-NL72YZWF.js';
1
+ export { VERSION_COMPARE_LABELS, VERSION_COMPARE_LENSES, VersionCompare } from '../chunk-ISHLFPNN.js';
2
2
  import '../chunk-AOFVXE6V.js';
3
3
  import '../chunk-OOC7Q67K.js';
4
- import '../chunk-3BQWARG2.js';
5
- import '../chunk-VN3DCUED.js';
6
- import '../chunk-WIATRXEJ.js';
4
+ import '../chunk-F7VBYCW2.js';
5
+ import '../chunk-27JCHL64.js';
7
6
  import '../chunk-EGMQURBR.js';
7
+ import '../chunk-WIATRXEJ.js';
8
8
  import '../chunk-PPUR46MK.js';
9
9
  import '../chunk-5KRRJNQO.js';
10
10
  import '../chunk-PQADV6P6.js';
11
11
  import '../chunk-LODRX4FU.js';
12
12
  import '../chunk-7QTPJDRF.js';
13
- import '../chunk-XSPCITPN.js';
14
13
  import '../chunk-OMV5W53A.js';
15
14
  import '../chunk-2YTOOH3A.js';
15
+ import '../chunk-XSPCITPN.js';
16
16
  import '../chunk-H5XTJ7GJ.js';
17
17
  import '../chunk-2XWFWNDT.js';
18
18
  import '../chunk-NUZHC6MM.js';
@@ -1,5 +1,5 @@
1
1
  import { useThemePreference, useDensityPreference } from './chunk-Z24ZUSTX.js';
2
- import { SegmentedControl } from './chunk-3BQWARG2.js';
2
+ import { SegmentedControl } from './chunk-F7VBYCW2.js';
3
3
  import { SunGlyph, MonitorGlyph, MoonGlyph } from '@crewlethq/icons/glyphs';
4
4
  import { jsx } from 'react/jsx-runtime';
5
5
 
@@ -0,0 +1,52 @@
1
+ import { VisuallyHidden } from './chunk-UT6CW3C7.js';
2
+ import { cx } from './chunk-ODEQTPFM.js';
3
+ import './FileList-TGDNV2QS.css';
4
+ import { useState } from 'react';
5
+ import { FileTextGlyph, ImageGlyph } from '@crewlethq/icons/glyphs';
6
+ import { jsx, jsxs } from 'react/jsx-runtime';
7
+
8
+ function FileRow({ file }) {
9
+ const [broken, setBroken] = useState(false);
10
+ const preview = file.preview !== void 0 && file.preview !== "" && !broken ? file.preview : void 0;
11
+ return /* @__PURE__ */ jsxs("li", { className: "crewlet-file-list__file", children: [
12
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-file-list__row", children: [
13
+ /* @__PURE__ */ jsx("span", { className: "crewlet-file-list__mark", "aria-hidden": "true", children: file.preview === void 0 ? /* @__PURE__ */ jsx(FileTextGlyph, { size: "sm" }) : /* @__PURE__ */ jsx(ImageGlyph, { size: "sm" }) }),
14
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-file-list__text", children: [
15
+ /* @__PURE__ */ jsx("span", { className: "crewlet-file-list__name", title: file.name, children: file.name }),
16
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-file-list__meta", children: [
17
+ file.type,
18
+ /* @__PURE__ */ jsx(VisuallyHidden, { children: "," }),
19
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: " \xB7 " }),
20
+ file.size
21
+ ] })
22
+ ] }),
23
+ file.action === void 0 || file.action === null ? null : /* @__PURE__ */ jsx("span", { className: "crewlet-file-list__action", children: file.action })
24
+ ] }),
25
+ preview === void 0 ? null : /* @__PURE__ */ jsx("div", { className: "crewlet-file-list__preview", children: /* @__PURE__ */ jsx(
26
+ "img",
27
+ {
28
+ src: preview,
29
+ alt: "",
30
+ loading: "lazy",
31
+ decoding: "async",
32
+ referrerPolicy: "no-referrer",
33
+ draggable: false,
34
+ onError: () => setBroken(true)
35
+ }
36
+ ) })
37
+ ] });
38
+ }
39
+ function FileList({ files, label, className, ...rest }) {
40
+ const seen = /* @__PURE__ */ new Set();
41
+ for (const file of files) {
42
+ if (seen.has(file.id)) throw new RangeError(`FileList file ids must be unique; "${file.id}" is used twice`);
43
+ seen.add(file.id);
44
+ }
45
+ return (
46
+ /* The role is restated for WebKit, which drops it from a list with no markers. */
47
+ /* eslint-disable-next-line jsx-a11y/no-redundant-roles */
48
+ /* @__PURE__ */ jsx("ul", { ...rest, role: "list", "aria-label": label, className: cx("crewlet-file-list", className), children: files.map((file) => /* @__PURE__ */ jsx(FileRow, { file }, file.id)) })
49
+ );
50
+ }
51
+
52
+ export { FileList };
@@ -1,4 +1,4 @@
1
- import { HuePicker } from './chunk-NRMXUNLR.js';
1
+ import { HuePicker } from './chunk-QCVAVAF6.js';
2
2
  import { Popover } from './chunk-KHJIEPZV.js';
3
3
  import { NODE_HUE_NAMES } from './chunk-AYKXMIOR.js';
4
4
  import { CharacterPicker } from './chunk-SNQRGH4A.js';
@@ -1,4 +1,4 @@
1
- import { tabId } from './chunk-VN3DCUED.js';
1
+ import { tabId } from './chunk-27JCHL64.js';
2
2
  import { useRoving, tabStop } from './chunk-EGMQURBR.js';
3
3
  import { Count } from './chunk-5KRRJNQO.js';
4
4
  import { HIT_AREA_CLASS } from './chunk-2YTOOH3A.js';
@@ -1,4 +1,4 @@
1
- import { SegmentedControl } from './chunk-3BQWARG2.js';
1
+ import { SegmentedControl } from './chunk-F7VBYCW2.js';
2
2
  import { Button } from './chunk-7QTPJDRF.js';
3
3
  import { cx } from './chunk-ODEQTPFM.js';
4
4
  import './MergeConflicts-O44ESH4T.css';
@@ -1,4 +1,4 @@
1
- import { Combobox } from './chunk-VC2M2E7N.js';
1
+ import { Combobox } from './chunk-PK2P2QH6.js';
2
2
  import { PRINCIPAL_KINDS, PrincipalAvatar } from './chunk-CI3VPIJN.js';
3
3
  import { cx } from './chunk-ODEQTPFM.js';
4
4
  import './PrincipalPicker-7NNZTGUP.css';
@@ -1,5 +1,5 @@
1
1
  import { diffLines, diffStat, collapseDiff, DiffSummary, DiffView } from './chunk-AOFVXE6V.js';
2
- import { SegmentedControl } from './chunk-3BQWARG2.js';
2
+ import { SegmentedControl } from './chunk-F7VBYCW2.js';
3
3
  import { EmptyState } from './chunk-PPUR46MK.js';
4
4
  import { useHeadingLevel, headingTag, nextHeadingLevel, HeadingLevelProvider } from './chunk-PQADV6P6.js';
5
5
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,5 +1,5 @@
1
1
  import { Tooltip } from './chunk-I33UIUZD.js';
2
- import { SegmentedControl } from './chunk-3BQWARG2.js';
2
+ import { SegmentedControl } from './chunk-F7VBYCW2.js';
3
3
  import { ArtifactIcon } from './chunk-AVL52EME.js';
4
4
  import { isApplePlatform, Kbd } from './chunk-ACRRRPWT.js';
5
5
  import { Menu } from './chunk-LODRX4FU.js';
@@ -1,5 +1,5 @@
1
1
  import { FileDrop, FilePickButton } from './chunk-2JHGPXYG.js';
2
- import { contrastRatio } from './chunk-WDRYUMN6.js';
2
+ import { contrastRatio } from './chunk-BSAQE7PO.js';
3
3
  import { normalizeHex } from './chunk-7W3LYIOC.js';
4
4
  import { Button } from './chunk-7QTPJDRF.js';
5
5
  import { VisuallyHidden } from './chunk-UT6CW3C7.js';
@@ -0,0 +1,56 @@
1
+ import { Tag } from './chunk-KYIAFNU7.js';
2
+ import { Spinner } from './chunk-XSPCITPN.js';
3
+ import { VisuallyHidden } from './chunk-UT6CW3C7.js';
4
+ import { cx } from './chunk-ODEQTPFM.js';
5
+ import './AttachmentChip-XF4KPQ3G.css';
6
+ import { useState } from 'react';
7
+ import { CircleAlertGlyph, ImageGlyph } from '@crewlethq/icons/glyphs';
8
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
+
10
+ var ATTACHMENT_CHIP_LABELS = {
11
+ uploading: "Uploading",
12
+ failed: "Not attached",
13
+ remove: (name) => `Remove ${name}`
14
+ };
15
+ function AttachmentChip({
16
+ name,
17
+ preview,
18
+ state = "ready",
19
+ onRemove,
20
+ labels: overrides,
21
+ className,
22
+ ...rest
23
+ }) {
24
+ const labels = overrides ? { ...ATTACHMENT_CHIP_LABELS, ...overrides } : ATTACHMENT_CHIP_LABELS;
25
+ const [broken, setBroken] = useState(false);
26
+ const picture = preview !== void 0 && preview !== "" && !broken;
27
+ const mark = state === "uploading" ? /* @__PURE__ */ jsx(Spinner, { size: "xs" }) : state === "failed" ? /* @__PURE__ */ jsx(CircleAlertGlyph, { size: "xs" }) : picture ? /* @__PURE__ */ jsx(
28
+ "img",
29
+ {
30
+ className: "crewlet-attachment-chip__thumb",
31
+ src: preview,
32
+ alt: "",
33
+ decoding: "async",
34
+ referrerPolicy: "no-referrer",
35
+ draggable: false,
36
+ onError: () => setBroken(true)
37
+ }
38
+ ) : /* @__PURE__ */ jsx(ImageGlyph, { size: "xs" });
39
+ const said = state === "ready" ? "" : `, ${labels[state]}`;
40
+ const common = {
41
+ ...rest,
42
+ className: cx("crewlet-attachment-chip", `crewlet-attachment-chip--${state}`, className),
43
+ size: "sm",
44
+ appearance: "outline",
45
+ variant: state === "failed" ? "danger" : "neutral",
46
+ leadingIcon: mark,
47
+ title: name
48
+ };
49
+ const words = /* @__PURE__ */ jsxs(Fragment, { children: [
50
+ name,
51
+ said === "" ? null : /* @__PURE__ */ jsx(VisuallyHidden, { children: said })
52
+ ] });
53
+ return onRemove === void 0 ? /* @__PURE__ */ jsx(Tag, { ...common, children: words }) : /* @__PURE__ */ jsx(Tag, { ...common, onRemove, removeAriaLabel: labels.remove(name), children: words });
54
+ }
55
+
56
+ export { ATTACHMENT_CHIP_LABELS, AttachmentChip };
@@ -0,0 +1,118 @@
1
+ import { StepList } from './chunk-Z4EKUMZW.js';
2
+ import { Meter } from './chunk-RQFRRPV6.js';
3
+ import { ReceiptStrip } from './chunk-NLI7OVO2.js';
4
+ import { StatusCard } from './chunk-WW4E5EUS.js';
5
+ import { Disclosure } from './chunk-P4YORMRZ.js';
6
+ import { Spinner } from './chunk-XSPCITPN.js';
7
+ import { cx } from './chunk-ODEQTPFM.js';
8
+ import './DeepWorkCard-DGHRIQDM.css';
9
+ import { useId } from 'react';
10
+ import { TelescopeGlyph, CircleAlertGlyph, CircleStopGlyph, CircleCheckGlyph, ClockGlyph } from '@crewlethq/icons/glyphs';
11
+ import { jsx, jsxs } from 'react/jsx-runtime';
12
+
13
+ var DEEP_WORK_STATES = [
14
+ "starting",
15
+ "running",
16
+ "waiting",
17
+ "finished",
18
+ "stopped",
19
+ "failed"
20
+ ];
21
+ var DEEP_WORK_STATE_LABELS = {
22
+ starting: "Starting",
23
+ running: "Working",
24
+ waiting: "Waiting for your approval",
25
+ finished: "Finished",
26
+ stopped: "Stopped",
27
+ failed: "Failed"
28
+ };
29
+ var STATUS = {
30
+ starting: { tone: "info", icon: /* @__PURE__ */ jsx(Spinner, { size: "xs" }) },
31
+ running: { tone: "info", icon: /* @__PURE__ */ jsx(Spinner, { size: "xs" }) },
32
+ waiting: { tone: "warning", icon: /* @__PURE__ */ jsx(ClockGlyph, { size: "xs" }) },
33
+ finished: { tone: "success", icon: /* @__PURE__ */ jsx(CircleCheckGlyph, { size: "xs" }) },
34
+ stopped: { tone: "neutral", icon: /* @__PURE__ */ jsx(CircleStopGlyph, { size: "xs" }) },
35
+ failed: { tone: "danger", icon: /* @__PURE__ */ jsx(CircleAlertGlyph, { size: "xs" }) }
36
+ };
37
+ var NOTE_TONE = {
38
+ starting: "info",
39
+ running: "info",
40
+ waiting: "warning",
41
+ finished: "success",
42
+ stopped: "neutral",
43
+ failed: "danger"
44
+ };
45
+ var SETTLED = /* @__PURE__ */ new Set(["finished", "stopped", "failed"]);
46
+ var DEEP_WORK_CARD_LABELS = {
47
+ title: "Deep work",
48
+ activity: "Latest activity",
49
+ steps: "Steps",
50
+ stepCount: (count) => count === 1 ? "1 step" : `${count} steps`
51
+ };
52
+ function DeepWorkCard({
53
+ state,
54
+ goal,
55
+ measures = [],
56
+ activity = [],
57
+ steps = [],
58
+ stepsOpenAt = 3,
59
+ note,
60
+ stateLabels,
61
+ labels: labelOverrides,
62
+ className,
63
+ ...rest
64
+ }) {
65
+ const id = useId();
66
+ const labels = labelOverrides ? { ...DEEP_WORK_CARD_LABELS, ...labelOverrides } : DEEP_WORK_CARD_LABELS;
67
+ const words = stateLabels ? { ...DEEP_WORK_STATE_LABELS, ...stateLabels } : DEEP_WORK_STATE_LABELS;
68
+ const hasNote = !(note === void 0 || note === null || note === false || note === "");
69
+ const list = steps.length > 0 ? /* @__PURE__ */ jsx(StepList, { label: labels.steps, steps }) : null;
70
+ return /* @__PURE__ */ jsxs(
71
+ StatusCard,
72
+ {
73
+ ...rest,
74
+ className: cx("crewlet-deep-work-card", `crewlet-deep-work-card--${state}`, className),
75
+ title: labels.title,
76
+ status: { label: words[state], ...STATUS[state] },
77
+ settled: SETTLED.has(state),
78
+ strip: hasNote ? /* @__PURE__ */ jsx(ReceiptStrip, { tone: NOTE_TONE[state], children: note }) : void 0,
79
+ children: [
80
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-deep-work-card__goal", children: [
81
+ /* @__PURE__ */ jsx(TelescopeGlyph, { size: "sm", className: "crewlet-deep-work-card__goal-mark" }),
82
+ /* @__PURE__ */ jsx("p", { className: "crewlet-deep-work-card__goal-text", children: goal })
83
+ ] }),
84
+ measures.length > 0 ? /* @__PURE__ */ jsx("div", { className: "crewlet-deep-work-card__measures", children: measures.map((measure) => /* @__PURE__ */ jsx(
85
+ Meter,
86
+ {
87
+ size: "compact",
88
+ label: measure.label,
89
+ value: measure.value,
90
+ max: measure.max,
91
+ hint: measure.hint,
92
+ valueText: measure.valueText ?? measure.hint
93
+ },
94
+ measure.key
95
+ )) }) : null,
96
+ activity.length > 0 ? (
97
+ /* The role is restated for WebKit, which drops it from a list with no markers. */
98
+ /* eslint-disable-next-line jsx-a11y/no-redundant-roles */
99
+ /* @__PURE__ */ jsx("ol", { role: "list", "aria-label": labels.activity, className: "crewlet-deep-work-card__activity", children: activity.map((line, index) => /* @__PURE__ */ jsx("li", { className: "crewlet-deep-work-card__line", title: line, children: /* @__PURE__ */ jsx("code", { children: line }) }, `${index}:${line}`)) })
100
+ ) : null,
101
+ list === null ? null : steps.length > stepsOpenAt ? /* @__PURE__ */ jsx(
102
+ Disclosure,
103
+ {
104
+ id: `${id}-steps`,
105
+ className: "crewlet-deep-work-card__steps",
106
+ size: "compact",
107
+ headingLevel: "none",
108
+ title: labels.stepCount(steps.length),
109
+ defaultOpen: false,
110
+ children: list
111
+ }
112
+ ) : /* @__PURE__ */ jsx("div", { className: "crewlet-deep-work-card__steps", children: list })
113
+ ]
114
+ }
115
+ );
116
+ }
117
+
118
+ export { DEEP_WORK_CARD_LABELS, DEEP_WORK_STATES, DEEP_WORK_STATE_LABELS, DeepWorkCard };
@@ -23,6 +23,7 @@ function DownloadButton({
23
23
  size = "small",
24
24
  variant = "ghost",
25
25
  title,
26
+ "aria-label": ariaLabel,
26
27
  disabled,
27
28
  resetMs,
28
29
  failedResetMs = null,
@@ -61,6 +62,7 @@ function DownloadButton({
61
62
  loading: fetching,
62
63
  disabled,
63
64
  title: state === "failed" ? failedMessage : title,
65
+ "aria-label": ariaLabel,
64
66
  children: state === "started" ? startedLabel : state === "failed" ? failedLabel : label
65
67
  }
66
68
  ),