@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,65 @@
1
+ import { r as registerInstance, c as createEvent, h, H as Host } from './index-e-glNjK6.js';
2
+
3
+ const dsDialogCss = () => `:host{display:contents}.ds-dialog{color:inherit;background-color:color-mix(in oklch, currentColor 4%, Canvas);border:1px solid color-mix(in oklch, currentColor 15%, transparent);border-radius:var(--ds-radius-md);padding:var(--ds-spacing-xl);box-sizing:border-box;max-width:min(90vw, 32rem);max-height:90vh;overflow:auto}.ds-dialog::backdrop{background-color:rgba(0, 0, 0, 0.5)}`;
4
+
5
+ const DsDialog = class {
6
+ constructor(hostRef) {
7
+ registerInstance(this, hostRef);
8
+ this.dsOpen = createEvent(this, "dsOpen");
9
+ this.dsClose = createEvent(this, "dsClose");
10
+ }
11
+ dialogEl;
12
+ open = false;
13
+ label;
14
+ labelledBy;
15
+ describedBy;
16
+ dsOpen;
17
+ dsClose;
18
+ watchOpen(newValue) {
19
+ this.syncOpen(newValue);
20
+ }
21
+ componentDidLoad() {
22
+ // The `close` event on the native <dialog> is not composed by
23
+ // default, so it does not bubble out of the shadow root. Wire it
24
+ // here rather than in the JSX so we can re-emit as a Stencil
25
+ // Event that composed-crosses the boundary.
26
+ this.dialogEl?.addEventListener("close", this.onNativeClose);
27
+ if (this.open) {
28
+ this.syncOpen(true);
29
+ }
30
+ }
31
+ disconnectedCallback() {
32
+ this.dialogEl?.removeEventListener("close", this.onNativeClose);
33
+ }
34
+ syncOpen(shouldOpen) {
35
+ if (!this.dialogEl)
36
+ return;
37
+ const isOpen = this.dialogEl.open;
38
+ if (shouldOpen && !isOpen) {
39
+ // showModal() is the modal form — traps focus, adds the ::backdrop,
40
+ // makes background inert. show() (non-modal) is intentionally not
41
+ // exposed in v1.
42
+ this.dialogEl.showModal();
43
+ this.dsOpen.emit();
44
+ }
45
+ else if (!shouldOpen && isOpen) {
46
+ this.dialogEl.close();
47
+ // dsClose is emitted by onNativeClose to also cover Escape /
48
+ // form-submit paths — no need to emit here.
49
+ }
50
+ }
51
+ onNativeClose = () => {
52
+ this.dsClose.emit();
53
+ };
54
+ render() {
55
+ return (h(Host, { key: '8b25b70865ea028c81405f77a4d016348507aae6' }, h("dialog", { key: '0c82754fe4e4ecf68232a93616bbff3621866375', class: "ds-dialog", "aria-label": this.label, "aria-labelledby": this.labelledBy, "aria-describedby": this.describedBy, ref: (el) => (this.dialogEl = el) }, h("slot", { key: '30131eed9eec7db67a407770b5caefe42c78b68a' }))));
56
+ }
57
+ static get watchers() { return {
58
+ "open": [{
59
+ "watchOpen": 0
60
+ }]
61
+ }; }
62
+ };
63
+ DsDialog.style = dsDialogCss();
64
+
65
+ export { DsDialog as ds_dialog };
@@ -0,0 +1,48 @@
1
+ import { r as registerInstance, c as createEvent, h, H as Host } from './index-e-glNjK6.js';
2
+
3
+ const dsInputCss = () => `:host{display:inline-block}.ds-input{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%}.ds-input::placeholder{color:color-mix(in oklch, currentColor 45%, transparent)}.ds-input:disabled{opacity:0.5;cursor:not-allowed}.ds-input[aria-invalid="true"]{border-color:color-mix(in oklch, currentColor 55%, transparent)}.ds-input--md{border-radius:var(--ds-radius-sm);padding:var(--ds-spacing-sm) var(--ds-spacing-lg)}.ds-input--lg{border-radius:var(--ds-radius-md);padding:var(--ds-spacing-md) var(--ds-spacing-xl)}`;
4
+
5
+ const DsInput = class {
6
+ constructor(hostRef) {
7
+ registerInstance(this, hostRef);
8
+ this.dsInput = createEvent(this, "dsInput");
9
+ }
10
+ inputEl;
11
+ value;
12
+ name;
13
+ type = "text";
14
+ placeholder;
15
+ disabled = false;
16
+ required = false;
17
+ invalid = false;
18
+ describedBy;
19
+ label;
20
+ size = "md";
21
+ dsInput;
22
+ watchValue(newValue) {
23
+ if (this.inputEl && this.inputEl.value !== (newValue ?? "")) {
24
+ this.inputEl.value = newValue ?? "";
25
+ }
26
+ }
27
+ componentDidLoad() {
28
+ if (this.inputEl && this.value !== undefined) {
29
+ this.inputEl.value = this.value;
30
+ }
31
+ }
32
+ onInput = (event) => {
33
+ const value = event.target.value;
34
+ this.dsInput.emit(value);
35
+ };
36
+ render() {
37
+ const cls = `ds-input ds-input--${this.size}`;
38
+ return (h(Host, { key: 'efce39c6ecfb8dda71577e7fb7b285ddc16287f5' }, h("input", { key: '5f6ad573f20e6eca20f42aa96c8acdf386508d1c', class: cls, type: this.type, name: this.name, placeholder: this.placeholder, disabled: this.disabled, "aria-label": this.label, "aria-required": this.required ? "true" : undefined, "aria-invalid": this.invalid ? "true" : undefined, "aria-describedby": this.describedBy, ref: (el) => (this.inputEl = el), onInput: this.onInput })));
39
+ }
40
+ static get watchers() { return {
41
+ "value": [{
42
+ "watchValue": 0
43
+ }]
44
+ }; }
45
+ };
46
+ DsInput.style = dsInputCss();
47
+
48
+ export { DsInput as ds_input };
@@ -0,0 +1,24 @@
1
+ import { r as registerInstance, h, H as Host } from './index-e-glNjK6.js';
2
+
3
+ const dsLoaderCss = () => `:host{display:inline-flex;color:currentColor;line-height:0}.ds-loader{display:block;width:40px;height:40px;color:inherit}.ds-loader--sm{width:16px;height:16px}.ds-loader--md{width:40px;height:40px}.ds-loader--lg{width:120px;height:120px}.ds-loader__half{transform-box:view-box;transform-origin:50% 50%;animation:ds-loader-swing 1.4s cubic-bezier(0.6, 0, 0.4, 1) infinite}.ds-loader__half--b{animation-name:ds-loader-swing-mirror}.ds-loader__mirror{transform-box:view-box;transform-origin:50% 50%;transform:scaleX(-1)}.ds-loader--speed-slow .ds-loader__half{animation-duration:2.2s}.ds-loader--speed-fast .ds-loader__half{animation-duration:0.9s}@keyframes ds-loader-swing{0%{transform:rotate(180deg)}50%{transform:rotate(0deg)}100%{transform:rotate(180deg)}}@keyframes ds-loader-swing-mirror{0%{transform:rotate(-180deg)}50%{transform:rotate(0deg)}100%{transform:rotate(-180deg)}}@media (prefers-reduced-motion: reduce){.ds-loader__half,.ds-loader__half--b{animation:ds-loader-pulse 2s ease-in-out infinite}@keyframes ds-loader-pulse{0%,100%{opacity:0.4;transform:rotate(0deg)}50%{opacity:1;transform:rotate(0deg)}}}`;
4
+
5
+ const DsLoader = class {
6
+ constructor(hostRef) {
7
+ registerInstance(this, hostRef);
8
+ }
9
+ size = "md";
10
+ label = "Loading";
11
+ speed = "normal";
12
+ render() {
13
+ const cls = [
14
+ "ds-loader",
15
+ `ds-loader--${this.size}`,
16
+ `ds-loader--speed-${this.speed}`,
17
+ ].join(" ");
18
+ return (h(Host, { key: 'd7017e7e3c970e27bffa30c193abd937c5ec13cd', role: "status", "aria-label": this.label }, h("svg", { key: '9eb10695249bc4c833b6347d38226fdc37d4be7d', class: cls, viewBox: "-48 -48 96 96", "aria-hidden": "true", focusable: "false" }, h("g", { key: '711ee60648593d216687087c5b2145ec25120bc5', class: "ds-loader__half ds-loader__half--a" }, h("path", { key: '9efdc31104b6037a57d7bdc802303938f7285666', d: LOGO_PATH_D, fill: "none", stroke: "currentColor", "stroke-width": "14", "stroke-linecap": "round", "stroke-linejoin": "round" })), h("g", { key: 'fcbeefc154e0e9db5b0378f77dafa3f9c0162e92', class: "ds-loader__half ds-loader__half--b" }, h("g", { key: '790b3ec1c4b262352cc383ab6b9f7d5cbb77474b', class: "ds-loader__mirror" }, h("path", { key: '694713be37532568852b2de2530cc50c1ff3b8de', d: LOGO_PATH_D, fill: "none", stroke: "currentColor", "stroke-width": "14", "stroke-linecap": "round", "stroke-linejoin": "round" }))))));
19
+ }
20
+ };
21
+ const LOGO_PATH_D = "M14.09 -27.22 L13.04 -28.53 L11.94 -29.76 L10.78 -30.92 L9.57 -32.01 L8.30 -33.02 L7.00 -33.95 L5.65 -34.80 L4.27 -35.57 L2.85 -36.25 L1.40 -36.84 L-0.07 -37.35 L-1.56 -37.76 L-3.07 -38.08 L-4.59 -38.31 L-6.13 -38.45 L-7.66 -38.50 L-9.20 -38.45 L-10.73 -38.31 L-12.25 -38.08 L-13.76 -37.76 L-15.25 -37.35 L-16.73 -36.84 L-18.17 -36.25 L-19.59 -35.57 L-20.97 -34.80 L-22.32 -33.95 L-23.63 -33.02 L-24.89 -32.01 L-26.10 -30.92 L-27.26 -29.76 L-28.37 -28.53 L-29.41 -27.22 L-30.40 -25.86 L-31.32 -24.42 L-32.17 -22.93 L-32.95 -21.39 L-33.66 -19.79 L-34.30 -18.15 L-34.86 -16.46 L-35.34 -14.73 L-35.74 -12.97 L-36.06 -11.18 L-36.29 -9.35 L-36.44 -7.51 L-36.50 -5.65 L-36.48 -3.77 L-36.37 -1.89 L-36.18 0 L-35.90 1.89 L-35.53 3.77 L-35.07 5.65 L-34.53 7.51 L-33.90 9.35 L-33.18 11.18 L-32.39 12.97 L-31.51 14.73 L-30.55 16.46 L-29.51 18.15 L-28.40 19.79 L-27.21 21.39 L-25.95 22.93 L-24.61 24.42 L-23.22 25.86 L-21.75 27.22 L-20.23 28.53 L-18.64 29.76 L-17.00 30.92 L-15.31 32.01 L-13.57 33.02 L-11.79 33.95 L-9.96 34.80 L-8.10 35.57 L-6.20 36.25 L-4.28 36.84 L-2.33 37.35 L-0.35 37.76 L1.63 38.08 L3.64 38.31 L5.65 38.45 L7.66 38.50 L9.68 38.45 L11.69 38.31 L13.69 38.08 L15.68 37.76 L17.65 37.35 L19.60 36.84 L21.53 36.25 L23.42 35.57 L25.28 34.80 L27.11 33.95 L28.89 33.02 L30.63 32.01 L32.32 30.92 L33.96 29.76 L35.55 28.53 L37.07 27.22";
22
+ DsLoader.style = dsLoaderCss();
23
+
24
+ export { DsLoader as ds_loader };
@@ -0,0 +1,83 @@
1
+ import { r as registerInstance, c as createEvent, h, H as Host } from './index-e-glNjK6.js';
2
+
3
+ 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))}`;
4
+
5
+ const DsSelect = class {
6
+ constructor(hostRef) {
7
+ registerInstance(this, hostRef);
8
+ this.dsChange = createEvent(this, "dsChange");
9
+ }
10
+ selectEl;
11
+ value;
12
+ name;
13
+ disabled = false;
14
+ size = "md";
15
+ label;
16
+ /**
17
+ * Options rendered inside the internal shadow `<select>`. Accepts either:
18
+ * - a JSON string (SSR-friendly — server-rendered HTML can only set
19
+ * string attributes, and Stencil does not JSON-parse array attributes),
20
+ * e.g. `options='[{"value":"en","label":"EN"}]'`
21
+ * - an array property set from client-side JS,
22
+ * e.g. `el.options = [{ value: 'en', label: 'EN' }]`
23
+ *
24
+ * Malformed JSON fails safe to an empty list rather than throwing, so the
25
+ * component still renders a visible (if empty) select.
26
+ */
27
+ options = "[]";
28
+ dsChange;
29
+ watchValue(newValue) {
30
+ if (this.selectEl && this.selectEl.value !== newValue) {
31
+ this.selectEl.value = newValue ?? "";
32
+ }
33
+ }
34
+ // Empty-bodied on purpose: `options` is already a @Prop, so Stencil
35
+ // schedules a re-render on its own whenever it changes — this watcher
36
+ // exists only to document that `options` is reactive. The actual value
37
+ // re-sync happens in componentDidUpdate, once the new <option> elements
38
+ // are actually in the DOM (syncing here, before that render lands, would
39
+ // assign `this.value` against the *old* option list and get dropped).
40
+ watchOptions() { }
41
+ componentDidLoad() {
42
+ this.syncValue();
43
+ }
44
+ componentDidUpdate() {
45
+ this.syncValue();
46
+ }
47
+ syncValue() {
48
+ if (this.selectEl && this.value !== undefined) {
49
+ this.selectEl.value = this.value;
50
+ }
51
+ }
52
+ parseOptions() {
53
+ if (typeof this.options === "string") {
54
+ try {
55
+ return JSON.parse(this.options);
56
+ }
57
+ catch {
58
+ console.warn("[ds-select] failed to parse options prop:", this.options);
59
+ return [];
60
+ }
61
+ }
62
+ return this.options;
63
+ }
64
+ onChange = (event) => {
65
+ const value = event.target.value;
66
+ this.dsChange.emit(value);
67
+ };
68
+ render() {
69
+ const cls = `ds-select ds-select--${this.size}`;
70
+ return (h(Host, { key: '9c5755ca98a3a3a1340414de0109133ffb6617c4' }, 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) => (h("option", { value: o.value }, o.label))))));
71
+ }
72
+ static get watchers() { return {
73
+ "value": [{
74
+ "watchValue": 0
75
+ }],
76
+ "options": [{
77
+ "watchOptions": 0
78
+ }]
79
+ }; }
80
+ };
81
+ DsSelect.style = dsSelectCss();
82
+
83
+ export { DsSelect as ds_select };
@@ -0,0 +1,136 @@
1
+ import { r as registerInstance, c as createEvent, h, H as Host } from './index-e-glNjK6.js';
2
+
3
+ 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}`;
4
+
5
+ const DsTabs = class {
6
+ constructor(hostRef) {
7
+ registerInstance(this, hostRef);
8
+ this.dsChange = createEvent(this, "dsChange");
9
+ }
10
+ tabRefs = new Map();
11
+ pendingFocusId;
12
+ items = "[]";
13
+ active;
14
+ orientation = "horizontal";
15
+ label;
16
+ dsChange;
17
+ watchItems() {
18
+ // Re-reconcile the active id when items change: if the current
19
+ // active is no longer in the list, fall back to the first enabled.
20
+ const parsed = this.parseItems();
21
+ if (parsed.length === 0)
22
+ return;
23
+ if (!parsed.some((it) => it.id === this.active && !it.disabled)) {
24
+ const firstEnabled = parsed.find((it) => !it.disabled);
25
+ if (firstEnabled) {
26
+ this.active = firstEnabled.id;
27
+ this.dsChange.emit(firstEnabled.id);
28
+ }
29
+ }
30
+ }
31
+ componentWillLoad() {
32
+ const parsed = this.parseItems();
33
+ if (parsed.length === 0)
34
+ return;
35
+ // Reconcile initial active — if the consumer passed an id that
36
+ // isn't in items (or none at all), fall back to the first enabled
37
+ // and emit dsChange once so their state matches ours.
38
+ if (!this.active || !parsed.some((it) => it.id === this.active && !it.disabled)) {
39
+ const firstEnabled = parsed.find((it) => !it.disabled);
40
+ if (firstEnabled) {
41
+ this.active = firstEnabled.id;
42
+ this.dsChange.emit(firstEnabled.id);
43
+ }
44
+ }
45
+ }
46
+ componentDidRender() {
47
+ // Move programmatic focus to the newly selected tab after
48
+ // arrow/Home/End nav so the visible focus ring tracks selection.
49
+ // Click-driven selection does not set pendingFocusId — the native
50
+ // button click already lands focus on the clicked element.
51
+ if (this.pendingFocusId) {
52
+ const target = this.tabRefs.get(this.pendingFocusId);
53
+ target?.focus();
54
+ this.pendingFocusId = undefined;
55
+ }
56
+ }
57
+ parseItems() {
58
+ if (typeof this.items === "string") {
59
+ try {
60
+ return JSON.parse(this.items);
61
+ }
62
+ catch {
63
+ console.warn("[ds-tabs] failed to parse items prop:", this.items);
64
+ return [];
65
+ }
66
+ }
67
+ return this.items;
68
+ }
69
+ enabledItems() {
70
+ return this.parseItems().filter((it) => !it.disabled);
71
+ }
72
+ selectAndFocus(id) {
73
+ if (id === this.active)
74
+ return;
75
+ this.active = id;
76
+ this.pendingFocusId = id;
77
+ this.dsChange.emit(id);
78
+ }
79
+ onClick = (id) => {
80
+ if (id === this.active)
81
+ return;
82
+ this.active = id;
83
+ // No pendingFocusId: click already focused the button natively.
84
+ this.dsChange.emit(id);
85
+ };
86
+ onKeyDown = (event, currentId) => {
87
+ const enabled = this.enabledItems();
88
+ if (enabled.length === 0)
89
+ return;
90
+ const isHorizontal = this.orientation === "horizontal";
91
+ const nextKey = isHorizontal ? "ArrowRight" : "ArrowDown";
92
+ const prevKey = isHorizontal ? "ArrowLeft" : "ArrowUp";
93
+ const currentIdx = enabled.findIndex((it) => it.id === currentId);
94
+ if (event.key === nextKey) {
95
+ event.preventDefault();
96
+ const nextIdx = (currentIdx + 1) % enabled.length;
97
+ this.selectAndFocus(enabled[nextIdx].id);
98
+ }
99
+ else if (event.key === prevKey) {
100
+ event.preventDefault();
101
+ const prevIdx = (currentIdx - 1 + enabled.length) % enabled.length;
102
+ this.selectAndFocus(enabled[prevIdx].id);
103
+ }
104
+ else if (event.key === "Home") {
105
+ event.preventDefault();
106
+ this.selectAndFocus(enabled[0].id);
107
+ }
108
+ else if (event.key === "End") {
109
+ event.preventDefault();
110
+ this.selectAndFocus(enabled[enabled.length - 1].id);
111
+ }
112
+ // Enter / Space intentionally not handled — automatic activation
113
+ // already selected the tab on focus move, and the native button
114
+ // click behavior remains available for consumers who bind to it.
115
+ };
116
+ render() {
117
+ const items = this.parseItems();
118
+ return (h(Host, { key: 'efc6a329ddbc14550f7e186480e41218f52b4865' }, 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) => {
119
+ const isActive = item.id === this.active;
120
+ return (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) => {
121
+ if (el)
122
+ this.tabRefs.set(item.id, el);
123
+ else
124
+ this.tabRefs.delete(item.id);
125
+ }, onClick: () => this.onClick(item.id), onKeyDown: (e) => this.onKeyDown(e, item.id) }, item.label));
126
+ }))));
127
+ }
128
+ static get watchers() { return {
129
+ "items": [{
130
+ "watchItems": 0
131
+ }]
132
+ }; }
133
+ };
134
+ DsTabs.style = dsTabsCss();
135
+
136
+ export { DsTabs as ds_tabs };
@@ -0,0 +1,48 @@
1
+ import { r as registerInstance, c as createEvent, h, H as Host } from './index-e-glNjK6.js';
2
+
3
+ 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)}`;
4
+
5
+ const DsTextarea = class {
6
+ constructor(hostRef) {
7
+ registerInstance(this, hostRef);
8
+ this.dsInput = createEvent(this, "dsInput");
9
+ }
10
+ textareaEl;
11
+ value;
12
+ name;
13
+ placeholder;
14
+ disabled = false;
15
+ required = false;
16
+ invalid = false;
17
+ describedBy;
18
+ label;
19
+ rows = 3;
20
+ size = "md";
21
+ dsInput;
22
+ watchValue(newValue) {
23
+ if (this.textareaEl && this.textareaEl.value !== (newValue ?? "")) {
24
+ this.textareaEl.value = newValue ?? "";
25
+ }
26
+ }
27
+ componentDidLoad() {
28
+ if (this.textareaEl && this.value !== undefined) {
29
+ this.textareaEl.value = this.value;
30
+ }
31
+ }
32
+ onInput = (event) => {
33
+ const value = event.target.value;
34
+ this.dsInput.emit(value);
35
+ };
36
+ render() {
37
+ const cls = `ds-textarea ds-textarea--${this.size}`;
38
+ return (h(Host, { key: '89e63314bca9f6f1b70f36c540a3ac48eed7311c' }, 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 })));
39
+ }
40
+ static get watchers() { return {
41
+ "value": [{
42
+ "watchValue": 0
43
+ }]
44
+ }; }
45
+ };
46
+ DsTextarea.style = dsTextareaCss();
47
+
48
+ export { DsTextarea as ds_textarea };
@@ -0,0 +1,231 @@
1
+ import { r as registerInstance, a as getElement, h, H as Host } from './index-e-glNjK6.js';
2
+
3
+ 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))}`;
4
+
5
+ /**
6
+ * ## Accessibility
7
+ *
8
+ * **Category:** state-machine (Tier 2)
9
+ * **APG pattern:** https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/
10
+ *
11
+ * Scratch build (there is no native tooltip element). Per the a11y
12
+ * spec §D ceremony: APG citation above, full keyboard enumeration
13
+ * and ARIA below, focus lifecycle in the tsx and spec.json, manual
14
+ * VoiceOver evidence pending (see commit message TODO).
15
+ *
16
+ * **Scope choice — wraps the consumer's first Element child as the
17
+ * trigger.** `<ds-tooltip label="Delete"><ds-button>×</ds-button>`
18
+ * — the first Element inside the ds-tooltip host is treated as the
19
+ * trigger. shadow:false so we can imperatively set `aria-describedby`
20
+ * on that light-DOM child (shadow-scoped ids can't be referenced
21
+ * from a light-DOM `aria-describedby`).
22
+ *
23
+ * **Consumer contract:** the first Element child MUST be focusable
24
+ * (`<button>`, `<a href>`, native form control, or an element with
25
+ * `tabindex="0"`) — otherwise keyboard users cannot summon the
26
+ * tooltip and the pattern fails WCAG 1.4.13. The component does not
27
+ * force focusability onto arbitrary children; that would produce
28
+ * silent AT surprises. The tooltip's `label` prop is required — a
29
+ * tooltip with no accessible text is inert.
30
+ *
31
+ * **Keyboard interactions (full APG enumeration):**
32
+ * - Focus (Tab into trigger): tooltip opens immediately (no
33
+ * `openDelay`). Delay-on-open is a mouse-hover ergonomic, not a
34
+ * keyboard one — waiting for keyboard users to see supplementary
35
+ * info is friction, not smoothing.
36
+ * - Escape (anywhere inside the tooltip's host, tooltip open):
37
+ * dismisses the tooltip WITHOUT moving focus. The trigger remains
38
+ * focused so the user can Tab away or re-summon. This is the WCAG
39
+ * 1.4.13 "dismissable" requirement.
40
+ * - Blur (Tab out of the trigger): tooltip closes immediately.
41
+ * - Enter / Space / arrow / printable: forwarded to the trigger
42
+ * (the tooltip does not intercept them). If Enter activates the
43
+ * underlying `<button>`, the button click closes the tooltip via
44
+ * the natural blur-then-refocus cycle.
45
+ *
46
+ * **Pointer interactions:**
47
+ * - mouseenter on the host → start `openDelay` timer → show.
48
+ * - mouseleave on the host → start `closeDelay` timer → hide.
49
+ * - Re-entering during the closeDelay window cancels the hide (the
50
+ * tooltip is "hoverable" — WCAG 1.4.13 — so users can move the
51
+ * pointer INTO the tooltip surface without it disappearing).
52
+ *
53
+ * **Persistence** (WCAG 1.4.13): the tooltip stays visible while
54
+ * the trigger is focused or hovered, and while the pointer is over
55
+ * the tooltip content itself. Dismissal only happens via Escape,
56
+ * blur, or genuine mouseleave (no residual hover on host or
57
+ * tooltip content).
58
+ *
59
+ * **ARIA attributes and value triggers:**
60
+ * - Tooltip element: `role="tooltip"`, `id` (auto-generated per
61
+ * instance so multiple tooltips on a page do not collide).
62
+ * - Trigger (the first Element child): `aria-describedby={tooltipId}`
63
+ * set on componentDidLoad and refreshed on slot mutations. We use
64
+ * describedby (APG default), NOT labelledby — the trigger has its
65
+ * own accessible name (its text or aria-label), and the tooltip
66
+ * supplements it.
67
+ *
68
+ * **Focus lifecycle:**
69
+ * - On mount: no auto-focus.
70
+ * - On trigger focus: tooltip opens immediately.
71
+ * - On trigger blur: tooltip closes.
72
+ * - On Escape while open: tooltip closes, focus stays on trigger.
73
+ * - The tooltip surface itself is NOT focusable — it is
74
+ * supplementary content, not an interactive region.
75
+ *
76
+ * **Motion:**
77
+ * - Animations: none applied by the component. Consumers who want a
78
+ * fade can style `[data-open="true"]` transitions gated on
79
+ * `prefers-reduced-motion: no-preference`.
80
+ *
81
+ * **Contrast:**
82
+ * - Tooltip surface: solid background via `Canvas` system color
83
+ * with `currentColor` text so it inherits the consumer theme's
84
+ * text color. Border uses `color-mix(currentColor 25%,
85
+ * transparent)`. Consumer theme owns the 4.5:1 text contrast and
86
+ * 3:1 non-text.
87
+ *
88
+ * **Screen reader announcement:**
89
+ * - Rendered state (closed): tooltip content is `hidden`, not in
90
+ * the a11y tree.
91
+ * - On focus: because the trigger has `aria-describedby`, AT reads
92
+ * the trigger's accessible name plus the tooltip text as a
93
+ * description. AT usually announces "…, [description]" after the
94
+ * trigger's role.
95
+ * - On Escape: the tooltip vanishes silently; AT falls back to
96
+ * announcing the trigger without its description on next
97
+ * interaction. This is APG behavior for dismissed tooltips.
98
+ *
99
+ * **Pending manual verification (see commit message TODO):**
100
+ * - VoiceOver on macOS: confirm the tooltip text is announced as a
101
+ * description of the trigger when the trigger gains focus.
102
+ * - VoiceOver: confirm Escape dismisses the tooltip and leaves the
103
+ * trigger focused; confirm re-focusing brings it back.
104
+ * - Chromium reduced-motion: confirm no residual animation is added
105
+ * by the component.
106
+ */
107
+ let tooltipIdCounter = 0;
108
+ const DsTooltip = class {
109
+ constructor(hostRef) {
110
+ registerInstance(this, hostRef);
111
+ }
112
+ get hostEl() { return getElement(this); }
113
+ label;
114
+ openDelay = 250;
115
+ closeDelay = 100;
116
+ placement = "bottom";
117
+ tooltipId = `ds-tooltip-${++tooltipIdCounter}`;
118
+ tooltipEl;
119
+ openTimer;
120
+ closeTimer;
121
+ isOpen = false;
122
+ watchLabel() {
123
+ if (this.tooltipEl) {
124
+ this.tooltipEl.textContent = this.label;
125
+ }
126
+ }
127
+ componentDidLoad() {
128
+ this.wireTrigger();
129
+ this.hostEl.addEventListener("mouseenter", this.onMouseEnter);
130
+ this.hostEl.addEventListener("mouseleave", this.onMouseLeave);
131
+ this.hostEl.addEventListener("focusin", this.onFocusIn);
132
+ this.hostEl.addEventListener("focusout", this.onFocusOut);
133
+ this.hostEl.addEventListener("keydown", this.onKeyDown);
134
+ }
135
+ disconnectedCallback() {
136
+ this.clearTimers();
137
+ this.hostEl.removeEventListener("mouseenter", this.onMouseEnter);
138
+ this.hostEl.removeEventListener("mouseleave", this.onMouseLeave);
139
+ this.hostEl.removeEventListener("focusin", this.onFocusIn);
140
+ this.hostEl.removeEventListener("focusout", this.onFocusOut);
141
+ this.hostEl.removeEventListener("keydown", this.onKeyDown);
142
+ }
143
+ wireTrigger() {
144
+ // First Element child within the host, ignoring our own tooltip
145
+ // <span> which we render at the end.
146
+ const children = Array.from(this.hostEl.children).filter((el) => el !== this.tooltipEl);
147
+ const trigger = children[0];
148
+ if (!trigger)
149
+ return;
150
+ trigger.setAttribute("aria-describedby", this.tooltipId);
151
+ }
152
+ clearTimers() {
153
+ if (this.openTimer !== undefined) {
154
+ window.clearTimeout(this.openTimer);
155
+ this.openTimer = undefined;
156
+ }
157
+ if (this.closeTimer !== undefined) {
158
+ window.clearTimeout(this.closeTimer);
159
+ this.closeTimer = undefined;
160
+ }
161
+ }
162
+ show(delay = 0) {
163
+ if (this.closeTimer !== undefined) {
164
+ window.clearTimeout(this.closeTimer);
165
+ this.closeTimer = undefined;
166
+ }
167
+ if (this.isOpen)
168
+ return;
169
+ if (delay === 0) {
170
+ this.applyOpen(true);
171
+ return;
172
+ }
173
+ if (this.openTimer !== undefined)
174
+ return;
175
+ this.openTimer = window.setTimeout(() => {
176
+ this.openTimer = undefined;
177
+ this.applyOpen(true);
178
+ }, delay);
179
+ }
180
+ hide(delay = 0) {
181
+ if (this.openTimer !== undefined) {
182
+ window.clearTimeout(this.openTimer);
183
+ this.openTimer = undefined;
184
+ }
185
+ if (!this.isOpen)
186
+ return;
187
+ if (delay === 0) {
188
+ this.applyOpen(false);
189
+ return;
190
+ }
191
+ if (this.closeTimer !== undefined)
192
+ return;
193
+ this.closeTimer = window.setTimeout(() => {
194
+ this.closeTimer = undefined;
195
+ this.applyOpen(false);
196
+ }, delay);
197
+ }
198
+ applyOpen(open) {
199
+ this.isOpen = open;
200
+ if (!this.tooltipEl)
201
+ return;
202
+ if (open) {
203
+ this.tooltipEl.removeAttribute("hidden");
204
+ this.tooltipEl.dataset.open = "true";
205
+ }
206
+ else {
207
+ this.tooltipEl.setAttribute("hidden", "");
208
+ this.tooltipEl.dataset.open = "false";
209
+ }
210
+ }
211
+ onMouseEnter = () => this.show(this.openDelay);
212
+ onMouseLeave = () => this.hide(this.closeDelay);
213
+ onFocusIn = () => this.show(0);
214
+ onFocusOut = () => this.hide(0);
215
+ onKeyDown = (event) => {
216
+ if (event.key === "Escape" && this.isOpen) {
217
+ this.hide(0);
218
+ }
219
+ };
220
+ render() {
221
+ return (h(Host, { key: 'e3822251c9edab36fdffa9178473823f3e9ae525' }, h("slot", { key: 'f7c490f42ae09a739d8d91d32c2394dbdef03aa5' }), 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)));
222
+ }
223
+ static get watchers() { return {
224
+ "label": [{
225
+ "watchLabel": 0
226
+ }]
227
+ }; }
228
+ };
229
+ DsTooltip.style = dsTooltipCss();
230
+
231
+ export { DsTooltip as ds_tooltip };