ion-accordion-group.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*!
  2. * (C) Ionic http://ionicframework.com - MIT License
  3. */
  4. import { proxyCustomElement, HTMLElement, createEvent, h, Host } from '@stencil/core/internal/client';
  5. import { a as printIonWarning } from './index4.js';
  6. import { b as getIonMode } from './ionic-global.js';
  7. const accordionGroupIosCss = ":host{display:block}:host(.accordion-group-expand-inset){-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:16px;margin-bottom:16px}:host(.accordion-group-expand-inset) ::slotted(ion-accordion.accordion-expanding),:host(.accordion-group-expand-inset) ::slotted(ion-accordion.accordion-expanded){border-bottom:none}";
  8. const IonAccordionGroupIosStyle0 = accordionGroupIosCss;
  9. const accordionGroupMdCss = ":host{display:block}:host(.accordion-group-expand-inset){-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:16px;margin-bottom:16px}:host(.accordion-group-expand-inset) ::slotted(ion-accordion){-webkit-box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12)}:host(.accordion-group-expand-inset) ::slotted(ion-accordion.accordion-expanding),:host(.accordion-group-expand-inset) ::slotted(ion-accordion.accordion-expanded){margin-left:0;margin-right:0;margin-top:16px;margin-bottom:16px;border-radius:6px}:host(.accordion-group-expand-inset) ::slotted(ion-accordion.accordion-previous){border-end-end-radius:6px;border-end-start-radius:6px}:host(.accordion-group-expand-inset) ::slotted(ion-accordion.accordion-next){border-start-start-radius:6px;border-start-end-radius:6px}:host(.accordion-group-expand-inset) ::slotted(ion-accordion):first-of-type{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}";
  10. const IonAccordionGroupMdStyle0 = accordionGroupMdCss;
  11. const AccordionGroup = /*@__PURE__*/ proxyCustomElement(class AccordionGroup extends HTMLElement {
  12. constructor() {
  13. super();
  14. this.__registerHost();
  15. this.__attachShadow();
  16. this.ionChange = createEvent(this, "ionChange", 7);
  17. this.ionValueChange = createEvent(this, "ionValueChange", 7);
  18. this.animated = true;
  19. this.multiple = undefined;
  20. this.value = undefined;
  21. this.disabled = false;
  22. this.readonly = false;
  23. this.expand = 'compact';
  24. }
  25. valueChanged() {
  26. const { value, multiple } = this;
  27. if (!multiple && Array.isArray(value)) {
  28. /**
  29. * We do some processing on the `value` array so
  30. * that it looks more like an array when logged to
  31. * the console.
  32. * Example given ['a', 'b']
  33. * Default toString() behavior: a,b
  34. * Custom behavior: ['a', 'b']
  35. */
  36. printIonWarning(`[ion-accordion-group] - An array of values was passed, but multiple is "false". This is incorrect usage and may result in unexpected behaviors. To dismiss this warning, pass a string to the "value" property when multiple="false".
  37. Value Passed: [${value.map((v) => `'${v}'`).join(', ')}]
  38. `, this.el);
  39. }
  40. /**
  41. * Do not use `value` here as that will be
  42. * not account for the adjustment we make above.
  43. */
  44. this.ionValueChange.emit({ value: this.value });
  45. }
  46. async disabledChanged() {
  47. const { disabled } = this;
  48. const accordions = await this.getAccordions();
  49. for (const accordion of accordions) {
  50. accordion.disabled = disabled;
  51. }
  52. }
  53. async readonlyChanged() {
  54. const { readonly } = this;
  55. const accordions = await this.getAccordions();
  56. for (const accordion of accordions) {
  57. accordion.readonly = readonly;
  58. }
  59. }
  60. async onKeydown(ev) {
  61. const activeElement = document.activeElement;
  62. if (!activeElement) {
  63. return;
  64. }
  65. /**
  66. * Make sure focus is in the header, not the body, of the accordion. This ensures
  67. * that if there are any interactable elements in the body, their keyboard
  68. * interaction doesn't get stolen by the accordion. Example: using up/down keys
  69. * in ion-textarea.
  70. */
  71. const activeAccordionHeader = activeElement.closest('ion-accordion [slot="header"]');
  72. if (!activeAccordionHeader) {
  73. return;
  74. }
  75. const accordionEl = activeElement.tagName === 'ION-ACCORDION' ? activeElement : activeElement.closest('ion-accordion');
  76. if (!accordionEl) {
  77. return;
  78. }
  79. const closestGroup = accordionEl.closest('ion-accordion-group');
  80. if (closestGroup !== this.el) {
  81. return;
  82. }
  83. // If the active accordion is not in the current array of accordions, do not do anything
  84. const accordions = await this.getAccordions();
  85. const startingIndex = accordions.findIndex((a) => a === accordionEl);
  86. if (startingIndex === -1) {
  87. return;
  88. }
  89. let accordion;
  90. if (ev.key === 'ArrowDown') {
  91. accordion = this.findNextAccordion(accordions, startingIndex);
  92. }
  93. else if (ev.key === 'ArrowUp') {
  94. accordion = this.findPreviousAccordion(accordions, startingIndex);
  95. }
  96. else if (ev.key === 'Home') {
  97. accordion = accordions[0];
  98. }
  99. else if (ev.key === 'End') {
  100. accordion = accordions[accordions.length - 1];
  101. }
  102. if (accordion !== undefined && accordion !== activeElement) {
  103. accordion.focus();
  104. }
  105. }
  106. async componentDidLoad() {
  107. if (this.disabled) {
  108. this.disabledChanged();
  109. }
  110. if (this.readonly) {
  111. this.readonlyChanged();
  112. }
  113. /**
  114. * When binding values in frameworks such as Angular
  115. * it is possible for the value to be set after the Web Component
  116. * initializes but before the value watcher is set up in Stencil.
  117. * As a result, the watcher callback may not be fired.
  118. * We work around this by manually calling the watcher
  119. * callback when the component has loaded and the watcher
  120. * is configured.
  121. */
  122. this.valueChanged();
  123. }
  124. /**
  125. * Sets the value property and emits ionChange.
  126. * This should only be called when the user interacts
  127. * with the accordion and not for any update
  128. * to the value property. The exception is when
  129. * the app sets the value of a single-select
  130. * accordion group to an array.
  131. */
  132. setValue(accordionValue) {
  133. const value = (this.value = accordionValue);
  134. this.ionChange.emit({ value });
  135. }
  136. /**
  137. * This method is used to ensure that the value
  138. * of ion-accordion-group is being set in a valid
  139. * way. This method should only be called in
  140. * response to a user generated action.
  141. * @internal
  142. */
  143. async requestAccordionToggle(accordionValue, accordionExpand) {
  144. const { multiple, value, readonly, disabled } = this;
  145. if (readonly || disabled) {
  146. return;
  147. }
  148. if (accordionExpand) {
  149. /**
  150. * If group accepts multiple values
  151. * check to see if value is already in
  152. * in values array. If not, add it
  153. * to the array.
  154. */
  155. if (multiple) {
  156. const groupValue = value !== null && value !== void 0 ? value : [];
  157. const processedValue = Array.isArray(groupValue) ? groupValue : [groupValue];
  158. const valueExists = processedValue.find((v) => v === accordionValue);
  159. if (valueExists === undefined && accordionValue !== undefined) {
  160. this.setValue([...processedValue, accordionValue]);
  161. }
  162. }
  163. else {
  164. this.setValue(accordionValue);
  165. }
  166. }
  167. else {
  168. /**
  169. * If collapsing accordion, either filter the value
  170. * out of the values array or unset the value.
  171. */
  172. if (multiple) {
  173. const groupValue = value !== null && value !== void 0 ? value : [];
  174. const processedValue = Array.isArray(groupValue) ? groupValue : [groupValue];
  175. this.setValue(processedValue.filter((v) => v !== accordionValue));
  176. }
  177. else {
  178. this.setValue(undefined);
  179. }
  180. }
  181. }
  182. findNextAccordion(accordions, startingIndex) {
  183. const nextAccordion = accordions[startingIndex + 1];
  184. if (nextAccordion === undefined) {
  185. return accordions[0];
  186. }
  187. return nextAccordion;
  188. }
  189. findPreviousAccordion(accordions, startingIndex) {
  190. const prevAccordion = accordions[startingIndex - 1];
  191. if (prevAccordion === undefined) {
  192. return accordions[accordions.length - 1];
  193. }
  194. return prevAccordion;
  195. }
  196. /**
  197. * @internal
  198. */
  199. async getAccordions() {
  200. return Array.from(this.el.querySelectorAll(':scope > ion-accordion'));
  201. }
  202. render() {
  203. const { disabled, readonly, expand } = this;
  204. const mode = getIonMode(this);
  205. return (h(Host, { key: 'd1a79a93179474fbba66fcf11a92f4871dacc975', class: {
  206. [mode]: true,
  207. 'accordion-group-disabled': disabled,
  208. 'accordion-group-readonly': readonly,
  209. [`accordion-group-expand-${expand}`]: true,
  210. }, role: "presentation" }, h("slot", { key: 'e6b8954b686d1fbb4fc92adb07fddc97a24b0a31' })));
  211. }
  212. get el() { return this; }
  213. static get watchers() { return {
  214. "value": ["valueChanged"],
  215. "disabled": ["disabledChanged"],
  216. "readonly": ["readonlyChanged"]
  217. }; }
  218. static get style() { return {
  219. ios: IonAccordionGroupIosStyle0,
  220. md: IonAccordionGroupMdStyle0
  221. }; }
  222. }, [33, "ion-accordion-group", {
  223. "animated": [4],
  224. "multiple": [4],
  225. "value": [1025],
  226. "disabled": [4],
  227. "readonly": [4],
  228. "expand": [1],
  229. "requestAccordionToggle": [64],
  230. "getAccordions": [64]
  231. }, [[0, "keydown", "onKeydown"]], {
  232. "value": ["valueChanged"],
  233. "disabled": ["disabledChanged"],
  234. "readonly": ["readonlyChanged"]
  235. }]);
  236. function defineCustomElement$1() {
  237. if (typeof customElements === "undefined") {
  238. return;
  239. }
  240. const components = ["ion-accordion-group"];
  241. components.forEach(tagName => { switch (tagName) {
  242. case "ion-accordion-group":
  243. if (!customElements.get(tagName)) {
  244. customElements.define(tagName, AccordionGroup);
  245. }
  246. break;
  247. } });
  248. }
  249. const IonAccordionGroup = AccordionGroup;
  250. const defineCustomElement = defineCustomElement$1;
  251. export { IonAccordionGroup, defineCustomElement };