@the-portland-company/canvas-editor 0.4.0 → 0.4.2
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/CHANGELOG.md +12 -0
- package/dist/canvas.css +12 -4
- package/dist/editor.cjs +53 -24
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.d.cts +4 -1
- package/dist/editor.d.ts +4 -1
- package/dist/editor.js +53 -24
- package/dist/editor.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.2 — tray fits the canvas column
|
|
4
|
+
|
|
5
|
+
- The tile strip shrinks and scrolls horizontally so the Side | Center toggle,
|
|
6
|
+
labels, undo/redo and × never clip outside the canvas column.
|
|
7
|
+
|
|
8
|
+
## 0.4.1 — tray always on screen
|
|
9
|
+
|
|
10
|
+
- The block tray is fixed to the viewport over the canvas column (live-measured
|
|
11
|
+
left/width, 1rem above the bottom) instead of sticking to the canvas scroll
|
|
12
|
+
box, which could sit below the fold inside a host page. `BlockToolbar` takes
|
|
13
|
+
an `anchor` ref to the canvas element.
|
|
14
|
+
|
|
3
15
|
## 0.4.0 — V1-inspired chrome: floating block tray, dashed block outlines, settings on the left
|
|
4
16
|
|
|
5
17
|
Per Spencer's 2026-09-11 direction that V2 (email.politogyvrm.com) take its
|
package/dist/canvas.css
CHANGED
|
@@ -174,19 +174,22 @@
|
|
|
174
174
|
|
|
175
175
|
/* ---- block tray (floating palette) --------------------------------------- */
|
|
176
176
|
|
|
177
|
+
/* Fixed to the viewport, spanning the canvas column (left/width set inline
|
|
178
|
+
from a live measurement) so it is always on screen; once dragged it keeps
|
|
179
|
+
the pointer-derived left/top instead. */
|
|
177
180
|
.ce-tray-dock {
|
|
178
|
-
position:
|
|
181
|
+
position: fixed; bottom: 1rem; z-index: 40;
|
|
179
182
|
display: flex; justify-content: center;
|
|
180
|
-
|
|
183
|
+
padding: 0 0.5rem;
|
|
181
184
|
pointer-events: none;
|
|
182
185
|
}
|
|
183
186
|
|
|
184
|
-
.ce-tray-dock.is-floating {
|
|
187
|
+
.ce-tray-dock.is-floating { bottom: auto; width: auto; padding: 0; }
|
|
185
188
|
|
|
186
189
|
.ce-tray {
|
|
187
190
|
pointer-events: auto;
|
|
188
191
|
display: flex; align-items: center; gap: 1rem;
|
|
189
|
-
width: fit-content; max-width: 100%;
|
|
192
|
+
width: fit-content; max-width: 100%; min-width: 0;
|
|
190
193
|
padding: 9px 10px 4px;
|
|
191
194
|
background: var(--color-surface);
|
|
192
195
|
border: 1px solid var(--color-border);
|
|
@@ -196,12 +199,17 @@
|
|
|
196
199
|
|
|
197
200
|
.dark .ce-tray { box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5), 0 4px 6px -4px rgba(0, 0, 0, 0.5); }
|
|
198
201
|
|
|
202
|
+
/* min-width:0 lets the strip shrink and scroll so the controls after it
|
|
203
|
+
(Side | Center, labels, undo/redo, ×) stay inside the canvas column. */
|
|
199
204
|
.ce-tray-tiles {
|
|
200
205
|
display: flex; align-items: stretch; gap: 0.5rem;
|
|
206
|
+
flex: 0 1 auto; min-width: 0;
|
|
201
207
|
overflow-x: auto; padding-bottom: 0.25rem;
|
|
202
208
|
scrollbar-width: thin;
|
|
203
209
|
}
|
|
204
210
|
|
|
211
|
+
.ce-tray-tiles > .ce-tile { flex: 0 0 auto; }
|
|
212
|
+
|
|
205
213
|
.ce-tile {
|
|
206
214
|
display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.25rem;
|
|
207
215
|
min-width: 2.75rem; height: 2.75rem; padding: 0.5rem;
|
package/dist/editor.cjs
CHANGED
|
@@ -3937,6 +3937,7 @@ function trayItems() {
|
|
|
3937
3937
|
return [...visible].sort((a, b) => rank(a) - rank(b));
|
|
3938
3938
|
}
|
|
3939
3939
|
function BlockToolbar({
|
|
3940
|
+
anchor,
|
|
3940
3941
|
insertMode,
|
|
3941
3942
|
onInsertModeChange,
|
|
3942
3943
|
showLabels,
|
|
@@ -3950,6 +3951,25 @@ function BlockToolbar({
|
|
|
3950
3951
|
const [pos, setPos] = react.useState(null);
|
|
3951
3952
|
const offset = react.useRef(null);
|
|
3952
3953
|
const pillRef = react.useRef(null);
|
|
3954
|
+
const [bounds, setBounds] = react.useState(null);
|
|
3955
|
+
react.useEffect(() => {
|
|
3956
|
+
const el = anchor.current;
|
|
3957
|
+
if (!el) return;
|
|
3958
|
+
const measure = () => {
|
|
3959
|
+
const r = el.getBoundingClientRect();
|
|
3960
|
+
setBounds({ left: Math.round(r.left), width: Math.round(r.width) });
|
|
3961
|
+
};
|
|
3962
|
+
measure();
|
|
3963
|
+
const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(measure) : null;
|
|
3964
|
+
ro?.observe(el);
|
|
3965
|
+
window.addEventListener("resize", measure);
|
|
3966
|
+
window.addEventListener("scroll", measure, true);
|
|
3967
|
+
return () => {
|
|
3968
|
+
ro?.disconnect();
|
|
3969
|
+
window.removeEventListener("resize", measure);
|
|
3970
|
+
window.removeEventListener("scroll", measure, true);
|
|
3971
|
+
};
|
|
3972
|
+
}, [anchor]);
|
|
3953
3973
|
const onHandlePointerDown = react.useCallback((e) => {
|
|
3954
3974
|
const rect = pillRef.current?.getBoundingClientRect();
|
|
3955
3975
|
if (!rect) return;
|
|
@@ -3972,29 +3992,36 @@ function BlockToolbar({
|
|
|
3972
3992
|
window.addEventListener("pointerup", up);
|
|
3973
3993
|
return up;
|
|
3974
3994
|
}, [pos !== null]);
|
|
3975
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
{
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3995
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3996
|
+
"div",
|
|
3997
|
+
{
|
|
3998
|
+
className: `ce-tray-dock${pos ? " is-floating" : ""}`,
|
|
3999
|
+
style: pos ? { left: pos.x, top: pos.y } : bounds ? { left: bounds.left, width: bounds.width } : void 0,
|
|
4000
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: pillRef, className: "ce-tray", role: "toolbar", "aria-label": "Blocks", children: [
|
|
4001
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4002
|
+
"button",
|
|
4003
|
+
{
|
|
4004
|
+
type: "button",
|
|
4005
|
+
className: "ce-tray-btn is-grab",
|
|
4006
|
+
onPointerDown: onHandlePointerDown,
|
|
4007
|
+
onDoubleClick: () => setPos(null),
|
|
4008
|
+
title: "Move toolbar (double-click to dock)",
|
|
4009
|
+
"aria-label": "Move toolbar",
|
|
4010
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "move", size: 18 })
|
|
4011
|
+
}
|
|
4012
|
+
),
|
|
4013
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "ce-tray-tiles", children: trayItems().map((def) => /* @__PURE__ */ jsxRuntime.jsx(TrayTile, { def, showLabel: showLabels }, def.type)) }),
|
|
4014
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ce-seg", role: "radiogroup", "aria-label": "Insert control placement", children: [
|
|
4015
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", role: "radio", "aria-checked": insertMode === "side", className: `ce-seg-btn${insertMode === "side" ? " is-active" : ""}`, onClick: () => onInsertModeChange("side"), children: "Side" }),
|
|
4016
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", role: "radio", "aria-checked": insertMode === "center", className: `ce-seg-btn${insertMode === "center" ? " is-active" : ""}`, onClick: () => onInsertModeChange("center"), children: "Center" })
|
|
4017
|
+
] }),
|
|
4018
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: `ce-tray-btn${showLabels ? " is-active" : ""}`, onClick: onToggleLabels, title: showLabels ? "Hide labels" : "Show labels", "aria-pressed": showLabels, "aria-label": "Toggle tile labels", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "type", size: 18 }) }),
|
|
4019
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ce-tray-btn", onClick: onUndo, disabled: !canUndo, title: "Undo (\u2318Z)", "aria-label": "Undo", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "rotate-ccw", size: 18 }) }),
|
|
4020
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ce-tray-btn", onClick: onRedo, disabled: !canRedo, title: "Redo (\u2318\u21E7Z)", "aria-label": "Redo", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "rotate-cw", size: 18 }) }),
|
|
4021
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ce-tray-btn", onClick: onClose, title: "Close blocks toolbar", "aria-label": "Close blocks toolbar", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "x", size: 18 }) })
|
|
4022
|
+
] })
|
|
4023
|
+
}
|
|
4024
|
+
);
|
|
3998
4025
|
}
|
|
3999
4026
|
function TrayTile({ def, showLabel }) {
|
|
4000
4027
|
const { attributes, listeners, setNodeRef, isDragging } = core$1.useDraggable({
|
|
@@ -4196,6 +4223,7 @@ function CanvasEditor({
|
|
|
4196
4223
|
writePref(TRAY_OPEN_KEY, open ? "1" : "0");
|
|
4197
4224
|
};
|
|
4198
4225
|
const [trayLabels, setTrayLabelsState] = react.useState(() => readPref(TRAY_LABELS_KEY) === "1");
|
|
4226
|
+
const canvasRef = react.useRef(null);
|
|
4199
4227
|
const toggleTrayLabels = () => setTrayLabelsState((v) => {
|
|
4200
4228
|
writePref(TRAY_LABELS_KEY, v ? "0" : "1");
|
|
4201
4229
|
return !v;
|
|
@@ -4581,7 +4609,7 @@ function CanvasEditor({
|
|
|
4581
4609
|
metaPanel && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t pt-4", style: { borderColor: "var(--color-border)" }, children: metaPanel({ doc: currentDoc(), setMeta }) })
|
|
4582
4610
|
] })
|
|
4583
4611
|
] }),
|
|
4584
|
-
/* @__PURE__ */ jsxRuntime.jsxs("main", { className: "ce-canvas", style: { background: settings?.outerBackground || void 0 }, children: [
|
|
4612
|
+
/* @__PURE__ */ jsxRuntime.jsxs("main", { ref: canvasRef, className: "ce-canvas", style: { background: settings?.outerBackground || void 0 }, children: [
|
|
4585
4613
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "ce-canvas-body", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4586
4614
|
CanvasArea,
|
|
4587
4615
|
{
|
|
@@ -4601,6 +4629,7 @@ function CanvasEditor({
|
|
|
4601
4629
|
trayOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4602
4630
|
BlockToolbar,
|
|
4603
4631
|
{
|
|
4632
|
+
anchor: canvasRef,
|
|
4604
4633
|
insertMode,
|
|
4605
4634
|
onInsertModeChange: setInsertMode,
|
|
4606
4635
|
showLabels: trayLabels,
|