fvn-ui 0.1.0-alpha.13 → 0.1.0-alpha.15
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/AGENTS.md +15 -0
- package/package.json +1 -1
- package/src/fvn-ui/LLM.md +33 -1
- package/src/fvn-ui/components/button.js +3 -1
- package/src/fvn-ui/components/collapsible.js +2 -2
- package/src/fvn-ui/components/draggable.js +1 -1
- package/src/fvn-ui/components/select.js +1 -1
- package/src/fvn-ui/components/svg.js +45 -18
- package/src/fvn-ui/index.js +1 -0
package/AGENTS.md
CHANGED
|
@@ -127,6 +127,21 @@ ui.col({ center: true }, [
|
|
|
127
127
|
| `center: true` | Center content (justify for col, align for row) |
|
|
128
128
|
| `distribute: 'equal'` | Children share space equally |
|
|
129
129
|
|
|
130
|
+
## Custom Icons
|
|
131
|
+
|
|
132
|
+
Extend with icons from [Lucide](https://lucide.dev/icons) or [Feather](https://feathericons.com):
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
// Add icons using SVG inner content (no <svg> wrapper)
|
|
136
|
+
ui.svg.extend({
|
|
137
|
+
github: '<path d="M15 22v-4a4.8..."/>',
|
|
138
|
+
custom: '<circle cx="12" cy="12" r="10"/>'
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
ui.button({ icon: 'github' }) // Now works
|
|
142
|
+
ui.svg.list() // Get all icon names
|
|
143
|
+
```
|
|
144
|
+
|
|
130
145
|
## Full Documentation
|
|
131
146
|
|
|
132
147
|
For complete API reference, examples, and patterns, read:
|
package/package.json
CHANGED
package/src/fvn-ui/LLM.md
CHANGED
|
@@ -475,10 +475,42 @@ avatar({ src: 'photo.jpg', name: 'Jane', size: 'large' })
|
|
|
475
475
|
|
|
476
476
|
---
|
|
477
477
|
|
|
478
|
-
##
|
|
478
|
+
## Icons
|
|
479
|
+
|
|
480
|
+
### Built-in Icons
|
|
479
481
|
|
|
480
482
|
`check`, `x`, `plus`, `minus`, `search`, `settings`, `user`, `users`, `mail`, `phone`, `calendar`, `clock`, `star`, `heart`, `home`, `menu`, `more`, `edit`, `trash`, `copy`, `download`, `upload`, `link`, `external`, `chevron-up`, `chevron-down`, `chevron-left`, `chevron-right`, `arrow-up`, `arrow-down`, `arrow-left`, `arrow-right`, `sun`, `moon`, `eye`, `eye-off`, `lock`, `unlock`, `bell`, `filter`, `sort`, `refresh`, `info`, `warning`, `error`, `success`
|
|
481
483
|
|
|
484
|
+
### Extending Icons
|
|
485
|
+
|
|
486
|
+
Add custom icons from [Feather Icons](https://feathericons.com) or [Lucide](https://lucide.dev/icons):
|
|
487
|
+
|
|
488
|
+
```js
|
|
489
|
+
import { svg } from 'fvn-ui'
|
|
490
|
+
|
|
491
|
+
// Add custom icons - use SVG inner content only (no <svg> wrapper)
|
|
492
|
+
svg.extend({
|
|
493
|
+
// From Lucide: copy the path/circle/line elements inside <svg>
|
|
494
|
+
github: '<path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"/><path d="M9 18c-4.51 2-5-2-7-2"/>',
|
|
495
|
+
|
|
496
|
+
// From Feather: same approach
|
|
497
|
+
activity: '<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>'
|
|
498
|
+
})
|
|
499
|
+
|
|
500
|
+
// Now use them
|
|
501
|
+
button({ icon: 'github', label: 'GitHub' })
|
|
502
|
+
svg('activity')
|
|
503
|
+
|
|
504
|
+
// List all available icons
|
|
505
|
+
svg.list() // ['check', 'x', ..., 'github', 'activity']
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
**How to extract icon content:**
|
|
509
|
+
1. Find icon on [lucide.dev/icons](https://lucide.dev/icons) or [feathericons.com](https://feathericons.com)
|
|
510
|
+
2. Copy the SVG code
|
|
511
|
+
3. Remove the outer `<svg>...</svg>` wrapper
|
|
512
|
+
4. Keep only the inner elements (`<path>`, `<circle>`, `<line>`, `<polyline>`, etc.)
|
|
513
|
+
|
|
482
514
|
---
|
|
483
515
|
|
|
484
516
|
## Colors
|
|
@@ -34,6 +34,7 @@ export function button(...args) {
|
|
|
34
34
|
size,
|
|
35
35
|
color,
|
|
36
36
|
muted,
|
|
37
|
+
loading,
|
|
37
38
|
type = 'button',
|
|
38
39
|
disabled,
|
|
39
40
|
attrs = {},
|
|
@@ -73,6 +74,7 @@ export function button(...args) {
|
|
|
73
74
|
shape && !isMinimal && bem(shape),
|
|
74
75
|
size && bem.core('size', size),
|
|
75
76
|
muted && bem('muted'),
|
|
77
|
+
loading && 'loading',
|
|
76
78
|
configToClasses(props),
|
|
77
79
|
rest.class
|
|
78
80
|
],
|
|
@@ -100,7 +102,7 @@ export function button(...args) {
|
|
|
100
102
|
}
|
|
101
103
|
},
|
|
102
104
|
toggleLoading(text) {
|
|
103
|
-
this.classList.toggle('loading',
|
|
105
|
+
this.classList.toggle('loading', typeof text === 'string');
|
|
104
106
|
this.textContent = text || label;
|
|
105
107
|
}
|
|
106
108
|
});
|
|
@@ -34,7 +34,7 @@ export function collapsible(...args) {
|
|
|
34
34
|
let state = !!open;
|
|
35
35
|
let iconEl;
|
|
36
36
|
|
|
37
|
-
const getIcon = () => svg(state ? '
|
|
37
|
+
const getIcon = () => svg(state ? 'chevron-down' : 'chevron-right');
|
|
38
38
|
|
|
39
39
|
const toggle = () => {
|
|
40
40
|
if (disabled) {
|
|
@@ -55,7 +55,7 @@ export function collapsible(...args) {
|
|
|
55
55
|
class: bem.el('trigger'),
|
|
56
56
|
variant: 'none',
|
|
57
57
|
disabled,
|
|
58
|
-
icon: state ? '
|
|
58
|
+
icon: state ? 'chevron-down' : 'chevron-right',
|
|
59
59
|
label,
|
|
60
60
|
onclick: toggle,
|
|
61
61
|
ref: (btn) => iconEl = btn.querySelector('.ui-btn__icon')
|
|
@@ -273,7 +273,7 @@ export function selectComponent(...args) {
|
|
|
273
273
|
children: [
|
|
274
274
|
el('span', { class: bem.el('value'), ref: (e) => valueEl = e }),
|
|
275
275
|
el('span', { class: bem.el('actions'), children: [
|
|
276
|
-
button({ icon: '
|
|
276
|
+
button({ icon: 'chevron-down', variant: 'stripped', muted: true }),
|
|
277
277
|
multiselect && el('span', {
|
|
278
278
|
class: bem.el('badge'),
|
|
279
279
|
ref: (e) => badgeEl = e,
|
|
@@ -5,18 +5,18 @@ import './svg.css';
|
|
|
5
5
|
|
|
6
6
|
const shapes = {
|
|
7
7
|
check: '<polyline points="20 6 9 17 4 12"></polyline>',
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
'chevron-down': '<polyline points="6 9 12 15 18 9"></polyline>',
|
|
9
|
+
'chevron-up': '<polyline points="18 15 12 9 6 15"></polyline>',
|
|
10
|
+
'chevron-left': '<polyline points="15 18 9 12 15 6"></polyline>',
|
|
11
|
+
'chevron-right': '<polyline points="9 18 15 12 9 6"></polyline>',
|
|
12
|
+
'arrow-right': '<line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline>',
|
|
13
|
+
'arrow-left': '<line x1="19" y1="12" x2="5" y2="12"></line><polyline points="12 19 5 12 12 5"></polyline>',
|
|
14
|
+
'arrow-up': '<line x1="12" y1="19" x2="12" y2="5"></line><polyline points="5 12 12 5 19 12"></polyline>',
|
|
15
|
+
'arrow-down': '<line x1="12" y1="5" x2="12" y2="19"></line><polyline points="19 12 12 19 5 12"></polyline>',
|
|
16
16
|
settings: '<path d="M10 5H3"/><path d="M12 19H3"/><path d="M14 3v4"/><path d="M16 17v4"/><path d="M21 12h-9"/><path d="M21 19h-5"/><path d="M21 5h-7"/><path d="M8 10v4"/><path d="M8 12H3"/>',
|
|
17
17
|
x: '<line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line>',
|
|
18
18
|
dots: '<circle cx="12" cy="12" r="1"></circle><circle cx="12" cy="5" r="1"></circle><circle cx="12" cy="19" r="1"></circle>',
|
|
19
|
-
|
|
19
|
+
'dots-horizontal': '<circle cx="12" cy="12" r="1"></circle><circle cx="19" cy="12" r="1"></circle><circle cx="5" cy="12" r="1"></circle>',
|
|
20
20
|
menu: '<line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line>',
|
|
21
21
|
code: '<rect width="18" height="18" x="3" y="3" rx="2"/><path d="m10 8 4 4-4 4"/>',
|
|
22
22
|
enter: '<path d="M11 9a1 1 0 0 0 1-1V5.061a1 1 0 0 1 1.811-.75l6.836 6.836a1.207 1.207 0 0 1 0 1.707l-6.836 6.835a1 1 0 0 1-1.811-.75V16a1 1 0 0 0-1-1H9a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1z"/><path d="M4 9v6"/>',
|
|
@@ -24,7 +24,6 @@ const shapes = {
|
|
|
24
24
|
chat: '<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>',
|
|
25
25
|
moon: '<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>',
|
|
26
26
|
sun: '<circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>',
|
|
27
|
-
hexagon: '<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/>',
|
|
28
27
|
circle: '<circle cx="12" cy="12" r="10"></circle>',
|
|
29
28
|
plus: '<line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line>',
|
|
30
29
|
minus: '<line x1="5" y1="12" x2="19" y2="12"></line>',
|
|
@@ -41,17 +40,17 @@ const shapes = {
|
|
|
41
40
|
star: '<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>',
|
|
42
41
|
bell: '<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path><path d="M13.73 21a2 2 0 0 1-3.46 0"></path>',
|
|
43
42
|
info: '<circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line>',
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
'alert-circle': '<circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line>',
|
|
44
|
+
'alert-triangle': '<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line>',
|
|
45
|
+
'check-circle': '<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline>',
|
|
46
|
+
'x-circle': '<circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line>',
|
|
48
47
|
eye: '<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle>',
|
|
49
|
-
|
|
48
|
+
'eye-off': '<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line>',
|
|
50
49
|
copy: '<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>',
|
|
51
50
|
download: '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line>',
|
|
52
51
|
upload: '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line>',
|
|
53
52
|
link: '<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>',
|
|
54
|
-
|
|
53
|
+
'external-link': '<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line>',
|
|
55
54
|
filter: '<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"></polygon>',
|
|
56
55
|
sliders: '<line x1="4" y1="21" x2="4" y2="14"></line><line x1="4" y1="10" x2="4" y2="3"></line><line x1="12" y1="21" x2="12" y2="12"></line><line x1="12" y1="8" x2="12" y2="3"></line><line x1="20" y1="21" x2="20" y2="16"></line><line x1="20" y1="12" x2="20" y2="3"></line><line x1="1" y1="14" x2="7" y2="14"></line><line x1="9" y1="8" x2="15" y2="8"></line><line x1="17" y1="16" x2="23" y2="16"></line>',
|
|
57
56
|
refresh: '<polyline points="23 4 23 10 17 10"></polyline><polyline points="1 20 1 14 7 14"></polyline><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>',
|
|
@@ -61,6 +60,7 @@ const shapes = {
|
|
|
61
60
|
unlock: '<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 9.9-1"></path>',
|
|
62
61
|
save: '<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path><polyline points="17 21 17 13 7 13 7 21"></polyline><polyline points="7 3 7 8 15 8"></polyline>',
|
|
63
62
|
file: '<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline>',
|
|
63
|
+
'file-text': '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline>',
|
|
64
64
|
folder: '<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path>',
|
|
65
65
|
image: '<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline>',
|
|
66
66
|
grid: '<rect x="3" y="3" width="7" height="7"></rect><rect x="14" y="3" width="7" height="7"></rect><rect x="14" y="14" width="7" height="7"></rect><rect x="3" y="14" width="7" height="7"></rect>',
|
|
@@ -72,7 +72,10 @@ const shapes = {
|
|
|
72
72
|
pause: '<rect x="6" y="4" width="4" height="16"></rect><rect x="14" y="4" width="4" height="16"></rect>',
|
|
73
73
|
rabbit: '<path d="M13 16a3 3 0 0 1 2.24 5"/><path d="M18 12h.01"/><path d="M18 21h-8a4 4 0 0 1-4-4 7 7 0 0 1 7-7h.2L9.6 6.4a1 1 0 1 1 2.8-2.8L15.8 7h.2c3.3 0 6 2.7 6 6v1a2 2 0 0 1-2 2h-1a3 3 0 0 0-3 3"/><path d="M20 8.54V4a2 2 0 1 0-4 0v3"/><path d="M7.612 12.524a3 3 0 1 0-1.6 4.3"/>',
|
|
74
74
|
bird: '<path d="M16 7h.01"/><path d="M3.4 18H12a8 8 0 0 0 8-8V7a4 4 0 0 0-7.28-2.3L2 20"/><path d="m20 7 2 .5-2 .5"/><path d="M10 18v3"/><path d="M14 17.75V21"/><path d="M7 18a6 6 0 0 0 3.84-10.61"/>',
|
|
75
|
-
toggle: '<rect x="1" y="5" width="22" height="14" rx="7" ry="7"></rect><circle cx="8" cy="12" r="3"></circle>'
|
|
75
|
+
toggle: '<rect x="1" y="5" width="22" height="14" rx="7" ry="7"></rect><circle cx="8" cy="12" r="3"></circle>',
|
|
76
|
+
hash: '<line x1="4" y1="9" x2="20" y2="9"></line><line x1="4" y1="15" x2="20" y2="15"></line><line x1="10" y1="3" x2="8" y2="21"></line><line x1="16" y1="3" x2="14" y2="21"></line>',
|
|
77
|
+
type: '<polyline points="4 7 4 4 20 4 20 7"></polyline><line x1="9" y1="20" x2="15" y2="20"></line><line x1="12" y1="4" x2="12" y2="20"></line>',
|
|
78
|
+
grip: '<circle cx="12" cy="5" r="1"/><circle cx="19" cy="5" r="1"/><circle cx="5" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/><circle cx="12" cy="19" r="1"/><circle cx="19" cy="19" r="1"/><circle cx="5" cy="19" r="1"/>'
|
|
76
79
|
};
|
|
77
80
|
|
|
78
81
|
const wrap = (shape, n) => !shape
|
|
@@ -83,4 +86,28 @@ const wrap = (shape, n) => !shape
|
|
|
83
86
|
</svg>
|
|
84
87
|
`;
|
|
85
88
|
|
|
86
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Get SVG icon markup by name
|
|
91
|
+
* @param {string} n - Icon name
|
|
92
|
+
* @returns {string} SVG markup
|
|
93
|
+
* @property {Function} extend - Add custom icons: `svg.extend({ iconName: '<path.../>' })`
|
|
94
|
+
* @property {Function} list - Get available icon names: `svg.list()` → string[]
|
|
95
|
+
* @example
|
|
96
|
+
* // Get built-in icon
|
|
97
|
+
* svg('check')
|
|
98
|
+
* svg('settings')
|
|
99
|
+
*
|
|
100
|
+
* // Extend with custom icons
|
|
101
|
+
* svg.extend({
|
|
102
|
+
* myIcon: '<path d="M12 2L2 22h20L12 2z"/>',
|
|
103
|
+
* logo: '<circle cx="12" cy="12" r="10"/>'
|
|
104
|
+
* })
|
|
105
|
+
* svg('myIcon') // Now available
|
|
106
|
+
*
|
|
107
|
+
* // List all icons
|
|
108
|
+
* svg.list() // ['check', 'x', 'plus', ..., 'myIcon', 'logo']
|
|
109
|
+
*/
|
|
110
|
+
export const svg = n => wrap(shapes[n], n);
|
|
111
|
+
|
|
112
|
+
svg.extend = (icons) => Object.assign(shapes, icons);
|
|
113
|
+
svg.list = () => Object.keys(shapes);
|
package/src/fvn-ui/index.js
CHANGED