@yoamigo.com/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +11 -0
- package/README.md +81 -0
- package/dist/MarkdownText-mylt-QX-.d.ts +106 -0
- package/dist/api-client-D8FkeBAI.d.ts +40 -0
- package/dist/asset-resolver-BnIvDkVv.d.ts +72 -0
- package/dist/builder-selection-CYP91nRu.d.ts +6 -0
- package/dist/index.css +372 -0
- package/dist/index.d.ts +118 -0
- package/dist/index.js +2579 -0
- package/dist/lib-prod.d.ts +13 -0
- package/dist/lib-prod.js +108 -0
- package/dist/lib.d.ts +84 -0
- package/dist/lib.js +736 -0
- package/dist/plugin.d.ts +47 -0
- package/dist/plugin.js +96 -0
- package/dist/prod.d.ts +31 -0
- package/dist/prod.js +295 -0
- package/dist/router.d.ts +46 -0
- package/dist/router.js +42 -0
- package/package.json +115 -0
- package/src/styles/index.css +5 -0
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { UserConfig, Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* YoAmigo Vite Plugin
|
|
5
|
+
*
|
|
6
|
+
* Handles all the build-time configuration for YoAmigo templates:
|
|
7
|
+
* - React → Preact swap in production (smaller bundles)
|
|
8
|
+
* - Component aliasing: @yoamigo/core → @yoamigo/core/prod in production
|
|
9
|
+
* - Path aliases: @/ → src/
|
|
10
|
+
* - Environment variables: YA_* prefix
|
|
11
|
+
* - Build output configuration
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* ```ts
|
|
15
|
+
* // vite.config.ts
|
|
16
|
+
* import { defineConfig } from 'vite'
|
|
17
|
+
* import { yoamigoPlugin } from '@yoamigo/core/plugin'
|
|
18
|
+
*
|
|
19
|
+
* export default defineConfig({
|
|
20
|
+
* plugins: [yoamigoPlugin()],
|
|
21
|
+
* })
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
interface YoamigoPluginOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Additional Vite plugins to include
|
|
28
|
+
*/
|
|
29
|
+
plugins?: UserConfig['plugins'];
|
|
30
|
+
/**
|
|
31
|
+
* Additional path aliases
|
|
32
|
+
*/
|
|
33
|
+
aliases?: Record<string, string>;
|
|
34
|
+
/**
|
|
35
|
+
* Custom build options
|
|
36
|
+
*/
|
|
37
|
+
build?: UserConfig['build'];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Creates the YoAmigo Vite plugin configuration.
|
|
41
|
+
*
|
|
42
|
+
* @param options - Optional customization options
|
|
43
|
+
* @returns Array of Vite plugins
|
|
44
|
+
*/
|
|
45
|
+
declare function yoamigoPlugin(options?: YoamigoPluginOptions): Plugin[];
|
|
46
|
+
|
|
47
|
+
export { type YoamigoPluginOptions, yoamigoPlugin as default, yoamigoPlugin };
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// src/plugin/index.ts
|
|
2
|
+
import react from "@vitejs/plugin-react";
|
|
3
|
+
import preact from "@preact/preset-vite";
|
|
4
|
+
import path from "path";
|
|
5
|
+
function yoamigoPlugin(options = {}) {
|
|
6
|
+
const templateDir = process.cwd();
|
|
7
|
+
const resolveFromTemplate = (relativePath) => path.resolve(templateDir, relativePath);
|
|
8
|
+
return [
|
|
9
|
+
{
|
|
10
|
+
name: "yoamigo:config",
|
|
11
|
+
config(config, { mode }) {
|
|
12
|
+
const isProd = mode === "production";
|
|
13
|
+
const aliasArray = [
|
|
14
|
+
// Production aliases must come FIRST for priority
|
|
15
|
+
...isProd ? [
|
|
16
|
+
// === React -> Preact (must be first for broad matching) ===
|
|
17
|
+
{ find: "react", replacement: "preact/compat" },
|
|
18
|
+
{ find: "react-dom/test-utils", replacement: "preact/test-utils" },
|
|
19
|
+
{ find: "react-dom/client", replacement: "preact/compat/client" },
|
|
20
|
+
{ find: "react-dom", replacement: "preact/compat" },
|
|
21
|
+
{ find: "react/jsx-runtime", replacement: "preact/jsx-runtime" },
|
|
22
|
+
// === @yoamigo/core -> Production barrel ===
|
|
23
|
+
// Redirect the entire components import to use static versions.
|
|
24
|
+
// This removes Tiptap and editing UI from the production bundle.
|
|
25
|
+
{
|
|
26
|
+
find: /^@yoamigo\/core$/,
|
|
27
|
+
replacement: "@yoamigo/core/prod"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
find: /^@yoamigo\/core\/lib$/,
|
|
31
|
+
replacement: "@yoamigo/core/lib/prod"
|
|
32
|
+
}
|
|
33
|
+
] : [],
|
|
34
|
+
// === Template-specific path aliases ===
|
|
35
|
+
{ find: "@", replacement: resolveFromTemplate("./src") },
|
|
36
|
+
{ find: "@components", replacement: resolveFromTemplate("./src/components") },
|
|
37
|
+
{ find: "@lib", replacement: resolveFromTemplate("./src/lib") },
|
|
38
|
+
{ find: "@assets", replacement: resolveFromTemplate("./assets") },
|
|
39
|
+
// Add any custom aliases from options
|
|
40
|
+
...Object.entries(options.aliases || {}).map(([find, replacement]) => ({
|
|
41
|
+
find,
|
|
42
|
+
replacement: resolveFromTemplate(replacement)
|
|
43
|
+
}))
|
|
44
|
+
];
|
|
45
|
+
return {
|
|
46
|
+
plugins: [isProd ? preact() : react(), ...options.plugins || []],
|
|
47
|
+
// Expose YA_ prefixed env vars to client code
|
|
48
|
+
envPrefix: "YA_",
|
|
49
|
+
// Serve static files from public/ directory
|
|
50
|
+
publicDir: "public",
|
|
51
|
+
resolve: {
|
|
52
|
+
alias: aliasArray,
|
|
53
|
+
// Ensure single React instance across all packages (prevents "Invalid hook call" errors)
|
|
54
|
+
dedupe: ["react", "react-dom"]
|
|
55
|
+
},
|
|
56
|
+
server: {
|
|
57
|
+
port: 5173,
|
|
58
|
+
strictPort: false,
|
|
59
|
+
// Allow Vite to find next available port
|
|
60
|
+
hmr: {
|
|
61
|
+
// When behind a proxy (builder worker), HMR needs to connect through the proxy
|
|
62
|
+
// Setting these to undefined lets Vite auto-detect from the page URL
|
|
63
|
+
// This ensures HMR WebSocket connects to the proxy (router) not directly to Vite
|
|
64
|
+
clientPort: void 0,
|
|
65
|
+
host: void 0,
|
|
66
|
+
protocol: void 0
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
// Dynamic base URL for different deployment contexts:
|
|
70
|
+
// - Preview builds: /deploy-preview/{siteId}/ (passed via YA_BASE_URL env var)
|
|
71
|
+
// - Published builds: / (default, served from subdomain root)
|
|
72
|
+
// - Dev server: ignored (base only affects production builds)
|
|
73
|
+
base: process.env.YA_BASE_URL || "/",
|
|
74
|
+
build: {
|
|
75
|
+
outDir: "dist",
|
|
76
|
+
emptyOutDir: true,
|
|
77
|
+
rollupOptions: {
|
|
78
|
+
output: {
|
|
79
|
+
// Output to build/ to avoid confusion with public/assets/ (source images)
|
|
80
|
+
entryFileNames: "build/[name].[hash].js",
|
|
81
|
+
chunkFileNames: "build/[name].[hash].js",
|
|
82
|
+
assetFileNames: "build/[name].[hash].[ext]"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
...options.build
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
var plugin_default = yoamigoPlugin;
|
|
93
|
+
export {
|
|
94
|
+
plugin_default as default,
|
|
95
|
+
yoamigoPlugin
|
|
96
|
+
};
|
package/dist/prod.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
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, u as useContentStore } from './MarkdownText-mylt-QX-.js';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
|
|
5
|
+
interface StaticLinkProps {
|
|
6
|
+
fieldId: string;
|
|
7
|
+
href?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
as?: 'a' | 'span';
|
|
10
|
+
children?: React.ReactNode;
|
|
11
|
+
/** Optional click handler called after navigation */
|
|
12
|
+
onClick?: () => void;
|
|
13
|
+
}
|
|
14
|
+
declare function StaticLink({ fieldId, href: defaultHref, className, as: Component, children, onClick }: StaticLinkProps): react_jsx_runtime.JSX.Element;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* SafeHtml (Production) - Renders trusted HTML without sanitization.
|
|
18
|
+
*
|
|
19
|
+
* Content is trusted because:
|
|
20
|
+
* 1. It's created in the builder using Tiptap (controlled markup)
|
|
21
|
+
* 2. Sanitized by DOMPurify when saved in the builder
|
|
22
|
+
* 3. Users can't inject arbitrary HTML into content.json
|
|
23
|
+
*/
|
|
24
|
+
interface SafeHtmlProps {
|
|
25
|
+
content: string;
|
|
26
|
+
className?: string;
|
|
27
|
+
mode?: 'read-only' | 'inline-edit';
|
|
28
|
+
}
|
|
29
|
+
declare function SafeHtml({ content, className }: SafeHtmlProps): react_jsx_runtime.JSX.Element;
|
|
30
|
+
|
|
31
|
+
export { SafeHtml, type SafeHtmlProps, StaticLink, type StaticLinkProps, StaticLink as YaLink, type StaticLinkProps as YaLinkProps };
|
package/dist/prod.js
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
// src/components/ContentStoreProvider.prod.tsx
|
|
2
|
+
import { createContext, useContext } from "react";
|
|
3
|
+
|
|
4
|
+
// src/lib/content-registry.ts
|
|
5
|
+
var contentMap = /* @__PURE__ */ new Map();
|
|
6
|
+
function getContent(fieldId) {
|
|
7
|
+
return contentMap.get(fieldId) ?? "";
|
|
8
|
+
}
|
|
9
|
+
function getAllContent() {
|
|
10
|
+
return Object.fromEntries(contentMap);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// src/components/ContentStoreProvider.prod.tsx
|
|
14
|
+
import { jsx } from "react/jsx-runtime";
|
|
15
|
+
var contentMap2 = new Map(Object.entries(getAllContent()));
|
|
16
|
+
var staticStore = {
|
|
17
|
+
getValue: (fieldId) => contentMap2.get(fieldId) ?? "",
|
|
18
|
+
setValue: () => {
|
|
19
|
+
},
|
|
20
|
+
// No-op in production
|
|
21
|
+
mode: "read-only",
|
|
22
|
+
setMode: () => {
|
|
23
|
+
},
|
|
24
|
+
// No-op in production
|
|
25
|
+
subscribe: () => () => {
|
|
26
|
+
},
|
|
27
|
+
// No-op, return empty unsubscribe
|
|
28
|
+
saveToWorker: void 0
|
|
29
|
+
};
|
|
30
|
+
var ContentStoreContext = createContext(staticStore);
|
|
31
|
+
function useContentStore() {
|
|
32
|
+
return useContext(ContentStoreContext);
|
|
33
|
+
}
|
|
34
|
+
function ContentStoreProvider({ children }) {
|
|
35
|
+
return /* @__PURE__ */ jsx(ContentStoreContext.Provider, { value: staticStore, children });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/components/StaticText.tsx
|
|
39
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
40
|
+
function MpText({ fieldId, className, as: Component = "span", children }) {
|
|
41
|
+
const content = getContent(fieldId) || (typeof children === "string" ? children : "");
|
|
42
|
+
return /* @__PURE__ */ jsx2(
|
|
43
|
+
Component,
|
|
44
|
+
{
|
|
45
|
+
className,
|
|
46
|
+
"data-field-id": fieldId,
|
|
47
|
+
dangerouslySetInnerHTML: { __html: content }
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/lib/asset-resolver.ts
|
|
53
|
+
var assetResolver = (path) => path;
|
|
54
|
+
function resolveAssetUrl(path) {
|
|
55
|
+
if (!path) return "";
|
|
56
|
+
if (path.startsWith("http://") || path.startsWith("https://")) {
|
|
57
|
+
return path;
|
|
58
|
+
}
|
|
59
|
+
return assetResolver(path);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/components/StaticImage.tsx
|
|
63
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
64
|
+
function parseImageValue(value) {
|
|
65
|
+
if (!value) {
|
|
66
|
+
return { src: "" };
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(value);
|
|
70
|
+
if (typeof parsed === "object" && parsed.src) {
|
|
71
|
+
return parsed;
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
return { src: value };
|
|
76
|
+
}
|
|
77
|
+
function getObjectPosition(imageData) {
|
|
78
|
+
if (imageData.focalPoint) {
|
|
79
|
+
return `${imageData.focalPoint.x}% ${imageData.focalPoint.y}%`;
|
|
80
|
+
}
|
|
81
|
+
return imageData.objectPosition || "50% 50%";
|
|
82
|
+
}
|
|
83
|
+
function MpImage({
|
|
84
|
+
fieldId,
|
|
85
|
+
className,
|
|
86
|
+
alt,
|
|
87
|
+
objectFit: propObjectFit,
|
|
88
|
+
objectPosition: propObjectPosition,
|
|
89
|
+
loading = "lazy",
|
|
90
|
+
fallbackSrc,
|
|
91
|
+
fallbackAlt
|
|
92
|
+
}) {
|
|
93
|
+
const rawValue = getContent(fieldId);
|
|
94
|
+
const imageData = parseImageValue(rawValue);
|
|
95
|
+
const src = imageData.src || fallbackSrc || "";
|
|
96
|
+
const altText = imageData.alt || alt || fallbackAlt || "";
|
|
97
|
+
const objectFit = imageData.objectFit || propObjectFit || "cover";
|
|
98
|
+
const objectPosition = getObjectPosition(imageData) || propObjectPosition || "50% 50%";
|
|
99
|
+
return /* @__PURE__ */ jsx3(
|
|
100
|
+
"img",
|
|
101
|
+
{
|
|
102
|
+
src: resolveAssetUrl(src),
|
|
103
|
+
alt: altText,
|
|
104
|
+
className,
|
|
105
|
+
style: {
|
|
106
|
+
objectFit,
|
|
107
|
+
objectPosition
|
|
108
|
+
},
|
|
109
|
+
loading,
|
|
110
|
+
"data-field-id": fieldId
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/components/StaticLink.tsx
|
|
116
|
+
import { useLocation } from "wouter";
|
|
117
|
+
|
|
118
|
+
// src/components/SafeHtml.prod.tsx
|
|
119
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
120
|
+
function SafeHtml({ content, className }) {
|
|
121
|
+
return /* @__PURE__ */ jsx4(
|
|
122
|
+
"span",
|
|
123
|
+
{
|
|
124
|
+
className,
|
|
125
|
+
dangerouslySetInnerHTML: { __html: content }
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/components/StaticLink.tsx
|
|
131
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
132
|
+
function isInternalPath(path) {
|
|
133
|
+
if (!path) return false;
|
|
134
|
+
if (path.startsWith("#")) return false;
|
|
135
|
+
if (path.startsWith("//")) return false;
|
|
136
|
+
if (path.includes("://")) return false;
|
|
137
|
+
if (path.startsWith("mailto:") || path.startsWith("tel:")) return false;
|
|
138
|
+
return path.startsWith("/");
|
|
139
|
+
}
|
|
140
|
+
function StaticLink({ fieldId, href: defaultHref = "#", className, as: Component = "a", children, onClick }) {
|
|
141
|
+
const { getValue, mode } = useContentStore();
|
|
142
|
+
const [, navigate] = useLocation();
|
|
143
|
+
const textFieldId = `${fieldId}.text`;
|
|
144
|
+
const hrefFieldId = `${fieldId}.href`;
|
|
145
|
+
const storeText = getValue(textFieldId);
|
|
146
|
+
const storeHref = getValue(hrefFieldId);
|
|
147
|
+
const href = storeHref || defaultHref;
|
|
148
|
+
const hasStoreText = Boolean(storeText);
|
|
149
|
+
const hasStringChildren = typeof children === "string";
|
|
150
|
+
const hasReactChildren = children && !hasStringChildren;
|
|
151
|
+
const handleClick = (e) => {
|
|
152
|
+
if (href.startsWith("#")) {
|
|
153
|
+
e.preventDefault();
|
|
154
|
+
const targetId = href.substring(1);
|
|
155
|
+
const targetElement = document.getElementById(targetId);
|
|
156
|
+
if (targetElement) {
|
|
157
|
+
const navHeight = 118;
|
|
158
|
+
const targetPosition = targetElement.offsetTop - navHeight;
|
|
159
|
+
window.scrollTo({
|
|
160
|
+
top: targetPosition,
|
|
161
|
+
behavior: "smooth"
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
onClick?.();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (isInternalPath(href)) {
|
|
168
|
+
e.preventDefault();
|
|
169
|
+
navigate(href);
|
|
170
|
+
onClick?.();
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
onClick?.();
|
|
174
|
+
};
|
|
175
|
+
return /* @__PURE__ */ jsx5(
|
|
176
|
+
Component,
|
|
177
|
+
{
|
|
178
|
+
href: Component === "a" ? href : void 0,
|
|
179
|
+
onClick: handleClick,
|
|
180
|
+
className,
|
|
181
|
+
"data-ya-restricted": "true",
|
|
182
|
+
"data-field-id": fieldId,
|
|
183
|
+
children: hasStoreText || hasStringChildren ? /* @__PURE__ */ jsx5(SafeHtml, { content: storeText || children || "", mode }) : hasReactChildren ? children : null
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// src/components/MarkdownText.tsx
|
|
189
|
+
import { Fragment } from "react";
|
|
190
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
191
|
+
function tokenize(text) {
|
|
192
|
+
const tokens = [];
|
|
193
|
+
let remaining = text;
|
|
194
|
+
const patterns = [
|
|
195
|
+
// Bold: **text**
|
|
196
|
+
{ regex: /^\*\*(.+?)\*\*/, type: "bold" },
|
|
197
|
+
// Italic: *text* (but not **)
|
|
198
|
+
{ regex: /^\*([^*]+?)\*/, type: "italic" },
|
|
199
|
+
// Link: [text](url)
|
|
200
|
+
{ regex: /^\[([^\]]+)\]\(([^)]+)\)/, type: "link" },
|
|
201
|
+
// Newline
|
|
202
|
+
{ regex: /^\n/, type: "newline" }
|
|
203
|
+
];
|
|
204
|
+
while (remaining.length > 0) {
|
|
205
|
+
let matched = false;
|
|
206
|
+
for (const pattern of patterns) {
|
|
207
|
+
const match = remaining.match(pattern.regex);
|
|
208
|
+
if (match) {
|
|
209
|
+
if (pattern.type === "bold") {
|
|
210
|
+
tokens.push({ type: "bold", content: match[1] });
|
|
211
|
+
} else if (pattern.type === "italic") {
|
|
212
|
+
tokens.push({ type: "italic", content: match[1] });
|
|
213
|
+
} else if (pattern.type === "link") {
|
|
214
|
+
tokens.push({ type: "link", text: match[1], url: match[2] });
|
|
215
|
+
} else if (pattern.type === "newline") {
|
|
216
|
+
tokens.push({ type: "newline" });
|
|
217
|
+
}
|
|
218
|
+
remaining = remaining.slice(match[0].length);
|
|
219
|
+
matched = true;
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (!matched) {
|
|
224
|
+
const nextSpecial = remaining.search(/[*[\n]/);
|
|
225
|
+
if (nextSpecial === -1) {
|
|
226
|
+
tokens.push({ type: "text", content: remaining });
|
|
227
|
+
remaining = "";
|
|
228
|
+
} else if (nextSpecial === 0) {
|
|
229
|
+
tokens.push({ type: "text", content: remaining[0] });
|
|
230
|
+
remaining = remaining.slice(1);
|
|
231
|
+
} else {
|
|
232
|
+
tokens.push({ type: "text", content: remaining.slice(0, nextSpecial) });
|
|
233
|
+
remaining = remaining.slice(nextSpecial);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const merged = [];
|
|
238
|
+
for (const token of tokens) {
|
|
239
|
+
const last = merged[merged.length - 1];
|
|
240
|
+
if (token.type === "text" && last?.type === "text") {
|
|
241
|
+
last.content += token.content;
|
|
242
|
+
} else {
|
|
243
|
+
merged.push(token);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return merged;
|
|
247
|
+
}
|
|
248
|
+
function tokensToElements(tokens) {
|
|
249
|
+
return tokens.map((token, index) => {
|
|
250
|
+
switch (token.type) {
|
|
251
|
+
case "text":
|
|
252
|
+
return /* @__PURE__ */ jsx6(Fragment, { children: token.content }, index);
|
|
253
|
+
case "bold":
|
|
254
|
+
return /* @__PURE__ */ jsx6("strong", { children: token.content }, index);
|
|
255
|
+
case "italic":
|
|
256
|
+
return /* @__PURE__ */ jsx6("em", { children: token.content }, index);
|
|
257
|
+
case "link":
|
|
258
|
+
return /* @__PURE__ */ jsx6(
|
|
259
|
+
"a",
|
|
260
|
+
{
|
|
261
|
+
href: token.url,
|
|
262
|
+
target: "_blank",
|
|
263
|
+
rel: "noopener noreferrer",
|
|
264
|
+
className: "text-[var(--color-primary)] underline hover:text-[var(--color-secondary)]",
|
|
265
|
+
children: token.text
|
|
266
|
+
},
|
|
267
|
+
index
|
|
268
|
+
);
|
|
269
|
+
case "newline":
|
|
270
|
+
return /* @__PURE__ */ jsx6("br", {}, index);
|
|
271
|
+
default:
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
function parseMarkdownToElements(content) {
|
|
277
|
+
const tokens = tokenize(content);
|
|
278
|
+
return tokensToElements(tokens);
|
|
279
|
+
}
|
|
280
|
+
function MarkdownText({ content, className }) {
|
|
281
|
+
const elements = parseMarkdownToElements(content);
|
|
282
|
+
return /* @__PURE__ */ jsx6("span", { className, children: elements });
|
|
283
|
+
}
|
|
284
|
+
export {
|
|
285
|
+
ContentStoreProvider,
|
|
286
|
+
MarkdownText,
|
|
287
|
+
SafeHtml,
|
|
288
|
+
MpImage as StaticImage,
|
|
289
|
+
StaticLink,
|
|
290
|
+
MpText as StaticText,
|
|
291
|
+
MpImage as YaImage,
|
|
292
|
+
StaticLink as YaLink,
|
|
293
|
+
MpText as YaText,
|
|
294
|
+
useContentStore
|
|
295
|
+
};
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode, MouseEvent } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Router Abstraction - Shared Types
|
|
6
|
+
*
|
|
7
|
+
* These types are used by both development (React Router) and
|
|
8
|
+
* production (wouter) router implementations.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
interface LinkProps {
|
|
12
|
+
/** Target path (alias: href) */
|
|
13
|
+
to?: string;
|
|
14
|
+
/** Target path (alias: to) */
|
|
15
|
+
href?: string;
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
className?: string;
|
|
18
|
+
onClick?: (e: MouseEvent<HTMLAnchorElement>) => void;
|
|
19
|
+
replace?: boolean;
|
|
20
|
+
[key: string]: unknown;
|
|
21
|
+
}
|
|
22
|
+
interface RouterProps$1 {
|
|
23
|
+
children: ReactNode;
|
|
24
|
+
base?: string;
|
|
25
|
+
}
|
|
26
|
+
type NavigateFunction = (to: string, options?: {
|
|
27
|
+
replace?: boolean;
|
|
28
|
+
}) => void;
|
|
29
|
+
|
|
30
|
+
declare function Link({ to, href, children, className, onClick, replace, ...props }: LinkProps): react_jsx_runtime.JSX.Element;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* useNavigate Hook - Production (wouter)
|
|
34
|
+
*
|
|
35
|
+
* Provides React Router-like useNavigate API using wouter's useLocation.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
declare function useNavigate(): NavigateFunction;
|
|
39
|
+
|
|
40
|
+
interface RouterProps {
|
|
41
|
+
children: ReactNode;
|
|
42
|
+
base?: string;
|
|
43
|
+
}
|
|
44
|
+
declare function Router({ children, base }: RouterProps): react_jsx_runtime.JSX.Element;
|
|
45
|
+
|
|
46
|
+
export { Link, type LinkProps, type NavigateFunction, Router, type RouterProps$1 as RouterProps, useNavigate };
|
package/dist/router.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// src/router/Link.tsx
|
|
2
|
+
import { Link as WouterLink } from "wouter";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
function Link({ to, href, children, className, onClick, replace, ...props }) {
|
|
5
|
+
const target = href ?? to ?? "/";
|
|
6
|
+
return /* @__PURE__ */ jsx(WouterLink, { href: target, className, onClick, replace, ...props, children });
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// src/router/useNavigate.ts
|
|
10
|
+
import { useLocation } from "wouter";
|
|
11
|
+
function useNavigate() {
|
|
12
|
+
const [, setLocation] = useLocation();
|
|
13
|
+
return (to, options) => {
|
|
14
|
+
if (options?.replace) {
|
|
15
|
+
window.history.replaceState(null, "", to);
|
|
16
|
+
setLocation(to);
|
|
17
|
+
} else {
|
|
18
|
+
setLocation(to);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/router/Router.tsx
|
|
24
|
+
import { Router as WouterRouter } from "wouter";
|
|
25
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
26
|
+
function detectBasename() {
|
|
27
|
+
if (typeof window === "undefined") return "";
|
|
28
|
+
const sessionMatch = window.location.pathname.match(/^\/session\/[^/]+/);
|
|
29
|
+
if (sessionMatch) return sessionMatch[0];
|
|
30
|
+
const previewMatch = window.location.pathname.match(/^\/deploy-preview\/[^/]+/);
|
|
31
|
+
if (previewMatch) return previewMatch[0];
|
|
32
|
+
return "";
|
|
33
|
+
}
|
|
34
|
+
function Router({ children, base }) {
|
|
35
|
+
const basename = base ?? detectBasename();
|
|
36
|
+
return /* @__PURE__ */ jsx2(WouterRouter, { base: basename, children });
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
Link,
|
|
40
|
+
Router,
|
|
41
|
+
useNavigate
|
|
42
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yoamigo.com/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Core components, router, and utilities for YoAmigo templates",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./plugin": {
|
|
15
|
+
"types": "./dist/plugin.d.ts",
|
|
16
|
+
"import": "./dist/plugin.js"
|
|
17
|
+
},
|
|
18
|
+
"./prod": {
|
|
19
|
+
"types": "./dist/prod.d.ts",
|
|
20
|
+
"import": "./dist/prod.js"
|
|
21
|
+
},
|
|
22
|
+
"./router": {
|
|
23
|
+
"types": "./dist/router.d.ts",
|
|
24
|
+
"import": "./dist/router.js"
|
|
25
|
+
},
|
|
26
|
+
"./lib": {
|
|
27
|
+
"types": "./dist/lib.d.ts",
|
|
28
|
+
"import": "./dist/lib.js"
|
|
29
|
+
},
|
|
30
|
+
"./lib/prod": {
|
|
31
|
+
"types": "./dist/lib-prod.d.ts",
|
|
32
|
+
"import": "./dist/lib-prod.js"
|
|
33
|
+
},
|
|
34
|
+
"./styles": "./src/styles/index.css",
|
|
35
|
+
"./styles/*": "./src/styles/*"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"src/styles",
|
|
40
|
+
"LICENSE",
|
|
41
|
+
"README.md"
|
|
42
|
+
],
|
|
43
|
+
"sideEffects": [
|
|
44
|
+
"*.css"
|
|
45
|
+
],
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "https://github.com/yoamigo/sdk.git",
|
|
52
|
+
"directory": "packages/yoamigo-core"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://yoamigo.com/developers",
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/yoamigo/sdk/issues"
|
|
57
|
+
},
|
|
58
|
+
"keywords": [
|
|
59
|
+
"yoamigo",
|
|
60
|
+
"vite",
|
|
61
|
+
"vite-plugin",
|
|
62
|
+
"template",
|
|
63
|
+
"react",
|
|
64
|
+
"preact",
|
|
65
|
+
"website-builder"
|
|
66
|
+
],
|
|
67
|
+
"scripts": {
|
|
68
|
+
"build": "tsup",
|
|
69
|
+
"dev": "tsup --watch",
|
|
70
|
+
"typecheck": "tsc --noEmit",
|
|
71
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
72
|
+
"lint:check": "eslint src --ext .ts,.tsx"
|
|
73
|
+
},
|
|
74
|
+
"dependencies": {
|
|
75
|
+
"clsx": "^2.1.1",
|
|
76
|
+
"preact": "^10.27.2",
|
|
77
|
+
"wouter": "^3.8.0"
|
|
78
|
+
},
|
|
79
|
+
"devDependencies": {
|
|
80
|
+
"@preact/preset-vite": "^2.8.0",
|
|
81
|
+
"@tiptap/core": "^3.11.1",
|
|
82
|
+
"@tiptap/extension-link": "^3.11.1",
|
|
83
|
+
"@tiptap/extension-text-style": "^3.11.1",
|
|
84
|
+
"@tiptap/pm": "^3.11.1",
|
|
85
|
+
"@tiptap/react": "^3.11.1",
|
|
86
|
+
"@tiptap/starter-kit": "^3.11.1",
|
|
87
|
+
"@types/dompurify": "^3.0.5",
|
|
88
|
+
"@types/node": "^20.0.0",
|
|
89
|
+
"@types/react": "^19.2.1",
|
|
90
|
+
"@types/react-dom": "^19.2.1",
|
|
91
|
+
"@vitejs/plugin-react": "^5.1.0",
|
|
92
|
+
"dompurify": "^3.2.3",
|
|
93
|
+
"react": "^19.2.1",
|
|
94
|
+
"react-dom": "^19.2.1",
|
|
95
|
+
"tsup": "^8.5.0",
|
|
96
|
+
"typescript": "^5.9.3",
|
|
97
|
+
"vite": "^7.2.4"
|
|
98
|
+
},
|
|
99
|
+
"peerDependencies": {
|
|
100
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
101
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
102
|
+
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
|
|
103
|
+
},
|
|
104
|
+
"peerDependenciesMeta": {
|
|
105
|
+
"react": {
|
|
106
|
+
"optional": true
|
|
107
|
+
},
|
|
108
|
+
"react-dom": {
|
|
109
|
+
"optional": true
|
|
110
|
+
},
|
|
111
|
+
"vite": {
|
|
112
|
+
"optional": true
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|