calcite-radio-button.entry.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*!
  2. * All material copyright ESRI, All Rights Reserved, unless otherwise specified.
  3. * See https://github.com/Esri/calcite-components/blob/master/LICENSE.md for details.
  4. * v1.0.0-beta.97
  5. */
  6. import { r as registerInstance, c as createEvent, h, H as Host, g as getElement } from './index-1f9b54dc.js';
  7. import { g as guid } from './guid-9f15e57a.js';
  8. import { a as getElementDir, f as focusElement, t as toAriaBoolean } from './dom-8f0a9ff2.js';
  9. import { c as connectLabel, d as disconnectLabel, g as getLabelText } from './label-333c4a4c.js';
  10. import { c as connectForm, d as disconnectForm, H as HiddenFormInputSlot } from './form-80dbd90e.js';
  11. import { g as getRoundRobinIndex } from './array-03a17827.js';
  12. import { u as updateHostInteraction } from './interactive-5db230e8.js';
  13. import './resources-9c476cb6.js';
  14. const CSS = {
  15. container: "container"
  16. };
  17. const radioButtonCss = "@keyframes in{0%{opacity:0}100%{opacity:1}}@keyframes in-down{0%{opacity:0;transform:translate3D(0, -5px, 0)}100%{opacity:1;transform:translate3D(0, 0, 0)}}@keyframes in-up{0%{opacity:0;transform:translate3D(0, 5px, 0)}100%{opacity:1;transform:translate3D(0, 0, 0)}}@keyframes in-scale{0%{opacity:0;transform:scale3D(0.95, 0.95, 1)}100%{opacity:1;transform:scale3D(1, 1, 1)}}:root{--calcite-animation-timing:calc(150ms * var(--calcite-internal-duration-factor));--calcite-internal-duration-factor:var(--calcite-duration-factor, 1);--calcite-internal-animation-timing-fast:calc(100ms * var(--calcite-internal-duration-factor));--calcite-internal-animation-timing-medium:calc(200ms * var(--calcite-internal-duration-factor));--calcite-internal-animation-timing-slow:calc(300ms * var(--calcite-internal-duration-factor))}.calcite-animate{opacity:0;animation-fill-mode:both;animation-duration:var(--calcite-animation-timing)}.calcite-animate__in{animation-name:in}.calcite-animate__in-down{animation-name:in-down}.calcite-animate__in-up{animation-name:in-up}.calcite-animate__in-scale{animation-name:in-scale}@media (prefers-reduced-motion: reduce){:root{--calcite-internal-duration-factor:0.01}}:root{--calcite-floating-ui-transition:var(--calcite-animation-timing)}:host([hidden]){display:none}:host([disabled]){pointer-events:none;cursor:default;-webkit-user-select:none;user-select:none;opacity:var(--calcite-ui-opacity-disabled)}:host{display:block;cursor:pointer}:host .container{position:relative;outline:2px solid transparent;outline-offset:2px}:host .radio{cursor:pointer;border-radius:9999px;background-color:var(--calcite-ui-foreground-1);outline-color:transparent;transition:all var(--calcite-animation-timing) ease-in-out 0s, outline 0s, outline-offset 0s;box-shadow:inset 0 0 0 1px var(--calcite-ui-border-input)}:host([hovered]) .radio,:host(:not([checked])[focused]:not([disabled])) .radio{box-shadow:inset 0 0 0 2px var(--calcite-ui-brand)}:host([focused]) .radio{outline:2px solid var(--calcite-ui-brand);outline-offset:2px}:host([disabled]) .radio{cursor:default;opacity:var(--calcite-ui-opacity-disabled)}:host([disabled]) ::slotted([calcite-hydrated][disabled]),:host([disabled]) [calcite-hydrated][disabled]{opacity:1}:host([hovered][disabled]) .radio{box-shadow:inset 0 0 0 1px var(--calcite-ui-border-input)}:host([scale=s]){--calcite-radio-size:var(--calcite-font-size--2)}:host([scale=m]){--calcite-radio-size:var(--calcite-font-size--1)}:host([scale=l]){--calcite-radio-size:var(--calcite-font-size-0)}.radio{block-size:var(--calcite-radio-size);max-inline-size:var(--calcite-radio-size);min-inline-size:var(--calcite-radio-size)}:host([scale=s][checked]) .radio,:host([hovered][scale=s][checked][disabled]) .radio{box-shadow:inset 0 0 0 4px var(--calcite-ui-brand)}:host([scale=s][focused][checked]:not([disabled])) .radio{box-shadow:inset 0 0 0 4px var(--calcite-ui-brand), 0 0 0 2px var(--calcite-ui-foreground-1)}:host([scale=m][checked]) .radio,:host([hovered][scale=m][checked][disabled]) .radio{box-shadow:inset 0 0 0 5px var(--calcite-ui-brand)}:host([scale=m][focused][checked]:not([disabled])) .radio{box-shadow:inset 0 0 0 5px var(--calcite-ui-brand), 0 0 0 2px var(--calcite-ui-foreground-1)}:host([scale=l][checked]) .radio,:host([hovered][scale=l][checked][disabled]) .radio{box-shadow:inset 0 0 0 6px var(--calcite-ui-brand)}:host([scale=l][focused][checked]:not([disabled])) .radio{box-shadow:inset 0 0 0 6px var(--calcite-ui-brand), 0 0 0 2px var(--calcite-ui-foreground-1)}@media (forced-colors: active){:host([checked]) .radio::after,:host([checked][disabled]) .radio::after{content:\"\";inline-size:var(--calcite-radio-size);block-size:var(--calcite-radio-size);background-color:windowText;display:block}}::slotted(input[slot=hidden-form-input]){margin:0 !important;opacity:0 !important;outline:none !important;padding:0 !important;position:absolute !important;inset:0 !important;transform:none !important;-webkit-appearance:none !important;z-index:-1 !important}";
  18. const RadioButton = class {
  19. constructor(hostRef) {
  20. registerInstance(this, hostRef);
  21. this.calciteInternalRadioButtonBlur = createEvent(this, "calciteInternalRadioButtonBlur", 6);
  22. this.calciteRadioButtonChange = createEvent(this, "calciteRadioButtonChange", 6);
  23. this.calciteInternalRadioButtonCheckedChange = createEvent(this, "calciteInternalRadioButtonCheckedChange", 6);
  24. this.calciteInternalRadioButtonFocus = createEvent(this, "calciteInternalRadioButtonFocus", 6);
  25. //--------------------------------------------------------------------------
  26. //
  27. // Properties
  28. //
  29. //--------------------------------------------------------------------------
  30. /** When `true`, the component is checked. */
  31. this.checked = false;
  32. /** When `true`, interaction is prevented and the component is displayed with lower opacity. */
  33. this.disabled = false;
  34. /**
  35. * The focused state of the component.
  36. *
  37. * @internal
  38. */
  39. this.focused = false;
  40. /** When `true`, the component is not displayed and is not focusable or checkable. */
  41. this.hidden = false;
  42. /**
  43. * The hovered state of the component.
  44. *
  45. * @internal
  46. */
  47. this.hovered = false;
  48. /** When `true`, the component must have a value selected from the `calcite-radio-button-group` in order for the form to submit. */
  49. this.required = false;
  50. /** Specifies the size of the component inherited from the `calcite-radio-button-group`. */
  51. this.scale = "m";
  52. //--------------------------------------------------------------------------
  53. //
  54. // Private Methods
  55. //
  56. //--------------------------------------------------------------------------
  57. this.selectItem = (items, selectedIndex) => {
  58. items[selectedIndex].click();
  59. };
  60. this.queryButtons = () => {
  61. return Array.from(this.rootNode.querySelectorAll("calcite-radio-button:not([hidden])")).filter((radioButton) => radioButton.name === this.name);
  62. };
  63. this.isDefaultSelectable = () => {
  64. const radioButtons = this.queryButtons();
  65. return !radioButtons.some((radioButton) => radioButton.checked) && radioButtons[0] === this.el;
  66. };
  67. this.check = () => {
  68. if (this.disabled) {
  69. return;
  70. }
  71. this.uncheckAllRadioButtonsInGroup();
  72. this.checked = true;
  73. this.focused = true;
  74. this.calciteRadioButtonChange.emit();
  75. this.setFocus();
  76. };
  77. this.clickHandler = () => {
  78. this.check();
  79. };
  80. this.setContainerEl = (el) => {
  81. this.containerEl = el;
  82. };
  83. this.handleKeyDown = (event) => {
  84. const keys = ["ArrowLeft", "ArrowUp", "ArrowRight", "ArrowDown", " "];
  85. const { key } = event;
  86. const { el } = this;
  87. if (keys.indexOf(key) === -1) {
  88. return;
  89. }
  90. if (key === " ") {
  91. this.check();
  92. event.preventDefault();
  93. return;
  94. }
  95. let adjustedKey = key;
  96. if (getElementDir(el) === "rtl") {
  97. if (key === "ArrowRight") {
  98. adjustedKey = "ArrowLeft";
  99. }
  100. if (key === "ArrowLeft") {
  101. adjustedKey = "ArrowRight";
  102. }
  103. }
  104. const radioButtons = Array.from(this.rootNode.querySelectorAll("calcite-radio-button:not([hidden]")).filter((radioButton) => radioButton.name === this.name);
  105. let currentIndex = 0;
  106. const radioButtonsLength = radioButtons.length;
  107. radioButtons.some((item, index) => {
  108. if (item.checked) {
  109. currentIndex = index;
  110. return true;
  111. }
  112. });
  113. switch (adjustedKey) {
  114. case "ArrowLeft":
  115. case "ArrowUp":
  116. event.preventDefault();
  117. this.selectItem(radioButtons, getRoundRobinIndex(Math.max(currentIndex - 1, -1), radioButtonsLength));
  118. return;
  119. case "ArrowRight":
  120. case "ArrowDown":
  121. event.preventDefault();
  122. this.selectItem(radioButtons, getRoundRobinIndex(currentIndex + 1, radioButtonsLength));
  123. return;
  124. default:
  125. return;
  126. }
  127. };
  128. this.onContainerBlur = () => {
  129. this.focused = false;
  130. this.calciteInternalRadioButtonBlur.emit();
  131. };
  132. this.onContainerFocus = () => {
  133. if (!this.disabled) {
  134. this.focused = true;
  135. this.calciteInternalRadioButtonFocus.emit();
  136. }
  137. };
  138. }
  139. checkedChanged(newChecked) {
  140. if (newChecked) {
  141. this.uncheckOtherRadioButtonsInGroup();
  142. }
  143. this.calciteInternalRadioButtonCheckedChange.emit();
  144. }
  145. nameChanged() {
  146. this.checkLastRadioButton();
  147. }
  148. //--------------------------------------------------------------------------
  149. //
  150. // Public Methods
  151. //
  152. //--------------------------------------------------------------------------
  153. /** Sets focus on the component. */
  154. async setFocus() {
  155. if (!this.disabled) {
  156. focusElement(this.containerEl);
  157. }
  158. }
  159. onLabelClick(event) {
  160. if (!this.disabled && !this.hidden) {
  161. this.uncheckOtherRadioButtonsInGroup();
  162. const label = event.currentTarget;
  163. const radioButton = label.for
  164. ? this.rootNode.querySelector(`calcite-radio-button[id="${label.for}"]`)
  165. : label.querySelector(`calcite-radio-button[name="${this.name}"]`);
  166. if (radioButton) {
  167. radioButton.checked = true;
  168. radioButton.focused = true;
  169. }
  170. this.calciteRadioButtonChange.emit();
  171. this.setFocus();
  172. }
  173. }
  174. checkLastRadioButton() {
  175. const radioButtons = this.queryButtons();
  176. const checkedRadioButtons = radioButtons.filter((radioButton) => radioButton.checked);
  177. if ((checkedRadioButtons === null || checkedRadioButtons === void 0 ? void 0 : checkedRadioButtons.length) > 1) {
  178. const lastCheckedRadioButton = checkedRadioButtons[checkedRadioButtons.length - 1];
  179. checkedRadioButtons
  180. .filter((checkedRadioButton) => checkedRadioButton !== lastCheckedRadioButton)
  181. .forEach((checkedRadioButton) => {
  182. checkedRadioButton.checked = false;
  183. checkedRadioButton.emitCheckedChange();
  184. });
  185. }
  186. }
  187. /** @internal */
  188. async emitCheckedChange() {
  189. this.calciteInternalRadioButtonCheckedChange.emit();
  190. }
  191. uncheckAllRadioButtonsInGroup() {
  192. const radioButtons = this.queryButtons();
  193. radioButtons.forEach((radioButton) => {
  194. if (radioButton.checked) {
  195. radioButton.checked = false;
  196. radioButton.focused = false;
  197. }
  198. });
  199. }
  200. uncheckOtherRadioButtonsInGroup() {
  201. const radioButtons = this.queryButtons();
  202. const otherRadioButtons = radioButtons.filter((radioButton) => radioButton.guid !== this.guid);
  203. otherRadioButtons.forEach((otherRadioButton) => {
  204. if (otherRadioButton.checked) {
  205. otherRadioButton.checked = false;
  206. otherRadioButton.focused = false;
  207. }
  208. });
  209. }
  210. getTabIndex() {
  211. if (this.disabled) {
  212. return undefined;
  213. }
  214. return this.checked || this.isDefaultSelectable() ? 0 : -1;
  215. }
  216. //--------------------------------------------------------------------------
  217. //
  218. // Event Listeners
  219. //
  220. //--------------------------------------------------------------------------
  221. mouseenter() {
  222. this.hovered = true;
  223. }
  224. mouseleave() {
  225. this.hovered = false;
  226. }
  227. //--------------------------------------------------------------------------
  228. //
  229. // Lifecycle
  230. //
  231. //--------------------------------------------------------------------------
  232. connectedCallback() {
  233. this.rootNode = this.el.getRootNode();
  234. this.guid = this.el.id || `calcite-radio-button-${guid()}`;
  235. if (this.name) {
  236. this.checkLastRadioButton();
  237. }
  238. connectLabel(this);
  239. connectForm(this);
  240. }
  241. componentDidLoad() {
  242. if (this.focused && !this.disabled) {
  243. this.setFocus();
  244. }
  245. }
  246. disconnectedCallback() {
  247. disconnectLabel(this);
  248. disconnectForm(this);
  249. }
  250. componentDidRender() {
  251. updateHostInteraction(this);
  252. }
  253. // --------------------------------------------------------------------------
  254. //
  255. // Render Methods
  256. //
  257. // --------------------------------------------------------------------------
  258. render() {
  259. const tabIndex = this.getTabIndex();
  260. return (h(Host, { onClick: this.clickHandler, onKeyDown: this.handleKeyDown }, h("div", { "aria-checked": toAriaBoolean(this.checked), "aria-label": getLabelText(this), class: CSS.container, onBlur: this.onContainerBlur, onFocus: this.onContainerFocus, ref: this.setContainerEl, role: "radio", tabIndex: tabIndex }, h("div", { class: "radio" })), h(HiddenFormInputSlot, { component: this })));
  261. }
  262. get el() { return getElement(this); }
  263. static get watchers() { return {
  264. "checked": ["checkedChanged"],
  265. "name": ["nameChanged"]
  266. }; }
  267. };
  268. RadioButton.style = radioButtonCss;
  269. export { RadioButton as calcite_radio_button };