UNPKG

svelte

Version:

Cybernetically enhanced web apps

473 lines (440 loc) 8.33 kB
const regex_return_characters = /\r/g; /** * @param {string} str * @returns {string} */ export function hash(str) { str = str.replace(regex_return_characters, ''); let hash = 5381; let i = str.length; while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i); return (hash >>> 0).toString(36); } const VOID_ELEMENT_NAMES = [ 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr' ]; /** * Returns `true` if `name` is of a void element * @param {string} name */ export function is_void(name) { return VOID_ELEMENT_NAMES.includes(name) || name.toLowerCase() === '!doctype'; } const RESERVED_WORDS = [ 'arguments', 'await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'else', 'enum', 'eval', 'export', 'extends', 'false', 'finally', 'for', 'function', 'if', 'implements', 'import', 'in', 'instanceof', 'interface', 'let', 'new', 'null', 'package', 'private', 'protected', 'public', 'return', 'static', 'super', 'switch', 'this', 'throw', 'true', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield' ]; /** * Returns `true` if `word` is a reserved JavaScript keyword * @param {string} word */ export function is_reserved(word) { return RESERVED_WORDS.includes(word); } /** * @param {string} name */ export function is_capture_event(name) { return name.endsWith('capture') && name !== 'gotpointercapture' && name !== 'lostpointercapture'; } /** List of Element events that will be delegated */ const DELEGATED_EVENTS = [ 'beforeinput', 'click', 'change', 'dblclick', 'contextmenu', 'focusin', 'focusout', 'input', 'keydown', 'keyup', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'pointerdown', 'pointermove', 'pointerout', 'pointerover', 'pointerup', 'touchend', 'touchmove', 'touchstart' ]; /** * Returns `true` if `event_name` is a delegated event * @param {string} event_name */ export function is_delegated(event_name) { return DELEGATED_EVENTS.includes(event_name); } /** * Attributes that are boolean, i.e. they are present or not present. */ const DOM_BOOLEAN_ATTRIBUTES = [ 'allowfullscreen', 'async', 'autofocus', 'autoplay', 'checked', 'controls', 'default', 'disabled', 'formnovalidate', 'hidden', 'indeterminate', 'inert', 'ismap', 'loop', 'multiple', 'muted', 'nomodule', 'novalidate', 'open', 'playsinline', 'readonly', 'required', 'reversed', 'seamless', 'selected', 'webkitdirectory', 'defer', 'disablepictureinpicture', 'disableremoteplayback' ]; /** * Returns `true` if `name` is a boolean attribute * @param {string} name */ export function is_boolean_attribute(name) { return DOM_BOOLEAN_ATTRIBUTES.includes(name); } /** * @type {Record<string, string>} * List of attribute names that should be aliased to their property names * because they behave differently between setting them as an attribute and * setting them as a property. */ const ATTRIBUTE_ALIASES = { // no `class: 'className'` because we handle that separately formnovalidate: 'formNoValidate', ismap: 'isMap', nomodule: 'noModule', playsinline: 'playsInline', readonly: 'readOnly', defaultvalue: 'defaultValue', defaultchecked: 'defaultChecked', srcobject: 'srcObject', novalidate: 'noValidate', allowfullscreen: 'allowFullscreen', disablepictureinpicture: 'disablePictureInPicture', disableremoteplayback: 'disableRemotePlayback' }; /** * @param {string} name */ export function normalize_attribute(name) { name = name.toLowerCase(); return ATTRIBUTE_ALIASES[name] ?? name; } const DOM_PROPERTIES = [ ...DOM_BOOLEAN_ATTRIBUTES, 'formNoValidate', 'isMap', 'noModule', 'playsInline', 'readOnly', 'value', 'volume', 'defaultValue', 'defaultChecked', 'srcObject', 'noValidate', 'allowFullscreen', 'disablePictureInPicture', 'disableRemotePlayback' ]; /** * @param {string} name */ export function is_dom_property(name) { return DOM_PROPERTIES.includes(name); } const NON_STATIC_PROPERTIES = ['autofocus', 'muted', 'defaultValue', 'defaultChecked']; /** * Returns `true` if the given attribute cannot be set through the template * string, i.e. needs some kind of JavaScript handling to work. * @param {string} name */ export function cannot_be_set_statically(name) { return NON_STATIC_PROPERTIES.includes(name); } /** * Subset of delegated events which should be passive by default. * These two are already passive via browser defaults on window, document and body. * But since * - we're delegating them * - they happen often * - they apply to mobile which is generally less performant * we're marking them as passive by default for other elements, too. */ const PASSIVE_EVENTS = ['touchstart', 'touchmove']; /** * Returns `true` if `name` is a passive event * @param {string} name */ export function is_passive_event(name) { return PASSIVE_EVENTS.includes(name); } const CONTENT_EDITABLE_BINDINGS = ['textContent', 'innerHTML', 'innerText']; /** @param {string} name */ export function is_content_editable_binding(name) { return CONTENT_EDITABLE_BINDINGS.includes(name); } const LOAD_ERROR_ELEMENTS = [ 'body', 'embed', 'iframe', 'img', 'link', 'object', 'script', 'style', 'track' ]; /** * Returns `true` if the element emits `load` and `error` events * @param {string} name */ export function is_load_error_element(name) { return LOAD_ERROR_ELEMENTS.includes(name); } const SVG_ELEMENTS = [ 'altGlyph', 'altGlyphDef', 'altGlyphItem', 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'circle', 'clipPath', 'color-profile', 'cursor', 'defs', 'desc', 'discard', 'ellipse', 'feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence', 'filter', 'font', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignObject', 'g', 'glyph', 'glyphRef', 'hatch', 'hatchpath', 'hkern', 'image', 'line', 'linearGradient', 'marker', 'mask', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'metadata', 'missing-glyph', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'set', 'solidcolor', 'stop', 'svg', 'switch', 'symbol', 'text', 'textPath', 'tref', 'tspan', 'unknown', 'use', 'view', 'vkern' ]; /** @param {string} name */ export function is_svg(name) { return SVG_ELEMENTS.includes(name); } const MATHML_ELEMENTS = [ 'annotation', 'annotation-xml', 'maction', 'math', 'merror', 'mfrac', 'mi', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mprescripts', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msubsup', 'msup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'semantics' ]; /** @param {string} name */ export function is_mathml(name) { return MATHML_ELEMENTS.includes(name); } const RUNES = /** @type {const} */ ([ '$state', '$state.raw', '$state.snapshot', '$props', '$props.id', '$bindable', '$derived', '$derived.by', '$effect', '$effect.pre', '$effect.tracking', '$effect.root', '$inspect', '$inspect().with', '$inspect.trace', '$host' ]); /** * @param {string} name * @returns {name is RUNES[number]} */ export function is_rune(name) { return RUNES.includes(/** @type {RUNES[number]} */ (name)); } /** List of elements that require raw contents and should not have SSR comments put in them */ const RAW_TEXT_ELEMENTS = /** @type {const} */ (['textarea', 'script', 'style', 'title']); /** @param {string} name */ export function is_raw_text_element(name) { return RAW_TEXT_ELEMENTS.includes(/** @type {RAW_TEXT_ELEMENTS[number]} */ (name)); } /** * Prevent devtools trying to make `location` a clickable link by inserting a zero-width space * @param {string | undefined} location */ export function sanitize_location(location) { return location?.replace(/\//g, '/\u200b'); }