smoodly 0.0.53 → 0.0.55
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/admin/editor/CanvasOverlay.d.ts +3 -1
- package/dist/admin/editor/CanvasOverlay.js +2 -2
- package/dist/admin/editor/EditorView.js +243 -63
- package/dist/admin/editor/InsertPicker.d.ts +8 -1
- package/dist/admin/editor/InsertPicker.js +2 -2
- package/dist/admin/editor/InspectorFields.js +1 -1
- package/dist/admin/editor/Outline.d.ts +11 -3
- package/dist/admin/editor/Outline.js +12 -3
- package/dist/admin/editor/PageInspector.js +1 -1
- package/dist/admin/editor/StructureView.d.ts +23 -0
- package/dist/admin/editor/StructureView.js +58 -0
- package/dist/admin/editor/card-preview.d.ts +10 -0
- package/dist/admin/editor/card-preview.js +50 -0
- package/dist/admin/editor/global-edit.js +29 -22
- package/dist/admin/editor/history.d.ts +39 -0
- package/dist/admin/editor/history.js +64 -0
- package/dist/admin/editor/section-clipboard.d.ts +40 -0
- package/dist/admin/editor/section-clipboard.js +106 -0
- package/dist/admin/editor/undo-keys.d.ts +19 -0
- package/dist/admin/editor/undo-keys.js +27 -0
- package/dist/admin/editor/useInlineSession.d.ts +4 -1
- package/dist/admin/editor/useInlineSession.js +11 -2
- package/dist/admin/editor/view-memory.d.ts +9 -0
- package/dist/admin/editor/view-memory.js +17 -0
- package/dist/admin/files.generated.js +1 -1
- package/dist/admin/ui/ActionMenu.d.ts +2 -0
- package/dist/admin/ui/ActionMenu.js +1 -1
- package/dist/admin/ui/primitives.d.ts +1 -0
- package/dist/admin/ui/primitives.js +1 -1
- package/dist/admin/ui/theme.js +69 -0
- package/dist/admin/ui/useSortable.js +3 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -3,6 +3,8 @@ export type ActionMenuItem = {
|
|
|
3
3
|
run(): void;
|
|
4
4
|
disabled?: boolean;
|
|
5
5
|
danger?: boolean;
|
|
6
|
+
/** The reason on a disabled entry (a paste the zone refuses), shown as the button's title. */
|
|
7
|
+
title?: string;
|
|
6
8
|
};
|
|
7
9
|
/** The button's box in viewport pixels, `right` measured from the viewport's right edge. */
|
|
8
10
|
type Anchor = {
|
|
@@ -68,5 +68,5 @@ export function ActionMenu({ label, items, disabled, small = false }) {
|
|
|
68
68
|
document.removeEventListener("scroll", onScroll, true);
|
|
69
69
|
};
|
|
70
70
|
}, [open]);
|
|
71
|
-
return (_jsxs("div", { ref: ref, style: { position: "relative", flex: "none" }, children: [_jsx("button", { ref: button, type: "button", className: cx("sm-dotmenu", small && "sm-dotmenu--sm"), "aria-label": label, title: label, "aria-haspopup": "menu", "aria-expanded": open !== null, disabled: disabled, onClick: toggle, children: "\u00B7\u00B7\u00B7" }), open && (_jsx("div", { ref: menu, role: "menu", className: "sm-picker sm-picker--menu", style: place ?? { top: open.bottom + 6, right: open.right, visibility: "hidden" }, children: items.map((item) => (_jsx("button", { type: "button", role: "menuitem", className: cx("sm-picker__item", item.danger && "sm-picker__item--danger"), disabled: item.disabled, onClick: () => { setOpen(null); item.run(); }, children: item.label }, item.label))) }))] }));
|
|
71
|
+
return (_jsxs("div", { ref: ref, style: { position: "relative", flex: "none" }, children: [_jsx("button", { ref: button, type: "button", className: cx("sm-dotmenu", small && "sm-dotmenu--sm"), "aria-label": label, title: label, "aria-haspopup": "menu", "aria-expanded": open !== null, disabled: disabled, onClick: toggle, children: "\u00B7\u00B7\u00B7" }), open && (_jsx("div", { ref: menu, role: "menu", className: "sm-picker sm-picker--menu", style: place ?? { top: open.bottom + 6, right: open.right, visibility: "hidden" }, children: items.map((item) => (_jsx("button", { type: "button", role: "menuitem", className: cx("sm-picker__item", item.danger && "sm-picker__item--danger"), disabled: item.disabled, title: item.title, onClick: () => { setOpen(null); item.run(); }, children: item.label }, item.label))) }))] }));
|
|
72
72
|
}
|
|
@@ -103,6 +103,7 @@ export declare function Segmented<T extends string>({ options, value, onChange,
|
|
|
103
103
|
disabled?: boolean;
|
|
104
104
|
title?: string;
|
|
105
105
|
className?: string;
|
|
106
|
+
"aria-label"?: string;
|
|
106
107
|
} | undefined;
|
|
107
108
|
}): import("react").JSX.Element;
|
|
108
109
|
export declare function StatusBadge({ status }: {
|
|
@@ -103,7 +103,7 @@ export function Tabs({ tabs, value, onChange }) {
|
|
|
103
103
|
export function Segmented({ options, value, onChange, stretch, disabled, label, option, className }) {
|
|
104
104
|
return (_jsx("div", { className: cx("sm-seg", stretch && "sm-seg--stretch", disabled && "sm-seg--disabled", className), children: options.map((o) => {
|
|
105
105
|
const extra = option?.(o);
|
|
106
|
-
return (_jsx("button", { type: "button", className: cx("sm-seg__opt", extra?.className), "aria-pressed": o === value, disabled: disabled || extra?.disabled, title: extra?.title, onClick: () => onChange(o), children: label ? label(o) : o }, o));
|
|
106
|
+
return (_jsx("button", { type: "button", className: cx("sm-seg__opt", extra?.className), "aria-pressed": o === value, disabled: disabled || extra?.disabled, title: extra?.title, "aria-label": extra?.["aria-label"], onClick: () => onChange(o), children: label ? label(o) : o }, o));
|
|
107
107
|
}) }));
|
|
108
108
|
}
|
|
109
109
|
/* ── data ────────────────────────────────────────────────────────────── */
|
package/dist/admin/ui/theme.js
CHANGED
|
@@ -638,6 +638,8 @@ body:has(.sm-admin){margin:0}
|
|
|
638
638
|
.sm-seg{display:flex;gap:2px;padding:3px;background:var(--seg-bg);border-radius:var(--radius-btn)}
|
|
639
639
|
/* A locale switch: each option wide enough to read as a tab, not a chip. */
|
|
640
640
|
.sm-seg--locale .sm-seg__opt{min-width:64px}
|
|
641
|
+
/* The Canvas | Structure switch: two icon options. */
|
|
642
|
+
.sm-seg--view .sm-seg__opt{padding:4px 8px;display:grid;place-items:center}
|
|
641
643
|
.sm-seg--stretch{width:100%}
|
|
642
644
|
.sm-seg--disabled{opacity:.6}
|
|
643
645
|
.sm-seg__opt:disabled{cursor:default}
|
|
@@ -768,6 +770,11 @@ body:has(.sm-admin){margin:0}
|
|
|
768
770
|
position:relative;background:var(--page-bg);border-radius:var(--page-radius);
|
|
769
771
|
box-shadow:var(--shadow-page);min-height:100%;
|
|
770
772
|
}
|
|
773
|
+
/* Structure (spec 2026-10-19 editor at launch §1): the structure layer takes the scroller; the frame stays mounted
|
|
774
|
+
and hidden under it: the wrapper is a zero-height absolute box that clips the frame (so the scroller does not grow by the
|
|
775
|
+
page's height), while the frame's own box keeps its width and height for the bridge. After .sm-page: it overrides its position. */
|
|
776
|
+
.sm-canvas__scroll--structure{position:relative}
|
|
777
|
+
.sm-page.sm-canvas__hidden{visibility:hidden;position:absolute;left:0;top:0;width:100%;height:0;min-height:0;pointer-events:none}
|
|
771
778
|
.sm-canvas__loading{
|
|
772
779
|
height:240px;display:grid;place-items:center;color:var(--text-subtle);font-family:var(--meta-font);
|
|
773
780
|
font-size:var(--meta-size);letter-spacing:var(--caps-tracking);text-transform:var(--caps-transform);
|
|
@@ -823,6 +830,7 @@ body:has(.sm-admin){margin:0}
|
|
|
823
830
|
.sm-outline-row__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
|
|
824
831
|
.sm-outline-row__note{font-size:var(--text-sm);font-weight:500;flex:none;letter-spacing:var(--caps-tracking);text-transform:var(--caps-transform)}
|
|
825
832
|
.sm-outline-row__add{color:var(--accent);font-weight:500;flex:none}
|
|
833
|
+
.sm-outline-row__menu{display:flex;flex:none}
|
|
826
834
|
/* Drift marks (spec 2026-09-27 editor safety §5): a stripe inside the row's left edge, red for broken, muted for left over. */
|
|
827
835
|
.sm-outline-row--broken{box-shadow:inset 3px 0 0 var(--danger)}
|
|
828
836
|
.sm-outline-row--orphan{box-shadow:inset 3px 0 0 var(--line-dashed)}
|
|
@@ -834,6 +842,65 @@ body:has(.sm-admin){margin:0}
|
|
|
834
842
|
/* A row with a grip: the grip takes the left padding's place and the label follows it. */
|
|
835
843
|
.sm-outline-row--grip{padding-left:2px}
|
|
836
844
|
.sm-outline-row--grip .sm-outline-row__label{flex:1}
|
|
845
|
+
/* The structure view (spec 2026-10-19 editor at launch §1): the canvas column as rows of cards, the
|
|
846
|
+
outline's boxes grown up — a zone's caps label, a card per section on the outline's white, the
|
|
847
|
+
outline's selected fill and drift stripes. The add affordance between cards is the "+" pill at
|
|
848
|
+
label size, faint until its row is hovered. */
|
|
849
|
+
.sm-structure{max-width:720px;margin:0 auto;padding:var(--canvas-pad);padding-bottom:40px;display:flex;flex-direction:column;gap:20px}
|
|
850
|
+
.sm-structure__group{display:flex;flex-direction:column;gap:4px}
|
|
851
|
+
.sm-structure__zone{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:24px}
|
|
852
|
+
.sm-structure__zone .sm-sectionlabel{flex:1;min-width:0}
|
|
853
|
+
.sm-structure__rows{display:flex;flex-direction:column}
|
|
854
|
+
.sm-structure__row{display:flex;flex-direction:column}
|
|
855
|
+
.sm-structure__card{
|
|
856
|
+
display:grid;grid-template-columns:24px 32px minmax(0,1fr) auto auto;gap:10px;align-items:center;
|
|
857
|
+
width:100%;min-height:56px;padding:8px 6px 8px 2px;text-align:left;font:inherit;
|
|
858
|
+
border-radius:var(--outline-row-radius);background:var(--outline-row-bg);border:var(--outline-row-border);
|
|
859
|
+
color:var(--text);cursor:pointer;
|
|
860
|
+
}
|
|
861
|
+
.sm-structure__card:hover{background:var(--control-hover)}
|
|
862
|
+
.sm-structure__card:hover .sm-grip{opacity:1}
|
|
863
|
+
.sm-structure__card:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
|
|
864
|
+
.sm-structure__card--selected,.sm-structure__card--selected:hover{background:var(--nav-active-bg);color:var(--nav-active-fg);border-color:transparent}
|
|
865
|
+
.sm-structure__card--locked{background:var(--surface-inset);color:var(--text-muted);border-color:transparent}
|
|
866
|
+
.sm-structure__card--broken{box-shadow:inset 3px 0 0 var(--danger)}
|
|
867
|
+
.sm-structure__card--orphan{box-shadow:inset 3px 0 0 var(--line-dashed)}
|
|
868
|
+
.sm-structure__gripslot{width:24px;height:24px}
|
|
869
|
+
.sm-structure__icon{
|
|
870
|
+
width:32px;height:32px;display:grid;place-items:center;border-radius:var(--radius-sm);
|
|
871
|
+
background:var(--surface-inset);font-size:var(--text-lg);line-height:1;flex:none;
|
|
872
|
+
}
|
|
873
|
+
.sm-structure__card--selected .sm-structure__icon,.sm-structure__card--locked .sm-structure__icon{background:color-mix(in srgb,currentColor 10%,transparent)}
|
|
874
|
+
.sm-structure__text{display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
875
|
+
.sm-structure__title{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:flex;align-items:center;gap:6px;min-width:0}
|
|
876
|
+
.sm-structure__badge{
|
|
877
|
+
font-size:var(--text-sm);font-weight:500;letter-spacing:var(--caps-tracking);text-transform:var(--caps-transform);
|
|
878
|
+
color:var(--text-muted);flex:none;
|
|
879
|
+
}
|
|
880
|
+
.sm-structure__card--selected .sm-structure__badge{color:inherit;opacity:.8}
|
|
881
|
+
.sm-structure__preview{font-size:var(--text-sm);color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400}
|
|
882
|
+
.sm-structure__card--selected .sm-structure__preview{color:inherit;opacity:.8}
|
|
883
|
+
.sm-structure__thumb{width:44px;height:30px;border-radius:4px;overflow:hidden;background:var(--surface-inset);flex:none;display:block}
|
|
884
|
+
.sm-structure__img{width:100%;height:100%;object-fit:cover;display:block}
|
|
885
|
+
.sm-structure__menu{display:flex;flex:none}
|
|
886
|
+
.sm-structure__slot{display:flex;justify-content:center;padding:4px 0}
|
|
887
|
+
.sm-structure__add{
|
|
888
|
+
display:inline-flex;align-items:center;gap:6px;height:24px;padding:0 10px 0 4px;border-radius:999px;border:0;
|
|
889
|
+
background:var(--plus-bg);color:var(--plus-fg);font:500 var(--text-sm)/1 var(--font-sans);cursor:pointer;
|
|
890
|
+
box-shadow:var(--plus-shadow);white-space:nowrap;transition:background .12s;
|
|
891
|
+
}
|
|
892
|
+
.sm-structure__add-icon{
|
|
893
|
+
width:16px;height:16px;flex:none;border-radius:50%;background:var(--plus-icon-bg);color:var(--plus-icon-fg);
|
|
894
|
+
display:grid;place-items:center;font-size:12px;line-height:1;
|
|
895
|
+
}
|
|
896
|
+
.sm-structure__add:hover{background:var(--plus-hover)}
|
|
897
|
+
/* The lifted row keeps the hook's transform and z-index; its card carries the shadow. */
|
|
898
|
+
.sm-structure__row.sm-drag--lifted{background:transparent;box-shadow:none}
|
|
899
|
+
.sm-structure__row.sm-drag--lifted .sm-structure__card{box-shadow:var(--shadow-pop)}
|
|
900
|
+
.sm-structure__empty{
|
|
901
|
+
display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:var(--outline-row-h);padding:4px 12px;
|
|
902
|
+
border:1px dashed var(--line-dashed);border-radius:var(--outline-row-radius);color:var(--text-muted);font-weight:500;
|
|
903
|
+
}
|
|
837
904
|
|
|
838
905
|
.sm-picker{
|
|
839
906
|
width:300px;background:var(--menu-bg);border:var(--menu-border);border-radius:var(--radius-md);
|
|
@@ -847,6 +914,8 @@ body:has(.sm-admin){margin:0}
|
|
|
847
914
|
/* after the base item rule: same specificity, so source order decides (ActionMenu states) */
|
|
848
915
|
.sm-picker__item:disabled{opacity:.4;cursor:default}
|
|
849
916
|
.sm-picker__item:disabled:hover{background:transparent}
|
|
917
|
+
/* The clipboard's entry leads the picker (spec 2026-10-19 editor at launch §3), set off from the sections under it. */
|
|
918
|
+
.sm-picker__item--paste{border-bottom:1px solid var(--line);margin-bottom:4px;border-radius:var(--radius-sm) var(--radius-sm) 0 0}
|
|
850
919
|
.sm-picker__item--danger{color:var(--danger)}
|
|
851
920
|
.sm-picker__icon{
|
|
852
921
|
width:26px;height:26px;flex:none;border-radius:var(--radius-sm);background:var(--accent-soft);
|
|
@@ -172,7 +172,9 @@ export function useSortable(options) {
|
|
|
172
172
|
window.addEventListener("keydown", key);
|
|
173
173
|
};
|
|
174
174
|
const onKeyDown = (index) => (e) => {
|
|
175
|
-
|
|
175
|
+
// The row's own Enter/Space handler must not see the grip's keys; every other key (the editor's Cmd+Z, review 2026-10-20) bubbles on.
|
|
176
|
+
if (e.key === "Enter" || e.key === " " || e.key === "ArrowUp" || e.key === "ArrowDown")
|
|
177
|
+
e.stopPropagation();
|
|
176
178
|
if (e.key !== "ArrowUp" && e.key !== "ArrowDown")
|
|
177
179
|
return;
|
|
178
180
|
e.preventDefault();
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SMOODLY_VERSION = "0.0.
|
|
1
|
+
export declare const SMOODLY_VERSION = "0.0.55";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by scripts/write-version.mjs from package.json — do not edit.
|
|
2
|
-
export const SMOODLY_VERSION = "0.0.
|
|
2
|
+
export const SMOODLY_VERSION = "0.0.55";
|
package/package.json
CHANGED