UNPKG

5.12 kBJavaScriptView Raw
1/*!
2 * (C) Ionic http://ionicframework.com - MIT License
3 */
4import { proxyCustomElement, HTMLElement, createEvent, h, Host } from '@stencil/core/internal/client';
5import { b as getIonMode } from './ionic-global.js';
6
7const RadioGroup = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
8 constructor() {
9 super();
10 this.__registerHost();
11 this.ionChange = createEvent(this, "ionChange", 7);
12 this.inputId = `ion-rg-${radioGroupIds++}`;
13 this.labelId = `${this.inputId}-lbl`;
14 /**
15 * If `true`, the radios can be deselected.
16 */
17 this.allowEmptySelection = false;
18 /**
19 * The name of the control, which is submitted with the form data.
20 */
21 this.name = this.inputId;
22 this.setRadioTabindex = (value) => {
23 const radios = this.getRadios();
24 // Get the first radio that is not disabled and the checked one
25 const first = radios.find(radio => !radio.disabled);
26 const checked = radios.find(radio => (radio.value === value && !radio.disabled));
27 if (!first && !checked) {
28 return;
29 }
30 // If an enabled checked radio exists, set it to be the focusable radio
31 // otherwise we default to focus the first radio
32 const focusable = checked || first;
33 for (const radio of radios) {
34 const tabindex = radio === focusable ? 0 : -1;
35 radio.setButtonTabindex(tabindex);
36 }
37 };
38 this.onClick = (ev) => {
39 ev.preventDefault();
40 const selectedRadio = ev.target && ev.target.closest('ion-radio');
41 if (selectedRadio) {
42 const currentValue = this.value;
43 const newValue = selectedRadio.value;
44 if (newValue !== currentValue) {
45 this.value = newValue;
46 }
47 else if (this.allowEmptySelection) {
48 this.value = undefined;
49 }
50 }
51 };
52 }
53 valueChanged(value) {
54 this.setRadioTabindex(value);
55 this.ionChange.emit({ value });
56 }
57 componentDidLoad() {
58 this.setRadioTabindex(this.value);
59 }
60 async connectedCallback() {
61 // Get the list header if it exists and set the id
62 // this is used to set aria-labelledby
63 const header = this.el.querySelector('ion-list-header') || this.el.querySelector('ion-item-divider');
64 if (header) {
65 const label = this.label = header.querySelector('ion-label');
66 if (label) {
67 this.labelId = label.id = this.name + '-lbl';
68 }
69 }
70 }
71 getRadios() {
72 return Array.from(this.el.querySelectorAll('ion-radio'));
73 }
74 onKeydown(ev) {
75 const inSelectPopover = !!this.el.closest('ion-select-popover');
76 if (ev.target && !this.el.contains(ev.target)) {
77 return;
78 }
79 // Get all radios inside of the radio group and then
80 // filter out disabled radios since we need to skip those
81 const radios = this.getRadios().filter(radio => !radio.disabled);
82 // Only move the radio if the current focus is in the radio group
83 if (ev.target && radios.includes(ev.target)) {
84 const index = radios.findIndex(radio => radio === ev.target);
85 const current = radios[index];
86 let next;
87 // If hitting arrow down or arrow right, move to the next radio
88 // If we're on the last radio, move to the first radio
89 if (['ArrowDown', 'ArrowRight'].includes(ev.code)) {
90 next = (index === radios.length - 1)
91 ? radios[0]
92 : radios[index + 1];
93 }
94 // If hitting arrow up or arrow left, move to the previous radio
95 // If we're on the first radio, move to the last radio
96 if (['ArrowUp', 'ArrowLeft'].includes(ev.code)) {
97 next = (index === 0)
98 ? radios[radios.length - 1]
99 : radios[index - 1];
100 }
101 if (next && radios.includes(next)) {
102 next.setFocus(ev);
103 if (!inSelectPopover) {
104 this.value = next.value;
105 }
106 }
107 // Update the radio group value when a user presses the
108 // space bar on top of a selected radio
109 if (['Space'].includes(ev.code)) {
110 this.value = (this.allowEmptySelection && this.value !== undefined)
111 ? undefined
112 : current.value;
113 // Prevent browsers from jumping
114 // to the bottom of the screen
115 ev.preventDefault();
116 }
117 }
118 }
119 render() {
120 const { label, labelId } = this;
121 const mode = getIonMode(this);
122 return (h(Host, { role: "radiogroup", "aria-labelledby": label ? labelId : null, onClick: this.onClick, class: mode }));
123 }
124 get el() { return this; }
125 static get watchers() { return {
126 "value": ["valueChanged"]
127 }; }
128}, [0, "ion-radio-group", {
129 "allowEmptySelection": [4, "allow-empty-selection"],
130 "name": [1],
131 "value": [1032]
132 }, [[4, "keydown", "onKeydown"]]]);
133let radioGroupIds = 0;
134function defineCustomElement() {
135 if (typeof customElements === "undefined") {
136 return;
137 }
138 const components = ["ion-radio-group"];
139 components.forEach(tagName => { switch (tagName) {
140 case "ion-radio-group":
141 if (!customElements.get(tagName)) {
142 customElements.define(tagName, RadioGroup);
143 }
144 break;
145 } });
146}
147
148export { RadioGroup as R, defineCustomElement as d };