@rotki/ui-library 2.8.3 → 2.9.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.
Files changed (47) hide show
  1. package/dist/README.md +84 -5
  2. package/dist/components/date-time-picker/RuiDateTimePicker.vue.d.ts +4 -0
  3. package/dist/components/date-time-picker/RuiDateTimePicker.vue2.js +16 -7
  4. package/dist/components/date-time-picker/RuiDateTimePicker.vue2.js.map +1 -1
  5. package/dist/components/forms/auto-complete/RuiAutoComplete.vue.d.ts +49 -16
  6. package/dist/components/forms/auto-complete/RuiAutoComplete.vue2.js +19 -12
  7. package/dist/components/forms/auto-complete/RuiAutoComplete.vue2.js.map +1 -1
  8. package/dist/components/forms/checkbox/RuiCheckbox.vue.d.ts +2 -0
  9. package/dist/components/forms/checkbox/RuiCheckbox.vue2.js +8 -2
  10. package/dist/components/forms/checkbox/RuiCheckbox.vue2.js.map +1 -1
  11. package/dist/components/forms/radio-button/radio/RuiRadio.vue.d.ts +1 -0
  12. package/dist/components/forms/radio-button/radio/RuiRadio.vue2.js +8 -2
  13. package/dist/components/forms/radio-button/radio/RuiRadio.vue2.js.map +1 -1
  14. package/dist/components/forms/radio-button/radio-group/RuiRadioGroup.vue.d.ts +1 -0
  15. package/dist/components/forms/radio-button/radio-group/RuiRadioGroup.vue2.js +12 -3
  16. package/dist/components/forms/radio-button/radio-group/RuiRadioGroup.vue2.js.map +1 -1
  17. package/dist/components/forms/revealable-text-field/RuiRevealableTextField.vue.d.ts +1 -0
  18. package/dist/components/forms/revealable-text-field/RuiRevealableTextField.vue.js +2 -1
  19. package/dist/components/forms/revealable-text-field/RuiRevealableTextField.vue.js.map +1 -1
  20. package/dist/components/forms/select/RuiMenuSelect.vue.d.ts +49 -16
  21. package/dist/components/forms/select/RuiMenuSelect.vue2.js +15 -8
  22. package/dist/components/forms/select/RuiMenuSelect.vue2.js.map +1 -1
  23. package/dist/components/forms/slider/RuiSlider.vue.d.ts +2 -0
  24. package/dist/components/forms/slider/RuiSlider.vue2.js +17 -9
  25. package/dist/components/forms/slider/RuiSlider.vue2.js.map +1 -1
  26. package/dist/components/forms/switch/RuiSwitch.vue.d.ts +2 -0
  27. package/dist/components/forms/switch/RuiSwitch.vue2.js +8 -2
  28. package/dist/components/forms/switch/RuiSwitch.vue2.js.map +1 -1
  29. package/dist/components/forms/text-area/RuiTextArea.vue.d.ts +2 -0
  30. package/dist/components/forms/text-area/RuiTextArea.vue2.js +18 -8
  31. package/dist/components/forms/text-area/RuiTextArea.vue2.js.map +1 -1
  32. package/dist/components/forms/text-field/RuiTextField.vue.d.ts +2 -0
  33. package/dist/components/forms/text-field/RuiTextField.vue2.js +18 -8
  34. package/dist/components/forms/text-field/RuiTextField.vue2.js.map +1 -1
  35. package/dist/components/tables/RuiDataTable.vue2.js +4 -1
  36. package/dist/components/tables/RuiDataTable.vue2.js.map +1 -1
  37. package/dist/style.css +26 -26
  38. package/dist/vite-plugin/client.d.ts +15 -0
  39. package/dist/vite-plugin/index.d.ts +8 -0
  40. package/dist/vite-plugin/index.js +161 -0
  41. package/dist/vite-plugin/index.js.map +1 -0
  42. package/dist/vite-plugin/scanner.d.ts +18 -0
  43. package/dist/vite-plugin/scanner.js +63 -0
  44. package/dist/vite-plugin/scanner.js.map +1 -0
  45. package/dist/vite-plugin/types.d.ts +28 -0
  46. package/dist/web-types.json +111 -1
  47. package/package.json +17 -4
@@ -0,0 +1,161 @@
1
+ import { readFileSync, existsSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { generateVirtualModule, extractIconsFromSource, validateIcons } from "./scanner.js";
5
+ const VIRTUAL_MODULE_ID = "virtual:rotki-icons";
6
+ const RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
7
+ const DEFAULT_SCAN_PATTERNS = ["**/*.vue", "**/*.ts", "**/*.tsx"];
8
+ const EXCLUDED_PATTERNS = ["**/node_modules/**", "**/dist/**", "**/.git/**"];
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = dirname(__filename);
11
+ function loadValidIcons() {
12
+ try {
13
+ const distPath = resolve(__dirname, "../icons/index.js");
14
+ if (existsSync(distPath)) {
15
+ const content = readFileSync(distPath, "utf-8");
16
+ const match = content.match(/const RuiIcons = \[(.*?)];/s);
17
+ if (match?.[1]) {
18
+ const iconsStr = match[1];
19
+ const icons = iconsStr.match(/"([^"]+)"/g)?.map((s) => s.slice(1, -1)) || [];
20
+ return new Set(icons);
21
+ }
22
+ }
23
+ } catch {
24
+ }
25
+ const sourcePath = resolve(__dirname, "../icons/index.ts");
26
+ if (existsSync(sourcePath)) {
27
+ const content = readFileSync(sourcePath, "utf-8");
28
+ const match = content.match(/export const RuiIcons = \[(.*?)] as const/s);
29
+ if (match?.[1]) {
30
+ const iconsStr = match[1];
31
+ const icons = iconsStr.match(/"([^"]+)"/g)?.map((s) => s.slice(1, -1)) || [];
32
+ return new Set(icons);
33
+ }
34
+ }
35
+ console.warn("[@rotki/ui-library] Could not load RuiIcons list, validation disabled");
36
+ return /* @__PURE__ */ new Set();
37
+ }
38
+ function ruiIconsPlugin(options = {}) {
39
+ const {
40
+ include = [],
41
+ scanPatterns = DEFAULT_SCAN_PATTERNS,
42
+ strict = false,
43
+ debug = false
44
+ } = options;
45
+ let validIcons;
46
+ let scanResult;
47
+ let server = null;
48
+ let root;
49
+ const log = (message) => {
50
+ if (debug) {
51
+ console.log(`[@rotki/ui-library/icons] ${message}`);
52
+ }
53
+ };
54
+ const warn = (message) => {
55
+ console.warn(`[@rotki/ui-library/icons] ${message}`);
56
+ };
57
+ async function scanFiles() {
58
+ const fg = await import("fast-glob");
59
+ const glob = fg.default || fg;
60
+ scanResult = {
61
+ icons: new Set(include),
62
+ invalidIcons: /* @__PURE__ */ new Map()
63
+ };
64
+ const files = glob.sync(scanPatterns, {
65
+ cwd: root,
66
+ ignore: EXCLUDED_PATTERNS,
67
+ absolute: true
68
+ });
69
+ log(`Scanning ${files.length} files for icon usage...`);
70
+ for (const filePath of files) {
71
+ try {
72
+ const content = readFileSync(filePath, "utf-8");
73
+ const detectedIcons = extractIconsFromSource(content);
74
+ if (detectedIcons.size > 0) {
75
+ log(`Found ${detectedIcons.size} potential icons in ${filePath}`);
76
+ validateIcons(detectedIcons, validIcons, filePath, scanResult);
77
+ }
78
+ } catch {
79
+ warn(`Failed to read file: ${filePath}`);
80
+ }
81
+ }
82
+ for (const icon of include) {
83
+ if (validIcons.has(icon)) {
84
+ scanResult.icons.add(icon);
85
+ } else {
86
+ warn(`Included icon "${icon}" is not a valid RuiIcon`);
87
+ }
88
+ }
89
+ log(`Detected ${scanResult.icons.size} valid icons`);
90
+ if (scanResult.invalidIcons.size > 0) {
91
+ const invalidList = [...scanResult.invalidIcons.entries()].map(([icon, files2]) => ` - "${icon}" in: ${files2.join(", ")}`).join("\n");
92
+ const message = `Found ${scanResult.invalidIcons.size} invalid icon name(s):
93
+ ${invalidList}`;
94
+ if (strict) {
95
+ throw new Error(message);
96
+ } else {
97
+ warn(message);
98
+ }
99
+ }
100
+ }
101
+ function handleFileChange(filePath) {
102
+ const isRelevantFile = scanPatterns.some((pattern) => {
103
+ const ext = filePath.split(".").pop();
104
+ return pattern.includes(`*.${ext}`);
105
+ });
106
+ if (!isRelevantFile)
107
+ return;
108
+ try {
109
+ const content = readFileSync(filePath, "utf-8");
110
+ const detectedIcons = extractIconsFromSource(content);
111
+ const previousSize = scanResult.icons.size;
112
+ validateIcons(detectedIcons, validIcons, filePath, scanResult);
113
+ if (scanResult.icons.size > previousSize) {
114
+ log(`New icons detected in ${filePath}, invalidating virtual module...`);
115
+ const mod = server?.moduleGraph.getModuleById(RESOLVED_VIRTUAL_MODULE_ID);
116
+ if (mod) {
117
+ server?.moduleGraph.invalidateModule(mod);
118
+ server?.ws.send({
119
+ type: "full-reload",
120
+ path: "*"
121
+ });
122
+ }
123
+ }
124
+ } catch {
125
+ }
126
+ }
127
+ return {
128
+ name: "rotki-ui-library-icons",
129
+ enforce: "pre",
130
+ configResolved(config) {
131
+ root = config.root;
132
+ validIcons = loadValidIcons();
133
+ log(`Loaded ${validIcons.size} valid icon names`);
134
+ },
135
+ configureServer(_server) {
136
+ server = _server;
137
+ server.watcher.on("change", handleFileChange);
138
+ server.watcher.on("add", handleFileChange);
139
+ },
140
+ async buildStart() {
141
+ await scanFiles();
142
+ },
143
+ resolveId(id) {
144
+ if (id === VIRTUAL_MODULE_ID) {
145
+ return RESOLVED_VIRTUAL_MODULE_ID;
146
+ }
147
+ },
148
+ load(id) {
149
+ if (id === RESOLVED_VIRTUAL_MODULE_ID) {
150
+ const moduleContent = generateVirtualModule(scanResult.icons);
151
+ log(`Generated virtual module with ${scanResult.icons.size} icons`);
152
+ return moduleContent;
153
+ }
154
+ }
155
+ };
156
+ }
157
+ export {
158
+ ruiIconsPlugin as default,
159
+ ruiIconsPlugin
160
+ };
161
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../src/vite-plugin/index.ts"],"sourcesContent":["import type { Plugin, ViteDevServer } from 'vite';\nimport type { RuiIconsPluginOptions, ScanResult } from './types';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n extractIconsFromSource,\n generateVirtualModule,\n validateIcons,\n} from './scanner';\n\nconst VIRTUAL_MODULE_ID = 'virtual:rotki-icons';\nconst RESOLVED_VIRTUAL_MODULE_ID = `\\0${VIRTUAL_MODULE_ID}`;\n\nconst DEFAULT_SCAN_PATTERNS = ['**/*.vue', '**/*.ts', '**/*.tsx'];\nconst EXCLUDED_PATTERNS = ['**/node_modules/**', '**/dist/**', '**/.git/**'];\n\n// Get __dirname equivalent in ES modules\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Loads the valid RuiIcons array from the library\n */\nfunction loadValidIcons(): Set<string> {\n // Import the RuiIcons array from the icons module\n // This will be resolved at build time\n try {\n // Try to load from the built dist first (for consumers)\n const distPath = resolve(__dirname, '../icons/index.js');\n if (existsSync(distPath)) {\n // Read and parse the file to extract the RuiIcons array\n const content = readFileSync(distPath, 'utf-8');\n // eslint-disable-next-line regexp/strict\n const match = content.match(/const RuiIcons = \\[(.*?)];/s);\n if (match?.[1]) {\n const iconsStr = match[1];\n const icons = iconsStr.match(/\"([^\"]+)\"/g)?.map(s => s.slice(1, -1)) || [];\n return new Set(icons);\n }\n }\n }\n catch {\n // Fallback: parse the icons source file directly\n }\n\n // Fallback: read and parse the source file\n const sourcePath = resolve(__dirname, '../icons/index.ts');\n if (existsSync(sourcePath)) {\n const content = readFileSync(sourcePath, 'utf-8');\n // eslint-disable-next-line regexp/strict\n const match = content.match(/export const RuiIcons = \\[(.*?)] as const/s);\n if (match?.[1]) {\n const iconsStr = match[1];\n const icons = iconsStr.match(/\"([^\"]+)\"/g)?.map(s => s.slice(1, -1)) || [];\n return new Set(icons);\n }\n }\n\n console.warn('[@rotki/ui-library] Could not load RuiIcons list, validation disabled');\n return new Set();\n}\n\n/**\n * Vite plugin for automatic icon detection and registration\n */\nexport function ruiIconsPlugin(options: RuiIconsPluginOptions = {}): Plugin {\n const {\n include = [],\n scanPatterns = DEFAULT_SCAN_PATTERNS,\n strict = false,\n debug = false,\n } = options;\n\n let validIcons: Set<string>;\n let scanResult: ScanResult;\n let server: ViteDevServer | null = null;\n let root: string;\n\n const log = (message: string): void => {\n if (debug) {\n // eslint-disable-next-line no-console\n console.log(`[@rotki/ui-library/icons] ${message}`);\n }\n };\n\n const warn = (message: string): void => {\n console.warn(`[@rotki/ui-library/icons] ${message}`);\n };\n\n /**\n * Scans all matching files for icon usage\n */\n async function scanFiles(): Promise<void> {\n const fg = await import('fast-glob');\n const glob = fg.default || fg;\n\n scanResult = {\n icons: new Set(include),\n invalidIcons: new Map(),\n };\n\n const files = glob.sync(scanPatterns, {\n cwd: root,\n ignore: EXCLUDED_PATTERNS,\n absolute: true,\n });\n\n log(`Scanning ${files.length} files for icon usage...`);\n\n for (const filePath of files) {\n try {\n const content = readFileSync(filePath, 'utf-8');\n const detectedIcons = extractIconsFromSource(content);\n\n if (detectedIcons.size > 0) {\n log(`Found ${detectedIcons.size} potential icons in ${filePath}`);\n validateIcons(detectedIcons, validIcons, filePath, scanResult);\n }\n }\n catch {\n warn(`Failed to read file: ${filePath}`);\n }\n }\n\n // Add manually included icons\n for (const icon of include) {\n if (validIcons.has(icon)) {\n scanResult.icons.add(icon);\n }\n else {\n warn(`Included icon \"${icon}\" is not a valid RuiIcon`);\n }\n }\n\n log(`Detected ${scanResult.icons.size} valid icons`);\n\n // Report invalid icons\n if (scanResult.invalidIcons.size > 0) {\n const invalidList = [...scanResult.invalidIcons.entries()]\n .map(([icon, files]) => ` - \"${icon}\" in: ${files.join(', ')}`)\n .join('\\n');\n\n const message = `Found ${scanResult.invalidIcons.size} invalid icon name(s):\\n${invalidList}`;\n\n if (strict) {\n throw new Error(message);\n }\n else {\n warn(message);\n }\n }\n }\n\n /**\n * Handles file changes in dev mode\n */\n function handleFileChange(filePath: string): void {\n // Check if the changed file matches our scan patterns\n const isRelevantFile = scanPatterns.some((pattern) => {\n const ext = filePath.split('.').pop();\n return pattern.includes(`*.${ext}`);\n });\n\n if (!isRelevantFile)\n return;\n\n try {\n const content = readFileSync(filePath, 'utf-8');\n const detectedIcons = extractIconsFromSource(content);\n const previousSize = scanResult.icons.size;\n\n validateIcons(detectedIcons, validIcons, filePath, scanResult);\n\n // If new icons were detected, invalidate the virtual module\n if (scanResult.icons.size > previousSize) {\n log(`New icons detected in ${filePath}, invalidating virtual module...`);\n\n // Invalidate the virtual module to trigger re-import\n const mod = server?.moduleGraph.getModuleById(RESOLVED_VIRTUAL_MODULE_ID);\n if (mod) {\n server?.moduleGraph.invalidateModule(mod);\n // Trigger HMR update\n server?.ws.send({\n type: 'full-reload',\n path: '*',\n });\n }\n }\n }\n catch {\n // Ignore read errors\n }\n }\n\n return {\n name: 'rotki-ui-library-icons',\n enforce: 'pre',\n\n configResolved(config) {\n root = config.root;\n validIcons = loadValidIcons();\n log(`Loaded ${validIcons.size} valid icon names`);\n },\n\n configureServer(_server) {\n server = _server;\n\n // Watch for file changes\n server.watcher.on('change', handleFileChange);\n server.watcher.on('add', handleFileChange);\n },\n\n async buildStart() {\n await scanFiles();\n },\n\n resolveId(id) {\n if (id === VIRTUAL_MODULE_ID) {\n return RESOLVED_VIRTUAL_MODULE_ID;\n }\n },\n\n load(id) {\n if (id === RESOLVED_VIRTUAL_MODULE_ID) {\n const moduleContent = generateVirtualModule(scanResult.icons);\n log(`Generated virtual module with ${scanResult.icons.size} icons`);\n return moduleContent;\n }\n },\n };\n}\n\nexport type { RuiIconsPluginOptions } from './types';\n\n// eslint-disable-next-line import/no-default-export\nexport default ruiIconsPlugin;\n"],"names":["files"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { ScanResult } from './types';
2
+ /**
3
+ * Extracts all potential icon names from source code
4
+ */
5
+ export declare function extractIconsFromSource(source: string): Set<string>;
6
+ /**
7
+ * Validates detected icons against known valid icons
8
+ */
9
+ export declare function validateIcons(detectedIcons: Set<string>, validIcons: Set<string>, filePath: string, result: ScanResult): void;
10
+ /**
11
+ * Converts icon name to export constant name
12
+ * e.g., 'lu-arrow-down' -> 'LuArrowDown'
13
+ */
14
+ export declare function iconNameToExportName(iconName: string): string;
15
+ /**
16
+ * Generates the virtual module content with detected icons
17
+ */
18
+ export declare function generateVirtualModule(icons: Set<string>): string;
@@ -0,0 +1,63 @@
1
+ const ICON_PATTERNS = [
2
+ // Static name attribute: <RuiIcon name="lu-star" /> or name='lu-star'
3
+ /\bname=["'](lu-[\da-z-]+)["']/gi,
4
+ // Dynamic bound name with string literal: :name="'lu-star'" or :name="`lu-star`"
5
+ /:name=["']['`](lu-[\da-z-]+)['`]?["']/gi,
6
+ // String literals that look like icon names: 'lu-star' or "lu-star"
7
+ /["'`](lu-[\da-z-]+)["'`]/gi
8
+ ];
9
+ function extractIconsFromSource(source) {
10
+ const icons = /* @__PURE__ */ new Set();
11
+ for (const pattern of ICON_PATTERNS) {
12
+ pattern.lastIndex = 0;
13
+ let match = pattern.exec(source);
14
+ while (match !== null) {
15
+ const iconName = match[1];
16
+ if (iconName) {
17
+ icons.add(iconName);
18
+ }
19
+ match = pattern.exec(source);
20
+ }
21
+ }
22
+ return icons;
23
+ }
24
+ function validateIcons(detectedIcons, validIcons, filePath, result) {
25
+ for (const icon of detectedIcons) {
26
+ if (validIcons.has(icon)) {
27
+ result.icons.add(icon);
28
+ } else {
29
+ const files = result.invalidIcons.get(icon) || [];
30
+ files.push(filePath);
31
+ result.invalidIcons.set(icon, files);
32
+ }
33
+ }
34
+ }
35
+ function iconNameToExportName(iconName) {
36
+ return iconName.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
37
+ }
38
+ function generateVirtualModule(icons) {
39
+ if (icons.size === 0) {
40
+ return `// No icons detected
41
+ export default [];
42
+ `;
43
+ }
44
+ const sortedIcons = [...icons].sort();
45
+ const exports = sortedIcons.map(iconNameToExportName);
46
+ const importStatement = `import {
47
+ ${exports.join(",\n ")},
48
+ } from '@rotki/ui-library';
49
+ `;
50
+ const exportStatement = `
51
+ export default [
52
+ ${exports.join(",\n ")},
53
+ ];
54
+ `;
55
+ return importStatement + exportStatement;
56
+ }
57
+ export {
58
+ extractIconsFromSource,
59
+ generateVirtualModule,
60
+ iconNameToExportName,
61
+ validateIcons
62
+ };
63
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sources":["../../src/vite-plugin/scanner.ts"],"sourcesContent":["import type { ScanResult } from './types';\n\n/**\n * Regex patterns to detect icon usage in source files\n */\nconst ICON_PATTERNS: RegExp[] = [\n // Static name attribute: <RuiIcon name=\"lu-star\" /> or name='lu-star'\n /\\bname=[\"'](lu-[\\da-z-]+)[\"']/gi,\n\n // Dynamic bound name with string literal: :name=\"'lu-star'\" or :name=\"`lu-star`\"\n /:name=[\"']['`](lu-[\\da-z-]+)['`]?[\"']/gi,\n\n // String literals that look like icon names: 'lu-star' or \"lu-star\"\n /[\"'`](lu-[\\da-z-]+)[\"'`]/gi,\n];\n\n/**\n * Extracts all potential icon names from source code\n */\nexport function extractIconsFromSource(source: string): Set<string> {\n const icons = new Set<string>();\n\n for (const pattern of ICON_PATTERNS) {\n // Reset lastIndex for global regex\n pattern.lastIndex = 0;\n\n let match: RegExpExecArray | null = pattern.exec(source);\n while (match !== null) {\n const iconName = match[1];\n if (iconName) {\n icons.add(iconName);\n }\n match = pattern.exec(source);\n }\n }\n\n return icons;\n}\n\n/**\n * Validates detected icons against known valid icons\n */\nexport function validateIcons(\n detectedIcons: Set<string>,\n validIcons: Set<string>,\n filePath: string,\n result: ScanResult,\n): void {\n for (const icon of detectedIcons) {\n if (validIcons.has(icon)) {\n result.icons.add(icon);\n }\n else {\n // Track invalid icons\n const files = result.invalidIcons.get(icon) || [];\n files.push(filePath);\n result.invalidIcons.set(icon, files);\n }\n }\n}\n\n/**\n * Converts icon name to export constant name\n * e.g., 'lu-arrow-down' -> 'LuArrowDown'\n */\nexport function iconNameToExportName(iconName: string): string {\n return iconName\n .split('-')\n .map(part => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n\n/**\n * Generates the virtual module content with detected icons\n */\nexport function generateVirtualModule(icons: Set<string>): string {\n if (icons.size === 0) {\n return `// No icons detected\nexport default [];\n`;\n }\n\n const sortedIcons = [...icons].sort();\n const exports = sortedIcons.map(iconNameToExportName);\n\n const importStatement = `import {\\n ${exports.join(',\\n ')},\\n} from '@rotki/ui-library';\\n`;\n const exportStatement = `\\nexport default [\\n ${exports.join(',\\n ')},\\n];\\n`;\n\n return importStatement + exportStatement;\n}\n"],"names":[],"mappings":"AAKA,MAAM,gBAA0B;AAAA;AAAA,EAE9B;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AACF;AAKO,SAAS,uBAAuB,QAA6B;AAClE,QAAM,4BAAY,IAAA;AAElB,aAAW,WAAW,eAAe;AAEnC,YAAQ,YAAY;AAEpB,QAAI,QAAgC,QAAQ,KAAK,MAAM;AACvD,WAAO,UAAU,MAAM;AACrB,YAAM,WAAW,MAAM,CAAC;AACxB,UAAI,UAAU;AACZ,cAAM,IAAI,QAAQ;AAAA,MACpB;AACA,cAAQ,QAAQ,KAAK,MAAM;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,cACd,eACA,YACA,UACA,QACM;AACN,aAAW,QAAQ,eAAe;AAChC,QAAI,WAAW,IAAI,IAAI,GAAG;AACxB,aAAO,MAAM,IAAI,IAAI;AAAA,IACvB,OACK;AAEH,YAAM,QAAQ,OAAO,aAAa,IAAI,IAAI,KAAK,CAAA;AAC/C,YAAM,KAAK,QAAQ;AACnB,aAAO,aAAa,IAAI,MAAM,KAAK;AAAA,IACrC;AAAA,EACF;AACF;AAMO,SAAS,qBAAqB,UAA0B;AAC7D,SAAO,SACJ,MAAM,GAAG,EACT,IAAI,CAAA,SAAQ,KAAK,OAAO,CAAC,EAAE,YAAA,IAAgB,KAAK,MAAM,CAAC,CAAC,EACxD,KAAK,EAAE;AACZ;AAKO,SAAS,sBAAsB,OAA4B;AAChE,MAAI,MAAM,SAAS,GAAG;AACpB,WAAO;AAAA;AAAA;AAAA,EAGT;AAEA,QAAM,cAAc,CAAC,GAAG,KAAK,EAAE,KAAA;AAC/B,QAAM,UAAU,YAAY,IAAI,oBAAoB;AAEpD,QAAM,kBAAkB;AAAA,IAAe,QAAQ,KAAK,OAAO,CAAC;AAAA;AAAA;AAC5D,QAAM,kBAAkB;AAAA;AAAA,IAAyB,QAAQ,KAAK,OAAO,CAAC;AAAA;AAAA;AAEtE,SAAO,kBAAkB;AAC3B;"}
@@ -0,0 +1,28 @@
1
+ export interface RuiIconsPluginOptions {
2
+ /**
3
+ * Additional icons to always include (for dynamically used icons that can't be statically detected)
4
+ * @example ['lu-custom-icon', 'lu-dynamic-icon']
5
+ */
6
+ include?: string[];
7
+ /**
8
+ * Glob patterns for files to scan
9
+ * @default ['** /*.vue', '** /*.ts', '** /*.tsx'] (without spaces)
10
+ */
11
+ scanPatterns?: string[];
12
+ /**
13
+ * Strict mode - fail build on invalid icon names
14
+ * @default false
15
+ */
16
+ strict?: boolean;
17
+ /**
18
+ * Enable debug logging
19
+ * @default false
20
+ */
21
+ debug?: boolean;
22
+ }
23
+ export interface ScanResult {
24
+ /** Set of detected icon names */
25
+ icons: Set<string>;
26
+ /** Map of invalid icons to the files they were found in */
27
+ invalidIcons: Map<string, string[]>;
28
+ }
@@ -2,7 +2,7 @@
2
2
  "$schema": "http://json.schemastore.org/web-types",
3
3
  "framework": "vue",
4
4
  "name": "@rotki/ui-library",
5
- "version": "2.8.3",
5
+ "version": "2.9.1",
6
6
  "js-types-syntax": "typescript",
7
7
  "description-markup": "markdown",
8
8
  "contributions": {
@@ -1035,6 +1035,16 @@
1035
1035
  "type": "boolean | undefined"
1036
1036
  }
1037
1037
  },
1038
+ {
1039
+ "name": "required",
1040
+ "description": "",
1041
+ "required": false,
1042
+ "default": "false",
1043
+ "value": {
1044
+ "kind": "expression",
1045
+ "type": "boolean | undefined"
1046
+ }
1047
+ },
1038
1048
  {
1039
1049
  "name": "model-value",
1040
1050
  "description": "",
@@ -3498,6 +3508,16 @@
3498
3508
  "type": "boolean | undefined"
3499
3509
  }
3500
3510
  },
3511
+ {
3512
+ "name": "required",
3513
+ "description": "",
3514
+ "required": false,
3515
+ "default": "false",
3516
+ "value": {
3517
+ "kind": "expression",
3518
+ "type": "boolean | undefined"
3519
+ }
3520
+ },
3501
3521
  {
3502
3522
  "name": "model-value",
3503
3523
  "description": "",
@@ -3779,6 +3799,16 @@
3779
3799
  "kind": "expression",
3780
3800
  "type": "boolean | undefined"
3781
3801
  }
3802
+ },
3803
+ {
3804
+ "name": "required",
3805
+ "description": "",
3806
+ "required": false,
3807
+ "default": "false",
3808
+ "value": {
3809
+ "kind": "expression",
3810
+ "type": "boolean | undefined"
3811
+ }
3782
3812
  }
3783
3813
  ],
3784
3814
  "slots": [
@@ -3970,6 +4000,16 @@
3970
4000
  "type": "boolean | undefined"
3971
4001
  }
3972
4002
  },
4003
+ {
4004
+ "name": "required",
4005
+ "description": "",
4006
+ "required": false,
4007
+ "default": "false",
4008
+ "value": {
4009
+ "kind": "expression",
4010
+ "type": "boolean | undefined"
4011
+ }
4012
+ },
3973
4013
  {
3974
4014
  "name": "model-value",
3975
4015
  "description": "",
@@ -4248,6 +4288,16 @@
4248
4288
  "type": "string | undefined"
4249
4289
  }
4250
4290
  },
4291
+ {
4292
+ "name": "required",
4293
+ "description": "",
4294
+ "required": false,
4295
+ "default": "false",
4296
+ "value": {
4297
+ "kind": "expression",
4298
+ "type": "boolean | undefined"
4299
+ }
4300
+ },
4251
4301
  {
4252
4302
  "name": "model-value",
4253
4303
  "description": "",
@@ -4653,6 +4703,16 @@
4653
4703
  "kind": "expression",
4654
4704
  "type": "string | undefined"
4655
4705
  }
4706
+ },
4707
+ {
4708
+ "name": "required",
4709
+ "description": "",
4710
+ "required": false,
4711
+ "default": "false",
4712
+ "value": {
4713
+ "kind": "expression",
4714
+ "type": "boolean | undefined"
4715
+ }
4656
4716
  }
4657
4717
  ],
4658
4718
  "slots": [],
@@ -4766,6 +4826,16 @@
4766
4826
  "kind": "expression",
4767
4827
  "type": "boolean | undefined"
4768
4828
  }
4829
+ },
4830
+ {
4831
+ "name": "required",
4832
+ "description": "",
4833
+ "required": false,
4834
+ "default": "false",
4835
+ "value": {
4836
+ "kind": "expression",
4837
+ "type": "boolean | undefined"
4838
+ }
4769
4839
  }
4770
4840
  ],
4771
4841
  "slots": [
@@ -4998,6 +5068,16 @@
4998
5068
  "type": "boolean | undefined"
4999
5069
  }
5000
5070
  },
5071
+ {
5072
+ "name": "required",
5073
+ "description": "",
5074
+ "required": false,
5075
+ "default": "false",
5076
+ "value": {
5077
+ "kind": "expression",
5078
+ "type": "boolean | undefined"
5079
+ }
5080
+ },
5001
5081
  {
5002
5082
  "name": "model-value",
5003
5083
  "description": "",
@@ -5200,6 +5280,16 @@
5200
5280
  "type": "boolean | undefined"
5201
5281
  }
5202
5282
  },
5283
+ {
5284
+ "name": "required",
5285
+ "description": "",
5286
+ "required": false,
5287
+ "default": "false",
5288
+ "value": {
5289
+ "kind": "expression",
5290
+ "type": "boolean | undefined"
5291
+ }
5292
+ },
5203
5293
  {
5204
5294
  "name": "model-value",
5205
5295
  "description": "",
@@ -6611,6 +6701,16 @@
6611
6701
  "type": "boolean | undefined"
6612
6702
  }
6613
6703
  },
6704
+ {
6705
+ "name": "required",
6706
+ "description": "",
6707
+ "required": false,
6708
+ "default": "false",
6709
+ "value": {
6710
+ "kind": "expression",
6711
+ "type": "boolean | undefined"
6712
+ }
6713
+ },
6614
6714
  {
6615
6715
  "name": "model-value",
6616
6716
  "description": "",
@@ -6741,6 +6841,16 @@
6741
6841
  "type": "'sm' | 'lg' | undefined"
6742
6842
  }
6743
6843
  },
6844
+ {
6845
+ "name": "required",
6846
+ "description": "",
6847
+ "required": false,
6848
+ "default": "false",
6849
+ "value": {
6850
+ "kind": "expression",
6851
+ "type": "boolean | undefined"
6852
+ }
6853
+ },
6744
6854
  {
6745
6855
  "name": "model-value",
6746
6856
  "description": "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rotki/ui-library",
3
- "version": "2.8.3",
3
+ "version": "2.9.1",
4
4
  "description": "A vue design system and component library for rotki",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -47,6 +47,14 @@
47
47
  },
48
48
  "./style.css": {
49
49
  "default": "./dist/style.css"
50
+ },
51
+ "./vite-plugin": {
52
+ "types": "./dist/vite-plugin/index.d.ts",
53
+ "import": "./dist/vite-plugin/index.js",
54
+ "default": "./dist/vite-plugin/index.js"
55
+ },
56
+ "./vite-plugin/client": {
57
+ "types": "./dist/vite-plugin/client.d.ts"
50
58
  }
51
59
  },
52
60
  "typesVersions": {
@@ -59,6 +67,12 @@
59
67
  ],
60
68
  "components": [
61
69
  "./dist/components/index.d.ts"
70
+ ],
71
+ "vite-plugin": [
72
+ "./dist/vite-plugin/index.d.ts"
73
+ ],
74
+ "vite-plugin/client": [
75
+ "./dist/vite-plugin/client.d.ts"
62
76
  ]
63
77
  }
64
78
  },
@@ -87,7 +101,7 @@
87
101
  "@storybook/addon-themes": "10.0.2",
88
102
  "@storybook/vue3-vite": "10.0.2",
89
103
  "@tsconfig/node22": "22.0.2",
90
- "@types/jsdom": "^27.0.0",
104
+ "@types/jsdom": "27.0.0",
91
105
  "@types/node": "22.18.13",
92
106
  "@types/tinycolor2": "1.4.6",
93
107
  "@vitejs/plugin-vue": "6.0.1",
@@ -106,7 +120,6 @@
106
120
  "consola": "3.4.2",
107
121
  "css-loader": "7.1.2",
108
122
  "eslint": "9.38.0",
109
- "eslint-plugin-cypress": "5.2.0",
110
123
  "eslint-plugin-storybook": "10.0.2",
111
124
  "fast-glob": "3.3.3",
112
125
  "fast-xml-parser": "5.3.0",
@@ -139,7 +152,7 @@
139
152
  },
140
153
  "scripts": {
141
154
  "build:prod": "tsx scripts/dist-build.mjs",
142
- "build": "pnpm run generate-icons && vite build && cp ../../README.md dist/",
155
+ "build": "pnpm run generate-icons && vite build && cp ../../README.md dist/ && cp src/vite-plugin/client.d.ts dist/vite-plugin/",
143
156
  "build:storybook": "STORYBOOK=true storybook build",
144
157
  "build:tailwind": "tailwindcss -o dist/style.css --minify",
145
158
  "build:types": "vue-tsc -p tsconfig.build.json",