@yoamigo.com/core 0.4.0 → 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.
@@ -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,7 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import React$1, { ReactNode, CSSProperties } from 'react';
3
- import { f as EmbedFieldValue } from './MarkdownText-_ykp-njt.js';
4
- export { C as ContentStoreProviderProd, h as EmbedType, d as MarkdownText, e as MarkdownTextProps, P as PageInfo, b as StaticImage, c as StaticImageProps, M as StaticText, S as StaticTextProps, Y as YaEmbed, g as YaEmbedProps, i as YaLink, j as YaLinkProps, p as parseEmbedUrl, s as serializeEmbedValue, u as useContentStoreProd } from './MarkdownText-_ykp-njt.js';
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';
5
4
  export { Link, LinkProps, NavigateFunction, Router, RouterProps, ScrollRestoration, useNavigate } from './router.js';
6
5
  export { Route, Switch, useParams } from 'wouter';
7
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';
@@ -63,122 +62,6 @@ declare module '@tiptap/core' {
63
62
  }
64
63
  declare function YaText({ fieldId, className, as: Component, children }: YaTextProps): react_jsx_runtime.JSX.Element;
65
64
 
66
- interface ImageFieldValue {
67
- src: string;
68
- alt?: string;
69
- objectFit?: 'cover' | 'contain' | 'fill';
70
- objectPosition?: string;
71
- focalPoint?: {
72
- x: number;
73
- y: number;
74
- };
75
- }
76
- interface YaImageProps {
77
- fieldId: string;
78
- className?: string;
79
- alt?: string;
80
- objectFit?: 'cover' | 'contain' | 'fill';
81
- objectPosition?: string;
82
- loading?: 'lazy' | 'eager';
83
- /** Fallback for backward compatibility with config.ts images */
84
- fallbackSrc?: string;
85
- /** Fallback alt text */
86
- fallbackAlt?: string;
87
- }
88
- /**
89
- * Serialize image field value for storage
90
- */
91
- declare function serializeImageValue(value: ImageFieldValue): string;
92
- declare function YaImage({ fieldId, className, alt, objectFit: propObjectFit, objectPosition: propObjectPosition, loading, fallbackSrc, fallbackAlt, }: YaImageProps): react_jsx_runtime.JSX.Element;
93
-
94
- interface VideoFieldValue {
95
- /** Video source type */
96
- type: 'upload' | 'youtube' | 'vimeo';
97
- /** Video URL (for upload) or video ID (for embeds) */
98
- src: string;
99
- /** Poster image URL */
100
- poster?: string;
101
- /** Autoplay video (requires muted for browser policy) */
102
- autoplay?: boolean;
103
- /** Mute video audio */
104
- muted?: boolean;
105
- /** Loop video playback */
106
- loop?: boolean;
107
- /** Show video controls */
108
- controls?: boolean;
109
- /** Play inline on mobile (prevent fullscreen hijack) */
110
- playsinline?: boolean;
111
- /** Preload strategy */
112
- preload?: 'none' | 'metadata' | 'auto';
113
- /** CSS object-fit */
114
- objectFit?: 'cover' | 'contain' | 'fill';
115
- /** CSS aspect-ratio (e.g., "16/9") */
116
- aspectRatio?: string;
117
- /** Start playback at this time (seconds) */
118
- startTime?: number;
119
- /** End playback at this time (seconds) */
120
- endTime?: number;
121
- }
122
- interface YaVideoProps {
123
- fieldId: string;
124
- className?: string;
125
- /** Default aspect ratio from props */
126
- aspectRatio?: string;
127
- /** Default object-fit */
128
- objectFit?: 'cover' | 'contain' | 'fill';
129
- /** Loading strategy */
130
- loading?: 'lazy' | 'eager';
131
- /** Default video value (used when nothing in content store) */
132
- defaultValue?: VideoFieldValue;
133
- /** Fallback for backward compatibility (deprecated: use defaultValue) */
134
- fallbackSrc?: string;
135
- /** Fallback poster image */
136
- fallbackPoster?: string;
137
- }
138
- /**
139
- * Serialize video field value for storage
140
- */
141
- declare function serializeVideoValue(value: VideoFieldValue): string;
142
- declare function YaVideo({ fieldId, className, aspectRatio: propAspectRatio, objectFit: propObjectFit, loading, defaultValue, fallbackSrc, fallbackPoster, }: YaVideoProps): react_jsx_runtime.JSX.Element;
143
-
144
- interface BackgroundImageConfig {
145
- src: string;
146
- objectFit?: 'cover' | 'contain' | 'fill';
147
- objectPosition?: string;
148
- focalPoint?: {
149
- x: number;
150
- y: number;
151
- };
152
- }
153
- interface OverlayConfig {
154
- color: string;
155
- opacity: number;
156
- }
157
- interface BackgroundConfig {
158
- type: 'none' | 'color' | 'image';
159
- backgroundColor?: string;
160
- backgroundImage?: BackgroundImageConfig;
161
- overlay?: OverlayConfig;
162
- }
163
- interface YaContainerProps {
164
- fieldId: string;
165
- className?: string;
166
- style?: CSSProperties;
167
- as?: 'section' | 'div' | 'article' | 'header' | 'footer' | 'main' | 'aside';
168
- children: ReactNode;
169
- /** Fallback background config if not in store */
170
- defaultBackground?: BackgroundConfig;
171
- }
172
- /**
173
- * Parse background config from content store
174
- */
175
- declare function parseBackgroundConfig(value: string): BackgroundConfig;
176
- /**
177
- * Serialize background config for storage
178
- */
179
- declare function serializeBackgroundConfig(config: BackgroundConfig): string;
180
- declare function YaContainer({ fieldId, className, style, as: Tag, children, defaultBackground, }: YaContainerProps): react_jsx_runtime.JSX.Element;
181
-
182
65
  /**
183
66
  * SafeHtml Component - Secure HTML Renderer
184
67
  *
@@ -230,109 +113,6 @@ interface SafeTriangleBelowProps {
230
113
  */
231
114
  declare function SafeTriangleBelow({ triggerRef, popoverRef, isVisible, onLeave, onStayInside, }: SafeTriangleBelowProps): null;
232
115
 
233
- /**
234
- * Content Helpers for content.ts
235
- *
236
- * Type-safe helper functions for creating content values.
237
- * These eliminate the need for manual JSON.stringify() and escaping.
238
- *
239
- * Usage:
240
- * ```ts
241
- * import { text, image, background, video, embed } from '@yoamigo.com/core'
242
- *
243
- * export default {
244
- * "hero.title": text("Welcome to Our Site"),
245
- * "profile.image": image({ src: "/photo.jpg", alt: "Headshot" }),
246
- * "hero.background": background({ type: "color", backgroundColor: "#000" }),
247
- * } as const satisfies Record<string, string>
248
- * ```
249
- */
250
-
251
- /**
252
- * Text content for YaText fields.
253
- *
254
- * Supports HTML formatting:
255
- * - `<strong>`, `<b>` for bold
256
- * - `<em>`, `<i>` for italic
257
- * - `<a href="...">` for links
258
- * - `<span style="...">` for inline styles
259
- * - `<br>` for line breaks
260
- *
261
- * Allowed inline styles: font-size, font-weight
262
- *
263
- * @example
264
- * text("Hello World")
265
- * text("Welcome to <strong>YoAmigo</strong>")
266
- * text('<span style="font-size: 20px">Large text</span>')
267
- */
268
- declare function text(content: string): string;
269
- /**
270
- * Image field value for YaImage components.
271
- *
272
- * @example
273
- * image({ src: "/photo.jpg", alt: "Description" })
274
- * image({ src: "/hero.jpg", objectFit: "cover", objectPosition: "center top" })
275
- * image({ src: "/profile.jpg", focalPoint: { x: 50, y: 30 } })
276
- */
277
- declare function image(config: ImageFieldValue): string;
278
- /**
279
- * Background config for YaContainer components.
280
- *
281
- * @example
282
- * // Solid color
283
- * background({ type: "color", backgroundColor: "#000" })
284
- *
285
- * // Image background
286
- * background({
287
- * type: "image",
288
- * backgroundImage: { src: "/bg.jpg", objectFit: "cover" }
289
- * })
290
- *
291
- * // Image with overlay
292
- * background({
293
- * type: "image",
294
- * backgroundImage: { src: "/bg.jpg" },
295
- * overlay: { color: "#000", opacity: 0.5 }
296
- * })
297
- *
298
- * // No background (transparent)
299
- * background({ type: "none" })
300
- */
301
- declare function background(config: BackgroundConfig): string;
302
- /**
303
- * Video field value for YaVideo components.
304
- *
305
- * @example
306
- * // YouTube video
307
- * video({ type: "youtube", src: "dQw4w9WgXcQ" })
308
- *
309
- * // Vimeo video
310
- * video({ type: "vimeo", src: "123456789" })
311
- *
312
- * // Uploaded video
313
- * video({ type: "upload", src: "/videos/intro.mp4" })
314
- *
315
- * // With options
316
- * video({ type: "youtube", src: "dQw4w9WgXcQ", autoplay: true, muted: true, loop: true })
317
- */
318
- declare function video(config: VideoFieldValue): string;
319
- /**
320
- * Embed field value for YaEmbed components.
321
- *
322
- * Supports: Spotify, SoundCloud, Twitter/X, Instagram
323
- *
324
- * @example
325
- * // Spotify track
326
- * embed({ type: "spotify", src: "track/4PTG3Z6", spotifyType: "track" })
327
- *
328
- * // Spotify playlist
329
- * embed({ type: "spotify", src: "playlist/37i9dQZF1DXcBWIGoYBM5M", spotifyType: "playlist" })
330
- *
331
- * // SoundCloud
332
- * embed({ type: "soundcloud", src: "user/track" })
333
- */
334
- declare function embed(config: EmbedFieldValue): string;
335
-
336
116
  /**
337
117
  * Animation state for a single field
338
118
  */
@@ -779,4 +559,4 @@ interface UseSafeTriangleReturn<T extends HTMLElement, U extends HTMLElement> {
779
559
  */
780
560
  declare function useSafeTriangle<T extends HTMLElement = HTMLElement, U extends HTMLElement = HTMLDivElement>(options?: UseSafeTriangleOptions): UseSafeTriangleReturn<T, U>;
781
561
 
782
- export { type AIEditContextValue, AIEditProvider, type AnimatedTextOptions, type AnimatedTextResult, type AnimationConfig, type AnimationMetadata, type AnimationOptions, type AnimationPhase, type AnimationResult, type AnimationState, type AnimationStrategy, type BackgroundConfig, type BackgroundImageConfig, type ContentStoreContextType, type ContentStoreMode, ContentStoreProvider, EmbedFieldValue, type ImageFieldValue, type ImageValue, type LinkValue, type OverlayConfig, SafeHtml, type SafeHtmlProps, SafeTriangleBelow, type TextAnimationMetadata, type TextDiff, type VideoFieldValue, YaContainer, type YaContainerProps, YaImage, type YaImageProps, YaText, type YaTextProps, YaVideo, type YaVideoProps, background, buildIntermediateText, calculateAnimationTiming, computeTextDiff, containsHtml, embed, getTextCursorPosition, image, imageCrossfadeStrategy, linkTransitionStrategy, parseBackgroundConfig, serializeBackgroundConfig, serializeImageValue, serializeVideoValue, stripHtml, text, textTypingStrategy, useAIEditAnimation, useAIEditContext, useAIEditContextOptional, useAnimatedText, useContentStore, useSafeTriangle, video };
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/prod.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { a as ContentStore, E as ContentStoreMode, C as ContentStoreProvider, d as MarkdownText, e as MarkdownTextProps, P as PageInfo, b as StaticImage, c as StaticImageProps, M as StaticText, S as StaticTextProps, b as YaImage, c as YaImageProps, M as YaText, S as YaTextProps, p as parseEmbedUrl, u as useContentStore } from './MarkdownText-_ykp-njt.js';
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(text) {
244
+ function tokenize(text2) {
245
245
  const tokens = [];
246
- let remaining = text;
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 video = videoRef.current;
519
- if (video) {
520
- if (video.paused) {
521
- video.play();
518
+ const video2 = videoRef.current;
519
+ if (video2) {
520
+ if (video2.paused) {
521
+ video2.play();
522
522
  } else {
523
- video.pause();
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@yoamigo.com/core",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Core components, router, and utilities for YoAmigo templates",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -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 EmbedFieldValue as f, type YaEmbedProps as g, type EmbedType as h, YaLink as i, type YaLinkProps as j, parseEmbedUrl as p, serializeEmbedValue as s, useContentStore as u };