juo 0.3.0-alpha.0 → 0.3.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +1 -1
  2. package/bin/dev.js +15 -4
  3. package/dist/commands/blocks/dev.d.ts +2 -2
  4. package/dist/commands/create.d.ts +4 -4
  5. package/dist/commands/create.js +85 -38
  6. package/dist/commands/generate.d.ts +5 -5
  7. package/dist/commands/publish/index.d.ts +2 -2
  8. package/dist/lib/index.d.ts +2 -0
  9. package/dist/lib/index.js +1 -1
  10. package/dist/{packageGenerator-Bx2FAq2Y.js → packageGenerator-BToocy-h.js} +6 -7
  11. package/oclif.manifest.json +1 -1
  12. package/package.json +1 -1
  13. package/templates/.storybook/preview-head.html.liquid +3 -5
  14. package/templates/block/preact/index.ts.liquid +65 -10
  15. package/templates/block/preact/{{block.clsName}}.tsx.liquid +100 -130
  16. package/templates/block/react/index.ts.liquid +64 -8
  17. package/templates/block/react/{{block.clsName}}.tsx.liquid +109 -61
  18. package/templates/configFiles/src/main.ts.liquid +5 -0
  19. package/templates/configFiles/vite-env.d.ts.liquid +11 -1
  20. package/templates/configFiles/vite.config.ts.liquid +1 -1
  21. package/templates/css/styles.css +31 -35
  22. package/templates/dev/index.html.liquid +18 -2
  23. package/templates/dev/vite/blocks-shim.ts.liquid +6 -0
  24. package/templates/dev/vite/juo-editor-plugin.ts.liquid +23 -2
  25. package/templates/dev/vite/mock-login.ts.liquid +83 -0
  26. package/templates/dev/vite/mock-services.ts.liquid +140 -0
  27. package/templates/dev/vite/theme-shell.ts.liquid +267 -0
  28. package/templates/dev/vite/workflowOverlay.ts.liquid +280 -0
  29. package/templates/stories/{{block.clsName}}.stories.tsx.liquid +6 -3
  30. package/templates/tailwind/postcss.config.js.liquid +6 -0
  31. package/templates/tailwind/src/tailwind.css.liquid +4 -2
  32. package/templates/tailwind/tailwind.config.cjs.liquid +15 -0
  33. package/templates/dev/src/main.ts.liquid +0 -136
  34. package/templates/tailwind/vite.config.ts.liquid +0 -35
package/README.md CHANGED
@@ -20,7 +20,7 @@ $ npm install -g juo
20
20
  $ juo COMMAND
21
21
  running command...
22
22
  $ juo (--version)
23
- juo/0.3.0-alpha.0 linux-x64 node-v22.21.0
23
+ juo/0.3.0-alpha.2 linux-x64 node-v22.21.0
24
24
  $ juo --help [COMMAND]
25
25
  USAGE
26
26
  $ juo COMMAND
package/bin/dev.js CHANGED
@@ -4,9 +4,20 @@ import {execute} from '@oclif/core'
4
4
  import {readFileSync} from 'node:fs'
5
5
  import {fileURLToPath} from 'node:url'
6
6
 
7
- const editorPkg = JSON.parse(
8
- readFileSync(fileURLToPath(new URL('../../editor/package.json', import.meta.url)), 'utf8'),
9
- )
10
- process.env.BLOCKS_EDITOR_VERSION = editorPkg.version
7
+ // Dev mode runs the TypeScript source through tsx, so tsdown's build-time
8
+ // `define` substitutions (see tsdown.config.ts) never happen. Reproduce them
9
+ // here from the workspace package.json files so `juo create` behaves like the
10
+ // built CLI.
11
+ const readVersion = (relPath) =>
12
+ JSON.parse(readFileSync(fileURLToPath(new URL(relPath, import.meta.url)), 'utf8')).version
13
+
14
+ process.env.BLOCKS_DEVTOOLS_VERSION = readVersion('../../devtools/overlay/package.json')
15
+ process.env.BLOCKS_EDITOR_VERSION = readVersion('../../editor/package.json')
16
+ process.env.BLOCKS_EXTENSIONS_VERSION = readVersion('../../extensions/package.json')
17
+ // `__CUSTOMER_UI_VERSION__` / `__BLOCKS_VERSION__` are bare globals in
18
+ // packageGenerator.ts (tsdown defines in prod); set them on globalThis so the
19
+ // free identifiers resolve in dev.
20
+ globalThis.__CUSTOMER_UI_VERSION__ = `^${readVersion('../../../components/customer-ui/package.json')}`
21
+ globalThis.__BLOCKS_VERSION__ = `^${readVersion('../../core/package.json')}`
11
22
 
12
23
  await execute({development: true, dir: import.meta.url})
@@ -1,12 +1,12 @@
1
1
  import { t as BaseCommand } from "../../base-command-BQVnm_gK.js";
2
- import * as _oclif_core_interfaces5 from "@oclif/core/interfaces";
2
+ import * as _oclif_core_interfaces0 from "@oclif/core/interfaces";
3
3
 
4
4
  //#region src/commands/blocks/dev.d.ts
5
5
  declare class Dev extends BaseCommand<typeof Dev> {
6
6
  static description: string;
7
7
  static examples: string[];
8
8
  static flags: {
9
- port: _oclif_core_interfaces5.OptionFlag<number, _oclif_core_interfaces5.CustomOptions>;
9
+ port: _oclif_core_interfaces0.OptionFlag<number, _oclif_core_interfaces0.CustomOptions>;
10
10
  };
11
11
  run(): Promise<void>;
12
12
  private resolvePackageJsonPath;
@@ -1,13 +1,13 @@
1
1
  import { Command } from "@oclif/core";
2
- import * as _oclif_core_interfaces9 from "@oclif/core/interfaces";
2
+ import * as _oclif_core_interfaces1 from "@oclif/core/interfaces";
3
3
 
4
4
  //#region src/commands/create.d.ts
5
5
  declare class Create extends Command {
6
6
  static description: string;
7
7
  static flags: {
8
- quickstart: _oclif_core_interfaces9.BooleanFlag<boolean>;
9
- storybook: _oclif_core_interfaces9.BooleanFlag<boolean>;
10
- verbose: _oclif_core_interfaces9.BooleanFlag<boolean>;
8
+ quickstart: _oclif_core_interfaces1.BooleanFlag<boolean>;
9
+ storybook: _oclif_core_interfaces1.BooleanFlag<boolean>;
10
+ verbose: _oclif_core_interfaces1.BooleanFlag<boolean>;
11
11
  };
12
12
  run(): Promise<void>;
13
13
  private getProjectConfig;
@@ -1,5 +1,5 @@
1
1
  import { r as BaseTemplateGenerator } from "../juoTemplateGenerator-RkinYN2l.js";
2
- import { t as PackageGenerator } from "../packageGenerator-Bx2FAq2Y.js";
2
+ import { t as PackageGenerator } from "../packageGenerator-BToocy-h.js";
3
3
  import { t as Generate } from "../generate-BiHo2p9_.js";
4
4
  import { Command, Flags } from "@oclif/core";
5
5
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
@@ -7,7 +7,7 @@ import path from "node:path";
7
7
  import { spawn } from "node:child_process";
8
8
  import { defineTSConfig, writeTSConfig } from "pkg-types";
9
9
  import { confirm, isCancel, outro, select, spinner, text } from "@clack/prompts";
10
- import { readdir, rm, stat, unlink } from "node:fs/promises";
10
+ import { rm } from "node:fs/promises";
11
11
 
12
12
  //#region src/utils/configFilesGenerator.ts
13
13
  var ConfigFilesGenerator = class extends BaseTemplateGenerator {
@@ -21,7 +21,9 @@ var ConfigFilesGenerator = class extends BaseTemplateGenerator {
21
21
  var DevHarnessGenerator = class extends BaseTemplateGenerator {
22
22
  generate(destDir, options) {
23
23
  this.renderTemplate("dev", destDir, {
24
- editorVersion: "0.25.0-alpha.1",
24
+ devtoolsVersion: "0.1.0-alpha.2",
25
+ editorVersion: "0.25.0-alpha.3",
26
+ extensionsVersion: "1.12.0-alpha.2",
25
27
  tailwind: options.tailwind
26
28
  });
27
29
  }
@@ -36,24 +38,8 @@ const COMMAND_CONFIG = {
36
38
  };
37
39
  var StorybookGenerator = class extends BaseTemplateGenerator {
38
40
  async appendStylesToPreview(destDir) {
39
- const storybookDir = path.join(destDir, ".storybook");
40
- const previewJsPath = path.join(storybookDir, "preview.js");
41
- const previewTsPath = path.join(storybookDir, "preview.ts");
42
- const importStatement = "import \"../src/styles.css\";\n";
43
41
  try {
44
- const previewJsExists = existsSync(previewJsPath);
45
- const previewTsExists = existsSync(previewTsPath);
46
- let targetPath;
47
- if (previewTsExists) targetPath = previewTsPath;
48
- else if (previewJsExists) targetPath = previewJsPath;
49
- else {
50
- targetPath = previewTsPath;
51
- mkdirSync(storybookDir, { recursive: true });
52
- writeFileSync(targetPath, importStatement);
53
- return;
54
- }
55
- const existingContent = readFileSync(targetPath, "utf8");
56
- if (!existingContent.includes("import \"../src/styles.css\"")) writeFileSync(targetPath, importStatement + existingContent);
42
+ this.prependImportToPreview(destDir, "import \"../src/styles.css\";");
57
43
  } catch (error) {
58
44
  throw new Error(`Error appending styles to preview: ${error}`);
59
45
  }
@@ -105,33 +91,94 @@ var StorybookGenerator = class extends BaseTemplateGenerator {
105
91
  const storybookDir = path.join(destDir, ".storybook");
106
92
  this.renderTemplate(".storybook", storybookDir, {});
107
93
  }
108
- async cleanUp(destDir) {
109
- try {
110
- const items = await readdir(destDir);
111
- const itemsToSkip = new Set(["assets", "Configure.mdx"]);
112
- for (const item of items) {
113
- const itemPath = path.join(destDir, item);
114
- const stats = await stat(itemPath);
115
- if (itemsToSkip.has(item)) continue;
116
- await (stats.isDirectory() ? rm(itemPath, {
117
- force: true,
118
- recursive: true
119
- }) : unlink(itemPath));
120
- }
121
- } catch (error) {
122
- throw new Error(`Error cleaning up storybook: ${error}`);
94
+ /**
95
+ * Prepends an import to the Storybook preview file (preview.ts/preview.js),
96
+ * creating it if Storybook init didn't. No-ops when the import is already
97
+ * present so repeated runs stay idempotent.
98
+ */
99
+ prependImportToPreview(destDir, importStatement) {
100
+ const storybookDir = path.join(destDir, ".storybook");
101
+ const previewTsPath = path.join(storybookDir, "preview.ts");
102
+ const previewJsPath = path.join(storybookDir, "preview.js");
103
+ const line = `${importStatement}\n`;
104
+ let targetPath;
105
+ if (existsSync(previewTsPath)) targetPath = previewTsPath;
106
+ else if (existsSync(previewJsPath)) targetPath = previewJsPath;
107
+ else {
108
+ mkdirSync(storybookDir, { recursive: true });
109
+ writeFileSync(previewTsPath, line);
110
+ return;
123
111
  }
112
+ const existingContent = readFileSync(targetPath, "utf8");
113
+ if (!existingContent.includes(importStatement)) writeFileSync(targetPath, line + existingContent);
114
+ }
115
+ /**
116
+ * The starter block renders `@juo/customer-ui` web components (`<juo-card>`,
117
+ * `<juo-text>`, `<juo-button>`). The dev harness registers them via the
118
+ * generated `register.ts`, but the Storybook preview has no such entry, so
119
+ * import the side-effecting bundle here to define the custom elements.
120
+ */
121
+ registerWebComponents(destDir) {
122
+ this.prependImportToPreview(destDir, "import \"@juo/customer-ui/web-components\";");
123
+ }
124
+ injectViteFinal(content, isTs) {
125
+ const viteFinal = [
126
+ " viteFinal: async (config) => {",
127
+ " // Storybook loads the project vite.config, which registers the dev-harness",
128
+ " // `juo()` plugin. That plugin injects the Blocks editor/devtools embed into",
129
+ " // every served HTML page, so strip it from the preview pipeline here.",
130
+ " config.plugins = (config.plugins ?? []).filter(",
131
+ ` (plugin) => !(plugin && typeof plugin === "object" && ${isTs ? "(plugin as { name?: string }).name === \"juo-editor\"" : "plugin.name === \"juo-editor\""}),`,
132
+ " );",
133
+ " return config;",
134
+ " },"
135
+ ].join("\n");
136
+ for (const pattern of [
137
+ /(const config\s*:\s*StorybookConfig\s*=\s*\{)/,
138
+ /(defineMain\(\{)/,
139
+ /(export default \{)/
140
+ ]) if (pattern.test(content)) return content.replace(pattern, `$1\n${viteFinal}`);
141
+ return content;
142
+ }
143
+ /**
144
+ * Rewrites the Storybook init `main.ts`/`main.js` so it (1) discovers stories
145
+ * from the top-level `stories/` dir the CLI emits block stories into, and
146
+ * (2) strips the dev-harness `juo()` plugin from the preview's vite pipeline.
147
+ */
148
+ async patchMainConfig(destDir) {
149
+ const storybookDir = path.join(destDir, ".storybook");
150
+ const tsPath = path.join(storybookDir, "main.ts");
151
+ const jsPath = path.join(storybookDir, "main.js");
152
+ const mainPath = existsSync(tsPath) ? tsPath : existsSync(jsPath) ? jsPath : null;
153
+ if (!mainPath) return;
154
+ let content = readFileSync(mainPath, "utf8");
155
+ content = content.replaceAll("../src/**", "../stories/**");
156
+ if (!content.includes("viteFinal")) content = this.injectViteFinal(content, mainPath.endsWith(".ts"));
157
+ writeFileSync(mainPath, content);
124
158
  }
125
159
  async postGenerate(destDir) {
126
- const storiesDir = path.join(destDir, "stories");
127
160
  try {
128
- if (!existsSync(storiesDir)) mkdirSync(storiesDir, { recursive: true });
129
- await this.cleanUp(storiesDir);
161
+ await this.removeExampleStories(destDir);
130
162
  await this.appendPreviewHead(destDir);
163
+ await this.patchMainConfig(destDir);
164
+ this.registerWebComponents(destDir);
131
165
  } catch (error) {
132
166
  throw new Error(`Error post-generating storybook: ${error}`);
133
167
  }
134
168
  }
169
+ /**
170
+ * Storybook init scaffolds example stories (Button/Header/Page) into
171
+ * `src/stories`. The CLI emits real block stories into the top-level
172
+ * `stories/` dir afterwards, so drop the scaffolding to avoid shipping
173
+ * unrelated example stories.
174
+ */
175
+ async removeExampleStories(destDir) {
176
+ const exampleDirs = [path.join(destDir, "src", "stories"), path.join(destDir, "stories")];
177
+ for (const dir of exampleDirs) if (existsSync(dir)) await rm(dir, {
178
+ force: true,
179
+ recursive: true
180
+ });
181
+ }
135
182
  };
136
183
 
137
184
  //#endregion
@@ -1,15 +1,15 @@
1
1
  import { Command } from "@oclif/core";
2
- import * as _oclif_core_interfaces0 from "@oclif/core/interfaces";
2
+ import * as _oclif_core_interfaces4 from "@oclif/core/interfaces";
3
3
 
4
4
  //#region src/commands/generate.d.ts
5
5
  declare class Generate extends Command {
6
6
  static description: string;
7
7
  static examples: string[];
8
8
  static flags: {
9
- name: _oclif_core_interfaces0.OptionFlag<string | undefined, _oclif_core_interfaces0.CustomOptions>;
10
- tailwind: _oclif_core_interfaces0.BooleanFlag<boolean>;
11
- type: _oclif_core_interfaces0.OptionFlag<string, _oclif_core_interfaces0.CustomOptions>;
12
- verbose: _oclif_core_interfaces0.BooleanFlag<boolean>;
9
+ name: _oclif_core_interfaces4.OptionFlag<string | undefined, _oclif_core_interfaces4.CustomOptions>;
10
+ tailwind: _oclif_core_interfaces4.BooleanFlag<boolean>;
11
+ type: _oclif_core_interfaces4.OptionFlag<string, _oclif_core_interfaces4.CustomOptions>;
12
+ verbose: _oclif_core_interfaces4.BooleanFlag<boolean>;
13
13
  };
14
14
  static id: string;
15
15
  run(): Promise<void>;
@@ -1,5 +1,5 @@
1
1
  import { t as BaseCommand } from "../../base-command-BQVnm_gK.js";
2
- import * as _oclif_core_interfaces7 from "@oclif/core/interfaces";
2
+ import * as _oclif_core_interfaces10 from "@oclif/core/interfaces";
3
3
 
4
4
  //#region src/commands/publish/index.d.ts
5
5
  declare class Publish extends BaseCommand<typeof Publish> {
@@ -7,7 +7,7 @@ declare class Publish extends BaseCommand<typeof Publish> {
7
7
  static description: string;
8
8
  static examples: string[];
9
9
  static flags: {
10
- theme: _oclif_core_interfaces7.OptionFlag<string, _oclif_core_interfaces7.CustomOptions>;
10
+ theme: _oclif_core_interfaces10.OptionFlag<string, _oclif_core_interfaces10.CustomOptions>;
11
11
  };
12
12
  getAllFiles(dirPath: string, basePath: string): string[];
13
13
  run(): Promise<void>;
@@ -7,7 +7,9 @@ interface TemplateScope {
7
7
  slug: string;
8
8
  tailwind?: boolean;
9
9
  };
10
+ devtoolsVersion?: string;
10
11
  editorVersion?: string;
12
+ extensionsVersion?: string;
11
13
  tailwind?: boolean;
12
14
  }
13
15
  declare abstract class BaseTemplateGenerator {
package/dist/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import { n as StoryGenerator, r as BaseTemplateGenerator, t as JuoTemplateGenerator } from "../juoTemplateGenerator-RkinYN2l.js";
2
- import { t as PackageGenerator } from "../packageGenerator-Bx2FAq2Y.js";
2
+ import { t as PackageGenerator } from "../packageGenerator-BToocy-h.js";
3
3
 
4
4
  export { BaseTemplateGenerator, JuoTemplateGenerator, PackageGenerator, StoryGenerator };
@@ -16,9 +16,6 @@ const FRAMEWORK_CONFIGS = {
16
16
  },
17
17
  react: {
18
18
  dependencies: {
19
- "@juo/blocks": "^1.0.0",
20
- "@mantine/core": "7.5.3",
21
- "@mantine/hooks": "7.5.3",
22
19
  react: "^18.2.0",
23
20
  "react-dom": "^18.2.0"
24
21
  },
@@ -53,8 +50,8 @@ var PackageGenerator = class {
53
50
  "postcss-prefix-selector": "^2.1.1",
54
51
  prettier: "^3.5.3",
55
52
  ...options.tailwind ? {
56
- "@tailwindcss/vite": "^4.1.17",
57
- tailwindcss: "^4.1.17"
53
+ autoprefixer: "^10.4.19",
54
+ tailwindcss: "^3.3.5"
58
55
  } : {},
59
56
  ...options.storybook ? { storybook: "^10.0.7" } : {},
60
57
  typebox: "^1.0.51",
@@ -83,14 +80,16 @@ var PackageGenerator = class {
83
80
  });
84
81
  const frameworkConfig = FRAMEWORK_CONFIGS[options.framework];
85
82
  baseConfig.dependencies = {
86
- "@juo/customer-ui": "^0.5.0-alpha.4",
83
+ "@juo/blocks": "^1.12.0-alpha.2",
84
+ "@juo/customer-ui": "^0.5.0-alpha.5",
87
85
  ...baseConfig.dependencies,
88
86
  ...frameworkConfig.dependencies
89
87
  };
90
88
  baseConfig.devDependencies = {
91
89
  ...baseConfig.devDependencies,
92
90
  ...frameworkConfig.devDependencies,
93
- ...options.storybook ? frameworkConfig.storybookDevDependencies : {}
91
+ ...options.storybook ? frameworkConfig.storybookDevDependencies : {},
92
+ "lit-html": "3.3.0"
94
93
  };
95
94
  return this.sort(baseConfig);
96
95
  }
@@ -179,5 +179,5 @@
179
179
  ]
180
180
  }
181
181
  },
182
- "version": "0.3.0-alpha.0"
182
+ "version": "0.3.0-alpha.2"
183
183
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "juo",
3
3
  "description": "A CLI tool for the Juo platform",
4
- "version": "0.3.0-alpha.0",
4
+ "version": "0.3.0-alpha.2",
5
5
  "author": "Juo (https://juo.io)",
6
6
  "bin": {
7
7
  "juo": "./bin/run.js"
@@ -1,10 +1,8 @@
1
- <link
2
- rel="stylesheet"
3
- href="https://cdn.jsdelivr.net/npm/inter-ui@3.19.3/inter.min.css"
4
- />
1
+ <link rel="preconnect" href="https://rsms.me/" />
2
+ <link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
5
3
  <style>
6
4
  html {
7
- font-family: "Inter var", sans-serif !important;
5
+ font-family: InterVariable, Inter, sans-serif !important;
8
6
  -webkit-font-smoothing: antialiased;
9
7
  -moz-osx-font-smoothing: grayscale;
10
8
  }
@@ -1,7 +1,22 @@
1
1
  import { defineBlock } from "@juo/blocks";
2
2
  import { createPreactRenderer } from "@juo/blocks/preact";
3
- import { {{ block.clsName }} } from "./{{block.clsName}}.tsx";
4
- import type { FromSchema, JSONSchema } from "json-schema-to-ts";
3
+ import type { ExtendedJSONSchema, FromSchema } from "json-schema-to-ts";
4
+ import { {{ block.clsName }} } from "./{{ block.clsName }}.tsx";
5
+
6
+ // Default copy for this block, keyed by translation key. Shipped through the
7
+ // block's `locales` loader so the editor's translation panel can override each
8
+ // string per theme/locale. The keys here are the namespace for this block.
9
+ const enTranslations = {
10
+ title: "{{ block.framework | capitalize }} + TypeScript",
11
+ subtitle: "Starter Block",
12
+ };
13
+
14
+ // Allow the juo-specific schema keywords used below. `format: "color"` is a
15
+ // standard JSON Schema keyword and needs no extension.
16
+ type ExtendedSchema = ExtendedJSONSchema<{
17
+ "x-juo-control-type": string;
18
+ "x-juo-option-labels": Record<string, string>;
19
+ }>;
5
20
 
6
21
  const schema = {
7
22
  type: "object",
@@ -9,31 +24,71 @@ const schema = {
9
24
  props: {
10
25
  type: "object",
11
26
  properties: {
12
- title: { type: "string" },
13
- subtitle: { type: "string" },
14
- initialCount: { type: "number" },
27
+ // `x-juo-control-type: "inline-text"` -> edited directly on the canvas
28
+ // via <juo-text>; the edit is stored as a translation override.
29
+ title: {
30
+ type: "string",
31
+ "x-juo-control-type": "inline-text",
32
+ description: "Heading — edit inline on the canvas.",
33
+ },
34
+ subtitle: {
35
+ type: "string",
36
+ "x-juo-control-type": "inline-text",
37
+ description: "Supporting text — edit inline on the canvas.",
38
+ },
39
+ // `enum` -> Select control. `x-juo-option-labels` gives each option a
40
+ // friendly label in the editor.
41
+ buttonVariant: {
42
+ enum: ["solid", "outline", "ghost"],
43
+ title: "Button style",
44
+ "x-juo-option-labels": {
45
+ solid: "Solid",
46
+ outline: "Outline",
47
+ ghost: "Ghost",
48
+ },
49
+ },
50
+ // `format: "color"` -> Color control
51
+ accentColor: {
52
+ type: "string",
53
+ format: "color",
54
+ title: "Accent color",
55
+ description:
56
+ "Color for the icons. Leave empty to use the default neutral color.",
57
+ },
58
+ // `x-juo-control-type: "stepper"` -> Stepper control
59
+ initialCount: {
60
+ type: "number",
61
+ title: "Initial count",
62
+ "x-juo-control-type": "stepper",
63
+ },
15
64
  },
16
- required: ["title", "subtitle", "initialCount"],
65
+ required: ["title", "subtitle", "buttonVariant", "initialCount"],
17
66
  additionalProperties: false,
18
67
  },
19
68
  },
20
69
  required: ["props"],
21
70
  additionalProperties: false,
22
- } as const satisfies JSONSchema;
71
+ } as const satisfies ExtendedSchema;
23
72
 
24
73
  type Schema = FromSchema<typeof schema>;
25
74
  export type Props = Schema["props"];
26
75
 
27
- export const {{ block.clsName }}Block = defineBlock("{{ block.name }}", {
76
+ export const {{ block.clsName }}Block = defineBlock<Schema>("{{ block.name }}", {
28
77
  group: "theme",
29
78
  schema,
30
79
  initialValue: () => ({
31
80
  props: {
32
- title: "{{ block.framework | capitalize }} + TypeScript",
33
- subtitle: "Starter Block",
81
+ title: enTranslations.title,
82
+ subtitle: enTranslations.subtitle,
83
+ buttonVariant: "solid",
84
+ accentColor: "",
34
85
  initialCount: 0,
35
86
  },
36
87
  slots: {},
37
88
  }),
38
89
  renderer: createPreactRenderer({{ block.clsName }}),
90
+ locales: {
91
+ supported: ["en"],
92
+ load: async () => enTranslations,
93
+ },
39
94
  });