@lytjs/common-dom 6.4.0 → 6.6.0

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["camelToKebab","isBooleanAttr","isSafeAttribute","warn","sanitizeHTML"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * @lytjs/common-dom - Shared DOM utilities for Lyt.js\r\n *\r\n * Provides unified SVG tag detection, DOM property patching functions\r\n * (patchClass, patchStyle, patchAttr, patchProp) shared between\r\n * @lytjs/vdom and @lytjs/renderer.\r\n *\r\n * @module @lytjs/common-dom\r\n * @version 0.1.0\r\n */\r\n\r\n// ==================== Imports ====================\r\n\r\nimport { camelToKebab, isSafeAttribute, sanitizeHTML, isBooleanAttr } from '@lytjs/common-string';\r\nimport { warn } from '@lytjs/common-error';\r\n\r\n// Global dev flag declaration (injected by build tool)\r\ndeclare const __DEV__: boolean;\r\n\r\n// ==================== SVG Constants ====================\r\n\r\n/**\r\n * Complete set of SVG elements that require the SVG namespace.\r\n * Merged from @lytjs/vdom and @lytjs/renderer (union of both sets).\r\n */\r\nexport const SVG_TAGS = new Set([\r\n // Basic shapes\r\n 'svg',\r\n 'path',\r\n 'circle',\r\n 'ellipse',\r\n 'line',\r\n 'polyline',\r\n 'polygon',\r\n 'rect',\r\n // Groups & containers\r\n 'g',\r\n 'defs',\r\n 'use',\r\n 'clipPath',\r\n 'mask',\r\n 'symbol',\r\n 'marker',\r\n 'pattern',\r\n 'foreignObject',\r\n 'image',\r\n // Text\r\n 'text',\r\n 'tspan',\r\n 'textPath',\r\n // Gradients\r\n 'linearGradient',\r\n 'radialGradient',\r\n 'stop',\r\n // Filters\r\n 'filter',\r\n 'feBlend',\r\n 'feColorMatrix',\r\n 'feComponentTransfer',\r\n 'feComposite',\r\n 'feConvolveMatrix',\r\n 'feDiffuseLighting',\r\n 'feDisplacementMap',\r\n 'feDistantLight',\r\n 'feFlood',\r\n 'feGaussianBlur',\r\n 'feImage',\r\n 'feMerge',\r\n 'feMergeNode',\r\n 'feMorphology',\r\n 'feOffset',\r\n 'fePointLight',\r\n 'feSpecularLighting',\r\n 'feSpotLight',\r\n 'feTile',\r\n 'feTurbulence',\r\n // Animation\r\n 'animate',\r\n 'animateTransform',\r\n 'animateMotion',\r\n 'set',\r\n]);\r\n\r\n/** SVG namespace URI */\r\nexport const SVG_NS = 'http://www.w3.org/2000/svg';\r\n\r\n/**\r\n * Check if a tag name is an SVG element\r\n */\r\nexport function isSVGTag(tag: string): boolean {\r\n return SVG_TAGS.has(tag);\r\n}\r\n\r\n// ==================== patchClass ====================\r\n\r\n/**\r\n * Patch the class attribute on an element.\r\n * Uses String() conversion for robust null/undefined handling.\r\n */\r\nexport function patchClass(el: Element, prev: unknown, next: unknown): void {\r\n const el_ = el as HTMLElement;\r\n const prevClass = prev == null ? '' : String(prev);\r\n const nextClass = next == null ? '' : String(next);\r\n if (prevClass !== nextClass) {\r\n el_.className = nextClass;\r\n }\r\n}\r\n\r\n// ==================== patchStyle ====================\r\n\r\n/**\r\n * Patch the style attribute on an element.\r\n * Handles string <-> object transitions, camelCase <-> kebab-case conversion,\r\n * and proper property removal via removeProperty.\r\n */\r\nexport function patchStyle(el: Element, prev: unknown, next: unknown): void {\r\n const el_ = el as HTMLElement;\r\n const style = el_.style;\r\n\r\n if (!next || next === '') {\r\n el_.removeAttribute('style');\r\n return;\r\n }\r\n\r\n const prevStyle = prev as Record<string, string | number> | null | undefined;\r\n const nextStyle = next as Record<string, string | number> | string;\r\n\r\n if (nextStyle && typeof nextStyle !== 'object' && typeof nextStyle !== 'string') {\r\n return;\r\n }\r\n\r\n if (typeof nextStyle === 'string') {\r\n if (prevStyle && typeof prevStyle !== 'string') {\r\n // Was object, now string - clear all inline styles\r\n for (const key in prevStyle) {\r\n style.removeProperty(camelToKebab(key));\r\n }\r\n }\r\n el_.setAttribute('style', nextStyle);\r\n return;\r\n }\r\n\r\n // nextStyle is an object\r\n if (prevStyle && typeof prevStyle !== 'string') {\r\n // Remove keys that existed in prev but not in next\r\n for (const key in prevStyle) {\r\n if (!(key in nextStyle)) {\r\n style.removeProperty(camelToKebab(key));\r\n }\r\n }\r\n } else if (typeof prevStyle === 'string') {\r\n // Was string, now object - clear the string style\r\n el_.removeAttribute('style');\r\n }\r\n\r\n // Apply all new styles\r\n for (const key in nextStyle) {\r\n const val = nextStyle[key];\r\n if (val != null && val !== '') {\r\n style.setProperty(camelToKebab(key), String(val));\r\n } else {\r\n style.removeProperty(camelToKebab(key));\r\n }\r\n }\r\n}\r\n\r\n// ==================== patchAttr ====================\r\n\r\n/**\r\n * Patch a regular or boolean attribute on an element.\r\n * Includes safety checks via isSafeAttribute.\r\n */\r\nexport function patchAttr(el: Element, key: string, value: unknown, _isSVG: boolean): void {\r\n if (value == null || value === false) {\r\n el.removeAttribute(key);\r\n } else if (isBooleanAttr(key)) {\r\n if (value === true || value === '') {\r\n el.setAttribute(key, '');\r\n } else {\r\n const strValue = typeof value === 'string' ? value : String(value);\r\n if (!isSafeAttribute(key, strValue)) {\r\n if (__DEV__) {\r\n warn(`Unsafe attribute \"${key}\" with value \"${strValue}\" has been blocked.`);\r\n }\r\n return;\r\n }\r\n el.setAttribute(key, strValue);\r\n }\r\n } else {\r\n const strValue = typeof value === 'string' ? value : String(value);\r\n if (!isSafeAttribute(key, strValue)) {\r\n if (__DEV__) {\r\n warn(`Unsafe attribute \"${key}\" with value \"${strValue}\" has been blocked.`);\r\n }\r\n return;\r\n }\r\n el.setAttribute(key, strValue);\r\n }\r\n}\r\n\r\n// ==================== patchProp ====================\r\n\r\n/**\r\n * Patch a prop on a DOM element.\r\n * Dispatches to specialized handlers for class, style, events, and attributes.\r\n *\r\n * Note: Event handling is intentionally NOT included here. Consumers\r\n * (vdom/renderer) should handle events themselves based on their\r\n * chosen strategy (direct binding vs invoker pattern).\r\n */\r\nexport function patchProp(\r\n el: Element,\r\n key: string,\r\n prevValue: unknown,\r\n nextValue: unknown,\r\n isSVG: boolean = false,\r\n): void {\r\n if (key === 'class') {\r\n patchClass(el, prevValue, nextValue);\r\n } else if (key === 'style') {\r\n patchStyle(el, prevValue, nextValue);\r\n } else if (key === 'innerHTML') {\r\n if (nextValue !== prevValue) {\r\n if (__DEV__ && nextValue != null && typeof nextValue !== 'string') {\r\n warn('v-html expects a string value.');\r\n }\r\n const sanitized = nextValue == null ? '' : sanitizeHTML(String(nextValue));\r\n el.innerHTML = sanitized;\r\n }\r\n } else if (key === 'textContent') {\r\n if (nextValue !== prevValue) {\r\n el.textContent = nextValue == null ? '' : String(nextValue);\r\n }\r\n } else {\r\n patchAttr(el, key, nextValue, isSVG);\r\n }\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["camelToKebab","isBooleanAttr","isSafeAttribute","warn","sanitizeHTML"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @lytjs/common-dom - Shared DOM utilities for Lyt.js\n *\n * Provides unified SVG tag detection, DOM property patching functions\n * (patchClass, patchStyle, patchAttr, patchProp) shared between\n * @lytjs/vdom and @lytjs/renderer.\n *\n * @module @lytjs/common-dom\n * @version 0.1.0\n */\n\n// ==================== Imports ====================\n\nimport { camelToKebab, isSafeAttribute, sanitizeHTML, isBooleanAttr } from '@lytjs/common-string';\nimport { warn } from '@lytjs/common-error';\n\n// Global dev flag declaration (injected by build tool)\ndeclare const __DEV__: boolean;\n\n// ==================== SVG Constants ====================\n\n/**\n * Complete set of SVG elements that require the SVG namespace.\n * Merged from @lytjs/vdom and @lytjs/renderer (union of both sets).\n */\nexport const SVG_TAGS = new Set([\n // Basic shapes\n 'svg',\n 'path',\n 'circle',\n 'ellipse',\n 'line',\n 'polyline',\n 'polygon',\n 'rect',\n // Groups & containers\n 'g',\n 'defs',\n 'use',\n 'clipPath',\n 'mask',\n 'symbol',\n 'marker',\n 'pattern',\n 'foreignObject',\n 'image',\n // Text\n 'text',\n 'tspan',\n 'textPath',\n // Gradients\n 'linearGradient',\n 'radialGradient',\n 'stop',\n // Filters\n 'filter',\n 'feBlend',\n 'feColorMatrix',\n 'feComponentTransfer',\n 'feComposite',\n 'feConvolveMatrix',\n 'feDiffuseLighting',\n 'feDisplacementMap',\n 'feDistantLight',\n 'feFlood',\n 'feGaussianBlur',\n 'feImage',\n 'feMerge',\n 'feMergeNode',\n 'feMorphology',\n 'feOffset',\n 'fePointLight',\n 'feSpecularLighting',\n 'feSpotLight',\n 'feTile',\n 'feTurbulence',\n // Animation\n 'animate',\n 'animateTransform',\n 'animateMotion',\n 'set',\n]);\n\n/** SVG namespace URI */\nexport const SVG_NS = 'http://www.w3.org/2000/svg';\n\n/**\n * Check if a tag name is an SVG element\n */\nexport function isSVGTag(tag: string): boolean {\n return SVG_TAGS.has(tag);\n}\n\n// ==================== patchClass ====================\n\n/**\n * Patch the class attribute on an element.\n * Uses String() conversion for robust null/undefined handling.\n */\nexport function patchClass(el: Element, prev: unknown, next: unknown): void {\n const el_ = el as HTMLElement;\n const prevClass = prev == null ? '' : String(prev);\n const nextClass = next == null ? '' : String(next);\n if (prevClass !== nextClass) {\n el_.className = nextClass;\n }\n}\n\n// ==================== patchStyle ====================\n\n/**\n * Patch the style attribute on an element.\n * Handles string <-> object transitions, camelCase <-> kebab-case conversion,\n * and proper property removal via removeProperty.\n */\nexport function patchStyle(el: Element, prev: unknown, next: unknown): void {\n const el_ = el as HTMLElement;\n const style = el_.style;\n\n if (!next || next === '') {\n el_.removeAttribute('style');\n return;\n }\n\n const prevStyle = prev as Record<string, string | number> | null | undefined;\n const nextStyle = next as Record<string, string | number> | string;\n\n if (nextStyle && typeof nextStyle !== 'object' && typeof nextStyle !== 'string') {\n return;\n }\n\n if (typeof nextStyle === 'string') {\n if (prevStyle && typeof prevStyle !== 'string') {\n // Was object, now string - clear all inline styles\n for (const key in prevStyle) {\n style.removeProperty(camelToKebab(key));\n }\n }\n el_.setAttribute('style', nextStyle);\n return;\n }\n\n // nextStyle is an object\n if (prevStyle && typeof prevStyle !== 'string') {\n // Remove keys that existed in prev but not in next\n for (const key in prevStyle) {\n if (!(key in nextStyle)) {\n style.removeProperty(camelToKebab(key));\n }\n }\n } else if (typeof prevStyle === 'string') {\n // Was string, now object - clear the string style\n el_.removeAttribute('style');\n }\n\n // Apply all new styles\n for (const key in nextStyle) {\n const val = nextStyle[key];\n if (val != null && val !== '') {\n style.setProperty(camelToKebab(key), String(val));\n } else {\n style.removeProperty(camelToKebab(key));\n }\n }\n}\n\n// ==================== patchAttr ====================\n\n/**\n * Patch a regular or boolean attribute on an element.\n * Includes safety checks via isSafeAttribute.\n */\nexport function patchAttr(el: Element, key: string, value: unknown, _isSVG: boolean): void {\n if (value == null || value === false) {\n el.removeAttribute(key);\n } else if (isBooleanAttr(key)) {\n if (value === true || value === '') {\n el.setAttribute(key, '');\n } else {\n const strValue = typeof value === 'string' ? value : String(value);\n if (!isSafeAttribute(key, strValue)) {\n if (__DEV__) {\n warn(`Unsafe attribute \"${key}\" with value \"${strValue}\" has been blocked.`);\n }\n return;\n }\n el.setAttribute(key, strValue);\n }\n } else {\n const strValue = typeof value === 'string' ? value : String(value);\n if (!isSafeAttribute(key, strValue)) {\n if (__DEV__) {\n warn(`Unsafe attribute \"${key}\" with value \"${strValue}\" has been blocked.`);\n }\n return;\n }\n el.setAttribute(key, strValue);\n }\n}\n\n// ==================== patchProp ====================\n\n/**\n * Patch a prop on a DOM element.\n * Dispatches to specialized handlers for class, style, events, and attributes.\n *\n * Note: Event handling is intentionally NOT included here. Consumers\n * (vdom/renderer) should handle events themselves based on their\n * chosen strategy (direct binding vs invoker pattern).\n */\nexport function patchProp(\n el: Element,\n key: string,\n prevValue: unknown,\n nextValue: unknown,\n isSVG: boolean = false,\n): void {\n if (key === 'class') {\n patchClass(el, prevValue, nextValue);\n } else if (key === 'style') {\n patchStyle(el, prevValue, nextValue);\n } else if (key === 'innerHTML') {\n if (nextValue !== prevValue) {\n if (__DEV__ && nextValue != null && typeof nextValue !== 'string') {\n warn('v-html expects a string value.');\n }\n const sanitized = nextValue == null ? '' : sanitizeHTML(String(nextValue));\n el.innerHTML = sanitized;\n }\n } else if (key === 'textContent') {\n if (nextValue !== prevValue) {\n el.textContent = nextValue == null ? '' : String(nextValue);\n }\n } else {\n patchAttr(el, key, nextValue, isSVG);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\r\n * @lytjs/common-dom - Shared DOM utilities for Lyt.js\r\n *\r\n * Provides unified SVG tag detection, DOM property patching functions\r\n * (patchClass, patchStyle, patchAttr, patchProp) shared between\r\n * @lytjs/vdom and @lytjs/renderer.\r\n *\r\n * @module @lytjs/common-dom\r\n * @version 0.1.0\r\n */\r\n\r\n// ==================== Imports ====================\r\n\r\nimport { camelToKebab, isSafeAttribute, sanitizeHTML, isBooleanAttr } from '@lytjs/common-string';\r\nimport { warn } from '@lytjs/common-error';\r\n\r\n// Global dev flag declaration (injected by build tool)\r\ndeclare const __DEV__: boolean;\r\n\r\n// ==================== SVG Constants ====================\r\n\r\n/**\r\n * Complete set of SVG elements that require the SVG namespace.\r\n * Merged from @lytjs/vdom and @lytjs/renderer (union of both sets).\r\n */\r\nexport const SVG_TAGS = new Set([\r\n // Basic shapes\r\n 'svg',\r\n 'path',\r\n 'circle',\r\n 'ellipse',\r\n 'line',\r\n 'polyline',\r\n 'polygon',\r\n 'rect',\r\n // Groups & containers\r\n 'g',\r\n 'defs',\r\n 'use',\r\n 'clipPath',\r\n 'mask',\r\n 'symbol',\r\n 'marker',\r\n 'pattern',\r\n 'foreignObject',\r\n 'image',\r\n // Text\r\n 'text',\r\n 'tspan',\r\n 'textPath',\r\n // Gradients\r\n 'linearGradient',\r\n 'radialGradient',\r\n 'stop',\r\n // Filters\r\n 'filter',\r\n 'feBlend',\r\n 'feColorMatrix',\r\n 'feComponentTransfer',\r\n 'feComposite',\r\n 'feConvolveMatrix',\r\n 'feDiffuseLighting',\r\n 'feDisplacementMap',\r\n 'feDistantLight',\r\n 'feFlood',\r\n 'feGaussianBlur',\r\n 'feImage',\r\n 'feMerge',\r\n 'feMergeNode',\r\n 'feMorphology',\r\n 'feOffset',\r\n 'fePointLight',\r\n 'feSpecularLighting',\r\n 'feSpotLight',\r\n 'feTile',\r\n 'feTurbulence',\r\n // Animation\r\n 'animate',\r\n 'animateTransform',\r\n 'animateMotion',\r\n 'set',\r\n]);\r\n\r\n/** SVG namespace URI */\r\nexport const SVG_NS = 'http://www.w3.org/2000/svg';\r\n\r\n/**\r\n * Check if a tag name is an SVG element\r\n */\r\nexport function isSVGTag(tag: string): boolean {\r\n return SVG_TAGS.has(tag);\r\n}\r\n\r\n// ==================== patchClass ====================\r\n\r\n/**\r\n * Patch the class attribute on an element.\r\n * Uses String() conversion for robust null/undefined handling.\r\n */\r\nexport function patchClass(el: Element, prev: unknown, next: unknown): void {\r\n const el_ = el as HTMLElement;\r\n const prevClass = prev == null ? '' : String(prev);\r\n const nextClass = next == null ? '' : String(next);\r\n if (prevClass !== nextClass) {\r\n el_.className = nextClass;\r\n }\r\n}\r\n\r\n// ==================== patchStyle ====================\r\n\r\n/**\r\n * Patch the style attribute on an element.\r\n * Handles string <-> object transitions, camelCase <-> kebab-case conversion,\r\n * and proper property removal via removeProperty.\r\n */\r\nexport function patchStyle(el: Element, prev: unknown, next: unknown): void {\r\n const el_ = el as HTMLElement;\r\n const style = el_.style;\r\n\r\n if (!next || next === '') {\r\n el_.removeAttribute('style');\r\n return;\r\n }\r\n\r\n const prevStyle = prev as Record<string, string | number> | null | undefined;\r\n const nextStyle = next as Record<string, string | number> | string;\r\n\r\n if (nextStyle && typeof nextStyle !== 'object' && typeof nextStyle !== 'string') {\r\n return;\r\n }\r\n\r\n if (typeof nextStyle === 'string') {\r\n if (prevStyle && typeof prevStyle !== 'string') {\r\n // Was object, now string - clear all inline styles\r\n for (const key in prevStyle) {\r\n style.removeProperty(camelToKebab(key));\r\n }\r\n }\r\n el_.setAttribute('style', nextStyle);\r\n return;\r\n }\r\n\r\n // nextStyle is an object\r\n if (prevStyle && typeof prevStyle !== 'string') {\r\n // Remove keys that existed in prev but not in next\r\n for (const key in prevStyle) {\r\n if (!(key in nextStyle)) {\r\n style.removeProperty(camelToKebab(key));\r\n }\r\n }\r\n } else if (typeof prevStyle === 'string') {\r\n // Was string, now object - clear the string style\r\n el_.removeAttribute('style');\r\n }\r\n\r\n // Apply all new styles\r\n for (const key in nextStyle) {\r\n const val = nextStyle[key];\r\n if (val != null && val !== '') {\r\n style.setProperty(camelToKebab(key), String(val));\r\n } else {\r\n style.removeProperty(camelToKebab(key));\r\n }\r\n }\r\n}\r\n\r\n// ==================== patchAttr ====================\r\n\r\n/**\r\n * Patch a regular or boolean attribute on an element.\r\n * Includes safety checks via isSafeAttribute.\r\n */\r\nexport function patchAttr(el: Element, key: string, value: unknown, _isSVG: boolean): void {\r\n if (value == null || value === false) {\r\n el.removeAttribute(key);\r\n } else if (isBooleanAttr(key)) {\r\n if (value === true || value === '') {\r\n el.setAttribute(key, '');\r\n } else {\r\n const strValue = typeof value === 'string' ? value : String(value);\r\n if (!isSafeAttribute(key, strValue)) {\r\n if (__DEV__) {\r\n warn(`Unsafe attribute \"${key}\" with value \"${strValue}\" has been blocked.`);\r\n }\r\n return;\r\n }\r\n el.setAttribute(key, strValue);\r\n }\r\n } else {\r\n const strValue = typeof value === 'string' ? value : String(value);\r\n if (!isSafeAttribute(key, strValue)) {\r\n if (__DEV__) {\r\n warn(`Unsafe attribute \"${key}\" with value \"${strValue}\" has been blocked.`);\r\n }\r\n return;\r\n }\r\n el.setAttribute(key, strValue);\r\n }\r\n}\r\n\r\n// ==================== patchProp ====================\r\n\r\n/**\r\n * Patch a prop on a DOM element.\r\n * Dispatches to specialized handlers for class, style, events, and attributes.\r\n *\r\n * Note: Event handling is intentionally NOT included here. Consumers\r\n * (vdom/renderer) should handle events themselves based on their\r\n * chosen strategy (direct binding vs invoker pattern).\r\n */\r\nexport function patchProp(\r\n el: Element,\r\n key: string,\r\n prevValue: unknown,\r\n nextValue: unknown,\r\n isSVG: boolean = false,\r\n): void {\r\n if (key === 'class') {\r\n patchClass(el, prevValue, nextValue);\r\n } else if (key === 'style') {\r\n patchStyle(el, prevValue, nextValue);\r\n } else if (key === 'innerHTML') {\r\n if (nextValue !== prevValue) {\r\n if (__DEV__ && nextValue != null && typeof nextValue !== 'string') {\r\n warn('v-html expects a string value.');\r\n }\r\n const sanitized = nextValue == null ? '' : sanitizeHTML(String(nextValue));\r\n el.innerHTML = sanitized;\r\n }\r\n } else if (key === 'textContent') {\r\n if (nextValue !== prevValue) {\r\n el.textContent = nextValue == null ? '' : String(nextValue);\r\n }\r\n } else {\r\n patchAttr(el, key, nextValue, isSVG);\r\n }\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @lytjs/common-dom - Shared DOM utilities for Lyt.js\n *\n * Provides unified SVG tag detection, DOM property patching functions\n * (patchClass, patchStyle, patchAttr, patchProp) shared between\n * @lytjs/vdom and @lytjs/renderer.\n *\n * @module @lytjs/common-dom\n * @version 0.1.0\n */\n\n// ==================== Imports ====================\n\nimport { camelToKebab, isSafeAttribute, sanitizeHTML, isBooleanAttr } from '@lytjs/common-string';\nimport { warn } from '@lytjs/common-error';\n\n// Global dev flag declaration (injected by build tool)\ndeclare const __DEV__: boolean;\n\n// ==================== SVG Constants ====================\n\n/**\n * Complete set of SVG elements that require the SVG namespace.\n * Merged from @lytjs/vdom and @lytjs/renderer (union of both sets).\n */\nexport const SVG_TAGS = new Set([\n // Basic shapes\n 'svg',\n 'path',\n 'circle',\n 'ellipse',\n 'line',\n 'polyline',\n 'polygon',\n 'rect',\n // Groups & containers\n 'g',\n 'defs',\n 'use',\n 'clipPath',\n 'mask',\n 'symbol',\n 'marker',\n 'pattern',\n 'foreignObject',\n 'image',\n // Text\n 'text',\n 'tspan',\n 'textPath',\n // Gradients\n 'linearGradient',\n 'radialGradient',\n 'stop',\n // Filters\n 'filter',\n 'feBlend',\n 'feColorMatrix',\n 'feComponentTransfer',\n 'feComposite',\n 'feConvolveMatrix',\n 'feDiffuseLighting',\n 'feDisplacementMap',\n 'feDistantLight',\n 'feFlood',\n 'feGaussianBlur',\n 'feImage',\n 'feMerge',\n 'feMergeNode',\n 'feMorphology',\n 'feOffset',\n 'fePointLight',\n 'feSpecularLighting',\n 'feSpotLight',\n 'feTile',\n 'feTurbulence',\n // Animation\n 'animate',\n 'animateTransform',\n 'animateMotion',\n 'set',\n]);\n\n/** SVG namespace URI */\nexport const SVG_NS = 'http://www.w3.org/2000/svg';\n\n/**\n * Check if a tag name is an SVG element\n */\nexport function isSVGTag(tag: string): boolean {\n return SVG_TAGS.has(tag);\n}\n\n// ==================== patchClass ====================\n\n/**\n * Patch the class attribute on an element.\n * Uses String() conversion for robust null/undefined handling.\n */\nexport function patchClass(el: Element, prev: unknown, next: unknown): void {\n const el_ = el as HTMLElement;\n const prevClass = prev == null ? '' : String(prev);\n const nextClass = next == null ? '' : String(next);\n if (prevClass !== nextClass) {\n el_.className = nextClass;\n }\n}\n\n// ==================== patchStyle ====================\n\n/**\n * Patch the style attribute on an element.\n * Handles string <-> object transitions, camelCase <-> kebab-case conversion,\n * and proper property removal via removeProperty.\n */\nexport function patchStyle(el: Element, prev: unknown, next: unknown): void {\n const el_ = el as HTMLElement;\n const style = el_.style;\n\n if (!next || next === '') {\n el_.removeAttribute('style');\n return;\n }\n\n const prevStyle = prev as Record<string, string | number> | null | undefined;\n const nextStyle = next as Record<string, string | number> | string;\n\n if (nextStyle && typeof nextStyle !== 'object' && typeof nextStyle !== 'string') {\n return;\n }\n\n if (typeof nextStyle === 'string') {\n if (prevStyle && typeof prevStyle !== 'string') {\n // Was object, now string - clear all inline styles\n for (const key in prevStyle) {\n style.removeProperty(camelToKebab(key));\n }\n }\n el_.setAttribute('style', nextStyle);\n return;\n }\n\n // nextStyle is an object\n if (prevStyle && typeof prevStyle !== 'string') {\n // Remove keys that existed in prev but not in next\n for (const key in prevStyle) {\n if (!(key in nextStyle)) {\n style.removeProperty(camelToKebab(key));\n }\n }\n } else if (typeof prevStyle === 'string') {\n // Was string, now object - clear the string style\n el_.removeAttribute('style');\n }\n\n // Apply all new styles\n for (const key in nextStyle) {\n const val = nextStyle[key];\n if (val != null && val !== '') {\n style.setProperty(camelToKebab(key), String(val));\n } else {\n style.removeProperty(camelToKebab(key));\n }\n }\n}\n\n// ==================== patchAttr ====================\n\n/**\n * Patch a regular or boolean attribute on an element.\n * Includes safety checks via isSafeAttribute.\n */\nexport function patchAttr(el: Element, key: string, value: unknown, _isSVG: boolean): void {\n if (value == null || value === false) {\n el.removeAttribute(key);\n } else if (isBooleanAttr(key)) {\n if (value === true || value === '') {\n el.setAttribute(key, '');\n } else {\n const strValue = typeof value === 'string' ? value : String(value);\n if (!isSafeAttribute(key, strValue)) {\n if (__DEV__) {\n warn(`Unsafe attribute \"${key}\" with value \"${strValue}\" has been blocked.`);\n }\n return;\n }\n el.setAttribute(key, strValue);\n }\n } else {\n const strValue = typeof value === 'string' ? value : String(value);\n if (!isSafeAttribute(key, strValue)) {\n if (__DEV__) {\n warn(`Unsafe attribute \"${key}\" with value \"${strValue}\" has been blocked.`);\n }\n return;\n }\n el.setAttribute(key, strValue);\n }\n}\n\n// ==================== patchProp ====================\n\n/**\n * Patch a prop on a DOM element.\n * Dispatches to specialized handlers for class, style, events, and attributes.\n *\n * Note: Event handling is intentionally NOT included here. Consumers\n * (vdom/renderer) should handle events themselves based on their\n * chosen strategy (direct binding vs invoker pattern).\n */\nexport function patchProp(\n el: Element,\n key: string,\n prevValue: unknown,\n nextValue: unknown,\n isSVG: boolean = false,\n): void {\n if (key === 'class') {\n patchClass(el, prevValue, nextValue);\n } else if (key === 'style') {\n patchStyle(el, prevValue, nextValue);\n } else if (key === 'innerHTML') {\n if (nextValue !== prevValue) {\n if (__DEV__ && nextValue != null && typeof nextValue !== 'string') {\n warn('v-html expects a string value.');\n }\n const sanitized = nextValue == null ? '' : sanitizeHTML(String(nextValue));\n el.innerHTML = sanitized;\n }\n } else if (key === 'textContent') {\n if (nextValue !== prevValue) {\n el.textContent = nextValue == null ? '' : String(nextValue);\n }\n } else {\n patchAttr(el, key, nextValue, isSVG);\n }\n}\n"]}
package/package.json CHANGED
@@ -1,47 +1,47 @@
1
- {
2
- "name": "@lytjs/common-dom",
3
- "version": "6.4.0",
4
- "description": "Shared DOM utilities for Lyt.js - SVG tags, patchClass, patchStyle, patchAttr, patchProp",
5
- "keywords": [
6
- "lytjs",
7
- "dom",
8
- "svg",
9
- "patch"
10
- ],
11
- "license": "MIT",
12
- "main": "./dist/index.cjs",
13
- "module": "./dist/index.mjs",
14
- "types": "./dist/index.d.ts",
15
- "exports": {
16
- ".": {
17
- "types": "./dist/index.d.ts",
18
- "import": "./dist/index.mjs",
19
- "require": "./dist/index.cjs"
20
- }
21
- },
22
- "files": [
23
- "dist",
24
- "README.md"
25
- ],
26
- "engines": {
27
- "node": ">=18.0.0"
28
- },
29
- "scripts": {
30
- "build": "tsup",
31
- "test": "vitest run",
32
- "test:watch": "vitest",
33
- "clean": "rm -rf dist .tsbuildinfo"
34
- },
35
- "dependencies": {
36
- "@lytjs/common-is": "^6.0.0",
37
- "@lytjs/common-string": "^6.0.0",
38
- "@lytjs/common-events": "^6.0.0",
39
- "@lytjs/common-error": "^6.0.0"
40
- },
41
- "devDependencies": {
42
- "typescript": "^5.8.2",
43
- "tsup": "^8.4.0",
44
- "vitest": "^3.0.0",
45
- "jsdom": "^24.0.0"
46
- }
47
- }
1
+ {
2
+ "name": "@lytjs/common-dom",
3
+ "version": "6.6.0",
4
+ "description": "Shared DOM utilities for Lyt.js - SVG tags, patchClass, patchStyle, patchAttr, patchProp",
5
+ "keywords": [
6
+ "lytjs",
7
+ "dom",
8
+ "svg",
9
+ "patch"
10
+ ],
11
+ "license": "MIT",
12
+ "main": "./dist/index.cjs",
13
+ "module": "./dist/index.mjs",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.mjs",
19
+ "require": "./dist/index.cjs"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md"
25
+ ],
26
+ "engines": {
27
+ "node": ">=18.0.0"
28
+ },
29
+ "scripts": {
30
+ "build": "tsup",
31
+ "test": "vitest run",
32
+ "test:watch": "vitest",
33
+ "clean": "rm -rf dist .tsbuildinfo"
34
+ },
35
+ "dependencies": {
36
+ "@lytjs/common-is": "workspace:*",
37
+ "@lytjs/common-string": "workspace:*",
38
+ "@lytjs/common-events": "workspace:*",
39
+ "@lytjs/common-error": "workspace:*"
40
+ },
41
+ "devDependencies": {
42
+ "typescript": "^5.8.2",
43
+ "tsup": "^8.4.0",
44
+ "vitest": "^3.0.0",
45
+ "jsdom": "^24.0.0"
46
+ }
47
+ }