frappe-ui 0.0.25 → 0.0.28

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.0.25",
3
+ "version": "0.0.28",
4
4
  "description": "A set of components and utilities for rapid UI development",
5
5
  "main": "./src/index.js",
6
6
  "scripts": {
@@ -30,12 +30,13 @@
30
30
  <textarea
31
31
  v-if="type === 'textarea'"
32
32
  v-bind="inputAttributes"
33
+ :placeholder="placeholder"
34
+ class="placeholder-gray-500"
33
35
  :class="['block w-full resize-none form-textarea', inputClass]"
34
36
  ref="input"
35
37
  :value="passedInputValue"
36
38
  :disabled="disabled"
37
39
  :rows="rows || 3"
38
- @blur="$emit('blur', $event)"
39
40
  ></textarea>
40
41
  <select
41
42
  v-bind="inputAttributes"
@@ -48,6 +49,7 @@
48
49
  v-for="option in selectOptions"
49
50
  :key="option.value"
50
51
  :value="option.value"
52
+ :disabled="option.disabled || false"
51
53
  :selected="passedInputValue === option.value"
52
54
  >
53
55
  {{ option.label }}
@@ -114,7 +116,7 @@ export default {
114
116
  type: String,
115
117
  },
116
118
  },
117
- emits: ['blur', 'input', 'change', 'update:modelValue'],
119
+ emits: ['input', 'change', 'update:modelValue'],
118
120
  methods: {
119
121
  focus() {
120
122
  this.$refs.input.focus()
@@ -158,16 +160,23 @@ export default {
158
160
  })
159
161
  },
160
162
  selectOptions() {
161
- return this.options.map((option) => {
162
- if (typeof option === 'string') {
163
- return {
164
- label: option,
165
- value: option,
163
+ return this.options
164
+ .map((option) => {
165
+ if (typeof option === 'string') {
166
+ return {
167
+ label: option,
168
+ value: option,
169
+ }
166
170
  }
167
- }
168
- return option
169
- })
171
+ return option
172
+ })
173
+ .filter(Boolean)
170
174
  },
171
175
  },
172
176
  }
173
177
  </script>
178
+ <style>
179
+ .form-select {
180
+ background-image: url("data:image/svg+xml;utf8,<svg fill='none' width='8' xmlns='http://www.w3.org/2000/svg' viewBox='-4 -2 16 16'><path d='M4.5 3.636 6.136 2l1.637 1.636M4.5 8.364 6.136 10l1.637-1.636' stroke='%23333C44' stroke-linecap='round' stroke-linejoin='round'/></svg>");
181
+ }
182
+ </style>
@@ -9,7 +9,7 @@
9
9
  >
10
10
  <slot
11
11
  name="target"
12
- v-bind="{ togglePopover, updatePosition, open, close }"
12
+ v-bind="{ togglePopover, updatePosition, open, close, isOpen }"
13
13
  ></slot>
14
14
  </div>
15
15
  <teleport to="#frappeui-popper-root">
@@ -18,12 +18,21 @@
18
18
  :class="popoverClass"
19
19
  class="relative z-[100] popover-container"
20
20
  :style="{ minWidth: targetWidth ? targetWidth + 'px' : null }"
21
+ v-show="isOpen"
21
22
  >
22
- <div v-if="!hideArrow" class="popover-arrow" ref="popover-arrow"></div>
23
- <slot
24
- name="content"
25
- v-bind="{ togglePopover, updatePosition, open, close }"
26
- ></slot>
23
+ <transition v-bind="transition">
24
+ <div v-show="isOpen">
25
+ <div
26
+ v-if="!hideArrow"
27
+ class="popover-arrow"
28
+ ref="popover-arrow"
29
+ ></div>
30
+ <slot
31
+ name="content"
32
+ v-bind="{ togglePopover, updatePosition, open, close, isOpen }"
33
+ ></slot>
34
+ </div>
35
+ </transition>
27
36
  </div>
28
37
  </teleport>
29
38
  </div>
@@ -48,6 +57,10 @@ export default {
48
57
  default: 'bottom-start',
49
58
  },
50
59
  popoverClass: [String, Object, Array],
60
+ transition: {
61
+ type: Object,
62
+ default: null,
63
+ },
51
64
  },
52
65
  emits: ['init', 'open', 'close'],
53
66
  watch: {
package/src/index.js CHANGED
@@ -29,6 +29,7 @@ export { default as onOutsideClickDirective } from './directives/onOutsideClick.
29
29
  export { default as call, createCall } from './utils/call.js'
30
30
  export { default as debounce } from './utils/debounce.js'
31
31
  export { createResource } from './utils/resources.js'
32
+ export { default as pageMeta } from './utils/pageMeta.js'
32
33
 
33
34
  // plugin
34
35
  export { default as FrappeUI } from './utils/plugin.js'
@@ -0,0 +1,47 @@
1
+ import { watch } from 'vue'
2
+
3
+ export default {
4
+ install(app) {
5
+ app.mixin(createMixin())
6
+ },
7
+ }
8
+
9
+ function createMixin() {
10
+ let faviconRef = document.querySelector('link[rel="icon"]')
11
+ let defaultFavIcon = faviconRef.href
12
+
13
+ return {
14
+ created() {
15
+ if (this.$options.pageMeta) {
16
+ watch(
17
+ () => {
18
+ try {
19
+ return this.$options.pageMeta.call(this)
20
+ } catch (error) {
21
+ console.warn('Failed to parse pageMeta\n\n', error)
22
+ return null
23
+ }
24
+ },
25
+ (pageMeta) => {
26
+ if (!pageMeta) return
27
+ if (pageMeta.title) {
28
+ document.title = pageMeta.title
29
+ }
30
+ if (pageMeta.emoji) {
31
+ let href = `data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>${pageMeta.emoji}</text></svg>`
32
+ faviconRef.href = href
33
+ } else if (pageMeta.icon) {
34
+ faviconRef.href = pageMeta.icon
35
+ } else {
36
+ faviconRef.href = defaultFavIcon
37
+ }
38
+ },
39
+ {
40
+ immediate: true,
41
+ deep: true,
42
+ }
43
+ )
44
+ }
45
+ },
46
+ }
47
+ }
@@ -196,6 +196,7 @@ export function createDocumentResource(options, vm) {
196
196
  onSuccess(data) {
197
197
  out.doc = transform(data)
198
198
  },
199
+ onError: options.onError,
199
200
  },
200
201
  vm
201
202
  ),
@@ -287,8 +288,10 @@ function createListResource(options, vm, getResource) {
287
288
  if (!options.doctype) return
288
289
 
289
290
  let cacheKey = getCacheKey(options.cache)
290
- if (listCache[cacheKey]) {
291
- return listCache[cacheKey]
291
+ if (cacheKey) {
292
+ if (listCache[cacheKey]) {
293
+ return listCache[cacheKey]
294
+ }
292
295
  }
293
296
 
294
297
  let out = reactive({
@@ -298,6 +301,7 @@ function createListResource(options, vm, getResource) {
298
301
  order_by: options.order_by,
299
302
  start: options.start,
300
303
  limit: options.limit,
304
+ originalData: null,
301
305
  data: null,
302
306
  list: createResource(
303
307
  {
@@ -313,6 +317,7 @@ function createListResource(options, vm, getResource) {
313
317
  }
314
318
  },
315
319
  onSuccess(data) {
320
+ out.originalData = data
316
321
  out.data = transform(data)
317
322
  options.onSuccess?.call(vm, out.data)
318
323
  },
@@ -320,6 +325,37 @@ function createListResource(options, vm, getResource) {
320
325
  },
321
326
  vm
322
327
  ),
328
+ fetchOne: createResource(
329
+ {
330
+ method: 'frappe.client.get_list',
331
+ makeParams(name) {
332
+ return {
333
+ doctype: out.doctype,
334
+ fields: out.fields,
335
+ filters: { name },
336
+ }
337
+ },
338
+ onSuccess(data) {
339
+ if (data.length > 0 && out.originalData) {
340
+ let doc = data[0]
341
+ let index = out.originalData.findIndex((d) => d.name === doc.name)
342
+ out.originalData = out.originalData.filter(
343
+ (d) => d.name !== doc.name
344
+ )
345
+ out.originalData = [
346
+ out.originalData.slice(0, index),
347
+ data,
348
+ out.originalData.slice(index),
349
+ ].flat()
350
+ }
351
+
352
+ out.data = transform(out.originalData)
353
+ options.fetchOne?.onSuccess?.call(vm, out.data)
354
+ },
355
+ onError: options.fetchOne?.onError,
356
+ },
357
+ vm
358
+ ),
323
359
  insert: createResource(
324
360
  {
325
361
  method: 'frappe.client.insert',
@@ -414,8 +450,10 @@ function createListResource(options, vm, getResource) {
414
450
  // fetch list
415
451
  out.list.fetch()
416
452
 
417
- // cache
418
- listCache[cacheKey] = out
453
+ if (cacheKey) {
454
+ // cache
455
+ listCache[cacheKey] = out
456
+ }
419
457
 
420
458
  return out
421
459
  }
@@ -431,6 +469,9 @@ function createResourceForOptions(options, vm, getResource) {
431
469
  }
432
470
 
433
471
  function getCacheKey(cacheKey) {
472
+ if (!cacheKey) {
473
+ return null
474
+ }
434
475
  if (typeof cacheKey === 'string') {
435
476
  cacheKey = [cacheKey]
436
477
  }