@storystick/react 0.0.0-stage → 0.2.0-rc.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.
- package/LICENSE +112 -0
- package/NOTICE +17 -0
- package/PUBLIC-API.md +38 -0
- package/README.md +226 -2
- package/dist/.source-hash +1 -0
- package/dist/authoring-skeleton.d.ts +5 -0
- package/dist/authoring-skeleton.js +29 -0
- package/dist/file.d.ts +18 -0
- package/dist/file.js +44 -0
- package/dist/hydrate-slice.d.ts +3 -0
- package/dist/hydrate-slice.js +1 -0
- package/dist/image-component.d.ts +26 -0
- package/dist/image-component.js +79 -0
- package/dist/image-element.d.ts +6 -0
- package/dist/image-element.js +68 -0
- package/dist/image.d.ts +3 -0
- package/dist/image.js +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/link-adapter.d.ts +2 -0
- package/dist/link-adapter.js +2 -0
- package/dist/link-component.d.ts +53 -0
- package/dist/link-component.js +97 -0
- package/dist/link.d.ts +3 -0
- package/dist/link.js +3 -0
- package/dist/preview-generation.d.ts +21 -0
- package/dist/preview-generation.js +134 -0
- package/dist/preview-host/preview-assistant-continuation.d.ts +9 -0
- package/dist/preview-host/preview-assistant-continuation.js +39 -0
- package/dist/preview-host/preview-authoring-client.d.ts +12 -0
- package/dist/preview-host/preview-authoring-client.js +108 -0
- package/dist/preview-host/preview-editor-continuation.d.ts +13 -0
- package/dist/preview-host/preview-editor-continuation.js +68 -0
- package/dist/preview-host/preview-standalone-controls.d.ts +18 -0
- package/dist/preview-host/preview-standalone-controls.js +528 -0
- package/dist/preview-host/preview-studio-destination.d.ts +20 -0
- package/dist/preview-host/preview-studio-destination.js +55 -0
- package/dist/preview-host/use-standalone-presentation.d.ts +15 -0
- package/dist/preview-host/use-standalone-presentation.js +223 -0
- package/dist/preview-icons.d.ts +10 -0
- package/dist/preview-icons.js +8 -0
- package/dist/preview-interaction-control.d.ts +6 -0
- package/dist/preview-interaction-control.js +39 -0
- package/dist/preview-page-state.d.ts +12 -0
- package/dist/preview-page-state.js +11 -0
- package/dist/preview-panel-state.d.ts +15 -0
- package/dist/preview-panel-state.js +28 -0
- package/dist/preview-provenance-publisher-model.d.ts +5 -0
- package/dist/preview-provenance-publisher-model.js +9 -0
- package/dist/preview-provenance-publisher.d.ts +15 -0
- package/dist/preview-provenance-publisher.js +68 -0
- package/dist/preview-provenance.d.ts +6 -0
- package/dist/preview-provenance.js +4 -0
- package/dist/preview-scope.d.ts +128 -0
- package/dist/preview-scope.js +161 -0
- package/dist/preview-slice-scope.d.ts +32 -0
- package/dist/preview-slice-scope.js +33 -0
- package/dist/preview-text-props.d.ts +18 -0
- package/dist/preview-text-props.js +13 -0
- package/dist/preview-toolbar-layout.d.ts +42 -0
- package/dist/preview-toolbar-layout.js +139 -0
- package/dist/preview-toolbar-panel.d.ts +14 -0
- package/dist/preview-toolbar-panel.js +6 -0
- package/dist/preview-toolbar-resize-handles.d.ts +9 -0
- package/dist/preview-toolbar-resize-handles.js +14 -0
- package/dist/preview-toolbar-shell.d.ts +19 -0
- package/dist/preview-toolbar-shell.js +144 -0
- package/dist/public-rich-text.d.ts +15 -0
- package/dist/public-rich-text.js +11 -0
- package/dist/public-slice-zone.d.ts +7 -0
- package/dist/public-slice-zone.js +6 -0
- package/dist/query-cache.d.ts +14 -0
- package/dist/query-cache.js +289 -0
- package/dist/query-preview-loader.d.ts +9 -0
- package/dist/query-preview-loader.js +28 -0
- package/dist/query-preview-runtime.d.ts +3 -0
- package/dist/query-preview-runtime.js +3 -0
- package/dist/rendering.d.ts +29 -0
- package/dist/rendering.js +17 -0
- package/dist/resize-edge.d.ts +8 -0
- package/dist/resize-edge.js +33 -0
- package/dist/rich-text.d.ts +150 -0
- package/dist/rich-text.js +618 -0
- package/dist/slice-render-failure.d.ts +8 -0
- package/dist/slice-render-failure.js +46 -0
- package/dist/slice-zone.d.ts +82 -0
- package/dist/slice-zone.js +273 -0
- package/dist/slice.d.ts +16 -0
- package/dist/slice.js +46 -0
- package/dist/storystick-mark.d.ts +3 -0
- package/dist/storystick-mark.js +6 -0
- package/dist/use-generated-query.d.ts +37 -0
- package/dist/use-generated-query.js +308 -0
- package/dist/use-momentary-preview-navigate-mode.d.ts +11 -0
- package/dist/use-momentary-preview-navigate-mode.js +158 -0
- package/dist/use-preview-perspective-intent.d.ts +53 -0
- package/dist/use-preview-perspective-intent.js +227 -0
- package/dist/use-preview-pointer-drag.d.ts +16 -0
- package/dist/use-preview-pointer-drag.js +98 -0
- package/dist/use-preview-toolbar-layout.d.ts +36 -0
- package/dist/use-preview-toolbar-layout.js +141 -0
- package/dist/use-render-mode-debounce.d.ts +31 -0
- package/dist/use-render-mode-debounce.js +143 -0
- package/dist/video.d.ts +21 -0
- package/dist/video.js +63 -0
- package/package.json +154 -3
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState, } from "react";
|
|
4
|
+
import { createPortal } from "react-dom";
|
|
5
|
+
import { ArrowUpRight, MessageCircle, SquarePen } from "./preview-icons.js";
|
|
6
|
+
import { Popover } from "@base-ui/react/popover";
|
|
7
|
+
import { PreviewToolbarPanel } from "./preview-toolbar-panel.js";
|
|
8
|
+
import { PreviewToolbarResizeHandles } from "./preview-toolbar-resize-handles.js";
|
|
9
|
+
import { TOOLBAR_GAP } from "./preview-toolbar-layout.js";
|
|
10
|
+
import { usePreviewToolbarLayout } from "./use-preview-toolbar-layout.js";
|
|
11
|
+
import { StorystickMark } from "./storystick-mark.js";
|
|
12
|
+
/** The host owns admission and active content; this shell owns presentation. */
|
|
13
|
+
export function PreviewToolbarShell(props) {
|
|
14
|
+
const ownHost = useRef(null);
|
|
15
|
+
const host = props.hostRef ?? ownHost;
|
|
16
|
+
const [root, setRoot] = useState(null);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (!host.current)
|
|
19
|
+
return;
|
|
20
|
+
const shadow = host.current.shadowRoot ?? host.current.attachShadow({ mode: "open" });
|
|
21
|
+
setRoot(shadow);
|
|
22
|
+
props.onRoot?.(shadow);
|
|
23
|
+
}, [host, props.onRoot]);
|
|
24
|
+
return _jsx("div", { ref: host, "data-storystick-preview-controls": "", style: { all: "initial", position: "fixed", zIndex: 2147483647, top: 0, left: 0, width: 0, height: 0 }, children: root ? createPortal(_jsx(ToolbarContents, { ...props, root: root }), root) : null });
|
|
25
|
+
}
|
|
26
|
+
function ToolbarContents({ root, menuOpen, panelOpen, menu, panel, panelLabel, panelTitle, panelLeading, panelTrailing, onMenuOpenChange, onPanelClose }) {
|
|
27
|
+
const layout = usePreviewToolbarLayout(() => onMenuOpenChange(false));
|
|
28
|
+
const menuRef = useRef(null);
|
|
29
|
+
const [shell, setShell] = useState(null);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!menuOpen)
|
|
32
|
+
return;
|
|
33
|
+
// Click to Edit consumes customer-page events at document capture. Observe
|
|
34
|
+
// outside presses above that boundary, leaving owned menus to Base UI.
|
|
35
|
+
const onPagePress = (event) => {
|
|
36
|
+
if (!event.composedPath().includes(root))
|
|
37
|
+
onMenuOpenChange(false);
|
|
38
|
+
};
|
|
39
|
+
const win = root.ownerDocument.defaultView;
|
|
40
|
+
win?.addEventListener('pointerdown', onPagePress, true);
|
|
41
|
+
return () => win?.removeEventListener('pointerdown', onPagePress, true);
|
|
42
|
+
}, [menuOpen, onMenuOpenChange, root]);
|
|
43
|
+
function closePanel() {
|
|
44
|
+
onPanelClose();
|
|
45
|
+
layout.bubble.current?.focus({ preventScroll: true });
|
|
46
|
+
}
|
|
47
|
+
return _jsxs(_Fragment, { children: [_jsx("style", { children: CONTROL_STYLES }), _jsxs("div", { ref: setShell, className: "storystick-shell", "data-ss-surface": "", dir: "ltr", children: [_jsx(PreviewToolbarPanel, { open: panelOpen, label: panelLabel, onClose: closePanel, leading: panelLeading, title: panelTitle, trailing: panelTrailing, panelRef: layout.panel, handleProps: { ...layout.panelDrag, onKeyDown: layout.onPanelKeyDown }, resizeHandles: _jsx(PreviewToolbarResizeHandles, { label: panelLabel, edges: layout.resizeEdges, size: layout.panelBounds, handleProps: layout.resizeHandleProps }), children: panel }), _jsxs(Popover.Root, { open: menuOpen, modal: false, onOpenChange: (open, details) => {
|
|
48
|
+
// Runtime menus live in a second React root, but remain part of this
|
|
49
|
+
// dropdown interaction. Their owned portals must not dismiss its parent.
|
|
50
|
+
const portals = root.querySelector('[data-storystick-authoring-portals]');
|
|
51
|
+
if (!open && details.reason === 'outside-press' && details.event.composedPath().some(node => node === menuRef.current || node === portals)) {
|
|
52
|
+
details.cancel();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!open && details.reason === 'focus-out' && portals?.contains(root.activeElement)) {
|
|
56
|
+
details.cancel();
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
onMenuOpenChange(open);
|
|
60
|
+
}, children: [_jsx(Popover.Trigger, { ref: layout.bubble, className: "bubble", "aria-label": menuOpen ? "Close Storystick" : "Open Storystick", title: "Drag to move. Alt + arrow keys change position.", ...layout.bubbleDrag, onKeyDown: layout.onBubbleKeyDown, children: _jsx(StorystickMark, { className: "storystick-brand" }) }), _jsx(Popover.Portal, { container: shell, keepMounted: true, children: _jsx(Popover.Positioner, { className: "menu-positioner", positionMethod: "fixed", side: layout.dock === 'left' ? 'right' : layout.dock === 'right' ? 'left' : 'top', align: layout.dock === 'bottom' ? 'end' : 'center', sideOffset: TOOLBAR_GAP, collisionPadding: TOOLBAR_GAP, children: _jsx(Popover.Popup, { ref: menuRef, className: "menu", "aria-label": "Storystick Preview", initialFocus: type => type === 'keyboard', children: _jsx("nav", { "aria-label": "Storystick Preview controls", hidden: !menuOpen, children: menu }) }) }) })] })] })] });
|
|
61
|
+
}
|
|
62
|
+
export function PreviewEditIcon() {
|
|
63
|
+
return _jsx(SquarePen, { className: "storystick-control-icon", size: 16, absoluteStrokeWidth: true, strokeWidth: 1.25, "aria-hidden": "true" });
|
|
64
|
+
}
|
|
65
|
+
export function PreviewAssistantIcon() {
|
|
66
|
+
return _jsx(MessageCircle, { className: "storystick-control-icon", size: 16, absoluteStrokeWidth: true, strokeWidth: 1.25, "aria-hidden": "true" });
|
|
67
|
+
}
|
|
68
|
+
export function PreviewStudioIcon() {
|
|
69
|
+
return _jsx(ArrowUpRight, { className: "storystick-control-icon", size: 16, absoluteStrokeWidth: true, strokeWidth: 1.25, "aria-hidden": "true" });
|
|
70
|
+
}
|
|
71
|
+
const CONTROL_STYLES = `
|
|
72
|
+
* { box-sizing: border-box; }
|
|
73
|
+
:is(.bubble, .menu-action, .panel-close, .panel-drag-handle, .notices button) { font: inherit; }
|
|
74
|
+
:is(.bubble, .menu-action, .panel-close, .panel-drag-handle, .notices button) { cursor: pointer; }
|
|
75
|
+
.storystick-control-icon { width: 16px; height: 16px; flex: none; }
|
|
76
|
+
/* Studio tokens arrive with the lazy authoring stylesheet. The initial shell
|
|
77
|
+
uses their light values too, without loading the editor just to paint it. */
|
|
78
|
+
.storystick-shell { position: fixed; inset: 0; pointer-events: none; color-scheme: light; font: 14px/18px "Storystick Inter", "Inter Variable", ui-sans-serif, system-ui, sans-serif; color: var(--ss-text-primary, oklch(0.2 0.007 258.364)); -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }
|
|
79
|
+
.bubble { pointer-events: auto; touch-action: none; user-select: none; position: fixed; top: 0; left: 0; z-index: 2; width: 40px; height: 40px; display: grid; place-items: center; color: inherit; background: var(--ss-surface-card, #fff); border: 0; border-radius: 999px; transition: background-color 140ms ease, transform 180ms ease-out; }
|
|
80
|
+
.bubble:hover { background: var(--ss-surface-field, oklch(0.958 0.001 255)); }
|
|
81
|
+
.bubble:focus-visible, .menu-action:focus-visible, .panel-close:focus-visible, .panel-drag-handle:focus-visible { outline: 2px solid var(--ss-focus-color, oklch(0.614 0.194 257)); outline-offset: -2px; }
|
|
82
|
+
.storystick-brand { width: 14px; height: 13px; transform: rotate(90deg); }
|
|
83
|
+
.menu-positioner { z-index: 3; pointer-events: auto; }
|
|
84
|
+
.menu { width: min(240px, calc(100vw - ${TOOLBAR_GAP * 2}px)); max-height: min(var(--available-height), calc(100dvh - ${TOOLBAR_GAP * 2}px)); overflow: auto; overscroll-behavior: contain; padding: 5px; }
|
|
85
|
+
/* Keep the bubble's relief stable before and after the authoring styles load. */
|
|
86
|
+
.bubble { box-shadow: 0 0 1px rgb(0 0 0 / 0.34), 0 2px 6px -1px rgb(0 0 0 / 0.12), 0 8px 20px -6px rgb(0 0 0 / 0.18); }
|
|
87
|
+
.menu, .editor-panel { box-shadow: 0 0 0 1px rgb(0 0 0 / 0.07), 0 4px 12px -2px rgb(0 0 0 / 0.1), 0 16px 40px -10px rgb(0 0 0 / 0.2); border: 0; }
|
|
88
|
+
.menu { background: var(--ss-surface-card, #fff); border-radius: var(--ss-radius-2xl, 19px); }
|
|
89
|
+
.menu-group { display: flex; flex-direction: column; gap: 2px; }
|
|
90
|
+
.menu-group-label { display: flex; align-items: center; min-height: 25px; padding: 4px 10px; color: var(--ss-text-tertiary, oklch(0.515 0.006 258.364)); font-size: 13px; line-height: 17px; font-weight: 500; }
|
|
91
|
+
.menu-group-content { padding: 0 10px 5px; }
|
|
92
|
+
.menu-context-loading { display: flex; gap: 8px; height: 32px; }
|
|
93
|
+
.menu-context-loading span { width: 88px; border-radius: 999px; background: var(--ss-surface-widget, #f0f0f0); }
|
|
94
|
+
.menu-context-loading span:last-child { width: 56px; }
|
|
95
|
+
.menu-separator { margin: 5px 10px; border-top: 1px solid var(--ss-border-separator, oklch(0.958 0.001 255)); }
|
|
96
|
+
.menu-action { width: 100%; min-height: 28px; display: flex; align-items: center; gap: 8px; padding: 5px 10px; color: inherit; text-decoration: none; text-align: left; font-size: 14px; line-height: 18px; font-weight: 400; background: transparent; border: 0; border-radius: var(--ss-radius-md, 7px); }
|
|
97
|
+
.menu-action + .menu-action { margin-block-start: 2px; }
|
|
98
|
+
.menu-action:hover { background: var(--ss-surface-field, oklch(0.958 0.001 255)); }
|
|
99
|
+
.menu-action:disabled { opacity: .45; cursor: default; }
|
|
100
|
+
.menu-action:disabled:hover { background: transparent; }
|
|
101
|
+
.notices { margin-top: 5px; padding: 5px 10px; color: var(--ss-text-tertiary, oklch(0.515 0.006 258.364)); border-top: 1px solid var(--ss-border-separator, oklch(0.958 0.001 255)); font-size: 12px; line-height: 16px; }
|
|
102
|
+
.notices p { margin: 4px 0; }
|
|
103
|
+
.notices button { padding: 0; color: inherit; background: none; border: 0; text-decoration: underline; }
|
|
104
|
+
.editor-panel { --ss-surface-page: var(--ss-surface-workspace, #fafafa); background: var(--ss-surface-page); border-radius: var(--ss-radius-bubble, 26px); pointer-events: auto; position: fixed; top: 0; left: 0; z-index: 1; }
|
|
105
|
+
/* Runtime roots carry theme defaults; their page ground belongs to this host. */
|
|
106
|
+
.editor-panel [data-ss-surface] { --ss-surface-page: inherit; }
|
|
107
|
+
.panel-contents { height: 100%; overflow: hidden; border-radius: inherit; display: grid; grid-template-rows: calc(2 * var(--ss-radius-bubble, 26px)) minmax(0, 1fr); }
|
|
108
|
+
.editor-panel[hidden] { display: none; }
|
|
109
|
+
/* The close control has an 18px radius; its inset keeps both curves concentric. */
|
|
110
|
+
.panel-header { display: flex; align-items: center; gap: 4px; padding: 0 calc(var(--ss-radius-bubble, 26px) - 18px); }
|
|
111
|
+
.panel-header > [data-ss-surface] { display: flex; flex: none; }
|
|
112
|
+
.panel-header > [data-ss-surface]:empty { display: none; }
|
|
113
|
+
.panel-drag-handle { min-width: 0; align-self: stretch; flex: 1; text-align: left; font-weight: 500; color: var(--ss-text-secondary, #52525b); background: none; border: 0; padding: 0; border-radius: 7px; touch-action: none; user-select: none; cursor: grab; }
|
|
114
|
+
.panel-title { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
115
|
+
.panel-title:empty::before { content: attr(data-placeholder); }
|
|
116
|
+
.panel-drag-handle:first-child, .panel-header > :empty + .panel-drag-handle { padding-inline-start: 10px; }
|
|
117
|
+
.panel-close { flex: none; width: 36px; height: 36px; display: grid; place-items: center; border: 0; border-radius: 999px; color: var(--ss-text-secondary, #52525b); background: none; }
|
|
118
|
+
.panel-close:hover { background: var(--ss-surface-field, #f4f4f5); }
|
|
119
|
+
.panel-body { position: relative; min-height: 0; display: grid; grid-template-rows: minmax(0, 1fr); }
|
|
120
|
+
.panel-resize-handle { --ss-resize-edge-inset: max(0px, calc(var(--ss-radius-bubble, 26px) - 12px)); position: absolute; z-index: 3; border: 0; padding: 0; background: transparent; touch-action: none; user-select: none; }
|
|
121
|
+
.panel-resize-handle:focus-visible { outline: 2px solid var(--ss-focus-color, oklch(0.614 0.194 257)); outline-offset: -2px; border-radius: 4px; }
|
|
122
|
+
.panel-resize-handle:is([data-resize-edge="n"], [data-resize-edge="s"]) { left: 12px; right: 12px; height: 8px; cursor: ns-resize; }
|
|
123
|
+
.panel-resize-handle:is([data-resize-edge="e"], [data-resize-edge="w"]) { top: 12px; bottom: 12px; width: 8px; cursor: ew-resize; }
|
|
124
|
+
.panel-resize-handle[data-resize-edge="n"] { top: -4px; }
|
|
125
|
+
.panel-resize-handle[data-resize-edge="s"] { bottom: -4px; }
|
|
126
|
+
.panel-resize-handle[data-resize-edge="e"] { right: -4px; }
|
|
127
|
+
.panel-resize-handle[data-resize-edge="w"] { left: -4px; }
|
|
128
|
+
.panel-resize-handle:is([data-resize-edge="ne"], [data-resize-edge="se"], [data-resize-edge="sw"], [data-resize-edge="nw"]) { width: 16px; height: 16px; }
|
|
129
|
+
.panel-resize-handle[data-resize-edge="ne"] { top: -4px; right: -4px; cursor: nesw-resize; }
|
|
130
|
+
.panel-resize-handle[data-resize-edge="se"] { bottom: -4px; right: -4px; cursor: nwse-resize; }
|
|
131
|
+
.panel-resize-handle[data-resize-edge="sw"] { bottom: -4px; left: -4px; cursor: nesw-resize; }
|
|
132
|
+
.panel-resize-handle[data-resize-edge="nw"] { top: -4px; left: -4px; cursor: nwse-resize; }
|
|
133
|
+
.bubble[data-dragging], .editor-panel[data-dragging] .panel-drag-handle { cursor: grabbing; }
|
|
134
|
+
.bubble[data-dragging] { transition: none; }
|
|
135
|
+
.editor-mount { min-height: 0; overflow: hidden; background: var(--ss-surface-page); }
|
|
136
|
+
.editor-mount > [data-storystick-authoring-root] { height: 100%; }
|
|
137
|
+
.editor-empty, .editor-loading { position: absolute; inset: 0; z-index: 2; display: grid; place-content: center; justify-items: center; padding: 24px; text-align: center; color: #52525b; background: var(--ss-surface-page); }
|
|
138
|
+
.panel-state-overlay { position: absolute; inset: 0; z-index: 2; min-height: 0; }
|
|
139
|
+
.editor-empty svg { width: 28px; height: 28px; margin-bottom: 12px; }
|
|
140
|
+
.editor-empty strong { color: #18181b; }
|
|
141
|
+
.editor-empty p { margin: 4px 0 0; }
|
|
142
|
+
.editor-loading { display: block; padding: 0; }
|
|
143
|
+
@media (prefers-reduced-motion: reduce) { .bubble { transition: none; } }
|
|
144
|
+
`;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type RichTextInlineProps as InternalRichTextInlineProps, type RichTextProps as InternalRichTextProps, type RichTextRenderMode } from './rich-text.js';
|
|
2
|
+
import type { RichTextComponentTypes, RichTextValue } from '@storystick/types';
|
|
3
|
+
export { toText } from './rich-text.js';
|
|
4
|
+
export type { RichTextCustomMarkComponentProps, RichTextBlockComponentProps, RichTextCodeComponentProps, RichTextComponents, RichTextLinkMarkComponentProps, RichTextListComponentProps, RichTextMarkComponentProps, RichTextNode, RichTextMark, RichTextOrderedListComponentProps, RichTextRenderMode, } from './rich-text.js';
|
|
5
|
+
export type RichTextProps<TContent = unknown, TMode extends RichTextRenderMode = 'permissive', TContext = unknown> = Omit<InternalRichTextProps<TContent, TMode, TContext>, 'sliceField' | 'parentPath' | 'parentAnchors' | 'content'> & {
|
|
6
|
+
content: TContent;
|
|
7
|
+
};
|
|
8
|
+
export type RichTextInlineProps<TContent extends RichTextValue<string, true, RichTextComponentTypes>, TMode extends RichTextRenderMode = 'permissive', TContext = unknown> = Omit<InternalRichTextInlineProps<TContent, TMode, TContext>, 'sliceField' | 'parentPath' | 'parentAnchors' | 'content'> & {
|
|
9
|
+
content: TContent | null | undefined;
|
|
10
|
+
};
|
|
11
|
+
declare function RichTextRoot<TContent = unknown, TMode extends RichTextRenderMode = 'permissive', TContext = unknown>(props: RichTextProps<TContent, TMode, TContext>): import("react").ReactNode;
|
|
12
|
+
declare function RichTextInline<TContent extends RichTextValue<string, true, RichTextComponentTypes>, TMode extends RichTextRenderMode = 'permissive', TContext = unknown>(props: RichTextInlineProps<TContent, TMode, TContext>): import("react").ReactNode;
|
|
13
|
+
export declare const RichText: typeof RichTextRoot & {
|
|
14
|
+
Inline: typeof RichTextInline;
|
|
15
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RichText as RenderRichText, } from './rich-text.js';
|
|
2
|
+
export { toText } from './rich-text.js';
|
|
3
|
+
function RichTextRoot(props) {
|
|
4
|
+
return RenderRichText(props);
|
|
5
|
+
}
|
|
6
|
+
function RichTextInline(props) {
|
|
7
|
+
return RenderRichText.Inline(props);
|
|
8
|
+
}
|
|
9
|
+
export const RichText = Object.assign(RichTextRoot, {
|
|
10
|
+
Inline: RichTextInline,
|
|
11
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { type SliceZoneProps as InternalSliceZoneProps, type SliceData } from './slice-zone.js';
|
|
3
|
+
import { ZoneSlot } from './slice-zone.js';
|
|
4
|
+
export { ZoneSlot };
|
|
5
|
+
export type { SliceComponentProps, SliceComponentRegistry, SliceContract, SliceContractRegistry, SliceData, SliceFallback, SliceRenderFailure, SliceRenderFailureHandler, ZoneSlotDescriptor, ZoneSlotKind, ZoneSlotProps, } from './slice-zone.js';
|
|
6
|
+
export type SliceZoneProps<TMap extends object = Record<string, SliceData>, TContext = unknown, TZones extends Record<string, ReactNode> = Record<string, ReactNode>> = Omit<InternalSliceZoneProps<TMap, TContext, TZones>, 'sliceField' | 'parentPath' | 'parentAnchors'>;
|
|
7
|
+
export declare function SliceZone<TMap extends object = Record<string, SliceData>, TContext = unknown, TZones extends Record<string, ReactNode> = Record<string, ReactNode>>(props: SliceZoneProps<TMap, TContext, TZones>): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { QueryClient, QueryObserver, type QueryKey, type QueryObserverOptions } from '@tanstack/query-core';
|
|
2
|
+
import type { Client } from '@storystick/client';
|
|
3
|
+
export declare const QUERY_GC_TIME_MS: number;
|
|
4
|
+
export declare function queryCoreClientFor(client: Client): QueryClient;
|
|
5
|
+
export declare function queryCacheKey(client: Client, canonical: string, locale: string, cursor: string | null, contextEpoch?: string): readonly unknown[];
|
|
6
|
+
export declare function createRefCountedObserver<TData, TError>(client: Client, options: QueryObserverOptions<TData, TError, TData, TData, QueryKey>): QueryObserver<TData, TError>;
|
|
7
|
+
export declare function subscribeRefCounted<TData, TError>(client: Client, observer: QueryObserver<TData, TError>, listener: () => void, targetingOwner?: Client): () => void;
|
|
8
|
+
export declare function registerPreviewQueryReceipt(owner: Client, executionClient: Client, queryKey: QueryKey, result: unknown): void;
|
|
9
|
+
export declare function previewQueryHasConfirmedCoverage(executionClient: Client, result: unknown): boolean;
|
|
10
|
+
export declare function previewQueryIsAwaitingTargetedProjection(executionClient: Client, result: unknown): boolean;
|
|
11
|
+
export declare function convergeQueryProjection(client: Client, queryKey: QueryKey, projectionHash: string): void;
|
|
12
|
+
export declare const __test: {
|
|
13
|
+
hasPreviewTargetingCoordinator(executionClient: Client): boolean;
|
|
14
|
+
};
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { getInternalClientRuntime } from '@storystick/client/internal';
|
|
2
|
+
import { QueryClient, QueryObserver, } from '@tanstack/query-core';
|
|
3
|
+
import { getPreviewQueryReceiptId } from '@storystick/client/internal';
|
|
4
|
+
import { getQueryPreviewState } from './query-preview-loader.js';
|
|
5
|
+
import { previewGenerationFor, } from './preview-generation.js';
|
|
6
|
+
const QUERY_CLIENTS = new WeakMap();
|
|
7
|
+
const OBSERVER_COUNTS = new WeakMap();
|
|
8
|
+
const PROJECTION_CONVERGENCE = new WeakMap();
|
|
9
|
+
const TARGETING_COORDINATORS = new WeakMap();
|
|
10
|
+
export const QUERY_GC_TIME_MS = 5 * 60 * 1_000;
|
|
11
|
+
export function queryCoreClientFor(client) {
|
|
12
|
+
const existing = QUERY_CLIENTS.get(client);
|
|
13
|
+
if (existing)
|
|
14
|
+
return existing;
|
|
15
|
+
const created = new QueryClient({
|
|
16
|
+
defaultOptions: {
|
|
17
|
+
queries: {
|
|
18
|
+
retry: false,
|
|
19
|
+
staleTime: Infinity,
|
|
20
|
+
gcTime: QUERY_GC_TIME_MS,
|
|
21
|
+
refetchOnMount: false,
|
|
22
|
+
refetchOnWindowFocus: false,
|
|
23
|
+
refetchOnReconnect: false,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
QUERY_CLIENTS.set(client, created);
|
|
28
|
+
return created;
|
|
29
|
+
}
|
|
30
|
+
export function queryCacheKey(client, canonical, locale, cursor, contextEpoch = getInternalClientRuntime(client).contextEpoch) {
|
|
31
|
+
return [
|
|
32
|
+
'storystick-query-v2',
|
|
33
|
+
client.projectId,
|
|
34
|
+
contextEpoch,
|
|
35
|
+
locale,
|
|
36
|
+
cursor,
|
|
37
|
+
canonical,
|
|
38
|
+
];
|
|
39
|
+
}
|
|
40
|
+
export function createRefCountedObserver(client, options) {
|
|
41
|
+
return new QueryObserver(queryCoreClientFor(client), options);
|
|
42
|
+
}
|
|
43
|
+
export function subscribeRefCounted(client, observer, listener, targetingOwner = client) {
|
|
44
|
+
const queryClient = queryCoreClientFor(client);
|
|
45
|
+
let counts = OBSERVER_COUNTS.get(queryClient);
|
|
46
|
+
if (!counts) {
|
|
47
|
+
counts = new Map();
|
|
48
|
+
OBSERVER_COUNTS.set(queryClient, counts);
|
|
49
|
+
}
|
|
50
|
+
const key = JSON.stringify(observer.options.queryKey);
|
|
51
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
52
|
+
const targeting = targetingOwner === client
|
|
53
|
+
? null
|
|
54
|
+
: previewTargetingCoordinator(targetingOwner, client);
|
|
55
|
+
targeting?.listeners.add(listener);
|
|
56
|
+
if (targeting)
|
|
57
|
+
retainPreviewTargeting(targetingOwner, client);
|
|
58
|
+
const unsubscribe = observer.subscribe(listener);
|
|
59
|
+
let active = true;
|
|
60
|
+
return () => {
|
|
61
|
+
if (!active)
|
|
62
|
+
return;
|
|
63
|
+
active = false;
|
|
64
|
+
unsubscribe();
|
|
65
|
+
const remaining = Math.max(0, (counts.get(key) ?? 1) - 1);
|
|
66
|
+
if (remaining === 0) {
|
|
67
|
+
counts.delete(key);
|
|
68
|
+
if (targeting)
|
|
69
|
+
unregisterPreviewQueryKey(targeting, key);
|
|
70
|
+
if (queryClient.isFetching({ queryKey: observer.options.queryKey, exact: true }) > 0) {
|
|
71
|
+
void queryClient.cancelQueries({ queryKey: observer.options.queryKey, exact: true });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
counts.set(key, remaining);
|
|
76
|
+
}
|
|
77
|
+
targeting?.listeners.delete(listener);
|
|
78
|
+
if (targeting)
|
|
79
|
+
releasePreviewTargeting(client);
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
export function registerPreviewQueryReceipt(owner, executionClient, queryKey, result) {
|
|
83
|
+
const coordinator = previewTargetingCoordinator(owner, executionClient);
|
|
84
|
+
const identity = JSON.stringify(queryKey);
|
|
85
|
+
const previous = coordinator.receiptByQuery.get(identity);
|
|
86
|
+
const receiptId = getPreviewQueryReceiptId(result);
|
|
87
|
+
if (previous === receiptId)
|
|
88
|
+
return;
|
|
89
|
+
if (previous) {
|
|
90
|
+
const previousQueries = coordinator.queriesByReceipt.get(previous);
|
|
91
|
+
previousQueries?.delete(identity);
|
|
92
|
+
if (previousQueries?.size === 0) {
|
|
93
|
+
coordinator.queriesByReceipt.delete(previous);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (!receiptId) {
|
|
97
|
+
coordinator.receiptByQuery.delete(identity);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
coordinator.receiptByQuery.set(identity, receiptId);
|
|
101
|
+
let queries = coordinator.queriesByReceipt.get(receiptId);
|
|
102
|
+
if (!queries) {
|
|
103
|
+
queries = new Map();
|
|
104
|
+
coordinator.queriesByReceipt.set(receiptId, queries);
|
|
105
|
+
}
|
|
106
|
+
queries.set(identity, queryKey);
|
|
107
|
+
}
|
|
108
|
+
export function previewQueryHasConfirmedCoverage(executionClient, result) {
|
|
109
|
+
const coordinator = TARGETING_COORDINATORS.get(queryCoreClientFor(executionClient));
|
|
110
|
+
const receiptId = getPreviewQueryReceiptId(result);
|
|
111
|
+
return receiptId !== null && coordinator?.covered.has(receiptId) === true;
|
|
112
|
+
}
|
|
113
|
+
export function previewQueryIsAwaitingTargetedProjection(executionClient, result) {
|
|
114
|
+
const coordinator = TARGETING_COORDINATORS.get(queryCoreClientFor(executionClient));
|
|
115
|
+
const receiptId = getPreviewQueryReceiptId(result);
|
|
116
|
+
return receiptId !== null &&
|
|
117
|
+
coordinator?.pendingEvent?.queryTargeting?.affectedQueryReceiptIds.includes(receiptId) === true;
|
|
118
|
+
}
|
|
119
|
+
export function convergeQueryProjection(client, queryKey, projectionHash) {
|
|
120
|
+
const queryClient = queryCoreClientFor(client);
|
|
121
|
+
const current = queryClient.getQueryData(queryKey);
|
|
122
|
+
const identity = JSON.stringify(queryKey);
|
|
123
|
+
if (current?.meta.projectionHash === projectionHash) {
|
|
124
|
+
PROJECTION_CONVERGENCE.get(queryClient)?.delete(identity);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
let pending = PROJECTION_CONVERGENCE.get(queryClient);
|
|
128
|
+
if (!pending) {
|
|
129
|
+
pending = new Map();
|
|
130
|
+
PROJECTION_CONVERGENCE.set(queryClient, pending);
|
|
131
|
+
}
|
|
132
|
+
const existing = pending.get(identity);
|
|
133
|
+
if (existing?.projectionHash === projectionHash) {
|
|
134
|
+
scheduleProjectionRefetch(queryClient, pending, identity, queryKey, existing);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const request = { projectionHash, attempted: false };
|
|
138
|
+
pending.set(identity, request);
|
|
139
|
+
scheduleProjectionRefetch(queryClient, pending, identity, queryKey, request);
|
|
140
|
+
}
|
|
141
|
+
function previewTargetingCoordinator(owner, executionClient) {
|
|
142
|
+
const queryClient = queryCoreClientFor(executionClient);
|
|
143
|
+
const existing = TARGETING_COORDINATORS.get(queryClient);
|
|
144
|
+
if (existing)
|
|
145
|
+
return existing;
|
|
146
|
+
const coordinator = {
|
|
147
|
+
receiptByQuery: new Map(),
|
|
148
|
+
queriesByReceipt: new Map(),
|
|
149
|
+
covered: new Set(),
|
|
150
|
+
retainCount: 0,
|
|
151
|
+
stopRuntime: null,
|
|
152
|
+
stopGeneration: null,
|
|
153
|
+
pendingEvent: null,
|
|
154
|
+
delivered: new Set(),
|
|
155
|
+
listeners: new Set(),
|
|
156
|
+
};
|
|
157
|
+
TARGETING_COORDINATORS.set(queryClient, coordinator);
|
|
158
|
+
return coordinator;
|
|
159
|
+
}
|
|
160
|
+
function retainPreviewTargeting(owner, executionClient) {
|
|
161
|
+
const queryClient = queryCoreClientFor(executionClient);
|
|
162
|
+
const coordinator = previewTargetingCoordinator(owner, executionClient);
|
|
163
|
+
coordinator.retainCount += 1;
|
|
164
|
+
if (coordinator.retainCount !== 1)
|
|
165
|
+
return;
|
|
166
|
+
const generation = previewGenerationFor(owner);
|
|
167
|
+
coordinator.stopRuntime = getQueryPreviewState().runtime?.previewRuntime.subscribeContentRefresh((event) => {
|
|
168
|
+
const targeting = event.queryTargeting;
|
|
169
|
+
coordinator.covered = targeting?.service === 'enabled'
|
|
170
|
+
? new Set(targeting.coveredQueryReceiptIds)
|
|
171
|
+
: new Set();
|
|
172
|
+
if (targeting?.service === 'enabled' &&
|
|
173
|
+
targeting.affectedQueryReceiptIds.length > 0) {
|
|
174
|
+
coordinator.pendingEvent = event;
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
coordinator.pendingEvent = null;
|
|
178
|
+
}
|
|
179
|
+
notifyPreviewTargeting(coordinator);
|
|
180
|
+
flushTargetedRefetches(queryClient, coordinator, generation.getSnapshot().signal);
|
|
181
|
+
}) ?? null;
|
|
182
|
+
coordinator.stopGeneration = generation.subscribe(() => {
|
|
183
|
+
flushTargetedRefetches(queryClient, coordinator, generation.getSnapshot().signal);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
function releasePreviewTargeting(executionClient) {
|
|
187
|
+
const queryClient = queryCoreClientFor(executionClient);
|
|
188
|
+
const coordinator = TARGETING_COORDINATORS.get(queryClient);
|
|
189
|
+
if (!coordinator)
|
|
190
|
+
return;
|
|
191
|
+
coordinator.retainCount = Math.max(0, coordinator.retainCount - 1);
|
|
192
|
+
if (coordinator.retainCount !== 0)
|
|
193
|
+
return;
|
|
194
|
+
coordinator.stopRuntime?.();
|
|
195
|
+
coordinator.stopGeneration?.();
|
|
196
|
+
coordinator.stopRuntime = null;
|
|
197
|
+
coordinator.stopGeneration = null;
|
|
198
|
+
coordinator.pendingEvent = null;
|
|
199
|
+
coordinator.covered = new Set();
|
|
200
|
+
coordinator.receiptByQuery.clear();
|
|
201
|
+
coordinator.queriesByReceipt.clear();
|
|
202
|
+
coordinator.delivered.clear();
|
|
203
|
+
notifyPreviewTargeting(coordinator);
|
|
204
|
+
}
|
|
205
|
+
function unregisterPreviewQueryKey(coordinator, identity) {
|
|
206
|
+
const receiptId = coordinator.receiptByQuery.get(identity);
|
|
207
|
+
if (!receiptId)
|
|
208
|
+
return;
|
|
209
|
+
coordinator.receiptByQuery.delete(identity);
|
|
210
|
+
const queries = coordinator.queriesByReceipt.get(receiptId);
|
|
211
|
+
queries?.delete(identity);
|
|
212
|
+
if (queries?.size === 0)
|
|
213
|
+
coordinator.queriesByReceipt.delete(receiptId);
|
|
214
|
+
}
|
|
215
|
+
function flushTargetedRefetches(queryClient, coordinator, generation) {
|
|
216
|
+
const event = coordinator.pendingEvent;
|
|
217
|
+
const targeting = event?.queryTargeting;
|
|
218
|
+
if (!event || targeting?.service !== 'enabled')
|
|
219
|
+
return;
|
|
220
|
+
const required = event.requiredProjectedThroughSeq;
|
|
221
|
+
if (generation?.status !== 'ready' ||
|
|
222
|
+
(required !== undefined &&
|
|
223
|
+
(generation.projectedThroughSeq ?? -1) < required))
|
|
224
|
+
return;
|
|
225
|
+
coordinator.pendingEvent = null;
|
|
226
|
+
notifyPreviewTargeting(coordinator);
|
|
227
|
+
for (const receiptId of targeting.affectedQueryReceiptIds) {
|
|
228
|
+
const deliveryIdentity = [
|
|
229
|
+
receiptId,
|
|
230
|
+
event.revision,
|
|
231
|
+
required ?? 'none',
|
|
232
|
+
].join('|');
|
|
233
|
+
if (coordinator.delivered.has(deliveryIdentity))
|
|
234
|
+
continue;
|
|
235
|
+
coordinator.delivered.add(deliveryIdentity);
|
|
236
|
+
const queries = coordinator.queriesByReceipt.get(receiptId);
|
|
237
|
+
if (!queries)
|
|
238
|
+
continue;
|
|
239
|
+
const observerCounts = OBSERVER_COUNTS.get(queryClient);
|
|
240
|
+
for (const [identity, queryKey] of queries) {
|
|
241
|
+
if ((observerCounts?.get(identity) ?? 0) > 0) {
|
|
242
|
+
void queryClient.refetchQueries({ queryKey, exact: true, type: 'active' }, { cancelRefetch: false });
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (coordinator.delivered.size > 512)
|
|
247
|
+
coordinator.delivered.clear();
|
|
248
|
+
}
|
|
249
|
+
function notifyPreviewTargeting(coordinator) {
|
|
250
|
+
for (const listener of coordinator.listeners)
|
|
251
|
+
listener();
|
|
252
|
+
}
|
|
253
|
+
function scheduleProjectionRefetch(queryClient, pending, identity, queryKey, request) {
|
|
254
|
+
void Promise.resolve().then(async () => {
|
|
255
|
+
if (pending.get(identity) !== request || request.attempted)
|
|
256
|
+
return;
|
|
257
|
+
let current = queryClient.getQueryData(queryKey);
|
|
258
|
+
if (current?.meta.projectionHash === request.projectionHash) {
|
|
259
|
+
pending.delete(identity);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (queryClient.isFetching({ queryKey, exact: true }) > 0) {
|
|
263
|
+
// Join initial loading first. That join is not the corrective refetch:
|
|
264
|
+
// compare its held result before spending the single repair attempt.
|
|
265
|
+
await queryClient.refetchQueries({ queryKey, exact: true, type: 'active' }, { cancelRefetch: false });
|
|
266
|
+
if (pending.get(identity) !== request)
|
|
267
|
+
return;
|
|
268
|
+
current = queryClient.getQueryData(queryKey);
|
|
269
|
+
if (current?.meta.projectionHash === request.projectionHash) {
|
|
270
|
+
pending.delete(identity);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (!current)
|
|
275
|
+
return;
|
|
276
|
+
request.attempted = true;
|
|
277
|
+
await queryClient.refetchQueries({ queryKey, exact: true, type: 'active' }, { cancelRefetch: false });
|
|
278
|
+
const resolved = queryClient.getQueryData(queryKey);
|
|
279
|
+
if (pending.get(identity) === request &&
|
|
280
|
+
resolved?.meta.projectionHash === request.projectionHash) {
|
|
281
|
+
pending.delete(identity);
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
export const __test = {
|
|
286
|
+
hasPreviewTargetingCoordinator(executionClient) {
|
|
287
|
+
return TARGETING_COORDINATORS.has(queryCoreClientFor(executionClient));
|
|
288
|
+
},
|
|
289
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { StorystickError } from '@storystick/client';
|
|
2
|
+
type Runtime = typeof import('./query-preview-runtime.js');
|
|
3
|
+
export declare const getQueryPreviewState: () => {
|
|
4
|
+
runtime: Runtime | null;
|
|
5
|
+
error: StorystickError | null;
|
|
6
|
+
};
|
|
7
|
+
export declare function subscribeQueryPreview(listener: () => void): () => void;
|
|
8
|
+
export declare function loadQueryPreview(): Promise<void>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { StorystickError } from '@storystick/client';
|
|
2
|
+
let snapshot = { runtime: null, error: null };
|
|
3
|
+
let pending = null;
|
|
4
|
+
const listeners = new Set();
|
|
5
|
+
export const getQueryPreviewState = () => snapshot;
|
|
6
|
+
export function subscribeQueryPreview(listener) {
|
|
7
|
+
listeners.add(listener);
|
|
8
|
+
return () => { listeners.delete(listener); };
|
|
9
|
+
}
|
|
10
|
+
export function loadQueryPreview() {
|
|
11
|
+
if (snapshot.runtime)
|
|
12
|
+
return Promise.resolve();
|
|
13
|
+
if (pending)
|
|
14
|
+
return pending;
|
|
15
|
+
snapshot = { runtime: null, error: null };
|
|
16
|
+
pending = import('./query-preview-runtime.js').then(runtime => {
|
|
17
|
+
snapshot = { runtime, error: null };
|
|
18
|
+
}, cause => {
|
|
19
|
+
snapshot = { runtime: null, error: new StorystickError('The Preview query runtime could not be loaded. Retry or reload Preview from Studio.', {
|
|
20
|
+
code: 'storystick/DELIVERY_UNAVAILABLE', category: 'system', retryable: true, payload: cause,
|
|
21
|
+
}) };
|
|
22
|
+
}).finally(() => {
|
|
23
|
+
pending = null;
|
|
24
|
+
for (const listener of listeners)
|
|
25
|
+
listener();
|
|
26
|
+
});
|
|
27
|
+
return pending;
|
|
28
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { previewRuntime } from '@storystick/preview/runtime/store';
|
|
2
|
+
export { applyPreviewLiveQueryProjection, previewLiveQueryOverlay } from '@storystick/preview/runtime/live-query-overlay';
|
|
3
|
+
export { estimatePreviewPayloadBytes, recordPreviewPerfMetric } from '@storystick/preview/runtime/perf-metrics';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { previewRuntime } from '@storystick/preview/runtime/store';
|
|
2
|
+
export { applyPreviewLiveQueryProjection, previewLiveQueryOverlay } from '@storystick/preview/runtime/live-query-overlay';
|
|
3
|
+
export { estimatePreviewPayloadBytes, recordPreviewPerfMetric } from '@storystick/preview/runtime/perf-metrics';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export { stripPreviewProvenance } from '@storystick/types/preview-provenance';
|
|
2
|
+
export { previewTextProps } from './preview-text-props.js';
|
|
3
|
+
export type { PreviewTextProps, PreviewTextValue } from './preview-text-props.js';
|
|
4
|
+
/**
|
|
5
|
+
* @storystick/react — rendering primitives for typed Storystick content.
|
|
6
|
+
*
|
|
7
|
+
* Client reads use `useQuery` from `@storystick/react/query`, without a provider.
|
|
8
|
+
* Next server reads use `site.client()` from a configured `createSite`; mount
|
|
9
|
+
* `<Storystick />` from `@storystick/next` once in a shared native layout.
|
|
10
|
+
*/
|
|
11
|
+
export { createClient, QueryExecutionError, resolveReference, resolveReferences, resolveSafeHref, safeHref, StorystickError, } from '@storystick/client';
|
|
12
|
+
export type { Client, ClientOptions, QueryResult, SelectedDocument, StorystickErrorCategory, StorystickErrorOptions, } from '@storystick/client';
|
|
13
|
+
export type { UseQueryOptions, UseQueryResult } from './use-generated-query.js';
|
|
14
|
+
export { SliceZone, ZoneSlot } from './public-slice-zone.js';
|
|
15
|
+
export type { SliceZoneProps, SliceData, SliceComponentRegistry, SliceComponentProps, SliceContract, SliceContractRegistry, SliceFallback, SliceRenderFailure, SliceRenderFailureHandler, ZoneSlotDescriptor, ZoneSlotKind, ZoneSlotProps, } from './public-slice-zone.js';
|
|
16
|
+
export { Slice } from './slice.js';
|
|
17
|
+
export type { SliceElements, SliceRootProps } from './slice.js';
|
|
18
|
+
export { RichText, toText } from './public-rich-text.js';
|
|
19
|
+
export type { RichTextCustomMarkComponentProps, RichTextBlockComponentProps, RichTextCodeComponentProps, RichTextComponents, RichTextInlineProps, RichTextLinkMarkComponentProps, RichTextListComponentProps, RichTextMarkComponentProps, RichTextOrderedListComponentProps, RichTextProps, RichTextNode, RichTextMark, RichTextRenderMode, } from './public-rich-text.js';
|
|
20
|
+
export { StorystickLink, resolveLink } from './link.js';
|
|
21
|
+
export type { StorystickLinkDocument, StorystickLinkOptions, StorystickLinkProps, StorystickLinkValue, } from './link.js';
|
|
22
|
+
export { StorystickImage, resolveImage } from './image.js';
|
|
23
|
+
export type { ImageStatus, ResolveImageOptions, ResolvedStorystickImage, StorystickAsset, StorystickAssetSidecar, StorystickImageField, StorystickImageProps, } from '@storystick/media';
|
|
24
|
+
export type { StorystickImageComponentProps, StorystickImageFailure, StorystickImageFallback, } from './image.js';
|
|
25
|
+
export { StorystickFile, resolveFile } from './file.js';
|
|
26
|
+
export type { FileStatus, ResolveFileOptions, ResolvedStorystickFile, StorystickFileComponentProps, StorystickFileFailure, StorystickFileFallback, StorystickFileField, StorystickFileProps, } from './file.js';
|
|
27
|
+
export { StorystickVideo, resolveVideo } from './video.js';
|
|
28
|
+
export type { ResolvedStorystickVideo, ResolvedStorystickVideoPoster, ResolvedStorystickVideoTrack, ResolveVideoOptions, StorystickVideoComponentProps, StorystickVideoFailure, StorystickVideoFallback, StorystickVideoField, StorystickVideoProps, StorystickVideoTrack, StorystickVideoTrackProps, VideoPosterStatus, VideoStatus, VideoTrackStatus, } from './video.js';
|
|
29
|
+
export type { LinkOptions, LinkProps, LinkStatus, LinkValue, ReferencedDocumentFailureReason, ReferencedDocumentPolicy, ReferencedDocumentSidecarEntry, ReferencedDocumentSidecarFailure, ReferencedDocumentsSidecar, ResolvedLink, } from '@storystick/types';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { stripPreviewProvenance } from '@storystick/types/preview-provenance';
|
|
2
|
+
export { previewTextProps } from './preview-text-props.js';
|
|
3
|
+
/**
|
|
4
|
+
* @storystick/react — rendering primitives for typed Storystick content.
|
|
5
|
+
*
|
|
6
|
+
* Client reads use `useQuery` from `@storystick/react/query`, without a provider.
|
|
7
|
+
* Next server reads use `site.client()` from a configured `createSite`; mount
|
|
8
|
+
* `<Storystick />` from `@storystick/next` once in a shared native layout.
|
|
9
|
+
*/
|
|
10
|
+
export { createClient, QueryExecutionError, resolveReference, resolveReferences, resolveSafeHref, safeHref, StorystickError, } from '@storystick/client';
|
|
11
|
+
export { SliceZone, ZoneSlot } from './public-slice-zone.js';
|
|
12
|
+
export { Slice } from './slice.js';
|
|
13
|
+
export { RichText, toText } from './public-rich-text.js';
|
|
14
|
+
export { StorystickLink, resolveLink } from './link.js';
|
|
15
|
+
export { StorystickImage, resolveImage } from './image.js';
|
|
16
|
+
export { StorystickFile, resolveFile } from './file.js';
|
|
17
|
+
export { StorystickVideo, resolveVideo } from './video.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
/** Passive border ink. Hosts own hit areas and geometry; native pointer/focus
|
|
3
|
+
* states own visibility. Inline CSS also works before the editor loads and
|
|
4
|
+
* inside the detached toolbar's ShadowRoot. */
|
|
5
|
+
export declare function ResizeEdgeIndicator({ orientation, style, }: {
|
|
6
|
+
orientation?: 'vertical' | 'horizontal';
|
|
7
|
+
style?: CSSProperties;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/** Passive border ink. Hosts own hit areas and geometry; native pointer/focus
|
|
3
|
+
* states own visibility. Inline CSS also works before the editor loads and
|
|
4
|
+
* inside the detached toolbar's ShadowRoot. */
|
|
5
|
+
export function ResizeEdgeIndicator({ orientation = 'vertical', style, }) {
|
|
6
|
+
return _jsxs(_Fragment, { children: [_jsx("style", { children: RESIZE_EDGE_STYLES }), _jsx("span", { "aria-hidden": "true", "data-ss-resize-border": orientation, style: style })] });
|
|
7
|
+
}
|
|
8
|
+
const RESIZE_EDGE_STYLES = `
|
|
9
|
+
[data-ss-resize-border] {
|
|
10
|
+
position: absolute;
|
|
11
|
+
pointer-events: none;
|
|
12
|
+
background: linear-gradient(
|
|
13
|
+
var(--ss-resize-edge-direction, to bottom),
|
|
14
|
+
transparent 0 var(--ss-resize-edge-inset, 0px),
|
|
15
|
+
color-mix(in srgb, var(--ss-text-primary, #16181b) 18%, transparent) 50%,
|
|
16
|
+
transparent calc(100% - var(--ss-resize-edge-inset, 0px)) 100%
|
|
17
|
+
);
|
|
18
|
+
opacity: 0;
|
|
19
|
+
transition: opacity 120ms ease;
|
|
20
|
+
}
|
|
21
|
+
[data-ss-resize-border="vertical"] { inset: 0 auto 0 0; width: 1px; }
|
|
22
|
+
[data-ss-resize-border="horizontal"] {
|
|
23
|
+
--ss-resize-edge-direction: to right;
|
|
24
|
+
inset: 0 0 auto 0;
|
|
25
|
+
height: 1px;
|
|
26
|
+
}
|
|
27
|
+
[data-ss-resize-handle]:is(:hover, :focus-visible, :active, [data-resizable-split-dragging]) > [data-ss-resize-border] {
|
|
28
|
+
opacity: 1;
|
|
29
|
+
}
|
|
30
|
+
@media (prefers-reduced-motion: reduce) {
|
|
31
|
+
[data-ss-resize-border] { transition: none; }
|
|
32
|
+
}
|
|
33
|
+
`;
|