@paulpaulstudio/strapi-render 0.4.1 → 0.5.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/dist/index.cjs +65 -163
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -24
- package/dist/index.d.ts +39 -24
- package/dist/index.js +65 -165
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4,29 +4,25 @@
|
|
|
4
4
|
var react = require('react');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
|
|
7
|
+
var EDIT_SESSION_KEY = "__pp_edit_session";
|
|
7
8
|
var noop = () => {
|
|
8
9
|
};
|
|
9
10
|
var EditModeContext = react.createContext({
|
|
10
11
|
enabled: false,
|
|
11
12
|
token: null,
|
|
12
|
-
|
|
13
|
-
isDirty: false,
|
|
14
|
-
isCommitting: false,
|
|
15
|
-
lastCommitError: null,
|
|
16
|
-
setChange: noop,
|
|
17
|
-
clearChange: noop,
|
|
18
|
-
commit: noop,
|
|
13
|
+
publishChange: noop,
|
|
19
14
|
openMediaPicker: noop,
|
|
20
15
|
onMediaPicked: () => noop
|
|
21
16
|
});
|
|
17
|
+
var ContentScopeContext = react.createContext(null);
|
|
22
18
|
function useStrapiEditMode() {
|
|
23
19
|
return react.useContext(EditModeContext);
|
|
24
20
|
}
|
|
21
|
+
function useContentScope() {
|
|
22
|
+
return react.useContext(ContentScopeContext);
|
|
23
|
+
}
|
|
25
24
|
function StrapiEditModeProvider({ children, enabled: enabledOverride }) {
|
|
26
25
|
const [urlState, setUrlState] = react.useState({ enabled: false, token: null });
|
|
27
|
-
const [changes, setChanges] = react.useState(/* @__PURE__ */ new Map());
|
|
28
|
-
const [isCommitting, setIsCommitting] = react.useState(false);
|
|
29
|
-
const [lastCommitError, setLastCommitError] = react.useState(null);
|
|
30
26
|
const mediaPickListeners = react.useRef(/* @__PURE__ */ new Map());
|
|
31
27
|
react.useEffect(() => {
|
|
32
28
|
if (typeof window === "undefined") return;
|
|
@@ -36,9 +32,15 @@ function StrapiEditModeProvider({ children, enabled: enabledOverride }) {
|
|
|
36
32
|
}
|
|
37
33
|
try {
|
|
38
34
|
const params = new URLSearchParams(window.location.search);
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
|
|
35
|
+
const urlEdit = params.get("__pp_edit") === "1";
|
|
36
|
+
const sessionFlag = window.sessionStorage.getItem(EDIT_SESSION_KEY) === "1";
|
|
37
|
+
const enabled = urlEdit || sessionFlag;
|
|
38
|
+
if (urlEdit) {
|
|
39
|
+
window.sessionStorage.setItem(EDIT_SESSION_KEY, "1");
|
|
40
|
+
}
|
|
41
|
+
const token = params.get("__pp_token") ?? window.sessionStorage.getItem("__pp_edit_token");
|
|
42
|
+
if (token) window.sessionStorage.setItem("__pp_edit_token", token);
|
|
43
|
+
setUrlState({ enabled, token });
|
|
42
44
|
} catch {
|
|
43
45
|
}
|
|
44
46
|
}, [enabledOverride]);
|
|
@@ -65,14 +67,9 @@ function StrapiEditModeProvider({ children, enabled: enabledOverride }) {
|
|
|
65
67
|
window.location.reload();
|
|
66
68
|
return;
|
|
67
69
|
}
|
|
68
|
-
if (d.type === "pp:edit:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
setChanges(/* @__PURE__ */ new Map());
|
|
72
|
-
setLastCommitError(null);
|
|
73
|
-
} else {
|
|
74
|
-
setLastCommitError(d.error || "Speichern fehlgeschlagen");
|
|
75
|
-
}
|
|
70
|
+
if (d.type === "pp:edit:exit") {
|
|
71
|
+
window.sessionStorage.removeItem(EDIT_SESSION_KEY);
|
|
72
|
+
window.location.reload();
|
|
76
73
|
return;
|
|
77
74
|
}
|
|
78
75
|
if (d.type === "pp:edit:media-picked") {
|
|
@@ -87,58 +84,12 @@ function StrapiEditModeProvider({ children, enabled: enabledOverride }) {
|
|
|
87
84
|
window.addEventListener("message", onMsg);
|
|
88
85
|
return () => window.removeEventListener("message", onMsg);
|
|
89
86
|
}, [urlState.enabled]);
|
|
90
|
-
const
|
|
91
|
-
setChanges((prev) => {
|
|
92
|
-
const next = new Map(prev);
|
|
93
|
-
next.set(path, { path, fieldType, value: value2 });
|
|
94
|
-
return next;
|
|
95
|
-
});
|
|
96
|
-
setLastCommitError(null);
|
|
97
|
-
if (typeof window !== "undefined" && window.parent !== window) {
|
|
98
|
-
try {
|
|
99
|
-
window.parent.postMessage({ type: "pp:edit:change", path, fieldType, value: value2 }, "*");
|
|
100
|
-
} catch {
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}, []);
|
|
104
|
-
const clearChange = react.useCallback((path) => {
|
|
105
|
-
setChanges((prev) => {
|
|
106
|
-
const next = new Map(prev);
|
|
107
|
-
next.delete(path);
|
|
108
|
-
return next;
|
|
109
|
-
});
|
|
87
|
+
const publishChange = react.useCallback((_path, _fieldType, _value) => {
|
|
110
88
|
}, []);
|
|
111
|
-
const commit = react.useCallback(() => {
|
|
112
|
-
if (changes.size === 0) return;
|
|
113
|
-
if (typeof window === "undefined" || window.parent === window) return;
|
|
114
|
-
setIsCommitting(true);
|
|
115
|
-
setLastCommitError(null);
|
|
116
|
-
try {
|
|
117
|
-
window.parent.postMessage(
|
|
118
|
-
{
|
|
119
|
-
type: "pp:edit:commit-request",
|
|
120
|
-
changes: Array.from(changes.values())
|
|
121
|
-
},
|
|
122
|
-
"*"
|
|
123
|
-
);
|
|
124
|
-
} catch (err) {
|
|
125
|
-
setIsCommitting(false);
|
|
126
|
-
setLastCommitError(err instanceof Error ? err.message : String(err));
|
|
127
|
-
}
|
|
128
|
-
}, [changes]);
|
|
129
89
|
const openMediaPicker = react.useCallback((path, multiple, allowedTypes, currentValue) => {
|
|
130
90
|
if (typeof window === "undefined" || window.parent === window) return;
|
|
131
91
|
try {
|
|
132
|
-
window.parent.postMessage(
|
|
133
|
-
{
|
|
134
|
-
type: "pp:edit:open-media-picker",
|
|
135
|
-
path,
|
|
136
|
-
multiple,
|
|
137
|
-
allowedTypes,
|
|
138
|
-
currentValue
|
|
139
|
-
},
|
|
140
|
-
"*"
|
|
141
|
-
);
|
|
92
|
+
window.parent.postMessage({ type: "pp:edit:open-media-picker", path, multiple, allowedTypes, currentValue }, "*");
|
|
142
93
|
} catch {
|
|
143
94
|
}
|
|
144
95
|
}, []);
|
|
@@ -151,98 +102,34 @@ function StrapiEditModeProvider({ children, enabled: enabledOverride }) {
|
|
|
151
102
|
const value = react.useMemo(() => ({
|
|
152
103
|
enabled: urlState.enabled,
|
|
153
104
|
token: urlState.token,
|
|
154
|
-
|
|
155
|
-
isDirty: changes.size > 0,
|
|
156
|
-
isCommitting,
|
|
157
|
-
lastCommitError,
|
|
158
|
-
setChange,
|
|
159
|
-
clearChange,
|
|
160
|
-
commit,
|
|
105
|
+
publishChange,
|
|
161
106
|
openMediaPicker,
|
|
162
107
|
onMediaPicked
|
|
163
|
-
}), [urlState,
|
|
164
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
165
|
-
children,
|
|
166
|
-
urlState.enabled && /* @__PURE__ */ jsxRuntime.jsx(SaveBar, {})
|
|
167
|
-
] });
|
|
108
|
+
}), [urlState, publishChange, openMediaPicker, onMediaPicked]);
|
|
109
|
+
return /* @__PURE__ */ jsxRuntime.jsx(EditModeContext.Provider, { value, children });
|
|
168
110
|
}
|
|
169
|
-
function
|
|
170
|
-
const {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}, children: lastCommitError }),
|
|
192
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
193
|
-
"button",
|
|
194
|
-
{
|
|
195
|
-
type: "button",
|
|
196
|
-
onClick: commit,
|
|
197
|
-
disabled: isCommitting || !isDirty,
|
|
198
|
-
style: {
|
|
199
|
-
background: isCommitting ? "#666" : "#000",
|
|
200
|
-
color: "#EBC6DF",
|
|
201
|
-
border: "2px solid #000",
|
|
202
|
-
padding: "14px 22px",
|
|
203
|
-
fontSize: 13,
|
|
204
|
-
fontWeight: 700,
|
|
205
|
-
textTransform: "uppercase",
|
|
206
|
-
letterSpacing: "0.2em",
|
|
207
|
-
cursor: isCommitting ? "wait" : "pointer",
|
|
208
|
-
display: "flex",
|
|
209
|
-
alignItems: "center",
|
|
210
|
-
gap: 10,
|
|
211
|
-
boxShadow: "0 4px 12px rgba(0,0,0,0.3)",
|
|
212
|
-
transition: "background 0.15s ease"
|
|
213
|
-
},
|
|
214
|
-
onMouseEnter: (e) => {
|
|
215
|
-
if (!isCommitting && isDirty) {
|
|
216
|
-
e.currentTarget.style.background = "#FA501E";
|
|
217
|
-
e.currentTarget.style.color = "#000";
|
|
218
|
-
}
|
|
219
|
-
},
|
|
220
|
-
onMouseLeave: (e) => {
|
|
221
|
-
if (!isCommitting && isDirty) {
|
|
222
|
-
e.currentTarget.style.background = "#000";
|
|
223
|
-
e.currentTarget.style.color = "#EBC6DF";
|
|
224
|
-
}
|
|
225
|
-
},
|
|
226
|
-
children: isCommitting ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Speichere\u2026" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
227
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: {
|
|
228
|
-
background: "#FA501E",
|
|
229
|
-
color: "#000",
|
|
230
|
-
width: 22,
|
|
231
|
-
height: 22,
|
|
232
|
-
borderRadius: "50%",
|
|
233
|
-
display: "inline-flex",
|
|
234
|
-
alignItems: "center",
|
|
235
|
-
justifyContent: "center",
|
|
236
|
-
fontSize: 11,
|
|
237
|
-
fontWeight: 700
|
|
238
|
-
}, children: changes.size }),
|
|
239
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Speichern" })
|
|
240
|
-
] })
|
|
241
|
-
}
|
|
242
|
-
)
|
|
243
|
-
]
|
|
244
|
-
}
|
|
245
|
-
);
|
|
111
|
+
function StrapiContent({ uid, kind, documentId, children }) {
|
|
112
|
+
const scope = react.useMemo(() => ({ uid, kind, documentId }), [uid, kind, documentId]);
|
|
113
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ContentScopeContext.Provider, { value: scope, children });
|
|
114
|
+
}
|
|
115
|
+
function postEditChange(scope, path, fieldType, value) {
|
|
116
|
+
if (typeof window === "undefined" || window.parent === window) return;
|
|
117
|
+
if (!scope) {
|
|
118
|
+
console.warn("[strapi-render] Feld ohne <StrapiContent>-Scope \u2014 Save wird nicht funktionieren. Wickle deine Seite mit <StrapiContent uid='...' kind='...'> ein.");
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
window.parent.postMessage({
|
|
123
|
+
type: "pp:edit:change",
|
|
124
|
+
uid: scope.uid,
|
|
125
|
+
kind: scope.kind,
|
|
126
|
+
documentId: scope.documentId,
|
|
127
|
+
path,
|
|
128
|
+
fieldType,
|
|
129
|
+
value
|
|
130
|
+
}, "*");
|
|
131
|
+
} catch {
|
|
132
|
+
}
|
|
246
133
|
}
|
|
247
134
|
var EDITABLE_TYPES = /* @__PURE__ */ new Set([
|
|
248
135
|
"text",
|
|
@@ -254,6 +141,7 @@ var EDITABLE_TYPES = /* @__PURE__ */ new Set([
|
|
|
254
141
|
var HOVER_OUTLINE_COLOR = "#FA501E";
|
|
255
142
|
function StrapiField({ path, type, value, children, className }) {
|
|
256
143
|
const ctx = useStrapiEditMode();
|
|
144
|
+
const scope = useContentScope();
|
|
257
145
|
const ref = react.useRef(null);
|
|
258
146
|
const initialText = react.useRef(void 0);
|
|
259
147
|
react.useEffect(() => {
|
|
@@ -309,7 +197,7 @@ function StrapiField({ path, type, value, children, className }) {
|
|
|
309
197
|
const original = typeof value === "string" ? value : initialText.current ?? "";
|
|
310
198
|
if (newText !== original) {
|
|
311
199
|
const newValue = type === "number" ? newText === "" ? null : Number(newText) : newText;
|
|
312
|
-
|
|
200
|
+
postEditChange(scope, path, type, newValue);
|
|
313
201
|
}
|
|
314
202
|
};
|
|
315
203
|
props.onKeyDown = (e) => {
|
|
@@ -349,6 +237,7 @@ function resolveUrl(value, baseUrl) {
|
|
|
349
237
|
var HOVER_OUTLINE_COLOR2 = "#FA501E";
|
|
350
238
|
function StrapiImage({ path, value, baseUrl, alt, className, style, loading = "lazy", fallback, allowedTypes, multiple = false, width, height, draggable }) {
|
|
351
239
|
const ctx = useStrapiEditMode();
|
|
240
|
+
const scope = useContentScope();
|
|
352
241
|
const containerRef = react.useRef(null);
|
|
353
242
|
const imgRef = react.useRef(null);
|
|
354
243
|
const handleClick = (e) => {
|
|
@@ -356,7 +245,7 @@ function StrapiImage({ path, value, baseUrl, alt, className, style, loading = "l
|
|
|
356
245
|
e.preventDefault();
|
|
357
246
|
e.stopPropagation();
|
|
358
247
|
const unsubscribe = ctx.onMediaPicked(path, (picked) => {
|
|
359
|
-
|
|
248
|
+
postEditChange(scope, path, "media", picked);
|
|
360
249
|
unsubscribe();
|
|
361
250
|
if (imgRef.current && picked && typeof picked === "object" && !Array.isArray(picked) && "url" in picked) {
|
|
362
251
|
imgRef.current.src = resolveUrl(picked, baseUrl);
|
|
@@ -421,7 +310,16 @@ function StrapiImage({ path, value, baseUrl, alt, className, style, loading = "l
|
|
|
421
310
|
ref: containerRef,
|
|
422
311
|
"data-pp-edit": path,
|
|
423
312
|
"data-pp-type": "media",
|
|
424
|
-
style: {
|
|
313
|
+
style: {
|
|
314
|
+
position: "relative",
|
|
315
|
+
display: "block",
|
|
316
|
+
// Wrapper ist block-level damit das innere img mit className w-full / h-[60vh] etc.
|
|
317
|
+
// die korrekte Größe ausfüllt. Im Read-Mode (kein Wrapper) hatte das img direkt
|
|
318
|
+
// diese Größe — beim Wrap mit inline-block-span schrumpfte das.
|
|
319
|
+
outline: "1px dashed transparent",
|
|
320
|
+
outlineOffset: 2,
|
|
321
|
+
transition: "outline-color 0.15s ease"
|
|
322
|
+
},
|
|
425
323
|
onMouseEnter: (e) => {
|
|
426
324
|
e.currentTarget.style.outlineColor = HOVER_OUTLINE_COLOR2;
|
|
427
325
|
const btn = e.currentTarget.querySelector("[data-pp-edit-btn]");
|
|
@@ -578,6 +476,7 @@ function parseBlocksFromDOM(root) {
|
|
|
578
476
|
}
|
|
579
477
|
function StrapiBlocks({ path, value, className }) {
|
|
580
478
|
const ctx = useStrapiEditMode();
|
|
479
|
+
const scope = useContentScope();
|
|
581
480
|
const containerRef = react.useRef(null);
|
|
582
481
|
const initialValue = react.useRef(null);
|
|
583
482
|
const blocks = Array.isArray(value) ? value : [];
|
|
@@ -618,7 +517,7 @@ function StrapiBlocks({ path, value, className }) {
|
|
|
618
517
|
const before = JSON.stringify(initialValue.current);
|
|
619
518
|
const after = JSON.stringify(parsed);
|
|
620
519
|
if (before !== after) {
|
|
621
|
-
|
|
520
|
+
postEditChange(scope, path, "blocks", parsed);
|
|
622
521
|
}
|
|
623
522
|
e.currentTarget.style.outlineColor = "transparent";
|
|
624
523
|
e.currentTarget.style.outlineStyle = "dashed";
|
|
@@ -630,6 +529,7 @@ function StrapiBlocks({ path, value, className }) {
|
|
|
630
529
|
var HOVER_OUTLINE2 = "#FA501E";
|
|
631
530
|
function StrapiMarkdownField({ path, value, render, className, minRows = 12 }) {
|
|
632
531
|
const ctx = useStrapiEditMode();
|
|
532
|
+
const scope = useContentScope();
|
|
633
533
|
const [draft, setDraft] = react.useState(value ?? "");
|
|
634
534
|
const initial = react.useRef(value ?? "");
|
|
635
535
|
react.useEffect(() => {
|
|
@@ -647,7 +547,7 @@ function StrapiMarkdownField({ path, value, render, className, minRows = 12 }) {
|
|
|
647
547
|
onChange: (e) => setDraft(e.target.value),
|
|
648
548
|
onBlur: () => {
|
|
649
549
|
if (draft !== initial.current) {
|
|
650
|
-
|
|
550
|
+
postEditChange(scope, path, "richText", draft);
|
|
651
551
|
}
|
|
652
552
|
},
|
|
653
553
|
onFocus: (e) => {
|
|
@@ -696,12 +596,14 @@ function StrapiMarkdownField({ path, value, render, className, minRows = 12 }) {
|
|
|
696
596
|
}
|
|
697
597
|
|
|
698
598
|
exports.StrapiBlocks = StrapiBlocks;
|
|
599
|
+
exports.StrapiContent = StrapiContent;
|
|
699
600
|
exports.StrapiEditModeProvider = StrapiEditModeProvider;
|
|
700
601
|
exports.StrapiField = StrapiField;
|
|
701
602
|
exports.StrapiImage = StrapiImage;
|
|
702
603
|
exports.StrapiList = StrapiList;
|
|
703
604
|
exports.StrapiMarkdownField = StrapiMarkdownField;
|
|
704
605
|
exports.StrapiText = StrapiText;
|
|
606
|
+
exports.useContentScope = useContentScope;
|
|
705
607
|
exports.useStrapiEditMode = useStrapiEditMode;
|
|
706
608
|
//# sourceMappingURL=index.cjs.map
|
|
707
609
|
//# sourceMappingURL=index.cjs.map
|