@pocketprep/ui-kit 3.8.4 → 3.9.0

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 (159) hide show
  1. package/dist/@pocketprep/ui-kit.css +1 -1
  2. package/dist/@pocketprep/ui-kit.js +14469 -17731
  3. package/dist/@pocketprep/ui-kit.js.map +1 -1
  4. package/dist/@pocketprep/ui-kit.umd.cjs +19 -29
  5. package/dist/@pocketprep/ui-kit.umd.cjs.map +1 -1
  6. package/eslint.config.ts +38 -11
  7. package/lib/SVGDefinitions.vue +32 -35
  8. package/lib/components/Banners/Banner.vue +10 -14
  9. package/lib/components/Blobs/Blob.vue +6 -14
  10. package/lib/components/Blobs/BlobEmptyState.vue +9 -8
  11. package/lib/components/Blobs/blob.d.ts +1 -1
  12. package/lib/components/BundleIcons/BundleIcon.vue +36 -63
  13. package/lib/components/BundleIcons/bundleIcon.d.ts +1 -1
  14. package/lib/components/Bundles/BundleList.vue +71 -59
  15. package/lib/components/Bundles/BundleSearch.vue +93 -117
  16. package/lib/components/Bundles/PremiumPill.vue +6 -12
  17. package/lib/components/Buttons/Button.vue +32 -35
  18. package/lib/components/Buttons/Link.vue +32 -31
  19. package/lib/components/Buttons/Tab.vue +14 -17
  20. package/lib/components/Calendar/Calendar.vue +87 -85
  21. package/lib/components/Charts/Bar.vue +192 -263
  22. package/lib/components/Charts/Pie.vue +55 -61
  23. package/lib/components/Charts/highcharts-wrap.ts +81 -0
  24. package/lib/components/Controls/SegmentControl.vue +26 -24
  25. package/lib/components/Controls/Slider.vue +51 -47
  26. package/lib/components/Controls/ToggleSwitch.vue +33 -31
  27. package/lib/components/EmptyStates/EmptyState.vue +69 -73
  28. package/lib/components/Exams/ExamCard.vue +59 -47
  29. package/lib/components/Exams/ExamMenuCard.vue +30 -28
  30. package/lib/components/Filters/FilterDropdown.vue +83 -86
  31. package/lib/components/Filters/FilterOptions.vue +83 -88
  32. package/lib/components/Forms/Checkbox.vue +27 -27
  33. package/lib/components/Forms/CheckboxOption.vue +30 -30
  34. package/lib/components/Forms/Errors.vue +21 -24
  35. package/lib/components/Forms/Input.vue +71 -59
  36. package/lib/components/Forms/Radio.vue +2 -2
  37. package/lib/components/Forms/RadioButton.vue +8 -8
  38. package/lib/components/Forms/Select.vue +265 -257
  39. package/lib/components/Forms/Textarea.vue +49 -35
  40. package/lib/components/Icons/IconAccordionArrow.vue +7 -9
  41. package/lib/components/Icons/IconActivity.vue +7 -9
  42. package/lib/components/Icons/IconAdd.vue +7 -11
  43. package/lib/components/Icons/IconAddCircle.vue +7 -9
  44. package/lib/components/Icons/IconArrow.vue +7 -9
  45. package/lib/components/Icons/IconBarChart.vue +7 -9
  46. package/lib/components/Icons/IconCalendar.vue +7 -9
  47. package/lib/components/Icons/IconCalendarPicker.vue +7 -9
  48. package/lib/components/Icons/IconChat.vue +7 -9
  49. package/lib/components/Icons/IconCheck.vue +7 -9
  50. package/lib/components/Icons/IconClose.vue +7 -9
  51. package/lib/components/Icons/IconConcept.vue +1 -1
  52. package/lib/components/Icons/IconCorrect.vue +7 -9
  53. package/lib/components/Icons/IconEdit.vue +7 -11
  54. package/lib/components/Icons/IconExam.vue +7 -9
  55. package/lib/components/Icons/IconExternalLink.vue +7 -9
  56. package/lib/components/Icons/IconEyeHide.vue +7 -9
  57. package/lib/components/Icons/IconEyeShow.vue +7 -9
  58. package/lib/components/Icons/IconFilter.vue +7 -9
  59. package/lib/components/Icons/IconFilterActive.vue +7 -9
  60. package/lib/components/Icons/IconFlag.vue +7 -9
  61. package/lib/components/Icons/IconFlagContent.vue +8 -9
  62. package/lib/components/Icons/IconFlagFeedback.vue +8 -10
  63. package/lib/components/Icons/IconFlagFilled.vue +7 -9
  64. package/lib/components/Icons/IconFullView.vue +7 -9
  65. package/lib/components/Icons/IconFullViewActive.vue +7 -9
  66. package/lib/components/Icons/IconGridDrag.vue +2 -2
  67. package/lib/components/Icons/IconHandle.vue +7 -9
  68. package/lib/components/Icons/IconHeart.vue +7 -9
  69. package/lib/components/Icons/IconHelp.vue +7 -9
  70. package/lib/components/Icons/IconHighlight.vue +2 -2
  71. package/lib/components/Icons/IconHourglass.vue +7 -9
  72. package/lib/components/Icons/IconImage.vue +7 -9
  73. package/lib/components/Icons/IconIncorrect.vue +7 -9
  74. package/lib/components/Icons/IconInfo.vue +7 -9
  75. package/lib/components/Icons/IconKeyboard.vue +7 -9
  76. package/lib/components/Icons/IconLaunch.vue +7 -9
  77. package/lib/components/Icons/IconLevelUp.vue +7 -9
  78. package/lib/components/Icons/IconLightbulb.vue +7 -9
  79. package/lib/components/Icons/IconLightning.vue +7 -9
  80. package/lib/components/Icons/IconLink.vue +7 -9
  81. package/lib/components/Icons/IconList.vue +7 -9
  82. package/lib/components/Icons/IconLoading.vue +7 -9
  83. package/lib/components/Icons/IconLoading2.vue +11 -11
  84. package/lib/components/Icons/IconLock.vue +7 -9
  85. package/lib/components/Icons/IconMissedQuestions.vue +7 -9
  86. package/lib/components/Icons/IconMoon.vue +7 -9
  87. package/lib/components/Icons/IconPaginationArrow.vue +7 -9
  88. package/lib/components/Icons/IconPaginationArrowDouble.vue +7 -9
  89. package/lib/components/Icons/IconPassage.vue +7 -9
  90. package/lib/components/Icons/IconPencil.vue +7 -9
  91. package/lib/components/Icons/IconPeople.vue +7 -9
  92. package/lib/components/Icons/IconPercent.vue +7 -9
  93. package/lib/components/Icons/IconPerson.vue +8 -9
  94. package/lib/components/Icons/IconPresent.vue +7 -9
  95. package/lib/components/Icons/IconPreview.vue +7 -9
  96. package/lib/components/Icons/IconQuestions.vue +7 -9
  97. package/lib/components/Icons/IconQuick10.vue +7 -9
  98. package/lib/components/Icons/IconQuickActions.vue +2 -2
  99. package/lib/components/Icons/IconRecommendedFilter.vue +1 -1
  100. package/lib/components/Icons/IconRemoveCircle.vue +7 -9
  101. package/lib/components/Icons/IconReviewFlag.vue +7 -9
  102. package/lib/components/Icons/IconSearch.vue +7 -9
  103. package/lib/components/Icons/IconShare.vue +7 -9
  104. package/lib/components/Icons/IconSideBar.vue +7 -9
  105. package/lib/components/Icons/IconSideBarActive.vue +7 -9
  106. package/lib/components/Icons/IconStar.vue +1 -1
  107. package/lib/components/Icons/IconStopwatch.vue +7 -9
  108. package/lib/components/Icons/IconStrike.vue +7 -9
  109. package/lib/components/Icons/IconSubject.vue +7 -9
  110. package/lib/components/Icons/IconText.vue +7 -9
  111. package/lib/components/Icons/IconTimer.vue +8 -9
  112. package/lib/components/Icons/IconWarning.vue +7 -9
  113. package/lib/components/Icons/icon.d.ts +1 -1
  114. package/lib/components/Loaders/SkeletonLoader.vue +1 -5
  115. package/lib/components/Modal/Modal.vue +23 -29
  116. package/lib/components/Modal/ModalContainer.vue +135 -133
  117. package/lib/components/Onboarding/EmailAuth.vue +66 -70
  118. package/lib/components/Onboarding/MagicCodeEntry.vue +88 -83
  119. package/lib/components/Pagination/QuestionReviewPagination.vue +3 -3
  120. package/lib/components/Pagination/TablePagination.vue +47 -44
  121. package/lib/components/PhonePerson/PhonePerson.vue +18 -18
  122. package/lib/components/PhonePerson/phonePerson.d.ts +1 -1
  123. package/lib/components/Quiz/FlagToggle.vue +45 -44
  124. package/lib/components/Quiz/GlobalMetricsToggle.vue +29 -28
  125. package/lib/components/Quiz/KeyboardShortcutsButton.vue +16 -23
  126. package/lib/components/Quiz/KeyboardShortcutsModal.vue +36 -37
  127. package/lib/components/Quiz/Question/BuildListChoicesContainer.vue +65 -65
  128. package/lib/components/Quiz/Question/ChoicesContainer.vue +5 -5
  129. package/lib/components/Quiz/Question/DropdownExplanation.vue +5 -5
  130. package/lib/components/Quiz/Question/Explanation.vue +6 -6
  131. package/lib/components/Quiz/Question/MPMCChoicesContainer.vue +17 -17
  132. package/lib/components/Quiz/Question/MPMCRadioGroup.vue +2 -2
  133. package/lib/components/Quiz/Question/MatrixChoicesContainer.vue +39 -39
  134. package/lib/components/Quiz/Question/MatrixRadioGroup.vue +6 -6
  135. package/lib/components/Quiz/Question/MobileMatrixChoicesContainer.vue +27 -28
  136. package/lib/components/Quiz/Question/MobileMatrixRadioGroup.vue +2 -2
  137. package/lib/components/Quiz/Question/PassageAndImage.vue +3 -3
  138. package/lib/components/Quiz/Question/PassageAndImageDropdown.vue +7 -7
  139. package/lib/components/Quiz/Question/Paywall.vue +2 -2
  140. package/lib/components/Quiz/Question/QuestionContext.vue +1 -1
  141. package/lib/components/Quiz/Question/StatsSummary.vue +2 -2
  142. package/lib/components/Quiz/Question/Summary.vue +11 -11
  143. package/lib/components/Quiz/Question.vue +90 -82
  144. package/lib/components/Quiz/QuizContainer.vue +1 -1
  145. package/lib/components/Quiz/QuizProgressBar.vue +23 -23
  146. package/lib/components/Quiz/question.d.ts +3 -3
  147. package/lib/components/Search/Pill.vue +16 -19
  148. package/lib/components/Search/Search.vue +52 -47
  149. package/lib/components/SidePanels/SidePanel.vue +168 -174
  150. package/lib/components/Tables/Table.vue +135 -122
  151. package/lib/components/Tables/TableActions.vue +81 -76
  152. package/lib/components/Tables/table.d.ts +1 -1
  153. package/lib/components/Tags/Tag.vue +49 -39
  154. package/lib/components/Toasts/Toast.vue +44 -42
  155. package/lib/components/Tooltips/OverflowTooltip.vue +39 -45
  156. package/lib/components/Tooltips/Tooltip.vue +69 -70
  157. package/lib/directives.ts +4 -4
  158. package/lib/utils.ts +13 -12
  159. package/package.json +27 -28
@@ -29,7 +29,7 @@
29
29
  <slot />
30
30
  </div>
31
31
  <div
32
- v-if="$slots.subtext?.()"
32
+ v-if="$slots.subtext"
33
33
  v-dark="isDarkMode"
34
34
  class="toast__content-subtext"
35
35
  >
@@ -39,57 +39,59 @@
39
39
  </div>
40
40
  </template>
41
41
 
42
- <script lang="ts">
43
- import { Vue, Component, Prop, Emit } from 'vue-facing-decorator'
42
+ <script setup lang="ts">
44
43
  import Icon from '../Icons/Icon.vue'
45
- import { dark } from '../../directives'
46
-
47
- @Component({
48
- directives: {
49
- dark,
50
- },
51
- components: {
52
- Icon,
53
- },
44
+ import { dark as vDark } from '../../directives'
45
+ import { onMounted, ref, useTemplateRef } from 'vue'
46
+
47
+ const props = withDefaults(defineProps<{
48
+ showCloseButton?: boolean
49
+ isDarkMode?: boolean
50
+ right?: boolean
51
+ }>(), {
52
+ showCloseButton: true,
53
+ isDarkMode: false,
54
+ right: false,
54
55
  })
55
- export default class Toast extends Vue {
56
- @Prop({ default: true }) showCloseButton!: boolean
57
- @Prop({ default: false }) isDarkMode!: boolean
58
- @Prop({ default: false }) right!: boolean
59
56
 
60
- closeTimeout: NodeJS.Timeout | null = null
57
+ const emit = defineEmits<{
58
+ 'close': []
59
+ }>()
61
60
 
62
- mounted () {
63
- this.setCloseTimeout()
64
- const toastEl = this.$refs['toast'] as HTMLElement
61
+ const closeTimeout = ref<NodeJS.Timeout | null>(null)
62
+ const toastEl = useTemplateRef<HTMLElement>('toast')
65
63
 
66
- setTimeout(() => {
67
- toastEl.classList.add(`toast--visible${this.right ? '--right' : ''}`)
68
- }, 1)
69
- }
70
-
71
- setCloseTimeout () {
72
- this.closeTimeout = setTimeout(() => {
73
- const toastEl = this.$refs['toast'] as HTMLElement
74
- toastEl?.classList.add('toast--closing')
64
+ onMounted(() => {
65
+ setCloseTimeout()
75
66
 
76
- setTimeout(() => {
77
- this.emitClose()
78
- }, 300)
79
- }, 5000)
80
- }
67
+ setTimeout(() => {
68
+ if (toastEl.value) {
69
+ toastEl.value.classList.add(`toast--visible${props.right ? '--right' : ''}`)
70
+ }
71
+ }, 1)
72
+ })
81
73
 
82
- clearCloseTimeout () {
83
- if (this.closeTimeout) {
84
- clearTimeout(this.closeTimeout)
74
+ const setCloseTimeout = () => {
75
+ closeTimeout.value = setTimeout(() => {
76
+ if (toastEl.value) {
77
+ toastEl.value.classList.add('toast--closing')
85
78
  }
86
- }
87
79
 
88
- @Emit('close')
89
- emitClose () {
90
- return true
80
+ setTimeout(() => {
81
+ emitClose()
82
+ }, 300)
83
+ }, 5000)
84
+ }
85
+
86
+ const clearCloseTimeout = () => {
87
+ if (closeTimeout.value) {
88
+ clearTimeout(closeTimeout.value)
91
89
  }
92
90
  }
91
+
92
+ const emitClose = () => {
93
+ emit('close')
94
+ }
93
95
  </script>
94
96
 
95
97
  <style lang="scss" scoped>
@@ -230,4 +232,4 @@ export default class Toast extends Vue {
230
232
  }
231
233
  }
232
234
  }
233
- </style>
235
+ </style>
@@ -27,57 +27,51 @@
27
27
  </div>
28
28
  </template>
29
29
 
30
- <script lang="ts">
31
- import { Vue, Component } from 'vue-facing-decorator'
30
+ <script setup lang="ts">
31
+ import { nextTick, onMounted, onUnmounted, ref, useTemplateRef } from 'vue'
32
32
  import Tooltip from '../Tooltips/Tooltip.vue'
33
33
 
34
- @Component({
35
- components: {
36
- Tooltip,
37
- },
38
- })
39
- export default class OverflowTooltip extends Vue {
40
- showTooltip = false
41
- textOverflows = false
42
- measurementComplete = false
43
- uid = Math.floor(Math.random() * 1e9)
44
- intersectionObserver: IntersectionObserver | null = null
45
- isVisible = false
34
+ const showTooltip = ref(false)
35
+ const textOverflows = ref(false)
36
+ const measurementComplete = ref(false)
37
+ const uid = Math.floor(Math.random() * 1e9)
38
+ const intersectionObserver = ref<IntersectionObserver | null>(null)
39
+ const isVisible = ref(false)
40
+ const containerEl = useTemplateRef<HTMLDivElement>('uikit-overflow-tooltip')
41
+ const contentEl = useTemplateRef<HTMLElement>(`content_${uid}`)
42
+ const contentFullWidthEl = useTemplateRef<HTMLElement>(`content_fullwidth_${uid}`)
46
43
 
47
- mounted () {
48
- this.checkTextOverflows()
44
+ onMounted(() => {
45
+ checkTextOverflows()
49
46
 
50
- // Watch for changes in the element's visibility to recalculate whether the text overflows
51
- const containerEl = this.$refs['uikit-overflow-tooltip'] as HTMLDivElement | undefined
52
- if (containerEl) {
53
- this.intersectionObserver = new IntersectionObserver((entries) => {
54
- if (!this.isVisible && entries[0]?.isIntersecting) {
55
- this.measurementComplete = false
56
- this.$nextTick(() => {
57
- this.isVisible = true
58
- this.checkTextOverflows()
59
- })
60
- }
61
- })
62
- this.intersectionObserver.observe(containerEl)
63
- }
64
- }
65
-
66
- unmounted () {
67
- this.intersectionObserver?.disconnect()
47
+ // Watch for changes in the element's visibility to recalculate whether the text overflows
48
+ if (containerEl.value) {
49
+ intersectionObserver.value = new IntersectionObserver(entries => {
50
+ if (!isVisible.value && entries[0]?.isIntersecting) {
51
+ measurementComplete.value = false
52
+ nextTick(() => {
53
+ isVisible.value = true
54
+ checkTextOverflows()
55
+ })
56
+ }
57
+ })
58
+ intersectionObserver.value.observe(containerEl.value)
68
59
  }
60
+ })
69
61
 
70
- checkTextOverflows () {
71
- const content = this.$refs[`content_${this.uid}`] as HTMLElement
72
- const contentFullWidth = this.$refs[`content_fullwidth_${this.uid}`] as HTMLElement
62
+ onUnmounted(() => {
63
+ intersectionObserver.value?.disconnect()
64
+ })
73
65
 
74
- this.$nextTick(() => {
75
- const truncatedWidth = content.getBoundingClientRect().width
76
- const fullWidth = contentFullWidth.getBoundingClientRect().width
77
- this.textOverflows = truncatedWidth < fullWidth
78
- this.measurementComplete = true
79
- })
80
- }
66
+ const checkTextOverflows = () => {
67
+ nextTick(() => {
68
+ if (contentEl.value && contentFullWidthEl.value) {
69
+ const truncatedWidth = contentEl.value.getBoundingClientRect().width
70
+ const fullWidth = contentFullWidthEl.value.getBoundingClientRect().width
71
+ textOverflows.value = truncatedWidth < fullWidth
72
+ measurementComplete.value = true
73
+ }
74
+ })
81
75
  }
82
76
  </script>
83
77
 
@@ -105,4 +99,4 @@ export default class OverflowTooltip extends Vue {
105
99
  top: calc(-100% - 14px);
106
100
  }
107
101
  }
108
- </style>
102
+ </style>
@@ -7,7 +7,7 @@
7
7
  :id="`tooltip-${tooltipId}`"
8
8
  v-dark="isDarkMode"
9
9
  class="uikit-tooltip-popup"
10
- :class="{
10
+ :class="{
11
11
  'uikit-tooltip-popup--rightalign': theme === 'rightalign',
12
12
  'uikit-tooltip-popup--leftalign': theme === 'leftalign'
13
13
  }"
@@ -15,7 +15,7 @@
15
15
  <div
16
16
  v-dark="isDarkMode"
17
17
  class="uikit-tooltip-popup__triangle"
18
- :class="{
18
+ :class="{
19
19
  'uikit-tooltip-popup__triangle--rightalign': theme === 'rightalign',
20
20
  'uikit-tooltip-popup__triangle--leftalign': theme === 'leftalign',
21
21
  'uikit-tooltip-popup__triangle--offset': theme === 'offset'
@@ -28,78 +28,77 @@
28
28
  </div>
29
29
  </template>
30
30
 
31
- <script lang="ts">
32
- import { Component, Vue, Prop } from 'vue-facing-decorator'
33
- import { dark } from '../../directives'
34
-
35
- @Component({
36
- directives: {
37
- dark,
38
- },
31
+ <script setup lang="ts">
32
+ import { nextTick, onMounted, onUnmounted } from 'vue'
33
+ import { dark as vDark } from '../../directives'
34
+
35
+ const props = withDefaults(defineProps<{
36
+ theme?: 'leftalign' | 'rightalign' | 'offset' | ''
37
+ styles?: Record<string, string> | null
38
+ isDarkMode?: boolean
39
+ }>(), {
40
+ theme: '',
41
+ styles: null,
42
+ isDarkMode: false,
39
43
  })
40
- export default class Tooltip extends Vue {
41
- @Prop({ default: '' }) theme!: 'leftalign' | 'rightalign' | 'offset'
42
- @Prop({ default: null }) styles!: null | Record<string, string>
43
- @Prop({ default: false }) isDarkMode!: boolean
44
-
45
- tooltipId = Math.floor(Math.random() * 1000000)
46
-
47
- mounted () {
48
- this.$nextTick(() => {
49
- const tooltipEl = document.querySelector(`.uikit-tooltip-popup#tooltip-${this.tooltipId}`) as HTMLElement
50
- const body = document.querySelector('body') as HTMLElement
51
-
52
- // Get original positioning before adding element to body
53
- const clientRectTop = tooltipEl.getBoundingClientRect().top
54
- const clientRectLeft = tooltipEl.getBoundingClientRect().left
55
- const computedStyle = getComputedStyle(tooltipEl)
56
- const singleLineTooltipHeight = parseInt(computedStyle.lineHeight)
57
- + parseInt(computedStyle.paddingTop)
58
- + parseInt(computedStyle.paddingBottom)
59
-
60
- // Move element to body
61
- tooltipEl.parentNode?.removeChild(tooltipEl)
62
- body.appendChild(tooltipEl)
63
- tooltipEl.style.position = 'absolute'
64
- tooltipEl.style.zIndex = '1002'
65
-
66
- // Apply Prop styles
67
- const propStyle = this.styles
68
- if (propStyle) {
69
- Object.keys(propStyle).forEach(styleProp => {
70
- tooltipEl.style[styleProp as 'color'] = propStyle[styleProp] || ''
71
- })
72
- if (tooltipEl.style.backgroundColor) {
73
- const triangleEl = document.querySelector(
74
- `.uikit-tooltip-popup#tooltip-${this.tooltipId} .uikit-tooltip-popup__triangle`
75
- ) as HTMLElement
76
- triangleEl.style.borderColor = `${tooltipEl.style.backgroundColor} transparent transparent`
77
- }
44
+
45
+ const tooltipId = Math.floor(Math.random() * 1000000)
46
+
47
+ onMounted(() => {
48
+ nextTick(() => {
49
+ const tooltipEl = document.querySelector(`.uikit-tooltip-popup#tooltip-${tooltipId}`) as HTMLElement
50
+ const body = document.querySelector('body') as HTMLElement
51
+
52
+ // Get original positioning before adding element to body
53
+ const clientRectTop = tooltipEl.getBoundingClientRect().top
54
+ const clientRectLeft = tooltipEl.getBoundingClientRect().left
55
+ const computedStyle = getComputedStyle(tooltipEl)
56
+ const singleLineTooltipHeight = parseInt(computedStyle.lineHeight)
57
+ + parseInt(computedStyle.paddingTop)
58
+ + parseInt(computedStyle.paddingBottom)
59
+
60
+ // Move element to body
61
+ tooltipEl.parentNode?.removeChild(tooltipEl)
62
+ body.appendChild(tooltipEl)
63
+ tooltipEl.style.position = 'absolute'
64
+ tooltipEl.style.zIndex = '1002'
65
+
66
+ // Apply Prop styles
67
+ const propStyle = props.styles
68
+ if (propStyle) {
69
+ Object.keys(propStyle).forEach(styleProp => {
70
+ tooltipEl.style[styleProp as 'color'] = propStyle[styleProp] || ''
71
+ })
72
+ if (tooltipEl.style.backgroundColor) {
73
+ const triangleEl = document.querySelector(
74
+ `.uikit-tooltip-popup#tooltip-${tooltipId} .uikit-tooltip-popup__triangle`
75
+ ) as HTMLElement
76
+ triangleEl.style.borderColor = `${tooltipEl.style.backgroundColor} transparent transparent`
78
77
  }
78
+ }
79
79
 
80
- // Apply horizontal positioning before vertical positioning (because the height depends on text wrap)
81
- const tooltipWidth = tooltipEl.clientWidth
82
- const leftOffset = this.theme === 'rightalign'
83
- ? 20
84
- : this.theme === 'leftalign'
85
- ? tooltipWidth - 20
86
- : Math.floor(tooltipWidth / 2)
87
- const left = Math.round(clientRectLeft + window.pageXOffset - leftOffset)
88
- tooltipEl.style.left = `${left}px`
89
-
90
- // Apply vertical positioning
91
- const top = Math.round(clientRectTop + window.pageYOffset)
92
- - tooltipEl.clientHeight
93
- + singleLineTooltipHeight
94
- tooltipEl.style.top = `${top}px`
95
- })
96
- }
80
+ // Apply horizontal positioning before vertical positioning (because the height depends on text wrap)
81
+ const tooltipWidth = tooltipEl.clientWidth
82
+ const leftOffset = props.theme === 'rightalign'
83
+ ? 20
84
+ : props.theme === 'leftalign'
85
+ ? tooltipWidth - 20
86
+ : Math.floor(tooltipWidth / 2)
87
+ const left = Math.round(clientRectLeft + window.pageXOffset - leftOffset)
88
+ tooltipEl.style.left = `${left}px`
89
+
90
+ // Apply vertical positioning
91
+ const top = Math.round(clientRectTop + window.pageYOffset)
92
+ - tooltipEl.clientHeight
93
+ + singleLineTooltipHeight
94
+ tooltipEl.style.top = `${top}px`
95
+ })
96
+ })
97
97
 
98
- unmounted () {
99
- const tooltipEl = document.querySelector(`.uikit-tooltip-popup#tooltip-${this.tooltipId}`) as HTMLElement
100
- tooltipEl.remove()
101
- }
102
- }
98
+ onUnmounted(() => {
99
+ const tooltipEl = document.querySelector(`.uikit-tooltip-popup#tooltip-${tooltipId}`) as HTMLElement
100
+ tooltipEl.remove()
101
+ })
103
102
  </script>
104
103
 
105
104
  <style lang="scss">
package/lib/directives.ts CHANGED
@@ -207,15 +207,15 @@ export const breakpoint: Directive<HTMLElement, {
207
207
  updateBreakpointClasses(el, binding.value, getCustomContainer(binding))
208
208
  })
209
209
  },
210
- unmounted: (el) => {
210
+ unmounted: el => {
211
211
  removeBreakpointListeners(el)
212
212
  },
213
213
  }
214
214
 
215
215
  export const dark: Directive<HTMLElement> = (el, { value }: { value?: boolean }) => {
216
216
  const isDarkMode = !!value
217
- const classes = (typeof el.className === 'string'
218
- ? el.className
217
+ const classes = (typeof el.className === 'string'
218
+ ? el.className
219
219
  : (el.className as unknown as { baseVal: string }).baseVal).split(' ')
220
220
  if (isDarkMode) {
221
221
  if (classes.find(c => c.endsWith('--dark'))) {
@@ -231,4 +231,4 @@ export const dark: Directive<HTMLElement> = (el, { value }: { value?: boolean })
231
231
  }
232
232
  })
233
233
  }
234
- }
234
+ }
package/lib/utils.ts CHANGED
@@ -99,8 +99,8 @@ export const highlightKeywordsInText = (params: {
99
99
 
100
100
  // Create an array for all matching keywords and substrings with their start and end indexes
101
101
  const allMatches: { start: number; end: number; keyword: string; keywordMatch: string }[] = []
102
-
103
- sortedKeywords.forEach((keyword) => {
102
+
103
+ sortedKeywords.forEach(keyword => {
104
104
  const escapedKeyword = escapeRegex(keyword)
105
105
  const regex = new RegExp(`\\b${escapedKeyword}\\b`, 'gi')
106
106
 
@@ -108,7 +108,7 @@ export const highlightKeywordsInText = (params: {
108
108
  // This will include keyword matches that are substrings of other keywords
109
109
  // ie: keyword 'stakeholder' will match in a keyword string 'key stakeholder'
110
110
  const matches = Array.from(params.text.matchAll(regex))
111
- matches.forEach((match) => {
111
+ matches.forEach(match => {
112
112
  allMatches.push({
113
113
  start: match.index,
114
114
  end: match.index + match[0].length,
@@ -117,7 +117,7 @@ export const highlightKeywordsInText = (params: {
117
117
  })
118
118
  })
119
119
  })
120
-
120
+
121
121
  // Sort all matches by start index
122
122
  allMatches.sort((a, b) => a.start - b.start)
123
123
 
@@ -127,27 +127,28 @@ export const highlightKeywordsInText = (params: {
127
127
  // Create an array to track non-overlapping keyword matches
128
128
  const nonOverlappingMatches: { start: number; end: number; keyword: string; keywordMatch: string }[] = []
129
129
  // Do not include any matches that are substrings of other matches
130
- allMatches.forEach((match) => {
131
- const overlaps = highlightedRanges.some(range =>
130
+ allMatches.forEach(match => {
131
+ const overlaps = highlightedRanges.some(range =>
132
132
  (match.start < range.end && match.end > range.start)
133
133
  )
134
-
134
+
135
135
  if (!overlaps) {
136
136
  nonOverlappingMatches.push(match)
137
137
  highlightedRanges.push({ start: match.start, end: match.end })
138
138
  }
139
139
  })
140
-
140
+
141
141
  // Sort by start position again and process in reverse order to maintain positions
142
142
  nonOverlappingMatches.sort((a, b) => b.start - a.start)
143
143
 
144
144
  let result = params.text
145
145
 
146
- nonOverlappingMatches.forEach((match) => {
146
+ nonOverlappingMatches.forEach(match => {
147
147
  const beforeMatch = result.substring(0, match.start)
148
148
  const afterMatch = result.substring(match.end)
149
- const highlightedMatch = `<span class="keyword-highlight${params.isDarkMode
150
- ? ' keyword-highlight--dark' : ''}" data-location="${
149
+ const highlightedMatch = `<span class="keyword-highlight${params.isDarkMode
150
+ ? ' keyword-highlight--dark'
151
+ : ''}" data-location="${
151
152
  params.location}" role="button" tabindex="0" aria-label="${
152
153
  match.keywordMatch}, Instruction. Click for definition" aria-haspopup="dialog" aria-expanded="false">
153
154
  <span style="pointer-events: none;">${match.keywordMatch}</span></span>`
@@ -164,4 +165,4 @@ export const stripHtmlTags = (string?: string) => {
164
165
  return div.textContent || ''
165
166
  }
166
167
  return ''
167
- }
168
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pocketprep/ui-kit",
3
- "version": "3.8.4",
3
+ "version": "3.9.0",
4
4
  "description": "Pocket Prep UI Kit",
5
5
  "author": "pocketprep",
6
6
  "scripts": {
@@ -77,34 +77,33 @@
77
77
  "highcharts": "10.3.3",
78
78
  "litepicker": "2.0.12",
79
79
  "resize-observer": "1.0.4",
80
- "vue": "3.5.13",
81
- "vue-facing-decorator": "3.0.4",
82
- "vue-router": "4.5.0"
80
+ "vue": "3.5.27",
81
+ "vue-router": "4.6.4"
83
82
  },
84
83
  "devDependencies": {
85
- "@pocketprep/types": "1.15.17",
86
- "@stylistic/eslint-plugin-ts": "4.2.0",
87
- "@tsconfig/node22": "22.0.0",
88
- "@types/node": "22.13.10",
89
- "@vitejs/plugin-vue": "5.2.3",
90
- "@vue/eslint-config-typescript": "14.5.0",
91
- "@vue/tsconfig": "0.7.0",
92
- "cypress": "14.2.0",
93
- "eslint": "9.22.0",
94
- "eslint-plugin-cypress": "4.2.0",
95
- "eslint-plugin-vue": "10.0.0",
84
+ "@pocketprep/types": "1.16.22",
85
+ "@stylistic/eslint-plugin": "5.7.1",
86
+ "@tsconfig/node24": "24.0.4",
87
+ "@types/node": "24.10.4",
88
+ "@vitejs/plugin-vue": "6.0.3",
89
+ "@vue/eslint-config-typescript": "14.6.0",
90
+ "@vue/tsconfig": "0.8.1",
91
+ "cypress": "15.9.0",
92
+ "eslint": "9.39.2",
93
+ "eslint-plugin-cypress": "5.2.1",
94
+ "eslint-plugin-vue": "10.7.0",
96
95
  "jiti": "2.4.2",
97
- "npm-run-all2": "7.0.2",
98
- "postcss-html": "1.8.0",
99
- "sass": "1.86.0",
100
- "start-server-and-test": "2.0.11",
101
- "stylelint": "16.16.0",
102
- "stylelint-config-recommended-scss": "14.1.0",
103
- "stylelint-config-recommended-vue": "1.6.0",
104
- "stylelint-config-standard-scss": "14.0.0",
105
- "typescript": "5.8.2",
106
- "vite": "6.2.2",
107
- "vite-plugin-vue-devtools": "7.7.2",
96
+ "npm-run-all2": "8.0.4",
97
+ "postcss-html": "1.8.1",
98
+ "sass": "1.97.3",
99
+ "start-server-and-test": "2.1.3",
100
+ "stylelint": "16.26.1",
101
+ "stylelint-config-recommended-scss": "16.0.2",
102
+ "stylelint-config-recommended-vue": "1.6.1",
103
+ "stylelint-config-standard-scss": "16.0.0",
104
+ "typescript": "5.9.3",
105
+ "vite": "7.3.1",
106
+ "vite-plugin-vue-devtools": "8.0.5",
108
107
  "vue-tsc": "2.2.8",
109
108
  "yorkie": "2.0.0"
110
109
  },
@@ -124,7 +123,7 @@
124
123
  "url": "git+https://github.com/Pocket-Prep/ui-kit.git"
125
124
  },
126
125
  "engines": {
127
- "node": "20.10.0",
128
- "npm": "10.2.3"
126
+ "node": "24.12.0",
127
+ "npm": "11.6.2"
129
128
  }
130
129
  }