@solid-design-system/components 1.35.1 → 1.37.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 (154) hide show
  1. package/dist/components/es/checkbox-group.js +1 -1
  2. package/dist/components/es/checkbox.js +1 -1
  3. package/dist/components/es/form.js +1 -1
  4. package/dist/components/es/input.js +1 -1
  5. package/dist/components/es/option.js +1 -1
  6. package/dist/components/es/radio-button.js +1 -0
  7. package/dist/components/es/radio-group.js +1 -1
  8. package/dist/components/es/radio.js +1 -1
  9. package/dist/components/es/select.js +2 -2
  10. package/dist/components/es/solid-components2.js +1 -1
  11. package/dist/components/es/solid-element.js +1 -1
  12. package/dist/components/es/switch.js +1 -1
  13. package/dist/components/es/textarea.js +1 -1
  14. package/dist/components/umd/solid-components.js +19 -19
  15. package/dist/custom-elements.json +1 -1
  16. package/dist/package/components/checkbox/checkbox.d.ts +2 -0
  17. package/dist/package/components/checkbox/checkbox.js +23 -6
  18. package/dist/package/components/checkbox-group/checkbox-group.js +1 -1
  19. package/dist/package/components/input/input.d.ts +3 -0
  20. package/dist/package/components/input/input.js +20 -19
  21. package/dist/package/components/option/option.js +0 -2
  22. package/dist/package/components/radio/radio.js +3 -3
  23. package/dist/package/components/radio-button/radio-button.d.ts +25 -0
  24. package/dist/package/components/radio-button/radio-button.js +118 -0
  25. package/dist/package/components/radio-group/radio-group.d.ts +4 -3
  26. package/dist/package/components/radio-group/radio-group.js +26 -26
  27. package/dist/package/components/select/select.d.ts +3 -3
  28. package/dist/package/components/select/select.js +18 -23
  29. package/dist/package/components/switch/switch.d.ts +2 -0
  30. package/dist/package/components/switch/switch.js +15 -7
  31. package/dist/package/components/textarea/textarea.d.ts +3 -0
  32. package/dist/package/components/textarea/textarea.js +30 -24
  33. package/dist/package/internal/form.d.ts +3 -1
  34. package/dist/package/internal/form.js +38 -10
  35. package/dist/package/internal/solid-element.d.ts +2 -0
  36. package/dist/package/solid-components.d.ts +1 -0
  37. package/dist/package/solid-components.js +20 -18
  38. package/dist/package/styles/tailwind.css.js +1 -1
  39. package/dist/versioned-components/es/accordion-group.js +1 -1
  40. package/dist/versioned-components/es/accordion.js +1 -1
  41. package/dist/versioned-components/es/badge.js +1 -1
  42. package/dist/versioned-components/es/brandshape.js +1 -1
  43. package/dist/versioned-components/es/button.js +1 -1
  44. package/dist/versioned-components/es/carousel-item.js +1 -1
  45. package/dist/versioned-components/es/carousel.js +3 -3
  46. package/dist/versioned-components/es/checkbox-group.js +1 -1
  47. package/dist/versioned-components/es/checkbox.js +1 -1
  48. package/dist/versioned-components/es/divider.js +1 -1
  49. package/dist/versioned-components/es/drawer.js +1 -1
  50. package/dist/versioned-components/es/dropdown.js +1 -1
  51. package/dist/versioned-components/es/form.js +1 -1
  52. package/dist/versioned-components/es/header.js +1 -1
  53. package/dist/versioned-components/es/icon.js +1 -1
  54. package/dist/versioned-components/es/include.js +1 -1
  55. package/dist/versioned-components/es/input.js +1 -1
  56. package/dist/versioned-components/es/link.js +1 -1
  57. package/dist/versioned-components/es/navigation-item.js +1 -1
  58. package/dist/versioned-components/es/notification.js +1 -1
  59. package/dist/versioned-components/es/option.js +1 -1
  60. package/dist/versioned-components/es/popup.js +1 -1
  61. package/dist/versioned-components/es/radio-button.js +1 -0
  62. package/dist/versioned-components/es/radio-group.js +1 -1
  63. package/dist/versioned-components/es/radio.js +1 -1
  64. package/dist/versioned-components/es/select.js +2 -2
  65. package/dist/versioned-components/es/solid-components2.js +1 -1
  66. package/dist/versioned-components/es/solid-element.js +1 -1
  67. package/dist/versioned-components/es/spinner.js +1 -1
  68. package/dist/versioned-components/es/switch.js +1 -1
  69. package/dist/versioned-components/es/tag.js +1 -1
  70. package/dist/versioned-components/es/teaser.js +1 -1
  71. package/dist/versioned-components/es/textarea.js +1 -1
  72. package/dist/versioned-components/es/tooltip.js +2 -2
  73. package/dist/versioned-components/es/video.js +1 -1
  74. package/dist/versioned-package/_components/button-group/button-group.d.ts +1 -1
  75. package/dist/versioned-package/_components/button-group/button-group.js +11 -11
  76. package/dist/versioned-package/components/accordion/accordion.d.ts +1 -1
  77. package/dist/versioned-package/components/accordion/accordion.js +2 -2
  78. package/dist/versioned-package/components/accordion-group/accordion-group.d.ts +1 -1
  79. package/dist/versioned-package/components/accordion-group/accordion-group.js +3 -3
  80. package/dist/versioned-package/components/badge/badge.d.ts +1 -1
  81. package/dist/versioned-package/components/badge/badge.js +1 -1
  82. package/dist/versioned-package/components/brandshape/brandshape.d.ts +1 -1
  83. package/dist/versioned-package/components/brandshape/brandshape.js +1 -1
  84. package/dist/versioned-package/components/button/button.d.ts +1 -1
  85. package/dist/versioned-package/components/button/button.js +4 -4
  86. package/dist/versioned-package/components/carousel/carousel.d.ts +1 -1
  87. package/dist/versioned-package/components/carousel/carousel.js +6 -6
  88. package/dist/versioned-package/components/carousel-item/carousel-item.d.ts +1 -1
  89. package/dist/versioned-package/components/carousel-item/carousel-item.js +1 -1
  90. package/dist/versioned-package/components/checkbox/checkbox.d.ts +3 -1
  91. package/dist/versioned-package/components/checkbox/checkbox.js +27 -10
  92. package/dist/versioned-package/components/checkbox-group/checkbox-group.d.ts +1 -1
  93. package/dist/versioned-package/components/checkbox-group/checkbox-group.js +6 -6
  94. package/dist/versioned-package/components/divider/divider.d.ts +1 -1
  95. package/dist/versioned-package/components/divider/divider.js +2 -2
  96. package/dist/versioned-package/components/drawer/drawer.d.ts +1 -1
  97. package/dist/versioned-package/components/drawer/drawer.js +2 -2
  98. package/dist/versioned-package/components/dropdown/dropdown.d.ts +1 -1
  99. package/dist/versioned-package/components/dropdown/dropdown.js +8 -8
  100. package/dist/versioned-package/components/header/header.d.ts +1 -1
  101. package/dist/versioned-package/components/header/header.js +4 -4
  102. package/dist/versioned-package/components/icon/icon.d.ts +1 -1
  103. package/dist/versioned-package/components/icon/icon.js +1 -1
  104. package/dist/versioned-package/components/include/include.d.ts +1 -1
  105. package/dist/versioned-package/components/include/include.js +1 -1
  106. package/dist/versioned-package/components/input/input.d.ts +4 -1
  107. package/dist/versioned-package/components/input/input.js +23 -22
  108. package/dist/versioned-package/components/link/link.d.ts +1 -1
  109. package/dist/versioned-package/components/link/link.js +2 -2
  110. package/dist/versioned-package/components/navigation-item/navigation-item.d.ts +1 -1
  111. package/dist/versioned-package/components/navigation-item/navigation-item.js +3 -3
  112. package/dist/versioned-package/components/notification/notification.d.ts +1 -1
  113. package/dist/versioned-package/components/notification/notification.js +5 -5
  114. package/dist/versioned-package/components/option/option.d.ts +1 -1
  115. package/dist/versioned-package/components/option/option.js +2 -4
  116. package/dist/versioned-package/components/popup/popup.d.ts +1 -1
  117. package/dist/versioned-package/components/popup/popup.js +1 -1
  118. package/dist/versioned-package/components/radio/radio.d.ts +1 -1
  119. package/dist/versioned-package/components/radio/radio.js +5 -5
  120. package/dist/versioned-package/components/radio-button/radio-button.d.ts +25 -0
  121. package/dist/versioned-package/components/radio-button/radio-button.js +118 -0
  122. package/dist/versioned-package/components/radio-group/radio-group.d.ts +6 -5
  123. package/dist/versioned-package/components/radio-group/radio-group.js +39 -39
  124. package/dist/versioned-package/components/select/select.d.ts +7 -7
  125. package/dist/versioned-package/components/select/select.js +44 -49
  126. package/dist/versioned-package/components/spinner/spinner.d.ts +1 -1
  127. package/dist/versioned-package/components/spinner/spinner.js +1 -1
  128. package/dist/versioned-package/components/switch/switch.d.ts +3 -1
  129. package/dist/versioned-package/components/switch/switch.js +17 -9
  130. package/dist/versioned-package/components/tag/tag.d.ts +1 -1
  131. package/dist/versioned-package/components/tag/tag.js +2 -2
  132. package/dist/versioned-package/components/teaser/teaser.js +1 -1
  133. package/dist/versioned-package/components/textarea/textarea.d.ts +4 -1
  134. package/dist/versioned-package/components/textarea/textarea.js +32 -26
  135. package/dist/versioned-package/components/tooltip/tooltip.d.ts +1 -1
  136. package/dist/versioned-package/components/tooltip/tooltip.js +5 -5
  137. package/dist/versioned-package/components/video/video.d.ts +1 -1
  138. package/dist/versioned-package/components/video/video.js +2 -2
  139. package/dist/versioned-package/internal/form.d.ts +3 -1
  140. package/dist/versioned-package/internal/form.js +40 -12
  141. package/dist/versioned-package/internal/solid-element.d.ts +2 -0
  142. package/dist/versioned-package/solid-components.d.ts +1 -0
  143. package/dist/versioned-package/solid-components.js +20 -18
  144. package/dist/versioned-package/styles/tailwind.css.js +1 -1
  145. package/dist/versioned-styles/solid-styles.css +1 -1
  146. package/dist/vscode.html-custom-data.json +107 -33
  147. package/dist/web-types.json +177 -18
  148. package/package.json +5 -4
  149. package/dist/components/es/form-control.styles.js +0 -1
  150. package/dist/package/styles/form-control.styles.d.ts +0 -2
  151. package/dist/package/styles/form-control.styles.js +0 -5
  152. package/dist/versioned-components/es/form-control.styles.js +0 -1
  153. package/dist/versioned-package/styles/form-control.styles.d.ts +0 -2
  154. package/dist/versioned-package/styles/form-control.styles.js +0 -5
@@ -13,7 +13,6 @@ import { waitForEvent } from "../../internal/event.js";
13
13
  import { watch } from "../../internal/watch.js";
14
14
  import componentStyles from "../../styles/component.styles.js";
15
15
  import cx from "classix";
16
- import formControlStyles from "../../styles/form-control.styles.js";
17
16
  import SdIcon from "../icon/icon.js";
18
17
  import SdPopup from "../popup/popup.js";
19
18
  import SdTag from "../tag/tag.js";
@@ -42,12 +41,12 @@ let SdSelect = class extends SolidElement {
42
41
  this.hasHover = false;
43
42
  this.displayLabel = "";
44
43
  this.selectedOptions = [];
45
- this.isValid = false;
46
- this.isInvalid = false;
44
+ this.showValidStyle = false;
45
+ this.showInvalidStyle = false;
47
46
  this.defaultValue = "";
48
47
  this.open = false;
49
48
  this.size = "lg";
50
- this.label = "Label";
49
+ this.label = "";
51
50
  this.placeholder = this.localize.term("selectDefaultPlaceholder");
52
51
  this.helpText = "";
53
52
  this.placement = "bottom";
@@ -187,15 +186,6 @@ let SdSelect = class extends SolidElement {
187
186
  this.applySizeToOptions();
188
187
  this.open = false;
189
188
  }
190
- /** Checks for the presence of the attributes 'data-user-valid' or 'data-user-invalid' and updates the corresponding state for reactive conditional styling. */
191
- updated() {
192
- if (this.hasAttribute("data-user-valid") && this.checkValidity()) {
193
- this.isValid = true;
194
- }
195
- if (this.hasAttribute("data-user-invalid") && !this.checkValidity()) {
196
- this.isInvalid = true;
197
- }
198
- }
199
189
  addOpenListeners() {
200
190
  document.addEventListener("focusin", this.handleDocumentFocusIn);
201
191
  document.addEventListener("keydown", this.handleDocumentKeyDown);
@@ -373,6 +363,7 @@ let SdSelect = class extends SolidElement {
373
363
  handleInvalid(event) {
374
364
  this.formControlController.setValidity(false);
375
365
  this.formControlController.emitInvalidEvent(event);
366
+ this.invalidMessage.textContent = event.target.validationMessage;
376
367
  }
377
368
  handleMouseEnter() {
378
369
  this.hasHover = true;
@@ -494,7 +485,7 @@ let SdSelect = class extends SolidElement {
494
485
  const hasLabel = this.label ? true : !!slots["label"];
495
486
  const hasHelpText = this.helpText ? true : !!slots["helpText"];
496
487
  const hasClearIcon = this.clearable && !this.disabled && this.value.length > 0;
497
- const selectState = this.disabled ? "disabled" : this.hasFocus && this.isInvalid ? "activeInvalid" : this.hasFocus && this.isValid ? "activeValid" : this.hasFocus || this.open ? "active" : this.isInvalid ? "invalid" : this.isValid ? "valid" : "default";
488
+ const selectState = this.disabled ? "disabled" : this.hasFocus && this.showInvalidStyle ? "activeInvalid" : this.hasFocus && this.showValidStyle ? "activeValid" : this.hasFocus || this.open ? "active" : this.showInvalidStyle ? "invalid" : this.showValidStyle ? "valid" : "default";
498
489
  const cursorStyles = this.disabled ? "cursor-not-allowed" : "cursor-pointer";
499
490
  const iconMarginLeft = { sm: "ml-1", md: "ml-2", lg: "ml-2" }[this.size];
500
491
  const iconSize = {
@@ -503,9 +494,12 @@ let SdSelect = class extends SolidElement {
503
494
  lg: "text-xl"
504
495
  }[this.size];
505
496
  return html`<div part="form-control" class="${cx(
506
- "form-control relative text-left",
497
+ "relative text-left",
507
498
  cursorStyles,
508
499
  this.size === "sm" ? "text-sm" : "text-base",
500
+ this.open && "z-50"
501
+ )}"><label id="label" part="form-control-label" class="${hasLabel && "inline-block mb-2"}" aria-hidden="${hasLabel ? "false" : "true"}" @click="${this.handleLabelClick}"><slot name="label">${this.label}</slot></label><div part="form-control-input" class="${cx(
502
+ "relative w-full bg-white",
509
503
  {
510
504
  disabled: "text-neutral-500",
511
505
  readonly: "text-black",
@@ -515,9 +509,8 @@ let SdSelect = class extends SolidElement {
515
509
  invalid: "text-error",
516
510
  valid: "text-success",
517
511
  default: "text-black"
518
- }[selectState],
519
- this.open && "z-10"
520
- )}"><label id="label" part="form-control-label" class="${hasLabel && "inline-block mb-2"}" aria-hidden="${hasLabel ? "false" : "true"}" @click="${this.handleLabelClick}"><slot name="label" class="${cx(this.disabled && "text-black")}">${this.label}</slot></label><div part="form-control-input" class="${cx("relative w-full bg-white")}"><div part="border" class="${cx(
512
+ }[selectState]
513
+ )}"><div part="border" class="${cx(
521
514
  "absolute top-0 w-full h-full pointer-events-none border rounded-default",
522
515
  this.hasHover && "bg-neutral-200",
523
516
  {
@@ -545,10 +538,10 @@ let SdSelect = class extends SolidElement {
545
538
  "appearance-none outline-none flex-grow bg-transparent",
546
539
  cursorStyles,
547
540
  this.multiple && this.useTags && this.value.length > 0 ? "hidden" : ""
548
- )}" type="text" placeholder="${this.placeholder}" .disabled="${this.disabled}" .value="${this.displayLabel}" autocomplete="off" spellcheck="false" autocapitalize="off" readonly="readonly" aria-controls="listbox" aria-expanded="${this.open ? "true" : "false"}" aria-haspopup="listbox" aria-labelledby="label" aria-disabled="${this.disabled ? "true" : "false"}" aria-describedby="help-text" role="combobox" tabindex="0" @focus="${this.handleFocus}" @blur="${this.handleBlur}"> ${this.multiple && this.useTags ? html`<div part="tags" class="flex-grow flex flex-wrap items-center gap-1">${this.tags}</div>` : ""} <input class="${cx("value-input absolute top-0 left-0 w-full h-full opacity-0 -z-10", cursorStyles)}" type="text" ?disabled="${this.disabled}" ?required="${this.required}" .value="${Array.isArray(this.value) ? this.value.join(", ") : this.value}" tabindex="-1" aria-hidden="true" @focus="${() => this.focus()}" @invalid="${this.handleInvalid}"> ${hasClearIcon ? html`<button part="clear-button" class="${cx("select__clear flex justify-center", iconMarginLeft)}" type="button" aria-label="${this.localize.term("clearEntry")}" @mousedown="${this.handleClearMouseDown}" @click="${this.handleClearClick}" tabindex="-1"><slot name="clear-icon"><sd-icon class="${cx("text-neutral-500", iconSize)}" library="system" name="closing-round"></sd-icon></slot></button>` : ""} ${this.isInvalid ? html`<sd-icon class="${cx("text-error", iconMarginLeft, iconSize)}" library="system" name="risk"></sd-icon>` : ""} ${this.isValid ? html`<sd-icon class="${cx("text-success", iconMarginLeft, iconSize)}" library="system" name="confirm"></sd-icon>` : ""}<slot name="expand-icon" part="expand-icon" class="${cx("inline-flex ml-2 transition-all", this.open ? "rotate-180" : "rotate-0", iconSize)}"><sd-icon name="chevron-down" part="chevron" library="system" color="currentColor"></sd-icon></slot></div><div id="listbox" role="listbox" aria-expanded="${this.open ? "true" : "false"}" aria-multiselectable="${this.multiple ? "true" : "false"}" aria-labelledby="label" part="listbox" class="${cx(
541
+ )}" type="text" placeholder="${this.placeholder}" .disabled="${this.disabled}" .value="${this.displayLabel}" autocomplete="off" spellcheck="false" autocapitalize="off" readonly="readonly" aria-controls="listbox" aria-expanded="${this.open ? "true" : "false"}" aria-haspopup="listbox" aria-labelledby="label" aria-disabled="${this.disabled ? "true" : "false"}" aria-describedby="help-text" role="combobox" tabindex="0" @focus="${this.handleFocus}" @blur="${this.handleBlur}"> ${this.multiple && this.useTags ? html`<div part="tags" class="flex-grow flex flex-wrap items-center gap-1">${this.tags}</div>` : ""} <input class="${cx("value-input absolute top-0 left-0 w-full h-full opacity-0 -z-10", cursorStyles)}" type="text" ?disabled="${this.disabled}" ?required="${this.required}" .value="${Array.isArray(this.value) ? this.value.join(", ") : this.value}" tabindex="-1" aria-hidden="true" @focus="${() => this.focus()}" @invalid="${this.handleInvalid}"> ${hasClearIcon ? html`<button part="clear-button" class="${cx("select__clear flex justify-center", iconMarginLeft)}" type="button" aria-label="${this.localize.term("clearEntry")}" @mousedown="${this.handleClearMouseDown}" @click="${this.handleClearClick}" tabindex="-1"><slot name="clear-icon"><sd-icon class="${cx("text-neutral-500", iconSize)}" library="system" name="closing-round"></sd-icon></slot></button>` : ""} ${this.showInvalidStyle ? html`<sd-icon class="${cx("text-error", iconMarginLeft, iconSize)}" library="system" name="risk"></sd-icon>` : ""} ${this.showValidStyle ? html`<sd-icon class="${cx("text-success", iconMarginLeft, iconSize)}" library="system" name="confirm"></sd-icon>` : ""}<slot name="expand-icon" part="expand-icon" class="${cx("inline-flex ml-2 transition-all", this.open ? "rotate-180" : "rotate-0", iconSize)}"><sd-icon name="chevron-down" part="chevron" library="system" color="currentColor"></sd-icon></slot></div><div id="listbox" role="listbox" aria-expanded="${this.open ? "true" : "false"}" aria-multiselectable="${this.multiple ? "true" : "false"}" aria-labelledby="label" part="listbox" class="${cx(
549
542
  "bg-white px-2 py-3 relative",
550
543
  this.currentPlacement === "bottom" ? "border-r-2 border-b-2 border-l-2 rounded-br-default rounded-bl-default" : "border-r-2 border-t-2 border-l-2 rounded-tr-default rounded-tl-default"
551
- )}" tabindex="-1" @mouseup="${this.handleOptionClick}" @slotchange="${this.handleDefaultSlotChange}"><slot></slot></div></sd-popup></div><div class="text-sm text-neutral-700" part="form-control-help-text" id="help-text" aria-hidden="${hasHelpText ? "false" : "true"}"><slot name="help-text">${this.helpText}</slot></div></div>`;
544
+ )}" tabindex="-1" @mouseup="${this.handleOptionClick}" @slotchange="${this.handleDefaultSlotChange}"><slot></slot></div></sd-popup></div><div class="text-sm text-neutral-700" part="form-control-help-text" id="help-text" aria-hidden="${hasHelpText ? "false" : "true"}"><slot name="help-text">${this.helpText}</slot></div></div>${this.formControlController.renderInvalidMessage()}`;
552
545
  }
553
546
  };
554
547
  SdSelect.dependencies = {
@@ -558,7 +551,6 @@ SdSelect.dependencies = {
558
551
  };
559
552
  SdSelect.styles = [
560
553
  componentStyles,
561
- formControlStyles,
562
554
  SolidElement.styles,
563
555
  css`:host{position:relative;display:block;width:100%}:host([required]) #label::after{content:' *'}sd-popup::part(popup){overflow-y:scroll}sd-tag::part(base){border-radius:var(--sd-border-radius-default,.25rem);padding-left:var(--sd-spacing-1,.25rem);padding-right:var(--sd-spacing-1,.25rem)}sd-tag[size=lg]::part(base){padding-left:var(--sd-spacing-2,.5rem);padding-right:var(--sd-spacing-2,.5rem)}sd-tag[disabled=false]::part(base):hover{--tw-bg-opacity:1;background-color:rgb(var(--sd-color-primary-100,236 240 249) / var(--tw-bg-opacity))}`
564
556
  ];
@@ -580,6 +572,9 @@ __decorateClass([
580
572
  __decorateClass([
581
573
  query('[part="listbox"]')
582
574
  ], SdSelect.prototype, "listbox", 2);
575
+ __decorateClass([
576
+ query("#invalid-message")
577
+ ], SdSelect.prototype, "invalidMessage", 2);
583
578
  __decorateClass([
584
579
  state()
585
580
  ], SdSelect.prototype, "hasFocus", 2);
@@ -597,10 +592,10 @@ __decorateClass([
597
592
  ], SdSelect.prototype, "selectedOptions", 2);
598
593
  __decorateClass([
599
594
  state()
600
- ], SdSelect.prototype, "isValid", 2);
595
+ ], SdSelect.prototype, "showValidStyle", 2);
601
596
  __decorateClass([
602
597
  state()
603
- ], SdSelect.prototype, "isInvalid", 2);
598
+ ], SdSelect.prototype, "showInvalidStyle", 2);
604
599
  __decorateClass([
605
600
  defaultValue()
606
601
  ], SdSelect.prototype, "defaultValue", 2);
@@ -3,6 +3,8 @@ import type { SolidFormControl } from '../../internal/solid-element';
3
3
  export default class SdSwitch extends SolidElement implements SolidFormControl {
4
4
  private readonly formControlController;
5
5
  input: HTMLInputElement;
6
+ invalidMessage: HTMLDivElement;
7
+ showInvalidStyle: boolean;
6
8
  title: string;
7
9
  name: string;
8
10
  value: string;
@@ -4,7 +4,7 @@ import { defaultValue } from "../../internal/default-value.js";
4
4
  import { FormControlController } from "../../internal/form.js";
5
5
  import { ifDefined } from "lit/directives/if-defined.js";
6
6
  import { live } from "lit/directives/live.js";
7
- import { query, property } from "lit/decorators.js";
7
+ import { query, state, property } from "lit/decorators.js";
8
8
  import { watch } from "../../internal/watch.js";
9
9
  import cx from "classix";
10
10
  import SolidElement from "../../internal/solid-element.js";
@@ -27,6 +27,7 @@ let SdSwitch = class extends SolidElement {
27
27
  defaultValue: (control) => control.defaultChecked,
28
28
  setValue: (control, checked) => control.checked = checked
29
29
  });
30
+ this.showInvalidStyle = false;
30
31
  this.title = "";
31
32
  this.name = "";
32
33
  this.disabled = false;
@@ -55,6 +56,7 @@ let SdSwitch = class extends SolidElement {
55
56
  handleInvalid(event) {
56
57
  this.formControlController.setValidity(false);
57
58
  this.formControlController.emitInvalidEvent(event);
59
+ this.invalidMessage.textContent = event.target.validationMessage;
58
60
  }
59
61
  handleFocus() {
60
62
  this.emit("sd-focus");
@@ -107,23 +109,29 @@ let SdSwitch = class extends SolidElement {
107
109
  `relative flex flex-initial items-center justify-center border rounded-full h-4 w-8 transition-colors ease duration-100
108
110
  peer-focus-visible:outline peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2
109
111
  peer-focus-visible:outline-primary`,
110
- this.disabled && this.checked && "border-neutral-500 bg-neutral-500" || this.disabled && "border-neutral-500" || this.checked && "border-accent bg-accent hover:bg-accent-550 group-hover:bg-accent-550" || "border-neutral-800 bg-white hover:bg-neutral-200 group-hover:bg-neutral-200"
112
+ this.disabled && this.checked ? "border-neutral-500 bg-neutral-500" : this.disabled ? "border-neutral-500" : this.showInvalidStyle ? "border-error bg-error hover:bg-error-400" : this.checked ? "border-accent bg-accent hover:bg-accent-550 group-hover:bg-accent-550" : "border-neutral-800 bg-white hover:bg-neutral-200 group-hover:bg-neutral-200"
111
113
  )}"><span id="thumb" part="thumb" class="${cx(
112
114
  "w-2.5 h-2.5 rounded-full transition-transform ease-in-out duration-200",
113
- this.checked && "translate-x-2 bg-white" || this.disabled && this.checked && "bg-white" || this.disabled && "-translate-x-2 bg-neutral-500" || "bg-neutral-800 -translate-x-2"
115
+ this.disabled && this.checked ? "bg-white" : this.disabled ? "-translate-x-2 bg-neutral-500" : this.showInvalidStyle ? "bg-white -translate-x-2" : this.checked ? "translate-x-2 bg-white" : "bg-neutral-800 -translate-x-2"
114
116
  )}"></span> </span><span part="label" id="label" class="${cx(
115
- "select-none inline-block ml-2 text-black",
116
- this.disabled && "text-neutral-500" || "text-neutral-800"
117
- )}"><slot></slot></span></label>`;
117
+ "select-none inline-block ml-2",
118
+ this.disabled ? "text-neutral-500" : this.showInvalidStyle ? "text-error" : "text-black"
119
+ )}"><slot></slot></span></label> ${this.formControlController.renderInvalidMessage()}`;
118
120
  }
119
121
  };
120
122
  SdSwitch.styles = [
121
123
  SolidElement.styles,
122
- css`:host{display:block}:host(:focus-visible){outline:2px solid transparent;outline-offset:2px}:host([required]) #label::after{content:' *'}:host([data-user-invalid]) #label{color:rgb(var(--sd-color-error,204 25 55))}:host([data-user-invalid]) #control{border-color:rgb(var(--sd-color-error,204 25 55));background-color:rgb(var(--sd-color-error,204 25 55))}:host([data-user-invalid]) #thumb{background-color:rgb(var(--sd-white,255 255 255))}:host([data-user-invalid]) #input:hover~#control{background-color:rgb(var(--sd-color-error-400,172 25 56))}`
124
+ css`:host{display:block}:host(:focus-visible){outline:2px solid transparent;outline-offset:2px}:host([required]) #label::after{content:' *'}`
123
125
  ];
124
126
  __decorateClass([
125
127
  query("input")
126
128
  ], SdSwitch.prototype, "input", 2);
129
+ __decorateClass([
130
+ query("#invalid-message")
131
+ ], SdSwitch.prototype, "invalidMessage", 2);
132
+ __decorateClass([
133
+ state()
134
+ ], SdSwitch.prototype, "showInvalidStyle", 2);
127
135
  __decorateClass([
128
136
  property()
129
137
  ], SdSwitch.prototype, "title", 2);
@@ -4,7 +4,10 @@ export default class SdTextarea extends SolidElement implements SolidFormControl
4
4
  private readonly formControlController;
5
5
  private readonly hasSlotController;
6
6
  textarea: HTMLTextAreaElement;
7
+ invalidMessage: HTMLDivElement;
7
8
  private hasFocus;
9
+ showValidStyle: boolean;
10
+ showInvalidStyle: boolean;
8
11
  title: string;
9
12
  name: string;
10
13
  value: string;
@@ -7,8 +7,8 @@ import { ifDefined } from "lit/directives/if-defined.js";
7
7
  import { live } from "lit/directives/live.js";
8
8
  import { query, state, property } from "lit/decorators.js";
9
9
  import { watch } from "../../internal/watch.js";
10
+ import componentStyles from "../../styles/component.styles.js";
10
11
  import cx from "classix";
11
- import formControlStyles from "../../styles/form-control.styles.js";
12
12
  import SolidElement from "../../internal/solid-element.js";
13
13
  var __defProp = Object.defineProperty;
14
14
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -27,6 +27,8 @@ let SdTextarea = class extends SolidElement {
27
27
  this.formControlController = new FormControlController(this);
28
28
  this.hasSlotController = new HasSlotController(this, "help-text", "label");
29
29
  this.hasFocus = false;
30
+ this.showValidStyle = false;
31
+ this.showInvalidStyle = false;
30
32
  this.title = "";
31
33
  this.name = "";
32
34
  this.value = "";
@@ -83,6 +85,7 @@ let SdTextarea = class extends SolidElement {
83
85
  handleInvalid(event) {
84
86
  this.formControlController.setValidity(false);
85
87
  this.formControlController.emitInvalidEvent(event);
88
+ this.invalidMessage.textContent = event.target.validationMessage;
86
89
  }
87
90
  setTextareaHeight() {
88
91
  this.textarea.style.height = void 0;
@@ -164,17 +167,14 @@ let SdTextarea = class extends SolidElement {
164
167
  };
165
168
  const hasLabel = this.label ? true : !!slots["label"];
166
169
  const hasHelpText = this.helpText ? true : !!slots["helpText"];
167
- const hasValidationAttr = this.required || !!this.minlength || !!this.maxlength;
168
- const isInvalid = hasValidationAttr && !this.checkValidity();
169
- const isValid = hasValidationAttr && this.checkValidity();
170
- const inputState = this.disabled ? "disabled" : this.readonly ? "readonly" : this.hasFocus && isInvalid ? "activeInvalid" : this.hasFocus && isValid ? "activeValid" : this.hasFocus ? "active" : isInvalid ? "invalid" : isValid ? "valid" : "default";
170
+ const textareaState = this.disabled ? "disabled" : this.readonly ? "readonly" : this.hasFocus && this.showInvalidStyle ? "activeInvalid" : this.hasFocus && this.showValidStyle ? "activeValid" : this.hasFocus ? "active" : this.showInvalidStyle ? "invalid" : this.showValidStyle ? "valid" : "default";
171
171
  const textSize = this.size === "sm" ? "text-sm" : "text-base";
172
- return html`<div part="form-control" class="${cx(
173
- "form-control text-left",
174
- hasLabel && "form-control--has-label",
175
- hasHelpText && "form-control--has-help-text",
176
- this.disabled && "cursor-not-allowed"
177
- )}"><label part="form-control-label" id="label" class="${cx("form-control-label mb-2", hasLabel ? "has-label inline-block" : "hidden", textSize)}" for="input" aria-hidden="${hasLabel ? "false" : "true"}"><slot name="label">${this.label}</slot></label><div part="form-control-input" class="form-control-input relative w-full"><div part="border" class="${cx(
172
+ const iconSizeMarginLeft = {
173
+ sm: "text-base ml-1",
174
+ md: "text-lg ml-2",
175
+ lg: "text-xl ml-2"
176
+ }[this.size];
177
+ return html`<div part="form-control" class="text-left"><label part="form-control-label" id="label" class="${cx("mb-2", hasLabel ? "inline-block" : "hidden", textSize)}" for="input" aria-hidden="${hasLabel ? "false" : "true"}"><slot name="label">${this.label}</slot></label><div part="form-control-input" class="${cx("relative w-full", this.disabled && "cursor-not-allowed")}"><div part="border" class="${cx(
178
178
  "absolute w-full h-full pointer-events-none border rounded-default",
179
179
  {
180
180
  disabled: "border-neutral-500",
@@ -185,9 +185,9 @@ let SdTextarea = class extends SolidElement {
185
185
  invalid: "border-error",
186
186
  valid: "border-success",
187
187
  default: "border-neutral-800"
188
- }[inputState]
188
+ }[textareaState]
189
189
  )}"></div><div part="base" class="${cx(
190
- "textarea px-4 flex flex-row items-center rounded-default",
190
+ "textarea px-4 flex items-top rounded-default bg-white group",
191
191
  {
192
192
  sm: "textarea-sm py-1",
193
193
  md: "textarea-md py-1",
@@ -202,30 +202,36 @@ let SdTextarea = class extends SolidElement {
202
202
  invalid: "text-error",
203
203
  valid: "text-success",
204
204
  default: "text-black"
205
- }[inputState],
205
+ }[textareaState],
206
206
  !this.disabled && !this.readonly ? "hover:bg-neutral-200" : "",
207
- this.readonly && "bg-neutral-100",
208
- isInvalid && "form-control-input--invalid",
209
- !this.value && "textarea--empty"
207
+ this.readonly && "bg-neutral-100"
210
208
  )}"><textarea part="textarea" id="input" class="${cx(
211
209
  "flex-grow focus:outline-none bg-transparent placeholder-neutral-700 resize-none",
212
- textSize,
213
- this.disabled && "cursor-not-allowed"
214
- )}" title="${this.title}" name="${ifDefined(this.name)}" .value="${live(this.value)}" ?disabled="${this.disabled}" ?readonly="${this.readonly}" ?required="${this.required}" placeholder="${ifDefined(this.placeholder)}" minlength="${ifDefined(this.minlength)}" maxlength="${ifDefined(this.maxlength)}" rows="${ifDefined(this.rows)}" autocapitalize="${ifDefined(this.autocapitalize)}" autocorrect="${ifDefined(this.autocorrect)}" ?autofocus="${this.autofocus}" spellcheck="${ifDefined(this.spellcheck)}" enterkeyhint="${ifDefined(this.enterkeyhint)}" inputmode="${ifDefined(this.inputmode)}" aria-describedby="help-text" @change="${this.handleChange}" @input="${this.handleInput}" @invalid="${this.handleInvalid}" @focus="${this.handleFocus}" @blur="${this.handleBlur}"></textarea></div></div><slot name="help-text" part="form-control-help-text" id="help-text" class="${cx("text-sm text-neutral-700", hasHelpText ? "block" : "hidden")}" aria-hidden="${hasHelpText ? "false" : "true"}">${this.helpText}</slot></div>`;
210
+ this.disabled && "cursor-not-allowed",
211
+ textSize
212
+ )}" title="${this.title}" name="${ifDefined(this.name)}" .value="${live(this.value)}" ?disabled="${this.disabled}" ?readonly="${this.readonly}" ?required="${this.required}" placeholder="${ifDefined(this.placeholder)}" minlength="${ifDefined(this.minlength)}" maxlength="${ifDefined(this.maxlength)}" rows="${ifDefined(this.rows)}" autocapitalize="${ifDefined(this.autocapitalize)}" autocorrect="${ifDefined(this.autocorrect)}" ?autofocus="${this.autofocus}" spellcheck="${ifDefined(this.spellcheck)}" enterkeyhint="${ifDefined(this.enterkeyhint)}" inputmode="${ifDefined(this.inputmode)}" aria-describedby="help-text" @change="${this.handleChange}" @input="${this.handleInput}" @invalid="${this.handleInvalid}" @focus="${this.handleFocus}" @blur="${this.handleBlur}"></textarea> ${this.showInvalidStyle ? html`<sd-icon class="${cx("text-error absolute right-4 bg-white group-hover:bg-neutral-200", iconSizeMarginLeft)}" library="system" name="risk"></sd-icon>` : ""} ${this.showValidStyle ? html`<sd-icon class="${cx("text-success absolute right-4 bg-white group-hover:bg-neutral-200", iconSizeMarginLeft)}" library="system" name="confirm"></sd-icon>` : ""}</div></div><slot name="help-text" part="form-control-help-text" id="help-text" class="${cx("text-sm text-neutral-700", hasHelpText ? "block" : "hidden")}" aria-hidden="${hasHelpText ? "false" : "true"}">${this.helpText}</slot></div>${this.formControlController.renderInvalidMessage()}`;
215
213
  }
216
214
  };
217
215
  SdTextarea.styles = [
218
- // componentStyles,
219
- formControlStyles,
216
+ componentStyles,
220
217
  SolidElement.styles,
221
- css`:host{display:block}:host([required]) #label.has-label::after{content:'*';margin-left:var(--sd-spacing-0-5,.125rem)}.no-scrollbar::-webkit-scrollbar{display:none}`
218
+ css`:host{display:block}:host([required]) #label::after{content:' *'}.no-scrollbar::-webkit-scrollbar{display:none}`
222
219
  ];
223
220
  __decorateClass([
224
- query("[part=textarea]")
221
+ query("#input")
225
222
  ], SdTextarea.prototype, "textarea", 2);
223
+ __decorateClass([
224
+ query("#invalid-message")
225
+ ], SdTextarea.prototype, "invalidMessage", 2);
226
226
  __decorateClass([
227
227
  state()
228
228
  ], SdTextarea.prototype, "hasFocus", 2);
229
+ __decorateClass([
230
+ state()
231
+ ], SdTextarea.prototype, "showValidStyle", 2);
232
+ __decorateClass([
233
+ state()
234
+ ], SdTextarea.prototype, "showInvalidStyle", 2);
229
235
  __decorateClass([
230
236
  property()
231
237
  ], SdTextarea.prototype, "title", 2);
@@ -1,4 +1,4 @@
1
- import type { ReactiveController, ReactiveControllerHost } from 'lit';
1
+ import { type ReactiveController, type ReactiveControllerHost } from 'lit';
2
2
  import type { SolidFormControl } from '../internal/solid-element';
3
3
  import type SdButton from '../components/button/button';
4
4
  export declare const formCollections: WeakMap<HTMLFormElement, Set<SolidFormControl>>;
@@ -29,7 +29,9 @@ export declare class FormControlController implements ReactiveController {
29
29
  private reportFormValidity;
30
30
  private setUserInteracted;
31
31
  private doAction;
32
+ updateValidityStyle(): void;
32
33
  getForm(): HTMLFormElement | null;
34
+ renderInvalidMessage(): import("lit-html").TemplateResult<1>;
33
35
  reset(invoker?: HTMLInputElement | SdButton): void;
34
36
  submit(invoker?: HTMLInputElement | SdButton): void;
35
37
  setValidity(isValid: boolean): void;
@@ -1,3 +1,4 @@
1
+ import { html } from "lit";
1
2
  const formCollections = /* @__PURE__ */ new WeakMap();
2
3
  const reportValidityOverloads = /* @__PURE__ */ new WeakMap();
3
4
  const userInteractedControls = /* @__PURE__ */ new WeakMap();
@@ -20,7 +21,7 @@ class FormControlController {
20
21
  }
21
22
  };
22
23
  this.handleFormSubmit = (event) => {
23
- var _a;
24
+ var _a, _b;
24
25
  const disabled = this.options.disabled(this.host);
25
26
  const reportValidity = this.options.reportValidity;
26
27
  if (this.form && !this.form.noValidate) {
@@ -31,6 +32,16 @@ class FormControlController {
31
32
  if (this.form && !this.form.noValidate && !disabled && !reportValidity(this.host)) {
32
33
  event.preventDefault();
33
34
  event.stopImmediatePropagation();
35
+ const invalidElements = (_b = this.form) == null ? void 0 : _b.querySelectorAll("[data-invalid]");
36
+ const sdRadioGroups = Array.from(invalidElements).filter(
37
+ (element) => element.tagName.toLowerCase() === "sd-radio-group"
38
+ );
39
+ sdRadioGroups.forEach((radioGroup) => {
40
+ var _a2, _b2;
41
+ (_b2 = (_a2 = radioGroup.shadowRoot) == null ? void 0 : _a2.querySelector("input")) == null ? void 0 : _b2.dispatchEvent(new Event("invalid"));
42
+ });
43
+ if (invalidElements == null ? void 0 : invalidElements.length)
44
+ invalidElements[0].focus();
34
45
  }
35
46
  };
36
47
  this.handleFormReset = () => {
@@ -98,6 +109,7 @@ class FormControlController {
98
109
  }
99
110
  if (this.host.hasUpdated) {
100
111
  this.setValidity((_a = this.host) == null ? void 0 : _a.validity.valid);
112
+ this.updateValidityStyle();
101
113
  }
102
114
  }
103
115
  attachForm(form) {
@@ -174,10 +186,30 @@ class FormControlController {
174
186
  button.remove();
175
187
  }
176
188
  }
189
+ /** Checks for the presence of the attributes 'data-user-valid' or 'data-user-invalid' on the host form element and updates its corresponding style state. */
190
+ updateValidityStyle() {
191
+ if (this.host.hasAttribute("data-user-valid") && this.host.checkValidity()) {
192
+ if (this.host.showValidStyle !== void 0)
193
+ this.host.showValidStyle = true;
194
+ this.host.showInvalidStyle = false;
195
+ } else if (this.host.hasAttribute("data-user-invalid") && !this.host.checkValidity()) {
196
+ if (this.host.showValidStyle !== void 0)
197
+ this.host.showValidStyle = false;
198
+ this.host.showInvalidStyle = true;
199
+ } else {
200
+ if (this.host.showValidStyle !== void 0)
201
+ this.host.showValidStyle = false;
202
+ this.host.showInvalidStyle = false;
203
+ }
204
+ }
177
205
  /** Returns the associated `<form>` element, if one exists. */
178
206
  getForm() {
179
207
  return this.form ?? null;
180
208
  }
209
+ /** Returns a styled `<div>` element to display inline validation messages via its `textContent` property when a form element is invalid. */
210
+ renderInvalidMessage() {
211
+ return html`<div id="invalid-message" class="text-error text-sm mt-2 text-left" part="error-message" aria-live="polite" ?hidden="${!this.host.showInvalidStyle}"></div>`;
212
+ }
181
213
  /** Resets the form, restoring all the control to their default value */
182
214
  reset(invoker) {
183
215
  this.doAction("reset", invoker);
@@ -220,24 +252,20 @@ class FormControlController {
220
252
  this.setValidity(host == null ? void 0 : host.validity.valid);
221
253
  }
222
254
  /**
223
- * Dispatches a non-bubbling, cancelable custom event of type `sl-invalid`.
224
- * If the `sl-invalid` event will be cancelled then the original `invalid`
225
- * event (which may have been passed as argument) will also be cancelled.
226
- * If no original `invalid` event has been passed then the `sl-invalid`
255
+ * Dispatches a non-bubbling, cancelable custom event of type `sd-invalid`.
256
+ * If no original `invalid` event has been passed then the `sd-invalid`
227
257
  * event will be cancelled before being dispatched.
228
258
  */
229
259
  emitInvalidEvent(originalInvalidEvent) {
230
- const slInvalidEvent = new CustomEvent("sd-invalid", {
260
+ originalInvalidEvent == null ? void 0 : originalInvalidEvent.preventDefault();
261
+ const sdInvalidEvent = new CustomEvent("sd-invalid", {
231
262
  bubbles: false,
232
263
  composed: false,
233
264
  cancelable: true,
234
265
  detail: {}
235
266
  });
236
267
  if (!originalInvalidEvent) {
237
- slInvalidEvent.preventDefault();
238
- }
239
- if (!this.host.dispatchEvent(slInvalidEvent)) {
240
- originalInvalidEvent == null ? void 0 : originalInvalidEvent.preventDefault();
268
+ sdInvalidEvent.preventDefault();
241
269
  }
242
270
  }
243
271
  }
@@ -25,4 +25,6 @@ export interface SolidFormControl extends SolidElement {
25
25
  checkValidity: () => boolean;
26
26
  reportValidity: () => boolean;
27
27
  setCustomValidity: (message: string) => void;
28
+ showValidStyle?: boolean;
29
+ showInvalidStyle?: boolean;
28
30
  }
@@ -20,6 +20,7 @@ export { default as SdNotification } from './components/notification/notificatio
20
20
  export { default as SdOption } from './components/option/option';
21
21
  export { default as SdPopup } from './components/popup/popup';
22
22
  export { default as SdRadio } from './components/radio/radio';
23
+ export { default as SdRadioButton } from './components/radio-button/radio-button';
23
24
  export { default as SdRadioGroup } from './components/radio-group/radio-group';
24
25
  export { default as SdSelect } from './components/select/select';
25
26
  export { default as SdSpinner } from './components/spinner/spinner';
@@ -20,15 +20,16 @@ import { default as default20 } from "./components/notification/notification.js"
20
20
  import { default as default21 } from "./components/option/option.js";
21
21
  import { default as default22 } from "./components/popup/popup.js";
22
22
  import { default as default23 } from "./components/radio/radio.js";
23
- import { default as default24 } from "./components/radio-group/radio-group.js";
24
- import { default as default25 } from "./components/select/select.js";
25
- import { default as default26 } from "./components/spinner/spinner.js";
26
- import { default as default27 } from "./components/switch/switch.js";
27
- import { default as default28 } from "./components/tag/tag.js";
28
- import { default as default29 } from "./components/teaser/teaser.js";
29
- import { default as default30 } from "./components/textarea/textarea.js";
30
- import { default as default31 } from "./components/tooltip/tooltip.js";
31
- import { default as default32 } from "./components/video/video.js";
23
+ import { default as default24 } from "./components/radio-button/radio-button.js";
24
+ import { default as default25 } from "./components/radio-group/radio-group.js";
25
+ import { default as default26 } from "./components/select/select.js";
26
+ import { default as default27 } from "./components/spinner/spinner.js";
27
+ import { default as default28 } from "./components/switch/switch.js";
28
+ import { default as default29 } from "./components/tag/tag.js";
29
+ import { default as default30 } from "./components/teaser/teaser.js";
30
+ import { default as default31 } from "./components/textarea/textarea.js";
31
+ import { default as default32 } from "./components/tooltip/tooltip.js";
32
+ import { default as default33 } from "./components/video/video.js";
32
33
  import { registerIconLibrary, unregisterIconLibrary } from "./components/icon/library.js";
33
34
  import { LocalizeController } from "./utilities/localize.js";
34
35
  export {
@@ -55,15 +56,16 @@ export {
55
56
  default21 as SdOption,
56
57
  default22 as SdPopup,
57
58
  default23 as SdRadio,
58
- default24 as SdRadioGroup,
59
- default25 as SdSelect,
60
- default26 as SdSpinner,
61
- default27 as SdSwitch,
62
- default28 as SdTag,
63
- default29 as SdTeaser,
64
- default30 as SdTextarea,
65
- default31 as SdTooltip,
66
- default32 as SdVideo,
59
+ default24 as SdRadioButton,
60
+ default25 as SdRadioGroup,
61
+ default26 as SdSelect,
62
+ default27 as SdSpinner,
63
+ default28 as SdSwitch,
64
+ default29 as SdTag,
65
+ default30 as SdTeaser,
66
+ default31 as SdTextarea,
67
+ default32 as SdTooltip,
68
+ default33 as SdVideo,
67
69
  registerIconLibrary,
68
70
  unregisterIconLibrary
69
71
  };