@emberkit/core 0.1.2-alpha.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.
Files changed (62) hide show
  1. package/LICENSE +199 -0
  2. package/dist/boundaries/error-boundary.js +70 -0
  3. package/dist/boundaries/errors.js +72 -0
  4. package/dist/boundaries/index.js +3 -0
  5. package/dist/boundaries/loading-boundary.js +106 -0
  6. package/dist/cache/index.js +213 -0
  7. package/dist/compiler/compiler.js +44 -0
  8. package/dist/compiler/helpers/attributes.js +35 -0
  9. package/dist/compiler/helpers/utils.js +31 -0
  10. package/dist/compiler/index.js +4 -0
  11. package/dist/compiler/types.js +3 -0
  12. package/dist/context/index.js +51 -0
  13. package/dist/context/types.js +1 -0
  14. package/dist/dev-server/index.js +121 -0
  15. package/dist/forms/index.js +164 -0
  16. package/dist/forms/mutations.js +258 -0
  17. package/dist/hmr/client.js +84 -0
  18. package/dist/hmr/index.js +2 -0
  19. package/dist/hmr/types.js +133 -0
  20. package/dist/hydration/helpers/analyzer.js +94 -0
  21. package/dist/hydration/helpers/hydration.js +129 -0
  22. package/dist/hydration/index.js +3 -0
  23. package/dist/hydration/types.js +18 -0
  24. package/dist/image/index.js +34 -0
  25. package/dist/image/processor.js +143 -0
  26. package/dist/index.js +16 -0
  27. package/dist/jsx-dev-runtime.js +7 -0
  28. package/dist/jsx-runtime.js +7 -0
  29. package/dist/loader/helpers/loader.js +61 -0
  30. package/dist/loader/index.js +2 -0
  31. package/dist/loader/types.js +14 -0
  32. package/dist/markdown/index.js +365 -0
  33. package/dist/mdx/index.js +156 -0
  34. package/dist/mdx/loader.js +6 -0
  35. package/dist/meta/head-registry.js +15 -0
  36. package/dist/meta/head.js +100 -0
  37. package/dist/meta/index.js +210 -0
  38. package/dist/navigation/helpers/navigation.js +53 -0
  39. package/dist/navigation/helpers/useNavigate.js +10 -0
  40. package/dist/navigation/index.js +3 -0
  41. package/dist/navigation/types.js +2 -0
  42. package/dist/plugin/index.js +74 -0
  43. package/dist/router/helpers/path.js +74 -0
  44. package/dist/router/helpers/route.js +109 -0
  45. package/dist/router/index.js +110 -0
  46. package/dist/router/types.js +5 -0
  47. package/dist/runtime/helpers/element.js +52 -0
  48. package/dist/runtime/helpers/render.js +121 -0
  49. package/dist/runtime/index.js +132 -0
  50. package/dist/runtime/types.js +1 -0
  51. package/dist/signals/helpers/core.js +96 -0
  52. package/dist/signals/helpers/utils.js +22 -0
  53. package/dist/signals/index.js +3 -0
  54. package/dist/signals/types.js +1 -0
  55. package/dist/ssg/index.js +119 -0
  56. package/dist/ssr/helpers/render-html.js +55 -0
  57. package/dist/ssr/helpers/ssr.js +90 -0
  58. package/dist/ssr/index.js +3 -0
  59. package/dist/ssr/types.js +24 -0
  60. package/dist/vite-plugin/index.js +650 -0
  61. package/dist/vite-plugin/types.js +13 -0
  62. package/package.json +66 -0
@@ -0,0 +1,156 @@
1
+ import { parseMarkdown } from '../markdown/index.js';
2
+ class MDXCompiler {
3
+ config;
4
+ components;
5
+ constructor(config = {}) {
6
+ this.config = config;
7
+ this.components = new Map(Object.entries(config.components ?? {}));
8
+ }
9
+ compile(source) {
10
+ const parsed = parseMarkdown(source, { gfm: this.config.gfm, breaks: this.config.breaks, tables: this.config.tables });
11
+ const { html, frontmatter } = parsed;
12
+ const componentCode = this.generateComponent(html);
13
+ return this.createComponent(componentCode, frontmatter);
14
+ }
15
+ generateComponent(html) {
16
+ const headings = this.extractHeadingIds(html);
17
+ const paragraphs = this.splitParagraphs(html);
18
+ let code = 'return (';
19
+ for (const p of paragraphs) {
20
+ if (p.startsWith('<h')) {
21
+ code += p;
22
+ }
23
+ else if (p.startsWith('<ul') || p.startsWith('<ol')) {
24
+ code += p;
25
+ }
26
+ else if (p.startsWith('<pre')) {
27
+ code += p;
28
+ }
29
+ else if (p.startsWith('<blockquote')) {
30
+ code += p;
31
+ }
32
+ else if (p.startsWith('<table')) {
33
+ code += p;
34
+ }
35
+ else {
36
+ code += `<p>${p}</p>`;
37
+ }
38
+ }
39
+ code += ')';
40
+ return code;
41
+ }
42
+ extractHeadingIds(html) {
43
+ const ids = [];
44
+ const regex = /id="([^"]+)"/g;
45
+ let match;
46
+ while ((match = regex.exec(html)) !== null) {
47
+ ids.push(match[1]);
48
+ }
49
+ return ids;
50
+ }
51
+ splitParagraphs(html) {
52
+ return html
53
+ .split(/\n\n+/)
54
+ .map((p) => p.trim())
55
+ .filter(Boolean);
56
+ }
57
+ createComponent(code, frontmatter) {
58
+ try {
59
+ const fn = new Function('createElement', code);
60
+ const component = (props) => {
61
+ const element = fn(createElementProxy);
62
+ return element;
63
+ };
64
+ if (frontmatter) {
65
+ component.frontmatter = frontmatter;
66
+ }
67
+ return component;
68
+ }
69
+ catch (error) {
70
+ console.error('MDX compilation error:', error);
71
+ return () => ({ type: 'div', props: { children: 'MDX Error' } });
72
+ }
73
+ }
74
+ registerComponent(name, component) {
75
+ this.components.set(name, component);
76
+ }
77
+ unregisterComponent(name) {
78
+ this.components.delete(name);
79
+ }
80
+ getComponent(name) {
81
+ return this.components.get(name);
82
+ }
83
+ }
84
+ const createElementProxy = {
85
+ createElement(tag, props, ...children) {
86
+ return {
87
+ type: tag,
88
+ props: {
89
+ ...props,
90
+ children: children.length === 1 ? children[0] : children,
91
+ },
92
+ };
93
+ },
94
+ };
95
+ export function createMDXCompiler(config) {
96
+ return new MDXCompiler(config);
97
+ }
98
+ export async function compileMDX(source, options) {
99
+ const compiler = createMDXCompiler(options);
100
+ return compiler.compile(source);
101
+ }
102
+ export function compileSync(source, options) {
103
+ const compiler = createMDXCompiler(options);
104
+ return compiler.compile(source);
105
+ }
106
+ export function useMDX(source, options) {
107
+ return compileSync(source, options);
108
+ }
109
+ export const DEFAULT_COMPONENTS = {
110
+ pre: (props) => ({ type: 'pre', props }),
111
+ code: (props) => {
112
+ const className = props.className;
113
+ const lang = className?.replace('language-', '') ?? '';
114
+ return {
115
+ type: 'code',
116
+ props: { ...props, className: lang ? `language-${lang}` : undefined },
117
+ };
118
+ },
119
+ h1: (props) => {
120
+ const children = props.children;
121
+ const id = children?.toLowerCase().replace(/\s+/g, '-');
122
+ return { type: 'h1', props: { ...props, id } };
123
+ },
124
+ h2: (props) => {
125
+ const children = props.children;
126
+ const id = children?.toLowerCase().replace(/\s+/g, '-');
127
+ return { type: 'h2', props: { ...props, id } };
128
+ },
129
+ a: (props) => {
130
+ const href = props.href;
131
+ if (href?.startsWith('/')) {
132
+ return { type: 'a', props: { ...props, 'data-link': '' } };
133
+ }
134
+ return { type: 'a', props: { ...props, target: '_blank', rel: 'noopener noreferrer' } };
135
+ },
136
+ img: (props) => ({
137
+ type: 'img',
138
+ props: { ...props, loading: 'lazy', decoding: 'async' },
139
+ }),
140
+ table: (props) => {
141
+ return {
142
+ type: 'div',
143
+ props: {
144
+ className: 'table-wrapper',
145
+ children: [{
146
+ type: 'table',
147
+ props: { children: [props.children] }
148
+ }]
149
+ },
150
+ };
151
+ },
152
+ };
153
+ export function mergeComponents(base, override) {
154
+ return { ...base, ...override };
155
+ }
156
+ export { parseMarkdown };
@@ -0,0 +1,6 @@
1
+ import { compileMDX } from './index.js';
2
+ export async function loadMDX(path, options) {
3
+ const fs = await import('node:fs');
4
+ const source = fs.readFileSync(path, 'utf-8');
5
+ return compileMDX(source, options);
6
+ }
@@ -0,0 +1,15 @@
1
+ let headBuffer = [];
2
+ export function registerHeadContent(html) {
3
+ headBuffer.push(html);
4
+ }
5
+ export function drainHeadContent() {
6
+ const content = headBuffer.join('\n');
7
+ headBuffer = [];
8
+ return content;
9
+ }
10
+ export function peekHeadContent() {
11
+ return headBuffer.join('\n');
12
+ }
13
+ export function clearHeadContent() {
14
+ headBuffer = [];
15
+ }
@@ -0,0 +1,100 @@
1
+ import { renderToString } from '../runtime/helpers/render.js';
2
+ import { registerHeadContent } from './head-registry.js';
3
+ import { escapeHtml } from '../ssr/helpers/render-html.js';
4
+ const MANAGED_ATTR = 'data-ek-head';
5
+ function buildShorthandTags(props) {
6
+ const tags = [];
7
+ if (props.title) {
8
+ tags.push(`<title ${MANAGED_ATTR}>${escapeHtml(props.title)}</title>`);
9
+ tags.push(`<meta ${MANAGED_ATTR} name="title" content="${escapeHtml(props.title)}">`);
10
+ }
11
+ if (props.description) {
12
+ tags.push(`<meta ${MANAGED_ATTR} name="description" content="${escapeHtml(props.description)}">`);
13
+ }
14
+ if (props.keywords?.length) {
15
+ tags.push(`<meta ${MANAGED_ATTR} name="keywords" content="${escapeHtml(props.keywords.join(', '))}">`);
16
+ }
17
+ if (props.author) {
18
+ tags.push(`<meta ${MANAGED_ATTR} name="author" content="${escapeHtml(props.author)}">`);
19
+ }
20
+ if (props.robots) {
21
+ tags.push(`<meta ${MANAGED_ATTR} name="robots" content="${escapeHtml(props.robots)}">`);
22
+ }
23
+ if (props.canonical) {
24
+ tags.push(`<link ${MANAGED_ATTR} rel="canonical" href="${escapeHtml(props.canonical)}">`);
25
+ }
26
+ if (props.og) {
27
+ const og = props.og;
28
+ if (og.type)
29
+ tags.push(`<meta ${MANAGED_ATTR} property="og:type" content="${escapeHtml(og.type)}">`);
30
+ if (og.title)
31
+ tags.push(`<meta ${MANAGED_ATTR} property="og:title" content="${escapeHtml(og.title)}">`);
32
+ if (og.description)
33
+ tags.push(`<meta ${MANAGED_ATTR} property="og:description" content="${escapeHtml(og.description)}">`);
34
+ if (og.url)
35
+ tags.push(`<meta ${MANAGED_ATTR} property="og:url" content="${escapeHtml(og.url)}">`);
36
+ if (og.image)
37
+ tags.push(`<meta ${MANAGED_ATTR} property="og:image" content="${escapeHtml(og.image)}">`);
38
+ if (og.locale)
39
+ tags.push(`<meta ${MANAGED_ATTR} property="og:locale" content="${escapeHtml(og.locale)}">`);
40
+ if (og.siteName)
41
+ tags.push(`<meta ${MANAGED_ATTR} property="og:site_name" content="${escapeHtml(og.siteName)}">`);
42
+ }
43
+ if (props.twitter) {
44
+ const tc = props.twitter;
45
+ if (tc.card)
46
+ tags.push(`<meta ${MANAGED_ATTR} name="twitter:card" content="${escapeHtml(tc.card)}">`);
47
+ if (tc.site)
48
+ tags.push(`<meta ${MANAGED_ATTR} name="twitter:site" content="${escapeHtml(tc.site)}">`);
49
+ if (tc.creator)
50
+ tags.push(`<meta ${MANAGED_ATTR} name="twitter:creator" content="${escapeHtml(tc.creator)}">`);
51
+ if (tc.title)
52
+ tags.push(`<meta ${MANAGED_ATTR} name="twitter:title" content="${escapeHtml(tc.title)}">`);
53
+ if (tc.description)
54
+ tags.push(`<meta ${MANAGED_ATTR} name="twitter:description" content="${escapeHtml(tc.description)}">`);
55
+ if (tc.image)
56
+ tags.push(`<meta ${MANAGED_ATTR} name="twitter:image" content="${escapeHtml(tc.image)}">`);
57
+ }
58
+ return tags.join('\n');
59
+ }
60
+ function updateClientHead(html) {
61
+ if (typeof document === 'undefined')
62
+ return;
63
+ const parsed = new DOMParser().parseFromString(`<root>${html}</root>`, 'text/html');
64
+ const newTags = parsed.body.firstChild?.childNodes ?? [];
65
+ const existing = document.querySelectorAll(`[${MANAGED_ATTR}]`);
66
+ existing.forEach((el) => el.remove());
67
+ for (const node of Array.from(newTags)) {
68
+ if (node.nodeType === Node.ELEMENT_NODE) {
69
+ const el = node;
70
+ if (el.tagName === 'TITLE') {
71
+ document.title = el.textContent ?? '';
72
+ }
73
+ else {
74
+ document.head.appendChild(document.importNode(el, true));
75
+ }
76
+ }
77
+ }
78
+ }
79
+ export function Head(props) {
80
+ let html = '';
81
+ if (props.children) {
82
+ const children = Array.isArray(props.children) ? props.children : [props.children];
83
+ html = children
84
+ .map((child) => {
85
+ if (child == null || child === false)
86
+ return '';
87
+ return renderToString(child);
88
+ })
89
+ .join('\n');
90
+ }
91
+ else {
92
+ html = buildShorthandTags(props);
93
+ }
94
+ registerHeadContent(html);
95
+ if (typeof document !== 'undefined') {
96
+ updateClientHead(html);
97
+ }
98
+ return null;
99
+ }
100
+ Head.displayName = 'Head';
@@ -0,0 +1,210 @@
1
+ export { Head } from './head.js';
2
+ export { registerHeadContent, drainHeadContent, peekHeadContent, clearHeadContent, } from './head-registry.js';
3
+ export class MetaGenerator {
4
+ baseUrl;
5
+ defaultTitle = 'EmberKit App';
6
+ defaultDescription = 'Built with EmberKit';
7
+ siteName = 'EmberKit';
8
+ constructor(baseUrl = 'https://example.com') {
9
+ this.baseUrl = baseUrl;
10
+ }
11
+ generate(data) {
12
+ const tags = [];
13
+ tags.push(...this.generateBasicMeta(data));
14
+ tags.push(...this.generateOpenGraph(data));
15
+ tags.push(...this.generateTwitter(data));
16
+ tags.push(...this.generateCanonical(data));
17
+ tags.push(...this.generateStructuredData(data));
18
+ return tags.join('\n');
19
+ }
20
+ generateBasicMeta(data) {
21
+ const tags = [];
22
+ const title = data.title ?? this.defaultTitle;
23
+ tags.push(`<title>${escapeHtml(title)}</title>`);
24
+ tags.push(`<meta name="title" content="${escapeHtml(title)}">`);
25
+ const description = data.description ?? this.defaultDescription;
26
+ tags.push(`<meta name="description" content="${escapeHtml(description)}">`);
27
+ if (data.keywords?.length) {
28
+ tags.push(`<meta name="keywords" content="${escapeHtml(data.keywords.join(', '))}">`);
29
+ }
30
+ if (data.author) {
31
+ tags.push(`<meta name="author" content="${escapeHtml(data.author)}">`);
32
+ }
33
+ if (data.robots) {
34
+ tags.push(`<meta name="robots" content="${escapeHtml(data.robots)}">`);
35
+ }
36
+ return tags;
37
+ }
38
+ generateOpenGraph(data) {
39
+ if (!data.openGraph)
40
+ return [];
41
+ const og = data.openGraph;
42
+ const tags = [];
43
+ tags.push(`<meta property="og:type" content="${og.type ?? 'website'}">`);
44
+ tags.push(`<meta property="og:title" content="${escapeHtml(og.title ?? data.title ?? '')}">`);
45
+ tags.push(`<meta property="og:description" content="${escapeHtml(og.description ?? data.description ?? '')}">`);
46
+ if (og.url) {
47
+ tags.push(`<meta property="og:url" content="${escapeHtml(og.url)}">`);
48
+ }
49
+ if (og.images?.length) {
50
+ for (const img of og.images) {
51
+ tags.push(`<meta property="og:image" content="${escapeHtml(img.url)}">`);
52
+ if (img.width)
53
+ tags.push(`<meta property="og:image:width" content="${img.width}">`);
54
+ if (img.height)
55
+ tags.push(`<meta property="og:image:height" content="${img.height}">`);
56
+ if (img.alt)
57
+ tags.push(`<meta property="og:image:alt" content="${escapeHtml(img.alt)}">`);
58
+ }
59
+ }
60
+ if (og.locale) {
61
+ tags.push(`<meta property="og:locale" content="${escapeHtml(og.locale)}">`);
62
+ }
63
+ if (og.siteName) {
64
+ tags.push(`<meta property="og:site_name" content="${escapeHtml(og.siteName)}">`);
65
+ }
66
+ return tags;
67
+ }
68
+ generateTwitter(data) {
69
+ if (!data.twitter)
70
+ return [];
71
+ const tc = data.twitter;
72
+ const tags = [];
73
+ tags.push(`<meta name="twitter:card" content="${tc.card}">`);
74
+ if (tc.title)
75
+ tags.push(`<meta name="twitter:title" content="${escapeHtml(tc.title)}">`);
76
+ if (tc.description)
77
+ tags.push(`<meta name="twitter:description" content="${escapeHtml(tc.description)}">`);
78
+ if (tc.image)
79
+ tags.push(`<meta name="twitter:image" content="${escapeHtml(tc.image)}">`);
80
+ if (tc.imageAlt)
81
+ tags.push(`<meta name="twitter:image:alt" content="${escapeHtml(tc.imageAlt)}">`);
82
+ if (tc.site)
83
+ tags.push(`<meta name="twitter:site" content="${escapeHtml(tc.site)}">`);
84
+ if (tc.creator)
85
+ tags.push(`<meta name="twitter:creator" content="${escapeHtml(tc.creator)}">`);
86
+ return tags;
87
+ }
88
+ generateCanonical(data) {
89
+ if (!data.canonical && this.baseUrl) {
90
+ return [`<link rel="canonical" href="${escapeHtml(this.baseUrl)}">`];
91
+ }
92
+ if (data.canonical) {
93
+ return [`<link rel="canonical" href="${escapeHtml(data.canonical)}">`];
94
+ }
95
+ return [];
96
+ }
97
+ generateStructuredData(data) {
98
+ if (!data.structuredData)
99
+ return [];
100
+ const json = JSON.stringify(data.structuredData);
101
+ return [`<script type="application/ld+json">${json}</script>`];
102
+ }
103
+ }
104
+ export function createMetaGenerator(baseUrl) {
105
+ return new MetaGenerator(baseUrl);
106
+ }
107
+ export function generateMeta(data, baseUrl) {
108
+ const generator = new MetaGenerator(baseUrl);
109
+ return generator.generate(data);
110
+ }
111
+ export function generateBreadcrumbs(items) {
112
+ const json = JSON.stringify({
113
+ '@context': 'https://schema.org',
114
+ '@type': 'BreadcrumbList',
115
+ itemListElement: items.map((item, index) => ({
116
+ '@type': 'ListItem',
117
+ position: index + 1,
118
+ name: item.name,
119
+ item: item.url,
120
+ })),
121
+ });
122
+ return `<script type="application/ld+json">${json}</script>`;
123
+ }
124
+ export function generateArticleSchema(data) {
125
+ return JSON.stringify({
126
+ '@context': 'https://schema.org',
127
+ '@type': 'Article',
128
+ headline: data.title,
129
+ description: data.description,
130
+ author: {
131
+ '@type': 'Person',
132
+ name: data.author,
133
+ },
134
+ datePublished: data.publishedAt,
135
+ url: data.url,
136
+ ...(data.image ? { image: data.image } : {}),
137
+ });
138
+ }
139
+ export function generateProductSchema(data) {
140
+ return JSON.stringify({
141
+ '@context': 'https://schema.org',
142
+ '@type': 'Product',
143
+ name: data.name,
144
+ description: data.description,
145
+ offers: {
146
+ '@type': 'Offer',
147
+ price: data.price,
148
+ priceCurrency: data.currency ?? 'USD',
149
+ availability: data.availability ?? 'https://schema.org/InStock',
150
+ },
151
+ ...(data.image ? { image: data.image } : {}),
152
+ });
153
+ }
154
+ export function generateLinks(links) {
155
+ return links
156
+ .map((link) => {
157
+ let tag = `<link rel="${link.rel}" href="${escapeHtml(link.href)}"`;
158
+ if (link.type)
159
+ tag += ` type="${link.type}"`;
160
+ if (link.sizes)
161
+ tag += ` sizes="${link.sizes}"`;
162
+ return tag + '>';
163
+ })
164
+ .join('\n');
165
+ }
166
+ export function generateScripts(scripts) {
167
+ return scripts
168
+ .map((script) => {
169
+ let tag = '<script';
170
+ if (script.type)
171
+ tag += ` type="${script.type}"`;
172
+ if (script.async)
173
+ tag += ' async';
174
+ if (script.defer)
175
+ tag += ' defer';
176
+ if (script.src)
177
+ tag += ` src="${escapeHtml(script.src)}"`;
178
+ if (script.content) {
179
+ return `${tag}>${script.content}</script>`;
180
+ }
181
+ return `${tag}></script>`;
182
+ })
183
+ .join('\n');
184
+ }
185
+ function escapeHtml(str) {
186
+ return str
187
+ .replace(/&/g, '&amp;')
188
+ .replace(/</g, '&lt;')
189
+ .replace(/>/g, '&gt;')
190
+ .replace(/"/g, '&quot;');
191
+ }
192
+ export const DEFAULT_META = {
193
+ title: 'EmberKit',
194
+ description: 'Minimalist TypeScript-first JSX framework',
195
+ robots: 'index, follow',
196
+ };
197
+ export function mergeMeta(base, override) {
198
+ return {
199
+ ...base,
200
+ ...override,
201
+ openGraph: {
202
+ ...base.openGraph,
203
+ ...override.openGraph,
204
+ },
205
+ twitter: {
206
+ ...base.twitter,
207
+ ...override.twitter,
208
+ },
209
+ };
210
+ }
@@ -0,0 +1,53 @@
1
+ export async function navigate(to, options = {}) {
2
+ const { replace = false, state, viewTransition } = options;
3
+ if (replace) {
4
+ history.replaceState(state ? { ...history.state, ...state } : history.state, '', to);
5
+ }
6
+ else {
7
+ history.pushState(state ?? null, '', to);
8
+ }
9
+ if (viewTransition) {
10
+ const viewTransitionOptions = typeof viewTransition === 'boolean'
11
+ ? {}
12
+ : viewTransition;
13
+ await startViewTransition(viewTransitionOptions);
14
+ }
15
+ window.dispatchEvent(new PopStateEvent('popstate', { state: history.state }));
16
+ }
17
+ export function redirect(to, status = 302) {
18
+ const response = new Response(null, {
19
+ status,
20
+ headers: {
21
+ Location: to,
22
+ },
23
+ });
24
+ throw response;
25
+ }
26
+ export function preload(path) {
27
+ const link = document.createElement('link');
28
+ link.rel = 'prefetch';
29
+ link.href = path;
30
+ link.as = 'document';
31
+ document.head.appendChild(link);
32
+ }
33
+ export async function startViewTransition(options = {}) {
34
+ const { skipTransition = false, documentViewTransition = true } = options;
35
+ if (skipTransition) {
36
+ return;
37
+ }
38
+ if (documentViewTransition && typeof document !== 'undefined' && 'startViewTransition' in document) {
39
+ const transition = document.startViewTransition(async () => {
40
+ await Promise.resolve();
41
+ });
42
+ await transition.finished;
43
+ }
44
+ }
45
+ export function reload() {
46
+ history.go(0);
47
+ }
48
+ export function back() {
49
+ history.back();
50
+ }
51
+ export function forward() {
52
+ history.forward();
53
+ }
@@ -0,0 +1,10 @@
1
+ import { navigate as coreNavigate } from './navigation.js';
2
+ export function useNavigate() {
3
+ return async (path, options = {}) => {
4
+ const { skipTransition = false, ...navigationOptions } = options;
5
+ return coreNavigate(path, {
6
+ ...navigationOptions,
7
+ viewTransition: skipTransition ? false : true,
8
+ });
9
+ };
10
+ }
@@ -0,0 +1,3 @@
1
+ export * from './types.js';
2
+ export * from './helpers/navigation.js';
3
+ export { useNavigate } from './helpers/useNavigate.js';
@@ -0,0 +1,2 @@
1
+ export const VIEW_TRANSITION_API_SUPPORTED = typeof document !== 'undefined' &&
2
+ 'startViewTransition' in document;
@@ -0,0 +1,74 @@
1
+ export class PluginPipeline {
2
+ plugins = [];
3
+ hookCache = new Map();
4
+ addPlugin(plugin) {
5
+ this.plugins.push(plugin);
6
+ this.invalidateCache();
7
+ }
8
+ removePlugin(name) {
9
+ this.plugins = this.plugins.filter((p) => p.name !== name);
10
+ this.invalidateCache();
11
+ }
12
+ async runHook(name, context) {
13
+ const hooks = this.hookCache.get(name) ?? [];
14
+ for (const callback of hooks) {
15
+ await callback(context);
16
+ }
17
+ }
18
+ invalidateCache() {
19
+ this.hookCache.clear();
20
+ }
21
+ getPlugins() {
22
+ return [...this.plugins];
23
+ }
24
+ }
25
+ export function createPluginContext(config, api) {
26
+ const hooks = new Map();
27
+ return {
28
+ config,
29
+ api,
30
+ onHook(name, callback) {
31
+ const existing = hooks.get(name) ?? [];
32
+ hooks.set(name, [...existing, callback]);
33
+ },
34
+ addWatchFile(_file) {
35
+ // File watching handled by Vite
36
+ },
37
+ };
38
+ }
39
+ export function createPluginAPI() {
40
+ return {
41
+ async resolveId(_id, _options) {
42
+ return null;
43
+ },
44
+ async load(_id) {
45
+ return null;
46
+ },
47
+ async transform(_code, _id) {
48
+ return null;
49
+ },
50
+ async render(html) {
51
+ return html;
52
+ },
53
+ };
54
+ }
55
+ export const CORE_PLUGINS = [];
56
+ export async function loadPlugin(name) {
57
+ try {
58
+ const module = await import(name);
59
+ return module.default ?? module;
60
+ }
61
+ catch {
62
+ throw new Error(`Failed to load plugin: ${name}`);
63
+ }
64
+ }
65
+ export async function resolvePlugins(plugins, config) {
66
+ const contexts = [];
67
+ const api = createPluginAPI();
68
+ for (const plugin of plugins) {
69
+ const context = createPluginContext(config, api);
70
+ await plugin.setup(context);
71
+ contexts.push(context);
72
+ }
73
+ return contexts;
74
+ }