dune-react 0.0.10 → 0.0.11
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/components/puck-base/article-card.js +1 -1
- package/dist/components/puck-base/button.d.ts +0 -1
- package/dist/components/puck-base/button.js +3 -3
- package/dist/components/puck-base/card.js +0 -1
- package/dist/components/puck-base/content.js +0 -1
- package/dist/components/puck-base/core/fields.d.ts +1 -23
- package/dist/components/puck-base/core/fields.js +6 -7
- package/dist/components/puck-base/core/styles.d.ts +102 -33
- package/dist/components/puck-base/core/styles.js +45 -81
- package/dist/components/puck-base/core/with-editable.d.ts +4 -9
- package/dist/components/puck-base/core/with-editable.js +43 -62
- package/dist/components/puck-base/{action-field.d.ts → fields/action-field.d.ts} +1 -1
- package/dist/components/puck-base/{action-field.js → fields/action-field.js} +91 -16
- package/dist/components/puck-base/fields/auto-field.d.ts +0 -1
- package/dist/components/puck-base/fields/auto-field.js +2 -90
- package/dist/components/puck-base/form.js +0 -1
- package/dist/components/puck-base/index.d.ts +1 -1
- package/dist/components/puck-base/navigation-menu.d.ts +18 -0
- package/dist/components/puck-base/navigation-menu.js +202 -0
- package/dist/components/puck-block/cta-sections/banner-cta-1/banner-cta.d.ts +2 -1
- package/dist/components/puck-block/cta-sections/banner-cta-1/banner-cta.js +6 -5
- package/dist/components/puck-block/cta-sections/banner-cta-1/index.js +2 -2
- package/dist/components/puck-block/cta-sections/gradient-cta-1/gradient-cta.js +34 -12
- package/dist/components/puck-block/cta-sections/promo-section-1/index.js +1 -2
- package/dist/components/puck-block/cta-sections/promo-section-1/promo-section.js +2 -2
- package/dist/components/puck-block/faq-sections/accordion-1/accordion.js +8 -3
- package/dist/components/puck-block/feature-sections/feature-cards-1/index.js +0 -2
- package/dist/components/puck-block/feature-sections/icon-grid-1/icon-grid.js +1 -1
- package/dist/components/puck-block/gallery-sections/gallery-1/index.js +1 -1
- package/dist/components/puck-block/gallery-sections/gallery-2/gallery-2.js +14 -6
- package/dist/components/puck-block/gallery-sections/gallery-2/index.js +1 -1
- package/dist/components/puck-block/header-sections/header-1/header.d.ts +4 -1
- package/dist/components/puck-block/header-sections/header-1/header.js +26 -19
- package/dist/components/puck-block/header-sections/header-1/index.js +13 -18
- package/dist/components/puck-block/hero-sections/fullscreen-hero-1/fullscreen-hero.js +15 -2
- package/dist/components/puck-block/hero-sections/fullscreen-hero-1/index.js +0 -1
- package/dist/components/puck-block/hero-sections/gradient-hero-1/gradient-hero.js +2 -2
- package/dist/components/puck-block/hero-sections/gradient-hero-1/index.js +1 -0
- package/dist/components/puck-block/hero-sections/grid-hero-1/grid-hero.js +1 -1
- package/dist/components/puck-block/hero-sections/hero-1/hero.js +1 -1
- package/dist/components/puck-block/hero-sections/image-hero-1/image-hero.d.ts +0 -1
- package/dist/components/puck-block/hero-sections/image-hero-1/image-hero.js +1 -1
- package/dist/components/puck-block/hero-sections/image-hero-1/index.js +21 -4
- package/dist/components/puck-block/hero-sections/video-hero-1/video-hero.js +1 -1
- package/dist/components/puck-block/location-sections/location-1/index.js +0 -3
- package/dist/components/puck-block/location-sections/location-1/location.d.ts +1 -0
- package/dist/components/puck-block/location-sections/location-1/location.js +1 -2
- package/dist/components/puck-block/location-sections/location-2/index.js +0 -3
- package/dist/components/puck-block/location-sections/location-2/location.d.ts +1 -0
- package/dist/components/puck-block/location-sections/location-2/location.js +1 -2
- package/dist/components/puck-block/location-sections/location-3/location.d.ts +2 -0
- package/dist/components/puck-block/location-sections/location-3/location.js +5 -2
- package/dist/components/puck-block/metrics-sections/stats-2/index.js +0 -2
- package/dist/components/puck-block/metrics-sections/stats-2/stats-2.js +0 -1
- package/dist/components/puck-block/metrics-sections/stats-3/index.js +0 -2
- package/dist/components/puck-block/metrics-sections/stats-3/stats-3.js +14 -1
- package/dist/components/puck-block/pricing-sections/pricing-1/index.js +0 -2
- package/dist/components/puck-block/pricing-sections/pricing-2/index.js +0 -4
- package/dist/components/puck-block/showcase-sections/before-after-1/index.js +0 -1
- package/dist/components/puck-block/showcase-sections/case-study-1/case-study.js +1 -1
- package/dist/components/puck-block/showcase-sections/case-study-1/index.js +1 -1
- package/dist/components/puck-block/team-sections/team-grid-1/index.js +1 -1
- package/dist/components/puck-block/team-sections/team-grid-2/index.js +0 -2
- package/dist/components/puck-block/testimonial-sections/logo-marquee-1/index.js +1 -1
- package/dist/components/puck-block/testimonial-sections/logo-marquee-1/logo-marquee.js +1 -1
- package/dist/components/puck-block/testimonial-sections/review-section-1/index.js +1 -1
- package/dist/components/puck-block/testimonial-sections/testimonials-1/testimonials.js +30 -10
- package/dist/components/puck-block/text-sections/articles-1/articles.js +1 -1
- package/dist/components/puck-block/text-sections/articles-1/index.js +1 -2
- package/dist/components/puck-block/text-sections/content-section-1/content-section.js +0 -1
- package/dist/components/puck-block/text-sections/content-section-1/index.js +0 -2
- package/dist/components/puck-block/text-sections/tab-section-1/tab-section.js +7 -3
- package/dist/components/shadcn/navigation-menu.js +8 -33
- package/dist/index.js +1 -1
- package/package.json +2 -2
|
@@ -6,23 +6,12 @@ const paddingLevel = {
|
|
|
6
6
|
{ label: "medium", value: "medium" },
|
|
7
7
|
{ label: "large", value: "large" }
|
|
8
8
|
],
|
|
9
|
-
ai: {
|
|
10
|
-
instructions: "Never select none as an option"
|
|
11
|
-
}
|
|
9
|
+
ai: { instructions: "Never select none as an option" }
|
|
12
10
|
};
|
|
13
11
|
const padding = {
|
|
14
12
|
type: "object",
|
|
15
|
-
objectFields: {
|
|
16
|
-
|
|
17
|
-
bottom: paddingLevel
|
|
18
|
-
},
|
|
19
|
-
ai: {
|
|
20
|
-
exclude: true
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
const paddingDefaults = {
|
|
24
|
-
top: "medium",
|
|
25
|
-
bottom: "medium"
|
|
13
|
+
objectFields: { top: paddingLevel, bottom: paddingLevel },
|
|
14
|
+
ai: { exclude: true }
|
|
26
15
|
};
|
|
27
16
|
const sectionStyle = {
|
|
28
17
|
type: "select",
|
|
@@ -38,19 +27,6 @@ const sectionStyle = {
|
|
|
38
27
|
instructions: "Match the section's background tone: use 'dark' for dark/black backgrounds, 'muted' for gray/subtle backgrounds, 'inverted' for full contrast reversal. Default for standard light backgrounds."
|
|
39
28
|
}
|
|
40
29
|
};
|
|
41
|
-
const sectionOverlay = {
|
|
42
|
-
type: "select",
|
|
43
|
-
label: "Overlay",
|
|
44
|
-
options: [
|
|
45
|
-
{ label: "None", value: "none" },
|
|
46
|
-
{ label: "Gradient Top", value: "gradient-top" },
|
|
47
|
-
{ label: "Gradient Bottom", value: "gradient-bottom" },
|
|
48
|
-
{ label: "Noise", value: "noise" }
|
|
49
|
-
],
|
|
50
|
-
ai: {
|
|
51
|
-
instructions: "Use gradient overlays when the section has a background image that needs text contrast. Use noise for subtle texture."
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
30
|
const backgroundColor = {
|
|
55
31
|
type: "text",
|
|
56
32
|
label: "Background Color",
|
|
@@ -66,12 +42,28 @@ const backgroundImage = {
|
|
|
66
42
|
stream: false
|
|
67
43
|
}
|
|
68
44
|
};
|
|
45
|
+
const sectionOverlay = {
|
|
46
|
+
type: "select",
|
|
47
|
+
label: "Overlay",
|
|
48
|
+
options: [
|
|
49
|
+
{ label: "None", value: "none" },
|
|
50
|
+
{ label: "Gradient Top", value: "gradient-top" },
|
|
51
|
+
{ label: "Gradient Bottom", value: "gradient-bottom" },
|
|
52
|
+
{ label: "Noise", value: "noise" }
|
|
53
|
+
],
|
|
54
|
+
ai: {
|
|
55
|
+
instructions: "Use gradient overlays when the section has a background image that needs text contrast. Use noise for subtle texture."
|
|
56
|
+
}
|
|
57
|
+
};
|
|
69
58
|
const sectionBaseStyleFields = {
|
|
70
59
|
sectionStyle,
|
|
71
60
|
backgroundColor,
|
|
72
61
|
padding
|
|
73
62
|
};
|
|
63
|
+
const paddingDefaults = { top: "medium", bottom: "medium" };
|
|
74
64
|
const sectionBaseStyleDefaults = {
|
|
65
|
+
sectionStyle: "default",
|
|
66
|
+
backgroundColor: "",
|
|
75
67
|
padding: paddingDefaults
|
|
76
68
|
};
|
|
77
69
|
function createStylesField(extraFields) {
|
|
@@ -90,11 +82,8 @@ function createStylesDefaults(extraDefaults) {
|
|
|
90
82
|
...extraDefaults
|
|
91
83
|
};
|
|
92
84
|
}
|
|
93
|
-
const
|
|
94
|
-
textColor: {
|
|
95
|
-
type: "text",
|
|
96
|
-
label: "Text Color"
|
|
97
|
-
},
|
|
85
|
+
const bannerStylesField = createStylesField({
|
|
86
|
+
textColor: { type: "text", label: "Text Color" },
|
|
98
87
|
align: {
|
|
99
88
|
type: "radio",
|
|
100
89
|
options: [
|
|
@@ -110,10 +99,9 @@ const bannerExtraFields = {
|
|
|
110
99
|
{ label: "Default", value: "default" }
|
|
111
100
|
]
|
|
112
101
|
}
|
|
113
|
-
};
|
|
114
|
-
const bannerStylesField = createStylesField(bannerExtraFields);
|
|
102
|
+
});
|
|
115
103
|
const bannerStylesDefaults = createStylesDefaults();
|
|
116
|
-
|
|
104
|
+
createStylesField({
|
|
117
105
|
backgroundImage,
|
|
118
106
|
overlay: sectionOverlay,
|
|
119
107
|
align: {
|
|
@@ -132,10 +120,9 @@ const heroExtraFields = {
|
|
|
132
120
|
{ label: "Full", value: "full" }
|
|
133
121
|
]
|
|
134
122
|
}
|
|
135
|
-
};
|
|
136
|
-
const heroStylesField = createStylesField(heroExtraFields);
|
|
123
|
+
});
|
|
137
124
|
const heroStylesDefaults = createStylesDefaults();
|
|
138
|
-
|
|
125
|
+
createStylesField({
|
|
139
126
|
layout: {
|
|
140
127
|
type: "radio",
|
|
141
128
|
label: "Layout",
|
|
@@ -144,10 +131,9 @@ const ctaExtraFields = {
|
|
|
144
131
|
{ label: "Full Bleed", value: "full-bleed" }
|
|
145
132
|
]
|
|
146
133
|
}
|
|
147
|
-
};
|
|
148
|
-
createStylesField(ctaExtraFields);
|
|
134
|
+
});
|
|
149
135
|
createStylesDefaults();
|
|
150
|
-
|
|
136
|
+
createStylesField({
|
|
151
137
|
columns: {
|
|
152
138
|
type: "select",
|
|
153
139
|
label: "Columns",
|
|
@@ -157,10 +143,9 @@ const featureExtraFields = {
|
|
|
157
143
|
{ label: "4", value: 4 }
|
|
158
144
|
]
|
|
159
145
|
}
|
|
160
|
-
};
|
|
161
|
-
createStylesField(featureExtraFields);
|
|
146
|
+
});
|
|
162
147
|
createStylesDefaults();
|
|
163
|
-
|
|
148
|
+
createStylesField({
|
|
164
149
|
layout: {
|
|
165
150
|
type: "radio",
|
|
166
151
|
label: "Layout",
|
|
@@ -169,10 +154,9 @@ const faqExtraFields = {
|
|
|
169
154
|
{ label: "Two Columns", value: "two-col" }
|
|
170
155
|
]
|
|
171
156
|
}
|
|
172
|
-
};
|
|
173
|
-
createStylesField(faqExtraFields);
|
|
157
|
+
});
|
|
174
158
|
createStylesDefaults();
|
|
175
|
-
|
|
159
|
+
createStylesField({
|
|
176
160
|
gap: {
|
|
177
161
|
type: "select",
|
|
178
162
|
label: "Gap",
|
|
@@ -182,10 +166,9 @@ const galleryExtraFields = {
|
|
|
182
166
|
{ label: "Large", value: "lg" }
|
|
183
167
|
]
|
|
184
168
|
}
|
|
185
|
-
};
|
|
186
|
-
createStylesField(galleryExtraFields);
|
|
169
|
+
});
|
|
187
170
|
createStylesDefaults();
|
|
188
|
-
|
|
171
|
+
createStylesField({
|
|
189
172
|
layout: {
|
|
190
173
|
type: "radio",
|
|
191
174
|
label: "Layout",
|
|
@@ -194,12 +177,9 @@ const testimonialExtraFields = {
|
|
|
194
177
|
{ label: "Quote", value: "quote" }
|
|
195
178
|
]
|
|
196
179
|
}
|
|
197
|
-
};
|
|
198
|
-
createStylesField(
|
|
199
|
-
testimonialExtraFields
|
|
200
|
-
);
|
|
180
|
+
});
|
|
201
181
|
createStylesDefaults();
|
|
202
|
-
|
|
182
|
+
createStylesField({
|
|
203
183
|
layout: {
|
|
204
184
|
type: "select",
|
|
205
185
|
label: "Layout",
|
|
@@ -209,10 +189,9 @@ const showcaseExtraFields = {
|
|
|
209
189
|
{ label: "Numbered", value: "numbered" }
|
|
210
190
|
]
|
|
211
191
|
}
|
|
212
|
-
};
|
|
213
|
-
createStylesField(showcaseExtraFields);
|
|
192
|
+
});
|
|
214
193
|
createStylesDefaults();
|
|
215
|
-
|
|
194
|
+
createStylesField({
|
|
216
195
|
maxWidth: {
|
|
217
196
|
type: "select",
|
|
218
197
|
label: "Max Width",
|
|
@@ -223,10 +202,9 @@ const textExtraFields = {
|
|
|
223
202
|
{ label: "Full", value: "full" }
|
|
224
203
|
]
|
|
225
204
|
}
|
|
226
|
-
};
|
|
227
|
-
createStylesField(textExtraFields);
|
|
205
|
+
});
|
|
228
206
|
createStylesDefaults();
|
|
229
|
-
|
|
207
|
+
createStylesField({
|
|
230
208
|
panelStyle: {
|
|
231
209
|
type: "select",
|
|
232
210
|
label: "Panel Style",
|
|
@@ -236,26 +214,13 @@ const contactExtraFields = {
|
|
|
236
214
|
{ label: "Flat", value: "flat" }
|
|
237
215
|
]
|
|
238
216
|
}
|
|
239
|
-
};
|
|
240
|
-
createStylesField(contactExtraFields);
|
|
217
|
+
});
|
|
241
218
|
createStylesDefaults();
|
|
242
|
-
|
|
243
|
-
mapHeight: {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
max: 800
|
|
248
|
-
},
|
|
249
|
-
mapFilter: {
|
|
250
|
-
type: "text",
|
|
251
|
-
label: "Map Filter (CSS)"
|
|
252
|
-
},
|
|
253
|
-
mapTintColor: {
|
|
254
|
-
type: "text",
|
|
255
|
-
label: "Map Tint Color"
|
|
256
|
-
}
|
|
257
|
-
};
|
|
258
|
-
createStylesField(locationExtraFields);
|
|
219
|
+
createStylesField({
|
|
220
|
+
mapHeight: { type: "number", label: "Map Height", min: 200, max: 800 },
|
|
221
|
+
mapFilter: { type: "text", label: "Map Filter (CSS)" },
|
|
222
|
+
mapTintColor: { type: "text", label: "Map Tint Color" }
|
|
223
|
+
});
|
|
259
224
|
createStylesDefaults();
|
|
260
225
|
createStylesField();
|
|
261
226
|
createStylesDefaults();
|
|
@@ -275,7 +240,6 @@ export {
|
|
|
275
240
|
createStylesDefaults,
|
|
276
241
|
createStylesField,
|
|
277
242
|
heroStylesDefaults,
|
|
278
|
-
heroStylesField,
|
|
279
243
|
padding,
|
|
280
244
|
paddingDefaults,
|
|
281
245
|
paddingLevel,
|
|
@@ -4,16 +4,11 @@ interface EditableConfig {
|
|
|
4
4
|
fields: Record<string, any>;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
|
-
* HOC:
|
|
7
|
+
* HOC: wraps any component to be inline-editable in Puck editor mode.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* 3. 点击打开 Dialog,传递 onSave 回调
|
|
13
|
-
* 4. 保存时用 dispatch 更新 Puck data
|
|
14
|
-
*
|
|
15
|
-
* Puck hooks (usePuckDispatch / usePuckAppState) 仅在 EditableInner 中调用,
|
|
16
|
-
* 确保非编辑模式(如 Storybook / 前台渲染)不会触发 "usePuck must be used inside <Puck>" 错误。
|
|
9
|
+
* Location strategy:
|
|
10
|
+
* 1. componentId — read from the nearest `[data-puck-component]` ancestor in the DOM.
|
|
11
|
+
* 2. propPath — search only within that single component's props (narrow scope).
|
|
17
12
|
*/
|
|
18
13
|
export declare function withEditable<P extends Record<string, any>>(Component: ComponentType<P>, config: EditableConfig): (props: P & {
|
|
19
14
|
onEdit?: (props: P, onSave: (updated: Partial<P>) => void) => void;
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useRef, useEffect,
|
|
3
|
+
import { useRef, useEffect, useCallback } from "react";
|
|
4
4
|
import { registerOverlayPortal } from "@puckeditor/core";
|
|
5
5
|
import { usePuckDispatch, usePuckAppState } from "./hooks.js";
|
|
6
6
|
import { Pencil } from "lucide-react";
|
|
7
7
|
import { useEditorContext } from "../editor-context.js";
|
|
8
8
|
import set from "../../../node_modules/.pnpm/lodash-es@4.17.23/node_modules/lodash-es/set.js";
|
|
9
9
|
const BLOCK_LEVEL_TYPES = /* @__PURE__ */ new Set(["image"]);
|
|
10
|
+
function getComponentIdFromDOM(el) {
|
|
11
|
+
if (!el) return null;
|
|
12
|
+
const puckEl = el.closest("[data-puck-component]");
|
|
13
|
+
return (puckEl == null ? void 0 : puckEl.getAttribute("data-puck-component")) ?? null;
|
|
14
|
+
}
|
|
10
15
|
function withEditable(Component, config) {
|
|
11
16
|
function EditableInner(props) {
|
|
12
17
|
const dispatch = usePuckDispatch();
|
|
@@ -17,29 +22,36 @@ function withEditable(Component, config) {
|
|
|
17
22
|
if (!wrapperRef.current) return;
|
|
18
23
|
return registerOverlayPortal(wrapperRef.current, { disableDrag: true });
|
|
19
24
|
}, []);
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
const getLocation = useCallback(() => {
|
|
26
|
+
const componentId = getComponentIdFromDOM(wrapperRef.current);
|
|
27
|
+
if (!componentId || !(appState == null ? void 0 : appState.data)) return null;
|
|
28
|
+
const component = findComponentById(appState.data, componentId);
|
|
29
|
+
if (!component) return null;
|
|
30
|
+
const propPath = findPropPath(component.props, props, config.fields);
|
|
31
|
+
if (propPath === null) return null;
|
|
32
|
+
return { componentId, propPath };
|
|
23
33
|
}, [appState == null ? void 0 : appState.data, props]);
|
|
24
34
|
const handleSave = useCallback(
|
|
25
35
|
(updated) => {
|
|
36
|
+
const location = getLocation();
|
|
26
37
|
if (!location) return;
|
|
27
38
|
dispatch({
|
|
28
39
|
type: "setData",
|
|
29
40
|
data: (prevData) => {
|
|
30
41
|
const newData = JSON.parse(JSON.stringify(prevData));
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
42
|
+
const id = getComponentIdFromDOM(wrapperRef.current);
|
|
43
|
+
console.log(id, "ididid");
|
|
44
|
+
const comp = findComponentById(newData, location.componentId);
|
|
45
|
+
if (!comp) return prevData;
|
|
34
46
|
for (const [key, value] of Object.entries(updated)) {
|
|
35
|
-
const fullPath = propPath ? `${propPath}.${key}` : key;
|
|
36
|
-
set(
|
|
47
|
+
const fullPath = location.propPath ? `${location.propPath}.${key}` : key;
|
|
48
|
+
set(comp.props, fullPath, value);
|
|
37
49
|
}
|
|
38
50
|
return newData;
|
|
39
51
|
}
|
|
40
52
|
});
|
|
41
53
|
},
|
|
42
|
-
[
|
|
54
|
+
[getLocation, dispatch]
|
|
43
55
|
);
|
|
44
56
|
const handleEdit = useCallback(
|
|
45
57
|
(e) => {
|
|
@@ -78,82 +90,51 @@ function withEditable(Component, config) {
|
|
|
78
90
|
return /* @__PURE__ */ jsx(EditableInner, { ...props });
|
|
79
91
|
};
|
|
80
92
|
}
|
|
81
|
-
function
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
component.props.id
|
|
90
|
-
);
|
|
91
|
-
if (result) return result;
|
|
92
|
-
}
|
|
93
|
-
const zones = data.zones && typeof data.zones === "object" ? data.zones : {};
|
|
93
|
+
function findComponentById(data, componentId) {
|
|
94
|
+
const content = Array.isArray(data == null ? void 0 : data.content) ? data.content : [];
|
|
95
|
+
const contentMatch = content.find((c) => {
|
|
96
|
+
var _a;
|
|
97
|
+
return ((_a = c == null ? void 0 : c.props) == null ? void 0 : _a.id) === componentId;
|
|
98
|
+
});
|
|
99
|
+
if (contentMatch) return contentMatch;
|
|
100
|
+
const zones = (data == null ? void 0 : data.zones) && typeof data.zones === "object" ? data.zones : {};
|
|
94
101
|
for (const zoneKey of Object.keys(zones)) {
|
|
95
102
|
const zoneComponents = Array.isArray(zones[zoneKey]) ? zones[zoneKey] : [];
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (result) return result;
|
|
104
|
-
}
|
|
103
|
+
const zoneMatch = zoneComponents.find(
|
|
104
|
+
(c) => {
|
|
105
|
+
var _a;
|
|
106
|
+
return ((_a = c == null ? void 0 : c.props) == null ? void 0 : _a.id) === componentId;
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
if (zoneMatch) return zoneMatch;
|
|
105
110
|
}
|
|
106
111
|
return null;
|
|
107
112
|
}
|
|
108
|
-
function
|
|
113
|
+
function findPropPath(obj, targetProps, fields, currentPath = "") {
|
|
109
114
|
if (!obj || typeof obj !== "object") return null;
|
|
110
115
|
if (isMatchingProps(obj, targetProps, fields)) {
|
|
111
|
-
return
|
|
116
|
+
return currentPath;
|
|
112
117
|
}
|
|
113
118
|
if (Array.isArray(obj)) {
|
|
114
119
|
for (let i = 0; i < obj.length; i++) {
|
|
115
|
-
const result =
|
|
120
|
+
const result = findPropPath(
|
|
116
121
|
obj[i],
|
|
117
122
|
targetProps,
|
|
118
123
|
fields,
|
|
119
|
-
componentId,
|
|
120
124
|
currentPath ? `${currentPath}[${i}]` : `[${i}]`
|
|
121
125
|
);
|
|
122
|
-
if (result) return result;
|
|
126
|
+
if (result !== null) return result;
|
|
123
127
|
}
|
|
124
128
|
return null;
|
|
125
129
|
}
|
|
126
130
|
for (const key of Object.keys(obj)) {
|
|
127
|
-
const result =
|
|
131
|
+
const result = findPropPath(
|
|
128
132
|
obj[key],
|
|
129
133
|
targetProps,
|
|
130
134
|
fields,
|
|
131
|
-
componentId,
|
|
132
135
|
currentPath ? `${currentPath}.${key}` : key
|
|
133
136
|
);
|
|
134
|
-
if (result) return result;
|
|
135
|
-
}
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
function findComponentById(data, componentId) {
|
|
139
|
-
const content = Array.isArray(data == null ? void 0 : data.content) ? data.content : [];
|
|
140
|
-
const contentMatch = content.find(
|
|
141
|
-
(component) => {
|
|
142
|
-
var _a;
|
|
143
|
-
return ((_a = component == null ? void 0 : component.props) == null ? void 0 : _a.id) === componentId;
|
|
144
|
-
}
|
|
145
|
-
);
|
|
146
|
-
if (contentMatch) return contentMatch;
|
|
147
|
-
const zones = (data == null ? void 0 : data.zones) && typeof data.zones === "object" ? data.zones : {};
|
|
148
|
-
for (const zoneKey of Object.keys(zones)) {
|
|
149
|
-
const zoneComponents = Array.isArray(zones[zoneKey]) ? zones[zoneKey] : [];
|
|
150
|
-
const zoneMatch = zoneComponents.find(
|
|
151
|
-
(component) => {
|
|
152
|
-
var _a;
|
|
153
|
-
return ((_a = component == null ? void 0 : component.props) == null ? void 0 : _a.id) === componentId;
|
|
154
|
-
}
|
|
155
|
-
);
|
|
156
|
-
if (zoneMatch) return zoneMatch;
|
|
137
|
+
if (result !== null) return result;
|
|
157
138
|
}
|
|
158
139
|
return null;
|
|
159
140
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { memo, useCallback } from "react";
|
|
4
|
+
import { Input } from "../../shadcn/input.js";
|
|
5
|
+
import { Button } from "../../shadcn/button.js";
|
|
6
|
+
import { Label } from "../../shadcn/label.js";
|
|
7
|
+
import { Tabs, TabsList, TabsTrigger } from "../../shadcn/tabs.js";
|
|
8
|
+
import { LinkIcon, XIcon, ClipboardIcon, GlobeIcon } from "lucide-react";
|
|
9
|
+
import { useEditorContext } from "../editor-context.js";
|
|
6
10
|
const ACTION_TYPE_OPTIONS = [
|
|
7
11
|
{ label: "Page Link", value: "page" },
|
|
8
12
|
{ label: "External Link", value: "external" },
|
|
@@ -12,6 +16,82 @@ const ACTION_TYPE_OPTIONS = [
|
|
|
12
16
|
{ label: "Download", value: "download" },
|
|
13
17
|
{ label: "None", value: "none" }
|
|
14
18
|
];
|
|
19
|
+
const PageUrlField = memo(function PageUrlField2({
|
|
20
|
+
name,
|
|
21
|
+
value,
|
|
22
|
+
onChange
|
|
23
|
+
}) {
|
|
24
|
+
const { sitePages } = useEditorContext();
|
|
25
|
+
const pages = sitePages ?? [];
|
|
26
|
+
const selectedSlug = value.startsWith("/") ? value.slice(1) : null;
|
|
27
|
+
const handlePaste = useCallback(async () => {
|
|
28
|
+
try {
|
|
29
|
+
const text = await navigator.clipboard.readText();
|
|
30
|
+
if (text) onChange(text.trim());
|
|
31
|
+
} catch {
|
|
32
|
+
}
|
|
33
|
+
}, [onChange]);
|
|
34
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
35
|
+
/* @__PURE__ */ jsx(Label, { children: "Page URL" }),
|
|
36
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
37
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-center gap-2 rounded-lg border px-3 py-2", children: [
|
|
38
|
+
/* @__PURE__ */ jsx(LinkIcon, { className: "text-muted-foreground size-4 shrink-0" }),
|
|
39
|
+
/* @__PURE__ */ jsx(
|
|
40
|
+
"input",
|
|
41
|
+
{
|
|
42
|
+
name: `${name}.pageUrl`,
|
|
43
|
+
className: "w-full bg-transparent text-sm outline-none placeholder:text-muted-foreground",
|
|
44
|
+
placeholder: "/about",
|
|
45
|
+
value,
|
|
46
|
+
onChange: (e) => onChange(e.target.value)
|
|
47
|
+
}
|
|
48
|
+
),
|
|
49
|
+
value && /* @__PURE__ */ jsx(
|
|
50
|
+
"button",
|
|
51
|
+
{
|
|
52
|
+
type: "button",
|
|
53
|
+
className: "text-muted-foreground hover:text-foreground shrink-0",
|
|
54
|
+
onClick: () => onChange(""),
|
|
55
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "size-3.5" })
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
] }),
|
|
59
|
+
/* @__PURE__ */ jsxs(
|
|
60
|
+
Button,
|
|
61
|
+
{
|
|
62
|
+
type: "button",
|
|
63
|
+
variant: "outline",
|
|
64
|
+
size: "sm",
|
|
65
|
+
className: "shrink-0 gap-1.5",
|
|
66
|
+
onClick: handlePaste,
|
|
67
|
+
children: [
|
|
68
|
+
/* @__PURE__ */ jsx(ClipboardIcon, { className: "size-3.5" }),
|
|
69
|
+
"Paste"
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
] }),
|
|
74
|
+
pages.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
75
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs font-medium", children: "Site pages" }),
|
|
76
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: pages.map((page) => {
|
|
77
|
+
const isSelected = selectedSlug === page.slug;
|
|
78
|
+
return /* @__PURE__ */ jsxs(
|
|
79
|
+
"button",
|
|
80
|
+
{
|
|
81
|
+
type: "button",
|
|
82
|
+
className: `inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs font-medium transition-colors ${isSelected ? "border-primary bg-primary text-primary-foreground" : "border-border bg-background text-foreground hover:bg-accent"}`,
|
|
83
|
+
onClick: () => onChange(isSelected ? "" : `${page.slug}`),
|
|
84
|
+
children: [
|
|
85
|
+
/* @__PURE__ */ jsx(GlobeIcon, { className: "size-3" }),
|
|
86
|
+
page.label
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
page.slug
|
|
90
|
+
);
|
|
91
|
+
}) })
|
|
92
|
+
] })
|
|
93
|
+
] });
|
|
94
|
+
});
|
|
15
95
|
function ActionField({ name, value, onChange }) {
|
|
16
96
|
const current = value ?? { type: "none" };
|
|
17
97
|
const update = (patch) => {
|
|
@@ -37,19 +117,14 @@ function ActionField({ name, value, onChange }) {
|
|
|
37
117
|
}
|
|
38
118
|
)
|
|
39
119
|
] }),
|
|
40
|
-
current.type === "page" && /* @__PURE__ */
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
onChange: (e) => update({ pageUrl: e.target.value }),
|
|
49
|
-
placeholder: "/about"
|
|
50
|
-
}
|
|
51
|
-
)
|
|
52
|
-
] }),
|
|
120
|
+
current.type === "page" && /* @__PURE__ */ jsx(
|
|
121
|
+
PageUrlField,
|
|
122
|
+
{
|
|
123
|
+
name,
|
|
124
|
+
value: current.pageUrl ?? "",
|
|
125
|
+
onChange: (val) => update({ pageUrl: val })
|
|
126
|
+
}
|
|
127
|
+
),
|
|
53
128
|
current.type === "external" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
54
129
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
55
130
|
/* @__PURE__ */ jsx(Label, { children: "External URL" }),
|