@brickflow/ui 0.0.26 → 0.0.28
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/module.d.mts +4 -1
- package/dist/module.json +2 -2
- package/dist/module.mjs +409 -11
- package/dist/runtime/components/Button/icons.demo.d.vue.ts +8 -0
- package/dist/runtime/components/Button/icons.demo.vue +25 -0
- package/dist/runtime/components/Button/icons.demo.vue.d.ts +8 -0
- package/dist/runtime/components/Button/index.d.vue.ts +45 -0
- package/dist/runtime/components/Button/index.vue +162 -0
- package/dist/runtime/components/Button/index.vue.d.ts +45 -0
- package/dist/runtime/components/Button/size.demo.d.vue.ts +7 -0
- package/dist/runtime/components/Button/size.demo.vue +78 -0
- package/dist/runtime/components/Button/size.demo.vue.d.ts +7 -0
- package/dist/runtime/components/Button/slots.demo.d.vue.ts +7 -0
- package/dist/runtime/components/Button/slots.demo.vue +23 -0
- package/dist/runtime/components/Button/slots.demo.vue.d.ts +7 -0
- package/dist/runtime/components/Button/state.demo.d.vue.ts +7 -0
- package/dist/runtime/components/Button/state.demo.vue +18 -0
- package/dist/runtime/components/Button/state.demo.vue.d.ts +7 -0
- package/dist/runtime/components/Button/variants.demo.d.vue.ts +7 -0
- package/dist/runtime/components/Button/variants.demo.vue +207 -0
- package/dist/runtime/components/Button/variants.demo.vue.d.ts +7 -0
- package/dist/runtime/components/Icon/basic.demo.d.vue.ts +8 -0
- package/dist/runtime/components/Icon/basic.demo.vue +44 -0
- package/dist/runtime/components/Icon/basic.demo.vue.d.ts +8 -0
- package/dist/runtime/components/Icon/index.d.vue.ts +7 -0
- package/dist/runtime/components/Icon/index.vue +18 -0
- package/dist/runtime/components/Icon/index.vue.d.ts +7 -0
- package/dist/runtime/components/Link/basic.demo.d.vue.ts +8 -0
- package/dist/runtime/components/Link/basic.demo.vue +27 -0
- package/dist/runtime/components/Link/basic.demo.vue.d.ts +8 -0
- package/dist/runtime/components/Link/index.d.vue.ts +51 -0
- package/dist/runtime/components/Link/index.vue +62 -0
- package/dist/runtime/components/Link/index.vue.d.ts +51 -0
- package/dist/runtime/composables/useScreen.d.ts +18 -0
- package/dist/runtime/composables/useScreen.js +68 -0
- package/dist/runtime/composables/useTheme.d.ts +17 -0
- package/dist/runtime/composables/useTheme.js +77 -0
- package/dist/runtime/composables/useTranslate.d.ts +20 -0
- package/dist/runtime/composables/useTranslate.js +17 -0
- package/dist/runtime/icon-font.d.ts +4 -0
- package/dist/runtime/pages/ui.d.vue.ts +4 -0
- package/dist/runtime/pages/ui.vue +717 -0
- package/dist/runtime/pages/ui.vue.d.ts +4 -0
- package/dist/runtime/tailwind.d.ts +4 -1
- package/dist/runtime/tailwind.js +2 -1
- package/dist/runtime/ui-catalog.d.ts +39 -0
- package/dist/runtime/ui-options.d.ts +3 -0
- package/dist/types.d.mts +2 -0
- package/package.json +10 -10
- package/dist/runtime/components/Button.d.vue.ts +0 -23
- package/dist/runtime/components/Button.vue +0 -29
- package/dist/runtime/components/Button.vue.d.ts +0 -23
- package/dist/runtime/composables/useBrickme.d.ts +0 -9
- 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
|
-
|
|
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
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 {
|
|
5
|
-
import { resolve, basename, extname,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|