@felleslosninger/minid-elements 0.0.126 → 0.0.127

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 (55) hide show
  1. package/README.md +37 -22
  2. package/dist/components/button.component.d.ts +7 -2
  3. package/dist/components/button.component.d.ts.map +1 -1
  4. package/dist/components/button.js +4 -8
  5. package/dist/components/button.js.map +1 -1
  6. package/dist/components/checkbox.component.d.ts +6 -0
  7. package/dist/components/checkbox.component.d.ts.map +1 -1
  8. package/dist/components/checkbox.js +31 -0
  9. package/dist/components/checkbox.js.map +1 -1
  10. package/dist/components/radio-button.component.d.ts +1 -1
  11. package/dist/components/radio-button.component.d.ts.map +1 -1
  12. package/dist/components/radio-button.js +3 -3
  13. package/dist/components/radio-button.js.map +1 -1
  14. package/dist/components/radio-group.component.d.ts +13 -5
  15. package/dist/components/radio-group.component.d.ts.map +1 -1
  16. package/dist/components/radio-group.js +75 -59
  17. package/dist/components/radio-group.js.map +1 -1
  18. package/dist/components/radio.component.d.ts +9 -7
  19. package/dist/components/radio.component.d.ts.map +1 -1
  20. package/dist/components/radio.js +45 -80
  21. package/dist/components/radio.js.map +1 -1
  22. package/dist/designsystemet-tailwind.css +9 -1
  23. package/dist/icons/arrow-right-left.svg +1 -1
  24. package/dist/icons/cpu-fill.svg +3 -0
  25. package/dist/icons/cpu.svg +3 -0
  26. package/dist/icons/expand-vertical.svg +3 -0
  27. package/dist/icons/expand.svg +1 -1
  28. package/dist/icons/file-jpeg-fill.svg +5 -0
  29. package/dist/icons/file-jpeg.svg +4 -0
  30. package/dist/icons/file-png-fill.svg +6 -0
  31. package/dist/icons/file-png.svg +4 -0
  32. package/dist/icons/line-height.svg +3 -0
  33. package/dist/icons/medical-thermometer-fill.svg +3 -0
  34. package/dist/icons/medical-thermometer.svg +3 -0
  35. package/dist/icons/questionmark-circle-fill.svg +3 -0
  36. package/dist/icons/questionmark-circle.svg +3 -0
  37. package/dist/icons/seal-xmark.svg +1 -1
  38. package/dist/icons/shield-checkmark-fill.svg +3 -0
  39. package/dist/icons/shield-checkmark.svg +3 -0
  40. package/dist/icons/shrink.svg +1 -1
  41. package/dist/icons/sort-down.svg +3 -0
  42. package/dist/icons/sort-up.svg +3 -0
  43. package/dist/icons/space-horizontal.svg +3 -0
  44. package/dist/icons/space-vertical.svg +3 -0
  45. package/dist/icons/square-grid-fill.svg +3 -0
  46. package/dist/icons/square-grid.svg +3 -0
  47. package/dist/icons/thumb-down-fill.svg +1 -1
  48. package/dist/icons/thumb-down.svg +1 -1
  49. package/dist/icons/truck-percent-fill.svg +3 -0
  50. package/dist/icons/truck-percent.svg +3 -0
  51. package/dist/mixins/tailwind.mixin.js +1 -1
  52. package/dist/mixins/tailwind.mixin.js.map +1 -1
  53. package/dist/types/icon-name.d.ts +1 -1
  54. package/dist/types/icon-name.d.ts.map +1 -1
  55. package/package.json +1 -1
@@ -2,9 +2,11 @@ import { css, LitElement, html } from "lit";
2
2
  import { property, state, customElement } from "lit/decorators.js";
3
3
  import { styled } from "../mixins/tailwind.mixin.js";
4
4
  import "./label.js";
5
- import { ConstraintsValidationMixin } from "../mixins/form-controller.mixin.js";
6
5
  import { classMap } from "lit/directives/class-map.js";
7
6
  import { watch } from "../internal/watch.js";
7
+ import { FormControlMixin } from "../mixins/form-control.mixin.js";
8
+ import { HasSlotController } from "../internal/slot.js";
9
+ import { requiredValidator } from "../mixins/validators.js";
8
10
  var __defProp = Object.defineProperty;
9
11
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
10
12
  var __decorateClass = (decorators, target, key, kind) => {
@@ -20,34 +22,42 @@ const styles = [
20
22
  :host {
21
23
  display: block;
22
24
  }
23
-
24
- .fds-label {
25
- margin-bottom: 1rem;
26
- }
27
25
  `
28
26
  ];
29
- let MinidRadioGroup = class extends ConstraintsValidationMixin(
27
+ let MinidRadioGroup = class extends FormControlMixin(
30
28
  styled(LitElement, styles)
31
29
  ) {
32
30
  constructor() {
33
31
  super(...arguments);
34
- this.name = "option";
32
+ this.hasSlotController = new HasSlotController(this, "label");
33
+ this.validationId = `radio-group-${MinidRadioGroup._uniqueId++}`;
34
+ this.name = null;
35
35
  this.value = null;
36
36
  this.label = "";
37
- this.size = "md";
38
37
  this.labelhidden = false;
39
38
  this.disabled = false;
39
+ this.required = false;
40
+ this.invalidmessage = "";
40
41
  this.hasButtonRadios = false;
41
42
  this.defaultValue = null;
42
43
  }
44
+ get validationTarget() {
45
+ const radio = this.querySelector(
46
+ ":is(mid-radio):not([disabled])"
47
+ );
48
+ return radio ?? void 0;
49
+ }
50
+ static get formcontrolValidators() {
51
+ return [requiredValidator];
52
+ }
43
53
  firstUpdated(_changedProperties) {
44
54
  super.firstUpdated(_changedProperties);
45
55
  this.defaultValue = this.value;
46
- this.setFormValue(this.value);
56
+ this.setValue(this.value);
47
57
  }
48
- formResetCallback() {
58
+ resetFormControl() {
49
59
  this.value = this.defaultValue;
50
- this.setFormValue(this.value);
60
+ this.setValue(this.value);
51
61
  this.updateCheckedRadio();
52
62
  }
53
63
  async syncRadioElements() {
@@ -60,7 +70,6 @@ let MinidRadioGroup = class extends ConstraintsValidationMixin(
60
70
  radios.map(async (radio) => {
61
71
  await radio.updateComplete;
62
72
  radio.checked = radio.value === this.value;
63
- radio.size = this.size;
64
73
  })
65
74
  );
66
75
  if (radios.length > 0 && !radios.some((radio) => radio.checked)) {
@@ -70,7 +79,7 @@ let MinidRadioGroup = class extends ConstraintsValidationMixin(
70
79
  buttonRadio.setAttribute("tabindex", "0");
71
80
  }
72
81
  } else {
73
- radios[0].element.setAttribute("tabindex", "0");
82
+ radios[0].input.setAttribute("tabindex", "0");
74
83
  }
75
84
  }
76
85
  }
@@ -110,14 +119,14 @@ let MinidRadioGroup = class extends ConstraintsValidationMixin(
110
119
  this.getAllRadios().forEach((radio) => {
111
120
  radio.checked = false;
112
121
  if (!this.hasButtonRadios) {
113
- radio.element.setAttribute("tabindex", "-1");
122
+ radio.input.setAttribute("tabindex", "-1");
114
123
  }
115
124
  });
116
125
  this.value = radios[index].value;
117
126
  radios[index].checked = true;
118
- this.setFormValue(this.value);
127
+ this.setValue(this.value);
119
128
  if (!this.hasButtonRadios) {
120
- radios[index].element.setAttribute("tabindex", "0");
129
+ radios[index].input.setAttribute("tabindex", "0");
121
130
  radios[index].focus();
122
131
  } else {
123
132
  radios[index].shadowRoot.querySelector("button").focus();
@@ -133,11 +142,7 @@ let MinidRadioGroup = class extends ConstraintsValidationMixin(
133
142
  event.preventDefault();
134
143
  }
135
144
  getAllRadios() {
136
- return Array.from(
137
- this.querySelectorAll(
138
- "mid-radio, mid-radio-button"
139
- )
140
- );
145
+ return Array.from(this.querySelectorAll("mid-radio"));
141
146
  }
142
147
  updateCheckedRadio() {
143
148
  const radios = this.getAllRadios();
@@ -155,7 +160,7 @@ let MinidRadioGroup = class extends ConstraintsValidationMixin(
155
160
  return;
156
161
  }
157
162
  this.value = target.value;
158
- this.setFormValue(this.value);
163
+ this.setValue(this.value);
159
164
  this.updateCheckedRadio();
160
165
  if (this.value !== oldValue) {
161
166
  this.dispatchEvent(
@@ -186,6 +191,11 @@ let MinidRadioGroup = class extends ConstraintsValidationMixin(
186
191
  }
187
192
  });
188
193
  }
194
+ handleInvalidChange() {
195
+ this.getAllRadios().forEach((radio) => {
196
+ radio.invalid = !!this.invalidmessage;
197
+ });
198
+ }
189
199
  /**
190
200
  * Sets focus on the radio-group.
191
201
  */
@@ -199,52 +209,52 @@ let MinidRadioGroup = class extends ConstraintsValidationMixin(
199
209
  }
200
210
  }
201
211
  render() {
212
+ const hasLabelSlot = this.hasSlotController.test("label");
213
+ const hasLabel = this.label ? true : !!hasLabelSlot;
202
214
  return html`
203
- <label
204
- part="form-control-label"
205
- id="label"
206
- class="class=${classMap({
207
- "fds-label": true,
208
- "fds-label--spacing": true,
209
- "fds-label--sm": this.size === "sm",
210
- "fds-label--md": this.size === "md",
211
- "fds-label--lg": this.size === "lg",
212
- "sr-only": this.labelhidden
213
- })}"
214
- @click=${this.handleLabelClick}
215
- >
216
- ${this.label}
217
- </label>
218
215
  <fieldset
219
- class="${classMap({
220
- "fds-togglegroup": this.hasButtonRadios
221
- })} flex"
216
+ class="flex flex-col gap-2"
222
217
  part="form-control"
223
218
  role="radiogroup"
224
219
  aria-labelledby="label"
220
+ aria-errormessage="${this.validationId}"
225
221
  >
226
- <div
227
- class="${classMap({
228
- grid: true,
229
- "gap-3": true,
230
- "fds-togglegroup__content": this.hasButtonRadios
231
- })}"
232
- part="base"
233
- role="presentation"
234
- aria-label=${this.label}
222
+ <label
223
+ part="form-control-label"
224
+ id="label"
225
+ class="class=${classMap({
226
+ "sr-only": this.labelhidden,
227
+ "mb-2": hasLabel
228
+ })} mid-label"
229
+ @click=${this.handleLabelClick}
235
230
  >
236
- <slot
237
- @slotchange=${this.syncRadios}
238
- @click=${this.handleRadioClick}
239
- @keydown=${this.handleKeyDown}
240
- ></slot>
241
- </div>
231
+ <slot name="label">${this.label}</slot>
232
+ </label>
233
+ <slot
234
+ class="flex flex-col flex-wrap gap-3.5"
235
+ @slotchange=${this.syncRadios}
236
+ @click=${this.handleRadioClick}
237
+ @keydown=${this.handleKeyDown}
238
+ ></slot>
242
239
  </fieldset>
240
+ <div
241
+ class="text-danger-subtle mt-2 flex gap-1"
242
+ id="${this.validationId}"
243
+ aria-live="polite"
244
+ ?hidden=${!this.invalidmessage}
245
+ >
246
+ <mid-icon
247
+ name="xmark-octagon-fill"
248
+ class="mt-1 min-h-6 min-w-6"
249
+ ></mid-icon>
250
+ ${this.invalidmessage}
251
+ </div>
243
252
  `;
244
253
  }
245
254
  };
255
+ MinidRadioGroup._uniqueId = 0;
246
256
  __decorateClass([
247
- property()
257
+ property({ reflect: true })
248
258
  ], MinidRadioGroup.prototype, "name", 2);
249
259
  __decorateClass([
250
260
  property({ reflect: true })
@@ -252,15 +262,18 @@ __decorateClass([
252
262
  __decorateClass([
253
263
  property()
254
264
  ], MinidRadioGroup.prototype, "label", 2);
255
- __decorateClass([
256
- property()
257
- ], MinidRadioGroup.prototype, "size", 2);
258
265
  __decorateClass([
259
266
  property({ type: Boolean })
260
267
  ], MinidRadioGroup.prototype, "labelhidden", 2);
261
268
  __decorateClass([
262
269
  property({ type: Boolean })
263
270
  ], MinidRadioGroup.prototype, "disabled", 2);
271
+ __decorateClass([
272
+ property({ type: Boolean, reflect: true })
273
+ ], MinidRadioGroup.prototype, "required", 2);
274
+ __decorateClass([
275
+ property()
276
+ ], MinidRadioGroup.prototype, "invalidmessage", 2);
264
277
  __decorateClass([
265
278
  state()
266
279
  ], MinidRadioGroup.prototype, "hasButtonRadios", 2);
@@ -276,6 +289,9 @@ __decorateClass([
276
289
  __decorateClass([
277
290
  watch("disabled")
278
291
  ], MinidRadioGroup.prototype, "handleDisabledChange", 1);
292
+ __decorateClass([
293
+ watch("invalidmessage")
294
+ ], MinidRadioGroup.prototype, "handleInvalidChange", 1);
279
295
  MinidRadioGroup = __decorateClass([
280
296
  customElement("mid-radio-group")
281
297
  ], MinidRadioGroup);
@@ -1 +1 @@
1
- {"version":3,"file":"radio-group.js","sources":["../../src/components/radio-group.component.ts"],"sourcesContent":["import { css, html, LitElement, type PropertyValues } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { styled } from '../mixins/tailwind.mixin';\nimport './label.component';\nimport { ConstraintsValidationMixin } from '../mixins/form-controller.mixin';\nimport { MinidRadioButton } from '../components/radio-button.component';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { watch } from '../internal/watch';\nimport { MinidRadio } from '../components/radio.component';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-radio-group': MinidRadioGroup;\n }\n}\n\nconst styles = [\n css`\n :host {\n display: block;\n }\n\n .fds-label {\n margin-bottom: 1rem;\n }\n `,\n];\n\n/**\n *\n * @slot -- The default slot where `<mid-radio>` or `<mid-radio-button>` elements are placed.\n *\n * @event mid-change - Emitted when the selected value changes\n * @event mid-input - Emitted when radio group recieves input\n *\n * @csspart form-control-label - Select the label element\n * @csspart form-control - Select the fieldset containing the radios\n * @csspart base - Select the container around the radios\n */\n@customElement('mid-radio-group')\nexport class MinidRadioGroup extends ConstraintsValidationMixin(\n styled(LitElement, styles)\n) {\n /**\n * The name of the radio group.\n */\n @property()\n name = 'option';\n\n /**\n * The current value of the radio group.\n */\n @property({ reflect: true })\n value: string | null = null;\n\n @property()\n label = '';\n\n @property()\n size: 'sm' | 'md' | 'lg' = 'md';\n\n @property({ type: Boolean })\n labelhidden = false;\n\n @property({ type: Boolean })\n disabled = false;\n\n @state()\n private hasButtonRadios = false;\n\n @state()\n defaultValue: string | null = null;\n\n protected firstUpdated(_changedProperties: PropertyValues): void {\n super.firstUpdated(_changedProperties);\n this.defaultValue = this.value;\n this.setFormValue(this.value);\n }\n\n protected formResetCallback() {\n this.value = this.defaultValue;\n this.setFormValue(this.value);\n this.updateCheckedRadio();\n }\n\n private async syncRadioElements() {\n const radios = this.getAllRadios();\n this.hasButtonRadios = radios.some(\n (radio) => radio.tagName.toLowerCase() === 'mid-radio-button'\n );\n\n await Promise.all(\n // Sync the checked state and size\n radios.map(async (radio) => {\n await radio.updateComplete;\n radio.checked = radio.value === this.value;\n radio.size = this.size;\n })\n );\n\n if (radios.length > 0 && !radios.some((radio) => radio.checked)) {\n if (this.hasButtonRadios) {\n const buttonRadio = radios[0].shadowRoot?.querySelector('button');\n if (buttonRadio) {\n buttonRadio.setAttribute('tabindex', '0');\n }\n } else {\n radios[0].element.setAttribute('tabindex', '0');\n }\n }\n }\n\n private syncRadios() {\n if (\n customElements.get('mid-radio') &&\n customElements.get('mid-radio-button')\n ) {\n this.syncRadioElements();\n return;\n }\n\n if (customElements.get('mid-radio')) {\n this.syncRadioElements();\n } else {\n customElements.whenDefined('mid-radio').then(() => this.syncRadios());\n }\n\n if (customElements.get('mid-radio-button')) {\n this.syncRadioElements();\n } else {\n // Rerun this handler when <mid-radio> or <mid-radio-button> is registered\n customElements\n .whenDefined('mid-radio-button')\n .then(() => this.syncRadios());\n }\n }\n\n private handleKeyDown(event: KeyboardEvent) {\n if (\n !['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', ' '].includes(\n event.key\n )\n ) {\n return;\n }\n\n const radios = this.getAllRadios().filter((radio) => !radio.disabled);\n const checkedRadio = radios.find((radio) => radio.checked) ?? radios[0];\n const incr =\n event.key === ' '\n ? 0\n : ['ArrowUp', 'ArrowLeft'].includes(event.key)\n ? -1\n : 1;\n const oldValue = this.value;\n let index = radios.indexOf(checkedRadio) + incr;\n\n if (index < 0) {\n index = radios.length - 1;\n }\n\n if (index > radios.length - 1) {\n index = 0;\n }\n\n this.getAllRadios().forEach((radio) => {\n radio.checked = false;\n\n if (!this.hasButtonRadios) {\n radio.element.setAttribute('tabindex', '-1');\n }\n });\n\n this.value = radios[index].value;\n radios[index].checked = true;\n this.setFormValue(this.value);\n\n if (!this.hasButtonRadios) {\n radios[index].element.setAttribute('tabindex', '0');\n radios[index].focus();\n } else {\n radios[index].shadowRoot!.querySelector('button')!.focus();\n }\n\n if (this.value !== oldValue) {\n this.dispatchEvent(\n new Event('mid-change', { bubbles: true, composed: true })\n );\n this.dispatchEvent(\n new Event('mid-input', { bubbles: true, composed: true })\n );\n }\n\n event.preventDefault();\n }\n\n private getAllRadios() {\n return Array.from(\n this.querySelectorAll<MinidRadioButton | MinidRadio>(\n 'mid-radio, mid-radio-button'\n )\n );\n }\n\n private updateCheckedRadio() {\n const radios = this.getAllRadios();\n radios.forEach((radio) => {\n radio.checked = radio.value === this.value;\n });\n }\n\n private handleLabelClick() {\n this.focus();\n }\n\n private handleRadioClick(event: MouseEvent) {\n const target = (event.target as HTMLElement).closest<\n MinidRadioButton | MinidRadio\n >('mid-radio, mid-radio-button')!;\n // const radios = this.getAllRadios();\n\n const oldValue = this.value;\n\n if (!target || target.disabled) {\n return;\n }\n\n this.value = target.value;\n this.setFormValue(this.value);\n\n this.updateCheckedRadio();\n\n if (this.value !== oldValue) {\n this.dispatchEvent(\n new Event('mid-change', { bubbles: true, composed: true })\n );\n this.dispatchEvent(\n new Event('mid-input', { bubbles: true, composed: true })\n );\n }\n }\n\n @watch('size', { waitUntilFirstUpdate: true })\n handleSizeChange() {\n this.syncRadios();\n }\n\n @watch('value')\n handleValueChange() {\n if (this.hasUpdated) {\n this.updateCheckedRadio();\n }\n }\n\n @watch('disabled')\n handleDisabledChange() {\n const radios = this.getAllRadios();\n const every = radios.every((radio) => radio.disabled);\n const some = radios.some((radio) => radio.disabled);\n radios.forEach((radio) => {\n if (every === some) {\n radio.disabled = this.disabled;\n } else if (this.disabled) {\n radio.disabled = true;\n }\n });\n }\n\n /**\n * Sets focus on the radio-group.\n */\n public focus(options?: FocusOptions) {\n const radios = this.getAllRadios();\n const checked = radios.find((radio) => radio.checked);\n const firstEnabledRadio = radios.find((radio) => !radio.disabled);\n\n const radioToFocus = checked || firstEnabledRadio;\n\n // Call focus for the checked radio\n // If no radio is checked, focus the first one that is not disabled\n if (radioToFocus) {\n radioToFocus.focus(options);\n }\n }\n\n override render() {\n return html`\n <label\n part=\"form-control-label\"\n id=\"label\"\n class=\"class=${classMap({\n 'fds-label': true,\n 'fds-label--spacing': true,\n 'fds-label--sm': this.size === 'sm',\n 'fds-label--md': this.size === 'md',\n 'fds-label--lg': this.size === 'lg',\n 'sr-only': this.labelhidden,\n })}\"\n @click=${this.handleLabelClick}\n >\n ${this.label}\n </label>\n <fieldset\n class=\"${classMap({\n 'fds-togglegroup': this.hasButtonRadios,\n })} flex\"\n part=\"form-control\"\n role=\"radiogroup\"\n aria-labelledby=\"label\"\n >\n <div\n class=\"${classMap({\n grid: true,\n 'gap-3': true,\n 'fds-togglegroup__content': this.hasButtonRadios,\n })}\"\n part=\"base\"\n role=\"presentation\"\n aria-label=${this.label}\n >\n <slot\n @slotchange=${this.syncRadios}\n @click=${this.handleRadioClick}\n @keydown=${this.handleKeyDown}\n ></slot>\n </div>\n </fieldset>\n `;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAgBA,MAAM,SAAS;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASF;AAcO,IAAM,kBAAN,cAA8B;AAAA,EACnC,OAAO,YAAY,MAAM;AAC3B,EAAE;AAAA,EAFK,cAAA;AAAA,UAAA,GAAA,SAAA;AAOL,SAAA,OAAO;AAMP,SAAA,QAAuB;AAGvB,SAAA,QAAQ;AAGR,SAAA,OAA2B;AAG3B,SAAA,cAAc;AAGd,SAAA,WAAW;AAGX,SAAQ,kBAAkB;AAG1B,SAAA,eAA8B;AAAA,EAAA;AAAA,EAEpB,aAAa,oBAA0C;AAC/D,UAAM,aAAa,kBAAkB;AACrC,SAAK,eAAe,KAAK;AACzB,SAAK,aAAa,KAAK,KAAK;AAAA,EAC9B;AAAA,EAEU,oBAAoB;AAC5B,SAAK,QAAQ,KAAK;AAClB,SAAK,aAAa,KAAK,KAAK;AAC5B,SAAK,mBAAA;AAAA,EACP;AAAA,EAEA,MAAc,oBAAoB;AAChC,UAAM,SAAS,KAAK,aAAA;AACpB,SAAK,kBAAkB,OAAO;AAAA,MAC5B,CAAC,UAAU,MAAM,QAAQ,kBAAkB;AAAA,IAAA;AAG7C,UAAM,QAAQ;AAAA;AAAA,MAEZ,OAAO,IAAI,OAAO,UAAU;AAC1B,cAAM,MAAM;AACZ,cAAM,UAAU,MAAM,UAAU,KAAK;AACrC,cAAM,OAAO,KAAK;AAAA,MACpB,CAAC;AAAA,IAAA;AAGH,QAAI,OAAO,SAAS,KAAK,CAAC,OAAO,KAAK,CAAC,UAAU,MAAM,OAAO,GAAG;AAC/D,UAAI,KAAK,iBAAiB;AACxB,cAAM,cAAc,OAAO,CAAC,EAAE,YAAY,cAAc,QAAQ;AAChE,YAAI,aAAa;AACf,sBAAY,aAAa,YAAY,GAAG;AAAA,QAC1C;AAAA,MACF,OAAO;AACL,eAAO,CAAC,EAAE,QAAQ,aAAa,YAAY,GAAG;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,aAAa;AACnB,QACE,eAAe,IAAI,WAAW,KAC9B,eAAe,IAAI,kBAAkB,GACrC;AACA,WAAK,kBAAA;AACL;AAAA,IACF;AAEA,QAAI,eAAe,IAAI,WAAW,GAAG;AACnC,WAAK,kBAAA;AAAA,IACP,OAAO;AACL,qBAAe,YAAY,WAAW,EAAE,KAAK,MAAM,KAAK,YAAY;AAAA,IACtE;AAEA,QAAI,eAAe,IAAI,kBAAkB,GAAG;AAC1C,WAAK,kBAAA;AAAA,IACP,OAAO;AAEL,qBACG,YAAY,kBAAkB,EAC9B,KAAK,MAAM,KAAK,YAAY;AAAA,IACjC;AAAA,EACF;AAAA,EAEQ,cAAc,OAAsB;AAC1C,QACE,CAAC,CAAC,WAAW,aAAa,aAAa,cAAc,GAAG,EAAE;AAAA,MACxD,MAAM;AAAA,IAAA,GAER;AACA;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,aAAA,EAAe,OAAO,CAAC,UAAU,CAAC,MAAM,QAAQ;AACpE,UAAM,eAAe,OAAO,KAAK,CAAC,UAAU,MAAM,OAAO,KAAK,OAAO,CAAC;AACtE,UAAM,OACJ,MAAM,QAAQ,MACV,IACA,CAAC,WAAW,WAAW,EAAE,SAAS,MAAM,GAAG,IACzC,KACA;AACR,UAAM,WAAW,KAAK;AACtB,QAAI,QAAQ,OAAO,QAAQ,YAAY,IAAI;AAE3C,QAAI,QAAQ,GAAG;AACb,cAAQ,OAAO,SAAS;AAAA,IAC1B;AAEA,QAAI,QAAQ,OAAO,SAAS,GAAG;AAC7B,cAAQ;AAAA,IACV;AAEA,SAAK,aAAA,EAAe,QAAQ,CAAC,UAAU;AACrC,YAAM,UAAU;AAEhB,UAAI,CAAC,KAAK,iBAAiB;AACzB,cAAM,QAAQ,aAAa,YAAY,IAAI;AAAA,MAC7C;AAAA,IACF,CAAC;AAED,SAAK,QAAQ,OAAO,KAAK,EAAE;AAC3B,WAAO,KAAK,EAAE,UAAU;AACxB,SAAK,aAAa,KAAK,KAAK;AAE5B,QAAI,CAAC,KAAK,iBAAiB;AACzB,aAAO,KAAK,EAAE,QAAQ,aAAa,YAAY,GAAG;AAClD,aAAO,KAAK,EAAE,MAAA;AAAA,IAChB,OAAO;AACL,aAAO,KAAK,EAAE,WAAY,cAAc,QAAQ,EAAG,MAAA;AAAA,IACrD;AAEA,QAAI,KAAK,UAAU,UAAU;AAC3B,WAAK;AAAA,QACH,IAAI,MAAM,cAAc,EAAE,SAAS,MAAM,UAAU,MAAM;AAAA,MAAA;AAE3D,WAAK;AAAA,QACH,IAAI,MAAM,aAAa,EAAE,SAAS,MAAM,UAAU,MAAM;AAAA,MAAA;AAAA,IAE5D;AAEA,UAAM,eAAA;AAAA,EACR;AAAA,EAEQ,eAAe;AACrB,WAAO,MAAM;AAAA,MACX,KAAK;AAAA,QACH;AAAA,MAAA;AAAA,IACF;AAAA,EAEJ;AAAA,EAEQ,qBAAqB;AAC3B,UAAM,SAAS,KAAK,aAAA;AACpB,WAAO,QAAQ,CAAC,UAAU;AACxB,YAAM,UAAU,MAAM,UAAU,KAAK;AAAA,IACvC,CAAC;AAAA,EACH;AAAA,EAEQ,mBAAmB;AACzB,SAAK,MAAA;AAAA,EACP;AAAA,EAEQ,iBAAiB,OAAmB;AAC1C,UAAM,SAAU,MAAM,OAAuB,QAE3C,6BAA6B;AAG/B,UAAM,WAAW,KAAK;AAEtB,QAAI,CAAC,UAAU,OAAO,UAAU;AAC9B;AAAA,IACF;AAEA,SAAK,QAAQ,OAAO;AACpB,SAAK,aAAa,KAAK,KAAK;AAE5B,SAAK,mBAAA;AAEL,QAAI,KAAK,UAAU,UAAU;AAC3B,WAAK;AAAA,QACH,IAAI,MAAM,cAAc,EAAE,SAAS,MAAM,UAAU,MAAM;AAAA,MAAA;AAE3D,WAAK;AAAA,QACH,IAAI,MAAM,aAAa,EAAE,SAAS,MAAM,UAAU,MAAM;AAAA,MAAA;AAAA,IAE5D;AAAA,EACF;AAAA,EAGA,mBAAmB;AACjB,SAAK,WAAA;AAAA,EACP;AAAA,EAGA,oBAAoB;AAClB,QAAI,KAAK,YAAY;AACnB,WAAK,mBAAA;AAAA,IACP;AAAA,EACF;AAAA,EAGA,uBAAuB;AACrB,UAAM,SAAS,KAAK,aAAA;AACpB,UAAM,QAAQ,OAAO,MAAM,CAAC,UAAU,MAAM,QAAQ;AACpD,UAAM,OAAO,OAAO,KAAK,CAAC,UAAU,MAAM,QAAQ;AAClD,WAAO,QAAQ,CAAC,UAAU;AACxB,UAAI,UAAU,MAAM;AAClB,cAAM,WAAW,KAAK;AAAA,MACxB,WAAW,KAAK,UAAU;AACxB,cAAM,WAAW;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKO,MAAM,SAAwB;AACnC,UAAM,SAAS,KAAK,aAAA;AACpB,UAAM,UAAU,OAAO,KAAK,CAAC,UAAU,MAAM,OAAO;AACpD,UAAM,oBAAoB,OAAO,KAAK,CAAC,UAAU,CAAC,MAAM,QAAQ;AAEhE,UAAM,eAAe,WAAW;AAIhC,QAAI,cAAc;AAChB,mBAAa,MAAM,OAAO;AAAA,IAC5B;AAAA,EACF;AAAA,EAES,SAAS;AAChB,WAAO;AAAA;AAAA;AAAA;AAAA,uBAIY,SAAS;AAAA,MACtB,aAAa;AAAA,MACb,sBAAsB;AAAA,MACtB,iBAAiB,KAAK,SAAS;AAAA,MAC/B,iBAAiB,KAAK,SAAS;AAAA,MAC/B,iBAAiB,KAAK,SAAS;AAAA,MAC/B,WAAW,KAAK;AAAA,IAAA,CACjB,CAAC;AAAA,iBACO,KAAK,gBAAgB;AAAA;AAAA,UAE5B,KAAK,KAAK;AAAA;AAAA;AAAA,iBAGH,SAAS;AAAA,MAChB,mBAAmB,KAAK;AAAA,IAAA,CACzB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAMS,SAAS;AAAA,MAChB,MAAM;AAAA,MACN,SAAS;AAAA,MACT,4BAA4B,KAAK;AAAA,IAAA,CAClC,CAAC;AAAA;AAAA;AAAA,uBAGW,KAAK,KAAK;AAAA;AAAA;AAAA,0BAGP,KAAK,UAAU;AAAA,qBACpB,KAAK,gBAAgB;AAAA,uBACnB,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,EAKvC;AACF;AA1RE,gBAAA;AAAA,EADC,SAAA;AAAS,GANC,gBAOX,WAAA,QAAA,CAAA;AAMA,gBAAA;AAAA,EADC,SAAS,EAAE,SAAS,KAAA,CAAM;AAAA,GAZhB,gBAaX,WAAA,SAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAA;AAAS,GAfC,gBAgBX,WAAA,SAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAA;AAAS,GAlBC,gBAmBX,WAAA,QAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GArBhB,gBAsBX,WAAA,eAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GAxBhB,gBAyBX,WAAA,YAAA,CAAA;AAGQ,gBAAA;AAAA,EADP,MAAA;AAAM,GA3BI,gBA4BH,WAAA,mBAAA,CAAA;AAGR,gBAAA;AAAA,EADC,MAAA;AAAM,GA9BI,gBA+BX,WAAA,gBAAA,CAAA;AA4KA,gBAAA;AAAA,EADC,MAAM,QAAQ,EAAE,sBAAsB,MAAM;AAAA,GA1MlC,gBA2MX,WAAA,oBAAA,CAAA;AAKA,gBAAA;AAAA,EADC,MAAM,OAAO;AAAA,GA/MH,gBAgNX,WAAA,qBAAA,CAAA;AAOA,gBAAA;AAAA,EADC,MAAM,UAAU;AAAA,GAtNN,gBAuNX,WAAA,wBAAA,CAAA;AAvNW,kBAAN,gBAAA;AAAA,EADN,cAAc,iBAAiB;AAAA,GACnB,eAAA;"}
1
+ {"version":3,"file":"radio-group.js","sources":["../../src/components/radio-group.component.ts"],"sourcesContent":["import { css, html, LitElement, type PropertyValues } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { styled } from '../mixins/tailwind.mixin';\nimport './label.component';\nimport { MinidRadioButton } from '../components/radio-button.component';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { watch } from '../internal/watch';\nimport { MinidRadio } from '../components/radio.component';\nimport { FormControlMixin } from '../mixins/form-control.mixin';\nimport { HasSlotController } from '../internal/slot';\nimport { requiredValidator } from 'src/mixins/validators';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-radio-group': MinidRadioGroup;\n }\n}\n\nconst styles = [\n css`\n :host {\n display: block;\n }\n `,\n];\n\n/**\n *\n * @slot -- The default slot where `<mid-radio>` or `<mid-radio-button>` elements are placed.\n *\n * @event mid-change - Emitted when the selected value changes\n * @event mid-input - Emitted when radio group recieves input\n *\n * @csspart form-control-label - Select the label element\n * @csspart form-control - Select the fieldset containing the radios\n * @csspart base - Select the container around the radios\n */\n@customElement('mid-radio-group')\nexport class MinidRadioGroup extends FormControlMixin(\n styled(LitElement, styles)\n) {\n private readonly hasSlotController = new HasSlotController(this, 'label');\n private readonly validationId = `radio-group-${MinidRadioGroup._uniqueId++}`;\n private static _uniqueId = 0;\n /**\n * The name of the radio group, submitted as a name/value pair with form data.\n */\n @property({ reflect: true })\n name: string | null = null;\n\n /**\n * The current value of the radio group.\n */\n @property({ reflect: true })\n value: string | null = null;\n\n @property()\n label = '';\n\n @property({ type: Boolean })\n labelhidden = false;\n\n @property({ type: Boolean })\n disabled = false;\n\n @property({ type: Boolean, reflect: true })\n required = false;\n\n @property()\n invalidmessage = '';\n\n @state()\n private hasButtonRadios = false;\n\n @state()\n defaultValue: string | null = null;\n\n get validationTarget() {\n const radio = this.querySelector<MinidRadio>(\n ':is(mid-radio):not([disabled])'\n );\n return radio ?? undefined;\n }\n\n static get formcontrolValidators() {\n return [requiredValidator];\n }\n\n protected firstUpdated(_changedProperties: PropertyValues): void {\n super.firstUpdated(_changedProperties);\n this.defaultValue = this.value;\n this.setValue(this.value);\n }\n\n resetFormControl() {\n this.value = this.defaultValue;\n this.setValue(this.value);\n this.updateCheckedRadio();\n }\n\n private async syncRadioElements() {\n const radios = this.getAllRadios();\n this.hasButtonRadios = radios.some(\n (radio) => radio.tagName.toLowerCase() === 'mid-radio-button'\n );\n\n await Promise.all(\n // Sync the checked state and size\n radios.map(async (radio) => {\n await radio.updateComplete;\n radio.checked = radio.value === this.value;\n })\n );\n\n if (radios.length > 0 && !radios.some((radio) => radio.checked)) {\n if (this.hasButtonRadios) {\n const buttonRadio = radios[0].shadowRoot?.querySelector('button');\n if (buttonRadio) {\n buttonRadio.setAttribute('tabindex', '0');\n }\n } else {\n radios[0].input.setAttribute('tabindex', '0');\n }\n }\n }\n\n private syncRadios() {\n if (\n customElements.get('mid-radio') &&\n customElements.get('mid-radio-button')\n ) {\n this.syncRadioElements();\n return;\n }\n\n if (customElements.get('mid-radio')) {\n this.syncRadioElements();\n } else {\n customElements.whenDefined('mid-radio').then(() => this.syncRadios());\n }\n\n if (customElements.get('mid-radio-button')) {\n this.syncRadioElements();\n } else {\n // Rerun this handler when <mid-radio> or <mid-radio-button> is registered\n customElements\n .whenDefined('mid-radio-button')\n .then(() => this.syncRadios());\n }\n }\n\n private handleKeyDown(event: KeyboardEvent) {\n if (\n !['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', ' '].includes(\n event.key\n )\n ) {\n return;\n }\n\n const radios = this.getAllRadios().filter((radio) => !radio.disabled);\n const checkedRadio = radios.find((radio) => radio.checked) ?? radios[0];\n const incr =\n event.key === ' '\n ? 0\n : ['ArrowUp', 'ArrowLeft'].includes(event.key)\n ? -1\n : 1;\n const oldValue = this.value;\n let index = radios.indexOf(checkedRadio) + incr;\n\n if (index < 0) {\n index = radios.length - 1;\n }\n\n if (index > radios.length - 1) {\n index = 0;\n }\n\n this.getAllRadios().forEach((radio) => {\n radio.checked = false;\n\n if (!this.hasButtonRadios) {\n radio.input.setAttribute('tabindex', '-1');\n }\n });\n\n this.value = radios[index].value;\n radios[index].checked = true;\n this.setValue(this.value);\n\n if (!this.hasButtonRadios) {\n radios[index].input.setAttribute('tabindex', '0');\n radios[index].focus();\n } else {\n radios[index].shadowRoot!.querySelector('button')!.focus();\n }\n\n if (this.value !== oldValue) {\n this.dispatchEvent(\n new Event('mid-change', { bubbles: true, composed: true })\n );\n this.dispatchEvent(\n new Event('mid-input', { bubbles: true, composed: true })\n );\n }\n\n event.preventDefault();\n }\n\n private getAllRadios() {\n return Array.from(this.querySelectorAll<MinidRadio>('mid-radio'));\n }\n\n private updateCheckedRadio() {\n const radios = this.getAllRadios();\n radios.forEach((radio) => {\n radio.checked = radio.value === this.value;\n });\n }\n\n private handleLabelClick() {\n this.focus();\n }\n\n private handleRadioClick(event: MouseEvent) {\n const target = (event.target as HTMLElement).closest<\n MinidRadioButton | MinidRadio\n >('mid-radio, mid-radio-button')!;\n // const radios = this.getAllRadios();\n\n const oldValue = this.value;\n\n if (!target || target.disabled) {\n return;\n }\n\n this.value = target.value;\n this.setValue(this.value);\n\n this.updateCheckedRadio();\n\n if (this.value !== oldValue) {\n this.dispatchEvent(\n new Event('mid-change', { bubbles: true, composed: true })\n );\n this.dispatchEvent(\n new Event('mid-input', { bubbles: true, composed: true })\n );\n }\n }\n\n @watch('size', { waitUntilFirstUpdate: true })\n handleSizeChange() {\n this.syncRadios();\n }\n\n @watch('value')\n handleValueChange() {\n if (this.hasUpdated) {\n this.updateCheckedRadio();\n }\n }\n\n @watch('disabled')\n handleDisabledChange() {\n const radios = this.getAllRadios();\n const every = radios.every((radio) => radio.disabled);\n const some = radios.some((radio) => radio.disabled);\n radios.forEach((radio) => {\n if (every === some) {\n radio.disabled = this.disabled;\n } else if (this.disabled) {\n radio.disabled = true;\n }\n });\n }\n\n @watch('invalidmessage')\n handleInvalidChange() {\n this.getAllRadios().forEach((radio) => {\n radio.invalid = !!this.invalidmessage;\n });\n }\n\n /**\n * Sets focus on the radio-group.\n */\n public focus(options?: FocusOptions) {\n const radios = this.getAllRadios();\n const checked = radios.find((radio) => radio.checked);\n const firstEnabledRadio = radios.find((radio) => !radio.disabled);\n\n const radioToFocus = checked || firstEnabledRadio;\n\n // Call focus for the checked radio\n // If no radio is checked, focus the first one that is not disabled\n if (radioToFocus) {\n radioToFocus.focus(options);\n }\n }\n\n override render() {\n const hasLabelSlot = this.hasSlotController.test('label');\n const hasLabel = this.label ? true : !!hasLabelSlot;\n\n return html`\n <fieldset\n class=\"flex flex-col gap-2\"\n part=\"form-control\"\n role=\"radiogroup\"\n aria-labelledby=\"label\"\n aria-errormessage=\"${this.validationId}\"\n >\n <label\n part=\"form-control-label\"\n id=\"label\"\n class=\"class=${classMap({\n 'sr-only': this.labelhidden,\n 'mb-2': hasLabel,\n })} mid-label\"\n @click=${this.handleLabelClick}\n >\n <slot name=\"label\">${this.label}</slot>\n </label>\n <slot\n class=\"flex flex-col flex-wrap gap-3.5\"\n @slotchange=${this.syncRadios}\n @click=${this.handleRadioClick}\n @keydown=${this.handleKeyDown}\n ></slot>\n </fieldset>\n <div\n class=\"text-danger-subtle mt-2 flex gap-1\"\n id=\"${this.validationId}\"\n aria-live=\"polite\"\n ?hidden=${!this.invalidmessage}\n >\n <mid-icon\n name=\"xmark-octagon-fill\"\n class=\"mt-1 min-h-6 min-w-6\"\n ></mid-icon>\n ${this.invalidmessage}\n </div>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ declare global {
4
4
  'mid-radio': MinidRadio;
5
5
  }
6
6
  }
7
- declare const MinidRadio_base: typeof LitElement;
7
+ declare const MinidRadio_base: import('../types/mixin-constructor.ts').Constructor<import('../types/form-control.ts').FormControlInterface> & typeof LitElement;
8
8
  /**
9
9
  *
10
10
  * @slot -- The radio's label
@@ -16,7 +16,10 @@ declare const MinidRadio_base: typeof LitElement;
16
16
  * @csspart label - Select the label element
17
17
  */
18
18
  export declare class MinidRadio extends MinidRadio_base {
19
- element: HTMLInputElement;
19
+ input: HTMLInputElement;
20
+ /**
21
+ * The name of the radio, used to bind together multiple radios.
22
+ */
20
23
  name: string;
21
24
  /**
22
25
  * The radio button's checked state.
@@ -30,13 +33,12 @@ export declare class MinidRadio extends MinidRadio_base {
30
33
  * Disables the radio button.
31
34
  */
32
35
  disabled: boolean;
33
- /**
34
- * The radio button's size. When used inside a radio group, the size will be determined by the radio group's size so
35
- * this attribute can typically be omitted.
36
- */
37
- size: 'sm' | 'md' | 'lg';
36
+ invalid: boolean;
37
+ shouldFormValueUpdate(): boolean;
38
+ get validationTarget(): HTMLInputElement;
38
39
  constructor();
39
40
  connectedCallback(): void;
41
+ private handleKeydown;
40
42
  private handleBlur;
41
43
  private handleFocus;
42
44
  private handleClick;
@@ -1 +1 @@
1
- {"version":3,"file":"radio.component.d.ts","sourceRoot":"","sources":["../../src/components/radio.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAE,MAAM,KAAK,CAAC;AAO5C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,UAAU,CAAC;KACzB;CACF;;AA4DD;;;;;;;;;GASG;AACH,qBACa,UAAW,SAAQ,eAA0B;IAExD,OAAO,EAAG,gBAAgB,CAAC;IAG3B,IAAI,SAAY;IAEhB;;OAEG;IAEH,OAAO,UAAS;IAEhB;;OAEG;IAEH,KAAK,SAAM;IAEX;;OAEG;IAEH,QAAQ,UAAS;IAEjB;;;OAGG;IAEH,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAQ;;IAShC,iBAAiB;IAQjB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,WAAW;IAWnB,oBAAoB;IAKpB,iBAAiB;IAIjB;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY;IAKnB,MAAM;CAgChB"}
1
+ {"version":3,"file":"radio.component.d.ts","sourceRoot":"","sources":["../../src/components/radio.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAE,MAAM,KAAK,CAAC;AAO5C,OAAO,0BAA0B,CAAC;AAElC,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,UAAU,CAAC;KACzB;CACF;;AAcD;;;;;;;;;GASG;AACH,qBACa,UAAW,SAAQ,eAA4C;IAE1E,KAAK,EAAG,gBAAgB,CAAC;IAEzB;;OAEG;IAEH,IAAI,SAAY;IAEhB;;OAEG;IAEH,OAAO,UAAS;IAEhB;;OAEG;IAEH,KAAK,SAAM;IAEX;;OAEG;IAEH,QAAQ,UAAS;IAGjB,OAAO,UAAS;IAEhB,qBAAqB,IAAI,OAAO;IAIhC,IAAI,gBAAgB,qBAEnB;;IASD,iBAAiB;IAQjB,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,WAAW;IAYnB,oBAAoB;IAKpB,iBAAiB;IAIjB;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY;IAInB,MAAM;CAwBhB"}
@@ -1,9 +1,11 @@
1
1
  import { css, LitElement, html } from "lit";
2
2
  import { query, property, customElement } from "lit/decorators.js";
3
- import { classMap } from "lit/directives/class-map.js";
4
3
  import { live } from "lit/directives/live.js";
4
+ import { classMap } from "lit/directives/class-map.js";
5
5
  import { watch } from "../internal/watch.js";
6
6
  import { styled } from "../mixins/tailwind.mixin.js";
7
+ import { FormControlMixin } from "../mixins/form-control.mixin.js";
8
+ import "./icon/icon.js";
7
9
  var __defProp = Object.defineProperty;
8
10
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
11
  var __decorateClass = (decorators, target, key, kind) => {
@@ -17,78 +19,48 @@ var __decorateClass = (decorators, target, key, kind) => {
17
19
  const styles = [
18
20
  css`
19
21
  :host {
20
- --color-checked: #0062ba;
21
- --color-border: #7a818c;
22
-
23
- color: white;
24
- padding: 0.25rem 0;
25
- display: grid;
26
- grid-template-columns: auto 1fr;
27
- gap: 0.5rem;
28
- cursor: pointer;
29
- font-weight: 400;
30
- }
31
-
32
- :host > * {
22
+ display: inline-flex;
33
23
  cursor: pointer;
34
24
  }
35
-
36
- :host:has(input:focus-visible) {
37
- --fds-focus-border-width: 3px;
38
- box-shadow: 0 0 0 var(--fds-focus-border-width)
39
- var(--fds-semantic-border-focus-boxshadow);
40
- }
41
-
42
- :host:has(input:disabled),
43
- :host:has(input:disabled) > * {
25
+ :host:has(input:disabled) {
44
26
  cursor: not-allowed;
45
27
  }
46
-
47
- :host:has(input:disabled) > * {
48
- opacity: 0.3;
49
- }
50
-
51
- .label {
52
- font-weight: 400;
53
- }
54
-
55
- .radio {
56
- -webkit-appearance: none;
57
- appearance: none;
58
-
59
- border-radius: 999px;
60
- display: grid;
61
- place-content: center;
62
- border: 2px solid var(--color-border);
63
- transform: translateY(-0.075em);
64
- }
65
-
66
- .radio:checked {
67
- border-color: var(--color-checked);
68
- background:
69
- radial-gradient(circle closest-side, currentcolor 45%, transparent 50%),
70
- var(--color-checked);
71
- }
72
28
  `
73
29
  ];
74
- let MinidRadio = class extends styled(LitElement, styles) {
30
+ let MinidRadio = class extends FormControlMixin(styled(LitElement, styles)) {
75
31
  constructor() {
76
32
  super();
77
33
  this.name = "option";
78
34
  this.checked = false;
79
35
  this.value = "";
80
36
  this.disabled = false;
81
- this.size = "md";
37
+ this.invalid = false;
82
38
  this.addEventListener("blur", this.handleBlur);
83
39
  this.addEventListener("click", this.handleClick);
84
40
  this.addEventListener("focus", this.handleFocus);
85
41
  }
42
+ shouldFormValueUpdate() {
43
+ return this.checked;
44
+ }
45
+ get validationTarget() {
46
+ return this.input;
47
+ }
86
48
  connectedCallback() {
87
49
  super.connectedCallback();
88
50
  this.setAttribute("role", "presentation");
89
51
  this.setAttribute("aria-disabled", this.disabled ? "true" : "false");
90
52
  this.classList.add("rounded");
91
53
  }
54
+ handleKeydown(event) {
55
+ const hasModifier = event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
56
+ if (event.key === "Enter" && !hasModifier) {
57
+ setTimeout(() => {
58
+ if (!event.defaultPrevented && !event.isComposing) {
59
+ this.form.requestSubmit();
60
+ }
61
+ });
62
+ }
63
+ }
92
64
  handleBlur() {
93
65
  this.classList.remove("shadow-focus-visible");
94
66
  this.dispatchEvent(
@@ -111,55 +83,48 @@ let MinidRadio = class extends styled(LitElement, styles) {
111
83
  return;
112
84
  }
113
85
  this.checked = true;
86
+ this.dispatchEvent(new Event("mid-change"));
114
87
  }
115
88
  handleDisabledChange() {
116
89
  this.setAttribute("aria-disabled", this.disabled ? "true" : "false");
117
90
  }
118
91
  handleCheckChange() {
119
- this.element.checked = this.checked;
92
+ this.input.checked = this.checked;
120
93
  }
121
94
  /**
122
95
  * Sets focus on the radio button.
123
96
  */
124
97
  focus(options) {
125
- this.element.focus(options);
98
+ this.input.focus(options);
126
99
  }
127
100
  render() {
128
101
  return html`
129
- <input
130
- type="radio"
131
- part="radio"
132
- name="${this.name}"
133
- class="${classMap({
134
- radio: true,
135
- "h-7": this.size === "lg",
136
- "w-7": this.size === "lg",
137
- "w-6": this.size === "md",
138
- "h-6": this.size === "md",
139
- "w-5": this.size === "sm",
140
- "h-5": this.size === "sm"
141
- })} shadow-none"
142
- ?checked=${live(this.checked)}
143
- ?disabled=${this.disabled}
144
- />
145
102
  <label
146
103
  part="label"
147
- class="${classMap({
148
- label: true,
149
- "fds-label": true,
150
- "fds-label--sm": this.size === "sm",
151
- "fds-label--md": this.size === "md",
152
- "fds-label--lg": this.size === "lg"
153
- })}"
104
+ class="has-disabled:opacity-disabled grid cursor-pointer grid-cols-[auto_1fr] gap-2 has-disabled:cursor-not-allowed"
154
105
  >
106
+ <input
107
+ type="radio"
108
+ part="radio"
109
+ name="${this.name}"
110
+ class="${classMap({
111
+ "bg-neutral": !this.invalid,
112
+ "border-neutral": !this.invalid,
113
+ "bg-danger-tinted": this.invalid,
114
+ "border-danger-base": this.invalid
115
+ })} checked:bg-accent-base checked:before:bg-neutral focus-visible:focus-ring-sm checked:border-accent-base my-0.5 grid size-6 cursor-pointer appearance-none place-content-center rounded-full border-2 p-0.5 shadow-none before:size-2.5 before:scale-0 before:rounded-full before:transition-transform before:duration-100 checked:before:scale-100 disabled:cursor-not-allowed"
116
+ ?checked=${live(this.checked)}
117
+ ?disabled=${this.disabled}
118
+ @keydown=${this.handleKeydown}
119
+ />
155
120
  <slot></slot>
156
121
  </label>
157
122
  `;
158
123
  }
159
124
  };
160
125
  __decorateClass([
161
- query(".radio")
162
- ], MinidRadio.prototype, "element", 2);
126
+ query('input[type="radio"]')
127
+ ], MinidRadio.prototype, "input", 2);
163
128
  __decorateClass([
164
129
  property()
165
130
  ], MinidRadio.prototype, "name", 2);
@@ -173,8 +138,8 @@ __decorateClass([
173
138
  property({ type: Boolean, reflect: true })
174
139
  ], MinidRadio.prototype, "disabled", 2);
175
140
  __decorateClass([
176
- property({ reflect: true })
177
- ], MinidRadio.prototype, "size", 2);
141
+ property({ type: Boolean })
142
+ ], MinidRadio.prototype, "invalid", 2);
178
143
  __decorateClass([
179
144
  watch("disabled", { waitUntilFirstUpdate: true })
180
145
  ], MinidRadio.prototype, "handleDisabledChange", 1);
@@ -1 +1 @@
1
- {"version":3,"file":"radio.js","sources":["../../src/components/radio.component.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { live } from 'lit/directives/live.js';\nimport { watch } from '../internal/watch';\nimport { styled } from '../mixins/tailwind.mixin';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-radio': MinidRadio;\n }\n}\n\nconst styles = [\n css`\n :host {\n --color-checked: #0062ba;\n --color-border: #7a818c;\n\n color: white;\n padding: 0.25rem 0;\n display: grid;\n grid-template-columns: auto 1fr;\n gap: 0.5rem;\n cursor: pointer;\n font-weight: 400;\n }\n\n :host > * {\n cursor: pointer;\n }\n\n :host:has(input:focus-visible) {\n --fds-focus-border-width: 3px;\n box-shadow: 0 0 0 var(--fds-focus-border-width)\n var(--fds-semantic-border-focus-boxshadow);\n }\n\n :host:has(input:disabled),\n :host:has(input:disabled) > * {\n cursor: not-allowed;\n }\n\n :host:has(input:disabled) > * {\n opacity: 0.3;\n }\n\n .label {\n font-weight: 400;\n }\n\n .radio {\n -webkit-appearance: none;\n appearance: none;\n\n border-radius: 999px;\n display: grid;\n place-content: center;\n border: 2px solid var(--color-border);\n transform: translateY(-0.075em);\n }\n\n .radio:checked {\n border-color: var(--color-checked);\n background:\n radial-gradient(circle closest-side, currentcolor 45%, transparent 50%),\n var(--color-checked);\n }\n `,\n];\n\n/**\n *\n * @slot -- The radio's label\n *\n * @event mid-blur - Emitted when the control loses focus.\n * @event mid-focus - Emitted when the control gains focus.\n *\n * @csspart radio - Select the radio input element\n * @csspart label - Select the label element\n */\n@customElement('mid-radio')\nexport class MinidRadio extends styled(LitElement, styles) {\n @query('.radio')\n element!: HTMLInputElement;\n\n @property()\n name = 'option';\n\n /**\n * The radio button's checked state.\n */\n @property({ type: Boolean, reflect: true })\n checked = false;\n\n /**\n * The radio's value. When selected, the radio group will receive this value.\n */\n @property()\n value = '';\n\n /**\n * Disables the radio button.\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * The radio button's size. When used inside a radio group, the size will be determined by the radio group's size so\n * this attribute can typically be omitted.\n */\n @property({ reflect: true })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n constructor() {\n super();\n this.addEventListener('blur', this.handleBlur);\n this.addEventListener('click', this.handleClick);\n this.addEventListener('focus', this.handleFocus);\n }\n\n connectedCallback() {\n super.connectedCallback();\n this.setAttribute('role', 'presentation');\n this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');\n\n this.classList.add('rounded');\n }\n\n private handleBlur() {\n this.classList.remove('shadow-focus-visible');\n this.dispatchEvent(\n new Event('mid-blur', { composed: true, bubbles: true })\n );\n }\n\n private handleFocus() {\n if (this.disabled) {\n return;\n }\n\n this.focus();\n this.dispatchEvent(\n new Event('mid-focus', { composed: true, bubbles: true })\n );\n }\n\n private handleClick(event: MouseEvent) {\n if (this.disabled) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n this.checked = true;\n }\n\n @watch('disabled', { waitUntilFirstUpdate: true })\n handleDisabledChange() {\n this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');\n }\n\n @watch('checked', { waitUntilFirstUpdate: true })\n handleCheckChange() {\n this.element.checked = this.checked;\n }\n\n /**\n * Sets focus on the radio button.\n */\n focus(options?: FocusOptions) {\n // this.classList.add('shadow-focus-visible');\n this.element.focus(options);\n }\n\n override render() {\n return html`\n <input\n type=\"radio\"\n part=\"radio\"\n name=\"${this.name}\"\n class=\"${classMap({\n radio: true,\n 'h-7': this.size === 'lg',\n 'w-7': this.size === 'lg',\n 'w-6': this.size === 'md',\n 'h-6': this.size === 'md',\n 'w-5': this.size === 'sm',\n 'h-5': this.size === 'sm',\n })} shadow-none\"\n ?checked=${live(this.checked)}\n ?disabled=${this.disabled}\n />\n <label\n part=\"label\"\n class=\"${classMap({\n label: true,\n 'fds-label': true,\n 'fds-label--sm': this.size === 'sm',\n 'fds-label--md': this.size === 'md',\n 'fds-label--lg': this.size === 'lg',\n })}\"\n >\n <slot></slot>\n </label>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"radio.js","sources":["../../src/components/radio.component.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { live } from 'lit/directives/live.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { watch } from '../internal/watch';\nimport { styled } from '../mixins/tailwind.mixin';\nimport { FormControlMixin } from '../mixins/form-control.mixin';\nimport './icon/icon.component.ts';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-radio': MinidRadio;\n }\n}\n\nconst styles = [\n css`\n :host {\n display: inline-flex;\n cursor: pointer;\n }\n :host:has(input:disabled) {\n cursor: not-allowed;\n }\n `,\n];\n\n/**\n *\n * @slot -- The radio's label\n *\n * @event mid-blur - Emitted when the control loses focus.\n * @event mid-focus - Emitted when the control gains focus.\n *\n * @csspart radio - Select the radio input element\n * @csspart label - Select the label element\n */\n@customElement('mid-radio')\nexport class MinidRadio extends FormControlMixin(styled(LitElement, styles)) {\n @query('input[type=\"radio\"]')\n input!: HTMLInputElement;\n\n /**\n * The name of the radio, used to bind together multiple radios.\n */\n @property()\n name = 'option';\n\n /**\n * The radio button's checked state.\n */\n @property({ type: Boolean, reflect: true })\n checked = false;\n\n /**\n * The radio's value. When selected, the radio group will receive this value.\n */\n @property()\n value = '';\n\n /**\n * Disables the radio button.\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n @property({ type: Boolean })\n invalid = false;\n\n shouldFormValueUpdate(): boolean {\n return this.checked;\n }\n\n get validationTarget() {\n return this.input;\n }\n\n constructor() {\n super();\n this.addEventListener('blur', this.handleBlur);\n this.addEventListener('click', this.handleClick);\n this.addEventListener('focus', this.handleFocus);\n }\n\n connectedCallback() {\n super.connectedCallback();\n this.setAttribute('role', 'presentation');\n this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');\n\n this.classList.add('rounded');\n }\n\n private handleKeydown(event: KeyboardEvent) {\n const hasModifier =\n event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;\n\n // Pressing enter when focused on an input should submit the form like a native input, but we wait a tick before\n // submitting to allow users to cancel the keydown event if they need to\n if (event.key === 'Enter' && !hasModifier) {\n setTimeout(() => {\n //\n // When using an Input Method Editor (IME), pressing enter will cause the form to submit unexpectedly. One way\n // to check for this is to look at event.isComposing, which will be true when the IME is open.\n if (!event.defaultPrevented && !event.isComposing) {\n this.form.requestSubmit();\n }\n });\n }\n }\n\n private handleBlur() {\n this.classList.remove('shadow-focus-visible');\n this.dispatchEvent(\n new Event('mid-blur', { composed: true, bubbles: true })\n );\n }\n\n private handleFocus() {\n if (this.disabled) {\n return;\n }\n\n this.focus();\n this.dispatchEvent(\n new Event('mid-focus', { composed: true, bubbles: true })\n );\n }\n\n private handleClick(event: MouseEvent) {\n if (this.disabled) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n this.checked = true;\n this.dispatchEvent(new Event('mid-change'));\n }\n\n @watch('disabled', { waitUntilFirstUpdate: true })\n handleDisabledChange() {\n this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');\n }\n\n @watch('checked', { waitUntilFirstUpdate: true })\n handleCheckChange() {\n this.input.checked = this.checked;\n }\n\n /**\n * Sets focus on the radio button.\n */\n focus(options?: FocusOptions) {\n this.input.focus(options);\n }\n\n override render() {\n return html`\n <label\n part=\"label\"\n class=\"has-disabled:opacity-disabled grid cursor-pointer grid-cols-[auto_1fr] gap-2 has-disabled:cursor-not-allowed\"\n >\n <input\n type=\"radio\"\n part=\"radio\"\n name=\"${this.name}\"\n class=\"${classMap({\n 'bg-neutral': !this.invalid,\n 'border-neutral': !this.invalid,\n 'bg-danger-tinted': this.invalid,\n 'border-danger-base': this.invalid,\n })} checked:bg-accent-base checked:before:bg-neutral focus-visible:focus-ring-sm checked:border-accent-base my-0.5 grid size-6 cursor-pointer appearance-none place-content-center rounded-full border-2 p-0.5 shadow-none before:size-2.5 before:scale-0 before:rounded-full before:transition-transform before:duration-100 checked:before:scale-100 disabled:cursor-not-allowed\"\n ?checked=${live(this.checked)}\n ?disabled=${this.disabled}\n @keydown=${this.handleKeydown}\n />\n <slot></slot>\n </label>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -355,11 +355,19 @@
355
355
  @apply border-accent-base bg-accent-tinted;
356
356
  }
357
357
 
358
- .mid-menu-item:focus {
358
+ .mid-menu-item:focus-visible {
359
359
  @apply border-accent-base bg-accent-tinted outline-0;
360
360
  }
361
361
 
362
362
  .mid-menu-item:active {
363
363
  @apply border-accent-base bg-accent-tinted;
364
364
  }
365
+
366
+ .mid-button {
367
+ @apply bg-accent-base text-accent-base-contrast hover:bg-accent-base-hover active:bg-accent-base-active focus-visible:focus-ring leading-sm flex h-fit min-h-12 min-w-12 grow cursor-pointer items-center justify-center gap-2 rounded border border-transparent px-4 py-2 font-medium;
368
+ }
369
+
370
+ .mid-label {
371
+ @apply inline-block font-medium;
372
+ }
365
373
  }
@@ -1,3 +1,3 @@
1
1
  <svg width="1em" height="1em" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" clip-rule="evenodd" d="M16.4699 2.96959C16.7627 2.67669 17.2376 2.67669 17.5305 2.96959L21.0305 6.46959C21.3234 6.76248 21.3234 7.23735 21.0305 7.53025L17.5305 11.0302C17.2376 11.3231 16.7627 11.3231 16.4699 11.0302C16.177 10.7374 16.177 10.2625 16.4699 9.96959L18.6895 7.74992L9.50018 7.74992C9.08597 7.74992 8.75018 7.41413 8.75018 6.99992C8.75018 6.5857 9.08597 6.24992 9.50018 6.24992L18.6895 6.24992L16.4699 4.03025C16.177 3.73735 16.177 3.26248 16.4699 2.96959ZM7.53051 12.9696C7.82341 13.2625 7.82341 13.7374 7.53051 14.0302L5.31084 16.2499L14.5002 16.2499C14.9144 16.2499 15.2502 16.5857 15.2502 16.9999C15.2502 17.4141 14.9144 17.7499 14.5002 17.7499L5.31084 17.7499L7.53051 19.9696C7.82341 20.2625 7.82341 20.7374 7.53051 21.0302C7.23762 21.3231 6.76275 21.3231 6.46985 21.0302L2.96985 17.5302C2.8292 17.3896 2.75018 17.1988 2.75018 16.9999C2.75018 16.801 2.8292 16.6102 2.96985 16.4696L6.46985 12.9696C6.76275 12.6767 7.23762 12.6767 7.53051 12.9696Z" fill="currentColor"/>
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M7.53015 21.0304C7.23725 21.3233 6.76238 21.3233 6.46949 21.0304L2.96949 17.5304C2.67659 17.2375 2.67659 16.7627 2.96949 16.4698L6.46949 12.9698C6.76238 12.6769 7.23725 12.6769 7.53015 12.9698C7.82304 13.2627 7.82304 13.7375 7.53015 14.0304L5.31048 16.2501L14.4998 16.2501C14.914 16.2501 15.2498 16.5859 15.2498 17.0001C15.2498 17.4143 14.914 17.7501 14.4998 17.7501L5.31048 17.7501L7.53015 19.9698C7.82304 20.2627 7.82304 20.7375 7.53015 21.0304ZM16.4695 11.0304C16.1766 10.7375 16.1766 10.2627 16.4695 9.96976L18.6892 7.75009L9.49982 7.75009C9.0856 7.75009 8.74982 7.4143 8.74982 7.00009C8.74982 6.58588 9.0856 6.25009 9.49982 6.25009L18.6892 6.25009L16.4695 4.03042C16.1766 3.73753 16.1766 3.26266 16.4695 2.96976C16.7624 2.67687 17.2373 2.67687 17.5301 2.96976L21.0301 6.46976C21.1708 6.61041 21.2498 6.80118 21.2498 7.00009C21.2498 7.19901 21.1708 7.38977 21.0301 7.53042L17.5301 11.0304C17.2373 11.3233 16.7624 11.3233 16.4695 11.0304Z" fill="currentColor"/>
3
3
  </svg>