@vobs/ui 1.3.1 → 1.3.3
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/icon.cjs +8 -1
- package/dist/icon.cjs.map +1 -1
- package/dist/icon.js +8 -1
- package/dist/icon.js.map +1 -1
- package/dist/index.cjs +36 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/toast.cjs +35 -30
- package/dist/toast.cjs.map +1 -1
- package/dist/toast.js +6 -1
- package/dist/toast.js.map +1 -1
- package/package.json +5 -5
- package/src/icon.ts +13 -1
package/dist/icon.cjs
CHANGED
|
@@ -30,6 +30,7 @@ __export(icon_exports, {
|
|
|
30
30
|
});
|
|
31
31
|
module.exports = __toCommonJS(icon_exports);
|
|
32
32
|
var import_icon_core = require("@vobs/icon-core");
|
|
33
|
+
var import_vobs2 = require("@vobs/vobs");
|
|
33
34
|
|
|
34
35
|
// packages/ui/src/utils.ts
|
|
35
36
|
var import_reactivity = require("@vobs/reactivity");
|
|
@@ -67,12 +68,15 @@ __name(resolveSlot, "resolveSlot");
|
|
|
67
68
|
// packages/ui/src/icon.ts
|
|
68
69
|
function Icon(props = {}) {
|
|
69
70
|
const root = (0, import_icon_core.createSvgIconNode)(() => {
|
|
71
|
+
registryVersion.value;
|
|
70
72
|
const definition = resolveIcon(
|
|
71
73
|
readProp(props, "icon", void 0) ?? readProp(props, "name", void 0)
|
|
72
74
|
);
|
|
73
75
|
if (!definition) {
|
|
74
76
|
if (hasProp(props, "children")) return void 0;
|
|
75
|
-
|
|
77
|
+
const requested = readProp(props, "icon", void 0) ?? readProp(props, "name", void 0);
|
|
78
|
+
console.warn(`Vobs UI: \u672A\u6CE8\u518C\u7684\u56FE\u6807 "${String(requested)}"\uFF0C\u5DF2\u6E32\u67D3\u4E3A\u7A7A\u3002\u8BF7\u5148 registerIcon \u6216\u6539\u7528\u5DF2\u6CE8\u518C\u7684\u540D\u79F0\u3002`);
|
|
79
|
+
return void 0;
|
|
76
80
|
}
|
|
77
81
|
return iconDefinitionToSvg(definition);
|
|
78
82
|
}, props, {
|
|
@@ -146,12 +150,15 @@ var VUI_ICON_PATHS = {
|
|
|
146
150
|
var iconRegistry = new Map(
|
|
147
151
|
Object.entries(VUI_ICON_PATHS).map(([name, path]) => [name, { name, path }])
|
|
148
152
|
);
|
|
153
|
+
var registryVersion = (0, import_vobs2.state)(0, "vui.iconRegistry.version");
|
|
149
154
|
function registerIcon(icon) {
|
|
150
155
|
const previous = iconRegistry.get(icon.name);
|
|
151
156
|
iconRegistry.set(icon.name, icon);
|
|
157
|
+
registryVersion.value++;
|
|
152
158
|
return () => {
|
|
153
159
|
if (previous) iconRegistry.set(icon.name, previous);
|
|
154
160
|
else iconRegistry.delete(icon.name);
|
|
161
|
+
registryVersion.value++;
|
|
155
162
|
};
|
|
156
163
|
}
|
|
157
164
|
__name(registerIcon, "registerIcon");
|
package/dist/icon.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/icon.ts","../src/utils.ts"],"sourcesContent":["import {\n createIcon,\n createSvgIconNode,\n type IconDefinition,\n type SvgIconDefinition,\n type VobsIconProps\n} from '@vobs/icon-core'\nimport { hasProp, mountSlot, readProp } from './utils'\nimport type { VobsNode } from '@vobs/vobs'\nimport type { VuiCommonProps } from './types'\n\nexport type { IconDefinition } from '@vobs/icon-core'\n\nexport interface IconProps extends VuiCommonProps, VobsIconProps {\n readonly name?: string\n readonly icon?: IconDefinition\n}\n\nexport function Icon(props: IconProps = {}): VobsNode {\n const root = createSvgIconNode(() => {\n const definition = resolveIcon(\n readProp<IconDefinition | string | undefined>(props, 'icon', undefined)\n ?? readProp<string | undefined>(props, 'name', undefined)\n )\n if (!definition) {\n if (hasProp(props, 'children')) return undefined\n throw new Error('Vobs UI: Icon requires a registered `name` or an `icon` definition')\n }\n return iconDefinitionToSvg(definition)\n }, props, {\n class: 'vui-icon icon',\n defaultSvgAttributes: {\n fill: 'none',\n stroke: 'currentColor',\n 'stroke-width': 2,\n 'stroke-linecap': 'butt',\n 'stroke-linejoin': 'miter'\n }\n }) as Element\n\n if (hasProp(props, 'children')) mountSlot(root, props, 'children')\n return root\n}\n\nfunction iconDefinitionToSvg(definition: IconDefinition): SvgIconDefinition {\n return {\n name: definition.name,\n body: definition.path,\n viewBox: definition.viewBox\n }\n}\n\nconst VUI_ICON_PATHS = {\n search: '<circle cx=\"11\" cy=\"11\" r=\"7\"/><path d=\"m20 20-3.5-3.5\"/>',\n check: '<polyline points=\"4 12 10 18 20 6\"/>',\n x: '<line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>',\n plus: '<line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/>',\n minus: '<line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/>',\n 'chevron-right': '<polyline points=\"9 6 15 12 9 18\"/>',\n 'chevron-down': '<polyline points=\"6 9 12 15 18 9\"/>',\n 'chevron-up': '<polyline points=\"6 15 12 9 18 15\"/>',\n 'chevron-left': '<polyline points=\"15 6 9 12 15 18\"/>',\n 'arrow-left': '<line x1=\"20\" y1=\"12\" x2=\"4\" y2=\"12\"/><polyline points=\"10 6 4 12 10 18\"/>',\n 'arrow-right': '<line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\"/><polyline points=\"14 6 20 12 14 18\"/>',\n 'arrow-up': '<line x1=\"12\" y1=\"20\" x2=\"12\" y2=\"4\"/><polyline points=\"6 10 12 4 18 10\"/>',\n 'arrow-down': '<line x1=\"12\" y1=\"4\" x2=\"12\" y2=\"20\"/><polyline points=\"6 14 12 20 18 14\"/>',\n atom: '<circle cx=\"12\" cy=\"12\" r=\"2\"/><ellipse cx=\"12\" cy=\"12\" rx=\"10\" ry=\"4\"/><ellipse cx=\"12\" cy=\"12\" rx=\"10\" ry=\"4\" transform=\"rotate(60 12 12)\"/><ellipse cx=\"12\" cy=\"12\" rx=\"10\" ry=\"4\" transform=\"rotate(120 12 12)\"/>',\n globe: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18\"/>',\n 'arrow-expand': '<polyline points=\"14 4 20 4 20 10\"/><line x1=\"14\" y1=\"10\" x2=\"20\" y2=\"4\"/><polyline points=\"10 20 4 20 4 14\"/><line x1=\"10\" y1=\"14\" x2=\"4\" y2=\"20\"/>',\n 'arrow-minimize': '<polyline points=\"20 4 14 10 20 10\"/><line x1=\"14\" y1=\"10\" x2=\"14\" y2=\"4\"/><polyline points=\"4 20 10 14 4 14\"/><line x1=\"10\" y1=\"14\" x2=\"10\" y2=\"20\"/>',\n 'check-circle': '<circle cx=\"12\" cy=\"12\" r=\"9\"/><polyline points=\"8 12 11 15 16 9\"/>',\n 'alert-circle': '<circle cx=\"12\" cy=\"12\" r=\"9\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"16.01\"/>',\n 'alert-triangle': '<path d=\"M12 3 22 20 2 20 Z\"/><line x1=\"12\" y1=\"10\" x2=\"12\" y2=\"15\"/><line x1=\"12\" y1=\"18\" x2=\"12\" y2=\"18.01\"/>',\n info: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"16\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"8.01\"/>',\n home: '<polygon points=\"3 11 12 3 21 11 21 21 14 21 14 14 10 14 10 21 3 21 3 11\"/>',\n user: '<path d=\"M4 21v-1a6 6 0 0 1 6-6h4a6 6 0 0 1 6 6v1\"/><circle cx=\"12\" cy=\"8\" r=\"4\"/>',\n settings: '<circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z\"/>',\n menu: '<line x1=\"4\" y1=\"6\" x2=\"20\" y2=\"6\"/><line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\"/><line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\"/>',\n 'more-h': '<circle cx=\"5\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"/><circle cx=\"12\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"/><circle cx=\"19\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"/>',\n calendar: '<rect x=\"3\" y=\"5\" width=\"18\" height=\"16\"/><line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"/><line x1=\"8\" y1=\"3\" x2=\"8\" y2=\"7\"/><line x1=\"16\" y1=\"3\" x2=\"16\" y2=\"7\"/>',\n filter: '<polygon points=\"3 4 21 4 14 12 14 20 10 18 10 12 3 4\"/>',\n sort: '<path d=\"M8 20V4\"/><polyline points=\"4 8 8 4 12 8\"/><path d=\"M16 4v16\"/><polyline points=\"12 16 16 20 20 16\"/>',\n edit: '<path d=\"M4 20h4l10-10-4-4L4 16v4z\"/><path d=\"M14 6l4 4\"/>',\n trash: '<polyline points=\"4 6 20 6\"/><path d=\"M6 6v14h12V6\"/><path d=\"M9 6V4h6v2\"/><line x1=\"10\" y1=\"10\" x2=\"10\" y2=\"17\"/><line x1=\"14\" y1=\"10\" x2=\"14\" y2=\"17\"/>',\n download: '<path d=\"M12 3v12\"/><polyline points=\"7 10 12 15 17 10\"/><line x1=\"3\" y1=\"21\" x2=\"21\" y2=\"21\"/>',\n upload: '<path d=\"M12 21V6\"/><polyline points=\"7 11 12 6 17 11\"/><line x1=\"3\" y1=\"21\" x2=\"21\" y2=\"21\"/>',\n pause: '<line x1=\"9\" y1=\"5\" x2=\"9\" y2=\"19\"/><line x1=\"15\" y1=\"5\" x2=\"15\" y2=\"19\"/>',\n play: '<polygon points=\"8 5 19 12 8 19 8 5\"/>',\n refresh: '<polyline points=\"21 4 21 10 15 10\"/><polyline points=\"3 20 3 14 9 14\"/><path d=\"M20.5 9A9 9 0 0 0 5 5.5L3 7M3.5 15A9 9 0 0 0 19 18.5L21 17\"/>',\n bell: '<path d=\"M6 8a6 6 0 0 1 12 0c0 7 3 8 3 8H3s3-1 3-8z\"/><path d=\"M10 21a2 2 0 0 0 4 0\"/>',\n folder: '<path d=\"M3 6h6l2 3h10v10H3z\"/>',\n code: '<polyline points=\"16 18 22 12 16 6\"/><polyline points=\"8 6 2 12 8 18\"/>',\n sparkles: '<path d=\"M12 3l1.8 4.2L18 9l-4.2 1.8L12 15l-1.8-4.2L6 9l4.2-1.8L12 3z\"/><path d=\"M19 14l1 2.2 2.2 1-2.2 1L19 20.4l-1-2.2-2.2-1 2.2-1L19 14z\"/>',\n zap: '<polygon points=\"13 2 4 14 12 14 11 22 20 10 12 10 13 2\"/>',\n sun: '<circle cx=\"12\" cy=\"12\" r=\"4\"/><line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"5\"/><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"22\"/><line x1=\"2\" y1=\"12\" x2=\"5\" y2=\"12\"/><line x1=\"19\" y1=\"12\" x2=\"22\" y2=\"12\"/><line x1=\"4.6\" y1=\"4.6\" x2=\"6.7\" y2=\"6.7\"/><line x1=\"17.3\" y1=\"17.3\" x2=\"19.4\" y2=\"19.4\"/><line x1=\"4.6\" y1=\"19.4\" x2=\"6.7\" y2=\"17.3\"/><line x1=\"17.3\" y1=\"6.7\" x2=\"19.4\" y2=\"4.6\"/>',\n moon: '<path d=\"M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z\"/>',\n terminal: '<polyline points=\"4 7 9 12 4 17\"/><line x1=\"12\" y1=\"17\" x2=\"20\" y2=\"17\"/>'\n} as const\n\nconst iconRegistry = new Map<string, IconDefinition>(\n Object.entries(VUI_ICON_PATHS).map(([name, path]) => [name, { name, path }])\n)\n\nexport { VUI_ICON_PATHS }\nexport { createIcon, registerIcon, resolveIcon }\n\nfunction registerIcon(icon: IconDefinition): () => void {\n const previous = iconRegistry.get(icon.name)\n iconRegistry.set(icon.name, icon)\n return () => {\n if (previous) iconRegistry.set(icon.name, previous)\n else iconRegistry.delete(icon.name)\n }\n}\n\nfunction resolveIcon(icon: string | IconDefinition | undefined): IconDefinition | undefined {\n return typeof icon === 'string' ? iconRegistry.get(icon) : icon\n}\n","import { effect } from '@vobs/reactivity'\nimport {\n addEventListener,\n createFragment,\n createText,\n insertBefore,\n insertDynamic,\n setAttribute,\n setProperty,\n setTextContent,\n type VobsNode\n} from '@vobs/vobs'\nimport type { VuiCommonProps } from './types'\n\ntype VuiProps = VuiCommonProps | object\n\nexport function classNames(...values: readonly (string | false | null | undefined)[]): string {\n return values\n .flatMap(value => typeof value === 'string' ? value.trim().split(/\\s+/u) : [])\n .filter(Boolean)\n .join(' ')\n}\n\nexport function readProp<T>(props: object, name: string, fallback: T): T {\n const value = Reflect.get(props, name)\n return (value === undefined ? fallback : value) as T\n}\n\nexport function hasProp(props: object, name: string): boolean {\n return name in props\n}\n\nexport function bindClass(\n root: Element,\n props: VuiProps,\n ...baseClasses: readonly (string | undefined)[]\n): void {\n effect(() => {\n setAttribute(root, 'class', classNames(\n ...baseClasses,\n readString(props, 'class'),\n readString(props, 'className')\n ))\n })\n}\n\nexport function bindClassList(\n root: Element,\n props: VuiProps,\n readBaseClasses: () => readonly (string | undefined)[]\n): void {\n effect(() => {\n setAttribute(root, 'class', classNames(\n ...readBaseClasses(),\n readString(props, 'class'),\n readString(props, 'className')\n ))\n })\n}\n\nexport function bindCommonAttributes(\n root: Element,\n props: VuiProps,\n skip: readonly string[] = [],\n options: { readonly includeDataAria?: boolean } = {}\n): void {\n const ignored = new Set(skip)\n ignored.add('class')\n ignored.add('className')\n ignored.add('children')\n ignored.add('style')\n\n effect(() => {\n const next = new Map<string, string>()\n for (const name of Object.keys(props)) {\n if (ignored.has(name) || name.startsWith('on')) continue\n if (!isCommonAttribute(name)) continue\n if (options.includeDataAria === false && (name.startsWith('aria-') || name.startsWith('data-'))) continue\n\n const value = Reflect.get(props, name)\n const normalized = normalizeAttribute(name, value)\n if (normalized !== undefined) next.set(normalized.name, normalized.value)\n }\n\n const managed = getManagedAttributes(root)\n for (const name of managed) {\n if (!next.has(name)) removeAttribute(root, name)\n }\n for (const [name, value] of next) setAttribute(root, name, value)\n setManagedAttributes(root, next.keys())\n })\n}\n\nexport function bindUserStyle(root: Element, props: VuiProps): void {\n bindStyle(root, props, () => '')\n}\n\nexport function bindStyle(root: Element, props: VuiProps, createStyle: () => string): void {\n effect(() => {\n const userStyle = readString(props, 'style')\n const internalStyle = createStyle()\n const style = [internalStyle, userStyle].filter(Boolean).join('; ')\n if (style) setAttribute(root, 'style', style)\n else removeAttribute(root, 'style')\n })\n}\n\nexport function bindTextContent(\n node: Text,\n read: () => unknown\n): void {\n effect(() => {\n setTextContent(node, String(read() ?? ''))\n })\n}\n\nexport function bindPropertyValue(\n node: Element,\n name: string,\n read: () => unknown\n): void {\n effect(() => setProperty(node, name, read()))\n}\n\nexport function bindAttributeValue(\n node: Element,\n name: string,\n read: () => unknown\n): void {\n effect(() => {\n const value = read()\n if (value === undefined || value === null || value === false) removeAttribute(node, name)\n else setAttribute(node, name, String(value))\n })\n}\n\nexport function listen(\n root: Element,\n event: string,\n props: object,\n propName: string,\n disabled?: () => boolean\n): void {\n addEventListener(root, event, (reason: Event) => {\n if (disabled?.()) return\n const handler = Reflect.get(props, propName)\n if (typeof handler === 'function') handler(reason)\n })\n}\n\nexport function mountSlot(\n parent: Node,\n props: object,\n propName: string\n): void {\n insertDynamic(parent, null, () => resolveSlot(Reflect.get(props, propName)))\n}\n\nexport function resolveSlot(value: unknown): VobsNode | null {\n const resolved = typeof value === 'function' ? value() : value\n if (resolved === undefined || resolved === null || resolved === false) return null\n if (typeof resolved === 'string' || typeof resolved === 'number') return createText(String(resolved))\n if (Array.isArray(resolved)) {\n const children = resolved\n return createFragment((parent, anchor) => {\n for (const child of children) {\n const node = resolveSlot(child)\n if (node) insertBefore(parent, node, anchor)\n }\n })\n }\n return resolved as VobsNode\n}\n\nexport function setOptionalAttribute(node: Element, name: string, value: unknown): void {\n if (value === undefined || value === null || value === false || value === '') {\n removeAttribute(node, name)\n return\n }\n setAttribute(node, name, String(value))\n}\n\nexport function setOptionalProperty(node: Element, name: string, value: unknown): void {\n if (value === undefined || value === null) return\n setProperty(node, name, value)\n}\n\nfunction readString(props: object, name: string): string | undefined {\n const value = Reflect.get(props, name)\n return typeof value === 'string' ? value : undefined\n}\n\nfunction isCommonAttribute(name: string): boolean {\n return name === 'id'\n || name === 'title'\n || name === 'role'\n || name === 'tabIndex'\n || name.startsWith('aria-')\n || name.startsWith('data-')\n}\n\nfunction normalizeAttribute(name: string, value: unknown): { name: string; value: string } | undefined {\n if (value === undefined || value === null) return undefined\n if (value === false && !name.startsWith('aria-') && !name.startsWith('data-')) return undefined\n return { name: name === 'tabIndex' ? 'tabindex' : name, value: String(value) }\n}\n\nconst managedAttributes = new WeakMap<object, Set<string>>()\n\nfunction getManagedAttributes(node: Element): Set<string> {\n return managedAttributes.get(node) ?? new Set<string>()\n}\n\nfunction setManagedAttributes(node: Element, names: IterableIterator<string>): void {\n managedAttributes.set(node, new Set(names))\n}\n\nfunction removeAttribute(node: Element, name: string): void {\n const candidate = node as Element & { removeAttribute?: (attribute: string) => void }\n candidate.removeAttribute?.(name)\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/icon.ts","../src/utils.ts"],"sourcesContent":["import {\n createIcon,\n createSvgIconNode,\n type IconDefinition,\n type SvgIconDefinition,\n type VobsIconProps\n} from '@vobs/icon-core'\nimport { state } from '@vobs/vobs'\nimport { hasProp, mountSlot, readProp } from './utils'\nimport type { VobsNode } from '@vobs/vobs'\nimport type { VuiCommonProps } from './types'\n\nexport type { IconDefinition } from '@vobs/icon-core'\n\nexport interface IconProps extends VuiCommonProps, VobsIconProps {\n readonly name?: string\n readonly icon?: IconDefinition\n}\n\nexport function Icon(props: IconProps = {}): VobsNode {\n const root = createSvgIconNode(() => {\n // 读取注册表版本号:registerIcon 后已挂载的 Icon 自动补渲染,\n // 支持异步/按需注册(如 Iconify 集合、在线加载)。\n registryVersion.value\n const definition = resolveIcon(\n readProp<IconDefinition | string | undefined>(props, 'icon', undefined)\n ?? readProp<string | undefined>(props, 'name', undefined)\n )\n if (!definition) {\n if (hasProp(props, 'children')) return undefined\n const requested = readProp<IconDefinition | string | undefined>(props, 'icon', undefined)\n ?? readProp<string | undefined>(props, 'name', undefined)\n console.warn(`Vobs UI: 未注册的图标 \"${String(requested)}\",已渲染为空。请先 registerIcon 或改用已注册的名称。`)\n return undefined\n }\n return iconDefinitionToSvg(definition)\n }, props, {\n class: 'vui-icon icon',\n defaultSvgAttributes: {\n fill: 'none',\n stroke: 'currentColor',\n 'stroke-width': 2,\n 'stroke-linecap': 'butt',\n 'stroke-linejoin': 'miter'\n }\n }) as Element\n\n if (hasProp(props, 'children')) mountSlot(root, props, 'children')\n return root\n}\n\nfunction iconDefinitionToSvg(definition: IconDefinition): SvgIconDefinition {\n return {\n name: definition.name,\n body: definition.path,\n viewBox: definition.viewBox\n }\n}\n\nconst VUI_ICON_PATHS = {\n search: '<circle cx=\"11\" cy=\"11\" r=\"7\"/><path d=\"m20 20-3.5-3.5\"/>',\n check: '<polyline points=\"4 12 10 18 20 6\"/>',\n x: '<line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>',\n plus: '<line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/>',\n minus: '<line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/>',\n 'chevron-right': '<polyline points=\"9 6 15 12 9 18\"/>',\n 'chevron-down': '<polyline points=\"6 9 12 15 18 9\"/>',\n 'chevron-up': '<polyline points=\"6 15 12 9 18 15\"/>',\n 'chevron-left': '<polyline points=\"15 6 9 12 15 18\"/>',\n 'arrow-left': '<line x1=\"20\" y1=\"12\" x2=\"4\" y2=\"12\"/><polyline points=\"10 6 4 12 10 18\"/>',\n 'arrow-right': '<line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\"/><polyline points=\"14 6 20 12 14 18\"/>',\n 'arrow-up': '<line x1=\"12\" y1=\"20\" x2=\"12\" y2=\"4\"/><polyline points=\"6 10 12 4 18 10\"/>',\n 'arrow-down': '<line x1=\"12\" y1=\"4\" x2=\"12\" y2=\"20\"/><polyline points=\"6 14 12 20 18 14\"/>',\n atom: '<circle cx=\"12\" cy=\"12\" r=\"2\"/><ellipse cx=\"12\" cy=\"12\" rx=\"10\" ry=\"4\"/><ellipse cx=\"12\" cy=\"12\" rx=\"10\" ry=\"4\" transform=\"rotate(60 12 12)\"/><ellipse cx=\"12\" cy=\"12\" rx=\"10\" ry=\"4\" transform=\"rotate(120 12 12)\"/>',\n globe: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18\"/>',\n 'arrow-expand': '<polyline points=\"14 4 20 4 20 10\"/><line x1=\"14\" y1=\"10\" x2=\"20\" y2=\"4\"/><polyline points=\"10 20 4 20 4 14\"/><line x1=\"10\" y1=\"14\" x2=\"4\" y2=\"20\"/>',\n 'arrow-minimize': '<polyline points=\"20 4 14 10 20 10\"/><line x1=\"14\" y1=\"10\" x2=\"14\" y2=\"4\"/><polyline points=\"4 20 10 14 4 14\"/><line x1=\"10\" y1=\"14\" x2=\"10\" y2=\"20\"/>',\n 'check-circle': '<circle cx=\"12\" cy=\"12\" r=\"9\"/><polyline points=\"8 12 11 15 16 9\"/>',\n 'alert-circle': '<circle cx=\"12\" cy=\"12\" r=\"9\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"16.01\"/>',\n 'alert-triangle': '<path d=\"M12 3 22 20 2 20 Z\"/><line x1=\"12\" y1=\"10\" x2=\"12\" y2=\"15\"/><line x1=\"12\" y1=\"18\" x2=\"12\" y2=\"18.01\"/>',\n info: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"16\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"8.01\"/>',\n home: '<polygon points=\"3 11 12 3 21 11 21 21 14 21 14 14 10 14 10 21 3 21 3 11\"/>',\n user: '<path d=\"M4 21v-1a6 6 0 0 1 6-6h4a6 6 0 0 1 6 6v1\"/><circle cx=\"12\" cy=\"8\" r=\"4\"/>',\n settings: '<circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z\"/>',\n menu: '<line x1=\"4\" y1=\"6\" x2=\"20\" y2=\"6\"/><line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\"/><line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\"/>',\n 'more-h': '<circle cx=\"5\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"/><circle cx=\"12\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"/><circle cx=\"19\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"/>',\n calendar: '<rect x=\"3\" y=\"5\" width=\"18\" height=\"16\"/><line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"/><line x1=\"8\" y1=\"3\" x2=\"8\" y2=\"7\"/><line x1=\"16\" y1=\"3\" x2=\"16\" y2=\"7\"/>',\n filter: '<polygon points=\"3 4 21 4 14 12 14 20 10 18 10 12 3 4\"/>',\n sort: '<path d=\"M8 20V4\"/><polyline points=\"4 8 8 4 12 8\"/><path d=\"M16 4v16\"/><polyline points=\"12 16 16 20 20 16\"/>',\n edit: '<path d=\"M4 20h4l10-10-4-4L4 16v4z\"/><path d=\"M14 6l4 4\"/>',\n trash: '<polyline points=\"4 6 20 6\"/><path d=\"M6 6v14h12V6\"/><path d=\"M9 6V4h6v2\"/><line x1=\"10\" y1=\"10\" x2=\"10\" y2=\"17\"/><line x1=\"14\" y1=\"10\" x2=\"14\" y2=\"17\"/>',\n download: '<path d=\"M12 3v12\"/><polyline points=\"7 10 12 15 17 10\"/><line x1=\"3\" y1=\"21\" x2=\"21\" y2=\"21\"/>',\n upload: '<path d=\"M12 21V6\"/><polyline points=\"7 11 12 6 17 11\"/><line x1=\"3\" y1=\"21\" x2=\"21\" y2=\"21\"/>',\n pause: '<line x1=\"9\" y1=\"5\" x2=\"9\" y2=\"19\"/><line x1=\"15\" y1=\"5\" x2=\"15\" y2=\"19\"/>',\n play: '<polygon points=\"8 5 19 12 8 19 8 5\"/>',\n refresh: '<polyline points=\"21 4 21 10 15 10\"/><polyline points=\"3 20 3 14 9 14\"/><path d=\"M20.5 9A9 9 0 0 0 5 5.5L3 7M3.5 15A9 9 0 0 0 19 18.5L21 17\"/>',\n bell: '<path d=\"M6 8a6 6 0 0 1 12 0c0 7 3 8 3 8H3s3-1 3-8z\"/><path d=\"M10 21a2 2 0 0 0 4 0\"/>',\n folder: '<path d=\"M3 6h6l2 3h10v10H3z\"/>',\n code: '<polyline points=\"16 18 22 12 16 6\"/><polyline points=\"8 6 2 12 8 18\"/>',\n sparkles: '<path d=\"M12 3l1.8 4.2L18 9l-4.2 1.8L12 15l-1.8-4.2L6 9l4.2-1.8L12 3z\"/><path d=\"M19 14l1 2.2 2.2 1-2.2 1L19 20.4l-1-2.2-2.2-1 2.2-1L19 14z\"/>',\n zap: '<polygon points=\"13 2 4 14 12 14 11 22 20 10 12 10 13 2\"/>',\n sun: '<circle cx=\"12\" cy=\"12\" r=\"4\"/><line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"5\"/><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"22\"/><line x1=\"2\" y1=\"12\" x2=\"5\" y2=\"12\"/><line x1=\"19\" y1=\"12\" x2=\"22\" y2=\"12\"/><line x1=\"4.6\" y1=\"4.6\" x2=\"6.7\" y2=\"6.7\"/><line x1=\"17.3\" y1=\"17.3\" x2=\"19.4\" y2=\"19.4\"/><line x1=\"4.6\" y1=\"19.4\" x2=\"6.7\" y2=\"17.3\"/><line x1=\"17.3\" y1=\"6.7\" x2=\"19.4\" y2=\"4.6\"/>',\n moon: '<path d=\"M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z\"/>',\n terminal: '<polyline points=\"4 7 9 12 4 17\"/><line x1=\"12\" y1=\"17\" x2=\"20\" y2=\"17\"/>'\n} as const\n\nconst iconRegistry = new Map<string, IconDefinition>(\n Object.entries(VUI_ICON_PATHS).map(([name, path]) => [name, { name, path }])\n)\n\n/** 注册表版本号:registerIcon/注销时递增,驱动已挂载 Icon 的 effect 重取定义。 */\nconst registryVersion = state(0, 'vui.iconRegistry.version')\n\nexport { VUI_ICON_PATHS }\nexport { createIcon, registerIcon, resolveIcon }\n\nfunction registerIcon(icon: IconDefinition): () => void {\n const previous = iconRegistry.get(icon.name)\n iconRegistry.set(icon.name, icon)\n registryVersion.value++\n return () => {\n if (previous) iconRegistry.set(icon.name, previous)\n else iconRegistry.delete(icon.name)\n registryVersion.value++\n }\n}\n\nfunction resolveIcon(icon: string | IconDefinition | undefined): IconDefinition | undefined {\n return typeof icon === 'string' ? iconRegistry.get(icon) : icon\n}\n","import { effect } from '@vobs/reactivity'\nimport {\n addEventListener,\n createFragment,\n createText,\n insertBefore,\n insertDynamic,\n setAttribute,\n setProperty,\n setTextContent,\n type VobsNode\n} from '@vobs/vobs'\nimport type { VuiCommonProps } from './types'\n\ntype VuiProps = VuiCommonProps | object\n\nexport function classNames(...values: readonly (string | false | null | undefined)[]): string {\n return values\n .flatMap(value => typeof value === 'string' ? value.trim().split(/\\s+/u) : [])\n .filter(Boolean)\n .join(' ')\n}\n\nexport function readProp<T>(props: object, name: string, fallback: T): T {\n const value = Reflect.get(props, name)\n return (value === undefined ? fallback : value) as T\n}\n\nexport function hasProp(props: object, name: string): boolean {\n return name in props\n}\n\nexport function bindClass(\n root: Element,\n props: VuiProps,\n ...baseClasses: readonly (string | undefined)[]\n): void {\n effect(() => {\n setAttribute(root, 'class', classNames(\n ...baseClasses,\n readString(props, 'class'),\n readString(props, 'className')\n ))\n })\n}\n\nexport function bindClassList(\n root: Element,\n props: VuiProps,\n readBaseClasses: () => readonly (string | undefined)[]\n): void {\n effect(() => {\n setAttribute(root, 'class', classNames(\n ...readBaseClasses(),\n readString(props, 'class'),\n readString(props, 'className')\n ))\n })\n}\n\nexport function bindCommonAttributes(\n root: Element,\n props: VuiProps,\n skip: readonly string[] = [],\n options: { readonly includeDataAria?: boolean } = {}\n): void {\n const ignored = new Set(skip)\n ignored.add('class')\n ignored.add('className')\n ignored.add('children')\n ignored.add('style')\n\n effect(() => {\n const next = new Map<string, string>()\n for (const name of Object.keys(props)) {\n if (ignored.has(name) || name.startsWith('on')) continue\n if (!isCommonAttribute(name)) continue\n if (options.includeDataAria === false && (name.startsWith('aria-') || name.startsWith('data-'))) continue\n\n const value = Reflect.get(props, name)\n const normalized = normalizeAttribute(name, value)\n if (normalized !== undefined) next.set(normalized.name, normalized.value)\n }\n\n const managed = getManagedAttributes(root)\n for (const name of managed) {\n if (!next.has(name)) removeAttribute(root, name)\n }\n for (const [name, value] of next) setAttribute(root, name, value)\n setManagedAttributes(root, next.keys())\n })\n}\n\nexport function bindUserStyle(root: Element, props: VuiProps): void {\n bindStyle(root, props, () => '')\n}\n\nexport function bindStyle(root: Element, props: VuiProps, createStyle: () => string): void {\n effect(() => {\n const userStyle = readString(props, 'style')\n const internalStyle = createStyle()\n const style = [internalStyle, userStyle].filter(Boolean).join('; ')\n if (style) setAttribute(root, 'style', style)\n else removeAttribute(root, 'style')\n })\n}\n\nexport function bindTextContent(\n node: Text,\n read: () => unknown\n): void {\n effect(() => {\n setTextContent(node, String(read() ?? ''))\n })\n}\n\nexport function bindPropertyValue(\n node: Element,\n name: string,\n read: () => unknown\n): void {\n effect(() => setProperty(node, name, read()))\n}\n\nexport function bindAttributeValue(\n node: Element,\n name: string,\n read: () => unknown\n): void {\n effect(() => {\n const value = read()\n if (value === undefined || value === null || value === false) removeAttribute(node, name)\n else setAttribute(node, name, String(value))\n })\n}\n\nexport function listen(\n root: Element,\n event: string,\n props: object,\n propName: string,\n disabled?: () => boolean\n): void {\n addEventListener(root, event, (reason: Event) => {\n if (disabled?.()) return\n const handler = Reflect.get(props, propName)\n if (typeof handler === 'function') handler(reason)\n })\n}\n\nexport function mountSlot(\n parent: Node,\n props: object,\n propName: string\n): void {\n insertDynamic(parent, null, () => resolveSlot(Reflect.get(props, propName)))\n}\n\nexport function resolveSlot(value: unknown): VobsNode | null {\n const resolved = typeof value === 'function' ? value() : value\n if (resolved === undefined || resolved === null || resolved === false) return null\n if (typeof resolved === 'string' || typeof resolved === 'number') return createText(String(resolved))\n if (Array.isArray(resolved)) {\n const children = resolved\n return createFragment((parent, anchor) => {\n for (const child of children) {\n const node = resolveSlot(child)\n if (node) insertBefore(parent, node, anchor)\n }\n })\n }\n return resolved as VobsNode\n}\n\nexport function setOptionalAttribute(node: Element, name: string, value: unknown): void {\n if (value === undefined || value === null || value === false || value === '') {\n removeAttribute(node, name)\n return\n }\n setAttribute(node, name, String(value))\n}\n\nexport function setOptionalProperty(node: Element, name: string, value: unknown): void {\n if (value === undefined || value === null) return\n setProperty(node, name, value)\n}\n\nfunction readString(props: object, name: string): string | undefined {\n const value = Reflect.get(props, name)\n return typeof value === 'string' ? value : undefined\n}\n\nfunction isCommonAttribute(name: string): boolean {\n return name === 'id'\n || name === 'title'\n || name === 'role'\n || name === 'tabIndex'\n || name.startsWith('aria-')\n || name.startsWith('data-')\n}\n\nfunction normalizeAttribute(name: string, value: unknown): { name: string; value: string } | undefined {\n if (value === undefined || value === null) return undefined\n if (value === false && !name.startsWith('aria-') && !name.startsWith('data-')) return undefined\n return { name: name === 'tabIndex' ? 'tabindex' : name, value: String(value) }\n}\n\nconst managedAttributes = new WeakMap<object, Set<string>>()\n\nfunction getManagedAttributes(node: Element): Set<string> {\n return managedAttributes.get(node) ?? new Set<string>()\n}\n\nfunction setManagedAttributes(node: Element, names: IterableIterator<string>): void {\n managedAttributes.set(node, new Set(names))\n}\n\nfunction removeAttribute(node: Element, name: string): void {\n const candidate = node as Element & { removeAttribute?: (attribute: string) => void }\n candidate.removeAttribute?.(name)\n}\n"],"mappings":"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","names":["import_vobs"]}
|
package/dist/icon.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
createIcon,
|
|
7
7
|
createSvgIconNode
|
|
8
8
|
} from "@vobs/icon-core";
|
|
9
|
+
import { state } from "@vobs/vobs";
|
|
9
10
|
|
|
10
11
|
// packages/ui/src/utils.ts
|
|
11
12
|
import { effect } from "@vobs/reactivity";
|
|
@@ -52,12 +53,15 @@ __name(resolveSlot, "resolveSlot");
|
|
|
52
53
|
// packages/ui/src/icon.ts
|
|
53
54
|
function Icon(props = {}) {
|
|
54
55
|
const root = createSvgIconNode(() => {
|
|
56
|
+
registryVersion.value;
|
|
55
57
|
const definition = resolveIcon(
|
|
56
58
|
readProp(props, "icon", void 0) ?? readProp(props, "name", void 0)
|
|
57
59
|
);
|
|
58
60
|
if (!definition) {
|
|
59
61
|
if (hasProp(props, "children")) return void 0;
|
|
60
|
-
|
|
62
|
+
const requested = readProp(props, "icon", void 0) ?? readProp(props, "name", void 0);
|
|
63
|
+
console.warn(`Vobs UI: \u672A\u6CE8\u518C\u7684\u56FE\u6807 "${String(requested)}"\uFF0C\u5DF2\u6E32\u67D3\u4E3A\u7A7A\u3002\u8BF7\u5148 registerIcon \u6216\u6539\u7528\u5DF2\u6CE8\u518C\u7684\u540D\u79F0\u3002`);
|
|
64
|
+
return void 0;
|
|
61
65
|
}
|
|
62
66
|
return iconDefinitionToSvg(definition);
|
|
63
67
|
}, props, {
|
|
@@ -131,12 +135,15 @@ var VUI_ICON_PATHS = {
|
|
|
131
135
|
var iconRegistry = new Map(
|
|
132
136
|
Object.entries(VUI_ICON_PATHS).map(([name, path]) => [name, { name, path }])
|
|
133
137
|
);
|
|
138
|
+
var registryVersion = state(0, "vui.iconRegistry.version");
|
|
134
139
|
function registerIcon(icon) {
|
|
135
140
|
const previous = iconRegistry.get(icon.name);
|
|
136
141
|
iconRegistry.set(icon.name, icon);
|
|
142
|
+
registryVersion.value++;
|
|
137
143
|
return () => {
|
|
138
144
|
if (previous) iconRegistry.set(icon.name, previous);
|
|
139
145
|
else iconRegistry.delete(icon.name);
|
|
146
|
+
registryVersion.value++;
|
|
140
147
|
};
|
|
141
148
|
}
|
|
142
149
|
__name(registerIcon, "registerIcon");
|
package/dist/icon.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/icon.ts","../src/utils.ts"],"sourcesContent":["import {\n createIcon,\n createSvgIconNode,\n type IconDefinition,\n type SvgIconDefinition,\n type VobsIconProps\n} from '@vobs/icon-core'\nimport { hasProp, mountSlot, readProp } from './utils'\nimport type { VobsNode } from '@vobs/vobs'\nimport type { VuiCommonProps } from './types'\n\nexport type { IconDefinition } from '@vobs/icon-core'\n\nexport interface IconProps extends VuiCommonProps, VobsIconProps {\n readonly name?: string\n readonly icon?: IconDefinition\n}\n\nexport function Icon(props: IconProps = {}): VobsNode {\n const root = createSvgIconNode(() => {\n const definition = resolveIcon(\n readProp<IconDefinition | string | undefined>(props, 'icon', undefined)\n ?? readProp<string | undefined>(props, 'name', undefined)\n )\n if (!definition) {\n if (hasProp(props, 'children')) return undefined\n throw new Error('Vobs UI: Icon requires a registered `name` or an `icon` definition')\n }\n return iconDefinitionToSvg(definition)\n }, props, {\n class: 'vui-icon icon',\n defaultSvgAttributes: {\n fill: 'none',\n stroke: 'currentColor',\n 'stroke-width': 2,\n 'stroke-linecap': 'butt',\n 'stroke-linejoin': 'miter'\n }\n }) as Element\n\n if (hasProp(props, 'children')) mountSlot(root, props, 'children')\n return root\n}\n\nfunction iconDefinitionToSvg(definition: IconDefinition): SvgIconDefinition {\n return {\n name: definition.name,\n body: definition.path,\n viewBox: definition.viewBox\n }\n}\n\nconst VUI_ICON_PATHS = {\n search: '<circle cx=\"11\" cy=\"11\" r=\"7\"/><path d=\"m20 20-3.5-3.5\"/>',\n check: '<polyline points=\"4 12 10 18 20 6\"/>',\n x: '<line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>',\n plus: '<line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/>',\n minus: '<line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/>',\n 'chevron-right': '<polyline points=\"9 6 15 12 9 18\"/>',\n 'chevron-down': '<polyline points=\"6 9 12 15 18 9\"/>',\n 'chevron-up': '<polyline points=\"6 15 12 9 18 15\"/>',\n 'chevron-left': '<polyline points=\"15 6 9 12 15 18\"/>',\n 'arrow-left': '<line x1=\"20\" y1=\"12\" x2=\"4\" y2=\"12\"/><polyline points=\"10 6 4 12 10 18\"/>',\n 'arrow-right': '<line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\"/><polyline points=\"14 6 20 12 14 18\"/>',\n 'arrow-up': '<line x1=\"12\" y1=\"20\" x2=\"12\" y2=\"4\"/><polyline points=\"6 10 12 4 18 10\"/>',\n 'arrow-down': '<line x1=\"12\" y1=\"4\" x2=\"12\" y2=\"20\"/><polyline points=\"6 14 12 20 18 14\"/>',\n atom: '<circle cx=\"12\" cy=\"12\" r=\"2\"/><ellipse cx=\"12\" cy=\"12\" rx=\"10\" ry=\"4\"/><ellipse cx=\"12\" cy=\"12\" rx=\"10\" ry=\"4\" transform=\"rotate(60 12 12)\"/><ellipse cx=\"12\" cy=\"12\" rx=\"10\" ry=\"4\" transform=\"rotate(120 12 12)\"/>',\n globe: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18\"/>',\n 'arrow-expand': '<polyline points=\"14 4 20 4 20 10\"/><line x1=\"14\" y1=\"10\" x2=\"20\" y2=\"4\"/><polyline points=\"10 20 4 20 4 14\"/><line x1=\"10\" y1=\"14\" x2=\"4\" y2=\"20\"/>',\n 'arrow-minimize': '<polyline points=\"20 4 14 10 20 10\"/><line x1=\"14\" y1=\"10\" x2=\"14\" y2=\"4\"/><polyline points=\"4 20 10 14 4 14\"/><line x1=\"10\" y1=\"14\" x2=\"10\" y2=\"20\"/>',\n 'check-circle': '<circle cx=\"12\" cy=\"12\" r=\"9\"/><polyline points=\"8 12 11 15 16 9\"/>',\n 'alert-circle': '<circle cx=\"12\" cy=\"12\" r=\"9\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"16.01\"/>',\n 'alert-triangle': '<path d=\"M12 3 22 20 2 20 Z\"/><line x1=\"12\" y1=\"10\" x2=\"12\" y2=\"15\"/><line x1=\"12\" y1=\"18\" x2=\"12\" y2=\"18.01\"/>',\n info: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"16\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"8.01\"/>',\n home: '<polygon points=\"3 11 12 3 21 11 21 21 14 21 14 14 10 14 10 21 3 21 3 11\"/>',\n user: '<path d=\"M4 21v-1a6 6 0 0 1 6-6h4a6 6 0 0 1 6 6v1\"/><circle cx=\"12\" cy=\"8\" r=\"4\"/>',\n settings: '<circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z\"/>',\n menu: '<line x1=\"4\" y1=\"6\" x2=\"20\" y2=\"6\"/><line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\"/><line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\"/>',\n 'more-h': '<circle cx=\"5\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"/><circle cx=\"12\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"/><circle cx=\"19\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"/>',\n calendar: '<rect x=\"3\" y=\"5\" width=\"18\" height=\"16\"/><line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"/><line x1=\"8\" y1=\"3\" x2=\"8\" y2=\"7\"/><line x1=\"16\" y1=\"3\" x2=\"16\" y2=\"7\"/>',\n filter: '<polygon points=\"3 4 21 4 14 12 14 20 10 18 10 12 3 4\"/>',\n sort: '<path d=\"M8 20V4\"/><polyline points=\"4 8 8 4 12 8\"/><path d=\"M16 4v16\"/><polyline points=\"12 16 16 20 20 16\"/>',\n edit: '<path d=\"M4 20h4l10-10-4-4L4 16v4z\"/><path d=\"M14 6l4 4\"/>',\n trash: '<polyline points=\"4 6 20 6\"/><path d=\"M6 6v14h12V6\"/><path d=\"M9 6V4h6v2\"/><line x1=\"10\" y1=\"10\" x2=\"10\" y2=\"17\"/><line x1=\"14\" y1=\"10\" x2=\"14\" y2=\"17\"/>',\n download: '<path d=\"M12 3v12\"/><polyline points=\"7 10 12 15 17 10\"/><line x1=\"3\" y1=\"21\" x2=\"21\" y2=\"21\"/>',\n upload: '<path d=\"M12 21V6\"/><polyline points=\"7 11 12 6 17 11\"/><line x1=\"3\" y1=\"21\" x2=\"21\" y2=\"21\"/>',\n pause: '<line x1=\"9\" y1=\"5\" x2=\"9\" y2=\"19\"/><line x1=\"15\" y1=\"5\" x2=\"15\" y2=\"19\"/>',\n play: '<polygon points=\"8 5 19 12 8 19 8 5\"/>',\n refresh: '<polyline points=\"21 4 21 10 15 10\"/><polyline points=\"3 20 3 14 9 14\"/><path d=\"M20.5 9A9 9 0 0 0 5 5.5L3 7M3.5 15A9 9 0 0 0 19 18.5L21 17\"/>',\n bell: '<path d=\"M6 8a6 6 0 0 1 12 0c0 7 3 8 3 8H3s3-1 3-8z\"/><path d=\"M10 21a2 2 0 0 0 4 0\"/>',\n folder: '<path d=\"M3 6h6l2 3h10v10H3z\"/>',\n code: '<polyline points=\"16 18 22 12 16 6\"/><polyline points=\"8 6 2 12 8 18\"/>',\n sparkles: '<path d=\"M12 3l1.8 4.2L18 9l-4.2 1.8L12 15l-1.8-4.2L6 9l4.2-1.8L12 3z\"/><path d=\"M19 14l1 2.2 2.2 1-2.2 1L19 20.4l-1-2.2-2.2-1 2.2-1L19 14z\"/>',\n zap: '<polygon points=\"13 2 4 14 12 14 11 22 20 10 12 10 13 2\"/>',\n sun: '<circle cx=\"12\" cy=\"12\" r=\"4\"/><line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"5\"/><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"22\"/><line x1=\"2\" y1=\"12\" x2=\"5\" y2=\"12\"/><line x1=\"19\" y1=\"12\" x2=\"22\" y2=\"12\"/><line x1=\"4.6\" y1=\"4.6\" x2=\"6.7\" y2=\"6.7\"/><line x1=\"17.3\" y1=\"17.3\" x2=\"19.4\" y2=\"19.4\"/><line x1=\"4.6\" y1=\"19.4\" x2=\"6.7\" y2=\"17.3\"/><line x1=\"17.3\" y1=\"6.7\" x2=\"19.4\" y2=\"4.6\"/>',\n moon: '<path d=\"M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z\"/>',\n terminal: '<polyline points=\"4 7 9 12 4 17\"/><line x1=\"12\" y1=\"17\" x2=\"20\" y2=\"17\"/>'\n} as const\n\nconst iconRegistry = new Map<string, IconDefinition>(\n Object.entries(VUI_ICON_PATHS).map(([name, path]) => [name, { name, path }])\n)\n\nexport { VUI_ICON_PATHS }\nexport { createIcon, registerIcon, resolveIcon }\n\nfunction registerIcon(icon: IconDefinition): () => void {\n const previous = iconRegistry.get(icon.name)\n iconRegistry.set(icon.name, icon)\n return () => {\n if (previous) iconRegistry.set(icon.name, previous)\n else iconRegistry.delete(icon.name)\n }\n}\n\nfunction resolveIcon(icon: string | IconDefinition | undefined): IconDefinition | undefined {\n return typeof icon === 'string' ? iconRegistry.get(icon) : icon\n}\n","import { effect } from '@vobs/reactivity'\nimport {\n addEventListener,\n createFragment,\n createText,\n insertBefore,\n insertDynamic,\n setAttribute,\n setProperty,\n setTextContent,\n type VobsNode\n} from '@vobs/vobs'\nimport type { VuiCommonProps } from './types'\n\ntype VuiProps = VuiCommonProps | object\n\nexport function classNames(...values: readonly (string | false | null | undefined)[]): string {\n return values\n .flatMap(value => typeof value === 'string' ? value.trim().split(/\\s+/u) : [])\n .filter(Boolean)\n .join(' ')\n}\n\nexport function readProp<T>(props: object, name: string, fallback: T): T {\n const value = Reflect.get(props, name)\n return (value === undefined ? fallback : value) as T\n}\n\nexport function hasProp(props: object, name: string): boolean {\n return name in props\n}\n\nexport function bindClass(\n root: Element,\n props: VuiProps,\n ...baseClasses: readonly (string | undefined)[]\n): void {\n effect(() => {\n setAttribute(root, 'class', classNames(\n ...baseClasses,\n readString(props, 'class'),\n readString(props, 'className')\n ))\n })\n}\n\nexport function bindClassList(\n root: Element,\n props: VuiProps,\n readBaseClasses: () => readonly (string | undefined)[]\n): void {\n effect(() => {\n setAttribute(root, 'class', classNames(\n ...readBaseClasses(),\n readString(props, 'class'),\n readString(props, 'className')\n ))\n })\n}\n\nexport function bindCommonAttributes(\n root: Element,\n props: VuiProps,\n skip: readonly string[] = [],\n options: { readonly includeDataAria?: boolean } = {}\n): void {\n const ignored = new Set(skip)\n ignored.add('class')\n ignored.add('className')\n ignored.add('children')\n ignored.add('style')\n\n effect(() => {\n const next = new Map<string, string>()\n for (const name of Object.keys(props)) {\n if (ignored.has(name) || name.startsWith('on')) continue\n if (!isCommonAttribute(name)) continue\n if (options.includeDataAria === false && (name.startsWith('aria-') || name.startsWith('data-'))) continue\n\n const value = Reflect.get(props, name)\n const normalized = normalizeAttribute(name, value)\n if (normalized !== undefined) next.set(normalized.name, normalized.value)\n }\n\n const managed = getManagedAttributes(root)\n for (const name of managed) {\n if (!next.has(name)) removeAttribute(root, name)\n }\n for (const [name, value] of next) setAttribute(root, name, value)\n setManagedAttributes(root, next.keys())\n })\n}\n\nexport function bindUserStyle(root: Element, props: VuiProps): void {\n bindStyle(root, props, () => '')\n}\n\nexport function bindStyle(root: Element, props: VuiProps, createStyle: () => string): void {\n effect(() => {\n const userStyle = readString(props, 'style')\n const internalStyle = createStyle()\n const style = [internalStyle, userStyle].filter(Boolean).join('; ')\n if (style) setAttribute(root, 'style', style)\n else removeAttribute(root, 'style')\n })\n}\n\nexport function bindTextContent(\n node: Text,\n read: () => unknown\n): void {\n effect(() => {\n setTextContent(node, String(read() ?? ''))\n })\n}\n\nexport function bindPropertyValue(\n node: Element,\n name: string,\n read: () => unknown\n): void {\n effect(() => setProperty(node, name, read()))\n}\n\nexport function bindAttributeValue(\n node: Element,\n name: string,\n read: () => unknown\n): void {\n effect(() => {\n const value = read()\n if (value === undefined || value === null || value === false) removeAttribute(node, name)\n else setAttribute(node, name, String(value))\n })\n}\n\nexport function listen(\n root: Element,\n event: string,\n props: object,\n propName: string,\n disabled?: () => boolean\n): void {\n addEventListener(root, event, (reason: Event) => {\n if (disabled?.()) return\n const handler = Reflect.get(props, propName)\n if (typeof handler === 'function') handler(reason)\n })\n}\n\nexport function mountSlot(\n parent: Node,\n props: object,\n propName: string\n): void {\n insertDynamic(parent, null, () => resolveSlot(Reflect.get(props, propName)))\n}\n\nexport function resolveSlot(value: unknown): VobsNode | null {\n const resolved = typeof value === 'function' ? value() : value\n if (resolved === undefined || resolved === null || resolved === false) return null\n if (typeof resolved === 'string' || typeof resolved === 'number') return createText(String(resolved))\n if (Array.isArray(resolved)) {\n const children = resolved\n return createFragment((parent, anchor) => {\n for (const child of children) {\n const node = resolveSlot(child)\n if (node) insertBefore(parent, node, anchor)\n }\n })\n }\n return resolved as VobsNode\n}\n\nexport function setOptionalAttribute(node: Element, name: string, value: unknown): void {\n if (value === undefined || value === null || value === false || value === '') {\n removeAttribute(node, name)\n return\n }\n setAttribute(node, name, String(value))\n}\n\nexport function setOptionalProperty(node: Element, name: string, value: unknown): void {\n if (value === undefined || value === null) return\n setProperty(node, name, value)\n}\n\nfunction readString(props: object, name: string): string | undefined {\n const value = Reflect.get(props, name)\n return typeof value === 'string' ? value : undefined\n}\n\nfunction isCommonAttribute(name: string): boolean {\n return name === 'id'\n || name === 'title'\n || name === 'role'\n || name === 'tabIndex'\n || name.startsWith('aria-')\n || name.startsWith('data-')\n}\n\nfunction normalizeAttribute(name: string, value: unknown): { name: string; value: string } | undefined {\n if (value === undefined || value === null) return undefined\n if (value === false && !name.startsWith('aria-') && !name.startsWith('data-')) return undefined\n return { name: name === 'tabIndex' ? 'tabindex' : name, value: String(value) }\n}\n\nconst managedAttributes = new WeakMap<object, Set<string>>()\n\nfunction getManagedAttributes(node: Element): Set<string> {\n return managedAttributes.get(node) ?? new Set<string>()\n}\n\nfunction setManagedAttributes(node: Element, names: IterableIterator<string>): void {\n managedAttributes.set(node, new Set(names))\n}\n\nfunction removeAttribute(node: Element, name: string): void {\n const candidate = node as Element & { removeAttribute?: (attribute: string) => void }\n candidate.removeAttribute?.(name)\n}\n"],"mappings":";;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,OAIK;;;ACNP,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAYA,SAAS,SAAY,OAAe,MAAc,UAAgB;AACvE,QAAM,QAAQ,QAAQ,IAAI,OAAO,IAAI;AACrC,SAAQ,UAAU,SAAY,WAAW;AAC3C;AAHgB;AAKT,SAAS,QAAQ,OAAe,MAAuB;AAC5D,SAAO,QAAQ;AACjB;AAFgB;AA0HT,SAAS,UACd,QACA,OACA,UACM;AACN,gBAAc,QAAQ,MAAM,MAAM,YAAY,QAAQ,IAAI,OAAO,QAAQ,CAAC,CAAC;AAC7E;AANgB;AAQT,SAAS,YAAY,OAAiC;AAC3D,QAAM,WAAW,OAAO,UAAU,aAAa,MAAM,IAAI;AACzD,MAAI,aAAa,UAAa,aAAa,QAAQ,aAAa,MAAO,QAAO;AAC9E,MAAI,OAAO,aAAa,YAAY,OAAO,aAAa,SAAU,QAAO,WAAW,OAAO,QAAQ,CAAC;AACpG,MAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,UAAM,WAAW;AACjB,WAAO,eAAe,CAAC,QAAQ,WAAW;AACxC,iBAAW,SAAS,UAAU;AAC5B,cAAM,OAAO,YAAY,KAAK;AAC9B,YAAI,KAAM,cAAa,QAAQ,MAAM,MAAM;AAAA,MAC7C;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAdgB;;;AD5IT,SAAS,KAAK,QAAmB,CAAC,GAAa;AACpD,QAAM,OAAO,kBAAkB,MAAM;AACnC,UAAM,aAAa;AAAA,MACjB,SAA8C,OAAO,QAAQ,MAAS,KACjE,SAA6B,OAAO,QAAQ,MAAS;AAAA,IAC5D;AACA,QAAI,CAAC,YAAY;AACf,UAAI,QAAQ,OAAO,UAAU,EAAG,QAAO;AACvC,YAAM,IAAI,MAAM,oEAAoE;AAAA,IACtF;AACA,WAAO,oBAAoB,UAAU;AAAA,EACvC,GAAG,OAAO;AAAA,IACR,OAAO;AAAA,IACP,sBAAsB;AAAA,MACpB,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,gBAAgB;AAAA,MAChB,kBAAkB;AAAA,MAClB,mBAAmB;AAAA,IACrB;AAAA,EACF,CAAC;AAED,MAAI,QAAQ,OAAO,UAAU,EAAG,WAAU,MAAM,OAAO,UAAU;AACjE,SAAO;AACT;AAxBgB;AA0BhB,SAAS,oBAAoB,YAA+C;AAC1E,SAAO;AAAA,IACL,MAAM,WAAW;AAAA,IACjB,MAAM,WAAW;AAAA,IACjB,SAAS,WAAW;AAAA,EACtB;AACF;AANS;AAQT,IAAM,iBAAiB;AAAA,EACrB,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,GAAG;AAAA,EACH,MAAM;AAAA,EACN,OAAO;AAAA,EACP,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,MAAM;AAAA,EACN,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU;AAAA,EACV,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,UAAU;AAAA,EACV,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,UAAU;AACZ;AAEA,IAAM,eAAe,IAAI;AAAA,EACvB,OAAO,QAAQ,cAAc,EAAE,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,KAAK,CAAC,CAAC;AAC7E;AAKA,SAAS,aAAa,MAAkC;AACtD,QAAM,WAAW,aAAa,IAAI,KAAK,IAAI;AAC3C,eAAa,IAAI,KAAK,MAAM,IAAI;AAChC,SAAO,MAAM;AACX,QAAI,SAAU,cAAa,IAAI,KAAK,MAAM,QAAQ;AAAA,QAC7C,cAAa,OAAO,KAAK,IAAI;AAAA,EACpC;AACF;AAPS;AAST,SAAS,YAAY,MAAuE;AAC1F,SAAO,OAAO,SAAS,WAAW,aAAa,IAAI,IAAI,IAAI;AAC7D;AAFS;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/icon.ts","../src/utils.ts"],"sourcesContent":["import {\n createIcon,\n createSvgIconNode,\n type IconDefinition,\n type SvgIconDefinition,\n type VobsIconProps\n} from '@vobs/icon-core'\nimport { state } from '@vobs/vobs'\nimport { hasProp, mountSlot, readProp } from './utils'\nimport type { VobsNode } from '@vobs/vobs'\nimport type { VuiCommonProps } from './types'\n\nexport type { IconDefinition } from '@vobs/icon-core'\n\nexport interface IconProps extends VuiCommonProps, VobsIconProps {\n readonly name?: string\n readonly icon?: IconDefinition\n}\n\nexport function Icon(props: IconProps = {}): VobsNode {\n const root = createSvgIconNode(() => {\n // 读取注册表版本号:registerIcon 后已挂载的 Icon 自动补渲染,\n // 支持异步/按需注册(如 Iconify 集合、在线加载)。\n registryVersion.value\n const definition = resolveIcon(\n readProp<IconDefinition | string | undefined>(props, 'icon', undefined)\n ?? readProp<string | undefined>(props, 'name', undefined)\n )\n if (!definition) {\n if (hasProp(props, 'children')) return undefined\n const requested = readProp<IconDefinition | string | undefined>(props, 'icon', undefined)\n ?? readProp<string | undefined>(props, 'name', undefined)\n console.warn(`Vobs UI: 未注册的图标 \"${String(requested)}\",已渲染为空。请先 registerIcon 或改用已注册的名称。`)\n return undefined\n }\n return iconDefinitionToSvg(definition)\n }, props, {\n class: 'vui-icon icon',\n defaultSvgAttributes: {\n fill: 'none',\n stroke: 'currentColor',\n 'stroke-width': 2,\n 'stroke-linecap': 'butt',\n 'stroke-linejoin': 'miter'\n }\n }) as Element\n\n if (hasProp(props, 'children')) mountSlot(root, props, 'children')\n return root\n}\n\nfunction iconDefinitionToSvg(definition: IconDefinition): SvgIconDefinition {\n return {\n name: definition.name,\n body: definition.path,\n viewBox: definition.viewBox\n }\n}\n\nconst VUI_ICON_PATHS = {\n search: '<circle cx=\"11\" cy=\"11\" r=\"7\"/><path d=\"m20 20-3.5-3.5\"/>',\n check: '<polyline points=\"4 12 10 18 20 6\"/>',\n x: '<line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>',\n plus: '<line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/>',\n minus: '<line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/>',\n 'chevron-right': '<polyline points=\"9 6 15 12 9 18\"/>',\n 'chevron-down': '<polyline points=\"6 9 12 15 18 9\"/>',\n 'chevron-up': '<polyline points=\"6 15 12 9 18 15\"/>',\n 'chevron-left': '<polyline points=\"15 6 9 12 15 18\"/>',\n 'arrow-left': '<line x1=\"20\" y1=\"12\" x2=\"4\" y2=\"12\"/><polyline points=\"10 6 4 12 10 18\"/>',\n 'arrow-right': '<line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\"/><polyline points=\"14 6 20 12 14 18\"/>',\n 'arrow-up': '<line x1=\"12\" y1=\"20\" x2=\"12\" y2=\"4\"/><polyline points=\"6 10 12 4 18 10\"/>',\n 'arrow-down': '<line x1=\"12\" y1=\"4\" x2=\"12\" y2=\"20\"/><polyline points=\"6 14 12 20 18 14\"/>',\n atom: '<circle cx=\"12\" cy=\"12\" r=\"2\"/><ellipse cx=\"12\" cy=\"12\" rx=\"10\" ry=\"4\"/><ellipse cx=\"12\" cy=\"12\" rx=\"10\" ry=\"4\" transform=\"rotate(60 12 12)\"/><ellipse cx=\"12\" cy=\"12\" rx=\"10\" ry=\"4\" transform=\"rotate(120 12 12)\"/>',\n globe: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18\"/>',\n 'arrow-expand': '<polyline points=\"14 4 20 4 20 10\"/><line x1=\"14\" y1=\"10\" x2=\"20\" y2=\"4\"/><polyline points=\"10 20 4 20 4 14\"/><line x1=\"10\" y1=\"14\" x2=\"4\" y2=\"20\"/>',\n 'arrow-minimize': '<polyline points=\"20 4 14 10 20 10\"/><line x1=\"14\" y1=\"10\" x2=\"14\" y2=\"4\"/><polyline points=\"4 20 10 14 4 14\"/><line x1=\"10\" y1=\"14\" x2=\"10\" y2=\"20\"/>',\n 'check-circle': '<circle cx=\"12\" cy=\"12\" r=\"9\"/><polyline points=\"8 12 11 15 16 9\"/>',\n 'alert-circle': '<circle cx=\"12\" cy=\"12\" r=\"9\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"16.01\"/>',\n 'alert-triangle': '<path d=\"M12 3 22 20 2 20 Z\"/><line x1=\"12\" y1=\"10\" x2=\"12\" y2=\"15\"/><line x1=\"12\" y1=\"18\" x2=\"12\" y2=\"18.01\"/>',\n info: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"16\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"8.01\"/>',\n home: '<polygon points=\"3 11 12 3 21 11 21 21 14 21 14 14 10 14 10 21 3 21 3 11\"/>',\n user: '<path d=\"M4 21v-1a6 6 0 0 1 6-6h4a6 6 0 0 1 6 6v1\"/><circle cx=\"12\" cy=\"8\" r=\"4\"/>',\n settings: '<circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z\"/>',\n menu: '<line x1=\"4\" y1=\"6\" x2=\"20\" y2=\"6\"/><line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\"/><line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\"/>',\n 'more-h': '<circle cx=\"5\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"/><circle cx=\"12\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"/><circle cx=\"19\" cy=\"12\" r=\"1.5\" fill=\"currentColor\"/>',\n calendar: '<rect x=\"3\" y=\"5\" width=\"18\" height=\"16\"/><line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"/><line x1=\"8\" y1=\"3\" x2=\"8\" y2=\"7\"/><line x1=\"16\" y1=\"3\" x2=\"16\" y2=\"7\"/>',\n filter: '<polygon points=\"3 4 21 4 14 12 14 20 10 18 10 12 3 4\"/>',\n sort: '<path d=\"M8 20V4\"/><polyline points=\"4 8 8 4 12 8\"/><path d=\"M16 4v16\"/><polyline points=\"12 16 16 20 20 16\"/>',\n edit: '<path d=\"M4 20h4l10-10-4-4L4 16v4z\"/><path d=\"M14 6l4 4\"/>',\n trash: '<polyline points=\"4 6 20 6\"/><path d=\"M6 6v14h12V6\"/><path d=\"M9 6V4h6v2\"/><line x1=\"10\" y1=\"10\" x2=\"10\" y2=\"17\"/><line x1=\"14\" y1=\"10\" x2=\"14\" y2=\"17\"/>',\n download: '<path d=\"M12 3v12\"/><polyline points=\"7 10 12 15 17 10\"/><line x1=\"3\" y1=\"21\" x2=\"21\" y2=\"21\"/>',\n upload: '<path d=\"M12 21V6\"/><polyline points=\"7 11 12 6 17 11\"/><line x1=\"3\" y1=\"21\" x2=\"21\" y2=\"21\"/>',\n pause: '<line x1=\"9\" y1=\"5\" x2=\"9\" y2=\"19\"/><line x1=\"15\" y1=\"5\" x2=\"15\" y2=\"19\"/>',\n play: '<polygon points=\"8 5 19 12 8 19 8 5\"/>',\n refresh: '<polyline points=\"21 4 21 10 15 10\"/><polyline points=\"3 20 3 14 9 14\"/><path d=\"M20.5 9A9 9 0 0 0 5 5.5L3 7M3.5 15A9 9 0 0 0 19 18.5L21 17\"/>',\n bell: '<path d=\"M6 8a6 6 0 0 1 12 0c0 7 3 8 3 8H3s3-1 3-8z\"/><path d=\"M10 21a2 2 0 0 0 4 0\"/>',\n folder: '<path d=\"M3 6h6l2 3h10v10H3z\"/>',\n code: '<polyline points=\"16 18 22 12 16 6\"/><polyline points=\"8 6 2 12 8 18\"/>',\n sparkles: '<path d=\"M12 3l1.8 4.2L18 9l-4.2 1.8L12 15l-1.8-4.2L6 9l4.2-1.8L12 3z\"/><path d=\"M19 14l1 2.2 2.2 1-2.2 1L19 20.4l-1-2.2-2.2-1 2.2-1L19 14z\"/>',\n zap: '<polygon points=\"13 2 4 14 12 14 11 22 20 10 12 10 13 2\"/>',\n sun: '<circle cx=\"12\" cy=\"12\" r=\"4\"/><line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"5\"/><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"22\"/><line x1=\"2\" y1=\"12\" x2=\"5\" y2=\"12\"/><line x1=\"19\" y1=\"12\" x2=\"22\" y2=\"12\"/><line x1=\"4.6\" y1=\"4.6\" x2=\"6.7\" y2=\"6.7\"/><line x1=\"17.3\" y1=\"17.3\" x2=\"19.4\" y2=\"19.4\"/><line x1=\"4.6\" y1=\"19.4\" x2=\"6.7\" y2=\"17.3\"/><line x1=\"17.3\" y1=\"6.7\" x2=\"19.4\" y2=\"4.6\"/>',\n moon: '<path d=\"M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z\"/>',\n terminal: '<polyline points=\"4 7 9 12 4 17\"/><line x1=\"12\" y1=\"17\" x2=\"20\" y2=\"17\"/>'\n} as const\n\nconst iconRegistry = new Map<string, IconDefinition>(\n Object.entries(VUI_ICON_PATHS).map(([name, path]) => [name, { name, path }])\n)\n\n/** 注册表版本号:registerIcon/注销时递增,驱动已挂载 Icon 的 effect 重取定义。 */\nconst registryVersion = state(0, 'vui.iconRegistry.version')\n\nexport { VUI_ICON_PATHS }\nexport { createIcon, registerIcon, resolveIcon }\n\nfunction registerIcon(icon: IconDefinition): () => void {\n const previous = iconRegistry.get(icon.name)\n iconRegistry.set(icon.name, icon)\n registryVersion.value++\n return () => {\n if (previous) iconRegistry.set(icon.name, previous)\n else iconRegistry.delete(icon.name)\n registryVersion.value++\n }\n}\n\nfunction resolveIcon(icon: string | IconDefinition | undefined): IconDefinition | undefined {\n return typeof icon === 'string' ? iconRegistry.get(icon) : icon\n}\n","import { effect } from '@vobs/reactivity'\nimport {\n addEventListener,\n createFragment,\n createText,\n insertBefore,\n insertDynamic,\n setAttribute,\n setProperty,\n setTextContent,\n type VobsNode\n} from '@vobs/vobs'\nimport type { VuiCommonProps } from './types'\n\ntype VuiProps = VuiCommonProps | object\n\nexport function classNames(...values: readonly (string | false | null | undefined)[]): string {\n return values\n .flatMap(value => typeof value === 'string' ? value.trim().split(/\\s+/u) : [])\n .filter(Boolean)\n .join(' ')\n}\n\nexport function readProp<T>(props: object, name: string, fallback: T): T {\n const value = Reflect.get(props, name)\n return (value === undefined ? fallback : value) as T\n}\n\nexport function hasProp(props: object, name: string): boolean {\n return name in props\n}\n\nexport function bindClass(\n root: Element,\n props: VuiProps,\n ...baseClasses: readonly (string | undefined)[]\n): void {\n effect(() => {\n setAttribute(root, 'class', classNames(\n ...baseClasses,\n readString(props, 'class'),\n readString(props, 'className')\n ))\n })\n}\n\nexport function bindClassList(\n root: Element,\n props: VuiProps,\n readBaseClasses: () => readonly (string | undefined)[]\n): void {\n effect(() => {\n setAttribute(root, 'class', classNames(\n ...readBaseClasses(),\n readString(props, 'class'),\n readString(props, 'className')\n ))\n })\n}\n\nexport function bindCommonAttributes(\n root: Element,\n props: VuiProps,\n skip: readonly string[] = [],\n options: { readonly includeDataAria?: boolean } = {}\n): void {\n const ignored = new Set(skip)\n ignored.add('class')\n ignored.add('className')\n ignored.add('children')\n ignored.add('style')\n\n effect(() => {\n const next = new Map<string, string>()\n for (const name of Object.keys(props)) {\n if (ignored.has(name) || name.startsWith('on')) continue\n if (!isCommonAttribute(name)) continue\n if (options.includeDataAria === false && (name.startsWith('aria-') || name.startsWith('data-'))) continue\n\n const value = Reflect.get(props, name)\n const normalized = normalizeAttribute(name, value)\n if (normalized !== undefined) next.set(normalized.name, normalized.value)\n }\n\n const managed = getManagedAttributes(root)\n for (const name of managed) {\n if (!next.has(name)) removeAttribute(root, name)\n }\n for (const [name, value] of next) setAttribute(root, name, value)\n setManagedAttributes(root, next.keys())\n })\n}\n\nexport function bindUserStyle(root: Element, props: VuiProps): void {\n bindStyle(root, props, () => '')\n}\n\nexport function bindStyle(root: Element, props: VuiProps, createStyle: () => string): void {\n effect(() => {\n const userStyle = readString(props, 'style')\n const internalStyle = createStyle()\n const style = [internalStyle, userStyle].filter(Boolean).join('; ')\n if (style) setAttribute(root, 'style', style)\n else removeAttribute(root, 'style')\n })\n}\n\nexport function bindTextContent(\n node: Text,\n read: () => unknown\n): void {\n effect(() => {\n setTextContent(node, String(read() ?? ''))\n })\n}\n\nexport function bindPropertyValue(\n node: Element,\n name: string,\n read: () => unknown\n): void {\n effect(() => setProperty(node, name, read()))\n}\n\nexport function bindAttributeValue(\n node: Element,\n name: string,\n read: () => unknown\n): void {\n effect(() => {\n const value = read()\n if (value === undefined || value === null || value === false) removeAttribute(node, name)\n else setAttribute(node, name, String(value))\n })\n}\n\nexport function listen(\n root: Element,\n event: string,\n props: object,\n propName: string,\n disabled?: () => boolean\n): void {\n addEventListener(root, event, (reason: Event) => {\n if (disabled?.()) return\n const handler = Reflect.get(props, propName)\n if (typeof handler === 'function') handler(reason)\n })\n}\n\nexport function mountSlot(\n parent: Node,\n props: object,\n propName: string\n): void {\n insertDynamic(parent, null, () => resolveSlot(Reflect.get(props, propName)))\n}\n\nexport function resolveSlot(value: unknown): VobsNode | null {\n const resolved = typeof value === 'function' ? value() : value\n if (resolved === undefined || resolved === null || resolved === false) return null\n if (typeof resolved === 'string' || typeof resolved === 'number') return createText(String(resolved))\n if (Array.isArray(resolved)) {\n const children = resolved\n return createFragment((parent, anchor) => {\n for (const child of children) {\n const node = resolveSlot(child)\n if (node) insertBefore(parent, node, anchor)\n }\n })\n }\n return resolved as VobsNode\n}\n\nexport function setOptionalAttribute(node: Element, name: string, value: unknown): void {\n if (value === undefined || value === null || value === false || value === '') {\n removeAttribute(node, name)\n return\n }\n setAttribute(node, name, String(value))\n}\n\nexport function setOptionalProperty(node: Element, name: string, value: unknown): void {\n if (value === undefined || value === null) return\n setProperty(node, name, value)\n}\n\nfunction readString(props: object, name: string): string | undefined {\n const value = Reflect.get(props, name)\n return typeof value === 'string' ? value : undefined\n}\n\nfunction isCommonAttribute(name: string): boolean {\n return name === 'id'\n || name === 'title'\n || name === 'role'\n || name === 'tabIndex'\n || name.startsWith('aria-')\n || name.startsWith('data-')\n}\n\nfunction normalizeAttribute(name: string, value: unknown): { name: string; value: string } | undefined {\n if (value === undefined || value === null) return undefined\n if (value === false && !name.startsWith('aria-') && !name.startsWith('data-')) return undefined\n return { name: name === 'tabIndex' ? 'tabindex' : name, value: String(value) }\n}\n\nconst managedAttributes = new WeakMap<object, Set<string>>()\n\nfunction getManagedAttributes(node: Element): Set<string> {\n return managedAttributes.get(node) ?? new Set<string>()\n}\n\nfunction setManagedAttributes(node: Element, names: IterableIterator<string>): void {\n managedAttributes.set(node, new Set(names))\n}\n\nfunction removeAttribute(node: Element, name: string): void {\n const candidate = node as Element & { removeAttribute?: (attribute: string) => void }\n candidate.removeAttribute?.(name)\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -2232,20 +2232,24 @@ function emitClose2(props, reason) {
|
|
|
2232
2232
|
__name(emitClose2, "emitClose");
|
|
2233
2233
|
|
|
2234
2234
|
// packages/ui/src/toast.ts
|
|
2235
|
-
var import_vobs25 = require("@vobs/vobs");
|
|
2236
2235
|
var import_vobs26 = require("@vobs/vobs");
|
|
2236
|
+
var import_vobs27 = require("@vobs/vobs");
|
|
2237
2237
|
var import_notification = require("@vobs/notification");
|
|
2238
2238
|
|
|
2239
2239
|
// packages/ui/src/icon.ts
|
|
2240
2240
|
var import_icon_core = require("@vobs/icon-core");
|
|
2241
|
+
var import_vobs25 = require("@vobs/vobs");
|
|
2241
2242
|
function Icon(props = {}) {
|
|
2242
2243
|
const root = (0, import_icon_core.createSvgIconNode)(() => {
|
|
2244
|
+
registryVersion.value;
|
|
2243
2245
|
const definition = resolveIcon(
|
|
2244
2246
|
readProp(props, "icon", void 0) ?? readProp(props, "name", void 0)
|
|
2245
2247
|
);
|
|
2246
2248
|
if (!definition) {
|
|
2247
2249
|
if (hasProp(props, "children")) return void 0;
|
|
2248
|
-
|
|
2250
|
+
const requested = readProp(props, "icon", void 0) ?? readProp(props, "name", void 0);
|
|
2251
|
+
console.warn(`Vobs UI: \u672A\u6CE8\u518C\u7684\u56FE\u6807 "${String(requested)}"\uFF0C\u5DF2\u6E32\u67D3\u4E3A\u7A7A\u3002\u8BF7\u5148 registerIcon \u6216\u6539\u7528\u5DF2\u6CE8\u518C\u7684\u540D\u79F0\u3002`);
|
|
2252
|
+
return void 0;
|
|
2249
2253
|
}
|
|
2250
2254
|
return iconDefinitionToSvg(definition);
|
|
2251
2255
|
}, props, {
|
|
@@ -2319,12 +2323,15 @@ var VUI_ICON_PATHS = {
|
|
|
2319
2323
|
var iconRegistry = new Map(
|
|
2320
2324
|
Object.entries(VUI_ICON_PATHS).map(([name, path]) => [name, { name, path }])
|
|
2321
2325
|
);
|
|
2326
|
+
var registryVersion = (0, import_vobs25.state)(0, "vui.iconRegistry.version");
|
|
2322
2327
|
function registerIcon(icon) {
|
|
2323
2328
|
const previous = iconRegistry.get(icon.name);
|
|
2324
2329
|
iconRegistry.set(icon.name, icon);
|
|
2330
|
+
registryVersion.value++;
|
|
2325
2331
|
return () => {
|
|
2326
2332
|
if (previous) iconRegistry.set(icon.name, previous);
|
|
2327
2333
|
else iconRegistry.delete(icon.name);
|
|
2334
|
+
registryVersion.value++;
|
|
2328
2335
|
};
|
|
2329
2336
|
}
|
|
2330
2337
|
__name(registerIcon, "registerIcon");
|
|
@@ -2336,45 +2343,45 @@ __name(resolveIcon, "resolveIcon");
|
|
|
2336
2343
|
// packages/ui/src/toast.ts
|
|
2337
2344
|
function ToastHost(props = {}) {
|
|
2338
2345
|
const notification = props.notification ?? (0, import_notification.useNotification)();
|
|
2339
|
-
const root = (0,
|
|
2346
|
+
const root = (0, import_vobs27.createElement)("ol");
|
|
2340
2347
|
bindClassList(root, props, () => [
|
|
2341
2348
|
"vui-toast-host",
|
|
2342
2349
|
`vui-toast-host--${readProp(props, "position", "top-right")}`
|
|
2343
2350
|
]);
|
|
2344
2351
|
bindCommonAttributes(root, props, ["notification", "position", "closeLabel", "portal", "portalTarget"]);
|
|
2345
2352
|
bindUserStyle(root, props);
|
|
2346
|
-
(0,
|
|
2347
|
-
(0,
|
|
2348
|
-
(0,
|
|
2353
|
+
(0, import_vobs27.setAttribute)(root, "aria-label", "Notifications");
|
|
2354
|
+
(0, import_vobs27.setAttribute)(root, "role", "region");
|
|
2355
|
+
(0, import_vobs26.insertList)(root, null, () => notification.notifications.value, (entry) => createToast(entry, notification, readProp(props, "closeLabel", "Dismiss notification")), (entry) => entry.id);
|
|
2349
2356
|
const portal = readProp(props, "portal", void 0);
|
|
2350
2357
|
return portal ? createPortal(root, portal, readProp(props, "portalTarget", void 0)) : root;
|
|
2351
2358
|
}
|
|
2352
2359
|
__name(ToastHost, "ToastHost");
|
|
2353
2360
|
function createToast(notification, context, closeLabel) {
|
|
2354
|
-
const item = (0,
|
|
2355
|
-
const content = (0,
|
|
2356
|
-
const close = (0,
|
|
2357
|
-
(0,
|
|
2358
|
-
(0,
|
|
2359
|
-
(0,
|
|
2360
|
-
(0,
|
|
2361
|
-
(0,
|
|
2362
|
-
(0,
|
|
2363
|
-
(0,
|
|
2364
|
-
(0,
|
|
2361
|
+
const item = (0, import_vobs27.createElement)("li");
|
|
2362
|
+
const content = (0, import_vobs27.createElement)("div");
|
|
2363
|
+
const close = (0, import_vobs27.createElement)("button");
|
|
2364
|
+
(0, import_vobs27.setAttribute)(item, "class", `vui-toast vui-toast--${notification.type}`);
|
|
2365
|
+
(0, import_vobs27.setAttribute)(item, "data-notification-id", notification.id);
|
|
2366
|
+
(0, import_vobs27.setAttribute)(item, "role", notification.type === "error" ? "alert" : "status");
|
|
2367
|
+
(0, import_vobs27.setAttribute)(content, "class", "vui-toast__content");
|
|
2368
|
+
(0, import_vobs27.setAttribute)(close, "class", "vui-toast__close");
|
|
2369
|
+
(0, import_vobs27.setAttribute)(close, "type", "button");
|
|
2370
|
+
(0, import_vobs27.setAttribute)(close, "aria-label", closeLabel);
|
|
2371
|
+
(0, import_vobs27.addEventListener)(close, "click", () => context.dismiss(notification.id));
|
|
2365
2372
|
if (notification.title) {
|
|
2366
|
-
const title = (0,
|
|
2367
|
-
(0,
|
|
2368
|
-
(0,
|
|
2369
|
-
(0,
|
|
2370
|
-
}
|
|
2371
|
-
const message = (0,
|
|
2372
|
-
(0,
|
|
2373
|
-
(0,
|
|
2374
|
-
(0,
|
|
2375
|
-
(0,
|
|
2376
|
-
(0,
|
|
2377
|
-
(0,
|
|
2373
|
+
const title = (0, import_vobs27.createElement)("div");
|
|
2374
|
+
(0, import_vobs27.setAttribute)(title, "class", "vui-toast__title");
|
|
2375
|
+
(0, import_vobs27.insertBefore)(title, (0, import_vobs27.createText)(notification.title), null);
|
|
2376
|
+
(0, import_vobs27.insertBefore)(content, title, null);
|
|
2377
|
+
}
|
|
2378
|
+
const message = (0, import_vobs27.createElement)("div");
|
|
2379
|
+
(0, import_vobs27.setAttribute)(message, "class", "vui-toast__message");
|
|
2380
|
+
(0, import_vobs27.insertBefore)(message, (0, import_vobs27.createText)(notification.content), null);
|
|
2381
|
+
(0, import_vobs27.insertBefore)(content, message, null);
|
|
2382
|
+
(0, import_vobs27.insertBefore)(close, Icon({ name: "x", size: 16, decorative: true }), null);
|
|
2383
|
+
(0, import_vobs27.insertBefore)(item, content, null);
|
|
2384
|
+
(0, import_vobs27.insertBefore)(item, close, null);
|
|
2378
2385
|
return item;
|
|
2379
2386
|
}
|
|
2380
2387
|
__name(createToast, "createToast");
|