frappe-ui 0.1.76 → 0.1.78

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frappe-ui",
3
- "version": "0.1.76",
3
+ "version": "0.1.78",
4
4
  "description": "A set of components and utilities for rapid UI development",
5
5
  "main": "./src/index.js",
6
6
  "scripts": {
@@ -41,37 +41,35 @@ const props = withDefaults(defineProps<BadgeProps>(), {
41
41
 
42
42
  const classes = computed(() => {
43
43
  let solidClasses = {
44
- gray: 'text-text-icons-white bg-surface-gray-7',
45
- blue: 'text-text-icons-blue-1 bg-surface-blue-2',
46
- green: 'text-text-icons-green-1 bg-surface-green-3',
47
- orange: 'text-text-icons-amber-1 bg-surface-amber-2',
48
- red: 'text-text-icons-red-1 bg-surface-red-4',
44
+ gray: 'text-ink-white bg-surface-gray-7',
45
+ blue: 'text-ink-blue-1 bg-surface-blue-2',
46
+ green: 'text-ink-green-1 bg-surface-green-3',
47
+ orange: 'text-ink-amber-1 bg-surface-amber-2',
48
+ red: 'text-ink-red-1 bg-surface-red-4',
49
49
  }[props.theme]
50
50
 
51
51
  let subtleClasses = {
52
- gray: 'text-text-icons-gray-6 bg-surface-gray-2',
53
- blue: 'text-text-icons-blue-2 bg-surface-blue-1',
54
- green: 'text-text-icons-green-3 bg-surface-green-2',
55
- orange: 'text-text-icons-amber-3 bg-surface-amber-1',
56
- red: 'text-text-icons-red-4 bg-surface-red-1',
52
+ gray: 'text-ink-gray-6 bg-surface-gray-2',
53
+ blue: 'text-ink-blue-2 bg-surface-blue-1',
54
+ green: 'text-ink-green-3 bg-surface-green-2',
55
+ orange: 'text-ink-amber-3 bg-surface-amber-1',
56
+ red: 'text-ink-red-4 bg-surface-red-1',
57
57
  }[props.theme]
58
58
 
59
59
  let outlineClasses = {
60
- gray: 'text-text-icons-gray-6 bg-transparent border border-outline-gray-1',
61
- blue: 'text-text-icons-blue-2 bg-transparent border border-outline-blue-1',
62
- green:
63
- 'text-text-icons-green-3 bg-transparent border border-outline-green-2',
64
- orange:
65
- 'text-text-icons-amber-3 bg-transparent border border-outline-amber-2',
66
- red: 'text-text-icons-red-4 bg-transparent border border-outline-red-2',
60
+ gray: 'text-ink-gray-6 bg-transparent border border-outline-gray-1',
61
+ blue: 'text-ink-blue-2 bg-transparent border border-outline-blue-1',
62
+ green: 'text-ink-green-3 bg-transparent border border-outline-green-2',
63
+ orange: 'text-ink-amber-3 bg-transparent border border-outline-amber-2',
64
+ red: 'text-ink-red-4 bg-transparent border border-outline-red-2',
67
65
  }[props.theme]
68
66
 
69
67
  let ghostClasses = {
70
- gray: 'text-text-icons-gray-6 bg-transparent',
71
- blue: 'text-text-icons-blue-2 bg-transparent',
72
- green: 'text-text-icons-green-3 bg-transparent',
73
- orange: 'text-text-icons-amber-3 bg-transparent',
74
- red: 'text-text-icons-red-4 bg-transparent',
68
+ gray: 'text-ink-gray-6 bg-transparent',
69
+ blue: 'text-ink-blue-2 bg-transparent',
70
+ green: 'text-ink-green-3 bg-transparent',
71
+ orange: 'text-ink-amber-3 bg-transparent',
72
+ red: 'text-ink-red-4 bg-transparent',
75
73
  }[props.theme]
76
74
 
77
75
  let variantClasses = {
@@ -5,6 +5,12 @@ import { Button } from './Button'
5
5
 
6
6
  const dialog1 = ref(false)
7
7
  const dialog2 = ref(false)
8
+
9
+ const createPromise = () => {
10
+ return new Promise((resolve) => {
11
+ setTimeout(resolve, 2000)
12
+ })
13
+ }
8
14
  </script>
9
15
  <template>
10
16
  <Story :layout="{ width: 500, type: 'grid' }">
@@ -15,7 +21,15 @@ const dialog2 = ref(false)
15
21
  title: 'Confirm',
16
22
  message: 'Are you sure you want to confirm this action?',
17
23
  size: 'xl',
18
- actions: [{ label: 'Confirm', variant: 'solid', onClick: () => {} }],
24
+ actions: [
25
+ {
26
+ label: 'Confirm',
27
+ variant: 'solid',
28
+ onClick: () => {
29
+ return createPromise()
30
+ },
31
+ },
32
+ ],
19
33
  }"
20
34
  v-model="dialog1"
21
35
  />
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <TransitionRoot
3
3
  as="template"
4
- :show="open"
4
+ :show="isOpen"
5
5
  @after-leave="$emit('after-leave')"
6
6
  >
7
7
  <HDialog
@@ -116,13 +116,13 @@
116
116
  </slot>
117
117
  <div
118
118
  class="px-4 pb-7 pt-4 sm:px-6"
119
- v-if="dialogActions.length || $slots.actions"
119
+ v-if="actions.length || $slots.actions"
120
120
  >
121
121
  <slot name="actions" v-bind="{ close }">
122
122
  <div class="space-y-2">
123
123
  <Button
124
124
  class="w-full"
125
- v-for="action in dialogActions"
125
+ v-for="action in actions"
126
126
  :key="action.label"
127
127
  v-bind="action"
128
128
  >
@@ -147,7 +147,7 @@ import {
147
147
  TransitionChild,
148
148
  TransitionRoot,
149
149
  } from '@headlessui/vue'
150
- import { computed, ref, watch } from 'vue'
150
+ import { computed, reactive } from 'vue'
151
151
  import { Button, ButtonProps } from './Button'
152
152
  import FeatherIcon from './FeatherIcon.vue'
153
153
 
@@ -178,8 +178,11 @@ type DialogOptions = {
178
178
  position?: 'top' | 'center'
179
179
  }
180
180
 
181
+ type DialogActionContext = {
182
+ close: () => void
183
+ }
181
184
  type DialogAction = ButtonProps & {
182
- onClick?: (close: () => void) => Promise<void> | void
185
+ onClick?: (context: DialogActionContext) => void | Promise<void>
183
186
  }
184
187
 
185
188
  interface DialogProps {
@@ -199,37 +202,41 @@ const emit = defineEmits<{
199
202
  (event: 'after-leave'): void
200
203
  }>()
201
204
 
202
- const dialogActions = ref<Array<DialogAction>>([])
203
- watch(
204
- () => props.options.actions,
205
- (actions) => {
206
- if (!actions?.length) return
205
+ const actions = computed(() => {
206
+ let actions = props.options.actions
207
+ if (!actions?.length) return []
207
208
 
208
- dialogActions.value = actions.map((action) => {
209
- let loading = ref(false)
210
- return {
211
- ...action,
212
- loading,
213
- onClick: !action.onClick
214
- ? close
215
- : async () => {
216
- loading.value = true
217
- try {
218
- if (action.onClick) {
219
- // pass close function to action
220
- await action.onClick(close)
209
+ return actions.map((action) => {
210
+ let _action = reactive({
211
+ ...action,
212
+ loading: false,
213
+ onClick: !action.onClick
214
+ ? close
215
+ : async () => {
216
+ _action.loading = true
217
+ try {
218
+ if (action.onClick) {
219
+ // deprecated: uncomment this when we remove the backwards compatibility
220
+ // let context: DialogActionContext = { close }
221
+ let backwardsCompatibleContext = function () {
222
+ console.warn(
223
+ 'Value passed to onClick is a context object. Please use context.close() instead of context() to close the dialog.',
224
+ )
225
+ close()
221
226
  }
222
- } finally {
223
- loading.value = false
227
+ backwardsCompatibleContext.close = close
228
+ await action.onClick(backwardsCompatibleContext)
224
229
  }
225
- },
226
- }
230
+ } finally {
231
+ _action.loading = false
232
+ }
233
+ },
227
234
  })
228
- },
229
- { immediate: true },
230
- )
235
+ return _action
236
+ })
237
+ })
231
238
 
232
- const open = computed({
239
+ const isOpen = computed({
233
240
  get() {
234
241
  return props.modelValue
235
242
  },
@@ -242,7 +249,7 @@ const open = computed({
242
249
  })
243
250
 
244
251
  function close() {
245
- open.value = false
252
+ isOpen.value = false
246
253
  }
247
254
 
248
255
  const icon = computed(() => {
@@ -26,7 +26,7 @@
26
26
  <div v-for="group in groups" :key="group.key" class="p-1.5">
27
27
  <div
28
28
  v-if="group.group && !group.hideLabel"
29
- class="flex h-7 items-center px-2 text-sm font-medium text-text-icons-gray-6"
29
+ class="flex h-7 items-center px-2 text-sm font-medium text-ink-gray-6"
30
30
  >
31
31
  {{ group.group }}
32
32
  </div>
@@ -43,7 +43,7 @@
43
43
  <button
44
44
  v-else
45
45
  :class="[
46
- active ? 'bg-gray-100' : 'text-text-icons-gray-6',
46
+ active ? 'bg-gray-100' : 'text-ink-gray-6',
47
47
  'group flex h-7 w-full items-center rounded px-2 text-base',
48
48
  ]"
49
49
  @click="item.onClick"
@@ -51,11 +51,11 @@
51
51
  <FeatherIcon
52
52
  v-if="item.icon && typeof item.icon === 'string'"
53
53
  :name="item.icon"
54
- class="mr-2 h-4 w-4 flex-shrink-0 text-text-icons-gray-6"
54
+ class="mr-2 h-4 w-4 flex-shrink-0 text-ink-gray-6"
55
55
  aria-hidden="true"
56
56
  />
57
57
  <component
58
- class="mr-2 h-4 w-4 flex-shrink-0 text-text-icons-gray-6"
58
+ class="mr-2 h-4 w-4 flex-shrink-0 text-ink-gray-6"
59
59
  v-else-if="item.icon"
60
60
  :is="item.icon"
61
61
  />
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="space-y-1">
3
- <label class="block text-xs text-text-icons-gray-5" v-if="label">
3
+ <label class="block text-xs text-ink-gray-5" v-if="label">
4
4
  {{ label }}
5
5
  </label>
6
6
  <div class="flex text-center">
@@ -12,7 +12,7 @@
12
12
  >
13
13
  <FeatherIcon
14
14
  name="star"
15
- class="fill-gray-400 text-text-icons-gray-1 stroke-1 mr-1"
15
+ class="fill-gray-400 text-ink-gray-1 stroke-1 mr-1"
16
16
  :class="iconClasses(index)"
17
17
  @click="markRating(index)"
18
18
  />
@@ -10,12 +10,6 @@ It is an array of objects which contains the following attributes:
10
10
  3. You can add more attributes which can be used for custom rendering in the tab
11
11
  header or content.
12
12
 
13
- ### Options
14
-
15
- Currently, it has only one option `indicatorLeft` which is used to set the left
16
- position of the indicator in case of custom rendering. It is optional and
17
- default value is `20`.
18
-
19
13
  ## v-model
20
14
 
21
15
  It is used to set the active tab or change the active tab. It is required.
@@ -1,13 +1,15 @@
1
1
  <template>
2
2
  <TabGroup
3
3
  as="div"
4
- class="flex flex-1 flex-col"
4
+ class="flex flex-1 flex-col overflow-y-hidden"
5
+ :style="`height: calc(100vh - ${tabListRef?.$el.offsetTop}px)`"
5
6
  :defaultIndex="changedIndex"
6
7
  :selectedIndex="changedIndex"
7
8
  @change="(idx) => (changedIndex = idx)"
8
9
  >
9
10
  <TabList
10
- class="relative flex items-center gap-7.5 overflow-x-auto border-b pl-5"
11
+ ref="tabListRef"
12
+ class="relative flex items-center gap-7.5 overflow-x-auto border-b px-5"
11
13
  :class="tablistClass"
12
14
  >
13
15
  <Tab
@@ -30,9 +32,8 @@
30
32
  </Tab>
31
33
  <div
32
34
  ref="indicator"
33
- class="absolute bottom-0 h-px bg-gray-900"
35
+ class="tab-indicator absolute bottom-0 h-px bg-gray-900"
34
36
  :class="transitionClass"
35
- :style="{ left: `${indicatorLeft}px` }"
36
37
  />
37
38
  </TabList>
38
39
  <TabPanels class="flex flex-1 overflow-hidden" :class="tabPanelClass">
@@ -68,12 +69,6 @@ const props = defineProps({
68
69
  type: String,
69
70
  default: '',
70
71
  },
71
- options: {
72
- type: Object,
73
- default: () => ({
74
- indicatorLeft: 20,
75
- }),
76
- },
77
72
  })
78
73
 
79
74
  const emit = defineEmits(['update:modelValue'])
@@ -83,11 +78,11 @@ const changedIndex = computed({
83
78
  set: (index) => emit('update:modelValue', index),
84
79
  })
85
80
 
81
+ const tabListRef = ref(null)
86
82
  const tabRef = ref([])
87
83
  const indicator = ref(null)
88
84
  const tabsLength = computed(() => props.tabs?.length)
89
85
 
90
- const indicatorLeft = ref(props.options?.indicatorLeft)
91
86
  const transitionClass = ref('')
92
87
 
93
88
  function moveIndicator(index) {
@@ -96,20 +91,20 @@ function moveIndicator(index) {
96
91
  }
97
92
  const selectedTab = tabRef.value[index].el
98
93
  indicator.value.style.width = `${selectedTab.offsetWidth}px`
99
- indicatorLeft.value = selectedTab.offsetLeft
94
+ indicator.value.style.left = `${selectedTab.offsetLeft}px`
100
95
  }
101
96
 
102
97
  watch(changedIndex, (index) => {
103
98
  if (index >= tabsLength.value) {
104
99
  changedIndex.value = tabsLength.value - 1
105
100
  }
101
+ transitionClass.value = 'transition-all duration-300 ease-in-out'
106
102
  nextTick(() => moveIndicator(index))
107
103
  })
108
104
 
109
105
  onMounted(() => {
110
- moveIndicator(changedIndex.value)
111
- nextTick(() => {
112
- transitionClass.value = 'transition-all duration-300 ease-in-out'
113
- })
106
+ nextTick(() => moveIndicator(changedIndex.value))
107
+ // Fix for indicator not moving on initial load
108
+ setTimeout(() => moveIndicator(changedIndex.value), 100)
114
109
  })
115
110
  </script>
@@ -51,6 +51,10 @@ interface TextInputProps {
51
51
  debounce?: number
52
52
  }
53
53
 
54
+ defineOptions({
55
+ inheritAttrs: false,
56
+ })
57
+
54
58
  const props = withDefaults(defineProps<TextInputProps>(), {
55
59
  type: 'text',
56
60
  size: 'sm',
package/src/style.css CHANGED
@@ -1,37 +1,5 @@
1
1
  @import './fonts/Inter/inter.css';
2
- @import './espressoColors.css';
3
2
 
4
3
  @tailwind base;
5
4
  @tailwind components;
6
5
  @tailwind utilities;
7
-
8
- @layer base {
9
- html,
10
- body,
11
- button,
12
- p,
13
- span,
14
- div {
15
- font-variation-settings: 'opsz' 24;
16
- -webkit-font-smoothing: antialiased;
17
- -moz-osx-font-smoothing: grayscale;
18
- }
19
-
20
- select {
21
- background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="%237C7C7C" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" aria-hidden="true" viewBox="0 0 24 24" ><path d="m6 9 6 6 6-6" /></svg>');
22
- background-size: 1.13em;
23
- background-position: right 0.44rem center;
24
- }
25
- }
26
-
27
- @layer components {
28
- .form-input,
29
- .form-textarea,
30
- .form-select {
31
- @apply h-7 rounded border border-gray-100 bg-gray-100 py-1.5 pl-2 pr-2 text-base text-gray-800 placeholder-gray-500 transition-colors hover:border-gray-200 hover:bg-gray-200 focus:border-gray-500 focus:bg-white focus:shadow-sm focus:ring-0 focus-visible:ring-2 focus-visible:ring-gray-400;
32
- }
33
-
34
- .form-checkbox {
35
- @apply rounded-md bg-gray-100 text-blue-500 focus:ring-0 focus-visible:ring-1;
36
- }
37
- }