@fluixi/core 1.0.0-alpha.53
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/LICENSE +21 -0
- package/README.md +611 -0
- package/dist/cdn/core.global.js +3 -0
- package/dist/cli/generate.cjs +1814 -0
- package/dist/cli/generate.d.ts +7 -0
- package/dist/cli/generate.d.ts.map +1 -0
- package/dist/cli/generate.js +2580 -0
- package/dist/cli/generate.mjs +1814 -0
- package/dist/cli/index.cjs +1814 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +2580 -0
- package/dist/cli/index.mjs +1814 -0
- package/dist/cli/run.cjs +2 -0
- package/dist/cli/run.d.ts +3 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +62 -0
- package/dist/cli/run.mjs +2 -0
- package/dist/fluixi.d.ts +5 -0
- package/dist/src/cdn/chunk-PFM5O5UE.mjs +1 -0
- package/dist/src/cdn/core.cjs +1 -0
- package/dist/src/cdn/core.d.ts +16 -0
- package/dist/src/cdn/core.d.ts.map +1 -0
- package/dist/src/cdn/core.js +15 -0
- package/dist/src/cdn/core.mjs +1 -0
- package/dist/src/cdn/router-next-WNWCFVC2.mjs +1 -0
- package/dist/src/index.cjs +1 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +26 -0
- package/dist/src/index.mjs +1 -0
- package/dist/src/jsx-dev-runtime.cjs +1 -0
- package/dist/src/jsx-dev-runtime.d.ts +2 -0
- package/dist/src/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/src/jsx-dev-runtime.js +1 -0
- package/dist/src/jsx-dev-runtime.mjs +1 -0
- package/dist/src/jsx-runtime.cjs +1 -0
- package/dist/src/jsx-runtime.d.ts +7 -0
- package/dist/src/jsx-runtime.d.ts.map +1 -0
- package/dist/src/jsx-runtime.js +17 -0
- package/dist/src/jsx-runtime.mjs +1 -0
- package/dist/src/lib/client/chunk-D3VTWVNJ.mjs +1 -0
- package/dist/src/lib/client/index.cjs +1 -0
- package/dist/src/lib/client/index.d.ts +54 -0
- package/dist/src/lib/client/index.d.ts.map +1 -0
- package/dist/src/lib/client/index.js +142 -0
- package/dist/src/lib/client/index.mjs +1 -0
- package/dist/src/lib/client/router-next-UYIYMRJL.mjs +1 -0
- package/dist/src/lib/context/context.cjs +1 -0
- package/dist/src/lib/context/context.d.ts +337 -0
- package/dist/src/lib/context/context.d.ts.map +1 -0
- package/dist/src/lib/context/context.js +462 -0
- package/dist/src/lib/context/context.mjs +1 -0
- package/dist/src/lib/context/index.cjs +1 -0
- package/dist/src/lib/context/index.d.ts +3 -0
- package/dist/src/lib/context/index.d.ts.map +1 -0
- package/dist/src/lib/context/index.js +5 -0
- package/dist/src/lib/context/index.mjs +1 -0
- package/dist/src/lib/control-flow.cjs +1 -0
- package/dist/src/lib/control-flow.d.ts +4 -0
- package/dist/src/lib/control-flow.d.ts.map +1 -0
- package/dist/src/lib/control-flow.js +1 -0
- package/dist/src/lib/control-flow.mjs +1 -0
- package/dist/src/lib/core.cjs +1 -0
- package/dist/src/lib/core.d.ts +90 -0
- package/dist/src/lib/core.d.ts.map +1 -0
- package/dist/src/lib/core.js +181 -0
- package/dist/src/lib/core.mjs +1 -0
- package/dist/src/lib/directives/lit.cjs +1 -0
- package/dist/src/lib/directives/lit.d.ts +2 -0
- package/dist/src/lib/directives/lit.d.ts.map +1 -0
- package/dist/src/lib/directives/lit.js +31 -0
- package/dist/src/lib/directives/lit.mjs +0 -0
- package/dist/src/lib/env/index.cjs +1 -0
- package/dist/src/lib/env/index.d.ts +39 -0
- package/dist/src/lib/env/index.d.ts.map +1 -0
- package/dist/src/lib/env/index.js +50 -0
- package/dist/src/lib/env/index.mjs +1 -0
- package/dist/src/lib/i18n/index.cjs +1 -0
- package/dist/src/lib/i18n/index.d.ts +79 -0
- package/dist/src/lib/i18n/index.d.ts.map +1 -0
- package/dist/src/lib/i18n/index.js +127 -0
- package/dist/src/lib/i18n/index.mjs +1 -0
- package/dist/src/lib/index.cjs +1 -0
- package/dist/src/lib/index.d.ts +83 -0
- package/dist/src/lib/index.d.ts.map +1 -0
- package/dist/src/lib/index.js +147 -0
- package/dist/src/lib/index.mjs +1 -0
- package/dist/src/lib/isomorphic.cjs +1 -0
- package/dist/src/lib/isomorphic.d.ts +69 -0
- package/dist/src/lib/isomorphic.d.ts.map +1 -0
- package/dist/src/lib/isomorphic.js +92 -0
- package/dist/src/lib/isomorphic.mjs +1 -0
- package/dist/src/lib/jsx-runtime/index.cjs +1 -0
- package/dist/src/lib/jsx-runtime/index.d.ts +13 -0
- package/dist/src/lib/jsx-runtime/index.d.ts.map +1 -0
- package/dist/src/lib/jsx-runtime/index.js +23 -0
- package/dist/src/lib/jsx-runtime/index.mjs +1 -0
- package/dist/src/lib/jsx-runtime/jsx-dev-runtime.cjs +1 -0
- package/dist/src/lib/jsx-runtime/jsx-dev-runtime.d.ts +2 -0
- package/dist/src/lib/jsx-runtime/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/src/lib/jsx-runtime/jsx-dev-runtime.js +1 -0
- package/dist/src/lib/jsx-runtime/jsx-dev-runtime.mjs +1 -0
- package/dist/src/lib/plugins/fluixi-routes-plugin.cjs +13 -0
- package/dist/src/lib/plugins/fluixi-routes-plugin.d.ts +21 -0
- package/dist/src/lib/plugins/fluixi-routes-plugin.d.ts.map +1 -0
- package/dist/src/lib/plugins/fluixi-routes-plugin.js +102 -0
- package/dist/src/lib/plugins/fluixi-routes-plugin.mjs +13 -0
- package/dist/src/lib/plugins/index.cjs +13 -0
- package/dist/src/lib/plugins/index.d.ts +4 -0
- package/dist/src/lib/plugins/index.d.ts.map +1 -0
- package/dist/src/lib/plugins/index.js +3 -0
- package/dist/src/lib/plugins/index.mjs +13 -0
- package/dist/src/lib/plugins/route-codegen.cjs +8 -0
- package/dist/src/lib/plugins/route-codegen.d.ts +13 -0
- package/dist/src/lib/plugins/route-codegen.d.ts.map +1 -0
- package/dist/src/lib/plugins/route-codegen.js +81 -0
- package/dist/src/lib/plugins/route-codegen.mjs +8 -0
- package/dist/src/lib/plugins/route-scanner.cjs +1 -0
- package/dist/src/lib/plugins/route-scanner.d.ts +39 -0
- package/dist/src/lib/plugins/route-scanner.d.ts.map +1 -0
- package/dist/src/lib/plugins/route-scanner.js +216 -0
- package/dist/src/lib/plugins/route-scanner.mjs +1 -0
- package/dist/src/lib/plugins/vite.cjs +1 -0
- package/dist/src/lib/plugins/vite.d.ts +3 -0
- package/dist/src/lib/plugins/vite.d.ts.map +1 -0
- package/dist/src/lib/plugins/vite.js +1 -0
- package/dist/src/lib/plugins/vite.mjs +1 -0
- package/dist/src/lib/render/component.cjs +1 -0
- package/dist/src/lib/render/component.d.ts +328 -0
- package/dist/src/lib/render/component.d.ts.map +1 -0
- package/dist/src/lib/render/component.js +520 -0
- package/dist/src/lib/render/component.mjs +1 -0
- package/dist/src/lib/render/index.cjs +1 -0
- package/dist/src/lib/render/index.d.ts +113 -0
- package/dist/src/lib/render/index.d.ts.map +1 -0
- package/dist/src/lib/render/index.js +201 -0
- package/dist/src/lib/render/index.mjs +1 -0
- package/dist/src/lib/render/lazy.cjs +1 -0
- package/dist/src/lib/render/lazy.d.ts +28 -0
- package/dist/src/lib/render/lazy.d.ts.map +1 -0
- package/dist/src/lib/render/lazy.js +62 -0
- package/dist/src/lib/render/lazy.mjs +1 -0
- package/dist/src/lib/render/suspense.cjs +1 -0
- package/dist/src/lib/render/suspense.d.ts +25 -0
- package/dist/src/lib/render/suspense.d.ts.map +1 -0
- package/dist/src/lib/render/suspense.js +139 -0
- package/dist/src/lib/render/suspense.mjs +1 -0
- package/dist/src/lib/router-next/data.cjs +1 -0
- package/dist/src/lib/router-next/data.d.ts +101 -0
- package/dist/src/lib/router-next/data.d.ts.map +1 -0
- package/dist/src/lib/router-next/data.js +179 -0
- package/dist/src/lib/router-next/data.mjs +1 -0
- package/dist/src/lib/router-next/index.cjs +1 -0
- package/dist/src/lib/router-next/index.d.ts +156 -0
- package/dist/src/lib/router-next/index.d.ts.map +1 -0
- package/dist/src/lib/router-next/index.js +464 -0
- package/dist/src/lib/router-next/index.mjs +1 -0
- package/dist/src/lib/server/hydration.cjs +1 -0
- package/dist/src/lib/server/hydration.d.ts +238 -0
- package/dist/src/lib/server/hydration.d.ts.map +1 -0
- package/dist/src/lib/server/hydration.js +384 -0
- package/dist/src/lib/server/hydration.mjs +1 -0
- package/dist/src/lib/server/index.cjs +16 -0
- package/dist/src/lib/server/index.d.ts +91 -0
- package/dist/src/lib/server/index.d.ts.map +1 -0
- package/dist/src/lib/server/index.js +141 -0
- package/dist/src/lib/server/index.mjs +16 -0
- package/dist/src/lib/server/reactive.cjs +1 -0
- package/dist/src/lib/server/reactive.d.ts +298 -0
- package/dist/src/lib/server/reactive.d.ts.map +1 -0
- package/dist/src/lib/server/reactive.js +472 -0
- package/dist/src/lib/server/reactive.mjs +1 -0
- package/dist/src/lib/theme/index.cjs +1 -0
- package/dist/src/lib/theme/index.d.ts +51 -0
- package/dist/src/lib/theme/index.d.ts.map +1 -0
- package/dist/src/lib/theme/index.js +79 -0
- package/dist/src/lib/theme/index.mjs +1 -0
- package/dist/src/lib/utils/index.cjs +1 -0
- package/dist/src/lib/utils/index.d.ts +379 -0
- package/dist/src/lib/utils/index.d.ts.map +1 -0
- package/dist/src/lib/utils/index.js +527 -0
- package/dist/src/lib/utils/index.mjs +1 -0
- package/dist/src/rx.cjs +1 -0
- package/dist/src/rx.d.ts +2 -0
- package/dist/src/rx.d.ts.map +1 -0
- package/dist/src/rx.js +101 -0
- package/dist/src/rx.mjs +0 -0
- package/dist/src/server.cjs +16 -0
- package/dist/src/server.d.ts +64 -0
- package/dist/src/server.d.ts.map +1 -0
- package/dist/src/server.js +63 -0
- package/dist/src/server.mjs +16 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/package.json +128 -0
- package/src/index.ts +31 -0
- package/types/fluixi.d.ts +5 -0
- package/types/vinxi.d.ts +50 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Fluixi - A reactive framework for lit-html inspired by SolidJS
|
|
3
|
+
* @module @fluixi/core
|
|
4
|
+
* @version 0.0.1
|
|
5
|
+
*
|
|
6
|
+
* Fluixi is a modern reactive framework that combines the power of lit-html
|
|
7
|
+
* with fine-grained reactivity from @fluixi/reactive, inspired by SolidJS's design.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { createSignal, render, html } from '@fluixi/core';
|
|
12
|
+
*
|
|
13
|
+
* const Counter = () => {
|
|
14
|
+
* const [count, setCount] = createSignal(0);
|
|
15
|
+
*
|
|
16
|
+
* return html`
|
|
17
|
+
* <div>
|
|
18
|
+
* <p>Count: ${count()}</p>
|
|
19
|
+
* <button @click=${() => setCount(count() + 1)}>Increment</button>
|
|
20
|
+
* </div>
|
|
21
|
+
* `;
|
|
22
|
+
* };
|
|
23
|
+
*
|
|
24
|
+
* render(Counter, document.getElementById('app')!);
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
import { createEffect, createMemo, createSignal, createResource, createRoot, createComputed, createRenderEffect, onCleanup, getOwner, runWithOwner, batch, untrack, createDeferred, setOwner, } from '@fluixi/reactive/signal';
|
|
28
|
+
// } from '@fluixi/core/rx';
|
|
29
|
+
import { createDebounce, createSelector } from '@fluixi/reactive/signal';
|
|
30
|
+
import { readSignal as read, reduceSignal as reduce, } from '@fluixi/reactive/operators';
|
|
31
|
+
import {
|
|
32
|
+
// batch,
|
|
33
|
+
createComponent,
|
|
34
|
+
// createRoot,
|
|
35
|
+
onMount, onUnmount,
|
|
36
|
+
// untrack,
|
|
37
|
+
// } from './core/index.js';
|
|
38
|
+
} from './render/index.js';
|
|
39
|
+
import { createContext, useContext } from './context/index.js';
|
|
40
|
+
export * from './context/index.js';
|
|
41
|
+
// Isomorphic request state (server-resolved → serialized → client-seeded). Public
|
|
42
|
+
// barrel is lib/core.ts (src/index.ts re-exports it), so the export must live here.
|
|
43
|
+
export { createIsomorphicState, createIsomorphicStore, } from './isomorphic.js';
|
|
44
|
+
// Universal env utilities — isomorphic storage + safe browser-global access, so app
|
|
45
|
+
// modules import these instead of touching localStorage/window/document directly.
|
|
46
|
+
export { isServer, isClient, storage, createMemoryStorage, env, clientOnly, } from './env/index.js';
|
|
47
|
+
// Theme store — detect → persist → apply → toggle + no-flash head script.
|
|
48
|
+
export { createTheme } from './theme/index.js';
|
|
49
|
+
export * from '@fluixi/utils';
|
|
50
|
+
// import { createContext, Provider, useContext } from './context/index.js';
|
|
51
|
+
// import { createContext, useContext } from './render/component.js';
|
|
52
|
+
// import { createResource } from './resources/index.js';
|
|
53
|
+
import { Link, Router, useNavigate, useRouter, } from './router-next/index.js';
|
|
54
|
+
import { ensureIntegration } from './render/component.js';
|
|
55
|
+
// Lit lives in @fluixi/lit — import html/svg/nothing/LitElement from there directly.
|
|
56
|
+
// The core @fluixi/core entry no longer pulls lit (keeps it out of SSR bundles).
|
|
57
|
+
// createReactiveJSX (a deprecated legacy adapter) lived here but pulled the jsx-runtime
|
|
58
|
+
// `.` entry into the core graph. It's gone — compiled JSX uses the jsx-runtime subpath
|
|
59
|
+
// directly, and nothing in the framework needs the adapter.
|
|
60
|
+
// Re-export reactive directives
|
|
61
|
+
export { query, queryAll, closest, addClass, removeClass, toggleClass, hasClass, setAttribute, getAttribute, removeAttribute, setStyles, getStyle, createElement as domCreateElement, removeChildren, appendChildren, isVisible, scrollIntoView, getOffset, delegate, waitForElement, observeIntersection, observeResize, } from '@fluixi/dom';
|
|
62
|
+
// Lit renderer symbols ($show/$match/portal helpers/html/litrx/…) live in @fluixi/lit —
|
|
63
|
+
// import them from there. They are intentionally NOT re-exported here so the core
|
|
64
|
+
// entry stays lit-free (and out of server bundles).
|
|
65
|
+
// import {For as _For} from "@fluixi/dom"
|
|
66
|
+
// export interface ForProps<T, U = any> {
|
|
67
|
+
// /** Reactive array to iterate over — static, readonly, accessor, or signal. */
|
|
68
|
+
// each: ReadonlyArray<T> | (() => ReadonlyArray<T> | null | undefined) | Accessor<ReadonlyArray<T>> | null | undefined | false;
|
|
69
|
+
// /** Rendered when the array is empty or nullish. */
|
|
70
|
+
// fallback?: any;
|
|
71
|
+
// /**
|
|
72
|
+
// * Render function called once per unique item (keyed by reference).
|
|
73
|
+
// * `index` is a reactive accessor — updates when the item moves position.
|
|
74
|
+
// *
|
|
75
|
+
// * JSX: <For each={() => store.items}>{(item, index) => <li>{item.name}</li>}</For>
|
|
76
|
+
// * lit: For({ each: items, children: (item, index) => html`<li>${item.name}</li>` })
|
|
77
|
+
// */
|
|
78
|
+
// children?: (item: T, index: Accessor<number>) => U;
|
|
79
|
+
// }
|
|
80
|
+
// export const For = <T>(props: ForProps<T>) => _For(props as any) as JSX.Element;
|
|
81
|
+
export { classMap, styleMap, Island, hydrateIslands,
|
|
82
|
+
// Prop helpers (Solid-compatible): merge prop sources (later `undefined` falls through) and
|
|
83
|
+
// split a reactive props object into groups + rest. The compiler emits mergeProps for JSX spreads.
|
|
84
|
+
mergeProps, splitProps, } from '@fluixi/dom';
|
|
85
|
+
export * from "./control-flow.js";
|
|
86
|
+
// Re-export reactive primitives from @fluixi/reactive
|
|
87
|
+
export { createStore, untrackStore, unwrap, Store } from '@fluixi/reactive/store';
|
|
88
|
+
export { render, portal, isRenderable, initDelegation, cleanupDelegation, createComponent, onMount, onUnmount, useEffect, useRef, useReducer, useMemo, useEventListener, useCallback, lazy, Suspense, SuspenseList,
|
|
89
|
+
// Show,
|
|
90
|
+
isNode, isLitResult, isJSXElement, $component, } from './render/index.js';
|
|
91
|
+
// Context API
|
|
92
|
+
// export {
|
|
93
|
+
// // createContext,
|
|
94
|
+
// // useContext,
|
|
95
|
+
// Provider,
|
|
96
|
+
// createContextWithProvider,
|
|
97
|
+
// composeProviders,
|
|
98
|
+
// createConsumer,
|
|
99
|
+
// useProvide,
|
|
100
|
+
// createScopedContext,
|
|
101
|
+
// } from './context/index.js';
|
|
102
|
+
// export type { Context, ProviderProps } from './context/index.js';
|
|
103
|
+
// Resources for async data
|
|
104
|
+
// export {
|
|
105
|
+
// createResource,
|
|
106
|
+
// createResources,
|
|
107
|
+
// createResourceWithRetry,
|
|
108
|
+
// createLazyResource,
|
|
109
|
+
// } from './resources/index.js';
|
|
110
|
+
// export type {
|
|
111
|
+
// Resource,
|
|
112
|
+
// ResourceState,
|
|
113
|
+
// ResourceOptions,
|
|
114
|
+
// ResourceFetcher,
|
|
115
|
+
// ResourceSource,
|
|
116
|
+
// } from './resources/index.js';
|
|
117
|
+
// Router — from router-next (the framework-agnostic router). The old lit-based router
|
|
118
|
+
// (./router) has been removed: it imported `html` from @fluixi/lit, which dragged lit
|
|
119
|
+
// (extends HTMLElement at module init) into the core/SSR graph. router-next is the
|
|
120
|
+
// only router now; `<Router routes={...}/>` replaces the old `<Routes>`/`<Route>` JSX.
|
|
121
|
+
export { Router, Link, useRouter, useLocation, useNavigate, useParams, } from './router-next/index.js';
|
|
122
|
+
// Web Component support moved to @fluixi/element (now in the wc-element repo).
|
|
123
|
+
// Import { defineElement, FluixiElement, createComponent, ... } from '@fluixi/element'.
|
|
124
|
+
/**
|
|
125
|
+
* Framework version
|
|
126
|
+
*/
|
|
127
|
+
export const VERSION = '0.0.1';
|
|
128
|
+
/**
|
|
129
|
+
* Framework name
|
|
130
|
+
*/
|
|
131
|
+
export const FRAMEWORK_NAME = 'Fluixi';
|
|
132
|
+
export { createEffect, createMemo, createSignal, createResource, createContext, createRoot, createDeferred, createDebounce, createComputed, createRenderEffect, createSelector, onCleanup, getOwner, runWithOwner, batch, untrack, useContext, setOwner, read, reduce, };
|
|
133
|
+
/**
|
|
134
|
+
* Default export - commonly used functions
|
|
135
|
+
*/
|
|
136
|
+
export default {
|
|
137
|
+
// Core
|
|
138
|
+
createComponent,
|
|
139
|
+
// render,
|
|
140
|
+
onMount,
|
|
141
|
+
onUnmount,
|
|
142
|
+
createEffect,
|
|
143
|
+
createMemo,
|
|
144
|
+
createSignal,
|
|
145
|
+
createContext,
|
|
146
|
+
createRoot,
|
|
147
|
+
createDeferred,
|
|
148
|
+
createComputed,
|
|
149
|
+
createRenderEffect,
|
|
150
|
+
createSelector,
|
|
151
|
+
onCleanup,
|
|
152
|
+
getOwner,
|
|
153
|
+
runWithOwner,
|
|
154
|
+
batch,
|
|
155
|
+
untrack,
|
|
156
|
+
useContext,
|
|
157
|
+
setOwner,
|
|
158
|
+
// Control Flow
|
|
159
|
+
// Show,
|
|
160
|
+
// For,
|
|
161
|
+
// Switch,
|
|
162
|
+
// Match,
|
|
163
|
+
// Portal,
|
|
164
|
+
// Dynamic,
|
|
165
|
+
// Context
|
|
166
|
+
// Provider,
|
|
167
|
+
// Resources
|
|
168
|
+
// createResource,
|
|
169
|
+
// Router
|
|
170
|
+
// createRouter,
|
|
171
|
+
Router,
|
|
172
|
+
Link,
|
|
173
|
+
useRouter,
|
|
174
|
+
useNavigate,
|
|
175
|
+
read,
|
|
176
|
+
reduce,
|
|
177
|
+
// Meta
|
|
178
|
+
VERSION,
|
|
179
|
+
FRAMEWORK_NAME,
|
|
180
|
+
};
|
|
181
|
+
ensureIntegration('fluixi element main');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createEffect as _t,createMemo as jt,createSignal as $t,createResource as Wr,createRoot as Vt,createComputed as Kt,createRenderEffect as Ht,onCleanup as Ut,getOwner as zt,runWithOwner as Wt,batch as Jt,untrack as Bt,createDeferred as qt,setOwner as Xt}from"@fluixi/reactive/signal";import{createDebounce as Br,createSelector as Yt}from"@fluixi/reactive/signal";import{readSignal as Gt,reduceSignal as Qt}from"@fluixi/reactive/operators";import{createRoot as We}from"@fluixi/reactive/signal";import{isDOMNode as Je,delegateEvents as pe,registerLitRender as Be,insert as qe}from"@fluixi/dom";import{registerCreateComponent as Ae,asComponent as Oe}from"@fluixi/dom";import{untrack as q,onCleanup as m,getOwner as M,createEffect as S,createMemo as X,createSignal as ke,isSignal as Ee,batch as Le,runWithOwner as Y}from"@fluixi/reactive/signal";var L=Symbol.for("fluixi-lifecycle");function G(){let e=M();if(!e)return null;if(!e[L]){let t={mounts:[],effects:[],scheduled:!1};e[L]=t}return e[L]}function Q(e){if(e.scheduled)return;e.scheduled=!0;let t=M();queueMicrotask(()=>{Y(t,()=>{for(let n of e.mounts)try{let r=n();typeof r=="function"&&m(r)}catch(r){console.error("Error in onMount callback:",r)}for(let n of e.effects){let r;S(()=>{r&&r(),r=n()}),m(()=>{r&&r()})}e.mounts=[],e.effects=[]})})}function g(e){Ae(C)}function C(e,t){return D(e,t)}function D(e,t){let n=typeof e=="function"?q(()=>e(t)):e;if(n!=null&&(typeof n=="function"||typeof n=="object")&&!Ee(n)){try{n.$name=e.name}catch{}return Oe(n)}return n}function P(e,t=!0){let n=G();if(n){if(!t){n.scheduled||e();return}n.mounts.push(e),Q(n)}else{if(!t){e();return}S(()=>{let r=q(e);typeof r=="function"&&m(r)})}}function w(e){m(e)}function I(e){let t=G();if(t)t.effects.push(e),Q(t);else{let n;S(()=>{n&&n(),n=e()}),m(()=>{n&&n()})}}function Z(e){return X(e)}function ee(e){let t={current:e};return m(()=>{t.current=null}),t}function te(e,t){let[n,r]=ke(t);return[n,i=>{r(e(n(),i))}]}function ne(e,t,n,r){I(()=>{let o=e&&"current"in e?e.current:e;if(o)return o.addEventListener(t,n,r),()=>{o.removeEventListener(t,n,r)}})}function re(e){return e}import{createSignal as N,createMemo as Me,createEffect as De,createRenderEffect as Ie,isSignal as F,useContext as Fe,createContext as Ne,createSuspenseBoundary as _e,provideSuspense as oe}from"@fluixi/reactive/signal";import{asSuspense as je,isComponent as $e,createComponent as se,runWithoutHydration as Ve}from"@fluixi/dom";function ie(e){return typeof window>"u"?!1:typeof Node=="function"&&e instanceof Node?!0:!!(e&&typeof e=="object"&&typeof e.nodeType=="number")}function ae(e){return!e||typeof e!="object"?!1:!!(typeof e._$litType$<"u"||typeof e._$litDirective$<"u"||Array.isArray(e.strings)&&Array.isArray(e.values))}function ce(e){return!!(e&&typeof e=="object"&&typeof e.then=="function"||e instanceof Promise)}function ue(e){return!!(e&&typeof e=="object"&&"type"in e&&"props"in e)}var de=Ne();function R(e){return se(Ke,e)}function Ke(e){let t=_e(),n=Fe(de),r=n?n.register(t.inFallback):void 0;function o(u){return u==null||typeof u=="boolean"?null:typeof u=="function"&&$e(u)&&!F(u)?u():u}let i=Ve(()=>o(e.fallback??null)),s=oe(t,()=>e.children);oe(t,()=>{Ie(()=>{let u=s;if(Array.isArray(u))for(let d of u)typeof d=="function"&&F(d)&&d();else typeof u=="function"&&F(u)&&u()})});let[c,a]=N(void 0),l=ce(s);return l&&(t.increment(),s.then(u=>{a(()=>u),t.decrement()},()=>t.decrement())),Me(()=>(r?r.showFallback():t.inFallback())?i:l?c():s)}function le(e){return se(He,e)}function He(e){let{revealOrder:t="together",tail:n}=e,r=[];function o(){if(t==="together"){let s=r.every(c=>!c.inFallback());r.forEach(c=>{c.setShowContent(s),c.setShowFallback(!s)})}else{let s=t==="backwards"?[...r].reverse():r,c=!1;for(let a of s)c||a.inFallback()?(c=!0,a.setShowContent(!1),a.setShowFallback(n!=="hidden")):(a.setShowContent(!0),a.setShowFallback(!1))}}let i={register:s=>{let[c,a]=N(!0),[l,u]=N(!1);return r.push({inFallback:s,setShowContent:a,setShowFallback:u}),De(()=>{s(),o()}),{showContent:c,showFallback:l}}};return de.Provider({value:i,children:e.children})}je(R);Object.defineProperty(R,"__suspense",{value:!0,enumerable:!0});import{untrack as fe,createMemo as Ue,createResource as ze}from"@fluixi/reactive/signal";function _(e,t){let n,r,o;function i(){return r||(r=e().then(c=>n=c.default)),r}t?.preload&&i();let s=(c=>{if(n){let a=n;return fe(()=>a(c))}if(!o){let[a]=ze(()=>i());if(o=a,a.error)throw a.error}return Ue(()=>{let a=o();return a?fe(()=>a(c)):void 0},void 0,{name:"lazy"})});return s.preload=()=>i().then(()=>{}),s.$lazy=!0,s.loader=e,s}typeof window<"u"&&import("lit").then(e=>Be(e.render));var j=typeof window>"u";function ye(e,t,n={}){if(g("render"),pe(["click","input","change","submit"]),j)throw new Error("render() is for client-side only. Use renderToString() on server.");if(!t)throw new Error("Container element is required");let r;return We(o=>{r=o;let i=typeof e=="function"?e():e;t.textContent="",t.setAttribute("fluixi-js","v1"),qe(t,()=>i)}),()=>{r&&(r(),r=void 0)}}function Xe(e){return e&&typeof e=="object"&&(e._$litType$!==void 0||e._$litDirective$!==void 0)}function Ye(e,t,n={}){let r=document.createElement("div");r.setAttribute("data-portal","true"),t.appendChild(r);let o=ye(e,r,n);return()=>{o(),t.contains(r)&&t.removeChild(r)}}function Ge(e){return!!(e==null||typeof e=="function"||Je(e)||Xe(e)||Array.isArray(e)||typeof e=="string"||typeof e=="number"||typeof e=="boolean")}function Qe(){j||pe(["click","input","change","submit"])}function Ze(){}import{asProvider as et}from"@fluixi/dom";import{createContext as tt,useContext as nt}from"@fluixi/reactive/signal";import{readChildren as rt}from"@fluixi/reactive/signal";g("index");var me=!1;function ot(){me||(me=!0,!(typeof process<"u")&&console.warn("[fluixi] createProvider({ context, value, children }) reads `children` eagerly: the object literal materialises `children` BEFORE the context is stamped, so a routed <Outlet/> that has siblings inside the provider renders detached and its descendants see no context under SSR. Use the lazy form instead:\n createProvider(Context, value, props) // children stays a getter\n // or JSX: <Context.Provider value={…}>{props.children}</Context.Provider>"))}function $(e,t,n){let r=!!e?.Provider,o=r?e:e.context,i=r?t:e.value,s=r?!1:e.debug??!1;r||ot();let c=typeof i=="function"?i():i,a=r?n:e;return o.Provider({value:c,get children(){return a?.children},debug:s})}function st(e){let t=h(e);return[t,r=>$(t,r.value,r)]}function ge(e,t){if(e.length===0)return rt(()=>t);let[n,r]=e[0],o=e.slice(1);return $(n,r,{get children(){return ge(o,t)}})}function it(e){return t=>{let n=x(e);return t.children(n)}}function at(e,t){let n=x(e);return n===e.defaultValue?t():n}function h(e){let t=tt(e),n=r=>(r.debug,t.Provider({value:r.value,get children(){return r.children},debug:r.debug}));return typeof Symbol<"u"&&Symbol.for&&(n.$$typeof=Symbol.for("react.provider")),n.$$typeof=Symbol.for("react.provider"),{id:t.id,Provider:et(n),defaultValue:e}}function x(e){let t=nt(e);return t!==void 0?t:e.defaultValue}import{createSignal as ct,createMemo as ut}from"@fluixi/reactive/signal";import{getServerData as dt}from"@fluixi/dom";var lt="__fluixi_iso_states__",ft="__iso:";function pt(){return globalThis[lt]??=new Map}function he(e){if(typeof window>"u")return;let t=dt();return t?t[ft+e]:void 0}function xe(e,t){let n=he(e),r=n!==void 0?n:typeof window<"u"&&t.client?t.client():t.fallback,[o,i]=ct(r);return pt().set(e,{server:t.server,set:i}),{value:o,set:i,key:e}}function yt(e,t){let n=he(e)!==void 0,r=xe(e,{server:t.server,fallback:t.fallback}),o=()=>r.value()??t.fallback,i=d=>{if(!(!t.persist||typeof localStorage>"u"))try{localStorage.setItem(t.persist,JSON.stringify(d))}catch{}},s=d=>{r.set(d),i(d)},c=(d,b)=>{s({...o(),[d]:b})},a={};for(let d of Object.keys(t.fallback))a[d]=ut(()=>o()[d]);let l=null;return{value:o,fields:a,set:s,setField:c,ensureInit:()=>n||!t.client?Promise.resolve():(l||(l=Promise.resolve(t.client()).then(d=>{s(d)}).catch(d=>{throw l=null,d})),l),key:e}}var Te=typeof document>"u",ve=!Te;function Ce(){let e=new Map;return{getItem:t=>e.has(t)?e.get(t):null,setItem:(t,n)=>{e.set(t,String(n))},removeItem:t=>{e.delete(t)},clear:()=>e.clear(),key:t=>Array.from(e.keys())[t]??null,get length(){return e.size}}}var A=typeof localStorage<"u"?localStorage:Ce(),O={get window(){return typeof window<"u"?window:void 0},get document(){return typeof document<"u"?document:void 0}};function mt(e,t){return ve?e():t}import{createSignal as be}from"@fluixi/reactive/signal";function gt(e){return e?e===!0?{dark:"dark",light:"light"}:e:null}function ht(e){let t=e.storageKey??"theme",n=e.attribute??"data-theme",r=gt(e.system),o=()=>{let f=A.getItem(t);return f&&e.themes.includes(f)?f:r&&O.window?.matchMedia?.("(prefers-color-scheme: dark)")?.matches?r.dark:r?r.light:e.default},[i,s]=be(o()),[c,a]=be(!1),l=f=>{O.document?.documentElement.setAttribute(n,f);try{A.setItem(t,f)}catch{}},u=f=>{if(!e.themes.includes(f))return;let Re=i();s(()=>f),l(f),e.onChange?.(f,Re),e.load&&(a(!0),e.onLoading?.(f),Promise.resolve(e.load(f)).finally(()=>{a(!1),e.onLoaded?.(f)}))};return{value:i,isLoading:c,set:u,toggle:()=>{let f=e.themes.indexOf(i());u(e.themes[(f+1)%e.themes.length])},init:()=>l(i()),headScript:()=>`<script>(function(){try{var c=${JSON.stringify({k:t,a:n,d:e.default,sys:r})},t=localStorage.getItem(c.k);if(!t&&c.sys)t=matchMedia('(prefers-color-scheme: dark)').matches?c.sys.dark:c.sys.light;if(!t)t=c.d;document.documentElement.setAttribute(c.a,t);}catch(e){}})();<\/script>`}}export*from"@fluixi/utils";import{createSignal as H,createMemo as T,createResource as St,createEffect as U,getOwner as Pt,onCleanup as Se,untrack as V}from"@fluixi/reactive/signal";import{insert as K,createComponent as Pe,createNativeElement as k,setAttribute as y}from"@fluixi/dom";import{createContext as E,useContext as we}from"@fluixi/reactive/signal";import{get as xr}from"@fluixi/utils/object";import{deepEqual as vr}from"@fluixi/utils/compare";import{createRouter as wt,createBrowserHistory as Rt,matchRoutes as br,matchPath as Sr}from"@fluixi/router";import{createMemoryHistory as Rr,createBrowserHistory as Ar,matchRoutes as Or,matchPath as kr}from"@fluixi/router";import{createResource as er,createSignal as Ct}from"@fluixi/reactive/signal";var xt=new Map;function Tt(){xt.clear()}function vt(){if(typeof window>"u")return;let e=document.getElementById("__FLUIXI_HYDRATION__");e&&e.remove();let t=document.createTreeWalker(document.body,NodeFilter.SHOW_COMMENT,null),n=[],r;for(;r=t.nextNode();){let o=r,i=o.nodeValue||"";(i.startsWith("#")||i.startsWith("/"))&&n.push(o)}n.forEach(o=>o.remove()),Tt()}typeof window<"u"&&window.addEventListener("load",()=>{setTimeout(vt,100)});var[or,sr]=Ct(0);var bt=h(),ir=bt.Provider;import{runWithOwner as Dr}from"@fluixi/reactive/signal";var z=E(),At=E(),Ot=E(),kt=E();function Et(e,t,n){let r,o=e.route.data;if(typeof o=="function"){let u=!1;Se(()=>{u=!0});let d=Pt(),[b]=St(()=>o({params:n.params,location:n.location},d,()=>u));r=b}let i=()=>kt.Provider({value:r,get children(){return Ot.Provider({value:e.params,get children(){return At.Provider({value:{depth:t,...n},get children(){return Pe(e.component,{})}})}})}});if(!r)return i();let s=r,c=()=>s.loading,[a,l]=H(V(()=>!c()));return U(()=>l(!c())),T(()=>a()?i():null)}function Lt(e){let t=e.depth+1,[n,r]=H(V(()=>e.matched()[t]?.component));return U(()=>{let o=e.matched()[t]?.component;r(()=>o)}),T(()=>{if(!n())return e.notFound?e.notFound():null;let i=V(()=>e.matched())[t];return Et(i,t,{matched:e.matched,params:e.params,location:e.location})})}function Mt(e){return e==null?Dt():typeof e=="function"?Pe(e,{}):e}function Dt(){let e=k("div");y(e,"class","fx-not-found"),y(e,"role","main"),y(e,"style","min-height:60vh;display:grid;place-content:center;gap:.25rem;text-align:center;font-family:system-ui,-apple-system,sans-serif");let t=k("h1");y(t,"style","margin:0;font-size:2.5rem;font-weight:700"),K(t,"404");let n=k("p");return y(n,"style","margin:0;opacity:.7"),K(n,"This page could not be found."),e.appendChild(t),e.appendChild(n),e}function W(e){let t=e.history??Rt(),n=wt({routes:e.routes,base:e.base,history:t}),[r,o]=H(n.state()),i=n.subscribe(o);Se(()=>{i(),n.destroy()});let s=T(()=>(r().match?.matched??[]).filter(u=>u.component)),c={router:n,location:T(()=>r().location),params:T(()=>r().match?.params??{})},a={depth:-1,matched:s,params:c.params,location:c.location,notFound:()=>Mt(e.notFound)},l;return z.Provider({value:c,get children(){return l??=Lt(a)}})}var It={router:{navigate:()=>{}},location:()=>({pathname:"",search:"",hash:"",query:{}}),params:()=>({})};function v(){let e=we(z);if(e)return e;if(typeof window>"u")return It;throw new Error("[router-next] useRouter must be used within <Router>")}function Ft(){let e=v().params;return T(()=>e(),{},{equals:(t,n)=>JSON.stringify(t)===JSON.stringify(n)})}function Nt(){let{location:e}=v();return new Proxy({},{get:(t,n)=>e()[n],has:(t,n)=>n in e(),ownKeys:()=>Reflect.ownKeys(e()),getOwnPropertyDescriptor:(t,n)=>Object.getOwnPropertyDescriptor(e(),n)})}function J(){let{router:e}=v();return(t,n)=>e.navigate(t,n)}var p=e=>typeof e=="function"?e():e;function B(e){let t=we(z),n=typeof document>"u",r=()=>t?.router.navigate(p(e.href)??"",{replace:p(e.replace)}),o=k("a");if(y(o,"href",p(e.href)??""),e.slot&&y(o,"slot",p(e.slot)),typeof o.addEventListener=="function")o.addEventListener("click",s=>{s.metaKey||s.ctrlKey||s.shiftKey||s.altKey||(s.preventDefault(),r())});else{let s=p(e.className??e.class)??"";s&&y(o,"class",s)}typeof o.addEventListener=="function"&&U(()=>{let s=p(e.href)??"";o.setAttribute("href",s);let c=p(e.className??e.class)??"",a=p(e.activeClass)??"",l=p(e.active)??t?.location().pathname===s;o.className=[c,l?a:""].filter(Boolean).join(" ")});let i=e.children;return i!=null&&K(o,i),o}import{query as ao,queryAll as co,closest as uo,addClass as lo,removeClass as fo,toggleClass as po,hasClass as yo,setAttribute as mo,getAttribute as go,removeAttribute as ho,setStyles as xo,getStyle as To,createElement as vo,removeChildren as Co,appendChildren as bo,isVisible as So,scrollIntoView as Po,getOffset as wo,delegate as Ro,waitForElement as Ao,observeIntersection as Oo,observeResize as ko}from"@fluixi/dom";import{classMap as Lo,styleMap as Mo,Island as Do,hydrateIslands as Io,mergeProps as Fo,splitProps as No}from"@fluixi/dom";import{Show as Nr,For as _r,Index as jr,Switch as $r,Match as Vr,Dynamic as Kr,ErrorBoundary as Hr,Portal as Ur}from"@fluixi/dom";import{createStore as $o,untrackStore as Vo,unwrap as Ko,Store as Ho}from"@fluixi/reactive/store";var Zt="0.0.1",en="Fluixi";var Zr={createComponent:C,onMount:P,onUnmount:w,createEffect:_t,createMemo:jt,createSignal:$t,createContext:h,createRoot:Vt,createDeferred:qt,createComputed:Kt,createRenderEffect:Ht,createSelector:Yt,onCleanup:Ut,getOwner:zt,runWithOwner:Wt,batch:Jt,untrack:Bt,useContext:x,setOwner:Xt,Router:W,Link:B,useRouter:v,useNavigate:J,read:Gt,reduce:Qt,VERSION:Zt,FRAMEWORK_NAME:en};g("fluixi element main");export{D as $component,Kr as Dynamic,Hr as ErrorBoundary,en as FRAMEWORK_NAME,_r as For,jr as Index,Do as Island,B as Link,Vr as Match,Ur as Portal,W as Router,Nr as Show,Ho as Store,R as Suspense,le as SuspenseList,$r as Switch,Zt as VERSION,lo as addClass,bo as appendChildren,Jt as batch,Lo as classMap,Ze as cleanupDelegation,mt as clientOnly,uo as closest,ge as composeProviders,C as createComponent,Kt as createComputed,it as createConsumer,h as createContext,st as createContextWithProvider,Br as createDebounce,qt as createDeferred,_t as createEffect,xe as createIsomorphicState,yt as createIsomorphicStore,jt as createMemo,Ce as createMemoryStorage,$ as createProvider,Ht as createRenderEffect,Wr as createResource,Vt as createRoot,Yt as createSelector,$t as createSignal,$o as createStore,ht as createTheme,Zr as default,Ro as delegate,vo as domCreateElement,O as env,go as getAttribute,wo as getOffset,zt as getOwner,To as getStyle,yo as hasClass,Io as hydrateIslands,Qe as initDelegation,ve as isClient,ue as isJSXElement,ae as isLitResult,ie as isNode,Ge as isRenderable,Te as isServer,So as isVisible,_ as lazy,Fo as mergeProps,Oo as observeIntersection,ko as observeResize,Ut as onCleanup,P as onMount,w as onUnmount,Ye as portal,ao as query,co as queryAll,Gt as read,Qt as reduce,ho as removeAttribute,Co as removeChildren,fo as removeClass,ye as render,Wt as runWithOwner,Po as scrollIntoView,mo as setAttribute,Xt as setOwner,xo as setStyles,No as splitProps,A as storage,Mo as styleMap,po as toggleClass,Bt as untrack,Vo as untrackStore,Ko as unwrap,re as useCallback,x as useContext,I as useEffect,ne as useEventListener,Nt as useLocation,Z as useMemo,J as useNavigate,Ft as useParams,at as useProvide,te as useReducer,ee as useRef,v as useRouter,Ao as waitForElement};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lit.d.ts","sourceRoot":"","sources":["../../../../src/lib/directives/lit.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// import { Accessor, createEffect } from '@fluixi/reactive';
|
|
2
|
+
export {};
|
|
3
|
+
// import { Directive, directive, PartInfo, PartType } from 'lit/directive.js';
|
|
4
|
+
// class ReadDirective extends Directive {
|
|
5
|
+
// private dispose?: () => void;
|
|
6
|
+
// constructor(partInfo: PartInfo) {
|
|
7
|
+
// super(partInfo);
|
|
8
|
+
// if (partInfo.type !== PartType.CHILD) {
|
|
9
|
+
// throw new Error('read() can only be used in text bindings');
|
|
10
|
+
// }
|
|
11
|
+
// }
|
|
12
|
+
// render(_getter: () => unknown) {
|
|
13
|
+
// // Initial render only
|
|
14
|
+
// return '';
|
|
15
|
+
// }
|
|
16
|
+
// override update(_part: any, [getter]: [() => unknown]) {
|
|
17
|
+
// if (!this.dispose) {
|
|
18
|
+
// // bridge to YOUR fine-grained system
|
|
19
|
+
// this.dispose = createEffect(() => {
|
|
20
|
+
// _part.setValue(getter());
|
|
21
|
+
// _part.commit();
|
|
22
|
+
// });
|
|
23
|
+
// }
|
|
24
|
+
// return noChange;
|
|
25
|
+
// }
|
|
26
|
+
// disconnected() {
|
|
27
|
+
// this.dispose?.();
|
|
28
|
+
// this.dispose = undefined;
|
|
29
|
+
// }
|
|
30
|
+
// }
|
|
31
|
+
// export const read = directive(ReadDirective);
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var r=Object.defineProperty;var c=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var a=Object.prototype.hasOwnProperty;var g=(n,e)=>{for(var t in e)r(n,t,{get:e[t],enumerable:!0})},s=(n,e,t,d)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of f(e))!a.call(n,o)&&o!==t&&r(n,o,{get:()=>e[o],enumerable:!(d=c(e,o))||d.enumerable});return n};var p=n=>s(r({},"__esModule",{value:!0}),n);var w={};g(w,{clientOnly:()=>T,createMemoryStorage:()=>l,env:()=>y,isClient:()=>u,isServer:()=>i,storage:()=>m});module.exports=p(w);var i=typeof document>"u",u=!i;function l(){let n=new Map;return{getItem:e=>n.has(e)?n.get(e):null,setItem:(e,t)=>{n.set(e,String(t))},removeItem:e=>{n.delete(e)},clear:()=>n.clear(),key:e=>Array.from(n.keys())[e]??null,get length(){return n.size}}}var m=typeof localStorage<"u"?localStorage:l(),y={get window(){return typeof window<"u"?window:void 0},get document(){return typeof document<"u"?document:void 0}};function T(n,e){return u?n():e}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal environment utilities — the same imports work on the server and the
|
|
3
|
+
* client, so app code never reaches for raw globals (`localStorage`, `window`,
|
|
4
|
+
* `document`) that don't exist under SSR and crash at module-eval time. This
|
|
5
|
+
* replaces hand-rolled `globalThis.localStorage = …` shims and scattered
|
|
6
|
+
* `typeof window === 'undefined'` guards.
|
|
7
|
+
*/
|
|
8
|
+
/** True when there is no DOM document — i.e. we're rendering on the server. */
|
|
9
|
+
export declare const isServer: boolean;
|
|
10
|
+
/** True in a browser (or jsdom) environment. */
|
|
11
|
+
export declare const isClient: boolean;
|
|
12
|
+
/** A Map-backed in-memory implementation of the Web Storage API (server/tests). */
|
|
13
|
+
export declare function createMemoryStorage(): Storage;
|
|
14
|
+
/**
|
|
15
|
+
* Universal key/value storage with the exact `localStorage` API. On the client it
|
|
16
|
+
* IS `localStorage`; on the server (no DOM) it is an ephemeral in-memory store, so
|
|
17
|
+
* a module that reads `storage.getItem(...)` at import time never crashes under SSR.
|
|
18
|
+
* Server reads/writes do not persist across requests (a later pass can back them with
|
|
19
|
+
* the request cookie for true per-user server state).
|
|
20
|
+
*/
|
|
21
|
+
export declare const storage: Storage;
|
|
22
|
+
/**
|
|
23
|
+
* Lazy, typed accessors for the browser globals. They return the real object on the
|
|
24
|
+
* client and `undefined` on the server, so `env.window?.matchMedia(...)` is safe and
|
|
25
|
+
* typed everywhere. Deliberately NOT faked on the server: a stub `location`/`innerWidth`
|
|
26
|
+
* would return wrong values and cause hydration mismatches — guard with `?.` instead.
|
|
27
|
+
*/
|
|
28
|
+
export declare const env: {
|
|
29
|
+
readonly window: (Window & typeof globalThis) | undefined;
|
|
30
|
+
readonly document: Document | undefined;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Run `fn` only on the client; on the server return `fallback` (or `undefined`).
|
|
34
|
+
* For values that genuinely don't exist server-side, e.g.
|
|
35
|
+
* `clientOnly(() => window.innerWidth, 0)`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function clientOnly<T>(fn: () => T): T | undefined;
|
|
38
|
+
export declare function clientOnly<T>(fn: () => T, fallback: T): T;
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/env/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,QAAQ,EAAE,OAAyC,CAAC;AACjE,gDAAgD;AAChD,eAAO,MAAM,QAAQ,EAAE,OAAmB,CAAC;AAE3C,mFAAmF;AACnF,wBAAgB,mBAAmB,IAAI,OAAO,CAY7C;AAED;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,EAAE,OACsD,CAAC;AAE7E;;;;;GAKG;AACH,eAAO,MAAM,GAAG;qBACA,CAAC,MAAM,GAAG,OAAO,UAAU,CAAC,GAAG,SAAS;uBAGtC,QAAQ,GAAG,SAAS;CAGrC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;AAC1D,wBAAgB,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal environment utilities — the same imports work on the server and the
|
|
3
|
+
* client, so app code never reaches for raw globals (`localStorage`, `window`,
|
|
4
|
+
* `document`) that don't exist under SSR and crash at module-eval time. This
|
|
5
|
+
* replaces hand-rolled `globalThis.localStorage = …` shims and scattered
|
|
6
|
+
* `typeof window === 'undefined'` guards.
|
|
7
|
+
*/
|
|
8
|
+
/** True when there is no DOM document — i.e. we're rendering on the server. */
|
|
9
|
+
export const isServer = typeof document === 'undefined';
|
|
10
|
+
/** True in a browser (or jsdom) environment. */
|
|
11
|
+
export const isClient = !isServer;
|
|
12
|
+
/** A Map-backed in-memory implementation of the Web Storage API (server/tests). */
|
|
13
|
+
export function createMemoryStorage() {
|
|
14
|
+
const mem = new Map();
|
|
15
|
+
return {
|
|
16
|
+
getItem: (k) => (mem.has(k) ? mem.get(k) : null),
|
|
17
|
+
setItem: (k, v) => void mem.set(k, String(v)),
|
|
18
|
+
removeItem: (k) => void mem.delete(k),
|
|
19
|
+
clear: () => mem.clear(),
|
|
20
|
+
key: (i) => Array.from(mem.keys())[i] ?? null,
|
|
21
|
+
get length() {
|
|
22
|
+
return mem.size;
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Universal key/value storage with the exact `localStorage` API. On the client it
|
|
28
|
+
* IS `localStorage`; on the server (no DOM) it is an ephemeral in-memory store, so
|
|
29
|
+
* a module that reads `storage.getItem(...)` at import time never crashes under SSR.
|
|
30
|
+
* Server reads/writes do not persist across requests (a later pass can back them with
|
|
31
|
+
* the request cookie for true per-user server state).
|
|
32
|
+
*/
|
|
33
|
+
export const storage = typeof localStorage !== 'undefined' ? localStorage : createMemoryStorage();
|
|
34
|
+
/**
|
|
35
|
+
* Lazy, typed accessors for the browser globals. They return the real object on the
|
|
36
|
+
* client and `undefined` on the server, so `env.window?.matchMedia(...)` is safe and
|
|
37
|
+
* typed everywhere. Deliberately NOT faked on the server: a stub `location`/`innerWidth`
|
|
38
|
+
* would return wrong values and cause hydration mismatches — guard with `?.` instead.
|
|
39
|
+
*/
|
|
40
|
+
export const env = {
|
|
41
|
+
get window() {
|
|
42
|
+
return typeof window !== 'undefined' ? window : undefined;
|
|
43
|
+
},
|
|
44
|
+
get document() {
|
|
45
|
+
return typeof document !== 'undefined' ? document : undefined;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
export function clientOnly(fn, fallback) {
|
|
49
|
+
return isClient ? fn() : fallback;
|
|
50
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var o=typeof document>"u",r=!o;function d(){let n=new Map;return{getItem:e=>n.has(e)?n.get(e):null,setItem:(e,t)=>{n.set(e,String(t))},removeItem:e=>{n.delete(e)},clear:()=>n.clear(),key:e=>Array.from(n.keys())[e]??null,get length(){return n.size}}}var i=typeof localStorage<"u"?localStorage:d(),u={get window(){return typeof window<"u"?window:void 0},get document(){return typeof document<"u"?document:void 0}};function l(n,e){return r?n():e}export{l as clientOnly,d as createMemoryStorage,u as env,r as isClient,o as isServer,i as storage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var L=Object.defineProperty;var K=Object.getOwnPropertyDescriptor;var I=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var k=(e,o)=>{for(var l in o)L(e,l,{get:o[l],enumerable:!0})},v=(e,o,l,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of I(o))!R.call(e,s)&&s!==l&&L(e,s,{get:()=>o[s],enumerable:!(i=K(o,s))||i.enumerable});return e};var C=e=>v(L({},"__esModule",{value:!0}),e);var h={};k(h,{createI18n:()=>F,detectLocale:()=>S});module.exports=C(h);var M=require("@fluixi/reactive/signal"),f=require("@fluixi/dom"),y="__i18n:locale",x=typeof document>"u";function _(){if(x)return;let e=(0,f.getServerData)();return e?e[y]:void 0}function D(e){if(!(typeof document>"u"))try{document.cookie=`locale=${e};path=/;max-age=31536000;samesite=lax`}catch{}}function F(e){let o=e.persist??D,[l,i]=(0,M.createSignal)(_()??e.locale),s=()=>x?(0,f.getRequestContext)():void 0;function a(){let n=s();return n?n.__i18nLocale??e.locale:l()}function d(n){let t=s();if(t){t.__i18nLocale=n,t.data?.set?.(y,n);return}i(()=>n),o(n)}function p(n,t){let c=e.messages[n];if(c==null)return;let r=c[t];if(r!==void 0)return r;let u=c;for(let g of t.split(".")){if(u==null||typeof u!="object")return;u=u[g]}return u}function m(n,t){return t?n.replace(/\{(\w+)\}/g,(c,r)=>r in t?String(t[r]):`{${r}}`):n}function w(n,t){let c=a(),r=p(c,n);if(r===void 0&&c!==e.locale&&(r=p(e.locale,n)),r===void 0)return n;if(typeof r!="string"){let u=Number(t?.count??0),g=new Intl.PluralRules(c).select(u),b=r[g]??r.other??Object.values(r)[0]??"";return m(b,t)}return m(r,t)}return{t:w,n:(n,t)=>new Intl.NumberFormat(a(),t).format(n),d:(n,t)=>new Intl.DateTimeFormat(a(),t).format(n),locale:a,setLocale:d,locales:e.locales}}function S(e,o){if(!e)return;let l=e.split(",").map(i=>{let[s,a]=i.trim().split(";q=");return{tag:s.toLowerCase(),q:a?parseFloat(a):1}}).sort((i,s)=>s.q-i.q);for(let{tag:i}of l){let s=i.split("-")[0],a=o.find(d=>d.toLowerCase()===i||d.toLowerCase()===s);if(a)return a}}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fluixi/core/i18n — built-in, reactive, SSR-correct internationalization.
|
|
3
|
+
*
|
|
4
|
+
* Three things make this distinct:
|
|
5
|
+
*
|
|
6
|
+
* 1. **SSR request-scoped locale.** The active locale is per-request on the server (kept in the
|
|
7
|
+
* RequestContext) and a reactive module signal on the client. Two concurrent SSR requests in
|
|
8
|
+
* different languages never bleed, and the server-resolved locale is seeded to the client
|
|
9
|
+
* (no flash, no hydration mismatch).
|
|
10
|
+
*
|
|
11
|
+
* 2. **No reactive-owner-context dependency.** `t()` reads the locale from the request context /
|
|
12
|
+
* module signal — NOT `useContext` — so it resolves in lazy routes, server functions, loaders,
|
|
13
|
+
* anywhere. (This is precisely why it sidesteps the classic "useLocale() is undefined under
|
|
14
|
+
* SSR on a lazy route" failure — there's no provider owner-chain to lose.)
|
|
15
|
+
*
|
|
16
|
+
* 3. **Platform-native formatting.** Pluralization via `Intl.PluralRules`, numbers/dates via
|
|
17
|
+
* `Intl.NumberFormat`/`Intl.DateTimeFormat` — correct CLDR rules, zero dependencies.
|
|
18
|
+
*
|
|
19
|
+
* const i18n = createI18n({ locale: 'en', locales: ['en', 'fr'] as const, messages: { en, fr } });
|
|
20
|
+
* export const { t, n, d, locale, setLocale } = i18n;
|
|
21
|
+
*
|
|
22
|
+
* t('welcome', { name: 'Ada' }) // "Welcome, Ada"
|
|
23
|
+
* t('cart.items', { count: 3 }) // plural branch via Intl.PluralRules
|
|
24
|
+
* n(1234.5); d(new Date()); // locale-aware number/date
|
|
25
|
+
* setLocale('fr'); // reactive — every t() re-evaluates
|
|
26
|
+
*/
|
|
27
|
+
import { type Accessor } from '@fluixi/reactive/signal';
|
|
28
|
+
/** A leaf message: a plain string, or a plural map keyed by CLDR category (`one`/`other`/…). */
|
|
29
|
+
export type MessageValue = string | {
|
|
30
|
+
readonly [pluralCategory: string]: string;
|
|
31
|
+
};
|
|
32
|
+
/** A (possibly nested) message tree. */
|
|
33
|
+
export interface Messages {
|
|
34
|
+
readonly [key: string]: MessageValue | Messages;
|
|
35
|
+
}
|
|
36
|
+
/** CLDR plural categories. An object keyed *only* by these is a plural leaf, not a subtree. */
|
|
37
|
+
type PluralCategory = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other';
|
|
38
|
+
/**
|
|
39
|
+
* The union of every valid translation key in `M` — `t()` autocompletes these and flags typos.
|
|
40
|
+
* Flat keys (`'welcome'`, `'nav.dashboard'`), nested trees (`'cart.items'`, `'nested.deep.key'`),
|
|
41
|
+
* and plural maps (`{ one, other }` → a leaf) all work. Only *leaf* paths are emitted, never the
|
|
42
|
+
* intermediate branch (`'nav'`, `'cart'`). Falls open to `string` when `M` is just `Messages`.
|
|
43
|
+
*
|
|
44
|
+
* A subtree and a plural map are both `Record<string, string>` structurally, so the plural leaf is
|
|
45
|
+
* detected by its keys being CLDR categories — not by "all children are strings" (which wrongly
|
|
46
|
+
* truncated `nav: { dashboard, settings }` to `'nav'`).
|
|
47
|
+
*/
|
|
48
|
+
export type MessageKey<M> = M extends object ? {
|
|
49
|
+
[K in keyof M & string]: M[K] extends string ? K : [keyof M[K]] extends [PluralCategory] ? K : M[K] extends object ? `${K}.${MessageKey<M[K]>}` : K;
|
|
50
|
+
}[keyof M & string] : string;
|
|
51
|
+
export interface I18nConfig<L extends string, M extends Record<L, Messages> = Record<L, Messages>> {
|
|
52
|
+
/** Default / fallback locale. */
|
|
53
|
+
locale: L;
|
|
54
|
+
/** Supported locales. */
|
|
55
|
+
locales: readonly L[];
|
|
56
|
+
/** Messages per locale (nested; a leaf is a string or a plural map). Keys are inferred for `t`. */
|
|
57
|
+
messages: M;
|
|
58
|
+
/** Persist the chosen locale on the client. Default: a year-long `locale` cookie. */
|
|
59
|
+
persist?: (locale: L) => void;
|
|
60
|
+
}
|
|
61
|
+
export interface I18n<L extends string, K extends string = string> {
|
|
62
|
+
/** Translate a key (autocompleted from your messages) with optional params; `count` pluralizes. */
|
|
63
|
+
t: (key: K | (string & {}), params?: Record<string, unknown>) => string;
|
|
64
|
+
/** Format a number for the active locale (`Intl.NumberFormat`). */
|
|
65
|
+
n: (value: number, options?: Intl.NumberFormatOptions) => string;
|
|
66
|
+
/** Format a date for the active locale (`Intl.DateTimeFormat`). */
|
|
67
|
+
d: (value: Date | number, options?: Intl.DateTimeFormatOptions) => string;
|
|
68
|
+
/** The active locale — reactive on the client, per-request on the server. */
|
|
69
|
+
locale: Accessor<L>;
|
|
70
|
+
/** Switch the active locale (client: reactive + persisted; server: this request only). */
|
|
71
|
+
setLocale: (locale: L) => void;
|
|
72
|
+
/** Supported locales. */
|
|
73
|
+
locales: readonly L[];
|
|
74
|
+
}
|
|
75
|
+
export declare function createI18n<L extends string, const M extends Record<L, Messages>>(config: I18nConfig<L, M>): I18n<L, MessageKey<M[keyof M]>>;
|
|
76
|
+
/** Pick the best supported locale from an `Accept-Language` header, else `undefined`. */
|
|
77
|
+
export declare function detectLocale<L extends string>(acceptLanguage: string | null | undefined, locales: readonly L[]): L | undefined;
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/i18n/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGtE,gGAAgG;AAChG,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG;IAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC;AAClF,wCAAwC;AACxC,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,QAAQ,CAAC;CACjD;AAED,+FAA+F;AAC/F,KAAK,cAAc,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;AAExE;;;;;;;;;GASG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GACxC;KACG,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GACxC,CAAC,GACD,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,GACnC,CAAC,GACD,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GACjB,GAAG,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAC1B,CAAC;CACV,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GACnB,MAAM,CAAC;AAEX,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC;IAC/F,iCAAiC;IACjC,MAAM,EAAE,CAAC,CAAC;IACV,yBAAyB;IACzB,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;IACtB,mGAAmG;IACnG,QAAQ,EAAE,CAAC,CAAC;IACZ,qFAAqF;IACrF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,IAAI,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM;IAC/D,mGAAmG;IACnG,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;IACxE,mEAAmE;IACnE,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,KAAK,MAAM,CAAC;IACjE,mEAAmE;IACnE,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,qBAAqB,KAAK,MAAM,CAAC;IAC1E,6EAA6E;IAC7E,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpB,0FAA0F;IAC1F,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC;IAC/B,yBAAyB;IACzB,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;CACvB;AAoBD,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,EAC9E,MAAM,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,GACvB,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAiEjC;AAED,yFAAyF;AACzF,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAC3C,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACzC,OAAO,EAAE,SAAS,CAAC,EAAE,GACpB,CAAC,GAAG,SAAS,CAef"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fluixi/core/i18n — built-in, reactive, SSR-correct internationalization.
|
|
3
|
+
*
|
|
4
|
+
* Three things make this distinct:
|
|
5
|
+
*
|
|
6
|
+
* 1. **SSR request-scoped locale.** The active locale is per-request on the server (kept in the
|
|
7
|
+
* RequestContext) and a reactive module signal on the client. Two concurrent SSR requests in
|
|
8
|
+
* different languages never bleed, and the server-resolved locale is seeded to the client
|
|
9
|
+
* (no flash, no hydration mismatch).
|
|
10
|
+
*
|
|
11
|
+
* 2. **No reactive-owner-context dependency.** `t()` reads the locale from the request context /
|
|
12
|
+
* module signal — NOT `useContext` — so it resolves in lazy routes, server functions, loaders,
|
|
13
|
+
* anywhere. (This is precisely why it sidesteps the classic "useLocale() is undefined under
|
|
14
|
+
* SSR on a lazy route" failure — there's no provider owner-chain to lose.)
|
|
15
|
+
*
|
|
16
|
+
* 3. **Platform-native formatting.** Pluralization via `Intl.PluralRules`, numbers/dates via
|
|
17
|
+
* `Intl.NumberFormat`/`Intl.DateTimeFormat` — correct CLDR rules, zero dependencies.
|
|
18
|
+
*
|
|
19
|
+
* const i18n = createI18n({ locale: 'en', locales: ['en', 'fr'] as const, messages: { en, fr } });
|
|
20
|
+
* export const { t, n, d, locale, setLocale } = i18n;
|
|
21
|
+
*
|
|
22
|
+
* t('welcome', { name: 'Ada' }) // "Welcome, Ada"
|
|
23
|
+
* t('cart.items', { count: 3 }) // plural branch via Intl.PluralRules
|
|
24
|
+
* n(1234.5); d(new Date()); // locale-aware number/date
|
|
25
|
+
* setLocale('fr'); // reactive — every t() re-evaluates
|
|
26
|
+
*/
|
|
27
|
+
import { createSignal } from '@fluixi/reactive/signal';
|
|
28
|
+
import { getRequestContext, getServerData } from '@fluixi/dom';
|
|
29
|
+
const SEED_KEY = '__i18n:locale';
|
|
30
|
+
const IS_SERVER = typeof document === 'undefined';
|
|
31
|
+
function readSeed() {
|
|
32
|
+
if (IS_SERVER)
|
|
33
|
+
return undefined;
|
|
34
|
+
const data = getServerData();
|
|
35
|
+
return data ? data[SEED_KEY] : undefined;
|
|
36
|
+
}
|
|
37
|
+
function cookiePersist(locale) {
|
|
38
|
+
if (typeof document === 'undefined')
|
|
39
|
+
return;
|
|
40
|
+
try {
|
|
41
|
+
document.cookie = `locale=${locale};path=/;max-age=31536000;samesite=lax`;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
/* private mode / disabled — best effort */
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export function createI18n(config) {
|
|
48
|
+
const persist = config.persist ?? cookiePersist;
|
|
49
|
+
// Client: a reactive signal seeded from the server-resolved locale (so hydration matches).
|
|
50
|
+
const [clientLocale, setClientLocale] = createSignal(readSeed() ?? config.locale);
|
|
51
|
+
const serverCtx = () => IS_SERVER ? getRequestContext() : undefined;
|
|
52
|
+
function locale() {
|
|
53
|
+
const ctx = serverCtx();
|
|
54
|
+
if (ctx)
|
|
55
|
+
return ctx.__i18nLocale ?? config.locale; // server: per-request, no shared signal → no leak
|
|
56
|
+
return clientLocale(); // client: reactive
|
|
57
|
+
}
|
|
58
|
+
function setLocale(next) {
|
|
59
|
+
const ctx = serverCtx();
|
|
60
|
+
if (ctx) {
|
|
61
|
+
ctx.__i18nLocale = next;
|
|
62
|
+
ctx.data?.set?.(SEED_KEY, next); // serialize → client hydrates in the same language
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
setClientLocale(() => next);
|
|
66
|
+
persist(next);
|
|
67
|
+
}
|
|
68
|
+
function resolve(loc, key) {
|
|
69
|
+
const bundle = config.messages[loc];
|
|
70
|
+
if (bundle == null)
|
|
71
|
+
return undefined;
|
|
72
|
+
// Flat key first — supports dotted flat keys like `nav.dashboard` (not just nested trees).
|
|
73
|
+
const flat = bundle[key];
|
|
74
|
+
if (flat !== undefined)
|
|
75
|
+
return flat;
|
|
76
|
+
// Else walk the dot-path through a nested message tree.
|
|
77
|
+
let node = bundle;
|
|
78
|
+
for (const part of key.split('.')) {
|
|
79
|
+
if (node == null || typeof node !== 'object')
|
|
80
|
+
return undefined;
|
|
81
|
+
node = node[part];
|
|
82
|
+
}
|
|
83
|
+
return node;
|
|
84
|
+
}
|
|
85
|
+
function interpolate(str, params) {
|
|
86
|
+
if (!params)
|
|
87
|
+
return str;
|
|
88
|
+
return str.replace(/\{(\w+)\}/g, (_m, k) => (k in params ? String(params[k]) : `{${k}}`));
|
|
89
|
+
}
|
|
90
|
+
function t(key, params) {
|
|
91
|
+
const loc = locale();
|
|
92
|
+
let msg = resolve(loc, key);
|
|
93
|
+
if (msg === undefined && loc !== config.locale)
|
|
94
|
+
msg = resolve(config.locale, key); // fallback locale
|
|
95
|
+
if (msg === undefined)
|
|
96
|
+
return key; // missing → echo the key (visible, debuggable)
|
|
97
|
+
if (typeof msg !== 'string') {
|
|
98
|
+
const count = Number(params?.count ?? 0);
|
|
99
|
+
const category = new Intl.PluralRules(loc).select(count);
|
|
100
|
+
const branch = msg[category] ?? msg.other ?? Object.values(msg)[0] ?? '';
|
|
101
|
+
return interpolate(branch, params);
|
|
102
|
+
}
|
|
103
|
+
return interpolate(msg, params);
|
|
104
|
+
}
|
|
105
|
+
const n = (value, options) => new Intl.NumberFormat(locale(), options).format(value);
|
|
106
|
+
const d = (value, options) => new Intl.DateTimeFormat(locale(), options).format(value);
|
|
107
|
+
return { t, n, d, locale, setLocale, locales: config.locales };
|
|
108
|
+
}
|
|
109
|
+
/** Pick the best supported locale from an `Accept-Language` header, else `undefined`. */
|
|
110
|
+
export function detectLocale(acceptLanguage, locales) {
|
|
111
|
+
if (!acceptLanguage)
|
|
112
|
+
return undefined;
|
|
113
|
+
const ranked = acceptLanguage
|
|
114
|
+
.split(',')
|
|
115
|
+
.map((part) => {
|
|
116
|
+
const [tag, q] = part.trim().split(';q=');
|
|
117
|
+
return { tag: tag.toLowerCase(), q: q ? parseFloat(q) : 1 };
|
|
118
|
+
})
|
|
119
|
+
.sort((a, b) => b.q - a.q);
|
|
120
|
+
for (const { tag } of ranked) {
|
|
121
|
+
const base = tag.split('-')[0];
|
|
122
|
+
const hit = locales.find((l) => l.toLowerCase() === tag || l.toLowerCase() === base);
|
|
123
|
+
if (hit)
|
|
124
|
+
return hit;
|
|
125
|
+
}
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createSignal as x}from"@fluixi/reactive/signal";import{getRequestContext as w,getServerData as b}from"@fluixi/dom";var p="__i18n:locale",m=typeof document>"u";function K(){if(m)return;let t=b();return t?t[p]:void 0}function I(t){if(!(typeof document>"u"))try{document.cookie=`locale=${t};path=/;max-age=31536000;samesite=lax`}catch{}}function _(t){let u=t.persist??I,[d,o]=x(K()??t.locale),i=()=>m?w():void 0;function s(){let e=i();return e?e.__i18nLocale??t.locale:d()}function c(e){let n=i();if(n){n.__i18nLocale=e,n.data?.set?.(p,e);return}o(()=>e),u(e)}function g(e,n){let a=t.messages[e];if(a==null)return;let r=a[n];if(r!==void 0)return r;let l=a;for(let f of n.split(".")){if(l==null||typeof l!="object")return;l=l[f]}return l}function L(e,n){return n?e.replace(/\{(\w+)\}/g,(a,r)=>r in n?String(n[r]):`{${r}}`):e}function M(e,n){let a=s(),r=g(a,e);if(r===void 0&&a!==t.locale&&(r=g(t.locale,e)),r===void 0)return e;if(typeof r!="string"){let l=Number(n?.count??0),f=new Intl.PluralRules(a).select(l),y=r[f]??r.other??Object.values(r)[0]??"";return L(y,n)}return L(r,n)}return{t:M,n:(e,n)=>new Intl.NumberFormat(s(),n).format(e),d:(e,n)=>new Intl.DateTimeFormat(s(),n).format(e),locale:s,setLocale:c,locales:t.locales}}function D(t,u){if(!t)return;let d=t.split(",").map(o=>{let[i,s]=o.trim().split(";q=");return{tag:i.toLowerCase(),q:s?parseFloat(s):1}}).sort((o,i)=>i.q-o.q);for(let{tag:o}of d){let i=o.split("-")[0],s=u.find(c=>c.toLowerCase()===o||c.toLowerCase()===i);if(s)return s}}export{_ as createI18n,D as detectLocale};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var Se=Object.create;var D=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var ge=Object.getOwnPropertyNames;var Pe=Object.getPrototypeOf,we=Object.prototype.hasOwnProperty;var Ee=(e,t)=>{for(var n in t)D(e,n,{get:t[n],enumerable:!0})},j=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of ge(t))!we.call(e,i)&&i!==n&&D(e,i,{get:()=>t[i],enumerable:!(o=be(t,i))||o.enumerable});return e},oe=(e,t,n)=>(j(e,t,"default"),n&&j(n,t,"default")),ke=(e,t,n)=>(n=e!=null?Se(Pe(e)):{},j(t||!e||!e.__esModule?D(n,"default",{value:e,enumerable:!0}):n,e)),Re=e=>j(D({},"__esModule",{value:!0}),e);var $e={};Ee($e,{$component:()=>$,DEV:()=>w,Dynamic:()=>f.Dynamic,ErrorBoundary:()=>f.ErrorBoundary,FRAMEWORK_NAME:()=>te,For:()=>f.For,Fragment:()=>m.Fragment,Index:()=>f.Index,Match:()=>f.Match,Portal:()=>f.Portal,Show:()=>f.Show,Store:()=>P.Store,Suspense:()=>M,Switch:()=>f.Switch,VERSION:()=>ee,addClass:()=>a.addClass,batch:()=>s.batch,classMap:()=>W.classMap,cleanupDelegation:()=>fe,composeProviders:()=>Q,createComponent:()=>S,createComputed:()=>s.createComputed,createConsumer:()=>xe,createContext:()=>F,createContextWithProvider:()=>me,createDebounce:()=>K.createDebounce,createDeferred:()=>s.createDeferred,createEffect:()=>s.createEffect,createIsomorphicState:()=>he,createMemo:()=>s.createMemo,createProvider:()=>N,createRenderEffect:()=>s.createRenderEffect,createResource:()=>s.createResource,createRoot:()=>s.createRoot,createSelector:()=>K.createSelector,createSignal:()=>s.createSignal,createStore:()=>P.createStore,default:()=>Ue,delegateEvents:()=>a.delegateEvents,devOnly:()=>Y,getFrameworkInfo:()=>Te,getOwner:()=>s.getOwner,getSharedConfig:()=>B,hydrate:()=>a.hydrate,initDelegation:()=>de,insert:()=>a.insert,isDOMNode:()=>a.isDOMNode,isDev:()=>H,isLitTemplateResult:()=>a.isLitTemplateResult,isRenderable:()=>ue,jsx:()=>m.jsx,jsxs:()=>m.jsxs,lazy:()=>q,onCleanup:()=>s.onCleanup,onMount:()=>E,onUnmount:()=>k,portal:()=>ce,read:()=>V.readSignal,reduce:()=>V.reduceSignal,removeClass:()=>a.removeClass,render:()=>I,runWithOwner:()=>s.runWithOwner,setAttribute:()=>a.setAttribute,setOwner:()=>s.setOwner,setProperty:()=>a.setProperty,spread:()=>a.spread,styleMap:()=>W.styleMap,toggleClass:()=>a.toggleClass,untrack:()=>s.untrack,untrackStore:()=>P.untrackStore,useCallback:()=>A,useContext:()=>g,useEffect:()=>b,useEventListener:()=>_,useMemo:()=>R,useProvide:()=>ve,useReducer:()=>L,useRef:()=>O});module.exports=Re($e);var s=require("@fluixi/reactive/signal"),K=require("@fluixi/reactive/signal"),V=require("@fluixi/reactive/operators"),P=require("@fluixi/reactive/store");var ae=require("@fluixi/reactive/signal"),x=require("@fluixi/dom");var U=require("@fluixi/dom"),r=require("@fluixi/reactive/signal"),Oe={context:null,owner:null};function B(){return Oe}var w=typeof process<"u"&&!1,X=Symbol.for("fluixi-lifecycle");function re(){let e=(0,r.getOwner)();if(!e)return null;if(!e[X]){let t={mounts:[],effects:[],scheduled:!1};e[X]=t}return e[X]}function se(e){if(e.scheduled)return;e.scheduled=!0;let t=(0,r.getOwner)();queueMicrotask(()=>{(0,r.runWithOwner)(t,()=>{for(let n of e.mounts)try{let o=n();typeof o=="function"&&(0,r.onCleanup)(o)}catch(o){console.error("Error in onMount callback:",o)}for(let n of e.effects){let o;(0,r.createEffect)(()=>{o&&o(),o=n()}),(0,r.onCleanup)(()=>{o&&o()})}e.mounts=[],e.effects=[]})})}function T(e){(0,U.registerCreateComponent)(S)}function S(e,t){return $(e,t)}function $(e,t){let n=typeof e=="function"?(0,r.untrack)(()=>e(t)):e;if(n!=null&&(typeof n=="function"||typeof n=="object")&&!(0,r.isSignal)(n)){try{n.$name=e.name}catch{}return(0,U.asComponent)(n)}return n}function E(e,t=!0){let n=re();if(n){if(!t){n.scheduled||e();return}n.mounts.push(e),se(n)}else{if(!t){e();return}(0,r.createEffect)(()=>{let o=(0,r.untrack)(e);typeof o=="function"&&(0,r.onCleanup)(o)})}}function k(e){(0,r.onCleanup)(e)}function b(e){let t=re();if(t)t.effects.push(e),se(t);else{let n;(0,r.createEffect)(()=>{n&&n(),n=e()}),(0,r.onCleanup)(()=>{n&&n()})}}function R(e){return(0,r.createMemo)(e)}function O(e){let t={current:e};return(0,r.onCleanup)(()=>{t.current=null}),t}function L(e,t){let[n,o]=(0,r.createSignal)(t);return[n,u=>{o(e(n(),u))}]}function _(e,t,n,o){b(()=>{let i=e&&"current"in e?e.current:e;if(i)return i.addEventListener(t,n,o),()=>{i.removeEventListener(t,n,o)}})}function A(e){return e}function H(){return w}function Y(e){w&&e()}var c=require("@fluixi/reactive/signal"),C=require("@fluixi/dom");function ie(e){return!!(e&&typeof e=="object"&&typeof e.then=="function"||e instanceof Promise)}var Le=(0,c.createContext)();function M(e){return(0,C.createComponent)(_e,e)}function _e(e){let t=(0,c.createSuspenseBoundary)(),n=(0,c.useContext)(Le),o=n?n.register(t.inFallback):void 0;function i(d){return d==null||typeof d=="boolean"?null:typeof d=="function"&&(0,C.isComponent)(d)&&!(0,c.isSignal)(d)?d():d}let u=(0,C.runWithoutHydration)(()=>i(e.fallback??null)),y=(0,c.provideSuspense)(t,()=>e.children);(0,c.provideSuspense)(t,()=>{(0,c.createRenderEffect)(()=>{let d=y;if(Array.isArray(d))for(let J of d)typeof J=="function"&&(0,c.isSignal)(J)&&J();else typeof d=="function"&&(0,c.isSignal)(d)&&d()})});let[v,l]=(0,c.createSignal)(void 0),ne=ie(y);return ne&&(t.increment(),y.then(d=>{l(()=>d),t.decrement()},()=>t.decrement())),(0,c.createMemo)(()=>(o?o.showFallback():t.inFallback())?u:ne?v():y)}(0,C.asSuspense)(M);Object.defineProperty(M,"__suspense",{value:!0,enumerable:!0});var h=require("@fluixi/reactive/signal");function q(e,t){let n,o,i;function u(){return o||(o=e().then(v=>n=v.default)),o}t?.preload&&u();let y=(v=>{if(n){let l=n;return(0,h.untrack)(()=>l(v))}if(!i){let[l]=(0,h.createResource)(()=>u());if(i=l,l.error)throw l.error}return(0,h.createMemo)(()=>{let l=i();return l?(0,h.untrack)(()=>l(v)):void 0},void 0,{name:"lazy"})});return y.preload=()=>u().then(()=>{}),y.$lazy=!0,y.loader=e,y}typeof window<"u"&&import("lit").then(e=>(0,x.registerLitRender)(e.render));var G=typeof window>"u";function I(e,t,n={}){if(T("render"),(0,x.delegateEvents)(["click","input","change","submit"]),G)throw new Error("render() is for client-side only. Use renderToString() on server.");if(!t)throw new Error("Container element is required");let o;return(0,ae.createRoot)(i=>{o=i;let u=typeof e=="function"?e():e;t.textContent="",t.setAttribute("fluixi-js","v1"),(0,x.insert)(t,()=>u)}),()=>{o&&(o(),o=void 0)}}function Ae(e){return e&&typeof e=="object"&&(e._$litType$!==void 0||e._$litDirective$!==void 0)}function ce(e,t,n={}){let o=document.createElement("div");o.setAttribute("data-portal","true"),t.appendChild(o);let i=I(e,o,n);return()=>{i(),t.contains(o)&&t.removeChild(o)}}function ue(e){return!!(e==null||typeof e=="function"||(0,x.isDOMNode)(e)||Ae(e)||Array.isArray(e)||typeof e=="string"||typeof e=="number"||typeof e=="boolean")}function de(){G||(0,x.delegateEvents)(["click","input","change","submit"])}function fe(){}var le=require("@fluixi/dom"),z=require("@fluixi/reactive/signal"),ye=require("@fluixi/reactive/signal");T("index");var pe=!1;function Me(){pe||(pe=!0,!(typeof process<"u")&&console.warn("[fluixi] createProvider({ context, value, children }) reads `children` eagerly: the object literal materialises `children` BEFORE the context is stamped, so a routed <Outlet/> that has siblings inside the provider renders detached and its descendants see no context under SSR. Use the lazy form instead:\n createProvider(Context, value, props) // children stays a getter\n // or JSX: <Context.Provider value={…}>{props.children}</Context.Provider>"))}function N(e,t,n){let o=!!e?.Provider,i=o?e:e.context,u=o?t:e.value,y=o?!1:e.debug??!1;o||Me();let v=typeof u=="function"?u():u,l=o?n:e;return i.Provider({value:v,get children(){return l?.children},debug:y})}function me(e){let t=F(e);return[t,o=>N(t,o.value,o)]}function Q(e,t){if(e.length===0)return(0,ye.readChildren)(()=>t);let[n,o]=e[0],i=e.slice(1);return N(n,o,{get children(){return Q(i,t)}})}function xe(e){return t=>{let n=g(e);return t.children(n)}}function ve(e,t){let n=g(e);return n===e.defaultValue?t():n}function F(e){let t=(0,z.createContext)(e),n=o=>(o.debug,t.Provider({value:o.value,get children(){return o.children},debug:o.debug}));return typeof Symbol<"u"&&Symbol.for&&(n.$$typeof=Symbol.for("react.provider")),n.$$typeof=Symbol.for("react.provider"),{id:t.id,Provider:(0,le.asProvider)(n),defaultValue:e}}function g(e){let t=(0,z.useContext)(e);return t!==void 0?t:e.defaultValue}var Z=require("@fluixi/reactive/signal"),Ce=require("@fluixi/dom"),Ie="__fluixi_iso_states__",Fe="__iso:";function je(){return globalThis[Ie]??=new Map}function De(e){if(typeof window>"u")return;let t=(0,Ce.getServerData)();return t?t[Fe+e]:void 0}function he(e,t){let n=De(e),o=n!==void 0?n:typeof window<"u"&&t.client?t.client():t.fallback,[i,u]=(0,Z.createSignal)(o);return je().set(e,{server:t.server,set:u}),{value:i,set:u,key:e}}var W=require("@fluixi/dom");var f=require("@fluixi/dom");var a=require("@fluixi/dom");var m={};oe(m,require("@fluixi/jsx/jsx-runtime"));var p=require("@fluixi/reactive/signal");var ee="0.0.1",te="Fluixi";function Te(){return{name:te,version:ee,features:{ssr:!0,hydration:!0,jsx:!0,litHtml:!0,signals:!0,fineGrained:!0,lazy:!0,hooks:!0,devMode:!0}}}var Ue={createSignal:p.createSignal,createEffect:p.createEffect,createMemo:p.createMemo,createRoot:p.createRoot,batch:p.batch,untrack:p.untrack,onCleanup:p.onCleanup,createContext:F,useContext:g,createComponent:S,onMount:E,onUnmount:k,useEffect:b,useMemo:R,useRef:O,useReducer:L,useEventListener:_,useCallback:A,render:I,VERSION:ee,FRAMEWORK_NAME:te,getFrameworkInfo:Te};T("index");
|