@arbidocs/blocks 0.5.122 → 0.5.123
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ConnectedNativeDocxComparison-QKHCYD6W.cjs +1 -1
- package/dist/{ConnectedPresentation-AU25OW25.cjs → ConnectedPresentation-5DOJ35XL.cjs} +7 -7
- package/dist/{ConnectedPresentation-AU25OW25.cjs.map → ConnectedPresentation-5DOJ35XL.cjs.map} +1 -1
- package/dist/{ConnectedSlidesTab-I75LKKN7.cjs → ConnectedSlidesTab-7YMEDGUU.cjs} +40 -18
- package/dist/ConnectedSlidesTab-7YMEDGUU.cjs.map +1 -0
- package/dist/ConnectedStreamedWordArtifact-AG62232A.cjs +1 -1
- package/dist/{FilesViewerDialog-4352KIOG.cjs → FilesViewerDialog-2QCCRWF2.cjs} +7 -7
- package/dist/{FilesViewerDialog-4352KIOG.cjs.map → FilesViewerDialog-2QCCRWF2.cjs.map} +1 -1
- package/dist/agents/index.cjs +176 -176
- package/dist/{chunk-LHWOKOMP.cjs → chunk-46P7IDBX.cjs} +3 -3
- package/dist/chunk-46P7IDBX.cjs.map +1 -0
- package/dist/{chunk-USNTRL22.cjs → chunk-DWMWEALB.cjs} +288 -214
- package/dist/chunk-DWMWEALB.cjs.map +1 -0
- package/dist/{chunk-UTJ223TI.cjs → chunk-JD2HX2BR.cjs} +98 -78
- package/dist/chunk-JD2HX2BR.cjs.map +1 -0
- package/dist/{chunk-QG2U2JGX.cjs → chunk-L4CIFLCU.cjs} +4 -4
- package/dist/{chunk-QG2U2JGX.cjs.map → chunk-L4CIFLCU.cjs.map} +1 -1
- package/dist/{chunk-CQQQIZU4.cjs → chunk-NQML7IUC.cjs} +3 -3
- package/dist/{chunk-CQQQIZU4.cjs.map → chunk-NQML7IUC.cjs.map} +1 -1
- package/dist/{chunk-WRLGLZIA.cjs → chunk-SNPK3R3O.cjs} +5 -5
- package/dist/{chunk-WRLGLZIA.cjs.map → chunk-SNPK3R3O.cjs.map} +1 -1
- package/dist/{chunk-XGM4VVNV.cjs → chunk-WV7BCGCK.cjs} +19 -19
- package/dist/{chunk-XGM4VVNV.cjs.map → chunk-WV7BCGCK.cjs.map} +1 -1
- package/dist/connect/docx.cjs +1 -1
- package/dist/connect/index.cjs +161 -161
- package/dist/connect/viewer.cjs +5 -5
- package/dist/connection/presentation/ConnectedSlidesTab.js +35 -13
- package/dist/connection/presentation/ConnectedSlidesTab.js.map +2 -2
- package/dist/connection/viewer/ConnectedDocumentViewer.js +51 -60
- package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
- package/dist/connection/viewer/ViewerMoreMenu.d.ts +18 -0
- package/dist/connection/viewer/ViewerMoreMenu.js +45 -0
- package/dist/connection/viewer/ViewerMoreMenu.js.map +7 -0
- package/dist/connection/viewer/pdf/PdfPassageHighlights.js +3 -2
- package/dist/connection/viewer/pdf/PdfPassageHighlights.js.map +2 -2
- package/dist/document-tools/DocumentToolButtons.js +2 -2
- package/dist/document-tools/DocumentToolButtons.js.map +2 -2
- package/dist/document-tools/index.cjs +13 -13
- package/dist/embed/index.cjs +2 -2
- package/dist/index.cjs +234 -234
- package/dist/presentation/BoxActionBar.d.ts +2 -2
- package/dist/presentation/BoxActionBar.js +62 -30
- package/dist/presentation/BoxActionBar.js.map +2 -2
- package/dist/presentation/ClipActionBar.js +60 -7
- package/dist/presentation/ClipActionBar.js.map +2 -2
- package/dist/presentation/ClipViewControls.d.ts +3 -3
- package/dist/presentation/ClipViewControls.js +59 -64
- package/dist/presentation/ClipViewControls.js.map +2 -2
- package/dist/presentation/SlidesEditor.js +56 -42
- package/dist/presentation/SlidesEditor.js.map +2 -2
- package/dist/presentation/StageItem.js +0 -5
- package/dist/presentation/StageItem.js.map +2 -2
- package/dist/styles.css +1 -1
- package/dist/workflow-canvas/index.cjs +12 -12
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +5 -5
- package/dist/ConnectedSlidesTab-I75LKKN7.cjs.map +0 -1
- package/dist/chunk-LHWOKOMP.cjs.map +0 -1
- package/dist/chunk-USNTRL22.cjs.map +0 -1
- package/dist/chunk-UTJ223TI.cjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The floating bar over a selected text box or shape: its type (smaller, larger, bold,
|
|
3
|
-
* colour), its
|
|
2
|
+
* The floating bar over a selected text box or shape: its type (smaller, larger, bold, its
|
|
3
|
+
* colour), its fill and delete; italic, alignment and stacking in its "…". Colours are picked with
|
|
4
4
|
* the system's colour picker.
|
|
5
5
|
*/
|
|
6
6
|
import { type SlideBox } from './boxes';
|
|
@@ -10,23 +10,26 @@ import {
|
|
|
10
10
|
Bold,
|
|
11
11
|
BringToFront,
|
|
12
12
|
Italic,
|
|
13
|
+
MoreHorizontal,
|
|
13
14
|
PaintBucket,
|
|
14
15
|
SendToBack,
|
|
15
16
|
Trash2
|
|
16
17
|
} from "lucide-react";
|
|
17
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
DropdownMenu,
|
|
20
|
+
DropdownMenuCheckboxItem,
|
|
21
|
+
DropdownMenuContent,
|
|
22
|
+
DropdownMenuItem,
|
|
23
|
+
DropdownMenuSeparator,
|
|
24
|
+
DropdownMenuTrigger,
|
|
25
|
+
cn
|
|
26
|
+
} from "@arbidocs/react/ui";
|
|
18
27
|
import { ACTION, Action } from "./ClipActionBar.js";
|
|
19
28
|
import { DEFAULT_TEXT_SIZE, firstRun, styleRuns } from "./boxes.js";
|
|
20
29
|
import { usePresentation } from "./store.js";
|
|
21
30
|
import { TEXT_COLORS } from "./theme.js";
|
|
22
31
|
const SIZE_STEPS = [8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 36, 44, 54, 66, 80, 96];
|
|
23
32
|
const nextSize = (size, up) => up ? SIZE_STEPS.find((step) => step > size + 0.5) ?? size : [...SIZE_STEPS].reverse().find((step) => step < size - 0.5) ?? size;
|
|
24
|
-
const ALIGN_NEXT = {
|
|
25
|
-
left: "center",
|
|
26
|
-
center: "right",
|
|
27
|
-
right: "left",
|
|
28
|
-
justify: "left"
|
|
29
|
-
};
|
|
30
33
|
const ALIGN_ICON = {
|
|
31
34
|
left: /* @__PURE__ */ jsx(AlignLeft, { className: "size-4" }),
|
|
32
35
|
center: /* @__PURE__ */ jsx(AlignCenter, { className: "size-4" }),
|
|
@@ -114,25 +117,6 @@ function BoxActionBar({ box, onRemoved }) {
|
|
|
114
117
|
children: /* @__PURE__ */ jsx(Bold, { className: cn("size-4", run?.bold && "text-primary") })
|
|
115
118
|
}
|
|
116
119
|
),
|
|
117
|
-
/* @__PURE__ */ jsx(
|
|
118
|
-
Action,
|
|
119
|
-
{
|
|
120
|
-
label: "Italic",
|
|
121
|
-
onClick: () => update((b) => styleRuns(b, (r) => ({ ...r, italic: !run?.italic }))),
|
|
122
|
-
children: /* @__PURE__ */ jsx(Italic, { className: cn("size-4", run?.italic && "text-primary") })
|
|
123
|
-
}
|
|
124
|
-
),
|
|
125
|
-
/* @__PURE__ */ jsx(
|
|
126
|
-
Action,
|
|
127
|
-
{
|
|
128
|
-
label: "Align",
|
|
129
|
-
onClick: () => update((b) => ({
|
|
130
|
-
...b,
|
|
131
|
-
paragraphs: b.paragraphs.map((p) => ({ ...p, align: ALIGN_NEXT[align] }))
|
|
132
|
-
})),
|
|
133
|
-
children: ALIGN_ICON[align]
|
|
134
|
-
}
|
|
135
|
-
),
|
|
136
120
|
/* @__PURE__ */ jsx(
|
|
137
121
|
ColorAction,
|
|
138
122
|
{
|
|
@@ -154,10 +138,58 @@ function BoxActionBar({ box, onRemoved }) {
|
|
|
154
138
|
children: /* @__PURE__ */ jsx(PaintBucket, { className: "size-4" })
|
|
155
139
|
}
|
|
156
140
|
),
|
|
157
|
-
/* @__PURE__ */
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
141
|
+
/* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
142
|
+
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
143
|
+
"button",
|
|
144
|
+
{
|
|
145
|
+
type: "button",
|
|
146
|
+
className: ACTION,
|
|
147
|
+
title: "More",
|
|
148
|
+
"aria-label": "More",
|
|
149
|
+
"data-testid": "box-more-menu",
|
|
150
|
+
children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "size-4" })
|
|
151
|
+
}
|
|
152
|
+
) }),
|
|
153
|
+
/* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", children: [
|
|
154
|
+
text && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
155
|
+
/* @__PURE__ */ jsxs(
|
|
156
|
+
DropdownMenuCheckboxItem,
|
|
157
|
+
{
|
|
158
|
+
checked: !!run?.italic,
|
|
159
|
+
onCheckedChange: () => update((b) => styleRuns(b, (r) => ({ ...r, italic: !run?.italic }))),
|
|
160
|
+
children: [
|
|
161
|
+
/* @__PURE__ */ jsx(Italic, { className: "size-4" }),
|
|
162
|
+
/* @__PURE__ */ jsx("span", { className: "ml-2", children: "Italic" })
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
),
|
|
166
|
+
["left", "center", "right"].map((value) => /* @__PURE__ */ jsxs(
|
|
167
|
+
DropdownMenuCheckboxItem,
|
|
168
|
+
{
|
|
169
|
+
checked: align === value,
|
|
170
|
+
onCheckedChange: () => update((b) => ({
|
|
171
|
+
...b,
|
|
172
|
+
paragraphs: b.paragraphs.map((p) => ({ ...p, align: value }))
|
|
173
|
+
})),
|
|
174
|
+
children: [
|
|
175
|
+
ALIGN_ICON[value],
|
|
176
|
+
/* @__PURE__ */ jsx("span", { className: "ml-2", children: value === "left" ? "Align left" : value === "center" ? "Centre" : "Align right" })
|
|
177
|
+
]
|
|
178
|
+
},
|
|
179
|
+
value
|
|
180
|
+
)),
|
|
181
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {})
|
|
182
|
+
] }),
|
|
183
|
+
/* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => actions.restackBox(box.id, "front"), children: [
|
|
184
|
+
/* @__PURE__ */ jsx(BringToFront, { className: "size-4" }),
|
|
185
|
+
/* @__PURE__ */ jsx("span", { className: "ml-2", children: "In front of the clips" })
|
|
186
|
+
] }),
|
|
187
|
+
/* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => actions.restackBox(box.id, "back"), children: [
|
|
188
|
+
/* @__PURE__ */ jsx(SendToBack, { className: "size-4" }),
|
|
189
|
+
/* @__PURE__ */ jsx("span", { className: "ml-2", children: "Behind the clips" })
|
|
190
|
+
] })
|
|
191
|
+
] })
|
|
192
|
+
] }),
|
|
161
193
|
/* @__PURE__ */ jsx(
|
|
162
194
|
"button",
|
|
163
195
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/presentation/BoxActionBar.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * The floating bar over a selected text box or shape: its type (smaller, larger, bold,
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["/**\n * The floating bar over a selected text box or shape: its type (smaller, larger, bold, its\n * colour), its fill and delete; italic, alignment and stacking in its \"\u2026\". Colours are picked with\n * the system's colour picker.\n */\n\nimport type { ReactNode } from 'react'\nimport {\n AlignCenter,\n AlignLeft,\n AlignRight,\n AArrowDown,\n AArrowUp,\n Baseline,\n Bold,\n BringToFront,\n Italic,\n MoreHorizontal,\n PaintBucket,\n SendToBack,\n Trash2,\n} from 'lucide-react'\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n cn,\n} from '@arbidocs/react/ui'\nimport { ACTION, Action } from './ClipActionBar'\nimport { DEFAULT_TEXT_SIZE, firstRun, styleRuns, type SlideBox, type TextAlign } from './boxes'\nimport { usePresentation } from './store'\nimport { TEXT_COLORS } from './theme'\n\nconst SIZE_STEPS = [8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 36, 44, 54, 66, 80, 96]\n\nconst nextSize = (size: number, up: boolean) =>\n up\n ? (SIZE_STEPS.find((step) => step > size + 0.5) ?? size)\n : ([...SIZE_STEPS].reverse().find((step) => step < size - 0.5) ?? size)\n\nconst ALIGN_ICON: Record<TextAlign, ReactNode> = {\n left: <AlignLeft className=\"size-4\" />,\n center: <AlignCenter className=\"size-4\" />,\n right: <AlignRight className=\"size-4\" />,\n justify: <AlignLeft className=\"size-4\" />,\n}\n\n/** A button that opens the system colour picker. */\nfunction ColorAction({\n label,\n value,\n onChange,\n children,\n}: {\n label: string\n value: string\n onChange: (color: string) => void\n children: ReactNode\n}) {\n return (\n <label className={cn(ACTION, 'relative cursor-pointer')} title={label} aria-label={label}>\n {children}\n <span\n className=\"pointer-events-none absolute inset-x-1.5 bottom-0.5 h-0.5 rounded-full\"\n style={{ background: value }}\n />\n <input\n type=\"color\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n className=\"absolute inset-0 size-full cursor-pointer opacity-0\"\n aria-label={label}\n />\n </label>\n )\n}\n\nexport interface BoxActionBarProps {\n box: SlideBox\n onRemoved: () => void\n}\n\nexport function BoxActionBar({ box, onRemoved }: BoxActionBarProps) {\n const actions = usePresentation.getState()\n const run = firstRun(box)\n const size = run?.size ?? DEFAULT_TEXT_SIZE\n const align = box.paragraphs[0]?.align ?? 'left'\n const update = (change: (b: SlideBox) => SlideBox) => actions.updateBox(box.id, change)\n const text = box.shape !== 'line'\n const top = Math.max(0, box.frame.y)\n return (\n <div\n role=\"toolbar\"\n aria-label=\"Text box\"\n className=\"absolute z-20 flex items-center gap-0.5 rounded-md border border-border bg-background p-0.5 shadow-md\"\n style={{\n left: `${Math.min(Math.max(0, box.frame.x), 0.6) * 100}%`,\n top: `calc(${top * 100}% - 40px)`,\n }}\n onPointerDown={(event) => event.stopPropagation()}\n data-testid=\"box-action-bar\"\n >\n {text && (\n <>\n <Action\n label=\"Smaller\"\n onClick={() =>\n update((b) => styleRuns(b, (r) => ({ ...r, size: nextSize(r.size ?? size, false) })))\n }\n >\n <AArrowDown className=\"size-4\" />\n </Action>\n <span\n className=\"w-7 text-center text-xs tabular-nums text-muted-foreground\"\n data-testid=\"box-text-size\"\n >\n {Math.round(size)}\n </span>\n <Action\n label=\"Larger\"\n onClick={() =>\n update((b) => styleRuns(b, (r) => ({ ...r, size: nextSize(r.size ?? size, true) })))\n }\n >\n <AArrowUp className=\"size-4\" />\n </Action>\n <Action\n label=\"Bold\"\n onClick={() => update((b) => styleRuns(b, (r) => ({ ...r, bold: !run?.bold })))}\n >\n <Bold className={cn('size-4', run?.bold && 'text-primary')} />\n </Action>\n <ColorAction\n label=\"Text colour\"\n value={run?.color ?? TEXT_COLORS.body}\n onChange={(color) => update((b) => styleRuns(b, (r) => ({ ...r, color })))}\n >\n <Baseline className=\"size-4\" />\n </ColorAction>\n </>\n )}\n <ColorAction\n label={box.shape === 'line' ? 'Line colour' : 'Fill'}\n value={(box.shape === 'line' ? box.line?.color : box.fill) ?? '#ffffff'}\n onChange={(color) =>\n update((b) =>\n b.shape === 'line'\n ? { ...b, line: { width: b.line?.width ?? 2, ...b.line, color } }\n : { ...b, fill: color, shape: b.shape === 'text' ? 'rect' : b.shape }\n )\n }\n >\n <PaintBucket className=\"size-4\" />\n </ColorAction>\n {/* The rest, behind \"\u2026\": italic, alignment, in front of or behind the clips. */}\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={ACTION}\n title=\"More\"\n aria-label=\"More\"\n data-testid=\"box-more-menu\"\n >\n <MoreHorizontal className=\"size-4\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {text && (\n <>\n <DropdownMenuCheckboxItem\n checked={!!run?.italic}\n onCheckedChange={() =>\n update((b) => styleRuns(b, (r) => ({ ...r, italic: !run?.italic })))\n }\n >\n <Italic className=\"size-4\" />\n <span className=\"ml-2\">Italic</span>\n </DropdownMenuCheckboxItem>\n {(['left', 'center', 'right'] as const).map((value) => (\n <DropdownMenuCheckboxItem\n key={value}\n checked={align === value}\n onCheckedChange={() =>\n update((b) => ({\n ...b,\n paragraphs: b.paragraphs.map((p) => ({ ...p, align: value })),\n }))\n }\n >\n {ALIGN_ICON[value]}\n <span className=\"ml-2\">\n {value === 'left'\n ? 'Align left'\n : value === 'center'\n ? 'Centre'\n : 'Align right'}\n </span>\n </DropdownMenuCheckboxItem>\n ))}\n <DropdownMenuSeparator />\n </>\n )}\n <DropdownMenuItem onSelect={() => actions.restackBox(box.id, 'front')}>\n <BringToFront className=\"size-4\" />\n <span className=\"ml-2\">In front of the clips</span>\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={() => actions.restackBox(box.id, 'back')}>\n <SendToBack className=\"size-4\" />\n <span className=\"ml-2\">Behind the clips</span>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n <button\n type=\"button\"\n className={cn(ACTION, 'text-destructive hover:bg-destructive/10')}\n title=\"Delete (Delete)\"\n aria-label=\"Delete\"\n onClick={() => {\n actions.removeBox(box.id)\n onRemoved()\n }}\n >\n <Trash2 className=\"size-4\" />\n </button>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -10,19 +10,26 @@ import {
|
|
|
10
10
|
BringToFront,
|
|
11
11
|
Crop,
|
|
12
12
|
Maximize2,
|
|
13
|
+
MoreHorizontal,
|
|
13
14
|
MoveHorizontal,
|
|
14
15
|
MoveVertical,
|
|
15
16
|
SendToBack,
|
|
16
17
|
Sparkles,
|
|
17
|
-
Trash2
|
|
18
|
+
Trash2,
|
|
19
|
+
ZoomIn
|
|
18
20
|
} from "lucide-react";
|
|
19
21
|
import {
|
|
20
22
|
DropdownMenu,
|
|
21
23
|
DropdownMenuContent,
|
|
22
24
|
DropdownMenuItem,
|
|
25
|
+
DropdownMenuSeparator,
|
|
23
26
|
DropdownMenuTrigger,
|
|
27
|
+
Popover,
|
|
28
|
+
PopoverContent,
|
|
29
|
+
PopoverTrigger,
|
|
24
30
|
cn
|
|
25
31
|
} from "@arbidocs/react/ui";
|
|
32
|
+
import { ClipViewControls } from "./ClipViewControls.js";
|
|
26
33
|
import { usePresentation } from "./store.js";
|
|
27
34
|
const ACTION = "inline-flex size-7 items-center justify-center rounded text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:size-11";
|
|
28
35
|
const SIZES = [
|
|
@@ -53,6 +60,7 @@ function ClipActionBar({
|
|
|
53
60
|
onCropImage
|
|
54
61
|
}) {
|
|
55
62
|
const actions = usePresentation.getState();
|
|
63
|
+
const clip = usePresentation((state) => state.clips.find((entry) => entry.id === clipId));
|
|
56
64
|
return /* @__PURE__ */ jsxs(
|
|
57
65
|
"div",
|
|
58
66
|
{
|
|
@@ -63,7 +71,7 @@ function ClipActionBar({
|
|
|
63
71
|
onPointerDown: (event) => event.stopPropagation(),
|
|
64
72
|
"data-testid": "clip-action-bar",
|
|
65
73
|
children: [
|
|
66
|
-
|
|
74
|
+
/* @__PURE__ */ jsx(Action, { label: "Fit the slide", onClick: () => actions.applyFrame(clipId, "fit"), children: /* @__PURE__ */ jsx(Maximize2, { className: "size-4" }) }),
|
|
67
75
|
/* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
68
76
|
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx("button", { type: "button", className: ACTION, title: "Align", "aria-label": "Align", children: /* @__PURE__ */ jsx(AlignCenterHorizontal, { className: "size-4" }) }) }),
|
|
69
77
|
/* @__PURE__ */ jsx(DropdownMenuContent, { align: "start", children: ALIGNMENTS.map(({ alignment, label, icon }) => /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => actions.align(clipId, alignment), children: [
|
|
@@ -71,11 +79,56 @@ function ClipActionBar({
|
|
|
71
79
|
/* @__PURE__ */ jsx("span", { className: "ml-2", children: label })
|
|
72
80
|
] }, alignment)) })
|
|
73
81
|
] }),
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
82
|
+
clip && /* @__PURE__ */ jsxs(Popover, { children: [
|
|
83
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
84
|
+
"button",
|
|
85
|
+
{
|
|
86
|
+
type: "button",
|
|
87
|
+
className: ACTION,
|
|
88
|
+
title: "View: scroll or zoom what the clip shows (or scroll over it)",
|
|
89
|
+
"aria-label": "View",
|
|
90
|
+
"data-testid": "clip-view-button",
|
|
91
|
+
children: /* @__PURE__ */ jsx(ZoomIn, { className: "size-4" })
|
|
92
|
+
}
|
|
93
|
+
) }),
|
|
94
|
+
/* @__PURE__ */ jsx(PopoverContent, { align: "start", className: "w-auto p-2", children: /* @__PURE__ */ jsx(ClipViewControls, { clip }) })
|
|
95
|
+
] }),
|
|
96
|
+
/* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
97
|
+
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
98
|
+
"button",
|
|
99
|
+
{
|
|
100
|
+
type: "button",
|
|
101
|
+
className: ACTION,
|
|
102
|
+
title: "More",
|
|
103
|
+
"aria-label": "More",
|
|
104
|
+
"data-testid": "clip-more-menu",
|
|
105
|
+
children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "size-4" })
|
|
106
|
+
}
|
|
107
|
+
) }),
|
|
108
|
+
/* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", children: [
|
|
109
|
+
SIZES.filter(({ command }) => command !== "fit").map(({ command, label, icon }) => /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => actions.applyFrame(clipId, command), children: [
|
|
110
|
+
icon,
|
|
111
|
+
/* @__PURE__ */ jsx("span", { className: "ml-2", children: label })
|
|
112
|
+
] }, command)),
|
|
113
|
+
onCropImage && /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: onCropImage, children: [
|
|
114
|
+
/* @__PURE__ */ jsx(Crop, { className: "size-4" }),
|
|
115
|
+
/* @__PURE__ */ jsx("span", { className: "ml-2", children: "Crop" })
|
|
116
|
+
] }),
|
|
117
|
+
onEditImage && /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: onEditImage, children: [
|
|
118
|
+
/* @__PURE__ */ jsx(Sparkles, { className: "size-4" }),
|
|
119
|
+
/* @__PURE__ */ jsx("span", { className: "ml-2", children: "Edit image" })
|
|
120
|
+
] }),
|
|
121
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
122
|
+
/* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => actions.bringToFront(clipId), children: [
|
|
123
|
+
/* @__PURE__ */ jsx(BringToFront, { className: "size-4" }),
|
|
124
|
+
/* @__PURE__ */ jsx("span", { className: "ml-2", children: "Bring to front" })
|
|
125
|
+
] }),
|
|
126
|
+
/* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => actions.sendToBack(clipId), children: [
|
|
127
|
+
/* @__PURE__ */ jsx(SendToBack, { className: "size-4" }),
|
|
128
|
+
/* @__PURE__ */ jsx("span", { className: "ml-2", children: "Send to back" })
|
|
129
|
+
] })
|
|
130
|
+
] })
|
|
131
|
+
] }),
|
|
79
132
|
/* @__PURE__ */ jsx("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
80
133
|
/* @__PURE__ */ jsx(
|
|
81
134
|
"button",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/presentation/ClipActionBar.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * The floating action bar over the selected clip (the markup overlay's pattern): size it to the\n * stage, align it, put it in front or behind, take it off the slide. Icons with labels on hover\n * (`title`: portalled tooltips misplace in a popped-out window).\n */\n\nimport type { ReactNode } from 'react'\nimport {\n AlignCenterHorizontal,\n AlignCenterVertical,\n AlignEndHorizontal,\n AlignEndVertical,\n AlignStartHorizontal,\n AlignStartVertical,\n BringToFront,\n Crop,\n Maximize2,\n MoveHorizontal,\n MoveVertical,\n SendToBack,\n Sparkles,\n Trash2,\n} from 'lucide-react'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n cn,\n} from '@arbidocs/react/ui'\nimport type { Alignment } from './model'\nimport { usePresentation, type FrameCommand } from './store'\n\nexport const ACTION =\n 'inline-flex size-7 items-center justify-center rounded text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:size-11'\n\nconst SIZES: { command: FrameCommand; label: string; icon: ReactNode }[] = [\n { command: 'fit', label: 'Fit the slide', icon: <Maximize2 className=\"size-4\" /> },\n { command: 'fullWidth', label: 'Full width', icon: <MoveHorizontal className=\"size-4\" /> },\n { command: 'fullHeight', label: 'Full height', icon: <MoveVertical className=\"size-4\" /> },\n]\n\nconst ALIGNMENTS: { alignment: Alignment; label: string; icon: ReactNode }[] = [\n { alignment: 'left', label: 'Left', icon: <AlignStartVertical className=\"size-4\" /> },\n { alignment: 'centre', label: 'Centre', icon: <AlignCenterVertical className=\"size-4\" /> },\n { alignment: 'right', label: 'Right', icon: <AlignEndVertical className=\"size-4\" /> },\n { alignment: 'top', label: 'Top', icon: <AlignStartHorizontal className=\"size-4\" /> },\n { alignment: 'middle', label: 'Middle', icon: <AlignCenterHorizontal className=\"size-4\" /> },\n { alignment: 'bottom', label: 'Bottom', icon: <AlignEndHorizontal className=\"size-4\" /> },\n]\n\nexport function Action({\n label,\n onClick,\n children,\n}: {\n label: string\n onClick: () => void\n children: ReactNode\n}) {\n return (\n <button type=\"button\" className={ACTION} title={label} aria-label={label} onClick={onClick}>\n {children}\n </button>\n )\n}\n\nexport interface ClipActionBarProps {\n clipId: string\n /** The clip's top-left, as fractions of the stage. */\n at: { x: number; y: number }\n onRemoved: () => void\n /** An image clip: make a new version of the image (Generate image with it as the reference). */\n onEditImage?: () => void\n /** An image clip: choose the part of the image it shows. */\n onCropImage?: () => void\n}\n\nexport function ClipActionBar({\n clipId,\n at,\n onRemoved,\n onEditImage,\n onCropImage,\n}: ClipActionBarProps) {\n const actions = usePresentation.getState()\n return (\n <div\n role=\"toolbar\"\n aria-label=\"Clip\"\n className=\"absolute z-20 flex items-center gap-0.5 rounded-md border border-border bg-background p-0.5 shadow-md\"\n style={{ left: `${at.x * 100}%`, top: `calc(${at.y * 100}% - 40px)` }}\n // Its clicks are not a click on the stage (which would deselect the clip).\n onPointerDown={(event) => event.stopPropagation()}\n data-testid=\"clip-action-bar\"\n >\n {
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["/**\n * The floating action bar over the selected clip (the markup overlay's pattern): size it to the\n * stage, align it, put it in front or behind, take it off the slide. Icons with labels on hover\n * (`title`: portalled tooltips misplace in a popped-out window).\n */\n\nimport type { ReactNode } from 'react'\nimport {\n AlignCenterHorizontal,\n AlignCenterVertical,\n AlignEndHorizontal,\n AlignEndVertical,\n AlignStartHorizontal,\n AlignStartVertical,\n BringToFront,\n Crop,\n Maximize2,\n MoreHorizontal,\n MoveHorizontal,\n MoveVertical,\n SendToBack,\n Sparkles,\n Trash2,\n ZoomIn,\n} from 'lucide-react'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Popover,\n PopoverContent,\n PopoverTrigger,\n cn,\n} from '@arbidocs/react/ui'\nimport { ClipViewControls } from './ClipViewControls'\nimport type { Alignment } from './model'\nimport { usePresentation, type FrameCommand } from './store'\n\nexport const ACTION =\n 'inline-flex size-7 items-center justify-center rounded text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:size-11'\n\nconst SIZES: { command: FrameCommand; label: string; icon: ReactNode }[] = [\n { command: 'fit', label: 'Fit the slide', icon: <Maximize2 className=\"size-4\" /> },\n { command: 'fullWidth', label: 'Full width', icon: <MoveHorizontal className=\"size-4\" /> },\n { command: 'fullHeight', label: 'Full height', icon: <MoveVertical className=\"size-4\" /> },\n]\n\nconst ALIGNMENTS: { alignment: Alignment; label: string; icon: ReactNode }[] = [\n { alignment: 'left', label: 'Left', icon: <AlignStartVertical className=\"size-4\" /> },\n { alignment: 'centre', label: 'Centre', icon: <AlignCenterVertical className=\"size-4\" /> },\n { alignment: 'right', label: 'Right', icon: <AlignEndVertical className=\"size-4\" /> },\n { alignment: 'top', label: 'Top', icon: <AlignStartHorizontal className=\"size-4\" /> },\n { alignment: 'middle', label: 'Middle', icon: <AlignCenterHorizontal className=\"size-4\" /> },\n { alignment: 'bottom', label: 'Bottom', icon: <AlignEndHorizontal className=\"size-4\" /> },\n]\n\nexport function Action({\n label,\n onClick,\n children,\n}: {\n label: string\n onClick: () => void\n children: ReactNode\n}) {\n return (\n <button type=\"button\" className={ACTION} title={label} aria-label={label} onClick={onClick}>\n {children}\n </button>\n )\n}\n\nexport interface ClipActionBarProps {\n clipId: string\n /** The clip's top-left, as fractions of the stage. */\n at: { x: number; y: number }\n onRemoved: () => void\n /** An image clip: make a new version of the image (Generate image with it as the reference). */\n onEditImage?: () => void\n /** An image clip: choose the part of the image it shows. */\n onCropImage?: () => void\n}\n\nexport function ClipActionBar({\n clipId,\n at,\n onRemoved,\n onEditImage,\n onCropImage,\n}: ClipActionBarProps) {\n const actions = usePresentation.getState()\n const clip = usePresentation((state) => state.clips.find((entry) => entry.id === clipId))\n return (\n <div\n role=\"toolbar\"\n aria-label=\"Clip\"\n className=\"absolute z-20 flex items-center gap-0.5 rounded-md border border-border bg-background p-0.5 shadow-md\"\n style={{ left: `${at.x * 100}%`, top: `calc(${at.y * 100}% - 40px)` }}\n // Its clicks are not a click on the stage (which would deselect the clip).\n onPointerDown={(event) => event.stopPropagation()}\n data-testid=\"clip-action-bar\"\n >\n {/* The commonest: fit it to the slide, line it up, adjust what it shows. */}\n <Action label=\"Fit the slide\" onClick={() => actions.applyFrame(clipId, 'fit')}>\n <Maximize2 className=\"size-4\" />\n </Action>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button type=\"button\" className={ACTION} title=\"Align\" aria-label=\"Align\">\n <AlignCenterHorizontal className=\"size-4\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {ALIGNMENTS.map(({ alignment, label, icon }) => (\n <DropdownMenuItem key={alignment} onSelect={() => actions.align(clipId, alignment)}>\n {icon}\n <span className=\"ml-2\">{label}</span>\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n {clip && (\n <Popover>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n className={ACTION}\n title=\"View: scroll or zoom what the clip shows (or scroll over it)\"\n aria-label=\"View\"\n data-testid=\"clip-view-button\"\n >\n <ZoomIn className=\"size-4\" />\n </button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-auto p-2\">\n <ClipViewControls clip={clip} />\n </PopoverContent>\n </Popover>\n )}\n {/* The rest, behind \"\u2026\". */}\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={ACTION}\n title=\"More\"\n aria-label=\"More\"\n data-testid=\"clip-more-menu\"\n >\n <MoreHorizontal className=\"size-4\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {SIZES.filter(({ command }) => command !== 'fit').map(({ command, label, icon }) => (\n <DropdownMenuItem key={command} onSelect={() => actions.applyFrame(clipId, command)}>\n {icon}\n <span className=\"ml-2\">{label}</span>\n </DropdownMenuItem>\n ))}\n {onCropImage && (\n <DropdownMenuItem onSelect={onCropImage}>\n <Crop className=\"size-4\" />\n <span className=\"ml-2\">Crop</span>\n </DropdownMenuItem>\n )}\n {onEditImage && (\n <DropdownMenuItem onSelect={onEditImage}>\n <Sparkles className=\"size-4\" />\n <span className=\"ml-2\">Edit image</span>\n </DropdownMenuItem>\n )}\n <DropdownMenuSeparator />\n <DropdownMenuItem onSelect={() => actions.bringToFront(clipId)}>\n <BringToFront className=\"size-4\" />\n <span className=\"ml-2\">Bring to front</span>\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={() => actions.sendToBack(clipId)}>\n <SendToBack className=\"size-4\" />\n <span className=\"ml-2\">Send to back</span>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n <div className=\"mx-0.5 h-5 w-px bg-border\" />\n <button\n type=\"button\"\n className={cn(ACTION, 'text-destructive hover:bg-destructive/10')}\n title=\"Remove from slide (Delete)\"\n aria-label=\"Remove from slide\"\n onClick={() => {\n actions.unplace(clipId)\n onRemoved()\n }}\n >\n <Trash2 className=\"size-4\" />\n </button>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* at the source's edge is off), and a zoom slider zooms about the clip's centre.
|
|
2
|
+
* A clip's view controls (in its action bar's View popover, so nothing covers what it shows):
|
|
3
|
+
* arrows scroll what the clip shows over its source (a press steps, holding keeps scrolling; an
|
|
4
|
+
* arrow at the source's edge is off), and a zoom slider zooms about the clip's centre.
|
|
5
5
|
* The clip's frame on the slide does not change; only the part of the source it shows. Presses
|
|
6
6
|
* here never start moving the clip.
|
|
7
7
|
*/
|
|
@@ -9,7 +9,7 @@ const PAN_STEP = 0.1;
|
|
|
9
9
|
const MAX_ZOOM = 800;
|
|
10
10
|
const HOLD_DELAY = 350;
|
|
11
11
|
const HOLD_EVERY = 90;
|
|
12
|
-
const BUTTON = "
|
|
12
|
+
const BUTTON = "flex size-7 items-center justify-center rounded-full border border-border bg-background text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-30 pointer-coarse:size-11";
|
|
13
13
|
function HoldButton({
|
|
14
14
|
label,
|
|
15
15
|
disabled,
|
|
@@ -64,74 +64,69 @@ function ClipViewControls({ clip }) {
|
|
|
64
64
|
return /* @__PURE__ */ jsxs(
|
|
65
65
|
"div",
|
|
66
66
|
{
|
|
67
|
-
className: "
|
|
67
|
+
className: "flex flex-col items-center gap-2 p-1",
|
|
68
68
|
onPointerDown: (event) => event.stopPropagation(),
|
|
69
69
|
"data-testid": "clip-view-controls",
|
|
70
70
|
children: [
|
|
71
|
-
/* @__PURE__ */
|
|
72
|
-
|
|
71
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 grid-rows-3 place-items-center gap-0.5", children: [
|
|
72
|
+
/* @__PURE__ */ jsx(
|
|
73
|
+
HoldButton,
|
|
74
|
+
{
|
|
75
|
+
label: "Show more above",
|
|
76
|
+
disabled: rect.y <= edge,
|
|
77
|
+
onStep: pan(0, -PAN_STEP),
|
|
78
|
+
className: "col-start-2 row-start-1",
|
|
79
|
+
children: /* @__PURE__ */ jsx(ChevronUp, { className: "size-4" })
|
|
80
|
+
}
|
|
81
|
+
),
|
|
82
|
+
/* @__PURE__ */ jsx(
|
|
83
|
+
HoldButton,
|
|
84
|
+
{
|
|
85
|
+
label: "Show more on the left",
|
|
86
|
+
disabled: rect.x <= edge,
|
|
87
|
+
onStep: pan(-PAN_STEP, 0),
|
|
88
|
+
className: "col-start-1 row-start-2",
|
|
89
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" })
|
|
90
|
+
}
|
|
91
|
+
),
|
|
92
|
+
/* @__PURE__ */ jsx(
|
|
93
|
+
HoldButton,
|
|
94
|
+
{
|
|
95
|
+
label: "Show more on the right",
|
|
96
|
+
disabled: rect.x + rect.w >= 1 - edge,
|
|
97
|
+
onStep: pan(PAN_STEP, 0),
|
|
98
|
+
className: "col-start-3 row-start-2",
|
|
99
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" })
|
|
100
|
+
}
|
|
101
|
+
),
|
|
102
|
+
/* @__PURE__ */ jsx(
|
|
103
|
+
HoldButton,
|
|
104
|
+
{
|
|
105
|
+
label: "Show more below",
|
|
106
|
+
disabled: rect.y + rect.h >= 1 - edge,
|
|
107
|
+
onStep: pan(0, PAN_STEP),
|
|
108
|
+
className: "col-start-2 row-start-3",
|
|
109
|
+
children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-4" })
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
] }),
|
|
113
|
+
/* @__PURE__ */ jsx("div", { "data-testid": "clip-zoom-control", children: /* @__PURE__ */ jsx(
|
|
114
|
+
ZoomSlider,
|
|
73
115
|
{
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
116
|
+
value: zoom,
|
|
117
|
+
min: minZoom,
|
|
118
|
+
max: Math.max(MAX_ZOOM, zoom),
|
|
119
|
+
zoomOutStep: 25,
|
|
120
|
+
onChange: (value) => setClipZoom(clip.id, value),
|
|
121
|
+
label: "Zoom",
|
|
122
|
+
valueLabel: /* @__PURE__ */ jsxs("span", { "data-testid": "clip-zoom", children: [
|
|
123
|
+
zoom,
|
|
124
|
+
"%"
|
|
125
|
+
] }),
|
|
126
|
+
className: "pointer-coarse:h-11",
|
|
127
|
+
sliderClassName: "w-28"
|
|
79
128
|
}
|
|
80
|
-
)
|
|
81
|
-
/* @__PURE__ */ jsx(
|
|
82
|
-
HoldButton,
|
|
83
|
-
{
|
|
84
|
-
label: "Show more below",
|
|
85
|
-
disabled: rect.y + rect.h >= 1 - edge,
|
|
86
|
-
onStep: pan(0, PAN_STEP),
|
|
87
|
-
className: "absolute bottom-10 left-1/2 -translate-x-1/2 pointer-coarse:bottom-14",
|
|
88
|
-
children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-4" })
|
|
89
|
-
}
|
|
90
|
-
),
|
|
91
|
-
/* @__PURE__ */ jsx(
|
|
92
|
-
HoldButton,
|
|
93
|
-
{
|
|
94
|
-
label: "Show more on the left",
|
|
95
|
-
disabled: rect.x <= edge,
|
|
96
|
-
onStep: pan(-PAN_STEP, 0),
|
|
97
|
-
className: "absolute left-4 top-1/2 -translate-y-1/2 pointer-coarse:left-7",
|
|
98
|
-
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" })
|
|
99
|
-
}
|
|
100
|
-
),
|
|
101
|
-
/* @__PURE__ */ jsx(
|
|
102
|
-
HoldButton,
|
|
103
|
-
{
|
|
104
|
-
label: "Show more on the right",
|
|
105
|
-
disabled: rect.x + rect.w >= 1 - edge,
|
|
106
|
-
onStep: pan(PAN_STEP, 0),
|
|
107
|
-
className: "absolute right-4 top-1/2 -translate-y-1/2 pointer-coarse:right-7",
|
|
108
|
-
children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" })
|
|
109
|
-
}
|
|
110
|
-
),
|
|
111
|
-
/* @__PURE__ */ jsx(
|
|
112
|
-
"div",
|
|
113
|
-
{
|
|
114
|
-
className: "pointer-events-auto absolute bottom-1.5 left-1/2 -translate-x-1/2",
|
|
115
|
-
"data-testid": "clip-zoom-control",
|
|
116
|
-
children: /* @__PURE__ */ jsx(
|
|
117
|
-
ZoomSlider,
|
|
118
|
-
{
|
|
119
|
-
value: zoom,
|
|
120
|
-
min: minZoom,
|
|
121
|
-
max: Math.max(MAX_ZOOM, zoom),
|
|
122
|
-
zoomOutStep: 25,
|
|
123
|
-
onChange: (value) => setClipZoom(clip.id, value),
|
|
124
|
-
label: "Zoom",
|
|
125
|
-
valueLabel: /* @__PURE__ */ jsxs("span", { "data-testid": "clip-zoom", children: [
|
|
126
|
-
zoom,
|
|
127
|
-
"%"
|
|
128
|
-
] }),
|
|
129
|
-
className: "bg-background/95 shadow-sm backdrop-blur-sm pointer-coarse:h-11",
|
|
130
|
-
sliderClassName: "w-24"
|
|
131
|
-
}
|
|
132
|
-
)
|
|
133
|
-
}
|
|
134
|
-
)
|
|
129
|
+
) })
|
|
135
130
|
]
|
|
136
131
|
}
|
|
137
132
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/presentation/ClipViewControls.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n *
|
|
5
|
-
"mappings": ";AA4DI,
|
|
4
|
+
"sourcesContent": ["/**\n * A clip's view controls (in its action bar's View popover, so nothing covers what it shows):\n * arrows scroll what the clip shows over its source (a press steps, holding keeps scrolling; an\n * arrow at the source's edge is off), and a zoom slider zooms about the clip's centre.\n * The clip's frame on the slide does not change; only the part of the source it shows. Presses\n * here never start moving the clip.\n */\n\nimport { useEffect, useRef, type PointerEvent as ReactPointerEvent, type ReactNode } from 'react'\nimport { ChevronDown, ChevronLeft, ChevronRight, ChevronUp } from 'lucide-react'\nimport { cn } from '@arbidocs/react/ui'\nimport { ZoomSlider } from '../components/ZoomSlider'\nimport type { Clip } from './model'\nimport { usePresentation } from './store'\n\n/** One step scrolls this much of what the clip shows. */\nconst PAN_STEP = 0.1\n/** The closest a clip zooms, in percent of how close it was cut. */\nconst MAX_ZOOM = 800\n/** Holding a button repeats it after this long, this often. */\nconst HOLD_DELAY = 350\nconst HOLD_EVERY = 90\n\nconst BUTTON =\n 'flex size-7 items-center justify-center rounded-full border border-border bg-background text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-30 pointer-coarse:size-11'\n\n/** A button that acts on press and keeps acting while held. */\nfunction HoldButton({\n label,\n disabled,\n onStep,\n className,\n children,\n}: {\n label: string\n disabled?: boolean\n onStep: () => void\n className?: string\n children: ReactNode\n}) {\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null)\n const stop = () => {\n if (timer.current) clearTimeout(timer.current)\n timer.current = null\n }\n useEffect(() => stop, [])\n useEffect(() => {\n if (disabled) stop()\n }, [disabled])\n const start = (event: ReactPointerEvent) => {\n event.stopPropagation()\n if (disabled || event.button !== 0) return\n onStep()\n const repeat = () => {\n onStep()\n timer.current = setTimeout(repeat, HOLD_EVERY)\n }\n timer.current = setTimeout(repeat, HOLD_DELAY)\n }\n return (\n <button\n type=\"button\"\n className={cn(BUTTON, className)}\n title={label}\n aria-label={label}\n disabled={disabled}\n onPointerDown={start}\n onPointerUp={stop}\n onPointerLeave={stop}\n onPointerCancel={stop}\n // Keyboard: Enter / Space step once.\n onClick={(event) => event.detail === 0 && onStep()}\n >\n {children}\n </button>\n )\n}\n\nexport function ClipViewControls({ clip }: { clip: Clip }) {\n const { panClip, setClipZoom } = usePresentation.getState()\n const { rect } = clip\n const zoomBase = clip.zoomBase ?? rect.w\n // As far out as it goes: the widest area of this shape the source holds.\n const minZoom = Math.min(100, Math.floor((zoomBase / Math.min(1, rect.w / rect.h)) * 100))\n const pan = (dx: number, dy: number) => () => panClip(clip.id, dx * rect.w, dy * rect.h)\n const zoom = Math.round((zoomBase / rect.w) * 100)\n const edge = 1e-6\n return (\n <div\n className=\"flex flex-col items-center gap-2 p-1\"\n // A press here is not a press on the clip (which would start moving it).\n onPointerDown={(event) => event.stopPropagation()}\n data-testid=\"clip-view-controls\"\n >\n {/* Move the view: what the clip shows, over its source (the wheel does the same). */}\n <div className=\"grid grid-cols-3 grid-rows-3 place-items-center gap-0.5\">\n <HoldButton\n label=\"Show more above\"\n disabled={rect.y <= edge}\n onStep={pan(0, -PAN_STEP)}\n className=\"col-start-2 row-start-1\"\n >\n <ChevronUp className=\"size-4\" />\n </HoldButton>\n <HoldButton\n label=\"Show more on the left\"\n disabled={rect.x <= edge}\n onStep={pan(-PAN_STEP, 0)}\n className=\"col-start-1 row-start-2\"\n >\n <ChevronLeft className=\"size-4\" />\n </HoldButton>\n <HoldButton\n label=\"Show more on the right\"\n disabled={rect.x + rect.w >= 1 - edge}\n onStep={pan(PAN_STEP, 0)}\n className=\"col-start-3 row-start-2\"\n >\n <ChevronRight className=\"size-4\" />\n </HoldButton>\n <HoldButton\n label=\"Show more below\"\n disabled={rect.y + rect.h >= 1 - edge}\n onStep={pan(0, PAN_STEP)}\n className=\"col-start-2 row-start-3\"\n >\n <ChevronDown className=\"size-4\" />\n </HoldButton>\n </div>\n {/* Zoom: a slider, from as far out as the source allows to MAX_ZOOM. */}\n <div data-testid=\"clip-zoom-control\">\n <ZoomSlider\n value={zoom}\n min={minZoom}\n max={Math.max(MAX_ZOOM, zoom)}\n zoomOutStep={25}\n onChange={(value) => setClipZoom(clip.id, value)}\n label=\"Zoom\"\n valueLabel={<span data-testid=\"clip-zoom\">{zoom}%</span>}\n className=\"pointer-coarse:h-11\"\n sliderClassName=\"w-28\"\n />\n </div>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|