@digdir/designsystemet-web 1.21.0 → 1.22.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.
- package/dist/cjs/_vendors/@oddbird/popover-polyfill/dist/popover-fn.cjs +1 -1
- package/dist/cjs/_vendors/@oddbird/popover-polyfill/dist/popover-fn.cjs.map +1 -1
- package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -1
- package/dist/cjs/focusgroup/focusgroup.cjs +1 -1
- package/dist/cjs/focusgroup/focusgroup.cjs.map +1 -1
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/packages/web/package.cjs +1 -1
- package/dist/cjs/suggestion/suggestion.cjs +1 -1
- package/dist/cjs/suggestion/suggestion.cjs.map +1 -1
- package/dist/cjs/toggle-group/toggle-group.cjs.map +1 -1
- package/dist/cjs/tooltip/tooltip.cjs +1 -1
- package/dist/cjs/tooltip/tooltip.cjs.map +1 -1
- package/dist/cjs/utils/utils.cjs +1 -1
- package/dist/cjs/utils/utils.cjs.map +1 -1
- package/dist/custom-elements.json +8 -8
- package/dist/esm/_vendors/@oddbird/popover-polyfill/dist/popover-fn.js +1 -1
- package/dist/esm/_vendors/@oddbird/popover-polyfill/dist/popover-fn.js.map +1 -1
- package/dist/esm/focusgroup/focusgroup.js +1 -1
- package/dist/esm/focusgroup/focusgroup.js.map +1 -1
- package/dist/esm/packages/web/package.js +1 -1
- package/dist/esm/suggestion/suggestion.js +1 -1
- package/dist/esm/suggestion/suggestion.js.map +1 -1
- package/dist/esm/toggle-group/toggle-group.js.map +1 -1
- package/dist/esm/tooltip/tooltip.js +1 -1
- package/dist/esm/tooltip/tooltip.js.map +1 -1
- package/dist/esm/utils/utils.js +1 -1
- package/dist/esm/utils/utils.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +49 -33
- package/dist/umd/index.js +8 -8
- package/dist/umd/index.js.map +1 -1
- package/package.json +7 -7
package/dist/esm/utils/utils.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{version as e}from"../packages/web/package.js";const t=`aria-description`,n=`aria-label`,r=`aria-labelledby`,i={passive:!0,capture:!0},a=()=>typeof window<`u`&&typeof document<`u`,o=()=>a()&&/^Win/i.test(navigator.userAgentData?.platform||navigator.platform),s=typeof HTMLElement>`u`?class{}:HTMLElement;function c(e,t){let n;return function(...r){clearTimeout(n),n=setTimeout(()=>e.apply(this,r),t)}}const l=(e,...t)=>!a()||window.dsWarnings===!1||console.log(`\x1B[1mDesignsystemet:\x1B[m ${e}`,...t),u=(e,t,n)=>n===void 0?e.getAttribute(t):(n===null?e.removeAttribute(t):e.getAttribute(t)!==n&&e.setAttribute(t,n),null),d=(e,t)=>getComputedStyle(e).getPropertyValue(t).trim(),f=/^["']|["']$/g,p=(e,t)=>{let n=u(e,t);return n||=d(e,`--_ds-${t}`).replace(f,``).trim(),n||null},
|
|
1
|
+
import{version as e}from"../packages/web/package.js";const t=`aria-description`,n=`aria-label`,r=`aria-labelledby`,i={passive:!0,capture:!0},a=()=>typeof window<`u`&&typeof document<`u`,o=()=>a()&&/^Win/i.test(navigator.userAgentData?.platform||navigator.platform),s=typeof HTMLElement>`u`?class{}:HTMLElement;function c(e,t){let n;return function(...r){clearTimeout(n),n=setTimeout(()=>e.apply(this,r),t)}}const l=(e,...t)=>!a()||window.dsWarnings===!1||console.log(`\x1B[1mDesignsystemet:\x1B[m ${e}`,...t),u=(e,t,n)=>n===void 0?e.getAttribute(t):(n===null?e.removeAttribute(t):e.getAttribute(t)!==n&&e.setAttribute(t,n),null),d=(e,t)=>getComputedStyle(e).getPropertyValue(t).trim(),f=/^["']|["']$/g,p=/\\(["'])/g,m=(e,t)=>{let n=u(e,t);return n||=d(e,`--_ds-${t}`).replace(f,``).replace(p,`$1`).trim(),n||null},h=e=>{let t=e?.getRootNode?.()||e?.ownerDocument;return t instanceof Document||t instanceof ShadowRoot?t:e?.ownerDocument||document},g=e=>{let t=e.target?.shadowRoot&&e.composedPath()[0]||e.target;return t?.nodeType===1?t:null},_=e=>{let t=new Set;for(;e;)t.add(e),e=e.nodeType===11?e.host:e.assignedSlot||e.parentNode;return t},v=(e,...t)=>{let[n,...r]=t;for(let t of n.split(` `))e.addEventListener(t,...r);return()=>y(e,...t)},y=(e,...t)=>{let[n,...r]=t;for(let t of n.split(` `))e.removeEventListener(t,...r)},b=`_dsHotReloadCleanup${e}`,x=(e,t)=>{if(a()){window[b]||(window[b]=new Map);for(let t of window[b]?.get(e)||[])t();window[b]?.set(e,t())}},S=(e,t,n)=>{let r=()=>i.disconnect(),i=new MutationObserver(n=>{if(!a()||!e.isConnected)return r();t(e,n)});return t(e),i.observe(e,n),r},C=(e,t)=>{let n=document.createElement(e);if(t)for(let[e,r]of Object.entries(t))u(n,e,r);return n},w={define:(e,t)=>!a()||window.customElements.get(e)||window.customElements.define(e,t)};let T=0;function E(e){return a()?(window.dsUseId||(window.dsUseId=0),e&&!e.id&&(e.id=`:ds:${++window.dsUseId}`),e?.id||``):`:ds:${++T}`}let D,O=0,k=0;const A=e=>{clearTimeout(k),D&&(D.textContent=`${e}${O++%2?`\xA0`:``}`),e&&(k=setTimeout(A,2e3,``))},j=()=>{document.readyState===`complete`&&(D||(D=C(`div`,{"aria-live":`assertive`}),D.style.overflow=`hidden`,D.style.position=`fixed`,D.style.whiteSpace=`nowrap`,D.style.width=`1px`),D.isConnected||document.body.appendChild(D))};x(`announce`,()=>[v(document,`focus mouseover`,j,i)]);export{t as ARIA_DESC,n as ARIA_LABEL,r as ARIA_LABELLEDBY,s as DSElement,i as QUICK_EVENT,A as announce,u as attr,m as attrOrCSS,w as customElements,c as debounce,d as getCSSProp,_ as getComposedPath,g as getComposedTarget,h as getRoot,a as isBrowser,o as isWindows,y as off,v as on,x as onHotReload,S as onMutation,C as tag,E as useId,l as warn};
|
|
2
2
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../../../src/utils/utils.ts"],"sourcesContent":["export const ARIA_DESC = 'aria-description';\nexport const ARIA_LABEL = 'aria-label';\nexport const ARIA_LABELLEDBY = 'aria-labelledby';\nexport const QUICK_EVENT = { passive: true, capture: true };\n\nimport { version } from '../../package.json' with { type: 'json' };\n\n// Using function instead of constant to support environments where DOM can be unloaded (like Vitest with jsdom)\nexport const isBrowser = () =>\n typeof window !== 'undefined' && typeof document !== 'undefined';\n\nexport const isWindows = () =>\n isBrowser() &&\n // @ts-expect-error Typescript has not implemented userAgentData yet https://stackoverflow.com/a/71392474\n /^Win/i.test(navigator.userAgentData?.platform || navigator.platform);\n\n// Make sure we have a HTMLElement to extend (for server side rendering)\nexport const DSElement =\n typeof HTMLElement === 'undefined'\n ? (class {} as typeof HTMLElement)\n : HTMLElement;\n\nexport function debounce<T extends unknown[]>(\n callback: (...args: T) => void,\n delay: number,\n) {\n let timer: ReturnType<typeof setTimeout>;\n\n return function (this: unknown, ...args: T) {\n clearTimeout(timer);\n timer = setTimeout(() => callback.apply(this, args), delay);\n };\n}\n\n/**\n * warn\n * @description Utility to console.log, but can be silenced in production with window.dsWarnings = false;\n */\ndeclare global {\n interface Window {\n dsWarnings?: boolean;\n }\n}\nexport const warn = (\n message: string,\n ...args: Parameters<typeof console.log> // Using console.log, not console.warn, to prevent stopping test runners such as Jest\n) =>\n !isBrowser() ||\n window.dsWarnings === false ||\n console.log(`\\x1B[1mDesignsystemet:\\x1B[m ${message}`, ...args);\n\n/**\n * attr\n * @description Utility to quickly get, set and remove attributes\n * @param el The Element to read/write attributes from\n * @param name The attribute name to get, set or remove, or a object to set multiple attributes\n * @param value A valid attribute value or null to remove attribute\n */\nexport const attr = (\n el: Element,\n name: string,\n value?: string | null,\n): string | null => {\n if (value === undefined) return el.getAttribute(name);\n if (value === null) el.removeAttribute(name);\n else if (el.getAttribute(name) !== value) el.setAttribute(name, value);\n return null;\n};\n\n/**\n * getCSSProp\n * @description Retrieves and CSS property value and trims it\n * @param el The Element to read attributes/CSS from\n * @param name Attribute or CSS property to get\n * @return string CSS property value\n */\nexport const getCSSProp = (el: Element, prop: string) =>\n getComputedStyle(el).getPropertyValue(prop).trim();\n\nconst STRIP_QUOTES = /^[\"']|[\"']$/g; // Matches surrounding single or double quotes\n/**\n * attrOrCSS\n * @description Retrieves and updates attribute based on attribute or CSS property value\n * @param el The Element to read attributes/CSS from\n * @param name Attribute or CSS property to get\n * @return string attribute or CSS property value\n */\nexport const attrOrCSS = (el: Element, name: string) => {\n let value = attr(el, name);\n if (!value)\n value = getCSSProp(el, `--_ds-${name}`).replace(STRIP_QUOTES, '').trim();\n return value || null;\n};\n\n/**\n * getRoot\n * @description Helper for better compatibility\n * @param node The target node\n * @return The shadow root or document\n */\nexport const getRoot = (node?: Node | null): Document | ShadowRoot => {\n const root = node?.getRootNode?.() || node?.ownerDocument;\n if (root instanceof Document || root instanceof ShadowRoot) return root;\n return node?.ownerDocument || document;\n};\n\n/**\n * getComposedTarget\n * @description Helper to get the composed target of an event, supporting ShadowDOM rendering\n * @param event The event\n * @return The target Element\n */\nexport const getComposedTarget = (e: Event): Element | null => {\n const el =\n ((e.target as Element)?.shadowRoot && e.composedPath()[0]) || e.target; // Only use composedPath if the target has a shadowRoot to boost performance\n return (el as Node)?.nodeType === 1 ? (el as Element) : null;\n};\n\n/**\n * getComposedPath\n * @description Helper to get the full composed path even if listener is bound to a ShadowRoot (unlike event.composedPath())\n * @param el The element to start traversing from\n * @return Set of nodes in the path\n */\nexport const getComposedPath = (el: Node | null) => {\n const path = new Set<Node>();\n while (el) {\n path.add(el);\n if (el.nodeType === 11) el = (el as ShadowRoot).host;\n else el = (el as Element).assignedSlot || el.parentNode;\n }\n return path;\n};\n\n/**\n * on\n * @param el The Element to use as EventTarget\n * @param types A space separated string of event types\n * @param listener An event listener function or listener object\n */\nexport const on = (\n el: Node | Window | ShadowRoot,\n ...rest: Parameters<typeof Element.prototype.addEventListener>\n): (() => void) => {\n const [types, ...options] = rest;\n for (const type of types.split(' ')) el.addEventListener(type, ...options);\n return () => off(el, ...rest);\n};\n\n/**\n * off\n * @param el The Element to use as EventTarget\n * @param types A space separated string of event types\n * @param listener An event listener function or listener object\n */\nexport const off = (\n el: Node | Window | ShadowRoot,\n ...rest: Parameters<typeof Element.prototype.removeEventListener>\n): void => {\n const [types, ...options] = rest;\n for (const type of types.split(' ')) el.removeEventListener(type, ...options);\n};\n\n// Used to store cleanup functions for hot-reloading\nconst HOT_RELOAD_KEY = `_dsHotReloadCleanup${version}` as const; // Ensure multiple versions of Designsystemet can run on same page\ndeclare global {\n interface Window {\n [HOT_RELOAD_KEY]?: Map<string, Array<() => void>>;\n }\n}\n\n/**\n * onHotReload\n * @description Runs a callback when window is loaded in browser, and ensures cleanup when hot-reloading\n * @param key The key to identify setup and corresponding cleanup\n * @param callback The callback to run when the page is ready\n */\nexport const onHotReload = (key: string, setup: () => Array<() => void>) => {\n if (!isBrowser()) return; // Skip if not in modern browser environment, but on each call as Vitest might have unloaded jsdom between tests\n if (!window[HOT_RELOAD_KEY]) window[HOT_RELOAD_KEY] = new Map(); // Hot reload cleanup support supporting all build tools\n for (const cleanup of window[HOT_RELOAD_KEY]?.get(key) || []) cleanup(); // Run previous cleanup\n window[HOT_RELOAD_KEY]?.set(key, setup()); // Store new cleanup\n};\n\n/**\n * MutationObserver wrapper with automatic cleanup\n * @return new MutaionObserver\n */\nexport const onMutation = <T extends Node>(\n el: T,\n callback: (el: T, records?: MutationRecord[]) => void,\n options: MutationObserverInit,\n) => {\n const cleanup = () => observer.disconnect();\n const observer = new MutationObserver((records) => {\n if (!isBrowser() || !el.isConnected) return cleanup(); // Stop observing if element is removed from DOM or document is removed by jdsom tests\n callback(el, records);\n });\n\n callback(el); // Initial is run instantly to make test markup predictable\n observer.observe(el, options);\n return cleanup;\n};\n\n/**\n * tag\n * @description creates element and assigns properties\n * @param tagName The tagname of element to create\n * @param attrs Optional attributes to add to the element\n * @param text Optional text content to add to the element\n * @return HTMLElement with props\n */\nexport const tag = <TagName extends keyof HTMLElementTagNameMap>(\n tagName: TagName,\n attrs?: Record<string, string | null> | null,\n): HTMLElementTagNameMap[TagName] => {\n const el = document.createElement(tagName);\n if (attrs) for (const [key, val] of Object.entries(attrs)) attr(el, key, val);\n return el;\n};\n\n/**\n * customElements.define\n * @description Defines a customElement if running in browser and if not already registered\n * Scoped/named \"customElements.define\" so @custom-elements-manifest/analyzer can find tag names\n */\nexport const customElements = {\n define: (name: string, instance: CustomElementConstructor) =>\n !isBrowser() ||\n window.customElements.get(name) ||\n window.customElements.define(name, instance),\n};\n\n/**\n * useId\n * @return A generated unique ID\n */\ndeclare global {\n interface Window {\n dsUseId?: number; // Use a global counter to ensure this works even when loading designsystemet multiple times\n }\n}\nlet id = 0;\nexport function useId(el?: Element | null) {\n if (!isBrowser()) return `:ds:${++id}`; // Emulate browser environment if window not available\n if (!window.dsUseId) window.dsUseId = 0; // Make sure we have a global to support multiple instances of designsystemet in same page\n if (el && !el.id) el.id = `:ds:${++window.dsUseId}`;\n return el?.id || '';\n}\n\n/**\n * @description Based off speak function from [U-elements](https://github.com/u-elements/u-elements/blob/main/packages/utils.ts#L210)\n * @param text The text to announce\n */\nlet LIVE_EL: HTMLElement | undefined;\nlet LIVE_FIX = 0;\nlet LIVE_CLEAR: ReturnType<typeof setTimeout> | number = 0;\nexport const announce = (text: string) => {\n clearTimeout(LIVE_CLEAR);\n if (LIVE_EL) LIVE_EL.textContent = `${text}${LIVE_FIX++ % 2 ? '\\u00A0' : ''}`; // Non-breaking space to ensure screen reader announces\n if (text) LIVE_CLEAR = setTimeout(announce, 2000, ''); // Clear prevent old announcements being found by screen readers, with 2 seconds brace period to avoid cutting of Android Talkback\n};\n\n// Mount live region on first focus so its ready to be used\nconst announceMount = () => {\n if (document.readyState !== 'complete') return; // Ensure page is loaded trying to avoid issues with React hydration\n if (!LIVE_EL) {\n LIVE_EL = tag('div', { 'aria-live': 'assertive' });\n LIVE_EL.style.overflow = 'hidden'; // Settings styles individually to prevent issues with CSP\n LIVE_EL.style.position = 'fixed';\n LIVE_EL.style.whiteSpace = 'nowrap';\n LIVE_EL.style.width = '1px';\n }\n if (!LIVE_EL.isConnected) document.body.appendChild(LIVE_EL);\n};\nonHotReload('announce', () => [\n on(document, 'focus mouseover', announceMount, QUICK_EVENT),\n]);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","names":[],"sources":["../../../src/utils/utils.ts"],"sourcesContent":["export const ARIA_DESC = 'aria-description';\nexport const ARIA_LABEL = 'aria-label';\nexport const ARIA_LABELLEDBY = 'aria-labelledby';\nexport const QUICK_EVENT = { passive: true, capture: true };\n\nimport { version } from '../../package.json' with { type: 'json' };\n\n// Using function instead of constant to support environments where DOM can be unloaded (like Vitest with jsdom)\nexport const isBrowser = () =>\n typeof window !== 'undefined' && typeof document !== 'undefined';\n\nexport const isWindows = () =>\n isBrowser() &&\n // @ts-expect-error Typescript has not implemented userAgentData yet https://stackoverflow.com/a/71392474\n /^Win/i.test(navigator.userAgentData?.platform || navigator.platform);\n\n// Make sure we have a HTMLElement to extend (for server side rendering)\nexport const DSElement =\n typeof HTMLElement === 'undefined'\n ? (class {} as typeof HTMLElement)\n : HTMLElement;\n\nexport function debounce<T extends unknown[]>(\n callback: (...args: T) => void,\n delay: number,\n) {\n let timer: ReturnType<typeof setTimeout>;\n\n return function (this: unknown, ...args: T) {\n clearTimeout(timer);\n timer = setTimeout(() => callback.apply(this, args), delay);\n };\n}\n\n/**\n * warn\n * @description Utility to console.log, but can be silenced in production with window.dsWarnings = false;\n */\ndeclare global {\n interface Window {\n dsWarnings?: boolean;\n }\n}\nexport const warn = (\n message: string,\n ...args: Parameters<typeof console.log> // Using console.log, not console.warn, to prevent stopping test runners such as Jest\n) =>\n !isBrowser() ||\n window.dsWarnings === false ||\n console.log(`\\x1B[1mDesignsystemet:\\x1B[m ${message}`, ...args);\n\n/**\n * attr\n * @description Utility to quickly get, set and remove attributes\n * @param el The Element to read/write attributes from\n * @param name The attribute name to get, set or remove, or a object to set multiple attributes\n * @param value A valid attribute value or null to remove attribute\n */\nexport const attr = (\n el: Element,\n name: string,\n value?: string | null,\n): string | null => {\n if (value === undefined) return el.getAttribute(name);\n if (value === null) el.removeAttribute(name);\n else if (el.getAttribute(name) !== value) el.setAttribute(name, value);\n return null;\n};\n\n/**\n * getCSSProp\n * @description Retrieves and CSS property value and trims it\n * @param el The Element to read attributes/CSS from\n * @param name Attribute or CSS property to get\n * @return string CSS property value\n */\nexport const getCSSProp = (el: Element, prop: string) =>\n getComputedStyle(el).getPropertyValue(prop).trim();\n\nconst QUOTES_STRIP_SURROUNDING = /^[\"']|[\"']$/g; // Matches surrounding single or double quotes\nconst QUOTES_MATCH = /\\\\([\"'])/g;\n\n/**\n * attrOrCSS\n * @description Retrieves and updates attribute based on attribute or CSS property value\n * @param el The Element to read attributes/CSS from\n * @param name Attribute or CSS property to get\n * @return string attribute or CSS property value\n */\nexport const attrOrCSS = (el: Element, name: string) => {\n let value = attr(el, name);\n if (!value)\n value = getCSSProp(el, `--_ds-${name}`)\n .replace(QUOTES_STRIP_SURROUNDING, '')\n .replace(QUOTES_MATCH, '$1') // Unescape quotes\n .trim();\n return value || null;\n};\n\n/**\n * getRoot\n * @description Helper for better compatibility\n * @param node The target node\n * @return The shadow root or document\n */\nexport const getRoot = (node?: Node | null): Document | ShadowRoot => {\n const root = node?.getRootNode?.() || node?.ownerDocument;\n if (root instanceof Document || root instanceof ShadowRoot) return root;\n return node?.ownerDocument || document;\n};\n\n/**\n * getComposedTarget\n * @description Helper to get the composed target of an event, supporting ShadowDOM rendering\n * @param event The event\n * @return The target Element\n */\nexport const getComposedTarget = (e: Event): Element | null => {\n const el =\n ((e.target as Element)?.shadowRoot && e.composedPath()[0]) || e.target; // Only use composedPath if the target has a shadowRoot to boost performance\n return (el as Node)?.nodeType === 1 ? (el as Element) : null;\n};\n\n/**\n * getComposedPath\n * @description Helper to get the full composed path even if listener is bound to a ShadowRoot (unlike event.composedPath())\n * @param el The element to start traversing from\n * @return Set of nodes in the path\n */\nexport const getComposedPath = (el: Node | null) => {\n const path = new Set<Node>();\n while (el) {\n path.add(el);\n if (el.nodeType === 11) el = (el as ShadowRoot).host;\n else el = (el as Element).assignedSlot || el.parentNode;\n }\n return path;\n};\n\n/**\n * on\n * @param el The Element to use as EventTarget\n * @param types A space separated string of event types\n * @param listener An event listener function or listener object\n */\nexport const on = (\n el: Node | Window | ShadowRoot,\n ...rest: Parameters<typeof Element.prototype.addEventListener>\n): (() => void) => {\n const [types, ...options] = rest;\n for (const type of types.split(' ')) el.addEventListener(type, ...options);\n return () => off(el, ...rest);\n};\n\n/**\n * off\n * @param el The Element to use as EventTarget\n * @param types A space separated string of event types\n * @param listener An event listener function or listener object\n */\nexport const off = (\n el: Node | Window | ShadowRoot,\n ...rest: Parameters<typeof Element.prototype.removeEventListener>\n): void => {\n const [types, ...options] = rest;\n for (const type of types.split(' ')) el.removeEventListener(type, ...options);\n};\n\n// Used to store cleanup functions for hot-reloading\nconst HOT_RELOAD_KEY = `_dsHotReloadCleanup${version}` as const; // Ensure multiple versions of Designsystemet can run on same page\ndeclare global {\n interface Window {\n [HOT_RELOAD_KEY]?: Map<string, Array<() => void>>;\n }\n}\n\n/**\n * onHotReload\n * @description Runs a callback when window is loaded in browser, and ensures cleanup when hot-reloading\n * @param key The key to identify setup and corresponding cleanup\n * @param callback The callback to run when the page is ready\n */\nexport const onHotReload = (key: string, setup: () => Array<() => void>) => {\n if (!isBrowser()) return; // Skip if not in modern browser environment, but on each call as Vitest might have unloaded jsdom between tests\n if (!window[HOT_RELOAD_KEY]) window[HOT_RELOAD_KEY] = new Map(); // Hot reload cleanup support supporting all build tools\n for (const cleanup of window[HOT_RELOAD_KEY]?.get(key) || []) cleanup(); // Run previous cleanup\n window[HOT_RELOAD_KEY]?.set(key, setup()); // Store new cleanup\n};\n\n/**\n * MutationObserver wrapper with automatic cleanup\n * @return new MutaionObserver\n */\nexport const onMutation = <T extends Node>(\n el: T,\n callback: (el: T, records?: MutationRecord[]) => void,\n options: MutationObserverInit,\n) => {\n const cleanup = () => observer.disconnect();\n const observer = new MutationObserver((records) => {\n if (!isBrowser() || !el.isConnected) return cleanup(); // Stop observing if element is removed from DOM or document is removed by jdsom tests\n callback(el, records);\n });\n\n callback(el); // Initial is run instantly to make test markup predictable\n observer.observe(el, options);\n return cleanup;\n};\n\n/**\n * tag\n * @description creates element and assigns properties\n * @param tagName The tagname of element to create\n * @param attrs Optional attributes to add to the element\n * @param text Optional text content to add to the element\n * @return HTMLElement with props\n */\nexport const tag = <TagName extends keyof HTMLElementTagNameMap>(\n tagName: TagName,\n attrs?: Record<string, string | null> | null,\n): HTMLElementTagNameMap[TagName] => {\n const el = document.createElement(tagName);\n if (attrs) for (const [key, val] of Object.entries(attrs)) attr(el, key, val);\n return el;\n};\n\n/**\n * customElements.define\n * @description Defines a customElement if running in browser and if not already registered\n * Scoped/named \"customElements.define\" so @custom-elements-manifest/analyzer can find tag names\n */\nexport const customElements = {\n define: (name: string, instance: CustomElementConstructor) =>\n !isBrowser() ||\n window.customElements.get(name) ||\n window.customElements.define(name, instance),\n};\n\n/**\n * useId\n * @return A generated unique ID\n */\ndeclare global {\n interface Window {\n dsUseId?: number; // Use a global counter to ensure this works even when loading designsystemet multiple times\n }\n}\nlet id = 0;\nexport function useId(el?: Element | null) {\n if (!isBrowser()) return `:ds:${++id}`; // Emulate browser environment if window not available\n if (!window.dsUseId) window.dsUseId = 0; // Make sure we have a global to support multiple instances of designsystemet in same page\n if (el && !el.id) el.id = `:ds:${++window.dsUseId}`;\n return el?.id || '';\n}\n\n/**\n * @description Based off speak function from [U-elements](https://github.com/u-elements/u-elements/blob/main/packages/utils.ts#L210)\n * @param text The text to announce\n */\nlet LIVE_EL: HTMLElement | undefined;\nlet LIVE_FIX = 0;\nlet LIVE_CLEAR: ReturnType<typeof setTimeout> | number = 0;\nexport const announce = (text: string) => {\n clearTimeout(LIVE_CLEAR);\n if (LIVE_EL) LIVE_EL.textContent = `${text}${LIVE_FIX++ % 2 ? '\\u00A0' : ''}`; // Non-breaking space to ensure screen reader announces\n if (text) LIVE_CLEAR = setTimeout(announce, 2000, ''); // Clear prevent old announcements being found by screen readers, with 2 seconds brace period to avoid cutting of Android Talkback\n};\n\n// Mount live region on first focus so its ready to be used\nconst announceMount = () => {\n if (document.readyState !== 'complete') return; // Ensure page is loaded trying to avoid issues with React hydration\n if (!LIVE_EL) {\n LIVE_EL = tag('div', { 'aria-live': 'assertive' });\n LIVE_EL.style.overflow = 'hidden'; // Settings styles individually to prevent issues with CSP\n LIVE_EL.style.position = 'fixed';\n LIVE_EL.style.whiteSpace = 'nowrap';\n LIVE_EL.style.width = '1px';\n }\n if (!LIVE_EL.isConnected) document.body.appendChild(LIVE_EL);\n};\nonHotReload('announce', () => [\n on(document, 'focus mouseover', announceMount, QUICK_EVENT),\n]);\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import type * as PreactTypes from 'preact'
|
|
2
|
+
import type * as ReactTypes from 'react'
|
|
3
|
+
import type * as SvelteTypes from 'svelte/elements'
|
|
4
|
+
import type * as VueJSX from '@vue/runtime-dom'
|
|
5
|
+
import type { JSX as QwikJSX } from '@builder.io/qwik/jsx-runtime'
|
|
6
|
+
import type { JSX as SolidJSX } from 'solid-js'
|
|
1
7
|
import "@u-elements/u-details/polyfill";
|
|
2
8
|
import { UHTMLComboboxElement } from "@u-elements/u-combobox";
|
|
3
9
|
import * as UTabs from "@u-elements/u-tabs";
|
|
@@ -157,7 +163,6 @@ declare class DSTabPanelElement extends UTabs.UHTMLTabPanelElement {}
|
|
|
157
163
|
//#endregion
|
|
158
164
|
export { DSBreadcrumbsElement, DSErrorSummaryElement, DSFieldElement, DSPaginationElement, DSSuggestionElement, DSTabElement, DSTabListElement, DSTabPanelElement, DSTabsElement, initTooltips, pagination, setTooltipElement };
|
|
159
165
|
|
|
160
|
-
|
|
161
166
|
export type PreactDstabs = PreactTypes.JSX.HTMLAttributes<DSTabsElement> & { }
|
|
162
167
|
export type ReactDstabs = ReactTypes.DetailedHTMLProps<ReactTypes.HTMLAttributes<DSTabsElement>, DSTabsElement> & { class?: string }
|
|
163
168
|
export type QwikDstabs = QwikJSX.IntrinsicElements['div'] & { class?: string }
|
|
@@ -235,7 +240,6 @@ declare module 'solid-js' {
|
|
|
235
240
|
}
|
|
236
241
|
}
|
|
237
242
|
|
|
238
|
-
|
|
239
243
|
export type PreactDssuggestion = PreactTypes.JSX.HTMLAttributes<DSSuggestionElement> & { }
|
|
240
244
|
export type ReactDssuggestion = ReactTypes.DetailedHTMLProps<ReactTypes.HTMLAttributes<DSSuggestionElement>, DSSuggestionElement> & { class?: string }
|
|
241
245
|
export type QwikDssuggestion = QwikJSX.IntrinsicElements['div'] & { class?: string }
|
|
@@ -256,7 +260,6 @@ declare module 'solid-js' {
|
|
|
256
260
|
}
|
|
257
261
|
}
|
|
258
262
|
|
|
259
|
-
|
|
260
263
|
export type PreactDspagination = PreactTypes.JSX.HTMLAttributes<DSPaginationElement> & { }
|
|
261
264
|
export type ReactDspagination = ReactTypes.DetailedHTMLProps<ReactTypes.HTMLAttributes<DSPaginationElement>, DSPaginationElement> & { class?: string }
|
|
262
265
|
export type QwikDspagination = QwikJSX.IntrinsicElements['div'] & { class?: string }
|
|
@@ -277,7 +280,6 @@ declare module 'solid-js' {
|
|
|
277
280
|
}
|
|
278
281
|
}
|
|
279
282
|
|
|
280
|
-
|
|
281
283
|
export type PreactDsfield = PreactTypes.JSX.HTMLAttributes<DSFieldElement> & { }
|
|
282
284
|
export type ReactDsfield = ReactTypes.DetailedHTMLProps<ReactTypes.HTMLAttributes<DSFieldElement>, DSFieldElement> & { class?: string }
|
|
283
285
|
export type QwikDsfield = QwikJSX.IntrinsicElements['div'] & { class?: string }
|
|
@@ -298,7 +300,6 @@ declare module 'solid-js' {
|
|
|
298
300
|
}
|
|
299
301
|
}
|
|
300
302
|
|
|
301
|
-
|
|
302
303
|
export type PreactDserrorsummary = PreactTypes.JSX.HTMLAttributes<DSErrorSummaryElement> & { }
|
|
303
304
|
export type ReactDserrorsummary = ReactTypes.DetailedHTMLProps<ReactTypes.HTMLAttributes<DSErrorSummaryElement>, DSErrorSummaryElement> & { class?: string }
|
|
304
305
|
export type QwikDserrorsummary = QwikJSX.IntrinsicElements['div'] & { class?: string }
|
|
@@ -319,7 +320,6 @@ declare module 'solid-js' {
|
|
|
319
320
|
}
|
|
320
321
|
}
|
|
321
322
|
|
|
322
|
-
|
|
323
323
|
export type PreactDsbreadcrumbs = PreactTypes.JSX.HTMLAttributes<DSBreadcrumbsElement> & { }
|
|
324
324
|
export type ReactDsbreadcrumbs = ReactTypes.DetailedHTMLProps<ReactTypes.HTMLAttributes<DSBreadcrumbsElement>, DSBreadcrumbsElement> & { class?: string }
|
|
325
325
|
export type QwikDsbreadcrumbs = QwikJSX.IntrinsicElements['div'] & { class?: string }
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { UHTMLComboboxElement } from "@u-elements/u-combobox";
|
|
|
4
4
|
import * as UTabs from "@u-elements/u-tabs";
|
|
5
5
|
export * from "@u-elements/u-datalist";
|
|
6
6
|
//#region package.json
|
|
7
|
-
var version = "1.
|
|
7
|
+
var version = "1.22.0";
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/utils/utils.ts
|
|
10
10
|
const ARIA_DESC = "aria-description";
|
|
@@ -46,7 +46,8 @@ const attr = (el, name, value) => {
|
|
|
46
46
|
* @return string CSS property value
|
|
47
47
|
*/
|
|
48
48
|
const getCSSProp = (el, prop) => getComputedStyle(el).getPropertyValue(prop).trim();
|
|
49
|
-
const
|
|
49
|
+
const QUOTES_STRIP_SURROUNDING = /^["']|["']$/g;
|
|
50
|
+
const QUOTES_MATCH = /\\(["'])/g;
|
|
50
51
|
/**
|
|
51
52
|
* attrOrCSS
|
|
52
53
|
* @description Retrieves and updates attribute based on attribute or CSS property value
|
|
@@ -56,7 +57,7 @@ const STRIP_QUOTES = /^["']|["']$/g;
|
|
|
56
57
|
*/
|
|
57
58
|
const attrOrCSS = (el, name) => {
|
|
58
59
|
let value = attr(el, name);
|
|
59
|
-
if (!value) value = getCSSProp(el, `--_ds-${name}`).replace(
|
|
60
|
+
if (!value) value = getCSSProp(el, `--_ds-${name}`).replace(QUOTES_STRIP_SURROUNDING, "").replace(QUOTES_MATCH, "$1").trim();
|
|
60
61
|
return value || null;
|
|
61
62
|
};
|
|
62
63
|
/**
|
|
@@ -373,7 +374,10 @@ const handleKeydown$2 = (e) => {
|
|
|
373
374
|
if (!group?.role) return;
|
|
374
375
|
const items = getItems(group.el, target);
|
|
375
376
|
let next = 0;
|
|
376
|
-
if (isTab)
|
|
377
|
+
if (isTab) {
|
|
378
|
+
const others = items.filter((item) => item !== target);
|
|
379
|
+
return setTimeout(setTab, 0, others, setTab(others));
|
|
380
|
+
}
|
|
377
381
|
if (e.key === "Home") next = 0;
|
|
378
382
|
else if (e.key === "End") next = items.length - 1;
|
|
379
383
|
else {
|
|
@@ -699,7 +703,7 @@ function apply$1() {
|
|
|
699
703
|
//#region src/invokers/invokers.ts
|
|
700
704
|
if (isBrowser() && !isSupported$1()) apply$1();
|
|
701
705
|
//#endregion
|
|
702
|
-
//#region ../../node_modules/.pnpm/@oddbird+popover-polyfill@0.7.
|
|
706
|
+
//#region ../../node_modules/.pnpm/@oddbird+popover-polyfill@0.7.2/node_modules/@oddbird/popover-polyfill/dist/popover-fn.js
|
|
703
707
|
var ToggleEvent = class extends Event {
|
|
704
708
|
oldState;
|
|
705
709
|
newState;
|
|
@@ -1010,7 +1014,7 @@ function lightDismissOpenPopovers(event) {
|
|
|
1010
1014
|
if (!event.isTrusted) return;
|
|
1011
1015
|
const target = event.composedPath()[0];
|
|
1012
1016
|
if (!target) return;
|
|
1013
|
-
const document2 = target.ownerDocument;
|
|
1017
|
+
const document2 = target.ownerDocument || target;
|
|
1014
1018
|
if (!topmostAutoOrHintPopover(document2)) return;
|
|
1015
1019
|
const ancestor = topMostClickedPopover(target);
|
|
1016
1020
|
if (ancestor && event.type === "pointerdown") popoverPointerDownTargets.set(document2, ancestor);
|
|
@@ -1054,7 +1058,7 @@ function hasLayerSupport() {
|
|
|
1054
1058
|
function getStyles(layerName) {
|
|
1055
1059
|
var _a;
|
|
1056
1060
|
const useLayer = hasLayerSupport();
|
|
1057
|
-
const layerNameEscaped = (layerName ?? ((_a = window.POPOVER_POLYFILL_OPTIONS) == null ? void 0 : _a.layerName) ?? DEFAULT_LAYER_NAME).split(".").map((
|
|
1061
|
+
const layerNameEscaped = (layerName ?? ((_a = window.POPOVER_POLYFILL_OPTIONS) == null ? void 0 : _a.layerName) ?? DEFAULT_LAYER_NAME).split(".").map((css) => CSS.escape(css)).join(".");
|
|
1058
1062
|
return `
|
|
1059
1063
|
${useLayer ? `@layer ${layerNameEscaped} {` : ""}
|
|
1060
1064
|
:where([popover]) {
|
|
@@ -1581,7 +1585,7 @@ const setupText = (el, canAnnounce = true) => {
|
|
|
1581
1585
|
attr(el, ATTR_TOOLTIP, text);
|
|
1582
1586
|
attr(el, ARIA_LABEL, hasText ? null : text);
|
|
1583
1587
|
attr(el, ARIA_DESC, hasText ? text : null);
|
|
1584
|
-
if (el.tabIndex === -1) warn("Missing tabindex=\"0\" attribute on: ", el);
|
|
1588
|
+
if (el.tabIndex === -1 && !el.hasAttribute("tabindex") && el.nodeName !== "LABEL") warn("Missing tabindex=\"0\" attribute on: ", el);
|
|
1585
1589
|
}
|
|
1586
1590
|
if (el === OPEN && TIP?.textContent !== text) {
|
|
1587
1591
|
if (TIP) TIP.textContent = text;
|
|
@@ -1775,7 +1779,7 @@ const handleFieldMutation = (field) => {
|
|
|
1775
1779
|
}
|
|
1776
1780
|
field.handleEvent();
|
|
1777
1781
|
};
|
|
1778
|
-
const TEXTS = {
|
|
1782
|
+
const TEXTS$1 = {
|
|
1779
1783
|
over: "%d tegn for mye",
|
|
1780
1784
|
under: "%d tegn igjen"
|
|
1781
1785
|
};
|
|
@@ -1815,7 +1819,7 @@ var DSFieldElement = class extends DSElement {
|
|
|
1815
1819
|
if (_counter?.isConnected && _input) {
|
|
1816
1820
|
const count = (Number(attr(_counter, ATTR_LIMIT)) || 0) - _input.value.length;
|
|
1817
1821
|
const state = count < 0 ? "over" : "under";
|
|
1818
|
-
const label = (attrOrCSS(_counter, `data-${state}`) || TEXTS[state])?.replace("%d", `${Math.abs(count)}`);
|
|
1822
|
+
const label = (attrOrCSS(_counter, `data-${state}`) || TEXTS$1[state])?.replace("%d", `${Math.abs(count)}`);
|
|
1819
1823
|
if (!label) warn(`Missing data-${state} on:`, _counter);
|
|
1820
1824
|
attr(_counter, "data-label", label);
|
|
1821
1825
|
attr(_counter, "data-state", state);
|
|
@@ -1922,53 +1926,65 @@ customElements.define("ds-pagination", DSPaginationElement);
|
|
|
1922
1926
|
//#region src/suggestion/suggestion.ts
|
|
1923
1927
|
const ATTR_EMPTY = "data-empty";
|
|
1924
1928
|
const ATTR_CREATE = "data-create";
|
|
1929
|
+
const EVENTS_EMPTY = "comboboxafterselect comboboxprogrammaticinput input";
|
|
1930
|
+
const REGEX_CREATE = /\{value\}|%s/;
|
|
1931
|
+
const SINGULAR = "data-sr-singular";
|
|
1932
|
+
const PLURAL = "data-sr-plural";
|
|
1933
|
+
const TEXTS = "added,clear,empty,found,invalid,items,of,plural,remove,removed,singular,toggle".split(",").map((key) => `data-sr-${key}`);
|
|
1925
1934
|
var DSSuggestionElement = class extends UHTMLComboboxElement {
|
|
1926
1935
|
_unmutate;
|
|
1927
1936
|
connectedCallback() {
|
|
1937
|
+
for (const key of TEXTS) attr(this, key, attrOrCSS(this, key));
|
|
1928
1938
|
super.connectedCallback();
|
|
1929
1939
|
this._unmutate = onMutation(this, render, { childList: true });
|
|
1930
|
-
on(this,
|
|
1940
|
+
on(this, EVENTS_EMPTY, handleEmpty, QUICK_EVENT);
|
|
1931
1941
|
on(this, "toggle", polyfillToggleSource, QUICK_EVENT);
|
|
1932
1942
|
}
|
|
1933
1943
|
disconnectedCallback() {
|
|
1934
1944
|
super.disconnectedCallback();
|
|
1935
1945
|
this._unmutate?.();
|
|
1936
1946
|
this._unmutate = void 0;
|
|
1937
|
-
off(this,
|
|
1947
|
+
off(this, EVENTS_EMPTY, handleEmpty, QUICK_EVENT);
|
|
1938
1948
|
off(this, "toggle", polyfillToggleSource, QUICK_EVENT);
|
|
1939
1949
|
}
|
|
1940
1950
|
};
|
|
1941
1951
|
const render = (self) => {
|
|
1942
|
-
|
|
1943
|
-
|
|
1952
|
+
let { control, list } = self;
|
|
1953
|
+
if (!list) list = self.querySelector("u-datalist");
|
|
1944
1954
|
if (control) attr(control, "popovertarget", list ? useId(list) : null);
|
|
1945
|
-
if (
|
|
1946
|
-
attr(
|
|
1947
|
-
attr(
|
|
1955
|
+
if (list) {
|
|
1956
|
+
if (!attr(list, PLURAL)) attr(list, PLURAL, attr(self, PLURAL));
|
|
1957
|
+
if (!attr(list, SINGULAR)) attr(list, SINGULAR, attr(self, SINGULAR));
|
|
1958
|
+
attr(list, "data-is-floating", "true");
|
|
1959
|
+
attr(list, "popover", "manual");
|
|
1948
1960
|
}
|
|
1949
1961
|
handleEmpty({ currentTarget: self });
|
|
1950
1962
|
};
|
|
1951
1963
|
const handleEmpty = ({ currentTarget: self }) => {
|
|
1952
|
-
const { creatable, control, options } = self;
|
|
1964
|
+
const { creatable, control, options, values } = self;
|
|
1953
1965
|
if (!options) return;
|
|
1954
1966
|
const value = control?.value.trim() || "";
|
|
1955
1967
|
const query = value.toLowerCase();
|
|
1956
|
-
let
|
|
1957
|
-
let
|
|
1968
|
+
let emptyOp;
|
|
1969
|
+
let hasMatch = false;
|
|
1958
1970
|
for (const opt of options) {
|
|
1959
|
-
if (!
|
|
1960
|
-
else if (!
|
|
1961
|
-
if (
|
|
1962
|
-
}
|
|
1963
|
-
if (!
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
if (
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1971
|
+
if (!emptyOp && opt.hasAttribute(ATTR_EMPTY)) emptyOp = opt;
|
|
1972
|
+
else if (!hasMatch && (!query || opt.label?.toLowerCase() === query)) hasMatch = true;
|
|
1973
|
+
if (hasMatch && emptyOp) break;
|
|
1974
|
+
}
|
|
1975
|
+
if (!emptyOp) return;
|
|
1976
|
+
emptyOp.hidden = hasMatch;
|
|
1977
|
+
attr(emptyOp, "label", value);
|
|
1978
|
+
attr(emptyOp, "value", creatable ? value : "");
|
|
1979
|
+
if (creatable) {
|
|
1980
|
+
const found = values.some((val) => val === value);
|
|
1981
|
+
const text = attrOrCSS(emptyOp, ATTR_EMPTY);
|
|
1982
|
+
const hint = !found && text?.replace(REGEX_CREATE, () => value) || value;
|
|
1983
|
+
if (!text) warn(`Missing ${ATTR_EMPTY} value on:`, emptyOp);
|
|
1984
|
+
else attr(emptyOp, ATTR_EMPTY, text);
|
|
1985
|
+
attr(emptyOp, "disabled", found && emptyOp.textContent ? "true" : null);
|
|
1986
|
+
attr(emptyOp, ATTR_CREATE, hint);
|
|
1987
|
+
}
|
|
1972
1988
|
};
|
|
1973
1989
|
const polyfillToggleSource = (event) => {
|
|
1974
1990
|
const self = event.currentTarget;
|