@crewlethq/ui 0.28.0 → 0.30.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 +45 -4
- package/dist/AccessDeniedCard/index.js +3 -3
- package/dist/Accordion/index.js +3 -3
- package/dist/AppShell/index.js +1 -1
- package/dist/{AppShell-APHZKJYH.css → AppShell-GCM4TDVY.css} +4 -1
- package/dist/ArtifactBar/ArtifactBar.d.ts +143 -0
- package/dist/ArtifactBar/index.d.ts +3 -0
- package/dist/ArtifactBar/index.js +25 -0
- package/dist/ArtifactBar-IBWB5POL.css +358 -0
- package/dist/ArtifactCard/index.js +3 -3
- package/dist/ArtifactCover/index.js +5 -5
- package/dist/ArtifactIcon/index.js +4 -4
- package/dist/ArtifactPanel/ArtifactPanel.d.ts +81 -0
- package/dist/ArtifactPanel/index.d.ts +3 -0
- package/dist/ArtifactPanel/index.js +5 -0
- package/dist/ArtifactPanel-YFXT5O77.css +132 -0
- package/dist/AuthLayout/index.js +3 -3
- package/dist/AvatarPicker/index.js +4 -4
- package/dist/Card/index.js +2 -2
- package/dist/ChangeMark/index.js +1 -1
- package/dist/CommandPalette/index.js +3 -3
- package/dist/CommentThread/index.js +5 -5
- package/dist/Composer/index.js +2 -2
- package/dist/DataView/index.js +4 -4
- package/dist/Disclosure/index.js +3 -3
- package/dist/Document/Document.d.ts +8 -1
- package/dist/Document/index.js +1 -1
- package/dist/{Document-PQGXJHB7.css → Document-G3YTZIUL.css} +71 -0
- package/dist/EditingStatus/EditingStatus.d.ts +25 -0
- package/dist/EditingStatus/index.d.ts +3 -0
- package/dist/EditingStatus/index.js +2 -0
- package/dist/EditingStatus-NFADEPSX.css +53 -0
- package/dist/Editor-YZ7KG2RD.js +2099 -0
- package/dist/HuePicker/index.js +2 -2
- package/dist/ListInput/index.js +2 -2
- package/dist/Markdown/grammar.d.ts +170 -0
- package/dist/Markdown/index.d.ts +2 -0
- package/dist/Markdown/index.js +1 -0
- package/dist/MarkdownEditor/index.js +1 -1
- package/dist/PeopleRail/PeopleRail.d.ts +8 -1
- package/dist/PeopleRail/index.js +1 -1
- package/dist/{PeopleRail-R64WVOSH.css → PeopleRail-SZGHZXVT.css} +8 -0
- package/dist/RichEditor/Editor.d.ts +17 -0
- package/dist/RichEditor/RichEditor.d.ts +26 -0
- package/dist/RichEditor/codec.d.ts +78 -0
- package/dist/RichEditor/commands.d.ts +89 -0
- package/dist/RichEditor/index.d.ts +4 -0
- package/dist/RichEditor/index.js +8 -0
- package/dist/RichEditor/keys.d.ts +16 -0
- package/dist/RichEditor/nodeviews.d.ts +60 -0
- package/dist/RichEditor/paste.d.ts +47 -0
- package/dist/RichEditor/plugins.d.ts +49 -0
- package/dist/RichEditor/roundtrip.d.ts +14 -0
- package/dist/RichEditor/schema.d.ts +23 -0
- package/dist/RichEditor/types.d.ts +140 -0
- package/dist/RichEditor-NPD2KAPS.css +419 -0
- package/dist/RichEditorMarkdown/index.d.ts +1 -0
- package/dist/RichEditorMarkdown/index.js +3 -0
- package/dist/SheetGrid/index.js +1 -1
- package/dist/ThemeSwitcher/index.js +1 -1
- package/dist/VersionCompare/index.js +2 -2
- package/dist/chunk-3DPIU2Q7.js +28 -0
- package/dist/{chunk-V2Z24W2Z.js → chunk-4JUKWWUD.js} +1 -1
- package/dist/{chunk-MQEEQVG6.js → chunk-6AH2XJ3Q.js} +2 -2
- package/dist/chunk-A4E5YLXO.js +85 -0
- package/dist/{chunk-WENCSQ47.js → chunk-EBNI36UQ.js} +1 -1
- package/dist/{chunk-6J35F334.js → chunk-GOSQXEZU.js} +1 -1
- package/dist/{chunk-M2VJGNCD.js → chunk-GR55WT4R.js} +3 -3
- package/dist/chunk-I3BSQUKN.js +121 -0
- package/dist/chunk-IDBHX5SR.js +12 -0
- package/dist/{chunk-WI6K5M5X.js → chunk-M3LUNN7F.js} +1 -1
- package/dist/{chunk-S4RCG44T.js → chunk-MICH6QSJ.js} +1 -1
- package/dist/chunk-QMBP23BL.js +347 -0
- package/dist/{chunk-G2AVKPSL.js → chunk-RIAZM6L3.js} +1 -1
- package/dist/chunk-SKOYC2CF.js +288 -0
- package/dist/{chunk-PRNX5AFE.js → chunk-TGYDROIB.js} +1 -1
- package/dist/{chunk-G3EEUNZQ.js → chunk-UB7TJEKZ.js} +1 -1
- package/dist/chunk-UQHKFF2N.js +106 -0
- package/dist/{chunk-WHZFDS62.js → chunk-VDPJGP4Q.js} +1 -1
- package/dist/chunk-VOX3YRFO.js +76 -0
- package/dist/chunk-YFW4MTK4.js +749 -0
- package/dist/generated/index.d.ts +6 -0
- package/dist/generated/index.js +83 -75
- package/dist/index.js +83 -75
- package/dist/styles.css +8849 -7793
- package/package.json +13 -3
- package/dist/chunk-FVLCTCMV.js +0 -96
- package/dist/{chunk-RIEDQSA4.js → chunk-7DZDSSJS.js} +1 -1
- package/dist/{chunk-YZCJ63JF.js → chunk-ACA27MZH.js} +1 -1
- package/dist/{chunk-ENJUPIND.js → chunk-FZVJDJFN.js} +1 -1
- package/dist/{chunk-SGIQCI6Y.js → chunk-LIXSV5YI.js} +1 -1
- package/dist/{chunk-NWW4IQJU.js → chunk-OC46246T.js} +0 -0
- package/dist/{chunk-VOMYRJV5.js → chunk-RODMM35O.js} +2 -2
- package/dist/{chunk-HCKJGBQH.js → chunk-VVRL27HM.js} +1 -1
- package/dist/{chunk-D5JZN3ML.js → chunk-Z6VW6CXX.js} +1 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { MARKDOWN_CALLOUT_NAMES } from './chunk-SKOYC2CF.js';
|
|
2
|
+
|
|
3
|
+
// src/RichEditor/types.ts
|
|
4
|
+
var RICH_EDITOR_LABELS = {
|
|
5
|
+
description: "Type a slash for blocks. Press Alt and F10 to reach the formatting toolbar.",
|
|
6
|
+
placeholder: "Write, or type a slash for blocks",
|
|
7
|
+
emptyLine: "Type / for blocks",
|
|
8
|
+
slashMenu: "Blocks",
|
|
9
|
+
slashEmpty: "No block matches",
|
|
10
|
+
slashGroupBlocks: "Blocks",
|
|
11
|
+
slashGroupInsert: "Insert",
|
|
12
|
+
blocks: {
|
|
13
|
+
paragraph: { label: "Text", description: "A plain paragraph" },
|
|
14
|
+
heading1: { label: "Heading 1", description: "A section heading" },
|
|
15
|
+
heading2: { label: "Heading 2", description: "A subsection heading" },
|
|
16
|
+
heading3: { label: "Heading 3", description: "A smaller heading" },
|
|
17
|
+
bullet: { label: "Bulleted list", description: "A simple list" },
|
|
18
|
+
ordered: { label: "Numbered list", description: "A list in order" },
|
|
19
|
+
task: { label: "Task list", description: "Items with a checkbox" },
|
|
20
|
+
quote: { label: "Quote", description: "Words set off from the text" },
|
|
21
|
+
callout: { label: "Callout", description: "A note that stands out" },
|
|
22
|
+
code: { label: "Code block", description: "Code, with its language" },
|
|
23
|
+
table: { label: "Table", description: "Rows and columns" },
|
|
24
|
+
divider: { label: "Divider", description: "A line between sections" },
|
|
25
|
+
image: { label: "Image", description: "A picture, by its address" }
|
|
26
|
+
},
|
|
27
|
+
toolbar: "Formatting",
|
|
28
|
+
bold: "Bold",
|
|
29
|
+
italic: "Italic",
|
|
30
|
+
strike: "Strikethrough",
|
|
31
|
+
code: "Inline code",
|
|
32
|
+
link: "Link",
|
|
33
|
+
heading: (level) => `Heading ${level}`,
|
|
34
|
+
linkPanel: "Link",
|
|
35
|
+
linkAddress: "Address",
|
|
36
|
+
linkText: "Text",
|
|
37
|
+
linkApply: "Apply",
|
|
38
|
+
linkRemove: "Remove link",
|
|
39
|
+
linkOpen: "Open link",
|
|
40
|
+
linkEdit: "Edit link",
|
|
41
|
+
linkInvalid: "Use an address that starts with https://, http://, mailto: or #/.",
|
|
42
|
+
linkRefused: "This address does not open from a page.",
|
|
43
|
+
imagePanel: "Image",
|
|
44
|
+
imageAddress: "Image address",
|
|
45
|
+
imageAlt: "Alt text",
|
|
46
|
+
imageAltHelp: "Describes the picture for anyone who cannot see it.",
|
|
47
|
+
imageInsert: "Insert image",
|
|
48
|
+
imageEdit: "Edit image",
|
|
49
|
+
imageRemove: "Remove image",
|
|
50
|
+
tableBar: "Table",
|
|
51
|
+
tableRow: "Row",
|
|
52
|
+
tableColumn: "Column",
|
|
53
|
+
rowAbove: "Insert row above",
|
|
54
|
+
rowBelow: "Insert row below",
|
|
55
|
+
rowDelete: "Delete row",
|
|
56
|
+
columnLeft: "Insert column left",
|
|
57
|
+
columnRight: "Insert column right",
|
|
58
|
+
columnDelete: "Delete column",
|
|
59
|
+
alignStart: "Align left",
|
|
60
|
+
alignCenter: "Align center",
|
|
61
|
+
alignEnd: "Align right",
|
|
62
|
+
tableDelete: "Delete table",
|
|
63
|
+
codeLanguage: "Code language",
|
|
64
|
+
codeLanguagePlaceholder: "Language",
|
|
65
|
+
calloutTone: "Callout type",
|
|
66
|
+
calloutRemove: "Remove callout",
|
|
67
|
+
tones: MARKDOWN_CALLOUT_NAMES,
|
|
68
|
+
taskDone: "Mark as done",
|
|
69
|
+
taskNotDone: "Mark as not done",
|
|
70
|
+
loading: "Loading the editor",
|
|
71
|
+
failed: "The editor did not load",
|
|
72
|
+
failedDetail: "The page may have been updated while it was open. Try again, or reload the page.",
|
|
73
|
+
retry: "Try again"
|
|
74
|
+
};
|
|
75
|
+
function richEditorLabels(overrides) {
|
|
76
|
+
if (!overrides) return RICH_EDITOR_LABELS;
|
|
77
|
+
return {
|
|
78
|
+
...RICH_EDITOR_LABELS,
|
|
79
|
+
...overrides,
|
|
80
|
+
blocks: { ...RICH_EDITOR_LABELS.blocks, ...overrides.blocks },
|
|
81
|
+
tones: { ...RICH_EDITOR_LABELS.tones, ...overrides.tones }
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export { RICH_EDITOR_LABELS, richEditorLabels };
|
|
@@ -4,7 +4,7 @@ import { useModalLayer, focusables } from './chunk-R25RGPUB.js';
|
|
|
4
4
|
import { IconButton } from './chunk-4FQT6ZAY.js';
|
|
5
5
|
import { VisuallyHidden } from './chunk-BZFWDIV6.js';
|
|
6
6
|
import { cx } from './chunk-ODEQTPFM.js';
|
|
7
|
-
import './AppShell-
|
|
7
|
+
import './AppShell-GCM4TDVY.css';
|
|
8
8
|
import { createContext, forwardRef, useContext, useId, useState, useRef, useCallback, useEffect, useLayoutEffect } from 'react';
|
|
9
9
|
import { breakpoint } from '@crewlethq/tokens';
|
|
10
10
|
import { ChevronUpGlyph, ChevronsUpDownGlyph, ChevronRightGlyph, MenuGlyph } from '@crewlethq/icons/glyphs';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PrincipalAvatar } from './chunk-4KP4RC3O.js';
|
|
2
2
|
import { RelativeTime } from './chunk-3CZ7XAVY.js';
|
|
3
3
|
import { AvatarStack } from './chunk-UAN5NE7M.js';
|
|
4
|
-
import { Card } from './chunk-
|
|
4
|
+
import { Card } from './chunk-ACA27MZH.js';
|
|
5
5
|
import { VisuallyHidden } from './chunk-BZFWDIV6.js';
|
|
6
6
|
import { cx } from './chunk-ODEQTPFM.js';
|
|
7
7
|
import './ArtifactCard-EXVAEBV6.css';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Composer } from './chunk-
|
|
2
|
-
import { Document } from './chunk-
|
|
1
|
+
import { Composer } from './chunk-7DZDSSJS.js';
|
|
2
|
+
import { Document } from './chunk-M3LUNN7F.js';
|
|
3
3
|
import { PrincipalAvatar } from './chunk-4KP4RC3O.js';
|
|
4
4
|
import { toInstant, RelativeTime, formatExact, toISO } from './chunk-3CZ7XAVY.js';
|
|
5
|
-
import { useHeadingLevel, headingTag } from './chunk-PQADV6P6.js';
|
|
6
5
|
import { Count } from './chunk-BHHIIK3M.js';
|
|
6
|
+
import { useHeadingLevel, headingTag } from './chunk-PQADV6P6.js';
|
|
7
7
|
import { Button } from './chunk-OG6CL3EB.js';
|
|
8
8
|
import { IconButton } from './chunk-4FQT6ZAY.js';
|
|
9
9
|
import { cx } from './chunk-ODEQTPFM.js';
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { HeadingLevelProvider } from './chunk-PQADV6P6.js';
|
|
2
|
+
import { IconButton } from './chunk-4FQT6ZAY.js';
|
|
3
|
+
import { cx } from './chunk-ODEQTPFM.js';
|
|
4
|
+
import './ArtifactPanel-YFXT5O77.css';
|
|
5
|
+
import { useId, useRef, useLayoutEffect, useEffect } from 'react';
|
|
6
|
+
import { MinimizeGlyph, MaximizeGlyph, XGlyph } from '@crewlethq/icons/glyphs';
|
|
7
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
8
|
+
|
|
9
|
+
var ARTIFACT_PANEL_LABELS = {
|
|
10
|
+
close: (title) => `Close ${title.toLowerCase()}`,
|
|
11
|
+
expand: "Expand to the full view",
|
|
12
|
+
collapse: "Back to the side"
|
|
13
|
+
};
|
|
14
|
+
function ArtifactPanel({
|
|
15
|
+
title,
|
|
16
|
+
icon,
|
|
17
|
+
onClose,
|
|
18
|
+
size = "md",
|
|
19
|
+
expanded = false,
|
|
20
|
+
onExpandedChange,
|
|
21
|
+
actions,
|
|
22
|
+
focusOnOpen = true,
|
|
23
|
+
labels,
|
|
24
|
+
className,
|
|
25
|
+
children
|
|
26
|
+
}) {
|
|
27
|
+
const words = { ...ARTIFACT_PANEL_LABELS, ...labels };
|
|
28
|
+
const titleId = useId();
|
|
29
|
+
const root = useRef(null);
|
|
30
|
+
const heading = useRef(null);
|
|
31
|
+
const before = useRef(null);
|
|
32
|
+
const focusing = useRef(focusOnOpen);
|
|
33
|
+
useLayoutEffect(() => {
|
|
34
|
+
const panel = root.current;
|
|
35
|
+
before.current = document.activeElement;
|
|
36
|
+
if (focusing.current) heading.current?.focus({ preventScroll: true });
|
|
37
|
+
return () => {
|
|
38
|
+
const back = before.current;
|
|
39
|
+
if (panel?.contains(document.activeElement) && back instanceof HTMLElement && back.isConnected) {
|
|
40
|
+
back.focus({ preventScroll: true });
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}, []);
|
|
44
|
+
const close = useRef(onClose);
|
|
45
|
+
close.current = onClose;
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const panel = root.current;
|
|
48
|
+
if (!panel) return void 0;
|
|
49
|
+
const doc = panel.ownerDocument;
|
|
50
|
+
const onKeyDown = (event) => {
|
|
51
|
+
if (event.key !== "Escape" || event.defaultPrevented || event.isComposing) return;
|
|
52
|
+
if (!(event.target instanceof Node) || !panel.contains(event.target)) return;
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
close.current();
|
|
55
|
+
};
|
|
56
|
+
doc.addEventListener("keydown", onKeyDown);
|
|
57
|
+
return () => doc.removeEventListener("keydown", onKeyDown);
|
|
58
|
+
}, []);
|
|
59
|
+
return /* @__PURE__ */ jsxs(
|
|
60
|
+
"aside",
|
|
61
|
+
{
|
|
62
|
+
ref: root,
|
|
63
|
+
className: cx("crewlet-artifact-panel", `crewlet-artifact-panel--${size}`, className),
|
|
64
|
+
"aria-labelledby": titleId,
|
|
65
|
+
"data-expanded": expanded || void 0,
|
|
66
|
+
children: [
|
|
67
|
+
/* @__PURE__ */ jsxs("div", { className: "crewlet-artifact-panel__head", children: [
|
|
68
|
+
icon ? /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-panel__icon", "aria-hidden": true, children: icon }) : null,
|
|
69
|
+
/* @__PURE__ */ jsx("h2", { ref: heading, id: titleId, className: "crewlet-artifact-panel__title", tabIndex: -1, children: title }),
|
|
70
|
+
/* @__PURE__ */ jsxs("span", { className: "crewlet-artifact-panel__actions", children: [
|
|
71
|
+
actions,
|
|
72
|
+
onExpandedChange ? /* @__PURE__ */ jsx(
|
|
73
|
+
IconButton,
|
|
74
|
+
{
|
|
75
|
+
label: expanded ? words.collapse : words.expand,
|
|
76
|
+
icon: expanded ? /* @__PURE__ */ jsx(MinimizeGlyph, { size: "sm" }) : /* @__PURE__ */ jsx(MaximizeGlyph, { size: "sm" }),
|
|
77
|
+
size: "sm",
|
|
78
|
+
variant: "ghost",
|
|
79
|
+
onClick: () => onExpandedChange(!expanded)
|
|
80
|
+
}
|
|
81
|
+
) : null,
|
|
82
|
+
/* @__PURE__ */ jsx(IconButton, { label: words.close(title), icon: /* @__PURE__ */ jsx(XGlyph, { size: "sm" }), size: "sm", variant: "ghost", onClick: onClose })
|
|
83
|
+
] })
|
|
84
|
+
] }),
|
|
85
|
+
/* @__PURE__ */ jsx("div", { className: "crewlet-artifact-panel__body", children: /* @__PURE__ */ jsx(HeadingLevelProvider, { level: 3, children }) })
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
function ArtifactWorkspace({
|
|
91
|
+
panel,
|
|
92
|
+
expanded = false,
|
|
93
|
+
bodyRef,
|
|
94
|
+
bodyClassName,
|
|
95
|
+
bodyLabel,
|
|
96
|
+
className,
|
|
97
|
+
children
|
|
98
|
+
}) {
|
|
99
|
+
return /* @__PURE__ */ jsxs(
|
|
100
|
+
"div",
|
|
101
|
+
{
|
|
102
|
+
className: cx("crewlet-artifact-workspace", className),
|
|
103
|
+
"data-panel": panel ? expanded ? "expanded" : "open" : void 0,
|
|
104
|
+
children: [
|
|
105
|
+
/* @__PURE__ */ jsx(
|
|
106
|
+
"div",
|
|
107
|
+
{
|
|
108
|
+
ref: bodyRef,
|
|
109
|
+
className: cx("crewlet-artifact-workspace__body", bodyClassName),
|
|
110
|
+
role: bodyLabel ? "region" : void 0,
|
|
111
|
+
"aria-label": bodyLabel,
|
|
112
|
+
children
|
|
113
|
+
}
|
|
114
|
+
),
|
|
115
|
+
panel
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export { ARTIFACT_PANEL_LABELS, ArtifactPanel, ArtifactWorkspace };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { readMarkdown, writeMarkdown } from './chunk-YFW4MTK4.js';
|
|
2
|
+
|
|
3
|
+
// src/RichEditor/roundtrip.ts
|
|
4
|
+
function roundTripMarkdown(markdown) {
|
|
5
|
+
const { doc, source } = readMarkdown(markdown);
|
|
6
|
+
return writeMarkdown(doc, source);
|
|
7
|
+
}
|
|
8
|
+
function canonicalMarkdown(markdown) {
|
|
9
|
+
return writeMarkdown(readMarkdown(markdown).doc);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { canonicalMarkdown, roundTripMarkdown };
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import { isApplePlatform, Kbd } from './chunk-SMBKXWML.js';
|
|
2
|
+
import { Tooltip } from './chunk-QWOPX2MN.js';
|
|
3
|
+
import { SegmentedControl } from './chunk-RCQXUT5K.js';
|
|
4
|
+
import { ArtifactIcon } from './chunk-4JUKWWUD.js';
|
|
5
|
+
import { Menu } from './chunk-2HIOJ4YZ.js';
|
|
6
|
+
import { Button } from './chunk-OG6CL3EB.js';
|
|
7
|
+
import { IconButton } from './chunk-4FQT6ZAY.js';
|
|
8
|
+
import { VisuallyHidden } from './chunk-BZFWDIV6.js';
|
|
9
|
+
import { cx } from './chunk-ODEQTPFM.js';
|
|
10
|
+
import './ArtifactBar-IBWB5POL.css';
|
|
11
|
+
import { useId, useState, useRef, useEffect } from 'react';
|
|
12
|
+
import { ChevronLeftGlyph, EllipsisGlyph, ChevronDownGlyph } from '@crewlethq/icons/glyphs';
|
|
13
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
14
|
+
|
|
15
|
+
var ARTIFACT_BAR_LABELS = {
|
|
16
|
+
more: (title) => `More for \u201C${title}\u201D`,
|
|
17
|
+
renameHint: "Rename",
|
|
18
|
+
titleField: "Title",
|
|
19
|
+
emptyTitle: "A title cannot be empty."
|
|
20
|
+
};
|
|
21
|
+
function ArtifactBar({
|
|
22
|
+
title,
|
|
23
|
+
kind,
|
|
24
|
+
icon,
|
|
25
|
+
kindLabel,
|
|
26
|
+
back,
|
|
27
|
+
start,
|
|
28
|
+
onRename,
|
|
29
|
+
renaming,
|
|
30
|
+
onRenamingChange,
|
|
31
|
+
version,
|
|
32
|
+
modes,
|
|
33
|
+
presence,
|
|
34
|
+
kindTools = [],
|
|
35
|
+
tools = [],
|
|
36
|
+
menu = [],
|
|
37
|
+
as = "header",
|
|
38
|
+
headingLevel = 1,
|
|
39
|
+
pending = false,
|
|
40
|
+
labels,
|
|
41
|
+
className
|
|
42
|
+
}) {
|
|
43
|
+
const words = { ...ARTIFACT_BAR_LABELS, ...labels };
|
|
44
|
+
const headingId = useId();
|
|
45
|
+
const Root = as;
|
|
46
|
+
const apple = isApplePlatform();
|
|
47
|
+
const folding = [...kindTools, ...tools].filter((t) => !t.labelled);
|
|
48
|
+
const pinned = [...kindTools, ...tools].filter((t) => t.labelled);
|
|
49
|
+
const folded = [
|
|
50
|
+
...modes ? modes.options.map(
|
|
51
|
+
(option) => ({
|
|
52
|
+
key: `mode:${option.value}`,
|
|
53
|
+
label: option.label,
|
|
54
|
+
icon: option.icon,
|
|
55
|
+
checked: option.value === modes.value,
|
|
56
|
+
onSelect: () => modes.onValueChange(option.value)
|
|
57
|
+
})
|
|
58
|
+
) : [],
|
|
59
|
+
...modes && folding.length > 0 ? [{ kind: "separator", key: "sep:modes" }] : [],
|
|
60
|
+
...folding.map(
|
|
61
|
+
(tool) => ({
|
|
62
|
+
key: `tool:${tool.key}`,
|
|
63
|
+
label: tool.label,
|
|
64
|
+
icon: tool.icon,
|
|
65
|
+
onSelect: tool.onSelect,
|
|
66
|
+
...tool.disabledReason !== void 0 ? { disabled: true, description: tool.disabledReason } : {},
|
|
67
|
+
...tool.keys ? { hint: /* @__PURE__ */ jsx(Kbd, { keys: tool.keys, subtle: true, apple }) } : {}
|
|
68
|
+
})
|
|
69
|
+
)
|
|
70
|
+
];
|
|
71
|
+
const narrowMenu = [
|
|
72
|
+
...folded,
|
|
73
|
+
...folded.length > 0 && menu.length > 0 ? [{ kind: "separator", key: "sep:menu" }] : [],
|
|
74
|
+
...menu
|
|
75
|
+
];
|
|
76
|
+
return /* @__PURE__ */ jsx(
|
|
77
|
+
Root,
|
|
78
|
+
{
|
|
79
|
+
className: cx("crewlet-artifact-bar", presence ? "crewlet-artifact-bar--present" : null, className),
|
|
80
|
+
"aria-labelledby": pending ? void 0 : headingId,
|
|
81
|
+
children: /* @__PURE__ */ jsxs("div", { className: cx("crewlet-artifact-bar__row", modes && "crewlet-artifact-bar__row--centred"), children: [
|
|
82
|
+
/* @__PURE__ */ jsxs("div", { className: "crewlet-artifact-bar__lead", children: [
|
|
83
|
+
start,
|
|
84
|
+
back ? /* @__PURE__ */ jsx(Tooltip, { content: back.label, placement: "bottom", children: /* @__PURE__ */ jsx(IconButton, { asChild: true, label: back.label, size: "sm", variant: "ghost", title: "", children: /* @__PURE__ */ jsx("a", { href: back.href, children: /* @__PURE__ */ jsx(ChevronLeftGlyph, { size: "sm" }) }) }) }) : null,
|
|
85
|
+
/* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__glyph", role: "img", "aria-label": kindLabel, title: kindLabel, children: /* @__PURE__ */ jsx(ArtifactIcon, { icon: icon ?? void 0, kind, size: "sm" }) }),
|
|
86
|
+
pending ? /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__placeholder", "aria-hidden": true }) : /* @__PURE__ */ jsx(
|
|
87
|
+
BarTitle,
|
|
88
|
+
{
|
|
89
|
+
title,
|
|
90
|
+
id: headingId,
|
|
91
|
+
level: headingLevel,
|
|
92
|
+
onRename,
|
|
93
|
+
renaming,
|
|
94
|
+
onRenamingChange,
|
|
95
|
+
words
|
|
96
|
+
}
|
|
97
|
+
),
|
|
98
|
+
version ? /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__version", children: version }) : null
|
|
99
|
+
] }),
|
|
100
|
+
modes ? /* @__PURE__ */ jsx("div", { className: "crewlet-artifact-bar__modes crewlet-artifact-bar__wide", children: /* @__PURE__ */ jsx(
|
|
101
|
+
SegmentedControl,
|
|
102
|
+
{
|
|
103
|
+
label: modes.label,
|
|
104
|
+
semantics: "radio",
|
|
105
|
+
size: "sm",
|
|
106
|
+
options: modes.options.map((o) => ({ value: o.value, label: o.label, ...o.icon ? { icon: o.icon } : {} })),
|
|
107
|
+
value: modes.value,
|
|
108
|
+
onValueChange: modes.onValueChange
|
|
109
|
+
}
|
|
110
|
+
) }) : null,
|
|
111
|
+
/* @__PURE__ */ jsxs("div", { className: "crewlet-artifact-bar__end", children: [
|
|
112
|
+
presence ? /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__presence", children: presence }) : null,
|
|
113
|
+
kindTools.some((t) => !t.labelled) ? /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__tools crewlet-artifact-bar__wide", children: kindTools.filter((t) => !t.labelled).map((tool) => /* @__PURE__ */ jsx(ToolButton, { tool, apple }, tool.key)) }) : null,
|
|
114
|
+
tools.some((t) => !t.labelled) ? /* @__PURE__ */ jsxs("span", { className: "crewlet-artifact-bar__tools crewlet-artifact-bar__wide", children: [
|
|
115
|
+
kindTools.some((t) => !t.labelled) ? /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__rule", "aria-hidden": true }) : null,
|
|
116
|
+
tools.filter((t) => !t.labelled).map((tool) => /* @__PURE__ */ jsx(ToolButton, { tool, apple }, tool.key))
|
|
117
|
+
] }) : null,
|
|
118
|
+
pinned.length > 0 ? /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__tools", children: pinned.map((tool) => /* @__PURE__ */ jsx(LabelledTool, { tool, apple }, tool.key)) }) : null,
|
|
119
|
+
menu.length > 0 ? /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__wide", children: /* @__PURE__ */ jsx(Menu, { label: words.more(title), icon: /* @__PURE__ */ jsx(EllipsisGlyph, { size: "sm" }), triggerVariant: "ghost", align: "end", items: menu }) }) : null,
|
|
120
|
+
narrowMenu.length > 0 ? /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__narrow", children: /* @__PURE__ */ jsx(
|
|
121
|
+
Menu,
|
|
122
|
+
{
|
|
123
|
+
label: words.more(title),
|
|
124
|
+
icon: /* @__PURE__ */ jsx(EllipsisGlyph, { size: "sm" }),
|
|
125
|
+
triggerVariant: "ghost",
|
|
126
|
+
align: "end",
|
|
127
|
+
items: narrowMenu
|
|
128
|
+
}
|
|
129
|
+
) }) : null
|
|
130
|
+
] })
|
|
131
|
+
] })
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
function ariaKeys(keys, apple) {
|
|
136
|
+
return keys.map((key) => {
|
|
137
|
+
if (key === "Mod") return apple ? "Meta" : "Control";
|
|
138
|
+
return key.length === 1 ? key.toUpperCase() : key;
|
|
139
|
+
}).join("+");
|
|
140
|
+
}
|
|
141
|
+
function Tip({ tool, apple }) {
|
|
142
|
+
return /* @__PURE__ */ jsxs("span", { className: "crewlet-artifact-bar__tip", children: [
|
|
143
|
+
tool.label,
|
|
144
|
+
tool.keys ? /* @__PURE__ */ jsx(Kbd, { keys: tool.keys, subtle: true, apple }) : null
|
|
145
|
+
] });
|
|
146
|
+
}
|
|
147
|
+
function ToolButton({ tool, apple }) {
|
|
148
|
+
return /* @__PURE__ */ jsxs("span", { className: "crewlet-artifact-bar__tool", children: [
|
|
149
|
+
/* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(Tip, { tool, apple }), placement: "bottom", children: /* @__PURE__ */ jsx(
|
|
150
|
+
IconButton,
|
|
151
|
+
{
|
|
152
|
+
label: tool.label,
|
|
153
|
+
icon: tool.icon,
|
|
154
|
+
size: "sm",
|
|
155
|
+
variant: "ghost",
|
|
156
|
+
title: "",
|
|
157
|
+
pressed: tool.pressed,
|
|
158
|
+
disabledReason: tool.disabledReason,
|
|
159
|
+
"aria-keyshortcuts": tool.keys ? ariaKeys(tool.keys, apple) : void 0,
|
|
160
|
+
onClick: tool.onSelect
|
|
161
|
+
}
|
|
162
|
+
) }),
|
|
163
|
+
tool.badge !== void 0 ? /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__badge", "aria-hidden": true, children: tool.badge }) : null
|
|
164
|
+
] });
|
|
165
|
+
}
|
|
166
|
+
function LabelledTool({ tool, apple }) {
|
|
167
|
+
const shortcut = tool.keys ? ariaKeys(tool.keys, apple) : void 0;
|
|
168
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
169
|
+
/* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__roomy", children: /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(Tip, { tool, apple }), placement: "bottom", disabled: !tool.keys, children: /* @__PURE__ */ jsx(
|
|
170
|
+
Button,
|
|
171
|
+
{
|
|
172
|
+
size: "small",
|
|
173
|
+
variant: "secondary",
|
|
174
|
+
leadingIcon: tool.icon,
|
|
175
|
+
pressed: tool.pressed,
|
|
176
|
+
disabledReason: tool.disabledReason,
|
|
177
|
+
"aria-keyshortcuts": shortcut,
|
|
178
|
+
onClick: tool.onSelect,
|
|
179
|
+
children: tool.label
|
|
180
|
+
}
|
|
181
|
+
) }) }),
|
|
182
|
+
/* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__tight", children: /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(Tip, { tool, apple }), placement: "bottom", children: /* @__PURE__ */ jsx(
|
|
183
|
+
IconButton,
|
|
184
|
+
{
|
|
185
|
+
label: tool.label,
|
|
186
|
+
icon: tool.icon,
|
|
187
|
+
size: "sm",
|
|
188
|
+
variant: "ghost",
|
|
189
|
+
title: "",
|
|
190
|
+
pressed: tool.pressed,
|
|
191
|
+
disabledReason: tool.disabledReason,
|
|
192
|
+
"aria-keyshortcuts": shortcut,
|
|
193
|
+
onClick: tool.onSelect
|
|
194
|
+
}
|
|
195
|
+
) }) })
|
|
196
|
+
] });
|
|
197
|
+
}
|
|
198
|
+
function BarTitle({
|
|
199
|
+
title,
|
|
200
|
+
id,
|
|
201
|
+
level,
|
|
202
|
+
onRename,
|
|
203
|
+
renaming,
|
|
204
|
+
onRenamingChange,
|
|
205
|
+
words
|
|
206
|
+
}) {
|
|
207
|
+
const Heading = `h${level}`;
|
|
208
|
+
const hintId = useId();
|
|
209
|
+
const errorId = useId();
|
|
210
|
+
const [own, setOwn] = useState(false);
|
|
211
|
+
const editing = (renaming ?? own) && onRename !== void 0;
|
|
212
|
+
const setEditing = (on) => {
|
|
213
|
+
if (renaming === void 0) setOwn(on);
|
|
214
|
+
onRenamingChange?.(on);
|
|
215
|
+
};
|
|
216
|
+
const [draft, setDraft] = useState(title);
|
|
217
|
+
const [error, setError] = useState(null);
|
|
218
|
+
const [busy, setBusy] = useState(false);
|
|
219
|
+
const field = useRef(null);
|
|
220
|
+
const button = useRef(null);
|
|
221
|
+
const settled = useRef(false);
|
|
222
|
+
useEffect(() => {
|
|
223
|
+
if (!editing) return;
|
|
224
|
+
settled.current = false;
|
|
225
|
+
setDraft(title);
|
|
226
|
+
setError(null);
|
|
227
|
+
const el = field.current;
|
|
228
|
+
el?.focus();
|
|
229
|
+
el?.select();
|
|
230
|
+
}, [editing]);
|
|
231
|
+
if (onRename === void 0) {
|
|
232
|
+
return /* @__PURE__ */ jsx(Heading, { id, className: "crewlet-artifact-bar__title", title, children: title });
|
|
233
|
+
}
|
|
234
|
+
const finish = (refocus) => {
|
|
235
|
+
settled.current = true;
|
|
236
|
+
setEditing(false);
|
|
237
|
+
setError(null);
|
|
238
|
+
if (refocus) requestAnimationFrame(() => button.current?.focus());
|
|
239
|
+
};
|
|
240
|
+
const commit = async (refocus) => {
|
|
241
|
+
if (settled.current || busy) return;
|
|
242
|
+
const next = draft.trim();
|
|
243
|
+
if (next === title) {
|
|
244
|
+
finish(refocus);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (next === "") {
|
|
248
|
+
setError(words.emptyTitle);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
setBusy(true);
|
|
252
|
+
try {
|
|
253
|
+
const answer = await onRename(next);
|
|
254
|
+
if (typeof answer === "string" && answer !== "") {
|
|
255
|
+
setError(answer);
|
|
256
|
+
field.current?.focus();
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
finish(refocus);
|
|
260
|
+
} finally {
|
|
261
|
+
setBusy(false);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
const onKeyDown = (event) => {
|
|
265
|
+
if (event.nativeEvent.isComposing) return;
|
|
266
|
+
if (event.key === "Enter") {
|
|
267
|
+
event.preventDefault();
|
|
268
|
+
void commit(true);
|
|
269
|
+
} else if (event.key === "Escape") {
|
|
270
|
+
event.preventDefault();
|
|
271
|
+
event.stopPropagation();
|
|
272
|
+
finish(true);
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
if (editing) {
|
|
276
|
+
return /* @__PURE__ */ jsxs(Heading, { id, className: "crewlet-artifact-bar__title crewlet-artifact-bar__title--editing", children: [
|
|
277
|
+
/* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__sizer", "data-value": draft || " ", children: /* @__PURE__ */ jsx(
|
|
278
|
+
"input",
|
|
279
|
+
{
|
|
280
|
+
ref: field,
|
|
281
|
+
className: "crewlet-artifact-bar__field",
|
|
282
|
+
"aria-label": words.titleField,
|
|
283
|
+
"aria-invalid": error ? true : void 0,
|
|
284
|
+
"aria-describedby": error ? errorId : void 0,
|
|
285
|
+
"aria-busy": busy || void 0,
|
|
286
|
+
readOnly: busy,
|
|
287
|
+
value: draft,
|
|
288
|
+
size: 1,
|
|
289
|
+
onChange: (event) => {
|
|
290
|
+
setDraft(event.target.value);
|
|
291
|
+
if (error) setError(null);
|
|
292
|
+
},
|
|
293
|
+
onKeyDown,
|
|
294
|
+
onBlur: () => void commit(false)
|
|
295
|
+
}
|
|
296
|
+
) }),
|
|
297
|
+
error ? /* @__PURE__ */ jsx("span", { id: errorId, role: "alert", className: "crewlet-artifact-bar__error", children: error }) : null
|
|
298
|
+
] });
|
|
299
|
+
}
|
|
300
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
301
|
+
/* @__PURE__ */ jsx(Heading, { id, className: "crewlet-artifact-bar__title", children: /* @__PURE__ */ jsx(
|
|
302
|
+
"button",
|
|
303
|
+
{
|
|
304
|
+
ref: button,
|
|
305
|
+
type: "button",
|
|
306
|
+
className: "crewlet-artifact-bar__rename",
|
|
307
|
+
title,
|
|
308
|
+
"aria-describedby": hintId,
|
|
309
|
+
onClick: () => setEditing(true),
|
|
310
|
+
children: title
|
|
311
|
+
}
|
|
312
|
+
) }),
|
|
313
|
+
/* @__PURE__ */ jsx(VisuallyHidden, { id: hintId, children: words.renameHint })
|
|
314
|
+
] });
|
|
315
|
+
}
|
|
316
|
+
function ArtifactVersionChip({
|
|
317
|
+
version,
|
|
318
|
+
latest,
|
|
319
|
+
items,
|
|
320
|
+
label = "Versions",
|
|
321
|
+
format = (v, l) => v === l ? `v${v}` : `v${v} of ${l}`
|
|
322
|
+
}) {
|
|
323
|
+
const older = version !== latest;
|
|
324
|
+
return /* @__PURE__ */ jsx(
|
|
325
|
+
Menu,
|
|
326
|
+
{
|
|
327
|
+
label,
|
|
328
|
+
items,
|
|
329
|
+
align: "start",
|
|
330
|
+
renderTrigger: (props) => /* @__PURE__ */ jsxs(
|
|
331
|
+
"button",
|
|
332
|
+
{
|
|
333
|
+
...props,
|
|
334
|
+
type: "button",
|
|
335
|
+
className: cx("crewlet-version-chip", older && "crewlet-version-chip--older"),
|
|
336
|
+
"aria-label": `${label}: ${format(version, latest)}`,
|
|
337
|
+
children: [
|
|
338
|
+
/* @__PURE__ */ jsx("span", { className: "crewlet-version-chip__words", children: format(version, latest) }),
|
|
339
|
+
/* @__PURE__ */ jsx(ChevronDownGlyph, { size: "xs" })
|
|
340
|
+
]
|
|
341
|
+
}
|
|
342
|
+
)
|
|
343
|
+
}
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export { ARTIFACT_BAR_LABELS, ArtifactBar, ArtifactVersionChip };
|