@vitus-labs/core 1.4.2 → 1.4.3-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/lib/index.d.ts +91 -17
  2. package/lib/index.js +123 -27
  3. package/package.json +4 -4
package/lib/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { ThemeProvider, css, styled } from "styled-components";
2
1
  import * as React from "react";
3
2
  import { ComponentType, FC, ReactNode, cloneElement, createElement } from "react";
4
3
 
@@ -137,28 +136,103 @@ type HTMLTagAttrsByTag<T extends HTMLTags> = T extends HTMLTags ? HTMLElementAtt
137
136
  //#endregion
138
137
  //#region src/config.d.ts
139
138
  /**
140
- * Singleton configuration that bridges the UI system with styled-components.
141
- * All packages reference `config.css`, `config.styled`, etc. so the styling
142
- * engine can be swapped at runtime (e.g. for React Native) via `init()`.
139
+ * Describes the shape of a CSS-in-JS engine connector.
140
+ * Packages like `@vitus-labs/connector-styler`, `@vitus-labs/connector-emotion`,
141
+ * and `@vitus-labs/connector-styled-components` export this shape.
142
+ *
143
+ * Required properties (`css`, `styled`, `provider`) are consumed by config
144
+ * across all packages. Optional properties (`keyframes`, `createGlobalStyle`,
145
+ * `useTheme`) are exposed for direct use in application code.
143
146
  */
144
- interface Internal {
145
- css: typeof css;
146
- styled: typeof styled;
147
- provider: typeof ThemeProvider;
147
+ interface CSSEngineConnector {
148
+ /** Tagged template for composable CSS fragments. */
149
+ css: (strings: TemplateStringsArray, ...values: any[]) => any;
150
+ /** Component factory: `styled(tag)`\`...\`` → React component. */
151
+ styled: ((tag: any, options?: any) => (strings: TemplateStringsArray, ...values: any[]) => any) & Record<string, any>;
152
+ /** ThemeProvider component wrapping children with a theme context. */
153
+ provider: FC<{
154
+ theme: any;
155
+ children: ReactNode;
156
+ }>;
157
+ /** Tagged template for @keyframes animations. */
158
+ keyframes?: (strings: TemplateStringsArray, ...values: any[]) => any;
159
+ /** Factory for injecting global CSS. */
160
+ createGlobalStyle?: (strings: TemplateStringsArray, ...values: any[]) => any;
161
+ /** Hook to read the current theme from the engine's context. */
162
+ useTheme?: () => any;
163
+ /** Hook that resolves CSS template → className without a component wrapper. */
164
+ useCSS?: (template: any, props?: Record<string, any>, boost?: boolean) => string;
165
+ }
166
+ interface PlatformConfig {
148
167
  component: ComponentType | HTMLTags;
149
168
  textComponent: ComponentType | HTMLTags;
150
169
  }
170
+ type InitConfig = Partial<CSSEngineConnector & PlatformConfig>;
171
+ /**
172
+ * Singleton configuration that bridges the UI system with the chosen
173
+ * CSS-in-JS engine. All packages reference `config.css`, `config.styled`,
174
+ * etc. — the engine is swapped via `init()` with a connector.
175
+ *
176
+ * The `css` and `styled` properties are **stable delegate functions** that
177
+ * can be safely destructured at module level (`const { styled, css } = config`).
178
+ * They internally read the latest engine reference set by `init()`.
179
+ *
180
+ * When destructured before `init()` is called:
181
+ * - `css` returns a thunk (function) that resolves at render time
182
+ * - `styled` returns a lazy component that creates the real component on first render
183
+ */
151
184
  declare class Configuration {
152
- css: Internal['css'];
153
- styled: Internal['styled'];
154
- ExternalProvider: Internal['provider'];
155
- component: Internal['component'];
156
- textComponent: Internal['textComponent'];
157
- constructor(props: Internal);
158
- init: (props: Partial<Internal>) => void;
185
+ _css: CSSEngineConnector['css'] | null;
186
+ _styled: CSSEngineConnector['styled'] | null;
187
+ _provider: CSSEngineConnector['provider'] | null;
188
+ _keyframes: CSSEngineConnector['keyframes'] | null;
189
+ _createGlobalStyle: CSSEngineConnector['createGlobalStyle'] | null;
190
+ _useTheme: CSSEngineConnector['useTheme'] | null;
191
+ _useCSS: CSSEngineConnector['useCSS'] | null;
192
+ component: ComponentType | HTMLTags;
193
+ textComponent: ComponentType | HTMLTags;
194
+ /**
195
+ * Stable CSS delegate. When the engine is available, delegates immediately.
196
+ * When not (module load time before init), returns a thunk that resolves
197
+ * at render time — all CSS-in-JS engines treat functions as interpolations.
198
+ */
199
+ css: (strings: TemplateStringsArray, ...values: any[]) => any;
200
+ /**
201
+ * Stable styled delegate (Proxy). Supports `styled(tag)` and `styled.div`.
202
+ * When the engine is not yet available, returns a lazy forwardRef component
203
+ * that creates the real styled component on first render.
204
+ */
205
+ styled: CSSEngineConnector['styled'];
206
+ /** The external ThemeProvider from the configured engine. */
207
+ get ExternalProvider(): CSSEngineConnector['provider'] | null;
208
+ /** Keyframes factory from the configured engine, or null. */
209
+ get keyframes(): CSSEngineConnector['keyframes'] | null;
210
+ /** Global style factory from the configured engine, or null. */
211
+ get createGlobalStyle(): CSSEngineConnector['createGlobalStyle'] | null;
212
+ /** Theme hook from the configured engine, or null. */
213
+ get useTheme(): CSSEngineConnector['useTheme'] | null;
214
+ /**
215
+ * Stable useCSS delegate. Delegates to the engine's useCSS hook at call
216
+ * time (render phase). Safe to destructure at module level — like `css`,
217
+ * reads the latest engine reference set by `init()`.
218
+ */
219
+ useCSS: (template: any, props?: Record<string, any>, boost?: boolean) => string;
220
+ constructor();
221
+ /**
222
+ * Initialize or swap the CSS-in-JS engine. Must be called before any
223
+ * component renders (typically at the app entry point).
224
+ *
225
+ * @example
226
+ * ```typescript
227
+ * import { init } from '@vitus-labs/core'
228
+ * import * as connector from '@vitus-labs/connector-styler'
229
+ * init(connector)
230
+ * ```
231
+ */
232
+ init: (props: InitConfig) => void;
159
233
  }
160
234
  declare const config: Configuration;
161
- declare const init: (props: Partial<Internal>) => void;
235
+ declare const init: (props: InitConfig) => void;
162
236
  //#endregion
163
237
  //#region src/types.d.ts
164
238
  interface Breakpoints {
@@ -247,5 +321,5 @@ declare const throttle: <T extends (...args: any[]) => any>(fn: T, wait?: number
247
321
  };
248
322
  declare const merge: <T extends Record<string, any>>(target: T, ...sources: Record<string, any>[]) => T;
249
323
  //#endregion
250
- export { type BreakpointKeys, type Breakpoints, type HTMLElementAttrs, type HTMLTagAttrsByTag, type HTMLTags, type HTMLTextTags, HTML_TAGS, HTML_TEXT_TAGS, type IsEmpty, Provider, type Render, compose, config, context, get, hoistNonReactStatics, init, isEmpty, isEqual, merge, omit, pick, render, set, throttle, useStableValue };
324
+ export { type BreakpointKeys, type Breakpoints, type CSSEngineConnector, type HTMLElementAttrs, type HTMLTagAttrsByTag, type HTMLTags, type HTMLTextTags, HTML_TAGS, HTML_TEXT_TAGS, type IsEmpty, Provider, type Render, compose, config, context, get, hoistNonReactStatics, init, isEmpty, isEqual, merge, omit, pick, render, set, throttle, useStableValue };
251
325
  //# sourceMappingURL=index2.d.ts.map
package/lib/index.js CHANGED
@@ -1,5 +1,4 @@
1
- import { ThemeProvider, css, styled } from "styled-components";
2
- import { cloneElement, createContext, createElement, isValidElement, useMemo, useRef } from "react";
1
+ import { cloneElement, createContext, createElement, forwardRef, isValidElement, useMemo, useRef } from "react";
3
2
  import { Fragment, jsx } from "react/jsx-runtime";
4
3
  import { isFragment, isMemo, isValidElementType } from "react-is";
5
4
 
@@ -15,34 +14,135 @@ const compose = (...fns) => (p) => fns.reduceRight((acc, cur) => cur(acc), p);
15
14
 
16
15
  //#endregion
17
16
  //#region src/config.ts
17
+ const notConfigured = (_name) => {
18
+ throw new Error("[@vitus-labs/core] CSS engine not configured. Call init() with a connector before rendering.\n\n import { init } from '@vitus-labs/core'\n import * as connector from '@vitus-labs/connector-styler'\n init(connector)\n");
19
+ };
20
+ const createStyledDelegate = (self) => {
21
+ const createLazy = (tag, options, strings, values) => {
22
+ let Real = null;
23
+ const Lazy = forwardRef((props, ref) => {
24
+ if (!Real) {
25
+ const engine = self._styled;
26
+ if (!engine) return notConfigured("styled");
27
+ Real = options ? engine(tag, options)(strings, ...values) : engine(tag)(strings, ...values);
28
+ }
29
+ return createElement(Real, {
30
+ ...props,
31
+ ref
32
+ });
33
+ });
34
+ Lazy.displayName = `styled(${typeof tag === "string" ? tag : tag.displayName || tag.name || "Component"})`;
35
+ return Lazy;
36
+ };
37
+ const factory = (tag, options) => {
38
+ return (strings, ...values) => {
39
+ if (self._styled) return options ? self._styled(tag, options)(strings, ...values) : self._styled(tag)(strings, ...values);
40
+ return createLazy(tag, options, strings, values);
41
+ };
42
+ };
43
+ return new Proxy(factory, { get(_target, prop) {
44
+ if (prop === "prototype" || prop === "$$typeof") return void 0;
45
+ return (strings, ...values) => {
46
+ if (self._styled) return self._styled[prop](strings, ...values);
47
+ return createLazy(prop, void 0, strings, values);
48
+ };
49
+ } });
50
+ };
51
+ /**
52
+ * Singleton configuration that bridges the UI system with the chosen
53
+ * CSS-in-JS engine. All packages reference `config.css`, `config.styled`,
54
+ * etc. — the engine is swapped via `init()` with a connector.
55
+ *
56
+ * The `css` and `styled` properties are **stable delegate functions** that
57
+ * can be safely destructured at module level (`const { styled, css } = config`).
58
+ * They internally read the latest engine reference set by `init()`.
59
+ *
60
+ * When destructured before `init()` is called:
61
+ * - `css` returns a thunk (function) that resolves at render time
62
+ * - `styled` returns a lazy component that creates the real component on first render
63
+ */
18
64
  var Configuration = class {
19
- css;
20
- styled;
21
- ExternalProvider;
65
+ _css = null;
66
+ _styled = null;
67
+ _provider = null;
68
+ _keyframes = null;
69
+ _createGlobalStyle = null;
70
+ _useTheme = null;
71
+ _useCSS = null;
22
72
  component = "div";
23
73
  textComponent = "span";
24
- constructor(props) {
25
- this.css = props.css;
26
- this.styled = props.styled;
27
- this.ExternalProvider = props.provider;
28
- this.component = props.component;
29
- this.textComponent = props.textComponent;
74
+ /**
75
+ * Stable CSS delegate. When the engine is available, delegates immediately.
76
+ * When not (module load time before init), returns a thunk that resolves
77
+ * at render time — all CSS-in-JS engines treat functions as interpolations.
78
+ */
79
+ css = (strings, ...values) => {
80
+ if (this._css) return this._css(strings, ...values);
81
+ return () => {
82
+ const engine = this._css;
83
+ if (!engine) return notConfigured("css");
84
+ return engine(strings, ...values);
85
+ };
86
+ };
87
+ /**
88
+ * Stable styled delegate (Proxy). Supports `styled(tag)` and `styled.div`.
89
+ * When the engine is not yet available, returns a lazy forwardRef component
90
+ * that creates the real styled component on first render.
91
+ */
92
+ styled;
93
+ /** The external ThemeProvider from the configured engine. */
94
+ get ExternalProvider() {
95
+ return this._provider;
96
+ }
97
+ /** Keyframes factory from the configured engine, or null. */
98
+ get keyframes() {
99
+ return this._keyframes ?? null;
100
+ }
101
+ /** Global style factory from the configured engine, or null. */
102
+ get createGlobalStyle() {
103
+ return this._createGlobalStyle ?? null;
104
+ }
105
+ /** Theme hook from the configured engine, or null. */
106
+ get useTheme() {
107
+ return this._useTheme ?? null;
108
+ }
109
+ /**
110
+ * Stable useCSS delegate. Delegates to the engine's useCSS hook at call
111
+ * time (render phase). Safe to destructure at module level — like `css`,
112
+ * reads the latest engine reference set by `init()`.
113
+ */
114
+ useCSS = (template, props, boost) => {
115
+ const hook = this._useCSS;
116
+ if (!hook) return notConfigured("useCSS");
117
+ return hook(template, props, boost);
118
+ };
119
+ constructor() {
120
+ this.styled = createStyledDelegate(this);
30
121
  }
122
+ /**
123
+ * Initialize or swap the CSS-in-JS engine. Must be called before any
124
+ * component renders (typically at the app entry point).
125
+ *
126
+ * @example
127
+ * ```typescript
128
+ * import { init } from '@vitus-labs/core'
129
+ * import * as connector from '@vitus-labs/connector-styler'
130
+ * init(connector)
131
+ * ```
132
+ */
31
133
  init = (props) => {
32
- if (props.css) this.css = props.css;
33
- if (props.styled) this.styled = props.styled;
34
- if (props.provider) this.ExternalProvider = props.provider;
134
+ if (props.css) this._css = props.css;
135
+ if (props.styled) this._styled = props.styled;
136
+ if (props.provider) this._provider = props.provider;
137
+ if (props.keyframes) this._keyframes = props.keyframes;
138
+ if (props.createGlobalStyle) this._createGlobalStyle = props.createGlobalStyle;
139
+ if (props.useTheme) this._useTheme = props.useTheme;
140
+ if (props.useCSS) this._useCSS = props.useCSS;
35
141
  if (props.component) this.component = props.component;
36
142
  if (props.textComponent) this.textComponent = props.textComponent;
37
143
  };
38
144
  };
39
- const config = new Configuration({
40
- css,
41
- styled,
42
- provider: ThemeProvider,
43
- component: "div",
44
- textComponent: "span"
45
- });
145
+ const config = new Configuration();
46
146
  const { init } = config;
47
147
 
48
148
  //#endregion
@@ -351,12 +451,8 @@ const HTML_TEXT_TAGS = [
351
451
  const render = (content, attachProps) => {
352
452
  if (!content) return null;
353
453
  const render = (child) => attachProps ? createElement(child, attachProps) : createElement(child);
354
- if ([
355
- "number",
356
- "boolean",
357
- "bigint",
358
- "string"
359
- ].includes(typeof content)) return content;
454
+ const t = typeof content;
455
+ if (t === "string" || t === "number" || t === "boolean" || t === "bigint") return content;
360
456
  if (Array.isArray(content) || isFragment(content)) return content;
361
457
  if (isValidElementType(content)) return render(content);
362
458
  if (isValidElement(content)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitus-labs/core",
3
- "version": "1.4.2",
3
+ "version": "1.4.3-alpha.1+cf4e0a6",
4
4
  "license": "MIT",
5
5
  "author": "Vit Bokisch <vit@bokisch.cz>",
6
6
  "maintainers": [
@@ -9,6 +9,7 @@
9
9
  "type": "module",
10
10
  "sideEffects": false,
11
11
  "exports": {
12
+ "source": "./src/index.ts",
12
13
  "import": "./lib/index.js",
13
14
  "types": "./lib/index.d.ts"
14
15
  },
@@ -51,8 +52,7 @@
51
52
  "typecheck": "tsc --noEmit"
52
53
  },
53
54
  "peerDependencies": {
54
- "react": ">= 19",
55
- "styled-components": ">= 6"
55
+ "react": ">= 19"
56
56
  },
57
57
  "dependencies": {
58
58
  "react-is": "^19.2.3"
@@ -61,5 +61,5 @@
61
61
  "@vitus-labs/tools-rolldown": "^1.6.0",
62
62
  "@vitus-labs/tools-typescript": "^1.6.0"
63
63
  },
64
- "gitHead": "f12f43c61149964ff4f3f4b80cb6f92da2825915"
64
+ "gitHead": "cf4e0a6230687c5c7acc2e07a3248bae4ae55f07"
65
65
  }