frappe-ui 0.1.215 → 0.1.216

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.
@@ -1,25 +1,10 @@
1
1
  <template>
2
- <div class="flex min-w-0 items-center">
3
- <template v-if="dropdownItems.length">
2
+ <div class="flex min-w-0 items-center" ref="crumbsRef">
3
+ <template v-if="overflowedX">
4
4
  <Dropdown class="h-7" :options="dropdownItems">
5
5
  <Button variant="ghost">
6
6
  <template #icon>
7
- <svg
8
- class="w-4 text-ink-gray-5"
9
- xmlns="http://www.w3.org/2000/svg"
10
- width="24"
11
- height="24"
12
- viewBox="0 0 24 24"
13
- fill="none"
14
- stroke="currentColor"
15
- stroke-width="2"
16
- stroke-linecap="round"
17
- stroke-linejoin="round"
18
- >
19
- <circle cx="12" cy="12" r="1" />
20
- <circle cx="19" cy="12" r="1" />
21
- <circle cx="5" cy="12" r="1" />
22
- </svg>
7
+ <LucideEllipsis class="w-4 text-ink-gray-5" />
23
8
  </template>
24
9
  </Button>
25
10
  </Dropdown>
@@ -27,9 +12,8 @@
27
12
  /
28
13
  </span>
29
14
  </template>
30
- <div
31
- class="flex min-w-0 items-center overflow-hidden text-ellipsis whitespace-nowrap"
32
- >
15
+
16
+ <div class="flex min-w-0 items-center text-ellipsis whitespace-nowrap">
33
17
  <template v-for="(item, i) in crumbs" :key="item.label">
34
18
  <router-link
35
19
  v-if="item.route"
@@ -75,26 +59,43 @@
75
59
  </div>
76
60
  </div>
77
61
  </template>
62
+
78
63
  <script setup lang="ts">
79
- import { useWindowSize } from '@vueuse/core'
80
- import { computed } from 'vue'
81
64
  import { useRouter } from 'vue-router'
82
65
  import { Dropdown } from '../Dropdown'
83
66
  import { Button } from '../Button'
84
67
  import type { BreadcrumbsProps } from './types'
68
+ import { ref, computed, nextTick, useTemplateRef } from 'vue'
69
+ import { useResizeObserver } from '@vueuse/core'
70
+ import LucideEllipsis from '~icons/lucide/ellipsis'
71
+
72
+ const crumbsEl = useTemplateRef<HTMLDivElement>('crumbsRef')
85
73
 
86
74
  const props = defineProps<BreadcrumbsProps>()
87
75
 
88
76
  const router = useRouter()
89
- const { width } = useWindowSize()
77
+ const overflowedX = ref(false)
90
78
 
91
79
  const items = computed(() => {
92
80
  return (props.items || []).filter(Boolean)
93
81
  })
94
82
 
95
- const dropdownItems = computed(() => {
96
- if (width.value > 640) return []
83
+ const checkOverflow = () => {
84
+ if (!crumbsEl.value) return
85
+
86
+ // tmp show all items to measure item width
87
+ overflowedX.value = false
97
88
 
89
+ nextTick(() => {
90
+ const scrollWidth = crumbsEl.value?.scrollWidth || 0
91
+ const clientWidth = crumbsEl.value?.clientWidth || 0
92
+ overflowedX.value = scrollWidth > clientWidth
93
+ })
94
+ }
95
+
96
+ useResizeObserver(crumbsEl, checkOverflow)
97
+
98
+ const dropdownItems = computed(() => {
98
99
  let allExceptLastTwo = items.value.slice(0, -2)
99
100
  return allExceptLastTwo.map((item) => {
100
101
  let onClick = () => {
@@ -114,10 +115,5 @@ const dropdownItems = computed(() => {
114
115
  })
115
116
  })
116
117
 
117
- const crumbs = computed(() => {
118
- if (width.value > 640) return items.value
119
-
120
- let lastTwo = items.value.slice(-2)
121
- return lastTwo
122
- })
118
+ const crumbs = computed(() => items.value.slice(overflowedX.value ? -2 : 0))
123
119
  </script>
@@ -97,6 +97,7 @@ import Calendar from './Calendar.vue'
97
97
  import { Select } from '../Select'
98
98
  import DatePicker from '../DatePicker/DatePicker.vue'
99
99
  import { Button } from '../Button'
100
+ import { logEvent } from 'histoire/client'
100
101
 
101
102
  const config = {
102
103
  defaultMode: 'Month',
@@ -145,7 +145,7 @@ const props = defineProps({
145
145
  },
146
146
  })
147
147
 
148
- const emit = defineEmits(['create', 'update', 'delete'])
148
+ const emit = defineEmits(['create', 'update', 'delete', 'rangeChange'])
149
149
 
150
150
  const defaultConfig = {
151
151
  scrollToHour: 15,
@@ -208,10 +208,14 @@ onUnmounted(() => {
208
208
  window.removeEventListener('keydown', handleShortcuts)
209
209
  })
210
210
  function handleShortcuts(e) {
211
- if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable) {
211
+ if (
212
+ e.target.tagName === 'INPUT' ||
213
+ e.target.tagName === 'TEXTAREA' ||
214
+ e.target.isContentEditable
215
+ ) {
212
216
  return
213
217
  }
214
-
218
+
215
219
  if (e.key.toLowerCase() === 'm') {
216
220
  activeView.value = 'Month'
217
221
  }
@@ -601,6 +605,64 @@ function setCalendarDate(d) {
601
605
  })
602
606
  }
603
607
 
608
+ function getVisibleRange() {
609
+ const toDateString = (date) => (date ? dayjs(date).format('YYYY-MM-DD') : '')
610
+
611
+ if (activeView.value === 'Day') {
612
+ const day = selectedDay.value
613
+ if (!day) return null
614
+ const start = dayjs(day).startOf('day')
615
+ const end = dayjs(day).endOf('day')
616
+ return {
617
+ startDate: toDateString(start),
618
+ endDate: toDateString(end),
619
+ }
620
+ }
621
+
622
+ if (activeView.value === 'Week') {
623
+ const weekDates = datesInWeeks.value[week.value] || []
624
+ if (!weekDates.length) return null
625
+ const orderedWeek = [...weekDates].sort((a, b) => a - b)
626
+ const start = dayjs(orderedWeek[0]).startOf('day')
627
+ const end = dayjs(orderedWeek[orderedWeek.length - 1]).endOf('day')
628
+ return {
629
+ startDate: toDateString(start),
630
+ endDate: toDateString(end),
631
+ }
632
+ }
633
+
634
+ const start = dayjs(
635
+ new Date(currentYear.value, currentMonth.value, 1),
636
+ ).startOf('day')
637
+ const end = dayjs(
638
+ new Date(currentYear.value, currentMonth.value + 1, 0),
639
+ ).endOf('day')
640
+ return {
641
+ startDate: toDateString(start),
642
+ endDate: toDateString(end),
643
+ }
644
+ }
645
+
646
+ let lastRangeKey = ''
647
+ watch(
648
+ () => {
649
+ const range = getVisibleRange()
650
+ if (!range) return null
651
+ return {
652
+ view: activeView.value,
653
+ ...range,
654
+ }
655
+ },
656
+ (payload) => {
657
+ if (!payload) return
658
+ const key = `${payload.view}-${payload.startDate}-${payload.endDate}`
659
+ if (key === lastRangeKey) return
660
+ lastRangeKey = key
661
+ emit('rangeChange', payload)
662
+ },
663
+ { immediate: true },
664
+ )
665
+
604
666
  defineExpose({
605
667
  reloadEvents,
606
668
  currentMonthYear,
@@ -14,7 +14,6 @@
14
14
  type="checkbox"
15
15
  :disabled="disabled"
16
16
  :id="htmlId"
17
- :checked="Boolean(modelValue)"
18
17
  @change="
19
18
  (e) =>
20
19
  $emit('update:modelValue', (e.target as HTMLInputElement).checked)
@@ -1,7 +1,6 @@
1
1
  export interface CheckboxProps {
2
2
  size?: 'sm' | 'md'
3
3
  label?: string
4
- checked?: boolean
5
4
  disabled?: boolean
6
5
  padding?: boolean
7
6
  modelValue?: boolean | 1 | 0
@@ -19,11 +19,16 @@
19
19
  success,
20
20
  openFileSelector,
21
21
  }"
22
- />
22
+ >
23
+ <Button @click="openFileSelector" :loading="uploading">
24
+ {{ uploading ? `Uploading ${progress}%` : 'Upload File' }}
25
+ </Button>
26
+ </slot>
23
27
  </div>
24
28
  </template>
25
29
 
26
30
  <script>
31
+ import { Button } from '../Button'
27
32
  import FileUploadHandler from '../../utils/fileUploadHandler'
28
33
 
29
34
  export default {
@@ -77,7 +77,7 @@ const selectOptions = computed(() => {
77
77
  })
78
78
 
79
79
  const textColor = computed(() => {
80
- return props.disabled ? 'text-ink-gray-4' : 'text-ink-gray-8'
80
+ return props.disabled ? 'text-ink-gray-5' : 'text-ink-gray-8'
81
81
  })
82
82
 
83
83
  const fontSizeClasses = computed(() => {