juo 0.0.1-alpha.4 → 0.0.2-pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
- import { defineBlock, createPreactRenderer } from "@juo/core";
2
- import { render } from "preact";
1
+ import { defineBlock } from "@juo/blocks";
2
+ import { createPreactRenderer } from "@juo/blocks/preact";
3
3
  import { {{ block.clsName }} } from "./{{block.clsName}}.tsx";
4
- import type { FromSchema, JSONSchema } from "json-schema-to-ts";
4
+ import type { FromSchema, JSONSchema } from "json-schema-to-ts";
5
5
 
6
6
  const schema = {
7
7
  type: "object",
@@ -35,6 +35,5 @@ export const {{ block.clsName }}Block = defineBlock("{{ block.name }}", {
35
35
  },
36
36
  slots: {},
37
37
  }),
38
- slots: [],
39
- renderer: createPreactRenderer((el: HTMLElement) => render(HelloWorld, el)),
38
+ renderer: createPreactRenderer({{ block.clsName }}),
40
39
  });
@@ -100,8 +100,7 @@ export function {{ block.clsName }}(props: Props) {
100
100
  }
101
101
 
102
102
  {% else %}
103
- import "../src/styles.css";
104
- {{ block | json }}
103
+ import "../../styles.css";
105
104
  const Counter = ({
106
105
  className,
107
106
  initialCount,
@@ -1,6 +1,5 @@
1
- import { defineBlock, createReactRenderer } from "@juo/orion-core";
2
- import { createElement } from "react";
3
- import { createRoot } from "react-dom/client";
1
+ import { defineBlock } from "@juo/blocks";
2
+ import { createReactRenderer } from "@juo/blocks/react";
4
3
  import { FromSchema, JSONSchema } from "json-schema-to-ts";
5
4
  import { {{ block.clsName }} } from "./{{ block.clsName }}.tsx";
6
5
 
@@ -35,7 +34,5 @@ export const {{ block.clsName }}Block = defineBlock<Schema>("{{ block.name }}",
35
34
  },
36
35
  slots: {},
37
36
  }),
38
- renderer: createReactRenderer((block, el) => {
39
- createRoot(el).render(createElement({{ block.clsName }}, block.props));
40
- }),
37
+ renderer: createReactRenderer({{ block.clsName }}),
41
38
  });
@@ -1,10 +1,9 @@
1
1
  import { useRef, useState } from "react";
2
2
  import { MantineProvider } from "@mantine/core";
3
3
  import type { Props } from ".";
4
- import ReactLogo from "../../assets/react-icon.svg?react";
5
4
 
6
- const Counter = ({ className }: { className: string }) => {
7
- const [count, setCount] = useState(0);
5
+ const Counter = ({ className, initialCount = 0 }: { className: string; initialCount?: number }) => {
6
+ const [count, setCount] = useState(initialCount);
8
7
  return (
9
8
  <button
10
9
  className={`px-4 py-2 rounded-md cursor-pointer ${className}`}
@@ -16,8 +16,18 @@ export default defineConfig({
16
16
  }),
17
17
  ],
18
18
  build: {
19
+ lib: {
20
+ entry: "src/blocks/index.ts",
21
+ formats: ["es"],
22
+ fileName: "index",
23
+ },
19
24
  rollupOptions: {
20
- external: ["@juo/orion-core"],
25
+ external: [
26
+ "@juo/blocks",
27
+ "react",
28
+ "react-dom",
29
+ "preact",
30
+ ],
21
31
  },
22
32
  },
23
33
  });
@@ -1,252 +0,0 @@
1
- import { Command, Flags } from "@oclif/core";
2
- import { isCancel, log, select, spinner, text } from "@clack/prompts";
3
- import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
4
- import path from "node:path";
5
- import { detectPackageManager } from "nypm";
6
- import slugify from "slugify";
7
- import { Liquid } from "liquidjs";
8
- import { fileURLToPath } from "node:url";
9
- import { readPackageJSON } from "pkg-types";
10
-
11
- //#region src/utils/baseTemplateGenerator.ts
12
- var BaseTemplateGenerator = class {
13
- renderTemplate(templateName, destDir, scope, fileFilter) {
14
- try {
15
- const templateDir = this.getTemplateDir(templateName);
16
- const engine = new Liquid();
17
- const files = this.getTemplateFiles(templateName);
18
- const filteredFiles = fileFilter ? files.filter(fileFilter) : files;
19
- for (const file of filteredFiles) {
20
- const filename = engine.parseAndRenderSync(file, scope).replace(/\.liquid$/, "");
21
- const tplPath = path.join(templateDir, file);
22
- const destPath = path.join(destDir, filename);
23
- mkdirSync(path.dirname(destPath), { recursive: true });
24
- writeFileSync(destPath, engine.parseAndRenderSync(readFileSync(tplPath, "utf-8"), scope));
25
- }
26
- } catch (error) {
27
- throw new Error(`Error rendering template ${templateName}: ${error}`);
28
- }
29
- }
30
- getTemplateDir(name) {
31
- const packageRoot = this.resolvePackageRoot();
32
- return path.join(packageRoot, "templates", name);
33
- }
34
- getTemplateFiles(name) {
35
- function scan(dirpath, baseDir) {
36
- return readdirSync(dirpath).flatMap((filename) => {
37
- const filepath = path.join(dirpath, filename);
38
- if (statSync(filepath).isDirectory()) return scan(filepath, baseDir);
39
- else return [path.relative(baseDir, filepath)];
40
- });
41
- }
42
- const templateDir = this.getTemplateDir(name);
43
- return scan(templateDir, templateDir);
44
- }
45
- resolvePackageRoot() {
46
- let currentPath = path.dirname(fileURLToPath(import.meta.url));
47
- while (!existsSync(path.join(currentPath, "package.json"))) {
48
- const parentDir = path.dirname(currentPath);
49
- if (parentDir === currentPath) throw new Error("Could not find package root");
50
- currentPath = parentDir;
51
- }
52
- return currentPath;
53
- }
54
- };
55
-
56
- //#endregion
57
- //#region src/utils/storyGenerator.ts
58
- var StoryGenerator = class extends BaseTemplateGenerator {
59
- async generate(destDir, options) {
60
- if (options.type === "block") await this.generateBlockTemplate(destDir, options);
61
- else await this.generateThemeTemplate(destDir, options);
62
- }
63
- async generateBlockTemplate(destDir, options) {
64
- const scope = { block: {
65
- slug: slugify(options.name, { lower: true }),
66
- name: options.name,
67
- clsName: slugify(options.name, { lower: true }).split("-").map((item) => `${item[0].toUpperCase()}${item.substring(1)}`).join(""),
68
- framework: options.framework
69
- } };
70
- if (["react", "preact"].includes(scope.block.framework)) {
71
- if (!existsSync(destDir)) mkdirSync(destDir, { recursive: true });
72
- this.renderTemplate("stories", destDir, scope);
73
- } else options.logger?.("Story generation skipped");
74
- }
75
- async generateThemeTemplate(destDir, options) {
76
- const themeScope = { theme: {
77
- name: options.name,
78
- slug: slugify(options.name, { lower: true }),
79
- framework: options.framework,
80
- clsName: slugify(options.name, { lower: true }).split("-").map((item) => `${item[0].toUpperCase()}${item.substring(1)}`).join("")
81
- } };
82
- if (options.framework === "react") this.renderTemplate("theme/react", destDir, themeScope, (filename) => filename.includes(".stories.tsx.liquid"));
83
- }
84
- };
85
-
86
- //#endregion
87
- //#region src/utils/juoTemplateGenerator.ts
88
- var JuoTemplateGenerator = class extends BaseTemplateGenerator {
89
- storyGenerator;
90
- constructor() {
91
- super();
92
- this.storyGenerator = new StoryGenerator();
93
- }
94
- async generate(destDir, options) {
95
- await this.generateBlockTemplate(destDir, options);
96
- }
97
- async generateBlockTemplate(destDir, options) {
98
- const scope = { block: {
99
- slug: slugify(options.name, { lower: true }),
100
- name: options.name,
101
- clsName: slugify(options.name, { lower: true }).split("-").map((item) => `${item[0].toUpperCase()}${item.substring(1)}`).join(""),
102
- tailwind: options.tailwind,
103
- framework: options.framework
104
- } };
105
- this.renderTemplate(`${options.type}/${options.framework}`, path.join(destDir, scope.block.slug), scope);
106
- options.logger?.("Adding block to theme");
107
- try {
108
- appendFileSync(path.join(destDir, "index.ts"), `export { ${scope.block.clsName}Block } from "./${scope.block.slug}";\n`);
109
- } catch (error) {
110
- options.logger?.("Error adding block to theme: " + error);
111
- throw error;
112
- }
113
- if (options.story) {
114
- const projectRoot = path.dirname(path.dirname(destDir));
115
- const storiesDir = path.join(projectRoot, "stories");
116
- try {
117
- await this.storyGenerator.generate(storiesDir, {
118
- name: scope.block.name,
119
- type: "block",
120
- framework: options.framework,
121
- tailwind: options.tailwind
122
- });
123
- } catch (error) {
124
- options.logger?.("Error generating story: " + error);
125
- throw error;
126
- }
127
- } else options.logger?.(`Story generation skipped (options.story = ${options.story})`);
128
- }
129
- appendStylesheet(destDir) {
130
- this.renderTemplate("css", path.join(destDir, "src"), {});
131
- }
132
- };
133
-
134
- //#endregion
135
- //#region src/utils/resolveFramework.ts
136
- async function resolveFramework() {
137
- try {
138
- const packageJson = await readPackageJSON();
139
- if (!packageJson) throw new Error("Could not find package.json");
140
- if (packageJson.dependencies == null) throw new Error("Could not find dependencies in package.json");
141
- if ("preact" in packageJson.dependencies) return "preact";
142
- return "react";
143
- } catch (error) {
144
- throw new Error(`Error resolving framework: ${error}`);
145
- }
146
- }
147
-
148
- //#endregion
149
- //#region src/commands/generate.ts
150
- var Generate = class Generate extends Command {
151
- static id = "generate";
152
- static description = "Generate blocks for your project";
153
- static flags = {
154
- name: Flags.string({
155
- char: "n",
156
- description: "The name of the component"
157
- }),
158
- type: Flags.string({
159
- description: "The type of the component",
160
- options: ["block"],
161
- default: "block"
162
- }),
163
- tailwind: Flags.boolean({
164
- char: "t",
165
- default: void 0,
166
- allowNo: true
167
- }),
168
- verbose: Flags.boolean({
169
- char: "v",
170
- default: true,
171
- allowNo: true
172
- })
173
- };
174
- static examples = ["<%= config.bin %> <%= command.id %>"];
175
- resolvePackageJsonPath() {
176
- let currentPath = path.resolve("./");
177
- while (!existsSync(path.join(currentPath, "package.json"))) {
178
- const parentDir = path.dirname(currentPath);
179
- if (parentDir === currentPath) throw new Error("Could not find 'package.json' in the project");
180
- currentPath = parentDir;
181
- }
182
- return currentPath;
183
- }
184
- async resolveCSSFramework(dir) {
185
- try {
186
- const packageJson = await readPackageJSON(path.join(dir, "package.json"));
187
- if (packageJson?.dependencies?.tailwindcss || packageJson?.devDependencies?.tailwindcss) return "tailwind";
188
- return false;
189
- } catch (error) {
190
- throw new Error(`Error resolving CSS framework: ${error}`);
191
- }
192
- }
193
- async run() {
194
- const { flags } = await this.parse(Generate);
195
- let rootDir;
196
- const templateGenerator = new JuoTemplateGenerator();
197
- try {
198
- rootDir = this.resolvePackageJsonPath();
199
- } catch (error) {
200
- throw new Error(`Error resolving package JSON path: ${error}`);
201
- }
202
- const tailwind = flags.tailwind ?? await this.resolveCSSFramework(rootDir);
203
- if (isCancel(flags.type ?? await select({
204
- message: "What you want to create?",
205
- options: [
206
- {
207
- value: "block",
208
- label: "Block"
209
- },
210
- {
211
- value: "page",
212
- label: "Page"
213
- },
214
- {
215
- value: "theme",
216
- label: "Theme"
217
- }
218
- ],
219
- initialValue: "block"
220
- }))) process.exit(0);
221
- const generateSpinner = flags.verbose ? spinner() : null;
222
- const blocksDir = path.join(rootDir, "src/blocks");
223
- const name = flags.name ?? await text({
224
- message: "What is the name of the component?",
225
- initialValue: "Starter Block",
226
- validate(value) {
227
- if (value.length === 0) return `Value is required!`;
228
- }
229
- });
230
- if (isCancel(name)) this.exit(0);
231
- const framework = await resolveFramework();
232
- generateSpinner?.start();
233
- generateSpinner?.message("Detecting package manager");
234
- const packageManager = await detectPackageManager(rootDir);
235
- if (!packageManager) throw new Error("Could not detect package manager");
236
- if (flags.verbose) log.info("Package manager detected: " + packageManager.name);
237
- generateSpinner?.message("Generating block");
238
- await templateGenerator.generate(blocksDir, {
239
- type: "block",
240
- framework,
241
- name,
242
- tailwind,
243
- logger: (msg) => generateSpinner?.message(msg),
244
- story: true
245
- });
246
- templateGenerator.appendStylesheet(rootDir);
247
- generateSpinner?.stop("Generated block");
248
- }
249
- };
250
-
251
- //#endregion
252
- export { BaseTemplateGenerator as n, Generate as t };
@@ -1,105 +0,0 @@
1
- import {
2
- type ContextType,
3
- createState,
4
- effect,
5
- injectContext,
6
- provideContext,
7
- Signal,
8
- StateContext,
9
- } from "@juo/orion-core";
10
-
11
- const product1 = "https://placehold.co/600x400";
12
- const product2 = "https://placehold.co/600x400";
13
- const product3 = "https://placehold.co/600x400";
14
-
15
- type State = ContextType<typeof StateContext>;
16
-
17
- export function provideState(el: HTMLElement) {
18
- provideContext(el, StateContext, createState());
19
-
20
- const state = new Signal<State | null>(null);
21
-
22
- setTimeout(() => {
23
- const v = injectContext(el, StateContext);
24
- state.value = v;
25
- }, 0);
26
-
27
- effect(() => {
28
- if (state.value == null) {
29
- return;
30
- }
31
-
32
- if (state.value.products.value.length === 0) {
33
- state.value.addProduct({
34
- id: "p1",
35
- name: "Hydrating Gel Cleanser for Face and Eye Area",
36
- description: "150 ml bottle",
37
- price: 12.49,
38
- imageUrl: product1,
39
- });
40
- state.value.addProduct({
41
- id: "p2",
42
- name: "More COLLAGEN",
43
- description: "blackcurrant",
44
- price: 22.6,
45
- imageUrl: product2,
46
- });
47
- state.value.addProduct({
48
- id: "p3",
49
- name: "Gentle deodorant for underarms and bust",
50
- description: "Green tea and jasmine",
51
- price: 6.7,
52
- imageUrl: product3,
53
- });
54
- state.value.addProduct({
55
- id: "gift",
56
- name: "Free summer gift",
57
- description: "",
58
- price: 0.0,
59
- imageUrl: product3,
60
- });
61
- }
62
-
63
- if (state.value.subscriptions.value.length === 0) {
64
- state.value.addSubscription({
65
- id: "s1",
66
- items: [
67
- {
68
- id: "i1",
69
- productId: "p1",
70
- price: 12.49,
71
- quantity: 2,
72
- },
73
- {
74
- id: "i2",
75
- productId: "p2",
76
- price: 22.6,
77
- quantity: 1,
78
- },
79
- ],
80
- status: "active",
81
- nextDeliveryDate: "2025-08-15",
82
- frequency: "Every 1 month",
83
- quantity: 1,
84
- createdAt: "2025-04-15",
85
- });
86
-
87
- state.value.addSubscription({
88
- id: "s2",
89
- items: [
90
- {
91
- id: "i1",
92
- productId: "p3",
93
- price: 12.49,
94
- quantity: 2,
95
- },
96
- ],
97
- status: "active",
98
- nextDeliveryDate: "2025-09-12",
99
- frequency: "Every 3 months",
100
- quantity: 1,
101
- createdAt: "2024-04-22",
102
- });
103
- }
104
- });
105
- }