@dso-toolkit/core 30.0.0 → 31.1.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 (93) hide show
  1. package/dist/cjs/dso-alert.cjs.entry.js +1 -1
  2. package/dist/cjs/dso-autosuggest.cjs.entry.js +15 -4
  3. package/dist/cjs/dso-banner.cjs.entry.js +1 -1
  4. package/dist/cjs/dso-date-picker.cjs.entry.js +56 -16
  5. package/dist/cjs/dso-icon.cjs.entry.js +6 -4
  6. package/dist/cjs/dso-info-button.cjs.entry.js +26 -0
  7. package/dist/cjs/{dso-info_3.cjs.entry.js → dso-info_2.cjs.entry.js} +0 -20
  8. package/dist/cjs/dso-label.cjs.entry.js +1 -1
  9. package/dist/cjs/dso-ozon-content.cjs.entry.js +26 -13
  10. package/dist/cjs/dso-toggletip.cjs.entry.js +62 -0
  11. package/dist/cjs/dso-toolkit.cjs.js +1 -1
  12. package/dist/cjs/dso-tooltip.cjs.entry.js +33 -26
  13. package/dist/cjs/dso-tree-view.cjs.entry.js +180 -0
  14. package/dist/cjs/loader.cjs.js +1 -1
  15. package/dist/collection/collection-manifest.json +3 -1
  16. package/dist/collection/components/alert/alert.css +2 -0
  17. package/dist/collection/components/autosuggest/autosuggest.css +1 -0
  18. package/dist/collection/components/autosuggest/autosuggest.js +3 -3
  19. package/dist/collection/components/banner/banner.css +2 -0
  20. package/dist/collection/components/date-picker/date-localization.js +1 -1
  21. package/dist/collection/components/date-picker/date-picker.js +108 -14
  22. package/dist/collection/components/date-picker/date-picker.template.js +2 -1
  23. package/dist/collection/components/date-picker/date-utils.js +3 -3
  24. package/dist/collection/components/icon/icon.js +9 -7
  25. package/dist/collection/components/info-button/info-button.css +10 -3
  26. package/dist/collection/components/info-button/info-button.js +18 -1
  27. package/dist/collection/components/info-button/info-button.template.js +2 -1
  28. package/dist/collection/components/label/label.decorator.js +6 -0
  29. package/dist/collection/components/label/label.js +1 -0
  30. package/dist/collection/components/label/label.template.js +10 -2
  31. package/dist/collection/components/ozon-content/ozon-content.transformer.js +26 -13
  32. package/dist/collection/components/toggletip/toggletip.css +8 -0
  33. package/dist/collection/components/toggletip/toggletip.js +137 -0
  34. package/dist/collection/components/toggletip/toggletip.template.js +12 -0
  35. package/dist/collection/components/tooltip/tooltip.css +1 -1
  36. package/dist/collection/components/tooltip/tooltip.js +49 -25
  37. package/dist/collection/components/tree-view/tree-item.js +20 -0
  38. package/dist/collection/components/tree-view/tree-view.css +43 -0
  39. package/dist/collection/components/tree-view/tree-view.interfaces.js +1 -0
  40. package/dist/collection/components/tree-view/tree-view.js +239 -0
  41. package/dist/collection/components/tree-view/tree-view.template.js +11 -0
  42. package/dist/custom-elements/index.d.ts +12 -0
  43. package/dist/custom-elements/index.js +381 -73
  44. package/dist/dso-toolkit/dso-toolkit.css +1 -1
  45. package/dist/dso-toolkit/dso-toolkit.esm.js +1 -1
  46. package/dist/dso-toolkit/{p-968d9e1d.entry.js → p-19de4cc7.entry.js} +1 -1
  47. package/dist/dso-toolkit/p-39dae284.entry.js +1 -0
  48. package/dist/dso-toolkit/p-5665f1ee.entry.js +1 -0
  49. package/dist/dso-toolkit/{p-eadba8c3.entry.js → p-5a67f3f7.entry.js} +1 -1
  50. package/dist/dso-toolkit/p-759920d0.entry.js +1 -0
  51. package/dist/dso-toolkit/{p-d748df48.entry.js → p-83f166b3.entry.js} +1 -1
  52. package/dist/dso-toolkit/p-9735f393.entry.js +1 -0
  53. package/dist/dso-toolkit/p-9e9f8bcf.entry.js +1 -0
  54. package/dist/dso-toolkit/p-a8a0e909.entry.js +1 -0
  55. package/dist/dso-toolkit/p-ad8f467f.entry.js +1 -0
  56. package/dist/dso-toolkit/p-e2dc97c4.entry.js +1 -0
  57. package/dist/dso-toolkit/p-faf19a1d.entry.js +1 -0
  58. package/dist/esm/dso-alert.entry.js +1 -1
  59. package/dist/esm/dso-autosuggest.entry.js +15 -4
  60. package/dist/esm/dso-banner.entry.js +1 -1
  61. package/dist/esm/dso-date-picker.entry.js +56 -16
  62. package/dist/esm/dso-icon.entry.js +6 -4
  63. package/dist/esm/dso-info-button.entry.js +22 -0
  64. package/dist/esm/{dso-info_3.entry.js → dso-info_2.entry.js} +1 -20
  65. package/dist/esm/dso-label.entry.js +1 -1
  66. package/dist/esm/dso-ozon-content.entry.js +26 -13
  67. package/dist/esm/dso-toggletip.entry.js +58 -0
  68. package/dist/esm/dso-toolkit.js +1 -1
  69. package/dist/esm/dso-tooltip.entry.js +33 -26
  70. package/dist/esm/dso-tree-view.entry.js +176 -0
  71. package/dist/esm/loader.js +1 -1
  72. package/dist/types/components/date-picker/date-picker.d.ts +20 -0
  73. package/dist/types/components/date-picker/date-picker.template.d.ts +1 -1
  74. package/dist/types/components/icon/icon.d.ts +1 -1
  75. package/dist/types/components/info-button/info-button.d.ts +1 -0
  76. package/dist/types/components/info-button/info-button.template.d.ts +1 -1
  77. package/dist/types/components/label/label.decorator.d.ts +3 -0
  78. package/dist/types/components/label/label.template.d.ts +1 -1
  79. package/dist/types/components/toggletip/toggletip.d.ts +17 -0
  80. package/dist/types/components/toggletip/toggletip.template.d.ts +2 -0
  81. package/dist/types/components/tooltip/tooltip.d.ts +6 -2
  82. package/dist/types/components/tree-view/tree-item.d.ts +13 -0
  83. package/dist/types/components/tree-view/tree-view.d.ts +36 -0
  84. package/dist/types/components/tree-view/tree-view.interfaces.d.ts +24 -0
  85. package/dist/types/components/tree-view/tree-view.template.d.ts +2 -0
  86. package/dist/types/components.d.ts +84 -3
  87. package/package.json +2 -1
  88. package/dist/dso-toolkit/p-2c6e9460.entry.js +0 -1
  89. package/dist/dso-toolkit/p-43772cee.entry.js +0 -1
  90. package/dist/dso-toolkit/p-94500196.entry.js +0 -1
  91. package/dist/dso-toolkit/p-9abac5e7.entry.js +0 -1
  92. package/dist/dso-toolkit/p-a2357726.entry.js +0 -1
  93. package/dist/dso-toolkit/p-c5acf7e2.entry.js +0 -1
@@ -1,6 +1,7 @@
1
- import { html } from 'lit-html';
1
+ import { html, nothing } from 'lit-html';
2
2
  import { ifDefined } from 'lit-html/directives/if-defined';
3
- export function labelTemplate({ status, label, button, compact }) {
3
+ import { unsafeHTML } from 'lit-html/directives/unsafe-html';
4
+ export function labelTemplate({ status, label, button, compact, symbol }) {
4
5
  return html `
5
6
  <dso-label
6
7
  status=${ifDefined(status)}
@@ -8,6 +9,13 @@ export function labelTemplate({ status, label, button, compact }) {
8
9
  ?compact=${compact}
9
10
  ?removable=${button}
10
11
  >
12
+ ${symbol
13
+ ? html `
14
+ <span slot="symbol">
15
+ ${unsafeHTML(symbol)}
16
+ </span>
17
+ `
18
+ : nothing}
11
19
  ${label}
12
20
  </dso-label>
13
21
  `;
@@ -1,20 +1,33 @@
1
1
  import isURL from 'validator/es/lib/isURL';
2
2
  function transformDescriptionNote(body) {
3
- body.querySelectorAll('a.noot > div.noot_popup').forEach((e, index) => {
4
- const contentElement = e.querySelector('.od-Al');
5
- const ozonPopupElement = contentElement === null || contentElement === void 0 ? void 0 : contentElement.parentElement;
6
- const anchorElement = ozonPopupElement === null || ozonPopupElement === void 0 ? void 0 : ozonPopupElement.parentElement;
3
+ body.querySelectorAll('div.noot').forEach((nootElement, index) => {
4
+ const contentElement = nootElement.nextElementSibling;
5
+ if (!(contentElement instanceof HTMLDivElement && contentElement.classList.value === 'noot_popup')) {
6
+ return;
7
+ }
8
+ const nootAnchorElement = nootElement.querySelector('a');
9
+ if (!(nootAnchorElement instanceof HTMLAnchorElement)) {
10
+ return;
11
+ }
12
+ const contentAlElement = contentElement.querySelector(':scope > .od-Al');
13
+ if (!(contentAlElement instanceof HTMLDivElement && contentAlElement.classList.value === 'od-Al')) {
14
+ return;
15
+ }
16
+ nootElement.replaceWith(...Array.from(nootElement.childNodes));
17
+ const contentWrapper = document.createElement('div');
18
+ contentWrapper.replaceChildren(...Array.from(contentAlElement.childNodes));
19
+ contentAlElement.replaceChildren(contentWrapper);
20
+ contentElement.replaceWith(contentAlElement);
7
21
  const supElement = document.createElement('sup');
8
- supElement.replaceChildren(...Array.from(anchorElement.childNodes));
9
- anchorElement === null || anchorElement === void 0 ? void 0 : anchorElement.replaceChildren(supElement);
10
- anchorElement === null || anchorElement === void 0 ? void 0 : anchorElement.after(contentElement);
11
- ozonPopupElement === null || ozonPopupElement === void 0 ? void 0 : ozonPopupElement.remove();
22
+ supElement.replaceChildren(...Array.from(nootAnchorElement.childNodes));
23
+ nootAnchorElement.replaceChildren(supElement);
12
24
  const id = (index + 1).toString(10);
13
25
  const [termId, contentId] = [`dso-ozon-term-${id}`, `dso-ozon-content-${id}`];
14
- anchorElement === null || anchorElement === void 0 ? void 0 : anchorElement.setAttribute('id', termId);
15
- anchorElement === null || anchorElement === void 0 ? void 0 : anchorElement.setAttribute('aria-controls', contentId);
16
- anchorElement === null || anchorElement === void 0 ? void 0 : anchorElement.setAttribute('aria-expanded', 'false');
17
- contentElement === null || contentElement === void 0 ? void 0 : contentElement.setAttribute('id', contentId);
26
+ nootAnchorElement.setAttribute('href', `#${termId}`);
27
+ nootAnchorElement.setAttribute('id', termId);
28
+ nootAnchorElement.setAttribute('aria-controls', contentId);
29
+ nootAnchorElement.setAttribute('aria-expanded', 'false');
30
+ contentAlElement === null || contentAlElement === void 0 ? void 0 : contentAlElement.setAttribute('id', contentId);
18
31
  });
19
32
  return body;
20
33
  }
@@ -84,7 +97,7 @@ export class OzonContentTransformer {
84
97
  return false;
85
98
  }
86
99
  // require_tld: false is needed to allow http://localhost
87
- return (_a = composedPath.slice(0, containerIndex)) === null || _a === void 0 ? void 0 : _a.some(e => { var _a; return e instanceof HTMLAnchorElement && isURL((_a = e.getAttribute('href')) !== null && _a !== void 0 ? _a : '', { require_tld: false }); });
100
+ return (_a = composedPath.slice(0, containerIndex)) === null || _a === void 0 ? void 0 : _a.some(e => { var _a; return e instanceof HTMLAnchorElement && isURL((_a = e.getAttribute('href')) !== null && _a !== void 0 ? _a : '', { require_tld: false, require_protocol: true }); });
88
101
  }
89
102
  isHostElement(value) {
90
103
  return value instanceof HTMLElement && value.tagName === 'DSO-OZON-CONTENT';
@@ -0,0 +1,8 @@
1
+ /* stylelint-disable value-keyword-case */
2
+ /* stylelint-disable string-no-newline */
3
+ /* stylelint-enable */
4
+ *,
5
+ *::after,
6
+ *::before {
7
+ box-sizing: border-box;
8
+ }
@@ -0,0 +1,137 @@
1
+ import { h, Component, Fragment, Element, Prop, State } from "@stencil/core";
2
+ export class Toggletip {
3
+ constructor() {
4
+ this.active = false;
5
+ this.label = "Toelichting";
6
+ this.position = "right";
7
+ this.click = () => {
8
+ this.active ? this.close() : this.open();
9
+ };
10
+ this.open = () => {
11
+ this.active = true;
12
+ this.host.addEventListener("keydown", this.keyDownListener);
13
+ this.host.addEventListener("focusout", this.focusOutListener);
14
+ };
15
+ this.close = () => {
16
+ this.host.removeEventListener("focusout", this.focusOutListener);
17
+ this.host.removeEventListener("keydown", this.keyDownListener);
18
+ this.active = false;
19
+ };
20
+ this.focusOutListener = (event) => {
21
+ if (!this.host.contains(event.relatedTarget)) {
22
+ this.close();
23
+ }
24
+ };
25
+ this.keyDownListener = (event) => {
26
+ if (!event.defaultPrevented && event.key == "Escape") {
27
+ this.close();
28
+ this.button.focus();
29
+ event.preventDefault();
30
+ }
31
+ return;
32
+ };
33
+ }
34
+ componentDidRender() {
35
+ var _a, _b, _c;
36
+ const infoButton = (_a = this.host.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector("dso-info-button");
37
+ if (!infoButton) {
38
+ throw Error("dso-info-button not found");
39
+ }
40
+ this.infoButton = infoButton;
41
+ const button = (_c = (_b = this.infoButton) === null || _b === void 0 ? void 0 : _b.shadowRoot) === null || _c === void 0 ? void 0 : _c.querySelector("button");
42
+ if (!button) {
43
+ throw Error("button not found");
44
+ }
45
+ this.button = button;
46
+ }
47
+ render() {
48
+ return (h(Fragment, null,
49
+ h("dso-info-button", { id: "toggle", onClick: this.click, label: this.label, active: this.active, secondary: this.secondary }),
50
+ h("dso-tooltip", { stateless: true, for: "toggle", active: this.active, position: this.position, small: this.small },
51
+ h("slot", null))));
52
+ }
53
+ static get is() { return "dso-toggletip"; }
54
+ static get encapsulation() { return "shadow"; }
55
+ static get originalStyleUrls() { return {
56
+ "$": ["toggletip.scss"]
57
+ }; }
58
+ static get styleUrls() { return {
59
+ "$": ["toggletip.css"]
60
+ }; }
61
+ static get properties() { return {
62
+ "label": {
63
+ "type": "string",
64
+ "mutable": false,
65
+ "complexType": {
66
+ "original": "string",
67
+ "resolved": "string",
68
+ "references": {}
69
+ },
70
+ "required": false,
71
+ "optional": false,
72
+ "docs": {
73
+ "tags": [],
74
+ "text": ""
75
+ },
76
+ "attribute": "label",
77
+ "reflect": false,
78
+ "defaultValue": "\"Toelichting\""
79
+ },
80
+ "position": {
81
+ "type": "string",
82
+ "mutable": false,
83
+ "complexType": {
84
+ "original": "\"top\" | \"right\" | \"bottom\" | \"left\"",
85
+ "resolved": "\"bottom\" | \"left\" | \"right\" | \"top\"",
86
+ "references": {}
87
+ },
88
+ "required": false,
89
+ "optional": false,
90
+ "docs": {
91
+ "tags": [],
92
+ "text": ""
93
+ },
94
+ "attribute": "position",
95
+ "reflect": false,
96
+ "defaultValue": "\"right\""
97
+ },
98
+ "small": {
99
+ "type": "boolean",
100
+ "mutable": false,
101
+ "complexType": {
102
+ "original": "boolean",
103
+ "resolved": "boolean | undefined",
104
+ "references": {}
105
+ },
106
+ "required": false,
107
+ "optional": true,
108
+ "docs": {
109
+ "tags": [],
110
+ "text": ""
111
+ },
112
+ "attribute": "small",
113
+ "reflect": false
114
+ },
115
+ "secondary": {
116
+ "type": "boolean",
117
+ "mutable": false,
118
+ "complexType": {
119
+ "original": "boolean",
120
+ "resolved": "boolean | undefined",
121
+ "references": {}
122
+ },
123
+ "required": false,
124
+ "optional": true,
125
+ "docs": {
126
+ "tags": [],
127
+ "text": ""
128
+ },
129
+ "attribute": "secondary",
130
+ "reflect": false
131
+ }
132
+ }; }
133
+ static get states() { return {
134
+ "active": {}
135
+ }; }
136
+ static get elementRef() { return "host"; }
137
+ }
@@ -0,0 +1,12 @@
1
+ import { html } from "lit-html";
2
+ import { ifDefined } from "lit-html/directives/if-defined";
3
+ import { unsafeHTML } from "lit-html/directives/unsafe-html";
4
+ export function toggletipTemplate({ children, label, position, small, secondary, }) {
5
+ return html `<dso-toggletip
6
+ label=${ifDefined(label)}
7
+ position=${ifDefined(position)}
8
+ ?small=${small}
9
+ ?secondary=${secondary}
10
+ >${unsafeHTML(children)}</dso-toggletip
11
+ >`;
12
+ }
@@ -2,7 +2,7 @@
2
2
  /* stylelint-disable string-no-newline */
3
3
  /* stylelint-enable */
4
4
  :host(:not([hidden])) {
5
- display: block;
5
+ display: inline-block;
6
6
  }
7
7
 
8
8
  *,
@@ -40,8 +40,25 @@ export class Tooltip {
40
40
  });
41
41
  }
42
42
  watchActive() {
43
+ var _a;
43
44
  if (this.active) {
44
45
  this.hidden = false;
46
+ if (!this.stateless) {
47
+ setTimeout(() => {
48
+ var _a;
49
+ (_a = this.popper) === null || _a === void 0 ? void 0 : _a.setOptions({
50
+ modifiers: [{ name: 'eventListeners', enabled: true }]
51
+ });
52
+ });
53
+ }
54
+ }
55
+ else {
56
+ if (!this.stateless) {
57
+ (_a = this.popper) === null || _a === void 0 ? void 0 : _a.setOptions({
58
+ modifiers: [{ name: 'eventListeners', enabled: false }]
59
+ });
60
+ }
61
+ setTimeout(() => (this.hidden = true), transitionDuration);
45
62
  }
46
63
  }
47
64
  listenClick(e) {
@@ -61,34 +78,20 @@ export class Tooltip {
61
78
  placement: this.position
62
79
  });
63
80
  this.callbacks = {
64
- activate: () => {
65
- this.hidden = false;
66
- setTimeout(() => {
67
- var _a;
68
- this.active = true;
69
- (_a = this.popper) === null || _a === void 0 ? void 0 : _a.setOptions({
70
- modifiers: [{ name: 'eventListeners', enabled: true }]
71
- });
72
- });
73
- },
74
- deactivate: () => {
75
- var _a;
76
- this.active = false;
77
- (_a = this.popper) === null || _a === void 0 ? void 0 : _a.setOptions({
78
- modifiers: [{ name: 'eventListeners', enabled: false }]
79
- });
80
- setTimeout(() => this.hidden = true, transitionDuration);
81
- }
81
+ activate: () => (this.active = true),
82
+ deactivate: () => (this.active = false)
82
83
  };
83
- this.target.addEventListener('mouseenter', this.callbacks.activate);
84
- this.target.addEventListener('mouseleave', this.callbacks.deactivate);
85
- this.target.addEventListener('focus', this.callbacks.activate);
86
- this.target.addEventListener('blur', this.callbacks.deactivate);
84
+ if (!this.stateless) {
85
+ this.target.addEventListener('mouseenter', this.callbacks.activate);
86
+ this.target.addEventListener('mouseleave', this.callbacks.deactivate);
87
+ this.target.addEventListener('focus', this.callbacks.activate);
88
+ this.target.addEventListener('blur', this.callbacks.deactivate);
89
+ }
87
90
  }
88
91
  disconnectedCallback() {
89
92
  var _a;
90
93
  (_a = this.popper) === null || _a === void 0 ? void 0 : _a.destroy();
91
- if (this.target && this.callbacks) {
94
+ if (!this.stateless && this.target && this.callbacks) {
92
95
  this.target.removeEventListener('mouseenter', this.callbacks.activate);
93
96
  this.target.removeEventListener('mouseleave', this.callbacks.deactivate);
94
97
  this.target.removeEventListener('focus', this.callbacks.activate);
@@ -106,7 +109,7 @@ export class Tooltip {
106
109
  render() {
107
110
  return (h(Host, { hidden: this.hidden },
108
111
  h("div", { class: clsx('tooltip', { in: this.active }), role: "tooltip" },
109
- !this.noArrow && (h("div", { class: "tooltip-arrow" })),
112
+ !this.noArrow && h("div", { class: "tooltip-arrow" }),
110
113
  h("div", { class: clsx('tooltip-inner', { 'dso-small': this.small }) },
111
114
  h("slot", null)))));
112
115
  }
@@ -115,7 +118,11 @@ export class Tooltip {
115
118
  return this.for;
116
119
  }
117
120
  if (typeof this.for === 'string') {
118
- const reference = document.getElementById(this.for);
121
+ const rootNode = this.element.getRootNode();
122
+ if (!(rootNode instanceof Document || rootNode instanceof ShadowRoot)) {
123
+ throw new Error(`rootNode is not instance of Document or ShadowRoot`);
124
+ }
125
+ const reference = rootNode.getElementById(this.for);
119
126
  if (!reference) {
120
127
  throw new Error(`Unable to find reference with id ${this.for}`);
121
128
  }
@@ -193,6 +200,23 @@ export class Tooltip {
193
200
  "reflect": false,
194
201
  "defaultValue": "false"
195
202
  },
203
+ "stateless": {
204
+ "type": "boolean",
205
+ "mutable": false,
206
+ "complexType": {
207
+ "original": "boolean",
208
+ "resolved": "boolean | undefined",
209
+ "references": {}
210
+ },
211
+ "required": false,
212
+ "optional": true,
213
+ "docs": {
214
+ "tags": [],
215
+ "text": "Deactivates mouseover behaviour"
216
+ },
217
+ "attribute": "stateless",
218
+ "reflect": false
219
+ },
196
220
  "small": {
197
221
  "type": "boolean",
198
222
  "mutable": false,
@@ -0,0 +1,20 @@
1
+ import { h, Fragment } from '@stencil/core';
2
+ import clsx from 'clsx';
3
+ export const DsoTreeItem = ({ owner, ancestors, item, index, level, setSize }) => {
4
+ var _a, _b, _c;
5
+ return (h("li", { key: item.reference, class: clsx('tree-item', { 'has-child': item.hasItems }), role: 'none' },
6
+ h("div", { class: "tree-branch-control" }, item.hasItems
7
+ ?
8
+ h("div", { onClick: (e) => owner.itemClick(e, ancestors, item) },
9
+ h("dso-icon", { icon: item.open ? 'chevron-down' : 'chevron-right' }))
10
+ : h("dso-icon", null)),
11
+ h("p", { class: "tree-content", tabindex: level === 1 && index === 0 ? 0 : -1, role: "treeitem", "aria-expanded": item.hasItems ? '' + (!!item.open && !!((_a = item.items) === null || _a === void 0 ? void 0 : _a.length)) : undefined, "aria-level": level, "aria-setsize": setSize, "aria-posinset": index + 1, "aria-busy": item.loading ? 'true' : undefined, onClick: (e) => owner.itemClick(e, ancestors, item) },
12
+ item.href
13
+ ? h("a", { href: item.href, tabindex: "-1" }, item.label)
14
+ : h("span", null, item.label), (_b = item.icons) === null || _b === void 0 ? void 0 :
15
+ _b.map((icon) => h("dso-icon", { icon: icon.icon, title: icon.label }))),
16
+ item.open &&
17
+ h(Fragment, null, item.hasItems && !item.items && item.loading
18
+ ? h("dso-progress-indicator", { size: "small", label: "Resultaten laden: een moment geduld alstublieft." })
19
+ : h("ul", { role: "group" }, (_c = item.items) === null || _c === void 0 ? void 0 : _c.map((childItem, index, org) => h(DsoTreeItem, { owner: owner, ancestors: [...ancestors, item], item: childItem, index: index, level: level + 1, setSize: org.length }))))));
20
+ };
@@ -0,0 +1,43 @@
1
+ /* stylelint-disable value-keyword-case */
2
+ /* stylelint-disable string-no-newline */
3
+ /* stylelint-enable */
4
+ :host ul {
5
+ list-style-type: none;
6
+ }
7
+ :host ul[role=tree] {
8
+ padding-left: 0;
9
+ }
10
+ :host li[role=treeitem] > ul {
11
+ padding-left: 1.5em;
12
+ }
13
+ :host .tree-branch-control {
14
+ cursor: pointer;
15
+ display: inline-block;
16
+ }
17
+ :host .tree-content {
18
+ cursor: pointer;
19
+ display: inline-block;
20
+ margin: 8px 0;
21
+ }
22
+ :host .tree-content a, :host .tree-content a:visited {
23
+ color: #39870c;
24
+ text-decoration: none;
25
+ }
26
+ :host .tree-content a:hover, :host .tree-content a:focus {
27
+ color: #676cb0;
28
+ text-decoration: underline;
29
+ }
30
+ :host .tree-content a:active {
31
+ text-decoration: none;
32
+ }
33
+ :host .tree-content dso-icon {
34
+ vertical-align: text-bottom;
35
+ font-size: 0.75em;
36
+ margin-left: 0.5em;
37
+ }
38
+
39
+ *,
40
+ *::after,
41
+ *::before {
42
+ box-sizing: border-box;
43
+ }
@@ -0,0 +1,239 @@
1
+ import { h, Component, Event, Prop } from '@stencil/core';
2
+ import { DsoTreeItem } from './tree-item';
3
+ export class TreeView {
4
+ constructor() {
5
+ this.keyDownListener = (event) => {
6
+ if (event.defaultPrevented) {
7
+ return;
8
+ }
9
+ const isIndexLetter = (str) => str.length === 1 && str.match(/\S/);
10
+ const tree = event.composedPath().find(item => (item instanceof HTMLElement) ? item.className === 'dso-tree' : false);
11
+ if (!(event.target instanceof HTMLParagraphElement) || !(tree instanceof HTMLElement)) {
12
+ return;
13
+ }
14
+ switch (event.key) {
15
+ case "ArrowDown":
16
+ TreeView.moveFocus(tree, event.target, 'next');
17
+ break;
18
+ case "ArrowUp":
19
+ TreeView.moveFocus(tree, event.target, 'previous');
20
+ break;
21
+ case "ArrowRight":
22
+ TreeView.expandItemOrFocusChild(tree, event.target);
23
+ break;
24
+ case "ArrowLeft":
25
+ TreeView.collapseItemOrFocusParent(tree, event.target);
26
+ break;
27
+ case "End":
28
+ TreeView.moveFocus(tree, event.target, 'last');
29
+ break;
30
+ case "Home":
31
+ TreeView.moveFocus(tree, event.target, 'first');
32
+ break;
33
+ case "Enter":
34
+ case " ":
35
+ event.target.click();
36
+ break;
37
+ default:
38
+ if (isIndexLetter(event.key)) {
39
+ if (TreeView.setFocusByFirstCharacter(tree, event.target, event.key, event.shiftKey)) {
40
+ break;
41
+ }
42
+ }
43
+ return;
44
+ }
45
+ event.preventDefault();
46
+ };
47
+ this.itemClick = (event, ancestors, item) => {
48
+ if (!(event.target instanceof HTMLElement)) {
49
+ return;
50
+ }
51
+ const contentElement = event.target.closest('.tree-content');
52
+ if (contentElement) {
53
+ const tree = event.composedPath().find(item => (item instanceof HTMLElement) ? item.className === 'dso-tree' : false);
54
+ if (!(contentElement instanceof HTMLParagraphElement) || !(tree instanceof HTMLElement)) {
55
+ return;
56
+ }
57
+ TreeView.setFocus(tree, contentElement);
58
+ this.clickItem.emit([...ancestors, item]);
59
+ return;
60
+ }
61
+ if (item.open) {
62
+ this.closeItem.emit([...ancestors, item]);
63
+ }
64
+ else {
65
+ this.openItem.emit([...ancestors, item]);
66
+ }
67
+ };
68
+ }
69
+ static setFocus(tree, target) {
70
+ if (target) {
71
+ Array.from(tree.querySelectorAll('p'))
72
+ .filter(item => item.tabIndex === 0)
73
+ .forEach(item => item.tabIndex = -1);
74
+ target.tabIndex = 0;
75
+ target.focus();
76
+ }
77
+ }
78
+ static moveFocus(tree, el, moveTo) {
79
+ const focusableItems = Array.from(tree.querySelectorAll('p'))
80
+ .filter(item => item.offsetWidth > 0 && item.offsetHeight > 0);
81
+ let index = 0;
82
+ switch (moveTo) {
83
+ case 'first':
84
+ index = 0;
85
+ break;
86
+ case 'previous':
87
+ index = focusableItems.indexOf(el) - 1;
88
+ break;
89
+ case 'next':
90
+ index = focusableItems.indexOf(el) + 1;
91
+ break;
92
+ case 'last':
93
+ index = focusableItems.length - 1;
94
+ break;
95
+ }
96
+ TreeView.setFocus(tree, focusableItems[index]);
97
+ }
98
+ static expandItemOrFocusChild(tree, target) {
99
+ var _a;
100
+ if ((target === null || target === void 0 ? void 0 : target.getAttribute('aria-expanded')) === 'true') {
101
+ TreeView.moveFocus(tree, target, 'next');
102
+ }
103
+ else {
104
+ const controlElement = (_a = target.previousElementSibling) === null || _a === void 0 ? void 0 : _a.firstElementChild;
105
+ if (controlElement instanceof HTMLElement) {
106
+ controlElement.click();
107
+ }
108
+ }
109
+ }
110
+ static collapseItemOrFocusParent(tree, target) {
111
+ var _a, _b, _c;
112
+ if ((target === null || target === void 0 ? void 0 : target.getAttribute('aria-expanded')) === 'true') {
113
+ const controlElement = (_a = target.previousElementSibling) === null || _a === void 0 ? void 0 : _a.firstElementChild;
114
+ if (controlElement instanceof HTMLElement) {
115
+ controlElement.click();
116
+ }
117
+ }
118
+ else {
119
+ const parentTarget = (_c = (_b = target === null || target === void 0 ? void 0 : target.parentElement) === null || _b === void 0 ? void 0 : _b.parentElement) === null || _c === void 0 ? void 0 : _c.previousElementSibling;
120
+ if (parentTarget instanceof HTMLElement) {
121
+ TreeView.setFocus(tree, parentTarget);
122
+ }
123
+ }
124
+ }
125
+ static setFocusByFirstCharacter(tree, el, char, backwards) {
126
+ const focusableItems = Array.from(tree.querySelectorAll('p'))
127
+ .filter(item => item.offsetWidth > 0 && item.offsetHeight > 0);
128
+ if (backwards) {
129
+ focusableItems.reverse();
130
+ }
131
+ const current = focusableItems.indexOf(el);
132
+ char = char.toLowerCase();
133
+ let nextItem = focusableItems.find((item, index) => { var _a; return index > current && ((_a = item.textContent) === null || _a === void 0 ? void 0 : _a.toLowerCase().startsWith(char)); });
134
+ if (!nextItem) {
135
+ nextItem = focusableItems.find((item, index) => { var _a; return index < current && ((_a = item.textContent) === null || _a === void 0 ? void 0 : _a.toLowerCase().startsWith(char)); });
136
+ }
137
+ if (nextItem) {
138
+ TreeView.setFocus(tree, nextItem);
139
+ return true;
140
+ }
141
+ return false;
142
+ }
143
+ render() {
144
+ var _a;
145
+ return (h("div", { id: "tree", class: "dso-tree", onKeyDown: (e) => this.keyDownListener(e) },
146
+ h("ul", { role: "tree", "aria-label": "Objectenboom" }, (_a = this.collection) === null || _a === void 0 ? void 0 : _a.map((item, index) => h(DsoTreeItem, { owner: this, ancestors: [], item: item, index: index, level: 1, setSize: this.collection.length })))));
147
+ }
148
+ static get is() { return "dso-tree-view"; }
149
+ static get encapsulation() { return "shadow"; }
150
+ static get originalStyleUrls() { return {
151
+ "$": ["./tree-view.scss"]
152
+ }; }
153
+ static get styleUrls() { return {
154
+ "$": ["tree-view.css"]
155
+ }; }
156
+ static get properties() { return {
157
+ "collection": {
158
+ "type": "unknown",
159
+ "mutable": false,
160
+ "complexType": {
161
+ "original": "TreeViewItem<string>[]",
162
+ "resolved": "TreeViewItem<string>[]",
163
+ "references": {
164
+ "TreeViewItem": {
165
+ "location": "import",
166
+ "path": "./tree-view.interfaces"
167
+ }
168
+ }
169
+ },
170
+ "required": true,
171
+ "optional": false,
172
+ "docs": {
173
+ "tags": [],
174
+ "text": "The collection of TreeViewItems"
175
+ }
176
+ }
177
+ }; }
178
+ static get events() { return [{
179
+ "method": "openItem",
180
+ "name": "openItem",
181
+ "bubbles": true,
182
+ "cancelable": true,
183
+ "composed": true,
184
+ "docs": {
185
+ "tags": [],
186
+ "text": "Emitted when a tree view item is opened.\nThe `detail` property of the `CustomEvent`\u00A0will contain the complete path of TreeViewItems from the\nroot to the item that is emitting the open event. The consumer of the event is responsible for updating\nthe TreeView's collection (usually set the open state on the last TreeViewItem in path)."
187
+ },
188
+ "complexType": {
189
+ "original": "TreeViewItem<string>[]",
190
+ "resolved": "TreeViewItem<string>[]",
191
+ "references": {
192
+ "TreeViewItem": {
193
+ "location": "import",
194
+ "path": "./tree-view.interfaces"
195
+ }
196
+ }
197
+ }
198
+ }, {
199
+ "method": "closeItem",
200
+ "name": "closeItem",
201
+ "bubbles": true,
202
+ "cancelable": true,
203
+ "composed": true,
204
+ "docs": {
205
+ "tags": [],
206
+ "text": "Emitted when a tree view item is closed.\nThe `detail` property of the `CustomEvent`\u00A0will contain the complete path of TreeViewItems from the\nroot to the item that is emitting the close event. The consumer of the event is responsible for updating\nthe TreeView's collection (usually set the closed state on the last TreeViewItem in path)."
207
+ },
208
+ "complexType": {
209
+ "original": "TreeViewItem<string>[]",
210
+ "resolved": "TreeViewItem<string>[]",
211
+ "references": {
212
+ "TreeViewItem": {
213
+ "location": "import",
214
+ "path": "./tree-view.interfaces"
215
+ }
216
+ }
217
+ }
218
+ }, {
219
+ "method": "clickItem",
220
+ "name": "clickItem",
221
+ "bubbles": true,
222
+ "cancelable": true,
223
+ "composed": true,
224
+ "docs": {
225
+ "tags": [],
226
+ "text": "Emitted when a tree view item is clicked.\nThe `detail` property of the `CustomEvent`\u00A0will contain the complete path of TreeViewItems from the\nroot to the item that is emitting the clicked event."
227
+ },
228
+ "complexType": {
229
+ "original": "TreeViewItem<string>[]",
230
+ "resolved": "TreeViewItem<string>[]",
231
+ "references": {
232
+ "TreeViewItem": {
233
+ "location": "import",
234
+ "path": "./tree-view.interfaces"
235
+ }
236
+ }
237
+ }
238
+ }]; }
239
+ }