@paulpaulstudio/strapi-render 0.4.0 → 0.5.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.
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
- changes: /* @__PURE__ */ new Map(),
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 edit = params.get("__pp_edit") === "1";
40
- const token = params.get("__pp_token");
41
- setUrlState({ enabled: edit, token });
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:commit-result") {
69
- setIsCommitting(false);
70
- if (d.ok) {
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 setChange = react.useCallback((path, fieldType, value2) => {
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
- changes,
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, changes, isCommitting, lastCommitError, setChange, clearChange, commit, openMediaPicker, onMediaPicked]);
164
- return /* @__PURE__ */ jsxRuntime.jsxs(EditModeContext.Provider, { value, children: [
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 SaveBar() {
170
- const { isDirty, isCommitting, lastCommitError, changes, commit } = useStrapiEditMode();
171
- if (!isDirty && !lastCommitError && !isCommitting) return null;
172
- return /* @__PURE__ */ jsxRuntime.jsxs(
173
- "div",
174
- {
175
- style: {
176
- position: "fixed",
177
- bottom: 24,
178
- right: 24,
179
- zIndex: 999999,
180
- fontFamily: "system-ui, -apple-system, sans-serif"
181
- },
182
- children: [
183
- lastCommitError && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
184
- background: "#FA501E",
185
- color: "#000",
186
- padding: "8px 14px",
187
- marginBottom: 8,
188
- fontSize: 13,
189
- fontWeight: 600,
190
- maxWidth: 320
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
- ctx.setChange(path, type, newValue);
200
+ postEditChange(scope, path, type, newValue);
313
201
  }
314
202
  };
315
203
  props.onKeyDown = (e) => {
@@ -347,8 +235,9 @@ function resolveUrl(value, baseUrl) {
347
235
  return value.url;
348
236
  }
349
237
  var HOVER_OUTLINE_COLOR2 = "#FA501E";
350
- function StrapiImage({ path, value, baseUrl, alt, className, style, loading = "lazy", fallback, allowedTypes, multiple = false }) {
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
- ctx.setChange(path, "media", picked);
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);
@@ -406,11 +295,12 @@ function StrapiImage({ path, value, baseUrl, alt, className, style, loading = "l
406
295
  ref: imgRef,
407
296
  src: resolveUrl(value, baseUrl),
408
297
  alt: alt ?? value.alternativeText ?? value.name ?? "",
409
- width: value.width,
410
- height: value.height,
298
+ width: width ?? value.width,
299
+ height: height ?? value.height,
411
300
  loading,
412
301
  className,
413
- style
302
+ style,
303
+ draggable
414
304
  }
415
305
  );
416
306
  if (!ctx.enabled) return imgEl;
@@ -577,6 +467,7 @@ function parseBlocksFromDOM(root) {
577
467
  }
578
468
  function StrapiBlocks({ path, value, className }) {
579
469
  const ctx = useStrapiEditMode();
470
+ const scope = useContentScope();
580
471
  const containerRef = react.useRef(null);
581
472
  const initialValue = react.useRef(null);
582
473
  const blocks = Array.isArray(value) ? value : [];
@@ -617,7 +508,7 @@ function StrapiBlocks({ path, value, className }) {
617
508
  const before = JSON.stringify(initialValue.current);
618
509
  const after = JSON.stringify(parsed);
619
510
  if (before !== after) {
620
- ctx.setChange(path, "blocks", parsed);
511
+ postEditChange(scope, path, "blocks", parsed);
621
512
  }
622
513
  e.currentTarget.style.outlineColor = "transparent";
623
514
  e.currentTarget.style.outlineStyle = "dashed";
@@ -629,6 +520,7 @@ function StrapiBlocks({ path, value, className }) {
629
520
  var HOVER_OUTLINE2 = "#FA501E";
630
521
  function StrapiMarkdownField({ path, value, render, className, minRows = 12 }) {
631
522
  const ctx = useStrapiEditMode();
523
+ const scope = useContentScope();
632
524
  const [draft, setDraft] = react.useState(value ?? "");
633
525
  const initial = react.useRef(value ?? "");
634
526
  react.useEffect(() => {
@@ -646,7 +538,7 @@ function StrapiMarkdownField({ path, value, render, className, minRows = 12 }) {
646
538
  onChange: (e) => setDraft(e.target.value),
647
539
  onBlur: () => {
648
540
  if (draft !== initial.current) {
649
- ctx.setChange(path, "richText", draft);
541
+ postEditChange(scope, path, "richText", draft);
650
542
  }
651
543
  },
652
544
  onFocus: (e) => {
@@ -695,12 +587,14 @@ function StrapiMarkdownField({ path, value, render, className, minRows = 12 }) {
695
587
  }
696
588
 
697
589
  exports.StrapiBlocks = StrapiBlocks;
590
+ exports.StrapiContent = StrapiContent;
698
591
  exports.StrapiEditModeProvider = StrapiEditModeProvider;
699
592
  exports.StrapiField = StrapiField;
700
593
  exports.StrapiImage = StrapiImage;
701
594
  exports.StrapiList = StrapiList;
702
595
  exports.StrapiMarkdownField = StrapiMarkdownField;
703
596
  exports.StrapiText = StrapiText;
597
+ exports.useContentScope = useContentScope;
704
598
  exports.useStrapiEditMode = useStrapiEditMode;
705
599
  //# sourceMappingURL=index.cjs.map
706
600
  //# sourceMappingURL=index.cjs.map