@bendyline/squisq-editor-react 2.11.27 → 2.12.1

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.
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  MarkdownEscape
3
- } from "./chunk-OCQEWWHI.js";
3
+ } from "./chunk-KI5XQWRU.js";
4
4
  import {
5
5
  markdownToTiptap,
6
6
  tiptapToMarkdown
7
- } from "./chunk-HSWWEWT4.js";
7
+ } from "./chunk-WMNL2WEI.js";
8
8
 
9
9
  // src/jsonEditor/JsonEditorContext.tsx
10
10
  import { createContext, useContext, useEffect, useMemo } from "react";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-LRZJD5YD.js";
9
9
  import {
10
10
  Icon
11
- } from "./chunk-GS7QWYFT.js";
11
+ } from "./chunk-UYB5CPRE.js";
12
12
  import {
13
13
  NarrationStage,
14
14
  buildTimingJson,
@@ -1851,7 +1851,9 @@ function resolveSlideVisual(doc, block, slide, theme, viewport, index, totalBloc
1851
1851
  }
1852
1852
 
1853
1853
  // src/recorder/slides/RecorderSlidesPanel.tsx
1854
- import { useCallback as useCallback3 } from "react";
1854
+ import { useBuildNavigation } from "@bendyline/squisq-react";
1855
+ import { blockBuildSteps, buildSourceText } from "@bendyline/squisq/doc";
1856
+ import { useCallback as useCallback3, useEffect as useEffect4 } from "react";
1855
1857
 
1856
1858
  // src/TimelineBlockPreview.tsx
1857
1859
  import { memo } from "react";
@@ -1860,11 +1862,21 @@ import { BlockRenderer, MediaContext } from "@bendyline/squisq-react";
1860
1862
  import { jsx as jsx3 } from "react/jsx-runtime";
1861
1863
  var BlockThumbnail = memo(function BlockThumbnail2({
1862
1864
  visual,
1865
+ buildPlayback = "all",
1863
1866
  viewport = VIEWPORT_PRESETS.landscape,
1864
1867
  basePath = "/",
1865
1868
  mediaProvider = null
1866
1869
  }) {
1867
- return /* @__PURE__ */ jsx3(MediaContext.Provider, { value: mediaProvider, children: /* @__PURE__ */ jsx3(BlockRenderer, { block: visual, blockTime: 0, basePath, viewport }) });
1870
+ return /* @__PURE__ */ jsx3(MediaContext.Provider, { value: mediaProvider, children: /* @__PURE__ */ jsx3(
1871
+ BlockRenderer,
1872
+ {
1873
+ buildPlayback,
1874
+ block: visual,
1875
+ blockTime: 0,
1876
+ basePath,
1877
+ viewport
1878
+ }
1879
+ ) });
1868
1880
  });
1869
1881
 
1870
1882
  // src/recorder/slides/RecorderSlidesPanel.tsx
@@ -1949,13 +1961,28 @@ function RecorderSlidesPanel({
1949
1961
  basePath = "/",
1950
1962
  mediaProvider = null,
1951
1963
  recording = false,
1952
- shownBlockIds
1964
+ shownBlockIds,
1965
+ onBuildShown
1953
1966
  }) {
1954
1967
  const count = slides.length;
1955
1968
  const active = slides[clampSlideIndex(index, count)];
1969
+ const builds = useBuildNavigation(active?.visual, true, true);
1970
+ const { next: nextBuild, previous: previousBuild, enter: enterBuild } = builds;
1971
+ const sourceText = active?.visual ? buildSourceText(blockBuildSteps(active.visual)) : "";
1972
+ useEffect4(() => {
1973
+ if (!active || !onBuildShown) return;
1974
+ for (let step2 = 0; step2 < builds.cursor.revealed; step2++)
1975
+ onBuildShown(active.blockId, step2, sourceText);
1976
+ }, [active, builds.cursor.revealed, sourceText, recording, onBuildShown]);
1956
1977
  const step = useCallback3(
1957
- (delta) => onIndexChange(clampSlideIndex(index + delta, count)),
1958
- [index, count, onIndexChange]
1978
+ (delta) => {
1979
+ if (delta > 0 ? nextBuild() : previousBuild()) return;
1980
+ const next = clampSlideIndex(index + delta, count);
1981
+ if (next === index) return;
1982
+ enterBuild(slides[next]?.visual, delta < 0);
1983
+ onIndexChange(next);
1984
+ },
1985
+ [index, count, onIndexChange, nextBuild, previousBuild, enterBuild, slides]
1959
1986
  );
1960
1987
  const handleKeyDown = useCallback3(
1961
1988
  (event) => {
@@ -1985,7 +2012,8 @@ function RecorderSlidesPanel({
1985
2012
  "Slide ",
1986
2013
  index + 1,
1987
2014
  " of ",
1988
- count
2015
+ count,
2016
+ builds.count > 0 ? ` \xB7 Build ${builds.cursor.revealed} of ${builds.count}` : ""
1989
2017
  ] }),
1990
2018
  /* @__PURE__ */ jsx4("span", { style: dotsStyle, "aria-hidden": "true", children: slides.map((slide, i) => /* @__PURE__ */ jsx4(
1991
2019
  "span",
@@ -2005,7 +2033,7 @@ function RecorderSlidesPanel({
2005
2033
  type: "button",
2006
2034
  style: navButtonStyle,
2007
2035
  onClick: () => step(-1),
2008
- disabled: index <= 0,
2036
+ disabled: index <= 0 && builds.cursor.revealed === 0,
2009
2037
  "aria-label": "Previous slide",
2010
2038
  children: /* @__PURE__ */ jsx4(Icon, { icon: "fa-solid fa-chevron-left" })
2011
2039
  }
@@ -2016,7 +2044,7 @@ function RecorderSlidesPanel({
2016
2044
  type: "button",
2017
2045
  style: navButtonStyle,
2018
2046
  onClick: () => step(1),
2019
- disabled: index >= count - 1,
2047
+ disabled: index >= count - 1 && builds.cursor.revealed >= builds.count && builds.cursor.progress >= 1,
2020
2048
  "aria-label": "Next slide",
2021
2049
  children: /* @__PURE__ */ jsx4(Icon, { icon: "fa-solid fa-chevron-right" })
2022
2050
  }
@@ -2036,6 +2064,7 @@ function RecorderSlidesPanel({
2036
2064
  BlockThumbnail,
2037
2065
  {
2038
2066
  visual: active.visual,
2067
+ buildPlayback: builds.cursor,
2039
2068
  viewport,
2040
2069
  basePath,
2041
2070
  mediaProvider
@@ -2074,10 +2103,11 @@ function RecorderSlidesPanel({
2074
2103
  }
2075
2104
 
2076
2105
  // src/recorder/RecorderModal.tsx
2106
+ import { recordBuildAdvance } from "@bendyline/squisq/schemas";
2077
2107
  import {
2078
2108
  Fragment as Fragment2,
2079
2109
  useCallback as useCallback4,
2080
- useEffect as useEffect4,
2110
+ useEffect as useEffect5,
2081
2111
  useId as useId2,
2082
2112
  useMemo,
2083
2113
  useRef as useRef2,
@@ -2278,14 +2308,17 @@ var modalStyle = {
2278
2308
  border: "1px solid var(--squisq-recorder-border)",
2279
2309
  borderRadius: 0,
2280
2310
  padding: "24px 28px",
2311
+ boxSizing: "border-box",
2281
2312
  width: "min(560px, calc(100vw - 48px))",
2282
- maxHeight: "calc(100vh - 48px)",
2313
+ maxHeight: "calc(100dvh - 48px)",
2283
2314
  overflowY: "auto",
2315
+ overscrollBehaviorY: "contain",
2284
2316
  boxShadow: "0 8px 32px rgba(0,0,0,0.18)",
2285
2317
  fontFamily: "system-ui, -apple-system, sans-serif",
2286
2318
  color: "var(--squisq-recorder-text)"
2287
2319
  };
2288
2320
  var titleStyle = {
2321
+ flexShrink: 0,
2289
2322
  margin: "0 0 16px 0",
2290
2323
  fontSize: 18,
2291
2324
  fontWeight: 600,
@@ -2466,8 +2499,7 @@ var recordingStatusStyle = {
2466
2499
  var modalExpandedStyle = {
2467
2500
  ...modalStyle,
2468
2501
  width: "calc(100vw - 48px)",
2469
- height: "calc(100vh - 48px)",
2470
- maxHeight: "none",
2502
+ height: "calc(100dvh - 48px)",
2471
2503
  overflowY: "hidden",
2472
2504
  display: "flex",
2473
2505
  flexDirection: "column"
@@ -2481,6 +2513,7 @@ var bodyRowStyle = {
2481
2513
  var leftColStyle = {
2482
2514
  flex: "0 0 min(420px, 38vw)",
2483
2515
  overflowY: "auto",
2516
+ overscrollBehaviorY: "contain",
2484
2517
  minHeight: 0,
2485
2518
  paddingRight: 4
2486
2519
  };
@@ -2499,6 +2532,11 @@ var checkboxRowStyle = {
2499
2532
  marginBottom: 12,
2500
2533
  fontSize: 13
2501
2534
  };
2535
+ var modeTogglesStyle = {
2536
+ display: "flex",
2537
+ flexWrap: "wrap",
2538
+ columnGap: 20
2539
+ };
2502
2540
  var meterLevelStyle = {
2503
2541
  position: "absolute",
2504
2542
  left: 0,
@@ -2708,6 +2746,19 @@ function RecorderModal({
2708
2746
  const slidesAvailable = slideDeck.length > 0;
2709
2747
  const slidesCaptureTimings = Boolean(slides?.captureTimings && slides?.doc);
2710
2748
  const [slideIndex, setSlideIndex] = useState3(0);
2749
+ const [buildLog, setBuildLog] = useState3([]);
2750
+ const buildLogRef = useRef2(buildLog);
2751
+ buildLogRef.current = buildLog;
2752
+ const handleBuildShown = useCallback4(
2753
+ (blockId, step, sourceText2) => {
2754
+ const elapsed = recorder.getElapsedMs();
2755
+ if (elapsed !== null)
2756
+ setBuildLog(
2757
+ (log) => recordBuildAdvance(log, { blockId, step, sourceText: sourceText2, time: elapsed / 1e3 })
2758
+ );
2759
+ },
2760
+ [recorder]
2761
+ );
2711
2762
  const [advanceLog, setAdvanceLog] = useState3(EMPTY_ADVANCE_LOG);
2712
2763
  const [applySlideTimings, setApplySlideTimings] = useState3(true);
2713
2764
  const slideIndexRef = useRef2(slideIndex);
@@ -2732,11 +2783,12 @@ function RecorderModal({
2732
2783
  [recorder]
2733
2784
  );
2734
2785
  const slideDeckKey = slideDeck.map((slide) => slide.blockId).join("\0");
2735
- useEffect4(() => {
2786
+ useEffect5(() => {
2736
2787
  setAdvanceLog(EMPTY_ADVANCE_LOG);
2788
+ setBuildLog([]);
2737
2789
  setSlideIndex(0);
2738
2790
  }, [slidesOn, slideDeckKey]);
2739
- useEffect4(() => {
2791
+ useEffect5(() => {
2740
2792
  if (!narrationOn || narrationRecording) return;
2741
2793
  const controller = stageRef.current.controller;
2742
2794
  if (recorder.state === "recording") controller.play();
@@ -2754,7 +2806,7 @@ function RecorderModal({
2754
2806
  [narrationRecording]
2755
2807
  );
2756
2808
  const narrationMicDeviceId = stage.controller.prefs.micDeviceId ?? "";
2757
- useEffect4(() => {
2809
+ useEffect5(() => {
2758
2810
  if (!narrationRecording) return;
2759
2811
  setDeviceSettings(
2760
2812
  (current) => current.audio.deviceId === narrationMicDeviceId ? current : {
@@ -2764,7 +2816,7 @@ function RecorderModal({
2764
2816
  );
2765
2817
  }, [narrationMicDeviceId, narrationRecording]);
2766
2818
  const prevNarrationOnRef = useRef2(narrationOn);
2767
- useEffect4(() => {
2819
+ useEffect5(() => {
2768
2820
  const was = prevNarrationOnRef.current;
2769
2821
  prevNarrationOnRef.current = narrationOn;
2770
2822
  if (was === narrationOn) return;
@@ -2779,7 +2831,7 @@ function RecorderModal({
2779
2831
  if (s.float.isOpen) s.float.close();
2780
2832
  }
2781
2833
  }, [narrationOn, narrationRecording, recorder]);
2782
- useEffect4(() => {
2834
+ useEffect5(() => {
2783
2835
  if (!narrationOn) return;
2784
2836
  const onKey = (event) => {
2785
2837
  if (event.key !== "Escape") return;
@@ -2792,7 +2844,7 @@ function RecorderModal({
2792
2844
  const narrationMicLive = stage.controller.mic.status === "live";
2793
2845
  const narrationPreviewWanted = narrationRecording && stage.recorder.withCamera && narrationMicLive && stage.recorder.cameraStream === null && stage.recorder.state !== "processing" && stage.recorder.state !== "review" && stage.recorder.state !== "saving";
2794
2846
  const narrationPreviewRef = useRef2(null);
2795
- useEffect4(() => {
2847
+ useEffect5(() => {
2796
2848
  const existing = narrationPreviewRef.current;
2797
2849
  if (existing) {
2798
2850
  for (const track of existing.getTracks()) track.stop();
@@ -2843,7 +2895,7 @@ function RecorderModal({
2843
2895
  const activePrimaryStream = narrationRecording ? stage.controller.mic.stream : recorder.stream;
2844
2896
  const activeCameraStream = narrationRecording ? narrationCameraStream : recorder.camera?.stream ?? null;
2845
2897
  const { devices: mediaDevices, refresh: refreshMediaDevices } = useMediaDevices();
2846
- useEffect4(() => {
2898
+ useEffect5(() => {
2847
2899
  if (activePrimaryStream || activeCameraStream) refreshMediaDevices();
2848
2900
  }, [activeCameraStream, activePrimaryStream, refreshMediaDevices]);
2849
2901
  useStreamPreview(
@@ -2854,7 +2906,7 @@ function RecorderModal({
2854
2906
  cameraPreviewRef,
2855
2907
  !narrationRecording && isDual && recorder.state !== "stopped" ? recorder.camera?.stream ?? null : null
2856
2908
  );
2857
- useEffect4(() => {
2909
+ useEffect5(() => {
2858
2910
  setPlaybackPositionMs(0);
2859
2911
  if (!recorder.blob) {
2860
2912
  setPlaybackUrl(null);
@@ -2867,7 +2919,7 @@ function RecorderModal({
2867
2919
  };
2868
2920
  }, [recorder.blob]);
2869
2921
  const cameraBlob = recorder.camera?.blob ?? null;
2870
- useEffect4(() => {
2922
+ useEffect5(() => {
2871
2923
  if (!cameraBlob) {
2872
2924
  setCameraPlaybackUrl(null);
2873
2925
  return;
@@ -2881,7 +2933,7 @@ function RecorderModal({
2881
2933
  const captureKey = `${source}:${cameraOn ? micOn : ""}:${includeSystemAudio}:${JSON.stringify(deviceSettings)}`;
2882
2934
  const previousKeyRef = useRef2(captureKey);
2883
2935
  const dualSaveProgressRef = useRef2({});
2884
- useEffect4(() => {
2936
+ useEffect5(() => {
2885
2937
  if (previousKeyRef.current !== captureKey) {
2886
2938
  previousKeyRef.current = captureKey;
2887
2939
  dualSaveProgressRef.current = {};
@@ -2937,6 +2989,7 @@ function RecorderModal({
2937
2989
  setCountingIn(false);
2938
2990
  if (!rolled) return;
2939
2991
  }
2992
+ setBuildLog([]);
2940
2993
  recorder.start();
2941
2994
  const blockId = slideDeckRef.current[slideIndexRef.current]?.blockId;
2942
2995
  setAdvanceLog(blockId ? recordSlideShown(EMPTY_ADVANCE_LOG, blockId, 0) : EMPTY_ADVANCE_LOG);
@@ -2955,7 +3008,10 @@ function RecorderModal({
2955
3008
  if (!slidesOn || !slidesCaptureTimings || !applySlideTimings || !doc) return null;
2956
3009
  const log = advanceLogRef.current;
2957
3010
  if (log.length === 0) return null;
2958
- const timing = buildAdvanceTimingJson(doc, log, durationSec);
3011
+ const timing = {
3012
+ ...buildAdvanceTimingJson(doc, log, durationSec),
3013
+ builds: buildLogRef.current
3014
+ };
2959
3015
  const encoded = encodeNarrationTimingJson(timing);
2960
3016
  const sidecarPath = timingPathFor(mediaRelativePath);
2961
3017
  if (container) {
@@ -3167,13 +3223,16 @@ function RecorderModal({
3167
3223
  [source, recorder.extension, recorder.blob, isDual, basename, filenameSeed]
3168
3224
  );
3169
3225
  const timingDownloadFilename = `${downloadFilename}.timing.json`;
3170
- useEffect4(() => {
3226
+ useEffect5(() => {
3171
3227
  if (narrationRecording || !canSave) {
3172
3228
  setTimingDownloadUrl(null);
3173
3229
  return;
3174
3230
  }
3175
3231
  const duration = recorder.durationMs / 1e3;
3176
- const encoded = slidesOn && slidesCaptureTimings && applySlideTimings && slides?.doc && advanceLog.length > 0 ? encodeNarrationTimingJson(buildAdvanceTimingJson(slides.doc, advanceLog, duration)) : source === "mic" ? encodeTimingJson(buildTimingJson(sourceText, duration)) : null;
3232
+ const encoded = slidesOn && slidesCaptureTimings && applySlideTimings && slides?.doc && advanceLog.length > 0 ? encodeNarrationTimingJson({
3233
+ ...buildAdvanceTimingJson(slides.doc, advanceLog, duration),
3234
+ builds: buildLog
3235
+ }) : source === "mic" ? encodeTimingJson(buildTimingJson(sourceText, duration)) : null;
3177
3236
  if (encoded === null) {
3178
3237
  setTimingDownloadUrl(null);
3179
3238
  return;
@@ -3187,6 +3246,7 @@ function RecorderModal({
3187
3246
  narrationRecording,
3188
3247
  canSave,
3189
3248
  recorder.durationMs,
3249
+ buildLog,
3190
3250
  slidesOn,
3191
3251
  slidesCaptureTimings,
3192
3252
  applySlideTimings,
@@ -3322,33 +3382,35 @@ function RecorderModal({
3322
3382
  }) })
3323
3383
  ] }, group.label)) }),
3324
3384
  /* @__PURE__ */ jsx6("p", { style: summaryStyle, children: narrationRecording ? narrationCaptureSummary(stage.recorder.withCamera) : captureSummary(micOn, cameraOn, screenOn, includeSystemAudio) }),
3325
- narrationAvailable && /* @__PURE__ */ jsxs5("label", { style: checkboxRowStyle, children: [
3326
- /* @__PURE__ */ jsx6(
3327
- "input",
3328
- {
3329
- type: "checkbox",
3330
- style: { accentColor: "var(--squisq-recorder-accent)" },
3331
- checked: narrationOn,
3332
- onChange: (e) => setPanelMode(panelModeAfterToggle(panelMode, "narration", e.target.checked)),
3333
- disabled: narrationToggleDisabled,
3334
- title: narrationToggleDisabled ? narrationRecording ? "Finish or discard the narration take first" : "Save or discard this recording before switching modes" : void 0
3335
- }
3336
- ),
3337
- "Show narration mode"
3338
- ] }),
3339
- slidesAvailable && /* @__PURE__ */ jsxs5("label", { style: checkboxRowStyle, children: [
3340
- /* @__PURE__ */ jsx6(
3341
- "input",
3342
- {
3343
- type: "checkbox",
3344
- style: { accentColor: "var(--squisq-recorder-accent)" },
3345
- checked: slidesOn,
3346
- onChange: (e) => setPanelMode(panelModeAfterToggle(panelMode, "slides", e.target.checked)),
3347
- disabled: narrationToggleDisabled,
3348
- title: narrationToggleDisabled ? "Save or discard this recording before switching modes" : void 0
3349
- }
3350
- ),
3351
- "Show slides mode"
3385
+ /* @__PURE__ */ jsxs5("div", { style: modeTogglesStyle, children: [
3386
+ narrationAvailable && /* @__PURE__ */ jsxs5("label", { style: checkboxRowStyle, children: [
3387
+ /* @__PURE__ */ jsx6(
3388
+ "input",
3389
+ {
3390
+ type: "checkbox",
3391
+ style: { accentColor: "var(--squisq-recorder-accent)" },
3392
+ checked: narrationOn,
3393
+ onChange: (e) => setPanelMode(panelModeAfterToggle(panelMode, "narration", e.target.checked)),
3394
+ disabled: narrationToggleDisabled,
3395
+ title: narrationToggleDisabled ? narrationRecording ? "Finish or discard the narration take first" : "Save or discard this recording before switching modes" : void 0
3396
+ }
3397
+ ),
3398
+ "Show narration mode"
3399
+ ] }),
3400
+ slidesAvailable && /* @__PURE__ */ jsxs5("label", { style: checkboxRowStyle, children: [
3401
+ /* @__PURE__ */ jsx6(
3402
+ "input",
3403
+ {
3404
+ type: "checkbox",
3405
+ style: { accentColor: "var(--squisq-recorder-accent)" },
3406
+ checked: slidesOn,
3407
+ onChange: (e) => setPanelMode(panelModeAfterToggle(panelMode, "slides", e.target.checked)),
3408
+ disabled: narrationToggleDisabled,
3409
+ title: narrationToggleDisabled ? "Save or discard this recording before switching modes" : void 0
3410
+ }
3411
+ ),
3412
+ "Show slides mode"
3413
+ ] })
3352
3414
  ] }),
3353
3415
  /* @__PURE__ */ jsx6(
3354
3416
  RecorderDeviceQuickPicks,
@@ -3764,6 +3826,7 @@ function RecorderModal({
3764
3826
  slides: slideDeck,
3765
3827
  index: slideIndex,
3766
3828
  onIndexChange: handleSlideIndexChange,
3829
+ onBuildShown: handleBuildShown,
3767
3830
  viewport: slidesViewport,
3768
3831
  basePath: slides?.basePath,
3769
3832
  mediaProvider: slides?.mediaProvider ?? mediaProvider,
@@ -0,0 +1,235 @@
1
+ // src/chromeIcons.ts
2
+ import {
3
+ AppWindow,
4
+ ArrowDown,
5
+ ArrowLeftRight,
6
+ ArrowUp,
7
+ Ban,
8
+ Bold,
9
+ Captions,
10
+ ChartColumn,
11
+ Check,
12
+ ChevronDown,
13
+ ChevronLeft,
14
+ ChevronRight,
15
+ ChevronsRight,
16
+ ChevronUp,
17
+ CirclePlay,
18
+ Clock,
19
+ Code,
20
+ Copy,
21
+ CopyPlus,
22
+ Crop,
23
+ Ellipsis,
24
+ ExternalLink,
25
+ Eye,
26
+ EyeOff,
27
+ FaceSlightlySmiling,
28
+ File,
29
+ FileCode,
30
+ FileCog,
31
+ FileImage,
32
+ FileText,
33
+ FileUp,
34
+ Film,
35
+ Folder,
36
+ FolderOpen,
37
+ FolderPlus,
38
+ FolderTree,
39
+ GitBranch,
40
+ GitCommitHorizontal,
41
+ GripHorizontal,
42
+ GripVertical,
43
+ Image,
44
+ Images,
45
+ Italic,
46
+ LayoutDashboard,
47
+ LayoutPanelLeft,
48
+ LayoutTemplate,
49
+ Link,
50
+ List,
51
+ ListChecks,
52
+ ListIndentDecrease,
53
+ ListIndentIncrease,
54
+ ListOrdered,
55
+ Lock,
56
+ LockOpen,
57
+ Maximize2,
58
+ MessageSquareMore,
59
+ Mic,
60
+ MicVocal,
61
+ Minimize2,
62
+ Minus,
63
+ Monitor,
64
+ MousePointer2,
65
+ Move,
66
+ MoveRight,
67
+ PaintBucket,
68
+ Paperclip,
69
+ Pencil,
70
+ PenTool,
71
+ Plus,
72
+ Printer,
73
+ Quote,
74
+ RotateCcwClock,
75
+ Search,
76
+ Settings2,
77
+ Shapes,
78
+ Share2,
79
+ SlidersHorizontal,
80
+ Square,
81
+ Strikethrough,
82
+ Subscript,
83
+ Superscript,
84
+ Table,
85
+ TextAlignCenter,
86
+ TextAlignEnd,
87
+ TextAlignStart,
88
+ Trash,
89
+ TriangleAlert,
90
+ Type,
91
+ Unlink,
92
+ Volume2,
93
+ WandSparkles,
94
+ Workflow,
95
+ X
96
+ } from "lucide-react";
97
+ var CHROME_ICONS = {
98
+ // Text formatting
99
+ bold: Bold,
100
+ italic: Italic,
101
+ strikethrough: Strikethrough,
102
+ superscript: Superscript,
103
+ subscript: Subscript,
104
+ font: Type,
105
+ code: Code,
106
+ "quote-left": Quote,
107
+ "list-ul": List,
108
+ "list-ol": ListOrdered,
109
+ "list-check": ListChecks,
110
+ indent: ListIndentIncrease,
111
+ outdent: ListIndentDecrease,
112
+ "align-left": TextAlignStart,
113
+ "align-center": TextAlignCenter,
114
+ "align-right": TextAlignEnd,
115
+ minus: Minus,
116
+ // Insert
117
+ plus: Plus,
118
+ link: Link,
119
+ "link-slash": Unlink,
120
+ table: Table,
121
+ image: Image,
122
+ images: Images,
123
+ "photo-film": Images,
124
+ "file-image": FileImage,
125
+ "file-arrow-up": FileUp,
126
+ "file-code": FileCode,
127
+ "chart-column": ChartColumn,
128
+ "diagram-project": Workflow,
129
+ "code-branch": GitBranch,
130
+ "folder-tree": FolderTree,
131
+ timeline: GitCommitHorizontal,
132
+ "pen-nib": PenTool,
133
+ "object-group": LayoutPanelLeft,
134
+ "circle-play": CirclePlay,
135
+ "face-smile": FaceSlightlySmiling,
136
+ microphone: Mic,
137
+ "microphone-lines": MicVocal,
138
+ "comment-dots": MessageSquareMore,
139
+ "volume-high": Volume2,
140
+ film: Film,
141
+ // Documents and files
142
+ file: File,
143
+ "file-lines": FileText,
144
+ folder: Folder,
145
+ "folder-open": FolderOpen,
146
+ "folder-plus": FolderPlus,
147
+ paperclip: Paperclip,
148
+ print: Printer,
149
+ "share-nodes": Share2,
150
+ "up-right-from-square": ExternalLink,
151
+ // Views and modes
152
+ eye: Eye,
153
+ "eye-slash": EyeOff,
154
+ display: Monitor,
155
+ "window-maximize": AppWindow,
156
+ "table-cells-large": LayoutDashboard,
157
+ expand: Maximize2,
158
+ compress: Minimize2,
159
+ "closed-captioning": Captions,
160
+ "clock-rotate-left": RotateCcwClock,
161
+ clock: Clock,
162
+ // Editing actions
163
+ pen: Pencil,
164
+ copy: Copy,
165
+ clone: CopyPlus,
166
+ trash: Trash,
167
+ check: Check,
168
+ xmark: X,
169
+ ban: Ban,
170
+ lock: Lock,
171
+ "lock-open": LockOpen,
172
+ "crop-simple": Crop,
173
+ "fill-drip": PaintBucket,
174
+ "border-top-left": Square,
175
+ square: Square,
176
+ shapes: Shapes,
177
+ sliders: SlidersHorizontal,
178
+ "wand-magic-sparkles": WandSparkles,
179
+ "magnifying-glass": Search,
180
+ "right-left": ArrowLeftRight,
181
+ "triangle-exclamation": TriangleAlert,
182
+ // Navigation and handles
183
+ "chevron-up": ChevronUp,
184
+ "chevron-down": ChevronDown,
185
+ "chevron-left": ChevronLeft,
186
+ "chevron-right": ChevronRight,
187
+ "angles-right": ChevronsRight,
188
+ "arrow-up": ArrowUp,
189
+ "arrow-down": ArrowDown,
190
+ "arrow-right-long": MoveRight,
191
+ "arrow-pointer": MousePointer2,
192
+ "arrows-up-down-left-right": Move,
193
+ "grip-vertical": GripVertical,
194
+ "grip-lines": GripHorizontal,
195
+ ellipsis: Ellipsis,
196
+ // Lucide-only glyphs, named directly by a call site
197
+ "layout-template": LayoutTemplate,
198
+ "file-cog": FileCog,
199
+ "settings-2": Settings2
200
+ };
201
+ var FA_MODIFIERS = /* @__PURE__ */ new Set(["fa-solid", "fa-regular", "fa-light", "fa-thin", "fa-fw", "fa-lg"]);
202
+ function chromeIconFor(icon) {
203
+ const tokens = icon.split(/\s+/u).filter(Boolean);
204
+ if (tokens.includes("fa-brands")) return void 0;
205
+ for (const token of tokens) {
206
+ if (FA_MODIFIERS.has(token)) continue;
207
+ const glyph = CHROME_ICONS[token.startsWith("fa-") ? token.slice(3) : token];
208
+ if (glyph) return glyph;
209
+ }
210
+ return void 0;
211
+ }
212
+
213
+ // src/Icon.tsx
214
+ import { jsx } from "react/jsx-runtime";
215
+ var STROKE_WIDTH = 1.75;
216
+ function Icon({ icon, className, style }) {
217
+ const Glyph = chromeIconFor(icon);
218
+ if (Glyph) {
219
+ return /* @__PURE__ */ jsx(
220
+ Glyph,
221
+ {
222
+ className: className ? `squisq-icon ${className}` : "squisq-icon",
223
+ style,
224
+ strokeWidth: STROKE_WIDTH,
225
+ "aria-hidden": "true",
226
+ focusable: "false"
227
+ }
228
+ );
229
+ }
230
+ return /* @__PURE__ */ jsx("i", { className: className ? `${icon} ${className}` : icon, style, "aria-hidden": "true" });
231
+ }
232
+
233
+ export {
234
+ Icon
235
+ };