@empathyco/x-components 6.0.0-alpha.62 → 6.0.0-alpha.64

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 (173) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/design-system/deprecated-full-theme.css +3942 -3942
  3. package/docs/API-reference/api/x-adapter-platform.md +1 -1
  4. package/docs/API-reference/api/x-adapter-platform.nextqueriesrelatedpromptsschema.md +2 -0
  5. package/docs/API-reference/api/x-components.fallbackdisclaimer.md +2 -2
  6. package/docs/API-reference/api/x-components.historyqueriesswitch.md +1 -1
  7. package/docs/API-reference/api/x-components.identifierresult.md +1 -1
  8. package/docs/API-reference/api/x-components.identifierresults.md +1 -1
  9. package/docs/API-reference/api/x-components.md +1 -1
  10. package/docs/API-reference/api/x-components.myhistory.md +1 -1
  11. package/docs/API-reference/api/x-components.partialresultslist.md +1 -1
  12. package/docs/API-reference/api/x-components.querypreview.md +2 -2
  13. package/docs/API-reference/api/x-components.recommendations.md +1 -1
  14. package/docs/API-reference/api/x-components.relatedpromptstaglist.md +2 -2
  15. package/docs/API-reference/api/x-components.relatedtag.md +3 -3
  16. package/docs/API-reference/api/x-components.scrolltotop.md +1 -1
  17. package/docs/API-reference/api/x-components.searchbutton.md +1 -1
  18. package/docs/API-reference/api/x-components.searchinput.md +1 -1
  19. package/docs/API-reference/api/x-components.semanticqueries.md +1 -1
  20. package/docs/API-reference/api/x-components.sortdropdown.md +1 -1
  21. package/docs/API-reference/api/x-components.sortlist.md +1 -1
  22. package/docs/API-reference/api/x-components.sortpickerlist.md +1 -1
  23. package/docs/API-reference/api/x-components.spellcheck.md +2 -2
  24. package/docs/API-reference/api/x-components.spellcheckbutton.md +1 -1
  25. package/docs/API-reference/api/x-components.usestate.md +5 -4
  26. package/docs/API-reference/api/x-types.md +1 -1
  27. package/docs/API-reference/api/x-types.xcomponentsadapter.md +2 -0
  28. package/js/composables/use-state.js +7 -9
  29. package/js/composables/use-state.js.map +1 -1
  30. package/js/directives/infinite-scroll.js +1 -1
  31. package/js/directives/infinite-scroll.js.map +1 -1
  32. package/js/x-installer/api/base-api.js +2 -2
  33. package/js/x-installer/api/base-api.js.map +1 -1
  34. package/js/x-modules/extra-params/components/extra-params.vue.js +1 -1
  35. package/js/x-modules/extra-params/components/extra-params.vue.js.map +1 -1
  36. package/js/x-modules/extra-params/components/renderless-extra-param.vue.js +1 -1
  37. package/js/x-modules/extra-params/components/renderless-extra-param.vue.js.map +1 -1
  38. package/js/x-modules/history-queries/components/clear-history-queries.vue.js.map +1 -1
  39. package/js/x-modules/history-queries/components/clear-history-queries.vue2.js +1 -1
  40. package/js/x-modules/history-queries/components/clear-history-queries.vue2.js.map +1 -1
  41. package/js/x-modules/history-queries/components/history-queries-switch.vue.js.map +1 -1
  42. package/js/x-modules/history-queries/components/history-queries-switch.vue2.js +1 -4
  43. package/js/x-modules/history-queries/components/history-queries-switch.vue2.js.map +1 -1
  44. package/js/x-modules/history-queries/components/my-history.vue.js.map +1 -1
  45. package/js/x-modules/history-queries/components/my-history.vue2.js +1 -1
  46. package/js/x-modules/history-queries/components/my-history.vue2.js.map +1 -1
  47. package/js/x-modules/identifier-results/components/identifier-result.vue.js.map +1 -1
  48. package/js/x-modules/identifier-results/components/identifier-result.vue2.js +1 -1
  49. package/js/x-modules/identifier-results/components/identifier-result.vue2.js.map +1 -1
  50. package/js/x-modules/identifier-results/components/identifier-results.vue.js.map +1 -1
  51. package/js/x-modules/identifier-results/components/identifier-results.vue2.js +1 -1
  52. package/js/x-modules/identifier-results/components/identifier-results.vue2.js.map +1 -1
  53. package/js/x-modules/next-queries/components/next-queries-list.vue.js +1 -1
  54. package/js/x-modules/next-queries/components/next-queries-list.vue.js.map +1 -1
  55. package/js/x-modules/next-queries/components/next-query-preview.vue.js.map +1 -1
  56. package/js/x-modules/next-queries/components/next-query-preview.vue2.js +1 -1
  57. package/js/x-modules/next-queries/components/next-query-preview.vue2.js.map +1 -1
  58. package/js/x-modules/queries-preview/components/query-preview-button.vue.js.map +1 -1
  59. package/js/x-modules/queries-preview/components/query-preview-button.vue2.js +1 -1
  60. package/js/x-modules/queries-preview/components/query-preview-button.vue2.js.map +1 -1
  61. package/js/x-modules/queries-preview/components/query-preview-list.vue.js.map +1 -1
  62. package/js/x-modules/queries-preview/components/query-preview-list.vue2.js +1 -1
  63. package/js/x-modules/queries-preview/components/query-preview-list.vue2.js.map +1 -1
  64. package/js/x-modules/queries-preview/components/query-preview.vue.js.map +1 -1
  65. package/js/x-modules/queries-preview/components/query-preview.vue2.js +6 -11
  66. package/js/x-modules/queries-preview/components/query-preview.vue2.js.map +1 -1
  67. package/js/x-modules/recommendations/components/recommendations.vue.js.map +1 -1
  68. package/js/x-modules/recommendations/components/recommendations.vue2.js +1 -3
  69. package/js/x-modules/recommendations/components/recommendations.vue2.js.map +1 -1
  70. package/js/x-modules/related-prompts/components/related-prompts-list.vue.js +1 -4
  71. package/js/x-modules/related-prompts/components/related-prompts-list.vue.js.map +1 -1
  72. package/js/x-modules/related-prompts/components/related-prompts-tag-list.vue.js.map +1 -1
  73. package/js/x-modules/related-prompts/components/related-prompts-tag-list.vue2.js +1 -6
  74. package/js/x-modules/related-prompts/components/related-prompts-tag-list.vue2.js.map +1 -1
  75. package/js/x-modules/related-tags/components/related-tag.vue.js.map +1 -1
  76. package/js/x-modules/related-tags/components/related-tag.vue2.js +1 -1
  77. package/js/x-modules/related-tags/components/related-tag.vue2.js.map +1 -1
  78. package/js/x-modules/scroll/components/main-scroll-item.vue.js.map +1 -1
  79. package/js/x-modules/scroll/components/main-scroll-item.vue2.js +1 -1
  80. package/js/x-modules/scroll/components/main-scroll-item.vue2.js.map +1 -1
  81. package/js/x-modules/scroll/components/main-scroll.vue.js +1 -1
  82. package/js/x-modules/scroll/components/main-scroll.vue.js.map +1 -1
  83. package/js/x-modules/scroll/components/scroll-to-top.vue.js.map +1 -1
  84. package/js/x-modules/scroll/components/scroll-to-top.vue2.js +1 -1
  85. package/js/x-modules/scroll/components/scroll-to-top.vue2.js.map +1 -1
  86. package/js/x-modules/search/components/banners-list.vue.js +1 -1
  87. package/js/x-modules/search/components/banners-list.vue.js.map +1 -1
  88. package/js/x-modules/search/components/fallback-disclaimer.vue.js.map +1 -1
  89. package/js/x-modules/search/components/fallback-disclaimer.vue2.js +1 -4
  90. package/js/x-modules/search/components/fallback-disclaimer.vue2.js.map +1 -1
  91. package/js/x-modules/search/components/partial-results-list.vue.js.map +1 -1
  92. package/js/x-modules/search/components/partial-results-list.vue2.js +1 -3
  93. package/js/x-modules/search/components/partial-results-list.vue2.js.map +1 -1
  94. package/js/x-modules/search/components/promoteds-list.vue.js +1 -1
  95. package/js/x-modules/search/components/promoteds-list.vue.js.map +1 -1
  96. package/js/x-modules/search/components/redirection.vue.js.map +1 -1
  97. package/js/x-modules/search/components/redirection.vue2.js +1 -1
  98. package/js/x-modules/search/components/redirection.vue2.js.map +1 -1
  99. package/js/x-modules/search/components/results-list.vue.js +1 -7
  100. package/js/x-modules/search/components/results-list.vue.js.map +1 -1
  101. package/js/x-modules/search/components/sort-dropdown.vue.js.map +1 -1
  102. package/js/x-modules/search/components/sort-dropdown.vue2.js +1 -1
  103. package/js/x-modules/search/components/sort-dropdown.vue2.js.map +1 -1
  104. package/js/x-modules/search/components/sort-list.vue.js.map +1 -1
  105. package/js/x-modules/search/components/sort-list.vue2.js +1 -1
  106. package/js/x-modules/search/components/sort-list.vue2.js.map +1 -1
  107. package/js/x-modules/search/components/sort-picker-list.vue.js.map +1 -1
  108. package/js/x-modules/search/components/sort-picker-list.vue2.js +1 -1
  109. package/js/x-modules/search/components/sort-picker-list.vue2.js.map +1 -1
  110. package/js/x-modules/search/components/spellcheck-button.vue.js.map +1 -1
  111. package/js/x-modules/search/components/spellcheck-button.vue2.js +1 -1
  112. package/js/x-modules/search/components/spellcheck-button.vue2.js.map +1 -1
  113. package/js/x-modules/search/components/spellcheck.vue.js.map +1 -1
  114. package/js/x-modules/search/components/spellcheck.vue2.js +1 -1
  115. package/js/x-modules/search/components/spellcheck.vue2.js.map +1 -1
  116. package/js/x-modules/search-box/components/clear-search-input.vue.js.map +1 -1
  117. package/js/x-modules/search-box/components/clear-search-input.vue2.js +1 -1
  118. package/js/x-modules/search-box/components/clear-search-input.vue2.js.map +1 -1
  119. package/js/x-modules/search-box/components/search-button.vue.js.map +1 -1
  120. package/js/x-modules/search-box/components/search-button.vue2.js +1 -1
  121. package/js/x-modules/search-box/components/search-button.vue2.js.map +1 -1
  122. package/js/x-modules/search-box/components/search-input-placeholder.vue.js.map +1 -1
  123. package/js/x-modules/search-box/components/search-input-placeholder.vue2.js +1 -1
  124. package/js/x-modules/search-box/components/search-input-placeholder.vue2.js.map +1 -1
  125. package/js/x-modules/search-box/components/search-input.vue.js.map +1 -1
  126. package/js/x-modules/search-box/components/search-input.vue2.js +1 -1
  127. package/js/x-modules/search-box/components/search-input.vue2.js.map +1 -1
  128. package/js/x-modules/semantic-queries/components/semantic-queries.vue.js.map +1 -1
  129. package/js/x-modules/semantic-queries/components/semantic-queries.vue2.js +1 -3
  130. package/js/x-modules/semantic-queries/components/semantic-queries.vue2.js.map +1 -1
  131. package/js/x-modules/url/components/url-handler.vue.js.map +1 -1
  132. package/js/x-modules/url/components/url-handler.vue2.js +1 -1
  133. package/js/x-modules/url/components/url-handler.vue2.js.map +1 -1
  134. package/package.json +3 -3
  135. package/report/x-adapter-platform.api.json +2 -2
  136. package/report/x-components.api.json +63 -70
  137. package/report/x-components.api.md +22 -20
  138. package/report/x-types.api.json +3 -3
  139. package/types/composables/use-state.d.ts +4 -5
  140. package/types/composables/use-state.d.ts.map +1 -1
  141. package/types/x-modules/extra-params/components/extra-params.vue.d.ts.map +1 -1
  142. package/types/x-modules/history-queries/components/history-queries-switch.vue.d.ts +1 -1
  143. package/types/x-modules/history-queries/components/history-queries-switch.vue.d.ts.map +1 -1
  144. package/types/x-modules/history-queries/components/my-history.vue.d.ts +1 -1
  145. package/types/x-modules/identifier-results/components/identifier-result.vue.d.ts +1 -1
  146. package/types/x-modules/identifier-results/components/identifier-results.vue.d.ts +1 -1
  147. package/types/x-modules/queries-preview/components/query-preview.vue.d.ts +3 -3
  148. package/types/x-modules/queries-preview/components/query-preview.vue.d.ts.map +1 -1
  149. package/types/x-modules/recommendations/components/recommendations.vue.d.ts +1 -2
  150. package/types/x-modules/recommendations/components/recommendations.vue.d.ts.map +1 -1
  151. package/types/x-modules/related-prompts/components/related-prompts-list.vue.d.ts.map +1 -1
  152. package/types/x-modules/related-prompts/components/related-prompts-tag-list.vue.d.ts +3 -3
  153. package/types/x-modules/related-prompts/components/related-prompts-tag-list.vue.d.ts.map +1 -1
  154. package/types/x-modules/related-tags/components/related-tag.vue.d.ts +4 -4
  155. package/types/x-modules/related-tags/components/related-tag.vue.d.ts.map +1 -1
  156. package/types/x-modules/scroll/components/scroll-to-top.vue.d.ts +1 -1
  157. package/types/x-modules/search/components/banners-list.vue.d.ts.map +1 -1
  158. package/types/x-modules/search/components/fallback-disclaimer.vue.d.ts +2 -2
  159. package/types/x-modules/search/components/fallback-disclaimer.vue.d.ts.map +1 -1
  160. package/types/x-modules/search/components/partial-results-list.vue.d.ts +1 -3
  161. package/types/x-modules/search/components/partial-results-list.vue.d.ts.map +1 -1
  162. package/types/x-modules/search/components/promoteds-list.vue.d.ts.map +1 -1
  163. package/types/x-modules/search/components/results-list.vue.d.ts.map +1 -1
  164. package/types/x-modules/search/components/sort-dropdown.vue.d.ts +1 -1
  165. package/types/x-modules/search/components/sort-list.vue.d.ts +1 -1
  166. package/types/x-modules/search/components/sort-picker-list.vue.d.ts +1 -1
  167. package/types/x-modules/search/components/spellcheck-button.vue.d.ts +1 -1
  168. package/types/x-modules/search/components/spellcheck.vue.d.ts +2 -2
  169. package/types/x-modules/search-box/components/search-button.vue.d.ts +1 -2
  170. package/types/x-modules/search-box/components/search-button.vue.d.ts.map +1 -1
  171. package/types/x-modules/search-box/components/search-input.vue.d.ts +1 -1
  172. package/types/x-modules/semantic-queries/components/semantic-queries.vue.d.ts +1 -3
  173. package/types/x-modules/semantic-queries/components/semantic-queries.vue.d.ts.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"search-input.vue.js","sources":["../../../../../src/x-modules/search-box/components/search-input.vue"],"sourcesContent":["<template>\n <input\n ref=\"inputElement\"\n :maxlength=\"maxLength\"\n :value=\"query\"\n autocomplete=\"off\"\n class=\"x-search-input x-input\"\n enterkeyhint=\"search\"\n inputmode=\"search\"\n type=\"search\"\n data-test=\"search-input\"\n aria-label=\"type your query here\"\n @mouseenter=\"emitUserHoveredInSearchBox\"\n @mouseleave=\"emitUserHoveredOutSearchBox\"\n @blur=\"emitUserBlurredSearchBox\"\n @click=\"emitUserClickedSearchBox\"\n @focus=\"emitUserFocusedSearchBox\"\n @input=\"emitUserIsTypingAQueryEvents\"\n @keydown.enter=\"emitUserPressedEnterKey\"\n @keydown.up.down.prevent=\"emitUserPressedArrowKey\"\n @beforeinput=\"preventSpecialKey\"\n />\n</template>\n\n<script lang=\"ts\">\nimport type { ArrowKey } from '../../../utils'\nimport type { DebouncedFunction } from '../../../utils/types'\nimport type { XEvent } from '../../../wiring/events.types'\nimport type { WireMetadata } from '../../../wiring/wiring.types'\nimport { defineComponent, onMounted, ref } from 'vue'\nimport { use$x } from '../../../composables/use-$x'\nimport { useState } from '../../../composables/use-state'\nimport { debounce } from '../../../utils/debounce'\nimport { searchBoxXModule } from '../x-module'\n\n/**\n * This component renders an input field that allows the user to type a query. It also reacts to\n * query changes through event listening.\n *\n * @public\n */\nexport default defineComponent({\n name: 'SearchInput',\n xModule: searchBoxXModule.name,\n props: {\n /**\n * Maximum characters allowed in the input search.\n */\n maxLength: {\n type: Number,\n default: 64,\n },\n /**\n * Allows input autofocus when the search field is rendered.\n */\n autofocus: {\n type: Boolean,\n default: true,\n },\n /**\n * Enables the auto-accept query after debounce.\n */\n instant: {\n type: Boolean,\n default: true,\n },\n /**\n * Debounce time for the instant.\n */\n instantDebounceInMs: {\n type: Number,\n default: 500,\n },\n },\n setup(props) {\n const $x = use$x()\n\n const { query } = useState('searchBox', ['query'])\n\n const inputElement = ref<HTMLInputElement>()\n\n let debouncedUserAcceptedAQuery: DebouncedFunction<[string]>\n\n /**\n * Generates the {@link WireMetadata} object omitting the moduleName.\n *\n * @returns The {@link WireMetadata} object omitting the moduleName.\n * @internal\n */\n const createEventMetadata = (): Omit<WireMetadata, 'moduleName'> => {\n return {\n target: inputElement.value,\n feature: 'search_box',\n }\n }\n\n /**\n * Emits {@link XEventsTypes.UserAcceptedAQuery} event.\n *\n * @remarks It is necessary in a separated method to use it as the parameter of debounce in\n * emitDebouncedUserAcceptedAQuery method.\n * @internal\n * @param query - The query that will be emitted.\n */\n const emitUserAcceptedAQuery = (query: string): void => {\n $x.emit('UserAcceptedAQuery', query, createEventMetadata())\n }\n\n /**\n * Emits {@link XEventsTypes.UserAcceptedAQuery} event with a debounce configured in\n * `instantDebounceInMs` prop.\n *\n * @internal\n * @param query - The query that will be emitted.\n */\n const emitDebouncedUserAcceptedAQuery = (query: string): void => {\n if (props.instant) {\n if (!debouncedUserAcceptedAQuery) {\n debouncedUserAcceptedAQuery = debounce(emitUserAcceptedAQuery, props.instantDebounceInMs)\n }\n debouncedUserAcceptedAQuery(query)\n }\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserHoveredInSearchBox} when search box is hovered in.\n *\n * @internal\n */\n const emitUserHoveredInSearchBox = (): void => {\n $x.emit('UserHoveredInSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserHoveredOutSearchBox} when search box is hovered out.\n *\n * @internal\n */\n const emitUserHoveredOutSearchBox = (): void => {\n $x.emit('UserHoveredOutSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserBlurredSearchBox} when search box loses focus.\n *\n * @internal\n */\n const emitUserBlurredSearchBox = (): void => {\n $x.emit('UserBlurredSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserClickedSearchBox} when user clicks the search input.\n *\n * @internal\n */\n const emitUserClickedSearchBox = (): void => {\n $x.emit('UserClickedSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserFocusedSearchBox} when search box gains focus.\n *\n * @internal\n */\n const emitUserFocusedSearchBox = (): void => {\n $x.emit('UserFocusedSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserIsTypingAQuery} when the user typed/pasted something\n * into the search-box. Also emits event {@link SearchBoxXEvents.UserClearedQuery} when the user\n * removes all characters in the search-box.\n *\n * @internal\n */\n const emitUserIsTypingAQueryEvents = (): void => {\n const query = inputElement.value?.value ?? ''\n\n $x.emit('UserIsTypingAQuery', query, { target: inputElement.value })\n if (query.trim()) {\n emitDebouncedUserAcceptedAQuery(query)\n } else {\n cancelDebouncedUserAcceptedAQuery()\n }\n }\n\n /**\n * Emits event {@link XEventsTypes.UserPressedArrowKey} when the user pressed an arrow key.\n *\n * @param event - The keyboard event with the arrow key pressed.\n * @internal\n */\n const emitUserPressedArrowKey = (event: KeyboardEvent): void => {\n $x.emit('UserPressedArrowKey', event.key as ArrowKey, createEventMetadata())\n }\n\n /**\n * Emits multiple events when the user pressed the enter key.\n *\n * @remarks\n * Emitted events are:\n * {@link SearchBoxXEvents.UserPressedEnterKey}\n * {@link XEventsTypes.UserAcceptedAQuery}\n *\n * @internal\n */\n const emitUserPressedEnterKey = (): void => {\n const query = inputElement.value?.value.trim()\n if (!!query && query.length > 0) {\n $x.emit('UserPressedEnterKey', query, createEventMetadata())\n emitUserAcceptedAQuery(query)\n }\n inputElement.value?.blur()\n }\n\n /**\n * Prevents the user from either typing or pasting special characters in the input field.\n *\n * @internal\n * @param event - The event that will be checked for special characters.\n */\n const preventSpecialKey = (event: InputEvent): void => {\n if (/[<>]/.test(event.data ?? '')) {\n event.preventDefault()\n }\n }\n\n /**\n * When event {@link XEventsTypes.UserReachedEmpathizeTop} or\n * {@link SearchBoxXEvents.UserPressedClearSearchBoxButton}\n * are emitted the search input is focused.\n *\n * @internal\n */\n function focusInput(): void {\n inputElement.value?.focus()\n }\n ;['UserReachedEmpathizeTop', 'UserPressedClearSearchBoxButton'].forEach(event =>\n $x.on(event as XEvent, false).subscribe(focusInput),\n )\n\n /**\n * When event {@link XEventsTypes.UserAcceptedAQuery} or\n * {@link SearchBoxXEvents.UserClearedQuery} are emitted the pending debounced emit\n * {@link XEvent} `UserAcceptedAQuery` is canceled.\n *\n * @internal\n */\n function cancelDebouncedUserAcceptedAQuery(): void {\n debouncedUserAcceptedAQuery?.cancel()\n }\n ;['UserAcceptedAQuery', 'UserClearedQuery'].forEach(event =>\n $x.on(event as XEvent, false).subscribe(cancelDebouncedUserAcceptedAQuery),\n )\n\n onMounted(() => {\n if (props.autofocus) {\n focusInput()\n }\n })\n\n return {\n query,\n inputElement,\n emitUserHoveredInSearchBox,\n emitUserHoveredOutSearchBox,\n emitUserBlurredSearchBox,\n emitUserClickedSearchBox,\n emitUserFocusedSearchBox,\n emitUserIsTypingAQueryEvents,\n emitUserPressedEnterKey,\n emitUserPressedArrowKey,\n preventSpecialKey,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-search-input::-webkit-search-decoration,\n.x-search-input::-webkit-search-cancel-button,\n.x-search-input::-webkit-search-results-button,\n.x-search-input::-webkit-search-results-decoration {\n -webkit-appearance: none;\n}\n</style>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits the following events:\n\n- [`UserClickedSearchBox`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserBlurredSearchBox`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserFocusedSearchBox`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserIsTypingAQuery`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserPressedEnterKey`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserPressedArrowKey`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserAcceptedAQuery`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n\n## See it in action\n\n<!-- prettier-ignore-start -->\n:::warning Backend service required\nTo use this component, the Search service must be implemented.\n:::\n<!-- prettier-ignore-end -->\n\nHere you have a basic example of how the search input is rendered.\n\n_Type any term in the input field to try it out!_\n\n```vue live\n<template>\n <SearchInput />\n</template>\n\n<script>\nimport { SearchInput } from '@empathyco/x-components/search-box'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n },\n}\n</script>\n```\n\n### Play with props\n\nIn this example, the search input has been limited to accept a maximum of 5 characters, including\nspaces, it won't take the focus when it is rendered, and it will emit the `UserAcceptedAQuery` event\nafter 1000 milliseconds without typing.\n\n_Type a term with more than 5 characters to try it out!_\n\n```vue live\n<template>\n <SearchInput :maxLength=\"5\" :autofocus=\"false\" :instant=\"true\" :instantDebounceInMs=\"1000\" />\n</template>\n\n<script>\nimport { SearchInput } from '@empathyco/x-components/search-box'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n },\n}\n</script>\n```\n\n### Play with events\n\nIn this example, a message has been added below the search input to illustrate the action performed.\nFor example, if you select the search input box, the message “focus” appears. When you start to\nenter a search term, the message “typing” appears. If you press Enter after typing a search term,\nthe message “enter” appears.\n\n<!-- prettier-ignore-start -->\n:::warning X Events are only emitted from the root X Component.\nAt the moment, X Events are only emitted from the root X Component. This means that if you wrap\nthe `SearchInput` with another component of another module like the `MainScroll`, you should add\nthe listeners to the `MainScroll` instead of the `SearchInput`. If you need to subscribe to these\nevents, it is recommended to use the [`GlobalXBus`](../common/x-components.global-x-bus.md)\ncomponent instead.\n:::\n<!-- prettier-ignore-end -->\n\n_Type any term in the input field to try it out!_\n\n```vue live\n<template>\n <div>\n <SearchInput\n @UserPressedEnterKey=\"value = 'enter'\"\n @UserFocusedSearchBox=\"hasFocus = true\"\n @UserBlurredSearchBox=\"hasFocus = false\"\n @UserIsTypingAQuery=\"value = 'typing'\"\n />\n <strong>{{ value }}</strong>\n <span>{{ hasFocus ? 'focused' : 'unfocused' }}</span>\n </div>\n</template>\n\n<script>\nimport { SearchInput } from '@empathyco/x-components/search-box'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n },\n data() {\n return {\n value: '',\n hasFocus: false,\n }\n },\n}\n</script>\n```\n\n## Extending the component\n\nComponents can be combined and communicate with each other. Commonly, the `SearchInput` component\ncommunicates with the [`SearchButton`](x-components.search-button.md) and the\n[`ClearSearchInput`](x-components.clear-search-input.md) to offer a full query entry experience.\nFurthermore, you can use it together with the [`QuerySuggestions`](query-suggestions.md) component\nto autocomplete the typed search term.\n\n_Type “trousers” or another fashion term in the input field and then click the clear icon to try it\nout!_\n\n```vue live\n<template>\n <div>\n <div style=\"display: flex; flex-flow: row nowrap;\">\n <SearchInput />\n <ClearSearchInput>\n <img src=\"/assets/icons/cross.svg\" />\n </ClearSearchInput>\n <SearchButton>Search</SearchButton>\n </div>\n <QuerySuggestions />\n </div>\n</template>\n\n<script>\nimport { SearchInput, ClearSearchInput, SearchButton } from '@empathyco/x-components/search-box'\nimport { QuerySuggestions } from '@empathyco/x-components/query-suggestions'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n ClearSearchInput,\n SearchButton,\n QuerySuggestions,\n },\n}\n</script>\n```\n</docs>\n"],"names":["_openBlock","_createElementBlock"],"mappings":";;;;;;SAEQ,WAAc,CAAA,IAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,KAAA,EAAA,QAAA,EAAA;AACjB,EAAA,OAAAA,SAAA,EAAoB,EAAAC,kBAAA,CAAA,OAAA,EAAA;AAAA,IACpB,GAAK,EAAA,cAAA;AAAA,IACN,SAAa,EAAA,IAAA,CAAA,SAAA;AAAA,IACb,KAAM,EAAA,IAAA,CAAA,KAAA;AAAA,IACN,YAAa,EAAA,KAAA;AAAA,IACb,KAAA,EAAA,wBAAA;AAAA,IACA,YAAa,EAAA,QAAA;AAAA,IACb,SAAS,EAAA,QAAA;AAAA,IACT,IAAA,EAAA,QAAA;AAAA,IACC,WAAU,EAAA,cAAA;AAAA,IACV,YAAU,EAAA,sBAAA;AAAA,IACV,YAAA,EAAI,uCAAE,IAAwB,CAAA,0BAAA,IAAA,IAAA,CAAA,0BAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,IAC9B,YAAA,EAAK,uCAAE,IAAwB,CAAA,2BAAA,IAAA,IAAA,CAAA,2BAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,IAC/B,QAAK,MAAE,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,wBAAA,IAAA,IAAA,CAAA,wBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,IACP,SAAK,MAAE,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,wBAAA,IAAA,IAAA,CAAA,wBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,IACP,OAAO,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,wBAAA,IAAA,IAAA,CAAA,wBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,IAAA,OAAA,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAlBZ,uBAkBoB,4BAAuB,IAAA,IAAA,CAAA,4BAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,IAAA,SAAA,EAAA;;AAEtC,MAAA,MAAA,CAAA,CAAA,CAAA,KAAW,uCAAE,IAAiB,KAAA,IAAA,CAAA,uBAAA,IAAA,IAAA,CAAA,uBAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,SAAA,CAAA,CAAA,EAAA,CAAA,IAAA,EAAA,MAAA,CAAA,CAAA,CAAA;AAAA,KAAA;;;;;;;;"}
1
+ {"version":3,"file":"search-input.vue.js","sources":["../../../../../src/x-modules/search-box/components/search-input.vue"],"sourcesContent":["<template>\n <input\n ref=\"inputElement\"\n :maxlength=\"maxLength\"\n :value=\"query\"\n autocomplete=\"off\"\n class=\"x-search-input x-input\"\n enterkeyhint=\"search\"\n inputmode=\"search\"\n type=\"search\"\n data-test=\"search-input\"\n aria-label=\"type your query here\"\n @mouseenter=\"emitUserHoveredInSearchBox\"\n @mouseleave=\"emitUserHoveredOutSearchBox\"\n @blur=\"emitUserBlurredSearchBox\"\n @click=\"emitUserClickedSearchBox\"\n @focus=\"emitUserFocusedSearchBox\"\n @input=\"emitUserIsTypingAQueryEvents\"\n @keydown.enter=\"emitUserPressedEnterKey\"\n @keydown.up.down.prevent=\"emitUserPressedArrowKey\"\n @beforeinput=\"preventSpecialKey\"\n />\n</template>\n\n<script lang=\"ts\">\nimport type { ArrowKey } from '../../../utils'\nimport type { DebouncedFunction } from '../../../utils/types'\nimport type { XEvent } from '../../../wiring/events.types'\nimport type { WireMetadata } from '../../../wiring/wiring.types'\nimport { defineComponent, onMounted, ref } from 'vue'\nimport { use$x } from '../../../composables/use-$x'\nimport { useState } from '../../../composables/use-state'\nimport { debounce } from '../../../utils/debounce'\nimport { searchBoxXModule } from '../x-module'\n\n/**\n * This component renders an input field that allows the user to type a query. It also reacts to\n * query changes through event listening.\n *\n * @public\n */\nexport default defineComponent({\n name: 'SearchInput',\n xModule: searchBoxXModule.name,\n props: {\n /**\n * Maximum characters allowed in the input search.\n */\n maxLength: {\n type: Number,\n default: 64,\n },\n /**\n * Allows input autofocus when the search field is rendered.\n */\n autofocus: {\n type: Boolean,\n default: true,\n },\n /**\n * Enables the auto-accept query after debounce.\n */\n instant: {\n type: Boolean,\n default: true,\n },\n /**\n * Debounce time for the instant.\n */\n instantDebounceInMs: {\n type: Number,\n default: 500,\n },\n },\n setup(props) {\n const $x = use$x()\n\n const { query } = useState('searchBox')\n\n const inputElement = ref<HTMLInputElement>()\n\n let debouncedUserAcceptedAQuery: DebouncedFunction<[string]>\n\n /**\n * Generates the {@link WireMetadata} object omitting the moduleName.\n *\n * @returns The {@link WireMetadata} object omitting the moduleName.\n * @internal\n */\n const createEventMetadata = (): Omit<WireMetadata, 'moduleName'> => {\n return {\n target: inputElement.value,\n feature: 'search_box',\n }\n }\n\n /**\n * Emits {@link XEventsTypes.UserAcceptedAQuery} event.\n *\n * @remarks It is necessary in a separated method to use it as the parameter of debounce in\n * emitDebouncedUserAcceptedAQuery method.\n * @internal\n * @param query - The query that will be emitted.\n */\n const emitUserAcceptedAQuery = (query: string): void => {\n $x.emit('UserAcceptedAQuery', query, createEventMetadata())\n }\n\n /**\n * Emits {@link XEventsTypes.UserAcceptedAQuery} event with a debounce configured in\n * `instantDebounceInMs` prop.\n *\n * @internal\n * @param query - The query that will be emitted.\n */\n const emitDebouncedUserAcceptedAQuery = (query: string): void => {\n if (props.instant) {\n if (!debouncedUserAcceptedAQuery) {\n debouncedUserAcceptedAQuery = debounce(emitUserAcceptedAQuery, props.instantDebounceInMs)\n }\n debouncedUserAcceptedAQuery(query)\n }\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserHoveredInSearchBox} when search box is hovered in.\n *\n * @internal\n */\n const emitUserHoveredInSearchBox = (): void => {\n $x.emit('UserHoveredInSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserHoveredOutSearchBox} when search box is hovered out.\n *\n * @internal\n */\n const emitUserHoveredOutSearchBox = (): void => {\n $x.emit('UserHoveredOutSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserBlurredSearchBox} when search box loses focus.\n *\n * @internal\n */\n const emitUserBlurredSearchBox = (): void => {\n $x.emit('UserBlurredSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserClickedSearchBox} when user clicks the search input.\n *\n * @internal\n */\n const emitUserClickedSearchBox = (): void => {\n $x.emit('UserClickedSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserFocusedSearchBox} when search box gains focus.\n *\n * @internal\n */\n const emitUserFocusedSearchBox = (): void => {\n $x.emit('UserFocusedSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserIsTypingAQuery} when the user typed/pasted something\n * into the search-box. Also emits event {@link SearchBoxXEvents.UserClearedQuery} when the user\n * removes all characters in the search-box.\n *\n * @internal\n */\n const emitUserIsTypingAQueryEvents = (): void => {\n const query = inputElement.value?.value ?? ''\n\n $x.emit('UserIsTypingAQuery', query, { target: inputElement.value })\n if (query.trim()) {\n emitDebouncedUserAcceptedAQuery(query)\n } else {\n cancelDebouncedUserAcceptedAQuery()\n }\n }\n\n /**\n * Emits event {@link XEventsTypes.UserPressedArrowKey} when the user pressed an arrow key.\n *\n * @param event - The keyboard event with the arrow key pressed.\n * @internal\n */\n const emitUserPressedArrowKey = (event: KeyboardEvent): void => {\n $x.emit('UserPressedArrowKey', event.key as ArrowKey, createEventMetadata())\n }\n\n /**\n * Emits multiple events when the user pressed the enter key.\n *\n * @remarks\n * Emitted events are:\n * {@link SearchBoxXEvents.UserPressedEnterKey}\n * {@link XEventsTypes.UserAcceptedAQuery}\n *\n * @internal\n */\n const emitUserPressedEnterKey = (): void => {\n const query = inputElement.value?.value.trim()\n if (!!query && query.length > 0) {\n $x.emit('UserPressedEnterKey', query, createEventMetadata())\n emitUserAcceptedAQuery(query)\n }\n inputElement.value?.blur()\n }\n\n /**\n * Prevents the user from either typing or pasting special characters in the input field.\n *\n * @internal\n * @param event - The event that will be checked for special characters.\n */\n const preventSpecialKey = (event: InputEvent): void => {\n if (/[<>]/.test(event.data ?? '')) {\n event.preventDefault()\n }\n }\n\n /**\n * When event {@link XEventsTypes.UserReachedEmpathizeTop} or\n * {@link SearchBoxXEvents.UserPressedClearSearchBoxButton}\n * are emitted the search input is focused.\n *\n * @internal\n */\n function focusInput(): void {\n inputElement.value?.focus()\n }\n ;['UserReachedEmpathizeTop', 'UserPressedClearSearchBoxButton'].forEach(event =>\n $x.on(event as XEvent, false).subscribe(focusInput),\n )\n\n /**\n * When event {@link XEventsTypes.UserAcceptedAQuery} or\n * {@link SearchBoxXEvents.UserClearedQuery} are emitted the pending debounced emit\n * {@link XEvent} `UserAcceptedAQuery` is canceled.\n *\n * @internal\n */\n function cancelDebouncedUserAcceptedAQuery(): void {\n debouncedUserAcceptedAQuery?.cancel()\n }\n ;['UserAcceptedAQuery', 'UserClearedQuery'].forEach(event =>\n $x.on(event as XEvent, false).subscribe(cancelDebouncedUserAcceptedAQuery),\n )\n\n onMounted(() => {\n if (props.autofocus) {\n focusInput()\n }\n })\n\n return {\n query,\n inputElement,\n emitUserHoveredInSearchBox,\n emitUserHoveredOutSearchBox,\n emitUserBlurredSearchBox,\n emitUserClickedSearchBox,\n emitUserFocusedSearchBox,\n emitUserIsTypingAQueryEvents,\n emitUserPressedEnterKey,\n emitUserPressedArrowKey,\n preventSpecialKey,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-search-input::-webkit-search-decoration,\n.x-search-input::-webkit-search-cancel-button,\n.x-search-input::-webkit-search-results-button,\n.x-search-input::-webkit-search-results-decoration {\n -webkit-appearance: none;\n}\n</style>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits the following events:\n\n- [`UserClickedSearchBox`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserBlurredSearchBox`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserFocusedSearchBox`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserIsTypingAQuery`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserPressedEnterKey`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserPressedArrowKey`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserAcceptedAQuery`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n\n## See it in action\n\n<!-- prettier-ignore-start -->\n:::warning Backend service required\nTo use this component, the Search service must be implemented.\n:::\n<!-- prettier-ignore-end -->\n\nHere you have a basic example of how the search input is rendered.\n\n_Type any term in the input field to try it out!_\n\n```vue live\n<template>\n <SearchInput />\n</template>\n\n<script>\nimport { SearchInput } from '@empathyco/x-components/search-box'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n },\n}\n</script>\n```\n\n### Play with props\n\nIn this example, the search input has been limited to accept a maximum of 5 characters, including\nspaces, it won't take the focus when it is rendered, and it will emit the `UserAcceptedAQuery` event\nafter 1000 milliseconds without typing.\n\n_Type a term with more than 5 characters to try it out!_\n\n```vue live\n<template>\n <SearchInput :maxLength=\"5\" :autofocus=\"false\" :instant=\"true\" :instantDebounceInMs=\"1000\" />\n</template>\n\n<script>\nimport { SearchInput } from '@empathyco/x-components/search-box'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n },\n}\n</script>\n```\n\n### Play with events\n\nIn this example, a message has been added below the search input to illustrate the action performed.\nFor example, if you select the search input box, the message “focus” appears. When you start to\nenter a search term, the message “typing” appears. If you press Enter after typing a search term,\nthe message “enter” appears.\n\n<!-- prettier-ignore-start -->\n:::warning X Events are only emitted from the root X Component.\nAt the moment, X Events are only emitted from the root X Component. This means that if you wrap\nthe `SearchInput` with another component of another module like the `MainScroll`, you should add\nthe listeners to the `MainScroll` instead of the `SearchInput`. If you need to subscribe to these\nevents, it is recommended to use the [`GlobalXBus`](../common/x-components.global-x-bus.md)\ncomponent instead.\n:::\n<!-- prettier-ignore-end -->\n\n_Type any term in the input field to try it out!_\n\n```vue live\n<template>\n <div>\n <SearchInput\n @UserPressedEnterKey=\"value = 'enter'\"\n @UserFocusedSearchBox=\"hasFocus = true\"\n @UserBlurredSearchBox=\"hasFocus = false\"\n @UserIsTypingAQuery=\"value = 'typing'\"\n />\n <strong>{{ value }}</strong>\n <span>{{ hasFocus ? 'focused' : 'unfocused' }}</span>\n </div>\n</template>\n\n<script>\nimport { SearchInput } from '@empathyco/x-components/search-box'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n },\n data() {\n return {\n value: '',\n hasFocus: false,\n }\n },\n}\n</script>\n```\n\n## Extending the component\n\nComponents can be combined and communicate with each other. Commonly, the `SearchInput` component\ncommunicates with the [`SearchButton`](x-components.search-button.md) and the\n[`ClearSearchInput`](x-components.clear-search-input.md) to offer a full query entry experience.\nFurthermore, you can use it together with the [`QuerySuggestions`](query-suggestions.md) component\nto autocomplete the typed search term.\n\n_Type “trousers” or another fashion term in the input field and then click the clear icon to try it\nout!_\n\n```vue live\n<template>\n <div>\n <div style=\"display: flex; flex-flow: row nowrap;\">\n <SearchInput />\n <ClearSearchInput>\n <img src=\"/assets/icons/cross.svg\" />\n </ClearSearchInput>\n <SearchButton>Search</SearchButton>\n </div>\n <QuerySuggestions />\n </div>\n</template>\n\n<script>\nimport { SearchInput, ClearSearchInput, SearchButton } from '@empathyco/x-components/search-box'\nimport { QuerySuggestions } from '@empathyco/x-components/query-suggestions'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n ClearSearchInput,\n SearchButton,\n QuerySuggestions,\n },\n}\n</script>\n```\n</docs>\n"],"names":["_openBlock","_createElementBlock"],"mappings":";;;;;;SAEQ,WAAc,CAAA,IAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,KAAA,EAAA,QAAA,EAAA;AACjB,EAAA,OAAAA,SAAA,EAAoB,EAAAC,kBAAA,CAAA,OAAA,EAAA;AAAA,IACpB,GAAK,EAAA,cAAA;AAAA,IACN,SAAa,EAAA,IAAA,CAAA,SAAA;AAAA,IACb,KAAM,EAAA,IAAA,CAAA,KAAA;AAAA,IACN,YAAa,EAAA,KAAA;AAAA,IACb,KAAA,EAAA,wBAAA;AAAA,IACA,YAAa,EAAA,QAAA;AAAA,IACb,SAAS,EAAA,QAAA;AAAA,IACT,IAAA,EAAA,QAAA;AAAA,IACC,WAAU,EAAA,cAAA;AAAA,IACV,YAAU,EAAA,sBAAA;AAAA,IACV,YAAA,EAAI,uCAAE,IAAwB,CAAA,0BAAA,IAAA,IAAA,CAAA,0BAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,IAC9B,YAAA,EAAK,uCAAE,IAAwB,CAAA,2BAAA,IAAA,IAAA,CAAA,2BAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,IAC/B,QAAK,MAAE,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,wBAAA,IAAA,IAAA,CAAA,wBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,IACP,SAAK,MAAE,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,wBAAA,IAAA,IAAA,CAAA,wBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,IACP,OAAO,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,wBAAA,IAAA,IAAA,CAAA,wBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,IAAA,OAAA,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAlBZ,uBAkBoB,4BAAuB,IAAA,IAAA,CAAA,4BAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,IAAA,SAAA,EAAA;;AAEtC,MAAA,MAAA,CAAA,CAAA,CAAA,KAAW,uCAAE,IAAiB,KAAA,IAAA,CAAA,uBAAA,IAAA,IAAA,CAAA,uBAAA,CAAA,GAAA,IAAA,CAAA,EAAA,CAAA,SAAA,CAAA,CAAA,EAAA,CAAA,IAAA,EAAA,MAAA,CAAA,CAAA,CAAA;AAAA,KAAA;;;;;;;;"}
@@ -45,7 +45,7 @@ var _sfc_main = defineComponent({
45
45
  },
46
46
  setup(props) {
47
47
  const $x = use$x();
48
- const { query } = useState('searchBox', ['query']);
48
+ const { query } = useState('searchBox');
49
49
  const inputElement = ref();
50
50
  let debouncedUserAcceptedAQuery;
51
51
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"search-input.vue2.js","sources":["../../../../../src/x-modules/search-box/components/search-input.vue"],"sourcesContent":["<template>\n <input\n ref=\"inputElement\"\n :maxlength=\"maxLength\"\n :value=\"query\"\n autocomplete=\"off\"\n class=\"x-search-input x-input\"\n enterkeyhint=\"search\"\n inputmode=\"search\"\n type=\"search\"\n data-test=\"search-input\"\n aria-label=\"type your query here\"\n @mouseenter=\"emitUserHoveredInSearchBox\"\n @mouseleave=\"emitUserHoveredOutSearchBox\"\n @blur=\"emitUserBlurredSearchBox\"\n @click=\"emitUserClickedSearchBox\"\n @focus=\"emitUserFocusedSearchBox\"\n @input=\"emitUserIsTypingAQueryEvents\"\n @keydown.enter=\"emitUserPressedEnterKey\"\n @keydown.up.down.prevent=\"emitUserPressedArrowKey\"\n @beforeinput=\"preventSpecialKey\"\n />\n</template>\n\n<script lang=\"ts\">\nimport type { ArrowKey } from '../../../utils'\nimport type { DebouncedFunction } from '../../../utils/types'\nimport type { XEvent } from '../../../wiring/events.types'\nimport type { WireMetadata } from '../../../wiring/wiring.types'\nimport { defineComponent, onMounted, ref } from 'vue'\nimport { use$x } from '../../../composables/use-$x'\nimport { useState } from '../../../composables/use-state'\nimport { debounce } from '../../../utils/debounce'\nimport { searchBoxXModule } from '../x-module'\n\n/**\n * This component renders an input field that allows the user to type a query. It also reacts to\n * query changes through event listening.\n *\n * @public\n */\nexport default defineComponent({\n name: 'SearchInput',\n xModule: searchBoxXModule.name,\n props: {\n /**\n * Maximum characters allowed in the input search.\n */\n maxLength: {\n type: Number,\n default: 64,\n },\n /**\n * Allows input autofocus when the search field is rendered.\n */\n autofocus: {\n type: Boolean,\n default: true,\n },\n /**\n * Enables the auto-accept query after debounce.\n */\n instant: {\n type: Boolean,\n default: true,\n },\n /**\n * Debounce time for the instant.\n */\n instantDebounceInMs: {\n type: Number,\n default: 500,\n },\n },\n setup(props) {\n const $x = use$x()\n\n const { query } = useState('searchBox', ['query'])\n\n const inputElement = ref<HTMLInputElement>()\n\n let debouncedUserAcceptedAQuery: DebouncedFunction<[string]>\n\n /**\n * Generates the {@link WireMetadata} object omitting the moduleName.\n *\n * @returns The {@link WireMetadata} object omitting the moduleName.\n * @internal\n */\n const createEventMetadata = (): Omit<WireMetadata, 'moduleName'> => {\n return {\n target: inputElement.value,\n feature: 'search_box',\n }\n }\n\n /**\n * Emits {@link XEventsTypes.UserAcceptedAQuery} event.\n *\n * @remarks It is necessary in a separated method to use it as the parameter of debounce in\n * emitDebouncedUserAcceptedAQuery method.\n * @internal\n * @param query - The query that will be emitted.\n */\n const emitUserAcceptedAQuery = (query: string): void => {\n $x.emit('UserAcceptedAQuery', query, createEventMetadata())\n }\n\n /**\n * Emits {@link XEventsTypes.UserAcceptedAQuery} event with a debounce configured in\n * `instantDebounceInMs` prop.\n *\n * @internal\n * @param query - The query that will be emitted.\n */\n const emitDebouncedUserAcceptedAQuery = (query: string): void => {\n if (props.instant) {\n if (!debouncedUserAcceptedAQuery) {\n debouncedUserAcceptedAQuery = debounce(emitUserAcceptedAQuery, props.instantDebounceInMs)\n }\n debouncedUserAcceptedAQuery(query)\n }\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserHoveredInSearchBox} when search box is hovered in.\n *\n * @internal\n */\n const emitUserHoveredInSearchBox = (): void => {\n $x.emit('UserHoveredInSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserHoveredOutSearchBox} when search box is hovered out.\n *\n * @internal\n */\n const emitUserHoveredOutSearchBox = (): void => {\n $x.emit('UserHoveredOutSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserBlurredSearchBox} when search box loses focus.\n *\n * @internal\n */\n const emitUserBlurredSearchBox = (): void => {\n $x.emit('UserBlurredSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserClickedSearchBox} when user clicks the search input.\n *\n * @internal\n */\n const emitUserClickedSearchBox = (): void => {\n $x.emit('UserClickedSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserFocusedSearchBox} when search box gains focus.\n *\n * @internal\n */\n const emitUserFocusedSearchBox = (): void => {\n $x.emit('UserFocusedSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserIsTypingAQuery} when the user typed/pasted something\n * into the search-box. Also emits event {@link SearchBoxXEvents.UserClearedQuery} when the user\n * removes all characters in the search-box.\n *\n * @internal\n */\n const emitUserIsTypingAQueryEvents = (): void => {\n const query = inputElement.value?.value ?? ''\n\n $x.emit('UserIsTypingAQuery', query, { target: inputElement.value })\n if (query.trim()) {\n emitDebouncedUserAcceptedAQuery(query)\n } else {\n cancelDebouncedUserAcceptedAQuery()\n }\n }\n\n /**\n * Emits event {@link XEventsTypes.UserPressedArrowKey} when the user pressed an arrow key.\n *\n * @param event - The keyboard event with the arrow key pressed.\n * @internal\n */\n const emitUserPressedArrowKey = (event: KeyboardEvent): void => {\n $x.emit('UserPressedArrowKey', event.key as ArrowKey, createEventMetadata())\n }\n\n /**\n * Emits multiple events when the user pressed the enter key.\n *\n * @remarks\n * Emitted events are:\n * {@link SearchBoxXEvents.UserPressedEnterKey}\n * {@link XEventsTypes.UserAcceptedAQuery}\n *\n * @internal\n */\n const emitUserPressedEnterKey = (): void => {\n const query = inputElement.value?.value.trim()\n if (!!query && query.length > 0) {\n $x.emit('UserPressedEnterKey', query, createEventMetadata())\n emitUserAcceptedAQuery(query)\n }\n inputElement.value?.blur()\n }\n\n /**\n * Prevents the user from either typing or pasting special characters in the input field.\n *\n * @internal\n * @param event - The event that will be checked for special characters.\n */\n const preventSpecialKey = (event: InputEvent): void => {\n if (/[<>]/.test(event.data ?? '')) {\n event.preventDefault()\n }\n }\n\n /**\n * When event {@link XEventsTypes.UserReachedEmpathizeTop} or\n * {@link SearchBoxXEvents.UserPressedClearSearchBoxButton}\n * are emitted the search input is focused.\n *\n * @internal\n */\n function focusInput(): void {\n inputElement.value?.focus()\n }\n ;['UserReachedEmpathizeTop', 'UserPressedClearSearchBoxButton'].forEach(event =>\n $x.on(event as XEvent, false).subscribe(focusInput),\n )\n\n /**\n * When event {@link XEventsTypes.UserAcceptedAQuery} or\n * {@link SearchBoxXEvents.UserClearedQuery} are emitted the pending debounced emit\n * {@link XEvent} `UserAcceptedAQuery` is canceled.\n *\n * @internal\n */\n function cancelDebouncedUserAcceptedAQuery(): void {\n debouncedUserAcceptedAQuery?.cancel()\n }\n ;['UserAcceptedAQuery', 'UserClearedQuery'].forEach(event =>\n $x.on(event as XEvent, false).subscribe(cancelDebouncedUserAcceptedAQuery),\n )\n\n onMounted(() => {\n if (props.autofocus) {\n focusInput()\n }\n })\n\n return {\n query,\n inputElement,\n emitUserHoveredInSearchBox,\n emitUserHoveredOutSearchBox,\n emitUserBlurredSearchBox,\n emitUserClickedSearchBox,\n emitUserFocusedSearchBox,\n emitUserIsTypingAQueryEvents,\n emitUserPressedEnterKey,\n emitUserPressedArrowKey,\n preventSpecialKey,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-search-input::-webkit-search-decoration,\n.x-search-input::-webkit-search-cancel-button,\n.x-search-input::-webkit-search-results-button,\n.x-search-input::-webkit-search-results-decoration {\n -webkit-appearance: none;\n}\n</style>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits the following events:\n\n- [`UserClickedSearchBox`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserBlurredSearchBox`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserFocusedSearchBox`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserIsTypingAQuery`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserPressedEnterKey`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserPressedArrowKey`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserAcceptedAQuery`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n\n## See it in action\n\n<!-- prettier-ignore-start -->\n:::warning Backend service required\nTo use this component, the Search service must be implemented.\n:::\n<!-- prettier-ignore-end -->\n\nHere you have a basic example of how the search input is rendered.\n\n_Type any term in the input field to try it out!_\n\n```vue live\n<template>\n <SearchInput />\n</template>\n\n<script>\nimport { SearchInput } from '@empathyco/x-components/search-box'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n },\n}\n</script>\n```\n\n### Play with props\n\nIn this example, the search input has been limited to accept a maximum of 5 characters, including\nspaces, it won't take the focus when it is rendered, and it will emit the `UserAcceptedAQuery` event\nafter 1000 milliseconds without typing.\n\n_Type a term with more than 5 characters to try it out!_\n\n```vue live\n<template>\n <SearchInput :maxLength=\"5\" :autofocus=\"false\" :instant=\"true\" :instantDebounceInMs=\"1000\" />\n</template>\n\n<script>\nimport { SearchInput } from '@empathyco/x-components/search-box'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n },\n}\n</script>\n```\n\n### Play with events\n\nIn this example, a message has been added below the search input to illustrate the action performed.\nFor example, if you select the search input box, the message “focus” appears. When you start to\nenter a search term, the message “typing” appears. If you press Enter after typing a search term,\nthe message “enter” appears.\n\n<!-- prettier-ignore-start -->\n:::warning X Events are only emitted from the root X Component.\nAt the moment, X Events are only emitted from the root X Component. This means that if you wrap\nthe `SearchInput` with another component of another module like the `MainScroll`, you should add\nthe listeners to the `MainScroll` instead of the `SearchInput`. If you need to subscribe to these\nevents, it is recommended to use the [`GlobalXBus`](../common/x-components.global-x-bus.md)\ncomponent instead.\n:::\n<!-- prettier-ignore-end -->\n\n_Type any term in the input field to try it out!_\n\n```vue live\n<template>\n <div>\n <SearchInput\n @UserPressedEnterKey=\"value = 'enter'\"\n @UserFocusedSearchBox=\"hasFocus = true\"\n @UserBlurredSearchBox=\"hasFocus = false\"\n @UserIsTypingAQuery=\"value = 'typing'\"\n />\n <strong>{{ value }}</strong>\n <span>{{ hasFocus ? 'focused' : 'unfocused' }}</span>\n </div>\n</template>\n\n<script>\nimport { SearchInput } from '@empathyco/x-components/search-box'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n },\n data() {\n return {\n value: '',\n hasFocus: false,\n }\n },\n}\n</script>\n```\n\n## Extending the component\n\nComponents can be combined and communicate with each other. Commonly, the `SearchInput` component\ncommunicates with the [`SearchButton`](x-components.search-button.md) and the\n[`ClearSearchInput`](x-components.clear-search-input.md) to offer a full query entry experience.\nFurthermore, you can use it together with the [`QuerySuggestions`](query-suggestions.md) component\nto autocomplete the typed search term.\n\n_Type “trousers” or another fashion term in the input field and then click the clear icon to try it\nout!_\n\n```vue live\n<template>\n <div>\n <div style=\"display: flex; flex-flow: row nowrap;\">\n <SearchInput />\n <ClearSearchInput>\n <img src=\"/assets/icons/cross.svg\" />\n </ClearSearchInput>\n <SearchButton>Search</SearchButton>\n </div>\n <QuerySuggestions />\n </div>\n</template>\n\n<script>\nimport { SearchInput, ClearSearchInput, SearchButton } from '@empathyco/x-components/search-box'\nimport { QuerySuggestions } from '@empathyco/x-components/query-suggestions'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n ClearSearchInput,\n SearchButton,\n QuerySuggestions,\n },\n}\n</script>\n```\n</docs>\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"search-input.vue2.js","sources":["../../../../../src/x-modules/search-box/components/search-input.vue"],"sourcesContent":["<template>\n <input\n ref=\"inputElement\"\n :maxlength=\"maxLength\"\n :value=\"query\"\n autocomplete=\"off\"\n class=\"x-search-input x-input\"\n enterkeyhint=\"search\"\n inputmode=\"search\"\n type=\"search\"\n data-test=\"search-input\"\n aria-label=\"type your query here\"\n @mouseenter=\"emitUserHoveredInSearchBox\"\n @mouseleave=\"emitUserHoveredOutSearchBox\"\n @blur=\"emitUserBlurredSearchBox\"\n @click=\"emitUserClickedSearchBox\"\n @focus=\"emitUserFocusedSearchBox\"\n @input=\"emitUserIsTypingAQueryEvents\"\n @keydown.enter=\"emitUserPressedEnterKey\"\n @keydown.up.down.prevent=\"emitUserPressedArrowKey\"\n @beforeinput=\"preventSpecialKey\"\n />\n</template>\n\n<script lang=\"ts\">\nimport type { ArrowKey } from '../../../utils'\nimport type { DebouncedFunction } from '../../../utils/types'\nimport type { XEvent } from '../../../wiring/events.types'\nimport type { WireMetadata } from '../../../wiring/wiring.types'\nimport { defineComponent, onMounted, ref } from 'vue'\nimport { use$x } from '../../../composables/use-$x'\nimport { useState } from '../../../composables/use-state'\nimport { debounce } from '../../../utils/debounce'\nimport { searchBoxXModule } from '../x-module'\n\n/**\n * This component renders an input field that allows the user to type a query. It also reacts to\n * query changes through event listening.\n *\n * @public\n */\nexport default defineComponent({\n name: 'SearchInput',\n xModule: searchBoxXModule.name,\n props: {\n /**\n * Maximum characters allowed in the input search.\n */\n maxLength: {\n type: Number,\n default: 64,\n },\n /**\n * Allows input autofocus when the search field is rendered.\n */\n autofocus: {\n type: Boolean,\n default: true,\n },\n /**\n * Enables the auto-accept query after debounce.\n */\n instant: {\n type: Boolean,\n default: true,\n },\n /**\n * Debounce time for the instant.\n */\n instantDebounceInMs: {\n type: Number,\n default: 500,\n },\n },\n setup(props) {\n const $x = use$x()\n\n const { query } = useState('searchBox')\n\n const inputElement = ref<HTMLInputElement>()\n\n let debouncedUserAcceptedAQuery: DebouncedFunction<[string]>\n\n /**\n * Generates the {@link WireMetadata} object omitting the moduleName.\n *\n * @returns The {@link WireMetadata} object omitting the moduleName.\n * @internal\n */\n const createEventMetadata = (): Omit<WireMetadata, 'moduleName'> => {\n return {\n target: inputElement.value,\n feature: 'search_box',\n }\n }\n\n /**\n * Emits {@link XEventsTypes.UserAcceptedAQuery} event.\n *\n * @remarks It is necessary in a separated method to use it as the parameter of debounce in\n * emitDebouncedUserAcceptedAQuery method.\n * @internal\n * @param query - The query that will be emitted.\n */\n const emitUserAcceptedAQuery = (query: string): void => {\n $x.emit('UserAcceptedAQuery', query, createEventMetadata())\n }\n\n /**\n * Emits {@link XEventsTypes.UserAcceptedAQuery} event with a debounce configured in\n * `instantDebounceInMs` prop.\n *\n * @internal\n * @param query - The query that will be emitted.\n */\n const emitDebouncedUserAcceptedAQuery = (query: string): void => {\n if (props.instant) {\n if (!debouncedUserAcceptedAQuery) {\n debouncedUserAcceptedAQuery = debounce(emitUserAcceptedAQuery, props.instantDebounceInMs)\n }\n debouncedUserAcceptedAQuery(query)\n }\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserHoveredInSearchBox} when search box is hovered in.\n *\n * @internal\n */\n const emitUserHoveredInSearchBox = (): void => {\n $x.emit('UserHoveredInSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserHoveredOutSearchBox} when search box is hovered out.\n *\n * @internal\n */\n const emitUserHoveredOutSearchBox = (): void => {\n $x.emit('UserHoveredOutSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserBlurredSearchBox} when search box loses focus.\n *\n * @internal\n */\n const emitUserBlurredSearchBox = (): void => {\n $x.emit('UserBlurredSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserClickedSearchBox} when user clicks the search input.\n *\n * @internal\n */\n const emitUserClickedSearchBox = (): void => {\n $x.emit('UserClickedSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserFocusedSearchBox} when search box gains focus.\n *\n * @internal\n */\n const emitUserFocusedSearchBox = (): void => {\n $x.emit('UserFocusedSearchBox', undefined, { target: inputElement.value })\n }\n\n /**\n * Emits event {@link SearchBoxXEvents.UserIsTypingAQuery} when the user typed/pasted something\n * into the search-box. Also emits event {@link SearchBoxXEvents.UserClearedQuery} when the user\n * removes all characters in the search-box.\n *\n * @internal\n */\n const emitUserIsTypingAQueryEvents = (): void => {\n const query = inputElement.value?.value ?? ''\n\n $x.emit('UserIsTypingAQuery', query, { target: inputElement.value })\n if (query.trim()) {\n emitDebouncedUserAcceptedAQuery(query)\n } else {\n cancelDebouncedUserAcceptedAQuery()\n }\n }\n\n /**\n * Emits event {@link XEventsTypes.UserPressedArrowKey} when the user pressed an arrow key.\n *\n * @param event - The keyboard event with the arrow key pressed.\n * @internal\n */\n const emitUserPressedArrowKey = (event: KeyboardEvent): void => {\n $x.emit('UserPressedArrowKey', event.key as ArrowKey, createEventMetadata())\n }\n\n /**\n * Emits multiple events when the user pressed the enter key.\n *\n * @remarks\n * Emitted events are:\n * {@link SearchBoxXEvents.UserPressedEnterKey}\n * {@link XEventsTypes.UserAcceptedAQuery}\n *\n * @internal\n */\n const emitUserPressedEnterKey = (): void => {\n const query = inputElement.value?.value.trim()\n if (!!query && query.length > 0) {\n $x.emit('UserPressedEnterKey', query, createEventMetadata())\n emitUserAcceptedAQuery(query)\n }\n inputElement.value?.blur()\n }\n\n /**\n * Prevents the user from either typing or pasting special characters in the input field.\n *\n * @internal\n * @param event - The event that will be checked for special characters.\n */\n const preventSpecialKey = (event: InputEvent): void => {\n if (/[<>]/.test(event.data ?? '')) {\n event.preventDefault()\n }\n }\n\n /**\n * When event {@link XEventsTypes.UserReachedEmpathizeTop} or\n * {@link SearchBoxXEvents.UserPressedClearSearchBoxButton}\n * are emitted the search input is focused.\n *\n * @internal\n */\n function focusInput(): void {\n inputElement.value?.focus()\n }\n ;['UserReachedEmpathizeTop', 'UserPressedClearSearchBoxButton'].forEach(event =>\n $x.on(event as XEvent, false).subscribe(focusInput),\n )\n\n /**\n * When event {@link XEventsTypes.UserAcceptedAQuery} or\n * {@link SearchBoxXEvents.UserClearedQuery} are emitted the pending debounced emit\n * {@link XEvent} `UserAcceptedAQuery` is canceled.\n *\n * @internal\n */\n function cancelDebouncedUserAcceptedAQuery(): void {\n debouncedUserAcceptedAQuery?.cancel()\n }\n ;['UserAcceptedAQuery', 'UserClearedQuery'].forEach(event =>\n $x.on(event as XEvent, false).subscribe(cancelDebouncedUserAcceptedAQuery),\n )\n\n onMounted(() => {\n if (props.autofocus) {\n focusInput()\n }\n })\n\n return {\n query,\n inputElement,\n emitUserHoveredInSearchBox,\n emitUserHoveredOutSearchBox,\n emitUserBlurredSearchBox,\n emitUserClickedSearchBox,\n emitUserFocusedSearchBox,\n emitUserIsTypingAQueryEvents,\n emitUserPressedEnterKey,\n emitUserPressedArrowKey,\n preventSpecialKey,\n }\n },\n})\n</script>\n\n<style lang=\"css\" scoped>\n.x-search-input::-webkit-search-decoration,\n.x-search-input::-webkit-search-cancel-button,\n.x-search-input::-webkit-search-results-button,\n.x-search-input::-webkit-search-results-decoration {\n -webkit-appearance: none;\n}\n</style>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits the following events:\n\n- [`UserClickedSearchBox`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserBlurredSearchBox`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserFocusedSearchBox`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserIsTypingAQuery`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserPressedEnterKey`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserPressedArrowKey`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserAcceptedAQuery`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n\n## See it in action\n\n<!-- prettier-ignore-start -->\n:::warning Backend service required\nTo use this component, the Search service must be implemented.\n:::\n<!-- prettier-ignore-end -->\n\nHere you have a basic example of how the search input is rendered.\n\n_Type any term in the input field to try it out!_\n\n```vue live\n<template>\n <SearchInput />\n</template>\n\n<script>\nimport { SearchInput } from '@empathyco/x-components/search-box'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n },\n}\n</script>\n```\n\n### Play with props\n\nIn this example, the search input has been limited to accept a maximum of 5 characters, including\nspaces, it won't take the focus when it is rendered, and it will emit the `UserAcceptedAQuery` event\nafter 1000 milliseconds without typing.\n\n_Type a term with more than 5 characters to try it out!_\n\n```vue live\n<template>\n <SearchInput :maxLength=\"5\" :autofocus=\"false\" :instant=\"true\" :instantDebounceInMs=\"1000\" />\n</template>\n\n<script>\nimport { SearchInput } from '@empathyco/x-components/search-box'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n },\n}\n</script>\n```\n\n### Play with events\n\nIn this example, a message has been added below the search input to illustrate the action performed.\nFor example, if you select the search input box, the message “focus” appears. When you start to\nenter a search term, the message “typing” appears. If you press Enter after typing a search term,\nthe message “enter” appears.\n\n<!-- prettier-ignore-start -->\n:::warning X Events are only emitted from the root X Component.\nAt the moment, X Events are only emitted from the root X Component. This means that if you wrap\nthe `SearchInput` with another component of another module like the `MainScroll`, you should add\nthe listeners to the `MainScroll` instead of the `SearchInput`. If you need to subscribe to these\nevents, it is recommended to use the [`GlobalXBus`](../common/x-components.global-x-bus.md)\ncomponent instead.\n:::\n<!-- prettier-ignore-end -->\n\n_Type any term in the input field to try it out!_\n\n```vue live\n<template>\n <div>\n <SearchInput\n @UserPressedEnterKey=\"value = 'enter'\"\n @UserFocusedSearchBox=\"hasFocus = true\"\n @UserBlurredSearchBox=\"hasFocus = false\"\n @UserIsTypingAQuery=\"value = 'typing'\"\n />\n <strong>{{ value }}</strong>\n <span>{{ hasFocus ? 'focused' : 'unfocused' }}</span>\n </div>\n</template>\n\n<script>\nimport { SearchInput } from '@empathyco/x-components/search-box'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n },\n data() {\n return {\n value: '',\n hasFocus: false,\n }\n },\n}\n</script>\n```\n\n## Extending the component\n\nComponents can be combined and communicate with each other. Commonly, the `SearchInput` component\ncommunicates with the [`SearchButton`](x-components.search-button.md) and the\n[`ClearSearchInput`](x-components.clear-search-input.md) to offer a full query entry experience.\nFurthermore, you can use it together with the [`QuerySuggestions`](query-suggestions.md) component\nto autocomplete the typed search term.\n\n_Type “trousers” or another fashion term in the input field and then click the clear icon to try it\nout!_\n\n```vue live\n<template>\n <div>\n <div style=\"display: flex; flex-flow: row nowrap;\">\n <SearchInput />\n <ClearSearchInput>\n <img src=\"/assets/icons/cross.svg\" />\n </ClearSearchInput>\n <SearchButton>Search</SearchButton>\n </div>\n <QuerySuggestions />\n </div>\n</template>\n\n<script>\nimport { SearchInput, ClearSearchInput, SearchButton } from '@empathyco/x-components/search-box'\nimport { QuerySuggestions } from '@empathyco/x-components/query-suggestions'\n\nexport default {\n name: 'SearchInputDemo',\n components: {\n SearchInput,\n ClearSearchInput,\n SearchButton,\n QuerySuggestions,\n },\n}\n</script>\n```\n</docs>\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"semantic-queries.vue.js","sources":["../../../../../src/x-modules/semantic-queries/components/semantic-queries.vue"],"sourcesContent":["<template>\n <BaseSuggestions\n v-if=\"suggestions.length\"\n v-slot=\"baseSuggestionsScope\"\n class=\"x-semantic-queries\"\n :suggestions=\"suggestions\"\n >\n <!--\n @slot Semantic Query content\n @binding {{suggestion: object - Suggestion data, index: number - Suggestion index}} v-bind\n BaseSuggestion bindings\n -->\n <slot name=\"suggestion\" v-bind=\"baseSuggestionsScope\">\n <SemanticQuery v-slot=\"baseSuggestionScope\" :suggestion=\"baseSuggestionsScope.suggestion\">\n <!--\n @slot Semantic Query content\n @binding {{suggestion: object - Suggestion data, query: string - The query that the\n suggestion belongs to}} v-bind SemanticQuery bindings\n -->\n <slot name=\"suggestion-content\" v-bind=\"baseSuggestionScope\" />\n </SemanticQuery>\n </slot>\n </BaseSuggestions>\n</template>\n\n<script lang=\"ts\">\nimport type { Suggestion } from '@empathyco/x-types'\nimport type { ComputedRef } from 'vue'\nimport { computed, defineComponent } from 'vue'\nimport BaseSuggestions from '../../../components/suggestions/base-suggestions.vue'\nimport { useState } from '../../../composables'\nimport { semanticQueriesXModule } from '../x-module'\nimport SemanticQuery from './semantic-query.vue'\n\n/**\n * Retrieves a list of semantic queries from the state and exposes them in the slots.\n *\n * @public\n */\nexport default defineComponent({\n name: 'SemanticQueries',\n xModule: semanticQueriesXModule.name,\n components: { BaseSuggestions, SemanticQuery },\n setup(_, { slots }) {\n /** The semantic queries from the state. */\n const suggestions: ComputedRef<Suggestion[]> = useState('semanticQueries', [\n 'semanticQueries',\n ]).semanticQueries\n\n /**\n * Maps the list of semantic queries to a list of queries, to make it compatible with\n * other components.\n */\n const queries = computed(() => suggestions.value.map(suggestion => suggestion.query))\n\n /**\n * Finds a {@link @empathyco/x-types#Suggestion} given a query.\n *\n * @param query - The query to search.\n * @returns The {@link @empathyco/x-types#Suggestion} or undefined if not found.\n */\n function findSemanticQuery(query: string) {\n return suggestions.value.find(suggestion => suggestion.query === query)\n }\n\n /**\n * Render function to execute the `default` slot, binding `slotsProps` and getting only the\n * first `vNode` to avoid Fragments and Text root nodes.\n * If there are no suggestions, nothing is rendered.\n *\n * @remarks `slotProps` must be values without Vue reactivity and located inside the\n * render-function to update the binding data properly.\n *\n * @returns The root `vNode` of the `default` slot or empty string if there are\n * no suggestions.\n */\n function renderDefaultSlot() {\n const slotProps = {\n suggestions: suggestions.value,\n queries: queries.value,\n findSemanticQuery,\n }\n return suggestions.value.length ? slots.default?.(slotProps)[0] : ''\n }\n\n /* Hack to render through a render-function, the `default` slot or, in its absence,\n the component itself. It is the alternative for the NoElement antipattern. */\n const componentProps = { suggestions }\n return (slots.default ? renderDefaultSlot : componentProps) as typeof componentProps\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component doesn't emit events.\n\n## See it in action\n\nBy default, the `SemanticQueries` component will render a list of semantic queries.\n\n```vue\n<template>\n <SemanticQueries />\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\n\nexport default {\n name: 'SemanticQueriesDemo',\n components: {\n SemanticQueries,\n },\n}\n</script>\n```\n\n### Play with props\n\nThe component has the following props:\n\n- maxItemsToRender to limit the number of semantic queries to render.\n- animation to specify the animation to be used to animate the semantic queries.\n\n```vue live\n<template>\n <SemanticQueries :animation=\"animation\" :maxItemsToRender=\"3\" />\n</template>\n\n<script>\nimport { FadeAndSlide } from '@empathyco/x-components'\n\nexport default {\n name: 'SemanticQueriesPropsDemo',\n data() {\n return {\n animation: FadeAndSlide,\n }\n },\n}\n</script>\n```\n\n### Play with the default slot\n\nThe default slot is used to overwrite the whole content of the component.\n\n```vue live\n<template>\n <SemanticQueries #default=\"{ suggestions }\">\n <section>\n <SlidingPanel>\n <div v-for=\"suggestion in suggestions\">\n {{ suggestion.query }}\n {{ suggestion.distance }}\n </div>\n </SlidingPanel>\n </section>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\nimport { SlidingPanel } from '@empathyco/x-components'\n\nexport default {\n name: 'SemanticQueriesDefaultSlotDemo',\n components: {\n SemanticQueries,\n SlidingPanel,\n },\n}\n</script>\n```\n\nThe default slot also exposes an array of semantic queries mapped to strings, and a method to find a\nsemantic query given a string query.\n\nThis is useful if you need an array of string queries, but also need to retrieve the original\nsemantic query to use it in another element.\n\n```vue live\n<template>\n <SemanticQueries #default=\"{ queries, findSemanticQuery }\">\n <section>\n <QueryPreviewList :queries=\"queries\" #slot=\"{ query, results }\">\n <div>\n <SemanticQuery :semanticQuery=\"findSemanticQuery(query)\" #default=\"{ query }\">\n {{ query.query }} ({{ query.distance }})\n </SemanticQuery>\n <ul>\n <li v-for=\"result in results\" :key=\"result.id\">\n {{ result.name }}\n </li>\n </ul>\n </div>\n </QueryPreviewList>\n </section>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries, SemanticQuery } from '@empathyco/x-components/semantic-queries'\nimport { QueryPreviewList } from '@empathyco/x-components/queries-preview'\n\nexport default {\n name: 'SemanticQueriesDefaultSlotDemo2',\n components: {\n SemanticQueries,\n SemanticQuery,\n QueryPreviewList,\n },\n}\n</script>\n```\n\n### Play with the suggestion slot\n\nThe suggestion slot can be used to override each semantic query item.\n\nIn this example, the query will be rendered along with the distance.\n\n```vue live\n<template>\n <SemanticQueries #suggestion=\"{ suggestion: { query, distance } }\">\n <span>\n ({{ distance }})\n {{ query }}\n </span>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\nexport default {\n name: 'SemanticQueriesItemSlotDemo',\n components: {\n SemanticQueries,\n },\n}\n</script>\n```\n\n### Play with the suggestion content slot\n\nThe suggsetion content slot can be used to override only the content, but keep using the\nSemanticQuery component internally.\n\n```vue live\n<template>\n <SemanticQueries #suggestion-content=\"{ suggestion: { query, distance } }\">\n <span>\n ({{ distance }})\n {{ query }}\n </span>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\nexport default {\n name: 'SemanticQueriesItemSlotDemo',\n components: {\n SemanticQueries,\n },\n}\n</script>\n```\n</docs>\n"],"names":["_resolveComponent","_openBlock","_createBlock","_withCtx","_renderSlot","_normalizeProps","_guardReactiveProps","_createVNode","_createCommentVNode"],"mappings":";;;;;;AAE4B,EAAA,MAAA,0BAAA,GAAAA,gBAAA,CAAA,iBAAA,CAAA,CAAA;AAF5B,EAAA,OAAA,IAAA,CAAA,WAAA,CAAA,MAAA,IAAAC,SAAA,EAI8B,EAAAC,WAAA,CAAA,0BAAA,EAAA;AAAA,IACzB,GAAA,EAAA,CAAA;AAAA,IAAA,KAAA,EAAA,oBAAA;IALL,WAYI,EAAA,IAAA,CAAA,WAAA;AAAA,GAAA,EAAA;aACEC,OAOgB,CAAA,CAAA,oBAAA,KAAA;AAAA,MAP6BC,UAAA,CAAA,IAAA,CAAY,sBAAqBC,cAAU,CAAAC,kBAAA,CAAA,oBAAA,CAAA,CAAA,EAAA,MAAA;AAAA,QAAAC,WAAA,CAAA,wBAAA,EAAA;UAb9F,UAa6B,EAAA,oBAAA,CAAA,UAAA;AAAA,SAAA,EAAA;;AAb7B,YAAAH,UAAA,CAAA,IAAA,CAAA,MAAA,EAAA,oBAAA,EAAAC,cAAA,CAAAC,kBAAA,CAAA,mBAAA,CAAA,CAAA,CAAA;AAAA,WAAA,CAAA;;;;AAAA,OAAA,CAAA;AAAA,KAAA,CAAA;AAAA,IAAA,CAAA,EAAA,CAAA;AAAA;AAAA,GAAA,EAAA,CAAA,EAAA,CAAA,aAAA,CAAA,CAAA,IAAAE,kBAAA,CAAA,MAAA,EAAA,IAAA,CAAA,CAAA;;;;;;"}
1
+ {"version":3,"file":"semantic-queries.vue.js","sources":["../../../../../src/x-modules/semantic-queries/components/semantic-queries.vue"],"sourcesContent":["<template>\n <BaseSuggestions\n v-if=\"suggestions.length\"\n v-slot=\"baseSuggestionsScope\"\n class=\"x-semantic-queries\"\n :suggestions=\"suggestions\"\n >\n <!--\n @slot Semantic Query content\n @binding {{suggestion: object - Suggestion data, index: number - Suggestion index}} v-bind\n BaseSuggestion bindings\n -->\n <slot name=\"suggestion\" v-bind=\"baseSuggestionsScope\">\n <SemanticQuery v-slot=\"baseSuggestionScope\" :suggestion=\"baseSuggestionsScope.suggestion\">\n <!--\n @slot Semantic Query content\n @binding {{suggestion: object - Suggestion data, query: string - The query that the\n suggestion belongs to}} v-bind SemanticQuery bindings\n -->\n <slot name=\"suggestion-content\" v-bind=\"baseSuggestionScope\" />\n </SemanticQuery>\n </slot>\n </BaseSuggestions>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent } from 'vue'\nimport BaseSuggestions from '../../../components/suggestions/base-suggestions.vue'\nimport { useState } from '../../../composables'\nimport { semanticQueriesXModule } from '../x-module'\nimport SemanticQuery from './semantic-query.vue'\n\n/**\n * Retrieves a list of semantic queries from the state and exposes them in the slots.\n *\n * @public\n */\nexport default defineComponent({\n name: 'SemanticQueries',\n xModule: semanticQueriesXModule.name,\n components: { BaseSuggestions, SemanticQuery },\n setup(_, { slots }) {\n /** The semantic queries from the state. */\n const suggestions = useState('semanticQueries').semanticQueries\n\n /**\n * Maps the list of semantic queries to a list of queries, to make it compatible with\n * other components.\n */\n const queries = computed(() => suggestions.value.map(suggestion => suggestion.query))\n\n /**\n * Finds a {@link @empathyco/x-types#Suggestion} given a query.\n *\n * @param query - The query to search.\n * @returns The {@link @empathyco/x-types#Suggestion} or undefined if not found.\n */\n function findSemanticQuery(query: string) {\n return suggestions.value.find(suggestion => suggestion.query === query)\n }\n\n /**\n * Render function to execute the `default` slot, binding `slotsProps` and getting only the\n * first `vNode` to avoid Fragments and Text root nodes.\n * If there are no suggestions, nothing is rendered.\n *\n * @remarks `slotProps` must be values without Vue reactivity and located inside the\n * render-function to update the binding data properly.\n *\n * @returns The root `vNode` of the `default` slot or empty string if there are\n * no suggestions.\n */\n function renderDefaultSlot() {\n const slotProps = {\n suggestions: suggestions.value,\n queries: queries.value,\n findSemanticQuery,\n }\n return suggestions.value.length ? slots.default?.(slotProps)[0] : ''\n }\n\n /* Hack to render through a render-function, the `default` slot or, in its absence,\n the component itself. It is the alternative for the NoElement antipattern. */\n const componentProps = { suggestions }\n return (slots.default ? renderDefaultSlot : componentProps) as typeof componentProps\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component doesn't emit events.\n\n## See it in action\n\nBy default, the `SemanticQueries` component will render a list of semantic queries.\n\n```vue\n<template>\n <SemanticQueries />\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\n\nexport default {\n name: 'SemanticQueriesDemo',\n components: {\n SemanticQueries,\n },\n}\n</script>\n```\n\n### Play with props\n\nThe component has the following props:\n\n- maxItemsToRender to limit the number of semantic queries to render.\n- animation to specify the animation to be used to animate the semantic queries.\n\n```vue live\n<template>\n <SemanticQueries :animation=\"animation\" :maxItemsToRender=\"3\" />\n</template>\n\n<script>\nimport { FadeAndSlide } from '@empathyco/x-components'\n\nexport default {\n name: 'SemanticQueriesPropsDemo',\n data() {\n return {\n animation: FadeAndSlide,\n }\n },\n}\n</script>\n```\n\n### Play with the default slot\n\nThe default slot is used to overwrite the whole content of the component.\n\n```vue live\n<template>\n <SemanticQueries #default=\"{ suggestions }\">\n <section>\n <SlidingPanel>\n <div v-for=\"suggestion in suggestions\">\n {{ suggestion.query }}\n {{ suggestion.distance }}\n </div>\n </SlidingPanel>\n </section>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\nimport { SlidingPanel } from '@empathyco/x-components'\n\nexport default {\n name: 'SemanticQueriesDefaultSlotDemo',\n components: {\n SemanticQueries,\n SlidingPanel,\n },\n}\n</script>\n```\n\nThe default slot also exposes an array of semantic queries mapped to strings, and a method to find a\nsemantic query given a string query.\n\nThis is useful if you need an array of string queries, but also need to retrieve the original\nsemantic query to use it in another element.\n\n```vue live\n<template>\n <SemanticQueries #default=\"{ queries, findSemanticQuery }\">\n <section>\n <QueryPreviewList :queries=\"queries\" #slot=\"{ query, results }\">\n <div>\n <SemanticQuery :semanticQuery=\"findSemanticQuery(query)\" #default=\"{ query }\">\n {{ query.query }} ({{ query.distance }})\n </SemanticQuery>\n <ul>\n <li v-for=\"result in results\" :key=\"result.id\">\n {{ result.name }}\n </li>\n </ul>\n </div>\n </QueryPreviewList>\n </section>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries, SemanticQuery } from '@empathyco/x-components/semantic-queries'\nimport { QueryPreviewList } from '@empathyco/x-components/queries-preview'\n\nexport default {\n name: 'SemanticQueriesDefaultSlotDemo2',\n components: {\n SemanticQueries,\n SemanticQuery,\n QueryPreviewList,\n },\n}\n</script>\n```\n\n### Play with the suggestion slot\n\nThe suggestion slot can be used to override each semantic query item.\n\nIn this example, the query will be rendered along with the distance.\n\n```vue live\n<template>\n <SemanticQueries #suggestion=\"{ suggestion: { query, distance } }\">\n <span>\n ({{ distance }})\n {{ query }}\n </span>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\nexport default {\n name: 'SemanticQueriesItemSlotDemo',\n components: {\n SemanticQueries,\n },\n}\n</script>\n```\n\n### Play with the suggestion content slot\n\nThe suggsetion content slot can be used to override only the content, but keep using the\nSemanticQuery component internally.\n\n```vue live\n<template>\n <SemanticQueries #suggestion-content=\"{ suggestion: { query, distance } }\">\n <span>\n ({{ distance }})\n {{ query }}\n </span>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\nexport default {\n name: 'SemanticQueriesItemSlotDemo',\n components: {\n SemanticQueries,\n },\n}\n</script>\n```\n</docs>\n"],"names":["_resolveComponent","_openBlock","_createBlock","_withCtx","_renderSlot","_normalizeProps","_guardReactiveProps","_createVNode","_createCommentVNode"],"mappings":";;;;;;AAE4B,EAAA,MAAA,0BAAA,GAAAA,gBAAA,CAAA,iBAAA,CAAA,CAAA;AAF5B,EAAA,OAAA,IAAA,CAAA,WAAA,CAAA,MAAA,IAAAC,SAAA,EAI8B,EAAAC,WAAA,CAAA,0BAAA,EAAA;AAAA,IACzB,GAAA,EAAA,CAAA;AAAA,IAAA,KAAA,EAAA,oBAAA;IALL,WAYI,EAAA,IAAA,CAAA,WAAA;AAAA,GAAA,EAAA;aACEC,OAOgB,CAAA,CAAA,oBAAA,KAAA;AAAA,MAP6BC,UAAA,CAAA,IAAA,CAAY,sBAAqBC,cAAU,CAAAC,kBAAA,CAAA,oBAAA,CAAA,CAAA,EAAA,MAAA;AAAA,QAAAC,WAAA,CAAA,wBAAA,EAAA;UAb9F,UAa6B,EAAA,oBAAA,CAAA,UAAA;AAAA,SAAA,EAAA;;AAb7B,YAAAH,UAAA,CAAA,IAAA,CAAA,MAAA,EAAA,oBAAA,EAAAC,cAAA,CAAAC,kBAAA,CAAA,mBAAA,CAAA,CAAA,CAAA;AAAA,WAAA,CAAA;;;;AAAA,OAAA,CAAA;AAAA,KAAA,CAAA;AAAA,IAAA,CAAA,EAAA,CAAA;AAAA;AAAA,GAAA,EAAA,CAAA,EAAA,CAAA,aAAA,CAAA,CAAA,IAAAE,kBAAA,CAAA,MAAA,EAAA,IAAA,CAAA,CAAA;;;;;;"}
@@ -26,9 +26,7 @@ var _sfc_main = defineComponent({
26
26
  components: { BaseSuggestions, SemanticQuery },
27
27
  setup(_, { slots }) {
28
28
  /** The semantic queries from the state. */
29
- const suggestions = useState('semanticQueries', [
30
- 'semanticQueries',
31
- ]).semanticQueries;
29
+ const suggestions = useState('semanticQueries').semanticQueries;
32
30
  /**
33
31
  * Maps the list of semantic queries to a list of queries, to make it compatible with
34
32
  * other components.
@@ -1 +1 @@
1
- {"version":3,"file":"semantic-queries.vue2.js","sources":["../../../../../src/x-modules/semantic-queries/components/semantic-queries.vue"],"sourcesContent":["<template>\n <BaseSuggestions\n v-if=\"suggestions.length\"\n v-slot=\"baseSuggestionsScope\"\n class=\"x-semantic-queries\"\n :suggestions=\"suggestions\"\n >\n <!--\n @slot Semantic Query content\n @binding {{suggestion: object - Suggestion data, index: number - Suggestion index}} v-bind\n BaseSuggestion bindings\n -->\n <slot name=\"suggestion\" v-bind=\"baseSuggestionsScope\">\n <SemanticQuery v-slot=\"baseSuggestionScope\" :suggestion=\"baseSuggestionsScope.suggestion\">\n <!--\n @slot Semantic Query content\n @binding {{suggestion: object - Suggestion data, query: string - The query that the\n suggestion belongs to}} v-bind SemanticQuery bindings\n -->\n <slot name=\"suggestion-content\" v-bind=\"baseSuggestionScope\" />\n </SemanticQuery>\n </slot>\n </BaseSuggestions>\n</template>\n\n<script lang=\"ts\">\nimport type { Suggestion } from '@empathyco/x-types'\nimport type { ComputedRef } from 'vue'\nimport { computed, defineComponent } from 'vue'\nimport BaseSuggestions from '../../../components/suggestions/base-suggestions.vue'\nimport { useState } from '../../../composables'\nimport { semanticQueriesXModule } from '../x-module'\nimport SemanticQuery from './semantic-query.vue'\n\n/**\n * Retrieves a list of semantic queries from the state and exposes them in the slots.\n *\n * @public\n */\nexport default defineComponent({\n name: 'SemanticQueries',\n xModule: semanticQueriesXModule.name,\n components: { BaseSuggestions, SemanticQuery },\n setup(_, { slots }) {\n /** The semantic queries from the state. */\n const suggestions: ComputedRef<Suggestion[]> = useState('semanticQueries', [\n 'semanticQueries',\n ]).semanticQueries\n\n /**\n * Maps the list of semantic queries to a list of queries, to make it compatible with\n * other components.\n */\n const queries = computed(() => suggestions.value.map(suggestion => suggestion.query))\n\n /**\n * Finds a {@link @empathyco/x-types#Suggestion} given a query.\n *\n * @param query - The query to search.\n * @returns The {@link @empathyco/x-types#Suggestion} or undefined if not found.\n */\n function findSemanticQuery(query: string) {\n return suggestions.value.find(suggestion => suggestion.query === query)\n }\n\n /**\n * Render function to execute the `default` slot, binding `slotsProps` and getting only the\n * first `vNode` to avoid Fragments and Text root nodes.\n * If there are no suggestions, nothing is rendered.\n *\n * @remarks `slotProps` must be values without Vue reactivity and located inside the\n * render-function to update the binding data properly.\n *\n * @returns The root `vNode` of the `default` slot or empty string if there are\n * no suggestions.\n */\n function renderDefaultSlot() {\n const slotProps = {\n suggestions: suggestions.value,\n queries: queries.value,\n findSemanticQuery,\n }\n return suggestions.value.length ? slots.default?.(slotProps)[0] : ''\n }\n\n /* Hack to render through a render-function, the `default` slot or, in its absence,\n the component itself. It is the alternative for the NoElement antipattern. */\n const componentProps = { suggestions }\n return (slots.default ? renderDefaultSlot : componentProps) as typeof componentProps\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component doesn't emit events.\n\n## See it in action\n\nBy default, the `SemanticQueries` component will render a list of semantic queries.\n\n```vue\n<template>\n <SemanticQueries />\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\n\nexport default {\n name: 'SemanticQueriesDemo',\n components: {\n SemanticQueries,\n },\n}\n</script>\n```\n\n### Play with props\n\nThe component has the following props:\n\n- maxItemsToRender to limit the number of semantic queries to render.\n- animation to specify the animation to be used to animate the semantic queries.\n\n```vue live\n<template>\n <SemanticQueries :animation=\"animation\" :maxItemsToRender=\"3\" />\n</template>\n\n<script>\nimport { FadeAndSlide } from '@empathyco/x-components'\n\nexport default {\n name: 'SemanticQueriesPropsDemo',\n data() {\n return {\n animation: FadeAndSlide,\n }\n },\n}\n</script>\n```\n\n### Play with the default slot\n\nThe default slot is used to overwrite the whole content of the component.\n\n```vue live\n<template>\n <SemanticQueries #default=\"{ suggestions }\">\n <section>\n <SlidingPanel>\n <div v-for=\"suggestion in suggestions\">\n {{ suggestion.query }}\n {{ suggestion.distance }}\n </div>\n </SlidingPanel>\n </section>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\nimport { SlidingPanel } from '@empathyco/x-components'\n\nexport default {\n name: 'SemanticQueriesDefaultSlotDemo',\n components: {\n SemanticQueries,\n SlidingPanel,\n },\n}\n</script>\n```\n\nThe default slot also exposes an array of semantic queries mapped to strings, and a method to find a\nsemantic query given a string query.\n\nThis is useful if you need an array of string queries, but also need to retrieve the original\nsemantic query to use it in another element.\n\n```vue live\n<template>\n <SemanticQueries #default=\"{ queries, findSemanticQuery }\">\n <section>\n <QueryPreviewList :queries=\"queries\" #slot=\"{ query, results }\">\n <div>\n <SemanticQuery :semanticQuery=\"findSemanticQuery(query)\" #default=\"{ query }\">\n {{ query.query }} ({{ query.distance }})\n </SemanticQuery>\n <ul>\n <li v-for=\"result in results\" :key=\"result.id\">\n {{ result.name }}\n </li>\n </ul>\n </div>\n </QueryPreviewList>\n </section>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries, SemanticQuery } from '@empathyco/x-components/semantic-queries'\nimport { QueryPreviewList } from '@empathyco/x-components/queries-preview'\n\nexport default {\n name: 'SemanticQueriesDefaultSlotDemo2',\n components: {\n SemanticQueries,\n SemanticQuery,\n QueryPreviewList,\n },\n}\n</script>\n```\n\n### Play with the suggestion slot\n\nThe suggestion slot can be used to override each semantic query item.\n\nIn this example, the query will be rendered along with the distance.\n\n```vue live\n<template>\n <SemanticQueries #suggestion=\"{ suggestion: { query, distance } }\">\n <span>\n ({{ distance }})\n {{ query }}\n </span>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\nexport default {\n name: 'SemanticQueriesItemSlotDemo',\n components: {\n SemanticQueries,\n },\n}\n</script>\n```\n\n### Play with the suggestion content slot\n\nThe suggsetion content slot can be used to override only the content, but keep using the\nSemanticQuery component internally.\n\n```vue live\n<template>\n <SemanticQueries #suggestion-content=\"{ suggestion: { query, distance } }\">\n <span>\n ({{ distance }})\n {{ query }}\n </span>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\nexport default {\n name: 'SemanticQueriesItemSlotDemo',\n components: {\n SemanticQueries,\n },\n}\n</script>\n```\n</docs>\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAkCA;;;;AAIE;AACF,gBAAe,eAAe,CAAC;AAC7B,IAAA,IAAI,EAAE,iBAAiB;IACvB,OAAO,EAAE,sBAAsB,CAAC,IAAI;AACpC,IAAA,UAAU,EAAE,EAAE,eAAe,EAAE,eAAe;AAC9C,IAAA,KAAK,CAAC,CAAC,EAAE,EAAE,KAAI,EAAG,EAAA;;AAEhB,QAAA,MAAM,WAAW,GAA8B,QAAQ,CAAC,iBAAiB,EAAE;YACzE,iBAAiB;SAClB,CAAC,CAAC,eAAc,CAAA;AAEjB;;;AAGE;QACF,MAAM,OAAQ,GAAE,QAAQ,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,UAAS,IAAK,UAAU,CAAC,KAAK,CAAC,CAAA,CAAA;AAEpF;;;;;AAKE;QACF,SAAS,iBAAiB,CAAC,KAAa,EAAA;AACtC,YAAA,OAAO,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,UAAW,IAAG,UAAU,CAAC,KAAI,KAAM,KAAK,CAAA,CAAA;SACxE;AAEA;;;;;;;;;;AAUE;AACF,QAAA,SAAS,iBAAiB,GAAA;AACxB,YAAA,MAAM,YAAY;gBAChB,WAAW,EAAE,WAAW,CAAC,KAAK;gBAC9B,OAAO,EAAE,OAAO,CAAC,KAAK;gBACtB,iBAAiB;aACnB,CAAA;YACA,OAAO,WAAW,CAAC,KAAK,CAAC,MAAO,GAAE,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAE,GAAE,EAAC,CAAA;SACrE;AAEA;AAC+E;AAC/E,QAAA,MAAM,cAAe,GAAE,EAAE,WAAY,EAAA,CAAA;AACrC,QAAA,QAAQ,KAAK,CAAC,OAAM,GAAI,iBAAkB,GAAE,cAAc,EAAyB;KACpF;AACF,CAAA,CAAA;;;;"}
1
+ {"version":3,"file":"semantic-queries.vue2.js","sources":["../../../../../src/x-modules/semantic-queries/components/semantic-queries.vue"],"sourcesContent":["<template>\n <BaseSuggestions\n v-if=\"suggestions.length\"\n v-slot=\"baseSuggestionsScope\"\n class=\"x-semantic-queries\"\n :suggestions=\"suggestions\"\n >\n <!--\n @slot Semantic Query content\n @binding {{suggestion: object - Suggestion data, index: number - Suggestion index}} v-bind\n BaseSuggestion bindings\n -->\n <slot name=\"suggestion\" v-bind=\"baseSuggestionsScope\">\n <SemanticQuery v-slot=\"baseSuggestionScope\" :suggestion=\"baseSuggestionsScope.suggestion\">\n <!--\n @slot Semantic Query content\n @binding {{suggestion: object - Suggestion data, query: string - The query that the\n suggestion belongs to}} v-bind SemanticQuery bindings\n -->\n <slot name=\"suggestion-content\" v-bind=\"baseSuggestionScope\" />\n </SemanticQuery>\n </slot>\n </BaseSuggestions>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent } from 'vue'\nimport BaseSuggestions from '../../../components/suggestions/base-suggestions.vue'\nimport { useState } from '../../../composables'\nimport { semanticQueriesXModule } from '../x-module'\nimport SemanticQuery from './semantic-query.vue'\n\n/**\n * Retrieves a list of semantic queries from the state and exposes them in the slots.\n *\n * @public\n */\nexport default defineComponent({\n name: 'SemanticQueries',\n xModule: semanticQueriesXModule.name,\n components: { BaseSuggestions, SemanticQuery },\n setup(_, { slots }) {\n /** The semantic queries from the state. */\n const suggestions = useState('semanticQueries').semanticQueries\n\n /**\n * Maps the list of semantic queries to a list of queries, to make it compatible with\n * other components.\n */\n const queries = computed(() => suggestions.value.map(suggestion => suggestion.query))\n\n /**\n * Finds a {@link @empathyco/x-types#Suggestion} given a query.\n *\n * @param query - The query to search.\n * @returns The {@link @empathyco/x-types#Suggestion} or undefined if not found.\n */\n function findSemanticQuery(query: string) {\n return suggestions.value.find(suggestion => suggestion.query === query)\n }\n\n /**\n * Render function to execute the `default` slot, binding `slotsProps` and getting only the\n * first `vNode` to avoid Fragments and Text root nodes.\n * If there are no suggestions, nothing is rendered.\n *\n * @remarks `slotProps` must be values without Vue reactivity and located inside the\n * render-function to update the binding data properly.\n *\n * @returns The root `vNode` of the `default` slot or empty string if there are\n * no suggestions.\n */\n function renderDefaultSlot() {\n const slotProps = {\n suggestions: suggestions.value,\n queries: queries.value,\n findSemanticQuery,\n }\n return suggestions.value.length ? slots.default?.(slotProps)[0] : ''\n }\n\n /* Hack to render through a render-function, the `default` slot or, in its absence,\n the component itself. It is the alternative for the NoElement antipattern. */\n const componentProps = { suggestions }\n return (slots.default ? renderDefaultSlot : componentProps) as typeof componentProps\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component doesn't emit events.\n\n## See it in action\n\nBy default, the `SemanticQueries` component will render a list of semantic queries.\n\n```vue\n<template>\n <SemanticQueries />\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\n\nexport default {\n name: 'SemanticQueriesDemo',\n components: {\n SemanticQueries,\n },\n}\n</script>\n```\n\n### Play with props\n\nThe component has the following props:\n\n- maxItemsToRender to limit the number of semantic queries to render.\n- animation to specify the animation to be used to animate the semantic queries.\n\n```vue live\n<template>\n <SemanticQueries :animation=\"animation\" :maxItemsToRender=\"3\" />\n</template>\n\n<script>\nimport { FadeAndSlide } from '@empathyco/x-components'\n\nexport default {\n name: 'SemanticQueriesPropsDemo',\n data() {\n return {\n animation: FadeAndSlide,\n }\n },\n}\n</script>\n```\n\n### Play with the default slot\n\nThe default slot is used to overwrite the whole content of the component.\n\n```vue live\n<template>\n <SemanticQueries #default=\"{ suggestions }\">\n <section>\n <SlidingPanel>\n <div v-for=\"suggestion in suggestions\">\n {{ suggestion.query }}\n {{ suggestion.distance }}\n </div>\n </SlidingPanel>\n </section>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\nimport { SlidingPanel } from '@empathyco/x-components'\n\nexport default {\n name: 'SemanticQueriesDefaultSlotDemo',\n components: {\n SemanticQueries,\n SlidingPanel,\n },\n}\n</script>\n```\n\nThe default slot also exposes an array of semantic queries mapped to strings, and a method to find a\nsemantic query given a string query.\n\nThis is useful if you need an array of string queries, but also need to retrieve the original\nsemantic query to use it in another element.\n\n```vue live\n<template>\n <SemanticQueries #default=\"{ queries, findSemanticQuery }\">\n <section>\n <QueryPreviewList :queries=\"queries\" #slot=\"{ query, results }\">\n <div>\n <SemanticQuery :semanticQuery=\"findSemanticQuery(query)\" #default=\"{ query }\">\n {{ query.query }} ({{ query.distance }})\n </SemanticQuery>\n <ul>\n <li v-for=\"result in results\" :key=\"result.id\">\n {{ result.name }}\n </li>\n </ul>\n </div>\n </QueryPreviewList>\n </section>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries, SemanticQuery } from '@empathyco/x-components/semantic-queries'\nimport { QueryPreviewList } from '@empathyco/x-components/queries-preview'\n\nexport default {\n name: 'SemanticQueriesDefaultSlotDemo2',\n components: {\n SemanticQueries,\n SemanticQuery,\n QueryPreviewList,\n },\n}\n</script>\n```\n\n### Play with the suggestion slot\n\nThe suggestion slot can be used to override each semantic query item.\n\nIn this example, the query will be rendered along with the distance.\n\n```vue live\n<template>\n <SemanticQueries #suggestion=\"{ suggestion: { query, distance } }\">\n <span>\n ({{ distance }})\n {{ query }}\n </span>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\nexport default {\n name: 'SemanticQueriesItemSlotDemo',\n components: {\n SemanticQueries,\n },\n}\n</script>\n```\n\n### Play with the suggestion content slot\n\nThe suggsetion content slot can be used to override only the content, but keep using the\nSemanticQuery component internally.\n\n```vue live\n<template>\n <SemanticQueries #suggestion-content=\"{ suggestion: { query, distance } }\">\n <span>\n ({{ distance }})\n {{ query }}\n </span>\n </SemanticQueries>\n</template>\n\n<script>\nimport { SemanticQueries } from '@empathyco/x-components/semantic-queries'\nexport default {\n name: 'SemanticQueriesItemSlotDemo',\n components: {\n SemanticQueries,\n },\n}\n</script>\n```\n</docs>\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAgCA;;;;AAIE;AACF,gBAAe,eAAe,CAAC;AAC7B,IAAA,IAAI,EAAE,iBAAiB;IACvB,OAAO,EAAE,sBAAsB,CAAC,IAAI;AACpC,IAAA,UAAU,EAAE,EAAE,eAAe,EAAE,eAAe;AAC9C,IAAA,KAAK,CAAC,CAAC,EAAE,EAAE,KAAI,EAAG,EAAA;;QAEhB,MAAM,WAAY,GAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC,eAAc,CAAA;AAE9D;;;AAGE;QACF,MAAM,OAAQ,GAAE,QAAQ,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,UAAS,IAAK,UAAU,CAAC,KAAK,CAAC,CAAA,CAAA;AAEpF;;;;;AAKE;QACF,SAAS,iBAAiB,CAAC,KAAa,EAAA;AACtC,YAAA,OAAO,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,UAAW,IAAG,UAAU,CAAC,KAAI,KAAM,KAAK,CAAA,CAAA;SACxE;AAEA;;;;;;;;;;AAUE;AACF,QAAA,SAAS,iBAAiB,GAAA;AACxB,YAAA,MAAM,YAAY;gBAChB,WAAW,EAAE,WAAW,CAAC,KAAK;gBAC9B,OAAO,EAAE,OAAO,CAAC,KAAK;gBACtB,iBAAiB;aACnB,CAAA;YACA,OAAO,WAAW,CAAC,KAAK,CAAC,MAAO,GAAE,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAE,GAAE,EAAC,CAAA;SACrE;AAEA;AAC+E;AAC/E,QAAA,MAAM,cAAe,GAAE,EAAE,WAAY,EAAA,CAAA;AACrC,QAAA,QAAQ,KAAK,CAAC,OAAM,GAAI,iBAAkB,GAAE,cAAc,EAAyB;KACpF;AACF,CAAA,CAAA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"url-handler.vue.js","sources":["../../../../../src/x-modules/url/components/url-handler.vue"],"sourcesContent":["<template>\n <GlobalEvents target=\"window\" @pageshow=\"onPageShow\" @popstate=\"emitEvents\" />\n</template>\n\n<script lang=\"ts\">\nimport type { Dictionary } from '@empathyco/x-utils'\nimport type { FeatureLocation } from '../../../types/origin'\nimport type { UrlParams } from '../../../types/url-params'\nimport type { WireMetadata } from '../../../wiring/wiring.types'\nimport type { SnippetConfig } from '../../../x-installer/api/api.types'\nimport type { UrlParamValue } from '../store/types'\nimport { objectFilter } from '@empathyco/x-utils'\nimport { computed, defineComponent, inject, onMounted, ref } from 'vue'\nimport { GlobalEvents } from 'vue-global-events'\nimport { use$x } from '../../../composables/use-$x'\nimport { useState } from '../../../composables/use-state'\nimport { isArrayEmpty } from '../../../utils/array'\nimport { initialUrlState } from '../store/initial-state'\nimport { urlXModule } from '../x-module'\n\ninterface ParsedUrlParams {\n all: UrlParams\n extra: Dictionary<unknown>\n}\n\n/**\n * This component manages the browser URL parameters to preserve them through reloads and browser\n * history navigation. It allow to configure the default url parameter names using its attributes.\n * This component doesn't render elements to the DOM.\n *\n * @public\n */\nexport default defineComponent({\n name: 'UrlHandler',\n components: {\n GlobalEvents,\n },\n xModule: urlXModule.name,\n setup(_, { attrs }) {\n const $x = use$x()\n\n const initialExtraParams = useState('url', ['initialExtraParams']).initialExtraParams\n\n /**\n * The {@link SnippetConfig} provided by an ancestor.\n *\n * @internal\n */\n const snippetConfig = inject<SnippetConfig | undefined>('snippetConfig')\n\n /**\n * Flag to know if the params were already loaded from the URL.\n *\n * @internal\n */\n const urlLoaded = ref(false)\n\n /**\n * The page URL. It is used to compare against the current URL to check navigation state.\n *\n * @internal\n */\n const url = ref<URL | undefined>(undefined)\n\n /**\n * Flag to know if the page has been persisted by the browser's back-forward cache.\n *\n * @internal\n */\n const isPagePersisted = ref(false)\n\n /**\n * Computed to know which params we must get from URL. It gets the params names from the initial\n * state, to get all default params names, and also from the `$attrs` to get the extra params\n * names to take into account.\n *\n * @returns An array with the name of the params.\n *\n * @internal\n */\n const managedParamsNames = computed(() => Object.keys({ ...initialUrlState, ...attrs }))\n\n /**\n * Returns the mapping of the param keys used in the URL is configured through $attrs. This way\n * we can support any param and extra param, no matters its name.\n *\n * @param paramName - The param name to get the Url key.\n * @returns The key used in the URL for the `paramName` passed.\n *\n * @internal\n */\n const getUrlKey = (paramName: string) => {\n const paramValue = attrs[paramName]\n return typeof paramValue === 'string' ? paramValue : paramName\n }\n\n /**\n * Deletes all the parameters in the passed URL.\n *\n * @param url - The URL to remove parameters from.\n * @internal\n */\n const deleteUrlParameters = (url: URL) => {\n managedParamsNames.value.forEach(paramName => url.searchParams.delete(getUrlKey(paramName)))\n }\n\n /**\n * Sorts the params in a tuple array [key,value] to generate always the same URL with the params\n * in the same order.\n *\n * @param urlParams - The {@link UrlParams} to sort.\n * @returns An array of tuples with the key-value of each paramter, sorted by key.\n * @internal\n */\n const sortParams = (urlParams: UrlParams): Array<[string, unknown]> => {\n return Object.entries(urlParams).sort(([param1], [param2]) => {\n return param1 < param2 ? -1 : 1\n })\n }\n\n /**\n * Set all the provided parameters to the url with the mapped key.\n *\n * @param url - The current URL.\n * @param urlParams - The list of parameters to add.\n * @remarks The params are filtered because there maybe received extra params which will not be\n * managed by URL. This is defined by the `managedParamsNames` computed. Also, the parameters\n * are sorted Alphabetically to produce always the same URL with the same parameters.This is\n * important for SEO purposes.\n *\n * @internal\n */\n const setUrlParameters = (url: URL, urlParams: UrlParams): void => {\n // Only when there is a query the rest of the parameters are valid.\n if (!urlParams.query) {\n return\n }\n const filteredParams = objectFilter(urlParams, paramName =>\n managedParamsNames.value.includes(paramName as string),\n )\n const sortedParameters = sortParams(filteredParams)\n sortedParameters.forEach(([paramName, paramValue]) => {\n const urlParamKey = getUrlKey(paramName)\n if (Array.isArray(paramValue)) {\n paramValue.forEach(value => {\n url.searchParams.append(urlParamKey, String(value))\n })\n } else {\n url.searchParams.set(urlParamKey, String(paramValue))\n }\n })\n }\n\n /**\n * Updates the browser URL with the passed `newUrlParams` and using the browser history method\n * passed as `historyMethod`. It only updates the browser history if the new URL is different\n * from the current.\n *\n * @param newUrlParams - The new params to add to the browser URL.\n * @param historyMethod - The browser history method used to add the new URL.\n *\n * @internal\n */\n const updateUrl = (\n newUrlParams: UrlParams,\n historyMethod: History['pushState'] | History['replaceState'],\n ): void => {\n if (urlLoaded.value) {\n const newUrl = new URL(window.location.href)\n deleteUrlParameters(newUrl)\n setUrlParameters(newUrl, newUrlParams)\n\n // Normalize '+' characters into '%20' for spaces in url params.\n newUrl.search = newUrl.search.replace(/\\+/g, '%20')\n\n if (newUrl.href !== window.location.href) {\n historyMethod({ ...window.history.state }, document.title, newUrl.href)\n }\n url.value = newUrl\n }\n }\n\n /**\n * Updates the browser URL with the new {@link UrlParams} using the history `pushState` method.\n *\n * @param newUrlParams - The new params to update browser URL.\n */\n $x.on('PushableUrlStateUpdated', false).subscribe((newUrlParams: UrlParams) => {\n updateUrl(newUrlParams, window.history.pushState.bind(window.history))\n })\n\n /**\n * Updates the browser URL with the new {@link UrlParams} using the history `replaceState`\n * method.\n *\n * @param newUrlParams - The new params to update browser URL.\n */\n $x.on('ReplaceableUrlStateUpdated', false).subscribe((newUrlParams: UrlParams) => {\n updateUrl(newUrlParams, window.history.replaceState.bind(window.history))\n })\n\n /**\n * Handler of the\n * [pageshow](https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event)\n * event.\n *\n * @remarks The pageshow event is listened to check if the browser has performed a navigation\n * using the back-forward cache. This information is available in the\n * PageTransitionEvent.persisted property.\n *\n * @param event - The page transition event.\n * @internal\n */\n const onPageShow = (event: PageTransitionEvent) => {\n isPagePersisted.value = event.persisted\n if (event.persisted) {\n // The internal url is reset due to the back-forward cache storing the previous value which\n // is no longer valid.\n url.value = undefined\n }\n }\n\n /**\n * Returns the URL param value parsed depending on its type in the initial store state. As we\n * can not know what type can have an extra param, all extra params are parsed as strings. We\n * know if it is an extra param because it is not in the initial state.\n *\n * @param name - The name of the param in {@link UrlParams}.\n * @param value - The `URLSearchParams` value as an arry of strings.\n * @returns The parsed value.\n *\n * @internal\n */\n const parseUrlParam = (name: string, value: string[]): UrlParamValue => {\n switch (typeof initialUrlState[name]) {\n case 'number':\n return Number(value[0])\n case 'boolean':\n return value[0].toLowerCase() === 'true'\n case 'string':\n return value[0]\n default:\n // array\n return value\n }\n }\n\n /**\n * Gets the {@link UrlParams} from the URL, including only the params defined by `paramsNames`.\n *\n * @returns ParsedUrlParams obtained from URL.\n * @internal\n */\n const parseUrlParams = (): ParsedUrlParams => {\n const urlSearchParams = new URL(window.location.href).searchParams\n return managedParamsNames.value.reduce<ParsedUrlParams>(\n (params, name) => {\n const urlKey = getUrlKey(name)\n if (urlSearchParams.has(urlKey)) {\n if (name in initialUrlState) {\n const urlValue = urlSearchParams.getAll(urlKey)\n params.all[name] = parseUrlParam(name, urlValue)\n } else {\n params.all[name] = params.extra[name] = urlSearchParams.get(urlKey)\n }\n }\n return params\n },\n { all: { ...initialUrlState }, extra: { ...initialExtraParams.value } },\n )\n }\n\n /**\n * Check if the navigation is from a product page.\n *\n * @remarks Due to Safari 14 not supporting the new and standard PerformanceNavigationTiming\n * API, we are falling back to the deprecated one, PerformanceNavigation. We also fallback to\n * this API whenever we get a navigationType equal to reload, because Safari has a bug that the\n * navigationType is permanently set to reload after you have reload the page and it never\n * resets. As some browsers have a back-forward cache implemented, we also take into account if\n * the page is persisted.\n *\n * @returns True if the navigation is from a product page, false otherwise.\n * @internal\n */\n const isNavigatingFromPdp = (): boolean => {\n const isPagePersistedValue = isPagePersisted.value\n const navigationEntries = window.performance.getEntriesByType('navigation')\n const navigationType = (navigationEntries[0] as PerformanceNavigationTiming)?.type\n const useFallbackStrategy =\n !navigationEntries.length &&\n (isArrayEmpty(navigationEntries) || navigationType === 'reload')\n\n // Reset internal isPagePersisted property value\n isPagePersisted.value = false\n\n if (useFallbackStrategy) {\n const isNavigatingInSpa = !!snippetConfig?.isSpa && navigationType === 'navigate'\n return navigationType === 'back_forward' || isNavigatingInSpa || isPagePersistedValue\n } else {\n const isNavigatingInSpa = !!snippetConfig?.isSpa && navigationType === 'navigate'\n return navigationType === 'back_forward' || isNavigatingInSpa || isPagePersistedValue\n }\n }\n\n /**\n * Detects the {@link FeatureLocation} used to build the\n * {@link QueryOriginInit} data.\n *\n * @returns The {@link FeatureLocation}.\n * @internal\n */\n const detectLocation = (): FeatureLocation => {\n const currentUrl = new URL(window.location.href)\n const previousUrl = url.value\n url.value = currentUrl\n\n const isInternalNavigation =\n previousUrl?.search !== currentUrl.search && previousUrl?.pathname === currentUrl.pathname\n if (isInternalNavigation) {\n return 'url_history'\n }\n\n if (isNavigatingFromPdp()) {\n return 'url_history_pdp'\n }\n\n return 'external'\n }\n\n /**\n * Creates the wire metadata to include in every emitted {@link XEvent}.\n *\n * @returns The {@link WireMetadata}.\n * @internal\n */\n const createWireMetadata = (): Pick<WireMetadata, 'feature' | 'location'> => {\n return {\n feature: 'url',\n location: detectLocation(),\n }\n }\n\n /**\n * Emits the {@link UrlXEvents.ParamsLoadedFromUrl} XEvent,\n * the {@link UrlXEvents.ExtraParamsLoadedFromUrl} XEvent and, if there is query, also emits\n * the {@link XEventsTypes.UserOpenXProgrammatically}.\n *\n * @internal\n */\n const emitEvents = () => {\n const { all, extra } = parseUrlParams()\n const metadata = createWireMetadata()\n $x.emit('ParamsLoadedFromUrl', all, metadata)\n $x.emit('ExtraParamsLoadedFromUrl', extra, metadata)\n if (all.query) {\n $x.emit('UserOpenXProgrammatically', undefined, metadata)\n }\n urlLoaded.value = true\n }\n\n /**\n * To emit the Url events just when the URL is load, and before the components mounted events\n * and state changes, we do it in the created of this component.\n */\n onMounted(() => {\n emitEvents()\n })\n\n return {\n onPageShow,\n emitEvents,\n }\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits the following events:\n\n- [`ParamsLoadedFromUrl`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`ExtraParamsLoadedFromUrl`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserOpenXProgrammatically`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n\n## See it in action\n\nThis component manages the browser URL parameters to preserve them through reloads and browser\nhistory navigation. It allow to configure the default url parameter names using its attributes. This\ncomponent doesn't render elements to the DOM.\n\n_Try to make some requests and take a look to the url!_\n\n```vue\n<template>\n <UrlHandler />\n</template>\n\n<script>\nimport { UrlHandler } from '@empathyco/x-components/url-handler'\n\nexport default {\n name: 'UrlHandlerDemo',\n components: {\n UrlHandler,\n },\n}\n</script>\n```\n\n### Play with props\n\nIn this example, the `UrlHandler` component changes the following query parameter names:\n\n- `query` to be `q`.\n- `page` to be `p`.\n- `filter` to be `f`\n- `sort` to be `s`\n\n_Try to make some requests and take a look to the url!_\n\n```vue\n<template>\n <UrlHandler query=\"q\" page=\"p\" filter=\"f\" sort=\"s\" />\n</template>\n\n<script>\nimport { UrlHandler } from '@empathyco/x-components/url-handler'\n\nexport default {\n name: 'UrlHandlerDemo',\n components: {\n UrlHandler,\n },\n}\n</script>\n```\n\n### Play with events\n\nThe `UrlHandler` will emit the `ParamsLoadedFromUrl` when the page is loaded.\n\nThe `UrlHandler` will emit the `ExtraParamsLoadedFromUrl` when the page is loaded with an extra\nparam configured and with a value in URL.\n\nThe `UrlHandler` will emit the `UserOpenXProgrammatically` when the page is loaded with a query in\nthe URL.\n</docs>\n"],"names":["_resolveComponent","_openBlock","_createBlock"],"mappings":";;;;;kCACEA,gBAA8E,CAAA,cAAA,CAAA,CAAA;AAA/C,EAAA,OAAAC,SAAA,EAAoB,EAAAC,WAAA,CAAA,uBAAA,EAAA;AAAA,IAAG,MAAA,EAAA,QAAA;AAAA,IAAA,UAAA,EAAA,IAAA,CAAA,UAAA;;;;;;;;"}
1
+ {"version":3,"file":"url-handler.vue.js","sources":["../../../../../src/x-modules/url/components/url-handler.vue"],"sourcesContent":["<template>\n <GlobalEvents target=\"window\" @pageshow=\"onPageShow\" @popstate=\"emitEvents\" />\n</template>\n\n<script lang=\"ts\">\nimport type { Dictionary } from '@empathyco/x-utils'\nimport type { FeatureLocation } from '../../../types/origin'\nimport type { UrlParams } from '../../../types/url-params'\nimport type { WireMetadata } from '../../../wiring/wiring.types'\nimport type { SnippetConfig } from '../../../x-installer/api/api.types'\nimport type { UrlParamValue } from '../store/types'\nimport { objectFilter } from '@empathyco/x-utils'\nimport { computed, defineComponent, inject, onMounted, ref } from 'vue'\nimport { GlobalEvents } from 'vue-global-events'\nimport { use$x } from '../../../composables/use-$x'\nimport { useState } from '../../../composables/use-state'\nimport { isArrayEmpty } from '../../../utils/array'\nimport { initialUrlState } from '../store/initial-state'\nimport { urlXModule } from '../x-module'\n\ninterface ParsedUrlParams {\n all: UrlParams\n extra: Dictionary<unknown>\n}\n\n/**\n * This component manages the browser URL parameters to preserve them through reloads and browser\n * history navigation. It allow to configure the default url parameter names using its attributes.\n * This component doesn't render elements to the DOM.\n *\n * @public\n */\nexport default defineComponent({\n name: 'UrlHandler',\n components: {\n GlobalEvents,\n },\n xModule: urlXModule.name,\n setup(_, { attrs }) {\n const $x = use$x()\n\n const { initialExtraParams } = useState('url')\n\n /**\n * The {@link SnippetConfig} provided by an ancestor.\n *\n * @internal\n */\n const snippetConfig = inject<SnippetConfig | undefined>('snippetConfig')\n\n /**\n * Flag to know if the params were already loaded from the URL.\n *\n * @internal\n */\n const urlLoaded = ref(false)\n\n /**\n * The page URL. It is used to compare against the current URL to check navigation state.\n *\n * @internal\n */\n const url = ref<URL | undefined>(undefined)\n\n /**\n * Flag to know if the page has been persisted by the browser's back-forward cache.\n *\n * @internal\n */\n const isPagePersisted = ref(false)\n\n /**\n * Computed to know which params we must get from URL. It gets the params names from the initial\n * state, to get all default params names, and also from the `$attrs` to get the extra params\n * names to take into account.\n *\n * @returns An array with the name of the params.\n *\n * @internal\n */\n const managedParamsNames = computed(() => Object.keys({ ...initialUrlState, ...attrs }))\n\n /**\n * Returns the mapping of the param keys used in the URL is configured through $attrs. This way\n * we can support any param and extra param, no matters its name.\n *\n * @param paramName - The param name to get the Url key.\n * @returns The key used in the URL for the `paramName` passed.\n *\n * @internal\n */\n const getUrlKey = (paramName: string) => {\n const paramValue = attrs[paramName]\n return typeof paramValue === 'string' ? paramValue : paramName\n }\n\n /**\n * Deletes all the parameters in the passed URL.\n *\n * @param url - The URL to remove parameters from.\n * @internal\n */\n const deleteUrlParameters = (url: URL) => {\n managedParamsNames.value.forEach(paramName => url.searchParams.delete(getUrlKey(paramName)))\n }\n\n /**\n * Sorts the params in a tuple array [key,value] to generate always the same URL with the params\n * in the same order.\n *\n * @param urlParams - The {@link UrlParams} to sort.\n * @returns An array of tuples with the key-value of each paramter, sorted by key.\n * @internal\n */\n const sortParams = (urlParams: UrlParams): Array<[string, unknown]> => {\n return Object.entries(urlParams).sort(([param1], [param2]) => {\n return param1 < param2 ? -1 : 1\n })\n }\n\n /**\n * Set all the provided parameters to the url with the mapped key.\n *\n * @param url - The current URL.\n * @param urlParams - The list of parameters to add.\n * @remarks The params are filtered because there maybe received extra params which will not be\n * managed by URL. This is defined by the `managedParamsNames` computed. Also, the parameters\n * are sorted Alphabetically to produce always the same URL with the same parameters.This is\n * important for SEO purposes.\n *\n * @internal\n */\n const setUrlParameters = (url: URL, urlParams: UrlParams): void => {\n // Only when there is a query the rest of the parameters are valid.\n if (!urlParams.query) {\n return\n }\n const filteredParams = objectFilter(urlParams, paramName =>\n managedParamsNames.value.includes(paramName as string),\n )\n const sortedParameters = sortParams(filteredParams)\n sortedParameters.forEach(([paramName, paramValue]) => {\n const urlParamKey = getUrlKey(paramName)\n if (Array.isArray(paramValue)) {\n paramValue.forEach(value => {\n url.searchParams.append(urlParamKey, String(value))\n })\n } else {\n url.searchParams.set(urlParamKey, String(paramValue))\n }\n })\n }\n\n /**\n * Updates the browser URL with the passed `newUrlParams` and using the browser history method\n * passed as `historyMethod`. It only updates the browser history if the new URL is different\n * from the current.\n *\n * @param newUrlParams - The new params to add to the browser URL.\n * @param historyMethod - The browser history method used to add the new URL.\n *\n * @internal\n */\n const updateUrl = (\n newUrlParams: UrlParams,\n historyMethod: History['pushState'] | History['replaceState'],\n ): void => {\n if (urlLoaded.value) {\n const newUrl = new URL(window.location.href)\n deleteUrlParameters(newUrl)\n setUrlParameters(newUrl, newUrlParams)\n\n // Normalize '+' characters into '%20' for spaces in url params.\n newUrl.search = newUrl.search.replace(/\\+/g, '%20')\n\n if (newUrl.href !== window.location.href) {\n historyMethod({ ...window.history.state }, document.title, newUrl.href)\n }\n url.value = newUrl\n }\n }\n\n /**\n * Updates the browser URL with the new {@link UrlParams} using the history `pushState` method.\n *\n * @param newUrlParams - The new params to update browser URL.\n */\n $x.on('PushableUrlStateUpdated', false).subscribe((newUrlParams: UrlParams) => {\n updateUrl(newUrlParams, window.history.pushState.bind(window.history))\n })\n\n /**\n * Updates the browser URL with the new {@link UrlParams} using the history `replaceState`\n * method.\n *\n * @param newUrlParams - The new params to update browser URL.\n */\n $x.on('ReplaceableUrlStateUpdated', false).subscribe((newUrlParams: UrlParams) => {\n updateUrl(newUrlParams, window.history.replaceState.bind(window.history))\n })\n\n /**\n * Handler of the\n * [pageshow](https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event)\n * event.\n *\n * @remarks The pageshow event is listened to check if the browser has performed a navigation\n * using the back-forward cache. This information is available in the\n * PageTransitionEvent.persisted property.\n *\n * @param event - The page transition event.\n * @internal\n */\n const onPageShow = (event: PageTransitionEvent) => {\n isPagePersisted.value = event.persisted\n if (event.persisted) {\n // The internal url is reset due to the back-forward cache storing the previous value which\n // is no longer valid.\n url.value = undefined\n }\n }\n\n /**\n * Returns the URL param value parsed depending on its type in the initial store state. As we\n * can not know what type can have an extra param, all extra params are parsed as strings. We\n * know if it is an extra param because it is not in the initial state.\n *\n * @param name - The name of the param in {@link UrlParams}.\n * @param value - The `URLSearchParams` value as an arry of strings.\n * @returns The parsed value.\n *\n * @internal\n */\n const parseUrlParam = (name: string, value: string[]): UrlParamValue => {\n switch (typeof initialUrlState[name]) {\n case 'number':\n return Number(value[0])\n case 'boolean':\n return value[0].toLowerCase() === 'true'\n case 'string':\n return value[0]\n default:\n // array\n return value\n }\n }\n\n /**\n * Gets the {@link UrlParams} from the URL, including only the params defined by `paramsNames`.\n *\n * @returns ParsedUrlParams obtained from URL.\n * @internal\n */\n const parseUrlParams = (): ParsedUrlParams => {\n const urlSearchParams = new URL(window.location.href).searchParams\n return managedParamsNames.value.reduce<ParsedUrlParams>(\n (params, name) => {\n const urlKey = getUrlKey(name)\n if (urlSearchParams.has(urlKey)) {\n if (name in initialUrlState) {\n const urlValue = urlSearchParams.getAll(urlKey)\n params.all[name] = parseUrlParam(name, urlValue)\n } else {\n params.all[name] = params.extra[name] = urlSearchParams.get(urlKey)\n }\n }\n return params\n },\n { all: { ...initialUrlState }, extra: { ...initialExtraParams.value } },\n )\n }\n\n /**\n * Check if the navigation is from a product page.\n *\n * @remarks Due to Safari 14 not supporting the new and standard PerformanceNavigationTiming\n * API, we are falling back to the deprecated one, PerformanceNavigation. We also fallback to\n * this API whenever we get a navigationType equal to reload, because Safari has a bug that the\n * navigationType is permanently set to reload after you have reload the page and it never\n * resets. As some browsers have a back-forward cache implemented, we also take into account if\n * the page is persisted.\n *\n * @returns True if the navigation is from a product page, false otherwise.\n * @internal\n */\n const isNavigatingFromPdp = (): boolean => {\n const isPagePersistedValue = isPagePersisted.value\n const navigationEntries = window.performance.getEntriesByType('navigation')\n const navigationType = (navigationEntries[0] as PerformanceNavigationTiming)?.type\n const useFallbackStrategy =\n !navigationEntries.length &&\n (isArrayEmpty(navigationEntries) || navigationType === 'reload')\n\n // Reset internal isPagePersisted property value\n isPagePersisted.value = false\n\n if (useFallbackStrategy) {\n const isNavigatingInSpa = !!snippetConfig?.isSpa && navigationType === 'navigate'\n return navigationType === 'back_forward' || isNavigatingInSpa || isPagePersistedValue\n } else {\n const isNavigatingInSpa = !!snippetConfig?.isSpa && navigationType === 'navigate'\n return navigationType === 'back_forward' || isNavigatingInSpa || isPagePersistedValue\n }\n }\n\n /**\n * Detects the {@link FeatureLocation} used to build the\n * {@link QueryOriginInit} data.\n *\n * @returns The {@link FeatureLocation}.\n * @internal\n */\n const detectLocation = (): FeatureLocation => {\n const currentUrl = new URL(window.location.href)\n const previousUrl = url.value\n url.value = currentUrl\n\n const isInternalNavigation =\n previousUrl?.search !== currentUrl.search && previousUrl?.pathname === currentUrl.pathname\n if (isInternalNavigation) {\n return 'url_history'\n }\n\n if (isNavigatingFromPdp()) {\n return 'url_history_pdp'\n }\n\n return 'external'\n }\n\n /**\n * Creates the wire metadata to include in every emitted {@link XEvent}.\n *\n * @returns The {@link WireMetadata}.\n * @internal\n */\n const createWireMetadata = (): Pick<WireMetadata, 'feature' | 'location'> => {\n return {\n feature: 'url',\n location: detectLocation(),\n }\n }\n\n /**\n * Emits the {@link UrlXEvents.ParamsLoadedFromUrl} XEvent,\n * the {@link UrlXEvents.ExtraParamsLoadedFromUrl} XEvent and, if there is query, also emits\n * the {@link XEventsTypes.UserOpenXProgrammatically}.\n *\n * @internal\n */\n const emitEvents = () => {\n const { all, extra } = parseUrlParams()\n const metadata = createWireMetadata()\n $x.emit('ParamsLoadedFromUrl', all, metadata)\n $x.emit('ExtraParamsLoadedFromUrl', extra, metadata)\n if (all.query) {\n $x.emit('UserOpenXProgrammatically', undefined, metadata)\n }\n urlLoaded.value = true\n }\n\n /**\n * To emit the Url events just when the URL is load, and before the components mounted events\n * and state changes, we do it in the created of this component.\n */\n onMounted(() => {\n emitEvents()\n })\n\n return {\n onPageShow,\n emitEvents,\n }\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits the following events:\n\n- [`ParamsLoadedFromUrl`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`ExtraParamsLoadedFromUrl`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserOpenXProgrammatically`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n\n## See it in action\n\nThis component manages the browser URL parameters to preserve them through reloads and browser\nhistory navigation. It allow to configure the default url parameter names using its attributes. This\ncomponent doesn't render elements to the DOM.\n\n_Try to make some requests and take a look to the url!_\n\n```vue\n<template>\n <UrlHandler />\n</template>\n\n<script>\nimport { UrlHandler } from '@empathyco/x-components/url-handler'\n\nexport default {\n name: 'UrlHandlerDemo',\n components: {\n UrlHandler,\n },\n}\n</script>\n```\n\n### Play with props\n\nIn this example, the `UrlHandler` component changes the following query parameter names:\n\n- `query` to be `q`.\n- `page` to be `p`.\n- `filter` to be `f`\n- `sort` to be `s`\n\n_Try to make some requests and take a look to the url!_\n\n```vue\n<template>\n <UrlHandler query=\"q\" page=\"p\" filter=\"f\" sort=\"s\" />\n</template>\n\n<script>\nimport { UrlHandler } from '@empathyco/x-components/url-handler'\n\nexport default {\n name: 'UrlHandlerDemo',\n components: {\n UrlHandler,\n },\n}\n</script>\n```\n\n### Play with events\n\nThe `UrlHandler` will emit the `ParamsLoadedFromUrl` when the page is loaded.\n\nThe `UrlHandler` will emit the `ExtraParamsLoadedFromUrl` when the page is loaded with an extra\nparam configured and with a value in URL.\n\nThe `UrlHandler` will emit the `UserOpenXProgrammatically` when the page is loaded with a query in\nthe URL.\n</docs>\n"],"names":["_resolveComponent","_openBlock","_createBlock"],"mappings":";;;;;kCACEA,gBAA8E,CAAA,cAAA,CAAA,CAAA;AAA/C,EAAA,OAAAC,SAAA,EAAoB,EAAAC,WAAA,CAAA,uBAAA,EAAA;AAAA,IAAG,MAAA,EAAA,QAAA;AAAA,IAAA,UAAA,EAAA,IAAA,CAAA,UAAA;;;;;;;;"}
@@ -22,7 +22,7 @@ var _sfc_main = defineComponent({
22
22
  xModule: urlXModule.name,
23
23
  setup(_, { attrs }) {
24
24
  const $x = use$x();
25
- const initialExtraParams = useState('url', ['initialExtraParams']).initialExtraParams;
25
+ const { initialExtraParams } = useState('url');
26
26
  /**
27
27
  * The {@link SnippetConfig} provided by an ancestor.
28
28
  *
@@ -1 +1 @@
1
- {"version":3,"file":"url-handler.vue2.js","sources":["../../../../../src/x-modules/url/components/url-handler.vue"],"sourcesContent":["<template>\n <GlobalEvents target=\"window\" @pageshow=\"onPageShow\" @popstate=\"emitEvents\" />\n</template>\n\n<script lang=\"ts\">\nimport type { Dictionary } from '@empathyco/x-utils'\nimport type { FeatureLocation } from '../../../types/origin'\nimport type { UrlParams } from '../../../types/url-params'\nimport type { WireMetadata } from '../../../wiring/wiring.types'\nimport type { SnippetConfig } from '../../../x-installer/api/api.types'\nimport type { UrlParamValue } from '../store/types'\nimport { objectFilter } from '@empathyco/x-utils'\nimport { computed, defineComponent, inject, onMounted, ref } from 'vue'\nimport { GlobalEvents } from 'vue-global-events'\nimport { use$x } from '../../../composables/use-$x'\nimport { useState } from '../../../composables/use-state'\nimport { isArrayEmpty } from '../../../utils/array'\nimport { initialUrlState } from '../store/initial-state'\nimport { urlXModule } from '../x-module'\n\ninterface ParsedUrlParams {\n all: UrlParams\n extra: Dictionary<unknown>\n}\n\n/**\n * This component manages the browser URL parameters to preserve them through reloads and browser\n * history navigation. It allow to configure the default url parameter names using its attributes.\n * This component doesn't render elements to the DOM.\n *\n * @public\n */\nexport default defineComponent({\n name: 'UrlHandler',\n components: {\n GlobalEvents,\n },\n xModule: urlXModule.name,\n setup(_, { attrs }) {\n const $x = use$x()\n\n const initialExtraParams = useState('url', ['initialExtraParams']).initialExtraParams\n\n /**\n * The {@link SnippetConfig} provided by an ancestor.\n *\n * @internal\n */\n const snippetConfig = inject<SnippetConfig | undefined>('snippetConfig')\n\n /**\n * Flag to know if the params were already loaded from the URL.\n *\n * @internal\n */\n const urlLoaded = ref(false)\n\n /**\n * The page URL. It is used to compare against the current URL to check navigation state.\n *\n * @internal\n */\n const url = ref<URL | undefined>(undefined)\n\n /**\n * Flag to know if the page has been persisted by the browser's back-forward cache.\n *\n * @internal\n */\n const isPagePersisted = ref(false)\n\n /**\n * Computed to know which params we must get from URL. It gets the params names from the initial\n * state, to get all default params names, and also from the `$attrs` to get the extra params\n * names to take into account.\n *\n * @returns An array with the name of the params.\n *\n * @internal\n */\n const managedParamsNames = computed(() => Object.keys({ ...initialUrlState, ...attrs }))\n\n /**\n * Returns the mapping of the param keys used in the URL is configured through $attrs. This way\n * we can support any param and extra param, no matters its name.\n *\n * @param paramName - The param name to get the Url key.\n * @returns The key used in the URL for the `paramName` passed.\n *\n * @internal\n */\n const getUrlKey = (paramName: string) => {\n const paramValue = attrs[paramName]\n return typeof paramValue === 'string' ? paramValue : paramName\n }\n\n /**\n * Deletes all the parameters in the passed URL.\n *\n * @param url - The URL to remove parameters from.\n * @internal\n */\n const deleteUrlParameters = (url: URL) => {\n managedParamsNames.value.forEach(paramName => url.searchParams.delete(getUrlKey(paramName)))\n }\n\n /**\n * Sorts the params in a tuple array [key,value] to generate always the same URL with the params\n * in the same order.\n *\n * @param urlParams - The {@link UrlParams} to sort.\n * @returns An array of tuples with the key-value of each paramter, sorted by key.\n * @internal\n */\n const sortParams = (urlParams: UrlParams): Array<[string, unknown]> => {\n return Object.entries(urlParams).sort(([param1], [param2]) => {\n return param1 < param2 ? -1 : 1\n })\n }\n\n /**\n * Set all the provided parameters to the url with the mapped key.\n *\n * @param url - The current URL.\n * @param urlParams - The list of parameters to add.\n * @remarks The params are filtered because there maybe received extra params which will not be\n * managed by URL. This is defined by the `managedParamsNames` computed. Also, the parameters\n * are sorted Alphabetically to produce always the same URL with the same parameters.This is\n * important for SEO purposes.\n *\n * @internal\n */\n const setUrlParameters = (url: URL, urlParams: UrlParams): void => {\n // Only when there is a query the rest of the parameters are valid.\n if (!urlParams.query) {\n return\n }\n const filteredParams = objectFilter(urlParams, paramName =>\n managedParamsNames.value.includes(paramName as string),\n )\n const sortedParameters = sortParams(filteredParams)\n sortedParameters.forEach(([paramName, paramValue]) => {\n const urlParamKey = getUrlKey(paramName)\n if (Array.isArray(paramValue)) {\n paramValue.forEach(value => {\n url.searchParams.append(urlParamKey, String(value))\n })\n } else {\n url.searchParams.set(urlParamKey, String(paramValue))\n }\n })\n }\n\n /**\n * Updates the browser URL with the passed `newUrlParams` and using the browser history method\n * passed as `historyMethod`. It only updates the browser history if the new URL is different\n * from the current.\n *\n * @param newUrlParams - The new params to add to the browser URL.\n * @param historyMethod - The browser history method used to add the new URL.\n *\n * @internal\n */\n const updateUrl = (\n newUrlParams: UrlParams,\n historyMethod: History['pushState'] | History['replaceState'],\n ): void => {\n if (urlLoaded.value) {\n const newUrl = new URL(window.location.href)\n deleteUrlParameters(newUrl)\n setUrlParameters(newUrl, newUrlParams)\n\n // Normalize '+' characters into '%20' for spaces in url params.\n newUrl.search = newUrl.search.replace(/\\+/g, '%20')\n\n if (newUrl.href !== window.location.href) {\n historyMethod({ ...window.history.state }, document.title, newUrl.href)\n }\n url.value = newUrl\n }\n }\n\n /**\n * Updates the browser URL with the new {@link UrlParams} using the history `pushState` method.\n *\n * @param newUrlParams - The new params to update browser URL.\n */\n $x.on('PushableUrlStateUpdated', false).subscribe((newUrlParams: UrlParams) => {\n updateUrl(newUrlParams, window.history.pushState.bind(window.history))\n })\n\n /**\n * Updates the browser URL with the new {@link UrlParams} using the history `replaceState`\n * method.\n *\n * @param newUrlParams - The new params to update browser URL.\n */\n $x.on('ReplaceableUrlStateUpdated', false).subscribe((newUrlParams: UrlParams) => {\n updateUrl(newUrlParams, window.history.replaceState.bind(window.history))\n })\n\n /**\n * Handler of the\n * [pageshow](https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event)\n * event.\n *\n * @remarks The pageshow event is listened to check if the browser has performed a navigation\n * using the back-forward cache. This information is available in the\n * PageTransitionEvent.persisted property.\n *\n * @param event - The page transition event.\n * @internal\n */\n const onPageShow = (event: PageTransitionEvent) => {\n isPagePersisted.value = event.persisted\n if (event.persisted) {\n // The internal url is reset due to the back-forward cache storing the previous value which\n // is no longer valid.\n url.value = undefined\n }\n }\n\n /**\n * Returns the URL param value parsed depending on its type in the initial store state. As we\n * can not know what type can have an extra param, all extra params are parsed as strings. We\n * know if it is an extra param because it is not in the initial state.\n *\n * @param name - The name of the param in {@link UrlParams}.\n * @param value - The `URLSearchParams` value as an arry of strings.\n * @returns The parsed value.\n *\n * @internal\n */\n const parseUrlParam = (name: string, value: string[]): UrlParamValue => {\n switch (typeof initialUrlState[name]) {\n case 'number':\n return Number(value[0])\n case 'boolean':\n return value[0].toLowerCase() === 'true'\n case 'string':\n return value[0]\n default:\n // array\n return value\n }\n }\n\n /**\n * Gets the {@link UrlParams} from the URL, including only the params defined by `paramsNames`.\n *\n * @returns ParsedUrlParams obtained from URL.\n * @internal\n */\n const parseUrlParams = (): ParsedUrlParams => {\n const urlSearchParams = new URL(window.location.href).searchParams\n return managedParamsNames.value.reduce<ParsedUrlParams>(\n (params, name) => {\n const urlKey = getUrlKey(name)\n if (urlSearchParams.has(urlKey)) {\n if (name in initialUrlState) {\n const urlValue = urlSearchParams.getAll(urlKey)\n params.all[name] = parseUrlParam(name, urlValue)\n } else {\n params.all[name] = params.extra[name] = urlSearchParams.get(urlKey)\n }\n }\n return params\n },\n { all: { ...initialUrlState }, extra: { ...initialExtraParams.value } },\n )\n }\n\n /**\n * Check if the navigation is from a product page.\n *\n * @remarks Due to Safari 14 not supporting the new and standard PerformanceNavigationTiming\n * API, we are falling back to the deprecated one, PerformanceNavigation. We also fallback to\n * this API whenever we get a navigationType equal to reload, because Safari has a bug that the\n * navigationType is permanently set to reload after you have reload the page and it never\n * resets. As some browsers have a back-forward cache implemented, we also take into account if\n * the page is persisted.\n *\n * @returns True if the navigation is from a product page, false otherwise.\n * @internal\n */\n const isNavigatingFromPdp = (): boolean => {\n const isPagePersistedValue = isPagePersisted.value\n const navigationEntries = window.performance.getEntriesByType('navigation')\n const navigationType = (navigationEntries[0] as PerformanceNavigationTiming)?.type\n const useFallbackStrategy =\n !navigationEntries.length &&\n (isArrayEmpty(navigationEntries) || navigationType === 'reload')\n\n // Reset internal isPagePersisted property value\n isPagePersisted.value = false\n\n if (useFallbackStrategy) {\n const isNavigatingInSpa = !!snippetConfig?.isSpa && navigationType === 'navigate'\n return navigationType === 'back_forward' || isNavigatingInSpa || isPagePersistedValue\n } else {\n const isNavigatingInSpa = !!snippetConfig?.isSpa && navigationType === 'navigate'\n return navigationType === 'back_forward' || isNavigatingInSpa || isPagePersistedValue\n }\n }\n\n /**\n * Detects the {@link FeatureLocation} used to build the\n * {@link QueryOriginInit} data.\n *\n * @returns The {@link FeatureLocation}.\n * @internal\n */\n const detectLocation = (): FeatureLocation => {\n const currentUrl = new URL(window.location.href)\n const previousUrl = url.value\n url.value = currentUrl\n\n const isInternalNavigation =\n previousUrl?.search !== currentUrl.search && previousUrl?.pathname === currentUrl.pathname\n if (isInternalNavigation) {\n return 'url_history'\n }\n\n if (isNavigatingFromPdp()) {\n return 'url_history_pdp'\n }\n\n return 'external'\n }\n\n /**\n * Creates the wire metadata to include in every emitted {@link XEvent}.\n *\n * @returns The {@link WireMetadata}.\n * @internal\n */\n const createWireMetadata = (): Pick<WireMetadata, 'feature' | 'location'> => {\n return {\n feature: 'url',\n location: detectLocation(),\n }\n }\n\n /**\n * Emits the {@link UrlXEvents.ParamsLoadedFromUrl} XEvent,\n * the {@link UrlXEvents.ExtraParamsLoadedFromUrl} XEvent and, if there is query, also emits\n * the {@link XEventsTypes.UserOpenXProgrammatically}.\n *\n * @internal\n */\n const emitEvents = () => {\n const { all, extra } = parseUrlParams()\n const metadata = createWireMetadata()\n $x.emit('ParamsLoadedFromUrl', all, metadata)\n $x.emit('ExtraParamsLoadedFromUrl', extra, metadata)\n if (all.query) {\n $x.emit('UserOpenXProgrammatically', undefined, metadata)\n }\n urlLoaded.value = true\n }\n\n /**\n * To emit the Url events just when the URL is load, and before the components mounted events\n * and state changes, we do it in the created of this component.\n */\n onMounted(() => {\n emitEvents()\n })\n\n return {\n onPageShow,\n emitEvents,\n }\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits the following events:\n\n- [`ParamsLoadedFromUrl`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`ExtraParamsLoadedFromUrl`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserOpenXProgrammatically`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n\n## See it in action\n\nThis component manages the browser URL parameters to preserve them through reloads and browser\nhistory navigation. It allow to configure the default url parameter names using its attributes. This\ncomponent doesn't render elements to the DOM.\n\n_Try to make some requests and take a look to the url!_\n\n```vue\n<template>\n <UrlHandler />\n</template>\n\n<script>\nimport { UrlHandler } from '@empathyco/x-components/url-handler'\n\nexport default {\n name: 'UrlHandlerDemo',\n components: {\n UrlHandler,\n },\n}\n</script>\n```\n\n### Play with props\n\nIn this example, the `UrlHandler` component changes the following query parameter names:\n\n- `query` to be `q`.\n- `page` to be `p`.\n- `filter` to be `f`\n- `sort` to be `s`\n\n_Try to make some requests and take a look to the url!_\n\n```vue\n<template>\n <UrlHandler query=\"q\" page=\"p\" filter=\"f\" sort=\"s\" />\n</template>\n\n<script>\nimport { UrlHandler } from '@empathyco/x-components/url-handler'\n\nexport default {\n name: 'UrlHandlerDemo',\n components: {\n UrlHandler,\n },\n}\n</script>\n```\n\n### Play with events\n\nThe `UrlHandler` will emit the `ParamsLoadedFromUrl` when the page is loaded.\n\nThe `UrlHandler` will emit the `ExtraParamsLoadedFromUrl` when the page is loaded with an extra\nparam configured and with a value in URL.\n\nThe `UrlHandler` will emit the `UserOpenXProgrammatically` when the page is loaded with a query in\nthe URL.\n</docs>\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"url-handler.vue2.js","sources":["../../../../../src/x-modules/url/components/url-handler.vue"],"sourcesContent":["<template>\n <GlobalEvents target=\"window\" @pageshow=\"onPageShow\" @popstate=\"emitEvents\" />\n</template>\n\n<script lang=\"ts\">\nimport type { Dictionary } from '@empathyco/x-utils'\nimport type { FeatureLocation } from '../../../types/origin'\nimport type { UrlParams } from '../../../types/url-params'\nimport type { WireMetadata } from '../../../wiring/wiring.types'\nimport type { SnippetConfig } from '../../../x-installer/api/api.types'\nimport type { UrlParamValue } from '../store/types'\nimport { objectFilter } from '@empathyco/x-utils'\nimport { computed, defineComponent, inject, onMounted, ref } from 'vue'\nimport { GlobalEvents } from 'vue-global-events'\nimport { use$x } from '../../../composables/use-$x'\nimport { useState } from '../../../composables/use-state'\nimport { isArrayEmpty } from '../../../utils/array'\nimport { initialUrlState } from '../store/initial-state'\nimport { urlXModule } from '../x-module'\n\ninterface ParsedUrlParams {\n all: UrlParams\n extra: Dictionary<unknown>\n}\n\n/**\n * This component manages the browser URL parameters to preserve them through reloads and browser\n * history navigation. It allow to configure the default url parameter names using its attributes.\n * This component doesn't render elements to the DOM.\n *\n * @public\n */\nexport default defineComponent({\n name: 'UrlHandler',\n components: {\n GlobalEvents,\n },\n xModule: urlXModule.name,\n setup(_, { attrs }) {\n const $x = use$x()\n\n const { initialExtraParams } = useState('url')\n\n /**\n * The {@link SnippetConfig} provided by an ancestor.\n *\n * @internal\n */\n const snippetConfig = inject<SnippetConfig | undefined>('snippetConfig')\n\n /**\n * Flag to know if the params were already loaded from the URL.\n *\n * @internal\n */\n const urlLoaded = ref(false)\n\n /**\n * The page URL. It is used to compare against the current URL to check navigation state.\n *\n * @internal\n */\n const url = ref<URL | undefined>(undefined)\n\n /**\n * Flag to know if the page has been persisted by the browser's back-forward cache.\n *\n * @internal\n */\n const isPagePersisted = ref(false)\n\n /**\n * Computed to know which params we must get from URL. It gets the params names from the initial\n * state, to get all default params names, and also from the `$attrs` to get the extra params\n * names to take into account.\n *\n * @returns An array with the name of the params.\n *\n * @internal\n */\n const managedParamsNames = computed(() => Object.keys({ ...initialUrlState, ...attrs }))\n\n /**\n * Returns the mapping of the param keys used in the URL is configured through $attrs. This way\n * we can support any param and extra param, no matters its name.\n *\n * @param paramName - The param name to get the Url key.\n * @returns The key used in the URL for the `paramName` passed.\n *\n * @internal\n */\n const getUrlKey = (paramName: string) => {\n const paramValue = attrs[paramName]\n return typeof paramValue === 'string' ? paramValue : paramName\n }\n\n /**\n * Deletes all the parameters in the passed URL.\n *\n * @param url - The URL to remove parameters from.\n * @internal\n */\n const deleteUrlParameters = (url: URL) => {\n managedParamsNames.value.forEach(paramName => url.searchParams.delete(getUrlKey(paramName)))\n }\n\n /**\n * Sorts the params in a tuple array [key,value] to generate always the same URL with the params\n * in the same order.\n *\n * @param urlParams - The {@link UrlParams} to sort.\n * @returns An array of tuples with the key-value of each paramter, sorted by key.\n * @internal\n */\n const sortParams = (urlParams: UrlParams): Array<[string, unknown]> => {\n return Object.entries(urlParams).sort(([param1], [param2]) => {\n return param1 < param2 ? -1 : 1\n })\n }\n\n /**\n * Set all the provided parameters to the url with the mapped key.\n *\n * @param url - The current URL.\n * @param urlParams - The list of parameters to add.\n * @remarks The params are filtered because there maybe received extra params which will not be\n * managed by URL. This is defined by the `managedParamsNames` computed. Also, the parameters\n * are sorted Alphabetically to produce always the same URL with the same parameters.This is\n * important for SEO purposes.\n *\n * @internal\n */\n const setUrlParameters = (url: URL, urlParams: UrlParams): void => {\n // Only when there is a query the rest of the parameters are valid.\n if (!urlParams.query) {\n return\n }\n const filteredParams = objectFilter(urlParams, paramName =>\n managedParamsNames.value.includes(paramName as string),\n )\n const sortedParameters = sortParams(filteredParams)\n sortedParameters.forEach(([paramName, paramValue]) => {\n const urlParamKey = getUrlKey(paramName)\n if (Array.isArray(paramValue)) {\n paramValue.forEach(value => {\n url.searchParams.append(urlParamKey, String(value))\n })\n } else {\n url.searchParams.set(urlParamKey, String(paramValue))\n }\n })\n }\n\n /**\n * Updates the browser URL with the passed `newUrlParams` and using the browser history method\n * passed as `historyMethod`. It only updates the browser history if the new URL is different\n * from the current.\n *\n * @param newUrlParams - The new params to add to the browser URL.\n * @param historyMethod - The browser history method used to add the new URL.\n *\n * @internal\n */\n const updateUrl = (\n newUrlParams: UrlParams,\n historyMethod: History['pushState'] | History['replaceState'],\n ): void => {\n if (urlLoaded.value) {\n const newUrl = new URL(window.location.href)\n deleteUrlParameters(newUrl)\n setUrlParameters(newUrl, newUrlParams)\n\n // Normalize '+' characters into '%20' for spaces in url params.\n newUrl.search = newUrl.search.replace(/\\+/g, '%20')\n\n if (newUrl.href !== window.location.href) {\n historyMethod({ ...window.history.state }, document.title, newUrl.href)\n }\n url.value = newUrl\n }\n }\n\n /**\n * Updates the browser URL with the new {@link UrlParams} using the history `pushState` method.\n *\n * @param newUrlParams - The new params to update browser URL.\n */\n $x.on('PushableUrlStateUpdated', false).subscribe((newUrlParams: UrlParams) => {\n updateUrl(newUrlParams, window.history.pushState.bind(window.history))\n })\n\n /**\n * Updates the browser URL with the new {@link UrlParams} using the history `replaceState`\n * method.\n *\n * @param newUrlParams - The new params to update browser URL.\n */\n $x.on('ReplaceableUrlStateUpdated', false).subscribe((newUrlParams: UrlParams) => {\n updateUrl(newUrlParams, window.history.replaceState.bind(window.history))\n })\n\n /**\n * Handler of the\n * [pageshow](https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event)\n * event.\n *\n * @remarks The pageshow event is listened to check if the browser has performed a navigation\n * using the back-forward cache. This information is available in the\n * PageTransitionEvent.persisted property.\n *\n * @param event - The page transition event.\n * @internal\n */\n const onPageShow = (event: PageTransitionEvent) => {\n isPagePersisted.value = event.persisted\n if (event.persisted) {\n // The internal url is reset due to the back-forward cache storing the previous value which\n // is no longer valid.\n url.value = undefined\n }\n }\n\n /**\n * Returns the URL param value parsed depending on its type in the initial store state. As we\n * can not know what type can have an extra param, all extra params are parsed as strings. We\n * know if it is an extra param because it is not in the initial state.\n *\n * @param name - The name of the param in {@link UrlParams}.\n * @param value - The `URLSearchParams` value as an arry of strings.\n * @returns The parsed value.\n *\n * @internal\n */\n const parseUrlParam = (name: string, value: string[]): UrlParamValue => {\n switch (typeof initialUrlState[name]) {\n case 'number':\n return Number(value[0])\n case 'boolean':\n return value[0].toLowerCase() === 'true'\n case 'string':\n return value[0]\n default:\n // array\n return value\n }\n }\n\n /**\n * Gets the {@link UrlParams} from the URL, including only the params defined by `paramsNames`.\n *\n * @returns ParsedUrlParams obtained from URL.\n * @internal\n */\n const parseUrlParams = (): ParsedUrlParams => {\n const urlSearchParams = new URL(window.location.href).searchParams\n return managedParamsNames.value.reduce<ParsedUrlParams>(\n (params, name) => {\n const urlKey = getUrlKey(name)\n if (urlSearchParams.has(urlKey)) {\n if (name in initialUrlState) {\n const urlValue = urlSearchParams.getAll(urlKey)\n params.all[name] = parseUrlParam(name, urlValue)\n } else {\n params.all[name] = params.extra[name] = urlSearchParams.get(urlKey)\n }\n }\n return params\n },\n { all: { ...initialUrlState }, extra: { ...initialExtraParams.value } },\n )\n }\n\n /**\n * Check if the navigation is from a product page.\n *\n * @remarks Due to Safari 14 not supporting the new and standard PerformanceNavigationTiming\n * API, we are falling back to the deprecated one, PerformanceNavigation. We also fallback to\n * this API whenever we get a navigationType equal to reload, because Safari has a bug that the\n * navigationType is permanently set to reload after you have reload the page and it never\n * resets. As some browsers have a back-forward cache implemented, we also take into account if\n * the page is persisted.\n *\n * @returns True if the navigation is from a product page, false otherwise.\n * @internal\n */\n const isNavigatingFromPdp = (): boolean => {\n const isPagePersistedValue = isPagePersisted.value\n const navigationEntries = window.performance.getEntriesByType('navigation')\n const navigationType = (navigationEntries[0] as PerformanceNavigationTiming)?.type\n const useFallbackStrategy =\n !navigationEntries.length &&\n (isArrayEmpty(navigationEntries) || navigationType === 'reload')\n\n // Reset internal isPagePersisted property value\n isPagePersisted.value = false\n\n if (useFallbackStrategy) {\n const isNavigatingInSpa = !!snippetConfig?.isSpa && navigationType === 'navigate'\n return navigationType === 'back_forward' || isNavigatingInSpa || isPagePersistedValue\n } else {\n const isNavigatingInSpa = !!snippetConfig?.isSpa && navigationType === 'navigate'\n return navigationType === 'back_forward' || isNavigatingInSpa || isPagePersistedValue\n }\n }\n\n /**\n * Detects the {@link FeatureLocation} used to build the\n * {@link QueryOriginInit} data.\n *\n * @returns The {@link FeatureLocation}.\n * @internal\n */\n const detectLocation = (): FeatureLocation => {\n const currentUrl = new URL(window.location.href)\n const previousUrl = url.value\n url.value = currentUrl\n\n const isInternalNavigation =\n previousUrl?.search !== currentUrl.search && previousUrl?.pathname === currentUrl.pathname\n if (isInternalNavigation) {\n return 'url_history'\n }\n\n if (isNavigatingFromPdp()) {\n return 'url_history_pdp'\n }\n\n return 'external'\n }\n\n /**\n * Creates the wire metadata to include in every emitted {@link XEvent}.\n *\n * @returns The {@link WireMetadata}.\n * @internal\n */\n const createWireMetadata = (): Pick<WireMetadata, 'feature' | 'location'> => {\n return {\n feature: 'url',\n location: detectLocation(),\n }\n }\n\n /**\n * Emits the {@link UrlXEvents.ParamsLoadedFromUrl} XEvent,\n * the {@link UrlXEvents.ExtraParamsLoadedFromUrl} XEvent and, if there is query, also emits\n * the {@link XEventsTypes.UserOpenXProgrammatically}.\n *\n * @internal\n */\n const emitEvents = () => {\n const { all, extra } = parseUrlParams()\n const metadata = createWireMetadata()\n $x.emit('ParamsLoadedFromUrl', all, metadata)\n $x.emit('ExtraParamsLoadedFromUrl', extra, metadata)\n if (all.query) {\n $x.emit('UserOpenXProgrammatically', undefined, metadata)\n }\n urlLoaded.value = true\n }\n\n /**\n * To emit the Url events just when the URL is load, and before the components mounted events\n * and state changes, we do it in the created of this component.\n */\n onMounted(() => {\n emitEvents()\n })\n\n return {\n onPageShow,\n emitEvents,\n }\n },\n})\n</script>\n\n<docs lang=\"mdx\">\n## Events\n\nThis component emits the following events:\n\n- [`ParamsLoadedFromUrl`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`ExtraParamsLoadedFromUrl`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n- [`UserOpenXProgrammatically`](https://github.com/empathyco/x/blob/main/packages/x-components/src/wiring/events.types.ts)\n\n## See it in action\n\nThis component manages the browser URL parameters to preserve them through reloads and browser\nhistory navigation. It allow to configure the default url parameter names using its attributes. This\ncomponent doesn't render elements to the DOM.\n\n_Try to make some requests and take a look to the url!_\n\n```vue\n<template>\n <UrlHandler />\n</template>\n\n<script>\nimport { UrlHandler } from '@empathyco/x-components/url-handler'\n\nexport default {\n name: 'UrlHandlerDemo',\n components: {\n UrlHandler,\n },\n}\n</script>\n```\n\n### Play with props\n\nIn this example, the `UrlHandler` component changes the following query parameter names:\n\n- `query` to be `q`.\n- `page` to be `p`.\n- `filter` to be `f`\n- `sort` to be `s`\n\n_Try to make some requests and take a look to the url!_\n\n```vue\n<template>\n <UrlHandler query=\"q\" page=\"p\" filter=\"f\" sort=\"s\" />\n</template>\n\n<script>\nimport { UrlHandler } from '@empathyco/x-components/url-handler'\n\nexport default {\n name: 'UrlHandlerDemo',\n components: {\n UrlHandler,\n },\n}\n</script>\n```\n\n### Play with events\n\nThe `UrlHandler` will emit the `ParamsLoadedFromUrl` when the page is loaded.\n\nThe `UrlHandler` will emit the `ExtraParamsLoadedFromUrl` when the page is loaded with an extra\nparam configured and with a value in URL.\n\nThe `UrlHandler` will emit the `UserOpenXProgrammatically` when the page is loaded with a query in\nthe URL.\n</docs>\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empathyco/x-components",
3
- "version": "6.0.0-alpha.62",
3
+ "version": "6.0.0-alpha.64",
4
4
  "description": "Empathy X Components",
5
5
  "author": "Empathy Systems Corporation S.L.",
6
6
  "license": "Apache-2.0",
@@ -96,7 +96,7 @@
96
96
  "devDependencies": {
97
97
  "@badeball/cypress-cucumber-preprocessor": "20.0.0",
98
98
  "@bahmutov/cypress-esbuild-preprocessor": "2.2.0",
99
- "@empathyco/x-tailwindcss": "^2.0.0-alpha.5",
99
+ "@empathyco/x-tailwindcss": "^2.0.0-alpha.6",
100
100
  "@microsoft/api-documenter": "7.23.0",
101
101
  "@microsoft/api-extractor": "7.39.0",
102
102
  "@testing-library/jest-dom": "5.17.0",
@@ -143,5 +143,5 @@
143
143
  "access": "public",
144
144
  "directory": "dist"
145
145
  },
146
- "gitHead": "2dee976ba7a42a12e786176f541899185d852c5a"
146
+ "gitHead": "84cea6597debb2a592031755820de29054ae8fcc"
147
147
  }
@@ -1169,7 +1169,7 @@
1169
1169
  {
1170
1170
  "kind": "Variable",
1171
1171
  "canonicalReference": "@empathyco/x-adapter-platform!nextQueriesRelatedPromptsSchema:var",
1172
- "docComment": "",
1172
+ "docComment": "/**\n * Default implementation for the NextQueriesRelatedPromptsSchema.\n *\n * @public\n */\n",
1173
1173
  "excerptTokens": [
1174
1174
  {
1175
1175
  "kind": "Content",
@@ -7517,7 +7517,7 @@
7517
7517
  {
7518
7518
  "kind": "Variable",
7519
7519
  "canonicalReference": "@empathyco/x-adapter-platform!taggingRequestMapper:var",
7520
- "docComment": "/**\n * Default implementation for the TaggingRequestMapper.\n *\n * @param params - The tagging request params.\n *\n * @returns The tagging request params.\n *\n * @public\n */\n",
7520
+ "docComment": "/**\n * Default implementation for the TaggingRequestMapper.\n *\n * @param params - The tagging request params.\n *\n * @param - params.params - The tagging request params.\n *\n * @returns The tagging request params.\n *\n * @public\n */\n",
7521
7521
  "excerptTokens": [
7522
7522
  {
7523
7523
  "kind": "Content",