create-newt-app 0.32.0 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import { existsSync, promises } from "fs";
11
11
  import path from "path";
12
12
  import https from "node:https";
13
13
  //#region package.json
14
- var version = "0.32.0";
14
+ var version = "0.33.0";
15
15
  var engines = { "node": ">=24.0.0" };
16
16
  //#endregion
17
17
  //#region src/templates/root/index.ts
@@ -231,7 +231,7 @@ This version has breaking changes — APIs, conventions, and file structure may
231
231
  const web$1 = {
232
232
  templates: [
233
233
  {
234
- when: (s) => s.nest !== "di-only",
234
+ when: (s) => s.nest !== "di-only" && !s.stylex,
235
235
  filename: "apps/web/package.json",
236
236
  template: `{
237
237
  "name": "web",
@@ -369,6 +369,7 @@ const nextConfig = {
369
369
  export default nextConfig;`
370
370
  },
371
371
  {
372
+ when: (s) => !s.stylex,
372
373
  filename: "apps/web/postcss.config.mjs",
373
374
  template: `export { default } from "@<%= projectName %>/ui/postcss.config";`
374
375
  },
@@ -399,7 +400,7 @@ export default nextConfig;`
399
400
  }`
400
401
  },
401
402
  {
402
- when: (s) => !s.shadcn,
403
+ when: (s) => !s.shadcn && !s.stylex,
403
404
  filename: "apps/web/app/layout.tsx",
404
405
  template: `import type { Metadata } from "next";
405
406
  import localFont from "next/font/local";
@@ -442,7 +443,7 @@ export default function RootLayout({
442
443
  }`
443
444
  },
444
445
  {
445
- when: (s) => !s.todoExample && !s.shadcn,
446
+ when: (s) => !s.todoExample && !s.shadcn && !s.stylex,
446
447
  filename: "apps/web/app/page.tsx",
447
448
  template: `'use client';
448
449
 
@@ -543,7 +544,7 @@ export default function Providers({ children }: { children: React.ReactNode }) {
543
544
  }`
544
545
  },
545
546
  {
546
- when: (s) => !s.shadcn,
547
+ when: (s) => !s.shadcn && !s.stylex,
547
548
  filename: "apps/web/app/auth-form.tsx",
548
549
  template: `'use client';
549
550
 
@@ -941,6 +942,7 @@ export type Auth = typeof auth;`
941
942
  filename: "packages/auth/tsconfig.json",
942
943
  template: `{
943
944
  "compilerOptions": {
945
+ "erasableSyntaxOnly": true,
944
946
  "esModuleInterop": true,
945
947
  "lib": ["es2022"],
946
948
  "module": "NodeNext",
@@ -961,6 +963,7 @@ var tsconfig_default$2 = {
961
963
  filename: "packages/db/tsconfig.json",
962
964
  template: `{
963
965
  "compilerOptions": {
966
+ "erasableSyntaxOnly": true,
964
967
  "esModuleInterop": true,
965
968
  "lib": ["es2022"],
966
969
  "module": "NodeNext",
@@ -1256,11 +1259,10 @@ const dbPostgres = { templates: [
1256
1259
  src_index_postgres_default
1257
1260
  ] };
1258
1261
  //#endregion
1259
- //#region src/templates/ui/index.ts
1260
- const ui$1 = { templates: [
1261
- {
1262
- filename: "packages/ui/package.json",
1263
- template: `{
1262
+ //#region src/templates/ui/templates/package-json.ts
1263
+ var package_json_default$4 = {
1264
+ filename: "packages/ui/package.json",
1265
+ template: `{
1264
1266
  "name": "@<%= projectName %>/ui",
1265
1267
  "version": "0.0.0",
1266
1268
  "private": true,
@@ -1292,10 +1294,12 @@ const ui$1 = { templates: [
1292
1294
  "tailwind-merge": "<%= versions["tailwind-merge"] %>"
1293
1295
  }
1294
1296
  }`
1295
- },
1296
- {
1297
- filename: "packages/ui/src/button.tsx",
1298
- template: `"use client";
1297
+ };
1298
+ //#endregion
1299
+ //#region src/templates/ui/templates/button.ts
1300
+ var button_default$2 = {
1301
+ filename: "packages/ui/src/button.tsx",
1302
+ template: `"use client";
1299
1303
 
1300
1304
  import { ReactNode } from "react";
1301
1305
  import { cn } from "./utils";
@@ -1327,10 +1331,12 @@ export const Button = ({ children, onClick, type = "button", disabled, className
1327
1331
  </button>
1328
1332
  );
1329
1333
  };`
1330
- },
1331
- {
1332
- filename: "packages/ui/src/link.tsx",
1333
- template: `import NextLink, { type LinkProps } from "next/link";
1334
+ };
1335
+ //#endregion
1336
+ //#region src/templates/ui/templates/link.ts
1337
+ var link_default$2 = {
1338
+ filename: "packages/ui/src/link.tsx",
1339
+ template: `import NextLink, { type LinkProps } from "next/link";
1334
1340
  import { type PropsWithChildren } from "react";
1335
1341
  import { cn } from "./utils";
1336
1342
 
@@ -1353,10 +1359,12 @@ export function Link({
1353
1359
  </NextLink>
1354
1360
  );
1355
1361
  }`
1356
- },
1357
- {
1358
- filename: "packages/ui/src/logo.tsx",
1359
- template: `import { cn } from "./utils";
1362
+ };
1363
+ //#endregion
1364
+ //#region src/templates/ui/templates/logo.ts
1365
+ var logo_default$2 = {
1366
+ filename: "packages/ui/src/logo.tsx",
1367
+ template: `import { cn } from "./utils";
1360
1368
 
1361
1369
  interface LogoProps {
1362
1370
  className?: string;
@@ -1379,19 +1387,23 @@ export function Logo({ className }: LogoProps) {
1379
1387
  </svg>
1380
1388
  );
1381
1389
  }`
1382
- },
1383
- {
1384
- filename: "packages/ui/src/utils.ts",
1385
- template: `import { clsx, type ClassValue } from "clsx";
1390
+ };
1391
+ //#endregion
1392
+ //#region src/templates/ui/templates/utils.ts
1393
+ var utils_default$1 = {
1394
+ filename: "packages/ui/src/utils.ts",
1395
+ template: `import { clsx, type ClassValue } from "clsx";
1386
1396
  import { twMerge } from "tailwind-merge";
1387
1397
 
1388
1398
  export function cn(...inputs: ClassValue[]) {
1389
1399
  return twMerge(clsx(inputs));
1390
1400
  }`
1391
- },
1392
- {
1393
- filename: "packages/ui/src/globals.css",
1394
- template: `@import 'tailwindcss';
1401
+ };
1402
+ //#endregion
1403
+ //#region src/templates/ui/templates/globals-css.ts
1404
+ var globals_css_default$2 = {
1405
+ filename: "packages/ui/src/globals.css",
1406
+ template: `@import 'tailwindcss';
1395
1407
  @source "../../../apps/**/*.{ts,tsx}";
1396
1408
  @source "../**/*.{ts,tsx}";
1397
1409
 
@@ -1428,20 +1440,24 @@ export function cn(...inputs: ClassValue[]) {
1428
1440
  border-color: var(--border);
1429
1441
  }
1430
1442
  }`
1431
- },
1432
- {
1433
- filename: "packages/ui/postcss.config.mjs",
1434
- template: `const config = {
1443
+ };
1444
+ //#endregion
1445
+ //#region src/templates/ui/templates/postcss-config.ts
1446
+ var postcss_config_default$2 = {
1447
+ filename: "packages/ui/postcss.config.mjs",
1448
+ template: `const config = {
1435
1449
  plugins: {
1436
1450
  "@tailwindcss/postcss": {},
1437
1451
  },
1438
1452
  };
1439
1453
 
1440
1454
  export default config;`
1441
- },
1442
- {
1443
- filename: "packages/ui/tsconfig.json",
1444
- template: `{
1455
+ };
1456
+ //#endregion
1457
+ //#region src/templates/ui/templates/tsconfig.ts
1458
+ var tsconfig_default$1 = {
1459
+ filename: "packages/ui/tsconfig.json",
1460
+ template: `{
1445
1461
  "extends": "@<%= projectName %>/typescript-config/react-library.json",
1446
1462
  "compilerOptions": {
1447
1463
  "outDir": "dist",
@@ -1450,11 +1466,24 @@ export default config;`
1450
1466
  "include": ["src"],
1451
1467
  "exclude": ["node_modules", "dist"]
1452
1468
  }`
1453
- }
1469
+ };
1470
+ //#endregion
1471
+ //#region src/templates/ui/index.ts
1472
+ const ui$1 = { templates: [
1473
+ package_json_default$4,
1474
+ button_default$2,
1475
+ link_default$2,
1476
+ logo_default$2,
1477
+ utils_default$1,
1478
+ globals_css_default$2,
1479
+ postcss_config_default$2,
1480
+ tsconfig_default$1
1454
1481
  ] };
1455
1482
  //#endregion
1456
1483
  //#region src/templates/versions.ts
1457
1484
  const versions = {
1485
+ "@babel/plugin-proposal-decorators": "^8.0.2",
1486
+ "@babel/plugin-transform-class-properties": "^8.0.1",
1458
1487
  "@base-ui/react": "^1.6.0",
1459
1488
  "@eslint/js": "^9.39.1",
1460
1489
  "@nestjs/cli": "^11.0.0",
@@ -1467,6 +1496,9 @@ const versions = {
1467
1496
  "@next/eslint-plugin-next": "^16.3.4",
1468
1497
  "@oxlint/plugins": "^1.74.0",
1469
1498
  "@shadcn/react": "^0.2.1",
1499
+ "@stylexjs/babel-plugin": "0.19.0",
1500
+ "@stylexjs/postcss-plugin": "0.19.0",
1501
+ "@stylexjs/stylex": "0.19.0",
1470
1502
  "@swc/core": "^1.10.0",
1471
1503
  "@tailwindcss/postcss": "^4.2.1",
1472
1504
  "@tanstack/react-form": "^1.28.5",
@@ -1482,6 +1514,7 @@ const versions = {
1482
1514
  "@types/supertest": "^6.0.2",
1483
1515
  "@vitest/coverage-v8": "^4.1.10",
1484
1516
  auth: "^1.5.5",
1517
+ "babel-plugin-transform-typescript-metadata": "^0.4.0",
1485
1518
  "better-auth": "^1.2.8",
1486
1519
  "better-sqlite3": "^12.11.1",
1487
1520
  "class-variance-authority": "^0.7.1",
@@ -9827,154 +9860,953 @@ export {
9827
9860
  }]
9828
9861
  };
9829
9862
  //#endregion
9830
- //#region src/templates/eslint-config/templates/package-json.ts
9831
- var package_json_default$1 = {
9832
- filename: "packages/eslint-config/package.json",
9833
- template: `{
9834
- "name": "@<%= projectName %>/eslint-config",
9863
+ //#region src/templates/stylex-ui/index.ts
9864
+ const stylexUi = { templates: [
9865
+ {
9866
+ filename: "packages/ui/package.json",
9867
+ template: `{
9868
+ "name": "@<%= projectName %>/ui",
9835
9869
  "version": "0.0.0",
9836
- "type": "module",
9837
9870
  "private": true,
9838
9871
  "exports": {
9839
- "./base": "./base.js",
9840
- "./next-js": "./next.js",
9841
- "./react-internal": "./react-internal.js"
9872
+ "./globals.css": "./src/globals.css",
9873
+ "./tokens.stylex": "./src/tokens.stylex.ts",
9874
+ "./*": "./src/*.tsx"
9875
+ },
9876
+ "scripts": {
9877
+ "typecheck": "tsc --noEmit"
9842
9878
  },
9843
9879
  "devDependencies": {
9844
- "@eslint/js": "<%= versions["@eslint/js"] %>",
9845
- "@next/eslint-plugin-next": "<%= versions["@next/eslint-plugin-next"] %>",
9846
- "eslint": "<%= versions.eslint %>",
9847
- "eslint-config-prettier": "<%= versions["eslint-config-prettier"] %>",
9848
- "eslint-plugin-only-warn": "<%= versions["eslint-plugin-only-warn"] %>",
9849
- "eslint-plugin-react": "<%= versions["eslint-plugin-react"] %>",
9850
- "eslint-plugin-react-hooks": "<%= versions["eslint-plugin-react-hooks"] %>",
9851
- "eslint-plugin-turbo": "<%= versions["eslint-plugin-turbo"] %>",
9852
- "globals": "<%= versions.globals %>",
9853
- "typescript": "<%= versions.typescript %>",
9854
- "typescript-eslint": "<%= versions["typescript-eslint"] %>"
9880
+ "@<%= projectName %>/typescript-config": "workspace:*",
9881
+ "@types/node": "<%= versions["@types/node"] %>",
9882
+ "@types/react": "<%= versions["@types/react"] %>",
9883
+ "@types/react-dom": "<%= versions["@types/react-dom"] %>",
9884
+ "typescript": "<%= versions.typescript %>"
9885
+ },
9886
+ "peerDependencies": {
9887
+ "next": ">=15.0.0",
9888
+ "react": ">=19.0.0",
9889
+ "react-dom": ">=19.0.0"
9890
+ },
9891
+ "dependencies": {
9892
+ "@stylexjs/stylex": "<%= versions["@stylexjs/stylex"] %>"
9855
9893
  }
9856
9894
  }`
9895
+ },
9896
+ {
9897
+ filename: "packages/ui/src/tokens.stylex.ts",
9898
+ template: `import * as stylex from "@stylexjs/stylex";
9899
+
9900
+ export const colors = stylex.defineVars({
9901
+ background: "oklch(0.145 0 0)",
9902
+ foreground: "oklch(0.985 0 0)",
9903
+ muted: "oklch(0.269 0 0)",
9904
+ mutedForeground: "oklch(0.708 0 0)",
9905
+ border: "oklch(0.469 0 0)",
9906
+ accent: "oklch(0.985 0 0)",
9907
+ accentForeground: "oklch(0.205 0 0)",
9908
+ danger: "oklch(0.637 0.237 25.331)",
9909
+ });
9910
+
9911
+ export const fonts = stylex.defineVars({
9912
+ sans: "var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif",
9913
+ mono: "var(--font-geist-mono), ui-monospace, monospace",
9914
+ });
9915
+
9916
+ export const radii = stylex.defineVars({
9917
+ sm: "6px",
9918
+ md: "8px",
9919
+ lg: "12px",
9920
+ });
9921
+ `
9922
+ },
9923
+ {
9924
+ filename: "packages/ui/src/button.tsx",
9925
+ template: `"use client";
9926
+
9927
+ import { ReactNode } from "react";
9928
+ import * as stylex from "@stylexjs/stylex";
9929
+ import type { StyleXStyles } from "@stylexjs/stylex";
9930
+ import { colors, fonts, radii } from "./tokens.stylex";
9931
+
9932
+ interface ButtonProps {
9933
+ children: ReactNode;
9934
+ onClick?: () => void;
9935
+ type?: "button" | "submit" | "reset";
9936
+ disabled?: boolean;
9937
+ style?: StyleXStyles;
9938
+ }
9939
+
9940
+ export const Button = ({ children, onClick, type = "button", disabled, style }: ButtonProps) => {
9941
+ return (
9942
+ <button
9943
+ type={type}
9944
+ onClick={onClick}
9945
+ disabled={disabled}
9946
+ {...stylex.props(styles.base, disabled && styles.disabled, style)}
9947
+ >
9948
+ {children}
9949
+ </button>
9950
+ );
9857
9951
  };
9858
- //#endregion
9859
- //#region src/templates/eslint-config/templates/base.ts
9860
- var base_default$1 = {
9861
- filename: "packages/eslint-config/base.js",
9862
- template: `import js from "@eslint/js";
9863
- import eslintConfigPrettier from "eslint-config-prettier";
9864
- import turboPlugin from "eslint-plugin-turbo";
9865
- import tseslint from "typescript-eslint";
9866
- import onlyWarn from "eslint-plugin-only-warn";
9867
9952
 
9868
- /**
9869
- * A shared ESLint configuration for the repository.
9870
- *
9871
- * @type {import("eslint").Linter.Config[]}
9872
- * */
9873
- export const config = [
9874
- js.configs.recommended,
9875
- eslintConfigPrettier,
9876
- ...tseslint.configs.recommended,
9877
- {
9878
- plugins: {
9879
- turbo: turboPlugin,
9880
- },
9881
- rules: {
9882
- "turbo/no-undeclared-env-vars": "warn",
9953
+ const styles = stylex.create({
9954
+ base: {
9955
+ display: "inline-flex",
9956
+ alignItems: "center",
9957
+ justifyContent: "center",
9958
+ gap: 8,
9959
+ height: 36,
9960
+ paddingBlock: 0,
9961
+ paddingInline: 16,
9962
+ fontFamily: fonts.sans,
9963
+ fontSize: 14,
9964
+ fontWeight: 500,
9965
+ whiteSpace: "nowrap",
9966
+ color: colors.accentForeground,
9967
+ backgroundColor: {
9968
+ default: colors.accent,
9969
+ ":hover": "oklch(0.922 0 0)",
9883
9970
  },
9884
- },
9885
- {
9886
- plugins: {
9887
- onlyWarn,
9971
+ borderStyle: "none",
9972
+ borderRadius: radii.sm,
9973
+ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.3)",
9974
+ cursor: "pointer",
9975
+ transitionProperty: "background-color",
9976
+ transitionDuration: "150ms",
9977
+ outlineColor: "rgba(255, 255, 255, 0.5)",
9978
+ outlineOffset: 2,
9979
+ outlineStyle: {
9980
+ default: "none",
9981
+ ":focus-visible": "solid",
9888
9982
  },
9983
+ outlineWidth: 2,
9889
9984
  },
9890
- {
9891
- ignores: ["dist/**"],
9985
+ disabled: {
9986
+ opacity: 0.5,
9987
+ pointerEvents: "none",
9892
9988
  },
9893
- ];`
9894
- };
9895
- //#endregion
9896
- //#region src/templates/eslint-config/templates/next.ts
9897
- var next_default = {
9898
- filename: "packages/eslint-config/next.js",
9899
- template: `import js from "@eslint/js";
9900
- import { globalIgnores } from "eslint/config";
9901
- import eslintConfigPrettier from "eslint-config-prettier";
9902
- import tseslint from "typescript-eslint";
9903
- import pluginReactHooks from "eslint-plugin-react-hooks";
9904
- import pluginReact from "eslint-plugin-react";
9905
- import globals from "globals";
9906
- import pluginNext from "@next/eslint-plugin-next";
9907
- import { config as baseConfig } from "./base.js";
9989
+ });
9990
+ `
9991
+ },
9992
+ {
9993
+ filename: "packages/ui/src/link.tsx",
9994
+ template: `import NextLink, { type LinkProps } from "next/link";
9995
+ import { type PropsWithChildren } from "react";
9996
+ import * as stylex from "@stylexjs/stylex";
9997
+ import type { StyleXStyles } from "@stylexjs/stylex";
9998
+ import { colors } from "./tokens.stylex";
9908
9999
 
9909
- /**
9910
- * A custom ESLint configuration for libraries that use Next.js.
9911
- *
9912
- * @type {import("eslint").Linter.Config[]}
9913
- * */
9914
- export const nextJsConfig = [
9915
- ...baseConfig,
9916
- js.configs.recommended,
9917
- eslintConfigPrettier,
9918
- ...tseslint.configs.recommended,
9919
- globalIgnores([
9920
- // Default ignores of eslint-config-next:
9921
- ".next/**",
9922
- "out/**",
9923
- "build/**",
9924
- "next-env.d.ts",
9925
- ]),
9926
- {
9927
- ...pluginReact.configs.flat.recommended,
9928
- languageOptions: {
9929
- ...pluginReact.configs.flat.recommended.languageOptions,
9930
- globals: {
9931
- ...globals.serviceworker,
9932
- ...globals.node,
9933
- },
9934
- },
9935
- },
9936
- {
9937
- plugins: {
9938
- "@next/next": pluginNext,
9939
- },
9940
- rules: {
9941
- ...pluginNext.configs.recommended.rules,
9942
- ...pluginNext.configs["core-web-vitals"].rules,
9943
- },
9944
- },
9945
- {
9946
- plugins: {
9947
- "react-hooks": pluginReactHooks,
9948
- },
9949
- settings: { react: { version: "detect" } },
9950
- rules: {
9951
- ...pluginReactHooks.configs.recommended.rules,
9952
- // React scope no longer necessary with new JSX transform.
9953
- "react/react-in-jsx-scope": "off",
10000
+ export function Link({
10001
+ href,
10002
+ children,
10003
+ style,
10004
+ ...rest
10005
+ }: PropsWithChildren<LinkProps & { style?: StyleXStyles }>) {
10006
+ return (
10007
+ <NextLink href={href} {...rest} {...stylex.props(styles.link, style)}>
10008
+ {children}
10009
+ </NextLink>
10010
+ );
10011
+ }
10012
+
10013
+ const styles = stylex.create({
10014
+ link: {
10015
+ color: "inherit",
10016
+ textDecorationLine: "underline",
10017
+ textDecorationColor: {
10018
+ default: colors.mutedForeground,
10019
+ ":hover": colors.foreground,
9954
10020
  },
10021
+ transitionProperty: "text-decoration-color",
10022
+ transitionDuration: "150ms",
9955
10023
  },
9956
- ];`
9957
- };
9958
- //#endregion
9959
- //#region src/templates/eslint-config/templates/react-internal.ts
9960
- var react_internal_default = {
9961
- filename: "packages/eslint-config/react-internal.js",
9962
- template: `import js from "@eslint/js";
9963
- import eslintConfigPrettier from "eslint-config-prettier";
9964
- import tseslint from "typescript-eslint";
9965
- import pluginReactHooks from "eslint-plugin-react-hooks";
9966
- import pluginReact from "eslint-plugin-react";
9967
- import globals from "globals";
9968
- import { config as baseConfig } from "./base.js";
10024
+ });
10025
+ `
10026
+ },
10027
+ {
10028
+ filename: "packages/ui/src/logo.tsx",
10029
+ template: `import * as stylex from "@stylexjs/stylex";
10030
+ import type { StyleXStyles } from "@stylexjs/stylex";
10031
+ import { colors } from "./tokens.stylex";
9969
10032
 
9970
- /**
9971
- * A custom ESLint configuration for libraries that use React.
9972
- *
9973
- * @type {import("eslint").Linter.Config[]} */
9974
- export const config = [
9975
- ...baseConfig,
9976
- js.configs.recommended,
9977
- eslintConfigPrettier,
10033
+ interface LogoProps {
10034
+ style?: StyleXStyles;
10035
+ }
10036
+
10037
+ export function Logo({ style }: LogoProps) {
10038
+ return (
10039
+ <svg
10040
+ width="196"
10041
+ height="138"
10042
+ viewBox="0 0 196 138"
10043
+ fill="none"
10044
+ xmlns="http://www.w3.org/2000/svg"
10045
+ {...stylex.props(styles.logo, style)}
10046
+ >
10047
+ <path
10048
+ d="M98 35C102.665 35 107.243 35.2232 111.707 35.6514C111.243 38.1972 111 40.8202 111 43.5C111 67.5244 130.476 87 154.5 87C165.156 87 174.914 83.1658 182.478 76.8057C183.476 79.9455 184 83.186 184 86.5C184 114.943 145.496 138 98 138C50.5035 138 12 114.943 12 86.5C12 83.1861 12.5228 79.9454 13.5215 76.8057C21.0851 83.1661 30.8441 87 41.5 87C65.5244 87 85 67.5244 85 43.5C85 40.8202 84.7559 38.1973 84.292 35.6514C88.7559 35.2232 93.3345 35 98 35ZM38.5 0C59.763 0 77 17.237 77 38.5C77 59.763 59.763 77 38.5 77C17.237 77 0 59.763 0 38.5C0 17.237 17.237 0 38.5 0ZM157.5 0C178.763 0 196 17.237 196 38.5C196 59.763 178.763 77 157.5 77C136.237 77 119 59.763 119 38.5C119 17.237 136.237 0 157.5 0Z"
10049
+ fill="currentColor"
10050
+ />
10051
+ </svg>
10052
+ );
10053
+ }
10054
+
10055
+ const styles = stylex.create({
10056
+ logo: {
10057
+ color: colors.foreground,
10058
+ },
10059
+ });
10060
+ `
10061
+ },
10062
+ {
10063
+ filename: "packages/ui/src/globals.css",
10064
+ template: `@layer resets {
10065
+ *,
10066
+ *::before,
10067
+ *::after {
10068
+ box-sizing: border-box;
10069
+ }
10070
+
10071
+ * {
10072
+ margin: 0;
10073
+ padding: 0;
10074
+ }
10075
+
10076
+ html,
10077
+ body {
10078
+ height: 100%;
10079
+ }
10080
+
10081
+ html {
10082
+ -webkit-font-smoothing: antialiased;
10083
+ -moz-osx-font-smoothing: grayscale;
10084
+ }
10085
+ }
10086
+
10087
+ @stylex;
10088
+ `
10089
+ },
10090
+ tsconfig_default$1,
10091
+ {
10092
+ when: (s) => s.nest !== "di-only",
10093
+ filename: "apps/web/package.json",
10094
+ template: `{
10095
+ "name": "web",
10096
+ "version": "0.1.0",
10097
+ "type": "module",
10098
+ "private": true,
10099
+ "scripts": {
10100
+ "dev": "next dev --port 3000",
10101
+ "build": "next build",
10102
+ "start": "next start",
10103
+ "typecheck": "next typegen && tsc --noEmit"
10104
+ },
10105
+ "dependencies": {
10106
+ "@<%= projectName %>/auth": "workspace:*",
10107
+ "@<%= projectName %>/ui": "workspace:*",
10108
+ "@stylexjs/stylex": "<%= versions["@stylexjs/stylex"] %>",
10109
+ "dotenv": "<%= versions.dotenv %>",
10110
+ "@tanstack/react-form": "<%= versions["@tanstack/react-form"] %>",
10111
+ "@tanstack/react-query": "<%= versions["@tanstack/react-query"] %>",
10112
+ "better-auth": "<%= versions["better-auth"] %>",
10113
+ "next": "<%= versions.next %>",
10114
+ "react": "<%= versions.react %>",
10115
+ "react-dom": "<%= versions["react-dom"] %>"
10116
+ },
10117
+ "devDependencies": {
10118
+ "@<%= projectName %>/typescript-config": "workspace:*",
10119
+ "@stylexjs/babel-plugin": "<%= versions["@stylexjs/babel-plugin"] %>",
10120
+ "@stylexjs/postcss-plugin": "<%= versions["@stylexjs/postcss-plugin"] %>",
10121
+ "@types/node": "<%= versions["@types/node"] %>",
10122
+ "@types/react": "<%= versions["@types/react"] %>",
10123
+ "@types/react-dom": "<%= versions["@types/react-dom"] %>",
10124
+ "typescript": "<%= versions.typescript %>"
10125
+ }
10126
+ }`
10127
+ },
10128
+ {
10129
+ when: (s) => s.nest === "di-only",
10130
+ filename: "apps/web/package.json",
10131
+ template: `{
10132
+ "name": "web",
10133
+ "version": "0.1.0",
10134
+ "type": "module",
10135
+ "private": true,
10136
+ "scripts": {
10137
+ "dev": "next dev --port 3000",
10138
+ "build": "next build",
10139
+ "start": "next start"
10140
+ },
10141
+ "dependencies": {
10142
+ "@<%= projectName %>/api": "workspace:*",
10143
+ "@<%= projectName %>/auth": "workspace:*",
10144
+ "@<%= projectName %>/db": "workspace:*",
10145
+ "@<%= projectName %>/ui": "workspace:*",
10146
+ "@nestjs/common": "<%= versions["@nestjs/common"] %>",
10147
+ "@nestjs/core": "<%= versions["@nestjs/core"] %>",
10148
+ "reflect-metadata": "<%= versions["reflect-metadata"] %>",
10149
+ "@stylexjs/stylex": "<%= versions["@stylexjs/stylex"] %>",
10150
+ "dotenv": "<%= versions.dotenv %>",
10151
+ "@tanstack/react-form": "<%= versions["@tanstack/react-form"] %>",
10152
+ "@tanstack/react-query": "<%= versions["@tanstack/react-query"] %>",
10153
+ "better-auth": "<%= versions["better-auth"] %>",
10154
+ "next": "<%= versions.next %>",
10155
+ "react": "<%= versions.react %>",
10156
+ "react-dom": "<%= versions["react-dom"] %>"
10157
+ },
10158
+ "devDependencies": {
10159
+ "@<%= projectName %>/typescript-config": "workspace:*",
10160
+ "@babel/plugin-proposal-decorators": "<%= versions["@babel/plugin-proposal-decorators"] %>",
10161
+ "@babel/plugin-transform-class-properties": "<%= versions["@babel/plugin-transform-class-properties"] %>",
10162
+ "babel-plugin-transform-typescript-metadata": "<%= versions["babel-plugin-transform-typescript-metadata"] %>",
10163
+ "@stylexjs/babel-plugin": "<%= versions["@stylexjs/babel-plugin"] %>",
10164
+ "@stylexjs/postcss-plugin": "<%= versions["@stylexjs/postcss-plugin"] %>",
10165
+ "@types/node": "<%= versions["@types/node"] %>",
10166
+ "@types/react": "<%= versions["@types/react"] %>",
10167
+ "@types/react-dom": "<%= versions["@types/react-dom"] %>",
10168
+ "typescript": "<%= versions.typescript %>"
10169
+ }
10170
+ }`
10171
+ },
10172
+ {
10173
+ filename: "apps/web/babel.config.js",
10174
+ template: `import path from "node:path";
10175
+ import { fileURLToPath } from "node:url";
10176
+
10177
+ const dirname = path.dirname(fileURLToPath(import.meta.url));
10178
+
10179
+ const config = {
10180
+ presets: ["next/babel"],
10181
+ plugins: [
10182
+ <% if (nest === 'di-only') { %> "babel-plugin-transform-typescript-metadata",
10183
+ ["@babel/plugin-proposal-decorators", { version: "legacy" }],
10184
+ ["@babel/plugin-transform-class-properties", { loose: true }],
10185
+ <% } %> [
10186
+ "@stylexjs/babel-plugin",
10187
+ {
10188
+ dev: process.env.NODE_ENV !== "production",
10189
+ runtimeInjection: false,
10190
+ treeshakeCompensation: true,
10191
+ unstable_moduleResolution: {
10192
+ type: "commonJS",
10193
+ rootDir: path.join(dirname, "../.."),
10194
+ },
10195
+ },
10196
+ ],
10197
+ ],
10198
+ };
10199
+
10200
+ export default config;`
10201
+ },
10202
+ {
10203
+ filename: "apps/web/postcss.config.mjs",
10204
+ template: `import babelConfig from "./babel.config.js";
10205
+
10206
+ const config = {
10207
+ plugins: {
10208
+ "@stylexjs/postcss-plugin": {
10209
+ include: [
10210
+ "app/**/*.{js,jsx,ts,tsx}",
10211
+ "../../packages/ui/src/**/*.{js,jsx,ts,tsx}",
10212
+ ],
10213
+ babelConfig: {
10214
+ babelrc: false,
10215
+ parserOpts: { plugins: ["typescript", "jsx"] },
10216
+ plugins: babelConfig.plugins,
10217
+ },
10218
+ useCSSLayers: true,
10219
+ },
10220
+ },
10221
+ };
10222
+
10223
+ export default config;`
10224
+ },
10225
+ {
10226
+ filename: "apps/web/app/layout.tsx",
10227
+ template: `import type { Metadata } from "next";
10228
+ import localFont from "next/font/local";
10229
+ import * as stylex from "@stylexjs/stylex";
10230
+ import Providers from "@/app/providers";
10231
+ import { colors, fonts } from "@<%= projectName %>/ui/tokens.stylex";
10232
+ import "@<%= projectName %>/ui/globals.css";
10233
+
10234
+ const geistSans = localFont({
10235
+ src: "./fonts/GeistVF.woff",
10236
+ variable: "--font-geist-sans",
10237
+ });
10238
+ const geistMono = localFont({
10239
+ src: "./fonts/GeistMonoVF.woff",
10240
+ variable: "--font-geist-mono",
10241
+ });
10242
+
10243
+ export const metadata: Metadata = {
10244
+ title: "<%= projectName %>",
10245
+ description: "Next + Nest = Newt",
10246
+ icons: {
10247
+ icon: [
10248
+ { url: "/icon0.svg", type: "image/svg+xml" },
10249
+ { url: "/icon1.png", type: "image/png" },
10250
+ ],
10251
+ apple: "/apple-icon.png",
10252
+ },
10253
+ };
10254
+
10255
+ export default function RootLayout({
10256
+ children,
10257
+ }: Readonly<{
10258
+ children: React.ReactNode;
10259
+ }>) {
10260
+ return (
10261
+ <html lang="en" className={\`\${geistSans.variable} \${geistMono.variable}\`}>
10262
+ <body {...stylex.props(styles.body)}>
10263
+ <Providers>{children}</Providers>
10264
+ </body>
10265
+ </html>
10266
+ );
10267
+ }
10268
+
10269
+ const styles = stylex.create({
10270
+ body: {
10271
+ backgroundColor: colors.background,
10272
+ color: colors.foreground,
10273
+ fontFamily: fonts.sans,
10274
+ },
10275
+ });
10276
+ `
10277
+ },
10278
+ {
10279
+ when: (s) => !s.todoExample,
10280
+ filename: "apps/web/app/page.tsx",
10281
+ template: `'use client';
10282
+
10283
+ import { useQuery } from '@tanstack/react-query';
10284
+ import * as stylex from '@stylexjs/stylex';
10285
+ import { authClient } from '@/lib/auth-client';
10286
+ import { AuthForm } from '@/app/auth-form';
10287
+ import { Button } from '@<%= projectName %>/ui/button';
10288
+ import { Link } from '@<%= projectName %>/ui/link';
10289
+ import { Logo } from '@<%= projectName %>/ui/logo';
10290
+ import { colors, fonts, radii } from '@<%= projectName %>/ui/tokens.stylex';
10291
+
10292
+ export default function Home() {
10293
+ const { data: session, isPending } = authClient.useSession();
10294
+
10295
+ const { data: hello } = useQuery({
10296
+ queryKey: ['hello'],
10297
+ queryFn: () => fetch('/api/hello').then((r) => r.json()),
10298
+ });
10299
+
10300
+ return (
10301
+ <main {...stylex.props(styles.main)}>
10302
+ <div {...stylex.props(styles.header)}>
10303
+ <p {...stylex.props(styles.mono, styles.muted)}>apps/web/app/page.tsx</p>
10304
+ <p {...stylex.props(styles.muted)}>Delete me to get started!</p>
10305
+ </div>
10306
+
10307
+ <div {...stylex.props(styles.titleRow)}>
10308
+ <Logo style={styles.logo} />
10309
+ <div>
10310
+ <h1 {...stylex.props(styles.h1)}><%= projectName %></h1>
10311
+ <p {...stylex.props(styles.muted, styles.tagline)}>
10312
+ Next + Nest = Newt 💜
10313
+ </p>
10314
+ </div>
10315
+ </div>
10316
+
10317
+ <div {...stylex.props(styles.card)}>
10318
+ <p {...stylex.props(styles.eyebrow)}>next.js</p>
10319
+ <p {...stylex.props(styles.mono, styles.muted)}>apps/web/app/layout.tsx</p>
10320
+ <p {...stylex.props(styles.muted)}>Next.js rendering</p>
10321
+ </div>
10322
+
10323
+ <div {...stylex.props(styles.card)}>
10324
+ <p {...stylex.props(styles.eyebrow)}>nest.js</p>
10325
+ <p {...stylex.props(styles.mono, styles.muted)}>GET /api/hello</p>
10326
+ <pre {...stylex.props(styles.pre)}>
10327
+ <code>{JSON.stringify(hello, null, 2)}</code>
10328
+ </pre>
10329
+ </div>
10330
+
10331
+ <div {...stylex.props(styles.card)}>
10332
+ <p {...stylex.props(styles.eyebrow, styles.eyebrowSpaced)}>better-auth</p>
10333
+ {isPending ? (
10334
+ <p {...stylex.props(styles.muted)}>Loading…</p>
10335
+ ) : session ? (
10336
+ <div {...stylex.props(styles.signedIn)}>
10337
+ <p>Signed in as {session.user.name}</p>
10338
+ <Button onClick={() => void authClient.signOut()}>
10339
+ Sign out
10340
+ </Button>
10341
+ </div>
10342
+ ) : (
10343
+ <AuthForm />
10344
+ )}
10345
+ </div>
10346
+
10347
+ <div {...stylex.props(styles.footer)}>
10348
+ <p {...stylex.props(styles.muted)}>Learn more</p>
10349
+ <ul {...stylex.props(styles.list)}>
10350
+ <li>
10351
+ <Link href="https://newt-app.com">Documentation</Link>
10352
+ </li>
10353
+ <li>
10354
+ <Link href="https://github.com/zeevo/newt-app">GitHub</Link>
10355
+ </li>
10356
+ <li>
10357
+ <Link href="https://nextjs.org">Next.js</Link>
10358
+ </li>
10359
+ <li>
10360
+ <Link href="https://nestjs.com">NestJS</Link>
10361
+ </li>
10362
+ </ul>
10363
+ </div>
10364
+ </main>
10365
+ );
10366
+ }
10367
+
10368
+ const styles = stylex.create({
10369
+ main: {
10370
+ display: 'flex',
10371
+ flexDirection: 'column',
10372
+ gap: '1rem',
10373
+ maxWidth: '32rem',
10374
+ minHeight: '100%',
10375
+ marginInline: 'auto',
10376
+ paddingBlock: '2rem',
10377
+ paddingInline: '1rem',
10378
+ fontSize: '0.875rem',
10379
+ },
10380
+ header: {
10381
+ paddingBottom: '1rem',
10382
+ borderBottomColor: colors.border,
10383
+ borderBottomStyle: 'solid',
10384
+ borderBottomWidth: 1,
10385
+ },
10386
+ titleRow: {
10387
+ display: 'flex',
10388
+ alignItems: 'center',
10389
+ gap: '0.75rem',
10390
+ paddingBlock: '0.5rem',
10391
+ },
10392
+ logo: {
10393
+ width: '2.5rem',
10394
+ height: 'auto',
10395
+ },
10396
+ h1: {
10397
+ fontSize: '2.25rem',
10398
+ fontWeight: 900,
10399
+ letterSpacing: '-0.025em',
10400
+ },
10401
+ tagline: {
10402
+ letterSpacing: '0.1em',
10403
+ textTransform: 'uppercase',
10404
+ },
10405
+ card: {
10406
+ display: 'flex',
10407
+ flexDirection: 'column',
10408
+ gap: '0.25rem',
10409
+ padding: '1.5rem',
10410
+ borderColor: colors.border,
10411
+ borderRadius: radii.lg,
10412
+ borderStyle: 'solid',
10413
+ borderWidth: 1,
10414
+ },
10415
+ eyebrow: {
10416
+ fontFamily: fonts.mono,
10417
+ fontSize: '0.75rem',
10418
+ letterSpacing: '0.1em',
10419
+ textTransform: 'uppercase',
10420
+ color: colors.mutedForeground,
10421
+ },
10422
+ eyebrowSpaced: {
10423
+ marginBottom: '0.75rem',
10424
+ },
10425
+ pre: {
10426
+ marginTop: '0.5rem',
10427
+ padding: '0.75rem',
10428
+ fontFamily: fonts.mono,
10429
+ backgroundColor: 'oklch(0.269 0 0 / 0.5)',
10430
+ borderColor: colors.border,
10431
+ borderRadius: radii.sm,
10432
+ borderStyle: 'solid',
10433
+ borderWidth: 1,
10434
+ overflowX: 'auto',
10435
+ },
10436
+ signedIn: {
10437
+ display: 'flex',
10438
+ flexDirection: 'column',
10439
+ alignItems: 'flex-start',
10440
+ gap: '0.75rem',
10441
+ },
10442
+ footer: {
10443
+ display: 'flex',
10444
+ flexDirection: 'column',
10445
+ gap: '0.5rem',
10446
+ paddingBlock: '1rem',
10447
+ paddingInline: '0.5rem',
10448
+ },
10449
+ list: {
10450
+ display: 'flex',
10451
+ flexDirection: 'column',
10452
+ gap: '0.5rem',
10453
+ listStylePosition: 'inside',
10454
+ listStyleType: 'disc',
10455
+ },
10456
+ mono: {
10457
+ fontFamily: fonts.mono,
10458
+ },
10459
+ muted: {
10460
+ color: colors.mutedForeground,
10461
+ },
10462
+ });
10463
+ `
10464
+ },
10465
+ {
10466
+ filename: "apps/web/app/auth-form.tsx",
10467
+ template: `'use client';
10468
+
10469
+ import { useForm } from '@tanstack/react-form';
10470
+ import { useState } from 'react';
10471
+ import * as stylex from '@stylexjs/stylex';
10472
+ import { authClient } from '@/lib/auth-client';
10473
+ import { Button } from '@<%= projectName %>/ui/button';
10474
+ import { colors, radii } from '@<%= projectName %>/ui/tokens.stylex';
10475
+
10476
+ export function AuthForm() {
10477
+ const [tab, setTab] = useState<'signin' | 'signup'>('signup');
10478
+ const [error, setError] = useState('');
10479
+
10480
+ const form = useForm({
10481
+ defaultValues: { name: '', email: '', password: '' },
10482
+ onSubmit: async ({ value }) => {
10483
+ setError('');
10484
+ if (tab === 'signin') {
10485
+ const { error } = await authClient.signIn.email(value);
10486
+ if (error) setError(error.message ?? 'Sign in failed');
10487
+ } else {
10488
+ const { error } = await authClient.signUp.email(value);
10489
+ if (error) setError(error.message ?? 'Sign up failed');
10490
+ }
10491
+ },
10492
+ });
10493
+
10494
+ return (
10495
+ <>
10496
+ <div {...stylex.props(styles.tabs)}>
10497
+ <button
10498
+ onClick={() => setTab('signup')}
10499
+ {...stylex.props(styles.tab, tab === 'signup' && styles.tabActive)}
10500
+ >
10501
+ Sign up
10502
+ </button>
10503
+ <span {...stylex.props(styles.divider)}>|</span>
10504
+ <button
10505
+ onClick={() => setTab('signin')}
10506
+ {...stylex.props(styles.tab, tab === 'signin' && styles.tabActive)}
10507
+ >
10508
+ Sign in
10509
+ </button>
10510
+ </div>
10511
+
10512
+ <form
10513
+ onSubmit={(e) => {
10514
+ e.preventDefault();
10515
+ form.handleSubmit();
10516
+ }}
10517
+ {...stylex.props(styles.form)}
10518
+ >
10519
+ {tab === 'signup' && (
10520
+ <form.Field name="name">
10521
+ {(field) => (
10522
+ <div {...stylex.props(styles.field)}>
10523
+ <label {...stylex.props(styles.label)}>Name</label>
10524
+ <input
10525
+ type="text"
10526
+ autoComplete="name"
10527
+ value={field.state.value}
10528
+ onChange={(e) => field.handleChange(e.target.value)}
10529
+ required
10530
+ {...stylex.props(styles.input)}
10531
+ />
10532
+ </div>
10533
+ )}
10534
+ </form.Field>
10535
+ )}
10536
+
10537
+ <form.Field name="email">
10538
+ {(field) => (
10539
+ <div {...stylex.props(styles.field)}>
10540
+ <label {...stylex.props(styles.label)}>Email</label>
10541
+ <input
10542
+ type="email"
10543
+ autoComplete="email"
10544
+ value={field.state.value}
10545
+ onChange={(e) => field.handleChange(e.target.value)}
10546
+ required
10547
+ {...stylex.props(styles.input)}
10548
+ />
10549
+ </div>
10550
+ )}
10551
+ </form.Field>
10552
+
10553
+ <form.Field name="password">
10554
+ {(field) => (
10555
+ <div {...stylex.props(styles.field)}>
10556
+ <label {...stylex.props(styles.label)}>Password</label>
10557
+ <input
10558
+ type="password"
10559
+ autoComplete={
10560
+ tab === 'signin' ? 'current-password' : 'new-password'
10561
+ }
10562
+ value={field.state.value}
10563
+ onChange={(e) => field.handleChange(e.target.value)}
10564
+ required
10565
+ minLength={8}
10566
+ {...stylex.props(styles.input)}
10567
+ />
10568
+ </div>
10569
+ )}
10570
+ </form.Field>
10571
+
10572
+ {error && <p {...stylex.props(styles.error)}>{error}</p>}
10573
+
10574
+ <form.Subscribe selector={(s) => s.isSubmitting}>
10575
+ {(isSubmitting) => (
10576
+ <Button type="submit" disabled={isSubmitting} style={styles.submit}>
10577
+ {isSubmitting
10578
+ ? 'Loading…'
10579
+ : tab === 'signin'
10580
+ ? 'Sign in'
10581
+ : 'Create account'}
10582
+ </Button>
10583
+ )}
10584
+ </form.Subscribe>
10585
+ </form>
10586
+ </>
10587
+ );
10588
+ }
10589
+
10590
+ const styles = stylex.create({
10591
+ tabs: {
10592
+ display: 'flex',
10593
+ gap: '0.5rem',
10594
+ marginBottom: '1.5rem',
10595
+ fontSize: '0.875rem',
10596
+ },
10597
+ tab: {
10598
+ color: {
10599
+ default: colors.mutedForeground,
10600
+ ':hover': colors.foreground,
10601
+ },
10602
+ backgroundColor: 'transparent',
10603
+ borderStyle: 'none',
10604
+ cursor: 'pointer',
10605
+ padding: 0,
10606
+ fontFamily: 'inherit',
10607
+ fontSize: 'inherit',
10608
+ },
10609
+ tabActive: {
10610
+ color: colors.foreground,
10611
+ fontWeight: 600,
10612
+ },
10613
+ divider: {
10614
+ color: colors.border,
10615
+ },
10616
+ form: {
10617
+ display: 'flex',
10618
+ flexDirection: 'column',
10619
+ gap: '1rem',
10620
+ },
10621
+ field: {
10622
+ display: 'flex',
10623
+ flexDirection: 'column',
10624
+ gap: '0.25rem',
10625
+ },
10626
+ label: {
10627
+ fontSize: '0.875rem',
10628
+ fontWeight: 500,
10629
+ },
10630
+ input: {
10631
+ width: '100%',
10632
+ height: 36,
10633
+ paddingBlock: '0.25rem',
10634
+ paddingInline: '0.75rem',
10635
+ fontFamily: 'inherit',
10636
+ fontSize: '0.875rem',
10637
+ color: colors.foreground,
10638
+ backgroundColor: 'oklch(0.269 0 0 / 0.5)',
10639
+ borderColor: {
10640
+ default: colors.border,
10641
+ ':focus-visible': colors.mutedForeground,
10642
+ },
10643
+ borderRadius: radii.sm,
10644
+ borderStyle: 'solid',
10645
+ borderWidth: 1,
10646
+ outlineStyle: 'none',
10647
+ transitionProperty: 'border-color',
10648
+ transitionDuration: '150ms',
10649
+ },
10650
+ error: {
10651
+ fontSize: '0.875rem',
10652
+ color: colors.danger,
10653
+ },
10654
+ submit: {
10655
+ width: '100%',
10656
+ },
10657
+ });
10658
+ `
10659
+ }
10660
+ ] };
10661
+ //#endregion
10662
+ //#region src/templates/eslint-config/templates/package-json.ts
10663
+ var package_json_default$1 = {
10664
+ filename: "packages/eslint-config/package.json",
10665
+ template: `{
10666
+ "name": "@<%= projectName %>/eslint-config",
10667
+ "version": "0.0.0",
10668
+ "type": "module",
10669
+ "private": true,
10670
+ "exports": {
10671
+ "./base": "./base.js",
10672
+ "./next-js": "./next.js",
10673
+ "./react-internal": "./react-internal.js"
10674
+ },
10675
+ "devDependencies": {
10676
+ "@eslint/js": "<%= versions["@eslint/js"] %>",
10677
+ "@next/eslint-plugin-next": "<%= versions["@next/eslint-plugin-next"] %>",
10678
+ "eslint": "<%= versions.eslint %>",
10679
+ "eslint-config-prettier": "<%= versions["eslint-config-prettier"] %>",
10680
+ "eslint-plugin-only-warn": "<%= versions["eslint-plugin-only-warn"] %>",
10681
+ "eslint-plugin-react": "<%= versions["eslint-plugin-react"] %>",
10682
+ "eslint-plugin-react-hooks": "<%= versions["eslint-plugin-react-hooks"] %>",
10683
+ "eslint-plugin-turbo": "<%= versions["eslint-plugin-turbo"] %>",
10684
+ "globals": "<%= versions.globals %>",
10685
+ "typescript": "<%= versions.typescript %>",
10686
+ "typescript-eslint": "<%= versions["typescript-eslint"] %>"
10687
+ }
10688
+ }`
10689
+ };
10690
+ //#endregion
10691
+ //#region src/templates/eslint-config/templates/base.ts
10692
+ var base_default$1 = {
10693
+ filename: "packages/eslint-config/base.js",
10694
+ template: `import js from "@eslint/js";
10695
+ import eslintConfigPrettier from "eslint-config-prettier";
10696
+ import turboPlugin from "eslint-plugin-turbo";
10697
+ import tseslint from "typescript-eslint";
10698
+ import onlyWarn from "eslint-plugin-only-warn";
10699
+
10700
+ /**
10701
+ * A shared ESLint configuration for the repository.
10702
+ *
10703
+ * @type {import("eslint").Linter.Config[]}
10704
+ * */
10705
+ export const config = [
10706
+ js.configs.recommended,
10707
+ eslintConfigPrettier,
10708
+ ...tseslint.configs.recommended,
10709
+ {
10710
+ plugins: {
10711
+ turbo: turboPlugin,
10712
+ },
10713
+ rules: {
10714
+ "turbo/no-undeclared-env-vars": "warn",
10715
+ },
10716
+ },
10717
+ {
10718
+ plugins: {
10719
+ onlyWarn,
10720
+ },
10721
+ },
10722
+ {
10723
+ ignores: ["dist/**"],
10724
+ },
10725
+ ];`
10726
+ };
10727
+ //#endregion
10728
+ //#region src/templates/eslint-config/templates/next.ts
10729
+ var next_default = {
10730
+ filename: "packages/eslint-config/next.js",
10731
+ template: `import js from "@eslint/js";
10732
+ import { globalIgnores } from "eslint/config";
10733
+ import eslintConfigPrettier from "eslint-config-prettier";
10734
+ import tseslint from "typescript-eslint";
10735
+ import pluginReactHooks from "eslint-plugin-react-hooks";
10736
+ import pluginReact from "eslint-plugin-react";
10737
+ import globals from "globals";
10738
+ import pluginNext from "@next/eslint-plugin-next";
10739
+ import { config as baseConfig } from "./base.js";
10740
+
10741
+ /**
10742
+ * A custom ESLint configuration for libraries that use Next.js.
10743
+ *
10744
+ * @type {import("eslint").Linter.Config[]}
10745
+ * */
10746
+ export const nextJsConfig = [
10747
+ ...baseConfig,
10748
+ js.configs.recommended,
10749
+ eslintConfigPrettier,
10750
+ ...tseslint.configs.recommended,
10751
+ globalIgnores([
10752
+ // Default ignores of eslint-config-next:
10753
+ ".next/**",
10754
+ "out/**",
10755
+ "build/**",
10756
+ "next-env.d.ts",
10757
+ ]),
10758
+ {
10759
+ ...pluginReact.configs.flat.recommended,
10760
+ languageOptions: {
10761
+ ...pluginReact.configs.flat.recommended.languageOptions,
10762
+ globals: {
10763
+ ...globals.serviceworker,
10764
+ ...globals.node,
10765
+ },
10766
+ },
10767
+ },
10768
+ {
10769
+ plugins: {
10770
+ "@next/next": pluginNext,
10771
+ },
10772
+ rules: {
10773
+ ...pluginNext.configs.recommended.rules,
10774
+ ...pluginNext.configs["core-web-vitals"].rules,
10775
+ },
10776
+ },
10777
+ {
10778
+ plugins: {
10779
+ "react-hooks": pluginReactHooks,
10780
+ },
10781
+ settings: { react: { version: "detect" } },
10782
+ rules: {
10783
+ ...pluginReactHooks.configs.recommended.rules,
10784
+ // React scope no longer necessary with new JSX transform.
10785
+ "react/react-in-jsx-scope": "off",
10786
+ },
10787
+ },
10788
+ ];`
10789
+ };
10790
+ //#endregion
10791
+ //#region src/templates/eslint-config/templates/react-internal.ts
10792
+ var react_internal_default = {
10793
+ filename: "packages/eslint-config/react-internal.js",
10794
+ template: `import js from "@eslint/js";
10795
+ import eslintConfigPrettier from "eslint-config-prettier";
10796
+ import tseslint from "typescript-eslint";
10797
+ import pluginReactHooks from "eslint-plugin-react-hooks";
10798
+ import pluginReact from "eslint-plugin-react";
10799
+ import globals from "globals";
10800
+ import { config as baseConfig } from "./base.js";
10801
+
10802
+ /**
10803
+ * A custom ESLint configuration for libraries that use React.
10804
+ *
10805
+ * @type {import("eslint").Linter.Config[]} */
10806
+ export const config = [
10807
+ ...baseConfig,
10808
+ js.configs.recommended,
10809
+ eslintConfigPrettier,
9978
10810
  ...tseslint.configs.recommended,
9979
10811
  pluginReact.configs.flat.recommended,
9980
10812
  {
@@ -11093,6 +11925,7 @@ export async function GET() {
11093
11925
  }`
11094
11926
  },
11095
11927
  {
11928
+ when: (s) => !s.stylex,
11096
11929
  filename: "apps/web/package.json",
11097
11930
  template: `{
11098
11931
  "name": "web",
@@ -11966,7 +12799,7 @@ export function TodoList({
11966
12799
  //#endregion
11967
12800
  //#region src/templates/todo-example/templates/web-page.ts
11968
12801
  var web_page_default = {
11969
- when: (s) => s.todoExample && !s.shadcn,
12802
+ when: (s) => s.todoExample && !s.shadcn && !s.stylex,
11970
12803
  filename: "apps/web/app/page.tsx",
11971
12804
  template: `'use client';
11972
12805
 
@@ -12304,6 +13137,424 @@ export default function Home() {
12304
13137
  }`
12305
13138
  };
12306
13139
  //#endregion
13140
+ //#region src/templates/todo-example/templates/stylex-todo-list.ts
13141
+ var stylex_todo_list_default = {
13142
+ filename: "apps/web/app/todo-list.tsx",
13143
+ template: `'use client';
13144
+
13145
+ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
13146
+ import { useForm } from '@tanstack/react-form';
13147
+ import * as stylex from '@stylexjs/stylex';
13148
+ import { authClient } from '@/lib/auth-client';
13149
+ import { Button } from '@<%= projectName %>/ui/button';
13150
+ import { colors, radii } from '@<%= projectName %>/ui/tokens.stylex';
13151
+
13152
+ interface Todo {
13153
+ id: string;
13154
+ title: string;
13155
+ done: boolean;
13156
+ }
13157
+
13158
+ const api = {
13159
+ getTodos: (): Promise<Todo[]> => fetch('/api/todos').then((r) => r.json()),
13160
+ createTodo: (title: string): Promise<Todo> =>
13161
+ fetch('/api/todos', {
13162
+ method: 'POST',
13163
+ headers: { 'Content-Type': 'application/json' },
13164
+ body: JSON.stringify({ title }),
13165
+ }).then((r) => r.json()),
13166
+ toggleTodo: (id: string): Promise<Todo> =>
13167
+ fetch(\`/api/todos/\${id}/toggle\`, { method: 'PATCH' }).then((r) => r.json()),
13168
+ deleteTodo: (id: string): Promise<void> =>
13169
+ fetch(\`/api/todos/\${id}\`, { method: 'DELETE' }).then(() => undefined),
13170
+ };
13171
+
13172
+ export function TodoList({
13173
+ session,
13174
+ }: {
13175
+ session: { user: { email: string } };
13176
+ }) {
13177
+ const queryClient = useQueryClient();
13178
+
13179
+ const { data: todos = [], isPending } = useQuery({
13180
+ queryKey: ['todos'],
13181
+ queryFn: api.getTodos,
13182
+ });
13183
+
13184
+ const createMutation = useMutation({
13185
+ mutationFn: api.createTodo,
13186
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
13187
+ });
13188
+
13189
+ const toggleMutation = useMutation({
13190
+ mutationFn: api.toggleTodo,
13191
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
13192
+ });
13193
+
13194
+ const deleteMutation = useMutation({
13195
+ mutationFn: api.deleteTodo,
13196
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
13197
+ });
13198
+
13199
+ const form = useForm({
13200
+ defaultValues: { title: '' },
13201
+ onSubmit: async ({ value }) => {
13202
+ if (!value.title.trim()) return;
13203
+ createMutation.mutate(value.title.trim());
13204
+ form.reset();
13205
+ },
13206
+ });
13207
+
13208
+ return (
13209
+ <>
13210
+ <div {...stylex.props(styles.header)}>
13211
+ <h1 {...stylex.props(styles.h1)}>Todos</h1>
13212
+ <div {...stylex.props(styles.session)}>
13213
+ <span>{session.user.email}</span>
13214
+ <button
13215
+ {...stylex.props(styles.signOut)}
13216
+ onClick={() => authClient.signOut()}
13217
+ >
13218
+ Sign out
13219
+ </button>
13220
+ </div>
13221
+ </div>
13222
+
13223
+ <form
13224
+ onSubmit={(e) => {
13225
+ e.preventDefault();
13226
+ form.handleSubmit();
13227
+ }}
13228
+ {...stylex.props(styles.form)}
13229
+ >
13230
+ <form.Field name="title">
13231
+ {(field) => (
13232
+ <input
13233
+ value={field.state.value}
13234
+ onChange={(e) => field.handleChange(e.target.value)}
13235
+ placeholder="New todo…"
13236
+ {...stylex.props(styles.input)}
13237
+ />
13238
+ )}
13239
+ </form.Field>
13240
+
13241
+ <form.Subscribe selector={(s) => s.isSubmitting}>
13242
+ {(isSubmitting) => (
13243
+ <Button type="submit" disabled={isSubmitting || createMutation.isPending}>
13244
+ Add
13245
+ </Button>
13246
+ )}
13247
+ </form.Subscribe>
13248
+ </form>
13249
+
13250
+ {isPending ? (
13251
+ <p {...stylex.props(styles.muted)}>Loading…</p>
13252
+ ) : (
13253
+ <ul {...stylex.props(styles.list)}>
13254
+ {todos.map((todo) => (
13255
+ <li key={todo.id} {...stylex.props(styles.item)}>
13256
+ <input
13257
+ type="checkbox"
13258
+ checked={todo.done}
13259
+ onChange={() => toggleMutation.mutate(todo.id)}
13260
+ />
13261
+ <span {...stylex.props(styles.title, todo.done && styles.titleDone)}>
13262
+ {todo.title}
13263
+ </span>
13264
+ <button
13265
+ onClick={() => deleteMutation.mutate(todo.id)}
13266
+ {...stylex.props(styles.remove)}
13267
+ >
13268
+ ×
13269
+ </button>
13270
+ </li>
13271
+ ))}
13272
+ </ul>
13273
+ )}
13274
+
13275
+ {!isPending && todos.length === 0 && (
13276
+ <p {...stylex.props(styles.muted)}>No todos yet.</p>
13277
+ )}
13278
+ </>
13279
+ );
13280
+ }
13281
+
13282
+ const styles = stylex.create({
13283
+ header: {
13284
+ display: 'flex',
13285
+ alignItems: 'center',
13286
+ justifyContent: 'space-between',
13287
+ marginBottom: '2rem',
13288
+ },
13289
+ h1: {
13290
+ fontSize: '1.5rem',
13291
+ fontWeight: 600,
13292
+ },
13293
+ session: {
13294
+ display: 'flex',
13295
+ alignItems: 'center',
13296
+ gap: '0.75rem',
13297
+ fontSize: '0.875rem',
13298
+ color: colors.mutedForeground,
13299
+ },
13300
+ signOut: {
13301
+ color: {
13302
+ default: 'inherit',
13303
+ ':hover': colors.foreground,
13304
+ },
13305
+ backgroundColor: 'transparent',
13306
+ borderStyle: 'none',
13307
+ cursor: 'pointer',
13308
+ padding: 0,
13309
+ fontFamily: 'inherit',
13310
+ fontSize: 'inherit',
13311
+ },
13312
+ form: {
13313
+ display: 'flex',
13314
+ gap: '0.5rem',
13315
+ marginBottom: '1.5rem',
13316
+ },
13317
+ input: {
13318
+ flexGrow: 1,
13319
+ height: 36,
13320
+ paddingBlock: '0.25rem',
13321
+ paddingInline: '0.75rem',
13322
+ fontFamily: 'inherit',
13323
+ fontSize: '0.875rem',
13324
+ color: colors.foreground,
13325
+ backgroundColor: 'oklch(0.269 0 0 / 0.5)',
13326
+ borderColor: {
13327
+ default: colors.border,
13328
+ ':focus-visible': colors.mutedForeground,
13329
+ },
13330
+ borderRadius: radii.sm,
13331
+ borderStyle: 'solid',
13332
+ borderWidth: 1,
13333
+ outlineStyle: 'none',
13334
+ transitionProperty: 'border-color',
13335
+ transitionDuration: '150ms',
13336
+ },
13337
+ list: {
13338
+ listStyleType: 'none',
13339
+ },
13340
+ item: {
13341
+ display: 'flex',
13342
+ alignItems: 'center',
13343
+ gap: '0.75rem',
13344
+ paddingBlock: '0.75rem',
13345
+ borderTopColor: colors.border,
13346
+ borderTopStyle: 'solid',
13347
+ borderTopWidth: {
13348
+ default: 1,
13349
+ ':first-child': 0,
13350
+ },
13351
+ },
13352
+ title: {
13353
+ flexGrow: 1,
13354
+ fontSize: '0.875rem',
13355
+ },
13356
+ titleDone: {
13357
+ color: colors.mutedForeground,
13358
+ textDecorationLine: 'line-through',
13359
+ },
13360
+ remove: {
13361
+ color: {
13362
+ default: colors.mutedForeground,
13363
+ ':hover': colors.danger,
13364
+ },
13365
+ backgroundColor: 'transparent',
13366
+ borderStyle: 'none',
13367
+ cursor: 'pointer',
13368
+ padding: 0,
13369
+ fontSize: '1.125rem',
13370
+ lineHeight: 1,
13371
+ },
13372
+ muted: {
13373
+ fontSize: '0.875rem',
13374
+ color: colors.mutedForeground,
13375
+ },
13376
+ });
13377
+ `
13378
+ };
13379
+ //#endregion
13380
+ //#region src/templates/todo-example/templates/stylex-page.ts
13381
+ var stylex_page_default = {
13382
+ when: (s) => s.todoExample && s.stylex,
13383
+ filename: "apps/web/app/page.tsx",
13384
+ template: `'use client';
13385
+
13386
+ import { useQuery } from '@tanstack/react-query';
13387
+ import * as stylex from '@stylexjs/stylex';
13388
+ import { authClient } from '@/lib/auth-client';
13389
+ import { AuthForm } from '@/app/auth-form';
13390
+ import { Link } from '@<%= projectName %>/ui/link';
13391
+ import { Logo } from '@<%= projectName %>/ui/logo';
13392
+ import { TodoList } from '@/app/todo-list';
13393
+ import { colors, fonts, radii } from '@<%= projectName %>/ui/tokens.stylex';
13394
+
13395
+ export default function Home() {
13396
+ const { data: session, isPending } = authClient.useSession();
13397
+
13398
+ const { data: hello } = useQuery({
13399
+ queryKey: ['hello'],
13400
+ queryFn: () => fetch('/api/hello').then((r) => r.json()),
13401
+ });
13402
+
13403
+ return (
13404
+ <main {...stylex.props(styles.main)}>
13405
+ <div {...stylex.props(styles.header)}>
13406
+ <p {...stylex.props(styles.mono, styles.muted)}>apps/web/app/page.tsx</p>
13407
+ <p {...stylex.props(styles.muted)}>Delete me to get started!</p>
13408
+ </div>
13409
+
13410
+ <div {...stylex.props(styles.titleRow)}>
13411
+ <Logo style={styles.logo} />
13412
+ <div>
13413
+ <h1 {...stylex.props(styles.h1)}><%= projectName %></h1>
13414
+ <p {...stylex.props(styles.muted, styles.tagline)}>
13415
+ Next + Nest = Newt 💜
13416
+ </p>
13417
+ </div>
13418
+ </div>
13419
+
13420
+ <div {...stylex.props(styles.card)}>
13421
+ <p {...stylex.props(styles.eyebrow)}>next.js</p>
13422
+ <p {...stylex.props(styles.mono, styles.muted)}>apps/web/app/layout.tsx</p>
13423
+ <p {...stylex.props(styles.muted)}>Next.js rendering</p>
13424
+ </div>
13425
+
13426
+ <div {...stylex.props(styles.card)}>
13427
+ <p {...stylex.props(styles.eyebrow)}>nest.js</p>
13428
+ <p {...stylex.props(styles.mono, styles.muted)}>GET /api/hello</p>
13429
+ <pre {...stylex.props(styles.pre)}>
13430
+ <code>{JSON.stringify(hello, null, 2)}</code>
13431
+ </pre>
13432
+ </div>
13433
+
13434
+ <div {...stylex.props(styles.card)}>
13435
+ <p {...stylex.props(styles.eyebrow, styles.eyebrowSpaced)}>better-auth</p>
13436
+ {isPending ? (
13437
+ <p {...stylex.props(styles.muted)}>Loading…</p>
13438
+ ) : session ? (
13439
+ <TodoList session={session} />
13440
+ ) : (
13441
+ <AuthForm />
13442
+ )}
13443
+ </div>
13444
+
13445
+ <div {...stylex.props(styles.footer)}>
13446
+ <p {...stylex.props(styles.muted)}>Learn more</p>
13447
+ <ul {...stylex.props(styles.list)}>
13448
+ <li>
13449
+ <Link href="https://newt-app.com">Documentation</Link>
13450
+ </li>
13451
+ <li>
13452
+ <Link href="https://github.com/zeevo/newt-app">GitHub</Link>
13453
+ </li>
13454
+ <li>
13455
+ <Link href="https://nextjs.org">Next.js</Link>
13456
+ </li>
13457
+ <li>
13458
+ <Link href="https://nestjs.com">NestJS</Link>
13459
+ </li>
13460
+ </ul>
13461
+ </div>
13462
+ </main>
13463
+ );
13464
+ }
13465
+
13466
+ const styles = stylex.create({
13467
+ main: {
13468
+ display: 'flex',
13469
+ flexDirection: 'column',
13470
+ gap: '1rem',
13471
+ maxWidth: '32rem',
13472
+ minHeight: '100%',
13473
+ marginInline: 'auto',
13474
+ paddingBlock: '2rem',
13475
+ paddingInline: '1rem',
13476
+ fontSize: '0.875rem',
13477
+ },
13478
+ header: {
13479
+ paddingBottom: '1rem',
13480
+ borderBottomColor: colors.border,
13481
+ borderBottomStyle: 'solid',
13482
+ borderBottomWidth: 1,
13483
+ },
13484
+ titleRow: {
13485
+ display: 'flex',
13486
+ alignItems: 'center',
13487
+ gap: '0.75rem',
13488
+ paddingBlock: '0.5rem',
13489
+ },
13490
+ logo: {
13491
+ width: '2.5rem',
13492
+ height: 'auto',
13493
+ },
13494
+ h1: {
13495
+ fontSize: '2.25rem',
13496
+ fontWeight: 900,
13497
+ letterSpacing: '-0.025em',
13498
+ },
13499
+ tagline: {
13500
+ letterSpacing: '0.1em',
13501
+ textTransform: 'uppercase',
13502
+ },
13503
+ card: {
13504
+ display: 'flex',
13505
+ flexDirection: 'column',
13506
+ gap: '0.25rem',
13507
+ padding: '1.5rem',
13508
+ borderColor: colors.border,
13509
+ borderRadius: radii.lg,
13510
+ borderStyle: 'solid',
13511
+ borderWidth: 1,
13512
+ },
13513
+ eyebrow: {
13514
+ fontFamily: fonts.mono,
13515
+ fontSize: '0.75rem',
13516
+ letterSpacing: '0.1em',
13517
+ textTransform: 'uppercase',
13518
+ color: colors.mutedForeground,
13519
+ },
13520
+ eyebrowSpaced: {
13521
+ marginBottom: '0.75rem',
13522
+ },
13523
+ pre: {
13524
+ marginTop: '0.5rem',
13525
+ padding: '0.75rem',
13526
+ fontFamily: fonts.mono,
13527
+ backgroundColor: 'oklch(0.269 0 0 / 0.5)',
13528
+ borderColor: colors.border,
13529
+ borderRadius: radii.sm,
13530
+ borderStyle: 'solid',
13531
+ borderWidth: 1,
13532
+ overflowX: 'auto',
13533
+ },
13534
+ footer: {
13535
+ display: 'flex',
13536
+ flexDirection: 'column',
13537
+ gap: '0.5rem',
13538
+ paddingBlock: '1rem',
13539
+ paddingInline: '0.5rem',
13540
+ },
13541
+ list: {
13542
+ display: 'flex',
13543
+ flexDirection: 'column',
13544
+ gap: '0.5rem',
13545
+ listStylePosition: 'inside',
13546
+ listStyleType: 'disc',
13547
+ },
13548
+ mono: {
13549
+ fontFamily: fonts.mono,
13550
+ },
13551
+ muted: {
13552
+ color: colors.mutedForeground,
13553
+ },
13554
+ });
13555
+ `
13556
+ };
13557
+ //#endregion
12307
13558
  //#region src/templates/todo-example/index.ts
12308
13559
  const todoExampleApi = { templates: [
12309
13560
  todos_module_default,
@@ -12326,6 +13577,7 @@ const todoExampleDi = { templates: [
12326
13577
  ] };
12327
13578
  const todoExampleWeb = { templates: [web_todo_list_default, web_page_default] };
12328
13579
  const todoExampleShadcn = { templates: [shadcn_todo_list_default, shadcn_page_default] };
13580
+ const todoExampleStylex = { templates: [stylex_todo_list_default, stylex_page_default] };
12329
13581
  //#endregion
12330
13582
  //#region src/templates/index.ts
12331
13583
  const staticDir = new URL("./static/", import.meta.url);
@@ -12339,7 +13591,7 @@ const E2E_FILES = [
12339
13591
  "apps/api/vitest.config.e2e.mts"
12340
13592
  ];
12341
13593
  function selectModules(selection) {
12342
- const { deployment, nest, todoExample, shadcn, database, linter, testing, extras } = selection;
13594
+ const { deployment, nest, todoExample, shadcn, stylex, database, linter, testing, extras } = selection;
12343
13595
  const deploymentModule = deployment === "standalone" ? deploymentStandalone : deployment === "spa" ? singleProcessStaticExport : null;
12344
13596
  const webModule = deployment === "spa" ? {
12345
13597
  ...web$1,
@@ -12358,7 +13610,7 @@ function selectModules(selection) {
12358
13610
  ...nest === "off" ? [] : [api$1],
12359
13611
  database === "postgres" ? dbPostgres : dbSqlite,
12360
13612
  auth,
12361
- shadcn ? shadcnUi : ui$1,
13613
+ shadcn ? shadcnUi : stylex ? stylexUi : ui$1,
12362
13614
  linter === "oxc" ? oxc : eslintConfig,
12363
13615
  ...extras.includes("anti-slop") ? [antiSlop] : [],
12364
13616
  typescriptConfig,
@@ -12369,7 +13621,7 @@ function selectModules(selection) {
12369
13621
  ...todoExample ? [
12370
13622
  todoExampleApi,
12371
13623
  ...nest === "di-only" ? [todoExampleDi] : [todoExampleControllers],
12372
- shadcn ? todoExampleShadcn : todoExampleWeb
13624
+ shadcn ? todoExampleShadcn : stylex ? todoExampleStylex : todoExampleWeb
12373
13625
  ] : []
12374
13626
  ];
12375
13627
  }
@@ -12476,6 +13728,13 @@ function validateExtrasCombo(extras, linter) {
12476
13728
  };
12477
13729
  return { valid: true };
12478
13730
  }
13731
+ function validateStylingCombo(shadcn, stylex) {
13732
+ if (shadcn && stylex) return {
13733
+ valid: false,
13734
+ error: "--shadcn cannot be combined with --stylex.\nshadcn/ui components are written in Tailwind utility classes, which StyleX does\nnot compile. Pick one styling system: drop --stylex for shadcn/ui, or drop\n--shadcn for StyleX."
13735
+ };
13736
+ return { valid: true };
13737
+ }
12479
13738
  function validateDeploymentCombo(deployment, nest) {
12480
13739
  if (deployment === "spa" && nest === "di-only") return {
12481
13740
  valid: false,
@@ -12631,6 +13890,7 @@ function buildPayload(report) {
12631
13890
  ci: detectCi(),
12632
13891
  explicitFlags: [...report.explicitFlags].sort().join(","),
12633
13892
  shadcn: selection.shadcn,
13893
+ stylex: selection.stylex,
12634
13894
  testing: selection.testing,
12635
13895
  database: selection.database,
12636
13896
  linter: selection.linter,
@@ -12704,6 +13964,10 @@ async function doInit(options) {
12704
13964
  message: "Use shadcn/ui?",
12705
13965
  initialValue: true
12706
13966
  }),
13967
+ stylex: ({ results }) => results.shadcn ? void 0 : p.confirm({
13968
+ message: "Use StyleX instead of Tailwind?",
13969
+ initialValue: false
13970
+ }),
12707
13971
  nest: () => p.select({
12708
13972
  message: "NestJS?",
12709
13973
  options: [
@@ -12809,6 +14073,7 @@ async function doInit(options) {
12809
14073
  process.exit(0);
12810
14074
  } });
12811
14075
  const useShadcn = options.nonInteractive ? options.shadcn : answers.shadcn ?? true;
14076
+ const useStylex = options.nonInteractive ? options.stylex : answers.stylex ?? false;
12812
14077
  const testing = options.nonInteractive ? options.testing : answers.testing ?? "jest";
12813
14078
  const database = options.nonInteractive ? options.database : answers.database ?? "sqlite";
12814
14079
  const linter = options.nonInteractive ? options.linter : answers.linter ?? "eslint";
@@ -12816,6 +14081,8 @@ async function doInit(options) {
12816
14081
  const nest = options.nonInteractive ? options.nest : answers.nest ?? "on";
12817
14082
  const todoExample = options.nonInteractive ? options.includeExample : nest !== "off" && (answers.todoExample ?? true);
12818
14083
  const extras = options.nonInteractive ? options.extras : answers.extras ?? [];
14084
+ const stylingCombo = validateStylingCombo(useShadcn, useStylex);
14085
+ if (!stylingCombo.valid) throw new Error(stylingCombo.error);
12819
14086
  const deploymentCombo = validateDeploymentCombo(deployment, nest);
12820
14087
  if (!deploymentCombo.valid) throw new Error(deploymentCombo.error);
12821
14088
  const exampleCombo = validateExampleCombo(todoExample, nest);
@@ -12827,6 +14094,7 @@ async function doInit(options) {
12827
14094
  nest,
12828
14095
  todoExample,
12829
14096
  shadcn: useShadcn,
14097
+ stylex: useStylex,
12830
14098
  database,
12831
14099
  linter,
12832
14100
  testing,
@@ -12895,10 +14163,11 @@ async function doInit(options) {
12895
14163
  }
12896
14164
  }
12897
14165
  const program = new Command();
12898
- program.name("create-newt-app").version(version).description("Create a new newt-app monorepo").argument("[name]").option("-ni, --no-install", "Skip pnpm install", true).option("-ng, --no-git", "Skip git initialization", true).option("--shadcn", "Include shadcn/ui", false).option("--testing <framework>", "Testing framework: vitest or jest", "jest").option("--database <database>", "Database: sqlite or postgres", "sqlite").option("--linter <linter>", "Linter: eslint or oxc", "eslint").option("--deployment <strategy>", "Deployment: none, standalone, or spa", "none").option("--nest <mode>", "NestJS: on, off, or di-only", "on").option("--include-example", "Include the todo example", false).option("--extras <list>", "Extras, comma-separated: anti-slop", "").action(async (name, options, command) => {
14166
+ program.name("create-newt-app").version(version).description("Create a new newt-app monorepo").argument("[name]").option("-ni, --no-install", "Skip pnpm install", true).option("-ng, --no-git", "Skip git initialization", true).option("--shadcn", "Include shadcn/ui", false).option("--stylex", "Use StyleX instead of Tailwind", false).option("--testing <framework>", "Testing framework: vitest or jest", "jest").option("--database <database>", "Database: sqlite or postgres", "sqlite").option("--linter <linter>", "Linter: eslint or oxc", "eslint").option("--deployment <strategy>", "Deployment: none, standalone, or spa", "none").option("--nest <mode>", "NestJS: on, off, or di-only", "on").option("--include-example", "Include the todo example", false).option("--extras <list>", "Extras, comma-separated: anti-slop", "").action(async (name, options, command) => {
12899
14167
  intro(`Create a ${chalk.blue("newt")} app.`);
12900
14168
  const explicitFlags = Object.entries({
12901
14169
  shadcn: "--shadcn",
14170
+ stylex: "--stylex",
12902
14171
  testing: "--testing",
12903
14172
  database: "--database",
12904
14173
  linter: "--linter",
@@ -12951,6 +14220,7 @@ program.name("create-newt-app").version(version).description("Create a new newt-
12951
14220
  git: options.git,
12952
14221
  nonInteractive,
12953
14222
  shadcn: options.shadcn,
14223
+ stylex: options.stylex,
12954
14224
  testing: options.testing,
12955
14225
  database: options.database,
12956
14226
  linter: options.linter,