frappe-ui 0.1.216 → 0.1.220

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 (34) hide show
  1. package/frappe/Billing/SignupBanner.vue +1 -1
  2. package/frappe/Billing/TrialBanner.vue +1 -1
  3. package/frappe/Help/HelpModal.vue +4 -4
  4. package/frappe/Onboarding/GettingStartedBanner.vue +1 -1
  5. package/frappe/index.d.ts +53 -0
  6. package/icons/index.ts +10 -0
  7. package/package.json +27 -3
  8. package/src/components/Charts/index.ts +0 -0
  9. package/src/components/Combobox/Combobox.story.vue +18 -0
  10. package/src/components/Combobox/Combobox.vue +13 -2
  11. package/src/components/Combobox/types.ts +2 -1
  12. package/src/components/DatePicker/index.ts +6 -0
  13. package/src/components/Dropdown/Dropdown.vue +19 -5
  14. package/src/components/Dropdown/types.ts +1 -0
  15. package/src/components/ListView/ListGroupHeader.vue +1 -1
  16. package/src/components/ListView/ListGroupRows.vue +5 -0
  17. package/src/components/Select/Select.story.vue +16 -3
  18. package/src/components/Select/Select.vue +109 -96
  19. package/src/components/Sidebar/index.ts +3 -0
  20. package/src/components/Toast/Toast.vue +1 -1
  21. package/src/data-fetching/index.ts +4 -2
  22. package/src/index.ts +9 -23
  23. package/src/resources/{index.js → index.ts} +3 -1
  24. package/src/resources/{local.js → local.ts} +4 -4
  25. package/src/resources/realtime.ts +21 -0
  26. package/src/resources/realtime.js +0 -15
  27. /package/{src/icons/CircleCheck.vue → icons/CircleCheckIcon.vue} +0 -0
  28. /package/{src/icons/DownSolid.vue → icons/DownSolidIcon.vue} +0 -0
  29. /package/{src/components → icons}/GreenCheckIcon.vue +0 -0
  30. /package/{frappe/Icons → icons}/HelpIcon.vue +0 -0
  31. /package/{frappe/Icons → icons}/LightningIcon.vue +0 -0
  32. /package/{frappe/Icons → icons}/MaximizeIcon.vue +0 -0
  33. /package/{frappe/Icons → icons}/MinimizeIcon.vue +0 -0
  34. /package/{frappe/Icons → icons}/StepsIcon.vue +0 -0
@@ -25,7 +25,7 @@
25
25
  </Button>
26
26
  </template>
27
27
  <script setup>
28
- import LightningIcon from '../Icons/LightningIcon.vue'
28
+ import LightningIcon from '../../icons/LightningIcon.vue'
29
29
 
30
30
  const props = defineProps({
31
31
  isSidebarCollapsed: {
@@ -23,7 +23,7 @@
23
23
  </Button>
24
24
  </template>
25
25
  <script setup>
26
- import LightningIcon from '../Icons/LightningIcon.vue'
26
+ import LightningIcon from '../../icons/LightningIcon.vue'
27
27
  import FeatherIcon from '../../src/components/FeatherIcon.vue'
28
28
  import { Button } from '../../src/components/Button'
29
29
  import { createResource } from '../../src/resources'
@@ -55,10 +55,10 @@
55
55
  <script setup>
56
56
  import Dropdown from '../../src/components/Dropdown/Dropdown.vue'
57
57
  import Button from '../../src/components/Button/Button.vue'
58
- import StepsIcon from '../Icons/StepsIcon.vue'
59
- import MinimizeIcon from '../Icons/MinimizeIcon.vue'
60
- import MaximizeIcon from '../Icons/MaximizeIcon.vue'
61
- import HelpIcon from '../Icons/HelpIcon.vue'
58
+ import StepsIcon from '../../icons/StepsIcon.vue'
59
+ import MinimizeIcon from '../../icons/MinimizeIcon.vue'
60
+ import MaximizeIcon from '../../icons/MaximizeIcon.vue'
61
+ import HelpIcon from '../../icons/HelpIcon.vue'
62
62
  import OnboardingSteps from '../Onboarding/OnboardingSteps.vue'
63
63
  import HelpCenter from '../HelpCenter/HelpCenter.vue'
64
64
  import { useOnboarding } from '../Onboarding/onboarding'
@@ -56,7 +56,7 @@
56
56
  </Button>
57
57
  </template>
58
58
  <script setup>
59
- import StepsIcon from '../Icons/StepsIcon.vue'
59
+ import StepsIcon from '../../icons/StepsIcon.vue'
60
60
  import Button from '../../src/components/Button/Button.vue'
61
61
  import FeatherIcon from '../../src/components/FeatherIcon.vue'
62
62
  import { useOnboarding } from './onboarding'
@@ -0,0 +1,53 @@
1
+ // Since the export is via JS file, we need to declare the module here
2
+ declare module 'frappe-ui/frappe' {
3
+ import type { Component, ComputedRef, Ref } from 'vue'
4
+
5
+ // Onboarding
6
+ export interface OnboardingStep {
7
+ name: string
8
+ completed: boolean
9
+ [key: string]: any
10
+ }
11
+
12
+ export function useOnboarding(appName: string):
13
+ | {
14
+ steps: OnboardingStep[]
15
+ stepsCompleted: ComputedRef<number>
16
+ totalSteps: ComputedRef<number>
17
+ completedPercentage: ComputedRef<number>
18
+ isOnboardingStepsCompleted: Ref<boolean>
19
+ updateOnboardingStep: (
20
+ step: string,
21
+ value?: boolean,
22
+ skipped?: boolean,
23
+ callback?: ((step: string, skipped: boolean) => void) | null,
24
+ ) => void
25
+ skip: (
26
+ step: string,
27
+ callback?: ((step: string, skipped: boolean) => void) | null,
28
+ ) => void
29
+ skipAll: (callback?: ((value: boolean) => void) | null) => void
30
+ reset: (
31
+ step: string,
32
+ callback?: ((step: string, skipped: boolean) => void) | null,
33
+ ) => void
34
+ resetAll: (callback?: ((value: boolean) => void) | null) => void
35
+ setUp: (steps: OnboardingStep[]) => void
36
+ syncStatus: () => void
37
+ }
38
+ | undefined
39
+
40
+ // Help Modal
41
+ export const showHelpModal: Ref<boolean>
42
+ export const minimize: Ref<boolean>
43
+ export const HelpModal: Component
44
+
45
+ // Banners
46
+ export const GettingStartedBanner: Component
47
+ export const TrialBanner: Component
48
+ export const IntermediateStepModal: Component
49
+
50
+ // Components
51
+ export const Link: Component
52
+ export type { LinkProps } from './Link/types'
53
+ }
package/icons/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ export { default as CircleCheckIcon } from './CircleCheckIcon.vue'
2
+ export { default as DownSolidIcon } from './DownSolidIcon.vue'
3
+ export { default as GreenCheckIcon } from './GreenCheckIcon.vue'
4
+
5
+ // Frappe Icons
6
+ export { default as HelpIcon } from './HelpIcon.vue'
7
+ export { default as LightningIcon } from './LightningIcon.vue'
8
+ export { default as MaximizeIcon } from './MaximizeIcon.vue'
9
+ export { default as MinimizeIcon } from './MinimizeIcon.vue'
10
+ export { default as StepsIcon } from './StepsIcon.vue'
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "frappe-ui",
3
- "version": "0.1.216",
3
+ "version": "0.1.220",
4
4
  "description": "A set of components and utilities for rapid UI development",
5
- "main": "./src/index.ts",
6
5
  "type": "module",
6
+ "sideEffects": false,
7
7
  "scripts": {
8
8
  "test": "vitest --run",
9
9
  "type-check": "tsc --noEmit",
@@ -17,11 +17,35 @@
17
17
  "story:build": "histoire build && cp 404.html .histoire/dist",
18
18
  "story:preview": "histoire preview"
19
19
  },
20
+ "exports": {
21
+ ".": {
22
+ "import": "./src/index.ts",
23
+ "types": "./src/index.ts"
24
+ },
25
+ "./frappe": {
26
+ "import": "./frappe/index.js"
27
+ },
28
+ "./icons": {
29
+ "import": "./icons/index.ts"
30
+ },
31
+ "./tailwind": {
32
+ "import": "./src/tailwind/preset.js",
33
+ "default": "./src/tailwind/preset.js"
34
+ },
35
+ "./vite": {
36
+ "import": "./vite/index.js"
37
+ },
38
+ "./style.css": {
39
+ "import": "./src/style.css"
40
+ },
41
+ "./tsconfig.base.json": "./tsconfig.base.json"
42
+ },
20
43
  "files": [
21
44
  "frappe",
22
45
  "src",
23
46
  "scripts",
24
- "vite"
47
+ "vite",
48
+ "icons"
25
49
  ],
26
50
  "repository": {
27
51
  "type": "git",
File without changes
@@ -178,6 +178,24 @@ const state = reactive({
178
178
  </div>
179
179
  </Variant>
180
180
 
181
+ <Variant title="Outline variant">
182
+ <div class="p-4">
183
+ <label class="block text-sm font-medium mb-2">Simple Options</label>
184
+ <Combobox
185
+ variant="outline"
186
+ :options="simpleOptions"
187
+ v-model="simpleValue"
188
+ :placeholder="state.placeholder"
189
+ :disabled="state.disabled"
190
+ :show-cancel="state.showCancel"
191
+ @update:selectedOption="selectedOption = $event"
192
+ />
193
+ <div class="mt-2 text-sm text-gray-600">
194
+ Selected: {{ simpleValue || 'None' }}
195
+ </div>
196
+ </div>
197
+ </Variant>
198
+
181
199
  <Variant title="Object Options">
182
200
  <div class="p-4">
183
201
  <label class="block text-sm font-medium mb-2">Object Options</label>
@@ -33,6 +33,7 @@ import type {
33
33
  } from './types'
34
34
 
35
35
  const props = withDefaults(defineProps<ComboboxProps>(), {
36
+ variant: 'subtle',
36
37
  options: () => [],
37
38
  })
38
39
  const emit = defineEmits([
@@ -279,6 +280,13 @@ const reset = () => {
279
280
  emit('update:selectedOption', null)
280
281
  }
281
282
 
283
+ const variantClasses = computed(() => {
284
+ return {
285
+ subtle: 'bg-surface-gray-2 hover:bg-surface-gray-3 border-transparent',
286
+ outline: 'border-outline-gray-2',
287
+ }[props.variant]
288
+ })
289
+
282
290
  defineExpose({
283
291
  reset,
284
292
  })
@@ -294,8 +302,11 @@ defineExpose({
294
302
  :open="isOpen"
295
303
  >
296
304
  <ComboboxAnchor
297
- class="flex h-7 w-full items-center justify-between gap-2 rounded bg-surface-gray-2 px-2 py-1 transition-colors hover:bg-surface-gray-3 border border-transparent focus-within:border-outline-gray-4 focus-within:ring-2 focus-within:ring-outline-gray-3"
298
- :class="{ 'opacity-50 pointer-events-none': disabled }"
305
+ class="flex h-7 w-full items-center justify-between gap-2 rounded px-2 py-1 transition-colors border focus-within:border-outline-gray-4 focus-within:ring-2 focus-within:ring-outline-gray-3"
306
+ :class="{
307
+ 'opacity-50 pointer-events-none': disabled,
308
+ [variantClasses]: true,
309
+ }"
299
310
  @click="handleClick"
300
311
  >
301
312
  <div class="flex items-center gap-2 flex-1 overflow-hidden">
@@ -26,6 +26,7 @@ export type GroupedOption = { group: string; options: SimpleOption[] }
26
26
  export type ComboboxOption = SimpleOption | GroupedOption
27
27
 
28
28
  export interface ComboboxProps {
29
+ variant?: 'subtle' | 'outline'
29
30
  options: Array<ComboboxOption>
30
31
  modelValue?: string | null
31
32
  placeholder?: string
@@ -33,4 +34,4 @@ export interface ComboboxProps {
33
34
  openOnFocus?: boolean
34
35
  openOnClick?: boolean
35
36
  placement?: 'start' | 'center' | 'end'
36
- }
37
+ }
@@ -0,0 +1,6 @@
1
+ export { default as DatePicker } from './DatePicker.vue'
2
+ export { default as DateRangePicker } from './DateRangePicker.vue'
3
+ export { default as DateTimePicker } from './DateTimePicker.vue'
4
+ export * from './types'
5
+ export { useDatePicker } from './useDatePicker'
6
+ export * from './utils'
@@ -53,7 +53,13 @@
53
53
  :model-value="item.switchValue || false"
54
54
  />
55
55
  </div>
56
- <DropdownMenuItem v-else as-child @select="item.onClick">
56
+ <DropdownMenuItem
57
+ v-else
58
+ as-child
59
+ @select="item.onClick"
60
+ :disabled="item.disabled"
61
+ class="data-[disabled]:cursor-not-allowed"
62
+ >
57
63
  <slot v-if="$slots.item" name="item" v-bind="{ item, close }" />
58
64
  <component
59
65
  v-else-if="item.component"
@@ -160,6 +166,8 @@
160
166
  (event: PointerEvent) =>
161
167
  handleItemClick(subItem, event)
162
168
  "
169
+ :disabled="subItem.disabled"
170
+ class="data-[disabled]:cursor-not-allowed"
163
171
  >
164
172
  <component
165
173
  v-if="subItem.component"
@@ -310,10 +318,16 @@ const normalizeDropdownItem = (option: DropdownOption) => {
310
318
  }
311
319
  }
312
320
 
313
- const getIconColor = (item: DropdownItem) =>
314
- item.theme === 'red' ? 'text-ink-red-3' : 'text-ink-gray-6'
315
- const getTextColor = (item: DropdownItem) =>
316
- item.theme === 'red' ? 'text-ink-red-3' : 'text-ink-gray-7'
321
+ const getIconColor = (item: DropdownItem) => {
322
+ if (item.disabled) return 'text-ink-gray-4'
323
+ return item.theme === 'red' ? 'text-ink-red-3' : 'text-ink-gray-6'
324
+ }
325
+
326
+ const getTextColor = (item: DropdownItem) => {
327
+ if (item.disabled) return 'text-ink-gray-4'
328
+ return item.theme === 'red' ? 'text-ink-red-3' : 'text-ink-gray-7'
329
+ }
330
+
317
331
  const getBackgroundColor = (item: DropdownItem) =>
318
332
  item.theme === 'red'
319
333
  ? 'focus:bg-surface-red-3 data-[highlighted]:bg-surface-red-3 data-[state=open]:bg-surface-red-3'
@@ -6,6 +6,7 @@ export type DropdownOption = {
6
6
  label: string
7
7
  icon?: string | Component | null
8
8
  switch?: boolean
9
+ disabled?: boolean
9
10
  switchValue?: boolean
10
11
  theme?: 'gray' | 'red'
11
12
  component?: any
@@ -26,7 +26,7 @@
26
26
  </template>
27
27
  <script setup>
28
28
  import { inject } from 'vue'
29
- import DownSolid from '../../icons/DownSolid.vue'
29
+ import DownSolid from '../../../icons/DownSolidIcon.vue'
30
30
 
31
31
  const props = defineProps({
32
32
  group: {
@@ -2,6 +2,11 @@
2
2
  <div class="mb-5 mt-2" v-if="!group.collapsed">
3
3
  <slot>
4
4
  <ListRow v-for="row in group.rows" :key="row[list.rowKey]" :row="row" />
5
+ <component
6
+ v-if="list.slots['group-empty'] && group.rows.length == 0"
7
+ :is="list.slots['group-empty']"
8
+ v-bind="{ group }"
9
+ />
5
10
  </slot>
6
11
  </div>
7
12
  </template>
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { ref } from 'vue'
3
3
  import Select from './Select.vue'
4
+ import LucideUser from '~icons/lucide/user'
4
5
 
5
6
  const value = ref('')
6
7
  const options = [
@@ -14,8 +15,20 @@ const options = [
14
15
  </script>
15
16
  <template>
16
17
  <Story :layout="{ width: 500, type: 'grid' }">
17
- <div class="p-2">
18
- <Select :options="options" v-model="value" />
19
- </div>
18
+ <Variant title="Default">
19
+ <div class="p-2">
20
+ <Select :options="options" v-model="value" />
21
+ </div>
22
+ </Variant>
23
+
24
+ <Variant title="With prefix">
25
+ <div class="p-2">
26
+ <Select :options="options" v-model="value">
27
+ <template #prefix>
28
+ <LucideUser class="size-4 text-ink-gray-9" />
29
+ </template>
30
+ </Select>
31
+ </div>
32
+ </Variant>
20
33
  </Story>
21
34
  </template>
@@ -1,83 +1,25 @@
1
- <template>
2
- <div class="relative flex items-center">
3
- <div
4
- :class="[
5
- 'absolute inset-y-0 left-0 flex items-center',
6
- textColor,
7
- prefixClasses,
8
- ]"
9
- v-if="$slots.prefix"
10
- >
11
- <slot name="prefix"> </slot>
12
- </div>
13
- <div
14
- v-if="placeholder"
15
- v-show="!modelValue"
16
- class="pointer-events-none absolute text-ink-gray-4 truncate w-full"
17
- :class="[fontSizeClasses, paddingClasses]"
18
- >
19
- {{ placeholder }}
20
- </div>
21
- <select
22
- :class="selectClasses"
23
- :disabled="disabled"
24
- :id="id"
25
- :value="modelValue"
26
- @change="handleChange"
27
- v-bind="attrs"
28
- >
29
- <option
30
- v-for="option in selectOptions"
31
- :key="option.value"
32
- :value="option.value"
33
- :disabled="option.disabled || false"
34
- :selected="modelValue === option.value"
35
- >
36
- {{ option.label }}
37
- </option>
38
- </select>
39
- </div>
40
- </template>
41
-
42
1
  <script setup lang="ts">
43
- import { computed, useSlots, useAttrs } from 'vue'
2
+ import { computed } from 'vue'
44
3
  import type { SelectProps } from './types'
4
+ import LucideChevronDown from '~icons/lucide/chevron-down'
45
5
 
46
- defineOptions({
47
- inheritAttrs: false,
48
- })
6
+ import {
7
+ SelectContent,
8
+ SelectItem,
9
+ SelectItemText,
10
+ SelectPortal,
11
+ SelectRoot,
12
+ SelectTrigger,
13
+ SelectValue,
14
+ SelectViewport,
15
+ } from 'reka-ui'
16
+
17
+ const model = defineModel<String>()
49
18
 
50
19
  const props = withDefaults(defineProps<SelectProps>(), {
51
20
  size: 'sm',
52
21
  variant: 'subtle',
53
- })
54
-
55
- const emit = defineEmits(['update:modelValue'])
56
- const slots = useSlots()
57
- const attrs = useAttrs()
58
-
59
- function handleChange(e: Event) {
60
- emit('update:modelValue', (e.target as HTMLInputElement).value)
61
- }
62
-
63
- const selectOptions = computed(() => {
64
- return (
65
- props.options
66
- ?.map((option) => {
67
- if (typeof option === 'string') {
68
- return {
69
- label: option,
70
- value: option,
71
- }
72
- }
73
- return option
74
- })
75
- .filter(Boolean) || []
76
- )
77
- })
78
-
79
- const textColor = computed(() => {
80
- return props.disabled ? 'text-ink-gray-5' : 'text-ink-gray-8'
22
+ placeholder: 'Select option',
81
23
  })
82
24
 
83
25
  const fontSizeClasses = computed(() => {
@@ -91,29 +33,29 @@ const fontSizeClasses = computed(() => {
91
33
 
92
34
  const paddingClasses = computed(() => {
93
35
  return {
94
- sm: 'pl-2 pr-5',
95
- md: 'pl-2.5 pr-5.5',
96
- lg: 'pl-3 pr-6',
97
- xl: 'pl-3 pr-6',
36
+ sm: 'px-2',
37
+ md: 'px-2.5 ',
38
+ lg: 'px-3',
39
+ xl: 'px-3',
98
40
  }[props.size]
99
41
  })
100
42
 
101
- const selectClasses = computed(() => {
102
- let sizeClasses = {
103
- sm: 'rounded h-7',
104
- md: 'rounded h-8',
105
- lg: 'rounded-md h-10',
106
- xl: 'rounded-md h-10',
107
- }[props.size]
43
+ let sizeClasses = {
44
+ sm: 'rounded min-h-7',
45
+ md: 'rounded min-h-8',
46
+ lg: 'rounded-md min-h-10',
47
+ xl: 'rounded-md min-h-10',
48
+ }[props.size]
108
49
 
50
+ const selectClasses = computed(() => {
109
51
  let variant = props.disabled ? 'disabled' : props.variant
110
52
  let variantClasses = {
111
53
  subtle:
112
- 'border border-[--surface-gray-2] bg-surface-gray-2 hover:border-outline-gray-modals hover:bg-surface-gray-3 focus:border-outline-gray-4 focus:ring-0 focus-visible:ring-2 focus-visible:ring-outline-gray-3',
54
+ 'border border-[--surface-gray-2] bg-surface-gray-2 hover:border-outline-gray-modals hover:bg-surface-gray-3',
113
55
  outline:
114
- 'border border-outline-gray-2 bg-surface-white hover:border-outline-gray-3 focus:border-outline-gray-4 focus:ring-0 focus-visible:ring-2 focus-visible:ring-outline-gray-3',
56
+ 'border border-outline-gray-2 bg-surface-white hover:border-outline-gray-3',
115
57
  ghost:
116
- 'bg-transparent border-transparent hover:bg-surface-gray-3 focus:bg-surface-gray-3 focus:border-outline-gray-4 focus:ring-0 focus-visible:ring-2 focus-visible:ring-outline-gray-3',
58
+ 'bg-transparent border-transparent hover:bg-surface-gray-3 focus:bg-surface-gray-3',
117
59
  disabled: [
118
60
  'border',
119
61
  props.variant !== 'ghost' ? 'bg-surface-gray-1' : '',
@@ -128,17 +70,88 @@ const selectClasses = computed(() => {
128
70
  fontSizeClasses.value,
129
71
  paddingClasses.value,
130
72
  variantClasses,
131
- textColor.value,
132
- 'transition-colors w-full py-0 truncate',
73
+ 'transition-colors w-full data-[state=open]:ring-2 ring-outline-gray-2 ',
133
74
  ]
134
75
  })
135
76
 
136
- let prefixClasses = computed(() => {
137
- return {
138
- sm: 'pl-2',
139
- md: 'pl-2.5',
140
- lg: 'pl-3',
141
- xl: 'pl-3',
142
- }[props.size]
77
+ const selectOptions = computed(() => {
78
+ const str = typeof props.options?.[0] == 'string'
79
+ const tmp = props.options?.map((x) => ({ label: x, value: x }))
80
+ return (str ? tmp : props.options)?.filter(Boolean) || []
143
81
  })
144
82
  </script>
83
+
84
+ <template>
85
+ <SelectRoot v-model="model">
86
+ <SelectTrigger
87
+ class="inline-flex items-center gap-2 outline-none text-base data-[placeholder]:text-ink-gray-4 data-[disabled]:text-ink-gray-4"
88
+ aria-label="Customise options"
89
+ :class="selectClasses"
90
+ :disabled="props.disabled"
91
+ >
92
+ <slot name="prefix" />
93
+ <SelectValue :placeholder="props.placeholder" />
94
+ <LucideChevronDown class="size-4 text-ink-gray-4 ml-auto" />
95
+ </SelectTrigger>
96
+
97
+ <SelectPortal>
98
+ <SelectContent
99
+ class="bg-surface-modal border rounded-lg shadow-lg will-change-[opacity,transform] z-[100] min-w-[--reka-select-trigger-width] max-h-[--reka-select-content-available-height] overflow-auto"
100
+ :side-offset="5"
101
+ position="popper"
102
+ >
103
+ <SelectViewport class="p-1 flex flex-col">
104
+ <SelectItem
105
+ v-for="(option, index) in selectOptions"
106
+ :disabled="option.disabled"
107
+ :key="index"
108
+ :value="option.value"
109
+ :class="[sizeClasses, paddingClasses, fontSizeClasses]"
110
+ class="text-base text-ink-gray-9 flex items-center relative data-[highlighted]:bg-surface-gray-2 border-0 [data-state=checked]:bg-surface-gray-2 data-[disabled]:text-ink-gray-4"
111
+ >
112
+ <SelectItemText>
113
+ {{ option.label }}
114
+ </SelectItemText>
115
+ </SelectItem>
116
+ </SelectViewport>
117
+ </SelectContent>
118
+ </SelectPortal>
119
+ </SelectRoot>
120
+ </template>
121
+
122
+ <style>
123
+ @keyframes slideDownFade {
124
+ from {
125
+ opacity: 0;
126
+ transform: translateY(-4px) scale(0.98);
127
+ }
128
+ to {
129
+ opacity: 1;
130
+ transform: translateY(0) scale(1);
131
+ }
132
+ }
133
+
134
+ @keyframes slideUpFade {
135
+ from {
136
+ opacity: 0;
137
+ transform: translateY(4px) scale(0.98);
138
+ }
139
+ to {
140
+ opacity: 1;
141
+ transform: translateY(0) scale(1);
142
+ }
143
+ }
144
+
145
+ [data-side='top'] {
146
+ animation: slideDownFade 280ms;
147
+ }
148
+
149
+ [data-side='bottom'] {
150
+ animation: slideUpFade 280ms;
151
+ }
152
+
153
+ [data-highlighted],
154
+ [data-state='checked'] {
155
+ outline: none !important;
156
+ }
157
+ </style>
@@ -1,2 +1,5 @@
1
1
  export { default as Sidebar } from './Sidebar.vue'
2
+ export { default as SidebarHeader } from './SidebarHeader.vue'
3
+ export { default as SidebarItem } from './SidebarItem.vue'
4
+ export { default as SidebarSection } from './SidebarSection.vue'
2
5
  export type { SidebarProps } from './types'
@@ -56,7 +56,7 @@ import { ToastAction, ToastClose, ToastDescription, ToastRoot } from 'reka-ui'
56
56
  import LucideInfo from '~icons/lucide/info'
57
57
  import LucideAlertTriangle from '~icons/lucide/alert-triangle'
58
58
  import LucideX from '~icons/lucide/x'
59
- import CircleCheck from '../../icons/CircleCheck.vue'
59
+ import CircleCheck from '../../../icons/CircleCheckIcon.vue'
60
60
  import type { ToastProps } from './types'
61
61
 
62
62
  const props = defineProps<ToastProps>()
@@ -1,6 +1,8 @@
1
+ export * from './useCall/types'
1
2
  export { useCall } from './useCall/useCall'
2
- export { useList } from './useList/useList'
3
3
  export { useDoc } from './useDoc/useDoc'
4
4
  export { useDoctype } from './useDoctype/useDoctype'
5
- export { useNewDoc } from './useNewDoc/useNewDoc'
6
5
  export { useFrappeFetch } from './useFrappeFetch'
6
+ export * from './useList/types'
7
+ export { useList } from './useList/useList'
8
+ export { useNewDoc } from './useNewDoc/useNewDoc'
package/src/index.ts CHANGED
@@ -9,9 +9,7 @@ export * from './components/Button'
9
9
  export { default as Card } from './components/Card.vue'
10
10
  export * from './components/Combobox'
11
11
  export * from './components/Checkbox'
12
- export { default as DatePicker } from './components/DatePicker/DatePicker.vue'
13
- export { default as DateTimePicker } from './components/DatePicker/DateTimePicker.vue'
14
- export { default as DateRangePicker } from './components/DatePicker/DateRangePicker.vue'
12
+ export * from './components/DatePicker'
15
13
  export * from './components/Dialog'
16
14
  export { default as Dialogs } from './components/Dialogs.vue'
17
15
  export * from './components/Divider'
@@ -21,7 +19,6 @@ export { default as FeatherIcon } from './components/FeatherIcon.vue'
21
19
  export * from './components/FileUploader'
22
20
  export * from './components/FormControl'
23
21
  export { default as FormLabel } from './components/FormLabel.vue'
24
- export { default as GreenCheckIcon } from './components/GreenCheckIcon.vue'
25
22
  export { default as Input } from './components/Input.vue'
26
23
  export { default as ListItem } from './components/ListItem.vue'
27
24
  export { default as LoadingIndicator } from './components/LoadingIndicator.vue'
@@ -67,7 +64,9 @@ export * from './components/Calendar'
67
64
  export * from './components/CircularProgressBar'
68
65
  export * from './components/Tree'
69
66
  export { default as FrappeUIProvider } from './components/Provider/FrappeUIProvider.vue'
70
- export { default as Sidebar } from './components/Sidebar/Sidebar.vue'
67
+ export * from './components/Sidebar/index.ts'
68
+ export { default as ConfirmDialog } from './components/ConfirmDialog.vue'
69
+
71
70
 
72
71
  // grid layout
73
72
  export { default as GridLayout } from './components/VueGridLayout/Layout.vue'
@@ -92,33 +91,20 @@ export { usePageMeta } from './utils/pageMeta'
92
91
  export { dayjsLocal, dayjs } from './utils/dayjs'
93
92
  export * from './utils/useFileUpload'
94
93
  export * from './utils/theme'
94
+ export * from './components/TextEditor/extensions/image'
95
95
 
96
96
  // old data-fetching: resources
97
- export {
98
- createResource,
99
- createDocumentResource,
100
- createListResource,
101
- getCachedResource,
102
- getCachedDocumentResource,
103
- getCachedListResource,
104
- resourcesPlugin,
105
- } from './resources/index.js'
97
+ export * from './resources/index.ts'
98
+
106
99
  export { request } from './utils/request.js'
107
100
  export { frappeRequest } from './utils/frappeRequest.js'
108
101
  export { default as initSocket } from './utils/socketio.js'
109
102
  export { setConfig, getConfig } from './utils/config'
110
103
 
111
104
  // new data-fetching composables
112
- export {
113
- useCall,
114
- useList,
115
- useDoc,
116
- useNewDoc,
117
- useDoctype,
118
- useFrappeFetch,
119
- } from './data-fetching'
105
+ export * from './data-fetching'
120
106
 
121
107
  // plugin
108
+ export { confirmDialog } from './utils/confirmDialog.js'
122
109
  export { default as pageMetaPlugin } from './utils/pageMeta.js'
123
110
  export { default as FrappeUI } from './utils/plugin.js'
124
- export { confirmDialog } from './utils/confirmDialog.js'
@@ -1,7 +1,9 @@
1
- export { createResource, getCachedResource } from './resources'
2
1
  export {
3
2
  createDocumentResource,
4
3
  getCachedDocumentResource,
5
4
  } from './documentResource'
6
5
  export { createListResource, getCachedListResource } from './listResource'
6
+ export * from './local'
7
7
  export { default as resourcesPlugin } from './plugin'
8
+ export * from './realtime'
9
+ export { createResource, getCachedResource } from './resources'
@@ -1,6 +1,6 @@
1
- import { get, set, del } from 'idb-keyval'
1
+ import { del, get, set } from 'idb-keyval'
2
2
 
3
- export function saveLocal(key, data) {
3
+ export function saveLocal<T = any>(key: string, data: T): Promise<void | null> {
4
4
  if (typeof indexedDB === 'undefined') {
5
5
  return Promise.resolve(null)
6
6
  }
@@ -8,7 +8,7 @@ export function saveLocal(key, data) {
8
8
  return set(key, JSON.stringify(data))
9
9
  }
10
10
 
11
- export function deleteLocal(key) {
11
+ export function deleteLocal(key: string): Promise<void | null> {
12
12
  if (typeof indexedDB === 'undefined') {
13
13
  return Promise.resolve(null)
14
14
  }
@@ -16,7 +16,7 @@ export function deleteLocal(key) {
16
16
  return del(key)
17
17
  }
18
18
 
19
- export function getLocal(key) {
19
+ export function getLocal<T = any>(key: string): Promise<T | null> {
20
20
  if (typeof indexedDB === 'undefined') {
21
21
  return Promise.resolve(null)
22
22
  }
@@ -0,0 +1,21 @@
1
+ import { Socket } from 'socket.io-client'
2
+
3
+ export function onDocUpdate(
4
+ socket: Socket,
5
+ doctype: string,
6
+ callback: (name: string) => void,
7
+ ): void {
8
+ subscribe(socket, doctype)
9
+ socket.on('list_update', (data) => {
10
+ if (data.doctype == doctype) {
11
+ callback(data.name)
12
+ }
13
+ })
14
+ }
15
+
16
+ let subscribed: Record<string, boolean> = {}
17
+ function subscribe(socket: Socket, doctype: string): void {
18
+ if (subscribed[doctype]) return
19
+ socket.emit('doctype_subscribe', doctype)
20
+ subscribed[doctype] = true
21
+ }
@@ -1,15 +0,0 @@
1
- export function onDocUpdate(socket, doctype, callback) {
2
- subscribe(socket, doctype)
3
- socket.on('list_update', (data) => {
4
- if (data.doctype == doctype) {
5
- callback(data.name)
6
- }
7
- })
8
- }
9
-
10
- let subscribed = {}
11
- function subscribe(socket, doctype) {
12
- if (subscribed[doctype]) return
13
- socket.emit('doctype_subscribe', doctype)
14
- subscribed[doctype] = true
15
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes