void-plugin-hono-jsx 0.1.0-alpha.3 → 0.1.0-alpha.4

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 (90) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +41 -12
  3. package/THIRD_PARTY_NOTICES.md +2 -2
  4. package/dist/browser/client.d.ts +2 -1
  5. package/dist/browser/client.d.ts.map +1 -1
  6. package/dist/browser/client.js +76 -22
  7. package/dist/browser/client.js.map +1 -1
  8. package/dist/browser/document-head.d.ts +1 -1
  9. package/dist/browser/document-head.d.ts.map +1 -1
  10. package/dist/browser/document-head.js +22 -1
  11. package/dist/browser/document-head.js.map +1 -1
  12. package/dist/browser/form-view.d.ts +10 -0
  13. package/dist/browser/form-view.d.ts.map +1 -0
  14. package/dist/browser/form-view.js +16 -0
  15. package/dist/browser/form-view.js.map +1 -0
  16. package/dist/browser/form.d.ts +28 -12
  17. package/dist/browser/form.d.ts.map +1 -1
  18. package/dist/browser/form.js +84 -23
  19. package/dist/browser/form.js.map +1 -1
  20. package/dist/browser/markdown.d.ts +15 -0
  21. package/dist/browser/markdown.d.ts.map +1 -0
  22. package/dist/browser/markdown.js +6 -0
  23. package/dist/browser/markdown.js.map +1 -0
  24. package/dist/browser/navigation.d.ts +13 -0
  25. package/dist/browser/navigation.d.ts.map +1 -0
  26. package/dist/browser/navigation.js +83 -0
  27. package/dist/browser/navigation.js.map +1 -0
  28. package/dist/browser/pages.d.ts +33 -3
  29. package/dist/browser/pages.d.ts.map +1 -1
  30. package/dist/browser/pages.js +76 -13
  31. package/dist/browser/pages.js.map +1 -1
  32. package/dist/plugins/hono-islands.d.ts +1 -1
  33. package/dist/plugins/hono-islands.d.ts.map +1 -1
  34. package/dist/plugins/hono-islands.js +156 -24
  35. package/dist/plugins/hono-islands.js.map +1 -1
  36. package/dist/plugins/hono-markdown.d.ts +4 -0
  37. package/dist/plugins/hono-markdown.d.ts.map +1 -0
  38. package/dist/plugins/hono-markdown.js +91 -0
  39. package/dist/plugins/hono-markdown.js.map +1 -0
  40. package/dist/plugins/hono-pages.d.ts +9 -1
  41. package/dist/plugins/hono-pages.d.ts.map +1 -1
  42. package/dist/plugins/hono-pages.js +51 -15
  43. package/dist/plugins/hono-pages.js.map +1 -1
  44. package/dist/plugins/markdown-api.d.ts +10 -0
  45. package/dist/plugins/markdown-api.d.ts.map +1 -0
  46. package/dist/plugins/markdown-api.js +13 -0
  47. package/dist/plugins/markdown-api.js.map +1 -0
  48. package/dist/plugins/markdown-compiler.d.ts +43 -0
  49. package/dist/plugins/markdown-compiler.d.ts.map +1 -0
  50. package/dist/plugins/markdown-compiler.js +91 -0
  51. package/dist/plugins/markdown-compiler.js.map +1 -0
  52. package/dist/plugins/resolve-component.d.ts +3 -0
  53. package/dist/plugins/resolve-component.d.ts.map +1 -0
  54. package/dist/plugins/resolve-component.js +15 -0
  55. package/dist/plugins/resolve-component.js.map +1 -0
  56. package/dist/plugins/runtime-paths.d.ts +1 -0
  57. package/dist/plugins/runtime-paths.d.ts.map +1 -1
  58. package/dist/plugins/runtime-paths.js +2 -0
  59. package/dist/plugins/runtime-paths.js.map +1 -1
  60. package/dist/server/form-view.d.ts +10 -0
  61. package/dist/server/form-view.d.ts.map +1 -0
  62. package/dist/server/form-view.js +16 -0
  63. package/dist/server/form-view.js.map +1 -0
  64. package/dist/server/form.d.ts +28 -12
  65. package/dist/server/form.d.ts.map +1 -1
  66. package/dist/server/form.js +84 -23
  67. package/dist/server/form.js.map +1 -1
  68. package/dist/server/markdown.d.ts +15 -0
  69. package/dist/server/markdown.d.ts.map +1 -0
  70. package/dist/server/markdown.js +6 -0
  71. package/dist/server/markdown.js.map +1 -0
  72. package/dist/server/pages.d.ts +33 -3
  73. package/dist/server/pages.d.ts.map +1 -1
  74. package/dist/server/pages.js +76 -13
  75. package/dist/server/pages.js.map +1 -1
  76. package/package.json +21 -3
  77. package/src/plugins/hono-islands.ts +121 -23
  78. package/src/plugins/hono-markdown.ts +78 -0
  79. package/src/plugins/hono-pages.ts +50 -14
  80. package/src/plugins/markdown-api.ts +17 -0
  81. package/src/plugins/markdown-compiler.ts +77 -0
  82. package/src/plugins/resolve-component.ts +12 -0
  83. package/src/plugins/runtime-paths.ts +2 -0
  84. package/src/runtime/client.tsx +66 -24
  85. package/src/runtime/document-head.ts +20 -1
  86. package/src/runtime/form-view.tsx +23 -0
  87. package/src/runtime/form.ts +82 -41
  88. package/src/runtime/markdown.ts +7 -0
  89. package/src/runtime/navigation.ts +72 -0
  90. package/src/runtime/pages.tsx +77 -15
@@ -1,54 +1,113 @@
1
- import { useContext, useRef, useState } from 'hono/jsx';
2
- import { isAbortError, submitAction } from 'void/pages-client';
3
- import { RouterContext, useErrors, useRouter } from "void-plugin-hono-jsx/pages";
1
+ import { useContext, useEffect, useRef, useState } from 'hono/jsx';
2
+ import { isAbortError, isEqualFormValue, interpolateRouteParams, submitAction, VoidActionError } from 'void/pages-client';
3
+ import { RouterContext, useErrors, useRouter, action } from "void-plugin-hono-jsx/pages";
4
+ export { Form } from './form-view.js';
5
+ export { action };
6
+ function toFormError(failure, url) {
7
+ if (failure instanceof VoidActionError)
8
+ return failure;
9
+ const message = failure instanceof Error ? failure.message : String(failure);
10
+ const error = new VoidActionError({ body: { message }, status: 0, statusText: 'Network Error', url });
11
+ error.message = message;
12
+ return error;
13
+ }
4
14
  function fieldErrors(error) {
5
15
  const body = error.body;
6
16
  if (typeof body !== 'object' || body === null || !('errors' in body) || typeof body.errors !== 'object' || body.errors === null)
7
17
  return {};
8
18
  return Object.fromEntries(Object.entries(body.errors).filter((entry) => typeof entry[1] === 'string'));
9
19
  }
10
- export function useForm(initialData) {
20
+ export function useForm(initial, values, options) {
11
21
  if (!useContext(RouterContext))
12
- throw new Error('Hono Pages: useForm requires the full Pages renderer; island form helpers are unsupported.');
22
+ throw new Error('Hono Pages: useForm requires the full Pages renderer; use useIslandForm for islands.');
13
23
  const router = useRouter();
14
- const initialErrors = useErrors();
15
- const [data, updateData] = useState(initialData);
24
+ const bound = typeof initial === 'string' ? initial : undefined;
25
+ return useFormModel(typeof initial === 'string' ? values ?? {} : initial, useErrors(), async (method, url, data) => submitAction(router, interpolateRouteParams(url, options?.params), { method: method.toUpperCase(), data, preserveScroll: true }), () => router.refresh(), bound);
26
+ }
27
+ export function useIslandForm(defaults) {
28
+ const controller = useRef(null);
29
+ useEffect(() => () => controller.current?.abort(), []);
30
+ return useFormModel(defaults, {}, async (method, url, data) => {
31
+ const target = new URL(url, window.location.href);
32
+ if (target.origin !== window.location.origin || !['http:', 'https:'].includes(target.protocol))
33
+ throw new Error('Hono island form: actions must target the current origin.');
34
+ controller.current = new AbortController();
35
+ const response = await fetch(target, { method: method.toUpperCase(), headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), signal: controller.current.signal });
36
+ if (response.redirected && response.ok) {
37
+ window.location.assign(response.url);
38
+ return { ok: true, pageData: undefined };
39
+ }
40
+ if (response.ok) {
41
+ window.location.reload();
42
+ return { ok: true, pageData: undefined };
43
+ }
44
+ let body;
45
+ try {
46
+ body = response.headers.get('content-type')?.includes('application/json') ? await response.json() : await response.text();
47
+ }
48
+ catch {
49
+ body = null;
50
+ }
51
+ return { ok: false, error: new VoidActionError({ body, status: response.status, statusText: response.statusText, url: target.href }) };
52
+ }, () => controller.current?.abort());
53
+ }
54
+ function useFormModel(initial, initialErrors, send, abort, bound) {
55
+ const defaults = useRef({ ...initial });
56
+ const current = useRef({ ...defaults.current });
57
+ const [data, updateData] = useState(current.current);
16
58
  const [errors, setErrors] = useState(initialErrors);
17
59
  const [pending, setPending] = useState(false);
18
60
  const [wasSuccessful, setSuccessful] = useState(false);
61
+ const [recentlySuccessful, setRecent] = useState(false);
19
62
  const [error, setError] = useState(null);
20
63
  const active = useRef(false);
21
64
  const generation = useRef(0);
22
- const setData = (next) => {
23
- updateData(next);
65
+ const timer = useRef(undefined);
66
+ useEffect(() => () => { ++generation.current; active.current = false; clearTimeout(timer.current); }, []);
67
+ const setData = (next, value) => {
68
+ current.current = typeof next === 'string' ? { ...current.current, [next]: value } : typeof next === 'function' ? next(current.current) : { ...next };
69
+ updateData(current.current);
24
70
  setSuccessful(false);
25
71
  setErrors({});
26
72
  setError(null);
73
+ setRecent(false);
74
+ clearTimeout(timer.current);
27
75
  };
28
- async function submit(method, url) {
76
+ async function submit(method, target) {
77
+ const url = typeof target === 'string' ? target : bound;
78
+ if (!url)
79
+ throw new Error('Hono Form: supply an action URL to useForm or submit.');
29
80
  if (active.current)
30
81
  return;
31
82
  active.current = true;
32
83
  const id = ++generation.current;
33
84
  setPending(true);
34
85
  setSuccessful(false);
86
+ setRecent(false);
87
+ clearTimeout(timer.current);
35
88
  setError(null);
36
89
  setErrors({});
90
+ const submitted = { ...current.current };
37
91
  try {
38
- const result = await submitAction(router, url, { method: method.toUpperCase(), data, preserveScroll: true });
92
+ const result = await send(method, url, submitted);
39
93
  if (id !== generation.current)
40
94
  return;
41
- if (result.ok)
95
+ if (result.ok) {
96
+ if (bound)
97
+ defaults.current = submitted;
42
98
  setSuccessful(true);
99
+ setRecent(true);
100
+ timer.current = setTimeout(() => { if (id === generation.current)
101
+ setRecent(false); }, 2000);
102
+ }
43
103
  else {
44
104
  setError(result.error);
45
105
  setErrors(fieldErrors(result.error));
46
106
  }
47
107
  }
48
108
  catch (failure) {
49
- if (id === generation.current && !isAbortError(failure)) {
50
- setError(failure instanceof Error ? failure : new Error(String(failure)));
51
- }
109
+ if (id === generation.current && !isAbortError(failure))
110
+ setError(toFormError(failure, url));
52
111
  }
53
112
  finally {
54
113
  if (id === generation.current) {
@@ -64,18 +123,20 @@ export function useForm(initialData) {
64
123
  active.current = false;
65
124
  setPending(false);
66
125
  setSuccessful(false);
67
- void router.refresh().catch((failure) => {
126
+ setRecent(false);
127
+ clearTimeout(timer.current);
128
+ void Promise.resolve(abort()).catch((failure) => {
68
129
  if (id === generation.current)
69
- setError(failure instanceof Error ? failure : new Error(String(failure)));
130
+ setError(toFormError(failure, bound ?? 'island'));
70
131
  });
71
132
  }
72
133
  return {
73
- data, setData, errors, pending, wasSuccessful, error, submit, cancel,
74
- reset() { setData(initialData); },
75
- post: (url) => submit('post', url),
76
- put: (url) => submit('put', url),
77
- patch: (url) => submit('patch', url),
78
- delete: (url) => submit('delete', url),
134
+ data, setData, errors, pending, wasSuccessful, recentlySuccessful, error, submit, cancel,
135
+ hasChanges: Object.keys({ ...defaults.current, ...data }).some((key) => !isEqualFormValue(defaults.current[key], data[key])),
136
+ reset(...fields) { const keys = fields.filter((field) => typeof field === 'string'); setData(keys.length ? { ...current.current, ...Object.fromEntries(keys.map((key) => [key, defaults.current[key]])) } : { ...defaults.current }); },
137
+ clearErrors(...fields) { setErrors((previous) => fields.length ? Object.fromEntries(Object.entries(previous).filter(([field]) => !fields.includes(field))) : {}); },
138
+ clearError() { setError(null); },
139
+ post: (target) => submit('post', target), put: (target) => submit('put', target), patch: (target) => submit('patch', target), delete: (target) => submit('delete', target),
79
140
  };
80
141
  }
81
142
  //# sourceMappingURL=form.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"form.js","mappings":"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","names":[],"ignoreList":[],"sources":["../../src/runtime/form.ts"],"sourcesContent":["import { useContext, useRef, useState } from 'hono/jsx';\nimport { isAbortError, submitAction, VoidActionError, type FormMethod } from 'void/pages-client';\nimport { RouterContext, useErrors, useRouter } from './pages.tsx';\n\nfunction fieldErrors(error: VoidActionError): Record<string, string> {\n const body = error.body;\n if (typeof body !== 'object' || body === null || !('errors' in body) || typeof body.errors !== 'object' || body.errors === null) return {};\n return Object.fromEntries(Object.entries(body.errors).filter((entry): entry is [string, string] => typeof entry[1] === 'string'));\n}\n\nexport function useForm<T extends Record<string, unknown>>(initialData: T) {\n if (!useContext(RouterContext)) throw new Error('Hono Pages: useForm requires the full Pages renderer; island form helpers are unsupported.');\n const router = useRouter();\n const initialErrors = useErrors();\n const [data, updateData] = useState(initialData);\n const [errors, setErrors] = useState(initialErrors);\n const [pending, setPending] = useState(false);\n const [wasSuccessful, setSuccessful] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const active = useRef(false);\n const generation = useRef(0);\n\n const setData: typeof updateData = (next) => {\n updateData(next);\n setSuccessful(false);\n setErrors({});\n setError(null);\n };\n\n async function submit(method: FormMethod, url: string) {\n if (active.current) return;\n active.current = true;\n const id = ++generation.current;\n setPending(true);\n setSuccessful(false);\n setError(null);\n setErrors({});\n try {\n const result = await submitAction(router, url, { method: method.toUpperCase(), data, preserveScroll: true });\n if (id !== generation.current) return;\n if (result.ok) setSuccessful(true);\n else { setError(result.error); setErrors(fieldErrors(result.error)); }\n } catch (failure) {\n if (id === generation.current && !isAbortError(failure)) {\n setError(failure instanceof Error ? failure : new Error(String(failure)));\n }\n } finally {\n if (id === generation.current) { active.current = false; setPending(false); }\n }\n }\n\n function cancel() {\n if (!active.current) return;\n const id = ++generation.current;\n active.current = false;\n setPending(false);\n setSuccessful(false);\n void router.refresh().catch((failure: unknown) => {\n if (id === generation.current) setError(failure instanceof Error ? failure : new Error(String(failure)));\n });\n }\n\n return {\n data, setData, errors, pending, wasSuccessful, error, submit, cancel,\n reset() { setData(initialData); },\n post: (url: string) => submit('post', url),\n put: (url: string) => submit('put', url),\n patch: (url: string) => submit('patch', url),\n delete: (url: string) => submit('delete', url),\n };\n}\n"]}
1
+ {"version":3,"file":"form.js","mappings":"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","names":[],"ignoreList":[],"sources":["../../src/runtime/form.ts"],"sourcesContent":["import { useContext, useEffect, useRef, useState } from 'hono/jsx';\nimport { isAbortError, isEqualFormValue, interpolateRouteParams, submitAction, VoidActionError, type ActionResult, type FormMethod } from 'void/pages-client';\nimport type { ActionFormOptions, ActionUrl, ResolveActionBody } from 'void/routes';\nimport { RouterContext, useErrors, useRouter, action } from './pages.tsx';\nexport { Form, type FormProps } from './form-view.tsx';\nexport { action };\n\ntype Fields = Record<string, unknown>;\ntype Body<U extends string> = ResolveActionBody<U> extends Fields ? ResolveActionBody<U> : Fields;\ntype SetData<T> = { (next: T | ((current: T) => T)): void; <K extends keyof T & string>(field: K, value: T[K]): void };\nexport type HonoForm<T extends Fields> = {\n data: T; setData: SetData<T>; errors: Record<string, string>; pending: boolean;\n error: VoidActionError | null; hasChanges: boolean; wasSuccessful: boolean; recentlySuccessful: boolean;\n submit(method: FormMethod, target?: string | FormData): Promise<void>; cancel(): void;\n reset: { (): void; (...fields: Array<keyof T & string>): void }; clearErrors(...fields: Array<keyof T & string>): void; clearError(): void;\n} & Record<FormMethod, (target?: string | FormData) => Promise<void>>;\n\nfunction toFormError(failure: unknown, url: string): VoidActionError {\n if (failure instanceof VoidActionError) return failure;\n const message = failure instanceof Error ? failure.message : String(failure);\n const error = new VoidActionError({ body: { message }, status: 0, statusText: 'Network Error', url });\n error.message = message;\n return error;\n}\n\nfunction fieldErrors(error: VoidActionError): Record<string, string> {\n const body = error.body;\n if (typeof body !== 'object' || body === null || !('errors' in body) || typeof body.errors !== 'object' || body.errors === null) return {};\n return Object.fromEntries(Object.entries(body.errors).filter((entry): entry is [string, string] => typeof entry[1] === 'string'));\n}\n\nexport function useForm<T extends Fields>(initialData: T): HonoForm<T>;\nexport function useForm<U extends ActionUrl & string>(url: U, defaults: Body<U>, options?: ActionFormOptions<U>): HonoForm<Body<U>>;\nexport function useForm(initial: string | Fields, values?: Fields, options?: { params?: Record<string, string> }): HonoForm<Fields> {\n if (!useContext(RouterContext)) throw new Error('Hono Pages: useForm requires the full Pages renderer; use useIslandForm for islands.');\n const router = useRouter();\n const bound = typeof initial === 'string' ? initial : undefined;\n return useFormModel(typeof initial === 'string' ? values ?? {} : initial, useErrors(), async (method, url, data) => submitAction(router, interpolateRouteParams(url, options?.params), { method: method.toUpperCase(), data, preserveScroll: true }), () => router.refresh(), bound);\n}\n\nexport function useIslandForm<T extends Fields>(defaults: T): HonoForm<T> {\n const controller = useRef<AbortController | null>(null);\n useEffect(() => () => controller.current?.abort(), []);\n return useFormModel(defaults, {}, async (method, url, data) => {\n const target = new URL(url, window.location.href);\n if (target.origin !== window.location.origin || !['http:', 'https:'].includes(target.protocol)) throw new Error('Hono island form: actions must target the current origin.');\n controller.current = new AbortController();\n const response = await fetch(target, { method: method.toUpperCase(), headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), signal: controller.current.signal });\n if (response.redirected && response.ok) { window.location.assign(response.url); return { ok: true, pageData: undefined }; }\n if (response.ok) { window.location.reload(); return { ok: true, pageData: undefined }; }\n let body: unknown;\n try { body = response.headers.get('content-type')?.includes('application/json') ? await response.json() : await response.text(); } catch { body = null; }\n return { ok: false, error: new VoidActionError({ body, status: response.status, statusText: response.statusText, url: target.href }) };\n }, () => controller.current?.abort());\n}\n\ntype FormTransport = (method: FormMethod, url: string, data: Fields) => Promise<ActionResult>;\nfunction useFormModel<T extends Fields>(initial: T, initialErrors: Record<string, string>, send: FormTransport, abort: () => void | Promise<unknown>, bound?: string): HonoForm<T> {\n const defaults = useRef({ ...initial });\n const current = useRef({ ...defaults.current });\n const [data, updateData] = useState(current.current);\n const [errors, setErrors] = useState(initialErrors);\n const [pending, setPending] = useState(false);\n const [wasSuccessful, setSuccessful] = useState(false);\n const [recentlySuccessful, setRecent] = useState(false);\n const [error, setError] = useState<VoidActionError | null>(null);\n const active = useRef(false);\n const generation = useRef(0);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n useEffect(() => () => { ++generation.current; active.current = false; clearTimeout(timer.current); }, []);\n\n const setData: SetData<T> = (next: T | ((current: T) => T) | string, value?: unknown) => {\n current.current = typeof next === 'string' ? { ...current.current, [next]: value } as T : typeof next === 'function' ? next(current.current) : { ...next };\n updateData(current.current); setSuccessful(false); setErrors({}); setError(null); setRecent(false); clearTimeout(timer.current);\n };\n async function submit(method: FormMethod, target?: string | FormData) {\n const url = typeof target === 'string' ? target : bound;\n if (!url) throw new Error('Hono Form: supply an action URL to useForm or submit.');\n if (active.current) return;\n active.current = true; const id = ++generation.current;\n setPending(true); setSuccessful(false); setRecent(false); clearTimeout(timer.current); setError(null); setErrors({});\n const submitted = { ...current.current };\n try {\n const result = await send(method, url, submitted);\n if (id !== generation.current) return;\n if (result.ok) {\n if (bound) defaults.current = submitted;\n setSuccessful(true); setRecent(true);\n timer.current = setTimeout(() => { if (id === generation.current) setRecent(false); }, 2000);\n } else { setError(result.error); setErrors(fieldErrors(result.error)); }\n } catch (failure) {\n if (id === generation.current && !isAbortError(failure)) setError(toFormError(failure, url));\n } finally {\n if (id === generation.current) { active.current = false; setPending(false); }\n }\n }\n function cancel() {\n if (!active.current) return;\n const id = ++generation.current; active.current = false; setPending(false); setSuccessful(false); setRecent(false); clearTimeout(timer.current);\n void Promise.resolve(abort()).catch((failure: unknown) => {\n if (id === generation.current) setError(toFormError(failure, bound ?? 'island'));\n });\n }\n return {\n data, setData, errors, pending, wasSuccessful, recentlySuccessful, error, submit, cancel,\n hasChanges: Object.keys({ ...defaults.current, ...data }).some((key) => !isEqualFormValue(defaults.current[key], data[key])),\n reset(...fields: Array<string | MouseEvent>) { const keys = fields.filter((field): field is string => typeof field === 'string'); setData(keys.length ? { ...current.current, ...Object.fromEntries(keys.map((key) => [key, defaults.current[key]])) } as T : { ...defaults.current }); },\n clearErrors(...fields) { setErrors((previous) => fields.length ? Object.fromEntries(Object.entries(previous).filter(([field]) => !fields.includes(field))) : {}); },\n clearError() { setError(null); },\n post: (target) => submit('post', target), put: (target) => submit('put', target), patch: (target) => submit('patch', target), delete: (target) => submit('delete', target),\n };\n}\n"]}
@@ -0,0 +1,15 @@
1
+ export type MarkdownHeading = {
2
+ depth: number;
3
+ slug: string;
4
+ text: string;
5
+ };
6
+ export type MarkdownContextValue = {
7
+ frontmatter: Record<string, unknown>;
8
+ headings: MarkdownHeading[];
9
+ props: Record<string, unknown>;
10
+ };
11
+ export declare const MarkdownContext: import("hono/jsx").Context<MarkdownContextValue>;
12
+ export declare function useFrontmatter<T = Record<string, unknown>>(): T;
13
+ export declare function useMarkdownHeadings(): MarkdownHeading[];
14
+ export declare function useMarkdownProps<T = Record<string, unknown>>(): T;
15
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/runtime/markdown.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,eAAe,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAC5E,MAAM,MAAM,oBAAoB,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AACzI,eAAO,MAAM,eAAe,kDAAoF,CAAC;AACjH,wBAAgB,cAAc,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAyD;AACzH,wBAAgB,mBAAmB,IAAI,eAAe,EAAE,CAAiD;AACzG,wBAAgB,gBAAgB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAmD"}
@@ -0,0 +1,6 @@
1
+ import { createContext, useContext } from 'hono/jsx';
2
+ export const MarkdownContext = createContext({ frontmatter: {}, headings: [], props: {} });
3
+ export function useFrontmatter() { return useContext(MarkdownContext).frontmatter; }
4
+ export function useMarkdownHeadings() { return useContext(MarkdownContext).headings; }
5
+ export function useMarkdownProps() { return useContext(MarkdownContext).props; }
6
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/runtime/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGrD,MAAM,CAAC,MAAM,eAAe,GAAG,aAAa,CAAuB,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;AACjH,MAAM,UAAU,cAAc,KAAqC,OAAO,UAAU,CAAC,eAAe,CAAC,CAAC,WAAgB,CAAC,CAAC,CAAC;AACzH,MAAM,UAAU,mBAAmB,KAAwB,OAAO,UAAU,CAAC,eAAe,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AACzG,MAAM,UAAU,gBAAgB,KAAqC,OAAO,UAAU,CAAC,eAAe,CAAC,CAAC,KAAU,CAAC,CAAC,CAAC","sourcesContent":["import { createContext, useContext } from 'hono/jsx';\nexport type MarkdownHeading = { depth: number; slug: string; text: string };\nexport type MarkdownContextValue = { frontmatter: Record<string, unknown>; headings: MarkdownHeading[]; props: Record<string, unknown> };\nexport const MarkdownContext = createContext<MarkdownContextValue>({ frontmatter: {}, headings: [], props: {} });\nexport function useFrontmatter<T = Record<string, unknown>>(): T { return useContext(MarkdownContext).frontmatter as T; }\nexport function useMarkdownHeadings(): MarkdownHeading[] { return useContext(MarkdownContext).headings; }\nexport function useMarkdownProps<T = Record<string, unknown>>(): T { return useContext(MarkdownContext).props as T; }\n"]}
@@ -1,18 +1,48 @@
1
1
  import { type JSX } from 'hono/jsx';
2
- import type { VoidRouter } from 'void/pages-client';
2
+ import { type NavigationState, type NavigationMethod, type VoidRouter } from 'void/pages-client';
3
+ import type { CacheForInput } from 'void/pages-prefetch';
3
4
  import type { PageObject } from 'void/pages-protocol';
4
5
  export type { DeferredState as Deferred } from 'void';
6
+ export declare const action: <U extends import("void/routes").ActionUrl & string>(url: U, ...args: ([import("void/routes").ResolveActionParams<U>] extends [never] ? false : true) extends true ? [options: {
7
+ data?: import("void/routes").ResolveActionBody<U> | undefined;
8
+ method?: "DELETE" | "PATCH" | "POST" | "PUT";
9
+ } & (([import("void/routes").ResolveActionParams<U>] extends [never] ? false : true) extends true ? {
10
+ params: import("void/routes").ResolveActionParams<U>;
11
+ } : {
12
+ params?: never;
13
+ })] : [options?: {
14
+ data?: import("void/routes").ResolveActionBody<U> | undefined;
15
+ method?: "DELETE" | "PATCH" | "POST" | "PUT";
16
+ } & (([import("void/routes").ResolveActionParams<U>] extends [never] ? false : true) extends true ? {
17
+ params: import("void/routes").ResolveActionParams<U>;
18
+ } : {
19
+ params?: never;
20
+ })]) => Promise<import("void/pages-client").ActionResult>;
21
+ export declare const setActionRouter: (router: VoidRouter) => void;
5
22
  export declare const RouterContext: import("hono/jsx").Context<VoidRouter | null>;
23
+ export declare const NavigationContext: import("hono/jsx").Context<NavigationState | null>;
6
24
  export declare const PageContext: import("hono/jsx").Context<PageObject | null>;
25
+ export declare function useNavigation(): NavigationState;
7
26
  export declare function useShared(): Record<string, unknown>;
8
27
  export declare function useParams(): Record<string, string>;
9
28
  export declare function useErrors(): Record<string, string>;
10
29
  export declare function useRouter(): VoidRouter;
11
- type LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {
30
+ export type PrefetchStrategy = 'hover' | 'click' | 'mount' | 'visible';
31
+ export type LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {
12
32
  href: string;
33
+ method?: NavigationMethod | Lowercase<NavigationMethod>;
34
+ data?: Record<string, unknown>;
35
+ preserveScroll?: boolean;
36
+ preserveState?: boolean;
13
37
  reloadDocument?: boolean;
14
38
  replace?: boolean;
39
+ viewTransition?: boolean;
40
+ prefetch?: boolean | PrefetchStrategy | ReadonlyArray<PrefetchStrategy>;
41
+ cacheFor?: CacheForInput;
42
+ onNavigate?: (event: {
43
+ preventDefault(): void;
44
+ }) => void;
15
45
  onClick?: (event: MouseEvent) => void;
16
46
  };
17
- export declare function Link({ href, reloadDocument, replace, onClick, ...attributes }: LinkProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
47
+ export declare function Link({ href, method, data, preserveScroll, preserveState, reloadDocument, replace, viewTransition, prefetch, cacheFor, onNavigate, onClick, onMouseEnter, onMouseLeave, onFocus, onMouseDown, onTouchStart, ...attributes }: LinkProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
18
48
  //# sourceMappingURL=pages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;AAEtD,eAAO,MAAM,aAAa,+CAAyC,CAAC;AACpE,eAAO,MAAM,WAAW,+CAAyC,CAAC;AAQlE,wBAAgB,SAAS,4BAA+B;AACxD,wBAAgB,SAAS,2BAA+B;AACxD,wBAAgB,SAAS,2BAAqC;AAE9D,wBAAgB,SAAS,IAAI,UAAU,CAItC;AAED,KAAK,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,EAAE,SAAS,kDAaxF"}
1
+ {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAClF,OAAO,EAAyC,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACxI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;AAGtD,eAAO,MAAM,MAAM;;;;;;;;;;;;;;yDAAsB,CAAC;AAC1C,eAAO,MAAM,eAAe,8BAA+B,CAAC;AAE5D,eAAO,MAAM,aAAa,+CAAyC,CAAC;AACpE,eAAO,MAAM,iBAAiB,oDAA8C,CAAC;AAC7E,eAAO,MAAM,WAAW,+CAAyC,CAAC;AAQlE,wBAAgB,aAAa,IAAI,eAAe,CAI/C;AAED,wBAAgB,SAAS,4BAA+B;AACxD,wBAAgB,SAAS,2BAA+B;AACxD,wBAAgB,SAAS,2BAAqC;AAE9D,wBAAgB,SAAS,IAAI,UAAU,CAItC;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AACvE,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,GAAG,gBAAgB,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACxE,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,cAAc,IAAI,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IACzD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,MAAc,EAAE,IAAI,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EACvH,QAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAC/G,GAAG,UAAU,EAAE,EAAE,SAAS,kDAoD3B"}
@@ -1,6 +1,11 @@
1
1
  import { jsx as _jsx } from "hono/jsx/jsx-runtime";
2
- import { createContext, useContext } from 'hono/jsx';
2
+ import { createContext, useContext, useEffect, useRef } from 'hono/jsx';
3
+ import { createActionClient, mergeDataIntoHref } from 'void/pages-client';
4
+ const actionClient = createActionClient();
5
+ export const action = actionClient.action;
6
+ export const setActionRouter = actionClient.setActionRouter;
3
7
  export const RouterContext = createContext(null);
8
+ export const NavigationContext = createContext(null);
4
9
  export const PageContext = createContext(null);
5
10
  function usePage() {
6
11
  const page = useContext(PageContext);
@@ -8,6 +13,12 @@ function usePage() {
8
13
  throw new Error('Hono Pages: page data requires a page provider.');
9
14
  return page;
10
15
  }
16
+ export function useNavigation() {
17
+ const navigation = useContext(NavigationContext);
18
+ if (!navigation)
19
+ throw new Error('Hono Pages: useNavigation requires a page provider.');
20
+ return navigation;
21
+ }
11
22
  export function useShared() { return usePage().shared; }
12
23
  export function useParams() { return usePage().params; }
13
24
  export function useErrors() { return usePage().errors ?? {}; }
@@ -17,21 +28,73 @@ export function useRouter() {
17
28
  throw new Error('Hono Pages: useRouter requires a page provider.');
18
29
  return router;
19
30
  }
20
- export function Link({ href, reloadDocument, replace, onClick, ...attributes }) {
31
+ export function Link({ href, method = 'GET', data, preserveScroll, preserveState, reloadDocument, replace, viewTransition, prefetch = false, cacheFor, onNavigate, onClick, onMouseEnter, onMouseLeave, onFocus, onMouseDown, onTouchStart, ...attributes }) {
21
32
  const router = useRouter();
22
- return _jsx("a", { ...attributes, href: href, onClick: (event) => {
33
+ const element = useRef(null);
34
+ const timer = useRef(undefined);
35
+ const normalized = method.toUpperCase();
36
+ const get = normalized === 'GET';
37
+ if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(normalized))
38
+ throw new Error('Hono Link: unsupported method.');
39
+ if (!get && (prefetch !== false || reloadDocument))
40
+ throw new Error('Hono Link: prefetch and reloadDocument only support GET links.');
41
+ const destination = get ? mergeDataIntoHref(href, data) : href;
42
+ const strategies = reloadDocument || prefetch === false ? [] : prefetch === true ? ['hover'] : typeof prefetch === 'string' ? [prefetch] : prefetch;
43
+ if (strategies.some((strategy) => !['hover', 'click', 'mount', 'visible'].includes(strategy)))
44
+ throw new Error('Hono Link: unsupported prefetch strategy.');
45
+ const clear = () => { clearTimeout(timer.current); timer.current = undefined; };
46
+ const canHandle = () => {
47
+ const url = new URL(destination, window.location.href);
48
+ return !reloadDocument && attributes.download === undefined && (!attributes.target || attributes.target === '_self') &&
49
+ !attributes.rel?.split(/\s+/).includes('external') && url.origin === window.location.origin && ['http:', 'https:'].includes(url.protocol);
50
+ };
51
+ const report = (error) => window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));
52
+ const fetchAhead = () => {
53
+ if (canHandle())
54
+ void router.prefetch(destination, { cacheFor }).catch(report);
55
+ };
56
+ useEffect(() => {
57
+ if (strategies.includes('mount'))
58
+ fetchAhead();
59
+ let observer;
60
+ if (strategies.includes('visible') && element.current) {
61
+ observer = new IntersectionObserver((entries) => {
62
+ if (entries.some((entry) => entry.isIntersecting)) {
63
+ observer?.disconnect();
64
+ fetchAhead();
65
+ }
66
+ });
67
+ observer.observe(element.current);
68
+ }
69
+ return () => { clear(); observer?.disconnect(); };
70
+ }, [destination, prefetch, cacheFor, reloadDocument, router]);
71
+ const events = {
72
+ onClick(event) {
23
73
  onClick?.(event);
24
- if (event.defaultPrevented || reloadDocument || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)
25
- return;
26
- if (attributes.download !== undefined || (attributes.target && attributes.target !== '_self') || attributes.rel?.split(/\s+/).includes('external'))
27
- return;
28
- const url = new URL(href, window.location.href);
29
- if (url.origin !== window.location.origin || !['http:', 'https:'].includes(url.protocol))
74
+ if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || !canHandle())
30
75
  return;
76
+ let cancelled = false;
77
+ onNavigate?.({ preventDefault() { cancelled = true; } });
31
78
  event.preventDefault();
32
- void router.visit(url, { replace }).catch((error) => {
33
- window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));
34
- });
35
- } });
79
+ if (!cancelled)
80
+ void router.visit(new URL(destination, window.location.href), { method: normalized, data: get ? undefined : data, preserveScroll, preserveState, replace, viewTransition }).catch(report);
81
+ },
82
+ onMouseEnter(event) {
83
+ onMouseEnter?.(event);
84
+ clear();
85
+ if (!event.defaultPrevented && strategies.includes('hover'))
86
+ timer.current = setTimeout(fetchAhead, router._hoverDelay);
87
+ },
88
+ onMouseLeave(event) { onMouseLeave?.(event); clear(); },
89
+ onFocus(event) { onFocus?.(event); if (!event.defaultPrevented && strategies.includes('hover'))
90
+ fetchAhead(); },
91
+ onMouseDown(event) { onMouseDown?.(event); if (!event.defaultPrevented && strategies.includes('click'))
92
+ fetchAhead(); },
93
+ onTouchStart(event) { onTouchStart?.(event); if (!event.defaultPrevented && strategies.includes('click'))
94
+ fetchAhead(); },
95
+ };
96
+ if (get)
97
+ return _jsx("a", { ...attributes, ...events, ref: element, href: destination });
98
+ return _jsx("button", { ...attributes, ...events, ref: element, type: "button" });
36
99
  }
37
100
  //# sourceMappingURL=pages.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAY,MAAM,UAAU,CAAC;AAK/D,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAoB,IAAI,CAAC,CAAC;AACpE,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAoB,IAAI,CAAC,CAAC;AAElE,SAAS,OAAO;IACd,MAAM,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IAC9E,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,SAAS,KAAK,OAAO,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AACxD,MAAM,UAAU,SAAS,KAAK,OAAO,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AACxD,MAAM,UAAU,SAAS,KAAK,OAAO,OAAO,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;AAE9D,MAAM,UAAU,SAAS;IACvB,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IAChF,OAAO,MAAM,CAAC;AAChB,CAAC;AASD,MAAM,UAAU,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,UAAU,EAAa;IACvF,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,OAAO,eAAO,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,KAAiB,EAAE,EAAE;YACnE,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;YACjB,IAAI,KAAK,CAAC,gBAAgB,IAAI,cAAc,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM;gBAAE,OAAO;YAC/I,IAAI,UAAU,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,KAAK,OAAO,CAAC,IAAI,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC;gBAAE,OAAO;YAC3J,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAChD,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAAE,OAAO;YACjG,KAAK,CAAC,cAAc,EAAE,CAAC;YACvB,KAAK,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBAC3D,MAAM,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,6BAA6B,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YAC1F,CAAC,CAAC,CAAC;QACL,CAAC,GAAI,CAAC;AACR,CAAC","sourcesContent":["import { createContext, useContext, type JSX } from 'hono/jsx';\nimport type { VoidRouter } from 'void/pages-client';\nimport type { PageObject } from 'void/pages-protocol';\nexport type { DeferredState as Deferred } from 'void';\n\nexport const RouterContext = createContext<VoidRouter | null>(null);\nexport const PageContext = createContext<PageObject | null>(null);\n\nfunction usePage() {\n const page = useContext(PageContext);\n if (!page) throw new Error('Hono Pages: page data requires a page provider.');\n return page;\n}\n\nexport function useShared() { return usePage().shared; }\nexport function useParams() { return usePage().params; }\nexport function useErrors() { return usePage().errors ?? {}; }\n\nexport function useRouter(): VoidRouter {\n const router = useContext(RouterContext);\n if (!router) throw new Error('Hono Pages: useRouter requires a page provider.');\n return router;\n}\n\ntype LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {\n href: string;\n reloadDocument?: boolean;\n replace?: boolean;\n onClick?: (event: MouseEvent) => void;\n};\n\nexport function Link({ href, reloadDocument, replace, onClick, ...attributes }: LinkProps) {\n const router = useRouter();\n return <a {...attributes} href={href} onClick={(event: MouseEvent) => {\n onClick?.(event);\n if (event.defaultPrevented || reloadDocument || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;\n if (attributes.download !== undefined || (attributes.target && attributes.target !== '_self') || attributes.rel?.split(/\\s+/).includes('external')) return;\n const url = new URL(href, window.location.href);\n if (url.origin !== window.location.origin || !['http:', 'https:'].includes(url.protocol)) return;\n event.preventDefault();\n void router.visit(url, { replace }).catch((error: unknown) => {\n window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));\n });\n }} />;\n}\n"]}
1
+ {"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"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","sourcesContent":["import { createContext, useContext, useEffect, useRef, type JSX } from 'hono/jsx';\nimport { createActionClient, mergeDataIntoHref, type NavigationState, type NavigationMethod, type VoidRouter } from 'void/pages-client';\nimport type { CacheForInput } from 'void/pages-prefetch';\nimport type { PageObject } from 'void/pages-protocol';\nexport type { DeferredState as Deferred } from 'void';\n\nconst actionClient = createActionClient();\nexport const action = actionClient.action;\nexport const setActionRouter = actionClient.setActionRouter;\n\nexport const RouterContext = createContext<VoidRouter | null>(null);\nexport const NavigationContext = createContext<NavigationState | null>(null);\nexport const PageContext = createContext<PageObject | null>(null);\n\nfunction usePage() {\n const page = useContext(PageContext);\n if (!page) throw new Error('Hono Pages: page data requires a page provider.');\n return page;\n}\n\nexport function useNavigation(): NavigationState {\n const navigation = useContext(NavigationContext);\n if (!navigation) throw new Error('Hono Pages: useNavigation requires a page provider.');\n return navigation;\n}\n\nexport function useShared() { return usePage().shared; }\nexport function useParams() { return usePage().params; }\nexport function useErrors() { return usePage().errors ?? {}; }\n\nexport function useRouter(): VoidRouter {\n const router = useContext(RouterContext);\n if (!router) throw new Error('Hono Pages: useRouter requires a page provider.');\n return router;\n}\n\nexport type PrefetchStrategy = 'hover' | 'click' | 'mount' | 'visible';\nexport type LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {\n href: string;\n method?: NavigationMethod | Lowercase<NavigationMethod>;\n data?: Record<string, unknown>;\n preserveScroll?: boolean;\n preserveState?: boolean;\n reloadDocument?: boolean;\n replace?: boolean;\n viewTransition?: boolean;\n prefetch?: boolean | PrefetchStrategy | ReadonlyArray<PrefetchStrategy>;\n cacheFor?: CacheForInput;\n onNavigate?: (event: { preventDefault(): void }) => void;\n onClick?: (event: MouseEvent) => void;\n};\n\nexport function Link({ href, method = 'GET', data, preserveScroll, preserveState, reloadDocument, replace, viewTransition,\n prefetch = false, cacheFor, onNavigate, onClick, onMouseEnter, onMouseLeave, onFocus, onMouseDown, onTouchStart,\n ...attributes }: LinkProps) {\n const router = useRouter();\n const element = useRef<HTMLAnchorElement | HTMLButtonElement | null>(null);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const normalized = method.toUpperCase();\n const get = normalized === 'GET';\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(normalized)) throw new Error('Hono Link: unsupported method.');\n if (!get && (prefetch !== false || reloadDocument)) throw new Error('Hono Link: prefetch and reloadDocument only support GET links.');\n const destination = get ? mergeDataIntoHref(href, data) : href;\n const strategies = reloadDocument || prefetch === false ? [] : prefetch === true ? ['hover'] : typeof prefetch === 'string' ? [prefetch] : prefetch;\n if (strategies.some((strategy) => !['hover', 'click', 'mount', 'visible'].includes(strategy))) throw new Error('Hono Link: unsupported prefetch strategy.');\n const clear = () => { clearTimeout(timer.current); timer.current = undefined; };\n const canHandle = () => {\n const url = new URL(destination, window.location.href);\n return !reloadDocument && attributes.download === undefined && (!attributes.target || attributes.target === '_self') &&\n !attributes.rel?.split(/\\s+/).includes('external') && url.origin === window.location.origin && ['http:', 'https:'].includes(url.protocol);\n };\n const report = (error: unknown) => window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));\n const fetchAhead = () => {\n if (canHandle()) void router.prefetch(destination, { cacheFor }).catch(report);\n };\n useEffect(() => {\n if (strategies.includes('mount')) fetchAhead();\n let observer: IntersectionObserver | undefined;\n if (strategies.includes('visible') && element.current) {\n observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) { observer?.disconnect(); fetchAhead(); }\n });\n observer.observe(element.current);\n }\n return () => { clear(); observer?.disconnect(); };\n }, [destination, prefetch, cacheFor, reloadDocument, router]);\n const events = {\n onClick(event: MouseEvent) {\n onClick?.(event);\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || !canHandle()) return;\n let cancelled = false;\n onNavigate?.({ preventDefault() { cancelled = true; } });\n event.preventDefault();\n if (!cancelled) void router.visit(new URL(destination, window.location.href), { method: normalized, data: get ? undefined : data, preserveScroll, preserveState, replace, viewTransition }).catch(report);\n },\n onMouseEnter(event: MouseEvent) {\n onMouseEnter?.(event); clear();\n if (!event.defaultPrevented && strategies.includes('hover')) timer.current = setTimeout(fetchAhead, router._hoverDelay);\n },\n onMouseLeave(event: MouseEvent) { onMouseLeave?.(event); clear(); },\n onFocus(event: FocusEvent) { onFocus?.(event); if (!event.defaultPrevented && strategies.includes('hover')) fetchAhead(); },\n onMouseDown(event: MouseEvent) { onMouseDown?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n onTouchStart(event: TouchEvent) { onTouchStart?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n };\n if (get) return <a {...attributes} {...events} ref={element} href={destination} />;\n return <button {...attributes} {...events} ref={element} type=\"button\" />;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "void-plugin-hono-jsx",
3
- "version": "0.1.0-alpha.3",
3
+ "version": "0.1.0-alpha.4",
4
4
  "private": false,
5
5
  "description": "Experimental Hono JSX Pages adapter for Void",
6
6
  "type": "module",
@@ -28,12 +28,22 @@
28
28
  "./form": {
29
29
  "types": "./dist/server/form.d.ts",
30
30
  "default": "./dist/server/form.js"
31
+ },
32
+ "./markdown/plugin": {
33
+ "types": "./dist/plugins/hono-markdown.d.ts",
34
+ "import": "./dist/plugins/hono-markdown.js"
35
+ },
36
+ "./markdown": {
37
+ "types": "./dist/server/markdown.d.ts",
38
+ "default": "./dist/server/markdown.js"
31
39
  }
32
40
  },
33
41
  "peerDependencies": {
34
42
  "hono": ">=4.13.13 <5.0.0",
35
43
  "void": ">=0.26.1 <0.28.0",
36
- "vite": ">=8.0.16 <9.0.0"
44
+ "vite": ">=8.0.16 <9.0.0",
45
+ "markdown-exit": ">=1.3.0 <2.0.0",
46
+ "yaml": ">=2.9.1 <3.0.0"
37
47
  },
38
48
  "repository": {
39
49
  "type": "git",
@@ -55,5 +65,13 @@
55
65
  "jsx",
56
66
  "vite",
57
67
  "ssr"
58
- ]
68
+ ],
69
+ "peerDependenciesMeta": {
70
+ "markdown-exit": {
71
+ "optional": true
72
+ },
73
+ "yaml": {
74
+ "optional": true
75
+ }
76
+ }
59
77
  }