create-fluixi 0.1.0-alpha.11 → 0.1.0-alpha.12
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/dist/index.js +78 -7
- package/package.json +1 -1
- package/template-spa/src/app.tsx +3 -4
- package/template-spa-html/src/app.ts +4 -4
- package/template-ssr/src/app.tsx +3 -3
- package/template-ssr/src/routes/index.tsx +1 -2
- package/template-ssr-html/src/app.ts +2 -2
- package/template-ssr-html/src/routes/index.ts +1 -2
package/dist/index.js
CHANGED
|
@@ -140,6 +140,52 @@ const UI_DEPS = {
|
|
|
140
140
|
};
|
|
141
141
|
/** Build-time only: it runs in the config, not in the app. */
|
|
142
142
|
const UI_DEV_DEPS = { '@fluixi-ui/resolver': 'alpha' };
|
|
143
|
+
/**
|
|
144
|
+
* What `fluixi.d.ts` holds until the compiler regenerates it.
|
|
145
|
+
*
|
|
146
|
+
* Only the intrinsics: the component globals depend on which packages are installed and
|
|
147
|
+
* on the resolver rules, so listing them here would go stale the moment a component is
|
|
148
|
+
* added. The compiler rewrites the whole file on the first dev run.
|
|
149
|
+
*/
|
|
150
|
+
const INTRINSICS_DTS = `// GENERATED by @fluixi/compiler, do not edit.
|
|
151
|
+
//
|
|
152
|
+
// The reactive intrinsics, which the compiler lowers to their \`create*\` calls. They
|
|
153
|
+
// need no import. This file is rewritten on the first \`fluixi dev\`, which adds the
|
|
154
|
+
// components the resolver supplies without an import.
|
|
155
|
+
import * as __fluixi_reactive_signal from '@fluixi/reactive/signal';
|
|
156
|
+
import * as __fluixi_reactive_store from '@fluixi/reactive/store';
|
|
157
|
+
|
|
158
|
+
declare global {
|
|
159
|
+
const $signal: typeof __fluixi_reactive_signal.signal;
|
|
160
|
+
const $memo: typeof __fluixi_reactive_signal.memo;
|
|
161
|
+
const $effect: typeof __fluixi_reactive_signal.effect;
|
|
162
|
+
const $store: typeof __fluixi_reactive_store.store;
|
|
163
|
+
const $resource: typeof __fluixi_reactive_signal.resource;
|
|
164
|
+
const $selector: typeof __fluixi_reactive_signal.createSelector;
|
|
165
|
+
const $deferred: typeof __fluixi_reactive_signal.createDeferred;
|
|
166
|
+
const $untrack: typeof __fluixi_reactive_signal.untrack;
|
|
167
|
+
const $untrackStore: typeof __fluixi_reactive_store.untrackStore;
|
|
168
|
+
}
|
|
169
|
+
`;
|
|
170
|
+
/**
|
|
171
|
+
* The cascade-layer order, declared before anything defines a layer.
|
|
172
|
+
*
|
|
173
|
+
* A layer ranks by where it is FIRST declared, and one nobody declared is appended last,
|
|
174
|
+
* which makes it the strongest. That default is wrong twice over here. The fluixi-css
|
|
175
|
+
* reset defines `flx.base`, which @fluixi-ui's own sheets do not declare, so the reset
|
|
176
|
+
* would outrank the components it is meant to sit under, and an app's plain
|
|
177
|
+
* `button { ... }` reset would outrank them too.
|
|
178
|
+
*
|
|
179
|
+
* Declaring the order up front fixes both: the app's element resets sit lowest, then the
|
|
180
|
+
* engine's preflight, then the component layers. An app's own `@layer base` and
|
|
181
|
+
* `@layer components` are deliberately absent, so they stay unregistered and keep
|
|
182
|
+
* winning, which is what an app expects of its own classes.
|
|
183
|
+
*/
|
|
184
|
+
const LAYERS_CSS = `/* Cascade-layer order. Imported before any component CSS, because a layer ranks by
|
|
185
|
+
where it is first declared and an undeclared one would rank last, above everything.
|
|
186
|
+
Add this app's own layers only if you want them to rank BELOW the component styles. */
|
|
187
|
+
@layer app-reset, flx.reset, flx.base, flx.tokens, flx.components, flx.skin;
|
|
188
|
+
`;
|
|
143
189
|
/** Add to a package.json section without dropping what the template already had. */
|
|
144
190
|
function addDeps(pkg, section, deps) {
|
|
145
191
|
pkg[section] = Object.fromEntries(Object.entries({ ...(pkg[section] ?? {}), ...deps }).sort(([a], [b]) => a.localeCompare(b)));
|
|
@@ -159,10 +205,20 @@ function styleSheet(ui, css) {
|
|
|
159
205
|
const sources = `@source '.';\n@source '../index.html';`;
|
|
160
206
|
const theme = `@theme {\n /* Design tokens. A --color-* scale here drives the whole app. */\n}`;
|
|
161
207
|
if (css === 'fluixi-css') {
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
|
|
165
|
-
|
|
208
|
+
// The layers are pulled in by directive rather than by import, and they come last:
|
|
209
|
+
// `@theme` above has to be read before `utilities` is generated from it.
|
|
210
|
+
return [
|
|
211
|
+
darkVariant,
|
|
212
|
+
'',
|
|
213
|
+
sources,
|
|
214
|
+
'',
|
|
215
|
+
theme,
|
|
216
|
+
'',
|
|
217
|
+
'@fluixi base;',
|
|
218
|
+
'@fluixi utilities;',
|
|
219
|
+
'@fluixi components;',
|
|
220
|
+
'',
|
|
221
|
+
].join('\n');
|
|
166
222
|
}
|
|
167
223
|
if (css === 'tailwind') {
|
|
168
224
|
return [`@import 'tailwindcss';`, '', darkVariant, '', theme, ''].join('\n');
|
|
@@ -218,7 +274,7 @@ function addVitePlugin(target, mode, importLine, call) {
|
|
|
218
274
|
* asked to resolve, and the components below need them defined before their own rules
|
|
219
275
|
* land. `emitUiTokens` does not replace this, that bridge covers a subset.
|
|
220
276
|
*/
|
|
221
|
-
function importStyles(target, mode, ui) {
|
|
277
|
+
function importStyles(target, mode, ui, css) {
|
|
222
278
|
const base = mode === 'ssr' ? 'entry-client' : 'main';
|
|
223
279
|
const file = ['tsx', 'ts']
|
|
224
280
|
.map((ext) => join(target, 'src', `${base}.${ext}`))
|
|
@@ -226,6 +282,8 @@ function importStyles(target, mode, ui) {
|
|
|
226
282
|
if (!file)
|
|
227
283
|
return;
|
|
228
284
|
const head = [
|
|
285
|
+
// First, before anything that defines a layer.
|
|
286
|
+
...(css === 'fluixi-css' ? [`import './layers.css';`] : []),
|
|
229
287
|
...(ui === 'fluixi-ui' ? [`import '@fluixi-ui/tokens/tokens.css';`] : []),
|
|
230
288
|
`import './styles.css';`,
|
|
231
289
|
'',
|
|
@@ -290,6 +348,13 @@ async function main() {
|
|
|
290
348
|
const gi = join(target, '_gitignore');
|
|
291
349
|
if (existsSync(gi))
|
|
292
350
|
renameSync(gi, join(target, '.gitignore'));
|
|
351
|
+
// The ambient declarations for the `$` intrinsics.
|
|
352
|
+
//
|
|
353
|
+
// The compiler rewrites this file on the first `fluixi dev`, adding whatever the
|
|
354
|
+
// resolver supplies without an import. Shipping it now means an editor knows what
|
|
355
|
+
// `$signal` is before the app has ever been run, instead of reporting "Cannot find
|
|
356
|
+
// name" across a project that compiles.
|
|
357
|
+
writeFileSync(join(target, 'fluixi.d.ts'), INTRINSICS_DTS);
|
|
293
358
|
const pkgPath = join(target, 'package.json');
|
|
294
359
|
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
295
360
|
pkg.name = name;
|
|
@@ -309,14 +374,20 @@ async function main() {
|
|
|
309
374
|
// The bridge only matters with the component kit installed: it maps the theme
|
|
310
375
|
// scales onto the `--flx-ui-*` custom properties those components read.
|
|
311
376
|
`fluixiCss({ reset: true${ui === 'fluixi-ui' ? ', emitUiTokens: true' : ''} })`);
|
|
312
|
-
|
|
377
|
+
// No `fluixi.css.config.js`: `@theme`, `@source` and `@custom-variant` in the
|
|
378
|
+
// stylesheet say the same things, and a project with both has two places to change
|
|
379
|
+
// one colour. The config file is still read when an app adds one.
|
|
313
380
|
}
|
|
314
381
|
if (ui === 'fluixi-ui' || css !== 'none') {
|
|
382
|
+
// Only for fluixi-css: it is the engine that defines `flx.base`, and without a
|
|
383
|
+
// declared order that layer lands above the components it belongs under.
|
|
384
|
+
if (css === 'fluixi-css')
|
|
385
|
+
writeFileSync(join(target, 'src', 'layers.css'), LAYERS_CSS);
|
|
315
386
|
const sheet = styleSheet(ui, css);
|
|
316
387
|
// An empty sheet still gets written: it is where an app puts its own css, and the
|
|
317
388
|
// entry already imports it.
|
|
318
389
|
writeFileSync(join(target, 'src', 'styles.css'), sheet);
|
|
319
|
-
importStyles(target, mode, ui);
|
|
390
|
+
importStyles(target, mode, ui, css);
|
|
320
391
|
}
|
|
321
392
|
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
322
393
|
// Outro + next steps. The leading gutter only makes sense after the intro/prompts.
|
package/package.json
CHANGED
package/template-spa/src/app.tsx
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { createSignal } from '@fluixi/core';
|
|
2
1
|
|
|
3
2
|
export function App() {
|
|
4
|
-
const
|
|
3
|
+
const count = $signal(0);
|
|
5
4
|
return (
|
|
6
5
|
<div class="app">
|
|
7
6
|
<h1>Fluixi</h1>
|
|
8
|
-
<button onClick={() =>
|
|
7
|
+
<button onClick={() => count.set(count() - 1)}>-</button>
|
|
9
8
|
<span>{count()}</span>
|
|
10
|
-
<button onClick={() =>
|
|
9
|
+
<button onClick={() => count.set(count() + 1)}>+</button>
|
|
11
10
|
</div>
|
|
12
11
|
);
|
|
13
12
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { html } from '@fluixi/core';
|
|
2
2
|
|
|
3
3
|
export function App() {
|
|
4
|
-
const
|
|
4
|
+
const count = $signal(0);
|
|
5
5
|
return html`
|
|
6
6
|
<div class="app">
|
|
7
7
|
<h1>Fluixi</h1>
|
|
8
|
-
<button @click=${() =>
|
|
8
|
+
<button @click=${() => count.set(count() - 1)}>-</button>
|
|
9
9
|
<span>${count()}</span>
|
|
10
|
-
<button @click=${() =>
|
|
10
|
+
<button @click=${() => count.set(count() + 1)}>+</button>
|
|
11
11
|
</div>
|
|
12
12
|
`;
|
|
13
13
|
}
|
package/template-ssr/src/app.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Router, Outlet, createMemoryHistory } from '@fluixi/start/router';
|
|
1
|
+
import { Router, Outlet, Link, createMemoryHistory } from '@fluixi/start/router';
|
|
2
2
|
import { Suspense } from '@fluixi/core';
|
|
3
3
|
import { routes } from '@fluixi/core/routes';
|
|
4
4
|
|
|
@@ -8,9 +8,9 @@ function RootLayout() {
|
|
|
8
8
|
return (
|
|
9
9
|
<div class="app">
|
|
10
10
|
<nav>
|
|
11
|
-
<
|
|
11
|
+
<Link href="/">home</Link>
|
|
12
12
|
{' · '}
|
|
13
|
-
<
|
|
13
|
+
<Link href="/about">about</Link>
|
|
14
14
|
</nav>
|
|
15
15
|
<main>
|
|
16
16
|
<Suspense fallback={<p>loading…</p>}>
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createResource } from '@fluixi/reactive/signal';
|
|
2
1
|
import { seo } from '@fluixi/start/head';
|
|
3
2
|
|
|
4
3
|
const tick = <T,>(v: T, ms = 30) => new Promise<T>((r) => setTimeout(() => r(v), ms));
|
|
@@ -6,7 +5,7 @@ const tick = <T,>(v: T, ms = 30) => new Promise<T>((r) => setTimeout(() => r(v),
|
|
|
6
5
|
// A data-gated route, like a real page: the resource is awaited during SSR so the
|
|
7
6
|
// content (not the spinner) is server-rendered, then hydrated.
|
|
8
7
|
export default function Home() {
|
|
9
|
-
const
|
|
8
|
+
const data = $resource(() => tick('Hello from Fluixi Start 👋'));
|
|
10
9
|
|
|
11
10
|
// Per-route document head: rendered into <head> on the server (great for crawlers/links)
|
|
12
11
|
// and kept reactive on the client. The head engine is always on; seo() is optional, call it
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Router, Outlet, createMemoryHistory } from '@fluixi/start/router';
|
|
1
|
+
import { Router, Outlet, createMemoryHistory, Link } from '@fluixi/start/router';
|
|
2
2
|
import { Suspense } from '@fluixi/core';
|
|
3
3
|
import { html } from '@fluixi/start';
|
|
4
4
|
import { routes } from '@fluixi/core/routes';
|
|
@@ -10,7 +10,7 @@ function RootLayout() {
|
|
|
10
10
|
return html`
|
|
11
11
|
<div class="app">
|
|
12
12
|
<nav>
|
|
13
|
-
|
|
13
|
+
<${Link} href="/">home<//> · <${Link} href="/about">about<//>
|
|
14
14
|
</nav>
|
|
15
15
|
<main>
|
|
16
16
|
<${Suspense} fallback=${html`<p>loading…</p>`}>
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createResource } from '@fluixi/reactive/signal';
|
|
2
1
|
import { seo } from '@fluixi/start/head';
|
|
3
2
|
import { html } from '@fluixi/start';
|
|
4
3
|
|
|
@@ -7,7 +6,7 @@ const tick = <T,>(v: T, ms = 30) => new Promise<T>((r) => setTimeout(() => r(v),
|
|
|
7
6
|
// A data-gated route, like a real page: the resource is awaited during SSR so the
|
|
8
7
|
// content (not the spinner) is server-rendered, then hydrated.
|
|
9
8
|
export default function Home() {
|
|
10
|
-
const
|
|
9
|
+
const data = $resource(() => tick('Hello from Fluixi Start 👋'));
|
|
11
10
|
|
|
12
11
|
// Per-route document head: rendered into <head> on the server (great for crawlers/links)
|
|
13
12
|
// and kept reactive on the client. seo() is optional; call it where you want metadata.
|