@bendyline/squisq-editor-react 1.5.3 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/dist/index.d.ts +757 -20
  2. package/dist/index.js +16875 -6883
  3. package/dist/index.js.map +1 -1
  4. package/package.json +4 -4
  5. package/src/BlockCardView.tsx +121 -0
  6. package/src/BlockPreviewPanel.tsx +69 -0
  7. package/src/BlockPropertiesPopover.tsx +191 -0
  8. package/src/EditorContext.tsx +143 -0
  9. package/src/EditorShell.tsx +200 -120
  10. package/src/FolderView.tsx +131 -0
  11. package/src/Icon.tsx +26 -0
  12. package/src/ImageEditor.tsx +69 -22
  13. package/src/OutlinePanel.tsx +38 -3
  14. package/src/PlainHtmlPreview.tsx +30 -3
  15. package/src/PreviewControls.tsx +180 -8
  16. package/src/RawEditor.tsx +169 -13
  17. package/src/RecorderEntry.tsx +9 -16
  18. package/src/TemplateAnnotation.ts +44 -0
  19. package/src/TemplatePicker.tsx +329 -54
  20. package/src/ThemeCustomizerPanel.tsx +30 -336
  21. package/src/ThemePicker.tsx +112 -3
  22. package/src/TimelineBlockPreview.tsx +37 -0
  23. package/src/TimelineTrack.tsx +671 -0
  24. package/src/Toolbar.tsx +528 -174
  25. package/src/Tooltip.tsx +22 -4
  26. package/src/TransitionPicker.tsx +351 -0
  27. package/src/VersionHistoryPanel.tsx +2 -14
  28. package/src/ViewMenuPanel.tsx +17 -14
  29. package/src/WysiwygEditor.tsx +161 -65
  30. package/src/__tests__/blockProperties.test.ts +92 -0
  31. package/src/__tests__/blockRange.test.ts +105 -0
  32. package/src/__tests__/buildPreviewDocTransition.test.ts +73 -0
  33. package/src/__tests__/createShapeLayer.test.ts +46 -0
  34. package/src/__tests__/drawingShapeRoundTrip.test.ts +49 -0
  35. package/src/__tests__/embeddedMedia.test.ts +48 -0
  36. package/src/__tests__/headingTransition.test.ts +138 -0
  37. package/src/__tests__/layoutChildRoundTrip.test.ts +71 -0
  38. package/src/__tests__/plainHtmlPreview.test.tsx +10 -8
  39. package/src/__tests__/recorderMediaInsert.test.ts +86 -0
  40. package/src/__tests__/templateAnnotationRoundTrip.test.ts +18 -0
  41. package/src/__tests__/templatePickerMetadata.test.ts +32 -0
  42. package/src/__tests__/timelineSource.test.ts +134 -0
  43. package/src/__tests__/tiptapBridge.test.ts +92 -0
  44. package/src/__tests__/tiptapBridgeConformance.test.ts +47 -0
  45. package/src/__tests__/tooltip.test.tsx +72 -0
  46. package/src/__tests__/transitionCatalog.test.ts +64 -0
  47. package/src/__tests__/useBlockNavigator.test.tsx +67 -0
  48. package/src/__tests__/useMediaRecorder.test.ts +24 -0
  49. package/src/__tests__/useTimelineClock.test.ts +21 -0
  50. package/src/blockProperties.ts +88 -0
  51. package/src/blockRange.ts +132 -0
  52. package/src/buildPreviewDoc.ts +98 -9
  53. package/src/customTemplates/AddBin.tsx +126 -0
  54. package/src/customTemplates/CustomLayoutManager.tsx +233 -0
  55. package/src/customTemplates/CustomTemplateContext.tsx +182 -0
  56. package/src/customTemplates/LayerToolbar.tsx +580 -0
  57. package/src/customTemplates/ShapeGlyph.tsx +47 -0
  58. package/src/customTemplates/TemplateDesigner.tsx +430 -0
  59. package/src/customTemplates/__tests__/library.test.ts +88 -0
  60. package/src/customTemplates/__tests__/normalizePositions.test.ts +109 -0
  61. package/src/customTemplates/__tests__/shapeDefs.test.ts +49 -0
  62. package/src/customTemplates/__tests__/useMemoryLayerAdapter.test.ts +95 -0
  63. package/src/customTemplates/designer.css +673 -0
  64. package/src/customTemplates/index.ts +31 -0
  65. package/src/customTemplates/library.ts +97 -0
  66. package/src/customTemplates/normalizePositions.ts +75 -0
  67. package/src/customTemplates/shapeDefs.ts +131 -0
  68. package/src/customTemplates/thumbnail.tsx +63 -0
  69. package/src/customTemplates/tokenDefs.ts +60 -0
  70. package/src/customTemplates/useDocCustomTemplates.ts +52 -0
  71. package/src/customTemplates/useMemoryLayerAdapter.ts +123 -0
  72. package/src/customThemes/CustomThemeContext.tsx +179 -0
  73. package/src/customThemes/CustomThemeDialog.tsx +286 -0
  74. package/src/customThemes/__tests__/CustomThemeContext.test.tsx +64 -0
  75. package/src/customThemes/__tests__/CustomThemeDialog.test.tsx +47 -0
  76. package/src/customThemes/__tests__/customThemeLibrary.test.ts +51 -0
  77. package/src/customThemes/customThemeLibrary.ts +97 -0
  78. package/src/customThemes/index.ts +31 -0
  79. package/src/customThemes/themeControls.tsx +229 -0
  80. package/src/customThemes/themeDraft.ts +272 -0
  81. package/src/customThemes/useDocCustomThemes.ts +49 -0
  82. package/src/diagram/DiagramCanvas.tsx +240 -0
  83. package/src/diagram/DiagramExtension.ts +209 -0
  84. package/src/diagram/DiagramMaximizedOverlay.tsx +46 -0
  85. package/src/diagram/DiagramWidget.tsx +270 -0
  86. package/src/diagram/diagramCommands.ts +604 -0
  87. package/src/diagram/diagramConstants.ts +17 -0
  88. package/src/diagram/useDiagramData.ts +126 -0
  89. package/src/embeddedMedia.ts +78 -0
  90. package/src/frontmatter.ts +29 -0
  91. package/src/headingTransition.ts +231 -0
  92. package/src/imageEditor/CanvasSurface.tsx +383 -88
  93. package/src/imageEditor/PropertiesPanel.tsx +47 -1
  94. package/src/imageEditor/Toolbar.tsx +229 -16
  95. package/src/imageEditor/createShapeLayer.ts +280 -0
  96. package/src/imageEditor/icons.tsx +34 -114
  97. package/src/imageEditor/image-editor.css +54 -5
  98. package/src/imageEditor/state.ts +23 -3
  99. package/src/index.ts +77 -0
  100. package/src/recorder/RecorderModal.tsx +120 -53
  101. package/src/recorder/RecorderPanel.tsx +2 -26
  102. package/src/recorder/hooks/useMediaRecorder.ts +8 -1
  103. package/src/recorder/insertMediaBlock.ts +30 -0
  104. package/src/resolveBlockVisual.ts +33 -0
  105. package/src/scene/Scene.tsx +540 -0
  106. package/src/scene/SceneBlockExtension.ts +198 -0
  107. package/src/scene/SceneBlockToolbar.tsx +201 -0
  108. package/src/scene/SceneBlockWidget.tsx +434 -0
  109. package/src/scene/ScenePropsBar.tsx +85 -0
  110. package/src/scene/SceneSelection.tsx +107 -0
  111. package/src/scene/SceneViewport.tsx +102 -0
  112. package/src/scene/ShapePalette.tsx +181 -0
  113. package/src/scene/__tests__/DiagramAdapter.test.ts +56 -0
  114. package/src/scene/__tests__/bezierEdit.test.ts +85 -0
  115. package/src/scene/__tests__/blockLayers.test.ts +57 -0
  116. package/src/scene/__tests__/shapeLayers.test.ts +106 -0
  117. package/src/scene/__tests__/useSceneHitTest.test.ts +90 -0
  118. package/src/scene/__tests__/useScenePanZoom.test.ts +103 -0
  119. package/src/scene/adapters/DiagramAdapter.ts +168 -0
  120. package/src/scene/adapters/DrawingAdapter.ts +415 -0
  121. package/src/scene/adapters/LayoutAdapter.ts +310 -0
  122. package/src/scene/adapters/blockLayers.ts +159 -0
  123. package/src/scene/commands/SceneCommand.ts +70 -0
  124. package/src/scene/commands/drawingCommands.ts +318 -0
  125. package/src/scene/commands/layoutCommands.ts +301 -0
  126. package/src/scene/hooks/useSceneHitTest.ts +105 -0
  127. package/src/scene/hooks/useScenePanZoom.ts +147 -0
  128. package/src/scene/hooks/useSceneSelection.ts +62 -0
  129. package/src/scene/index.ts +95 -0
  130. package/src/scene/layers/DiagramEdges.tsx +127 -0
  131. package/src/scene/layers/edgeGeometry.ts +77 -0
  132. package/src/scene/layers/nodeCard.tsx +145 -0
  133. package/src/scene/layers/renderLayer.tsx +70 -0
  134. package/src/scene/layers/shapeLayers.ts +201 -0
  135. package/src/scene/paths/bezierEdit.ts +208 -0
  136. package/src/scene/scene.css +649 -0
  137. package/src/scene/text/SceneTextOverlay.tsx +161 -0
  138. package/src/scene/text/sceneTextChannel.ts +40 -0
  139. package/src/scene/text/sceneTextConfig.ts +27 -0
  140. package/src/scene/text/sceneTiptap.ts +36 -0
  141. package/src/scene/text/useSceneTextEditing.ts +39 -0
  142. package/src/scene/tools/ConnectTool.ts +111 -0
  143. package/src/scene/tools/DrawingConnectTool.ts +161 -0
  144. package/src/scene/tools/PathTool.ts +158 -0
  145. package/src/scene/tools/PlaceTool.ts +47 -0
  146. package/src/scene/tools/SceneTool.ts +75 -0
  147. package/src/scene/tools/SelectTool.ts +284 -0
  148. package/src/scene/tools/ShapeTool.ts +144 -0
  149. package/src/scene/tools/TextTool.ts +72 -0
  150. package/src/scene/tools/TokenTool.ts +95 -0
  151. package/src/scene/tools/createDrawShapeTool.ts +82 -0
  152. package/src/styles/diagram.css +183 -0
  153. package/src/styles/editor.css +1615 -203
  154. package/src/styles/folder-view.css +210 -0
  155. package/src/styles/image-edit-affordance.css +2 -2
  156. package/src/styles/index.css +4 -0
  157. package/src/timelineSource.ts +244 -0
  158. package/src/tiptapBridge.ts +115 -34
  159. package/src/tooltipPlacement.ts +13 -0
  160. package/src/transitionCatalog.ts +159 -0
  161. package/src/types/monaco-shims.d.ts +10 -0
  162. package/src/useBlockNavigator.ts +153 -0
  163. package/src/useMonacoLoader.ts +23 -1
  164. package/src/useTimelineClock.ts +76 -0
  165. package/src/utils/dropUtils.ts +1 -1
@@ -0,0 +1,673 @@
1
+ /*
2
+ * TemplateDesigner — full-viewport modal overlay with a Scene-backed
3
+ * canvas in the middle, a token palette on the left, name/label inputs
4
+ * at the top, and save/cancel actions at the bottom.
5
+ */
6
+
7
+ .squisq-template-designer-overlay {
8
+ position: fixed;
9
+ inset: 0;
10
+ z-index: 9999;
11
+ background: rgba(15, 23, 42, 0.55);
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: center;
15
+ padding: 24px;
16
+ }
17
+
18
+ .squisq-template-designer-panel {
19
+ display: flex;
20
+ flex-direction: column;
21
+ width: min(1200px, 100%);
22
+ height: min(800px, 100%);
23
+ background: #ffffff;
24
+ border-radius: 12px;
25
+ box-shadow: 0 24px 60px rgba(0, 0, 0, 0.3);
26
+ overflow: hidden;
27
+ /* The designer is a direct-manipulation surface: dragging a layer on
28
+ the canvas must not start a text selection that bleeds into the
29
+ toolbar/labels (which the browser then paints as a translucent drag
30
+ "ghost" of the selected text). Suppress selection on the chrome;
31
+ re-enable it on the editable fields below. */
32
+ user-select: none;
33
+ -webkit-user-select: none;
34
+ }
35
+
36
+ .squisq-template-designer-panel input,
37
+ .squisq-template-designer-panel textarea {
38
+ user-select: text;
39
+ -webkit-user-select: text;
40
+ }
41
+
42
+ /* Embedded variant — the designer rendered inside a host frame (the
43
+ Custom Layout Manager's right pane) rather than as its own modal.
44
+ Fills the container and drops the standalone modal's chrome. */
45
+ .squisq-template-designer-panel--embedded {
46
+ width: 100%;
47
+ height: 100%;
48
+ border-radius: 0;
49
+ box-shadow: none;
50
+ }
51
+
52
+ .squisq-template-designer-header {
53
+ display: flex;
54
+ align-items: center;
55
+ justify-content: space-between;
56
+ padding: 14px 20px;
57
+ border-bottom: 1px solid #e5e7eb;
58
+ background: #f9fafb;
59
+ }
60
+
61
+ .squisq-template-designer-title {
62
+ margin: 0;
63
+ font-size: 16px;
64
+ font-weight: 600;
65
+ color: #111827;
66
+ }
67
+
68
+ .squisq-template-designer-close {
69
+ width: 32px;
70
+ height: 32px;
71
+ display: inline-flex;
72
+ align-items: center;
73
+ justify-content: center;
74
+ font-size: 24px;
75
+ line-height: 1;
76
+ color: #6b7280;
77
+ background: transparent;
78
+ border: 1px solid transparent;
79
+ border-radius: 6px;
80
+ cursor: pointer;
81
+ }
82
+
83
+ .squisq-template-designer-close:hover {
84
+ color: #111827;
85
+ background: #f1f5f9;
86
+ border-color: #cbd5e1;
87
+ }
88
+
89
+ .squisq-template-designer-meta {
90
+ display: grid;
91
+ grid-template-columns: minmax(160px, 1fr) minmax(160px, 1fr) minmax(240px, 2fr);
92
+ gap: 12px;
93
+ padding: 12px 20px;
94
+ border-bottom: 1px solid #e5e7eb;
95
+ background: #fdfdfd;
96
+ }
97
+
98
+ .squisq-template-designer-field {
99
+ display: flex;
100
+ flex-direction: column;
101
+ gap: 4px;
102
+ }
103
+
104
+ .squisq-template-designer-field span {
105
+ font-size: 11px;
106
+ font-weight: 600;
107
+ text-transform: uppercase;
108
+ letter-spacing: 0.04em;
109
+ color: #6b7280;
110
+ }
111
+
112
+ .squisq-template-designer-field input {
113
+ padding: 6px 10px;
114
+ font-size: 13px;
115
+ color: #111827;
116
+ background: #ffffff;
117
+ border: 1px solid #d1d5db;
118
+ border-radius: 6px;
119
+ outline: none;
120
+ }
121
+
122
+ .squisq-template-designer-field input:focus {
123
+ border-color: #6366f1;
124
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.15);
125
+ }
126
+
127
+ .squisq-template-designer-field span.squisq-template-designer-field-hint {
128
+ font-size: 11px;
129
+ font-weight: 400;
130
+ text-transform: none;
131
+ letter-spacing: normal;
132
+ color: #9ca3af;
133
+ }
134
+
135
+ .squisq-template-designer-body {
136
+ flex: 1;
137
+ display: flex;
138
+ min-height: 0;
139
+ }
140
+
141
+ .squisq-template-designer-palette {
142
+ width: 220px;
143
+ flex-shrink: 0;
144
+ padding: 16px;
145
+ border-right: 1px solid #e5e7eb;
146
+ background: #fafafa;
147
+ overflow-y: auto;
148
+ }
149
+
150
+ .squisq-template-designer-palette-title {
151
+ margin: 0 0 4px;
152
+ font-size: 12px;
153
+ font-weight: 700;
154
+ text-transform: uppercase;
155
+ letter-spacing: 0.06em;
156
+ color: #4338ca;
157
+ }
158
+
159
+ .squisq-template-designer-palette-hint {
160
+ margin: 0 0 12px;
161
+ font-size: 11px;
162
+ color: #6b7280;
163
+ line-height: 1.4;
164
+ }
165
+
166
+ .squisq-template-designer-palette-list {
167
+ display: flex;
168
+ flex-direction: column;
169
+ gap: 6px;
170
+ }
171
+
172
+ /* ─── Add bin: sections ──────────────────────────────────── */
173
+
174
+ .squisq-template-designer-palette-section {
175
+ margin-top: 14px;
176
+ }
177
+
178
+ .squisq-template-designer-palette-section:first-of-type {
179
+ margin-top: 0;
180
+ }
181
+
182
+ .squisq-template-designer-palette-section-title {
183
+ margin-bottom: 6px;
184
+ font-size: 11px;
185
+ font-weight: 700;
186
+ text-transform: uppercase;
187
+ letter-spacing: 0.06em;
188
+ color: #6b7280;
189
+ }
190
+
191
+ /* Shapes are compact icon tiles in a grid. */
192
+ .squisq-template-designer-palette-shapes {
193
+ display: grid;
194
+ grid-template-columns: repeat(4, 1fr);
195
+ gap: 6px;
196
+ }
197
+
198
+ .squisq-template-designer-shape-item {
199
+ display: inline-flex;
200
+ align-items: center;
201
+ justify-content: center;
202
+ aspect-ratio: 1 / 1;
203
+ padding: 4px;
204
+ background: #ffffff;
205
+ border: 1px solid #e5e7eb;
206
+ border-radius: 6px;
207
+ cursor: grab;
208
+ color: #475569;
209
+ transition:
210
+ background 0.1s,
211
+ border-color 0.1s;
212
+ }
213
+
214
+ .squisq-template-designer-shape-item:active {
215
+ cursor: grabbing;
216
+ }
217
+
218
+ .squisq-template-designer-shape-item:hover {
219
+ background: #eef2ff;
220
+ border-color: #c7d2fe;
221
+ }
222
+
223
+ .squisq-template-designer-shape-item--active {
224
+ background: #eef2ff;
225
+ border-color: #6366f1;
226
+ }
227
+
228
+ .squisq-template-designer-palette-media-add {
229
+ width: 100%;
230
+ margin-top: 4px;
231
+ padding: 8px 10px;
232
+ font-size: 12px;
233
+ font-weight: 600;
234
+ color: #4338ca;
235
+ background: #eef2ff;
236
+ border: 1px dashed #c7d2fe;
237
+ border-radius: 6px;
238
+ cursor: pointer;
239
+ }
240
+
241
+ .squisq-template-designer-palette-media-add:hover:not(:disabled) {
242
+ background: #e0e7ff;
243
+ border-color: #a5b4fc;
244
+ }
245
+
246
+ .squisq-template-designer-palette-media-add:disabled {
247
+ color: #9ca3af;
248
+ background: #f3f4f6;
249
+ border-color: #e5e7eb;
250
+ cursor: not-allowed;
251
+ }
252
+
253
+ .squisq-template-designer-palette-item {
254
+ display: flex;
255
+ flex-direction: column;
256
+ align-items: flex-start;
257
+ gap: 2px;
258
+ padding: 8px 10px;
259
+ background: #ffffff;
260
+ border: 1px solid #e5e7eb;
261
+ border-radius: 6px;
262
+ /* Draggable onto the canvas — `grab` hints the drag affordance. */
263
+ cursor: grab;
264
+ text-align: left;
265
+ transition:
266
+ background 0.1s,
267
+ border-color 0.1s;
268
+ }
269
+
270
+ .squisq-template-designer-palette-item:active {
271
+ cursor: grabbing;
272
+ }
273
+
274
+ .squisq-template-designer-palette-item:hover {
275
+ background: #eef2ff;
276
+ border-color: #c7d2fe;
277
+ }
278
+
279
+ .squisq-template-designer-palette-item--active {
280
+ background: #eef2ff;
281
+ border-color: #6366f1;
282
+ }
283
+
284
+ .squisq-template-designer-palette-item-preview {
285
+ font-family: 'JetBrains Mono', 'SF Mono', 'Menlo', monospace;
286
+ font-size: 12px;
287
+ color: #4338ca;
288
+ }
289
+
290
+ .squisq-template-designer-palette-item-label {
291
+ font-size: 11px;
292
+ color: #6b7280;
293
+ }
294
+
295
+ .squisq-template-designer-stage {
296
+ flex: 1;
297
+ display: flex;
298
+ flex-direction: column;
299
+ min-width: 0;
300
+ padding: 12px;
301
+ gap: 8px;
302
+ background: #f3f4f6;
303
+ }
304
+
305
+ /* Unified controls bar above the canvas: the compact aspect-ratio
306
+ dropdown sits inline with the contextual layer styling controls, so
307
+ the two share one row instead of stacking and eating vertical space. */
308
+ .squisq-template-designer-stage-bar {
309
+ display: flex;
310
+ /* Single row for vertical efficiency. If the controls outgrow the
311
+ width (narrow panels, the text layer's full control set), the bar
312
+ scrolls horizontally rather than wrapping to a second line. */
313
+ flex-wrap: nowrap;
314
+ align-items: center;
315
+ gap: 5px;
316
+ padding: 6px 8px;
317
+ background: #ffffff;
318
+ border: 1px solid #e5e7eb;
319
+ border-radius: 6px;
320
+ align-self: stretch;
321
+ overflow-x: auto;
322
+ scrollbar-width: thin;
323
+ }
324
+
325
+ .squisq-template-designer-viewport-label {
326
+ font-size: 11px;
327
+ font-weight: 600;
328
+ text-transform: uppercase;
329
+ letter-spacing: 0.04em;
330
+ color: #6b7280;
331
+ }
332
+
333
+ /* ─── Contextual layer styling controls ─────────────────── */
334
+ /* Transparent group — the surrounding stage-bar provides the box, so the
335
+ layer controls flow inline with the aspect-ratio dropdown on one row.
336
+ `flex-shrink: 0` keeps each control its natural size; the stage-bar
337
+ scrolls instead of squashing them. */
338
+ .squisq-layer-toolbar {
339
+ display: flex;
340
+ flex-wrap: nowrap;
341
+ align-items: center;
342
+ gap: 5px;
343
+ }
344
+
345
+ .squisq-template-designer-stage-bar > *,
346
+ .squisq-layer-toolbar > * {
347
+ flex-shrink: 0;
348
+ }
349
+
350
+ /* The font-family select is the widest control; cap it so it doesn't
351
+ crowd the rest off the row. */
352
+ .squisq-layer-toolbar-select--font {
353
+ max-width: 104px;
354
+ }
355
+
356
+ .squisq-layer-toolbar-seg {
357
+ display: inline-flex;
358
+ gap: 2px;
359
+ }
360
+
361
+ .squisq-layer-toolbar-btn {
362
+ display: inline-flex;
363
+ align-items: center;
364
+ justify-content: center;
365
+ width: 28px;
366
+ height: 28px;
367
+ font-size: 13px;
368
+ color: #374151;
369
+ background: transparent;
370
+ border: 1px solid transparent;
371
+ border-radius: 4px;
372
+ cursor: pointer;
373
+ }
374
+
375
+ .squisq-layer-toolbar-btn:hover {
376
+ background: #f1f5f9;
377
+ }
378
+
379
+ .squisq-layer-toolbar-btn--active {
380
+ background: #eef2ff;
381
+ border-color: #6366f1;
382
+ color: #4338ca;
383
+ }
384
+
385
+ .squisq-layer-toolbar-select {
386
+ height: 28px;
387
+ padding: 0 6px;
388
+ font-size: 12px;
389
+ color: #1f2937;
390
+ background: #ffffff;
391
+ border: 1px solid #d1d5db;
392
+ border-radius: 4px;
393
+ cursor: pointer;
394
+ }
395
+
396
+ .squisq-layer-toolbar-number {
397
+ width: 48px;
398
+ height: 28px;
399
+ padding: 0 4px 0 6px;
400
+ font-size: 12px;
401
+ color: #1f2937;
402
+ background: #ffffff;
403
+ border: 1px solid #d1d5db;
404
+ border-radius: 4px;
405
+ }
406
+
407
+ .squisq-layer-toolbar-opacity {
408
+ display: inline-flex;
409
+ align-items: center;
410
+ }
411
+
412
+ .squisq-layer-toolbar-opacity input[type='range'] {
413
+ width: 64px;
414
+ cursor: pointer;
415
+ }
416
+
417
+ .squisq-layer-toolbar-label {
418
+ display: inline-flex;
419
+ align-items: center;
420
+ color: #6b7280;
421
+ font-size: 13px;
422
+ }
423
+
424
+ .squisq-layer-toolbar-color {
425
+ display: inline-flex;
426
+ align-items: center;
427
+ gap: 2px;
428
+ }
429
+
430
+ .squisq-layer-toolbar-color input[type='color'] {
431
+ width: 28px;
432
+ height: 28px;
433
+ padding: 0;
434
+ border: 1px solid #d1d5db;
435
+ border-radius: 4px;
436
+ background: #ffffff;
437
+ cursor: pointer;
438
+ }
439
+
440
+ .squisq-layer-toolbar-sep {
441
+ width: 1px;
442
+ align-self: stretch;
443
+ margin: 2px 2px;
444
+ background: #e5e7eb;
445
+ }
446
+
447
+ .squisq-template-designer-scene {
448
+ flex: 1;
449
+ min-height: 0;
450
+ background: #ffffff;
451
+ border: 1px solid #e5e7eb;
452
+ border-radius: 8px;
453
+ overflow: hidden;
454
+ }
455
+
456
+ .squisq-template-designer-footer {
457
+ display: flex;
458
+ align-items: center;
459
+ justify-content: space-between;
460
+ padding: 12px 20px;
461
+ border-top: 1px solid #e5e7eb;
462
+ background: #f9fafb;
463
+ gap: 12px;
464
+ }
465
+
466
+ .squisq-template-designer-footer-hint {
467
+ font-size: 11px;
468
+ color: #6b7280;
469
+ flex: 1;
470
+ min-width: 0;
471
+ }
472
+
473
+ .squisq-template-designer-footer-actions {
474
+ display: flex;
475
+ gap: 8px;
476
+ }
477
+
478
+ .squisq-template-designer-btn {
479
+ padding: 6px 14px;
480
+ font-size: 13px;
481
+ font-weight: 500;
482
+ color: #1f2937;
483
+ background: #ffffff;
484
+ border: 1px solid #d1d5db;
485
+ border-radius: 6px;
486
+ cursor: pointer;
487
+ transition: background 0.1s;
488
+ }
489
+
490
+ .squisq-template-designer-btn:hover {
491
+ background: #f1f5f9;
492
+ }
493
+
494
+ .squisq-template-designer-btn--primary {
495
+ color: #ffffff;
496
+ background: #4f46e5;
497
+ border-color: #4338ca;
498
+ }
499
+
500
+ .squisq-template-designer-btn--primary:hover {
501
+ background: #4338ca;
502
+ }
503
+
504
+ /* ─── Custom Layout Manager ────────────────────────────────
505
+ Near-full-window modal: a sidebar list of layouts on the left and an
506
+ embedded TemplateDesigner on the right. */
507
+
508
+ .squisq-layout-manager-overlay {
509
+ position: fixed;
510
+ inset: 0;
511
+ z-index: 9999;
512
+ background: rgba(15, 23, 42, 0.55);
513
+ display: flex;
514
+ align-items: center;
515
+ justify-content: center;
516
+ padding: 16px;
517
+ }
518
+
519
+ .squisq-layout-manager-panel {
520
+ display: flex;
521
+ flex-direction: column;
522
+ width: min(1600px, 96vw);
523
+ height: 92vh;
524
+ background: #ffffff;
525
+ border-radius: 12px;
526
+ box-shadow: 0 24px 60px rgba(0, 0, 0, 0.3);
527
+ overflow: hidden;
528
+ }
529
+
530
+ .squisq-layout-manager-header {
531
+ display: flex;
532
+ align-items: center;
533
+ justify-content: space-between;
534
+ padding: 14px 20px;
535
+ border-bottom: 1px solid #e5e7eb;
536
+ background: #f9fafb;
537
+ }
538
+
539
+ .squisq-layout-manager-title {
540
+ margin: 0;
541
+ font-size: 16px;
542
+ font-weight: 600;
543
+ color: #111827;
544
+ }
545
+
546
+ .squisq-layout-manager-body {
547
+ flex: 1;
548
+ display: flex;
549
+ min-height: 0;
550
+ }
551
+
552
+ .squisq-layout-manager-sidebar {
553
+ width: 280px;
554
+ flex-shrink: 0;
555
+ display: flex;
556
+ flex-direction: column;
557
+ gap: 8px;
558
+ padding: 16px;
559
+ border-right: 1px solid #e5e7eb;
560
+ background: #fafafa;
561
+ overflow-y: auto;
562
+ }
563
+
564
+ .squisq-layout-manager-new {
565
+ padding: 10px 12px;
566
+ font-size: 13px;
567
+ font-weight: 600;
568
+ color: #4338ca;
569
+ background: #eef2ff;
570
+ border: 1px dashed #c7d2fe;
571
+ border-radius: 8px;
572
+ cursor: pointer;
573
+ text-align: center;
574
+ }
575
+
576
+ .squisq-layout-manager-new:hover {
577
+ background: #e0e7ff;
578
+ border-color: #a5b4fc;
579
+ }
580
+
581
+ .squisq-layout-manager-new--active {
582
+ border-style: solid;
583
+ border-color: #6366f1;
584
+ }
585
+
586
+ .squisq-layout-manager-section-title {
587
+ margin-top: 6px;
588
+ font-size: 11px;
589
+ font-weight: 700;
590
+ text-transform: uppercase;
591
+ letter-spacing: 0.06em;
592
+ color: #6b7280;
593
+ }
594
+
595
+ .squisq-layout-manager-list {
596
+ display: flex;
597
+ flex-direction: column;
598
+ gap: 6px;
599
+ }
600
+
601
+ .squisq-layout-manager-item {
602
+ display: flex;
603
+ align-items: center;
604
+ gap: 10px;
605
+ padding: 8px;
606
+ background: #ffffff;
607
+ border: 1px solid #e5e7eb;
608
+ border-radius: 8px;
609
+ cursor: pointer;
610
+ text-align: left;
611
+ transition:
612
+ background 0.1s,
613
+ border-color 0.1s;
614
+ }
615
+
616
+ .squisq-layout-manager-item:hover {
617
+ background: #eef2ff;
618
+ border-color: #c7d2fe;
619
+ }
620
+
621
+ .squisq-layout-manager-item--active {
622
+ background: #eef2ff;
623
+ border-color: #6366f1;
624
+ }
625
+
626
+ .squisq-layout-manager-item-thumb {
627
+ flex-shrink: 0;
628
+ display: inline-flex;
629
+ width: 56px;
630
+ height: 40px;
631
+ border: 1px solid #e5e7eb;
632
+ border-radius: 4px;
633
+ overflow: hidden;
634
+ background: #f8fafc;
635
+ }
636
+
637
+ .squisq-layout-manager-item-text {
638
+ display: flex;
639
+ flex-direction: column;
640
+ gap: 2px;
641
+ min-width: 0;
642
+ }
643
+
644
+ .squisq-layout-manager-item-label {
645
+ font-size: 13px;
646
+ font-weight: 600;
647
+ color: #111827;
648
+ white-space: nowrap;
649
+ overflow: hidden;
650
+ text-overflow: ellipsis;
651
+ }
652
+
653
+ .squisq-layout-manager-item-name {
654
+ font-family: 'JetBrains Mono', 'SF Mono', 'Menlo', monospace;
655
+ font-size: 11px;
656
+ color: #6b7280;
657
+ white-space: nowrap;
658
+ overflow: hidden;
659
+ text-overflow: ellipsis;
660
+ }
661
+
662
+ .squisq-layout-manager-empty-hint {
663
+ margin: 8px 2px;
664
+ font-size: 12px;
665
+ line-height: 1.5;
666
+ color: #6b7280;
667
+ }
668
+
669
+ .squisq-layout-manager-main {
670
+ flex: 1;
671
+ min-width: 0;
672
+ display: flex;
673
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Public exports for the custom-template designer + runtime.
3
+ *
4
+ * The host editor consumes these in three places:
5
+ * - `<CustomTemplateProvider>` wraps the editor so the picker and
6
+ * designer can read/write doc + library template lists.
7
+ * - `<TemplateThumbnail>` renders the small icon shown on each
8
+ * custom template's picker card.
9
+ * - `<TemplateDesigner>` is the modal Scene-backed editor opened by
10
+ * the picker's "+ New custom template" card. (Coming in step 10.)
11
+ */
12
+
13
+ export {
14
+ CustomTemplateProvider,
15
+ useCustomTemplates,
16
+ type CustomTemplateContextValue,
17
+ type CustomTemplateProviderProps,
18
+ } from './CustomTemplateContext';
19
+ export { TemplateThumbnail } from './thumbnail';
20
+ export {
21
+ listLibraryTemplates,
22
+ saveLibraryTemplate,
23
+ deleteLibraryTemplate,
24
+ clearLibrary,
25
+ LIBRARY_STORAGE_KEY,
26
+ } from './library';
27
+ export { TemplateDesigner, type DesignerSaveTarget } from './TemplateDesigner';
28
+ export { CustomLayoutManager, type CustomLayoutManagerProps } from './CustomLayoutManager';
29
+ export { useDocCustomTemplates, type DocCustomTemplates } from './useDocCustomTemplates';
30
+ export { useMemoryLayerAdapter, applyCommand } from './useMemoryLayerAdapter';
31
+ export { normalizePositions } from './normalizePositions';