@flightdev/ui 2.0.1 → 4.0.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 (120) hide show
  1. package/README.md +283 -68
  2. package/dist/{chunk-XTDK7ME5.js → chunk-S4DTUQII.js} +246 -19
  3. package/dist/chunk-S4DTUQII.js.map +1 -0
  4. package/dist/core/index.d.ts +423 -3
  5. package/dist/core/index.js +23 -2
  6. package/dist/core/index.js.map +1 -0
  7. package/dist/index.d.ts +2 -3
  8. package/dist/index.js +29 -5
  9. package/dist/index.js.map +1 -0
  10. package/package.json +7 -183
  11. package/.turbo/turbo-build.log +0 -81
  12. package/.turbo/turbo-lint.log +0 -40
  13. package/.turbo/turbo-typecheck.log +0 -4
  14. package/TESTING.md +0 -124
  15. package/dist/adapter-MMD-iHNx.d.ts +0 -424
  16. package/dist/adapters/tier-1/angular.d.ts +0 -60
  17. package/dist/adapters/tier-1/angular.js +0 -2
  18. package/dist/adapters/tier-1/index.d.ts +0 -7
  19. package/dist/adapters/tier-1/index.js +0 -7
  20. package/dist/adapters/tier-1/qwik.d.ts +0 -55
  21. package/dist/adapters/tier-1/qwik.js +0 -2
  22. package/dist/adapters/tier-1/react.d.ts +0 -67
  23. package/dist/adapters/tier-1/react.js +0 -2
  24. package/dist/adapters/tier-1/solid.d.ts +0 -45
  25. package/dist/adapters/tier-1/solid.js +0 -2
  26. package/dist/adapters/tier-1/svelte.d.ts +0 -48
  27. package/dist/adapters/tier-1/svelte.js +0 -2
  28. package/dist/adapters/tier-1/vue.d.ts +0 -47
  29. package/dist/adapters/tier-1/vue.js +0 -2
  30. package/dist/adapters/tier-2/index.d.ts +0 -7
  31. package/dist/adapters/tier-2/index.js +0 -7
  32. package/dist/adapters/tier-2/inferno.d.ts +0 -31
  33. package/dist/adapters/tier-2/inferno.js +0 -2
  34. package/dist/adapters/tier-2/lit.d.ts +0 -34
  35. package/dist/adapters/tier-2/lit.js +0 -2
  36. package/dist/adapters/tier-2/marko.d.ts +0 -59
  37. package/dist/adapters/tier-2/marko.js +0 -2
  38. package/dist/adapters/tier-2/mithril.d.ts +0 -31
  39. package/dist/adapters/tier-2/mithril.js +0 -2
  40. package/dist/adapters/tier-2/preact.d.ts +0 -33
  41. package/dist/adapters/tier-2/preact.js +0 -2
  42. package/dist/adapters/tier-2/stencil.d.ts +0 -52
  43. package/dist/adapters/tier-2/stencil.js +0 -2
  44. package/dist/adapters/tier-3/alpine.d.ts +0 -73
  45. package/dist/adapters/tier-3/alpine.js +0 -2
  46. package/dist/adapters/tier-3/hotwire.d.ts +0 -71
  47. package/dist/adapters/tier-3/hotwire.js +0 -2
  48. package/dist/adapters/tier-3/htmx.d.ts +0 -88
  49. package/dist/adapters/tier-3/htmx.js +0 -2
  50. package/dist/adapters/tier-3/index.d.ts +0 -7
  51. package/dist/adapters/tier-3/index.js +0 -7
  52. package/dist/adapters/tier-3/petite-vue.d.ts +0 -56
  53. package/dist/adapters/tier-3/petite-vue.js +0 -2
  54. package/dist/adapters/tier-3/stimulus.d.ts +0 -63
  55. package/dist/adapters/tier-3/stimulus.js +0 -2
  56. package/dist/adapters/tier-3/vanilla.d.ts +0 -63
  57. package/dist/adapters/tier-3/vanilla.js +0 -2
  58. package/dist/chunk-2SNQ6PTM.js +0 -217
  59. package/dist/chunk-3D4XMIZI.js +0 -136
  60. package/dist/chunk-3HU6GSQ4.js +0 -125
  61. package/dist/chunk-4PZDNFL7.js +0 -148
  62. package/dist/chunk-5IBLFTYL.js +0 -114
  63. package/dist/chunk-64JZJ7OK.js +0 -142
  64. package/dist/chunk-7ZJI3QU2.js +0 -132
  65. package/dist/chunk-CE4FJHQJ.js +0 -133
  66. package/dist/chunk-DTCAUBH5.js +0 -87
  67. package/dist/chunk-NTASPOHG.js +0 -106
  68. package/dist/chunk-OI2AMQLG.js +0 -152
  69. package/dist/chunk-Q7HUE44H.js +0 -106
  70. package/dist/chunk-QH3LOWXU.js +0 -155
  71. package/dist/chunk-QIVAK6BH.js +0 -103
  72. package/dist/chunk-V34XPVGK.js +0 -103
  73. package/dist/chunk-VK7ZPMO7.js +0 -221
  74. package/dist/chunk-X6CNUW6T.js +0 -136
  75. package/dist/chunk-YFGSHW5S.js +0 -121
  76. package/dist/chunk-ZAJVSE7J.js +0 -90
  77. package/docs/ADAPTERS.md +0 -946
  78. package/docs/PATTERNS.md +0 -836
  79. package/src/adapters/tier-1/angular.ts +0 -223
  80. package/src/adapters/tier-1/index.ts +0 -12
  81. package/src/adapters/tier-1/qwik.ts +0 -177
  82. package/src/adapters/tier-1/react.ts +0 -330
  83. package/src/adapters/tier-1/solid.ts +0 -222
  84. package/src/adapters/tier-1/svelte.ts +0 -211
  85. package/src/adapters/tier-1/vue.ts +0 -234
  86. package/src/adapters/tier-2/index.ts +0 -12
  87. package/src/adapters/tier-2/inferno.ts +0 -149
  88. package/src/adapters/tier-2/lit.ts +0 -191
  89. package/src/adapters/tier-2/marko.ts +0 -199
  90. package/src/adapters/tier-2/mithril.ts +0 -152
  91. package/src/adapters/tier-2/preact.ts +0 -133
  92. package/src/adapters/tier-2/stencil.ts +0 -214
  93. package/src/adapters/tier-3/alpine.ts +0 -218
  94. package/src/adapters/tier-3/hotwire.ts +0 -254
  95. package/src/adapters/tier-3/htmx.ts +0 -263
  96. package/src/adapters/tier-3/index.ts +0 -12
  97. package/src/adapters/tier-3/petite-vue.ts +0 -163
  98. package/src/adapters/tier-3/stimulus.ts +0 -233
  99. package/src/adapters/tier-3/vanilla.ts +0 -252
  100. package/src/ambient.d.ts +0 -310
  101. package/src/core/adapter.ts +0 -366
  102. package/src/core/index.ts +0 -56
  103. package/src/core/registry.ts +0 -518
  104. package/src/core/types.ts +0 -461
  105. package/src/htmx.ts +0 -134
  106. package/src/index.ts +0 -263
  107. package/test/__mocks__/stencil-core.ts +0 -19
  108. package/test/__mocks__/stencil-hydrate.ts +0 -15
  109. package/test/adapters/tier-1.test.ts +0 -206
  110. package/test/adapters/tier-2.test.ts +0 -175
  111. package/test/adapters/tier-3.test.ts +0 -284
  112. package/test/contracts/adapter.contract.ts +0 -293
  113. package/test/core/core.test.ts +0 -310
  114. package/test/errors/error-handling.test.ts +0 -454
  115. package/test/integration/htmx.integration.test.ts +0 -246
  116. package/test/integration/react.integration.test.ts +0 -271
  117. package/test/integration/registry.integration.test.ts +0 -308
  118. package/tsconfig.json +0 -22
  119. package/tsup.config.ts +0 -93
  120. package/vitest.config.ts +0 -101
@@ -1,263 +0,0 @@
1
- /**
2
- * @flightdev/ui - HTMX Adapter (Tier 3)
3
- *
4
- * HTMX adapter - HTML over the wire, server-driven UI.
5
- *
6
- * @module @flightdev/ui/htmx
7
- * @version 2.0.0
8
- */
9
-
10
- import { BaseUIAdapter } from '../../core/adapter.js';
11
- import type {
12
- AdapterCapabilities,
13
- Component,
14
- RenderContext,
15
- RenderResult,
16
- } from '../../core/types.js';
17
-
18
- // ============================================================================
19
- // Types
20
- // ============================================================================
21
-
22
- export type HTMXExtension =
23
- | 'json-enc'
24
- | 'loading-states'
25
- | 'class-tools'
26
- | 'morphdom-swap'
27
- | 'alpine-morph'
28
- | 'path-deps'
29
- | 'preload'
30
- | 'remove-me'
31
- | 'response-targets'
32
- | 'head-support'
33
- | 'sse'
34
- | 'ws';
35
-
36
- export interface HTMXAdapterOptions {
37
- /** HTMX version */
38
- version?: string;
39
-
40
- /** Extensions to load */
41
- extensions?: HTMXExtension[];
42
-
43
- /** Enable WebSocket extension */
44
- websocket?: boolean;
45
-
46
- /** Enable SSE extension */
47
- sse?: boolean;
48
-
49
- /** CDN base URL */
50
- cdnBase?: string;
51
-
52
- /** Enable head element support */
53
- headSupport?: boolean;
54
- }
55
-
56
- // ============================================================================
57
- // HTMX Adapter
58
- // ============================================================================
59
-
60
- export class HTMXAdapter extends BaseUIAdapter {
61
- readonly id = 'htmx';
62
- readonly name = 'HTMX';
63
- readonly framework = 'htmx';
64
- readonly frameworkVersion = '2.0+';
65
- readonly tier = 'tier-3' as const;
66
-
67
- override readonly capabilities: AdapterCapabilities = {
68
- streaming: false,
69
- partialHydration: false,
70
- islands: false,
71
- resumable: false,
72
- ssg: true,
73
- csr: false, // HTMX is server-driven
74
- serverComponents: false,
75
- };
76
-
77
- constructor(private options: HTMXAdapterOptions = {}) {
78
- super();
79
- }
80
-
81
- async renderToString(
82
- component: Component,
83
- _context?: RenderContext
84
- ): Promise<RenderResult> {
85
- const startTime = performance.now();
86
-
87
- // HTMX components are pure HTML
88
- let html: string;
89
-
90
- if (typeof component.component === 'function') {
91
- html = (component.component as (props: unknown) => string)(component.props ?? {});
92
- } else if (typeof component.component === 'string') {
93
- html = component.component;
94
- } else {
95
- throw new Error(
96
- '[Flight/HTMX] Components must be HTML strings or template functions.\n' +
97
- 'HTMX is server-driven - use hx-* attributes for interactivity.'
98
- );
99
- }
100
-
101
- return {
102
- html,
103
- // No hydration data - HTMX is server-driven
104
- timing: this.createTiming(startTime),
105
- };
106
- }
107
-
108
- override getHydrationScript(_result: RenderResult): string {
109
- const {
110
- version = '2.0.2',
111
- extensions = [],
112
- websocket = false,
113
- sse = false,
114
- cdnBase = 'https://unpkg.com',
115
- headSupport = false,
116
- } = this.options;
117
-
118
- // Build extension list
119
- const allExtensions = [
120
- ...extensions,
121
- ...(websocket ? ['ws'] : []),
122
- ...(sse ? ['sse'] : []),
123
- ...(headSupport ? ['head-support'] : []),
124
- ] as HTMXExtension[];
125
-
126
- // Extension script tags
127
- const extScripts = allExtensions
128
- .map((ext) =>
129
- `<script src="${cdnBase}/htmx.org@${version}/dist/ext/${ext}.js"></script>`
130
- )
131
- .join('\n');
132
-
133
- return `
134
- <!-- Flight/HTMX -->
135
- <script src="${cdnBase}/htmx.org@${version}"></script>
136
- ${extScripts}
137
- <script>
138
- window.__FLIGHT_ADAPTER__ = 'htmx';
139
- // HTMX is ready - server-driven UI active
140
- </script>
141
- `.trim();
142
- }
143
-
144
- override getClientEntry(): string {
145
- return `
146
- // HTMX Client Entry
147
- // HTMX requires no explicit client-side initialization
148
-
149
- export function hydrate() {
150
- // HTMX auto-initializes via script tag
151
- // No JavaScript framework needed
152
- console.log('[Flight/HTMX] Server-driven UI ready');
153
- }
154
-
155
- // HTMX event helpers
156
- export function onLoad(callback) {
157
- document.addEventListener('htmx:load', callback);
158
- }
159
-
160
- export function onAfterSwap(callback) {
161
- document.addEventListener('htmx:afterSwap', callback);
162
- }
163
-
164
- export function onBeforeRequest(callback) {
165
- document.addEventListener('htmx:beforeRequest', callback);
166
- }
167
- `.trim();
168
- }
169
- }
170
-
171
- // ============================================================================
172
- // Template Helpers
173
- // ============================================================================
174
-
175
- /**
176
- * Create an hx-get element
177
- */
178
- export function hxGet(
179
- url: string,
180
- options: { target?: string; swap?: string; trigger?: string } = {}
181
- ): Record<string, string> {
182
- const attrs: Record<string, string> = { 'hx-get': url };
183
- if (options.target) attrs['hx-target'] = options.target;
184
- if (options.swap) attrs['hx-swap'] = options.swap;
185
- if (options.trigger) attrs['hx-trigger'] = options.trigger;
186
- return attrs;
187
- }
188
-
189
- /**
190
- * Create an hx-post element
191
- */
192
- export function hxPost(
193
- url: string,
194
- options: { target?: string; swap?: string; trigger?: string } = {}
195
- ): Record<string, string> {
196
- const attrs: Record<string, string> = { 'hx-post': url };
197
- if (options.target) attrs['hx-target'] = options.target;
198
- if (options.swap) attrs['hx-swap'] = options.swap;
199
- if (options.trigger) attrs['hx-trigger'] = options.trigger;
200
- return attrs;
201
- }
202
-
203
- /**
204
- * Create an hx-delete element
205
- */
206
- export function hxDelete(
207
- url: string,
208
- options: { target?: string; swap?: string; confirm?: string } = {}
209
- ): Record<string, string> {
210
- const attrs: Record<string, string> = { 'hx-delete': url };
211
- if (options.target) attrs['hx-target'] = options.target;
212
- if (options.swap) attrs['hx-swap'] = options.swap;
213
- if (options.confirm) attrs['hx-confirm'] = options.confirm;
214
- return attrs;
215
- }
216
-
217
- /**
218
- * Convert attributes object to HTML string
219
- */
220
- export function attrsToString(attrs: Record<string, string>): string {
221
- return Object.entries(attrs)
222
- .map(([k, v]) => `${k}="${v}"`)
223
- .join(' ');
224
- }
225
-
226
- /**
227
- * Create a simple HTML element with hx-* attributes
228
- */
229
- export function hx(
230
- tag: string,
231
- attrs: Record<string, string>,
232
- content?: string
233
- ): string {
234
- const attrStr = attrsToString(attrs);
235
- if (content !== undefined) {
236
- return `<${tag} ${attrStr}>${content}</${tag}>`;
237
- }
238
- return `<${tag} ${attrStr} />`;
239
- }
240
-
241
- // ============================================================================
242
- // Factory Function
243
- // ============================================================================
244
-
245
- /**
246
- * Create an HTMX UI adapter.
247
- *
248
- * @example
249
- * ```typescript
250
- * import { htmx } from '@flightdev/ui/htmx';
251
- * import { defineUI } from '@flightdev/ui';
252
- *
253
- * export default defineUI(htmx({
254
- * extensions: ['json-enc', 'loading-states'],
255
- * sse: true,
256
- * }));
257
- * ```
258
- */
259
- export function htmx(options?: HTMXAdapterOptions): HTMXAdapter {
260
- return new HTMXAdapter(options);
261
- }
262
-
263
- export default htmx;
@@ -1,12 +0,0 @@
1
- /**
2
- * @flightdev/ui - Tier 3 Adapters Index
3
- *
4
- * Re-exports all Tier 3 (HTML-First) adapters.
5
- */
6
-
7
- export { alpine, AlpineAdapter, xData, xFor, xIf, xBind, xOn, type AlpineAdapterOptions, type AlpinePlugin } from './alpine.js';
8
- export { htmx, HTMXAdapter, hxGet, hxPost, hxDelete, hx, attrsToString, type HTMXAdapterOptions, type HTMXExtension } from './htmx.js';
9
- export { hotwire, HotwireAdapter, turboFrame, turboStream, stimulusController, type HotwireAdapterOptions } from './hotwire.js';
10
- export { stimulus, StimulusAdapter, controller, action, target, type StimulusAdapterOptions } from './stimulus.js';
11
- export { petiteVue, PetiteVueAdapter, vScope, vFor, vIf, type PetiteVueAdapterOptions } from './petite-vue.js';
12
- export { vanilla, VanillaAdapter, shadowRoot, slot, createElementClass, type VanillaAdapterOptions } from './vanilla.js';
@@ -1,163 +0,0 @@
1
- /**
2
- * @flightdev/ui - Petite-vue Adapter (Tier 3)
3
- *
4
- * Petite-vue adapter - minimal (~6kb) Vue subset for progressive enhancement.
5
- *
6
- * @module @flightdev/ui/petite-vue
7
- * @version 2.0.0
8
- */
9
-
10
- import { BaseUIAdapter } from '../../core/adapter.js';
11
- import type {
12
- AdapterCapabilities,
13
- Component,
14
- RenderContext,
15
- RenderResult,
16
- } from '../../core/types.js';
17
-
18
- // ============================================================================
19
- // Types
20
- // ============================================================================
21
-
22
- export interface PetiteVueAdapterOptions {
23
- /** Petite-vue version */
24
- version?: string;
25
-
26
- /** Auto-initialize with v-scope */
27
- autoInit?: boolean;
28
- }
29
-
30
- // ============================================================================
31
- // Petite-vue Adapter
32
- // ============================================================================
33
-
34
- export class PetiteVueAdapter extends BaseUIAdapter {
35
- readonly id = 'petite-vue';
36
- readonly name = 'Petite-vue';
37
- readonly framework = 'petite-vue';
38
- readonly frameworkVersion = '0.4+';
39
- readonly tier = 'tier-3' as const;
40
-
41
- override readonly capabilities: AdapterCapabilities = {
42
- streaming: false,
43
- partialHydration: false,
44
- islands: false,
45
- resumable: false,
46
- ssg: true,
47
- csr: true,
48
- serverComponents: false,
49
- };
50
-
51
- constructor(private options: PetiteVueAdapterOptions = {}) {
52
- super();
53
- }
54
-
55
- async renderToString(
56
- component: Component,
57
- _context?: RenderContext
58
- ): Promise<RenderResult> {
59
- const startTime = performance.now();
60
-
61
- let html: string;
62
-
63
- if (typeof component.component === 'function') {
64
- html = (component.component as (props: unknown) => string)(component.props ?? {});
65
- } else if (typeof component.component === 'string') {
66
- html = component.component;
67
- } else {
68
- throw new Error(
69
- '[Flight/Petite-vue] Components must be HTML strings or template functions.\n' +
70
- 'Use v-scope for state and @click, v-model, etc. for interactivity.'
71
- );
72
- }
73
-
74
- return {
75
- html,
76
- hydrationData: component.props,
77
- timing: this.createTiming(startTime),
78
- };
79
- }
80
-
81
- override getHydrationScript(_result: RenderResult): string {
82
- const {
83
- version = '0.4.1',
84
- autoInit = true,
85
- } = this.options;
86
-
87
- return `
88
- <!-- Flight/Petite-vue -->
89
- <script type="module">
90
- import { createApp } from 'https://esm.sh/petite-vue@${version}';
91
-
92
- window.__FLIGHT_ADAPTER__ = 'petite-vue';
93
- ${autoInit ? `createApp().mount();` : '// Manual init: createApp().mount()'}
94
-
95
- console.log('[Flight/Petite-vue] Initialized');
96
- </script>
97
- `.trim();
98
- }
99
-
100
- override getClientEntry(): string {
101
- return `
102
- import { createApp, reactive } from 'petite-vue';
103
-
104
- export { createApp, reactive };
105
-
106
- export function hydrate() {
107
- createApp().mount();
108
- console.log('[Flight/Petite-vue] Application mounted');
109
- }
110
-
111
- export function createScope(initialState) {
112
- return reactive(initialState);
113
- }
114
- `.trim();
115
- }
116
- }
117
-
118
- // ============================================================================
119
- // Template Helpers
120
- // ============================================================================
121
-
122
- /**
123
- * Create a v-scope element
124
- */
125
- export function vScope(state: Record<string, unknown>, content: string): string {
126
- const stateStr = JSON.stringify(state).replace(/"/g, "'");
127
- return `<div v-scope="${stateStr}">${content}</div>`;
128
- }
129
-
130
- /**
131
- * Create v-for binding
132
- */
133
- export function vFor(items: string, itemName: string, content: string): string {
134
- return `<template v-for="${itemName} in ${items}">${content}</template>`;
135
- }
136
-
137
- /**
138
- * Create v-if binding
139
- */
140
- export function vIf(condition: string, content: string): string {
141
- return `<template v-if="${condition}">${content}</template>`;
142
- }
143
-
144
- // ============================================================================
145
- // Factory Function
146
- // ============================================================================
147
-
148
- /**
149
- * Create a Petite-vue UI adapter.
150
- *
151
- * @example
152
- * ```typescript
153
- * import { petiteVue } from '@flightdev/ui/petite-vue';
154
- * import { defineUI } from '@flightdev/ui';
155
- *
156
- * export default defineUI(petiteVue());
157
- * ```
158
- */
159
- export function petiteVue(options?: PetiteVueAdapterOptions): PetiteVueAdapter {
160
- return new PetiteVueAdapter(options);
161
- }
162
-
163
- export default petiteVue;
@@ -1,233 +0,0 @@
1
- /**
2
- * @flightdev/ui - Stimulus Adapter (Tier 3)
3
- *
4
- * Stimulus adapter - modest JavaScript for the HTML you already have.
5
- *
6
- * @module @flightdev/ui/stimulus
7
- * @version 2.0.0
8
- */
9
-
10
- import { BaseUIAdapter } from '../../core/adapter.js';
11
- import type {
12
- AdapterCapabilities,
13
- Component,
14
- RenderContext,
15
- RenderResult,
16
- } from '../../core/types.js';
17
-
18
- // ============================================================================
19
- // Types
20
- // ============================================================================
21
-
22
- export interface StimulusAdapterOptions {
23
- /** Stimulus version */
24
- version?: string;
25
-
26
- /** Controllers directory path */
27
- controllersPath?: string;
28
-
29
- /** Enable debug mode */
30
- debug?: boolean;
31
- }
32
-
33
- // ============================================================================
34
- // Stimulus Adapter
35
- // ============================================================================
36
-
37
- export class StimulusAdapter extends BaseUIAdapter {
38
- readonly id = 'stimulus';
39
- readonly name = 'Stimulus';
40
- readonly framework = 'stimulus';
41
- readonly frameworkVersion = '3+';
42
- readonly tier = 'tier-3' as const;
43
-
44
- override readonly capabilities: AdapterCapabilities = {
45
- streaming: false,
46
- partialHydration: false,
47
- islands: false,
48
- resumable: false,
49
- ssg: true,
50
- csr: true,
51
- serverComponents: false,
52
- };
53
-
54
- constructor(private options: StimulusAdapterOptions = {}) {
55
- super();
56
- }
57
-
58
- async renderToString(
59
- component: Component,
60
- _context?: RenderContext
61
- ): Promise<RenderResult> {
62
- const startTime = performance.now();
63
-
64
- let html: string;
65
-
66
- if (typeof component.component === 'function') {
67
- html = (component.component as (props: unknown) => string)(component.props ?? {});
68
- } else if (typeof component.component === 'string') {
69
- html = component.component;
70
- } else {
71
- throw new Error(
72
- '[Flight/Stimulus] Components must be HTML strings or template functions.\n' +
73
- 'Use data-controller and data-action for interactivity.'
74
- );
75
- }
76
-
77
- return {
78
- html,
79
- hydrationData: component.props,
80
- timing: this.createTiming(startTime),
81
- };
82
- }
83
-
84
- override getHydrationScript(_result: RenderResult): string {
85
- const {
86
- version = '3.2.2',
87
- debug = false,
88
- } = this.options;
89
-
90
- return `
91
- <!-- Flight/Stimulus -->
92
- <script type="module">
93
- import { Application } from 'https://esm.sh/@hotwired/stimulus@${version}';
94
-
95
- window.Stimulus = Application.start();
96
- ${debug ? 'window.Stimulus.debug = true;' : ''}
97
-
98
- window.__FLIGHT_ADAPTER__ = 'stimulus';
99
- console.log('[Flight/Stimulus] Application started');
100
- </script>
101
- `.trim();
102
- }
103
-
104
- override getClientEntry(): string {
105
- return `
106
- import { Application, Controller } from '@hotwired/stimulus';
107
-
108
- // Start Stimulus application
109
- export const application = Application.start();
110
-
111
- // Export Controller for extension
112
- export { Controller };
113
-
114
- // Register controller helper
115
- export function register(name, controller) {
116
- application.register(name, controller);
117
- }
118
-
119
- // Bulk register controllers
120
- export function registerControllers(controllers) {
121
- for (const [name, controller] of Object.entries(controllers)) {
122
- register(name, controller);
123
- }
124
- }
125
-
126
- // Dynamic controller loading via import.meta.glob (Vite)
127
- export function eagerLoadControllers(controllerModules) {
128
- for (const [path, module] of Object.entries(controllerModules)) {
129
- const match = path.match(/\\/([^/]+)_controller\\.[jt]s$/);
130
- if (match && module.default) {
131
- const name = match[1].replace(/_/g, '-');
132
- register(name, module.default);
133
- }
134
- }
135
- }
136
-
137
- // Default hydration
138
- export function hydrate() {
139
- console.log('[Flight/Stimulus] Controllers ready');
140
- }
141
- `.trim();
142
- }
143
- }
144
-
145
- // ============================================================================
146
- // Template Helpers
147
- // ============================================================================
148
-
149
- /**
150
- * Create an element with a Stimulus controller
151
- */
152
- export function controller(
153
- name: string,
154
- content: string,
155
- options: {
156
- values?: Record<string, unknown>;
157
- classes?: Record<string, string>;
158
- outlets?: Record<string, string>;
159
- targets?: string[];
160
- } = {}
161
- ): string {
162
- const attrs: string[] = [`data-controller="${name}"`];
163
-
164
- // Values
165
- if (options.values) {
166
- for (const [key, value] of Object.entries(options.values)) {
167
- attrs.push(`data-${name}-${toKebab(key)}-value="${value}"`);
168
- }
169
- }
170
-
171
- // Classes
172
- if (options.classes) {
173
- for (const [key, value] of Object.entries(options.classes)) {
174
- attrs.push(`data-${name}-${toKebab(key)}-class="${value}"`);
175
- }
176
- }
177
-
178
- // Outlets
179
- if (options.outlets) {
180
- for (const [key, selector] of Object.entries(options.outlets)) {
181
- attrs.push(`data-${name}-${toKebab(key)}-outlet="${selector}"`);
182
- }
183
- }
184
-
185
- return `<div ${attrs.join(' ')}>${content}</div>`;
186
- }
187
-
188
- /**
189
- * Create a data-action attribute
190
- */
191
- export function action(
192
- controller: string,
193
- method: string,
194
- event?: string
195
- ): string {
196
- const eventPart = event ? `${event}->` : '';
197
- return `data-action="${eventPart}${controller}#${method}"`;
198
- }
199
-
200
- /**
201
- * Create a data-target attribute
202
- */
203
- export function target(controller: string, name: string): string {
204
- return `data-${controller}-target="${name}"`;
205
- }
206
-
207
- /**
208
- * Convert camelCase to kebab-case
209
- */
210
- function toKebab(str: string): string {
211
- return str.replace(/([A-Z])/g, '-$1').toLowerCase();
212
- }
213
-
214
- // ============================================================================
215
- // Factory Function
216
- // ============================================================================
217
-
218
- /**
219
- * Create a Stimulus UI adapter.
220
- *
221
- * @example
222
- * ```typescript
223
- * import { stimulus } from '@flightdev/ui/stimulus';
224
- * import { defineUI } from '@flightdev/ui';
225
- *
226
- * export default defineUI(stimulus({ debug: true }));
227
- * ```
228
- */
229
- export function stimulus(options?: StimulusAdapterOptions): StimulusAdapter {
230
- return new StimulusAdapter(options);
231
- }
232
-
233
- export default stimulus;