@vc-shell/framework 1.0.38 → 1.0.39

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 (142) hide show
  1. package/components/atoms/vc-badge/vc-badge.stories.ts +27 -0
  2. package/components/atoms/vc-badge/vc-badge.vue +63 -0
  3. package/components/atoms/vc-button/vc-button.stories.ts +34 -0
  4. package/components/atoms/vc-button/vc-button.vue +219 -0
  5. package/components/atoms/vc-card/vc-card.vue +137 -0
  6. package/components/atoms/vc-checkbox/vc-checkbox.stories.ts +25 -0
  7. package/components/atoms/vc-checkbox/vc-checkbox.vue +130 -0
  8. package/components/atoms/vc-col/vc-col.vue +22 -0
  9. package/components/atoms/vc-container/vc-container.stories.ts +31 -0
  10. package/components/atoms/vc-container/vc-container.vue +220 -0
  11. package/components/atoms/vc-hint/vc-hint.stories.ts +23 -0
  12. package/components/atoms/vc-hint/vc-hint.vue +11 -0
  13. package/components/atoms/vc-icon/vc-icon.stories.ts +32 -0
  14. package/components/atoms/vc-icon/vc-icon.vue +36 -0
  15. package/components/atoms/vc-image/vc-image.stories.ts +40 -0
  16. package/components/atoms/vc-image/vc-image.vue +122 -0
  17. package/components/atoms/vc-info-row/vc-info-row.vue +42 -0
  18. package/components/atoms/vc-label/vc-label.stories.ts +23 -0
  19. package/components/atoms/vc-label/vc-label.vue +49 -0
  20. package/components/atoms/vc-link/vc-link.stories.ts +30 -0
  21. package/components/atoms/vc-link/vc-link.vue +46 -0
  22. package/components/atoms/vc-loading/vc-loading.vue +30 -0
  23. package/components/atoms/vc-progress/vc-progress.stories.ts +25 -0
  24. package/components/atoms/vc-progress/vc-progress.vue +65 -0
  25. package/components/atoms/vc-row/vc-row.vue +13 -0
  26. package/components/atoms/vc-status/vc-status.stories.ts +26 -0
  27. package/components/atoms/vc-status/vc-status.vue +78 -0
  28. package/components/atoms/vc-status-icon/vc-status-icon.vue +21 -0
  29. package/components/atoms/vc-switch/vc-switch.stories.ts +27 -0
  30. package/components/atoms/vc-switch/vc-switch.vue +100 -0
  31. package/components/atoms/vc-widget/vc-widget.vue +85 -0
  32. package/components/index.ts +43 -0
  33. package/components/molecules/vc-breadcrumbs/_internal/vc-breadcrumbs-item/vc-breadcrumbs-item.vue +103 -0
  34. package/components/molecules/vc-breadcrumbs/vc-breadcrumbs.stories.ts +39 -0
  35. package/components/molecules/vc-breadcrumbs/vc-breadcrumbs.vue +21 -0
  36. package/components/molecules/vc-editor/vc-editor.vue +117 -0
  37. package/components/molecules/vc-file-upload/vc-file-upload.vue +134 -0
  38. package/components/molecules/vc-form/vc-form.stories.ts +23 -0
  39. package/components/molecules/vc-form/vc-form.vue +5 -0
  40. package/components/molecules/vc-input/vc-input.stories.ts +26 -0
  41. package/components/molecules/vc-input/vc-input.vue +443 -0
  42. package/components/molecules/vc-multivalue/vc-multivalue.vue +447 -0
  43. package/components/molecules/vc-notification/vc-notification.vue +101 -0
  44. package/components/molecules/vc-pagination/vc-pagination.stories.ts +23 -0
  45. package/components/molecules/vc-pagination/vc-pagination.vue +169 -0
  46. package/components/molecules/vc-rating/vc-rating.stories.ts +23 -0
  47. package/components/molecules/vc-rating/vc-rating.vue +77 -0
  48. package/components/molecules/vc-select/vc-select.stories.ts +25 -0
  49. package/components/molecules/vc-select/vc-select.vue +402 -0
  50. package/components/molecules/vc-slider/vc-slider.vue +106 -0
  51. package/components/molecules/vc-textarea/vc-textarea.stories.ts +23 -0
  52. package/components/molecules/vc-textarea/vc-textarea.vue +155 -0
  53. package/components/organisms/vc-app/_internal/vc-app-bar/vc-app-bar.vue +146 -0
  54. package/components/organisms/vc-app/_internal/vc-app-menu/_internal/vc-app-menu-item/_internal/vc-app-menu-link.vue +148 -0
  55. package/components/organisms/vc-app/_internal/vc-app-menu/_internal/vc-app-menu-item/vc-app-menu-item.vue +157 -0
  56. package/components/organisms/vc-app/_internal/vc-app-menu/vc-app-menu.vue +110 -0
  57. package/components/organisms/vc-app/vc-app.stories.ts +75 -0
  58. package/components/organisms/vc-app/vc-app.vue +171 -0
  59. package/components/organisms/vc-blade/_internal/vc-blade-header/vc-blade-header.vue +126 -0
  60. package/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-button/vc-blade-toolbar-button.vue +223 -0
  61. package/components/organisms/vc-blade/_internal/vc-blade-toolbar/vc-blade-toolbar.vue +67 -0
  62. package/components/organisms/vc-blade/vc-blade.stories.ts +46 -0
  63. package/components/organisms/vc-blade/vc-blade.vue +87 -0
  64. package/components/organisms/vc-dynamic-property/vc-dynamic-property.vue +292 -0
  65. package/components/organisms/vc-gallery/_internal/vc-gallery-item/vc-gallery-item.vue +123 -0
  66. package/components/organisms/vc-gallery/_internal/vc-gallery-preview/vc-gallery-preview.vue +93 -0
  67. package/components/organisms/vc-gallery/vc-gallery.vue +186 -0
  68. package/components/organisms/vc-login-form/vc-login-form.stories.ts +55 -0
  69. package/components/organisms/vc-login-form/vc-login-form.vue +48 -0
  70. package/components/organisms/vc-popup/vc-popup.stories.ts +23 -0
  71. package/components/organisms/vc-popup/vc-popup.vue +97 -0
  72. package/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue +113 -0
  73. package/components/organisms/vc-table/_internal/vc-table-counter/vc-table-counter.vue +29 -0
  74. package/components/organisms/vc-table/_internal/vc-table-filter/vc-table-filter.vue +152 -0
  75. package/components/organisms/vc-table/_internal/vc-table-mobile-item/vc-table-mobile-item.vue +272 -0
  76. package/components/organisms/vc-table/vc-table.stories.ts +99 -0
  77. package/components/organisms/vc-table/vc-table.vue +638 -0
  78. package/core/api/index.ts +1 -0
  79. package/core/api/platform.ts +8332 -0
  80. package/core/composables/index.ts +8 -0
  81. package/core/composables/useAutosave/index.ts +57 -0
  82. package/core/composables/useFunctions/debounce.ts +18 -0
  83. package/core/composables/useFunctions/delay.ts +7 -0
  84. package/core/composables/useFunctions/index.ts +21 -0
  85. package/core/composables/useFunctions/once.ts +14 -0
  86. package/core/composables/useFunctions/sleep.ts +4 -0
  87. package/core/composables/useFunctions/throttle.ts +17 -0
  88. package/core/composables/useI18n/index.ts +28 -0
  89. package/core/composables/useLogger/index.ts +24 -0
  90. package/core/composables/useNotifications/index.ts +116 -0
  91. package/core/composables/usePermissions/index.ts +32 -0
  92. package/core/composables/useSettings/index.ts +36 -0
  93. package/core/composables/useUser/index.ts +266 -0
  94. package/core/directives/autofocus/index.ts +9 -0
  95. package/core/directives/click-outside/index.ts +21 -0
  96. package/core/directives/index.ts +4 -0
  97. package/core/directives/loading/index.ts +28 -0
  98. package/core/directives/permissions/index.ts +20 -0
  99. package/core/plugins/index.ts +1 -0
  100. package/core/plugins/validation/index.ts +2 -0
  101. package/core/plugins/validation/rules.ts +196 -0
  102. package/core/types/index.ts +92 -0
  103. package/core/utilities/camelToSnake.ts +7 -0
  104. package/core/utilities/index.ts +1 -0
  105. package/dist/core/composables/useNotifications/index.d.ts +1 -1
  106. package/dist/core/composables/useNotifications/index.d.ts.map +1 -1
  107. package/dist/core/composables/useUser/index.d.ts +2 -2
  108. package/dist/core/composables/useUser/index.d.ts.map +1 -1
  109. package/dist/core/plugins/validation/index.d.ts.map +1 -1
  110. package/dist/core/types/index.d.ts +1 -1
  111. package/dist/core/types/index.d.ts.map +1 -1
  112. package/dist/framework.js +70 -97
  113. package/dist/framework.js.map +1 -1
  114. package/dist/shared/app-switcher/composables/useAppSwitcher/index.d.ts +1 -1
  115. package/dist/shared/app-switcher/composables/useAppSwitcher/index.d.ts.map +1 -1
  116. package/dist/shared/app-switcher/index.d.ts +2 -2
  117. package/dist/shared/app-switcher/index.d.ts.map +1 -1
  118. package/dist/shared/blade-navigation/composables/useBladeNavigation/index.d.ts +1 -1
  119. package/dist/shared/blade-navigation/composables/useBladeNavigation/index.d.ts.map +1 -1
  120. package/dist/shared/blade-navigation/types/index.d.ts +1 -1
  121. package/dist/shared/blade-navigation/types/index.d.ts.map +1 -1
  122. package/dist/style.css +1 -1
  123. package/dist/tsconfig.tsbuildinfo +1 -0
  124. package/dist/vite.config.d.ts.map +1 -1
  125. package/package.json +11 -8
  126. package/shared/app-switcher/components/index.ts +1 -0
  127. package/shared/app-switcher/components/vc-app-switcher/vc-app-switcher.vue +90 -0
  128. package/shared/app-switcher/composables/index.ts +1 -0
  129. package/shared/app-switcher/composables/useAppSwitcher/index.ts +54 -0
  130. package/shared/app-switcher/index.ts +14 -0
  131. package/shared/assets/components/assets-details/assets-details.vue +138 -0
  132. package/shared/assets/components/index.ts +1 -0
  133. package/shared/assets/index.ts +19 -0
  134. package/shared/assets/locales/en.json +29 -0
  135. package/shared/assets/locales/index.ts +2 -0
  136. package/shared/blade-navigation/components/index.ts +1 -0
  137. package/shared/blade-navigation/components/vc-blade-navigation/vc-blade-navigation.vue +84 -0
  138. package/shared/blade-navigation/composables/index.ts +1 -0
  139. package/shared/blade-navigation/composables/useBladeNavigation/index.ts +216 -0
  140. package/shared/blade-navigation/index.ts +15 -0
  141. package/shared/blade-navigation/types/index.ts +52 -0
  142. package/shared/index.ts +16 -0
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Login Form component.
3
+ * @author Iurii A Taranov <me@flanker72.ru>
4
+ */
5
+ import { Story } from "@storybook/vue3";
6
+ import VcLoginForm from "./vc-login-form.vue";
7
+ import VcInput from "../../molecules/vc-input/vc-input.vue";
8
+ import VcButton from "../../atoms/vc-button/vc-button.vue";
9
+
10
+ export default {
11
+ title: "organisms/vc-login-form",
12
+ component: VcLoginForm,
13
+ };
14
+
15
+ const Template: Story = (args) => ({
16
+ components: { VcLoginForm, VcInput, VcButton },
17
+ setup() {
18
+ return { args };
19
+ },
20
+ template: `<vc-login-form v-bind="args">
21
+ <vc-input
22
+ ref="loginField"
23
+ class="mb-4 mt-1"
24
+ label="Username"
25
+ placeholder="Enter username"
26
+ ></vc-input>
27
+ <vc-input
28
+ ref="passwordField"
29
+ class="mb-4"
30
+ label="Password"
31
+ placeholder="Enter password"
32
+ type="password"
33
+ ></vc-input>
34
+ <div
35
+ class="
36
+ flex
37
+ justify-center
38
+ items-center
39
+ pt-2
40
+ "
41
+ >
42
+ <span class="grow basis-0"></span>
43
+ <vc-button variant="primary">
44
+ Submit
45
+ </vc-button>
46
+ </div>
47
+ </vc-login-form>`,
48
+ });
49
+
50
+ export const LoginForm = Template.bind({});
51
+ LoginForm.storyName = "vc-login-form";
52
+ LoginForm.args = {
53
+ background: "images/background.jpg",
54
+ logo: "images/logo-white.svg",
55
+ };
@@ -0,0 +1,48 @@
1
+ <template>
2
+ <div
3
+ class="w-full h-full box-border flex flex-col items-center justify-center"
4
+ :style="{
5
+ background: `url(${background}) center / cover no-repeat`,
6
+ }"
7
+ >
8
+ <div
9
+ class="h-[80px] w-[516px] max-w-[90%] mb-[50px] -mt-[90px]"
10
+ :style="{
11
+ background: `url(${logo}) center / contain no-repeat`,
12
+ }"
13
+ ></div>
14
+ <div
15
+ class="w-[516px] max-w-[90%] bg-white rounded-md overflow-hidden shadow-[0_0_0_rgba(0,0,0,0.05)]"
16
+ >
17
+ <div
18
+ class="uppercase text-white bg-[#465769] h-[50px] px-[28px] text-xl flex items-center"
19
+ >
20
+ {{ title }}
21
+ </div>
22
+ <div class="pt-4 px-[28px] pb-[24px]">
23
+ <slot></slot>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </template>
28
+
29
+ <script lang="ts" setup>
30
+ defineProps({
31
+ logo: {
32
+ type: String,
33
+ default: undefined,
34
+ },
35
+
36
+ background: {
37
+ type: String,
38
+ default: undefined,
39
+ },
40
+
41
+ title: {
42
+ type: String,
43
+ default: "Login",
44
+ },
45
+ });
46
+
47
+ console.debug("Init vc-login-form");
48
+ </script>
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Popup component.
3
+ * @author Iurii A Taranov <me@flanker72.ru>
4
+ */
5
+ import { Story } from "@storybook/vue3";
6
+ import VcPopup from "./vc-popup.vue";
7
+
8
+ export default {
9
+ title: "organisms/vc-popup",
10
+ component: VcPopup,
11
+ };
12
+
13
+ const Template: Story = (args) => ({
14
+ components: { VcPopup },
15
+ setup() {
16
+ return { args };
17
+ },
18
+ template: '<vc-popup v-bind="args"></vc-popup>',
19
+ });
20
+
21
+ export const Popup = Template.bind({});
22
+ Popup.storyName = "vc-popup";
23
+ Popup.args = {};
@@ -0,0 +1,97 @@
1
+ <template>
2
+ <div class="vc-popup" :class="`vc-popup_${variant}`">
3
+ <div class="vc-popup__wrapper">
4
+ <div class="vc-popup__inner">
5
+ <div class="vc-popup__header">
6
+ <div class="truncate grow basis-0">
7
+ <slot name="title">{{ title }}</slot>
8
+ </div>
9
+ <VcIcon
10
+ v-if="closable"
11
+ class="vc-popup__header-icon"
12
+ icon="fas fa-times"
13
+ @click="$emit('close')"
14
+ ></VcIcon>
15
+ </div>
16
+
17
+ <div class="vc-popup__content grow basis-0">
18
+ <slot></slot>
19
+ </div>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ </template>
24
+
25
+ <script lang="ts" setup>
26
+ defineProps({
27
+ title: {
28
+ type: String,
29
+ default: undefined,
30
+ },
31
+
32
+ closable: {
33
+ type: Boolean,
34
+ default: true,
35
+ },
36
+
37
+ variant: {
38
+ type: String,
39
+ default: "fullscreen",
40
+ enum: ["small", "medium", "fullscreen"],
41
+ },
42
+ });
43
+
44
+ defineEmits(["close"]);
45
+ </script>
46
+
47
+ <style lang="scss">
48
+ .vc-popup {
49
+ @apply fixed top-0 right-0 bottom-0 left-0 z-[9999] bg-[rgba(31,40,50,0.58)];
50
+
51
+ &_small {
52
+ .vc-popup__wrapper {
53
+ @apply max-h-fit items-center flex grow-0 shrink-0 basis-auto [flex-direction:inherit] justify-center;
54
+ }
55
+
56
+ .vc-popup__inner {
57
+ @apply max-w-[439px] w-full flex flex-col grow basis-0;
58
+ }
59
+ }
60
+
61
+ &_medium {
62
+ .vc-popup__wrapper {
63
+ @apply max-h-[75vh];
64
+ }
65
+ }
66
+
67
+ &_fullscreen {
68
+ .vc-popup__wrapper {
69
+ @apply max-h-[100vh];
70
+ }
71
+ }
72
+
73
+ &__wrapper {
74
+ @apply fixed top-2/4 -translate-y-2/4 right-0 bottom-0 left-0 flex grow shrink basis-auto flex-col h-full;
75
+
76
+ .vc-app_phone & {
77
+ @apply max-h-[100vh];
78
+ }
79
+ }
80
+
81
+ &__inner {
82
+ @apply grow shrink basis-auto m-[40px] box-border bg-white rounded-[5px] overflow-hidden relative flex flex-col grow basis-0;
83
+
84
+ .vc-app_phone & {
85
+ @apply m-0 rounded-none;
86
+ }
87
+ }
88
+
89
+ &__header {
90
+ @apply h-[44px] px-4 bg-[#eef5fa] flex shrink-0 items-center;
91
+
92
+ &-icon {
93
+ @apply cursor-pointer text-[#a1c0d4];
94
+ }
95
+ }
96
+ }
97
+ </style>
@@ -0,0 +1,113 @@
1
+ <template>
2
+ <!-- Money cell -->
3
+ <template v-if="cell.type === 'money'">
4
+ <template v-if="value > 0">
5
+ <span>{{ Math.trunc(Number(value)) }}</span
6
+ ><span class="text-[#a5a5a5] text-xs"
7
+ >.{{
8
+ `${(Number(value) * 100) % 100}`.padEnd(2, "0").slice(0, 2)
9
+ }}</span
10
+ >
11
+ </template>
12
+ <template v-else>
13
+ <span>N/A</span>
14
+ </template>
15
+ </template>
16
+
17
+ <!-- Date ago cell -->
18
+ <span v-else-if="cell.type === 'date-ago'" class="text-[#a5a5a5]">
19
+ <template v-if="value">
20
+ {{ moment(value).fromNow() }}
21
+ </template>
22
+ <template v-else>N/A</template>
23
+ </span>
24
+
25
+ <!-- Date exact cell -->
26
+ <span
27
+ v-else-if="
28
+ cell.type === 'date' || cell.type === 'time' || cell.type === 'date-time'
29
+ "
30
+ class="text-[#a5a5a5]"
31
+ >
32
+ <template v-if="value">
33
+ <template v-if="cell.format">
34
+ {{ moment(value).locale(locale).format(cell.format) }}
35
+ </template>
36
+ <template v-else>
37
+ <template v-if="cell.type === 'date'">{{
38
+ value.toLocaleDateString()
39
+ }}</template>
40
+ <template v-if="cell.type === 'time'">{{
41
+ value.toLocaleTimeString()
42
+ }}</template>
43
+ <template v-if="cell.type === 'date-time'">{{
44
+ value.toLocaleString()
45
+ }}</template>
46
+ </template>
47
+ </template>
48
+ <template v-else>N/A</template>
49
+ </span>
50
+
51
+ <!-- Image cell -->
52
+ <template v-else-if="cell.type === 'image'">
53
+ <VcImage
54
+ :bordered="true"
55
+ size="s"
56
+ aspect="1x1"
57
+ :src="value"
58
+ background="contain"
59
+ />
60
+ </template>
61
+
62
+ <!-- Status cell -->
63
+ <template v-else-if="cell.type === 'status'">
64
+ <VcStatus>{{ value }}</VcStatus>
65
+ </template>
66
+
67
+ <!-- Status icon cell -->
68
+ <div v-else-if="cell.type === 'status-icon'" class="flex justify-center">
69
+ <VcStatusIcon :status="value"></VcStatusIcon>
70
+ </div>
71
+
72
+ <!-- Number cell -->
73
+ <span v-else-if="cell.type === 'number'" class="text-right">
74
+ {{ Number(value).toFixed(0) }}
75
+ </span>
76
+
77
+ <!-- Link cell -->
78
+ <template v-else-if="cell.type === 'link'">
79
+ <VcLink>{{ value }}</VcLink>
80
+ </template>
81
+
82
+ <!-- Default cell -->
83
+ <span v-else>
84
+ {{ value }}
85
+ </span>
86
+ </template>
87
+
88
+ <script lang="ts" setup>
89
+ import { computed } from "vue";
90
+ import moment from "moment";
91
+ import { ITableColumns } from "@/core/types";
92
+ import { VcImage, VcStatus, VcStatusIcon, VcLink } from "@/components";
93
+
94
+ export interface Props {
95
+ cell: ITableColumns;
96
+ item: Record<string, unknown>;
97
+ }
98
+
99
+ const props = withDefaults(defineProps<Props>(), {
100
+ cell: undefined,
101
+ item: undefined,
102
+ });
103
+
104
+ const locale = window.navigator.language;
105
+ const value = computed(() =>
106
+ (props.cell.field || props.cell.id)
107
+ .split(".")
108
+ .reduce(
109
+ (p: { [x: string]: unknown }, c: string) => (p && p[c]) || null,
110
+ props.item
111
+ )
112
+ );
113
+ </script>
@@ -0,0 +1,29 @@
1
+ <template>
2
+ <div class="font-medium text-base">
3
+ <span class="text-[color:var(--table-counter-label-color)]"
4
+ >{{ label }}&nbsp;</span
5
+ >
6
+ <span class="text-[color:var(--table-counter-value-color)]">{{
7
+ value
8
+ }}</span>
9
+ </div>
10
+ </template>
11
+
12
+ <script lang="ts" setup>
13
+ export interface Props {
14
+ label: string;
15
+ value: number;
16
+ }
17
+
18
+ withDefaults(defineProps<Props>(), {
19
+ label: "Total",
20
+ value: 0,
21
+ });
22
+ </script>
23
+
24
+ <style lang="scss">
25
+ :root {
26
+ --table-counter-label-color: #465769;
27
+ --table-counter-value-color: #43b0e6;
28
+ }
29
+ </style>
@@ -0,0 +1,152 @@
1
+ <template>
2
+ <div class="relative overflow-visible">
3
+ <!-- Filter button -->
4
+ <div
5
+ class="rounded-[3px] bg-[#43b0e6] flex items-center px-[10px] text-white h-[38px] box-border cursor-pointer"
6
+ @click="openPanel($isMobile.value)"
7
+ ref="filterToggle"
8
+ >
9
+ <VcIcon icon="fas fa-filter" size="m" />
10
+ <span v-if="title" class="ml-[10px] font-medium">
11
+ {{ title }}
12
+ </span>
13
+ <div
14
+ v-if="counter"
15
+ class="ml-[10px] rounded-[10px] bg-white text-[#43b0e6] h-[20px] min-w-[20px] leading-[20px] text-center font-medium"
16
+ >
17
+ {{ counter }}
18
+ </div>
19
+ </div>
20
+
21
+ <!-- Filter panel -->
22
+ <teleport to="body">
23
+ <div
24
+ :class="{
25
+ 'vc-table-filter__panel_mobile fixed left-0 top-0 w-full bottom-0 z-[9999] bg-[rgba(128,140,153,0.6)] shadow-none rounded-none max-h-full max-w-full min-w-full':
26
+ $isMobile.value,
27
+ 'vc-table-filter__panel absolute max-h-[400px] max-w-[800px] min-w-[400px] z-[100] shadow-[1px_1px_11px_rgba(141,152,163,0.6)] rounded-[3px] overflow-hidden':
28
+ !$isMobile.value,
29
+ }"
30
+ v-if="isPanelVisible"
31
+ @click.self="closePanel"
32
+ ref="filterPanel"
33
+ >
34
+ <div
35
+ class="vc-table-filter__panel-inner bg-white box-border p-5 flex flex-col"
36
+ @click.stop
37
+ >
38
+ <VcIcon
39
+ class="vc-table-filter__panel-close text-[#43b0e6] cursor-pointer self-end shrink-0"
40
+ icon="fas fa-times"
41
+ size="xl"
42
+ @click="closePanel"
43
+ />
44
+
45
+ <slot :closePanel="closePanel"></slot>
46
+ </div>
47
+ </div>
48
+ </teleport>
49
+ </div>
50
+ </template>
51
+
52
+ <script lang="ts">
53
+ import { defineComponent, nextTick, ref, watch } from "vue";
54
+
55
+ export default defineComponent({
56
+ inheritAttrs: false,
57
+ });
58
+ </script>
59
+
60
+ <script lang="ts" setup>
61
+ import { createPopper, Instance } from "@popperjs/core";
62
+ import { VcIcon } from "@/components";
63
+
64
+ export interface Props {
65
+ title: string;
66
+ counter: number;
67
+ parentExpanded?: boolean;
68
+ }
69
+
70
+ const props = withDefaults(defineProps<Props>(), {
71
+ title: undefined,
72
+ counter: 0,
73
+ parentExpanded: true,
74
+ });
75
+
76
+ const isPanelVisible = ref(false);
77
+ const filterToggle = ref();
78
+ const filterPanel = ref();
79
+ const popper = ref<Instance>();
80
+
81
+ watch(
82
+ () => props.parentExpanded,
83
+ () => {
84
+ closePanel();
85
+ }
86
+ );
87
+
88
+ function openPanel(isMobile: boolean) {
89
+ isPanelVisible.value = !isPanelVisible.value;
90
+
91
+ if (!isMobile) {
92
+ const element = document.querySelector(".vc-blade");
93
+ if (isPanelVisible.value) {
94
+ nextTick(() => {
95
+ popper.value = createPopper(filterToggle.value, filterPanel.value, {
96
+ placement: "bottom-end",
97
+ modifiers: [
98
+ {
99
+ name: "offset",
100
+ options: {
101
+ offset: [0, 10],
102
+ },
103
+ },
104
+ {
105
+ name: "preventOverflow",
106
+ options: {
107
+ boundary: element,
108
+ },
109
+ },
110
+ ],
111
+ });
112
+ });
113
+ } else {
114
+ destroyPopper();
115
+ }
116
+ }
117
+ }
118
+
119
+ function closePanel() {
120
+ isPanelVisible.value = false;
121
+ destroyPopper();
122
+ }
123
+
124
+ function destroyPopper() {
125
+ // To prevent memory leaks Popper needs to be destroyed.
126
+ popper.value?.destroy();
127
+ }
128
+ </script>
129
+
130
+ <style lang="scss">
131
+ .vc-table-filter {
132
+ @apply relative overflow-visible;
133
+
134
+ &__panel {
135
+ &_mobile {
136
+ .vc-table-filter__panel {
137
+ &-inner {
138
+ @apply w-[280px] h-full;
139
+ }
140
+
141
+ &-close {
142
+ @apply self-start;
143
+ }
144
+ }
145
+
146
+ .vc-row {
147
+ @apply block;
148
+ }
149
+ }
150
+ }
151
+ }
152
+ </style>