@empathyco/x-components 3.0.0-alpha.319 → 3.0.0-alpha.320
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/design-system/default-theme.css +2 -2
- package/design-system/deprecated-full-theme.css +43 -43
- package/design-system/full-theme.css +2 -2
- package/design-system/tag-default.css +2 -2
- package/js/components/modals/base-modal.vue.js +1 -1
- package/js/components/modals/base-modal.vue.js.map +1 -1
- package/js/components/modals/base-modal.vue_rollup-plugin-vue_script.vue.js +11 -4
- package/js/components/modals/base-modal.vue_rollup-plugin-vue_script.vue.js.map +1 -1
- package/js/components/modals/base-modal.vue_rollup-plugin-vue_styles.0.vue.js +1 -1
- package/js/x-modules/search-box/components/search-input-placeholder.vue.js +1 -1
- package/js/x-modules/search-box/components/search-input-placeholder.vue.js.map +1 -1
- package/js/x-modules/search-box/components/search-input-placeholder.vue_rollup-plugin-vue_styles.1.vue.js +1 -1
- package/package.json +2 -2
- package/types/components/modals/base-modal.vue.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See
|
|
4
4
|
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [3.0.0-alpha.320](https://github.com/empathyco/x/compare/@empathyco/x-components@3.0.0-alpha.319...@empathyco/x-components@3.0.0-alpha.320) (2023-02-28)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- **components:** Fix open issue when focused on body. Fix `SearchInputPlaceholder` styles. (#1078)
|
|
11
|
+
([25aa285](https://github.com/empathyco/x/commit/25aa2851daf713512c42ef394707a9f1fc41fe4b)),
|
|
12
|
+
closes [EX-8011](https://searchbroker.atlassian.net/browse/EX-8011)
|
|
13
|
+
|
|
14
|
+
# Change Log
|
|
15
|
+
|
|
16
|
+
All notable changes to this project will be documented in this file. See
|
|
17
|
+
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
18
|
+
|
|
6
19
|
## [3.0.0-alpha.319](https://github.com/empathyco/x/compare/@empathyco/x-components@3.0.0-alpha.318...@empathyco/x-components@3.0.0-alpha.319) (2023-02-27)
|
|
7
20
|
|
|
8
21
|
### Features
|
|
@@ -1566,7 +1566,7 @@
|
|
|
1566
1566
|
--x-size-border-radius-bottom-right-tag-default
|
|
1567
1567
|
);
|
|
1568
1568
|
--x-size-border-radius-bottom-left-suggestion-default: var(
|
|
1569
|
-
--x-size-border-radius-bottom-
|
|
1569
|
+
--x-size-border-radius-bottom-left-tag-default
|
|
1570
1570
|
);
|
|
1571
1571
|
--x-size-border-radius-top-right-suggestion-default: var(
|
|
1572
1572
|
--x-size-border-radius-top-right-tag-default
|
|
@@ -1597,7 +1597,7 @@
|
|
|
1597
1597
|
--x-size-border-radius-bottom-right-tag-default
|
|
1598
1598
|
);
|
|
1599
1599
|
--x-size-border-radius-bottom-left-suggestion-group-default: var(
|
|
1600
|
-
--x-size-border-radius-bottom-
|
|
1600
|
+
--x-size-border-radius-bottom-left-tag-default
|
|
1601
1601
|
);
|
|
1602
1602
|
--x-size-border-radius-top-right-suggestion-group-default: var(
|
|
1603
1603
|
--x-size-border-radius-top-right-tag-default
|
|
@@ -1487,49 +1487,6 @@
|
|
|
1487
1487
|
.x-text--stroke.x-small {
|
|
1488
1488
|
--x-string-text-decoration-small: line-through;
|
|
1489
1489
|
}
|
|
1490
|
-
.x-font-color--lead {
|
|
1491
|
-
color: var(--x-color-base-lead) !important;
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
|
-
.x-font-color--auxiliary {
|
|
1495
|
-
color: var(--x-color-base-auxiliary) !important;
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
.x-font-color--neutral-10 {
|
|
1499
|
-
color: var(--x-color-base-neutral-10) !important;
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
.x-font-color--neutral-35 {
|
|
1503
|
-
color: var(--x-color-base-neutral-35) !important;
|
|
1504
|
-
}
|
|
1505
|
-
|
|
1506
|
-
.x-font-color--neutral-70 {
|
|
1507
|
-
color: var(--x-color-base-neutral-70) !important;
|
|
1508
|
-
}
|
|
1509
|
-
|
|
1510
|
-
.x-font-color--neutral-95 {
|
|
1511
|
-
color: var(--x-color-base-neutral-95) !important;
|
|
1512
|
-
}
|
|
1513
|
-
|
|
1514
|
-
.x-font-color--neutral-100 {
|
|
1515
|
-
color: var(--x-color-base-neutral-100) !important;
|
|
1516
|
-
}
|
|
1517
|
-
|
|
1518
|
-
.x-font-color--accent {
|
|
1519
|
-
color: var(--x-color-base-accent) !important;
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
|
-
.x-font-color--enable {
|
|
1523
|
-
color: var(--x-color-base-enable) !important;
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
|
-
.x-font-color--disable {
|
|
1527
|
-
color: var(--x-color-base-disable) !important;
|
|
1528
|
-
}
|
|
1529
|
-
|
|
1530
|
-
.x-font-color--transparent {
|
|
1531
|
-
color: var(--x-color-base-transparent) !important;
|
|
1532
|
-
}
|
|
1533
1490
|
.x-font-size--01 {
|
|
1534
1491
|
font-size: var(--x-size-base-01) !important;
|
|
1535
1492
|
line-height: 1.5;
|
|
@@ -1642,6 +1599,49 @@
|
|
|
1642
1599
|
.x-line-height--loose {
|
|
1643
1600
|
line-height: 2 !important;
|
|
1644
1601
|
}
|
|
1602
|
+
.x-font-color--lead {
|
|
1603
|
+
color: var(--x-color-base-lead) !important;
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
.x-font-color--auxiliary {
|
|
1607
|
+
color: var(--x-color-base-auxiliary) !important;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
.x-font-color--neutral-10 {
|
|
1611
|
+
color: var(--x-color-base-neutral-10) !important;
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
.x-font-color--neutral-35 {
|
|
1615
|
+
color: var(--x-color-base-neutral-35) !important;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
.x-font-color--neutral-70 {
|
|
1619
|
+
color: var(--x-color-base-neutral-70) !important;
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
.x-font-color--neutral-95 {
|
|
1623
|
+
color: var(--x-color-base-neutral-95) !important;
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
.x-font-color--neutral-100 {
|
|
1627
|
+
color: var(--x-color-base-neutral-100) !important;
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
.x-font-color--accent {
|
|
1631
|
+
color: var(--x-color-base-accent) !important;
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
.x-font-color--enable {
|
|
1635
|
+
color: var(--x-color-base-enable) !important;
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
.x-font-color--disable {
|
|
1639
|
+
color: var(--x-color-base-disable) !important;
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
.x-font-color--transparent {
|
|
1643
|
+
color: var(--x-color-base-transparent) !important;
|
|
1644
|
+
}
|
|
1645
1645
|
.x-underline {
|
|
1646
1646
|
text-decoration-line: underline;
|
|
1647
1647
|
}
|
|
@@ -2688,7 +2688,7 @@
|
|
|
2688
2688
|
--x-size-border-radius-bottom-right-tag-default
|
|
2689
2689
|
);
|
|
2690
2690
|
--x-size-border-radius-bottom-left-suggestion-default: var(
|
|
2691
|
-
--x-size-border-radius-bottom-
|
|
2691
|
+
--x-size-border-radius-bottom-left-tag-default
|
|
2692
2692
|
);
|
|
2693
2693
|
--x-size-border-radius-top-right-suggestion-default: var(
|
|
2694
2694
|
--x-size-border-radius-top-right-tag-default
|
|
@@ -2719,7 +2719,7 @@
|
|
|
2719
2719
|
--x-size-border-radius-bottom-right-tag-default
|
|
2720
2720
|
);
|
|
2721
2721
|
--x-size-border-radius-bottom-left-suggestion-group-default: var(
|
|
2722
|
-
--x-size-border-radius-bottom-
|
|
2722
|
+
--x-size-border-radius-bottom-left-tag-default
|
|
2723
2723
|
);
|
|
2724
2724
|
--x-size-border-radius-top-right-suggestion-group-default: var(
|
|
2725
2725
|
--x-size-border-radius-top-right-tag-default
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
--x-size-border-radius-bottom-right-tag-default
|
|
126
126
|
);
|
|
127
127
|
--x-size-border-radius-bottom-left-suggestion-default: var(
|
|
128
|
-
--x-size-border-radius-bottom-
|
|
128
|
+
--x-size-border-radius-bottom-left-tag-default
|
|
129
129
|
);
|
|
130
130
|
--x-size-border-radius-top-right-suggestion-default: var(
|
|
131
131
|
--x-size-border-radius-top-right-tag-default
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
--x-size-border-radius-bottom-right-tag-default
|
|
157
157
|
);
|
|
158
158
|
--x-size-border-radius-bottom-left-suggestion-group-default: var(
|
|
159
|
-
--x-size-border-radius-bottom-
|
|
159
|
+
--x-size-border-radius-bottom-left-tag-default
|
|
160
160
|
);
|
|
161
161
|
--x-size-border-radius-top-right-suggestion-group-default: var(
|
|
162
162
|
--x-size-border-radius-top-right-tag-default
|
|
@@ -76,7 +76,7 @@ __vue_render__._withStripped = true;
|
|
|
76
76
|
/* style */
|
|
77
77
|
const __vue_inject_styles__ = undefined;
|
|
78
78
|
/* scoped */
|
|
79
|
-
const __vue_scope_id__ = "data-v-
|
|
79
|
+
const __vue_scope_id__ = "data-v-46833e30";
|
|
80
80
|
/* module identifier */
|
|
81
81
|
const __vue_module_identifier__ = undefined;
|
|
82
82
|
/* functional template */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-modal.vue.js","sources":["../../../../src/components/modals/base-modal.vue"],"sourcesContent":["<template>\n <div v-show=\"isWaitingForLeave || open\" ref=\"modal\" class=\"x-modal\" data-test=\"modal\">\n <component\n :is=\"animation\"\n @before-leave=\"isWaitingForLeave = true\"\n @after-leave=\"isWaitingForLeave = false\"\n >\n <div\n v-if=\"open\"\n ref=\"modalContent\"\n class=\"x-modal__content x-list\"\n data-test=\"modal-content\"\n role=\"dialog\"\n :class=\"contentClass\"\n >\n <!-- @slot (Required) Modal container content -->\n <slot />\n </div>\n </component>\n <component :is=\"overlayAnimation\">\n <div\n v-if=\"open\"\n @click=\"emitOverlayClicked\"\n @keydown=\"emitOverlayClicked\"\n class=\"x-modal__overlay\"\n data-test=\"modal-overlay\"\n />\n </component>\n </div>\n</template>\n\n<script lang=\"ts\">\n import Vue from 'vue';\n import { Component, Prop, Mixins } from 'vue-property-decorator';\n import { getTargetElement } from '../../utils/html';\n import Fade from '../animations/fade.vue';\n import { NoElement } from '../no-element';\n import { FOCUSABLE_SELECTORS } from '../../utils/focus';\n import { Debounce } from '../decorators/debounce.decorators';\n import { dynamicPropsMixin } from '../dynamic-props.mixin';\n\n /**\n * Base component with no XPlugin dependencies that serves as a utility for constructing more\n * complex modals.\n *\n * @public\n */\n @Component\n export default class BaseModal extends Mixins(dynamicPropsMixin(['contentClass'])) {\n /**\n * Animation to use for opening/closing the modal. This animation only affects the content.\n */\n @Prop({ default: () => NoElement })\n public animation!: Vue | string;\n\n /**\n * Animation to use for the overlay (backdrop) part of the modal. By default, it uses\n * a fade transition.\n */\n @Prop({ default: () => Fade })\n public overlayAnimation!: Vue | string;\n\n /**\n * Determines if the modal is open or not.\n */\n @Prop({ required: true })\n public open!: boolean;\n\n /**\n * Determines if the focused element changes to one inside the modal when it opens. Either the\n * first element with a positive tabindex or just the first focusable element.\n */\n @Prop({ default: true })\n public focusOnOpen!: boolean;\n\n /**\n * The reference selector of a DOM element to use as reference to position the modal.\n * This selector can be an ID or a class, if it is a class, it will use the first\n * element that matches.\n */\n @Prop()\n public referenceSelector?: string;\n\n /**\n * The previous value of the body overflow style.\n */\n protected previousBodyOverflow = '';\n /**\n * The previous value of the HTML element overflow style.\n */\n protected previousHTMLOverflow = '';\n /**\n * Boolean to delay the leave animation until it has completed.\n */\n protected isWaitingForLeave = false;\n /**\n * The reference element to use to find the modal's position.\n */\n protected referenceElement!: HTMLElement;\n\n public $refs!: {\n /**\n * Reference to the modal element in the DOM.\n */\n modal: HTMLDivElement;\n /**\n * Reference to the modal content element in the DOM.\n */\n modalContent: HTMLDivElement;\n };\n\n protected mounted(): void {\n /* Watcher added after mount to prevent SSR from breaking */\n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.$watch('open', this.syncBody);\n if (this.open) {\n this.syncBody(true);\n }\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const resizeObserver = new ResizeObserver(this.updatePosition);\n\n this.$watch(\n 'clientHeaderSelector',\n () => {\n if (this.referenceSelector) {\n const element = document.querySelector(this.referenceSelector) as HTMLElement;\n if (element) {\n this.referenceElement = element;\n resizeObserver.observe(element);\n }\n }\n },\n { immediate: true }\n );\n\n this.$on('hook:beforeDestroy', () => {\n resizeObserver.disconnect();\n });\n }\n\n /**\n * Updates the position of the modal setting the top of the element depending\n * on the selector. The modal will be placed under this selector.\n *\n * @internal\n */\n @Debounce(100, { leading: true })\n updatePosition(): void {\n const { height, y } = this.referenceElement?.getBoundingClientRect() ?? { height: 0, y: 0 };\n this.$refs.modal.style.top = `${height + y}px`;\n this.$refs.modal.style.bottom = '0';\n this.$refs.modal.style.height = 'auto';\n }\n\n /**\n * Syncs the body to the open state of the modal, adding or removing styles and listeners.\n *\n * @param isOpen - True when the modal is opened.\n * @internal\n */\n protected syncBody(isOpen: boolean): void {\n if (isOpen) {\n this.disableScroll();\n this.addBodyListeners();\n /* eslint-disable @typescript-eslint/unbound-method */\n this.$on('hook:beforeDestroy', this.removeBodyListeners);\n this.$on('hook:beforeDestroy', this.enableScroll);\n /* eslint-enable @typescript-eslint/unbound-method */\n if (this.focusOnOpen) {\n this.setFocus();\n }\n } else {\n this.enableScroll();\n this.removeBodyListeners();\n /* eslint-disable @typescript-eslint/unbound-method */\n this.$off('hook:beforeDestroy', this.removeBodyListeners);\n this.$off('hook:beforeDestroy', this.enableScroll);\n /* eslint-enable @typescript-eslint/unbound-method */\n }\n }\n\n /**\n * Disables the scroll of both the body and the window.\n *\n * @internal\n */\n protected disableScroll(): void {\n this.previousBodyOverflow = document.body.style.overflow;\n this.previousHTMLOverflow = document.documentElement.style.overflow;\n document.body.style.overflow = document.documentElement.style.overflow = 'hidden';\n }\n\n /**\n * Restores the scroll of both the body and the window.\n *\n * @internal\n */\n protected enableScroll(): void {\n document.body.style.overflow = this.previousBodyOverflow;\n document.documentElement.style.overflow = this.previousHTMLOverflow;\n }\n\n /**\n * Adds listeners to the body element ot detect if the modal should be closed.\n *\n * @internal\n */\n protected addBodyListeners(): void {\n /* eslint-disable @typescript-eslint/unbound-method */\n document.body.addEventListener('focusin', this.emitFocusInBody);\n /* eslint-enable @typescript-eslint/unbound-method */\n }\n\n /**\n * Removes the body listeners.\n *\n * @internal\n */\n protected removeBodyListeners(): void {\n /* eslint-disable @typescript-eslint/unbound-method */\n document.body.removeEventListener('focusin', this.emitFocusInBody);\n /* eslint-enable @typescript-eslint/unbound-method */\n }\n\n /**\n * Emits the `click:overlay` event if the click has been triggered in the overlay layer.\n *\n * @param event - The click event.\n * @internal\n */\n protected emitOverlayClicked(event: MouseEvent): void {\n this.$emit('click:overlay', event);\n }\n\n /**\n * Emits the `focusin:body` event if a focus event has been triggered outside the modal.\n *\n * @param event - The focusin event.\n * @internal\n */\n protected emitFocusInBody(event: FocusEvent): void {\n if (!this.$refs.modalContent.contains(getTargetElement(event))) {\n this.$emit('focusin:body', event);\n }\n }\n\n /**\n * Sets the focused element to the first element either the first element with a positive\n * tabindex or, if there isn't any, the first focusable element inside the modal.\n *\n * @internal\n */\n protected setFocus(): void {\n const focusCandidates: HTMLElement[] = Array.from(\n this.$refs.modalContent.querySelectorAll(FOCUSABLE_SELECTORS)\n );\n\n const elementToFocus =\n focusCandidates.find(element => element.tabIndex) ?? focusCandidates[0];\n\n elementToFocus?.focus();\n }\n }\n</script>\n\n<style lang=\"scss\" scoped>\n .x-modal {\n position: fixed;\n top: 0;\n left: 0;\n display: flex;\n align-items: flex-start;\n justify-content: flex-start;\n width: 100%;\n height: 100%;\n z-index: 1;\n\n &__content {\n z-index: 1;\n }\n\n &__overlay {\n width: 100%;\n height: 100%;\n position: absolute;\n background-color: var(--x-modal-overlay-color, rgb(0, 0, 0));\n opacity: var(--x-modal-overlay-opacity, 0.7);\n }\n }\n</style>\n\n<docs lang=\"mdx\">\n## Examples\n\nThe `BaseModal` is a simple component that serves to create complex modals. Its open state has to be\npassed via prop. There is a prop, `referenceSelector`, used to place the modal under some element\ninstead of set the top of the element directly. It also accepts an animation to use for opening &\nclosing.\n\nIt emits a `click:overlay` event when any part out of the content is clicked, but only if the modal\nis open.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n### Customized usage\n\n#### Customizing the content with classes\n\nThe `contentClass` prop can be used to add classes to the modal content.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n contentClass=\"x-background--neutral-35\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n## Vue Events\n\nA list of events that the component will emit:\n\n- `click:overlay`: the event is emitted after the user clicks any part out of the content but only\n if the modal is open. The event payload is the mouse event that triggers it.\n- `focusin:body`: the event is emitted after the user focus in any part out of the content but only\n if the modal is open. The event payload is the focus event that triggers it.\n</docs>\n"],"names":[],"mappings":";;;;;AAEA,MAAc,cAAA,GAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"base-modal.vue.js","sources":["../../../../src/components/modals/base-modal.vue"],"sourcesContent":["<template>\n <div v-show=\"isWaitingForLeave || open\" ref=\"modal\" class=\"x-modal\" data-test=\"modal\">\n <component\n :is=\"animation\"\n @before-leave=\"isWaitingForLeave = true\"\n @after-leave=\"isWaitingForLeave = false\"\n >\n <div\n v-if=\"open\"\n ref=\"modalContent\"\n class=\"x-modal__content x-list\"\n data-test=\"modal-content\"\n role=\"dialog\"\n :class=\"contentClass\"\n >\n <!-- @slot (Required) Modal container content -->\n <slot />\n </div>\n </component>\n <component :is=\"overlayAnimation\">\n <div\n v-if=\"open\"\n @click=\"emitOverlayClicked\"\n @keydown=\"emitOverlayClicked\"\n class=\"x-modal__overlay\"\n data-test=\"modal-overlay\"\n />\n </component>\n </div>\n</template>\n\n<script lang=\"ts\">\n import Vue from 'vue';\n import { Component, Prop, Mixins } from 'vue-property-decorator';\n import { getTargetElement } from '../../utils/html';\n import Fade from '../animations/fade.vue';\n import { NoElement } from '../no-element';\n import { FOCUSABLE_SELECTORS } from '../../utils/focus';\n import { Debounce } from '../decorators/debounce.decorators';\n import { dynamicPropsMixin } from '../dynamic-props.mixin';\n\n /**\n * Base component with no XPlugin dependencies that serves as a utility for constructing more\n * complex modals.\n *\n * @public\n */\n @Component\n export default class BaseModal extends Mixins(dynamicPropsMixin(['contentClass'])) {\n /**\n * Animation to use for opening/closing the modal. This animation only affects the content.\n */\n @Prop({ default: () => NoElement })\n public animation!: Vue | string;\n\n /**\n * Animation to use for the overlay (backdrop) part of the modal. By default, it uses\n * a fade transition.\n */\n @Prop({ default: () => Fade })\n public overlayAnimation!: Vue | string;\n\n /**\n * Determines if the modal is open or not.\n */\n @Prop({ required: true })\n public open!: boolean;\n\n /**\n * Determines if the focused element changes to one inside the modal when it opens. Either the\n * first element with a positive tabindex or just the first focusable element.\n */\n @Prop({ default: true })\n public focusOnOpen!: boolean;\n\n /**\n * The reference selector of a DOM element to use as reference to position the modal.\n * This selector can be an ID or a class, if it is a class, it will use the first\n * element that matches.\n */\n @Prop()\n public referenceSelector?: string;\n\n /**\n * The previous value of the body overflow style.\n */\n protected previousBodyOverflow = '';\n /**\n * The previous value of the HTML element overflow style.\n */\n protected previousHTMLOverflow = '';\n /**\n * Boolean to delay the leave animation until it has completed.\n */\n protected isWaitingForLeave = false;\n /**\n * The reference element to use to find the modal's position.\n */\n protected referenceElement!: HTMLElement;\n\n public $refs!: {\n /**\n * Reference to the modal element in the DOM.\n */\n modal: HTMLDivElement;\n /**\n * Reference to the modal content element in the DOM.\n */\n modalContent: HTMLDivElement;\n };\n\n protected mounted(): void {\n /* Watcher added after mount to prevent SSR from breaking */\n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.$watch('open', this.syncBody);\n if (this.open) {\n this.syncBody(true);\n }\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const resizeObserver = new ResizeObserver(this.updatePosition);\n\n this.$watch(\n 'clientHeaderSelector',\n () => {\n if (this.referenceSelector) {\n const element = document.querySelector(this.referenceSelector) as HTMLElement;\n if (element) {\n this.referenceElement = element;\n resizeObserver.observe(element);\n }\n }\n },\n { immediate: true }\n );\n\n this.$on('hook:beforeDestroy', () => {\n resizeObserver.disconnect();\n });\n }\n\n /**\n * Updates the position of the modal setting the top of the element depending\n * on the selector. The modal will be placed under this selector.\n *\n * @internal\n */\n @Debounce(100, { leading: true })\n updatePosition(): void {\n const { height, y } = this.referenceElement?.getBoundingClientRect() ?? { height: 0, y: 0 };\n this.$refs.modal.style.top = `${height + y}px`;\n this.$refs.modal.style.bottom = '0';\n this.$refs.modal.style.height = 'auto';\n }\n\n /**\n * Syncs the body to the open state of the modal, adding or removing styles and listeners.\n *\n * @param isOpen - True when the modal is opened.\n * @internal\n */\n protected syncBody(isOpen: boolean): void {\n if (isOpen) {\n this.disableScroll();\n this.addBodyListeners();\n /* eslint-disable @typescript-eslint/unbound-method */\n this.$on('hook:beforeDestroy', this.removeBodyListeners);\n this.$on('hook:beforeDestroy', this.enableScroll);\n /* eslint-enable @typescript-eslint/unbound-method */\n if (this.focusOnOpen) {\n this.setFocus();\n }\n } else {\n this.enableScroll();\n this.removeBodyListeners();\n /* eslint-disable @typescript-eslint/unbound-method */\n this.$off('hook:beforeDestroy', this.removeBodyListeners);\n this.$off('hook:beforeDestroy', this.enableScroll);\n /* eslint-enable @typescript-eslint/unbound-method */\n }\n }\n\n /**\n * Disables the scroll of both the body and the window.\n *\n * @internal\n */\n protected disableScroll(): void {\n this.previousBodyOverflow = document.body.style.overflow;\n this.previousHTMLOverflow = document.documentElement.style.overflow;\n document.body.style.overflow = document.documentElement.style.overflow = 'hidden';\n }\n\n /**\n * Restores the scroll of both the body and the window.\n *\n * @internal\n */\n protected enableScroll(): void {\n document.body.style.overflow = this.previousBodyOverflow;\n document.documentElement.style.overflow = this.previousHTMLOverflow;\n }\n\n /**\n * Adds listeners to the body element ot detect if the modal should be closed.\n *\n * @internal\n */\n protected addBodyListeners(): void {\n // TODO find a better solution and remove the timeout\n // to avoid emit the focusin on opening X that provokes closing it immediately.\n // This is because this event was emitted after the open of main modal when the user clicks\n // on the customer website search box (focus event). This way we avoid add the listener before\n // the open and the avoid the event that provokes the close.\n setTimeout(() => {\n /* eslint-disable @typescript-eslint/unbound-method */\n document.body.addEventListener('focusin', this.emitFocusInBody);\n /* eslint-enable @typescript-eslint/unbound-method */\n });\n }\n\n /**\n * Removes the body listeners.\n *\n * @internal\n */\n protected removeBodyListeners(): void {\n /* eslint-disable @typescript-eslint/unbound-method */\n document.body.removeEventListener('focusin', this.emitFocusInBody);\n /* eslint-enable @typescript-eslint/unbound-method */\n }\n\n /**\n * Emits the `click:overlay` event if the click has been triggered in the overlay layer.\n *\n * @param event - The click event.\n * @internal\n */\n protected emitOverlayClicked(event: MouseEvent): void {\n this.$emit('click:overlay', event);\n }\n\n /**\n * Emits the `focusin:body` event if a focus event has been triggered outside the modal.\n *\n * @param event - The focusin event.\n * @internal\n */\n protected emitFocusInBody(event: FocusEvent): void {\n if (!this.$refs.modalContent?.contains(getTargetElement(event))) {\n this.$emit('focusin:body', event);\n }\n }\n\n /**\n * Sets the focused element to the first element either the first element with a positive\n * tabindex or, if there isn't any, the first focusable element inside the modal.\n *\n * @internal\n */\n protected setFocus(): void {\n const focusCandidates: HTMLElement[] = Array.from(\n this.$refs.modalContent.querySelectorAll(FOCUSABLE_SELECTORS)\n );\n\n const elementToFocus =\n focusCandidates.find(element => element.tabIndex) ?? focusCandidates[0];\n\n elementToFocus?.focus();\n }\n }\n</script>\n\n<style lang=\"scss\" scoped>\n .x-modal {\n position: fixed;\n top: 0;\n left: 0;\n display: flex;\n align-items: flex-start;\n justify-content: flex-start;\n width: 100%;\n height: 100%;\n z-index: 1;\n\n &__content {\n z-index: 1;\n }\n\n &__overlay {\n width: 100%;\n height: 100%;\n position: absolute;\n background-color: var(--x-modal-overlay-color, rgb(0, 0, 0));\n opacity: var(--x-modal-overlay-opacity, 0.7);\n }\n }\n</style>\n\n<docs lang=\"mdx\">\n## Examples\n\nThe `BaseModal` is a simple component that serves to create complex modals. Its open state has to be\npassed via prop. There is a prop, `referenceSelector`, used to place the modal under some element\ninstead of set the top of the element directly. It also accepts an animation to use for opening &\nclosing.\n\nIt emits a `click:overlay` event when any part out of the content is clicked, but only if the modal\nis open.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n### Customized usage\n\n#### Customizing the content with classes\n\nThe `contentClass` prop can be used to add classes to the modal content.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n contentClass=\"x-background--neutral-35\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n## Vue Events\n\nA list of events that the component will emit:\n\n- `click:overlay`: the event is emitted after the user clicks any part out of the content but only\n if the modal is open. The event payload is the mouse event that triggers it.\n- `focusin:body`: the event is emitted after the user focus in any part out of the content but only\n if the modal is open. The event payload is the focus event that triggers it.\n</docs>\n"],"names":[],"mappings":";;;;;AAEA,MAAc,cAAA,GAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -115,9 +115,16 @@ let BaseModal = class BaseModal extends Mixins(dynamicPropsMixin(['contentClass'
|
|
|
115
115
|
* @internal
|
|
116
116
|
*/
|
|
117
117
|
addBodyListeners() {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
// TODO find a better solution and remove the timeout
|
|
119
|
+
// to avoid emit the focusin on opening X that provokes closing it immediately.
|
|
120
|
+
// This is because this event was emitted after the open of main modal when the user clicks
|
|
121
|
+
// on the customer website search box (focus event). This way we avoid add the listener before
|
|
122
|
+
// the open and the avoid the event that provokes the close.
|
|
123
|
+
setTimeout(() => {
|
|
124
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
125
|
+
document.body.addEventListener('focusin', this.emitFocusInBody);
|
|
126
|
+
/* eslint-enable @typescript-eslint/unbound-method */
|
|
127
|
+
});
|
|
121
128
|
}
|
|
122
129
|
/**
|
|
123
130
|
* Removes the body listeners.
|
|
@@ -145,7 +152,7 @@ let BaseModal = class BaseModal extends Mixins(dynamicPropsMixin(['contentClass'
|
|
|
145
152
|
* @internal
|
|
146
153
|
*/
|
|
147
154
|
emitFocusInBody(event) {
|
|
148
|
-
if (!this.$refs.modalContent
|
|
155
|
+
if (!this.$refs.modalContent?.contains(getTargetElement(event))) {
|
|
149
156
|
this.$emit('focusin:body', event);
|
|
150
157
|
}
|
|
151
158
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-modal.vue_rollup-plugin-vue_script.vue.js","sources":["../../../../src/components/modals/base-modal.vue?rollup-plugin-vue=script.ts"],"sourcesContent":["\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n import Vue from 'vue';\n import { Component, Prop, Mixins } from 'vue-property-decorator';\n import { getTargetElement } from '../../utils/html';\n import Fade from '../animations/fade.vue';\n import { NoElement } from '../no-element';\n import { FOCUSABLE_SELECTORS } from '../../utils/focus';\n import { Debounce } from '../decorators/debounce.decorators';\n import { dynamicPropsMixin } from '../dynamic-props.mixin';\n\n /**\n * Base component with no XPlugin dependencies that serves as a utility for constructing more\n * complex modals.\n *\n * @public\n */\n @Component\n export default class BaseModal extends Mixins(dynamicPropsMixin(['contentClass'])) {\n /**\n * Animation to use for opening/closing the modal. This animation only affects the content.\n */\n @Prop({ default: () => NoElement })\n public animation!: Vue | string;\n\n /**\n * Animation to use for the overlay (backdrop) part of the modal. By default, it uses\n * a fade transition.\n */\n @Prop({ default: () => Fade })\n public overlayAnimation!: Vue | string;\n\n /**\n * Determines if the modal is open or not.\n */\n @Prop({ required: true })\n public open!: boolean;\n\n /**\n * Determines if the focused element changes to one inside the modal when it opens. Either the\n * first element with a positive tabindex or just the first focusable element.\n */\n @Prop({ default: true })\n public focusOnOpen!: boolean;\n\n /**\n * The reference selector of a DOM element to use as reference to position the modal.\n * This selector can be an ID or a class, if it is a class, it will use the first\n * element that matches.\n */\n @Prop()\n public referenceSelector?: string;\n\n /**\n * The previous value of the body overflow style.\n */\n protected previousBodyOverflow = '';\n /**\n * The previous value of the HTML element overflow style.\n */\n protected previousHTMLOverflow = '';\n /**\n * Boolean to delay the leave animation until it has completed.\n */\n protected isWaitingForLeave = false;\n /**\n * The reference element to use to find the modal's position.\n */\n protected referenceElement!: HTMLElement;\n\n public $refs!: {\n /**\n * Reference to the modal element in the DOM.\n */\n modal: HTMLDivElement;\n /**\n * Reference to the modal content element in the DOM.\n */\n modalContent: HTMLDivElement;\n };\n\n protected mounted(): void {\n /* Watcher added after mount to prevent SSR from breaking */\n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.$watch('open', this.syncBody);\n if (this.open) {\n this.syncBody(true);\n }\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const resizeObserver = new ResizeObserver(this.updatePosition);\n\n this.$watch(\n 'clientHeaderSelector',\n () => {\n if (this.referenceSelector) {\n const element = document.querySelector(this.referenceSelector) as HTMLElement;\n if (element) {\n this.referenceElement = element;\n resizeObserver.observe(element);\n }\n }\n },\n { immediate: true }\n );\n\n this.$on('hook:beforeDestroy', () => {\n resizeObserver.disconnect();\n });\n }\n\n /**\n * Updates the position of the modal setting the top of the element depending\n * on the selector. The modal will be placed under this selector.\n *\n * @internal\n */\n @Debounce(100, { leading: true })\n updatePosition(): void {\n const { height, y } = this.referenceElement?.getBoundingClientRect() ?? { height: 0, y: 0 };\n this.$refs.modal.style.top = `${height + y}px`;\n this.$refs.modal.style.bottom = '0';\n this.$refs.modal.style.height = 'auto';\n }\n\n /**\n * Syncs the body to the open state of the modal, adding or removing styles and listeners.\n *\n * @param isOpen - True when the modal is opened.\n * @internal\n */\n protected syncBody(isOpen: boolean): void {\n if (isOpen) {\n this.disableScroll();\n this.addBodyListeners();\n /* eslint-disable @typescript-eslint/unbound-method */\n this.$on('hook:beforeDestroy', this.removeBodyListeners);\n this.$on('hook:beforeDestroy', this.enableScroll);\n /* eslint-enable @typescript-eslint/unbound-method */\n if (this.focusOnOpen) {\n this.setFocus();\n }\n } else {\n this.enableScroll();\n this.removeBodyListeners();\n /* eslint-disable @typescript-eslint/unbound-method */\n this.$off('hook:beforeDestroy', this.removeBodyListeners);\n this.$off('hook:beforeDestroy', this.enableScroll);\n /* eslint-enable @typescript-eslint/unbound-method */\n }\n }\n\n /**\n * Disables the scroll of both the body and the window.\n *\n * @internal\n */\n protected disableScroll(): void {\n this.previousBodyOverflow = document.body.style.overflow;\n this.previousHTMLOverflow = document.documentElement.style.overflow;\n document.body.style.overflow = document.documentElement.style.overflow = 'hidden';\n }\n\n /**\n * Restores the scroll of both the body and the window.\n *\n * @internal\n */\n protected enableScroll(): void {\n document.body.style.overflow = this.previousBodyOverflow;\n document.documentElement.style.overflow = this.previousHTMLOverflow;\n }\n\n /**\n * Adds listeners to the body element ot detect if the modal should be closed.\n *\n * @internal\n */\n protected addBodyListeners(): void {\n /* eslint-disable @typescript-eslint/unbound-method */\n document.body.addEventListener('focusin', this.emitFocusInBody);\n /* eslint-enable @typescript-eslint/unbound-method */\n }\n\n /**\n * Removes the body listeners.\n *\n * @internal\n */\n protected removeBodyListeners(): void {\n /* eslint-disable @typescript-eslint/unbound-method */\n document.body.removeEventListener('focusin', this.emitFocusInBody);\n /* eslint-enable @typescript-eslint/unbound-method */\n }\n\n /**\n * Emits the `click:overlay` event if the click has been triggered in the overlay layer.\n *\n * @param event - The click event.\n * @internal\n */\n protected emitOverlayClicked(event: MouseEvent): void {\n this.$emit('click:overlay', event);\n }\n\n /**\n * Emits the `focusin:body` event if a focus event has been triggered outside the modal.\n *\n * @param event - The focusin event.\n * @internal\n */\n protected emitFocusInBody(event: FocusEvent): void {\n if (!this.$refs.modalContent.contains(getTargetElement(event))) {\n this.$emit('focusin:body', event);\n }\n }\n\n /**\n * Sets the focused element to the first element either the first element with a positive\n * tabindex or, if there isn't any, the first focusable element inside the modal.\n *\n * @internal\n */\n protected setFocus(): void {\n const focusCandidates: HTMLElement[] = Array.from(\n this.$refs.modalContent.querySelectorAll(FOCUSABLE_SELECTORS)\n );\n\n const elementToFocus =\n focusCandidates.find(element => element.tabIndex) ?? focusCandidates[0];\n\n elementToFocus?.focus();\n }\n }\n"],"names":["Fade"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"base-modal.vue_rollup-plugin-vue_script.vue.js","sources":["../../../../src/components/modals/base-modal.vue?rollup-plugin-vue=script.ts"],"sourcesContent":["\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n import Vue from 'vue';\n import { Component, Prop, Mixins } from 'vue-property-decorator';\n import { getTargetElement } from '../../utils/html';\n import Fade from '../animations/fade.vue';\n import { NoElement } from '../no-element';\n import { FOCUSABLE_SELECTORS } from '../../utils/focus';\n import { Debounce } from '../decorators/debounce.decorators';\n import { dynamicPropsMixin } from '../dynamic-props.mixin';\n\n /**\n * Base component with no XPlugin dependencies that serves as a utility for constructing more\n * complex modals.\n *\n * @public\n */\n @Component\n export default class BaseModal extends Mixins(dynamicPropsMixin(['contentClass'])) {\n /**\n * Animation to use for opening/closing the modal. This animation only affects the content.\n */\n @Prop({ default: () => NoElement })\n public animation!: Vue | string;\n\n /**\n * Animation to use for the overlay (backdrop) part of the modal. By default, it uses\n * a fade transition.\n */\n @Prop({ default: () => Fade })\n public overlayAnimation!: Vue | string;\n\n /**\n * Determines if the modal is open or not.\n */\n @Prop({ required: true })\n public open!: boolean;\n\n /**\n * Determines if the focused element changes to one inside the modal when it opens. Either the\n * first element with a positive tabindex or just the first focusable element.\n */\n @Prop({ default: true })\n public focusOnOpen!: boolean;\n\n /**\n * The reference selector of a DOM element to use as reference to position the modal.\n * This selector can be an ID or a class, if it is a class, it will use the first\n * element that matches.\n */\n @Prop()\n public referenceSelector?: string;\n\n /**\n * The previous value of the body overflow style.\n */\n protected previousBodyOverflow = '';\n /**\n * The previous value of the HTML element overflow style.\n */\n protected previousHTMLOverflow = '';\n /**\n * Boolean to delay the leave animation until it has completed.\n */\n protected isWaitingForLeave = false;\n /**\n * The reference element to use to find the modal's position.\n */\n protected referenceElement!: HTMLElement;\n\n public $refs!: {\n /**\n * Reference to the modal element in the DOM.\n */\n modal: HTMLDivElement;\n /**\n * Reference to the modal content element in the DOM.\n */\n modalContent: HTMLDivElement;\n };\n\n protected mounted(): void {\n /* Watcher added after mount to prevent SSR from breaking */\n // eslint-disable-next-line @typescript-eslint/unbound-method\n this.$watch('open', this.syncBody);\n if (this.open) {\n this.syncBody(true);\n }\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const resizeObserver = new ResizeObserver(this.updatePosition);\n\n this.$watch(\n 'clientHeaderSelector',\n () => {\n if (this.referenceSelector) {\n const element = document.querySelector(this.referenceSelector) as HTMLElement;\n if (element) {\n this.referenceElement = element;\n resizeObserver.observe(element);\n }\n }\n },\n { immediate: true }\n );\n\n this.$on('hook:beforeDestroy', () => {\n resizeObserver.disconnect();\n });\n }\n\n /**\n * Updates the position of the modal setting the top of the element depending\n * on the selector. The modal will be placed under this selector.\n *\n * @internal\n */\n @Debounce(100, { leading: true })\n updatePosition(): void {\n const { height, y } = this.referenceElement?.getBoundingClientRect() ?? { height: 0, y: 0 };\n this.$refs.modal.style.top = `${height + y}px`;\n this.$refs.modal.style.bottom = '0';\n this.$refs.modal.style.height = 'auto';\n }\n\n /**\n * Syncs the body to the open state of the modal, adding or removing styles and listeners.\n *\n * @param isOpen - True when the modal is opened.\n * @internal\n */\n protected syncBody(isOpen: boolean): void {\n if (isOpen) {\n this.disableScroll();\n this.addBodyListeners();\n /* eslint-disable @typescript-eslint/unbound-method */\n this.$on('hook:beforeDestroy', this.removeBodyListeners);\n this.$on('hook:beforeDestroy', this.enableScroll);\n /* eslint-enable @typescript-eslint/unbound-method */\n if (this.focusOnOpen) {\n this.setFocus();\n }\n } else {\n this.enableScroll();\n this.removeBodyListeners();\n /* eslint-disable @typescript-eslint/unbound-method */\n this.$off('hook:beforeDestroy', this.removeBodyListeners);\n this.$off('hook:beforeDestroy', this.enableScroll);\n /* eslint-enable @typescript-eslint/unbound-method */\n }\n }\n\n /**\n * Disables the scroll of both the body and the window.\n *\n * @internal\n */\n protected disableScroll(): void {\n this.previousBodyOverflow = document.body.style.overflow;\n this.previousHTMLOverflow = document.documentElement.style.overflow;\n document.body.style.overflow = document.documentElement.style.overflow = 'hidden';\n }\n\n /**\n * Restores the scroll of both the body and the window.\n *\n * @internal\n */\n protected enableScroll(): void {\n document.body.style.overflow = this.previousBodyOverflow;\n document.documentElement.style.overflow = this.previousHTMLOverflow;\n }\n\n /**\n * Adds listeners to the body element ot detect if the modal should be closed.\n *\n * @internal\n */\n protected addBodyListeners(): void {\n // TODO find a better solution and remove the timeout\n // to avoid emit the focusin on opening X that provokes closing it immediately.\n // This is because this event was emitted after the open of main modal when the user clicks\n // on the customer website search box (focus event). This way we avoid add the listener before\n // the open and the avoid the event that provokes the close.\n setTimeout(() => {\n /* eslint-disable @typescript-eslint/unbound-method */\n document.body.addEventListener('focusin', this.emitFocusInBody);\n /* eslint-enable @typescript-eslint/unbound-method */\n });\n }\n\n /**\n * Removes the body listeners.\n *\n * @internal\n */\n protected removeBodyListeners(): void {\n /* eslint-disable @typescript-eslint/unbound-method */\n document.body.removeEventListener('focusin', this.emitFocusInBody);\n /* eslint-enable @typescript-eslint/unbound-method */\n }\n\n /**\n * Emits the `click:overlay` event if the click has been triggered in the overlay layer.\n *\n * @param event - The click event.\n * @internal\n */\n protected emitOverlayClicked(event: MouseEvent): void {\n this.$emit('click:overlay', event);\n }\n\n /**\n * Emits the `focusin:body` event if a focus event has been triggered outside the modal.\n *\n * @param event - The focusin event.\n * @internal\n */\n protected emitFocusInBody(event: FocusEvent): void {\n if (!this.$refs.modalContent?.contains(getTargetElement(event))) {\n this.$emit('focusin:body', event);\n }\n }\n\n /**\n * Sets the focused element to the first element either the first element with a positive\n * tabindex or, if there isn't any, the first focusable element inside the modal.\n *\n * @internal\n */\n protected setFocus(): void {\n const focusCandidates: HTMLElement[] = Array.from(\n this.$refs.modalContent.querySelectorAll(FOCUSABLE_SELECTORS)\n );\n\n const elementToFocus =\n focusCandidates.find(element => element.tabIndex) ?? focusCandidates[0];\n\n elementToFocus?.focus();\n }\n }\n"],"names":["Fade"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createInjector, createInjectorSSR } from 'vue-runtime-helpers';
|
|
2
2
|
|
|
3
|
-
var css = ".x-modal[data-v-
|
|
3
|
+
var css = ".x-modal[data-v-46833e30] {\n position: fixed;\n top: 0;\n left: 0;\n display: flex;\n align-items: flex-start;\n justify-content: flex-start;\n width: 100%;\n height: 100%;\n z-index: 1;\n}\n.x-modal__content[data-v-46833e30] {\n z-index: 1;\n}\n.x-modal__overlay[data-v-46833e30] {\n width: 100%;\n height: 100%;\n position: absolute;\n background-color: var(--x-modal-overlay-color, rgb(0, 0, 0));\n opacity: var(--x-modal-overlay-opacity, 0.7);\n}";
|
|
4
4
|
const isBrowser = /*#__PURE__*/ (function () {
|
|
5
5
|
return (
|
|
6
6
|
Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) !==
|
|
@@ -37,7 +37,7 @@ __vue_render__._withStripped = true;
|
|
|
37
37
|
/* style */
|
|
38
38
|
const __vue_inject_styles__ = undefined;
|
|
39
39
|
/* scoped */
|
|
40
|
-
const __vue_scope_id__ = "data-v-
|
|
40
|
+
const __vue_scope_id__ = "data-v-6a52742e";
|
|
41
41
|
/* module identifier */
|
|
42
42
|
const __vue_module_identifier__ = undefined;
|
|
43
43
|
/* functional template */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-input-placeholder.vue.js","sources":["../../../../../src/x-modules/search-box/components/search-input-placeholder.vue"],"sourcesContent":["<template>\n <component\n :is=\"animation\"\n v-if=\"isVisible\"\n class=\"x-input-placeholder x-search-input-placeholder\"\n mode=\"out-in\"\n >\n <span :key=\"message\" data-test=\"search-input-placeholder\">\n {{ message }}\n </span>\n </component>\n</template>\n\n<script lang=\"ts\">\n import Vue from 'vue';\n import { Component, Prop, Watch } from 'vue-property-decorator';\n import { animateTranslate, State, xComponentMixin, XOn } from '../../../components';\n import { searchBoxXModule } from '../x-module';\n\n /**.\n * This component renders an animated placeholder for the search input in the shape of a list of\n * iterating messages that can be configured to happen always or only when hovering the input\n *\n * @public\n */\n @Component({\n mixins: [xComponentMixin(searchBoxXModule)]\n })\n export default class SearchInputPlaceholder extends Vue {\n /**\n * List of messages to animate.\n *\n * @public\n */\n @Prop({ required: true })\n protected messages!: Array<string>;\n\n /**\n * Animation component used for the messages.\n *\n * @public\n */\n @Prop({ default: () => animateTranslate('bottom-to-top') })\n protected animation!: Vue;\n\n /**\n * Time in milliseconds during which each message is visible.\n *\n * @public\n */\n @Prop({ default: 1500 })\n protected animationIntervalMs!: number;\n\n /**\n * Whether the messages animation is active only when hovering the search input or always.\n *\n * @public\n */\n @Prop({ default: false })\n protected animateOnlyOnHover!: boolean;\n\n /**.\n * The search box written query\n *\n * @internal\n */\n @State('searchBox', 'query')\n public query!: string;\n\n /**.\n * The search box hover status\n *\n * @internal\n */\n protected isSearchBoxHovered = false;\n\n /**.\n * The search box focus status\n *\n * @internal\n */\n protected isSearchBoxFocused = false;\n\n /**\n * The index used to point to the current animation message in the list.\n *\n * @internal\n */\n protected animationMessageIndex = 0;\n\n /**\n * The interval used for the animation.\n *\n * @internal\n */\n protected animationInterval: number | undefined;\n\n /**\n * The visibility state of the component.\n *\n * @returns The visibility state based on the search input state (query & focus).\n *\n * @internal\n */\n protected get isVisible(): boolean {\n return !this.query && !this.isSearchBoxFocused;\n }\n\n /**\n * The animation state of the component.\n *\n * @returns Whether the animation is active or not.\n *\n * @internal\n */\n protected get isBeingAnimated(): boolean {\n return this.isVisible && (!this.animateOnlyOnHover || this.isSearchBoxHovered);\n }\n\n /**\n * The current placeholder message.\n *\n * @returns The message to display as placeholder at any moment.\n *\n * @internal\n */\n protected get message(): string | undefined {\n return this.isBeingAnimated ? this.messages[this.animationMessageIndex] : this.messages[0];\n }\n\n /**\n * Starts or stops the animation depending on the current animation state.\n *\n * @internal\n */\n @Watch('isBeingAnimated', { immediate: true })\n @Watch('messages', { deep: true })\n @Watch('animationIntervalMs')\n protected resetAnimation(): void {\n this.stopAnimationInterval();\n\n if (this.isBeingAnimated) {\n this.animationInterval = window.setInterval((): void => {\n this.incrementAnimationMessageIndex();\n }, this.animationIntervalMs);\n }\n }\n\n /**\n * Clears the interval used for the animation.\n *\n * @internal\n */\n protected stopAnimationInterval(): void {\n if (this.animationInterval) {\n clearInterval(this.animationInterval);\n this.animationInterval = undefined;\n }\n }\n\n /**\n * Increments animation message index; if the new index exceeds the messages list length, it is\n * reset to 0.\n *\n * @internal\n */\n protected incrementAnimationMessageIndex(): void {\n this.animationMessageIndex = (this.animationMessageIndex + 1) % this.messages.length;\n }\n\n /**\n * Sets the animation message index with the right value for the next future iteration when the\n * current one stops,assuring the user will see always a new message on each animation state\n * change.\n *\n * @internal\n */\n @Watch('isBeingAnimated', { immediate: true })\n protected prepareMessageIndexForNextAnimation(): void {\n if (!this.isBeingAnimated) {\n if (this.animateOnlyOnHover) {\n this.resetAnimationMessageIndex();\n }\n this.incrementAnimationMessageIndex();\n }\n }\n\n /**\n * Resets the animation message index to zero.\n *\n * @internal\n */\n @Watch('messages', { deep: true })\n protected resetAnimationMessageIndex(): void {\n this.animationMessageIndex = 0;\n }\n\n // TODO: EX-7173 - Get search input state(s) from the store instead of using events\n @XOn('UserHoveredInSearchBox')\n onUserHoveredInSearchBox(): void {\n this.isSearchBoxHovered = true;\n }\n\n @XOn('UserHoveredOutSearchBox')\n onUserHoveredOutSearchBox(): void {\n this.isSearchBoxHovered = false;\n }\n\n @XOn('UserFocusedSearchBox')\n onUserFocusedSearchBox(): void {\n this.isSearchBoxFocused = true;\n }\n\n @XOn('UserBlurredSearchBox')\n onUserBlurredSearchBox(): void {\n this.isSearchBoxFocused = false;\n }\n\n beforeDestroy(): void {\n this.stopAnimationInterval();\n }\n }\n</script>\n\n<style lang=\"scss\">\n .x-search-input-placeholder-container {\n position: relative;\n }\n</style>\n\n<style lang=\"scss\" scoped>\n .x-search-input-placeholder {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n }\n</style>\n\n<docs lang=\"mdx\">\n## See it in action\n\nHere a basic example of how the animated search input placeholder is rendered.\n\n```vue live\n<template>\n <div style=\"position: relative; overflow: hidden;\">\n <SearchInputPlaceholder\n style=\"position: absolute; height: 100%; pointer-events: none;\"\n :messages=\"placeholderMessages\"\n />\n <SearchInput />\n </div>\n</template>\n\n<script>\n import { SearchInput, SearchInputPlaceholder } from '@empathyco/x-components/search-box';\n\n export default {\n name: 'SearchInputPlaceholderDemo',\n components: {\n SearchInput,\n SearchInputPlaceholder\n },\n data: function () {\n return {\n placeholderMessages: [\n 'Find shirts',\n 'Find shoes',\n 'Find watches',\n 'Find handbags',\n 'Find sunglasses'\n ]\n };\n }\n };\n</script>\n```\n\n### Animating only on hover\n\nIn this example, the placeholder is configured to animate only when the user hovers in the search\ninput, showing the first message of the array the rest of the time.\n\n```vue live\n<template>\n <div style=\"position: relative; overflow: hidden;\">\n <SearchInputPlaceholder\n style=\"position: absolute; height: 100%; pointer-events: none;\"\n :messages=\"placeholderMessages\"\n :animate-only-on-hover=\"true\"\n />\n <SearchInput />\n </div>\n</template>\n\n<script>\n import { SearchInput, SearchInputPlaceholder } from '@empathyco/x-components/search-box';\n\n export default {\n name: 'SearchInputPlaceholderDemo',\n components: {\n SearchInput,\n SearchInputPlaceholder\n },\n data: function () {\n return {\n placeholderMessages: [\n 'Find shirts',\n 'Find shoes',\n 'Find watches',\n 'Find handbags',\n 'Find sunglasses'\n ]\n };\n }\n };\n</script>\n```\n</docs>\n"],"names":[],"mappings":";;;;;;AAEA,MAAc,cAAA,GAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"search-input-placeholder.vue.js","sources":["../../../../../src/x-modules/search-box/components/search-input-placeholder.vue"],"sourcesContent":["<template>\n <component\n :is=\"animation\"\n v-if=\"isVisible\"\n class=\"x-input-placeholder x-search-input-placeholder\"\n mode=\"out-in\"\n >\n <span :key=\"message\" data-test=\"search-input-placeholder\">\n {{ message }}\n </span>\n </component>\n</template>\n\n<script lang=\"ts\">\n import Vue from 'vue';\n import { Component, Prop, Watch } from 'vue-property-decorator';\n import { animateTranslate, State, xComponentMixin, XOn } from '../../../components';\n import { searchBoxXModule } from '../x-module';\n\n /**.\n * This component renders an animated placeholder for the search input in the shape of a list of\n * iterating messages that can be configured to happen always or only when hovering the input\n *\n * @public\n */\n @Component({\n mixins: [xComponentMixin(searchBoxXModule)]\n })\n export default class SearchInputPlaceholder extends Vue {\n /**\n * List of messages to animate.\n *\n * @public\n */\n @Prop({ required: true })\n protected messages!: Array<string>;\n\n /**\n * Animation component used for the messages.\n *\n * @public\n */\n @Prop({ default: () => animateTranslate('bottom-to-top') })\n protected animation!: Vue;\n\n /**\n * Time in milliseconds during which each message is visible.\n *\n * @public\n */\n @Prop({ default: 1500 })\n protected animationIntervalMs!: number;\n\n /**\n * Whether the messages animation is active only when hovering the search input or always.\n *\n * @public\n */\n @Prop({ default: false })\n protected animateOnlyOnHover!: boolean;\n\n /**.\n * The search box written query\n *\n * @internal\n */\n @State('searchBox', 'query')\n public query!: string;\n\n /**.\n * The search box hover status\n *\n * @internal\n */\n protected isSearchBoxHovered = false;\n\n /**.\n * The search box focus status\n *\n * @internal\n */\n protected isSearchBoxFocused = false;\n\n /**\n * The index used to point to the current animation message in the list.\n *\n * @internal\n */\n protected animationMessageIndex = 0;\n\n /**\n * The interval used for the animation.\n *\n * @internal\n */\n protected animationInterval: number | undefined;\n\n /**\n * The visibility state of the component.\n *\n * @returns The visibility state based on the search input state (query & focus).\n *\n * @internal\n */\n protected get isVisible(): boolean {\n return !this.query && !this.isSearchBoxFocused;\n }\n\n /**\n * The animation state of the component.\n *\n * @returns Whether the animation is active or not.\n *\n * @internal\n */\n protected get isBeingAnimated(): boolean {\n return this.isVisible && (!this.animateOnlyOnHover || this.isSearchBoxHovered);\n }\n\n /**\n * The current placeholder message.\n *\n * @returns The message to display as placeholder at any moment.\n *\n * @internal\n */\n protected get message(): string | undefined {\n return this.isBeingAnimated ? this.messages[this.animationMessageIndex] : this.messages[0];\n }\n\n /**\n * Starts or stops the animation depending on the current animation state.\n *\n * @internal\n */\n @Watch('isBeingAnimated', { immediate: true })\n @Watch('messages', { deep: true })\n @Watch('animationIntervalMs')\n protected resetAnimation(): void {\n this.stopAnimationInterval();\n\n if (this.isBeingAnimated) {\n this.animationInterval = window.setInterval((): void => {\n this.incrementAnimationMessageIndex();\n }, this.animationIntervalMs);\n }\n }\n\n /**\n * Clears the interval used for the animation.\n *\n * @internal\n */\n protected stopAnimationInterval(): void {\n if (this.animationInterval) {\n clearInterval(this.animationInterval);\n this.animationInterval = undefined;\n }\n }\n\n /**\n * Increments animation message index; if the new index exceeds the messages list length, it is\n * reset to 0.\n *\n * @internal\n */\n protected incrementAnimationMessageIndex(): void {\n this.animationMessageIndex = (this.animationMessageIndex + 1) % this.messages.length;\n }\n\n /**\n * Sets the animation message index with the right value for the next future iteration when the\n * current one stops,assuring the user will see always a new message on each animation state\n * change.\n *\n * @internal\n */\n @Watch('isBeingAnimated', { immediate: true })\n protected prepareMessageIndexForNextAnimation(): void {\n if (!this.isBeingAnimated) {\n if (this.animateOnlyOnHover) {\n this.resetAnimationMessageIndex();\n }\n this.incrementAnimationMessageIndex();\n }\n }\n\n /**\n * Resets the animation message index to zero.\n *\n * @internal\n */\n @Watch('messages', { deep: true })\n protected resetAnimationMessageIndex(): void {\n this.animationMessageIndex = 0;\n }\n\n // TODO: EX-7173 - Get search input state(s) from the store instead of using events\n @XOn('UserHoveredInSearchBox')\n onUserHoveredInSearchBox(): void {\n this.isSearchBoxHovered = true;\n }\n\n @XOn('UserHoveredOutSearchBox')\n onUserHoveredOutSearchBox(): void {\n this.isSearchBoxHovered = false;\n }\n\n @XOn('UserFocusedSearchBox')\n onUserFocusedSearchBox(): void {\n this.isSearchBoxFocused = true;\n }\n\n @XOn('UserBlurredSearchBox')\n onUserBlurredSearchBox(): void {\n this.isSearchBoxFocused = false;\n }\n\n beforeDestroy(): void {\n this.stopAnimationInterval();\n }\n }\n</script>\n\n<style lang=\"scss\">\n .x-search-input-placeholder-container {\n position: relative;\n }\n</style>\n\n<style lang=\"scss\" scoped>\n .x-search-input-placeholder {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n pointer-events: none;\n }\n</style>\n\n<docs lang=\"mdx\">\n## See it in action\n\nHere a basic example of how the animated search input placeholder is rendered.\n\n```vue live\n<template>\n <div style=\"position: relative; overflow: hidden;\">\n <SearchInputPlaceholder\n style=\"position: absolute; height: 100%; pointer-events: none;\"\n :messages=\"placeholderMessages\"\n />\n <SearchInput />\n </div>\n</template>\n\n<script>\n import { SearchInput, SearchInputPlaceholder } from '@empathyco/x-components/search-box';\n\n export default {\n name: 'SearchInputPlaceholderDemo',\n components: {\n SearchInput,\n SearchInputPlaceholder\n },\n data: function () {\n return {\n placeholderMessages: [\n 'Find shirts',\n 'Find shoes',\n 'Find watches',\n 'Find handbags',\n 'Find sunglasses'\n ]\n };\n }\n };\n</script>\n```\n\n### Animating only on hover\n\nIn this example, the placeholder is configured to animate only when the user hovers in the search\ninput, showing the first message of the array the rest of the time.\n\n```vue live\n<template>\n <div style=\"position: relative; overflow: hidden;\">\n <SearchInputPlaceholder\n style=\"position: absolute; height: 100%; pointer-events: none;\"\n :messages=\"placeholderMessages\"\n :animate-only-on-hover=\"true\"\n />\n <SearchInput />\n </div>\n</template>\n\n<script>\n import { SearchInput, SearchInputPlaceholder } from '@empathyco/x-components/search-box';\n\n export default {\n name: 'SearchInputPlaceholderDemo',\n components: {\n SearchInput,\n SearchInputPlaceholder\n },\n data: function () {\n return {\n placeholderMessages: [\n 'Find shirts',\n 'Find shoes',\n 'Find watches',\n 'Find handbags',\n 'Find sunglasses'\n ]\n };\n }\n };\n</script>\n```\n</docs>\n"],"names":[],"mappings":";;;;;;AAEA,MAAc,cAAA,GAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createInjector, createInjectorSSR } from 'vue-runtime-helpers';
|
|
2
2
|
|
|
3
|
-
var css = ".x-search-input-placeholder[data-v-
|
|
3
|
+
var css = ".x-search-input-placeholder[data-v-6a52742e] {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n display: flex;\n align-items: center;\n pointer-events: none;\n}";
|
|
4
4
|
const isBrowser = /*#__PURE__*/ (function () {
|
|
5
5
|
return (
|
|
6
6
|
Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) !==
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empathyco/x-components",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.320",
|
|
4
4
|
"description": "Empathy X Components",
|
|
5
5
|
"author": "Empathy Systems Corporation S.L.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -141,5 +141,5 @@
|
|
|
141
141
|
"access": "public",
|
|
142
142
|
"directory": "dist"
|
|
143
143
|
},
|
|
144
|
-
"gitHead": "
|
|
144
|
+
"gitHead": "fc3cdb5375414f4f647d77caf2ab493e80358d0c"
|
|
145
145
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-modal.vue?rollup-plugin-vue=script.d.ts","sourceRoot":"","sources":["../../../../src/components/modals/base-modal.vue?rollup-plugin-vue=script.ts"],"names":[],"mappings":"AAgCE,OAAO,GAAG,MAAM,KAAK,CAAC;;AAStB;;;;;GAKG;AAEH,MAAM,CAAC,OAAO,OAAO,SAAU,SAAQ,cAA2C;IAChF;;OAEG;IAEI,SAAS,EAAG,GAAG,GAAG,MAAM,CAAC;IAEhC;;;OAGG;IAEI,gBAAgB,EAAG,GAAG,GAAG,MAAM,CAAC;IAEvC;;OAEG;IAEI,IAAI,EAAG,OAAO,CAAC;IAEtB;;;OAGG;IAEI,WAAW,EAAG,OAAO,CAAC;IAE7B;;;;OAIG;IAEI,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAElC;;OAEG;IACH,SAAS,CAAC,oBAAoB,SAAM;IACpC;;OAEG;IACH,SAAS,CAAC,oBAAoB,SAAM;IACpC;;OAEG;IACH,SAAS,CAAC,iBAAiB,UAAS;IACpC;;OAEG;IACH,SAAS,CAAC,gBAAgB,EAAG,WAAW,CAAC;IAElC,KAAK,EAAG;QACb;;WAEG;QACH,KAAK,EAAE,cAAc,CAAC;QACtB;;WAEG;QACH,YAAY,EAAE,cAAc,CAAC;KAC9B,CAAC;IAEF,SAAS,CAAC,OAAO,IAAI,IAAI;IA8BzB;;;;;OAKG;IAEH,cAAc,IAAI,IAAI;IAOtB;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAqBzC;;;;OAIG;IACH,SAAS,CAAC,aAAa,IAAI,IAAI;IAM/B;;;;OAIG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAK9B;;;;OAIG;IACH,SAAS,CAAC,gBAAgB,IAAI,IAAI;
|
|
1
|
+
{"version":3,"file":"base-modal.vue?rollup-plugin-vue=script.d.ts","sourceRoot":"","sources":["../../../../src/components/modals/base-modal.vue?rollup-plugin-vue=script.ts"],"names":[],"mappings":"AAgCE,OAAO,GAAG,MAAM,KAAK,CAAC;;AAStB;;;;;GAKG;AAEH,MAAM,CAAC,OAAO,OAAO,SAAU,SAAQ,cAA2C;IAChF;;OAEG;IAEI,SAAS,EAAG,GAAG,GAAG,MAAM,CAAC;IAEhC;;;OAGG;IAEI,gBAAgB,EAAG,GAAG,GAAG,MAAM,CAAC;IAEvC;;OAEG;IAEI,IAAI,EAAG,OAAO,CAAC;IAEtB;;;OAGG;IAEI,WAAW,EAAG,OAAO,CAAC;IAE7B;;;;OAIG;IAEI,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAElC;;OAEG;IACH,SAAS,CAAC,oBAAoB,SAAM;IACpC;;OAEG;IACH,SAAS,CAAC,oBAAoB,SAAM;IACpC;;OAEG;IACH,SAAS,CAAC,iBAAiB,UAAS;IACpC;;OAEG;IACH,SAAS,CAAC,gBAAgB,EAAG,WAAW,CAAC;IAElC,KAAK,EAAG;QACb;;WAEG;QACH,KAAK,EAAE,cAAc,CAAC;QACtB;;WAEG;QACH,YAAY,EAAE,cAAc,CAAC;KAC9B,CAAC;IAEF,SAAS,CAAC,OAAO,IAAI,IAAI;IA8BzB;;;;;OAKG;IAEH,cAAc,IAAI,IAAI;IAOtB;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAqBzC;;;;OAIG;IACH,SAAS,CAAC,aAAa,IAAI,IAAI;IAM/B;;;;OAIG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAK9B;;;;OAIG;IACH,SAAS,CAAC,gBAAgB,IAAI,IAAI;IAalC;;;;OAIG;IACH,SAAS,CAAC,mBAAmB,IAAI,IAAI;IAMrC;;;;;OAKG;IACH,SAAS,CAAC,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAIrD;;;;;OAKG;IACH,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAMlD;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,IAAI,IAAI;CAU3B"}
|