@c2n/radio 0.0.6 → 0.0.7

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.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as Radio } from "./radio-DKp0-FOe.js";
1
+ import { t as Radio } from "./radio-B3fDuJv1.js";
2
2
  import { t as radioGroupContext } from "./radio-context-De4Idbg9.js";
3
- import { t as RadioGroup } from "./radio-group-DhI6N66I.js";
3
+ import { t as RadioGroup } from "./radio-group-DQJl6oBt.js";
4
4
  export { Radio, RadioGroup, radioGroupContext };
@@ -1,6 +1,7 @@
1
1
  import { t as radioGroupContext } from "./radio-context-De4Idbg9.js";
2
2
  import { LitElement, html, nothing, unsafeCSS } from "lit";
3
- import { customElement, property, query, state } from "lit/decorators.js";
3
+ import { property, query, state } from "lit/decorators.js";
4
+ import { customElement } from "@c2n/core/element-helper.js";
4
5
  import { classMap } from "lit/directives/class-map.js";
5
6
  import { ifDefined } from "lit/directives/if-defined.js";
6
7
  import { redispatchEvent } from "@c2n/core/dom-helper.js";
@@ -87,10 +88,16 @@ function __decorate(decorators, target, key, desc) {
87
88
  var Radio = class Radio extends LitElement {
88
89
  constructor(..._args) {
89
90
  super(..._args);
91
+ this.internals = this.attachInternals();
92
+ this.customValidityMessage = "";
93
+ this.disabledByForm = false;
94
+ this.defaultChecked = false;
95
+ this.defaultCheckedCaptured = false;
90
96
  this.checked = false;
91
97
  this.disabled = false;
92
98
  this.value = "";
93
99
  this.name = "";
100
+ this.required = false;
94
101
  this.label = "";
95
102
  this.tabbable = true;
96
103
  this.hasDescription = false;
@@ -98,16 +105,64 @@ var Radio = class Radio extends LitElement {
98
105
  this.hasIcon = false;
99
106
  this.hasCheckedIcon = false;
100
107
  }
108
+ static {
109
+ this.formAssociated = true;
110
+ }
101
111
  static {
102
112
  this.styles = unsafeCSS(radio_default);
103
113
  }
114
+ connectedCallback() {
115
+ super.connectedCallback();
116
+ if (!this.defaultCheckedCaptured) {
117
+ this.defaultChecked = this.hasAttribute("checked");
118
+ this.defaultCheckedCaptured = true;
119
+ }
120
+ }
104
121
  /** Field name in effect: the group's, or this radio's own. */
105
122
  get effectiveName() {
106
123
  return this.group?.name || this.name;
107
124
  }
108
125
  /** Disabled by its own attribute or by the group. */
109
126
  get effectiveDisabled() {
110
- return this.disabled || !!this.group?.disabled;
127
+ return this.disabled || this.disabledByForm || !!this.group?.disabled;
128
+ }
129
+ /** The containing form, when this standalone radio is associated with one. */
130
+ get form() {
131
+ return this.internals.form;
132
+ }
133
+ /** Labels associated with this form control. */
134
+ get labels() {
135
+ return this.internals.labels;
136
+ }
137
+ get validity() {
138
+ return this.internals.validity;
139
+ }
140
+ get validationMessage() {
141
+ return this.internals.validationMessage;
142
+ }
143
+ get willValidate() {
144
+ return this.internals.willValidate;
145
+ }
146
+ formResetCallback() {
147
+ if (this.group) return;
148
+ this.checked = this.defaultChecked;
149
+ }
150
+ formDisabledCallback(disabled) {
151
+ this.disabledByForm = disabled && !this.hasAttribute("disabled");
152
+ }
153
+ formStateRestoreCallback(state) {
154
+ if (this.group) return;
155
+ this.checked = state === "checked";
156
+ }
157
+ checkValidity() {
158
+ return this.internals.checkValidity();
159
+ }
160
+ reportValidity() {
161
+ return this.internals.reportValidity();
162
+ }
163
+ setCustomValidity(message) {
164
+ this.customValidityMessage = message;
165
+ this.requestUpdate();
111
166
  }
112
167
  focus(options) {
113
168
  this.formElement?.focus(options);
@@ -128,14 +183,46 @@ var Radio = class Radio extends LitElement {
128
183
  if (changed.has("checked") && changed.get("checked") !== void 0 && this.isConnected) {
129
184
  if (this.group) this.group.checkedChanged(this);
130
185
  else if (this.checked) this.uncheckSiblings();
186
+ else this.requestSiblingValidityUpdates();
131
187
  }
188
+ this.syncFormState();
132
189
  }
133
190
  /** Standalone radios sharing a `name` in the same root behave as one group. */
134
191
  uncheckSiblings() {
135
192
  if (!this.name) return;
136
193
  const root = this.getRootNode();
137
194
  if (typeof root.querySelectorAll !== "function") return;
138
- for (const radio of root.querySelectorAll("c2-radio")) if (radio !== this && radio.checked && radio.name === this.name && !radio.group) radio.checked = false;
195
+ for (const radio of root.querySelectorAll("c2-radio")) if (this.isStandalonePeer(radio)) {
196
+ if (radio.checked) radio.checked = false;
197
+ else radio.requestUpdate();
198
+ }
199
+ }
200
+ requestSiblingValidityUpdates() {
201
+ if (!this.name) return;
202
+ const root = this.getRootNode();
203
+ if (typeof root.querySelectorAll !== "function") return;
204
+ for (const radio of root.querySelectorAll("c2-radio")) if (this.isStandalonePeer(radio)) radio.requestUpdate();
205
+ }
206
+ syncFormState() {
207
+ this.internals.setFormValue(!this.group && this.checked ? this.value : null, this.checked ? "checked" : "unchecked");
208
+ if (this.group) {
209
+ this.internals.setValidity({});
210
+ return;
211
+ }
212
+ const missing = this.required && !this.hasCheckedStandaloneSibling();
213
+ const flags = this.customValidityMessage ? { customError: true } : missing ? { valueMissing: true } : {};
214
+ const message = this.customValidityMessage || (missing ? "Please select an option." : "");
215
+ this.internals.setValidity(flags, message, this.formElement);
216
+ }
217
+ hasCheckedStandaloneSibling() {
218
+ if (this.checked) return true;
219
+ if (!this.name) return false;
220
+ const root = this.getRootNode();
221
+ if (typeof root.querySelectorAll !== "function") return false;
222
+ return [...root.querySelectorAll("c2-radio")].some((radio) => this.isStandalonePeer(radio) && radio.checked);
223
+ }
224
+ isStandalonePeer(radio) {
225
+ return radio !== this && radio.name === this.name && !radio.group && radio.form === this.form;
139
226
  }
140
227
  handleSlotChange(event) {
141
228
  this.updateSlot(event.target);
@@ -174,6 +261,7 @@ var Radio = class Radio extends LitElement {
174
261
  aria-describedby=${ifDefined(this.ariaDescribedBy)}
175
262
  ?checked=${this.checked}
176
263
  ?disabled=${disabled}
264
+ ?required=${this.group?.required || this.required}
177
265
  @change=${this.handleChange}
178
266
  />
179
267
  <span class="c2-radio__background" part="control">
@@ -193,6 +281,7 @@ var Radio = class Radio extends LitElement {
193
281
  `;
194
282
  }
195
283
  };
284
+ __decorate([state()], Radio.prototype, "disabledByForm", void 0);
196
285
  __decorate([query("input")], Radio.prototype, "formElement", void 0);
197
286
  __decorate([property({
198
287
  type: Boolean,
@@ -204,6 +293,10 @@ __decorate([property({
204
293
  })], Radio.prototype, "disabled", void 0);
205
294
  __decorate([property()], Radio.prototype, "value", void 0);
206
295
  __decorate([property()], Radio.prototype, "name", void 0);
296
+ __decorate([property({
297
+ type: Boolean,
298
+ reflect: true
299
+ })], Radio.prototype, "required", void 0);
207
300
  __decorate([property()], Radio.prototype, "label", void 0);
208
301
  __decorate([property({
209
302
  type: Boolean,
@@ -1,7 +1,8 @@
1
- import { n as __decorate, r as s$1, t as Radio } from "./radio-DKp0-FOe.js";
1
+ import { n as __decorate, r as s$1, t as Radio } from "./radio-B3fDuJv1.js";
2
2
  import { t as radioGroupContext } from "./radio-context-De4Idbg9.js";
3
3
  import { LitElement, html, isServer, nothing, unsafeCSS } from "lit";
4
- import { customElement, property, state } from "lit/decorators.js";
4
+ import { property, state } from "lit/decorators.js";
5
+ import { customElement } from "@c2n/core/element-helper.js";
5
6
  import { ifDefined } from "lit/directives/if-defined.js";
6
7
  //#region ../../../node_modules/@lit/context/lib/value-notifier.js
7
8
  /**
@@ -137,14 +138,21 @@ var radio_group_default = "/* ex : var((width: 24px), width, c2-checkbox) retur
137
138
  //#region src/radio-group.ts
138
139
  var RADIO_TAG = "c2-radio";
139
140
  var RadioGroup = class RadioGroup extends LitElement {
141
+ static {
142
+ this.formAssociated = true;
143
+ }
140
144
  static {
141
145
  this.styles = unsafeCSS(radio_group_default);
142
146
  }
143
147
  constructor() {
144
148
  super();
149
+ this.internals = this.attachInternals();
150
+ this.customValidityMessage = "";
151
+ this.disabledByForm = false;
145
152
  this.value = "";
146
153
  this.name = "";
147
154
  this.disabled = false;
155
+ this.required = false;
148
156
  this.orientation = "vertical";
149
157
  this.hasLabel = false;
150
158
  this.hasDescription = false;
@@ -152,11 +160,11 @@ var RadioGroup = class RadioGroup extends LitElement {
152
160
  this.handleRadioChange = (event) => {
153
161
  const radio = event.target;
154
162
  if (radio === this || !(radio instanceof Radio) || radio.closest("c2-radio-group") !== this) return;
155
- event.stopPropagation();
163
+ event.stopImmediatePropagation();
156
164
  this.select(radio);
157
165
  };
158
166
  this.handleKeydown = (event) => {
159
- if (this.disabled) return;
167
+ if (this.effectiveDisabled) return;
160
168
  const radios = this.radios.filter((radio) => !radio.disabled);
161
169
  const current = radios.indexOf(event.target);
162
170
  if (current === -1) return;
@@ -187,6 +195,48 @@ var RadioGroup = class RadioGroup extends LitElement {
187
195
  this.addEventListener("keydown", this.handleKeydown);
188
196
  }
189
197
  }
198
+ connectedCallback() {
199
+ super.connectedCallback();
200
+ this.defaultValue = this.getAttribute("value") ?? void 0;
201
+ }
202
+ /** The containing form, when this control is associated with one. */
203
+ get form() {
204
+ return this.internals.form;
205
+ }
206
+ /** Labels associated with this form control. */
207
+ get labels() {
208
+ return this.internals.labels;
209
+ }
210
+ get validity() {
211
+ return this.internals.validity;
212
+ }
213
+ get validationMessage() {
214
+ return this.internals.validationMessage;
215
+ }
216
+ get willValidate() {
217
+ return this.internals.willValidate;
218
+ }
219
+ formResetCallback() {
220
+ this.value = this.defaultValue ?? "";
221
+ }
222
+ formDisabledCallback(disabled) {
223
+ this.disabledByForm = disabled && !this.hasAttribute("disabled");
224
+ this.context = this.createContext();
225
+ this.syncRadios();
226
+ }
227
+ formStateRestoreCallback(state) {
228
+ if (typeof state === "string") this.value = state;
229
+ }
230
+ checkValidity() {
231
+ return this.internals.checkValidity();
232
+ }
233
+ reportValidity() {
234
+ return this.internals.reportValidity();
235
+ }
236
+ setCustomValidity(message) {
237
+ this.customValidityMessage = message;
238
+ this.syncFormState();
239
+ }
190
240
  /** The `c2-radio` elements of this group (nested groups keep their own), in DOM order. */
191
241
  get radios() {
192
242
  return [...this.querySelectorAll(RADIO_TAG)].filter((radio) => radio.closest("c2-radio-group") === this);
@@ -194,7 +244,8 @@ var RadioGroup = class RadioGroup extends LitElement {
194
244
  createContext() {
195
245
  return {
196
246
  name: this.name,
197
- disabled: this.disabled,
247
+ disabled: this.effectiveDisabled,
248
+ required: this.required,
198
249
  checkedChanged: (radio) => this.handleCheckedChanged(radio)
199
250
  };
200
251
  }
@@ -203,10 +254,11 @@ var RadioGroup = class RadioGroup extends LitElement {
203
254
  for (const slot of this.renderRoot.querySelectorAll("slot")) this.updateSlot(slot);
204
255
  }
205
256
  willUpdate(changed) {
206
- if (changed.has("name") || changed.has("disabled")) this.context = this.createContext();
257
+ if (changed.has("name") || changed.has("disabled") || changed.has("required")) this.context = this.createContext();
207
258
  }
208
259
  updated(changed) {
209
260
  if (changed.has("value") || changed.has("disabled")) this.syncRadios();
261
+ this.syncFormState();
210
262
  }
211
263
  handleSlotChange(event) {
212
264
  this.updateSlot(event.target);
@@ -227,6 +279,7 @@ var RadioGroup = class RadioGroup extends LitElement {
227
279
  const checked = radios.find((radio) => radio.checked);
228
280
  if (checked) this.value = checked.value;
229
281
  }
282
+ this.defaultValue ??= this.value;
230
283
  this.syncRadios();
231
284
  }
232
285
  /** Called through the context when an option's `checked` changed (user or code). */
@@ -256,6 +309,16 @@ var RadioGroup = class RadioGroup extends LitElement {
256
309
  composed: true
257
310
  }));
258
311
  }
312
+ syncFormState() {
313
+ this.internals.setFormValue(this.value || null, this.value);
314
+ const missing = this.required && !this.value;
315
+ const flags = this.customValidityMessage ? { customError: true } : missing ? { valueMissing: true } : {};
316
+ const message = this.customValidityMessage || (missing ? "Please select an option." : "");
317
+ this.internals.setValidity(flags, message);
318
+ }
319
+ get effectiveDisabled() {
320
+ return this.disabled || this.disabledByForm;
321
+ }
259
322
  render() {
260
323
  return html`
261
324
  <div
@@ -264,7 +327,7 @@ var RadioGroup = class RadioGroup extends LitElement {
264
327
  aria-label=${ifDefined(this.ariaLabel)}
265
328
  aria-labelledby=${this.hasLabel ? "label" : nothing}
266
329
  aria-describedby=${this.hasDescription ? "description" : nothing}
267
- aria-disabled=${this.disabled ? "true" : nothing}
330
+ aria-disabled=${this.effectiveDisabled ? "true" : nothing}
268
331
  aria-orientation=${this.orientation}
269
332
  >
270
333
  <div class="c2-radio-group-header" ?hidden=${!this.hasLabel && !this.hasDescription}>
@@ -278,12 +341,17 @@ var RadioGroup = class RadioGroup extends LitElement {
278
341
  `;
279
342
  }
280
343
  };
344
+ __decorate([state()], RadioGroup.prototype, "disabledByForm", void 0);
281
345
  __decorate([property({ reflect: true })], RadioGroup.prototype, "value", void 0);
282
346
  __decorate([property()], RadioGroup.prototype, "name", void 0);
283
347
  __decorate([property({
284
348
  type: Boolean,
285
349
  reflect: true
286
350
  })], RadioGroup.prototype, "disabled", void 0);
351
+ __decorate([property({
352
+ type: Boolean,
353
+ reflect: true
354
+ })], RadioGroup.prototype, "required", void 0);
287
355
  __decorate([property({ reflect: true })], RadioGroup.prototype, "orientation", void 0);
288
356
  __decorate([property({
289
357
  type: String,
@@ -1,2 +1,2 @@
1
- import { t as RadioGroup } from "./radio-group-DhI6N66I.js";
1
+ import { t as RadioGroup } from "./radio-group-DQJl6oBt.js";
2
2
  export { RadioGroup };
package/dist/radio.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as Radio } from "./radio-DKp0-FOe.js";
1
+ import { t as Radio } from "./radio-B3fDuJv1.js";
2
2
  export { Radio };
package/package.json CHANGED
@@ -1,30 +1,42 @@
1
1
  {
2
2
  "name": "@c2n/radio",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
7
7
  ".": {
8
- "default": "./dist/index.js",
9
- "types": "./types/src/index.d.ts"
8
+ "types": "./types/src/index.d.ts",
9
+ "default": "./dist/index.js"
10
10
  },
11
11
  "./radio.js": {
12
- "default": "./dist/radio.js",
13
- "types": "./types/src/radio.d.ts"
12
+ "types": "./types/src/radio.d.ts",
13
+ "default": "./dist/radio.js"
14
14
  },
15
15
  "./radio-group.js": {
16
- "default": "./dist/radio-group.js",
17
- "types": "./types/src/radio-group.d.ts"
16
+ "types": "./types/src/radio-group.d.ts",
17
+ "default": "./dist/radio-group.js"
18
18
  },
19
19
  "./radio-context.js": {
20
- "default": "./dist/radio-context.js",
21
- "types": "./types/src/radio-context.d.ts"
20
+ "types": "./types/src/radio-context.d.ts",
21
+ "default": "./dist/radio-context.js"
22
+ },
23
+ "./react": {
24
+ "types": "./react.d.ts",
25
+ "default": "./react.js"
26
+ },
27
+ "./vue": {
28
+ "types": "./vue.d.ts",
29
+ "default": "./vue.js"
22
30
  },
23
31
  "./custom-elements.json": "./custom-elements.json"
24
32
  },
25
33
  "files": [
26
34
  "dist",
27
- "types"
35
+ "types",
36
+ "react.d.ts",
37
+ "react.js",
38
+ "vue.d.ts",
39
+ "vue.js"
28
40
  ],
29
41
  "keywords": [
30
42
  "radio",
@@ -63,7 +75,7 @@
63
75
  }
64
76
  },
65
77
  "dependencies": {
66
- "@c2n/core": "0.0.6",
78
+ "@c2n/core": "0.0.7",
67
79
  "@lit/context": "1.1.6",
68
80
  "lit": "3.3.3"
69
81
  },
@@ -71,5 +83,5 @@
71
83
  "@c2n/config": "*"
72
84
  },
73
85
  "customElements": "custom-elements.json",
74
- "gitHead": "2921054bc75299da66dad11c1e374246ff88a51e"
86
+ "gitHead": "c8db398a27f7cd417d665fdf5da455fee2d4e910"
75
87
  }
package/react.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ // GENERATED by @c2n/framework-types. Do not edit by hand.
2
+ //
3
+ // JSX types for the custom elements of @c2n/radio. Import once, anywhere in the program:
4
+ //
5
+ // import '@c2n/radio/react'
6
+ //
7
+ // Register the elements at module scope before React renders, or React writes an object prop as an
8
+ // attribute and it stringifies.
9
+
10
+ import type { DetailedHTMLProps, HTMLAttributes } from 'react'
11
+ import type { Radio } from '@c2n/radio/radio.js'
12
+ import type { RadioGroup } from '@c2n/radio/radio-group.js'
13
+
14
+ /** Standard React host-element attributes plus the element's own public properties. */
15
+ type C2Props<T> = DetailedHTMLProps<HTMLAttributes<T>, T> & Partial<Omit<T, keyof HTMLElement>>
16
+
17
+ declare module 'react' {
18
+ namespace JSX {
19
+ interface IntrinsicElements {
20
+ 'c2-radio': C2Props<Radio>
21
+ 'c2-radio-group': C2Props<RadioGroup>
22
+ }
23
+ }
24
+ }
25
+
26
+ export {}
package/react.js ADDED
@@ -0,0 +1,3 @@
1
+ // GENERATED by @c2n/framework-types. Do not edit by hand.
2
+ // Types only — see the matching .d.ts.
3
+ export {}
@@ -5,6 +5,8 @@ export interface RadioGroupContext {
5
5
  name: string;
6
6
  /** Disables every radio of the group. */
7
7
  disabled: boolean;
8
+ /** Requires the group to have a selected radio. */
9
+ required: boolean;
8
10
  /** Called by a radio after its `checked` state changed, so the group can update `value` and uncheck the others. */
9
11
  checkedChanged(radio: Radio): void;
10
12
  }
@@ -1 +1 @@
1
- {"version":3,"file":"radio-context.d.ts","sourceRoot":"","sources":["../../src/radio-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAA;IACZ,yCAAyC;IACzC,QAAQ,EAAE,OAAO,CAAA;IACjB,mHAAmH;IACnH,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CACnC;AAED,eAAO,MAAM,iBAAiB;;CAAyE,CAAA"}
1
+ {"version":3,"file":"radio-context.d.ts","sourceRoot":"","sources":["../../src/radio-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAA;IACZ,yCAAyC;IACzC,QAAQ,EAAE,OAAO,CAAA;IACjB,mDAAmD;IACnD,QAAQ,EAAE,OAAO,CAAA;IACjB,mHAAmH;IACnH,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CACnC;AAED,eAAO,MAAM,iBAAiB;;CAAyE,CAAA"}
@@ -1,7 +1,18 @@
1
1
  import { LitElement, type PropertyValues } from 'lit';
2
+ import type { TypedAddEventListener, TypedRemoveEventListener } from '@c2n/core/event-helper.js';
2
3
  import { type RadioGroupContext } from './radio-context';
3
4
  import { Radio } from './radio';
4
5
  export type RadioGroupOrientation = 'vertical' | 'horizontal';
6
+ /** Events fired by {@link RadioGroup}, keyed for `addEventListener`. */
7
+ export interface RadioGroupEventMap {
8
+ change: CustomEvent<{
9
+ value: string;
10
+ }>;
11
+ }
12
+ export interface RadioGroup {
13
+ addEventListener: TypedAddEventListener<RadioGroup, RadioGroupEventMap>;
14
+ removeEventListener: TypedRemoveEventListener<RadioGroup, RadioGroupEventMap>;
15
+ }
5
16
  /**
6
17
  * Groups `c2-radio` options into one control: a single `value`, one `name` for every option, group-level `disabled`,
7
18
  * and keyboard behaviour that matches native radios across the shadow boundary (Arrow keys move and select, only the
@@ -29,20 +40,42 @@ export type RadioGroupOrientation = 'vertical' | 'horizontal';
29
40
  * @slotcomponent c2-radio
30
41
  */
31
42
  export declare class RadioGroup extends LitElement {
43
+ static formAssociated: boolean;
32
44
  static styles: import("lit").CSSResult;
45
+ private readonly internals;
46
+ private customValidityMessage;
47
+ private disabledByForm;
48
+ private defaultValue;
33
49
  /** `value` of the checked option; empty when none is checked. Setting it checks the matching option. */
34
50
  value: string;
35
51
  /** Form field name applied to every option. */
36
52
  name: string;
37
53
  /** Disables every option. */
38
54
  disabled: boolean;
55
+ /** Requires one option to be selected for the form to be valid. */
56
+ required: boolean;
39
57
  /** Lays the options out in a row instead of a column. */
40
58
  orientation: RadioGroupOrientation;
59
+ /** Accessible name of the radiogroup when its heading does not label it. */
41
60
  ariaLabel: string;
42
61
  private hasLabel;
43
62
  private hasDescription;
44
63
  protected context: RadioGroupContext;
45
64
  constructor();
65
+ connectedCallback(): void;
66
+ /** The containing form, when this control is associated with one. */
67
+ get form(): HTMLFormElement | null;
68
+ /** Labels associated with this form control. */
69
+ get labels(): NodeList;
70
+ get validity(): ValidityState;
71
+ get validationMessage(): string;
72
+ get willValidate(): boolean;
73
+ formResetCallback(): void;
74
+ formDisabledCallback(disabled: boolean): void;
75
+ formStateRestoreCallback(state: string | File | FormData | null): void;
76
+ checkValidity(): boolean;
77
+ reportValidity(): boolean;
78
+ setCustomValidity(message: string): void;
46
79
  /** The `c2-radio` elements of this group (nested groups keep their own), in DOM order. */
47
80
  get radios(): Radio[];
48
81
  private createContext;
@@ -59,6 +92,8 @@ export declare class RadioGroup extends LitElement {
59
92
  /** Mirrors `value` onto the options and keeps exactly one of them in the tab order. */
60
93
  private syncRadios;
61
94
  private select;
95
+ private syncFormState;
96
+ private get effectiveDisabled();
62
97
  private handleRadioChange;
63
98
  private handleKeydown;
64
99
  render(): import("lit-html").TemplateResult<1>;
@@ -1 +1 @@
1
- {"version":3,"file":"radio-group.d.ts","sourceRoot":"","sources":["../../src/radio-group.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsC,KAAK,cAAc,EAAE,MAAM,KAAK,CAAA;AAIzF,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAE3E,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAK/B,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,YAAY,CAAA;AAE7D;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBACa,UAAW,SAAQ,UAAU;IACxC,OAAgB,MAAM,0BAAoB;IAE1C,wGAAwG;IAC3E,KAAK,SAAK;IAEvC,+CAA+C;IACnC,IAAI,SAAK;IAErB,6BAA6B;IACe,QAAQ,UAAQ;IAE5D,yDAAyD;IAC5B,WAAW,EAAE,qBAAqB,CAAa;IAGnE,SAAS,EAAG,MAAM,CAAA;IAElB,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,cAAc,CAAQ;IAGvC,SAAS,CAAC,OAAO,EAAE,iBAAiB,CAAuB;;IAU3D,0FAA0F;IAC1F,IAAI,MAAM,IAAI,KAAK,EAAE,CAEpB;IAED,OAAO,CAAC,aAAa;IAIrB,sGAAsG;IAC7F,YAAY;IAIZ,UAAU,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IAKxC,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IAI9C,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,UAAU;IAUlB,8GAA8G;YAChG,WAAW;IAWzB,oFAAoF;IACpF,OAAO,CAAC,oBAAoB;IAS5B,uFAAuF;IACvF,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,iBAAiB,CAMxB;IAED,OAAO,CAAC,aAAa,CA4BpB;IAEQ,MAAM;CAqBhB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE,UAAU,CAAA;KAC7B;CACF"}
1
+ {"version":3,"file":"radio-group.d.ts","sourceRoot":"","sources":["../../src/radio-group.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsC,KAAK,cAAc,EAAE,MAAM,KAAK,CAAA;AAGzF,OAAO,KAAK,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAA;AAGhG,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAE3E,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAK/B,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,YAAY,CAAA;AAE7D,wEAAwE;AACxE,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACvC;AAED,MAAM,WAAW,UAAU;IACzB,gBAAgB,EAAE,qBAAqB,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAA;IACvE,mBAAmB,EAAE,wBAAwB,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAA;CAC9E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBACa,UAAW,SAAQ,UAAU;IACxC,MAAM,CAAC,cAAc,UAAO;IAE5B,OAAgB,MAAM,0BAAoB;IAE1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;IACnD,OAAO,CAAC,qBAAqB,CAAK;IACzB,OAAO,CAAC,cAAc,CAAQ;IACvC,OAAO,CAAC,YAAY,CAAoB;IAExC,wGAAwG;IAC3E,KAAK,SAAK;IAEvC,+CAA+C;IACnC,IAAI,SAAK;IAErB,6BAA6B;IACe,QAAQ,UAAQ;IAE5D,mEAAmE;IACvB,QAAQ,UAAQ;IAE5D,yDAAyD;IAC5B,WAAW,EAAE,qBAAqB,CAAa;IAE5E,4EAA4E;IAEnE,SAAS,EAAG,MAAM,CAAA;IAElB,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,cAAc,CAAQ;IAGvC,SAAS,CAAC,OAAO,EAAE,iBAAiB,CAAuB;;IAUlD,iBAAiB;IAK1B,qEAAqE;IACrE,IAAI,IAAI,2BAEP;IAED,gDAAgD;IAChD,IAAI,MAAM,aAET;IAED,IAAI,QAAQ,kBAEX;IAED,IAAI,iBAAiB,WAEpB;IAED,IAAI,YAAY,YAEf;IAED,iBAAiB;IAIjB,oBAAoB,CAAC,QAAQ,EAAE,OAAO;IAMtC,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI;IAI/D,aAAa;IAIb,cAAc;IAId,iBAAiB,CAAC,OAAO,EAAE,MAAM;IAKjC,0FAA0F;IAC1F,IAAI,MAAM,IAAI,KAAK,EAAE,CAEpB;IAED,OAAO,CAAC,aAAa;IAIrB,sGAAsG;IAC7F,YAAY;IAIZ,UAAU,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IAKxC,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IAK9C,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,UAAU;IAUlB,8GAA8G;YAChG,WAAW;IAYzB,oFAAoF;IACpF,OAAO,CAAC,oBAAoB;IAS5B,uFAAuF;IACvF,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,aAAa;IAQrB,OAAO,KAAK,iBAAiB,GAE5B;IAED,OAAO,CAAC,iBAAiB,CAMxB;IAED,OAAO,CAAC,aAAa,CA4BpB;IAEQ,MAAM;CAqBhB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE,UAAU,CAAA;KAC7B;CACF"}
@@ -1,4 +1,13 @@
1
1
  import { LitElement, type PropertyValues } from 'lit';
2
+ import type { TypedAddEventListener, TypedRemoveEventListener } from '@c2n/core/event-helper.js';
3
+ /** Events fired by {@link Radio}, keyed for `addEventListener`. */
4
+ export interface RadioEventMap {
5
+ change: Event;
6
+ }
7
+ export interface Radio {
8
+ addEventListener: TypedAddEventListener<Radio, RadioEventMap>;
9
+ removeEventListener: TypedRemoveEventListener<Radio, RadioEventMap>;
10
+ }
2
11
  /**
3
12
  * A single radio option built on a native `<input type="radio">`, with its label and an optional description beside
4
13
  * the control. Put several in a `c2-radio-group` to get a single `value`, arrow-key navigation and a roving tab stop;
@@ -66,7 +75,13 @@ import { LitElement, type PropertyValues } from 'lit';
66
75
  * @cssproperty {pixel} [--c2-radio__description--margin-top=2px]
67
76
  */
68
77
  export declare class Radio extends LitElement {
78
+ static formAssociated: boolean;
69
79
  static styles: import("lit").CSSResult;
80
+ private readonly internals;
81
+ private customValidityMessage;
82
+ private disabledByForm;
83
+ private defaultChecked;
84
+ private defaultCheckedCaptured;
70
85
  protected formElement: HTMLInputElement;
71
86
  /** Whether this option is selected. Checking one radio unchecks the others of its group. */
72
87
  checked: boolean;
@@ -76,21 +91,39 @@ export declare class Radio extends LitElement {
76
91
  value: string;
77
92
  /** Form field name. Inside a group, the group's `name` wins. */
78
93
  name: string;
94
+ /** Requires this standalone radio, or its containing group, to have a selected option. */
95
+ required: boolean;
79
96
  /** Label text when the default slot is empty. */
80
97
  label: string;
81
98
  /** Whether the inner input is in the tab order. The parent group manages this (roving tabindex); do not set by hand. */
82
99
  tabbable: boolean;
100
+ /** Accessible name used when no visible label names the radio. */
83
101
  ariaLabel: string;
102
+ /** Id of the element that describes the radio. */
84
103
  ariaDescribedBy: undefined | string;
85
104
  private hasDescription;
86
105
  private hasDot;
87
106
  private hasIcon;
88
107
  private hasCheckedIcon;
89
108
  private group;
109
+ connectedCallback(): void;
90
110
  /** Field name in effect: the group's, or this radio's own. */
91
111
  get effectiveName(): string;
92
112
  /** Disabled by its own attribute or by the group. */
93
113
  get effectiveDisabled(): boolean;
114
+ /** The containing form, when this standalone radio is associated with one. */
115
+ get form(): HTMLFormElement | null;
116
+ /** Labels associated with this form control. */
117
+ get labels(): NodeList;
118
+ get validity(): ValidityState;
119
+ get validationMessage(): string;
120
+ get willValidate(): boolean;
121
+ formResetCallback(): void;
122
+ formDisabledCallback(disabled: boolean): void;
123
+ formStateRestoreCallback(state: string | File | FormData | null): void;
124
+ checkValidity(): boolean;
125
+ reportValidity(): boolean;
126
+ setCustomValidity(message: string): void;
94
127
  focus(options?: FocusOptions): void;
95
128
  disconnectedCallback(): void;
96
129
  /** `slotchange` does not fire for server-rendered slots, so read them once after the first render. */
@@ -99,6 +132,10 @@ export declare class Radio extends LitElement {
99
132
  updated(changed: PropertyValues<this>): void;
100
133
  /** Standalone radios sharing a `name` in the same root behave as one group. */
101
134
  private uncheckSiblings;
135
+ private requestSiblingValidityUpdates;
136
+ private syncFormState;
137
+ private hasCheckedStandaloneSibling;
138
+ private isStandalonePeer;
102
139
  private handleSlotChange;
103
140
  private updateSlot;
104
141
  private handleChange;
@@ -1 +1 @@
1
- {"version":3,"file":"radio.d.ts","sourceRoot":"","sources":["../../src/radio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA4B,KAAK,cAAc,EAAE,MAAM,KAAK,CAAA;AAS/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,qBACa,KAAM,SAAQ,UAAU;IACnC,OAAgB,MAAM,0BAAoB;IAE1B,SAAS,CAAC,WAAW,EAAG,gBAAgB,CAAA;IAExD,4FAA4F;IAChD,OAAO,UAAQ;IAE3D,wFAAwF;IAC5C,QAAQ,UAAQ;IAE5D,4FAA4F;IAChF,KAAK,SAAK;IAEtB,gEAAgE;IACpD,IAAI,SAAK;IAErB,iDAAiD;IACrC,KAAK,SAAK;IAEtB,wHAAwH;IACzE,QAAQ,UAAO;IAGrD,SAAS,EAAG,MAAM,CAAA;IAG3B,eAAe,EAAG,SAAS,GAAG,MAAM,CAAA;IAE3B,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,cAAc,CAAQ;IAGvC,OAAO,CAAC,KAAK,CAA+B;IAE5C,8DAA8D;IAC9D,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,qDAAqD;IACrD,IAAI,iBAAiB,IAAI,OAAO,CAE/B;IAEQ,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY;IAI5B,oBAAoB;IAK7B,sGAAsG;IAC7F,YAAY;cAIF,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IAM9C,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IAO9C,+EAA+E;IAC/E,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,YAAY;IAKX,MAAM;CAyChB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,UAAU,EAAE,KAAK,CAAA;KAClB;CACF"}
1
+ {"version":3,"file":"radio.d.ts","sourceRoot":"","sources":["../../src/radio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA4B,KAAK,cAAc,EAAE,MAAM,KAAK,CAAA;AAG/E,OAAO,KAAK,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAA;AAQhG,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,KAAK,CAAA;CACd;AAED,MAAM,WAAW,KAAK;IACpB,gBAAgB,EAAE,qBAAqB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAA;IAC7D,mBAAmB,EAAE,wBAAwB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAA;CACpE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,qBACa,KAAM,SAAQ,UAAU;IACnC,MAAM,CAAC,cAAc,UAAO;IAE5B,OAAgB,MAAM,0BAAoB;IAE1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;IACnD,OAAO,CAAC,qBAAqB,CAAK;IACzB,OAAO,CAAC,cAAc,CAAQ;IACvC,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,sBAAsB,CAAQ;IAEtB,SAAS,CAAC,WAAW,EAAG,gBAAgB,CAAA;IAExD,4FAA4F;IAChD,OAAO,UAAQ;IAE3D,wFAAwF;IAC5C,QAAQ,UAAQ;IAE5D,4FAA4F;IAChF,KAAK,SAAK;IAEtB,gEAAgE;IACpD,IAAI,SAAK;IAErB,0FAA0F;IAC9C,QAAQ,UAAQ;IAE5D,iDAAiD;IACrC,KAAK,SAAK;IAEtB,wHAAwH;IACzE,QAAQ,UAAO;IAE9D,kEAAkE;IAEzD,SAAS,EAAG,MAAM,CAAA;IAE3B,kDAAkD;IAElD,eAAe,EAAG,SAAS,GAAG,MAAM,CAAA;IAE3B,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,cAAc,CAAQ;IAGvC,OAAO,CAAC,KAAK,CAA+B;IAEnC,iBAAiB;IAQ1B,8DAA8D;IAC9D,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,qDAAqD;IACrD,IAAI,iBAAiB,IAAI,OAAO,CAE/B;IAED,8EAA8E;IAC9E,IAAI,IAAI,2BAEP;IAED,gDAAgD;IAChD,IAAI,MAAM,aAET;IAED,IAAI,QAAQ,kBAEX;IAED,IAAI,iBAAiB,WAEpB;IAED,IAAI,YAAY,YAEf;IAED,iBAAiB;IAKjB,oBAAoB,CAAC,QAAQ,EAAE,OAAO;IAItC,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI;IAK/D,aAAa;IAIb,cAAc;IAId,iBAAiB,CAAC,OAAO,EAAE,MAAM;IAKxB,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY;IAI5B,oBAAoB;IAK7B,sGAAsG;IAC7F,YAAY;cAIF,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IAM9C,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IAS9C,+EAA+E;IAC/E,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,6BAA6B;IASrC,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,2BAA2B;IAQnC,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,YAAY;IAKX,MAAM;CA0ChB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,UAAU,EAAE,KAAK,CAAA;KAClB;CACF"}
package/vue.d.ts ADDED
@@ -0,0 +1,42 @@
1
+ // GENERATED by @c2n/framework-types. Do not edit by hand.
2
+ //
3
+ // Vue template types for the custom elements of @c2n/radio. Import once, anywhere in the program:
4
+ //
5
+ // import '@c2n/radio/vue'
6
+ //
7
+ // Tell the compiler about the tags as well, or every c2-* tag is resolved as a Vue component and renders
8
+ // nothing: template.compilerOptions.isCustomElement = (tag) => tag.startsWith('c2-') in vite.config.ts.
9
+
10
+ import type { DefineComponent, HTMLAttributes } from 'vue'
11
+ import type { Radio, RadioEventMap } from '@c2n/radio/radio.js'
12
+ import type { RadioGroup, RadioGroupEventMap } from '@c2n/radio/radio-group.js'
13
+
14
+ /** The element's own public properties, plus every attribute Vue understands on a host element. */
15
+ type C2Props<T> = Partial<Omit<T, keyof HTMLElement>> & HTMLAttributes
16
+
17
+ declare module 'vue' {
18
+ interface GlobalComponents {
19
+ 'c2-radio': DefineComponent<
20
+ C2Props<Radio> & {
21
+ 'aria-label'?: unknown
22
+ 'aria-describedby'?: unknown
23
+ onChange?: (event: RadioEventMap['change']) => void
24
+ }
25
+ >
26
+ 'c2-radio-group': DefineComponent<
27
+ C2Props<RadioGroup> & {
28
+ 'aria-label'?: unknown
29
+ onChange?: (event: RadioGroupEventMap['change']) => void
30
+ }
31
+ >
32
+ }
33
+ }
34
+
35
+ declare module '@vue/runtime-dom' {
36
+ interface HTMLAttributes {
37
+ /** Vue's own definition omits it, and slotting a plain element into a component needs it. */
38
+ slot?: string
39
+ }
40
+ }
41
+
42
+ export {}
package/vue.js ADDED
@@ -0,0 +1,3 @@
1
+ // GENERATED by @c2n/framework-types. Do not edit by hand.
2
+ // Types only — see the matching .d.ts.
3
+ export {}