@itfin/components 2.0.79 → 2.0.81

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.
@@ -0,0 +1,4 @@
1
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.000000" height="24.000000" fill="none">
2
+ <rect id="Filled/ai" width="24.000000" height="24.000000" x="0.000000" y="0.000000" fill="rgb(255,255,255)" fill-opacity="0" />
3
+ <path id="Vector" d="M17.7877 13.5465C17.7893 13.7995 17.7124 14.0468 17.5677 14.2543C17.4229 14.4619 17.2174 14.6194 16.9794 14.7054L12.9782 16.1839L11.5043 20.1882C11.4171 20.4253 11.2591 20.63 11.0519 20.7745C10.8447 20.9191 10.5981 20.9966 10.3454 20.9966C10.0927 20.9966 9.84614 20.9191 9.6389 20.7745C9.43167 20.63 9.27375 20.4253 9.18647 20.1882L7.70328 16.1839L3.69898 14.71C3.46187 14.6228 3.25723 14.4649 3.11268 14.2576C2.96813 14.0504 2.89062 13.8038 2.89062 13.5511C2.89062 13.2984 2.96813 13.0519 3.11268 12.8446C3.25723 12.6374 3.46187 12.4795 3.69898 12.3922L7.70328 10.909L9.17716 6.90469C9.26444 6.66757 9.42236 6.46293 9.62959 6.31839C9.83683 6.17384 10.0834 6.09633 10.3361 6.09633C10.5888 6.09633 10.8354 6.17384 11.0426 6.31839C11.2498 6.46293 11.4077 6.66757 11.495 6.90469L12.9782 10.909L16.9825 12.3829C17.2207 12.4696 17.4261 12.6281 17.5703 12.8365C17.7145 13.045 17.7905 13.293 17.7877 13.5465ZM13.4437 6.09949L14.6848 6.09949L14.6848 7.34065C14.6848 7.50524 14.7502 7.66308 14.8666 7.77947C14.983 7.89585 15.1408 7.96123 15.3054 7.96123C15.47 7.96123 15.6278 7.89585 15.7442 7.77947C15.8606 7.66308 15.926 7.50524 15.926 7.34065L15.926 6.09949L17.1671 6.09949C17.3317 6.09949 17.4896 6.0341 17.606 5.91772C17.7223 5.80134 17.7877 5.64349 17.7877 5.47891C17.7877 5.31432 17.7223 5.15647 17.606 5.04009C17.4896 4.92371 17.3317 4.85833 17.1671 4.85833L15.926 4.85833L15.926 3.61716C15.926 3.45257 15.8606 3.29473 15.7442 3.17835C15.6278 3.06196 15.47 2.99658 15.3054 2.99658C15.1408 2.99658 14.983 3.06196 14.8666 3.17835C14.7502 3.29473 14.6848 3.45257 14.6848 3.61716L14.6848 4.85833L13.4437 4.85833C13.2791 4.85833 13.1212 4.92371 13.0048 5.04009C12.8885 5.15647 12.8231 5.31432 12.8231 5.47891C12.8231 5.64349 12.8885 5.80134 13.0048 5.91772C13.1212 6.0341 13.2791 6.09949 13.4437 6.09949ZM20.27 8.58181L19.6495 8.58181L19.6495 7.96123C19.6495 7.79664 19.5841 7.63879 19.4677 7.52241C19.3513 7.40603 19.1935 7.34065 19.0289 7.34065C18.8643 7.34065 18.7064 7.40603 18.5901 7.52241C18.4737 7.63879 18.4083 7.79664 18.4083 7.96123L18.4083 8.58181L17.7877 8.58181C17.6231 8.58181 17.4653 8.64719 17.3489 8.76357C17.2325 8.87996 17.1671 9.0378 17.1671 9.20239C17.1671 9.36698 17.2325 9.52483 17.3489 9.64121C17.4653 9.75759 17.6231 9.82297 17.7877 9.82297L18.4083 9.82297L18.4083 10.4436C18.4083 10.6081 18.4737 10.766 18.5901 10.8824C18.7064 10.9988 18.8643 11.0641 19.0289 11.0641C19.1935 11.0641 19.3513 10.9988 19.4677 10.8824C19.5841 10.766 19.6495 10.6081 19.6495 10.4436L19.6495 9.82297L20.27 9.82297C20.4346 9.82297 20.5925 9.75759 20.7089 9.64121C20.8252 9.52483 20.8906 9.36698 20.8906 9.20239C20.8906 9.0378 20.8252 8.87996 20.7089 8.76357C20.5925 8.64719 20.4346 8.58181 20.27 8.58181Z" fill="currentColor" fill-rule="nonzero" />
4
+ </svg>
@@ -0,0 +1,27 @@
1
+ <svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32.000000" height="32.000000" fill="none" clip-path="url(#clipPath_0)" customFrame="url(#clipPath_0)">
2
+ <defs>
3
+ <clipPath id="clipPath_0">
4
+ <rect width="32.000000" height="32.000000" x="0.000000" y="0.000000" rx="6.153846" fill="rgb(255,255,255)" />
5
+ </clipPath>
6
+ </defs>
7
+ <rect id="start" width="32.000000" height="32.000000" x="0.000000" y="0.000000" rx="6.153846" />
8
+ <path id="Vector" d="M22.8126 9.55948C22.7556 9.49796 22.6869 9.44902 22.6108 9.41564C22.5348 9.38226 22.4529 9.36515 22.3701 9.36533L22.3653 9.36533C22.1623 9.40866 21.9797 9.48171 21.8173 9.58448L21.8246 9.58031C21.5497 9.72252 21.2585 9.88194 20.9511 10.0586C20.617 10.2472 20.2663 10.4031 19.9038 10.5244L19.8592 10.5377C19.4846 10.674 19.0908 10.7466 18.6934 10.7527L18.6901 10.7527L18.6495 10.7535C18.3467 10.7535 18.0602 10.6819 17.8052 10.5535L17.8166 10.5585C17.1534 10.2247 16.4688 9.93765 15.7676 9.69946L15.6425 9.66197C15.0154 9.46353 14.3626 9.3638 13.7063 9.36617L13.6536 9.36617L13.656 9.36617C12.1713 9.43417 10.7233 9.86189 9.43046 10.6144L9.47673 10.5894C9.152 10.7543 8.92307 10.8818 8.77369 10.976L8.62513 9.85861C8.87777 9.63392 9.05479 9.33306 9.13092 8.99897C9.20706 8.66488 9.17842 8.31464 9.04909 7.99825C8.91976 7.68186 8.69635 7.41549 8.41076 7.23717C8.12516 7.05885 7.79198 6.97769 7.45877 7.00527C7.12556 7.03286 6.80936 7.16778 6.55531 7.39078C6.30125 7.61378 6.12233 7.91345 6.04407 8.24703C5.96582 8.5806 5.99224 8.93102 6.11957 9.24827C6.24689 9.56551 6.4686 9.83337 6.75306 10.0136L6.75955 10.0178L8.90277 26.1701C8.96691 26.6409 9.35658 26.9992 9.82744 27C9.8729 27 9.91837 26.9969 9.9622 26.9908L9.95733 26.9917C10.0798 26.9752 10.1979 26.934 10.3048 26.8704C10.4117 26.8068 10.5052 26.7222 10.5801 26.6213C10.655 26.5205 10.7096 26.4054 10.741 26.2828C10.7723 26.1602 10.7797 26.0324 10.7627 25.9068L10.7635 25.9118L9.90132 19.42C11.1393 18.7113 12.5183 18.3013 13.9337 18.221L13.9588 18.2202L13.9661 18.2202C14.4686 18.2202 14.9533 18.3018 15.4063 18.4535L15.373 18.4443C15.7821 18.5697 16.1772 18.739 16.5518 18.9492L16.5201 18.9326C16.8238 19.1084 17.1793 19.2734 17.5495 19.4067L17.5966 19.4217C17.9611 19.5617 18.3825 19.6433 18.8217 19.6467L18.8233 19.6467C20.1328 19.5616 21.4021 19.1488 22.5203 18.4443L22.4854 18.4651C22.6348 18.3901 22.7647 18.2965 22.8751 18.1843C22.9647 18.0745 23.0089 17.9331 22.9985 17.7902L22.9985 17.7919L22.9985 10.0136C22.9988 9.92914 22.9824 9.84551 22.9503 9.76774C22.9182 9.68998 22.8711 9.6197 22.8118 9.56115L22.8126 9.55948Z" opacity="0" fill="currentColor" fill-rule="nonzero" />
9
+ <path id="Vector" d="M9.26667 17.1765L9.26667 23.8823C9.26667 24.199 9.15787 24.4646 8.94027 24.6792C8.72267 24.8938 8.45369 25.0007 8.13333 25C7.81298 24.9993 7.544 24.892 7.3264 24.6781C7.1088 24.4643 7 24.199 7 23.8823L7 7.11765C7 6.80098 7.1088 6.53573 7.3264 6.32188C7.544 6.10804 7.81298 6.00075 8.13333 6L16.265 6C16.5294 6 16.7656 6.08382 16.9733 6.25147C17.1811 6.41912 17.3133 6.63333 17.37 6.89412L17.6533 8.23529L22.8667 8.23529C23.1878 8.23529 23.4571 8.34259 23.6747 8.55718C23.8923 8.77176 24.0008 9.03702 24 9.35294L24 18.2941C24 18.6108 23.8912 18.8764 23.6736 19.091C23.456 19.3056 23.187 19.4125 22.8667 19.4118L17.0017 19.4118C16.7372 19.4118 16.5011 19.3279 16.2933 19.1603C16.0856 18.9926 15.9533 18.7784 15.8967 18.5176L15.6133 17.1765L9.26667 17.1765Z" opacity="0" fill="currentColor" fill-rule="nonzero" />
10
+ <path id="Vector" d="M16.1098 10.0207L26.7746 13.7236C27.0751 13.8338 27.0751 14.2764 26.7746 14.3866L25.0518 14.9672L25.0518 16.957C25.2158 17.0403 25.3524 17.2061 25.3524 17.3987L25.3524 18.145C25.3524 18.3108 25.2699 18.4487 25.1334 18.5321L25.5164 19.3608C25.0518 19.6099 24.3957 19.6099 23.9302 19.3608L24.2858 18.5321C24.1767 18.4487 24.0942 18.3108 24.0942 18.145L24.0942 17.3987C24.0942 17.2052 24.2033 17.0394 24.3673 16.957L24.3673 15.2162L16.1092 18.0896C16.0267 18.1173 15.9726 18.1173 15.8902 18.0896L5.22544 14.3867C4.92485 14.2765 4.92485 13.8339 5.22544 13.7237L15.8902 10.0208C15.9726 9.99306 16.0267 9.99306 16.1092 10.0208L16.1098 10.0207ZM22.3172 16.6247L22.3172 21.0729C18.1066 23.6424 13.8948 23.6424 9.68414 21.0729L9.68414 16.6247L15.6725 18.697C15.8915 18.7803 16.1097 18.7803 16.3287 18.697L22.3172 16.6247Z" opacity="0" fill="currentColor" fill-rule="evenodd" />
11
+ <g id="Group">
12
+ <g id="Group">
13
+ <path id="Vector" d="M16 6C10.4842 6 6 10.4842 6 16C6 21.5158 10.4842 26 16 26C21.5158 26 26 21.5158 26 16C26 10.4842 21.5158 6 16 6ZM20.0421 12.8421L16.7789 20.9895C16.5474 21.6 15.6632 21.5368 15.4947 20.9053L14.6737 17.7684C14.6105 17.5368 14.4211 17.3474 14.1895 17.2842L11.0526 16.4632C10.4211 16.2947 10.3789 15.4316 10.9684 15.1789L19.1579 11.9579C19.7053 11.7474 20.2526 12.2947 20.0421 12.8421Z" fill="currentColor" fill-rule="nonzero" />
14
+ </g>
15
+ </g>
16
+ <g id="Group" opacity="0">
17
+ <path id="Vector" d="M24 8L21 8" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
18
+ <path id="Vector" d="M0 0L4 0" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" transform="matrix(0,1,-1,0,17,6)" />
19
+ <path id="Vector" d="M17 8L6 8" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
20
+ <path id="Vector" d="M10 15L6 15" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
21
+ <path id="Vector" d="M0 0L4 0" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" transform="matrix(0,1,-1,0,14,13)" />
22
+ <path id="Vector" d="M25 15L14 15" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
23
+ <path id="Vector" d="M24 22L21 22" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
24
+ <path id="Vector" d="M0 0L4 0" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" transform="matrix(0,1,-1,0,17,20)" />
25
+ <path id="Vector" d="M17 22L6 22" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
26
+ </g>
27
+ </svg>
@@ -40,30 +40,44 @@
40
40
  <div v-show="!collapsed" class="b-panel-body">
41
41
  <slot></slot>
42
42
  </div>
43
+
44
+ <template v-if="!isMobile">
45
+ <itf-popover
46
+ v-for="step of popoversToRender"
47
+ :key="step.name"
48
+ :ref="`popover-${step.name}`"
49
+ :visible="step.isSequence ? true : step.visible"
50
+ :locator="step.locator"
51
+ :is-activator-highlighted="step.isActivatorHighlighted"
52
+ :trigger="step.isSequence ? 'manual' : 'click'"
53
+ :placement="step.placement || 'bottom'"
54
+ custom-class="onboarding-popover"
55
+ >
56
+ <div>
57
+ <div v-if="step.title" class="d-flex align-items-center gap-2 px-3 py-2 border-bottom border-secondary h6 mb-0">
58
+ <itf-icon v-if="step.titleIcon" new :name="step.titleIcon" />
59
+ {{ step.title }}
60
+ </div>
61
+ <div class="d-flex flex-column gap-3 p-3">
62
+ <div v-if="step.html" v-html="step.html" />
63
+ <div v-else-if="step.text">{{ step.text }}</div>
64
+ <div class="d-flex justify-content-between align-items-center">
65
+ <div>
66
+ <div v-if="step.isSequence && !step.isOutOfCount" class="py-1 px-2 rounded-3 text-white" style="background: #5981C0">
67
+ {{ currentOnboardingStepIndex + 1 }} <span class="opacity-50">з {{ sequenceOnboardingStepsCount }}</span>
68
+ </div>
69
+ </div>
70
+ <itf-button small secondary @click="onboardingStepProgress(step)">
71
+ {{ $t('components.iveGotIt') }}
72
+ </itf-button>
73
+ </div>
74
+ </div>
75
+ </div>
76
+ </itf-popover>
77
+ </template>
43
78
  </div>
44
79
  </template>
45
80
  <style lang="scss">
46
- @keyframes bellRing {
47
- 0% {
48
- transform: rotate(0deg);
49
- }
50
- 10% {
51
- transform: rotate(30deg);
52
- }
53
- 20% {
54
- transform: rotate(0deg);
55
- }
56
- 30% {
57
- transform: rotate(30deg);
58
- }
59
- 40% {
60
- transform: rotate(0deg);
61
- }
62
- 100% {
63
- transform: rotate(0deg);
64
- }
65
- }
66
-
67
81
  .b-panel {
68
82
  --b-panel-bg: var(--bs-body-bg);
69
83
  --b-panel-color: var(--bs-body-color);
@@ -165,14 +179,16 @@
165
179
  }
166
180
  </style>
167
181
  <script>
168
- import { Vue, Prop, Component } from 'vue-property-decorator';
182
+ import { Vue, Prop, Component, Watch } from 'vue-property-decorator';
169
183
  import itfIcon from '@itfin/components/src/components/icon/Icon';
170
184
  import itfButton from '@itfin/components/src/components/button/Button.vue';
185
+ import itfPopover from '@itfin/components/src/components/popover/Popover';
171
186
 
172
187
  export default @Component({
173
188
  components: {
174
189
  itfIcon,
175
- itfButton
190
+ itfButton,
191
+ itfPopover,
176
192
  },
177
193
  directives: {
178
194
  },
@@ -195,6 +211,50 @@ class Panel extends Vue {
195
211
  @Prop(Boolean) animate;
196
212
  @Prop(Boolean) nocard;
197
213
 
214
+ onboardingSteps = [];
215
+ currentOnboardingStepIndex = 0;
216
+
217
+ @Watch('panel.inAppOnboarding', { deep: true })
218
+ onOnboardingDataChange() {
219
+ this.initOnboarding();
220
+ this.rebuildOnboardingPopovers(0);
221
+ }
222
+
223
+ @Watch('currentSequenceOnboardingStep', { deep: true })
224
+ onCurrentStepChange() {
225
+ this.$emit('onboarding-step-viewed', this.currentSequenceOnboardingStep);
226
+ }
227
+
228
+ mounted() {
229
+ this.initOnboarding();
230
+ }
231
+
232
+ get isMobile() {
233
+ return window.matchMedia('(max-width: 768px)').matches;
234
+ }
235
+
236
+ get sequenceOnboardingSteps() {
237
+ return this.onboardingSteps?.filter(s => s.isSequence) ?? [];
238
+ }
239
+
240
+ get staticOnboardingSteps() {
241
+ return this.onboardingSteps?.filter(s => !s.isSequence) ?? [];
242
+ }
243
+
244
+ get currentSequenceOnboardingStep() {
245
+ return this.sequenceOnboardingSteps?.[this.currentOnboardingStepIndex];
246
+ }
247
+
248
+ get popoversToRender() {
249
+ const list = [...this.staticOnboardingSteps.filter(s => !s.isFinished)];
250
+ if (this.currentSequenceOnboardingStep) list.push(this.currentSequenceOnboardingStep);
251
+ return list;
252
+ }
253
+
254
+ get sequenceOnboardingStepsCount() {
255
+ return this.sequenceOnboardingSteps.filter(s => !s.isOutOfCount).length;
256
+ }
257
+
198
258
  openPanel(...args) {
199
259
  this.$emit('open', args);
200
260
  }
@@ -214,5 +274,32 @@ class Panel extends Vue {
214
274
  closePanel() {
215
275
  this.$emit('close');
216
276
  }
277
+
278
+ initOnboarding() {
279
+ this.onboardingSteps = this.panel?.inAppOnboarding?.steps ?? [];
280
+ const firstUnfinishedIndex = this.sequenceOnboardingSteps.findIndex(s => !s.isFinished);
281
+ this.currentOnboardingStepIndex = firstUnfinishedIndex === -1 ? this.sequenceOnboardingSteps.length : firstUnfinishedIndex;
282
+ }
283
+
284
+ rebuildOnboardingPopovers(refreshDelay) {
285
+ this.popoversToRender.forEach(step => {
286
+ const popoverRef = this.$refs[`popover-${step.name}`];
287
+ if (popoverRef?.[0]) popoverRef[0].refresh(refreshDelay);
288
+ });
289
+ }
290
+
291
+ onboardingStepProgress(step) {
292
+ const popoverRef = this.$refs[`popover-${step.name}`];
293
+ if (popoverRef?.[0]) popoverRef[0].hide();
294
+
295
+ if (step.isSequence) {
296
+ const nextUnfinishedIndex = this.sequenceOnboardingSteps.findIndex((s, index) => {
297
+ return index > this.currentOnboardingStepIndex && !s.isFinished;
298
+ });
299
+ this.currentOnboardingStepIndex = nextUnfinishedIndex === -1 ? this.sequenceOnboardingSteps.length : nextUnfinishedIndex;
300
+ }
301
+
302
+ this.$emit('onboarding-progress', step);
303
+ }
217
304
  }
218
305
  </script>
@@ -10,6 +10,7 @@
10
10
  <template v-for="(panel, n) of panelsStack">
11
11
  <panel
12
12
  :key="n"
13
+ :ref="`panel-${panel.id}`"
13
14
  :index="n"
14
15
  :panel="panel"
15
16
  :title="panel.title"
@@ -27,6 +28,8 @@
27
28
  @collapse="collapsePanel(panel)"
28
29
  @close="closePanel(panel)"
29
30
  @open-menu="$emit('open-menu', panel.type, panel.payload)"
31
+ @onboarding-progress="$emit('onboarding-progress', $event)"
32
+ @onboarding-step-viewed="$emit('onboarding-step-viewed', $event)"
30
33
  >
31
34
  <template #before-header>
32
35
  <slot name="before-header" :panel="panel" :index="n" :payload="panel.payload"></slot>
@@ -163,7 +166,7 @@ $double-an-time: $an-time * 2;
163
166
  //}
164
167
  </style>
165
168
  <script lang="ts">
166
- import { Vue, Component, Prop } from 'vue-property-decorator';
169
+ import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
167
170
  import itfIcon from '../icon/Icon.vue';
168
171
  import Panel from './Panel.vue';
169
172
  import {hashToStack, stackToHash} from "@itfin/components/src/components/panels/helpers";
@@ -223,6 +226,17 @@ export default class PanelList extends Vue {
223
226
 
224
227
  nextId:number = 0;
225
228
 
229
+ @Watch('panels', { deep: true })
230
+ onPanelsPropChanged(newPanels: Record<string, Component>) {
231
+ this.panelsStack.forEach(stackedPanel => {
232
+ const newPanel = newPanels[stackedPanel.type];
233
+ if (newPanel && typeof newPanel.inAppOnboarding === 'function') {
234
+ const updatedOnboarding = newPanel.inAppOnboarding(this.$t.bind(this));
235
+ stackedPanel.inAppOnboarding = updatedOnboarding;
236
+ }
237
+ });
238
+ }
239
+
226
240
  created() {
227
241
  setRootPanelList(this);
228
242
  if (this.firstPanel) {
@@ -307,6 +321,7 @@ export default class PanelList extends Vue {
307
321
  isCollapsed: false,
308
322
  isCloseable: true,
309
323
  __events: {},
324
+ inAppOnboarding: panel.inAppOnboarding ? panel.inAppOnboarding(this.$t.bind(this)) : null,
310
325
  };
311
326
  if (!this.panelsStack.length || openIndex === 0) {
312
327
  newPanel.isCloseable = false;
@@ -369,6 +384,10 @@ export default class PanelList extends Vue {
369
384
  newPanel.payload = value;
370
385
  this.setPanelHash();
371
386
  }
387
+ newPanel.rebuildAllOnboardingPopovers = (refreshDelay?: number) => this.rebuildAllOnboardingPopovers(refreshDelay);
388
+ newPanel.rebuildPanelOnboardingPopovers = (panelId: string | number, refreshDelay?: number) => {
389
+ this.rebuildPanelOnboardingPopovers(panelId, refreshDelay);
390
+ }
372
391
  newStack.push(newPanel);
373
392
  this.panelsStack = newStack;
374
393
  this.ensureOnlyTwoOpenPanels(newPanel.id);
@@ -390,6 +409,7 @@ export default class PanelList extends Vue {
390
409
  async openPanel(type: string, payload: any, openIndex?: number) {
391
410
  await this.internalOpenPanel(type, payload, openIndex);
392
411
  this.setPanelHash();
412
+ if(openIndex) this.$nextTick(() => { this.rebuildAllOnboardingPopovers() });
393
413
  }
394
414
 
395
415
  emitEvent(event: string, ...args: any[]) {
@@ -418,6 +438,7 @@ export default class PanelList extends Vue {
418
438
  this.setPanelHash();
419
439
  this.emitEvent('panels.closed', panel);
420
440
  this.emitEvent('panels.changed', this.panelsStack);
441
+ this.$nextTick(() => { this.rebuildAllOnboardingPopovers() });
421
442
  }
422
443
 
423
444
  fullsizePanel(panel: IPanel) {
@@ -428,6 +449,7 @@ export default class PanelList extends Vue {
428
449
  }
429
450
  this.panelsStack = newStack;
430
451
  this.setPanelHash();
452
+ this.$nextTick(() => { this.rebuildAllOnboardingPopovers() });
431
453
  }
432
454
 
433
455
  get isFullSize() {
@@ -441,6 +463,7 @@ export default class PanelList extends Vue {
441
463
  this.panelsStack = newStack;
442
464
  this.ensureOnlyTwoOpenPanels(panel.id);
443
465
  this.setPanelHash();
466
+ this.$nextTick(() => { this.rebuildAllOnboardingPopovers() });
444
467
  }
445
468
 
446
469
  collapsePanel(panel: IPanel) {
@@ -455,6 +478,7 @@ export default class PanelList extends Vue {
455
478
  this.panelsStack = newStack;
456
479
  this.ensureOnlyTwoOpenPanels(panel.id);
457
480
  this.setPanelHash();
481
+ this.$nextTick(() => { this.rebuildAllOnboardingPopovers() });
458
482
  }
459
483
 
460
484
  getPanels(type) {
@@ -521,5 +545,16 @@ export default class PanelList extends Vue {
521
545
  element.classList.add('animate');
522
546
  }
523
547
  }
548
+
549
+ rebuildPanelOnboardingPopovers(panelId: string | number, refreshDelay?: number) {
550
+ const panelRef = this.$refs[`panel-${panelId}`];
551
+ if (panelRef?.[0]) panelRef[0].rebuildOnboardingPopovers(refreshDelay);
552
+ }
553
+
554
+ rebuildAllOnboardingPopovers(refreshDelay?: number) {
555
+ this.panelsStack.forEach((panel) => {
556
+ this.rebuildPanelOnboardingPopovers(panel.id, refreshDelay);
557
+ });
558
+ }
524
559
  }
525
560
  </script>
@@ -24,22 +24,26 @@ export default @Component({
24
24
  class itfPopover extends Vue {
25
25
  @PropSync('visible') value;
26
26
 
27
- @Prop({ type: String, default: 'bottom', validator: (value) => ['bottom', 'left', 'right', 'top'].includes(value) }) placement;
27
+ @Prop({ type: String, default: 'bottom', validator: (value) => ['bottom', 'left', 'right', 'top', 'auto'].includes(value) }) placement;
28
28
 
29
29
  @Prop({ type: String, default: 'click', validator: (value) => ['click', 'focus', 'hover', 'manual'].includes(value) }) trigger;
30
30
 
31
31
  @Prop({ type: String, default: '' }) customClass;
32
32
  @Prop({ type: Boolean }) appendToBody;
33
33
  @Prop({ type: Boolean }) appendToContext;
34
+ @Prop({ type: String }) locator;
35
+ @Prop({ type: Boolean, default: false }) isActivatorHighlighted;
34
36
 
35
37
  modalId = '';
36
-
37
38
  modalEl = null;
39
+ targetEl = null;
38
40
 
39
41
  ignoreUpdate = false; // потрібно щоб не оновлювалось visible декілька разів, бо буде баг коли вікно відкривається і одразу закривається
40
42
 
43
+ initTimeout = null;
44
+
41
45
  beforeDestroy() {
42
- this.hide();
46
+ this.destroy();
43
47
  }
44
48
 
45
49
  @Watch('value')
@@ -48,9 +52,26 @@ class itfPopover extends Vue {
48
52
  return;
49
53
  }
50
54
  if (newValue) {
51
- this.modalEl.show();
55
+ this.modalEl?.show();
52
56
  } else {
53
- this.modalEl.hide();
57
+ this.modalEl?.hide();
58
+ }
59
+ }
60
+
61
+ @Watch('locator')
62
+ onLocatorChanged(newValue, oldValue) {
63
+ if (newValue !== oldValue && newValue && this.modalEl) {
64
+ this.initPopover();
65
+ }
66
+ }
67
+
68
+ @Watch('isActivatorHighlighted')
69
+ onIsActivatorHighlightedChanged(newValue, oldValue) {
70
+ if (!this.targetEl) return;
71
+ if (newValue) {
72
+ this.targetEl.classList.add('pulsing');
73
+ } else {
74
+ this.targetEl.classList.remove('pulsing');
54
75
  }
55
76
  }
56
77
 
@@ -60,22 +81,62 @@ class itfPopover extends Vue {
60
81
  }
61
82
 
62
83
  async mounted() {
84
+ this.refresh(100);
85
+ }
86
+
87
+ destroy() {
88
+ if (this.initTimeout) {
89
+ clearTimeout(this.initTimeout);
90
+ this.initTimeout = null;
91
+ }
92
+ if (this.modalEl) {
93
+ this.modalEl.dispose();
94
+ this.modalEl = null;
95
+ }
96
+ if (this.targetEl) this.resetTargetEl();
97
+ }
98
+
99
+ refresh(delay = 300) {
100
+ this.destroy();
101
+
102
+ if (this.initTimeout) clearTimeout(this.initTimeout);
103
+ this.initTimeout = setTimeout(() => this.initPopover(), delay);
104
+ }
105
+
106
+ async initPopover() {
63
107
  if (typeof window === 'undefined') {
64
108
  return;
65
109
  }
66
- const el = this.$refs.popover;
110
+
111
+ // Remove listeners from the previous target element before finding the new one
112
+ if (this.modalEl) this.destroy();
113
+
114
+ // Determine target
115
+ if (this.locator) {
116
+ this.targetEl = document.querySelector(this.locator);
117
+ if (!this.targetEl) return;
118
+ } else {
119
+ this.targetEl = this.$el;
120
+ }
121
+
122
+ if (this.isActivatorHighlighted) this.targetEl.classList.add('pulsing');
123
+
124
+ const el = this.$refs.popover || "";
67
125
  const { default: Popover } = await import('bootstrap/js/src/popover');
68
126
 
127
+ if (this._isDestroyed) return;
128
+
69
129
  let context = document.body;
70
- if (this.appendToContext && this.$el instanceof Node && this.$el.parentNode) {
71
- context = this.$el.closest('.itf-append-context') || document.body;
72
- this.$el.parentNode.removeChild(this.$el);
73
- context.appendChild(this.$el); // should append only to body
74
- } else if (this.appendToBody && this.$el instanceof Node && this.$el.parentNode) {
75
- this.$el.parentNode.removeChild(this.$el);
76
- context.appendChild(this.$el); // should append only to body
130
+ if (this.appendToContext && this.targetEl instanceof Node && this.targetEl.parentNode) {
131
+ context = this.targetEl.closest('.itf-append-context') || document.body;
132
+ this.targetEl.parentNode.removeChild(this.targetEl);
133
+ context.appendChild(this.targetEl); // should append only to body
134
+ } else if (this.appendToBody && this.targetEl instanceof Node && this.targetEl.parentNode) {
135
+ this.targetEl.parentNode.removeChild(this.targetEl);
136
+ context.appendChild(this.targetEl); // should append only to body
77
137
  }
78
- this.modalEl = new Popover(this.$el, {
138
+
139
+ this.modalEl = new Popover(this.targetEl, {
79
140
  content: el,
80
141
  container: context,
81
142
  sanitize: false,
@@ -84,26 +145,38 @@ class itfPopover extends Vue {
84
145
  placement: this.placement,
85
146
  trigger: this.trigger,
86
147
  });
148
+
87
149
  this.onVisibleChanged(this.value);
88
- this.$el.addEventListener('shown.bs.popover', () => {
89
- this.ignoreUpdate = true;
90
- this.value = true;
91
- document.body.addEventListener('click', this.clickOutside);
92
- this.$nextTick(() => this.ignoreUpdate = false);
93
- });
94
- this.$el.addEventListener('hidden.bs.popover', () => {
95
- this.ignoreUpdate = true;
96
- this.value = false;
97
- document.body.removeEventListener('click', this.clickOutside);
98
- this.$nextTick(() => this.ignoreUpdate = false);
99
- });
150
+ this.targetEl.addEventListener('shown.bs.popover', this.handleShown);
151
+ this.targetEl.addEventListener('hidden.bs.popover', this.handleHidden);
152
+ }
153
+
154
+ resetTargetEl() {
155
+ this.targetEl.removeEventListener('shown.bs.popover', this.handleShown);
156
+ this.targetEl.removeEventListener('hidden.bs.popover', this.handleHidden);
157
+ this.targetEl.classList.remove('pulsing');
158
+ this.targetEl = null;
159
+ }
160
+
161
+ handleShown() {
162
+ this.ignoreUpdate = true;
163
+ this.value = true;
164
+ document.body.addEventListener('click', this.clickOutside);
165
+ this.$nextTick(() => this.ignoreUpdate = false);
166
+ }
167
+
168
+ handleHidden() {
169
+ this.ignoreUpdate = true;
170
+ this.value = false;
171
+ document.body.removeEventListener('click', this.clickOutside);
172
+ this.$nextTick(() => this.ignoreUpdate = false);
100
173
  }
101
174
 
102
175
  clickOutside(e) {
103
176
  if (this.trigger !== 'click' || !e.target) {
104
177
  return;
105
178
  }
106
- if (this.$el !== e.target && e.target.closest('.itf-popover') !== this.$refs.popover) {
179
+ if (this.targetEl !== e.target && e.target.closest('.itf-popover') !== this.$refs.popover) {
107
180
  this.hide();
108
181
  }
109
182
  }
@@ -117,7 +190,7 @@ class itfPopover extends Vue {
117
190
  hide() {
118
191
  if (this.modalEl) {
119
192
  // треба затримка щоб попав не показався знову через отримання фокусу
120
- setTimeout(() => this.modalEl.hide(), 10);
193
+ setTimeout(() => this.modalEl?.hide(), 10);
121
194
  }
122
195
  }
123
196
  }
@@ -4,7 +4,7 @@
4
4
  <div ref="container" class="table-row-template">
5
5
  <div accept-group="items" class="table-view-body-space" v-dropzone="{ payload: 0 }"></div>
6
6
  <div class="shadow-area"></div>
7
- <div class="table-view-header-value reserved sticky">
7
+ <div class="table-view-header-value reserved sticky" data-test="table-header-checkbox">
8
8
  <itf-checkbox v-if="indicatorType === 'checkbox' && visibleHeader && !noSelectAll" ungrouped value="all" v-model="selectAll" ref="selectAll" />
9
9
  </div>
10
10
 
package/src/locales/en.js CHANGED
@@ -154,4 +154,5 @@ module.exports = {
154
154
  value: 'Value',
155
155
  },
156
156
  passwordValidation: 'Password should contain at least 8 characters, including uppercase letters, lowercase letters, numbers, and special characters (e.g. @, $, !, %, *, ?, &)',
157
+ iveGotIt: 'I\'ve got it',
157
158
  };
package/src/locales/pl.js CHANGED
@@ -154,4 +154,5 @@ module.exports = {
154
154
  value: 'Wartość',
155
155
  },
156
156
  passwordValidation: 'Hasło powinno zawierać co najmniej 8 znaków, w tym wielkie i małe litery, cyfry oraz znaki specjalne (np. @, $, !, %, *, ?, &)',
157
+ iveGotIt: 'Rozumiem',
157
158
  };
package/src/locales/uk.js CHANGED
@@ -155,4 +155,5 @@ module.exports = {
155
155
  value: 'Значення',
156
156
  },
157
157
  passwordValidation: 'Пароль має містити принаймні 8 символів, включаючи великі літери, малі літери, цифри та спеціальні символи (@, $, !, %, *, ?, &)',
158
+ iveGotIt: 'Зрозуміло',
158
159
  };