frappe-ui 0.0.12 → 0.0.13

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.12",
3
+ "version": "0.0.13",
4
4
  "description": "A set of components and utilities for rapid UI development",
5
5
  "main": "./src/index.js",
6
6
  "scripts": {
@@ -86,25 +86,25 @@ export default {
86
86
  onClick,
87
87
  }
88
88
  },
89
- },
90
- computed: {
91
- dropdownItems() {
92
- return (this.options || [])
89
+ filterOptions(options) {
90
+ return (options || [])
93
91
  .filter(Boolean)
94
92
  .filter((option) => (option.condition ? option.condition() : true))
95
93
  .map((option) => this.normalizeDropdownItem(option))
96
94
  },
95
+ },
96
+ computed: {
97
97
  groups() {
98
98
  let groups = this.options[0]?.group
99
99
  ? this.options
100
- : [{ group: '', items: this.options }]
100
+ : [{ group: '', items: this.filterOptions(this.options) }]
101
101
 
102
102
  return groups.map((group, i) => {
103
103
  return {
104
104
  key: i,
105
105
  group: group.group,
106
106
  hideLabel: group.hideLabel || false,
107
- items: group.items.map((item) => this.normalizeDropdownItem(item)),
107
+ items: this.filterOptions(group.items),
108
108
  }
109
109
  })
110
110
  },
@@ -68,6 +68,7 @@ import { debounce } from 'frappe-ui'
68
68
  export default {
69
69
  name: 'Input',
70
70
  inheritAttrs: false,
71
+ expose: ['getInputValue'],
71
72
  props: {
72
73
  label: {
73
74
  type: String,
@@ -122,9 +123,10 @@ export default {
122
123
  this.$refs.input.blur()
123
124
  },
124
125
  getInputValue(e) {
125
- let value = e.target.value
126
+ let $input = e ? e.target : this.$refs.input
127
+ let value = $input.value
126
128
  if (this.type == 'checkbox') {
127
- value = e.target.checked
129
+ value = $input.checked
128
130
  }
129
131
  return value
130
132
  },
@@ -134,7 +136,7 @@ export default {
134
136
  if ('value' in this.$attrs) {
135
137
  return this.$attrs.value
136
138
  }
137
- return this.modelValue
139
+ return this.modelValue || null
138
140
  },
139
141
  inputAttributes() {
140
142
  let onInput = (e) => {
@@ -1,17 +1,29 @@
1
1
  <template>
2
2
  <div ref="reference">
3
- <div class="h-full">
4
- <slot name="target" :togglePopover="togglePopover"></slot>
3
+ <div
4
+ class="h-full"
5
+ ref="target"
6
+ @click="updatePosition"
7
+ @focusin="updatePosition"
8
+ @keydown="updatePosition"
9
+ >
10
+ <slot
11
+ name="target"
12
+ v-bind="{ togglePopover, updatePosition, open, close }"
13
+ ></slot>
5
14
  </div>
6
- <teleport to="#popovers">
15
+ <teleport to="#frappeui-popper-root">
7
16
  <div
8
17
  ref="popover"
9
18
  :class="popoverClass"
10
- class="bg-white rounded-md border shadow-md popover-container relative"
11
- v-show="isOpen"
19
+ class="relative z-[100] popover-container"
20
+ :style="{ minWidth: targetWidth ? targetWidth + 'px' : null }"
12
21
  >
13
22
  <div v-if="!hideArrow" class="popover-arrow" ref="popover-arrow"></div>
14
- <slot name="content" :togglePopover="togglePopover"></slot>
23
+ <slot
24
+ name="content"
25
+ v-bind="{ togglePopover, updatePosition, open, close }"
26
+ ></slot>
15
27
  </div>
16
28
  </teleport>
17
29
  </div>
@@ -25,9 +37,9 @@ export default {
25
37
  props: {
26
38
  hideArrow: {
27
39
  type: Boolean,
28
- default: false,
40
+ default: true,
29
41
  },
30
- showPopup: {
42
+ show: {
31
43
  default: null,
32
44
  },
33
45
  right: Boolean,
@@ -39,18 +51,28 @@ export default {
39
51
  },
40
52
  emits: ['init', 'open', 'close'],
41
53
  watch: {
42
- showPopup(value) {
43
- if (value === true) {
44
- this.open()
45
- }
46
- if (value === false) {
47
- this.close()
48
- }
54
+ show: {
55
+ immediate: true,
56
+ handler(val) {
57
+ if (val) {
58
+ this.open()
59
+ } else {
60
+ this.close()
61
+ }
62
+ },
49
63
  },
50
64
  },
51
65
  data() {
52
66
  return {
53
67
  isOpen: false,
68
+ targetWidth: null,
69
+ }
70
+ },
71
+ created() {
72
+ if (!document.getElementById('frappeui-popper-root')) {
73
+ const root = document.createElement('div')
74
+ root.id = 'frappeui-popper-root'
75
+ document.body.appendChild(root)
54
76
  }
55
77
  },
56
78
  mounted() {
@@ -67,6 +89,9 @@ export default {
67
89
  if (this.show == null) {
68
90
  document.addEventListener('click', this.listener)
69
91
  }
92
+ this.$nextTick(() => {
93
+ this.targetWidth = this.$refs['target'].clientWidth
94
+ })
70
95
  },
71
96
  beforeDestroy() {
72
97
  this.popper && this.popper.destroy()
@@ -95,10 +120,13 @@ export default {
95
120
  : [],
96
121
  })
97
122
  } else {
98
- this.popper.update()
123
+ this.updatePosition()
99
124
  }
100
125
  this.$emit('init')
101
126
  },
127
+ updatePosition() {
128
+ this.popper && this.popper.update()
129
+ },
102
130
  togglePopover(flag) {
103
131
  if (flag == null) {
104
132
  flag = !this.isOpen
@@ -115,9 +143,7 @@ export default {
115
143
  return
116
144
  }
117
145
  this.isOpen = true
118
- this.$nextTick(() => {
119
- this.setupPopper()
120
- })
146
+ this.$nextTick(() => this.setupPopper())
121
147
  this.$emit('open')
122
148
  },
123
149
  close() {
@@ -41,7 +41,7 @@ export function createResource(options, vm, getResource) {
41
41
  setData,
42
42
  })
43
43
 
44
- async function fetch(params) {
44
+ async function fetch(params, tempOptions = {}) {
45
45
  if (params instanceof Event) {
46
46
  params = null
47
47
  }
@@ -57,18 +57,22 @@ export function createResource(options, vm, getResource) {
57
57
  options.onFetch.call(vm, out.params)
58
58
  }
59
59
 
60
- if (options.validate) {
60
+ let validateFunction = tempOptions.validate || options.validate
61
+ let errorFunction = tempOptions.onError || options.onError
62
+ let successFunction = tempOptions.onSuccess || options.onSuccess
63
+
64
+ if (validateFunction) {
61
65
  let invalidMessage
62
66
  try {
63
- invalidMessage = await options.validate.call(vm, out.params)
67
+ invalidMessage = await validateFunction.call(vm, out.params)
64
68
  if (invalidMessage && typeof invalidMessage == 'string') {
65
69
  let error = new Error(invalidMessage)
66
- handleError(error)
70
+ handleError(error, errorFunction)
67
71
  out.loading = false
68
72
  return
69
73
  }
70
74
  } catch (error) {
71
- handleError(error)
75
+ handleError(error, errorFunction)
72
76
  out.loading = false
73
77
  return
74
78
  }
@@ -78,11 +82,11 @@ export function createResource(options, vm, getResource) {
78
82
  let data = await resourceFetcher(options.method, params || options.params)
79
83
  out.data = data
80
84
  out.fetched = true
81
- if (options.onSuccess) {
82
- options.onSuccess.call(vm, data)
85
+ if (successFunction) {
86
+ successFunction.call(vm, data)
83
87
  }
84
88
  } catch (error) {
85
- handleError(error)
89
+ handleError(error, errorFunction)
86
90
  }
87
91
  out.loading = false
88
92
  }
@@ -109,14 +113,14 @@ export function createResource(options, vm, getResource) {
109
113
  out.auto = options.auto
110
114
  }
111
115
 
112
- function handleError(error) {
116
+ function handleError(error, errorFunction) {
113
117
  console.error(error)
114
118
  if (out.previousData) {
115
119
  out.data = out.previousData
116
120
  }
117
121
  out.error = error
118
- if (options.onError) {
119
- options.onError.call(vm, error)
122
+ if (errorFunction) {
123
+ errorFunction.call(vm, error)
120
124
  }
121
125
  }
122
126
 
@@ -138,6 +142,8 @@ export function createResource(options, vm, getResource) {
138
142
  }
139
143
 
140
144
  export function createDocumentResource(options, vm) {
145
+ if (!(options.doctype && options.name)) return
146
+
141
147
  let cacheKey = getCacheKey([options.doctype, options.name])
142
148
  if (documentCache[cacheKey]) {
143
149
  return documentCache[cacheKey]
@@ -153,7 +159,7 @@ export function createDocumentResource(options, vm) {
153
159
  }
154
160
  },
155
161
  onSuccess(data) {
156
- out.doc = data
162
+ out.doc = postprocess(data)
157
163
  },
158
164
  }
159
165
 
@@ -170,7 +176,7 @@ export function createDocumentResource(options, vm) {
170
176
  }
171
177
  },
172
178
  onSuccess(data) {
173
- out.doc = data
179
+ out.doc = postprocess(data)
174
180
  },
175
181
  }),
176
182
  setValue: createResource(setValueOptions),
@@ -193,12 +199,47 @@ export function createDocumentResource(options, vm) {
193
199
  update,
194
200
  })
195
201
 
202
+ for (let method in options.whitelistedMethods) {
203
+ let methodName = options.whitelistedMethods[method]
204
+ out[method] = createResource({
205
+ method: 'run_doc_method',
206
+ makeParams(values) {
207
+ return {
208
+ dt: out.doctype,
209
+ dn: out.name,
210
+ method: methodName,
211
+ args: JSON.stringify(values),
212
+ }
213
+ },
214
+ onSuccess(data) {
215
+ if (data.docs) {
216
+ for (let doc of data.docs) {
217
+ if (doc.doctype === out.doctype && doc.name === out.name) {
218
+ out.doc = postprocess(doc)
219
+ break
220
+ }
221
+ }
222
+ }
223
+ },
224
+ })
225
+ }
226
+
196
227
  function update(updatedOptions) {
197
228
  out.doctype = updatedOptions.doctype
198
229
  out.name = updatedOptions.name
199
230
  out.get.fetch()
200
231
  }
201
232
 
233
+ function postprocess(doc) {
234
+ if (options.postprocess) {
235
+ let returnValue = options.postprocess(doc)
236
+ if (typeof returnValue === 'object') {
237
+ return returnValue
238
+ }
239
+ }
240
+ return doc
241
+ }
242
+
202
243
  // fetch the doc
203
244
  out.get.fetch()
204
245
  // cache
@@ -248,7 +289,7 @@ let createMixin = (mixinOptions) => ({
248
289
  } else {
249
290
  resource.update(updatedOptions)
250
291
  }
251
- if (resource.auto) {
292
+ if (resource && resource.auto) {
252
293
  resource.fetch()
253
294
  }
254
295
  },