@chiralkit/design-system 0.1.0-alpha.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.
Files changed (146) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +11 -0
  3. package/dist/chiralkit-ds/chiralkit-ds.css +1 -0
  4. package/dist/chiralkit-ds/chiralkit-ds.esm.js +1 -0
  5. package/dist/chiralkit-ds/index.esm.js +1 -0
  6. package/dist/chiralkit-ds/p-038fa008.entry.js +1 -0
  7. package/dist/chiralkit-ds/p-2fdc1012.entry.js +1 -0
  8. package/dist/chiralkit-ds/p-306ec33b.entry.js +1 -0
  9. package/dist/chiralkit-ds/p-3f704698.entry.js +1 -0
  10. package/dist/chiralkit-ds/p-41081d22.entry.js +1 -0
  11. package/dist/chiralkit-ds/p-7d7e5aac.entry.js +1 -0
  12. package/dist/chiralkit-ds/p-84b801f8.entry.js +1 -0
  13. package/dist/chiralkit-ds/p-a28c71b4.entry.js +1 -0
  14. package/dist/chiralkit-ds/p-be84312f.entry.js +1 -0
  15. package/dist/chiralkit-ds/p-c8015fe6.entry.js +1 -0
  16. package/dist/chiralkit-ds/p-d36a6bea.entry.js +1 -0
  17. package/dist/chiralkit-ds/p-e-glNjK6.js +2 -0
  18. package/dist/chiralkit-ds/p-f0f9ff61.entry.js +1 -0
  19. package/dist/cjs/chiralkit-ds.cjs.js +24 -0
  20. package/dist/cjs/ds-badge.cjs.entry.js +18 -0
  21. package/dist/cjs/ds-button.cjs.entry.js +26 -0
  22. package/dist/cjs/ds-card.cjs.entry.js +17 -0
  23. package/dist/cjs/ds-checkbox.cjs.entry.js +67 -0
  24. package/dist/cjs/ds-code-block.cjs.entry.js +39 -0
  25. package/dist/cjs/ds-dialog.cjs.entry.js +67 -0
  26. package/dist/cjs/ds-input.cjs.entry.js +50 -0
  27. package/dist/cjs/ds-loader.cjs.entry.js +26 -0
  28. package/dist/cjs/ds-select.cjs.entry.js +85 -0
  29. package/dist/cjs/ds-tabs.cjs.entry.js +138 -0
  30. package/dist/cjs/ds-textarea.cjs.entry.js +50 -0
  31. package/dist/cjs/ds-tooltip.cjs.entry.js +233 -0
  32. package/dist/cjs/index-mMvyq7U_.js +2018 -0
  33. package/dist/cjs/index.cjs.js +10 -0
  34. package/dist/cjs/loader.cjs.js +12 -0
  35. package/dist/collection/collection-manifest.json +24 -0
  36. package/dist/collection/components/ds-badge/ds-badge.css +36 -0
  37. package/dist/collection/components/ds-badge/ds-badge.js +93 -0
  38. package/dist/collection/components/ds-button/ds-button.css +66 -0
  39. package/dist/collection/components/ds-button/ds-button.js +197 -0
  40. package/dist/collection/components/ds-card/ds-card.css +12 -0
  41. package/dist/collection/components/ds-card/ds-card.js +68 -0
  42. package/dist/collection/components/ds-checkbox/ds-checkbox.css +22 -0
  43. package/dist/collection/components/ds-checkbox/ds-checkbox.js +339 -0
  44. package/dist/collection/components/ds-code-block/ds-code-block.css +65 -0
  45. package/dist/collection/components/ds-code-block/ds-code-block.js +162 -0
  46. package/dist/collection/components/ds-dialog/ds-dialog.css +30 -0
  47. package/dist/collection/components/ds-dialog/ds-dialog.js +313 -0
  48. package/dist/collection/components/ds-input/ds-input.css +38 -0
  49. package/dist/collection/components/ds-input/ds-input.js +353 -0
  50. package/dist/collection/components/ds-loader/ds-loader.css +94 -0
  51. package/dist/collection/components/ds-loader/ds-loader.js +149 -0
  52. package/dist/collection/components/ds-select/ds-select.css +69 -0
  53. package/dist/collection/components/ds-select/ds-select.js +235 -0
  54. package/dist/collection/components/ds-tabs/ds-tabs.css +59 -0
  55. package/dist/collection/components/ds-tabs/ds-tabs.js +248 -0
  56. package/dist/collection/components/ds-textarea/ds-textarea.css +41 -0
  57. package/dist/collection/components/ds-textarea/ds-textarea.js +342 -0
  58. package/dist/collection/components/ds-tooltip/ds-tooltip.css +31 -0
  59. package/dist/collection/components/ds-tooltip/ds-tooltip.js +318 -0
  60. package/dist/collection/components.js +2 -0
  61. package/dist/collection/index.js +1 -0
  62. package/dist/components/ds-badge.d.ts +11 -0
  63. package/dist/components/ds-badge.js +1 -0
  64. package/dist/components/ds-button.d.ts +11 -0
  65. package/dist/components/ds-button.js +1 -0
  66. package/dist/components/ds-card.d.ts +11 -0
  67. package/dist/components/ds-card.js +1 -0
  68. package/dist/components/ds-checkbox.d.ts +11 -0
  69. package/dist/components/ds-checkbox.js +1 -0
  70. package/dist/components/ds-code-block.d.ts +11 -0
  71. package/dist/components/ds-code-block.js +1 -0
  72. package/dist/components/ds-dialog.d.ts +11 -0
  73. package/dist/components/ds-dialog.js +1 -0
  74. package/dist/components/ds-input.d.ts +11 -0
  75. package/dist/components/ds-input.js +1 -0
  76. package/dist/components/ds-loader.d.ts +11 -0
  77. package/dist/components/ds-loader.js +1 -0
  78. package/dist/components/ds-select.d.ts +11 -0
  79. package/dist/components/ds-select.js +1 -0
  80. package/dist/components/ds-tabs.d.ts +11 -0
  81. package/dist/components/ds-tabs.js +1 -0
  82. package/dist/components/ds-textarea.d.ts +11 -0
  83. package/dist/components/ds-textarea.js +1 -0
  84. package/dist/components/ds-tooltip.d.ts +11 -0
  85. package/dist/components/ds-tooltip.js +1 -0
  86. package/dist/components/index.d.ts +35 -0
  87. package/dist/components/index.js +1 -0
  88. package/dist/components/p-DDUZow8F.js +1 -0
  89. package/dist/components/p-ZsYP0VBq.js +1 -0
  90. package/dist/components/p-k0ywxWpC.js +1 -0
  91. package/dist/esm/chiralkit-ds.js +20 -0
  92. package/dist/esm/ds-badge.entry.js +16 -0
  93. package/dist/esm/ds-button.entry.js +24 -0
  94. package/dist/esm/ds-card.entry.js +15 -0
  95. package/dist/esm/ds-checkbox.entry.js +65 -0
  96. package/dist/esm/ds-code-block.entry.js +37 -0
  97. package/dist/esm/ds-dialog.entry.js +65 -0
  98. package/dist/esm/ds-input.entry.js +48 -0
  99. package/dist/esm/ds-loader.entry.js +24 -0
  100. package/dist/esm/ds-select.entry.js +83 -0
  101. package/dist/esm/ds-tabs.entry.js +136 -0
  102. package/dist/esm/ds-textarea.entry.js +48 -0
  103. package/dist/esm/ds-tooltip.entry.js +231 -0
  104. package/dist/esm/index-e-glNjK6.js +2008 -0
  105. package/dist/esm/index.js +3 -0
  106. package/dist/esm/loader.js +10 -0
  107. package/dist/index.cjs.js +1 -0
  108. package/dist/index.js +1 -0
  109. package/dist/layouts/app-shell.css +84 -0
  110. package/dist/tests/a11y.js +55 -0
  111. package/dist/types/Users/alex/projects/MyGitHub/chiralkit/packages/design-system/.stencil/tests/a11y.d.ts +17 -0
  112. package/dist/types/components/ds-badge/ds-badge.d.ts +54 -0
  113. package/dist/types/components/ds-button/ds-button.d.ts +75 -0
  114. package/dist/types/components/ds-card/ds-card.d.ts +53 -0
  115. package/dist/types/components/ds-checkbox/ds-checkbox.d.ts +94 -0
  116. package/dist/types/components/ds-code-block/ds-code-block.d.ts +83 -0
  117. package/dist/types/components/ds-dialog/ds-dialog.d.ts +148 -0
  118. package/dist/types/components/ds-input/ds-input.d.ts +104 -0
  119. package/dist/types/components/ds-loader/ds-loader.d.ts +64 -0
  120. package/dist/types/components/ds-select/ds-select.d.ts +123 -0
  121. package/dist/types/components/ds-tabs/ds-tabs.d.ts +155 -0
  122. package/dist/types/components/ds-textarea/ds-textarea.d.ts +93 -0
  123. package/dist/types/components/ds-tooltip/ds-tooltip.d.ts +26 -0
  124. package/dist/types/components.d.ts +3068 -0
  125. package/dist/types/index.d.ts +1 -0
  126. package/dist/types/stencil-public-runtime.d.ts +1861 -0
  127. package/docs.json +2112 -0
  128. package/loader/cdn.js +1 -0
  129. package/loader/index.cjs.js +1 -0
  130. package/loader/index.d.ts +24 -0
  131. package/loader/index.es2017.js +1 -0
  132. package/loader/index.js +2 -0
  133. package/package.json +78 -0
  134. package/react/components/ds-badge.tsx +25 -0
  135. package/react/components/ds-button.tsx +25 -0
  136. package/react/components/ds-card.tsx +25 -0
  137. package/react/components/ds-checkbox.tsx +25 -0
  138. package/react/components/ds-code-block.tsx +25 -0
  139. package/react/components/ds-dialog.tsx +31 -0
  140. package/react/components/ds-input.tsx +25 -0
  141. package/react/components/ds-loader.tsx +25 -0
  142. package/react/components/ds-select.tsx +25 -0
  143. package/react/components/ds-tabs.tsx +25 -0
  144. package/react/components/ds-textarea.tsx +25 -0
  145. package/react/components/ds-tooltip.tsx +25 -0
  146. package/react/components.ts +162 -0
@@ -0,0 +1,85 @@
1
+ 'use strict';
2
+
3
+ var index = require('./index-mMvyq7U_.js');
4
+
5
+ const dsSelectCss = () => `:host{display:inline-block;position:relative}.ds-select{font-family:var(--ds-font-family);font-size:var(--ds-font-size-md);background-color:transparent;color:inherit;border:1px solid color-mix(in oklch, currentColor 22%, transparent);cursor:pointer;-webkit-appearance:none;appearance:none}:host::after{content:"";position:absolute;top:50%;right:var(--ds-spacing-sm);width:12px;height:12px;transform:translateY(-50%);background-color:currentColor;-webkit-mask-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'><path d='M2.5 4.5L6 8L9.5 4.5' stroke='currentColor' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");mask-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'><path d='M2.5 4.5L6 8L9.5 4.5' stroke='currentColor' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:center;mask-position:center;-webkit-mask-size:contain;mask-size:contain;pointer-events:none}.ds-select:disabled{opacity:0.5;cursor:not-allowed}:host(:has(.ds-select:disabled))::after{opacity:0.5}.ds-select--md{border-radius:var(--ds-radius-sm);padding:var(--ds-spacing-sm) var(--ds-spacing-lg);padding-right:calc(var(--ds-spacing-lg) + var(--ds-spacing-lg))}.ds-select--lg{border-radius:var(--ds-radius-md);padding:var(--ds-spacing-md) var(--ds-spacing-xl);padding-right:calc(var(--ds-spacing-xl) + var(--ds-spacing-lg))}`;
6
+
7
+ const DsSelect = class {
8
+ constructor(hostRef) {
9
+ index.registerInstance(this, hostRef);
10
+ this.dsChange = index.createEvent(this, "dsChange");
11
+ }
12
+ selectEl;
13
+ value;
14
+ name;
15
+ disabled = false;
16
+ size = "md";
17
+ label;
18
+ /**
19
+ * Options rendered inside the internal shadow `<select>`. Accepts either:
20
+ * - a JSON string (SSR-friendly — server-rendered HTML can only set
21
+ * string attributes, and Stencil does not JSON-parse array attributes),
22
+ * e.g. `options='[{"value":"en","label":"EN"}]'`
23
+ * - an array property set from client-side JS,
24
+ * e.g. `el.options = [{ value: 'en', label: 'EN' }]`
25
+ *
26
+ * Malformed JSON fails safe to an empty list rather than throwing, so the
27
+ * component still renders a visible (if empty) select.
28
+ */
29
+ options = "[]";
30
+ dsChange;
31
+ watchValue(newValue) {
32
+ if (this.selectEl && this.selectEl.value !== newValue) {
33
+ this.selectEl.value = newValue ?? "";
34
+ }
35
+ }
36
+ // Empty-bodied on purpose: `options` is already a @Prop, so Stencil
37
+ // schedules a re-render on its own whenever it changes — this watcher
38
+ // exists only to document that `options` is reactive. The actual value
39
+ // re-sync happens in componentDidUpdate, once the new <option> elements
40
+ // are actually in the DOM (syncing here, before that render lands, would
41
+ // assign `this.value` against the *old* option list and get dropped).
42
+ watchOptions() { }
43
+ componentDidLoad() {
44
+ this.syncValue();
45
+ }
46
+ componentDidUpdate() {
47
+ this.syncValue();
48
+ }
49
+ syncValue() {
50
+ if (this.selectEl && this.value !== undefined) {
51
+ this.selectEl.value = this.value;
52
+ }
53
+ }
54
+ parseOptions() {
55
+ if (typeof this.options === "string") {
56
+ try {
57
+ return JSON.parse(this.options);
58
+ }
59
+ catch {
60
+ console.warn("[ds-select] failed to parse options prop:", this.options);
61
+ return [];
62
+ }
63
+ }
64
+ return this.options;
65
+ }
66
+ onChange = (event) => {
67
+ const value = event.target.value;
68
+ this.dsChange.emit(value);
69
+ };
70
+ render() {
71
+ const cls = `ds-select ds-select--${this.size}`;
72
+ return (index.h(index.Host, { key: '9c5755ca98a3a3a1340414de0109133ffb6617c4' }, index.h("select", { key: '7ac471b32e083e754c398ed22baf8ba993997ee5', class: cls, name: this.name, disabled: this.disabled, "aria-label": this.label, ref: (el) => (this.selectEl = el), onChange: this.onChange }, this.parseOptions().map((o) => (index.h("option", { value: o.value }, o.label))))));
73
+ }
74
+ static get watchers() { return {
75
+ "value": [{
76
+ "watchValue": 0
77
+ }],
78
+ "options": [{
79
+ "watchOptions": 0
80
+ }]
81
+ }; }
82
+ };
83
+ DsSelect.style = dsSelectCss();
84
+
85
+ exports.ds_select = DsSelect;
@@ -0,0 +1,138 @@
1
+ 'use strict';
2
+
3
+ var index = require('./index-mMvyq7U_.js');
4
+
5
+ const dsTabsCss = () => `ds-tabs{display:block;color:inherit;font-family:var(--ds-font-family);font-size:var(--ds-font-size-md)}.ds-tabs{display:flex;gap:var(--ds-spacing-sm);border-bottom:1px solid color-mix(in oklch, currentColor 15%, transparent)}.ds-tabs--vertical{flex-direction:column;align-items:stretch;border-bottom:none;border-right:1px solid color-mix(in oklch, currentColor 15%, transparent)}.ds-tab{font:inherit;color:inherit;background-color:transparent;border:none;padding:var(--ds-spacing-sm) var(--ds-spacing-lg);cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px}.ds-tabs--vertical .ds-tab{text-align:left;border-bottom:none;border-right:2px solid transparent;margin-bottom:0;margin-right:-1px}.ds-tab--active{border-bottom-color:currentColor}.ds-tabs--vertical .ds-tab--active{border-bottom-color:transparent;border-right-color:currentColor}.ds-tab:disabled{opacity:0.5;cursor:not-allowed}`;
6
+
7
+ const DsTabs = class {
8
+ constructor(hostRef) {
9
+ index.registerInstance(this, hostRef);
10
+ this.dsChange = index.createEvent(this, "dsChange");
11
+ }
12
+ tabRefs = new Map();
13
+ pendingFocusId;
14
+ items = "[]";
15
+ active;
16
+ orientation = "horizontal";
17
+ label;
18
+ dsChange;
19
+ watchItems() {
20
+ // Re-reconcile the active id when items change: if the current
21
+ // active is no longer in the list, fall back to the first enabled.
22
+ const parsed = this.parseItems();
23
+ if (parsed.length === 0)
24
+ return;
25
+ if (!parsed.some((it) => it.id === this.active && !it.disabled)) {
26
+ const firstEnabled = parsed.find((it) => !it.disabled);
27
+ if (firstEnabled) {
28
+ this.active = firstEnabled.id;
29
+ this.dsChange.emit(firstEnabled.id);
30
+ }
31
+ }
32
+ }
33
+ componentWillLoad() {
34
+ const parsed = this.parseItems();
35
+ if (parsed.length === 0)
36
+ return;
37
+ // Reconcile initial active — if the consumer passed an id that
38
+ // isn't in items (or none at all), fall back to the first enabled
39
+ // and emit dsChange once so their state matches ours.
40
+ if (!this.active || !parsed.some((it) => it.id === this.active && !it.disabled)) {
41
+ const firstEnabled = parsed.find((it) => !it.disabled);
42
+ if (firstEnabled) {
43
+ this.active = firstEnabled.id;
44
+ this.dsChange.emit(firstEnabled.id);
45
+ }
46
+ }
47
+ }
48
+ componentDidRender() {
49
+ // Move programmatic focus to the newly selected tab after
50
+ // arrow/Home/End nav so the visible focus ring tracks selection.
51
+ // Click-driven selection does not set pendingFocusId — the native
52
+ // button click already lands focus on the clicked element.
53
+ if (this.pendingFocusId) {
54
+ const target = this.tabRefs.get(this.pendingFocusId);
55
+ target?.focus();
56
+ this.pendingFocusId = undefined;
57
+ }
58
+ }
59
+ parseItems() {
60
+ if (typeof this.items === "string") {
61
+ try {
62
+ return JSON.parse(this.items);
63
+ }
64
+ catch {
65
+ console.warn("[ds-tabs] failed to parse items prop:", this.items);
66
+ return [];
67
+ }
68
+ }
69
+ return this.items;
70
+ }
71
+ enabledItems() {
72
+ return this.parseItems().filter((it) => !it.disabled);
73
+ }
74
+ selectAndFocus(id) {
75
+ if (id === this.active)
76
+ return;
77
+ this.active = id;
78
+ this.pendingFocusId = id;
79
+ this.dsChange.emit(id);
80
+ }
81
+ onClick = (id) => {
82
+ if (id === this.active)
83
+ return;
84
+ this.active = id;
85
+ // No pendingFocusId: click already focused the button natively.
86
+ this.dsChange.emit(id);
87
+ };
88
+ onKeyDown = (event, currentId) => {
89
+ const enabled = this.enabledItems();
90
+ if (enabled.length === 0)
91
+ return;
92
+ const isHorizontal = this.orientation === "horizontal";
93
+ const nextKey = isHorizontal ? "ArrowRight" : "ArrowDown";
94
+ const prevKey = isHorizontal ? "ArrowLeft" : "ArrowUp";
95
+ const currentIdx = enabled.findIndex((it) => it.id === currentId);
96
+ if (event.key === nextKey) {
97
+ event.preventDefault();
98
+ const nextIdx = (currentIdx + 1) % enabled.length;
99
+ this.selectAndFocus(enabled[nextIdx].id);
100
+ }
101
+ else if (event.key === prevKey) {
102
+ event.preventDefault();
103
+ const prevIdx = (currentIdx - 1 + enabled.length) % enabled.length;
104
+ this.selectAndFocus(enabled[prevIdx].id);
105
+ }
106
+ else if (event.key === "Home") {
107
+ event.preventDefault();
108
+ this.selectAndFocus(enabled[0].id);
109
+ }
110
+ else if (event.key === "End") {
111
+ event.preventDefault();
112
+ this.selectAndFocus(enabled[enabled.length - 1].id);
113
+ }
114
+ // Enter / Space intentionally not handled — automatic activation
115
+ // already selected the tab on focus move, and the native button
116
+ // click behavior remains available for consumers who bind to it.
117
+ };
118
+ render() {
119
+ const items = this.parseItems();
120
+ return (index.h(index.Host, { key: 'efc6a329ddbc14550f7e186480e41218f52b4865' }, index.h("div", { key: '4d475ddcb89198d97440e1e807acbef5984f658e', class: `ds-tabs ds-tabs--${this.orientation}`, role: "tablist", "aria-label": this.label, "aria-orientation": this.orientation === "vertical" ? "vertical" : undefined }, items.map((item) => {
121
+ const isActive = item.id === this.active;
122
+ return (index.h("button", { key: item.id, type: "button", role: "tab", id: item.id, class: `ds-tab${isActive ? " ds-tab--active" : ""}`, "aria-selected": isActive ? "true" : "false", "aria-controls": item.controls ?? item.id, tabindex: isActive ? 0 : -1, disabled: item.disabled, ref: (el) => {
123
+ if (el)
124
+ this.tabRefs.set(item.id, el);
125
+ else
126
+ this.tabRefs.delete(item.id);
127
+ }, onClick: () => this.onClick(item.id), onKeyDown: (e) => this.onKeyDown(e, item.id) }, item.label));
128
+ }))));
129
+ }
130
+ static get watchers() { return {
131
+ "items": [{
132
+ "watchItems": 0
133
+ }]
134
+ }; }
135
+ };
136
+ DsTabs.style = dsTabsCss();
137
+
138
+ exports.ds_tabs = DsTabs;
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ var index = require('./index-mMvyq7U_.js');
4
+
5
+ const dsTextareaCss = () => `:host{display:inline-block;width:100%}.ds-textarea{font-family:var(--ds-font-family);font-size:var(--ds-font-size-md);background-color:transparent;color:inherit;border:1px solid color-mix(in oklch, currentColor 22%, transparent);-webkit-appearance:none;appearance:none;box-sizing:border-box;width:100%;resize:vertical}.ds-textarea::placeholder{color:color-mix(in oklch, currentColor 45%, transparent)}.ds-textarea:disabled{opacity:0.5;cursor:not-allowed;resize:none}.ds-textarea[aria-invalid="true"]{border-color:color-mix(in oklch, currentColor 55%, transparent)}.ds-textarea--md{border-radius:var(--ds-radius-sm);padding:var(--ds-spacing-sm) var(--ds-spacing-lg)}.ds-textarea--lg{border-radius:var(--ds-radius-md);padding:var(--ds-spacing-md) var(--ds-spacing-xl)}`;
6
+
7
+ const DsTextarea = class {
8
+ constructor(hostRef) {
9
+ index.registerInstance(this, hostRef);
10
+ this.dsInput = index.createEvent(this, "dsInput");
11
+ }
12
+ textareaEl;
13
+ value;
14
+ name;
15
+ placeholder;
16
+ disabled = false;
17
+ required = false;
18
+ invalid = false;
19
+ describedBy;
20
+ label;
21
+ rows = 3;
22
+ size = "md";
23
+ dsInput;
24
+ watchValue(newValue) {
25
+ if (this.textareaEl && this.textareaEl.value !== (newValue ?? "")) {
26
+ this.textareaEl.value = newValue ?? "";
27
+ }
28
+ }
29
+ componentDidLoad() {
30
+ if (this.textareaEl && this.value !== undefined) {
31
+ this.textareaEl.value = this.value;
32
+ }
33
+ }
34
+ onInput = (event) => {
35
+ const value = event.target.value;
36
+ this.dsInput.emit(value);
37
+ };
38
+ render() {
39
+ const cls = `ds-textarea ds-textarea--${this.size}`;
40
+ return (index.h(index.Host, { key: '89e63314bca9f6f1b70f36c540a3ac48eed7311c' }, index.h("textarea", { key: '59f9b8ee9a48a4e495da7fb56745102a1f0ee7c2', class: cls, name: this.name, placeholder: this.placeholder, disabled: this.disabled, rows: this.rows, "aria-label": this.label, "aria-required": this.required ? "true" : undefined, "aria-invalid": this.invalid ? "true" : undefined, "aria-describedby": this.describedBy, ref: (el) => (this.textareaEl = el), onInput: this.onInput })));
41
+ }
42
+ static get watchers() { return {
43
+ "value": [{
44
+ "watchValue": 0
45
+ }]
46
+ }; }
47
+ };
48
+ DsTextarea.style = dsTextareaCss();
49
+
50
+ exports.ds_textarea = DsTextarea;
@@ -0,0 +1,233 @@
1
+ 'use strict';
2
+
3
+ var index = require('./index-mMvyq7U_.js');
4
+
5
+ const dsTooltipCss = () => `ds-tooltip{display:inline-block;position:relative;color:inherit}.ds-tooltip{position:absolute;left:50%;transform:translateX(-50%);z-index:1;max-width:240px;padding:var(--ds-spacing-xs) var(--ds-spacing-sm);font-family:var(--ds-font-family);font-size:var(--ds-font-size-md);line-height:1.3;color:inherit;background-color:Canvas;border:1px solid color-mix(in oklch, currentColor 25%, transparent);border-radius:var(--ds-radius-sm);pointer-events:none;white-space:normal}.ds-tooltip--bottom{top:calc(100% + var(--ds-spacing-xs))}.ds-tooltip--top{bottom:calc(100% + var(--ds-spacing-xs))}`;
6
+
7
+ /**
8
+ * ## Accessibility
9
+ *
10
+ * **Category:** state-machine (Tier 2)
11
+ * **APG pattern:** https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/
12
+ *
13
+ * Scratch build (there is no native tooltip element). Per the a11y
14
+ * spec §D ceremony: APG citation above, full keyboard enumeration
15
+ * and ARIA below, focus lifecycle in the tsx and spec.json, manual
16
+ * VoiceOver evidence pending (see commit message TODO).
17
+ *
18
+ * **Scope choice — wraps the consumer's first Element child as the
19
+ * trigger.** `<ds-tooltip label="Delete"><ds-button>×</ds-button>`
20
+ * — the first Element inside the ds-tooltip host is treated as the
21
+ * trigger. shadow:false so we can imperatively set `aria-describedby`
22
+ * on that light-DOM child (shadow-scoped ids can't be referenced
23
+ * from a light-DOM `aria-describedby`).
24
+ *
25
+ * **Consumer contract:** the first Element child MUST be focusable
26
+ * (`<button>`, `<a href>`, native form control, or an element with
27
+ * `tabindex="0"`) — otherwise keyboard users cannot summon the
28
+ * tooltip and the pattern fails WCAG 1.4.13. The component does not
29
+ * force focusability onto arbitrary children; that would produce
30
+ * silent AT surprises. The tooltip's `label` prop is required — a
31
+ * tooltip with no accessible text is inert.
32
+ *
33
+ * **Keyboard interactions (full APG enumeration):**
34
+ * - Focus (Tab into trigger): tooltip opens immediately (no
35
+ * `openDelay`). Delay-on-open is a mouse-hover ergonomic, not a
36
+ * keyboard one — waiting for keyboard users to see supplementary
37
+ * info is friction, not smoothing.
38
+ * - Escape (anywhere inside the tooltip's host, tooltip open):
39
+ * dismisses the tooltip WITHOUT moving focus. The trigger remains
40
+ * focused so the user can Tab away or re-summon. This is the WCAG
41
+ * 1.4.13 "dismissable" requirement.
42
+ * - Blur (Tab out of the trigger): tooltip closes immediately.
43
+ * - Enter / Space / arrow / printable: forwarded to the trigger
44
+ * (the tooltip does not intercept them). If Enter activates the
45
+ * underlying `<button>`, the button click closes the tooltip via
46
+ * the natural blur-then-refocus cycle.
47
+ *
48
+ * **Pointer interactions:**
49
+ * - mouseenter on the host → start `openDelay` timer → show.
50
+ * - mouseleave on the host → start `closeDelay` timer → hide.
51
+ * - Re-entering during the closeDelay window cancels the hide (the
52
+ * tooltip is "hoverable" — WCAG 1.4.13 — so users can move the
53
+ * pointer INTO the tooltip surface without it disappearing).
54
+ *
55
+ * **Persistence** (WCAG 1.4.13): the tooltip stays visible while
56
+ * the trigger is focused or hovered, and while the pointer is over
57
+ * the tooltip content itself. Dismissal only happens via Escape,
58
+ * blur, or genuine mouseleave (no residual hover on host or
59
+ * tooltip content).
60
+ *
61
+ * **ARIA attributes and value triggers:**
62
+ * - Tooltip element: `role="tooltip"`, `id` (auto-generated per
63
+ * instance so multiple tooltips on a page do not collide).
64
+ * - Trigger (the first Element child): `aria-describedby={tooltipId}`
65
+ * set on componentDidLoad and refreshed on slot mutations. We use
66
+ * describedby (APG default), NOT labelledby — the trigger has its
67
+ * own accessible name (its text or aria-label), and the tooltip
68
+ * supplements it.
69
+ *
70
+ * **Focus lifecycle:**
71
+ * - On mount: no auto-focus.
72
+ * - On trigger focus: tooltip opens immediately.
73
+ * - On trigger blur: tooltip closes.
74
+ * - On Escape while open: tooltip closes, focus stays on trigger.
75
+ * - The tooltip surface itself is NOT focusable — it is
76
+ * supplementary content, not an interactive region.
77
+ *
78
+ * **Motion:**
79
+ * - Animations: none applied by the component. Consumers who want a
80
+ * fade can style `[data-open="true"]` transitions gated on
81
+ * `prefers-reduced-motion: no-preference`.
82
+ *
83
+ * **Contrast:**
84
+ * - Tooltip surface: solid background via `Canvas` system color
85
+ * with `currentColor` text so it inherits the consumer theme's
86
+ * text color. Border uses `color-mix(currentColor 25%,
87
+ * transparent)`. Consumer theme owns the 4.5:1 text contrast and
88
+ * 3:1 non-text.
89
+ *
90
+ * **Screen reader announcement:**
91
+ * - Rendered state (closed): tooltip content is `hidden`, not in
92
+ * the a11y tree.
93
+ * - On focus: because the trigger has `aria-describedby`, AT reads
94
+ * the trigger's accessible name plus the tooltip text as a
95
+ * description. AT usually announces "…, [description]" after the
96
+ * trigger's role.
97
+ * - On Escape: the tooltip vanishes silently; AT falls back to
98
+ * announcing the trigger without its description on next
99
+ * interaction. This is APG behavior for dismissed tooltips.
100
+ *
101
+ * **Pending manual verification (see commit message TODO):**
102
+ * - VoiceOver on macOS: confirm the tooltip text is announced as a
103
+ * description of the trigger when the trigger gains focus.
104
+ * - VoiceOver: confirm Escape dismisses the tooltip and leaves the
105
+ * trigger focused; confirm re-focusing brings it back.
106
+ * - Chromium reduced-motion: confirm no residual animation is added
107
+ * by the component.
108
+ */
109
+ let tooltipIdCounter = 0;
110
+ const DsTooltip = class {
111
+ constructor(hostRef) {
112
+ index.registerInstance(this, hostRef);
113
+ }
114
+ get hostEl() { return index.getElement(this); }
115
+ label;
116
+ openDelay = 250;
117
+ closeDelay = 100;
118
+ placement = "bottom";
119
+ tooltipId = `ds-tooltip-${++tooltipIdCounter}`;
120
+ tooltipEl;
121
+ openTimer;
122
+ closeTimer;
123
+ isOpen = false;
124
+ watchLabel() {
125
+ if (this.tooltipEl) {
126
+ this.tooltipEl.textContent = this.label;
127
+ }
128
+ }
129
+ componentDidLoad() {
130
+ this.wireTrigger();
131
+ this.hostEl.addEventListener("mouseenter", this.onMouseEnter);
132
+ this.hostEl.addEventListener("mouseleave", this.onMouseLeave);
133
+ this.hostEl.addEventListener("focusin", this.onFocusIn);
134
+ this.hostEl.addEventListener("focusout", this.onFocusOut);
135
+ this.hostEl.addEventListener("keydown", this.onKeyDown);
136
+ }
137
+ disconnectedCallback() {
138
+ this.clearTimers();
139
+ this.hostEl.removeEventListener("mouseenter", this.onMouseEnter);
140
+ this.hostEl.removeEventListener("mouseleave", this.onMouseLeave);
141
+ this.hostEl.removeEventListener("focusin", this.onFocusIn);
142
+ this.hostEl.removeEventListener("focusout", this.onFocusOut);
143
+ this.hostEl.removeEventListener("keydown", this.onKeyDown);
144
+ }
145
+ wireTrigger() {
146
+ // First Element child within the host, ignoring our own tooltip
147
+ // <span> which we render at the end.
148
+ const children = Array.from(this.hostEl.children).filter((el) => el !== this.tooltipEl);
149
+ const trigger = children[0];
150
+ if (!trigger)
151
+ return;
152
+ trigger.setAttribute("aria-describedby", this.tooltipId);
153
+ }
154
+ clearTimers() {
155
+ if (this.openTimer !== undefined) {
156
+ window.clearTimeout(this.openTimer);
157
+ this.openTimer = undefined;
158
+ }
159
+ if (this.closeTimer !== undefined) {
160
+ window.clearTimeout(this.closeTimer);
161
+ this.closeTimer = undefined;
162
+ }
163
+ }
164
+ show(delay = 0) {
165
+ if (this.closeTimer !== undefined) {
166
+ window.clearTimeout(this.closeTimer);
167
+ this.closeTimer = undefined;
168
+ }
169
+ if (this.isOpen)
170
+ return;
171
+ if (delay === 0) {
172
+ this.applyOpen(true);
173
+ return;
174
+ }
175
+ if (this.openTimer !== undefined)
176
+ return;
177
+ this.openTimer = window.setTimeout(() => {
178
+ this.openTimer = undefined;
179
+ this.applyOpen(true);
180
+ }, delay);
181
+ }
182
+ hide(delay = 0) {
183
+ if (this.openTimer !== undefined) {
184
+ window.clearTimeout(this.openTimer);
185
+ this.openTimer = undefined;
186
+ }
187
+ if (!this.isOpen)
188
+ return;
189
+ if (delay === 0) {
190
+ this.applyOpen(false);
191
+ return;
192
+ }
193
+ if (this.closeTimer !== undefined)
194
+ return;
195
+ this.closeTimer = window.setTimeout(() => {
196
+ this.closeTimer = undefined;
197
+ this.applyOpen(false);
198
+ }, delay);
199
+ }
200
+ applyOpen(open) {
201
+ this.isOpen = open;
202
+ if (!this.tooltipEl)
203
+ return;
204
+ if (open) {
205
+ this.tooltipEl.removeAttribute("hidden");
206
+ this.tooltipEl.dataset.open = "true";
207
+ }
208
+ else {
209
+ this.tooltipEl.setAttribute("hidden", "");
210
+ this.tooltipEl.dataset.open = "false";
211
+ }
212
+ }
213
+ onMouseEnter = () => this.show(this.openDelay);
214
+ onMouseLeave = () => this.hide(this.closeDelay);
215
+ onFocusIn = () => this.show(0);
216
+ onFocusOut = () => this.hide(0);
217
+ onKeyDown = (event) => {
218
+ if (event.key === "Escape" && this.isOpen) {
219
+ this.hide(0);
220
+ }
221
+ };
222
+ render() {
223
+ return (index.h(index.Host, { key: 'e3822251c9edab36fdffa9178473823f3e9ae525' }, index.h("slot", { key: 'f7c490f42ae09a739d8d91d32c2394dbdef03aa5' }), index.h("span", { key: '8bda1876026129859665f82b1983065df602d092', class: `ds-tooltip ds-tooltip--${this.placement}`, role: "tooltip", id: this.tooltipId, hidden: true, "data-open": "false", ref: (el) => (this.tooltipEl = el) }, this.label)));
224
+ }
225
+ static get watchers() { return {
226
+ "label": [{
227
+ "watchLabel": 0
228
+ }]
229
+ }; }
230
+ };
231
+ DsTooltip.style = dsTooltipCss();
232
+
233
+ exports.ds_tooltip = DsTooltip;