@digdir/designsystemet-web 0.0.1

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.
Files changed (88) hide show
  1. package/README.md +21 -0
  2. package/dist/cjs/_virtual/rolldown_runtime.cjs +29 -0
  3. package/dist/cjs/breadcrumbs.cjs +50 -0
  4. package/dist/cjs/breadcrumbs.cjs.map +1 -0
  5. package/dist/cjs/clickdelegatefor.cjs +35 -0
  6. package/dist/cjs/clickdelegatefor.cjs.map +1 -0
  7. package/dist/cjs/details.cjs +21 -0
  8. package/dist/cjs/details.cjs.map +1 -0
  9. package/dist/cjs/dialog.cjs +18 -0
  10. package/dist/cjs/dialog.cjs.map +1 -0
  11. package/dist/cjs/error-summary.cjs +24 -0
  12. package/dist/cjs/error-summary.cjs.map +1 -0
  13. package/dist/cjs/field.cjs +115 -0
  14. package/dist/cjs/field.cjs.map +1 -0
  15. package/dist/cjs/index.cjs +37 -0
  16. package/dist/cjs/index.cjs.map +1 -0
  17. package/dist/cjs/pagination.cjs +72 -0
  18. package/dist/cjs/pagination.cjs.map +1 -0
  19. package/dist/cjs/popover.cjs +89 -0
  20. package/dist/cjs/popover.cjs.map +1 -0
  21. package/dist/cjs/suggestion.cjs +24 -0
  22. package/dist/cjs/suggestion.cjs.map +1 -0
  23. package/dist/cjs/tabs.cjs +21 -0
  24. package/dist/cjs/tabs.cjs.map +1 -0
  25. package/dist/cjs/toggle-group.cjs +29 -0
  26. package/dist/cjs/toggle-group.cjs.map +1 -0
  27. package/dist/cjs/tooltip.cjs +55 -0
  28. package/dist/cjs/tooltip.cjs.map +1 -0
  29. package/dist/cjs/utils.cjs +159 -0
  30. package/dist/cjs/utils.cjs.map +1 -0
  31. package/dist/esm/breadcrumbs.js +50 -0
  32. package/dist/esm/breadcrumbs.js.map +1 -0
  33. package/dist/esm/clickdelegatefor.js +35 -0
  34. package/dist/esm/clickdelegatefor.js.map +1 -0
  35. package/dist/esm/details.js +21 -0
  36. package/dist/esm/details.js.map +1 -0
  37. package/dist/esm/dialog.js +18 -0
  38. package/dist/esm/dialog.js.map +1 -0
  39. package/dist/esm/error-summary.js +24 -0
  40. package/dist/esm/error-summary.js.map +1 -0
  41. package/dist/esm/field.js +115 -0
  42. package/dist/esm/field.js.map +1 -0
  43. package/dist/esm/index.js +22 -0
  44. package/dist/esm/index.js.map +1 -0
  45. package/dist/esm/pagination.js +71 -0
  46. package/dist/esm/pagination.js.map +1 -0
  47. package/dist/esm/popover.js +88 -0
  48. package/dist/esm/popover.js.map +1 -0
  49. package/dist/esm/src/breadcrumbs.d.ts +16 -0
  50. package/dist/esm/src/breadcrumbs.d.ts.map +1 -0
  51. package/dist/esm/src/clickdelegatefor.d.ts +2 -0
  52. package/dist/esm/src/clickdelegatefor.d.ts.map +1 -0
  53. package/dist/esm/src/details.d.ts +2 -0
  54. package/dist/esm/src/details.d.ts.map +1 -0
  55. package/dist/esm/src/dialog.d.ts +2 -0
  56. package/dist/esm/src/dialog.d.ts.map +1 -0
  57. package/dist/esm/src/error-summary.d.ts +12 -0
  58. package/dist/esm/src/error-summary.d.ts.map +1 -0
  59. package/dist/esm/src/field.d.ts +15 -0
  60. package/dist/esm/src/field.d.ts.map +1 -0
  61. package/dist/esm/src/index.d.ts +14 -0
  62. package/dist/esm/src/index.d.ts.map +1 -0
  63. package/dist/esm/src/pagination.d.ts +27 -0
  64. package/dist/esm/src/pagination.d.ts.map +1 -0
  65. package/dist/esm/src/popover.d.ts +2 -0
  66. package/dist/esm/src/popover.d.ts.map +1 -0
  67. package/dist/esm/src/suggestion.d.ts +11 -0
  68. package/dist/esm/src/suggestion.d.ts.map +1 -0
  69. package/dist/esm/src/tabs.d.ts +18 -0
  70. package/dist/esm/src/tabs.d.ts.map +1 -0
  71. package/dist/esm/src/toggle-group.d.ts +2 -0
  72. package/dist/esm/src/toggle-group.d.ts.map +1 -0
  73. package/dist/esm/src/tooltip.d.ts +2 -0
  74. package/dist/esm/src/tooltip.d.ts.map +1 -0
  75. package/dist/esm/src/utils.d.ts +78 -0
  76. package/dist/esm/src/utils.d.ts.map +1 -0
  77. package/dist/esm/suggestion.js +23 -0
  78. package/dist/esm/suggestion.js.map +1 -0
  79. package/dist/esm/tabs.js +16 -0
  80. package/dist/esm/tabs.js.map +1 -0
  81. package/dist/esm/toggle-group.js +29 -0
  82. package/dist/esm/toggle-group.js.map +1 -0
  83. package/dist/esm/tooltip.js +55 -0
  84. package/dist/esm/tooltip.js.map +1 -0
  85. package/dist/esm/tsconfig.tsbuildinfo +1 -0
  86. package/dist/esm/utils.js +145 -0
  87. package/dist/esm/utils.js.map +1 -0
  88. package/package.json +47 -0
@@ -0,0 +1,115 @@
1
+ import { DSElement, QUICK_EVENT, attr, customElements, debounce, isBrowser, isWindows, off, on, onHotReload, onMutation, tag, useId } from "./utils.js";
2
+
3
+ //#region src/field.ts
4
+ const CSS_FIELD_SIZE = "--_ds-field-sizing";
5
+ const ATTR_COUNTER_TEXT = "data-counter-text";
6
+ const ATTR_COUNTER_ARIA = "data-counter-aria";
7
+ const ATTR_FIELD = "data-field";
8
+ const TYPE_DESCRIPTION = "description";
9
+ const TYPE_VALIDATION = "validation";
10
+ const COUNTER_DEBOUNCE = isWindows() ? 800 : 200;
11
+ const COUNTER_TEXT = {
12
+ over: "%d tegn for mye",
13
+ under: "%d tegn for mye",
14
+ hint: "Maks %d tegn tillatt."
15
+ };
16
+ const SELECTOR_FIELDSET_DESCRIPTION = `:scope > [${ATTR_FIELD}="${TYPE_DESCRIPTION}"],:scope > legend + p`;
17
+ const SELECTOR_FIELDSET_VALIDATION = `:scope > [${ATTR_FIELD}="${TYPE_VALIDATION}"]`;
18
+ const SELECTOR_FIELD_COUNTER = "[data-field=\"counter\"]";
19
+ const FIELDS = /* @__PURE__ */ new Set();
20
+ const FILEDSETS = isBrowser() ? document.getElementsByTagName("fieldset") : [];
21
+ const STYLE_SR_ONLY = `position:absolute;clip:rect(0 0 0 0);overflow:hidden;width:1px;height:1px;white-space:nowrap;pointer-events:none`;
22
+ const handleMutations = debounce(() => {
23
+ setupFieldsets();
24
+ setupFields();
25
+ }, 100);
26
+ const setupFieldsets = () => {
27
+ for (const fieldset of FILEDSETS) attr(fieldset, "aria-labelledby", [fieldset.querySelector("legend"), fieldset.querySelector(SELECTOR_FIELDSET_DESCRIPTION)].filter(isNotHidden).map(useId).join(" "));
28
+ };
29
+ const setupFields = () => {
30
+ for (const field of FIELDS) {
31
+ const descs = [];
32
+ const labels = [];
33
+ let input;
34
+ for (const el of field.getElementsByTagName("*")) if (el instanceof HTMLLabelElement) labels.push(el);
35
+ else if (isInputLike(el)) {
36
+ if (input) console.warn(`Designsystemet: Fields should only have one input element. Use <fieldset> to group multiple fields:`, field);
37
+ input = el;
38
+ } else if (isNotHidden(el)) {
39
+ const type = el.getAttribute(ATTR_FIELD);
40
+ if (type === TYPE_VALIDATION) descs.unshift(el);
41
+ else if (type) descs.push(el);
42
+ }
43
+ if (!input) console.warn(`Designsystemet: Field is missing input element:`, field);
44
+ else {
45
+ for (const label of labels) attr(label, "for", useId(input));
46
+ const isBoolish = input.type === "radio" || input.type === "checkbox";
47
+ const fieldsetValidation = field.closest("fieldset")?.querySelector(SELECTOR_FIELDSET_VALIDATION);
48
+ if (isNotHidden(fieldsetValidation)) descs.unshift(fieldsetValidation);
49
+ field.handleEvent({ target: input });
50
+ attr(field, "data-clickdelegatefor", isBoolish ? useId(input) : null);
51
+ attr(input, "aria-describedby", descs.map(useId).join(" "));
52
+ attr(input, "aria-invalid", `${descs.some(isInvalid)}`);
53
+ }
54
+ }
55
+ };
56
+ const getCounterText = (el, key, num) => (attr(el, `data-${key}`) || COUNTER_TEXT[key]).replace("%d", `${Math.abs(num)}`);
57
+ const setupCounter = (field, target) => {
58
+ const el = isInputLike(target) && field.querySelector(SELECTOR_FIELD_COUNTER);
59
+ if (el) {
60
+ const live = field.shadowRoot?.lastElementChild;
61
+ const limit = Number(attr(el, "data-limit")) || 0;
62
+ const count = limit - target.value.length;
63
+ const text = getCounterText(el, count < 0 ? "over" : "under", count);
64
+ attr(el, ATTR_COUNTER_TEXT, text);
65
+ attr(el, ATTR_COUNTER_ARIA, getCounterText(el, "hint", limit));
66
+ attr(el, "data-color", count < 0 ? "danger" : null);
67
+ setupCounterLiveRegion(live, text);
68
+ }
69
+ };
70
+ const setupCounterLiveRegion = debounce((live, text) => {
71
+ live.textContent = text;
72
+ }, COUNTER_DEBOUNCE);
73
+ const setupTextareaFieldSizingiOS = (target) => {
74
+ if (target instanceof HTMLTextAreaElement) {
75
+ target.style.setProperty(CSS_FIELD_SIZE, "auto");
76
+ target.style.setProperty(CSS_FIELD_SIZE, `${target.scrollHeight}px`);
77
+ }
78
+ };
79
+ const isInputLike = (el) => el instanceof HTMLElement && "validity" in el && !(el instanceof HTMLButtonElement);
80
+ const isNotHidden = (el) => !!el && !el.hidden;
81
+ const isInvalid = (el) => el.getAttribute(ATTR_FIELD) === TYPE_VALIDATION && attr(el, "data-color") !== "success";
82
+ var DSFieldElement = class extends DSElement {
83
+ constructor() {
84
+ super();
85
+ this.attachShadow({ mode: "open" }).append(tag("slot"), tag("div", {
86
+ "aria-live": "polite",
87
+ style: STYLE_SR_ONLY
88
+ }));
89
+ }
90
+ connectedCallback() {
91
+ FIELDS.add(this);
92
+ on(this, "input", this, QUICK_EVENT);
93
+ handleMutations();
94
+ }
95
+ handleEvent({ target }) {
96
+ setupCounter(this, target);
97
+ setupTextareaFieldSizingiOS(target);
98
+ }
99
+ disconnectedCallback() {
100
+ off(this, "input", this, QUICK_EVENT);
101
+ FIELDS.delete(this);
102
+ }
103
+ };
104
+ customElements.define("ds-field", DSFieldElement);
105
+ onHotReload("field", () => [onMutation(document, handleMutations, {
106
+ debounce: false,
107
+ attributeFilter: ["hidden", ATTR_FIELD],
108
+ attributes: true,
109
+ childList: true,
110
+ subtree: true
111
+ })]);
112
+
113
+ //#endregion
114
+ export { DSFieldElement };
115
+ //# sourceMappingURL=field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field.js","names":[],"sources":["../../src/field.ts"],"sourcesContent":["import {\r\n attr,\r\n customElements,\r\n DSElement,\r\n debounce,\r\n isBrowser,\r\n off,\r\n on,\r\n onHotReload,\r\n onMutation,\r\n QUICK_EVENT,\r\n tag,\r\n useId,\r\n isWindows,\r\n} from './utils';\r\n\r\ndeclare global {\r\n interface HTMLElementTagNameMap {\r\n 'ds-field': DSFieldElement;\r\n }\r\n}\r\n\r\nconst CSS_FIELD_SIZE = '--_ds-field-sizing';\r\nconst ATTR_COUNTER_TEXT = 'data-counter-text';\r\nconst ATTR_COUNTER_ARIA = 'data-counter-aria';\r\nconst ATTR_FIELD = 'data-field';\r\nconst TYPE_DESCRIPTION = 'description';\r\nconst TYPE_VALIDATION = 'validation';\r\nconst COUNTER_DEBOUNCE = isWindows() ? 800 : 200; // Longer debounce on Windows due to NVDA performance\r\nconst COUNTER_TEXT = {\r\n over: '%d tegn for mye',\r\n under: '%d tegn for mye',\r\n hint: 'Maks %d tegn tillatt.',\r\n};\r\n\r\nconst SELECTOR_FIELDSET_DESCRIPTION = `:scope > [${ATTR_FIELD}=\"${TYPE_DESCRIPTION}\"],:scope > legend + p`; // legend + p is kept for backwards compatibility\r\nconst SELECTOR_FIELDSET_VALIDATION = `:scope > [${ATTR_FIELD}=\"${TYPE_VALIDATION}\"]`;\r\nconst SELECTOR_FIELD_COUNTER = '[data-field=\"counter\"]';\r\n\r\nconst FIELDS = new Set<DSFieldElement>();\r\nconst FILEDSETS = isBrowser() ? document.getElementsByTagName('fieldset') : [];\r\nconst STYLE_SR_ONLY = `position:absolute;clip:rect(0 0 0 0);overflow:hidden;width:1px;height:1px;white-space:nowrap;pointer-events:none`;\r\n\r\n// TODO: Document that Validation must be hidden with \"hidden\" attribute (or completely removed from DOM), not display: none\r\nconst handleMutations = debounce(() => {\r\n setupFieldsets();\r\n setupFields();\r\n}, 100); // Debounce to avoid excessive calculations on multiple mutations\r\n\r\n// Connect fieldset legend and descriptions\r\nconst setupFieldsets = () => {\r\n for (const fieldset of FILEDSETS) {\r\n const labelledby = [\r\n fieldset.querySelector('legend'),\r\n fieldset.querySelector(SELECTOR_FIELDSET_DESCRIPTION),\r\n ].filter(isNotHidden);\r\n\r\n attr(fieldset, 'aria-labelledby', labelledby.map(useId).join(' '));\r\n }\r\n};\r\n\r\nconst setupFields = () => {\r\n for (const field of FIELDS) {\r\n const descs: Element[] = [];\r\n const labels: HTMLLabelElement[] = [];\r\n let input: HTMLInputElement | undefined;\r\n\r\n for (const el of field.getElementsByTagName('*')) {\r\n if (el instanceof HTMLLabelElement) labels.push(el);\r\n else if (isInputLike(el)) {\r\n if (input)\r\n console.warn(\r\n `Designsystemet: Fields should only have one input element. Use <fieldset> to group multiple fields:`,\r\n field,\r\n );\r\n input = el;\r\n } else if (isNotHidden(el)) {\r\n const type = el.getAttribute(ATTR_FIELD); // Using getAttribute not attr for best performance\r\n if (type === TYPE_VALIDATION) descs.unshift(el);\r\n else if (type) descs.push(el);\r\n }\r\n }\r\n\r\n if (!input)\r\n console.warn(`Designsystemet: Field is missing input element:`, field);\r\n else {\r\n for (const label of labels) attr(label, 'for', useId(input));\r\n\r\n const isBoolish = input.type === 'radio' || input.type === 'checkbox';\r\n const fieldsetValidation = field\r\n .closest('fieldset')\r\n ?.querySelector(SELECTOR_FIELDSET_VALIDATION);\r\n if (isNotHidden(fieldsetValidation)) descs.unshift(fieldsetValidation);\r\n\r\n field.handleEvent({ target: input }); // Run counter and textrarea resize\r\n attr(field, 'data-clickdelegatefor', isBoolish ? useId(input) : null); // Expand click area to ds-field if radio/checkbox\r\n attr(input, 'aria-describedby', descs.map(useId).join(' '));\r\n attr(input, 'aria-invalid', `${descs.some(isInvalid)}`);\r\n }\r\n }\r\n};\r\n\r\nconst getCounterText = (el: Element, key: keyof typeof COUNTER_TEXT, num: number) =>\r\n (attr(el, `data-${key}`) || COUNTER_TEXT[key]).replace('%d', `${Math.abs(num)}`);\r\n\r\nconst setupCounter = (field: DSFieldElement, target: EventTarget | null) => {\r\n const el =\r\n isInputLike(target) &&\r\n field.querySelector<HTMLElement>(SELECTOR_FIELD_COUNTER);\r\n\r\n if (el) {\r\n const live = field.shadowRoot?.lastElementChild as HTMLElement;\r\n const limit = Number(attr(el, 'data-limit')) || 0;\r\n const count = limit - target.value.length;\r\n const text = getCounterText(el, count < 0 ? 'over' : 'under', count);\r\n\r\n attr(el, ATTR_COUNTER_TEXT, text);\r\n attr(el, ATTR_COUNTER_ARIA, getCounterText(el, 'hint', limit));\r\n attr(el, 'data-color', count < 0 ? 'danger' : null);\r\n setupCounterLiveRegion(live, text); // Debounce live region to avoid NVDA interupting announcing typed text\r\n }\r\n};\r\n\r\nconst setupCounterLiveRegion = debounce((live: Element, text: string) => {\r\n live.textContent = text;\r\n}, COUNTER_DEBOUNCE);\r\n\r\n// iOS does not support field-sizing: content, so we need to manually resize\r\nconst setupTextareaFieldSizingiOS = (target: EventTarget | null) => {\r\n if (target instanceof HTMLTextAreaElement) {\r\n target.style.setProperty(CSS_FIELD_SIZE, 'auto');\r\n target.style.setProperty(CSS_FIELD_SIZE, `${target.scrollHeight}px`);\r\n }\r\n};\r\n\r\nconst isInputLike = (el: unknown): el is HTMLInputElement =>\r\n el instanceof HTMLElement &&\r\n 'validity' in el && // Adds support for custom elements implemeted with attachInternals()\r\n !(el instanceof HTMLButtonElement); // But skip <button> elements\r\n\r\nconst isNotHidden = (el?: Element | null): el is Element =>\r\n !!el && !(el as HTMLElement).hidden;\r\n\r\nconst isInvalid = (el: Element): boolean =>\r\n el.getAttribute(ATTR_FIELD) === TYPE_VALIDATION &&\r\n attr(el, 'data-color') !== 'success';\r\n\r\n// Custom element is used to performantly keep track of fields on the page\r\nexport class DSFieldElement extends DSElement {\r\n constructor() {\r\n super();\r\n this.attachShadow({ mode: 'open' }).append(\r\n tag('slot'),\r\n tag('div', { 'aria-live': 'polite', style: STYLE_SR_ONLY }), // Used to announce counter updates\r\n );\r\n }\r\n connectedCallback() {\r\n FIELDS.add(this);\r\n on(this, 'input', this, QUICK_EVENT);\r\n handleMutations(); // Initial setup\r\n }\r\n handleEvent({ target }: { target: EventTarget | null }) {\r\n setupCounter(this, target);\r\n setupTextareaFieldSizingiOS(target);\r\n }\r\n disconnectedCallback() {\r\n off(this, 'input', this, QUICK_EVENT);\r\n FIELDS.delete(this);\r\n }\r\n}\r\n\r\ncustomElements.define('ds-field', DSFieldElement);\r\n\r\nonHotReload('field', () => [\r\n onMutation(document, handleMutations, {\r\n debounce: false, // No need to timeout debounce here as we handle it ourselves\r\n attributeFilter: ['hidden', ATTR_FIELD], // Listen for hidden to detect hidden validations\r\n attributes: true,\r\n childList: true,\r\n subtree: true,\r\n }),\r\n]);\r\n"],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { isBrowser } from "./utils.js";
2
+ import { DSBreadcrumbsElement } from "./breadcrumbs.js";
3
+ import "./clickdelegatefor.js";
4
+ import "./details.js";
5
+ import "./dialog.js";
6
+ import { DSErrorSummaryElement } from "./error-summary.js";
7
+ import { DSFieldElement } from "./field.js";
8
+ import { DSPaginationElement, pagination } from "./pagination.js";
9
+ import { DSSuggestionElement } from "./suggestion.js";
10
+ import { DSTabElement, DSTabListElement, DSTabPanelElement, DSTabsElement } from "./tabs.js";
11
+ import "./popover.js";
12
+ import "./toggle-group.js";
13
+ import "./tooltip.js";
14
+
15
+ export * from "@u-elements/u-datalist"
16
+
17
+ //#region src/index.ts
18
+ if (isBrowser()) import("invokers-polyfill");
19
+
20
+ //#endregion
21
+ export { DSBreadcrumbsElement, DSErrorSummaryElement, DSFieldElement, DSPaginationElement, DSSuggestionElement, DSTabElement, DSTabListElement, DSTabPanelElement, DSTabsElement, pagination };
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import { isBrowser } from './utils';\r\n\r\n// Ensure polyfill is loaded in browser environment only\r\nif (isBrowser()) import('invokers-polyfill');\r\n\r\nexport * from '@u-elements/u-datalist'; // Re-export u-datalist since this is a pure polyfill and not custom Designsystemet elements\r\nexport * from './breadcrumbs';\r\nexport * from './error-summary';\r\nexport * from './field';\r\nexport * from './pagination';\r\nexport * from './suggestion';\r\nexport * from './tabs';\r\nimport './clickdelegatefor';\r\nimport './details';\r\nimport './dialog';\r\nimport './popover';\r\nimport './toggle-group';\r\nimport './tooltip';\r\n"],"mappings":";;;;;;;;;;;;;;;;;AAGA,IAAI,WAAW,CAAE,QAAO"}
@@ -0,0 +1,71 @@
1
+ import { DSElement, attr, attrRequiredWarning, customElements, onMutation } from "./utils.js";
2
+
3
+ //#region src/pagination.ts
4
+ const ATTR_LABEL = "aria-label";
5
+ const ATTR_CURRENT = "data-current";
6
+ const ATTR_TOTAL = "data-total";
7
+ const ATTR_HREF = "data-href";
8
+ const pagination = ({ current = 1, total = 10, show = 7 }) => ({
9
+ prev: current > 1 ? current - 1 : 0,
10
+ next: current < total ? current + 1 : 0,
11
+ pages: getSteps(current, total, show).map((page, index) => ({
12
+ current: page === current && "page",
13
+ key: `key-${page}-${index}`,
14
+ page
15
+ }))
16
+ });
17
+ var DSPaginationElement = class extends DSElement {
18
+ _unmutate;
19
+ static get observedAttributes() {
20
+ return [ATTR_CURRENT, ATTR_TOTAL];
21
+ }
22
+ connectedCallback() {
23
+ attrRequiredWarning(this, ATTR_LABEL);
24
+ if (attr(this, ATTR_TOTAL)) attrRequiredWarning(this, ATTR_CURRENT);
25
+ if (attr(this, ATTR_CURRENT)) attrRequiredWarning(this, ATTR_TOTAL);
26
+ this._unmutate = onMutation(this, this.render.bind(this), {
27
+ childList: true,
28
+ subtree: true,
29
+ debounce: 0
30
+ });
31
+ }
32
+ disconnectedCallback() {
33
+ this._unmutate?.();
34
+ this._unmutate = void 0;
35
+ }
36
+ render() {
37
+ const items = this.querySelectorAll("button,a");
38
+ const href = attr(this, ATTR_HREF);
39
+ const CURRENT = attr(this, ATTR_CURRENT) || void 0;
40
+ const TOTAL = attr(this, ATTR_TOTAL) || void 0;
41
+ if (!CURRENT || !TOTAL) return;
42
+ const { next, prev, pages } = pagination({
43
+ current: parseInt(CURRENT, 10),
44
+ total: parseInt(TOTAL, 10),
45
+ show: items.length - 2
46
+ });
47
+ items.forEach((item, i) => {
48
+ const page = i ? items[i + 1] ? pages[i - 1]?.page : next : prev;
49
+ attr(item, "aria-current", pages[i - 1]?.current ? "true" : null);
50
+ attr(item, "aria-hidden", page ? null : "true");
51
+ attr(item, "data-page", `${page}`);
52
+ attr(item, "tabindex", page ? null : "-1");
53
+ if (item instanceof HTMLButtonElement) attr(item, "value", `${page}`);
54
+ if (href) attr(item, "href", href.replace("$page", `${page}`));
55
+ });
56
+ }
57
+ };
58
+ customElements.define("ds-pagination", DSPaginationElement);
59
+ function getSteps(now, max, show = Number.POSITIVE_INFINITY) {
60
+ const offset = (show - 1) / 2;
61
+ const start = Math.max(Math.min(now - Math.floor(offset), max - show + 1), 1);
62
+ const end = Math.min(Math.max(now + Math.ceil(offset), show), max);
63
+ const pages = Array.from({ length: end + 1 - start }, (_, i) => i + start);
64
+ if (show > 4 && start > 1) pages.splice(0, 2, 1, 0);
65
+ if (show > 3 && end < max) pages.splice(-2, 2, 0, max);
66
+ return pages;
67
+ }
68
+
69
+ //#endregion
70
+ export { DSPaginationElement, pagination };
71
+ //# sourceMappingURL=pagination.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.js","names":[],"sources":["../../src/pagination.ts"],"sourcesContent":["import {\r\n attr,\r\n attrRequiredWarning,\r\n customElements,\r\n DSElement,\r\n onMutation,\r\n} from './utils';\r\n\r\ndeclare global {\r\n interface HTMLElementTagNameMap {\r\n 'ds-pagination': DSPaginationElement;\r\n }\r\n}\r\n\r\nconst ATTR_LABEL = 'aria-label';\r\nconst ATTR_CURRENT = 'data-current';\r\nconst ATTR_TOTAL = 'data-total';\r\nconst ATTR_HREF = 'data-href';\r\n\r\n// Expose pagination logic if wanting to do custom rendering (i.e. in React/Vue/etc)\r\nexport const pagination = ({ current = 1, total = 10, show = 7 }) => ({\r\n prev: current > 1 ? current - 1 : 0,\r\n next: current < total ? current + 1 : 0,\r\n pages: getSteps(current, total, show).map((page, index) => ({\r\n current: page === current && ('page' as const),\r\n key: `key-${page}-${index}`,\r\n page,\r\n })),\r\n});\r\n\r\nexport class DSPaginationElement extends DSElement {\r\n _unmutate?: () => void;\r\n\r\n static get observedAttributes() {\r\n return [ATTR_CURRENT, ATTR_TOTAL]; // Using ES2015 syntax for backwards compatibility\r\n }\r\n connectedCallback() {\r\n attrRequiredWarning(this, ATTR_LABEL);\r\n if (attr(this, ATTR_TOTAL)) attrRequiredWarning(this, ATTR_CURRENT);\r\n if (attr(this, ATTR_CURRENT)) attrRequiredWarning(this, ATTR_TOTAL);\r\n\r\n this._unmutate = onMutation(this, this.render.bind(this), {\r\n childList: true,\r\n subtree: true,\r\n debounce: 0,\r\n });\r\n }\r\n disconnectedCallback() {\r\n this._unmutate?.();\r\n this._unmutate = undefined;\r\n }\r\n render() {\r\n const items = this.querySelectorAll('button,a');\r\n const href = attr(this, ATTR_HREF);\r\n const CURRENT = attr(this, ATTR_CURRENT) || undefined;\r\n const TOTAL = attr(this, ATTR_TOTAL) || undefined;\r\n\r\n if (!CURRENT || !TOTAL) return;\r\n\r\n const { next, prev, pages } = pagination({\r\n current: parseInt(CURRENT, 10),\r\n total: parseInt(TOTAL, 10),\r\n show: items.length - 2,\r\n });\r\n\r\n items.forEach((item, i) => {\r\n const page = i ? (items[i + 1] ? pages[i - 1]?.page : next) : prev; // First is prev, last is next\r\n attr(item, 'aria-current', pages[i - 1]?.current ? 'true' : null);\r\n attr(item, 'aria-hidden', page ? null : 'true');\r\n attr(item, 'data-page', `${page}`);\r\n attr(item, 'tabindex', page ? null : '-1');\r\n if (item instanceof HTMLButtonElement) attr(item, 'value', `${page}`);\r\n if (href) attr(item, 'href', href.replace('$page', `${page}`));\r\n });\r\n }\r\n}\r\n\r\ncustomElements.define('ds-pagination', DSPaginationElement);\r\n\r\nfunction getSteps(now: number, max: number, show = Number.POSITIVE_INFINITY) {\r\n const offset = (show - 1) / 2;\r\n const start = Math.max(Math.min(now - Math.floor(offset), max - show + 1), 1);\r\n const end = Math.min(Math.max(now + Math.ceil(offset), show), max);\r\n const pages = Array.from({ length: end + 1 - start }, (_, i) => i + start);\r\n\r\n if (show > 4 && start > 1) pages.splice(0, 2, 1, 0);\r\n if (show > 3 && end < max) pages.splice(-2, 2, 0, max);\r\n return pages;\r\n}\r\n"],"mappings":";;;AAcA,MAAM,aAAa;AACnB,MAAM,eAAe;AACrB,MAAM,aAAa;AACnB,MAAM,YAAY;AAGlB,MAAa,cAAc,EAAE,UAAU,GAAG,QAAQ,IAAI,OAAO,SAAS;CACpE,MAAM,UAAU,IAAI,UAAU,IAAI;CAClC,MAAM,UAAU,QAAQ,UAAU,IAAI;CACtC,OAAO,SAAS,SAAS,OAAO,KAAK,CAAC,KAAK,MAAM,WAAW;EAC1D,SAAS,SAAS,WAAY;EAC9B,KAAK,OAAO,KAAK,GAAG;EACpB;EACD,EAAE;CACJ;AAED,IAAa,sBAAb,cAAyC,UAAU;CACjD;CAEA,WAAW,qBAAqB;AAC9B,SAAO,CAAC,cAAc,WAAW;;CAEnC,oBAAoB;AAClB,sBAAoB,MAAM,WAAW;AACrC,MAAI,KAAK,MAAM,WAAW,CAAE,qBAAoB,MAAM,aAAa;AACnE,MAAI,KAAK,MAAM,aAAa,CAAE,qBAAoB,MAAM,WAAW;AAEnE,OAAK,YAAY,WAAW,MAAM,KAAK,OAAO,KAAK,KAAK,EAAE;GACxD,WAAW;GACX,SAAS;GACT,UAAU;GACX,CAAC;;CAEJ,uBAAuB;AACrB,OAAK,aAAa;AAClB,OAAK,YAAY;;CAEnB,SAAS;EACP,MAAM,QAAQ,KAAK,iBAAiB,WAAW;EAC/C,MAAM,OAAO,KAAK,MAAM,UAAU;EAClC,MAAM,UAAU,KAAK,MAAM,aAAa,IAAI;EAC5C,MAAM,QAAQ,KAAK,MAAM,WAAW,IAAI;AAExC,MAAI,CAAC,WAAW,CAAC,MAAO;EAExB,MAAM,EAAE,MAAM,MAAM,UAAU,WAAW;GACvC,SAAS,SAAS,SAAS,GAAG;GAC9B,OAAO,SAAS,OAAO,GAAG;GAC1B,MAAM,MAAM,SAAS;GACtB,CAAC;AAEF,QAAM,SAAS,MAAM,MAAM;GACzB,MAAM,OAAO,IAAK,MAAM,IAAI,KAAK,MAAM,IAAI,IAAI,OAAO,OAAQ;AAC9D,QAAK,MAAM,gBAAgB,MAAM,IAAI,IAAI,UAAU,SAAS,KAAK;AACjE,QAAK,MAAM,eAAe,OAAO,OAAO,OAAO;AAC/C,QAAK,MAAM,aAAa,GAAG,OAAO;AAClC,QAAK,MAAM,YAAY,OAAO,OAAO,KAAK;AAC1C,OAAI,gBAAgB,kBAAmB,MAAK,MAAM,SAAS,GAAG,OAAO;AACrE,OAAI,KAAM,MAAK,MAAM,QAAQ,KAAK,QAAQ,SAAS,GAAG,OAAO,CAAC;IAC9D;;;AAIN,eAAe,OAAO,iBAAiB,oBAAoB;AAE3D,SAAS,SAAS,KAAa,KAAa,OAAO,OAAO,mBAAmB;CAC3E,MAAM,UAAU,OAAO,KAAK;CAC5B,MAAM,QAAQ,KAAK,IAAI,KAAK,IAAI,MAAM,KAAK,MAAM,OAAO,EAAE,MAAM,OAAO,EAAE,EAAE,EAAE;CAC7E,MAAM,MAAM,KAAK,IAAI,KAAK,IAAI,MAAM,KAAK,KAAK,OAAO,EAAE,KAAK,EAAE,IAAI;CAClE,MAAM,QAAQ,MAAM,KAAK,EAAE,QAAQ,MAAM,IAAI,OAAO,GAAG,GAAG,MAAM,IAAI,MAAM;AAE1E,KAAI,OAAO,KAAK,QAAQ,EAAG,OAAM,OAAO,GAAG,GAAG,GAAG,EAAE;AACnD,KAAI,OAAO,KAAK,MAAM,IAAK,OAAM,OAAO,IAAI,GAAG,GAAG,IAAI;AACtD,QAAO"}
@@ -0,0 +1,88 @@
1
+ import { QUICK_EVENT, attr, on, onHotReload } from "./utils.js";
2
+ import { autoUpdate, computePosition, flip, limitShift, offset, shift, size } from "@floating-ui/dom";
3
+
4
+ //#region src/popover.ts
5
+ const ATTR_PLACEMENT = "data-placement";
6
+ const ATTR_FLOATING = "data-floating";
7
+ const ATTR_AUTOPLACEMENT = "data-autoplacement";
8
+ const CSS_FLOATING = "--_ds-floating";
9
+ const CSS_FLOATING_ARROW_X = "--_ds-floating-arrow-x";
10
+ const CSS_FLOATING_ARROW_Y = "--_ds-floating-arrow-y";
11
+ const CSS_FLOATING_OVERSCROLL = "--_ds-floating-overscroll";
12
+ const POPOVERS = /* @__PURE__ */ new Map();
13
+ function handleToggle(event) {
14
+ const { newState, target, source = event.detail } = event;
15
+ if (!isDSFloating(target)) return;
16
+ if (newState === "closed") return POPOVERS.get(target)?.();
17
+ if (!source || source === target) return;
18
+ const padding = 10;
19
+ const overscroll = getCSSProp(target, CSS_FLOATING_OVERSCROLL);
20
+ const placement = attr(target, ATTR_PLACEMENT) || attr(source, ATTR_PLACEMENT) || getCSSProp(target, CSS_FLOATING);
21
+ const shiftOffset = placement.match(/left|right/gi) ? source.offsetHeight : source.offsetWidth;
22
+ const autoPlacement = attr(target, ATTR_AUTOPLACEMENT) || attr(source, ATTR_AUTOPLACEMENT);
23
+ const options = {
24
+ strategy: "absolute",
25
+ placement,
26
+ middleware: [
27
+ offset(parseFloat(getComputedStyle(target, "::before").height) || 0),
28
+ shift({
29
+ padding,
30
+ limiter: limitShift({ offset: { mainAxis: shiftOffset } })
31
+ }),
32
+ arrowPseudo(),
33
+ ...autoPlacement !== "false" ? [flip({
34
+ padding,
35
+ crossAxis: false
36
+ })] : [],
37
+ ...overscroll ? [size({ apply({ availableHeight }) {
38
+ if (overscroll === "fit") target.style.width = `${source.clientWidth}px`;
39
+ target.style.maxHeight = `${Math.max(50, availableHeight - padding * 2)}px`;
40
+ } })] : []
41
+ ]
42
+ };
43
+ const unfloat = autoUpdate(source, target, async () => {
44
+ if (!source?.isConnected) return POPOVERS.get(target)?.();
45
+ const { x, y } = await computePosition(source, target, options);
46
+ target.style.translate = `${x}px ${y}px`;
47
+ });
48
+ POPOVERS.set(target, () => POPOVERS.delete(target) && unfloat());
49
+ }
50
+ function handleBeforeToggle({ target: el, newState }) {
51
+ if (newState === "open" && isDSFloating(el)) attr(el, "popover", "manual");
52
+ }
53
+ function handleClickOutside({ target: el }) {
54
+ for (const [popover] of POPOVERS) if (!popover.contains(el)) {
55
+ const id = popover.id;
56
+ const trigger = `[popovertarget="${id}"],[commandfor="${id}"]`;
57
+ if (!el?.closest?.(trigger)) popover.hidePopover();
58
+ }
59
+ }
60
+ function handleKeydown(event) {
61
+ const last = event.key === "Escape" && Array.from(POPOVERS.keys()).pop();
62
+ if (last) last.hidePopover();
63
+ if (last) event.preventDefault?.();
64
+ }
65
+ onHotReload("popover", () => [
66
+ on(document, "beforetoggle", handleBeforeToggle, QUICK_EVENT),
67
+ on(document, "click", handleClickOutside, QUICK_EVENT),
68
+ on(document, "keydown", handleKeydown),
69
+ on(document, "toggle ds-toggle-source", handleToggle, QUICK_EVENT)
70
+ ]);
71
+ const getCSSProp = (el, prop) => getComputedStyle(el).getPropertyValue(prop).trim();
72
+ const isDSFloating = (el) => el instanceof HTMLElement && !!getCSSProp(el, CSS_FLOATING);
73
+ const arrowPseudo = () => ({
74
+ name: "arrowPseudo",
75
+ fn(data) {
76
+ const target = data.elements.floating;
77
+ const source = data.rects.reference;
78
+ const x = `${Math.round(source.width / 2 + source.x - data.x)}px`;
79
+ const y = `${Math.round(source.height / 2 + source.y - data.y)}px`;
80
+ target.style.setProperty(CSS_FLOATING_ARROW_X, x);
81
+ target.style.setProperty(CSS_FLOATING_ARROW_Y, y);
82
+ attr(target, ATTR_FLOATING, data.placement);
83
+ return data;
84
+ }
85
+ });
86
+
87
+ //#endregion
88
+ //# sourceMappingURL=popover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"popover.js","names":[],"sources":["../../src/popover.ts"],"sourcesContent":["import type { ComputePositionConfig, MiddlewareState } from '@floating-ui/dom';\r\nimport {\r\n autoUpdate,\r\n computePosition,\r\n limitShift,\r\n flip,\r\n offset,\r\n shift,\r\n size,\r\n} from '@floating-ui/dom';\r\nimport { attr, on, onHotReload, QUICK_EVENT } from './utils';\r\n\r\nconst ATTR_PLACEMENT = 'data-placement';\r\nconst ATTR_FLOATING = 'data-floating';\r\nconst ATTR_AUTOPLACEMENT = 'data-autoplacement';\r\nconst CSS_FLOATING = '--_ds-floating';\r\nconst CSS_FLOATING_ARROW_X = '--_ds-floating-arrow-x';\r\nconst CSS_FLOATING_ARROW_Y = '--_ds-floating-arrow-y';\r\nconst CSS_FLOATING_OVERSCROLL = '--_ds-floating-overscroll';\r\nconst POPOVERS = new Map<HTMLElement, () => void>();\r\n\r\n// Sometimes use \"ds-toggle\" event while waiting for better support of\r\n// event.source (https://developer.mozilla.org/en-US/docs/Web/API/ToggleEvent/source)\r\ntype DSToggleEvent = Partial<ToggleEvent> & {\r\n detail?: HTMLElement;\r\n source?: HTMLElement;\r\n};\r\n\r\nfunction handleToggle(event: DSToggleEvent) {\r\n const { newState, target, source = event.detail } = event;\r\n\r\n if (!isDSFloating(target)) return;\r\n if (newState === 'closed') return POPOVERS.get(target)?.(); // Cleanup on close\r\n if (!source || source === target) return; // No need to update\r\n const padding = 10;\r\n const overscroll = getCSSProp(target, CSS_FLOATING_OVERSCROLL);\r\n const placement = attr(target, ATTR_PLACEMENT) || attr(source, ATTR_PLACEMENT) || getCSSProp(target, CSS_FLOATING);\r\n const shiftOffset = placement.match(/left|right/gi) ? source.offsetHeight : source.offsetWidth;\r\n const autoPlacement = attr(target, ATTR_AUTOPLACEMENT) || attr(source, ATTR_AUTOPLACEMENT);\r\n const options = {\r\n strategy: 'absolute',\r\n placement,\r\n middleware: [\r\n offset(parseFloat(getComputedStyle(target, '::before').height) || 0),\r\n shift({\r\n padding,\r\n limiter: limitShift({ offset: { mainAxis: shiftOffset } }) // Prevent from shifing away from source\r\n }),\r\n arrowPseudo(),\r\n ...(autoPlacement !== 'false' ? [flip({ padding, crossAxis: false })] : []),\r\n ...(overscroll\r\n ? [\r\n size({\r\n apply({ availableHeight }) {\r\n if (overscroll === 'fit')\r\n target.style.width = `${source.clientWidth}px`;\r\n target.style.maxHeight = `${Math.max(50, availableHeight - padding * 2)}px`;\r\n },\r\n }),\r\n ]\r\n : []),\r\n ],\r\n } as ComputePositionConfig;\r\n const unfloat = autoUpdate(source, target, async () => {\r\n if (!source?.isConnected) return POPOVERS.get(target)?.(); // Cleanup if source element is removed\r\n const { x, y } = await computePosition(source, target, options);\r\n target.style.translate = `${x}px ${y}px`;\r\n });\r\n POPOVERS.set(target, () => POPOVERS.delete(target) && unfloat());\r\n}\r\n\r\nfunction handleBeforeToggle({ target: el, newState }: Partial<ToggleEvent>) {\r\n if (newState === 'open' && isDSFloating(el)) attr(el, 'popover', 'manual'); // Make manual to prevent closing when clicking scrollbar\r\n}\r\n\r\n// Since we use manual popover, we also manually need to close on outside click\r\nfunction handleClickOutside({ target: el }: Event) {\r\n for (const [popover] of POPOVERS)\r\n if (!popover.contains(el as Node)) {\r\n const id = popover.id;\r\n const trigger = `[popovertarget=\"${id}\"],[commandfor=\"${id}\"]`;\r\n if (!(el as Element)?.closest?.(trigger)) popover.hidePopover();\r\n }\r\n}\r\n\r\nfunction handleKeydown(event: Partial<KeyboardEvent>) {\r\n const last = event.key === 'Escape' && Array.from(POPOVERS.keys()).pop();\r\n if (last) last.hidePopover();\r\n if (last) event.preventDefault?.(); // Prevent minimize fullscreen Safari\r\n}\r\n\r\nonHotReload('popover', () => [\r\n on(document, 'beforetoggle', handleBeforeToggle, QUICK_EVENT), // Use capture since toggle does not bubble\r\n on(document, 'click', handleClickOutside, QUICK_EVENT), // Close open popovers on outside click\r\n on(document, 'keydown', handleKeydown),\r\n on(document, 'toggle ds-toggle-source', handleToggle, QUICK_EVENT), // Use capture since the toggle event does not bubble\r\n]);\r\n\r\nconst getCSSProp = (el: Element, prop: string) =>\r\n getComputedStyle(el).getPropertyValue(prop).trim();\r\n\r\nconst isDSFloating = (el?: EventTarget | null): el is HTMLElement =>\r\n el instanceof HTMLElement && !!getCSSProp(el, CSS_FLOATING);\r\n\r\nconst arrowPseudo = () => ({\r\n name: 'arrowPseudo',\r\n fn(data: MiddlewareState) {\r\n const target = data.elements.floating;\r\n const source = data.rects.reference;\r\n const x = `${Math.round(source.width / 2 + source.x - data.x)}px`;\r\n const y = `${Math.round(source.height / 2 + source.y - data.y)}px`;\r\n\r\n target.style.setProperty(CSS_FLOATING_ARROW_X, x);\r\n target.style.setProperty(CSS_FLOATING_ARROW_Y, y);\r\n attr(target, ATTR_FLOATING, data.placement);\r\n return data;\r\n },\r\n});\r\n"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { DSElement } from './utils';
2
+ declare global {
3
+ interface HTMLElementTagNameMap {
4
+ 'ds-breadcrumbs': DSBreadcrumbsElement;
5
+ }
6
+ }
7
+ export declare class DSBreadcrumbsElement extends DSElement {
8
+ _items?: HTMLCollectionOf<HTMLAnchorElement>;
9
+ _unresize?: () => void;
10
+ _unmutate?: () => void;
11
+ static get observedAttributes(): string[];
12
+ connectedCallback(): void;
13
+ attributeChangedCallback(): void;
14
+ disconnectedCallback(): void;
15
+ }
16
+ //# sourceMappingURL=breadcrumbs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breadcrumbs.d.ts","sourceRoot":"","sources":["../../../src/breadcrumbs.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,SAAS,EAIV,MAAM,SAAS,CAAC;AAEjB,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE,oBAAoB,CAAC;KACxC;CACF;AAKD,qBAAa,oBAAqB,SAAQ,SAAS;IACjD,MAAM,CAAC,EAAE,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IAEvB,MAAM,KAAK,kBAAkB,aAE5B;IACD,iBAAiB;IAWjB,wBAAwB;IAoBxB,oBAAoB;CAKrB"}
@@ -0,0 +1,2 @@
1
+ export declare const handleClickDelegateFor: (event: MouseEvent) => void;
2
+ //# sourceMappingURL=clickdelegatefor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clickdelegatefor.d.ts","sourceRoot":"","sources":["../../../src/clickdelegatefor.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,sBAAsB,GAAI,OAAO,UAAU,SAcvD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=details.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"details.d.ts","sourceRoot":"","sources":["../../../src/details.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/dialog.ts"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ import { DSElement } from './utils';
2
+ declare global {
3
+ interface HTMLElementTagNameMap {
4
+ 'ds-error-summary': DSErrorSummaryElement;
5
+ }
6
+ }
7
+ export declare class DSErrorSummaryElement extends DSElement {
8
+ connectedCallback(): void;
9
+ handleEvent({ target }: Partial<Event>): void;
10
+ disconnectedCallback(): void;
11
+ }
12
+ //# sourceMappingURL=error-summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-summary.d.ts","sourceRoot":"","sources":["../../../src/error-summary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,SAAS,EAA+B,MAAM,SAAS,CAAC;AAEvE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,kBAAkB,EAAE,qBAAqB,CAAC;KAC3C;CACF;AAED,qBAAa,qBAAsB,SAAQ,SAAS;IAClD,iBAAiB;IAIjB,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC;IAOtC,oBAAoB;CAGrB"}
@@ -0,0 +1,15 @@
1
+ import { DSElement } from './utils';
2
+ declare global {
3
+ interface HTMLElementTagNameMap {
4
+ 'ds-field': DSFieldElement;
5
+ }
6
+ }
7
+ export declare class DSFieldElement extends DSElement {
8
+ constructor();
9
+ connectedCallback(): void;
10
+ handleEvent({ target }: {
11
+ target: EventTarget | null;
12
+ }): void;
13
+ disconnectedCallback(): void;
14
+ }
15
+ //# sourceMappingURL=field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../../src/field.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,SAAS,EAWV,MAAM,SAAS,CAAC;AAEjB,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,UAAU,EAAE,cAAc,CAAC;KAC5B;CACF;AAgID,qBAAa,cAAe,SAAQ,SAAS;;IAQ3C,iBAAiB;IAKjB,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE;QAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAAA;KAAE;IAItD,oBAAoB;CAIrB"}
@@ -0,0 +1,14 @@
1
+ export * from '@u-elements/u-datalist';
2
+ export * from './breadcrumbs';
3
+ export * from './error-summary';
4
+ export * from './field';
5
+ export * from './pagination';
6
+ export * from './suggestion';
7
+ export * from './tabs';
8
+ import './clickdelegatefor';
9
+ import './details';
10
+ import './dialog';
11
+ import './popover';
12
+ import './toggle-group';
13
+ import './tooltip';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,wBAAwB,CAAC;AACvC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,QAAQ,CAAC;AACvB,OAAO,oBAAoB,CAAC;AAC5B,OAAO,WAAW,CAAC;AACnB,OAAO,UAAU,CAAC;AAClB,OAAO,WAAW,CAAC;AACnB,OAAO,gBAAgB,CAAC;AACxB,OAAO,WAAW,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { DSElement } from './utils';
2
+ declare global {
3
+ interface HTMLElementTagNameMap {
4
+ 'ds-pagination': DSPaginationElement;
5
+ }
6
+ }
7
+ export declare const pagination: ({ current, total, show }: {
8
+ current?: number | undefined;
9
+ total?: number | undefined;
10
+ show?: number | undefined;
11
+ }) => {
12
+ prev: number;
13
+ next: number;
14
+ pages: {
15
+ current: false | "page";
16
+ key: string;
17
+ page: number;
18
+ }[];
19
+ };
20
+ export declare class DSPaginationElement extends DSElement {
21
+ _unmutate?: () => void;
22
+ static get observedAttributes(): string[];
23
+ connectedCallback(): void;
24
+ disconnectedCallback(): void;
25
+ render(): void;
26
+ }
27
+ //# sourceMappingURL=pagination.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../src/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,SAAS,EAEV,MAAM,SAAS,CAAC;AAEjB,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,mBAAmB,CAAC;KACtC;CACF;AAQD,eAAO,MAAM,UAAU,GAAI;;;;CAAqC;;;;;;;;CAQ9D,CAAC;AAEH,qBAAa,mBAAoB,SAAQ,SAAS;IAChD,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IAEvB,MAAM,KAAK,kBAAkB,aAE5B;IACD,iBAAiB;IAWjB,oBAAoB;IAIpB,MAAM;CAwBP"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=popover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"popover.d.ts","sourceRoot":"","sources":["../../../src/popover.ts"],"names":[],"mappings":""}
@@ -0,0 +1,11 @@
1
+ import { UHTMLComboboxElement } from '@u-elements/u-combobox';
2
+ declare global {
3
+ interface HTMLElementTagNameMap {
4
+ 'ds-suggestion': DSSuggestionElement;
5
+ }
6
+ }
7
+ export declare class DSSuggestionElement extends UHTMLComboboxElement {
8
+ connectedCallback(): void;
9
+ disconnectedCallback(): void;
10
+ }
11
+ //# sourceMappingURL=suggestion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggestion.d.ts","sourceRoot":"","sources":["../../../src/suggestion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAG9D,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,mBAAmB,CAAC;KACtC;CACF;AAED,qBAAa,mBAAoB,SAAQ,oBAAoB;IAC3D,iBAAiB;IAIjB,oBAAoB;CAIrB"}
@@ -0,0 +1,18 @@
1
+ import * as UTabs from '@u-elements/u-tabs';
2
+ declare global {
3
+ interface HTMLElementTagNameMap {
4
+ 'ds-tabs': DSTabsElement;
5
+ 'ds-tablist': DSTabListElement;
6
+ 'ds-tab': DSTabElement;
7
+ 'ds-tabpanel': DSTabPanelElement;
8
+ }
9
+ }
10
+ export declare class DSTabsElement extends UTabs.UHTMLTabsElement {
11
+ }
12
+ export declare class DSTabListElement extends UTabs.UHTMLTabListElement {
13
+ }
14
+ export declare class DSTabElement extends UTabs.UHTMLTabElement {
15
+ }
16
+ export declare class DSTabPanelElement extends UTabs.UHTMLTabPanelElement {
17
+ }
18
+ //# sourceMappingURL=tabs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../../src/tabs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,oBAAoB,CAAC;AAG5C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,SAAS,EAAE,aAAa,CAAC;QACzB,YAAY,EAAE,gBAAgB,CAAC;QAC/B,QAAQ,EAAE,YAAY,CAAC;QACvB,aAAa,EAAE,iBAAiB,CAAC;KAClC;CACF;AAED,qBAAa,aAAc,SAAQ,KAAK,CAAC,gBAAgB;CAAG;AAC5D,qBAAa,gBAAiB,SAAQ,KAAK,CAAC,mBAAmB;CAAG;AAClE,qBAAa,YAAa,SAAQ,KAAK,CAAC,eAAe;CAAG;AAC1D,qBAAa,iBAAkB,SAAQ,KAAK,CAAC,oBAAoB;CAAG"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=toggle-group.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toggle-group.d.ts","sourceRoot":"","sources":["../../../src/toggle-group.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tooltip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../../src/tooltip.ts"],"names":[],"mappings":""}
@@ -0,0 +1,78 @@
1
+ export declare const QUICK_EVENT: {
2
+ passive: boolean;
3
+ capture: boolean;
4
+ };
5
+ export declare const isBrowser: () => boolean;
6
+ export declare const isWindows: () => boolean;
7
+ export declare const DSElement: {
8
+ new (): HTMLElement;
9
+ prototype: HTMLElement;
10
+ };
11
+ export declare function debounce<T extends unknown[]>(callback: (...args: T) => void, delay: number): (this: unknown, ...args: T) => void;
12
+ /**
13
+ * attr
14
+ * @description Utility to quickly get, set and remove attributes
15
+ * @param el The Element to read/write attributes from
16
+ * @param name The attribute name to get, set or remove, or a object to set multiple attributes
17
+ * @param value A valid attribute value or null to remove attribute
18
+ */
19
+ export declare const attr: (el: Element, name: string, value?: string | null) => string | null;
20
+ /**
21
+ * attrRequiredWarning
22
+ * @description Warn if element is missing attribute
23
+ * @param el The Element to read/write attributes from
24
+ * @param ...names The attribute name(s) check
25
+ */
26
+ export declare const attrRequiredWarning: (el: Element, name: string) => true | void;
27
+ /**
28
+ * on
29
+ * @param el The Element to use as EventTarget
30
+ * @param types A space separated string of event types
31
+ * @param listener An event listener function or listener object
32
+ */
33
+ export declare const on: (el: Node | Window | ShadowRoot, ...rest: Parameters<typeof Element.prototype.addEventListener>) => (() => void);
34
+ /**
35
+ * off
36
+ * @param el The Element to use as EventTarget
37
+ * @param types A space separated string of event types
38
+ * @param listener An event listener function or listener object
39
+ */
40
+ export declare const off: (el: Node | Window | ShadowRoot, ...rest: Parameters<typeof Element.prototype.removeEventListener>) => void;
41
+ declare global {
42
+ interface Window {
43
+ _dsHotReloadCleanup?: Map<string, Array<() => void>>;
44
+ }
45
+ }
46
+ /**
47
+ * onHotReload
48
+ * @description Runs a callback when window is loaded in browser, and ensures cleanup when hot-reloading
49
+ * @param key The key to identify setup and corresponding cleanup
50
+ * @param callback The callback to run when the page is ready
51
+ */
52
+ export declare const onHotReload: (key: string, setup: () => Array<() => void>) => void;
53
+ /**
54
+ * Speed up MutationObserver by debouncing and only running when page is visible
55
+ * @return new MutaionObserver
56
+ */
57
+ export declare const onMutation: (el: Node, callback: (observer: MutationObserver) => void, options: MutationObserverInit & {
58
+ debounce?: number | false;
59
+ }) => () => void;
60
+ /**
61
+ * tag
62
+ * @description creates element and assigns properties
63
+ * @param tagName The tagname of element to create
64
+ * @param attrs Optional attributes to add to the element
65
+ * @param text Optional text content to add to the element
66
+ * @return HTMLElement with props
67
+ */
68
+ export declare const tag: <TagName extends keyof HTMLElementTagNameMap>(tagName: TagName, attrs?: Record<string, string | null> | null) => HTMLElementTagNameMap[TagName];
69
+ /**
70
+ * customElements.define
71
+ * @description Defines a customElement if running in browser and if not already registered
72
+ * Scoped/named "customElements.define" so @custom-elements-manifest/analyzer can find tag names
73
+ */
74
+ export declare const customElements: {
75
+ define: (name: string, instance: CustomElementConstructor) => true | void | CustomElementConstructor;
76
+ };
77
+ export declare function useId(el?: Element | null): string;
78
+ //# sourceMappingURL=utils.d.ts.map