@flightdev/ui 2.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.
- package/.turbo/turbo-build.log +81 -0
- package/.turbo/turbo-lint.log +40 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/LICENSE +21 -0
- package/README.md +92 -0
- package/TESTING.md +124 -0
- package/dist/adapter-MMD-iHNx.d.ts +424 -0
- package/dist/adapters/tier-1/angular.d.ts +60 -0
- package/dist/adapters/tier-1/angular.js +2 -0
- package/dist/adapters/tier-1/index.d.ts +7 -0
- package/dist/adapters/tier-1/index.js +7 -0
- package/dist/adapters/tier-1/qwik.d.ts +55 -0
- package/dist/adapters/tier-1/qwik.js +2 -0
- package/dist/adapters/tier-1/react.d.ts +67 -0
- package/dist/adapters/tier-1/react.js +2 -0
- package/dist/adapters/tier-1/solid.d.ts +45 -0
- package/dist/adapters/tier-1/solid.js +2 -0
- package/dist/adapters/tier-1/svelte.d.ts +48 -0
- package/dist/adapters/tier-1/svelte.js +2 -0
- package/dist/adapters/tier-1/vue.d.ts +47 -0
- package/dist/adapters/tier-1/vue.js +2 -0
- package/dist/adapters/tier-2/index.d.ts +7 -0
- package/dist/adapters/tier-2/index.js +7 -0
- package/dist/adapters/tier-2/inferno.d.ts +31 -0
- package/dist/adapters/tier-2/inferno.js +2 -0
- package/dist/adapters/tier-2/lit.d.ts +34 -0
- package/dist/adapters/tier-2/lit.js +2 -0
- package/dist/adapters/tier-2/marko.d.ts +59 -0
- package/dist/adapters/tier-2/marko.js +2 -0
- package/dist/adapters/tier-2/mithril.d.ts +31 -0
- package/dist/adapters/tier-2/mithril.js +2 -0
- package/dist/adapters/tier-2/preact.d.ts +33 -0
- package/dist/adapters/tier-2/preact.js +2 -0
- package/dist/adapters/tier-2/stencil.d.ts +52 -0
- package/dist/adapters/tier-2/stencil.js +2 -0
- package/dist/adapters/tier-3/alpine.d.ts +73 -0
- package/dist/adapters/tier-3/alpine.js +2 -0
- package/dist/adapters/tier-3/hotwire.d.ts +71 -0
- package/dist/adapters/tier-3/hotwire.js +2 -0
- package/dist/adapters/tier-3/htmx.d.ts +88 -0
- package/dist/adapters/tier-3/htmx.js +2 -0
- package/dist/adapters/tier-3/index.d.ts +7 -0
- package/dist/adapters/tier-3/index.js +7 -0
- package/dist/adapters/tier-3/petite-vue.d.ts +56 -0
- package/dist/adapters/tier-3/petite-vue.js +2 -0
- package/dist/adapters/tier-3/stimulus.d.ts +63 -0
- package/dist/adapters/tier-3/stimulus.js +2 -0
- package/dist/adapters/tier-3/vanilla.d.ts +63 -0
- package/dist/adapters/tier-3/vanilla.js +2 -0
- package/dist/chunk-2SNQ6PTM.js +217 -0
- package/dist/chunk-3D4XMIZI.js +136 -0
- package/dist/chunk-3HU6GSQ4.js +125 -0
- package/dist/chunk-4PZDNFL7.js +148 -0
- package/dist/chunk-5IBLFTYL.js +114 -0
- package/dist/chunk-64JZJ7OK.js +142 -0
- package/dist/chunk-7ZJI3QU2.js +132 -0
- package/dist/chunk-CE4FJHQJ.js +133 -0
- package/dist/chunk-DTCAUBH5.js +87 -0
- package/dist/chunk-NTASPOHG.js +106 -0
- package/dist/chunk-OI2AMQLG.js +152 -0
- package/dist/chunk-Q7HUE44H.js +106 -0
- package/dist/chunk-QH3LOWXU.js +155 -0
- package/dist/chunk-QIVAK6BH.js +103 -0
- package/dist/chunk-V34XPVGK.js +103 -0
- package/dist/chunk-VK7ZPMO7.js +221 -0
- package/dist/chunk-X6CNUW6T.js +136 -0
- package/dist/chunk-XTDK7ME5.js +382 -0
- package/dist/chunk-YFGSHW5S.js +121 -0
- package/dist/chunk-ZAJVSE7J.js +90 -0
- package/dist/core/index.d.ts +161 -0
- package/dist/core/index.js +2 -0
- package/dist/index.d.ts +103 -0
- package/dist/index.js +71 -0
- package/docs/ADAPTERS.md +946 -0
- package/docs/PATTERNS.md +836 -0
- package/package.json +229 -0
- package/src/adapters/tier-1/angular.ts +223 -0
- package/src/adapters/tier-1/index.ts +12 -0
- package/src/adapters/tier-1/qwik.ts +177 -0
- package/src/adapters/tier-1/react.ts +330 -0
- package/src/adapters/tier-1/solid.ts +222 -0
- package/src/adapters/tier-1/svelte.ts +211 -0
- package/src/adapters/tier-1/vue.ts +234 -0
- package/src/adapters/tier-2/index.ts +12 -0
- package/src/adapters/tier-2/inferno.ts +149 -0
- package/src/adapters/tier-2/lit.ts +191 -0
- package/src/adapters/tier-2/marko.ts +199 -0
- package/src/adapters/tier-2/mithril.ts +152 -0
- package/src/adapters/tier-2/preact.ts +133 -0
- package/src/adapters/tier-2/stencil.ts +214 -0
- package/src/adapters/tier-3/alpine.ts +218 -0
- package/src/adapters/tier-3/hotwire.ts +254 -0
- package/src/adapters/tier-3/htmx.ts +263 -0
- package/src/adapters/tier-3/index.ts +12 -0
- package/src/adapters/tier-3/petite-vue.ts +163 -0
- package/src/adapters/tier-3/stimulus.ts +233 -0
- package/src/adapters/tier-3/vanilla.ts +252 -0
- package/src/ambient.d.ts +310 -0
- package/src/core/adapter.ts +366 -0
- package/src/core/index.ts +56 -0
- package/src/core/registry.ts +518 -0
- package/src/core/types.ts +461 -0
- package/src/htmx.ts +134 -0
- package/src/index.ts +263 -0
- package/test/__mocks__/stencil-core.ts +19 -0
- package/test/__mocks__/stencil-hydrate.ts +15 -0
- package/test/adapters/tier-1.test.ts +206 -0
- package/test/adapters/tier-2.test.ts +175 -0
- package/test/adapters/tier-3.test.ts +284 -0
- package/test/contracts/adapter.contract.ts +293 -0
- package/test/core/core.test.ts +310 -0
- package/test/errors/error-handling.test.ts +454 -0
- package/test/integration/htmx.integration.test.ts +246 -0
- package/test/integration/react.integration.test.ts +271 -0
- package/test/integration/registry.integration.test.ts +308 -0
- package/tsconfig.json +22 -0
- package/tsup.config.ts +93 -0
- package/vitest.config.ts +101 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { BaseUIAdapter } from './chunk-2SNQ6PTM.js';
|
|
2
|
+
|
|
3
|
+
// src/adapters/tier-3/hotwire.ts
|
|
4
|
+
var HotwireAdapter = class extends BaseUIAdapter {
|
|
5
|
+
constructor(options = {}) {
|
|
6
|
+
super();
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
9
|
+
id = "hotwire";
|
|
10
|
+
name = "Hotwire";
|
|
11
|
+
framework = "hotwire";
|
|
12
|
+
frameworkVersion = "8+";
|
|
13
|
+
tier = "tier-3";
|
|
14
|
+
capabilities = {
|
|
15
|
+
streaming: false,
|
|
16
|
+
partialHydration: false,
|
|
17
|
+
islands: false,
|
|
18
|
+
resumable: false,
|
|
19
|
+
ssg: true,
|
|
20
|
+
csr: false,
|
|
21
|
+
// Hotwire is server-driven
|
|
22
|
+
serverComponents: false
|
|
23
|
+
};
|
|
24
|
+
async renderToString(component, _context) {
|
|
25
|
+
const startTime = performance.now();
|
|
26
|
+
let html;
|
|
27
|
+
if (typeof component.component === "function") {
|
|
28
|
+
html = component.component(component.props ?? {});
|
|
29
|
+
} else if (typeof component.component === "string") {
|
|
30
|
+
html = component.component;
|
|
31
|
+
} else {
|
|
32
|
+
throw new Error(
|
|
33
|
+
"[Flight/Hotwire] Components must be HTML strings or template functions.\nUse turbo-frame, turbo-stream, and data-controller for interactivity."
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
html,
|
|
38
|
+
timing: this.createTiming(startTime)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
getHydrationScript(_result) {
|
|
42
|
+
const {
|
|
43
|
+
turboDrive = true,
|
|
44
|
+
turboFrames = true,
|
|
45
|
+
turboStreams = true,
|
|
46
|
+
stimulus = true,
|
|
47
|
+
turboVersion = "8.0.4",
|
|
48
|
+
stimulusVersion = "3.2.2"
|
|
49
|
+
} = this.options;
|
|
50
|
+
let scripts = `
|
|
51
|
+
<!-- Flight/Hotwire -->
|
|
52
|
+
<script type="module">
|
|
53
|
+
import * as Turbo from 'https://esm.sh/@hotwired/turbo@${turboVersion}';
|
|
54
|
+
window.Turbo = Turbo;
|
|
55
|
+
`;
|
|
56
|
+
if (!turboDrive) {
|
|
57
|
+
scripts += `Turbo.session.drive = false;
|
|
58
|
+
`;
|
|
59
|
+
}
|
|
60
|
+
scripts += `
|
|
61
|
+
window.__FLIGHT_ADAPTER__ = 'hotwire';
|
|
62
|
+
console.log('[Flight/Hotwire] Turbo initialized');
|
|
63
|
+
</script>
|
|
64
|
+
`;
|
|
65
|
+
if (stimulus) {
|
|
66
|
+
scripts += `
|
|
67
|
+
<script type="module">
|
|
68
|
+
import { Application } from 'https://esm.sh/@hotwired/stimulus@${stimulusVersion}';
|
|
69
|
+
|
|
70
|
+
window.Stimulus = Application.start();
|
|
71
|
+
|
|
72
|
+
// Auto-register controllers via data-controller-url attribute
|
|
73
|
+
document.querySelectorAll('[data-controller-url]').forEach(async (el) => {
|
|
74
|
+
const url = el.dataset.controllerUrl;
|
|
75
|
+
const name = el.dataset.controller;
|
|
76
|
+
if (url && name) {
|
|
77
|
+
const module = await import(url);
|
|
78
|
+
window.Stimulus.register(name, module.default);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
</script>
|
|
82
|
+
`;
|
|
83
|
+
}
|
|
84
|
+
return scripts.trim();
|
|
85
|
+
}
|
|
86
|
+
getClientEntry() {
|
|
87
|
+
return `
|
|
88
|
+
import * as Turbo from '@hotwired/turbo';
|
|
89
|
+
import { Application } from '@hotwired/stimulus';
|
|
90
|
+
|
|
91
|
+
// Initialize Turbo
|
|
92
|
+
export function initTurbo(options = {}) {
|
|
93
|
+
if (options.drive === false) {
|
|
94
|
+
Turbo.session.drive = false;
|
|
95
|
+
}
|
|
96
|
+
return Turbo;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Initialize Stimulus
|
|
100
|
+
export function initStimulus() {
|
|
101
|
+
const application = Application.start();
|
|
102
|
+
window.Stimulus = application;
|
|
103
|
+
return application;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Auto-register Stimulus controllers
|
|
107
|
+
export function registerControllers(application, controllers) {
|
|
108
|
+
for (const [name, controller] of Object.entries(controllers)) {
|
|
109
|
+
application.register(name, controller);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Default hydration
|
|
114
|
+
export function hydrate() {
|
|
115
|
+
initTurbo();
|
|
116
|
+
initStimulus();
|
|
117
|
+
console.log('[Flight/Hotwire] Application ready');
|
|
118
|
+
}
|
|
119
|
+
`.trim();
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
function turboFrame(id, content, options = {}) {
|
|
123
|
+
const attrs = [`id="${id}"`];
|
|
124
|
+
if (options.src) attrs.push(`src="${options.src}"`);
|
|
125
|
+
if (options.loading) attrs.push(`loading="${options.loading}"`);
|
|
126
|
+
if (options.target) attrs.push(`target="${options.target}"`);
|
|
127
|
+
return `<turbo-frame ${attrs.join(" ")}>${content}</turbo-frame>`;
|
|
128
|
+
}
|
|
129
|
+
function turboStream(action, target, content) {
|
|
130
|
+
if (action === "remove") {
|
|
131
|
+
return `<turbo-stream action="remove" target="${target}"></turbo-stream>`;
|
|
132
|
+
}
|
|
133
|
+
return `
|
|
134
|
+
<turbo-stream action="${action}" target="${target}">
|
|
135
|
+
<template>${content ?? ""}</template>
|
|
136
|
+
</turbo-stream>
|
|
137
|
+
`.trim();
|
|
138
|
+
}
|
|
139
|
+
function stimulusController(controller, content, values = {}) {
|
|
140
|
+
const valueAttrs = Object.entries(values).map(([key, value]) => `data-${controller}-${key}-value="${value}"`).join(" ");
|
|
141
|
+
return `<div data-controller="${controller}" ${valueAttrs}>${content}</div>`;
|
|
142
|
+
}
|
|
143
|
+
function hotwire(options) {
|
|
144
|
+
return new HotwireAdapter(options);
|
|
145
|
+
}
|
|
146
|
+
var hotwire_default = hotwire;
|
|
147
|
+
|
|
148
|
+
export { HotwireAdapter, hotwire, hotwire_default, stimulusController, turboFrame, turboStream };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { BaseUIAdapter } from './chunk-2SNQ6PTM.js';
|
|
2
|
+
|
|
3
|
+
// src/adapters/tier-2/marko.ts
|
|
4
|
+
var MarkoAdapter = class extends BaseUIAdapter {
|
|
5
|
+
constructor(options = {}) {
|
|
6
|
+
super();
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
9
|
+
id = "marko";
|
|
10
|
+
name = "Marko";
|
|
11
|
+
framework = "marko";
|
|
12
|
+
frameworkVersion = "5+";
|
|
13
|
+
tier = "tier-2";
|
|
14
|
+
capabilities = {
|
|
15
|
+
streaming: true,
|
|
16
|
+
// Marko pioneered streaming SSR!
|
|
17
|
+
partialHydration: true,
|
|
18
|
+
islands: true,
|
|
19
|
+
resumable: false,
|
|
20
|
+
ssg: true,
|
|
21
|
+
csr: true,
|
|
22
|
+
serverComponents: false
|
|
23
|
+
};
|
|
24
|
+
async renderToString(component, _context) {
|
|
25
|
+
const startTime = performance.now();
|
|
26
|
+
const template = component.component;
|
|
27
|
+
const input = {
|
|
28
|
+
...this.options.globalData,
|
|
29
|
+
...component.props
|
|
30
|
+
};
|
|
31
|
+
const html = await template.renderToString(input);
|
|
32
|
+
return {
|
|
33
|
+
html,
|
|
34
|
+
hydrationData: {
|
|
35
|
+
props: component.props,
|
|
36
|
+
componentId: component.id ?? this.generateId()
|
|
37
|
+
},
|
|
38
|
+
timing: this.createTiming(startTime)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
renderToStream(component, _context, options) {
|
|
42
|
+
let aborted = false;
|
|
43
|
+
let resolvePromise;
|
|
44
|
+
let rejectPromise;
|
|
45
|
+
const done = new Promise((resolve, reject) => {
|
|
46
|
+
resolvePromise = resolve;
|
|
47
|
+
rejectPromise = reject;
|
|
48
|
+
});
|
|
49
|
+
const template = component.component;
|
|
50
|
+
const input = {
|
|
51
|
+
...this.options.globalData,
|
|
52
|
+
...component.props
|
|
53
|
+
};
|
|
54
|
+
const stream = new ReadableStream({
|
|
55
|
+
start(controller) {
|
|
56
|
+
const out = template.render(input);
|
|
57
|
+
options?.onShellReady?.();
|
|
58
|
+
out.on("data", (chunk) => {
|
|
59
|
+
if (!aborted) {
|
|
60
|
+
controller.enqueue(new Uint8Array(chunk));
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
out.on("end", () => {
|
|
64
|
+
if (!aborted) {
|
|
65
|
+
controller.close();
|
|
66
|
+
resolvePromise();
|
|
67
|
+
options?.onAllReady?.();
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
out.on("error", (error) => {
|
|
71
|
+
options?.onError?.(error);
|
|
72
|
+
controller.error(error);
|
|
73
|
+
rejectPromise(error);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
return {
|
|
78
|
+
stream,
|
|
79
|
+
done,
|
|
80
|
+
abort() {
|
|
81
|
+
aborted = true;
|
|
82
|
+
resolvePromise();
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
getHydrationScript(result) {
|
|
87
|
+
const data = this.serializeProps(result.hydrationData);
|
|
88
|
+
return `
|
|
89
|
+
<script type="module">
|
|
90
|
+
window.__FLIGHT_DATA__ = ${data};
|
|
91
|
+
window.__FLIGHT_ADAPTER__ = 'marko';
|
|
92
|
+
// Marko handles hydration via inline component scripts
|
|
93
|
+
</script>
|
|
94
|
+
`.trim();
|
|
95
|
+
}
|
|
96
|
+
getClientEntry() {
|
|
97
|
+
return `
|
|
98
|
+
// Marko Client Entry
|
|
99
|
+
// Marko components are self-hydrating
|
|
100
|
+
|
|
101
|
+
export function hydrate() {
|
|
102
|
+
// Marko components automatically hydrate themselves
|
|
103
|
+
// No additional client-side setup needed
|
|
104
|
+
console.log('[Flight/Marko] Components are self-hydrating');
|
|
105
|
+
}
|
|
106
|
+
`.trim();
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
function marko(options) {
|
|
110
|
+
return new MarkoAdapter(options);
|
|
111
|
+
}
|
|
112
|
+
var marko_default = marko;
|
|
113
|
+
|
|
114
|
+
export { MarkoAdapter, marko, marko_default };
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { BaseUIAdapter } from './chunk-2SNQ6PTM.js';
|
|
2
|
+
|
|
3
|
+
// src/adapters/tier-1/solid.ts
|
|
4
|
+
var SolidAdapter = class extends BaseUIAdapter {
|
|
5
|
+
constructor(options = {}) {
|
|
6
|
+
super();
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
9
|
+
id = "solid";
|
|
10
|
+
name = "Solid";
|
|
11
|
+
framework = "solid";
|
|
12
|
+
frameworkVersion = "1.8+";
|
|
13
|
+
tier = "tier-1";
|
|
14
|
+
capabilities = {
|
|
15
|
+
streaming: true,
|
|
16
|
+
partialHydration: true,
|
|
17
|
+
islands: true,
|
|
18
|
+
resumable: false,
|
|
19
|
+
ssg: true,
|
|
20
|
+
csr: true,
|
|
21
|
+
serverComponents: false
|
|
22
|
+
};
|
|
23
|
+
async renderToString(component, _context) {
|
|
24
|
+
const startTime = performance.now();
|
|
25
|
+
const { renderToString } = await import('solid-js/web');
|
|
26
|
+
const SolidComponent = component.component;
|
|
27
|
+
const props = component.props ?? {};
|
|
28
|
+
const html = await renderToString(() => SolidComponent());
|
|
29
|
+
return {
|
|
30
|
+
html,
|
|
31
|
+
hydrationData: {
|
|
32
|
+
props,
|
|
33
|
+
componentId: component.id ?? this.generateId()
|
|
34
|
+
},
|
|
35
|
+
timing: this.createTiming(startTime)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
renderToStream(component, _context, options) {
|
|
39
|
+
let aborted = false;
|
|
40
|
+
let resolvePromise;
|
|
41
|
+
let rejectPromise;
|
|
42
|
+
const done = new Promise((resolve, reject) => {
|
|
43
|
+
resolvePromise = resolve;
|
|
44
|
+
rejectPromise = reject;
|
|
45
|
+
});
|
|
46
|
+
const stream = new ReadableStream({
|
|
47
|
+
async start(controller) {
|
|
48
|
+
try {
|
|
49
|
+
const { renderToStream: solidRenderToStream } = await import('solid-js/web');
|
|
50
|
+
const SolidComponent = component.component;
|
|
51
|
+
const App = () => SolidComponent();
|
|
52
|
+
const { readable } = solidRenderToStream(() => SolidComponent());
|
|
53
|
+
const reader = readable.getReader();
|
|
54
|
+
options?.onShellReady?.();
|
|
55
|
+
while (true) {
|
|
56
|
+
const { done: readerDone, value } = await reader.read();
|
|
57
|
+
if (aborted) {
|
|
58
|
+
reader.cancel();
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
if (readerDone) {
|
|
62
|
+
controller.close();
|
|
63
|
+
resolvePromise();
|
|
64
|
+
options?.onAllReady?.();
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
const chunk = typeof value === "string" ? new TextEncoder().encode(value) : value;
|
|
68
|
+
controller.enqueue(chunk);
|
|
69
|
+
}
|
|
70
|
+
} catch (error) {
|
|
71
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
72
|
+
options?.onError?.(err);
|
|
73
|
+
controller.error(err);
|
|
74
|
+
rejectPromise(err);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
return {
|
|
79
|
+
stream,
|
|
80
|
+
done,
|
|
81
|
+
abort() {
|
|
82
|
+
aborted = true;
|
|
83
|
+
resolvePromise();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
getHydrationScript(result) {
|
|
88
|
+
const data = this.serializeProps(result.hydrationData);
|
|
89
|
+
return `
|
|
90
|
+
<script type="module">
|
|
91
|
+
window.__FLIGHT_DATA__ = ${data};
|
|
92
|
+
window.__FLIGHT_ADAPTER__ = 'solid';
|
|
93
|
+
|
|
94
|
+
import { hydrate } from 'solid-js/web';
|
|
95
|
+
|
|
96
|
+
const App = window.__FLIGHT_APP__;
|
|
97
|
+
const container = document.getElementById('app');
|
|
98
|
+
|
|
99
|
+
if (App && container) {
|
|
100
|
+
hydrate(() => App(window.__FLIGHT_DATA__.props), container);
|
|
101
|
+
}
|
|
102
|
+
</script>
|
|
103
|
+
`.trim();
|
|
104
|
+
}
|
|
105
|
+
getClientEntry() {
|
|
106
|
+
return `
|
|
107
|
+
import { hydrate, render } from 'solid-js/web';
|
|
108
|
+
|
|
109
|
+
export function hydrateApp() {
|
|
110
|
+
const container = document.getElementById('app');
|
|
111
|
+
const App = window.__FLIGHT_APP__;
|
|
112
|
+
const data = window.__FLIGHT_DATA__ ?? {};
|
|
113
|
+
|
|
114
|
+
if (!container || !App) {
|
|
115
|
+
console.warn('[Flight/Solid] Missing container or App');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Check if we have SSR content to hydrate
|
|
120
|
+
if (container.innerHTML.trim()) {
|
|
121
|
+
return hydrate(() => App(data.props), container);
|
|
122
|
+
} else {
|
|
123
|
+
// Fallback to client-side render
|
|
124
|
+
return render(() => App(data.props), container);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function renderApp(App, container, props = {}) {
|
|
129
|
+
return render(() => App(props), container);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Export for Flight
|
|
133
|
+
export { hydrateApp as hydrate };
|
|
134
|
+
`.trim();
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
function solid(options) {
|
|
138
|
+
return new SolidAdapter(options);
|
|
139
|
+
}
|
|
140
|
+
var solid_default = solid;
|
|
141
|
+
|
|
142
|
+
export { SolidAdapter, solid, solid_default };
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { BaseUIAdapter } from './chunk-2SNQ6PTM.js';
|
|
2
|
+
|
|
3
|
+
// src/adapters/tier-3/htmx.ts
|
|
4
|
+
var HTMXAdapter = class extends BaseUIAdapter {
|
|
5
|
+
constructor(options = {}) {
|
|
6
|
+
super();
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
9
|
+
id = "htmx";
|
|
10
|
+
name = "HTMX";
|
|
11
|
+
framework = "htmx";
|
|
12
|
+
frameworkVersion = "2.0+";
|
|
13
|
+
tier = "tier-3";
|
|
14
|
+
capabilities = {
|
|
15
|
+
streaming: false,
|
|
16
|
+
partialHydration: false,
|
|
17
|
+
islands: false,
|
|
18
|
+
resumable: false,
|
|
19
|
+
ssg: true,
|
|
20
|
+
csr: false,
|
|
21
|
+
// HTMX is server-driven
|
|
22
|
+
serverComponents: false
|
|
23
|
+
};
|
|
24
|
+
async renderToString(component, _context) {
|
|
25
|
+
const startTime = performance.now();
|
|
26
|
+
let html;
|
|
27
|
+
if (typeof component.component === "function") {
|
|
28
|
+
html = component.component(component.props ?? {});
|
|
29
|
+
} else if (typeof component.component === "string") {
|
|
30
|
+
html = component.component;
|
|
31
|
+
} else {
|
|
32
|
+
throw new Error(
|
|
33
|
+
"[Flight/HTMX] Components must be HTML strings or template functions.\nHTMX is server-driven - use hx-* attributes for interactivity."
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
html,
|
|
38
|
+
// No hydration data - HTMX is server-driven
|
|
39
|
+
timing: this.createTiming(startTime)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
getHydrationScript(_result) {
|
|
43
|
+
const {
|
|
44
|
+
version = "2.0.2",
|
|
45
|
+
extensions = [],
|
|
46
|
+
websocket = false,
|
|
47
|
+
sse = false,
|
|
48
|
+
cdnBase = "https://unpkg.com",
|
|
49
|
+
headSupport = false
|
|
50
|
+
} = this.options;
|
|
51
|
+
const allExtensions = [
|
|
52
|
+
...extensions,
|
|
53
|
+
...websocket ? ["ws"] : [],
|
|
54
|
+
...sse ? ["sse"] : [],
|
|
55
|
+
...headSupport ? ["head-support"] : []
|
|
56
|
+
];
|
|
57
|
+
const extScripts = allExtensions.map(
|
|
58
|
+
(ext) => `<script src="${cdnBase}/htmx.org@${version}/dist/ext/${ext}.js"></script>`
|
|
59
|
+
).join("\n");
|
|
60
|
+
return `
|
|
61
|
+
<!-- Flight/HTMX -->
|
|
62
|
+
<script src="${cdnBase}/htmx.org@${version}"></script>
|
|
63
|
+
${extScripts}
|
|
64
|
+
<script>
|
|
65
|
+
window.__FLIGHT_ADAPTER__ = 'htmx';
|
|
66
|
+
// HTMX is ready - server-driven UI active
|
|
67
|
+
</script>
|
|
68
|
+
`.trim();
|
|
69
|
+
}
|
|
70
|
+
getClientEntry() {
|
|
71
|
+
return `
|
|
72
|
+
// HTMX Client Entry
|
|
73
|
+
// HTMX requires no explicit client-side initialization
|
|
74
|
+
|
|
75
|
+
export function hydrate() {
|
|
76
|
+
// HTMX auto-initializes via script tag
|
|
77
|
+
// No JavaScript framework needed
|
|
78
|
+
console.log('[Flight/HTMX] Server-driven UI ready');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// HTMX event helpers
|
|
82
|
+
export function onLoad(callback) {
|
|
83
|
+
document.addEventListener('htmx:load', callback);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function onAfterSwap(callback) {
|
|
87
|
+
document.addEventListener('htmx:afterSwap', callback);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function onBeforeRequest(callback) {
|
|
91
|
+
document.addEventListener('htmx:beforeRequest', callback);
|
|
92
|
+
}
|
|
93
|
+
`.trim();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
function hxGet(url, options = {}) {
|
|
97
|
+
const attrs = { "hx-get": url };
|
|
98
|
+
if (options.target) attrs["hx-target"] = options.target;
|
|
99
|
+
if (options.swap) attrs["hx-swap"] = options.swap;
|
|
100
|
+
if (options.trigger) attrs["hx-trigger"] = options.trigger;
|
|
101
|
+
return attrs;
|
|
102
|
+
}
|
|
103
|
+
function hxPost(url, options = {}) {
|
|
104
|
+
const attrs = { "hx-post": url };
|
|
105
|
+
if (options.target) attrs["hx-target"] = options.target;
|
|
106
|
+
if (options.swap) attrs["hx-swap"] = options.swap;
|
|
107
|
+
if (options.trigger) attrs["hx-trigger"] = options.trigger;
|
|
108
|
+
return attrs;
|
|
109
|
+
}
|
|
110
|
+
function hxDelete(url, options = {}) {
|
|
111
|
+
const attrs = { "hx-delete": url };
|
|
112
|
+
if (options.target) attrs["hx-target"] = options.target;
|
|
113
|
+
if (options.swap) attrs["hx-swap"] = options.swap;
|
|
114
|
+
if (options.confirm) attrs["hx-confirm"] = options.confirm;
|
|
115
|
+
return attrs;
|
|
116
|
+
}
|
|
117
|
+
function attrsToString(attrs) {
|
|
118
|
+
return Object.entries(attrs).map(([k, v]) => `${k}="${v}"`).join(" ");
|
|
119
|
+
}
|
|
120
|
+
function hx(tag, attrs, content) {
|
|
121
|
+
const attrStr = attrsToString(attrs);
|
|
122
|
+
if (content !== void 0) {
|
|
123
|
+
return `<${tag} ${attrStr}>${content}</${tag}>`;
|
|
124
|
+
}
|
|
125
|
+
return `<${tag} ${attrStr} />`;
|
|
126
|
+
}
|
|
127
|
+
function htmx(options) {
|
|
128
|
+
return new HTMXAdapter(options);
|
|
129
|
+
}
|
|
130
|
+
var htmx_default = htmx;
|
|
131
|
+
|
|
132
|
+
export { HTMXAdapter, attrsToString, htmx, htmx_default, hx, hxDelete, hxGet, hxPost };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { BaseUIAdapter } from './chunk-2SNQ6PTM.js';
|
|
2
|
+
|
|
3
|
+
// src/adapters/tier-3/stimulus.ts
|
|
4
|
+
var StimulusAdapter = class extends BaseUIAdapter {
|
|
5
|
+
constructor(options = {}) {
|
|
6
|
+
super();
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
9
|
+
id = "stimulus";
|
|
10
|
+
name = "Stimulus";
|
|
11
|
+
framework = "stimulus";
|
|
12
|
+
frameworkVersion = "3+";
|
|
13
|
+
tier = "tier-3";
|
|
14
|
+
capabilities = {
|
|
15
|
+
streaming: false,
|
|
16
|
+
partialHydration: false,
|
|
17
|
+
islands: false,
|
|
18
|
+
resumable: false,
|
|
19
|
+
ssg: true,
|
|
20
|
+
csr: true,
|
|
21
|
+
serverComponents: false
|
|
22
|
+
};
|
|
23
|
+
async renderToString(component, _context) {
|
|
24
|
+
const startTime = performance.now();
|
|
25
|
+
let html;
|
|
26
|
+
if (typeof component.component === "function") {
|
|
27
|
+
html = component.component(component.props ?? {});
|
|
28
|
+
} else if (typeof component.component === "string") {
|
|
29
|
+
html = component.component;
|
|
30
|
+
} else {
|
|
31
|
+
throw new Error(
|
|
32
|
+
"[Flight/Stimulus] Components must be HTML strings or template functions.\nUse data-controller and data-action for interactivity."
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
html,
|
|
37
|
+
hydrationData: component.props,
|
|
38
|
+
timing: this.createTiming(startTime)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
getHydrationScript(_result) {
|
|
42
|
+
const {
|
|
43
|
+
version = "3.2.2",
|
|
44
|
+
debug = false
|
|
45
|
+
} = this.options;
|
|
46
|
+
return `
|
|
47
|
+
<!-- Flight/Stimulus -->
|
|
48
|
+
<script type="module">
|
|
49
|
+
import { Application } from 'https://esm.sh/@hotwired/stimulus@${version}';
|
|
50
|
+
|
|
51
|
+
window.Stimulus = Application.start();
|
|
52
|
+
${debug ? "window.Stimulus.debug = true;" : ""}
|
|
53
|
+
|
|
54
|
+
window.__FLIGHT_ADAPTER__ = 'stimulus';
|
|
55
|
+
console.log('[Flight/Stimulus] Application started');
|
|
56
|
+
</script>
|
|
57
|
+
`.trim();
|
|
58
|
+
}
|
|
59
|
+
getClientEntry() {
|
|
60
|
+
return `
|
|
61
|
+
import { Application, Controller } from '@hotwired/stimulus';
|
|
62
|
+
|
|
63
|
+
// Start Stimulus application
|
|
64
|
+
export const application = Application.start();
|
|
65
|
+
|
|
66
|
+
// Export Controller for extension
|
|
67
|
+
export { Controller };
|
|
68
|
+
|
|
69
|
+
// Register controller helper
|
|
70
|
+
export function register(name, controller) {
|
|
71
|
+
application.register(name, controller);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Bulk register controllers
|
|
75
|
+
export function registerControllers(controllers) {
|
|
76
|
+
for (const [name, controller] of Object.entries(controllers)) {
|
|
77
|
+
register(name, controller);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Dynamic controller loading via import.meta.glob (Vite)
|
|
82
|
+
export function eagerLoadControllers(controllerModules) {
|
|
83
|
+
for (const [path, module] of Object.entries(controllerModules)) {
|
|
84
|
+
const match = path.match(/\\/([^/]+)_controller\\.[jt]s$/);
|
|
85
|
+
if (match && module.default) {
|
|
86
|
+
const name = match[1].replace(/_/g, '-');
|
|
87
|
+
register(name, module.default);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Default hydration
|
|
93
|
+
export function hydrate() {
|
|
94
|
+
console.log('[Flight/Stimulus] Controllers ready');
|
|
95
|
+
}
|
|
96
|
+
`.trim();
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
function controller(name, content, options = {}) {
|
|
100
|
+
const attrs = [`data-controller="${name}"`];
|
|
101
|
+
if (options.values) {
|
|
102
|
+
for (const [key, value] of Object.entries(options.values)) {
|
|
103
|
+
attrs.push(`data-${name}-${toKebab(key)}-value="${value}"`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (options.classes) {
|
|
107
|
+
for (const [key, value] of Object.entries(options.classes)) {
|
|
108
|
+
attrs.push(`data-${name}-${toKebab(key)}-class="${value}"`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (options.outlets) {
|
|
112
|
+
for (const [key, selector] of Object.entries(options.outlets)) {
|
|
113
|
+
attrs.push(`data-${name}-${toKebab(key)}-outlet="${selector}"`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return `<div ${attrs.join(" ")}>${content}</div>`;
|
|
117
|
+
}
|
|
118
|
+
function action(controller2, method, event) {
|
|
119
|
+
const eventPart = event ? `${event}->` : "";
|
|
120
|
+
return `data-action="${eventPart}${controller2}#${method}"`;
|
|
121
|
+
}
|
|
122
|
+
function target(controller2, name) {
|
|
123
|
+
return `data-${controller2}-target="${name}"`;
|
|
124
|
+
}
|
|
125
|
+
function toKebab(str) {
|
|
126
|
+
return str.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
127
|
+
}
|
|
128
|
+
function stimulus(options) {
|
|
129
|
+
return new StimulusAdapter(options);
|
|
130
|
+
}
|
|
131
|
+
var stimulus_default = stimulus;
|
|
132
|
+
|
|
133
|
+
export { StimulusAdapter, action, controller, stimulus, stimulus_default, target };
|