@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,74 @@
1
+ import { PARAM_REGEX, CATCH_ALL_REGEX } from '../types.js';
2
+ export function normalizePath(path) {
3
+ const cleaned = path.replace(/^\/|\/$/g, '').replace(/\/+/g, '/') || '';
4
+ return '/' + cleaned;
5
+ }
6
+ export function pathToRegex(path) {
7
+ const paramNames = [];
8
+ let regexString = path.replace(CATCH_ALL_REGEX, (_, name) => {
9
+ paramNames.push(name);
10
+ return '(.*)';
11
+ });
12
+ regexString = regexString.replace(PARAM_REGEX, (_, name) => {
13
+ paramNames.push(name);
14
+ return '([^/]+)';
15
+ });
16
+ return {
17
+ pattern: new RegExp(`^${regexString}$`),
18
+ paramNames,
19
+ };
20
+ }
21
+ export function matchPath(pattern, path) {
22
+ const match = path.match(pattern);
23
+ if (match) {
24
+ return match.slice(1);
25
+ }
26
+ return null;
27
+ }
28
+ export function scoreRoute(routePath) {
29
+ let score = 100;
30
+ const segments = routePath.split('/').filter(Boolean);
31
+ score -= segments.length * 20;
32
+ for (const segment of segments) {
33
+ if (segment.startsWith(':') || segment.startsWith('*')) {
34
+ score -= 30;
35
+ }
36
+ else {
37
+ score += 10;
38
+ }
39
+ }
40
+ if (routePath.includes('*')) {
41
+ score -= 50;
42
+ }
43
+ return Math.max(0, score);
44
+ }
45
+ export function extractSegments(filePath) {
46
+ return filePath
47
+ .replace(/^\/|\/$/g, '')
48
+ .split('/')
49
+ .filter(Boolean);
50
+ }
51
+ export function segmentsToPath(segments) {
52
+ return '/' + segments.join('/');
53
+ }
54
+ export function isIndexFile(fileName) {
55
+ return fileName === 'index' || fileName === 'index.tsx' || fileName === 'index.ts';
56
+ }
57
+ export function isDynamicSegment(segment) {
58
+ return segment.startsWith('[') && segment.endsWith(']');
59
+ }
60
+ export function isCatchAll(segment) {
61
+ return segment.startsWith('[...') && segment.endsWith(']');
62
+ }
63
+ export function getParamName(segment) {
64
+ if (isDynamicSegment(segment)) {
65
+ return segment.slice(1, -1);
66
+ }
67
+ return null;
68
+ }
69
+ export function getCatchAllName(segment) {
70
+ if (isCatchAll(segment)) {
71
+ return segment.slice(4, -1);
72
+ }
73
+ return null;
74
+ }
@@ -0,0 +1,109 @@
1
+ import { normalizePath, matchPath, scoreRoute, extractSegments } from './path.js';
2
+ export function createRoute(filePath, routeDir = 'src/routes') {
3
+ const relativePath = filePath.replace(/\\/g, '/').replace(routeDir, '').replace(/\.(tsx|ts|jsx|js|md|mdx)$/, '');
4
+ if (relativePath.startsWith('/_api/') || relativePath.startsWith('_api/') || relativePath.includes('/_api/')) {
5
+ return null;
6
+ }
7
+ const isLayout = filePath.includes('/_layout.tsx') || filePath.includes('/_layout.ts');
8
+ const isError = filePath.includes('/_error.tsx') || filePath.includes('/_error.ts');
9
+ const isLoading = filePath.includes('/_loading.tsx') || filePath.includes('/_loading.ts');
10
+ let cleanPath = relativePath
11
+ .replace(/\/_layout$/, '')
12
+ .replace(/\/_layout\/index$/, '')
13
+ .replace(/^\/_layout/, '')
14
+ .replace(/\/_error$/, '')
15
+ .replace(/\/_loading$/, '');
16
+ cleanPath = cleanPath
17
+ .replace(/\/index$/, '')
18
+ .replace(/\/\[/g, '/:')
19
+ .replace(/\[/g, ':')
20
+ .replace(/\]/g, '')
21
+ .replace(/\.\.\./g, '');
22
+ if (cleanPath === '' || cleanPath === '/') {
23
+ return {
24
+ path: '/',
25
+ pattern: /^\/$/,
26
+ paramNames: [],
27
+ filePath,
28
+ fileName: filePath.split('/').pop() ?? '',
29
+ isLayout,
30
+ isError,
31
+ isLoading,
32
+ isApi: false,
33
+ };
34
+ }
35
+ const { pattern, paramNames } = createPatternFromPath(cleanPath);
36
+ return {
37
+ path: normalizePath(cleanPath),
38
+ pattern,
39
+ paramNames,
40
+ filePath,
41
+ fileName: filePath.split('/').pop() ?? '',
42
+ isLayout,
43
+ isError,
44
+ isLoading,
45
+ isApi: false,
46
+ };
47
+ }
48
+ function createPatternFromPath(path) {
49
+ const paramNames = [];
50
+ const segments = path.split('/').filter(Boolean);
51
+ const regexSegments = segments.map((segment) => {
52
+ if (segment.startsWith(':')) {
53
+ const paramName = segment.slice(1);
54
+ paramNames.push(paramName);
55
+ return '([^/]+)';
56
+ }
57
+ if (segment.startsWith('*')) {
58
+ return '(.*)';
59
+ }
60
+ return segment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
61
+ });
62
+ return {
63
+ pattern: new RegExp('^/' + regexSegments.join('/') + '$'),
64
+ paramNames,
65
+ };
66
+ }
67
+ export function matchRoute(routes, pathname) {
68
+ const normalizedPath = normalizePath(pathname);
69
+ let bestMatch = null;
70
+ for (const route of routes) {
71
+ const paramValues = matchPath(route.pattern, normalizedPath);
72
+ if (paramValues !== null) {
73
+ const params = {};
74
+ for (let i = 0; i < route.paramNames.length; i++) {
75
+ const paramName = route.paramNames[i];
76
+ const paramValue = paramValues[i];
77
+ if (paramName !== undefined && paramValue !== undefined) {
78
+ params[paramName] = paramValue;
79
+ }
80
+ }
81
+ const score = scoreRoute(route.path);
82
+ if (!bestMatch || score > bestMatch.score) {
83
+ bestMatch = { route, params, score };
84
+ }
85
+ }
86
+ }
87
+ return bestMatch;
88
+ }
89
+ export function sortRoutes(routes) {
90
+ return [...routes].sort((a, b) => scoreRoute(b.path) - scoreRoute(a.path));
91
+ }
92
+ export function findLayoutChain(routes, pathname) {
93
+ const normalizedPath = normalizePath(pathname);
94
+ const segments = extractSegments(normalizedPath);
95
+ const layouts = [];
96
+ for (let i = 0; i <= segments.length; i++) {
97
+ const pathPrefix = '/' + segments.slice(0, i).join('/');
98
+ const layout = routes.find((r) => r.isLayout &&
99
+ (r.path === pathPrefix || r.path === pathPrefix + '/_layout' || r.path === pathPrefix + '/index'));
100
+ if (layout) {
101
+ layouts.push(layout);
102
+ }
103
+ }
104
+ const rootLayout = routes.find((r) => r.isLayout && (r.path === '/' || r.path === '/_layout'));
105
+ if (rootLayout && !layouts.includes(rootLayout)) {
106
+ layouts.unshift(rootLayout);
107
+ }
108
+ return layouts;
109
+ }
@@ -0,0 +1,110 @@
1
+ import { createRoute, matchRoute, sortRoutes, findLayoutChain } from './helpers/route.js';
2
+ import { normalizePath } from './helpers/path.js';
3
+ class EmberKitRouter {
4
+ basePath = '';
5
+ currentPath = '/';
6
+ listeners = new Set();
7
+ routes = [];
8
+ back() {
9
+ history.back();
10
+ }
11
+ createHref(path) {
12
+ return this.basePath + path;
13
+ }
14
+ createRouteParams(params) {
15
+ return {
16
+ params,
17
+ query: this.parseQuery(this.currentPath),
18
+ request: new Request(this.currentPath),
19
+ };
20
+ }
21
+ forward() {
22
+ history.forward();
23
+ }
24
+ getBasePath() {
25
+ return this.basePath;
26
+ }
27
+ getCurrentPath() {
28
+ return this.currentPath;
29
+ }
30
+ getLayouts(pathname) {
31
+ return findLayoutChain(this.routes, pathname);
32
+ }
33
+ getRoutes() {
34
+ return this.routes;
35
+ }
36
+ initialize(routes) {
37
+ this.routes = sortRoutes(routes);
38
+ this.currentPath = normalizePath(window.location.pathname);
39
+ }
40
+ match(pathname) {
41
+ return matchRoute(this.routes, pathname);
42
+ }
43
+ navigate(path, options) {
44
+ const normalizedPath = normalizePath(path);
45
+ if (options?.replace) {
46
+ history.replaceState(options.state ?? null, '', path);
47
+ }
48
+ else {
49
+ history.pushState(options?.state ?? null, '', path);
50
+ }
51
+ this.currentPath = normalizedPath;
52
+ this.notify();
53
+ }
54
+ setBasePath(path) {
55
+ this.basePath = path;
56
+ }
57
+ subscribe(listener) {
58
+ this.listeners.add(listener);
59
+ return () => this.listeners.delete(listener);
60
+ }
61
+ notify() {
62
+ const state = {
63
+ pathname: this.currentPath,
64
+ params: this.match(this.currentPath)?.params ?? {},
65
+ query: this.parseQuery(this.currentPath),
66
+ };
67
+ this.listeners.forEach((listener) => listener(state));
68
+ }
69
+ parseQuery(pathname) {
70
+ const query = {};
71
+ const queryIndex = pathname.indexOf('?');
72
+ if (queryIndex === -1) {
73
+ return query;
74
+ }
75
+ const queryString = pathname.slice(queryIndex + 1);
76
+ const pairs = queryString.split('&');
77
+ for (const pair of pairs) {
78
+ const [key, value] = pair.split('=');
79
+ if (!key)
80
+ continue;
81
+ const decodedKey = decodeURIComponent(key);
82
+ const decodedValue = decodeURIComponent(value ?? '');
83
+ if (query[decodedKey]) {
84
+ const existing = query[decodedKey];
85
+ if (Array.isArray(existing)) {
86
+ existing.push(decodedValue);
87
+ }
88
+ else {
89
+ query[decodedKey] = [existing, decodedValue];
90
+ }
91
+ }
92
+ else {
93
+ query[decodedKey] = decodedValue;
94
+ }
95
+ }
96
+ return query;
97
+ }
98
+ }
99
+ export const router = new EmberKitRouter();
100
+ export function createRouter(routes) {
101
+ const instance = new EmberKitRouter();
102
+ instance.initialize(routes);
103
+ return instance;
104
+ }
105
+ export function createMemoryRouter(initialPath = '/') {
106
+ const instance = new EmberKitRouter();
107
+ instance.navigate(initialPath);
108
+ return instance;
109
+ }
110
+ export { createRoute, matchRoute, sortRoutes, findLayoutChain };
@@ -0,0 +1,5 @@
1
+ export const SPECIAL_FILES = new Set([
2
+ '_layout', '_error', '_loading', 'index',
3
+ ]);
4
+ export const PARAM_REGEX = /\[([^\]]+)\]/g;
5
+ export const CATCH_ALL_REGEX = /\[\.\.\.(\w+)\]/g;
@@ -0,0 +1,52 @@
1
+ export function createElement(type, props, ...children) {
2
+ const resolvedProps = props ?? {};
3
+ if (children.length > 0) {
4
+ const flatChildren = children.flat().filter((child) => child != null && child !== false);
5
+ if (flatChildren.length > 0) {
6
+ resolvedProps.children = flatChildren;
7
+ }
8
+ }
9
+ return {
10
+ type: type,
11
+ props: resolvedProps,
12
+ };
13
+ }
14
+ export function isValidElement(element) {
15
+ if (typeof element !== 'object' || element === null)
16
+ return false;
17
+ const obj = element;
18
+ return typeof obj['type'] === 'string' && typeof obj['props'] === 'object';
19
+ }
20
+ export function isComponent(type) {
21
+ return typeof type === 'function';
22
+ }
23
+ export function flattenChildren(children) {
24
+ const result = [];
25
+ for (const child of children) {
26
+ if (child == null || child === false || child === undefined)
27
+ continue;
28
+ if (typeof child === 'string' || typeof child === 'number') {
29
+ result.push(child);
30
+ }
31
+ else if (Array.isArray(child)) {
32
+ result.push(...flattenChildren(child));
33
+ }
34
+ else {
35
+ result.push(child);
36
+ }
37
+ }
38
+ return result;
39
+ }
40
+ export function resolveComponent(type, props) {
41
+ if (isComponent(type)) {
42
+ const result = type(props);
43
+ if (typeof result === 'string' || typeof result === 'number') {
44
+ return createElement('span', null, result);
45
+ }
46
+ if (isValidElement(result)) {
47
+ return result;
48
+ }
49
+ return createElement('span', null, String(result));
50
+ }
51
+ return createElement(type, props);
52
+ }
@@ -0,0 +1,121 @@
1
+ const SELF_CLOSING_TAGS = new Set([
2
+ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'source', 'track', 'wbr',
3
+ ]);
4
+ let handlerCounter = 0;
5
+ const handlerRegistry = new Map();
6
+ export function getHandler(id) {
7
+ return handlerRegistry.get(id);
8
+ }
9
+ export function clearHandlers() {
10
+ handlerRegistry.clear();
11
+ handlerCounter = 0;
12
+ }
13
+ export function renderElementToHTML(element) {
14
+ if (!element)
15
+ return '';
16
+ let currentType = element.type;
17
+ let props = element.props ?? {};
18
+ while (typeof currentType === 'function') {
19
+ try {
20
+ const result = currentType(props);
21
+ if (result && typeof result === 'object' && 'type' in result) {
22
+ currentType = result.type;
23
+ props = result.props ?? {};
24
+ }
25
+ else if (typeof result === 'string' || typeof result === 'number') {
26
+ return String(result);
27
+ }
28
+ else {
29
+ return '';
30
+ }
31
+ }
32
+ catch (error) {
33
+ return `<div style="color: red;">Error rendering component</div>`;
34
+ }
35
+ }
36
+ const rawChildren = props.children ?? [];
37
+ const children = Array.isArray(rawChildren) ? rawChildren : [rawChildren];
38
+ const childHtml = children
39
+ .map((child) => {
40
+ if (typeof child === 'string' || typeof child === 'number') {
41
+ return String(child);
42
+ }
43
+ if (typeof child === 'object' && child !== null && 'type' in child) {
44
+ return renderElementToHTML(child);
45
+ }
46
+ return '';
47
+ })
48
+ .join('');
49
+ if (currentType === 'Fragment' || currentType === 'React.Fragment') {
50
+ return childHtml;
51
+ }
52
+ // Handle dangerouslySetInnerHTML
53
+ let innerHtml = childHtml;
54
+ for (const [, value] of Object.entries(props)) {
55
+ if (typeof value === 'object' && value !== null && '__html' in value) {
56
+ innerHtml = String(value.__html);
57
+ break;
58
+ }
59
+ }
60
+ const attributes = Object.entries(props)
61
+ .filter(([key, value]) => {
62
+ if (key === 'children' || key === 'key')
63
+ return false;
64
+ if (typeof value === 'object' && value !== null && '__html' in value)
65
+ return false;
66
+ return true;
67
+ })
68
+ .filter(([, value]) => typeof value !== 'function' && value != null)
69
+ .map(([key, value]) => {
70
+ // Map React/JSX prop names to HTML attributes
71
+ if (key === 'className')
72
+ key = 'class';
73
+ if (key === 'strokeWidth' || key === 'strokeLinecap' || key === 'strokeLinejoin') {
74
+ key = key.replace(/([A-Z])/g, '-$1').toLowerCase();
75
+ }
76
+ if (value === true)
77
+ return ` ${key}`;
78
+ if (value === false)
79
+ return '';
80
+ return ` ${key}="${value}"`;
81
+ })
82
+ .join('');
83
+ // Register onClick handler as data attribute
84
+ const onClick = props.onClick;
85
+ let onclickAttr = '';
86
+ if (typeof onClick === 'function') {
87
+ const id = `ekh${++handlerCounter}`;
88
+ handlerRegistry.set(id, onClick);
89
+ onclickAttr = ` data-ekclick="${id}"`;
90
+ }
91
+ if (SELF_CLOSING_TAGS.has(currentType)) {
92
+ return `<${currentType}${attributes}${onclickAttr}/>`;
93
+ }
94
+ return `<${currentType}${attributes}${onclickAttr}>${innerHtml}</${currentType}>`;
95
+ }
96
+ export function renderToString(element) {
97
+ if (!element && element !== 0)
98
+ return '';
99
+ if (typeof element === 'string')
100
+ return element;
101
+ if (typeof element === 'number')
102
+ return String(element);
103
+ return renderElementToHTML(element);
104
+ }
105
+ export function getComponentName(type) {
106
+ if (typeof type === 'function') {
107
+ const fn = type;
108
+ return fn.displayName ?? fn.name ?? 'Anonymous';
109
+ }
110
+ return type;
111
+ }
112
+ export function createPropsProxy(props) {
113
+ return new Proxy(props, {
114
+ get(target, prop) {
115
+ if (prop === 'toJSON') {
116
+ return () => target;
117
+ }
118
+ return target[prop];
119
+ },
120
+ });
121
+ }
@@ -0,0 +1,132 @@
1
+ import { renderToString, getHandler, clearHandlers } from './helpers/render.js';
2
+ export function createElement(type, props, ...children) {
3
+ const resolvedProps = props ?? {};
4
+ const flatChildren = children.flat().filter((child) => child != null && child !== false);
5
+ if (flatChildren.length > 0) {
6
+ resolvedProps.children = flatChildren;
7
+ }
8
+ return {
9
+ type: type,
10
+ props: resolvedProps,
11
+ };
12
+ }
13
+ function attachEventHandlers(container) {
14
+ const elements = container.querySelectorAll('[data-ekclick]');
15
+ elements.forEach((el) => {
16
+ const id = el.getAttribute('data-ekclick');
17
+ if (id) {
18
+ const handler = getHandler(id);
19
+ if (handler) {
20
+ el.addEventListener('click', handler);
21
+ el.removeAttribute('data-ekclick');
22
+ }
23
+ }
24
+ });
25
+ }
26
+ function renderToTarget(layout, target, routeComponent) {
27
+ clearHandlers();
28
+ const jsxElement = {
29
+ type: layout,
30
+ props: routeComponent ? { children: [createElement(routeComponent, {})] } : {},
31
+ };
32
+ const html = renderToString(jsxElement);
33
+ target.innerHTML = html;
34
+ attachEventHandlers(target);
35
+ }
36
+ export function render(element, container, options) {
37
+ if (!element)
38
+ return;
39
+ const target = typeof container === 'string' ? document.querySelector(container) : container;
40
+ if (!target) {
41
+ throw new Error(`Container element not found: ${container}`);
42
+ }
43
+ const layout = typeof element === 'function'
44
+ ? element
45
+ : null;
46
+ if (!layout) {
47
+ const html = renderToString(element);
48
+ target.innerHTML = html;
49
+ return;
50
+ }
51
+ const routes = options?.routes;
52
+ if (!routes || routes.length === 0) {
53
+ renderToTarget(layout, target);
54
+ return;
55
+ }
56
+ function matchRoute(pathname) {
57
+ const normalized = pathname === '/' ? '/' : pathname.replace(/\/$/, '');
58
+ for (const route of routes) {
59
+ const routePath = route.path === '/' ? '/' : route.path.replace(/\/$/, '');
60
+ if (routePath === normalized)
61
+ return route;
62
+ if (routePath !== '/' && normalized.startsWith(routePath + '/'))
63
+ return route;
64
+ if (routePath !== '/' && routePath.includes(':')) {
65
+ const routeParts = routePath.split('/');
66
+ const pathParts = normalized.split('/');
67
+ if (routeParts.length === pathParts.length) {
68
+ let match = true;
69
+ for (let i = 0; i < routeParts.length; i++) {
70
+ if (routeParts[i].startsWith(':'))
71
+ continue;
72
+ if (routeParts[i] !== pathParts[i]) {
73
+ match = false;
74
+ break;
75
+ }
76
+ }
77
+ if (match)
78
+ return route;
79
+ }
80
+ }
81
+ }
82
+ return undefined;
83
+ }
84
+ async function renderCurrentRoute() {
85
+ const matched = matchRoute(window.location.pathname);
86
+ if (matched) {
87
+ const mod = await matched.component();
88
+ renderToTarget(layout, target, mod.default);
89
+ }
90
+ else {
91
+ renderToTarget(layout, target);
92
+ }
93
+ }
94
+ renderCurrentRoute();
95
+ // Global link interceptor for SPA navigation
96
+ document.addEventListener('click', (e) => {
97
+ const link = e.target.closest('a');
98
+ if (!link)
99
+ return;
100
+ const href = link.getAttribute('href');
101
+ if (!href || href.startsWith('http') || href.startsWith('#') || link.target === '_blank')
102
+ return;
103
+ e.preventDefault();
104
+ history.pushState(null, '', href);
105
+ renderCurrentRoute();
106
+ });
107
+ window.addEventListener('popstate', () => {
108
+ renderCurrentRoute();
109
+ });
110
+ const originalPushState = history.pushState.bind(history);
111
+ history.pushState = function (...args) {
112
+ originalPushState(...args);
113
+ renderCurrentRoute();
114
+ };
115
+ const originalReplaceState = history.replaceState.bind(history);
116
+ history.replaceState = function (...args) {
117
+ originalReplaceState(...args);
118
+ renderCurrentRoute();
119
+ };
120
+ }
121
+ export function hydrate(element, container) {
122
+ render(element, container, { hydrate: true });
123
+ }
124
+ export function flushSync(fn) {
125
+ fn();
126
+ }
127
+ export function isElement(element) {
128
+ return (typeof element === 'object' &&
129
+ element !== null &&
130
+ 'type' in element &&
131
+ 'props' in element);
132
+ }
@@ -0,0 +1 @@
1
+ export {};