gonia 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -0
- package/dist/client/hydrate.d.ts +54 -0
- package/dist/client/hydrate.js +445 -0
- package/dist/client/index.d.ts +7 -0
- package/dist/client/index.js +6 -0
- package/dist/context.d.ts +40 -0
- package/dist/context.js +69 -0
- package/dist/directives/class.d.ts +21 -0
- package/dist/directives/class.js +42 -0
- package/dist/directives/for.d.ts +29 -0
- package/dist/directives/for.js +265 -0
- package/dist/directives/html.d.ts +16 -0
- package/dist/directives/html.js +19 -0
- package/dist/directives/if.d.ts +25 -0
- package/dist/directives/if.js +133 -0
- package/dist/directives/index.d.ts +15 -0
- package/dist/directives/index.js +15 -0
- package/dist/directives/model.d.ts +27 -0
- package/dist/directives/model.js +134 -0
- package/dist/directives/on.d.ts +21 -0
- package/dist/directives/on.js +54 -0
- package/dist/directives/show.d.ts +15 -0
- package/dist/directives/show.js +19 -0
- package/dist/directives/slot.d.ts +48 -0
- package/dist/directives/slot.js +99 -0
- package/dist/directives/template.d.ts +55 -0
- package/dist/directives/template.js +147 -0
- package/dist/directives/text.d.ts +15 -0
- package/dist/directives/text.js +18 -0
- package/dist/expression.d.ts +60 -0
- package/dist/expression.js +96 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +16 -0
- package/dist/inject.d.ts +42 -0
- package/dist/inject.js +63 -0
- package/dist/providers.d.ts +96 -0
- package/dist/providers.js +146 -0
- package/dist/reactivity.d.ts +95 -0
- package/dist/reactivity.js +219 -0
- package/dist/scope.d.ts +43 -0
- package/dist/scope.js +112 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.js +6 -0
- package/dist/server/render.d.ts +61 -0
- package/dist/server/render.js +243 -0
- package/dist/templates.d.ts +92 -0
- package/dist/templates.js +124 -0
- package/dist/types.d.ts +362 -0
- package/dist/types.js +110 -0
- package/dist/vite/index.d.ts +6 -0
- package/dist/vite/index.js +6 -0
- package/dist/vite/plugin.d.ts +30 -0
- package/dist/vite/plugin.js +127 -0
- package/package.json +67 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template registry for reusable DOM.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Templates are just reusable HTML. The registry provides async access
|
|
6
|
+
* to templates from various sources: inline `<template>` tags, fetched
|
|
7
|
+
* files, or custom sources.
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Interface for template retrieval.
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* Implementations can source templates from anywhere:
|
|
16
|
+
* inline tags, files, network, bundled, etc.
|
|
17
|
+
*/
|
|
18
|
+
export interface TemplateRegistry {
|
|
19
|
+
/**
|
|
20
|
+
* Get a template by name.
|
|
21
|
+
*
|
|
22
|
+
* @param name - Template name/path
|
|
23
|
+
* @returns The template HTML string
|
|
24
|
+
*/
|
|
25
|
+
get(name: string): Promise<string>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create a template registry with inline -> fetch fallback.
|
|
29
|
+
*
|
|
30
|
+
* @remarks
|
|
31
|
+
* First checks for a `<template id="{name}">` in the document.
|
|
32
|
+
* If not found, fetches from `/{name}` (or custom base path).
|
|
33
|
+
* Results are cached.
|
|
34
|
+
*
|
|
35
|
+
* @param options - Configuration options
|
|
36
|
+
* @returns A template registry
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* // Default: inline -> fetch from /
|
|
41
|
+
* const templates = createTemplateRegistry();
|
|
42
|
+
*
|
|
43
|
+
* // Custom base path
|
|
44
|
+
* const templates = createTemplateRegistry({ basePath: '/templates/' });
|
|
45
|
+
*
|
|
46
|
+
* // Usage
|
|
47
|
+
* const html = await templates.get('dialog');
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function createTemplateRegistry(options?: {
|
|
51
|
+
basePath?: string;
|
|
52
|
+
fetch?: typeof globalThis.fetch;
|
|
53
|
+
}): TemplateRegistry;
|
|
54
|
+
/**
|
|
55
|
+
* Create a simple in-memory template registry.
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* Useful for testing or when templates are bundled.
|
|
59
|
+
*
|
|
60
|
+
* @param templates - Map of template names to HTML
|
|
61
|
+
* @returns A template registry
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* const templates = createMemoryRegistry({
|
|
66
|
+
* dialog: '<div class="dialog"><slot></slot></div>',
|
|
67
|
+
* card: '<div class="card"><slot name="title"></slot><slot></slot></div>'
|
|
68
|
+
* });
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare function createMemoryRegistry(templates: Record<string, string>): TemplateRegistry;
|
|
72
|
+
/**
|
|
73
|
+
* Create a server-side template registry that reads from filesystem.
|
|
74
|
+
*
|
|
75
|
+
* @remarks
|
|
76
|
+
* For Node.js/server environments. Reads templates from disk.
|
|
77
|
+
*
|
|
78
|
+
* @param readFile - Async file reader function
|
|
79
|
+
* @param basePath - Base directory path
|
|
80
|
+
* @returns A template registry
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* import { readFile } from 'fs/promises';
|
|
85
|
+
*
|
|
86
|
+
* const templates = createServerRegistry(
|
|
87
|
+
* (path) => readFile(path, 'utf-8'),
|
|
88
|
+
* './templates/'
|
|
89
|
+
* );
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export declare function createServerRegistry(readFile: (path: string) => Promise<string>, basePath?: string): TemplateRegistry;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template registry for reusable DOM.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Templates are just reusable HTML. The registry provides async access
|
|
6
|
+
* to templates from various sources: inline `<template>` tags, fetched
|
|
7
|
+
* files, or custom sources.
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Create a template registry with inline -> fetch fallback.
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* First checks for a `<template id="{name}">` in the document.
|
|
16
|
+
* If not found, fetches from `/{name}` (or custom base path).
|
|
17
|
+
* Results are cached.
|
|
18
|
+
*
|
|
19
|
+
* @param options - Configuration options
|
|
20
|
+
* @returns A template registry
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* // Default: inline -> fetch from /
|
|
25
|
+
* const templates = createTemplateRegistry();
|
|
26
|
+
*
|
|
27
|
+
* // Custom base path
|
|
28
|
+
* const templates = createTemplateRegistry({ basePath: '/templates/' });
|
|
29
|
+
*
|
|
30
|
+
* // Usage
|
|
31
|
+
* const html = await templates.get('dialog');
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function createTemplateRegistry(options = {}) {
|
|
35
|
+
const { basePath = '/', fetch: fetchFn = globalThis.fetch } = options;
|
|
36
|
+
const cache = new Map();
|
|
37
|
+
return {
|
|
38
|
+
async get(name) {
|
|
39
|
+
if (cache.has(name)) {
|
|
40
|
+
return cache.get(name);
|
|
41
|
+
}
|
|
42
|
+
// Try inline <template> first
|
|
43
|
+
if (typeof document !== 'undefined') {
|
|
44
|
+
const el = document.getElementById(name);
|
|
45
|
+
if (el instanceof HTMLTemplateElement) {
|
|
46
|
+
const html = el.innerHTML;
|
|
47
|
+
cache.set(name, html);
|
|
48
|
+
return html;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Fall back to fetch
|
|
52
|
+
const url = basePath + name;
|
|
53
|
+
const response = await fetchFn(url);
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
throw new Error(`Template not found: ${name} (${response.status})`);
|
|
56
|
+
}
|
|
57
|
+
const html = await response.text();
|
|
58
|
+
cache.set(name, html);
|
|
59
|
+
return html;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Create a simple in-memory template registry.
|
|
65
|
+
*
|
|
66
|
+
* @remarks
|
|
67
|
+
* Useful for testing or when templates are bundled.
|
|
68
|
+
*
|
|
69
|
+
* @param templates - Map of template names to HTML
|
|
70
|
+
* @returns A template registry
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* const templates = createMemoryRegistry({
|
|
75
|
+
* dialog: '<div class="dialog"><slot></slot></div>',
|
|
76
|
+
* card: '<div class="card"><slot name="title"></slot><slot></slot></div>'
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export function createMemoryRegistry(templates) {
|
|
81
|
+
return {
|
|
82
|
+
async get(name) {
|
|
83
|
+
const html = templates[name];
|
|
84
|
+
if (html === undefined) {
|
|
85
|
+
throw new Error(`Template not found: ${name}`);
|
|
86
|
+
}
|
|
87
|
+
return html;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create a server-side template registry that reads from filesystem.
|
|
93
|
+
*
|
|
94
|
+
* @remarks
|
|
95
|
+
* For Node.js/server environments. Reads templates from disk.
|
|
96
|
+
*
|
|
97
|
+
* @param readFile - Async file reader function
|
|
98
|
+
* @param basePath - Base directory path
|
|
99
|
+
* @returns A template registry
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* import { readFile } from 'fs/promises';
|
|
104
|
+
*
|
|
105
|
+
* const templates = createServerRegistry(
|
|
106
|
+
* (path) => readFile(path, 'utf-8'),
|
|
107
|
+
* './templates/'
|
|
108
|
+
* );
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export function createServerRegistry(readFile, basePath = './templates/') {
|
|
112
|
+
const cache = new Map();
|
|
113
|
+
return {
|
|
114
|
+
async get(name) {
|
|
115
|
+
if (cache.has(name)) {
|
|
116
|
+
return cache.get(name);
|
|
117
|
+
}
|
|
118
|
+
const path = basePath + name + '.html';
|
|
119
|
+
const html = await readFile(path);
|
|
120
|
+
cache.set(name, html);
|
|
121
|
+
return html;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for gonia.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Execution mode for the framework.
|
|
8
|
+
*/
|
|
9
|
+
export declare enum Mode {
|
|
10
|
+
/** Server-side rendering */
|
|
11
|
+
SERVER = "server",
|
|
12
|
+
/** Client-side hydration/runtime */
|
|
13
|
+
CLIENT = "client"
|
|
14
|
+
}
|
|
15
|
+
declare const __brand: unique symbol;
|
|
16
|
+
/**
|
|
17
|
+
* A branded string type for expressions.
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* This prevents arbitrary strings from being passed as expressions,
|
|
21
|
+
* reducing the risk of eval injection. Only the framework's parser
|
|
22
|
+
* should create Expression values.
|
|
23
|
+
*/
|
|
24
|
+
export type Expression = string & {
|
|
25
|
+
[__brand]: 'expression';
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Function to evaluate an expression against state.
|
|
29
|
+
*/
|
|
30
|
+
export type EvalFn = <T = unknown>(expr: Expression) => T;
|
|
31
|
+
/**
|
|
32
|
+
* Registry of framework-provided injectables.
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* For provider contexts, use the second type parameter of `Directive` instead:
|
|
36
|
+
*
|
|
37
|
+
* ```ts
|
|
38
|
+
* const themed: Directive<['$element', 'theme'], {theme: ThemeContext}> = ($el, theme) => {
|
|
39
|
+
* // theme is typed as ThemeContext
|
|
40
|
+
* };
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export interface InjectableRegistry {
|
|
44
|
+
/** The expression string from the directive attribute */
|
|
45
|
+
$expr: Expression;
|
|
46
|
+
/** The target DOM element */
|
|
47
|
+
$element: Element;
|
|
48
|
+
/** Function to evaluate expressions against state */
|
|
49
|
+
$eval: EvalFn;
|
|
50
|
+
/** Local reactive state object (isolated per element) */
|
|
51
|
+
$state: Record<string, unknown>;
|
|
52
|
+
/** Root reactive state object (shared across all elements) */
|
|
53
|
+
$rootState: Record<string, unknown>;
|
|
54
|
+
/** Template registry for c-template directive */
|
|
55
|
+
$templates: {
|
|
56
|
+
get(name: string): Promise<string>;
|
|
57
|
+
};
|
|
58
|
+
/** Current execution mode (server or client) */
|
|
59
|
+
$mode: Mode;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Maps a tuple of injectable names to their corresponding types.
|
|
63
|
+
*
|
|
64
|
+
* @typeParam K - Tuple of injectable name strings
|
|
65
|
+
* @typeParam T - Type map (defaults to InjectableRegistry)
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* type Args = MapInjectables<['$element', '$state']>;
|
|
70
|
+
* // => [Element, Record<string, unknown>]
|
|
71
|
+
*
|
|
72
|
+
* // With custom type map
|
|
73
|
+
* type Args2 = MapInjectables<['$element', 'custom'], { $element: Element; custom: MyType }>;
|
|
74
|
+
* // => [Element, MyType]
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export type MapInjectables<K extends readonly string[], T = InjectableRegistry> = {
|
|
78
|
+
[I in keyof K]: K[I] extends keyof T ? T[K[I]] : unknown;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Evaluation context passed to directives.
|
|
82
|
+
*/
|
|
83
|
+
export interface Context {
|
|
84
|
+
/** Current execution mode */
|
|
85
|
+
readonly mode: Mode;
|
|
86
|
+
/**
|
|
87
|
+
* Evaluate an expression against the current state.
|
|
88
|
+
*
|
|
89
|
+
* @typeParam T - Expected return type
|
|
90
|
+
* @param expr - The expression to evaluate
|
|
91
|
+
* @returns The evaluated result
|
|
92
|
+
*/
|
|
93
|
+
eval<T = unknown>(expr: Expression): T;
|
|
94
|
+
/**
|
|
95
|
+
* Get a value from the context by key.
|
|
96
|
+
*
|
|
97
|
+
* @param key - The key to look up
|
|
98
|
+
* @returns The value, or undefined
|
|
99
|
+
*/
|
|
100
|
+
get<T = unknown>(key: string): T | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* Create a child context with additional values.
|
|
103
|
+
*
|
|
104
|
+
* @param additions - Values to add to the child context
|
|
105
|
+
* @returns A new child context
|
|
106
|
+
*/
|
|
107
|
+
child(additions: Record<string, unknown>): Context;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Directive priority levels.
|
|
111
|
+
*
|
|
112
|
+
* @remarks
|
|
113
|
+
* Higher priority directives run first. Structural directives
|
|
114
|
+
* (like c-if, c-for) need to run before behavioral ones.
|
|
115
|
+
*/
|
|
116
|
+
export declare enum DirectivePriority {
|
|
117
|
+
/** Structural directives that control DOM presence (c-if, c-for) */
|
|
118
|
+
STRUCTURAL = 1000,
|
|
119
|
+
/** Template/transclusion directives */
|
|
120
|
+
TEMPLATE = 500,
|
|
121
|
+
/** Normal behavioral directives */
|
|
122
|
+
NORMAL = 0
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Static metadata for a directive.
|
|
126
|
+
*
|
|
127
|
+
* @remarks
|
|
128
|
+
* Declared on the directive function before registration.
|
|
129
|
+
* Used to determine processing order and behavior.
|
|
130
|
+
*
|
|
131
|
+
* @typeParam T - Type map for injectable dependencies
|
|
132
|
+
*/
|
|
133
|
+
export interface DirectiveMeta<T = InjectableRegistry> {
|
|
134
|
+
/**
|
|
135
|
+
* Whether this directive transcludes content.
|
|
136
|
+
*
|
|
137
|
+
* @remarks
|
|
138
|
+
* If true, children are saved before the directive runs.
|
|
139
|
+
*/
|
|
140
|
+
transclude?: boolean;
|
|
141
|
+
/**
|
|
142
|
+
* Dependencies to inject into the directive.
|
|
143
|
+
*
|
|
144
|
+
* @remarks
|
|
145
|
+
* Available injectables:
|
|
146
|
+
* - `$expr`: The expression string from the attribute
|
|
147
|
+
* - `$element`: The target DOM element
|
|
148
|
+
* - `$eval`: Function to evaluate expressions: `(expr) => value`
|
|
149
|
+
* - `$state`: Local reactive state object (isolated per element)
|
|
150
|
+
* - Any registered service names
|
|
151
|
+
* - Any names provided by ancestor directives via `$context`
|
|
152
|
+
*/
|
|
153
|
+
$inject?: readonly string[];
|
|
154
|
+
/**
|
|
155
|
+
* Names this directive exposes as context to descendants.
|
|
156
|
+
*
|
|
157
|
+
* @remarks
|
|
158
|
+
* When a directive declares `$context`, its `$state` becomes
|
|
159
|
+
* available to descendant directives under those names.
|
|
160
|
+
* Useful for passing state through isolate scope boundaries.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```ts
|
|
164
|
+
* const themeProvider: Directive = ($state) => {
|
|
165
|
+
* $state.mode = 'dark';
|
|
166
|
+
* };
|
|
167
|
+
* themeProvider.$inject = ['$state'];
|
|
168
|
+
* themeProvider.$context = ['theme'];
|
|
169
|
+
*
|
|
170
|
+
* // Descendants can inject 'theme'
|
|
171
|
+
* const button: Directive = ($element, theme) => {
|
|
172
|
+
* console.log(theme.mode);
|
|
173
|
+
* };
|
|
174
|
+
* button.$inject = ['$element', 'theme'];
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
$context?: string[];
|
|
178
|
+
/**
|
|
179
|
+
* Processing priority. Higher runs first.
|
|
180
|
+
*
|
|
181
|
+
* @defaultValue DirectivePriority.NORMAL
|
|
182
|
+
*/
|
|
183
|
+
priority?: number;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* A directive function with typed parameters based on injectable keys.
|
|
187
|
+
*
|
|
188
|
+
* @remarks
|
|
189
|
+
* Use this type annotation to get contextual typing for directive parameters.
|
|
190
|
+
* The tuple of keys maps to parameter types from InjectableRegistry.
|
|
191
|
+
*
|
|
192
|
+
* @typeParam K - Tuple of injectable key names
|
|
193
|
+
* @typeParam T - Optional custom type map to extend InjectableRegistry
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```ts
|
|
197
|
+
* // Basic usage - $element is typed as Element
|
|
198
|
+
* const myDirective: Directive<['$element']> = ($element) => {
|
|
199
|
+
* $element.textContent = 'hello';
|
|
200
|
+
* };
|
|
201
|
+
*
|
|
202
|
+
* // Multiple injectables
|
|
203
|
+
* const text: Directive<['$expr', '$element', '$eval']> = ($expr, $element, $eval) => {
|
|
204
|
+
* $element.textContent = String($eval($expr) ?? '');
|
|
205
|
+
* };
|
|
206
|
+
*
|
|
207
|
+
* // With custom types (extend InjectableRegistry first)
|
|
208
|
+
* declare module 'gonia' {
|
|
209
|
+
* interface InjectableRegistry {
|
|
210
|
+
* myService: { doThing(): void };
|
|
211
|
+
* }
|
|
212
|
+
* }
|
|
213
|
+
* const custom: Directive<['$element', 'myService']> = ($el, svc) => {
|
|
214
|
+
* svc.doThing();
|
|
215
|
+
* };
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
export type Directive<K extends readonly (string & keyof (InjectableRegistry & T))[] = readonly (string & keyof InjectableRegistry)[], T extends Record<string, unknown> = {}> = ((...args: MapInjectables<K, InjectableRegistry & T>) => void | Promise<void>) & DirectiveMeta<InjectableRegistry & T>;
|
|
219
|
+
/**
|
|
220
|
+
* Attributes passed to template functions.
|
|
221
|
+
*/
|
|
222
|
+
export interface TemplateAttrs {
|
|
223
|
+
/** The element's innerHTML before transformation */
|
|
224
|
+
children: string;
|
|
225
|
+
/** All attributes from the element */
|
|
226
|
+
[attr: string]: string;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Template can be a string or a function that receives element attributes and the element.
|
|
230
|
+
*/
|
|
231
|
+
export type TemplateOption = string | ((attrs: TemplateAttrs, el: Element) => string | Promise<string>);
|
|
232
|
+
/**
|
|
233
|
+
* Options for directive registration.
|
|
234
|
+
*/
|
|
235
|
+
export interface DirectiveOptions {
|
|
236
|
+
/**
|
|
237
|
+
* Whether to create a new scope for this directive.
|
|
238
|
+
*
|
|
239
|
+
* @remarks
|
|
240
|
+
* When true, the directive creates a new scope that inherits
|
|
241
|
+
* from the parent scope via prototype chain.
|
|
242
|
+
*
|
|
243
|
+
* @defaultValue false
|
|
244
|
+
*/
|
|
245
|
+
scope?: boolean;
|
|
246
|
+
/**
|
|
247
|
+
* Template for the directive's content.
|
|
248
|
+
*
|
|
249
|
+
* @remarks
|
|
250
|
+
* Can be a string or a function that receives the element's
|
|
251
|
+
* attributes and children, returning HTML.
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```ts
|
|
255
|
+
* // Static template
|
|
256
|
+
* directive('my-modal', handler, {
|
|
257
|
+
* template: '<div class="modal"><slot></slot></div>'
|
|
258
|
+
* });
|
|
259
|
+
*
|
|
260
|
+
* // Dynamic template with props
|
|
261
|
+
* directive('fancy-heading', null, {
|
|
262
|
+
* template: ({ level, children }) => `<h${level}>${children}</h${level}>`
|
|
263
|
+
* });
|
|
264
|
+
*
|
|
265
|
+
* // Async template (e.g., dynamic import)
|
|
266
|
+
* directive('lazy-component', handler, {
|
|
267
|
+
* template: () => import('./template.html?raw').then(m => m.default)
|
|
268
|
+
* });
|
|
269
|
+
* ```
|
|
270
|
+
*/
|
|
271
|
+
template?: TemplateOption;
|
|
272
|
+
/**
|
|
273
|
+
* DI provider overrides for descendants.
|
|
274
|
+
*
|
|
275
|
+
* @remarks
|
|
276
|
+
* Maps injectable names to values. Descendants requesting these
|
|
277
|
+
* names via `$inject` will receive the provided values instead
|
|
278
|
+
* of global services.
|
|
279
|
+
*
|
|
280
|
+
* Useful for testing (mock services) or scoping services to a subtree.
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```ts
|
|
284
|
+
* // Test harness with mock services
|
|
285
|
+
* directive('test-harness', null, {
|
|
286
|
+
* scope: true,
|
|
287
|
+
* provide: {
|
|
288
|
+
* '$http': mockHttpClient,
|
|
289
|
+
* 'apiUrl': 'http://localhost:3000/test'
|
|
290
|
+
* }
|
|
291
|
+
* });
|
|
292
|
+
*
|
|
293
|
+
* // Descendants get mock values
|
|
294
|
+
* directive('api-consumer', ($http, apiUrl) => {
|
|
295
|
+
* $http.get(apiUrl + '/users');
|
|
296
|
+
* });
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
provide?: Record<string, unknown>;
|
|
300
|
+
}
|
|
301
|
+
/** Registered directive with options */
|
|
302
|
+
export interface DirectiveRegistration {
|
|
303
|
+
fn: Directive<any> | null;
|
|
304
|
+
options: DirectiveOptions;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Register a directive by name.
|
|
308
|
+
*
|
|
309
|
+
* @remarks
|
|
310
|
+
* Directives are functions with `$inject` set to declare dependencies.
|
|
311
|
+
* If the name contains a hyphen and scope is true, it's also registered
|
|
312
|
+
* as a custom element.
|
|
313
|
+
*
|
|
314
|
+
* The function can be `null` for pure template directives that have no
|
|
315
|
+
* runtime behavior.
|
|
316
|
+
*
|
|
317
|
+
* @param name - The directive name (e.g., 'c-text' or 'todo-app')
|
|
318
|
+
* @param fn - The directive function, or null for template-only directives
|
|
319
|
+
* @param options - Registration options
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* ```ts
|
|
323
|
+
* // Directive with behavior
|
|
324
|
+
* directive('todo-app', ($element, $state) => {
|
|
325
|
+
* $state.todos = [];
|
|
326
|
+
* }, { scope: true });
|
|
327
|
+
*
|
|
328
|
+
* // Template-only directive
|
|
329
|
+
* directive('fancy-heading', null, {
|
|
330
|
+
* template: ({ level, children }) => `<h${level}>${children}</h${level}>`
|
|
331
|
+
* });
|
|
332
|
+
* ```
|
|
333
|
+
*/
|
|
334
|
+
export declare function directive(name: string, fn: Directive<any> | null, options?: DirectiveOptions): void;
|
|
335
|
+
/**
|
|
336
|
+
* Get a directive registration by name.
|
|
337
|
+
*
|
|
338
|
+
* @param name - The directive name
|
|
339
|
+
* @returns The directive registration (fn and options), or undefined if not found
|
|
340
|
+
*/
|
|
341
|
+
export declare function getDirective(name: string): DirectiveRegistration | undefined;
|
|
342
|
+
/**
|
|
343
|
+
* Get a directive function by name.
|
|
344
|
+
*
|
|
345
|
+
* @param name - The directive name
|
|
346
|
+
* @returns The directive function, null for template-only directives, or undefined if not found
|
|
347
|
+
*/
|
|
348
|
+
export declare function getDirectiveFn(name: string): Directive<any> | null | undefined;
|
|
349
|
+
/**
|
|
350
|
+
* Get all registered directive names.
|
|
351
|
+
*
|
|
352
|
+
* @returns Array of directive names
|
|
353
|
+
*/
|
|
354
|
+
export declare function getDirectiveNames(): string[];
|
|
355
|
+
/**
|
|
356
|
+
* Clear all registered directives.
|
|
357
|
+
*
|
|
358
|
+
* @remarks
|
|
359
|
+
* Primarily useful for testing.
|
|
360
|
+
*/
|
|
361
|
+
export declare function clearDirectives(): void;
|
|
362
|
+
export {};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for gonia.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Execution mode for the framework.
|
|
8
|
+
*/
|
|
9
|
+
export var Mode;
|
|
10
|
+
(function (Mode) {
|
|
11
|
+
/** Server-side rendering */
|
|
12
|
+
Mode["SERVER"] = "server";
|
|
13
|
+
/** Client-side hydration/runtime */
|
|
14
|
+
Mode["CLIENT"] = "client";
|
|
15
|
+
})(Mode || (Mode = {}));
|
|
16
|
+
/**
|
|
17
|
+
* Directive priority levels.
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* Higher priority directives run first. Structural directives
|
|
21
|
+
* (like c-if, c-for) need to run before behavioral ones.
|
|
22
|
+
*/
|
|
23
|
+
export var DirectivePriority;
|
|
24
|
+
(function (DirectivePriority) {
|
|
25
|
+
/** Structural directives that control DOM presence (c-if, c-for) */
|
|
26
|
+
DirectivePriority[DirectivePriority["STRUCTURAL"] = 1000] = "STRUCTURAL";
|
|
27
|
+
/** Template/transclusion directives */
|
|
28
|
+
DirectivePriority[DirectivePriority["TEMPLATE"] = 500] = "TEMPLATE";
|
|
29
|
+
/** Normal behavioral directives */
|
|
30
|
+
DirectivePriority[DirectivePriority["NORMAL"] = 0] = "NORMAL";
|
|
31
|
+
})(DirectivePriority || (DirectivePriority = {}));
|
|
32
|
+
/** Global directive registry */
|
|
33
|
+
const directiveRegistry = new Map();
|
|
34
|
+
/**
|
|
35
|
+
* Register a directive by name.
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* Directives are functions with `$inject` set to declare dependencies.
|
|
39
|
+
* If the name contains a hyphen and scope is true, it's also registered
|
|
40
|
+
* as a custom element.
|
|
41
|
+
*
|
|
42
|
+
* The function can be `null` for pure template directives that have no
|
|
43
|
+
* runtime behavior.
|
|
44
|
+
*
|
|
45
|
+
* @param name - The directive name (e.g., 'c-text' or 'todo-app')
|
|
46
|
+
* @param fn - The directive function, or null for template-only directives
|
|
47
|
+
* @param options - Registration options
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* // Directive with behavior
|
|
52
|
+
* directive('todo-app', ($element, $state) => {
|
|
53
|
+
* $state.todos = [];
|
|
54
|
+
* }, { scope: true });
|
|
55
|
+
*
|
|
56
|
+
* // Template-only directive
|
|
57
|
+
* directive('fancy-heading', null, {
|
|
58
|
+
* template: ({ level, children }) => `<h${level}>${children}</h${level}>`
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
|
+
export function directive(name, fn, options = {}) {
|
|
64
|
+
directiveRegistry.set(name, { fn, options });
|
|
65
|
+
// Register as custom element if name contains hyphen and scope is true
|
|
66
|
+
if (fn && name.includes('-') && options.scope && typeof customElements !== 'undefined') {
|
|
67
|
+
// Defer to avoid circular deps - custom element class is created in scope.ts
|
|
68
|
+
queueMicrotask(() => {
|
|
69
|
+
import('./scope.js').then(({ registerDirectiveElement }) => {
|
|
70
|
+
registerDirectiveElement(name, fn, options);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get a directive registration by name.
|
|
77
|
+
*
|
|
78
|
+
* @param name - The directive name
|
|
79
|
+
* @returns The directive registration (fn and options), or undefined if not found
|
|
80
|
+
*/
|
|
81
|
+
export function getDirective(name) {
|
|
82
|
+
return directiveRegistry.get(name);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get a directive function by name.
|
|
86
|
+
*
|
|
87
|
+
* @param name - The directive name
|
|
88
|
+
* @returns The directive function, null for template-only directives, or undefined if not found
|
|
89
|
+
*/
|
|
90
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
91
|
+
export function getDirectiveFn(name) {
|
|
92
|
+
return directiveRegistry.get(name)?.fn;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get all registered directive names.
|
|
96
|
+
*
|
|
97
|
+
* @returns Array of directive names
|
|
98
|
+
*/
|
|
99
|
+
export function getDirectiveNames() {
|
|
100
|
+
return Array.from(directiveRegistry.keys());
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Clear all registered directives.
|
|
104
|
+
*
|
|
105
|
+
* @remarks
|
|
106
|
+
* Primarily useful for testing.
|
|
107
|
+
*/
|
|
108
|
+
export function clearDirectives() {
|
|
109
|
+
directiveRegistry.clear();
|
|
110
|
+
}
|