@yoamigo.com/core 0.3.17 → 0.4.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/content-helpers-kWphH5Tn.d.ts +376 -0
- package/dist/index.d.ts +3 -119
- package/dist/index.js +58 -36
- package/dist/prod.d.ts +1 -1
- package/dist/prod.js +30 -8
- package/package.json +1 -1
- package/dist/MarkdownText-DHJo0ofY.d.ts +0 -157
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React$1, { ReactNode, CSSProperties } from 'react';
|
|
3
|
+
|
|
4
|
+
type EditMode = 'read-only' | 'inline-edit';
|
|
5
|
+
interface ContentStore {
|
|
6
|
+
getValue: (fieldId: string) => string;
|
|
7
|
+
setValue: (fieldId: string, value: string) => void;
|
|
8
|
+
mode: EditMode;
|
|
9
|
+
setMode: (mode: EditMode) => void;
|
|
10
|
+
subscribe: (listener: () => void) => () => void;
|
|
11
|
+
saveToWorker?: (fieldId: string, value: string) => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
declare function useContentStore(): ContentStore;
|
|
14
|
+
interface ContentStoreProviderProps {
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
initialContent?: Record<string, string>;
|
|
17
|
+
initialMode?: EditMode;
|
|
18
|
+
}
|
|
19
|
+
declare function ContentStoreProvider({ children, initialContent }: ContentStoreProviderProps): react_jsx_runtime.JSX.Element;
|
|
20
|
+
|
|
21
|
+
interface ImageFieldValue {
|
|
22
|
+
src: string;
|
|
23
|
+
alt?: string;
|
|
24
|
+
objectFit?: 'cover' | 'contain' | 'fill';
|
|
25
|
+
objectPosition?: string;
|
|
26
|
+
focalPoint?: {
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
interface YaImageProps {
|
|
32
|
+
fieldId: string;
|
|
33
|
+
className?: string;
|
|
34
|
+
alt?: string;
|
|
35
|
+
objectFit?: 'cover' | 'contain' | 'fill';
|
|
36
|
+
objectPosition?: string;
|
|
37
|
+
loading?: 'lazy' | 'eager';
|
|
38
|
+
/** Fallback for backward compatibility with config.ts images */
|
|
39
|
+
fallbackSrc?: string;
|
|
40
|
+
/** Fallback alt text */
|
|
41
|
+
fallbackAlt?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Serialize image field value for storage
|
|
45
|
+
*/
|
|
46
|
+
declare function serializeImageValue(value: ImageFieldValue): string;
|
|
47
|
+
declare function YaImage({ fieldId, className, alt, objectFit: propObjectFit, objectPosition: propObjectPosition, loading, fallbackSrc, fallbackAlt, }: YaImageProps): react_jsx_runtime.JSX.Element;
|
|
48
|
+
|
|
49
|
+
interface VideoFieldValue {
|
|
50
|
+
/** Video source type */
|
|
51
|
+
type: 'upload' | 'youtube' | 'vimeo';
|
|
52
|
+
/** Video URL (for upload) or video ID (for embeds) */
|
|
53
|
+
src: string;
|
|
54
|
+
/** Poster image URL */
|
|
55
|
+
poster?: string;
|
|
56
|
+
/** Autoplay video (requires muted for browser policy) */
|
|
57
|
+
autoplay?: boolean;
|
|
58
|
+
/** Mute video audio */
|
|
59
|
+
muted?: boolean;
|
|
60
|
+
/** Loop video playback */
|
|
61
|
+
loop?: boolean;
|
|
62
|
+
/** Show video controls */
|
|
63
|
+
controls?: boolean;
|
|
64
|
+
/** Play inline on mobile (prevent fullscreen hijack) */
|
|
65
|
+
playsinline?: boolean;
|
|
66
|
+
/** Preload strategy */
|
|
67
|
+
preload?: 'none' | 'metadata' | 'auto';
|
|
68
|
+
/** CSS object-fit */
|
|
69
|
+
objectFit?: 'cover' | 'contain' | 'fill';
|
|
70
|
+
/** CSS aspect-ratio (e.g., "16/9") */
|
|
71
|
+
aspectRatio?: string;
|
|
72
|
+
/** Start playback at this time (seconds) */
|
|
73
|
+
startTime?: number;
|
|
74
|
+
/** End playback at this time (seconds) */
|
|
75
|
+
endTime?: number;
|
|
76
|
+
}
|
|
77
|
+
interface YaVideoProps {
|
|
78
|
+
fieldId: string;
|
|
79
|
+
className?: string;
|
|
80
|
+
/** Default aspect ratio from props */
|
|
81
|
+
aspectRatio?: string;
|
|
82
|
+
/** Default object-fit */
|
|
83
|
+
objectFit?: 'cover' | 'contain' | 'fill';
|
|
84
|
+
/** Loading strategy */
|
|
85
|
+
loading?: 'lazy' | 'eager';
|
|
86
|
+
/** Default video value (used when nothing in content store) */
|
|
87
|
+
defaultValue?: VideoFieldValue;
|
|
88
|
+
/** Fallback for backward compatibility (deprecated: use defaultValue) */
|
|
89
|
+
fallbackSrc?: string;
|
|
90
|
+
/** Fallback poster image */
|
|
91
|
+
fallbackPoster?: string;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Serialize video field value for storage
|
|
95
|
+
*/
|
|
96
|
+
declare function serializeVideoValue(value: VideoFieldValue): string;
|
|
97
|
+
declare function YaVideo({ fieldId, className, aspectRatio: propAspectRatio, objectFit: propObjectFit, loading, defaultValue, fallbackSrc, fallbackPoster, }: YaVideoProps): react_jsx_runtime.JSX.Element;
|
|
98
|
+
|
|
99
|
+
type EmbedType = 'spotify' | 'soundcloud' | 'twitter' | 'instagram' | 'custom';
|
|
100
|
+
interface EmbedFieldValue {
|
|
101
|
+
/** Embed platform type */
|
|
102
|
+
type: EmbedType;
|
|
103
|
+
/** Embed URL or ID (platform-specific) */
|
|
104
|
+
src: string;
|
|
105
|
+
/** Original URL pasted by user (for editing) */
|
|
106
|
+
originalUrl?: string;
|
|
107
|
+
/** CSS aspect-ratio (e.g., "16/9", "1/1") */
|
|
108
|
+
aspectRatio?: string;
|
|
109
|
+
/** Fixed height in pixels (for audio players) */
|
|
110
|
+
height?: number;
|
|
111
|
+
/** Spotify-specific: content type */
|
|
112
|
+
spotifyType?: 'track' | 'album' | 'playlist' | 'episode' | 'show';
|
|
113
|
+
}
|
|
114
|
+
interface YaEmbedProps {
|
|
115
|
+
fieldId: string;
|
|
116
|
+
className?: string;
|
|
117
|
+
/** Default aspect ratio from props */
|
|
118
|
+
aspectRatio?: string;
|
|
119
|
+
/** Max width constraint */
|
|
120
|
+
maxWidth?: number;
|
|
121
|
+
/** Loading strategy */
|
|
122
|
+
loading?: 'lazy' | 'eager';
|
|
123
|
+
/** Default embed value (used when nothing in content store) */
|
|
124
|
+
defaultValue?: EmbedFieldValue;
|
|
125
|
+
}
|
|
126
|
+
interface ParsedEmbed {
|
|
127
|
+
type: EmbedType;
|
|
128
|
+
src: string;
|
|
129
|
+
originalUrl: string;
|
|
130
|
+
aspectRatio?: string;
|
|
131
|
+
height?: number;
|
|
132
|
+
spotifyType?: EmbedFieldValue['spotifyType'];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Parse a URL and detect the embed platform
|
|
136
|
+
*/
|
|
137
|
+
declare function parseEmbedUrl(url: string): ParsedEmbed | null;
|
|
138
|
+
/**
|
|
139
|
+
* Serialize embed field value for storage
|
|
140
|
+
*/
|
|
141
|
+
declare function serializeEmbedValue(value: EmbedFieldValue): string;
|
|
142
|
+
declare function YaEmbed({ fieldId, className, aspectRatio: propAspectRatio, maxWidth, loading, defaultValue, }: YaEmbedProps): react_jsx_runtime.JSX.Element;
|
|
143
|
+
|
|
144
|
+
interface PageInfo {
|
|
145
|
+
path: string;
|
|
146
|
+
label: string;
|
|
147
|
+
}
|
|
148
|
+
interface YaLinkProps {
|
|
149
|
+
fieldId: string;
|
|
150
|
+
/** Default href if not set in content store */
|
|
151
|
+
href?: string;
|
|
152
|
+
className?: string;
|
|
153
|
+
/** Inline styles to apply to the link element */
|
|
154
|
+
style?: React$1.CSSProperties;
|
|
155
|
+
as?: 'a' | 'span';
|
|
156
|
+
children?: React$1.ReactNode;
|
|
157
|
+
/** Available pages for href dropdown (injected by template) */
|
|
158
|
+
availablePages?: PageInfo[];
|
|
159
|
+
/** Optional click handler called after navigation */
|
|
160
|
+
onClick?: () => void;
|
|
161
|
+
/** Target attribute for the link (e.g., "_blank" to open in new tab) */
|
|
162
|
+
target?: string;
|
|
163
|
+
/** Rel attribute for the link (e.g., "noopener noreferrer" for security) */
|
|
164
|
+
rel?: string;
|
|
165
|
+
}
|
|
166
|
+
declare module '@tiptap/core' {
|
|
167
|
+
interface Commands<ReturnType> {
|
|
168
|
+
fontSize: {
|
|
169
|
+
setFontSize: (fontSize: string) => ReturnType;
|
|
170
|
+
unsetFontSize: () => ReturnType;
|
|
171
|
+
};
|
|
172
|
+
fontWeight: {
|
|
173
|
+
setFontWeight: (fontWeight: string) => ReturnType;
|
|
174
|
+
unsetFontWeight: () => ReturnType;
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
declare function YaLink({ fieldId, href: defaultHref, className, style, as: Component, children, availablePages, onClick, target, rel }: YaLinkProps): react_jsx_runtime.JSX.Element;
|
|
179
|
+
|
|
180
|
+
interface BackgroundImageConfig {
|
|
181
|
+
src: string;
|
|
182
|
+
objectFit?: 'cover' | 'contain' | 'fill';
|
|
183
|
+
objectPosition?: string;
|
|
184
|
+
focalPoint?: {
|
|
185
|
+
x: number;
|
|
186
|
+
y: number;
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
interface OverlayConfig {
|
|
190
|
+
color: string;
|
|
191
|
+
opacity: number;
|
|
192
|
+
}
|
|
193
|
+
interface BackgroundConfig {
|
|
194
|
+
type: 'none' | 'color' | 'image';
|
|
195
|
+
backgroundColor?: string;
|
|
196
|
+
backgroundImage?: BackgroundImageConfig;
|
|
197
|
+
overlay?: OverlayConfig;
|
|
198
|
+
}
|
|
199
|
+
interface YaContainerProps {
|
|
200
|
+
fieldId: string;
|
|
201
|
+
className?: string;
|
|
202
|
+
style?: CSSProperties;
|
|
203
|
+
as?: 'section' | 'div' | 'article' | 'header' | 'footer' | 'main' | 'aside';
|
|
204
|
+
children: ReactNode;
|
|
205
|
+
/** Fallback background config if not in store */
|
|
206
|
+
defaultBackground?: BackgroundConfig;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Parse background config from content store
|
|
210
|
+
*/
|
|
211
|
+
declare function parseBackgroundConfig(value: string): BackgroundConfig;
|
|
212
|
+
/**
|
|
213
|
+
* Serialize background config for storage
|
|
214
|
+
*/
|
|
215
|
+
declare function serializeBackgroundConfig(config: BackgroundConfig): string;
|
|
216
|
+
declare function YaContainer({ fieldId, className, style, as: Tag, children, defaultBackground, }: YaContainerProps): react_jsx_runtime.JSX.Element;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* StaticText Component - Production-only static text renderer
|
|
220
|
+
*
|
|
221
|
+
* This component replaces MpText in production builds via Vite alias.
|
|
222
|
+
* No editing capabilities, no Tiptap, no DOMPurify - minimal bundle size.
|
|
223
|
+
*
|
|
224
|
+
* Content from content.json is trusted because:
|
|
225
|
+
* 1. It's created in the builder using Tiptap (which controls allowed markup)
|
|
226
|
+
* 2. It's sanitized by SafeHtml when displayed in the builder
|
|
227
|
+
* 3. Users can't inject arbitrary HTML
|
|
228
|
+
*/
|
|
229
|
+
/** Common HTML elements that MpText can render as */
|
|
230
|
+
type MpTextElement = 'span' | 'div' | 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'strong' | 'em';
|
|
231
|
+
interface MpTextProps {
|
|
232
|
+
fieldId: string;
|
|
233
|
+
className?: string;
|
|
234
|
+
as?: MpTextElement;
|
|
235
|
+
/** Optional fallback content (used if fieldId not in store) */
|
|
236
|
+
children?: React.ReactNode;
|
|
237
|
+
}
|
|
238
|
+
declare function MpText({ fieldId, className, as: Component, children }: MpTextProps): react_jsx_runtime.JSX.Element;
|
|
239
|
+
|
|
240
|
+
type StaticTextProps = MpTextProps;
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* StaticImage Component - Production-only static image renderer
|
|
244
|
+
*
|
|
245
|
+
* This component replaces MpImage in production builds via Vite alias.
|
|
246
|
+
* No editing overlay, no click handlers, no postMessage - minimal bundle size.
|
|
247
|
+
*/
|
|
248
|
+
interface MpImageProps {
|
|
249
|
+
fieldId: string;
|
|
250
|
+
className?: string;
|
|
251
|
+
alt?: string;
|
|
252
|
+
objectFit?: 'cover' | 'contain' | 'fill';
|
|
253
|
+
objectPosition?: string;
|
|
254
|
+
loading?: 'lazy' | 'eager';
|
|
255
|
+
/** Fallback for backward compatibility with config.ts images */
|
|
256
|
+
fallbackSrc?: string;
|
|
257
|
+
/** Fallback alt text */
|
|
258
|
+
fallbackAlt?: string;
|
|
259
|
+
}
|
|
260
|
+
declare function MpImage({ fieldId, className, alt, objectFit: propObjectFit, objectPosition: propObjectPosition, loading, fallbackSrc, fallbackAlt, }: MpImageProps): react_jsx_runtime.JSX.Element;
|
|
261
|
+
|
|
262
|
+
type StaticImageProps = MpImageProps;
|
|
263
|
+
|
|
264
|
+
interface MarkdownTextProps {
|
|
265
|
+
content: string;
|
|
266
|
+
className?: string;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* MarkdownText component - renders markdown content safely
|
|
270
|
+
*/
|
|
271
|
+
declare function MarkdownText({ content, className }: MarkdownTextProps): react_jsx_runtime.JSX.Element;
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Content Helpers for content.ts
|
|
275
|
+
*
|
|
276
|
+
* Type-safe helper functions for creating content values.
|
|
277
|
+
* These eliminate the need for manual JSON.stringify() and escaping.
|
|
278
|
+
*
|
|
279
|
+
* Usage:
|
|
280
|
+
* ```ts
|
|
281
|
+
* import { text, image, background, video, embed } from '@yoamigo.com/core'
|
|
282
|
+
*
|
|
283
|
+
* export default {
|
|
284
|
+
* "hero.title": text("Welcome to Our Site"),
|
|
285
|
+
* "profile.image": image({ src: "/photo.jpg", alt: "Headshot" }),
|
|
286
|
+
* "hero.background": background({ type: "color", backgroundColor: "#000" }),
|
|
287
|
+
* } as const satisfies Record<string, string>
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Text content for YaText fields.
|
|
293
|
+
*
|
|
294
|
+
* Supports HTML formatting:
|
|
295
|
+
* - `<strong>`, `<b>` for bold
|
|
296
|
+
* - `<em>`, `<i>` for italic
|
|
297
|
+
* - `<a href="...">` for links
|
|
298
|
+
* - `<span style="...">` for inline styles
|
|
299
|
+
* - `<br>` for line breaks
|
|
300
|
+
*
|
|
301
|
+
* Allowed inline styles: font-size, font-weight
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* text("Hello World")
|
|
305
|
+
* text("Welcome to <strong>YoAmigo</strong>")
|
|
306
|
+
* text('<span style="font-size: 20px">Large text</span>')
|
|
307
|
+
*/
|
|
308
|
+
declare function text(content: string): string;
|
|
309
|
+
/**
|
|
310
|
+
* Image field value for YaImage components.
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* image({ src: "/photo.jpg", alt: "Description" })
|
|
314
|
+
* image({ src: "/hero.jpg", objectFit: "cover", objectPosition: "center top" })
|
|
315
|
+
* image({ src: "/profile.jpg", focalPoint: { x: 50, y: 30 } })
|
|
316
|
+
*/
|
|
317
|
+
declare function image(config: ImageFieldValue): string;
|
|
318
|
+
/**
|
|
319
|
+
* Background config for YaContainer components.
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* // Solid color
|
|
323
|
+
* background({ type: "color", backgroundColor: "#000" })
|
|
324
|
+
*
|
|
325
|
+
* // Image background
|
|
326
|
+
* background({
|
|
327
|
+
* type: "image",
|
|
328
|
+
* backgroundImage: { src: "/bg.jpg", objectFit: "cover" }
|
|
329
|
+
* })
|
|
330
|
+
*
|
|
331
|
+
* // Image with overlay
|
|
332
|
+
* background({
|
|
333
|
+
* type: "image",
|
|
334
|
+
* backgroundImage: { src: "/bg.jpg" },
|
|
335
|
+
* overlay: { color: "#000", opacity: 0.5 }
|
|
336
|
+
* })
|
|
337
|
+
*
|
|
338
|
+
* // No background (transparent)
|
|
339
|
+
* background({ type: "none" })
|
|
340
|
+
*/
|
|
341
|
+
declare function background(config: BackgroundConfig): string;
|
|
342
|
+
/**
|
|
343
|
+
* Video field value for YaVideo components.
|
|
344
|
+
*
|
|
345
|
+
* @example
|
|
346
|
+
* // YouTube video
|
|
347
|
+
* video({ type: "youtube", src: "dQw4w9WgXcQ" })
|
|
348
|
+
*
|
|
349
|
+
* // Vimeo video
|
|
350
|
+
* video({ type: "vimeo", src: "123456789" })
|
|
351
|
+
*
|
|
352
|
+
* // Uploaded video
|
|
353
|
+
* video({ type: "upload", src: "/videos/intro.mp4" })
|
|
354
|
+
*
|
|
355
|
+
* // With options
|
|
356
|
+
* video({ type: "youtube", src: "dQw4w9WgXcQ", autoplay: true, muted: true, loop: true })
|
|
357
|
+
*/
|
|
358
|
+
declare function video(config: VideoFieldValue): string;
|
|
359
|
+
/**
|
|
360
|
+
* Embed field value for YaEmbed components.
|
|
361
|
+
*
|
|
362
|
+
* Supports: Spotify, SoundCloud, Twitter/X, Instagram
|
|
363
|
+
*
|
|
364
|
+
* @example
|
|
365
|
+
* // Spotify track
|
|
366
|
+
* embed({ type: "spotify", src: "track/4PTG3Z6", spotifyType: "track" })
|
|
367
|
+
*
|
|
368
|
+
* // Spotify playlist
|
|
369
|
+
* embed({ type: "spotify", src: "playlist/37i9dQZF1DXcBWIGoYBM5M", spotifyType: "playlist" })
|
|
370
|
+
*
|
|
371
|
+
* // SoundCloud
|
|
372
|
+
* embed({ type: "soundcloud", src: "user/track" })
|
|
373
|
+
*/
|
|
374
|
+
declare function embed(config: EmbedFieldValue): string;
|
|
375
|
+
|
|
376
|
+
export { serializeBackgroundConfig as A, type YaContainerProps as B, ContentStoreProvider as C, type BackgroundConfig as D, type EditMode as E, type BackgroundImageConfig as F, type ImageFieldValue as I, MpText as M, type OverlayConfig as O, type PageInfo as P, type StaticTextProps as S, type VideoFieldValue as V, YaImage as Y, type ContentStore as a, background as b, MpImage as c, type StaticImageProps as d, embed as e, MarkdownText as f, type MarkdownTextProps as g, type YaImageProps as h, image as i, YaVideo as j, serializeVideoValue as k, type YaVideoProps as l, YaEmbed as m, serializeEmbedValue as n, type YaEmbedProps as o, parseEmbedUrl as p, type EmbedFieldValue as q, type EmbedType as r, serializeImageValue as s, text as t, useContentStore as u, video as v, YaLink as w, type YaLinkProps as x, YaContainer as y, parseBackgroundConfig as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import React$1, { ReactNode
|
|
3
|
-
export { C as ContentStoreProviderProd,
|
|
2
|
+
import React$1, { ReactNode } from 'react';
|
|
3
|
+
export { D as BackgroundConfig, F as BackgroundImageConfig, C as ContentStoreProviderProd, q as EmbedFieldValue, r as EmbedType, I as ImageFieldValue, f as MarkdownText, g as MarkdownTextProps, O as OverlayConfig, P as PageInfo, c as StaticImage, d as StaticImageProps, M as StaticText, S as StaticTextProps, V as VideoFieldValue, y as YaContainer, B as YaContainerProps, m as YaEmbed, o as YaEmbedProps, Y as YaImage, h as YaImageProps, w as YaLink, x as YaLinkProps, j as YaVideo, l as YaVideoProps, b as background, e as embed, i as image, z as parseBackgroundConfig, p as parseEmbedUrl, A as serializeBackgroundConfig, n as serializeEmbedValue, s as serializeImageValue, k as serializeVideoValue, t as text, u as useContentStoreProd, v as video } from './content-helpers-kWphH5Tn.js';
|
|
4
4
|
export { Link, LinkProps, NavigateFunction, Router, RouterProps, ScrollRestoration, useNavigate } from './router.js';
|
|
5
5
|
export { Route, Switch, useParams } from 'wouter';
|
|
6
6
|
export { A as AssetResolverFn, C as ContentRegistry, c as contentRegistry, a as getAllContent, g as getContent, h as hasContent, r as registerContent, b as resolveAssetUrl, s as setAssetResolver } from './asset-resolver-BnIvDkVv.js';
|
|
@@ -62,122 +62,6 @@ declare module '@tiptap/core' {
|
|
|
62
62
|
}
|
|
63
63
|
declare function YaText({ fieldId, className, as: Component, children }: YaTextProps): react_jsx_runtime.JSX.Element;
|
|
64
64
|
|
|
65
|
-
interface ImageFieldValue {
|
|
66
|
-
src: string;
|
|
67
|
-
alt?: string;
|
|
68
|
-
objectFit?: 'cover' | 'contain' | 'fill';
|
|
69
|
-
objectPosition?: string;
|
|
70
|
-
focalPoint?: {
|
|
71
|
-
x: number;
|
|
72
|
-
y: number;
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
interface YaImageProps {
|
|
76
|
-
fieldId: string;
|
|
77
|
-
className?: string;
|
|
78
|
-
alt?: string;
|
|
79
|
-
objectFit?: 'cover' | 'contain' | 'fill';
|
|
80
|
-
objectPosition?: string;
|
|
81
|
-
loading?: 'lazy' | 'eager';
|
|
82
|
-
/** Fallback for backward compatibility with config.ts images */
|
|
83
|
-
fallbackSrc?: string;
|
|
84
|
-
/** Fallback alt text */
|
|
85
|
-
fallbackAlt?: string;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Serialize image field value for storage
|
|
89
|
-
*/
|
|
90
|
-
declare function serializeImageValue(value: ImageFieldValue): string;
|
|
91
|
-
declare function YaImage({ fieldId, className, alt, objectFit: propObjectFit, objectPosition: propObjectPosition, loading, fallbackSrc, fallbackAlt, }: YaImageProps): react_jsx_runtime.JSX.Element;
|
|
92
|
-
|
|
93
|
-
interface VideoFieldValue {
|
|
94
|
-
/** Video source type */
|
|
95
|
-
type: 'upload' | 'youtube' | 'vimeo';
|
|
96
|
-
/** Video URL (for upload) or video ID (for embeds) */
|
|
97
|
-
src: string;
|
|
98
|
-
/** Poster image URL */
|
|
99
|
-
poster?: string;
|
|
100
|
-
/** Autoplay video (requires muted for browser policy) */
|
|
101
|
-
autoplay?: boolean;
|
|
102
|
-
/** Mute video audio */
|
|
103
|
-
muted?: boolean;
|
|
104
|
-
/** Loop video playback */
|
|
105
|
-
loop?: boolean;
|
|
106
|
-
/** Show video controls */
|
|
107
|
-
controls?: boolean;
|
|
108
|
-
/** Play inline on mobile (prevent fullscreen hijack) */
|
|
109
|
-
playsinline?: boolean;
|
|
110
|
-
/** Preload strategy */
|
|
111
|
-
preload?: 'none' | 'metadata' | 'auto';
|
|
112
|
-
/** CSS object-fit */
|
|
113
|
-
objectFit?: 'cover' | 'contain' | 'fill';
|
|
114
|
-
/** CSS aspect-ratio (e.g., "16/9") */
|
|
115
|
-
aspectRatio?: string;
|
|
116
|
-
/** Start playback at this time (seconds) */
|
|
117
|
-
startTime?: number;
|
|
118
|
-
/** End playback at this time (seconds) */
|
|
119
|
-
endTime?: number;
|
|
120
|
-
}
|
|
121
|
-
interface YaVideoProps {
|
|
122
|
-
fieldId: string;
|
|
123
|
-
className?: string;
|
|
124
|
-
/** Default aspect ratio from props */
|
|
125
|
-
aspectRatio?: string;
|
|
126
|
-
/** Default object-fit */
|
|
127
|
-
objectFit?: 'cover' | 'contain' | 'fill';
|
|
128
|
-
/** Loading strategy */
|
|
129
|
-
loading?: 'lazy' | 'eager';
|
|
130
|
-
/** Default video value (used when nothing in content store) */
|
|
131
|
-
defaultValue?: VideoFieldValue;
|
|
132
|
-
/** Fallback for backward compatibility (deprecated: use defaultValue) */
|
|
133
|
-
fallbackSrc?: string;
|
|
134
|
-
/** Fallback poster image */
|
|
135
|
-
fallbackPoster?: string;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Serialize video field value for storage
|
|
139
|
-
*/
|
|
140
|
-
declare function serializeVideoValue(value: VideoFieldValue): string;
|
|
141
|
-
declare function YaVideo({ fieldId, className, aspectRatio: propAspectRatio, objectFit: propObjectFit, loading, defaultValue, fallbackSrc, fallbackPoster, }: YaVideoProps): react_jsx_runtime.JSX.Element;
|
|
142
|
-
|
|
143
|
-
interface BackgroundImageConfig {
|
|
144
|
-
src: string;
|
|
145
|
-
objectFit?: 'cover' | 'contain' | 'fill';
|
|
146
|
-
objectPosition?: string;
|
|
147
|
-
focalPoint?: {
|
|
148
|
-
x: number;
|
|
149
|
-
y: number;
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
interface OverlayConfig {
|
|
153
|
-
color: string;
|
|
154
|
-
opacity: number;
|
|
155
|
-
}
|
|
156
|
-
interface BackgroundConfig {
|
|
157
|
-
type: 'none' | 'color' | 'image';
|
|
158
|
-
backgroundColor?: string;
|
|
159
|
-
backgroundImage?: BackgroundImageConfig;
|
|
160
|
-
overlay?: OverlayConfig;
|
|
161
|
-
}
|
|
162
|
-
interface YaContainerProps {
|
|
163
|
-
fieldId: string;
|
|
164
|
-
className?: string;
|
|
165
|
-
style?: CSSProperties;
|
|
166
|
-
as?: 'section' | 'div' | 'article' | 'header' | 'footer' | 'main' | 'aside';
|
|
167
|
-
children: ReactNode;
|
|
168
|
-
/** Fallback background config if not in store */
|
|
169
|
-
defaultBackground?: BackgroundConfig;
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Parse background config from content store
|
|
173
|
-
*/
|
|
174
|
-
declare function parseBackgroundConfig(value: string): BackgroundConfig;
|
|
175
|
-
/**
|
|
176
|
-
* Serialize background config for storage
|
|
177
|
-
*/
|
|
178
|
-
declare function serializeBackgroundConfig(config: BackgroundConfig): string;
|
|
179
|
-
declare function YaContainer({ fieldId, className, style, as: Tag, children, defaultBackground, }: YaContainerProps): react_jsx_runtime.JSX.Element;
|
|
180
|
-
|
|
181
65
|
/**
|
|
182
66
|
* SafeHtml Component - Secure HTML Renderer
|
|
183
67
|
*
|
|
@@ -675,4 +559,4 @@ interface UseSafeTriangleReturn<T extends HTMLElement, U extends HTMLElement> {
|
|
|
675
559
|
*/
|
|
676
560
|
declare function useSafeTriangle<T extends HTMLElement = HTMLElement, U extends HTMLElement = HTMLDivElement>(options?: UseSafeTriangleOptions): UseSafeTriangleReturn<T, U>;
|
|
677
561
|
|
|
678
|
-
export { type AIEditContextValue, AIEditProvider, type AnimatedTextOptions, type AnimatedTextResult, type AnimationConfig, type AnimationMetadata, type AnimationOptions, type AnimationPhase, type AnimationResult, type AnimationState, type AnimationStrategy, type
|
|
562
|
+
export { type AIEditContextValue, AIEditProvider, type AnimatedTextOptions, type AnimatedTextResult, type AnimationConfig, type AnimationMetadata, type AnimationOptions, type AnimationPhase, type AnimationResult, type AnimationState, type AnimationStrategy, type ContentStoreContextType, type ContentStoreMode, ContentStoreProvider, type ImageValue, type LinkValue, SafeHtml, type SafeHtmlProps, SafeTriangleBelow, type TextAnimationMetadata, type TextDiff, YaText, type YaTextProps, buildIntermediateText, calculateAnimationTiming, computeTextDiff, containsHtml, getTextCursorPosition, imageCrossfadeStrategy, linkTransitionStrategy, stripHtml, textTypingStrategy, useAIEditAnimation, useAIEditContext, useAIEditContextOptional, useAnimatedText, useContentStore, useSafeTriangle };
|
package/dist/index.js
CHANGED
|
@@ -395,12 +395,12 @@ var BuilderSelectionManager = class {
|
|
|
395
395
|
return this.toTitleCase(el.dataset.mpSelectable);
|
|
396
396
|
}
|
|
397
397
|
const tag = el.tagName.toLowerCase();
|
|
398
|
-
const
|
|
398
|
+
const text2 = el.textContent?.trim().slice(0, 30) || "";
|
|
399
399
|
if (tag === "button" || el.getAttribute("role") === "button") {
|
|
400
|
-
return
|
|
400
|
+
return text2 ? `"${text2}" Button` : "Button";
|
|
401
401
|
}
|
|
402
402
|
if (tag === "a") {
|
|
403
|
-
return
|
|
403
|
+
return text2 ? `"${text2}" Link` : "Link";
|
|
404
404
|
}
|
|
405
405
|
if (tag === "img") {
|
|
406
406
|
return el.alt || "Image";
|
|
@@ -422,7 +422,7 @@ var BuilderSelectionManager = class {
|
|
|
422
422
|
return caption ? `Figure: ${caption.slice(0, 20)}` : "Figure";
|
|
423
423
|
}
|
|
424
424
|
if (tag === "figcaption") {
|
|
425
|
-
return
|
|
425
|
+
return text2 ? `Caption: ${text2.slice(0, 20)}` : "Caption";
|
|
426
426
|
}
|
|
427
427
|
if (tag === "input") {
|
|
428
428
|
const type = el.type || "text";
|
|
@@ -440,19 +440,19 @@ var BuilderSelectionManager = class {
|
|
|
440
440
|
return "Dropdown";
|
|
441
441
|
}
|
|
442
442
|
if (tag === "label") {
|
|
443
|
-
return
|
|
443
|
+
return text2 ? `Label: ${text2.slice(0, 20)}` : "Label";
|
|
444
444
|
}
|
|
445
445
|
if (tag === "form") {
|
|
446
446
|
return "Form";
|
|
447
447
|
}
|
|
448
448
|
if (["h1", "h2", "h3", "h4", "h5", "h6"].includes(tag)) {
|
|
449
|
-
return
|
|
449
|
+
return text2 ? `Heading: ${text2.slice(0, 25)}` : `${tag.toUpperCase()} Heading`;
|
|
450
450
|
}
|
|
451
451
|
if (tag === "p") {
|
|
452
|
-
return
|
|
452
|
+
return text2 ? `Paragraph: ${text2.slice(0, 20)}...` : "Paragraph";
|
|
453
453
|
}
|
|
454
454
|
if (tag === "blockquote") {
|
|
455
|
-
return
|
|
455
|
+
return text2 ? `Quote: ${text2.slice(0, 20)}...` : "Block Quote";
|
|
456
456
|
}
|
|
457
457
|
if (tag === "table") {
|
|
458
458
|
return "Table";
|
|
@@ -461,7 +461,7 @@ var BuilderSelectionManager = class {
|
|
|
461
461
|
return "Table Row";
|
|
462
462
|
}
|
|
463
463
|
if (tag === "td" || tag === "th") {
|
|
464
|
-
return
|
|
464
|
+
return text2 ? `Cell: ${text2.slice(0, 15)}` : "Table Cell";
|
|
465
465
|
}
|
|
466
466
|
if (tag === "ol") {
|
|
467
467
|
return "Ordered List";
|
|
@@ -470,7 +470,7 @@ var BuilderSelectionManager = class {
|
|
|
470
470
|
return "Unordered List";
|
|
471
471
|
}
|
|
472
472
|
if (tag === "li") {
|
|
473
|
-
const preview =
|
|
473
|
+
const preview = text2.length > 20 ? text2.slice(0, 20) + "..." : text2;
|
|
474
474
|
return preview ? `List Item: ${preview}` : "List Item";
|
|
475
475
|
}
|
|
476
476
|
if (tag === "section") {
|
|
@@ -490,7 +490,7 @@ var BuilderSelectionManager = class {
|
|
|
490
490
|
if (tag === "footer") {
|
|
491
491
|
return "Footer";
|
|
492
492
|
}
|
|
493
|
-
return
|
|
493
|
+
return text2 || this.toTitleCase(tag);
|
|
494
494
|
}
|
|
495
495
|
/**
|
|
496
496
|
* Convert kebab-case or tag names to Title Case
|
|
@@ -1409,8 +1409,8 @@ function extractLinkDisplayText(href) {
|
|
|
1409
1409
|
if (href.startsWith("/")) {
|
|
1410
1410
|
const segments = href.split("/").filter(Boolean);
|
|
1411
1411
|
const lastSegment = segments[segments.length - 1] || "home";
|
|
1412
|
-
const
|
|
1413
|
-
return { text, isExternal: false };
|
|
1412
|
+
const text2 = lastSegment.replace(/-/g, " ").replace(/^\w/, (c) => c.toUpperCase());
|
|
1413
|
+
return { text: text2, isExternal: false };
|
|
1414
1414
|
}
|
|
1415
1415
|
if (href.startsWith("mailto:")) {
|
|
1416
1416
|
return { text: "email", isExternal: true };
|
|
@@ -1532,14 +1532,14 @@ function SafeHtml({ content, className, mode = "read-only" }) {
|
|
|
1532
1532
|
clearTimeout(hideTimerRef.current);
|
|
1533
1533
|
showTimerRef.current = window.setTimeout(() => {
|
|
1534
1534
|
const href = link.getAttribute("href") || "";
|
|
1535
|
-
const { text, isExternal } = extractLinkDisplayText(href);
|
|
1535
|
+
const { text: text2, isExternal } = extractLinkDisplayText(href);
|
|
1536
1536
|
const rect = link.getBoundingClientRect();
|
|
1537
1537
|
const top = rect.bottom + window.scrollY + 8;
|
|
1538
1538
|
const left = rect.left + rect.width / 2 + window.scrollX;
|
|
1539
1539
|
setPopoverState({
|
|
1540
1540
|
isVisible: true,
|
|
1541
1541
|
href,
|
|
1542
|
-
displayText:
|
|
1542
|
+
displayText: text2,
|
|
1543
1543
|
isExternal,
|
|
1544
1544
|
position: { top, left }
|
|
1545
1545
|
});
|
|
@@ -1859,8 +1859,8 @@ function useAIEditAnimation(fieldId, value, options) {
|
|
|
1859
1859
|
}
|
|
1860
1860
|
|
|
1861
1861
|
// src/lib/text-diff.ts
|
|
1862
|
-
function containsHtml(
|
|
1863
|
-
return /<[^>]+>/.test(
|
|
1862
|
+
function containsHtml(text2) {
|
|
1863
|
+
return /<[^>]+>/.test(text2);
|
|
1864
1864
|
}
|
|
1865
1865
|
function stripHtml(html) {
|
|
1866
1866
|
const withNewlines = html.replace(/<br\s*\/?>/gi, "\n");
|
|
@@ -3978,12 +3978,12 @@ function YaVideo({
|
|
|
3978
3978
|
(e) => {
|
|
3979
3979
|
if ((e.key === " " || e.key === "Enter") && videoData.type === "upload" && controls) {
|
|
3980
3980
|
e.preventDefault();
|
|
3981
|
-
const
|
|
3982
|
-
if (
|
|
3983
|
-
if (
|
|
3984
|
-
|
|
3981
|
+
const video2 = videoRef.current;
|
|
3982
|
+
if (video2) {
|
|
3983
|
+
if (video2.paused) {
|
|
3984
|
+
video2.play();
|
|
3985
3985
|
} else {
|
|
3986
|
-
|
|
3986
|
+
video2.pause();
|
|
3987
3987
|
}
|
|
3988
3988
|
}
|
|
3989
3989
|
}
|
|
@@ -4910,13 +4910,13 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
|
|
|
4910
4910
|
const storeText = getValue(textFieldId);
|
|
4911
4911
|
const storeHref = getValue(hrefFieldId);
|
|
4912
4912
|
const isIconMode = children != null && typeof children !== "string";
|
|
4913
|
-
const
|
|
4913
|
+
const text2 = storeText || (typeof children === "string" ? children : "");
|
|
4914
4914
|
const href = storeHref || defaultHref;
|
|
4915
4915
|
const isExternal = isExternalHref(href);
|
|
4916
4916
|
const effectiveTarget = target ?? (isExternal ? "_blank" : void 0);
|
|
4917
4917
|
const effectiveRel = rel ?? (isExternal ? "noopener noreferrer" : void 0);
|
|
4918
4918
|
const [editingMode, setEditingMode] = useState12(null);
|
|
4919
|
-
const [originalText, setOriginalText] = useState12(
|
|
4919
|
+
const [originalText, setOriginalText] = useState12(text2);
|
|
4920
4920
|
const [originalHref, setOriginalHref] = useState12(href);
|
|
4921
4921
|
const [currentHref, setCurrentHref] = useState12(href);
|
|
4922
4922
|
const [isExternalUrl, setIsExternalUrl] = useState12(false);
|
|
@@ -4970,7 +4970,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
|
|
|
4970
4970
|
FontSize2,
|
|
4971
4971
|
FontWeight2
|
|
4972
4972
|
],
|
|
4973
|
-
content:
|
|
4973
|
+
content: text2,
|
|
4974
4974
|
editable: true,
|
|
4975
4975
|
editorProps: {
|
|
4976
4976
|
attributes: {
|
|
@@ -4999,11 +4999,11 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
|
|
|
4999
4999
|
});
|
|
5000
5000
|
useEffect13(() => {
|
|
5001
5001
|
if (editor && editingMode !== "text") {
|
|
5002
|
-
if (editor.getHTML() !==
|
|
5003
|
-
editor.commands.setContent(
|
|
5002
|
+
if (editor.getHTML() !== text2) {
|
|
5003
|
+
editor.commands.setContent(text2);
|
|
5004
5004
|
}
|
|
5005
5005
|
}
|
|
5006
|
-
}, [
|
|
5006
|
+
}, [text2, editor, editingMode]);
|
|
5007
5007
|
useEffect13(() => {
|
|
5008
5008
|
if (editingMode !== "link") {
|
|
5009
5009
|
setCurrentHref(href);
|
|
@@ -5128,12 +5128,12 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
|
|
|
5128
5128
|
}));
|
|
5129
5129
|
} else {
|
|
5130
5130
|
setEditingMode("text");
|
|
5131
|
-
setOriginalText(
|
|
5131
|
+
setOriginalText(text2);
|
|
5132
5132
|
setTimeout(() => {
|
|
5133
5133
|
editor?.chain().focus().selectAll().run();
|
|
5134
5134
|
}, 20);
|
|
5135
5135
|
}
|
|
5136
|
-
}, [
|
|
5136
|
+
}, [text2, editor, hideEditPopover, isIconMode, fieldId]);
|
|
5137
5137
|
const startEditLink = useCallback14(() => {
|
|
5138
5138
|
hideEditPopover();
|
|
5139
5139
|
setEditingMode("link");
|
|
@@ -5213,7 +5213,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
|
|
|
5213
5213
|
return attrs.fontWeight || "";
|
|
5214
5214
|
};
|
|
5215
5215
|
if (mode === "read-only") {
|
|
5216
|
-
const content = isIconMode ? children : /* @__PURE__ */ jsx15(SafeHtml, { content:
|
|
5216
|
+
const content = isIconMode ? children : /* @__PURE__ */ jsx15(SafeHtml, { content: text2, mode });
|
|
5217
5217
|
if (isInternalPath(href)) {
|
|
5218
5218
|
return /* @__PURE__ */ jsx15(
|
|
5219
5219
|
WouterLink,
|
|
@@ -5344,8 +5344,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
|
|
|
5344
5344
|
),
|
|
5345
5345
|
document.body
|
|
5346
5346
|
)
|
|
5347
|
-
] }) : /* @__PURE__ */ jsx15(SafeHtml, { content:
|
|
5348
|
-
] }) : /* @__PURE__ */ jsx15(SafeHtml, { content:
|
|
5347
|
+
] }) : /* @__PURE__ */ jsx15(SafeHtml, { content: text2, mode })
|
|
5348
|
+
] }) : /* @__PURE__ */ jsx15(SafeHtml, { content: text2, mode })
|
|
5349
5349
|
}
|
|
5350
5350
|
),
|
|
5351
5351
|
showEditPopover && !editingMode && mode === "inline-edit" && /* @__PURE__ */ jsxs9(
|
|
@@ -6061,9 +6061,9 @@ function MpImage({
|
|
|
6061
6061
|
// src/components/MarkdownText.tsx
|
|
6062
6062
|
import { Fragment as Fragment6 } from "react";
|
|
6063
6063
|
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
6064
|
-
function tokenize(
|
|
6064
|
+
function tokenize(text2) {
|
|
6065
6065
|
const tokens = [];
|
|
6066
|
-
let remaining =
|
|
6066
|
+
let remaining = text2;
|
|
6067
6067
|
const patterns = [
|
|
6068
6068
|
// Bold: **text**
|
|
6069
6069
|
{ regex: /^\*\*(.+?)\*\*/, type: "bold" },
|
|
@@ -6295,6 +6295,23 @@ function ScrollRestoration() {
|
|
|
6295
6295
|
|
|
6296
6296
|
// src/router/index.ts
|
|
6297
6297
|
import { Route, Switch, useParams } from "wouter";
|
|
6298
|
+
|
|
6299
|
+
// src/lib/content-helpers.ts
|
|
6300
|
+
function text(content) {
|
|
6301
|
+
return content;
|
|
6302
|
+
}
|
|
6303
|
+
function image(config) {
|
|
6304
|
+
return JSON.stringify(config);
|
|
6305
|
+
}
|
|
6306
|
+
function background(config) {
|
|
6307
|
+
return JSON.stringify(config);
|
|
6308
|
+
}
|
|
6309
|
+
function video(config) {
|
|
6310
|
+
return JSON.stringify(config);
|
|
6311
|
+
}
|
|
6312
|
+
function embed(config) {
|
|
6313
|
+
return JSON.stringify(config);
|
|
6314
|
+
}
|
|
6298
6315
|
export {
|
|
6299
6316
|
AIEditProvider,
|
|
6300
6317
|
ContentStoreProvider,
|
|
@@ -6315,15 +6332,18 @@ export {
|
|
|
6315
6332
|
YaLink,
|
|
6316
6333
|
YaText,
|
|
6317
6334
|
YaVideo,
|
|
6335
|
+
background,
|
|
6318
6336
|
buildIntermediateText,
|
|
6319
6337
|
calculateAnimationTiming,
|
|
6320
6338
|
computeTextDiff,
|
|
6321
6339
|
containsHtml,
|
|
6322
6340
|
contentRegistry,
|
|
6341
|
+
embed,
|
|
6323
6342
|
getAllContent,
|
|
6324
6343
|
getContent,
|
|
6325
6344
|
getTextCursorPosition,
|
|
6326
6345
|
hasContent,
|
|
6346
|
+
image,
|
|
6327
6347
|
imageCrossfadeStrategy,
|
|
6328
6348
|
initBuilderSelection,
|
|
6329
6349
|
linkTransitionStrategy,
|
|
@@ -6337,6 +6357,7 @@ export {
|
|
|
6337
6357
|
serializeVideoValue,
|
|
6338
6358
|
setAssetResolver,
|
|
6339
6359
|
stripHtml,
|
|
6360
|
+
text,
|
|
6340
6361
|
textTypingStrategy,
|
|
6341
6362
|
useAIEditAnimation,
|
|
6342
6363
|
useAIEditContext,
|
|
@@ -6346,5 +6367,6 @@ export {
|
|
|
6346
6367
|
useContentStore2 as useContentStoreProd,
|
|
6347
6368
|
useNavigate,
|
|
6348
6369
|
useParams,
|
|
6349
|
-
useSafeTriangle
|
|
6370
|
+
useSafeTriangle,
|
|
6371
|
+
video
|
|
6350
6372
|
};
|
package/dist/prod.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { a as ContentStore, E as ContentStoreMode, C as ContentStoreProvider,
|
|
1
|
+
export { a as ContentStore, E as ContentStoreMode, C as ContentStoreProvider, f as MarkdownText, g as MarkdownTextProps, P as PageInfo, c as StaticImage, d as StaticImageProps, M as StaticText, S as StaticTextProps, c as YaImage, d as YaImageProps, M as YaText, S as YaTextProps, b as background, e as embed, i as image, p as parseEmbedUrl, t as text, u as useContentStore, v as video } from './content-helpers-kWphH5Tn.js';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
3
|
import React, { CSSProperties, ReactNode } from 'react';
|
|
4
4
|
export { Link, LinkProps, NavigateFunction, Router, RouterProps, ScrollRestoration, useNavigate } from './router.js';
|
package/dist/prod.js
CHANGED
|
@@ -241,9 +241,9 @@ function StaticLink({ fieldId, href: defaultHref = "#", className, style, as: Co
|
|
|
241
241
|
// src/components/MarkdownText.tsx
|
|
242
242
|
import { Fragment } from "react";
|
|
243
243
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
244
|
-
function tokenize(
|
|
244
|
+
function tokenize(text2) {
|
|
245
245
|
const tokens = [];
|
|
246
|
-
let remaining =
|
|
246
|
+
let remaining = text2;
|
|
247
247
|
const patterns = [
|
|
248
248
|
// Bold: **text**
|
|
249
249
|
{ regex: /^\*\*(.+?)\*\*/, type: "bold" },
|
|
@@ -515,12 +515,12 @@ function StaticVideo({
|
|
|
515
515
|
(e) => {
|
|
516
516
|
if ((e.key === " " || e.key === "Enter") && videoData.type === "upload" && controls) {
|
|
517
517
|
e.preventDefault();
|
|
518
|
-
const
|
|
519
|
-
if (
|
|
520
|
-
if (
|
|
521
|
-
|
|
518
|
+
const video2 = videoRef.current;
|
|
519
|
+
if (video2) {
|
|
520
|
+
if (video2.paused) {
|
|
521
|
+
video2.play();
|
|
522
522
|
} else {
|
|
523
|
-
|
|
523
|
+
video2.pause();
|
|
524
524
|
}
|
|
525
525
|
}
|
|
526
526
|
}
|
|
@@ -1051,6 +1051,23 @@ function ScrollRestoration() {
|
|
|
1051
1051
|
|
|
1052
1052
|
// src/router/index.ts
|
|
1053
1053
|
import { Route, Switch, useParams } from "wouter";
|
|
1054
|
+
|
|
1055
|
+
// src/lib/content-helpers.ts
|
|
1056
|
+
function text(content) {
|
|
1057
|
+
return content;
|
|
1058
|
+
}
|
|
1059
|
+
function image(config) {
|
|
1060
|
+
return JSON.stringify(config);
|
|
1061
|
+
}
|
|
1062
|
+
function background(config) {
|
|
1063
|
+
return JSON.stringify(config);
|
|
1064
|
+
}
|
|
1065
|
+
function video(config) {
|
|
1066
|
+
return JSON.stringify(config);
|
|
1067
|
+
}
|
|
1068
|
+
function embed(config) {
|
|
1069
|
+
return JSON.stringify(config);
|
|
1070
|
+
}
|
|
1054
1071
|
export {
|
|
1055
1072
|
ContentStoreProvider,
|
|
1056
1073
|
Link,
|
|
@@ -1072,10 +1089,13 @@ export {
|
|
|
1072
1089
|
StaticLink as YaLink,
|
|
1073
1090
|
MpText as YaText,
|
|
1074
1091
|
StaticVideo as YaVideo,
|
|
1092
|
+
background,
|
|
1075
1093
|
contentRegistry,
|
|
1094
|
+
embed,
|
|
1076
1095
|
getAllContent,
|
|
1077
1096
|
getContent,
|
|
1078
1097
|
hasContent,
|
|
1098
|
+
image,
|
|
1079
1099
|
parseBackgroundConfig,
|
|
1080
1100
|
parseEmbedUrl,
|
|
1081
1101
|
registerContent,
|
|
@@ -1084,7 +1104,9 @@ export {
|
|
|
1084
1104
|
serializeEmbedValue,
|
|
1085
1105
|
serializeVideoValue,
|
|
1086
1106
|
setAssetResolver,
|
|
1107
|
+
text,
|
|
1087
1108
|
useContentStore,
|
|
1088
1109
|
useNavigate,
|
|
1089
|
-
useParams
|
|
1110
|
+
useParams,
|
|
1111
|
+
video
|
|
1090
1112
|
};
|
package/package.json
CHANGED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import React$1, { ReactNode } from 'react';
|
|
3
|
-
|
|
4
|
-
type EditMode = 'read-only' | 'inline-edit';
|
|
5
|
-
interface ContentStore {
|
|
6
|
-
getValue: (fieldId: string) => string;
|
|
7
|
-
setValue: (fieldId: string, value: string) => void;
|
|
8
|
-
mode: EditMode;
|
|
9
|
-
setMode: (mode: EditMode) => void;
|
|
10
|
-
subscribe: (listener: () => void) => () => void;
|
|
11
|
-
saveToWorker?: (fieldId: string, value: string) => Promise<void>;
|
|
12
|
-
}
|
|
13
|
-
declare function useContentStore(): ContentStore;
|
|
14
|
-
interface ContentStoreProviderProps {
|
|
15
|
-
children: ReactNode;
|
|
16
|
-
initialContent?: Record<string, string>;
|
|
17
|
-
initialMode?: EditMode;
|
|
18
|
-
}
|
|
19
|
-
declare function ContentStoreProvider({ children, initialContent }: ContentStoreProviderProps): react_jsx_runtime.JSX.Element;
|
|
20
|
-
|
|
21
|
-
type EmbedType = 'spotify' | 'soundcloud' | 'twitter' | 'instagram' | 'custom';
|
|
22
|
-
interface EmbedFieldValue {
|
|
23
|
-
/** Embed platform type */
|
|
24
|
-
type: EmbedType;
|
|
25
|
-
/** Embed URL or ID (platform-specific) */
|
|
26
|
-
src: string;
|
|
27
|
-
/** Original URL pasted by user (for editing) */
|
|
28
|
-
originalUrl?: string;
|
|
29
|
-
/** CSS aspect-ratio (e.g., "16/9", "1/1") */
|
|
30
|
-
aspectRatio?: string;
|
|
31
|
-
/** Fixed height in pixels (for audio players) */
|
|
32
|
-
height?: number;
|
|
33
|
-
/** Spotify-specific: content type */
|
|
34
|
-
spotifyType?: 'track' | 'album' | 'playlist' | 'episode' | 'show';
|
|
35
|
-
}
|
|
36
|
-
interface YaEmbedProps {
|
|
37
|
-
fieldId: string;
|
|
38
|
-
className?: string;
|
|
39
|
-
/** Default aspect ratio from props */
|
|
40
|
-
aspectRatio?: string;
|
|
41
|
-
/** Max width constraint */
|
|
42
|
-
maxWidth?: number;
|
|
43
|
-
/** Loading strategy */
|
|
44
|
-
loading?: 'lazy' | 'eager';
|
|
45
|
-
/** Default embed value (used when nothing in content store) */
|
|
46
|
-
defaultValue?: EmbedFieldValue;
|
|
47
|
-
}
|
|
48
|
-
interface ParsedEmbed {
|
|
49
|
-
type: EmbedType;
|
|
50
|
-
src: string;
|
|
51
|
-
originalUrl: string;
|
|
52
|
-
aspectRatio?: string;
|
|
53
|
-
height?: number;
|
|
54
|
-
spotifyType?: EmbedFieldValue['spotifyType'];
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Parse a URL and detect the embed platform
|
|
58
|
-
*/
|
|
59
|
-
declare function parseEmbedUrl(url: string): ParsedEmbed | null;
|
|
60
|
-
/**
|
|
61
|
-
* Serialize embed field value for storage
|
|
62
|
-
*/
|
|
63
|
-
declare function serializeEmbedValue(value: EmbedFieldValue): string;
|
|
64
|
-
declare function YaEmbed({ fieldId, className, aspectRatio: propAspectRatio, maxWidth, loading, defaultValue, }: YaEmbedProps): react_jsx_runtime.JSX.Element;
|
|
65
|
-
|
|
66
|
-
interface PageInfo {
|
|
67
|
-
path: string;
|
|
68
|
-
label: string;
|
|
69
|
-
}
|
|
70
|
-
interface YaLinkProps {
|
|
71
|
-
fieldId: string;
|
|
72
|
-
/** Default href if not set in content store */
|
|
73
|
-
href?: string;
|
|
74
|
-
className?: string;
|
|
75
|
-
/** Inline styles to apply to the link element */
|
|
76
|
-
style?: React$1.CSSProperties;
|
|
77
|
-
as?: 'a' | 'span';
|
|
78
|
-
children?: React$1.ReactNode;
|
|
79
|
-
/** Available pages for href dropdown (injected by template) */
|
|
80
|
-
availablePages?: PageInfo[];
|
|
81
|
-
/** Optional click handler called after navigation */
|
|
82
|
-
onClick?: () => void;
|
|
83
|
-
/** Target attribute for the link (e.g., "_blank" to open in new tab) */
|
|
84
|
-
target?: string;
|
|
85
|
-
/** Rel attribute for the link (e.g., "noopener noreferrer" for security) */
|
|
86
|
-
rel?: string;
|
|
87
|
-
}
|
|
88
|
-
declare module '@tiptap/core' {
|
|
89
|
-
interface Commands<ReturnType> {
|
|
90
|
-
fontSize: {
|
|
91
|
-
setFontSize: (fontSize: string) => ReturnType;
|
|
92
|
-
unsetFontSize: () => ReturnType;
|
|
93
|
-
};
|
|
94
|
-
fontWeight: {
|
|
95
|
-
setFontWeight: (fontWeight: string) => ReturnType;
|
|
96
|
-
unsetFontWeight: () => ReturnType;
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
declare function YaLink({ fieldId, href: defaultHref, className, style, as: Component, children, availablePages, onClick, target, rel }: YaLinkProps): react_jsx_runtime.JSX.Element;
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* StaticText Component - Production-only static text renderer
|
|
104
|
-
*
|
|
105
|
-
* This component replaces MpText in production builds via Vite alias.
|
|
106
|
-
* No editing capabilities, no Tiptap, no DOMPurify - minimal bundle size.
|
|
107
|
-
*
|
|
108
|
-
* Content from content.json is trusted because:
|
|
109
|
-
* 1. It's created in the builder using Tiptap (which controls allowed markup)
|
|
110
|
-
* 2. It's sanitized by SafeHtml when displayed in the builder
|
|
111
|
-
* 3. Users can't inject arbitrary HTML
|
|
112
|
-
*/
|
|
113
|
-
/** Common HTML elements that MpText can render as */
|
|
114
|
-
type MpTextElement = 'span' | 'div' | 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'strong' | 'em';
|
|
115
|
-
interface MpTextProps {
|
|
116
|
-
fieldId: string;
|
|
117
|
-
className?: string;
|
|
118
|
-
as?: MpTextElement;
|
|
119
|
-
/** Optional fallback content (used if fieldId not in store) */
|
|
120
|
-
children?: React.ReactNode;
|
|
121
|
-
}
|
|
122
|
-
declare function MpText({ fieldId, className, as: Component, children }: MpTextProps): react_jsx_runtime.JSX.Element;
|
|
123
|
-
|
|
124
|
-
type StaticTextProps = MpTextProps;
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* StaticImage Component - Production-only static image renderer
|
|
128
|
-
*
|
|
129
|
-
* This component replaces MpImage in production builds via Vite alias.
|
|
130
|
-
* No editing overlay, no click handlers, no postMessage - minimal bundle size.
|
|
131
|
-
*/
|
|
132
|
-
interface MpImageProps {
|
|
133
|
-
fieldId: string;
|
|
134
|
-
className?: string;
|
|
135
|
-
alt?: string;
|
|
136
|
-
objectFit?: 'cover' | 'contain' | 'fill';
|
|
137
|
-
objectPosition?: string;
|
|
138
|
-
loading?: 'lazy' | 'eager';
|
|
139
|
-
/** Fallback for backward compatibility with config.ts images */
|
|
140
|
-
fallbackSrc?: string;
|
|
141
|
-
/** Fallback alt text */
|
|
142
|
-
fallbackAlt?: string;
|
|
143
|
-
}
|
|
144
|
-
declare function MpImage({ fieldId, className, alt, objectFit: propObjectFit, objectPosition: propObjectPosition, loading, fallbackSrc, fallbackAlt, }: MpImageProps): react_jsx_runtime.JSX.Element;
|
|
145
|
-
|
|
146
|
-
type StaticImageProps = MpImageProps;
|
|
147
|
-
|
|
148
|
-
interface MarkdownTextProps {
|
|
149
|
-
content: string;
|
|
150
|
-
className?: string;
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* MarkdownText component - renders markdown content safely
|
|
154
|
-
*/
|
|
155
|
-
declare function MarkdownText({ content, className }: MarkdownTextProps): react_jsx_runtime.JSX.Element;
|
|
156
|
-
|
|
157
|
-
export { ContentStoreProvider as C, type EditMode as E, MpText as M, type PageInfo as P, type StaticTextProps as S, YaEmbed as Y, type ContentStore as a, MpImage as b, type StaticImageProps as c, MarkdownText as d, type MarkdownTextProps as e, type YaEmbedProps as f, type EmbedFieldValue as g, type EmbedType as h, YaLink as i, type YaLinkProps as j, parseEmbedUrl as p, serializeEmbedValue as s, useContentStore as u };
|