frappe-ui 0.1.277 → 0.1.278

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 (111) hide show
  1. package/package.json +7 -5
  2. package/src/components/Autocomplete/Autocomplete.vue +1 -0
  3. package/src/components/Button/Button.vue +61 -21
  4. package/src/components/Calendar/Calendar.vue +38 -0
  5. package/src/components/Combobox/Combobox.cy.ts +590 -81
  6. package/src/components/Combobox/Combobox.vue +627 -381
  7. package/src/components/Combobox/ComboboxResults.vue +380 -0
  8. package/src/components/Combobox/stories/CustomValue.vue +11 -9
  9. package/src/components/Combobox/stories/EmojiPicker.vue +52 -0
  10. package/src/components/Combobox/stories/Grouped.vue +29 -18
  11. package/src/components/Combobox/stories/MemberPicker.vue +129 -0
  12. package/src/components/Combobox/stories/Simple.vue +22 -9
  13. package/src/components/Combobox/stories/StatusPicker.vue +98 -0
  14. package/src/components/Combobox/types.ts +219 -24
  15. package/src/components/Combobox/utils.ts +268 -0
  16. package/src/components/CommandPalette/CommandPaletteItem.vue +1 -1
  17. package/src/components/DatePicker/DatePicker.vue +26 -0
  18. package/src/components/DatePicker/types.ts +30 -0
  19. package/src/components/Divider/Divider.cy.ts +110 -0
  20. package/src/components/Divider/Divider.vue +64 -30
  21. package/src/components/Divider/stories/Action.vue +32 -0
  22. package/src/components/Divider/stories/Examples.vue +23 -0
  23. package/src/components/Divider/types.ts +4 -2
  24. package/src/components/Dropdown/Dropdown.cy.ts +75 -1
  25. package/src/components/Dropdown/Dropdown.vue +77 -394
  26. package/src/components/Dropdown/DropdownMenuItemContent.vue +226 -0
  27. package/src/components/Dropdown/DropdownMenuList.vue +207 -0
  28. package/src/components/Dropdown/DropdownRenderContent.vue +24 -0
  29. package/src/components/Dropdown/DropdownRenderContentAsChild.vue +19 -0
  30. package/src/components/Dropdown/index.ts +1 -1
  31. package/src/components/Dropdown/stories/01_Simple.vue +38 -0
  32. package/src/components/Dropdown/stories/02_Shortcuts.vue +42 -0
  33. package/src/components/Dropdown/stories/03_Submenus.vue +69 -0
  34. package/src/components/Dropdown/stories/04_Switches.vue +44 -0
  35. package/src/components/Dropdown/stories/05_KebabMenu.vue +78 -0
  36. package/src/components/Dropdown/stories/06_UserMenu.vue +145 -0
  37. package/src/components/Dropdown/types.ts +212 -26
  38. package/src/components/Dropdown/utils.ts +150 -0
  39. package/src/components/FormControl/FormControl.cy.ts +66 -0
  40. package/src/components/FormControl/FormControl.vue +5 -6
  41. package/src/components/ItemList/ItemList.cy.ts +110 -0
  42. package/src/components/ItemList/ItemList.vue +166 -0
  43. package/src/components/ItemList/ItemListRow.cy.ts +52 -0
  44. package/src/components/ItemList/ItemListRow.vue +80 -0
  45. package/src/components/ItemList/index.ts +3 -0
  46. package/src/components/ItemList/stories/AdvancedSlots.vue +73 -0
  47. package/src/components/ItemList/stories/Basic.vue +92 -0
  48. package/src/components/ItemList/stories/CustomSlots.vue +91 -0
  49. package/src/components/ItemList/stories/EmptyAndFooter.vue +79 -0
  50. package/src/components/ItemList/stories/RowStates.vue +38 -0
  51. package/src/components/ItemList/types.ts +121 -0
  52. package/src/components/MultiSelect/MultiSelect.cy.ts +101 -19
  53. package/src/components/MultiSelect/MultiSelect.vue +490 -115
  54. package/src/components/MultiSelect/MultiSelectResults.vue +288 -0
  55. package/src/components/MultiSelect/index.ts +16 -1
  56. package/src/components/MultiSelect/stories/Example.vue +13 -12
  57. package/src/components/MultiSelect/stories/Footer.vue +21 -22
  58. package/src/components/MultiSelect/stories/Grouped.vue +42 -0
  59. package/src/components/MultiSelect/stories/Options.vue +16 -17
  60. package/src/components/MultiSelect/stories/TagsTrigger.vue +79 -0
  61. package/src/components/MultiSelect/stories/TriggerSlot.vue +41 -0
  62. package/src/components/MultiSelect/types.ts +191 -6
  63. package/src/components/MultiSelect/utils.ts +191 -0
  64. package/src/components/Select/Select.cy.ts +235 -3
  65. package/src/components/Select/Select.vue +442 -71
  66. package/src/components/Select/index.ts +1 -1
  67. package/src/components/Select/stories/Example.vue +53 -3
  68. package/src/components/Select/stories/OptionSlot.vue +49 -34
  69. package/src/components/Select/stories/States.vue +47 -0
  70. package/src/components/Select/stories/TriggerSlots.vue +84 -31
  71. package/src/components/Select/types.ts +89 -10
  72. package/src/components/Slider/Slider.cy.ts +48 -0
  73. package/src/components/Slider/Slider.vue +26 -21
  74. package/src/components/Slider/types.ts +42 -0
  75. package/src/components/TabButtons/TabButtons.cy.ts +80 -0
  76. package/src/components/TabButtons/TabButtons.vue +204 -62
  77. package/src/components/Tabs/Tabs.cy.ts +37 -7
  78. package/src/components/Tabs/Tabs.vue +24 -4
  79. package/src/components/Tabs/types.ts +18 -10
  80. package/src/components/TextEditor/components/CodeBlockComponent.vue +183 -58
  81. package/src/components/TextEditor/components/MediaNodeView.vue +4 -4
  82. package/src/components/TextEditor/extensions/mention/mention-extension.ts +4 -0
  83. package/src/components/TextEditor/style.css +17 -0
  84. package/src/components/TextInput/TextInput.vue +3 -3
  85. package/src/components/TextInput/types.ts +14 -9
  86. package/src/components/Textarea/Textarea.cy.ts +72 -0
  87. package/src/components/Textarea/Textarea.vue +3 -3
  88. package/src/components/Textarea/types.ts +14 -9
  89. package/src/components/Toast/Toast.cy.ts +58 -0
  90. package/src/components/Toast/Toast.vue +1 -0
  91. package/src/components/Toast/stories/Actions.vue +65 -0
  92. package/src/components/Toast/stories/Examples.vue +42 -0
  93. package/src/components/Toast/types.ts +25 -5
  94. package/src/components/Tooltip/Tooltip.vue +15 -25
  95. package/src/components/Tooltip/TooltipBubble.vue +52 -0
  96. package/src/composables/usePopoverMotion.ts +37 -0
  97. package/src/index.ts +1 -0
  98. package/src/utils/iconString.ts +25 -0
  99. package/src/utils/vnode.ts +62 -0
  100. package/tailwind/lucideIconsPlugin.js +101 -0
  101. package/tailwind/plugin.js +227 -2
  102. package/tailwind/preset.js +2 -1
  103. package/vite/lucideIcons.js +12 -3
  104. package/src/components/Combobox/stories/CustomRender.vue +0 -26
  105. package/src/components/Combobox/stories/OptionSlots.vue +0 -42
  106. package/src/components/Combobox/stories/WithIcons.vue +0 -16
  107. package/src/components/Dropdown/stories/CustomTrigger.vue +0 -19
  108. package/src/components/Dropdown/stories/Examples.vue +0 -17
  109. package/src/components/Dropdown/stories/Grouped.vue +0 -36
  110. package/src/components/Dropdown/stories/Submenus.vue +0 -31
  111. package/src/components/Dropdown/stories/Switches.vue +0 -28
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "frappe-ui",
3
- "version": "0.1.277",
3
+ "version": "0.1.278",
4
4
  "description": "A set of components and utilities for rapid UI development",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "scripts": {
8
8
  "test": "vitest --run",
9
9
  "type-check": "tsc --noEmit",
10
- "prettier": "yarn prettier -w ./src",
10
+ "prettier": "yarn run prettier -w ./src",
11
11
  "bump-and-release": "yarn test && git pull --rebase origin main && yarn run release-patch",
12
12
  "release-patch": "yarn version --patch && git push && git push --tags",
13
13
  "dev": "vite",
@@ -16,7 +16,8 @@
16
16
  "docs:dev": "vitepress dev docs --host",
17
17
  "docs:build": "vitepress build docs",
18
18
  "docs:preview": "vitepress preview docs",
19
- "docs:gen": "node docs/scripts/propsgen.ts --trace-uncaught"
19
+ "docs:gen": "tsx docs/scripts/propsgen.ts",
20
+ "docs:gen:all": "yarn docs:gen --all"
20
21
  },
21
22
  "exports": {
22
23
  ".": {
@@ -49,8 +50,8 @@
49
50
  "import": "./src/components/TextEditor/style.css"
50
51
  },
51
52
  "./tsconfig.base.json": {
52
- "default": "./tsconfig.base.json",
53
- "types": "./tsconfig.base.json"
53
+ "types": "./tsconfig.base.json",
54
+ "default": "./tsconfig.base.json"
54
55
  }
55
56
  },
56
57
  "files": [
@@ -140,6 +141,7 @@
140
141
  "postcss": "^8.4.21",
141
142
  "prettier-plugin-tailwindcss": "^0.1.13",
142
143
  "tailwindcss": "^3.2.7",
144
+ "tsx": "^4.20.6",
143
145
  "vite": "^5.1.8",
144
146
  "vitepress": "^2.0.0-alpha.15",
145
147
  "vitest": "^2.1.8",
@@ -321,6 +321,7 @@ const findOption = (option: AutocompleteOption) => {
321
321
  }
322
322
 
323
323
  const makeOption = (option: AutocompleteOption) => {
324
+ if (option == null) return { label: '', value: '' }
324
325
  return isOption(option) ? option : { label: option, value: option }
325
326
  }
326
327
 
@@ -1,14 +1,25 @@
1
1
  <template>
2
- <Tooltip :text="tooltip" :disabled="!tooltip?.length">
3
- <button
4
- v-bind="$attrs"
5
- :class="buttonClasses"
6
- @click="handleClick"
7
- :disabled="isDisabled"
8
- :ariaLabel="label"
9
- :type = "props.type"
10
- ref="rootRef"
11
- >
2
+ <!--
3
+ The <button> is the effective DOM root. reka's Tooltip primitives
4
+ (TooltipProvider/TooltipRoot/TooltipTrigger) are renderless / pass-
5
+ through, so consumers wrapping <Button> in their own reka primitives
6
+ (e.g. ComboboxTrigger as-child) see a native <button> element with
7
+ all forwarded attrs — tabindex, aria-expanded, role — intact. Using
8
+ the separate <Tooltip> component as a wrapper dropped those attrs
9
+ because it's a Vue component with `inheritAttrs: false`.
10
+ -->
11
+ <TooltipProvider>
12
+ <TooltipRoot>
13
+ <TooltipTrigger as-child>
14
+ <button
15
+ v-bind="$attrs"
16
+ :class="buttonClasses"
17
+ @click="handleClick"
18
+ :disabled="isDisabled"
19
+ :aria-label="label"
20
+ :type="props.type"
21
+ ref="rootRef"
22
+ >
12
23
  <LoadingIndicator
13
24
  v-if="loading"
14
25
  :class="{
@@ -19,8 +30,13 @@
19
30
  }"
20
31
  />
21
32
  <slot name="prefix" v-else-if="$slots['prefix'] || iconLeft">
33
+ <span
34
+ v-if="iconLeft && typeof iconLeft === 'string' && iconLeft.startsWith('lucide-')"
35
+ :class="[iconLeft, lucideSlotClasses]"
36
+ aria-hidden="true"
37
+ />
22
38
  <FeatherIcon
23
- v-if="iconLeft && typeof iconLeft === 'string'"
39
+ v-else-if="iconLeft && typeof iconLeft === 'string'"
24
40
  :name="iconLeft"
25
41
  :class="slotClasses"
26
42
  aria-hidden="true"
@@ -30,8 +46,13 @@
30
46
 
31
47
  <template v-if="loading && loadingText">{{ loadingText }}</template>
32
48
  <template v-else-if="isIconButton && !loading">
49
+ <span
50
+ v-if="icon && typeof icon === 'string' && icon.startsWith('lucide-')"
51
+ :class="[icon, lucideSlotClasses]"
52
+ aria-hidden="true"
53
+ />
33
54
  <FeatherIcon
34
- v-if="icon && typeof icon === 'string'"
55
+ v-else-if="icon && typeof icon === 'string'"
35
56
  :name="icon"
36
57
  :class="slotClasses"
37
58
  />
@@ -46,28 +67,37 @@
46
67
  </span>
47
68
 
48
69
  <slot name="suffix">
70
+ <span
71
+ v-if="iconRight && typeof iconRight === 'string' && iconRight.startsWith('lucide-')"
72
+ :class="[iconRight, lucideSlotClasses]"
73
+ aria-hidden="true"
74
+ />
49
75
  <FeatherIcon
50
- v-if="iconRight && typeof iconRight === 'string'"
76
+ v-else-if="iconRight && typeof iconRight === 'string'"
51
77
  :name="iconRight"
52
78
  :class="slotClasses"
53
79
  aria-hidden="true"
54
80
  />
55
- <component
56
- v-else-if="iconRight"
57
- :is="iconRight"
58
- :class="slotClasses"
59
- />
81
+ <component
82
+ v-else-if="iconRight"
83
+ :is="iconRight"
84
+ :class="slotClasses"
85
+ />
60
86
  </slot>
61
- </button>
62
- </Tooltip>
87
+ </button>
88
+ </TooltipTrigger>
89
+ <TooltipBubble v-if="tooltip?.length" :text="tooltip" />
90
+ </TooltipRoot>
91
+ </TooltipProvider>
63
92
  </template>
64
93
  <script lang="ts" setup>
65
94
  import { computed, useSlots, ref } from 'vue'
95
+ import { TooltipProvider, TooltipRoot, TooltipTrigger } from 'reka-ui'
66
96
  import FeatherIcon from '../FeatherIcon.vue'
67
97
  import LoadingIndicator from '../LoadingIndicator.vue'
98
+ import TooltipBubble from '../Tooltip/TooltipBubble.vue'
68
99
  import { useRouter } from 'vue-router'
69
100
  import type { ButtonProps, ThemeVariant } from './types'
70
- import Tooltip from '../Tooltip/Tooltip.vue'
71
101
 
72
102
  defineOptions({ inheritAttrs: false })
73
103
 
@@ -197,6 +227,16 @@ const slotClasses = computed(() => {
197
227
  return classes
198
228
  })
199
229
 
230
+ const lucideSlotClasses = computed(() => {
231
+ return {
232
+ sm: 'size-4',
233
+ md: 'size-4.5',
234
+ lg: 'size-5',
235
+ xl: 'size-6',
236
+ '2xl': 'size-6',
237
+ }[props.size]
238
+ })
239
+
200
240
  const isDisabled = computed(() => {
201
241
  return props.disabled || props.loading
202
242
  })
@@ -182,6 +182,9 @@ function updateActiveView(value, d, isPreviousMonth, isNextMonth) {
182
182
  isPreviousMonth && decrementMonth()
183
183
  isNextMonth && incrementMonth()
184
184
  }
185
+ if (value === 'Week') {
186
+ week.value = findCurrentWeek(currentMonthDates.value[date.value])
187
+ }
185
188
  }
186
189
 
187
190
  const selectedMonthDate = ref(dayjs().format('YYYY-MM-DD'))
@@ -251,6 +254,12 @@ function handleShortcuts(e) {
251
254
  provide('activeView', activeView)
252
255
  provide('config', overrideConfig)
253
256
 
257
+ watch(activeView, (value) => {
258
+ if (value === 'Week') {
259
+ week.value = findCurrentWeek(currentMonthDates.value[date.value])
260
+ }
261
+ })
262
+
254
263
  const parseEvents = computed(() => {
255
264
  return (
256
265
  props.events?.map((event) => {
@@ -401,6 +410,34 @@ let date = ref(
401
410
  )
402
411
  let selectedDay = computed(() => currentMonthDates.value[date.value])
403
412
 
413
+ function computeCurrentDay() {
414
+ if (activeView.value === 'Week') {
415
+ const weekDates = datesInWeeks.value[week.value] || []
416
+ return weekDates[0] ? weekDates[0].getDate() : null
417
+ }
418
+ if (activeView.value === 'Day') {
419
+ const day = selectedDay.value
420
+ return day ? new Date(day).getDate() : null
421
+ }
422
+ return 1
423
+ }
424
+
425
+ let currentDay = ref(computeCurrentDay())
426
+ let _lastInternalDay = currentDay.value
427
+
428
+ watch([activeView, week, date], () => {
429
+ const val = computeCurrentDay()
430
+ _lastInternalDay = val
431
+ currentDay.value = val
432
+ })
433
+
434
+ watch(currentDay, (newVal) => {
435
+ if (newVal == null) return
436
+ if (newVal === _lastInternalDay) return
437
+ const target = new Date(currentYear.value, currentMonth.value, newVal)
438
+ setCalendarDate(target)
439
+ })
440
+
404
441
  function updateCurrentDate(d) {
405
442
  activeView.value = 'Day'
406
443
  date.value = findIndexOfDate(d)
@@ -685,6 +722,7 @@ defineExpose({
685
722
  currentMonthYear,
686
723
  currentYear,
687
724
  currentMonth,
725
+ currentDay,
688
726
  enabledModes,
689
727
  activeView,
690
728
  decrement,