@brickflow/ui 0.0.27 → 0.0.29

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 (52) hide show
  1. package/dist/module.d.mts +4 -1
  2. package/dist/module.json +2 -2
  3. package/dist/module.mjs +409 -11
  4. package/dist/runtime/components/Button/icons.demo.d.vue.ts +8 -0
  5. package/dist/runtime/components/Button/icons.demo.vue +25 -0
  6. package/dist/runtime/components/Button/icons.demo.vue.d.ts +8 -0
  7. package/dist/runtime/components/Button/index.d.vue.ts +45 -0
  8. package/dist/runtime/components/Button/index.vue +162 -0
  9. package/dist/runtime/components/Button/index.vue.d.ts +45 -0
  10. package/dist/runtime/components/Button/size.demo.d.vue.ts +7 -0
  11. package/dist/runtime/components/Button/size.demo.vue +78 -0
  12. package/dist/runtime/components/Button/size.demo.vue.d.ts +7 -0
  13. package/dist/runtime/components/Button/slots.demo.d.vue.ts +7 -0
  14. package/dist/runtime/components/Button/slots.demo.vue +23 -0
  15. package/dist/runtime/components/Button/slots.demo.vue.d.ts +7 -0
  16. package/dist/runtime/components/Button/state.demo.d.vue.ts +7 -0
  17. package/dist/runtime/components/Button/state.demo.vue +18 -0
  18. package/dist/runtime/components/Button/state.demo.vue.d.ts +7 -0
  19. package/dist/runtime/components/Button/variants.demo.d.vue.ts +7 -0
  20. package/dist/runtime/components/Button/variants.demo.vue +207 -0
  21. package/dist/runtime/components/Button/variants.demo.vue.d.ts +7 -0
  22. package/dist/runtime/components/Icon/basic.demo.d.vue.ts +8 -0
  23. package/dist/runtime/components/Icon/basic.demo.vue +44 -0
  24. package/dist/runtime/components/Icon/basic.demo.vue.d.ts +8 -0
  25. package/dist/runtime/components/Icon/index.d.vue.ts +7 -0
  26. package/dist/runtime/components/Icon/index.vue +18 -0
  27. package/dist/runtime/components/Icon/index.vue.d.ts +7 -0
  28. package/dist/runtime/components/Link/basic.demo.d.vue.ts +8 -0
  29. package/dist/runtime/components/Link/basic.demo.vue +27 -0
  30. package/dist/runtime/components/Link/basic.demo.vue.d.ts +8 -0
  31. package/dist/runtime/components/Link/index.d.vue.ts +51 -0
  32. package/dist/runtime/components/Link/index.vue +62 -0
  33. package/dist/runtime/components/Link/index.vue.d.ts +51 -0
  34. package/dist/runtime/composables/useScreen.d.ts +18 -0
  35. package/dist/runtime/composables/useScreen.js +68 -0
  36. package/dist/runtime/composables/useTheme.d.ts +17 -0
  37. package/dist/runtime/composables/useTheme.js +77 -0
  38. package/dist/runtime/composables/useTranslate.d.ts +20 -0
  39. package/dist/runtime/composables/useTranslate.js +17 -0
  40. package/dist/runtime/icon-font.d.ts +4 -0
  41. package/dist/runtime/pages/ui.d.vue.ts +4 -0
  42. package/dist/runtime/pages/ui.vue +717 -0
  43. package/dist/runtime/pages/ui.vue.d.ts +4 -0
  44. package/dist/runtime/ui-catalog.d.ts +39 -0
  45. package/dist/runtime/ui-options.d.ts +3 -0
  46. package/dist/types.d.mts +2 -0
  47. package/package.json +10 -10
  48. package/dist/runtime/components/Button.d.vue.ts +0 -23
  49. package/dist/runtime/components/Button.vue +0 -29
  50. package/dist/runtime/components/Button.vue.d.ts +0 -23
  51. package/dist/runtime/composables/useBrickme.d.ts +0 -9
  52. package/dist/runtime/composables/useBrickme.js +0 -14
package/dist/module.d.mts CHANGED
@@ -1,10 +1,13 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
+ export { BrickflowConfig, BrickflowI18n, BrickflowRouteLocationParam } from '../dist/runtime/composables/useTranslate.js';
2
3
 
3
4
  interface ModuleOptions {
4
5
  componentPrefix?: string;
5
6
  configPath?: string;
6
- target?: string;
7
+ iconsPath?: string;
8
+ theme?: boolean;
7
9
  }
10
+
8
11
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
9
12
 
10
13
  export { _default as default };
package/dist/module.json CHANGED
@@ -4,9 +4,9 @@
4
4
  },
5
5
  "configKey": "brickflowUi",
6
6
  "name": "@brickflow/ui",
7
- "version": "0.0.27",
7
+ "version": "0.0.29",
8
8
  "builder": {
9
- "@nuxt/module-builder": "1.0.2",
9
+ "@nuxt/module-builder": "1.0.3",
10
10
  "unbuild": "3.6.1"
11
11
  }
12
12
  }
package/dist/module.mjs CHANGED
@@ -1,9 +1,88 @@
1
- import { defineNuxtModule, createResolver, resolvePath, addTemplate, addImportsDir, addComponentsDir } from '@nuxt/kit';
1
+ import { defineNuxtModule, createResolver, resolvePath, addTemplate, updateTemplates, addImportsDir, addComponentsDir } from '@nuxt/kit';
2
2
  import tailwindcss from '@tailwindcss/vite';
3
3
  import { createJiti } from 'jiti';
4
- import { readFile, mkdir, writeFile, readdir } from 'node:fs/promises';
5
- import { resolve, basename, extname, relative, join } from 'node:path';
4
+ import { readdir, mkdir, readFile, writeFile } from 'node:fs/promises';
5
+ import { join, resolve, basename, extname, dirname, relative } from 'node:path';
6
6
  import { defineBrickflowUiConfig } from '../dist/runtime/tailwind.js';
7
+ import { generateFonts, FontAssetType, OtherAssetType } from 'fantasticon';
8
+
9
+ const ICON_FILE_PATTERN = /\.svg$/i;
10
+ const minifyCss = (css) => css.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").replace(/\s*([{}:;,>+~])\s*/g, "$1").replace(/;\}/g, "}").trim();
11
+ const normalizeGeneratedCss = (css) => `${css.replace(/"/g, "'").replace(/^ {4}/gm, " ").replace(/(\.(?:eot|ttf|woff2?))\?[^#'")]+(#iefix)?/gi, "$1$2").replace(/src: ([^\n]+),\n([^\n]+),\n([^\n]+);/, "src:\n $1,\n $2,\n $3;").replace(
12
+ /i\[class\^='icon-'\]:before, i\[class\*=' icon-'\]:before \{/,
13
+ "@layer base {\n i[class^='icon-'],\n i[class*=' icon-'] {\n container-type: inline-size;\n display: inline-flex;\n width: 1em;\n }\n}\n\ni[class^='icon-']:before,\ni[class*=' icon-']:before {\n font-size: 100cqw;"
14
+ ).replace(/\n{3,}/g, "\n\n").trim()}
15
+ `;
16
+ const getIconFontNames = async (inputDir) => {
17
+ const entries = await readdir(inputDir, { withFileTypes: true });
18
+ const invalidEntries = entries.filter((entry) => !entry.isFile() || !ICON_FILE_PATTERN.test(entry.name));
19
+ if (invalidEntries.length > 0) {
20
+ throw new Error(
21
+ `brickflowUi.iconsPath must be a flat directory containing only .svg files. Invalid entries: ${invalidEntries.map((entry) => entry.name).join(", ")}`
22
+ );
23
+ }
24
+ if (entries.length === 0) {
25
+ throw new Error("brickflowUi.iconsPath must contain at least one .svg file");
26
+ }
27
+ return entries.map((entry) => entry.name.replace(ICON_FILE_PATTERN, "")).sort((a, b) => a.localeCompare(b));
28
+ };
29
+ const getIconFontCssPath = (outputDir) => join(outputDir, "icon.minify.css");
30
+ const createIconFontAssetsInlineLimit = (outputDir, currentLimit) => {
31
+ const normalizedOutputDir = outputDir.replaceAll("\\", "/");
32
+ return (filePath, content) => {
33
+ if (filePath.replaceAll("\\", "/").startsWith(`${normalizedOutputDir}/`)) {
34
+ return false;
35
+ }
36
+ if (typeof currentLimit === "function") {
37
+ return currentLimit(filePath, content);
38
+ }
39
+ return typeof currentLimit === "number" ? content.length < currentLimit : void 0;
40
+ };
41
+ };
42
+ const generateIconFont = async ({ inputDir, outputDir }) => {
43
+ await getIconFontNames(inputDir);
44
+ await mkdir(outputDir, { recursive: true });
45
+ await generateFonts({
46
+ assetTypes: [OtherAssetType.CSS],
47
+ fontsUrl: ".",
48
+ fontTypes: [FontAssetType.EOT, FontAssetType.WOFF2, FontAssetType.WOFF],
49
+ inputDir,
50
+ name: "icon",
51
+ normalize: true,
52
+ outputDir
53
+ });
54
+ const cssPath = join(outputDir, "icon.css");
55
+ const css = normalizeGeneratedCss(await readFile(cssPath, "utf8"));
56
+ await writeFile(cssPath, css);
57
+ await writeFile(getIconFontCssPath(outputDir), minifyCss(css));
58
+ };
59
+ const brickflowUiIconFontPlugin = (options) => ({
60
+ buildStart: () => generateIconFont(options),
61
+ name: "brickflow-ui-icons"
62
+ });
63
+
64
+ const CSS_FILE_PATTERN = /\.css(?:\?.*)?$/;
65
+ const CUSTOM_DARK_VARIANT = "@custom-variant dark (&:where([data-ui-theme='dark'], [data-ui-theme='dark'] *));";
66
+ const TAILWIND_IMPORT_PATTERN = /@import\s+(['"])tailwindcss\1\s*;/u;
67
+ const brickflowUiTailwindVariantPlugin = () => ({
68
+ enforce: "pre",
69
+ name: "brickflow-ui-tailwind-variant",
70
+ transform(code, id) {
71
+ if (!CSS_FILE_PATTERN.test(id) || code.includes("@custom-variant dark")) {
72
+ return null;
73
+ }
74
+ const importMatch = code.match(TAILWIND_IMPORT_PATTERN);
75
+ if (!importMatch) {
76
+ return null;
77
+ }
78
+ const index = (importMatch.index ?? 0) + importMatch[0].length;
79
+ return {
80
+ code: `${code.slice(0, index)}
81
+ ${CUSTOM_DARK_VARIANT}${code.slice(index)}`,
82
+ map: null
83
+ };
84
+ }
85
+ });
7
86
 
8
87
  const UI_STYLE_PATTERN = /\bUI_STYLE((?:\.[A-Za-z_$][\w$]*)+)/g;
9
88
  const SCRIPT_FILE_PATTERN = /\.(?:[cm]?[jt]sx?|vue)(?:\?.*)?$/;
@@ -29,7 +108,9 @@ const resolveUiStyleConfigPath = (id, path) => {
29
108
  if (!cleanId.endsWith(".vue")) {
30
109
  return path;
31
110
  }
32
- return [toCamelCase(basename(cleanId, extname(cleanId))), ...path];
111
+ const componentName = basename(cleanId, extname(cleanId));
112
+ const configName = componentName === "index" ? basename(dirname(cleanId)) : componentName;
113
+ return [toCamelCase(configName), ...path];
33
114
  };
34
115
  const resolveStyleValue = (styles, id, path) => {
35
116
  const configPathValue = readPath(styles, resolveUiStyleConfigPath(id, path));
@@ -140,6 +221,107 @@ const brickflowUiStylePlugin = (options) => ({
140
221
  });
141
222
 
142
223
  const UI_STYLE_FILE_PATTERN = /\.(?:[cm]?[jt]sx?|vue)$/;
224
+ const UI_COMPONENT_FILE_PATTERN = /(?:^|[/\\])index\.vue$/;
225
+ const UI_DEMO_FILE_PATTERN = /\.demo\.vue$/;
226
+ const THEME_BOOTSTRAP_SCRIPT = `;(() => {
227
+ let storedTheme
228
+
229
+ try {
230
+ storedTheme = localStorage.getItem('ui-theme')
231
+ } catch {}
232
+
233
+ const theme =
234
+ storedTheme === 'dark' || storedTheme === 'light'
235
+ ? storedTheme
236
+ : window.matchMedia('(prefers-color-scheme: dark)').matches
237
+ ? 'dark'
238
+ : 'light'
239
+ const root = document.documentElement
240
+
241
+ root.dataset.uiTheme = theme
242
+ root.style.colorScheme = theme
243
+ })()`;
244
+ const toKebabCase = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[\\/]/g, "-").toLowerCase();
245
+ const getComponentName = (path) => path.replace(/[/\\]index\.vue$/, "").replaceAll("/", " / ");
246
+ const readObjectPath = (source, path) => path.reduce((value, key) => {
247
+ if (!value || typeof value !== "object") {
248
+ return void 0;
249
+ }
250
+ return value[key];
251
+ }, source);
252
+ const getBracedContent = (source, fromIndex) => {
253
+ const openingIndex = source.indexOf("{", fromIndex);
254
+ if (openingIndex === -1) {
255
+ return void 0;
256
+ }
257
+ let depth = 0;
258
+ for (let index = openingIndex; index < source.length; index += 1) {
259
+ const character = source[index];
260
+ if (character === "{") {
261
+ depth += 1;
262
+ } else if (character === "}") {
263
+ depth -= 1;
264
+ }
265
+ if (depth === 0) {
266
+ return source.slice(openingIndex + 1, index);
267
+ }
268
+ }
269
+ return void 0;
270
+ };
271
+ const getPropsSource = (source) => {
272
+ const interfaceIndex = source.indexOf("interface Props");
273
+ if (interfaceIndex !== -1) {
274
+ return getBracedContent(source, interfaceIndex);
275
+ }
276
+ const definePropsIndex = source.indexOf("defineProps<");
277
+ return definePropsIndex === -1 ? void 0 : getBracedContent(source, definePropsIndex);
278
+ };
279
+ const collectComponentProps = (source) => {
280
+ const propsSource = getPropsSource(source);
281
+ if (!propsSource) {
282
+ return [];
283
+ }
284
+ return propsSource.split("\n").flatMap((sourceLine) => {
285
+ const line = sourceLine.trim().replace(/[;,]$/, "");
286
+ const separatorIndex = line.indexOf(":");
287
+ const name = line.slice(0, separatorIndex);
288
+ const type = line.slice(separatorIndex + 1).trim();
289
+ if (separatorIndex === -1 || !/^[a-z_$][\w$]*\??$/i.test(name) || !type) {
290
+ return [];
291
+ }
292
+ return [
293
+ {
294
+ name: name.replace(/\?$/, ""),
295
+ required: !name.endsWith("?"),
296
+ type
297
+ }
298
+ ];
299
+ });
300
+ };
301
+ const collectComponentSlots = (source) => {
302
+ const conditionalSlots = [...source.matchAll(/\$slots\.([A-Za-z_$][\w$]*)/g)].map((match) => match[1]).filter((slot) => Boolean(slot));
303
+ const renderedSlots = [...source.matchAll(/<slot\b[^>]*>/g)].map((match) => {
304
+ const name = match[0].match(/\bname=["']([^"']+)["']/)?.[1];
305
+ return name ?? "default";
306
+ });
307
+ return [.../* @__PURE__ */ new Set([...conditionalSlots, ...renderedSlots])].sort();
308
+ };
309
+ const toComponentStyleKey = (path) => {
310
+ const componentName = basename(dirname(path));
311
+ return `${componentName[0]?.toLowerCase()}${componentName.slice(1)}`;
312
+ };
313
+ const collectComponentStyleValues = (source, componentPath, styles) => [...new Set(collectUiStylePathsFromCode(source).map((path) => path.join(".")))].sort().map((path) => {
314
+ const segments = path.split(".");
315
+ const componentValue = readObjectPath(styles, [toComponentStyleKey(componentPath), ...segments]);
316
+ const globalValue = readObjectPath(styles, segments);
317
+ let value;
318
+ if (typeof componentValue === "string") {
319
+ value = componentValue;
320
+ } else if (typeof globalValue === "string") {
321
+ value = globalValue;
322
+ }
323
+ return { path, value };
324
+ });
143
325
  const scanUiStyleFiles = async (directory) => {
144
326
  const entries = await readdir(directory, { withFileTypes: true }).catch(() => []);
145
327
  const files = [];
@@ -159,7 +341,8 @@ const module$1 = defineNuxtModule({
159
341
  defaults: {
160
342
  componentPrefix: "Brick",
161
343
  configPath: "~/ui.config.ts",
162
- target: "world"
344
+ iconsPath: void 0,
345
+ theme: false
163
346
  },
164
347
  meta: {
165
348
  compatibility: {
@@ -169,17 +352,106 @@ const module$1 = defineNuxtModule({
169
352
  name: "@brickflow/ui"
170
353
  },
171
354
  async setup(options, nuxt) {
355
+ const nuxtOptions = nuxt.options;
356
+ nuxtOptions.routeRules ??= {};
357
+ const uiRouteRule = nuxtOptions.routeRules["/ui"] ?? {};
358
+ nuxtOptions.routeRules["/ui"] = {
359
+ ...uiRouteRule,
360
+ headers: {
361
+ "X-Robots-Tag": "noindex, nofollow, noarchive",
362
+ ...uiRouteRule.headers
363
+ },
364
+ ssr: uiRouteRule.ssr ?? false
365
+ };
172
366
  const resolver = createResolver(import.meta.url);
173
- const currentConfig = nuxt.options.runtimeConfig.public.brickflowUi ?? {};
174
367
  const defaultConfigPath = resolver.resolve("./runtime/tailwind");
175
368
  const runtimePath = resolver.resolve("./runtime");
369
+ const componentsDirectory = resolve(runtimePath, "components");
176
370
  const resolvedConfigPath = await resolvePath(options.configPath ?? defaultConfigPath).catch(
177
371
  () => defaultConfigPath
178
372
  );
373
+ if (options.theme) {
374
+ nuxt.options.app.head.script ??= [];
375
+ nuxt.options.app.head.script.unshift({
376
+ innerHTML: THEME_BOOTSTRAP_SCRIPT,
377
+ key: "ui-theme"
378
+ });
379
+ }
380
+ const iconFont = options.iconsPath ? {
381
+ inputDir: await resolvePath(options.iconsPath).catch(() => resolve(options.iconsPath)),
382
+ outputDir: resolve(nuxt.options.buildDir, "brickflow/icons")
383
+ } : void 0;
384
+ if (iconFont) {
385
+ nuxt.options.css.push(getIconFontCssPath(iconFont.outputDir));
386
+ }
179
387
  const loadConfig = createJiti(import.meta.url, {
180
388
  interopDefault: true,
181
389
  moduleCache: false
182
390
  });
391
+ const toPascalCase = (value) => value.split(/[/\\._-]+/).filter(Boolean).map((segment) => `${segment[0]?.toUpperCase()}${segment.slice(1)}`).join("");
392
+ const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
393
+ const getUiComponentNameFromImport = (specifier, demoPath, componentsRoot) => {
394
+ if (!specifier.startsWith(".")) {
395
+ return void 0;
396
+ }
397
+ const componentPath = resolve(dirname(demoPath), specifier);
398
+ if (relative(componentsRoot, componentPath).startsWith("..") || !UI_COMPONENT_FILE_PATTERN.test(componentPath)) {
399
+ return void 0;
400
+ }
401
+ return toPascalCase(relative(componentsRoot, componentPath).replace(/[/\\]index\.vue$/, ""));
402
+ };
403
+ const createDemoCode = (source, demoPath, componentsRoot, componentPrefix) => {
404
+ const importedComponents = /* @__PURE__ */ new Map();
405
+ const removeScriptBlocks = (code, shouldRemove) => {
406
+ const openingTagPrefix = "<script";
407
+ const closingTag = "<\/script>";
408
+ let result = "";
409
+ let cursor = 0;
410
+ let scriptStart = code.indexOf(openingTagPrefix, cursor);
411
+ while (scriptStart !== -1) {
412
+ const nextCharacter = code[scriptStart + openingTagPrefix.length];
413
+ if (nextCharacter && !/[\s>]/.test(nextCharacter)) {
414
+ scriptStart = code.indexOf(openingTagPrefix, scriptStart + openingTagPrefix.length);
415
+ continue;
416
+ }
417
+ const openingEnd = code.indexOf(">", scriptStart);
418
+ const closingStart = openingEnd === -1 ? -1 : code.indexOf(closingTag, openingEnd);
419
+ if (openingEnd === -1 || closingStart === -1) {
420
+ break;
421
+ }
422
+ const openingTag = code.slice(scriptStart, openingEnd + 1);
423
+ const content = code.slice(openingEnd + 1, closingStart);
424
+ result += code.slice(cursor, scriptStart);
425
+ if (!shouldRemove(openingTag, content)) {
426
+ result += code.slice(scriptStart, closingStart + closingTag.length);
427
+ }
428
+ cursor = closingStart + closingTag.length;
429
+ scriptStart = code.indexOf(openingTagPrefix, cursor);
430
+ }
431
+ return result + code.slice(cursor);
432
+ };
433
+ const isSetupScript = (openingTag) => /\bsetup(?:\s|>)/.test(openingTag);
434
+ const codeWithoutMeta = removeScriptBlocks(source, (openingTag) => !isSetupScript(openingTag));
435
+ const codeWithoutImports = codeWithoutMeta.replace(
436
+ /^\s*import\s+([A-Za-z_$][\w$]*)\s+from\s+['"]([^'"]+)['"];?\s*$/gm,
437
+ (statement, localName, specifier) => {
438
+ const componentName = getUiComponentNameFromImport(specifier, demoPath, componentsRoot);
439
+ if (!componentName) {
440
+ return statement;
441
+ }
442
+ importedComponents.set(localName, `${componentPrefix}${componentName}`);
443
+ return "";
444
+ }
445
+ );
446
+ const codeWithPrefixedComponents = [...importedComponents.entries()].reduce(
447
+ (code, [localName, componentName]) => code.replace(new RegExp(`<(/?)${escapeRegExp(localName)}(?=[\\s>/])`, "g"), `<$1${componentName}`),
448
+ codeWithoutImports
449
+ );
450
+ return removeScriptBlocks(
451
+ codeWithPrefixedComponents,
452
+ (openingTag, content) => isSetupScript(openingTag) && !content.trim()
453
+ );
454
+ };
183
455
  const loadUiConfig = async () => {
184
456
  const validateConfig = defineBrickflowUiConfig;
185
457
  return validateConfig(
@@ -209,6 +481,17 @@ const module$1 = defineNuxtModule({
209
481
  })
210
482
  );
211
483
  };
484
+ const iconFontTemplate = addTemplate({
485
+ filename: "brickflow/brickflow-ui-icons.mjs",
486
+ getContents: async () => {
487
+ const iconNames = iconFont ? await getIconFontNames(iconFont.inputDir) : [];
488
+ return [
489
+ `export const iconNames = ${JSON.stringify(iconNames)}`,
490
+ `export const firstIconName = ${JSON.stringify(iconNames[0] ?? "")}`,
491
+ ""
492
+ ].join("\n");
493
+ }
494
+ });
212
495
  const uiConfigTemplate = addTemplate({
213
496
  filename: "brickflow/brickflow-ui-config.mjs",
214
497
  getContents: () => [
@@ -223,12 +506,112 @@ const module$1 = defineNuxtModule({
223
506
  ""
224
507
  ].join("\n")
225
508
  });
226
- nuxt.options.runtimeConfig.public.brickflowUi = {
227
- ...currentConfig,
228
- message: "world",
229
- target: options.target ?? "world"
230
- };
509
+ const uiOptionsTemplate = addTemplate({
510
+ filename: "brickflow/brickflow-ui-options.mjs",
511
+ getContents: () => `export const uiThemeEnabled = ${JSON.stringify(options.theme === true)}
512
+ `
513
+ });
514
+ const uiCatalogTemplate = addTemplate({
515
+ filename: "brickflow/ui-catalog.ts",
516
+ getContents: async () => {
517
+ const files = await scanUiStyleFiles(componentsDirectory);
518
+ const styles = (await loadUiConfig()).uiStyles;
519
+ const components = await Promise.all(
520
+ files.filter((path) => UI_COMPONENT_FILE_PATTERN.test(path)).sort().map(async (path) => {
521
+ const source = await readFile(path, "utf8");
522
+ const relativePath = relative(componentsDirectory, path).replaceAll("\\", "/");
523
+ const demos = await Promise.all(
524
+ files.filter((file) => dirname(file) === dirname(path) && UI_DEMO_FILE_PATTERN.test(file)).sort().map(async (demoPath) => ({
525
+ code: createDemoCode(
526
+ await readFile(demoPath, "utf8"),
527
+ demoPath,
528
+ componentsDirectory,
529
+ options.componentPrefix ?? "Brick"
530
+ ),
531
+ id: toKebabCase(basename(demoPath).replace(UI_DEMO_FILE_PATTERN, "")),
532
+ path: demoPath
533
+ }))
534
+ );
535
+ return {
536
+ demos,
537
+ id: toKebabCase(relativePath.replace(/[/\\]index\.vue$/, "")),
538
+ name: getComponentName(relativePath),
539
+ path,
540
+ props: collectComponentProps(source),
541
+ slots: collectComponentSlots(source),
542
+ styles: collectComponentStyleValues(source, path, styles)
543
+ };
544
+ })
545
+ );
546
+ return [
547
+ "import type { Component } from 'vue'",
548
+ ...components.map(
549
+ (component, index) => `import Component${index} from ${JSON.stringify(component.path.replaceAll("\\", "/"))}`
550
+ ),
551
+ ...components.flatMap(
552
+ (component, componentIndex) => component.demos.map(
553
+ (demo, demoIndex) => `import Demo${componentIndex}_${demoIndex}, { uiDemo as uiDemo${componentIndex}_${demoIndex} } from ${JSON.stringify(demo.path.replaceAll("\\", "/"))}`
554
+ )
555
+ ),
556
+ "",
557
+ "export interface BrickflowUiDemo {",
558
+ " code: string",
559
+ " component: Component",
560
+ " description?: string",
561
+ " id: string",
562
+ " title: string",
563
+ "}",
564
+ "",
565
+ "export interface BrickflowUiDemoMeta {",
566
+ " description?: string",
567
+ " title?: string",
568
+ "}",
569
+ "",
570
+ "export interface BrickflowUiProp {",
571
+ " name: string",
572
+ " required: boolean",
573
+ " type: string",
574
+ "}",
575
+ "",
576
+ "export interface BrickflowUiStyleValue {",
577
+ " path: string",
578
+ " value?: string",
579
+ "}",
580
+ "",
581
+ "export interface BrickflowUiComponent {",
582
+ " component: Component",
583
+ " demos: BrickflowUiDemo[]",
584
+ " id: string",
585
+ " name: string",
586
+ " props: BrickflowUiProp[]",
587
+ " slots: string[]",
588
+ " styles: BrickflowUiStyleValue[]",
589
+ "}",
590
+ "",
591
+ "export const uiComponents = [",
592
+ ...components.map(
593
+ (component, componentIndex) => ` { component: Component${componentIndex}, demos: [${component.demos.map(
594
+ (demo, demoIndex) => `{ code: ${JSON.stringify(demo.code)}, component: Demo${componentIndex}_${demoIndex}, description: uiDemo${componentIndex}_${demoIndex}.description, id: ${JSON.stringify(demo.id)}, title: uiDemo${componentIndex}_${demoIndex}.title ?? 'Demo' }`
595
+ ).join(
596
+ ", "
597
+ )}], id: ${JSON.stringify(component.id)}, name: ${JSON.stringify(component.name)}, props: ${JSON.stringify(component.props)}, slots: ${JSON.stringify(component.slots)}, styles: ${JSON.stringify(component.styles)} },`
598
+ ),
599
+ "] satisfies BrickflowUiComponent[]",
600
+ ""
601
+ ].join("\n");
602
+ }
603
+ });
231
604
  nuxt.options.alias["#brickflow-ui-config"] = uiConfigTemplate.dst;
605
+ nuxt.options.alias["#brickflow-ui-catalog"] = uiCatalogTemplate.dst;
606
+ nuxt.options.alias["#brickflow-ui-icons"] = iconFontTemplate.dst;
607
+ nuxt.options.alias["#brickflow-ui-options"] = uiOptionsTemplate.dst;
608
+ nuxt.hook("pages:extend", (pages) => {
609
+ pages.push({
610
+ file: resolver.resolve("./runtime/pages/ui.vue"),
611
+ name: "brickflow-ui",
612
+ path: "/ui"
613
+ });
614
+ });
232
615
  await generateUiStyleTypes();
233
616
  nuxt.hook("prepare:types", async ({ references }) => {
234
617
  await generateUiStyleTypes();
@@ -240,20 +623,35 @@ const module$1 = defineNuxtModule({
240
623
  return;
241
624
  }
242
625
  await generateUiStyleTypes();
626
+ if (!relative(componentsDirectory, absolutePath).startsWith("..") && (UI_COMPONENT_FILE_PATTERN.test(path) || UI_DEMO_FILE_PATTERN.test(path))) {
627
+ await updateTemplates({ filter: (template) => template.filename === uiCatalogTemplate.filename });
628
+ }
243
629
  });
244
630
  nuxt.hook("vite:extendConfig", (config) => {
245
631
  const viteConfig = config;
246
632
  viteConfig.plugins ??= [];
633
+ if (iconFont) {
634
+ viteConfig.build ??= {};
635
+ viteConfig.build.assetsInlineLimit = createIconFontAssetsInlineLimit(
636
+ iconFont.outputDir,
637
+ viteConfig.build.assetsInlineLimit
638
+ );
639
+ viteConfig.plugins.push(brickflowUiIconFontPlugin(iconFont));
640
+ }
247
641
  viteConfig.plugins.push(
248
642
  brickflowUiStylePlugin({
249
643
  configPath: resolvedConfigPath,
250
644
  getStyles: async () => (await loadUiConfig()).uiStyles
251
645
  })
252
646
  );
647
+ if (options.theme) {
648
+ viteConfig.plugins.push(brickflowUiTailwindVariantPlugin());
649
+ }
253
650
  viteConfig.plugins.push(tailwindcss());
254
651
  });
255
652
  addImportsDir(resolver.resolve("./runtime/composables"));
256
653
  addComponentsDir({
654
+ ignore: ["**/*.demo.vue"],
257
655
  path: resolver.resolve("./runtime/components"),
258
656
  pathPrefix: false,
259
657
  prefix: options.componentPrefix ?? "Brick"
@@ -0,0 +1,8 @@
1
+ export declare const uiDemo: {
2
+ description: string;
3
+ title: string;
4
+ };
5
+ declare const _default: typeof __VLS_export;
6
+ export default _default;
7
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
8
+ //# sourceMappingURL=icons.demo.vue.d.ts.map
@@ -0,0 +1,25 @@
1
+ <script>
2
+ export const uiDemo = {
3
+ description: "Set leadingIcon and trailingIcon to an icon name. Slots take precedence when both are provided.",
4
+ title: "Icons"
5
+ };
6
+ </script>
7
+
8
+ <script setup>
9
+ import { firstIconName } from "#brickflow-ui-icons";
10
+ import Button from "./index.vue";
11
+ </script>
12
+
13
+ <template>
14
+ <div class="flex flex-wrap items-center gap-3">
15
+ <Button :icon="firstIconName">Launch</Button>
16
+ <Button :trailingIcon="firstIconName">Add to cart</Button>
17
+ <Button
18
+ :icon="firstIconName"
19
+ :trailingIcon="firstIconName"
20
+ variant="soft"
21
+ >
22
+ View profile
23
+ </Button>
24
+ </div>
25
+ </template>
@@ -0,0 +1,8 @@
1
+ export declare const uiDemo: {
2
+ description: string;
3
+ title: string;
4
+ };
5
+ declare const _default: typeof __VLS_export;
6
+ export default _default;
7
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
8
+ //# sourceMappingURL=icons.demo.vue.d.ts.map
@@ -0,0 +1,45 @@
1
+ import type { RouteLocationRaw } from 'vue-router';
2
+ type __VLS_Props = {
3
+ block?: boolean;
4
+ color?: ButtonColor;
5
+ disabled?: boolean;
6
+ icon?: string;
7
+ loading?: boolean;
8
+ rounded?: boolean;
9
+ size?: ButtonSize;
10
+ square?: boolean;
11
+ to?: RouteLocationRaw;
12
+ trailingIcon?: string;
13
+ type?: 'button' | 'reset' | 'submit';
14
+ variant?: ButtonVariant;
15
+ };
16
+ type ButtonColor = 'alt' | 'danger' | 'info' | 'main' | 'plain' | 'warn' | 'win';
17
+ type ButtonSize = 'lg' | 'md' | 'sm' | 'xl' | 'xs';
18
+ type ButtonVariant = 'ghost' | 'glass' | 'soft' | 'solid' | 'subtle';
19
+ declare var __VLS_10: {}, __VLS_22: {}, __VLS_24: {};
20
+ type __VLS_Slots = {} & {
21
+ leading?: (props: typeof __VLS_10) => any;
22
+ } & {
23
+ default?: (props: typeof __VLS_22) => any;
24
+ } & {
25
+ trailing?: (props: typeof __VLS_24) => any;
26
+ };
27
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
28
+ size: ButtonSize;
29
+ type: "button" | "reset" | "submit";
30
+ to: RouteLocationRaw;
31
+ color: ButtonColor;
32
+ icon: string;
33
+ rounded: boolean;
34
+ trailingIcon: string;
35
+ variant: ButtonVariant;
36
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
37
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
38
+ declare const _default: typeof __VLS_export;
39
+ export default _default;
40
+ type __VLS_WithSlots<T, S> = T & {
41
+ new (): {
42
+ $slots: S;
43
+ };
44
+ };
45
+ //# sourceMappingURL=index.vue.d.ts.map