@xy-planning-network/trees 0.6.7 → 0.6.9

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 (49) hide show
  1. package/dist/style.css +1 -1
  2. package/dist/trees.es.js +3654 -3208
  3. package/dist/trees.umd.js +8 -8
  4. package/package.json +8 -7
  5. package/src/lib-components/forms/DateRangePicker.vue +37 -2
  6. package/src/lib-components/lists/DataTable.vue +1 -1
  7. package/src/lib-components/lists/DynamicTable.vue +9 -1
  8. package/src/lib-components/navigation/ActionsDropdown.vue +42 -30
  9. package/src/lib-components/overlays/Popover/Popover.vue +35 -193
  10. package/src/lib-components/overlays/Tooltip.vue +39 -9
  11. package/types/composables/date.d.ts +6 -0
  12. package/types/composables/table.d.ts +2 -1
  13. package/types/composables/useActionItems.d.ts +1 -1
  14. package/types/composables/useTable.d.ts +1 -1
  15. package/types/lib-components/forms/BaseInput.vue.d.ts +9 -10
  16. package/types/lib-components/forms/Checkbox.vue.d.ts +7 -8
  17. package/types/lib-components/forms/DateRangePicker.vue.d.ts +14 -10
  18. package/types/lib-components/forms/FieldsetLegend.vue.d.ts +5 -5
  19. package/types/lib-components/forms/InputHelp.vue.d.ts +6 -6
  20. package/types/lib-components/forms/InputLabel.vue.d.ts +8 -8
  21. package/types/lib-components/forms/MultiCheckboxes.vue.d.ts +10 -13
  22. package/types/lib-components/forms/Radio.vue.d.ts +12 -14
  23. package/types/lib-components/forms/RadioCards.vue.d.ts +12 -14
  24. package/types/lib-components/forms/Select.vue.d.ts +13 -15
  25. package/types/lib-components/forms/TextArea.vue.d.ts +9 -9
  26. package/types/lib-components/forms/Toggle.vue.d.ts +5 -5
  27. package/types/lib-components/forms/YesOrNoRadio.vue.d.ts +10 -11
  28. package/types/lib-components/indicators/XYSpinner.vue.d.ts +1 -1
  29. package/types/lib-components/layout/DateFilter.vue.d.ts +4 -8
  30. package/types/lib-components/layout/SidebarLayout.vue.d.ts +6 -9
  31. package/types/lib-components/layout/StackedLayout.vue.d.ts +7 -11
  32. package/types/lib-components/lists/Cards.vue.d.ts +2 -4
  33. package/types/lib-components/lists/DataTable.vue.d.ts +9 -8
  34. package/types/lib-components/lists/DetailList.vue.d.ts +6 -8
  35. package/types/lib-components/lists/DownloadCell.vue.d.ts +2 -5
  36. package/types/lib-components/lists/DynamicTable.vue.d.ts +9 -8
  37. package/types/lib-components/lists/TableActionButtons.vue.d.ts +7 -7
  38. package/types/lib-components/navigation/ActionsDropdown.vue.d.ts +6 -6
  39. package/types/lib-components/navigation/Paginator.vue.d.ts +3 -5
  40. package/types/lib-components/navigation/Steps.vue.d.ts +9 -11
  41. package/types/lib-components/navigation/Tabs.vue.d.ts +8 -10
  42. package/types/lib-components/overlays/ContentModal.vue.d.ts +6 -7
  43. package/types/lib-components/overlays/Flash.vue.d.ts +1 -1
  44. package/types/lib-components/overlays/Modal.vue.d.ts +10 -11
  45. package/types/lib-components/overlays/Popover/Popover.vue.d.ts +10 -10
  46. package/types/lib-components/overlays/Popover/PopoverContent.vue.d.ts +1 -1
  47. package/types/lib-components/overlays/Slideover.vue.d.ts +4 -8
  48. package/types/lib-components/overlays/Spinner.vue.d.ts +1 -1
  49. package/types/lib-components/overlays/Tooltip.vue.d.ts +10 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xy-planning-network/trees",
3
- "version": "0.6.7",
3
+ "version": "0.6.9",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "repository": "github:xy-planning-network/trees",
@@ -40,24 +40,25 @@
40
40
  "@tailwindcss/line-clamp": "^0.4.2",
41
41
  "@tailwindcss/typography": "^0.5.7",
42
42
  "@types/node": "^18.15.11",
43
- "@vitejs/plugin-vue": "^4.1.0",
43
+ "@vitejs/plugin-vue": "^4.2.3",
44
44
  "@vue/eslint-config-prettier": "^7.1.0",
45
- "@vue/eslint-config-typescript": "^11.0.2",
45
+ "@vue/eslint-config-typescript": "^11.0.3",
46
46
  "autoprefixer": "^10.4.14",
47
47
  "copyfiles": "^2.4.1",
48
48
  "deepmerge": "^4.3.1",
49
- "eslint": "^8.38.0",
50
- "eslint-plugin-vue": "^9.10.0",
49
+ "eslint": "^8.42.0",
50
+ "eslint-plugin-vue": "^9.14.1",
51
51
  "postcss": "^8.4.21",
52
52
  "prettier": "^2.8.7",
53
53
  "tailwindcss": "^3.2.1",
54
54
  "tsc-alias": "^1.8.5",
55
55
  "typescript": "^5.0.4",
56
- "vite": "^4.2.1",
56
+ "vite": "^4.3.9",
57
57
  "vite-plugin-environment": "^1.1.3",
58
58
  "vue-tsc": "^1.2.0"
59
59
  },
60
60
  "dependencies": {
61
+ "@floating-ui/vue": "^1.0.1",
61
62
  "@headlessui/vue": "^1.4.2",
62
63
  "@heroicons/vue": "^1.0.5",
63
64
  "axios": "^0.27.2",
@@ -70,7 +71,7 @@
70
71
  "autoprefixer": "^10.4.7",
71
72
  "postcss": "^8.4.14",
72
73
  "tailwindcss": "^3.1.4",
73
- "vue": "^3.2.0"
74
+ "vue": "^3.3.4"
74
75
  },
75
76
  "engines": {
76
77
  "node": ">=12"
@@ -11,11 +11,13 @@ const props = withDefaults(
11
11
  minDate: number
12
12
  maxDate: number
13
13
  }
14
+ maxRange?: number
14
15
  startDate?: number
15
16
  label?: string
16
17
  help?: string
17
18
  }>(),
18
19
  {
20
+ maxRange: 0,
19
21
  startDate: 0,
20
22
  label: "",
21
23
  help: "",
@@ -31,7 +33,7 @@ const updateModelValue = (value: { minDate: number; maxDate: number }) => {
31
33
  }
32
34
 
33
35
  onMounted(() => {
34
- flatpickr(`#${uuid}`, {
36
+ const opts: flatpickr.Options.Options = {
35
37
  dateFormat: "m-d-Y",
36
38
  mode: "range",
37
39
  maxDate: new Date(), // So far, we cannot have options past today for ranges
@@ -51,7 +53,40 @@ onMounted(() => {
51
53
  })
52
54
  }
53
55
  },
54
- })
56
+ }
57
+
58
+ if (props.maxRange) {
59
+ // Set the range to a prefilled value given the allowed range
60
+ const daysAgo = new Date()
61
+ const minDate = daysAgo.setDate(daysAgo.getDate() - props.maxRange)
62
+ const maxDate = new Date()
63
+ opts.defaultDate = [minDate, maxDate]
64
+ updateModelValue({
65
+ minDate: Math.floor(minDate / 1000),
66
+ maxDate: Math.floor(maxDate.getTime() / 1000),
67
+ })
68
+
69
+ // Handle onChange to dynamically adjust maxDate to x days ahead of the selected start date
70
+ opts.onChange = (selectedDates, _, self) => {
71
+ if (selectedDates.length === 1) {
72
+ // Clone date so as to not change selectedDates[0] value
73
+ var daysAhead = new Date(selectedDates[0].getTime())
74
+ var daysBefore = new Date(selectedDates[0].getTime())
75
+ daysAhead.setDate(daysAhead.getDate() + props.maxRange)
76
+ daysBefore.setDate(daysBefore.getDate() - props.maxRange)
77
+ const now = new Date()
78
+
79
+ if (daysAhead > now) {
80
+ daysAhead = now
81
+ }
82
+
83
+ self.set("minDate", daysBefore)
84
+ self.set("maxDate", daysAhead)
85
+ }
86
+ }
87
+ }
88
+
89
+ flatpickr(`#${uuid}`, opts)
55
90
  })
56
91
  </script>
57
92
  <template>
@@ -73,7 +73,7 @@ const { columns, hasActions, isEmptyCellValue, rows } = useTable(
73
73
  <!--Table Actions Cell-->
74
74
  <td
75
75
  v-if="hasActions"
76
- class="px-6 py-4 text-sm text-gray-700 whitespace-nowrap leading-5"
76
+ class="px-6 py-2 text-sm text-gray-700 whitespace-nowrap leading-5"
77
77
  >
78
78
  <ActionsDropdown
79
79
  v-if="tableActions.type === 'dropdown'"
@@ -12,6 +12,7 @@ import type {
12
12
  } from "@/composables/table"
13
13
  import { useAppFlasher } from "@/composables/useFlashes"
14
14
  import { TrailsRespPaged } from "@/api/client"
15
+ import { DateRangeProps } from "@/composables/date"
15
16
  import { useTable } from "@/composables/useTable"
16
17
  import TableActionButtons from "./TableActionButtons.vue"
17
18
 
@@ -121,6 +122,12 @@ const handleSort = (selectedSort: string): void => {
121
122
  loadAndRender()
122
123
  }
123
124
 
125
+ const dateSearchProps = computed((): DateRangeProps => {
126
+ if (typeof props.tableOptions.dateSearch === "object")
127
+ return props.tableOptions.dateSearch
128
+ return {}
129
+ })
130
+
124
131
  const hasContent = computed((): boolean => {
125
132
  return rows.value.length ? true : false
126
133
  })
@@ -181,6 +188,7 @@ loadAndRender()
181
188
  <div v-if="tableOptions.dateSearch" class="w-full max-w-lg lg:max-w-xs">
182
189
  <DateRangePicker
183
190
  v-model="dateRange"
191
+ v-bind="{ ...dateSearchProps }"
184
192
  @update:model-value="dateRangeChanged"
185
193
  />
186
194
  </div>
@@ -281,7 +289,7 @@ loadAndRender()
281
289
  <!--Table Actions Cell-->
282
290
  <td
283
291
  v-if="hasActions"
284
- class="px-6 py-4 text-sm text-gray-700 whitespace-nowrap leading-5"
292
+ class="px-6 py-2 text-sm text-gray-700 whitespace-nowrap leading-5"
285
293
  >
286
294
  <ActionsDropdown
287
295
  v-if="tableActions.type === 'dropdown'"
@@ -3,7 +3,8 @@ import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/vue"
3
3
  import { DotsVerticalIcon } from "@heroicons/vue/solid"
4
4
  import type { ActionItem } from "@/composables/nav"
5
5
  import { useActionItems } from "@/composables/useActionItems"
6
- import { toRef } from "vue"
6
+ import { ref, toRef } from "vue"
7
+ import { useFloating, autoUpdate } from "@floating-ui/vue"
7
8
 
8
9
  const props = withDefaults(
9
10
  defineProps<{
@@ -15,10 +16,19 @@ const props = withDefaults(
15
16
  )
16
17
 
17
18
  const { actions, hasActions } = useActionItems(toRef(props, "actions"))
19
+
20
+ const trigger = ref<HTMLElement | null>(null)
21
+ const wrapper = ref<HTMLElement | null>(null)
22
+ const { floatingStyles } = useFloating(trigger, wrapper, {
23
+ placement: "bottom-end",
24
+ strategy: "fixed",
25
+ whileElementsMounted: autoUpdate,
26
+ })
18
27
  </script>
19
28
  <template>
20
29
  <Menu as="div" class="relative flex justify-end items-center">
21
30
  <MenuButton
31
+ ref="trigger"
22
32
  class="w-8 h-8 bg-white inline-flex items-center justify-center text-gray-700 rounded-full hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
23
33
  :disabled="!hasActions"
24
34
  >
@@ -33,35 +43,37 @@ const { actions, hasActions } = useActionItems(toRef(props, "actions"))
33
43
  leave-from-class="transform opacity-100 scale-100"
34
44
  leave-to-class="transform opacity-0 scale-95"
35
45
  >
36
- <MenuItems
37
- class="z-10 mx-3 origin-top-right absolute right-7 top-0 w-48 mt-1 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 divide-y divide-gray-200 focus:outline-none"
38
- >
39
- <div class="py-1">
40
- <template v-for="(action, idx) in actions" :key="idx">
41
- <MenuItem v-slot="{ active }: { active: boolean }" as="div">
42
- <button
43
- type="submit"
44
- :disabled="action.disabled"
45
- :class="[
46
- active ? 'bg-gray-100 text-gray-900' : 'text-gray-700',
47
- 'block w-full text-left px-4 py-2 text-sm font-semibold disabled:cursor-not-allowed',
48
- ]"
49
- @click="action.onClick"
50
- >
51
- <span class="relative inline-flex items-center gap-x-1.5">
52
- <component
53
- :is="action.icon"
54
- v-if="action.icon"
55
- class="-ml-0.5 h-4 w-4 text-gray-400"
56
- aria-hidden="true"
57
- />
58
- {{ action.label }}
59
- </span>
60
- </button>
61
- </MenuItem>
62
- </template>
63
- </div>
64
- </MenuItems>
46
+ <div ref="wrapper" class="z-[5]" :style="floatingStyles">
47
+ <MenuItems
48
+ class="w-48 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 divide-y divide-gray-200 focus:outline-none"
49
+ >
50
+ <div class="py-1">
51
+ <template v-for="(action, idx) in actions" :key="idx">
52
+ <MenuItem v-slot="{ active }: { active: boolean }" as="div">
53
+ <button
54
+ type="submit"
55
+ :disabled="action.disabled"
56
+ :class="[
57
+ active ? 'bg-gray-100 text-gray-900' : 'text-gray-700',
58
+ 'block w-full text-left px-4 py-2 text-sm font-semibold disabled:cursor-not-allowed',
59
+ ]"
60
+ @click="action.onClick"
61
+ >
62
+ <span class="relative inline-flex items-center gap-x-1.5">
63
+ <component
64
+ :is="action.icon"
65
+ v-if="action.icon"
66
+ class="-ml-0.5 h-4 w-4 text-gray-400"
67
+ aria-hidden="true"
68
+ />
69
+ {{ action.label }}
70
+ </span>
71
+ </button>
72
+ </MenuItem>
73
+ </template>
74
+ </div>
75
+ </MenuItems>
76
+ </div>
65
77
  </transition>
66
78
  </Menu>
67
79
  </template>
@@ -1,29 +1,23 @@
1
- <script lang="ts">
2
- export type PopoverPosition =
3
- | "top-left"
4
- | "top-center"
5
- | "top-right"
6
- | "bottom-left"
7
- | "bottom-center"
8
- | "bottom-right"
9
- | "left"
10
- | "right"
11
- | "auto"
12
- | "none"
13
- </script>
14
1
  <script lang="ts" setup>
15
- import { throttle } from "@/helpers/Throttle"
16
2
  import {
17
3
  Popover as HeadlessPopover,
18
4
  PopoverButton as HeadlessPopoverButton,
19
5
  PopoverPanel as HeadlessPopoverPanel,
20
6
  } from "@headlessui/vue"
21
- import { computed, onMounted, onUnmounted, ref } from "vue"
7
+ import { computed, ref } from "vue"
8
+ import {
9
+ useFloating,
10
+ offset,
11
+ autoPlacement,
12
+ autoUpdate,
13
+ shift,
14
+ } from "@floating-ui/vue"
15
+ import type { Placement } from "@floating-ui/vue"
22
16
 
23
17
  const props = withDefaults(
24
18
  defineProps<{
25
19
  as?: string
26
- position?: PopoverPosition
20
+ position?: Placement | "auto"
27
21
  }>(),
28
22
  {
29
23
  as: "div",
@@ -31,199 +25,47 @@ const props = withDefaults(
31
25
  }
32
26
  )
33
27
 
34
- const getViewportDimensions = () => {
35
- return {
36
- vw: document.documentElement.clientWidth,
37
- vh: document.documentElement.clientHeight,
38
- }
39
- }
40
-
41
- const trigger = ref<typeof HeadlessPopoverButton>()
42
- const wrapper = ref<typeof HeadlessPopoverPanel>()
43
- const viewport = ref<{ vw: number; vh: number }>(getViewportDimensions())
44
-
45
- const classes = computed(() => {
46
- const classes = {
47
- wrapper: "",
48
- content: "",
49
- }
50
-
51
- if (props.position === "none") {
52
- return classes
28
+ const trigger = ref<HTMLElement | null>(null)
29
+ const wrapper = ref<HTMLElement | null>(null)
30
+ const middleware = computed(() => {
31
+ const middleware = [offset(5), shift()]
32
+ if (props.position === "auto") {
33
+ middleware.push(autoPlacement())
53
34
  }
54
35
 
55
- // defaults classes when positioning
56
- classes.wrapper = "h-0 flex w-screen"
57
- classes.content = "absolute"
58
-
59
- // merge static positioning classes
60
- if (props.position !== "auto") {
61
- classes.wrapper += ` ${staticPosition.value.wrapper}`
62
- classes.content += ` ${staticPosition.value.content}`
63
- }
64
-
65
- return classes
36
+ return middleware
66
37
  })
67
38
 
68
- const staticPosition = computed(() => {
69
- let wrapperClasses = ""
70
- let contentClasses = ""
71
-
72
- switch (props.position) {
73
- case "top-left":
74
- wrapperClasses = "top-0 right-0 -translate-y-full justify-end"
75
- contentClasses = "bottom-full"
76
- break
77
- case "top-center":
78
- wrapperClasses =
79
- "top-0 -translate-y-full -translate-x-full left-1/2 justify-end"
80
- contentClasses = "bottom-full translate-x-1/2"
81
- break
82
- case "top-right":
83
- wrapperClasses =
84
- "top-0 -translate-y-full left-0 -translate-x-full justify-end"
85
- contentClasses = "bottom-full translate-x-full"
86
- break
87
- case "bottom-left":
88
- wrapperClasses = "top-full right-0 justify-end"
89
- contentClasses = "top-full"
90
- break
91
- case "bottom-center":
92
- wrapperClasses = "top-full -translate-x-full left-1/2 justify-end"
93
- contentClasses = "top-full translate-x-1/2"
94
- break
95
- case "bottom-right":
96
- wrapperClasses = "top-full left-0 -translate-x-full justify-end"
97
- contentClasses = "top-full translate-x-full"
98
- break
99
- case "left":
100
- wrapperClasses =
101
- "top-1/2 left-0 -translate-y-1/2 -translate-x-full justify-end"
102
- contentClasses = "-translate-y-1/2"
103
- break
104
- case "right":
105
- wrapperClasses = "top-1/2 -translate-y-1/2 right-0 justify-end"
106
- contentClasses = "translate-x-full -translate-y-1/2"
107
- break
39
+ /**
40
+ * floating-ui's placement property does not support a direct "auto"
41
+ * mode. Passing undefined is expected when auto position is used.
42
+ */
43
+ const placement = computed(() => {
44
+ if (props.position === "auto") {
45
+ return undefined
108
46
  }
109
47
 
110
- return {
111
- wrapper: wrapperClasses,
112
- content: contentClasses,
113
- }
48
+ return props.position
114
49
  })
115
50
 
116
- const autoPosition = computed(() => {
117
- if (!wrapper?.value?.el || !trigger?.value?.el) {
118
- return {}
119
- }
120
-
121
- const { vw, vh } = viewport.value
122
-
123
- // avoid bumping up against the edge of the browser when possible
124
- const offset = 10
125
-
126
- // base the anchor rectangle off of the entire trigger dom element to move around it
127
- const anchorRect: DOMRect = trigger.value.el.getBoundingClientRect()
128
- // the content rectangle is best calculated by our first child (content) element inside the wrapper
129
- const contentRect: DOMRect =
130
- wrapper.value.el.firstChild.getBoundingClientRect()
131
- const distToBottom = vh - anchorRect.bottom
132
- // NOTE: edge case - there may be more space below in the viewport
133
- // but less document space for display
134
- // the inverse could also be true - but will be very rare
135
- // occurring with unreasonably large popover content
136
- const positionAbove = anchorRect.top > distToBottom
137
- const distToRight = vw - anchorRect.left
138
- const flowLeft = anchorRect.left > distToRight
139
-
140
- // translate the content container on the x axis to the correct position
141
- // considering the flow the content should take
142
- let xPos = 0
143
- if (flowLeft) {
144
- if (contentRect.width > anchorRect.right) {
145
- xPos =
146
- anchorRect.right -
147
- contentRect.width +
148
- (contentRect.width - anchorRect.right)
149
- } else {
150
- xPos = anchorRect.right - contentRect.width
151
- }
152
-
153
- if (vw > contentRect.width + offset) {
154
- xPos = xPos + offset
155
- }
156
- } else {
157
- if (contentRect.width > distToRight) {
158
- xPos = anchorRect.left - (contentRect.width - distToRight)
159
- } else {
160
- xPos = anchorRect.left
161
- }
162
-
163
- if (vw > contentRect.width + offset) {
164
- xPos = xPos - offset
165
- }
166
- }
167
-
168
- return {
169
- wrapper: {
170
- top: positionAbove ? "auto" : `100%`,
171
- bottom: positionAbove ? "100%" : `auto`,
172
- transform: `translate(${anchorRect.left * -1}px, 0)`, // pin to left of window
173
- width: `${vw}px`,
174
- },
175
- content: {
176
- top: positionAbove ? "auto" : `100%`,
177
- bottom: positionAbove ? "100%" : `auto`,
178
- transform: `translate(${xPos}px, 0)`,
179
- },
180
- }
51
+ const { floatingStyles } = useFloating(trigger, wrapper, {
52
+ middleware: middleware,
53
+ placement: placement,
54
+ strategy: "fixed",
55
+ whileElementsMounted: autoUpdate,
181
56
  })
182
-
183
- if (props.position === "auto") {
184
- const throttledSetPositions = throttle(() => {
185
- viewport.value = getViewportDimensions()
186
- })
187
-
188
- onMounted(() => {
189
- window.addEventListener("resize", throttledSetPositions)
190
- window.addEventListener("scroll", throttledSetPositions)
191
- })
192
-
193
- onUnmounted(() => {
194
- window.removeEventListener("resize", throttledSetPositions)
195
- window.removeEventListener("scroll", throttledSetPositions)
196
- })
197
- }
198
57
  </script>
199
58
 
200
59
  <template>
201
- <HeadlessPopover v-slot="{ open, close }" class="relative flex" :as="as">
60
+ <HeadlessPopover v-slot="{ open, close }" :as="as" class="relative">
202
61
  <HeadlessPopoverButton ref="trigger">
203
62
  <slot name="button" :open="open" :close="close"></slot>
204
63
  </HeadlessPopoverButton>
205
64
 
206
- <transition
207
- enter-active-class="transition-opacity transition-faster ease-out-quad"
208
- leave-active-class="transition-opacity transition-fastest ease-in-quad"
209
- enter-from-class="opacity-0"
210
- enter-to-class="opacity-100"
211
- leave-from-class="opacity-100"
212
- leave-to-class="opacity-0"
213
- >
214
- <HeadlessPopoverPanel
215
- ref="wrapper"
216
- class="absolute z-10"
217
- :class="classes.wrapper"
218
- :style="position === 'auto' ? autoPosition.wrapper : {}"
219
- >
220
- <div
221
- :class="classes.content"
222
- :style="position === 'auto' ? autoPosition.content : {}"
223
- >
224
- <slot :open="open" :close="close"></slot>
225
- </div>
65
+ <div ref="wrapper" class="z-[5]" :style="floatingStyles">
66
+ <HeadlessPopoverPanel>
67
+ <slot :open="open" :close="close"></slot>
226
68
  </HeadlessPopoverPanel>
227
- </transition>
69
+ </div>
228
70
  </HeadlessPopover>
229
71
  </template>
@@ -1,23 +1,47 @@
1
1
  <script lang="ts" setup>
2
- import Popover, { PopoverPosition } from "./Popover/Popover.vue"
2
+ import Popover from "./Popover/Popover.vue"
3
3
  import { InformationCircleIcon } from "@heroicons/vue/outline"
4
+ import type { Placement } from "@floating-ui/vue"
4
5
 
6
+ // props
5
7
  withDefaults(
6
8
  defineProps<{
7
9
  as?: string
8
- position?: PopoverPosition
10
+ position?: Placement | "auto"
9
11
  }>(),
10
12
  {
11
13
  as: "span",
12
14
  position: "auto",
13
15
  }
14
16
  )
17
+
18
+ // data
19
+ var popoverHover = false
20
+ var popoverTimeout: null | NodeJS.Timeout = null
21
+
22
+ // functions
23
+ const closePopover = (close: () => void): void => {
24
+ popoverHover = false
25
+ if (popoverTimeout) clearTimeout(popoverTimeout)
26
+ popoverTimeout = setTimeout(() => {
27
+ if (!popoverHover) close()
28
+ }, 100)
29
+ }
30
+
31
+ const hoverPopover = (e: MouseEvent, open: boolean): void => {
32
+ popoverHover = true
33
+ if (!open && e.target) (e.target as HTMLElement).click()
34
+ }
15
35
  </script>
16
36
 
17
37
  <template>
18
38
  <Popover :position="position" :as="as">
19
- <template #button>
20
- <div class="leading-none w-4 h-4">
39
+ <template #button="{ open, close }: { open: boolean, close: () => void }">
40
+ <div
41
+ class="leading-none relative w-4 h-4"
42
+ @mouseover="hoverPopover($event, open)"
43
+ @mouseleave="closePopover(close)"
44
+ >
21
45
  <InformationCircleIcon />
22
46
  <!--creates a larger clickable surface area 40 x 40-->
23
47
  <div
@@ -25,10 +49,16 @@ withDefaults(
25
49
  ></div>
26
50
  </div>
27
51
  </template>
28
- <div
29
- class="w-full max-w-xs bg-white rounded-md px-3 py-2 border border-gray-100 drop-shadow-md text-xs text-gray-900 leading-snug font-medium"
30
- >
31
- <slot></slot>
32
- </div>
52
+ <template #default="{ close }: { close: () => void }">
53
+ <div
54
+ class="sm:min-w-max bg-white rounded-md px-3 py-2 border border-gray-100 drop-shadow-md text-xs text-gray-900 leading-snug font-medium"
55
+ @mouseover.prevent="popoverHover = true"
56
+ @mouseleave.prevent="closePopover(close)"
57
+ >
58
+ <div class="max-w-xs">
59
+ <slot></slot>
60
+ </div>
61
+ </div>
62
+ </template>
33
63
  </Popover>
34
64
  </template>
@@ -2,3 +2,9 @@ export interface DateRange {
2
2
  minDate: number;
3
3
  maxDate: number;
4
4
  }
5
+ export interface DateRangeProps {
6
+ help?: string;
7
+ label?: string;
8
+ maxRange?: number;
9
+ startDate?: number;
10
+ }
@@ -1,7 +1,8 @@
1
1
  import { VNodeChild } from "vue";
2
2
  import { ActionItem } from "../composables/nav";
3
+ import { DateRangeProps } from "./date";
3
4
  export interface DynamicTableOptions {
4
- dateSearch?: boolean;
5
+ dateSearch?: boolean | DateRangeProps;
5
6
  defaultSort?: string;
6
7
  defaultSortDirection?: string;
7
8
  refreshTrigger: number;
@@ -5,7 +5,7 @@ export declare const useActionItems: (items: ActionItem[] | Ref<ActionItem[]>) =
5
5
  disabled: boolean;
6
6
  show: boolean;
7
7
  onClick: (...args: any[]) => void;
8
- icon?: import("vue").RenderFunction | import("vue").FunctionalComponent<{}, {}> | undefined;
8
+ icon?: import("vue").RenderFunction | import("vue").FunctionalComponent<{}, {}, any> | undefined;
9
9
  label: string;
10
10
  }[]>;
11
11
  hasActions: import("vue").ComputedRef<boolean>;
@@ -15,7 +15,7 @@ export declare const useTable: (rowData: TableRowsData | Ref<TableRowsData>, col
15
15
  disabled: boolean | undefined;
16
16
  onClick: () => void;
17
17
  show: boolean | undefined;
18
- icon?: import("vue").RenderFunction | import("vue").FunctionalComponent<{}, {}> | undefined;
18
+ icon?: import("vue").RenderFunction | import("vue").FunctionalComponent<{}, {}, any> | undefined;
19
19
  label: string;
20
20
  }[];
21
21
  rowData: import("./table").TableRowData;
@@ -7,23 +7,22 @@ declare const _default: import("vue").DefineComponent<__VLS_WithDefaults<__VLS_T
7
7
  help: string;
8
8
  label: string;
9
9
  modelValue: string;
10
- }>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "update:modelValue"[], "update:modelValue", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<{
11
- label?: unknown;
12
- type?: unknown;
13
- help?: unknown;
14
- modelValue?: unknown;
15
- } & {
16
- label: string;
10
+ }>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "update:modelValue"[], "update:modelValue", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
17
11
  type: string;
12
+ help?: string | undefined;
13
+ label?: string | undefined;
14
+ modelValue?: string | number | undefined;
15
+ }>, {
18
16
  help: string;
19
- modelValue: string | number;
20
- } & {}> & {
17
+ label: string;
18
+ modelValue: string;
19
+ }>>> & {
21
20
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
22
21
  }, {
23
22
  label: string;
24
23
  help: string;
25
24
  modelValue: string | number;
26
- }>;
25
+ }, {}>;
27
26
  export default _default;
28
27
  type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
29
28
  type __VLS_TypePropsToRuntimeProps<T> = {