@typestyles/next 0.0.0-unstable.247bf362710f

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/README.md ADDED
@@ -0,0 +1,303 @@
1
+ # @typestyles/next
2
+
3
+ Next.js integration for typestyles with full support for App Router, Pages Router, and React Server Components.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @typestyles/next typestyles
9
+ # or
10
+ pnpm add @typestyles/next typestyles
11
+ # or
12
+ yarn add @typestyles/next typestyles
13
+ ```
14
+
15
+ ## Requirements
16
+
17
+ - Next.js >= 13.0.0
18
+ - React >= 18.0.0
19
+ - typestyles >= 0.1.0
20
+
21
+ ## Quick Start
22
+
23
+ ### App Router (Recommended)
24
+
25
+ Import `getRegisteredCss` in your root layout to inject styles during SSR:
26
+
27
+ ```tsx
28
+ // app/layout.tsx
29
+ import { getRegisteredCss } from '@typestyles/next';
30
+
31
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
32
+ const css = getRegisteredCss();
33
+
34
+ return (
35
+ <html lang="en">
36
+ <head>{css && <style dangerouslySetInnerHTML={{ __html: css }} />}</head>
37
+ <body>{children}</body>
38
+ </html>
39
+ );
40
+ }
41
+ ```
42
+
43
+ ### Pages Router
44
+
45
+ Wrap your pages with the stylesheet component:
46
+
47
+ ```tsx
48
+ // pages/_app.tsx
49
+ import { TypestylesStylesheet } from '@typestyles/next';
50
+ import type { AppProps } from 'next/app';
51
+
52
+ export default function App({ Component, pageProps }: AppProps) {
53
+ return (
54
+ <TypestylesStylesheet>
55
+ <Component {...pageProps} />
56
+ </TypestylesStylesheet>
57
+ );
58
+ }
59
+ ```
60
+
61
+ ## React Server Components (RSC)
62
+
63
+ The package provides multiple approaches for RSC support:
64
+
65
+ ### Option 1: Layout SSR (Simplest)
66
+
67
+ Import `getRegisteredCss` in your root layout - this works in both Server and Client Components:
68
+
69
+ ```tsx
70
+ // app/layout.tsx
71
+ import { getRegisteredCss } from '@typestyles/next';
72
+
73
+ export default function RootLayout({ children }) {
74
+ const css = getRegisteredCss();
75
+
76
+ return (
77
+ <html>
78
+ <head>{css && <style dangerouslySetInnerHTML={{ __html: css }} />}</head>
79
+ <body>{children}</body>
80
+ </html>
81
+ );
82
+ }
83
+ ```
84
+
85
+ ### Option 2: Client Component Provider
86
+
87
+ For complex cases with dynamic styles, create a client component wrapper:
88
+
89
+ ```tsx
90
+ // components/TypestylesProvider.tsx
91
+ 'use client';
92
+
93
+ import { getRegisteredCss } from 'typestyles/server';
94
+ import { useEffect, useState } from 'react';
95
+
96
+ export function TypestylesProvider({ children }) {
97
+ const [css, setCss] = useState('');
98
+ const [mounted, setMounted] = useState(false);
99
+
100
+ useEffect(() => {
101
+ setMounted(true);
102
+ setCss(getRegisteredCss());
103
+ }, []);
104
+
105
+ return (
106
+ <>
107
+ {children}
108
+ {mounted && css && <style id="typestyles" dangerouslySetInnerHTML={{ __html: css }} />}
109
+ </>
110
+ );
111
+ }
112
+ ```
113
+
114
+ Then use it in your layout:
115
+
116
+ ```tsx
117
+ // app/layout.tsx
118
+ import { TypestylesProvider } from '@/components/TypestylesProvider';
119
+
120
+ export default function RootLayout({ children }) {
121
+ return (
122
+ <html>
123
+ <body>
124
+ <TypestylesProvider>{children}</TypestylesProvider>
125
+ </body>
126
+ </html>
127
+ );
128
+ }
129
+ ```
130
+
131
+ ### Option 3: Metadata API
132
+
133
+ For static generation, you can collect styles in `generateMetadata`:
134
+
135
+ ```tsx
136
+ // app/layout.tsx
137
+ import { generateMetadata } from 'next';
138
+ import { getTypestylesMetadata } from '@typestyles/next/server';
139
+ import { Home } from './Home';
140
+
141
+ export async function generateMetadata() {
142
+ const css = await getTypestylesMetadata(<Home />);
143
+ return {
144
+ styles: [{ cssText: css, id: 'typestyles' }],
145
+ };
146
+ }
147
+ ```
148
+
149
+ ## API Reference
150
+
151
+ ### getRegisteredCss
152
+
153
+ Returns all currently registered CSS as a string. This is the simplest way to get styles for SSR.
154
+
155
+ ```tsx
156
+ import { getRegisteredCss } from '@typestyles/next';
157
+
158
+ const css = getRegisteredCss();
159
+ ```
160
+
161
+ ### collectStylesFromComponent
162
+
163
+ Collect styles from a React component tree. Useful when you need explicit control over style collection.
164
+
165
+ ```tsx
166
+ import { collectStylesFromComponent } from '@typestyles/next/server';
167
+ import { YourComponent } from './YourComponent';
168
+
169
+ const css = await collectStylesFromComponent(<YourComponent />);
170
+ ```
171
+
172
+ ### getTypestylesMetadata
173
+
174
+ Generate CSS for use in Next.js metadata API. Collects styles by rendering the component server-side.
175
+
176
+ ```tsx
177
+ import { getTypestylesMetadata } from '@typestyles/next/server';
178
+ import { Home } from './Home';
179
+
180
+ const css = await getTypestylesMetadata(<Home />);
181
+ ```
182
+
183
+ ### TypestylesStylesheet (Pages Router)
184
+
185
+ A React component that renders typestyles CSS. Works with Pages Router.
186
+
187
+ ```tsx
188
+ import { TypestylesStylesheet } from '@typestyles/next';
189
+
190
+ <TypestylesStylesheet>
191
+ <YourApp />
192
+ </TypestylesStylesheet>;
193
+ ```
194
+
195
+ ## Examples
196
+
197
+ ### Basic Usage with App Router
198
+
199
+ ```tsx
200
+ // app/page.tsx
201
+ import { styles } from 'typestyles';
202
+
203
+ const button = styles.create('button', {
204
+ base: {
205
+ padding: '12px 24px',
206
+ backgroundColor: '#0066ff',
207
+ color: 'white',
208
+ border: 'none',
209
+ borderRadius: '6px',
210
+ cursor: 'pointer',
211
+ },
212
+ });
213
+
214
+ export default function Home() {
215
+ return (
216
+ <main>
217
+ <button className={button('base')}>Click me</button>
218
+ </main>
219
+ );
220
+ }
221
+ ```
222
+
223
+ ### With Design Tokens
224
+
225
+ ```tsx
226
+ // app/tokens.ts
227
+ import { tokens } from 'typestyles';
228
+
229
+ export const colors = tokens.create('color', {
230
+ primary: '#0066ff',
231
+ secondary: '#64748b',
232
+ });
233
+
234
+ export const spacing = tokens.create('space', {
235
+ sm: '8px',
236
+ md: '16px',
237
+ lg: '24px',
238
+ });
239
+
240
+ // app/page.tsx
241
+ import { styles } from 'typestyles';
242
+ import { colors, spacing } from './tokens';
243
+
244
+ const card = styles.create('card', {
245
+ base: {
246
+ padding: spacing.md,
247
+ backgroundColor: colors.primary,
248
+ borderRadius: '8px',
249
+ },
250
+ });
251
+
252
+ export default function Page() {
253
+ return <div className={card('base')}>Hello World</div>;
254
+ }
255
+ ```
256
+
257
+ ### With Dark Mode
258
+
259
+ ```tsx
260
+ // app/layout.tsx
261
+ import { tokens } from 'typestyles';
262
+ import { getRegisteredCss } from '@typestyles/next';
263
+
264
+ const darkTheme = tokens.createTheme('dark', {
265
+ color: {
266
+ background: '#1a1a1a',
267
+ text: '#ffffff',
268
+ },
269
+ });
270
+
271
+ export default function RootLayout({ children }) {
272
+ const css = getRegisteredCss();
273
+
274
+ return (
275
+ <html className={darkTheme}>
276
+ <head>{css && <style dangerouslySetInnerHTML={{ __html: css }} />}</head>
277
+ <body>{children}</body>
278
+ </html>
279
+ );
280
+ }
281
+ ```
282
+
283
+ ## Troubleshooting
284
+
285
+ ### Flash of Unstyled Content (FOUC)
286
+
287
+ If you see a flash of unstyled content, ensure `getRegisteredCss()` is called in the layout and styles are injected before the body renders.
288
+
289
+ ### Styles not appearing
290
+
291
+ Make sure `typestyles` is installed in your project:
292
+
293
+ ```bash
294
+ npm install typestyles
295
+ ```
296
+
297
+ ### TypeScript errors
298
+
299
+ Ensure you have `"moduleResolution": "bundler"` or `"node"` in your `tsconfig.json`.
300
+
301
+ ## License
302
+
303
+ MIT
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/client.tsx
22
+ var client_exports = {};
23
+ __export(client_exports, {
24
+ TypestylesStylesheet: () => TypestylesStylesheet,
25
+ createTypestylesLayout: () => createTypestylesLayout,
26
+ useServerInsertedHTML: () => import_react.useServerInsertedHTML,
27
+ useTypestyles: () => useTypestyles
28
+ });
29
+ module.exports = __toCommonJS(client_exports);
30
+ var import_react = require("react");
31
+ var import_server = require("typestyles/server");
32
+ var import_jsx_runtime = require("react/jsx-runtime");
33
+ function useTypestyles() {
34
+ return (0, import_react.useSyncExternalStore)(
35
+ () => () => {
36
+ },
37
+ () => (0, import_server.getRegisteredCss)(),
38
+ () => ""
39
+ );
40
+ }
41
+ function TypestylesStylesheet({ children }) {
42
+ const [css, setCss] = (0, import_react.useState)("");
43
+ (0, import_react.useServerInsertedHTML)(() => {
44
+ const registeredCss = (0, import_server.getRegisteredCss)();
45
+ if (registeredCss) {
46
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { id: "typestyles", dangerouslySetInnerHTML: { __html: registeredCss } });
47
+ }
48
+ return null;
49
+ });
50
+ (0, import_react.useEffect)(() => {
51
+ setCss((0, import_server.getRegisteredCss)());
52
+ }, []);
53
+ if (children) {
54
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
55
+ children,
56
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { id: "typestyles-client", dangerouslySetInnerHTML: { __html: css } })
57
+ ] });
58
+ }
59
+ return null;
60
+ }
61
+ function createTypestylesLayout(layout) {
62
+ return function TypestylesLayout(props) {
63
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TypestylesStylesheet, { children: layout(props) });
64
+ };
65
+ }
66
+ // Annotate the CommonJS export names for ESM import in node:
67
+ 0 && (module.exports = {
68
+ TypestylesStylesheet,
69
+ createTypestylesLayout,
70
+ useServerInsertedHTML,
71
+ useTypestyles
72
+ });
package/dist/client.js ADDED
@@ -0,0 +1,45 @@
1
+ "use client";
2
+
3
+ // src/client.tsx
4
+ import { useState, useEffect, useServerInsertedHTML, useSyncExternalStore } from "react";
5
+ import { getRegisteredCss } from "typestyles/server";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ function useTypestyles() {
8
+ return useSyncExternalStore(
9
+ () => () => {
10
+ },
11
+ () => getRegisteredCss(),
12
+ () => ""
13
+ );
14
+ }
15
+ function TypestylesStylesheet({ children }) {
16
+ const [css, setCss] = useState("");
17
+ useServerInsertedHTML(() => {
18
+ const registeredCss = getRegisteredCss();
19
+ if (registeredCss) {
20
+ return /* @__PURE__ */ jsx("style", { id: "typestyles", dangerouslySetInnerHTML: { __html: registeredCss } });
21
+ }
22
+ return null;
23
+ });
24
+ useEffect(() => {
25
+ setCss(getRegisteredCss());
26
+ }, []);
27
+ if (children) {
28
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
29
+ children,
30
+ /* @__PURE__ */ jsx("style", { id: "typestyles-client", dangerouslySetInnerHTML: { __html: css } })
31
+ ] });
32
+ }
33
+ return null;
34
+ }
35
+ function createTypestylesLayout(layout) {
36
+ return function TypestylesLayout(props) {
37
+ return /* @__PURE__ */ jsx(TypestylesStylesheet, { children: layout(props) });
38
+ };
39
+ }
40
+ export {
41
+ TypestylesStylesheet,
42
+ createTypestylesLayout,
43
+ useServerInsertedHTML,
44
+ useTypestyles
45
+ };
package/dist/index.cjs ADDED
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.tsx
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ TypestylesStylesheet: () => TypestylesStylesheet,
34
+ collectStylesFromComponent: () => collectStylesFromComponent,
35
+ createTypestylesLayout: () => createTypestylesLayout,
36
+ getRegisteredCss: () => import_server.getRegisteredCss,
37
+ getTypestylesMetadata: () => getTypestylesMetadata,
38
+ useServerInsertedHTML: () => import_react.useServerInsertedHTML,
39
+ useTypestyles: () => useTypestyles
40
+ });
41
+ module.exports = __toCommonJS(index_exports);
42
+
43
+ // src/server.ts
44
+ var import_server = require("typestyles/server");
45
+ async function collectStylesFromComponent(component) {
46
+ const { renderToString } = await import("react-dom/server");
47
+ const { css } = (0, import_server.collectStyles)(() => renderToString(component));
48
+ return css;
49
+ }
50
+ async function getTypestylesMetadata(component) {
51
+ return collectStylesFromComponent(component);
52
+ }
53
+
54
+ // src/client.tsx
55
+ var import_react = require("react");
56
+ var import_server2 = require("typestyles/server");
57
+ var import_jsx_runtime = require("react/jsx-runtime");
58
+ function useTypestyles() {
59
+ return (0, import_react.useSyncExternalStore)(
60
+ () => () => {
61
+ },
62
+ () => (0, import_server2.getRegisteredCss)(),
63
+ () => ""
64
+ );
65
+ }
66
+ function TypestylesStylesheet({ children }) {
67
+ const [css, setCss] = (0, import_react.useState)("");
68
+ (0, import_react.useServerInsertedHTML)(() => {
69
+ const registeredCss = (0, import_server2.getRegisteredCss)();
70
+ if (registeredCss) {
71
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { id: "typestyles", dangerouslySetInnerHTML: { __html: registeredCss } });
72
+ }
73
+ return null;
74
+ });
75
+ (0, import_react.useEffect)(() => {
76
+ setCss((0, import_server2.getRegisteredCss)());
77
+ }, []);
78
+ if (children) {
79
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
80
+ children,
81
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { id: "typestyles-client", dangerouslySetInnerHTML: { __html: css } })
82
+ ] });
83
+ }
84
+ return null;
85
+ }
86
+ function createTypestylesLayout(layout) {
87
+ return function TypestylesLayout(props) {
88
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TypestylesStylesheet, { children: layout(props) });
89
+ };
90
+ }
91
+ // Annotate the CommonJS export names for ESM import in node:
92
+ 0 && (module.exports = {
93
+ TypestylesStylesheet,
94
+ collectStylesFromComponent,
95
+ createTypestylesLayout,
96
+ getRegisteredCss,
97
+ getTypestylesMetadata,
98
+ useServerInsertedHTML,
99
+ useTypestyles
100
+ });
package/dist/index.js ADDED
@@ -0,0 +1,57 @@
1
+ // src/server.ts
2
+ import { collectStyles, getRegisteredCss } from "typestyles/server";
3
+ async function collectStylesFromComponent(component) {
4
+ const { renderToString } = await import("react-dom/server");
5
+ const { css } = collectStyles(() => renderToString(component));
6
+ return css;
7
+ }
8
+ async function getTypestylesMetadata(component) {
9
+ return collectStylesFromComponent(component);
10
+ }
11
+
12
+ // src/client.tsx
13
+ import { useState, useEffect, useServerInsertedHTML, useSyncExternalStore } from "react";
14
+ import { getRegisteredCss as getRegisteredCss2 } from "typestyles/server";
15
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
16
+ function useTypestyles() {
17
+ return useSyncExternalStore(
18
+ () => () => {
19
+ },
20
+ () => getRegisteredCss2(),
21
+ () => ""
22
+ );
23
+ }
24
+ function TypestylesStylesheet({ children }) {
25
+ const [css, setCss] = useState("");
26
+ useServerInsertedHTML(() => {
27
+ const registeredCss = getRegisteredCss2();
28
+ if (registeredCss) {
29
+ return /* @__PURE__ */ jsx("style", { id: "typestyles", dangerouslySetInnerHTML: { __html: registeredCss } });
30
+ }
31
+ return null;
32
+ });
33
+ useEffect(() => {
34
+ setCss(getRegisteredCss2());
35
+ }, []);
36
+ if (children) {
37
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
38
+ children,
39
+ /* @__PURE__ */ jsx("style", { id: "typestyles-client", dangerouslySetInnerHTML: { __html: css } })
40
+ ] });
41
+ }
42
+ return null;
43
+ }
44
+ function createTypestylesLayout(layout) {
45
+ return function TypestylesLayout(props) {
46
+ return /* @__PURE__ */ jsx(TypestylesStylesheet, { children: layout(props) });
47
+ };
48
+ }
49
+ export {
50
+ TypestylesStylesheet,
51
+ collectStylesFromComponent,
52
+ createTypestylesLayout,
53
+ getRegisteredCss,
54
+ getTypestylesMetadata,
55
+ useServerInsertedHTML,
56
+ useTypestyles
57
+ };
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/server.ts
31
+ var server_exports = {};
32
+ __export(server_exports, {
33
+ collectStylesFromComponent: () => collectStylesFromComponent,
34
+ getRegisteredCss: () => import_server.getRegisteredCss,
35
+ getTypestylesMetadata: () => getTypestylesMetadata
36
+ });
37
+ module.exports = __toCommonJS(server_exports);
38
+ var import_server = require("typestyles/server");
39
+ async function collectStylesFromComponent(component) {
40
+ const { renderToString } = await import("react-dom/server");
41
+ const { css } = (0, import_server.collectStyles)(() => renderToString(component));
42
+ return css;
43
+ }
44
+ async function getTypestylesMetadata(component) {
45
+ return collectStylesFromComponent(component);
46
+ }
47
+ // Annotate the CommonJS export names for ESM import in node:
48
+ 0 && (module.exports = {
49
+ collectStylesFromComponent,
50
+ getRegisteredCss,
51
+ getTypestylesMetadata
52
+ });
package/dist/server.js ADDED
@@ -0,0 +1,15 @@
1
+ // src/server.ts
2
+ import { collectStyles, getRegisteredCss } from "typestyles/server";
3
+ async function collectStylesFromComponent(component) {
4
+ const { renderToString } = await import("react-dom/server");
5
+ const { css } = collectStyles(() => renderToString(component));
6
+ return css;
7
+ }
8
+ async function getTypestylesMetadata(component) {
9
+ return collectStylesFromComponent(component);
10
+ }
11
+ export {
12
+ collectStylesFromComponent,
13
+ getRegisteredCss,
14
+ getTypestylesMetadata
15
+ };
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@typestyles/next",
3
+ "version": "0.0.0-unstable.247bf362710f",
4
+ "description": "Next.js integration for typestyles SSR",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./src/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./src/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ },
15
+ "./server": {
16
+ "types": "./src/server.d.ts",
17
+ "import": "./dist/server.js",
18
+ "require": "./dist/server.cjs"
19
+ },
20
+ "./client": {
21
+ "types": "./src/client.d.ts",
22
+ "import": "./dist/client.js",
23
+ "require": "./dist/client.cjs",
24
+ "default": "./dist/client.js"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "src"
30
+ ],
31
+ "keywords": [
32
+ "next",
33
+ "nextjs",
34
+ "typestyles",
35
+ "ssr",
36
+ "react"
37
+ ],
38
+ "license": "MIT",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://github.com/dbanksdesign/typestyles",
42
+ "directory": "packages/next"
43
+ },
44
+ "peerDependencies": {
45
+ "next": ">=13.0.0",
46
+ "react": ">=18.0.0",
47
+ "react-dom": ">=18.0.0",
48
+ "typestyles": ">=0.1.0"
49
+ },
50
+ "peerDependenciesMeta": {
51
+ "next": {
52
+ "optional": false
53
+ },
54
+ "react": {
55
+ "optional": false
56
+ },
57
+ "react-dom": {
58
+ "optional": false
59
+ }
60
+ },
61
+ "devDependencies": {
62
+ "@types/node": "^25.2.1",
63
+ "@types/react": "^18.0.0",
64
+ "@types/react-dom": "^18.0.0",
65
+ "next": "^14.0.0",
66
+ "react": "^18.0.0",
67
+ "react-dom": "^18.0.0",
68
+ "tsup": "^8.0.0",
69
+ "typescript": "^5.4.0"
70
+ },
71
+ "scripts": {
72
+ "build": "tsup"
73
+ }
74
+ }
@@ -0,0 +1,34 @@
1
+ import type * as React from 'react';
2
+ import type { useSyncExternalStore, useServerInsertedHTML } from 'react';
3
+
4
+ /**
5
+ * Subscribe to typestyles CSS changes. Use this in client components
6
+ * that need to stay up-to-date with dynamically registered styles.
7
+ */
8
+ export function useTypestyles(): ReturnType<typeof useSyncExternalStore<string>>;
9
+
10
+ /**
11
+ * Collect styles during server rendering for App Router.
12
+ */
13
+ export { useServerInsertedHTML };
14
+
15
+ /**
16
+ * Props for the TypestylesStylesheet component.
17
+ */
18
+ export interface TypestylesStylesheetProps {
19
+ children?: React.ReactNode;
20
+ }
21
+
22
+ /**
23
+ * A React component that renders typestyles CSS.
24
+ */
25
+ export function TypestylesStylesheet(
26
+ props: TypestylesStylesheetProps,
27
+ ): React.JSX.Element | null;
28
+
29
+ /**
30
+ * Create a Next.js layout export that includes typestyles.
31
+ */
32
+ export function createTypestylesLayout<P extends { children?: React.ReactNode }>(
33
+ layout: (props: P) => React.ReactNode,
34
+ ): (props: P) => React.JSX.Element;
package/src/client.tsx ADDED
@@ -0,0 +1,143 @@
1
+ 'use client';
2
+
3
+ import React, { useState, useEffect, useServerInsertedHTML, useSyncExternalStore } from 'react';
4
+ import { getRegisteredCss } from 'typestyles/server';
5
+
6
+ /**
7
+ * Subscribe to typestyles CSS changes. Use this in client components
8
+ * that need to stay up-to-date with dynamically registered styles.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * // components/Styles.tsx
13
+ * 'use client';
14
+ * import { useTypestyles } from '@typestyles/next/client';
15
+ *
16
+ * export function Styles() {
17
+ * useTypestyles();
18
+ * return null;
19
+ * }
20
+ * ```
21
+ */
22
+ export function useTypestyles() {
23
+ return useSyncExternalStore(
24
+ () => () => {},
25
+ () => getRegisteredCss(),
26
+ () => '',
27
+ );
28
+ }
29
+
30
+ /**
31
+ * Collect styles during server rendering for App Router.
32
+ * Use this in a Client Component wrapper that collects styles from its children.
33
+ *
34
+ * @example
35
+ * ```tsx
36
+ * // components/TypestylesProvider.tsx
37
+ * 'use client';
38
+ *
39
+ * import { useServerInsertedHTML, getRegisteredCss } from '@typestyles/next/client';
40
+ *
41
+ * export function TypestylesProvider({ children }: { children: React.ReactNode }) {
42
+ * useServerInsertedHTML(() => {
43
+ * return (
44
+ * <style
45
+ * id="typestyles"
46
+ * dangerouslySetInnerHTML={{ __html: getRegisteredCss() }}
47
+ * />
48
+ * );
49
+ * });
50
+ * return <>{children}</>;
51
+ * }
52
+ * ```
53
+ */
54
+ export { useServerInsertedHTML };
55
+
56
+ /**
57
+ * Props for the TypestylesStylesheet component.
58
+ */
59
+ export interface TypestylesStylesheetProps {
60
+ /**
61
+ * The children to render (styles will be collected from these).
62
+ * If not provided, only the existing registered CSS will be included.
63
+ */
64
+ children?: React.ReactNode;
65
+ }
66
+
67
+ /**
68
+ * A React component that renders typestyles CSS.
69
+ *
70
+ * For App Router: Use this in your root layout to collect and render styles.
71
+ * Works with both Client Components and React Server Components.
72
+ *
73
+ * @example
74
+ * ```tsx
75
+ * // app/layout.tsx
76
+ * import { TypestylesStylesheet } from '@typestyles/next/client';
77
+ *
78
+ * export default function RootLayout({ children }) {
79
+ * return (
80
+ * <html>
81
+ * <head>
82
+ * <TypestylesStylesheet />
83
+ * </head>
84
+ * <body>{children}</body>
85
+ * </html>
86
+ * );
87
+ * }
88
+ * ```
89
+ */
90
+ export function TypestylesStylesheet({ children }: TypestylesStylesheetProps) {
91
+ const [css, setCss] = useState('');
92
+
93
+ useServerInsertedHTML(() => {
94
+ const registeredCss = getRegisteredCss();
95
+ if (registeredCss) {
96
+ return <style id="typestyles" dangerouslySetInnerHTML={{ __html: registeredCss }} />;
97
+ }
98
+ return null;
99
+ });
100
+
101
+ useEffect(() => {
102
+ setCss(getRegisteredCss());
103
+ }, []);
104
+
105
+ if (children) {
106
+ return (
107
+ <>
108
+ {children}
109
+ <style id="typestyles-client" dangerouslySetInnerHTML={{ __html: css }} />
110
+ </>
111
+ );
112
+ }
113
+
114
+ return null;
115
+ }
116
+
117
+ /**
118
+ * Create a Next.js layout export that includes typestyles.
119
+ *
120
+ * @example
121
+ * ```tsx
122
+ * // app/layout.tsx
123
+ * import { createTypestylesLayout } from '@typestyles/next/client';
124
+ *
125
+ * export default createTypestylesLayout(function RootLayout({ children }) {
126
+ * return (
127
+ * <html>
128
+ * <head>
129
+ * <title>My App</title>
130
+ * </head>
131
+ * <body>{children}</body>
132
+ * </html>
133
+ * );
134
+ * });
135
+ * ```
136
+ */
137
+ export function createTypestylesLayout<P extends { children?: React.ReactNode }>(
138
+ layout: (props: P) => React.ReactNode,
139
+ ): (props: P) => React.ReactNode {
140
+ return function TypestylesLayout(props: P) {
141
+ return <TypestylesStylesheet>{layout(props)}</TypestylesStylesheet>;
142
+ };
143
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ export { getRegisteredCss } from 'typestyles/server';
2
+
3
+ export interface TypestylesStylesheetProps {
4
+ children?: React.ReactNode;
5
+ }
6
+
7
+ export function TypestylesStylesheet(props: TypestylesStylesheetProps): React.JSX.Element;
8
+
9
+ export function collectStylesFromComponent(component: React.ReactElement): Promise<string>;
10
+
11
+ export function createTypestylesLayout<P extends { children?: React.ReactNode }>(
12
+ layout: (props: P) => React.ReactNode,
13
+ ): (props: P) => React.JSX.Element;
package/src/index.tsx ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @typestyles/next - Next.js integration for typestyles
3
+ *
4
+ * This package provides two entry points:
5
+ *
6
+ * 1. Main entry (this file) - Re-exports everything
7
+ * 2. `/server` - Server-safe utilities (getRegisteredCss, collectStylesFromComponent, getTypestylesMetadata)
8
+ * 3. `/client` - Client components (TypestylesStylesheet, useTypestyles, useServerInsertedHTML)
9
+ *
10
+ * For App Router, prefer using the client entry for components:
11
+ * import { TypestylesStylesheet } from '@typestyles/next/client';
12
+ *
13
+ * Or use server utilities for SSR:
14
+ * import { getRegisteredCss } from '@typestyles/next/server';
15
+ */
16
+
17
+ // Re-export server-safe utilities
18
+ export { getRegisteredCss, collectStylesFromComponent, getTypestylesMetadata } from './server';
19
+
20
+ // Re-export client components and hooks
21
+ export {
22
+ TypestylesStylesheet,
23
+ useTypestyles,
24
+ useServerInsertedHTML,
25
+ createTypestylesLayout,
26
+ type TypestylesStylesheetProps,
27
+ } from './client';
package/src/server.ts ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Server-safe utilities for Next.js integration.
3
+ * These functions can be used in Server Components without adding "use client".
4
+ */
5
+ import { collectStyles, getRegisteredCss } from 'typestyles/server';
6
+
7
+ export { getRegisteredCss };
8
+
9
+ /**
10
+ * Collect styles from a React component and return them as a string.
11
+ * Useful for server components or when you need more control.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * // app/styles.ts
16
+ * import { collectStylesFromComponent } from '@typestyles/next/server';
17
+ * import { YourApp } from './YourApp';
18
+ *
19
+ * export async function getStyles() {
20
+ * return collectStylesFromComponent(<YourApp />);
21
+ * }
22
+ * ```
23
+ */
24
+ export async function collectStylesFromComponent(component: React.ReactElement): Promise<string> {
25
+ const { renderToString } = await import('react-dom/server');
26
+ const { css } = collectStyles(() => renderToString(component));
27
+ return css;
28
+ }
29
+
30
+ /**
31
+ * Generate CSS for use in Next.js metadata API.
32
+ * Call this in your layout or page to get CSS for the head.
33
+ *
34
+ * Note: This only captures CSS registered during the synchronous render.
35
+ * For dynamic styles that may be registered client-side, use TypestylesStylesheet.
36
+ *
37
+ * @example
38
+ * ```tsx
39
+ * // app/layout.tsx
40
+ * import { generateMetadata } from 'next/metadata';
41
+ * import { getTypestylesMetadata } from '@typestyles/next/server';
42
+ * import { Home } from './Home';
43
+ *
44
+ * export async function generateMetadata() {
45
+ * const css = await getTypestylesMetadata(<Home />);
46
+ * return {
47
+ * styles: [{ cssText: css }],
48
+ * };
49
+ * }
50
+ * ```
51
+ */
52
+ export async function getTypestylesMetadata(component: React.ReactElement): Promise<string> {
53
+ return collectStylesFromComponent(component);
54
+ }