@radio-garden/ditojs-admin 2.85.2-0.5067ad799

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 (153) hide show
  1. package/README.md +180 -0
  2. package/dist/dito-admin.css +1 -0
  3. package/dist/dito-admin.es.js +12106 -0
  4. package/dist/dito-admin.umd.js +7 -0
  5. package/package.json +96 -0
  6. package/src/DitoAdmin.js +293 -0
  7. package/src/DitoComponent.js +34 -0
  8. package/src/DitoContext.js +318 -0
  9. package/src/DitoTypeComponent.js +42 -0
  10. package/src/DitoUser.js +12 -0
  11. package/src/appState.js +12 -0
  12. package/src/components/DitoAccount.vue +60 -0
  13. package/src/components/DitoAffix.vue +68 -0
  14. package/src/components/DitoAffixes.vue +200 -0
  15. package/src/components/DitoButtons.vue +80 -0
  16. package/src/components/DitoClipboard.vue +186 -0
  17. package/src/components/DitoContainer.vue +374 -0
  18. package/src/components/DitoCreateButton.vue +146 -0
  19. package/src/components/DitoDialog.vue +242 -0
  20. package/src/components/DitoDraggable.vue +117 -0
  21. package/src/components/DitoEditButtons.vue +135 -0
  22. package/src/components/DitoErrors.vue +83 -0
  23. package/src/components/DitoForm.vue +521 -0
  24. package/src/components/DitoFormInner.vue +26 -0
  25. package/src/components/DitoFormNested.vue +17 -0
  26. package/src/components/DitoHeader.vue +84 -0
  27. package/src/components/DitoLabel.vue +200 -0
  28. package/src/components/DitoMenu.vue +186 -0
  29. package/src/components/DitoNavigation.vue +40 -0
  30. package/src/components/DitoNotifications.vue +170 -0
  31. package/src/components/DitoPagination.vue +42 -0
  32. package/src/components/DitoPane.vue +334 -0
  33. package/src/components/DitoPanel.vue +256 -0
  34. package/src/components/DitoPanels.vue +61 -0
  35. package/src/components/DitoRoot.vue +524 -0
  36. package/src/components/DitoSchema.vue +846 -0
  37. package/src/components/DitoSchemaInlined.vue +97 -0
  38. package/src/components/DitoScopes.vue +76 -0
  39. package/src/components/DitoSidebar.vue +50 -0
  40. package/src/components/DitoSpinner.vue +95 -0
  41. package/src/components/DitoTableCell.vue +64 -0
  42. package/src/components/DitoTableHead.vue +121 -0
  43. package/src/components/DitoTabs.vue +103 -0
  44. package/src/components/DitoTrail.vue +124 -0
  45. package/src/components/DitoTreeItem.vue +420 -0
  46. package/src/components/DitoUploadFile.vue +199 -0
  47. package/src/components/DitoVNode.vue +14 -0
  48. package/src/components/DitoView.vue +143 -0
  49. package/src/components/index.js +42 -0
  50. package/src/directives/resize.js +83 -0
  51. package/src/index.js +1 -0
  52. package/src/mixins/ContextMixin.js +68 -0
  53. package/src/mixins/DataMixin.js +131 -0
  54. package/src/mixins/DitoMixin.js +591 -0
  55. package/src/mixins/DomMixin.js +29 -0
  56. package/src/mixins/EmitterMixin.js +158 -0
  57. package/src/mixins/ItemMixin.js +144 -0
  58. package/src/mixins/LoadingMixin.js +23 -0
  59. package/src/mixins/NumberMixin.js +118 -0
  60. package/src/mixins/OptionsMixin.js +304 -0
  61. package/src/mixins/PulldownMixin.js +63 -0
  62. package/src/mixins/ResourceMixin.js +398 -0
  63. package/src/mixins/RouteMixin.js +190 -0
  64. package/src/mixins/SchemaParentMixin.js +33 -0
  65. package/src/mixins/SortableMixin.js +49 -0
  66. package/src/mixins/SourceMixin.js +734 -0
  67. package/src/mixins/TextMixin.js +26 -0
  68. package/src/mixins/TypeMixin.js +280 -0
  69. package/src/mixins/ValidationMixin.js +119 -0
  70. package/src/mixins/ValidatorMixin.js +57 -0
  71. package/src/mixins/ValueMixin.js +31 -0
  72. package/src/styles/_base.scss +17 -0
  73. package/src/styles/_button.scss +191 -0
  74. package/src/styles/_imports.scss +3 -0
  75. package/src/styles/_info.scss +19 -0
  76. package/src/styles/_layout.scss +19 -0
  77. package/src/styles/_pulldown.scss +38 -0
  78. package/src/styles/_scroll.scss +13 -0
  79. package/src/styles/_settings.scss +88 -0
  80. package/src/styles/_table.scss +223 -0
  81. package/src/styles/_tippy.scss +45 -0
  82. package/src/styles/style.scss +9 -0
  83. package/src/types/DitoTypeButton.vue +143 -0
  84. package/src/types/DitoTypeCheckbox.vue +27 -0
  85. package/src/types/DitoTypeCheckboxes.vue +65 -0
  86. package/src/types/DitoTypeCode.vue +199 -0
  87. package/src/types/DitoTypeColor.vue +272 -0
  88. package/src/types/DitoTypeComponent.vue +31 -0
  89. package/src/types/DitoTypeComputed.vue +50 -0
  90. package/src/types/DitoTypeDate.vue +99 -0
  91. package/src/types/DitoTypeLabel.vue +23 -0
  92. package/src/types/DitoTypeList.vue +364 -0
  93. package/src/types/DitoTypeMarkup.vue +700 -0
  94. package/src/types/DitoTypeMultiselect.vue +522 -0
  95. package/src/types/DitoTypeNumber.vue +66 -0
  96. package/src/types/DitoTypeObject.vue +136 -0
  97. package/src/types/DitoTypePanel.vue +18 -0
  98. package/src/types/DitoTypeProgress.vue +40 -0
  99. package/src/types/DitoTypeRadio.vue +45 -0
  100. package/src/types/DitoTypeSection.vue +80 -0
  101. package/src/types/DitoTypeSelect.vue +133 -0
  102. package/src/types/DitoTypeSlider.vue +66 -0
  103. package/src/types/DitoTypeSpacer.vue +11 -0
  104. package/src/types/DitoTypeSwitch.vue +40 -0
  105. package/src/types/DitoTypeText.vue +101 -0
  106. package/src/types/DitoTypeTextarea.vue +48 -0
  107. package/src/types/DitoTypeTreeList.vue +193 -0
  108. package/src/types/DitoTypeUpload.vue +503 -0
  109. package/src/types/index.js +30 -0
  110. package/src/utils/SchemaGraph.js +147 -0
  111. package/src/utils/accessor.js +75 -0
  112. package/src/utils/agent.js +47 -0
  113. package/src/utils/data.js +92 -0
  114. package/src/utils/filter.js +266 -0
  115. package/src/utils/math.js +14 -0
  116. package/src/utils/options.js +48 -0
  117. package/src/utils/path.js +5 -0
  118. package/src/utils/resource.js +44 -0
  119. package/src/utils/route.js +53 -0
  120. package/src/utils/schema.js +1121 -0
  121. package/src/utils/type.js +81 -0
  122. package/src/utils/uid.js +15 -0
  123. package/src/utils/units.js +5 -0
  124. package/src/validators/_creditcard.js +6 -0
  125. package/src/validators/_decimals.js +11 -0
  126. package/src/validators/_domain.js +6 -0
  127. package/src/validators/_email.js +6 -0
  128. package/src/validators/_hostname.js +6 -0
  129. package/src/validators/_integer.js +6 -0
  130. package/src/validators/_max.js +6 -0
  131. package/src/validators/_min.js +6 -0
  132. package/src/validators/_password.js +5 -0
  133. package/src/validators/_range.js +6 -0
  134. package/src/validators/_required.js +9 -0
  135. package/src/validators/_url.js +6 -0
  136. package/src/validators/index.js +12 -0
  137. package/src/verbs.js +17 -0
  138. package/types/index.d.ts +3298 -0
  139. package/types/tests/admin.test-d.ts +27 -0
  140. package/types/tests/component-buttons.test-d.ts +44 -0
  141. package/types/tests/component-list.test-d.ts +159 -0
  142. package/types/tests/component-misc.test-d.ts +137 -0
  143. package/types/tests/component-object.test-d.ts +69 -0
  144. package/types/tests/component-section.test-d.ts +174 -0
  145. package/types/tests/component-select.test-d.ts +107 -0
  146. package/types/tests/components.test-d.ts +81 -0
  147. package/types/tests/context.test-d.ts +31 -0
  148. package/types/tests/fixtures.ts +24 -0
  149. package/types/tests/form.test-d.ts +109 -0
  150. package/types/tests/instance.test-d.ts +20 -0
  151. package/types/tests/schema-features.test-d.ts +402 -0
  152. package/types/tests/variance.test-d.ts +125 -0
  153. package/types/tests/view.test-d.ts +146 -0
@@ -0,0 +1,304 @@
1
+ import DitoContext from '../DitoContext.js'
2
+ import DataMixin from './DataMixin.js'
3
+ import {
4
+ hasViewSchema,
5
+ getViewEditPath,
6
+ getMultipleValue
7
+ } from '../utils/schema.js'
8
+ import { getSchemaAccessor } from '../utils/accessor.js'
9
+ import { setTemporaryId, isReference } from '../utils/data.js'
10
+ import {
11
+ isObject,
12
+ isArray,
13
+ isString,
14
+ isFunction,
15
+ normalizeDataPath,
16
+ labelize,
17
+ debounceAsync
18
+ } from '@ditojs/utils'
19
+
20
+ // @vue/component
21
+ export default {
22
+ mixins: [DataMixin],
23
+
24
+ computed: {
25
+ // @overridable
26
+ multiple() {
27
+ return getMultipleValue(this.schema)
28
+ },
29
+
30
+ selectedValue: {
31
+ get() {
32
+ const convertValue = value => {
33
+ const val = this.relate
34
+ ? this.getValueForOption(value)
35
+ : value
36
+
37
+ return this.hasOptions
38
+ ? this.getOptionForValue(val)
39
+ ? val
40
+ : null
41
+ : value
42
+ }
43
+
44
+ const value =
45
+ this.multiple && isArray(this.value)
46
+ ? this.value.map(convertValue).filter(value => value !== null)
47
+ : convertValue(this.value)
48
+
49
+ if (
50
+ // As soon as the options are available, and...
51
+ this.hasOptions && (
52
+ // ...if the value is forced to null because a disappeared option...
53
+ value === null && this.value !== null ||
54
+ // ...or if the value is a reference, replace it with its option
55
+ // value, so that it'll hold actual data, not just a reference id.
56
+ isReference(this.value)
57
+ )
58
+ ) {
59
+ // TODO: Fix side-effects
60
+ // eslint-disable-next-line vue/no-side-effects-in-computed-properties
61
+ this.selectedValue = value
62
+ }
63
+ return value
64
+ },
65
+
66
+ set(value) {
67
+ const convertValue = value =>
68
+ this.relate
69
+ ? this.getOptionForValue(value)
70
+ : value
71
+
72
+ this.value =
73
+ this.multiple && isArray(value)
74
+ ? value.map(convertValue)
75
+ : convertValue(value)
76
+ }
77
+ },
78
+
79
+ selectedOption() {
80
+ return this.getOptionForValue(this.selectedValue)
81
+ },
82
+
83
+ options() {
84
+ const data = this.handleDataSchema(this.schema.options, 'options') ?? []
85
+ if (!isArray(data)) {
86
+ throw new Error(`Invalid options data, should be array: ${data}`)
87
+ }
88
+ return this.processOptions(data)
89
+ },
90
+
91
+ activeOptions() {
92
+ // This is overridden in `TypeMultiselect` to return the `searchedOptions`
93
+ // when a search filter was applied.
94
+ return this.options
95
+ },
96
+
97
+ hasOptions() {
98
+ return this.activeOptions.length > 0
99
+ },
100
+
101
+ relate: getSchemaAccessor('relate', {
102
+ // TODO: Convert to `relateBy: 'id'`
103
+ type: Boolean,
104
+ default: false,
105
+ // We cannot use schema accessor callback magic for `relate` as we need
106
+ // this outside of the component's life-span, see `processData()` below.
107
+ callback: false
108
+ }),
109
+
110
+ groupBy: getSchemaAccessor('groupBy', {
111
+ type: String,
112
+ default: null
113
+ }),
114
+
115
+ // TODO: Rename to `options.labelKey` / `optionLabelKey`?
116
+ optionLabel: getSchemaAccessor('options.label', {
117
+ type: [String, Function],
118
+ default: null,
119
+ get(label) {
120
+ // If no `label` was provided but the options are objects, assume a
121
+ // default value of 'label':
122
+ return (
123
+ label ||
124
+ this.getOptionKey('label') ||
125
+ null
126
+ )
127
+ }
128
+ }),
129
+
130
+ // TODO: Rename to `options.valueKey` / `optionValueKey`?
131
+ optionValue: getSchemaAccessor('options.value', {
132
+ type: [String, Function],
133
+ default: null,
134
+ get(value) {
135
+ // If no `label` was provided but the options are objects, assume a
136
+ // default value of 'value':
137
+ return (
138
+ value ||
139
+ this.relate && 'id' ||
140
+ this.getOptionKey('value') ||
141
+ null
142
+ )
143
+ }
144
+ }),
145
+
146
+ optionEquals: getSchemaAccessor('options.equals', {
147
+ type: Function,
148
+ default: null
149
+ }),
150
+
151
+ // TODO: Consider moving search to `options.search`?
152
+ searchFilter: getSchemaAccessor('search', {
153
+ type: [Object, Function],
154
+ default: null,
155
+ get(search) {
156
+ if (search) {
157
+ const { filter, debounce } = isFunction(search)
158
+ ? { filter: search }
159
+ : search
160
+ return debounce ? debounceAsync(filter, debounce) : filter
161
+ }
162
+ }
163
+ }),
164
+
165
+ editable: getSchemaAccessor('editable', {
166
+ type: Boolean,
167
+ default: false,
168
+ get(editable) {
169
+ return (
170
+ editable &&
171
+ hasViewSchema(this.schema, this.context)
172
+ )
173
+ }
174
+ }),
175
+
176
+ editPath() {
177
+ return this.editable && this.selectedValue
178
+ ? getViewEditPath(this.schema, this.selectedValue, this.context)
179
+ : null
180
+ },
181
+
182
+ groupByLabel() {
183
+ return this.groupBy ? 'label' : null
184
+ },
185
+
186
+ groupByOptions() {
187
+ return this.groupBy ? 'options' : null
188
+ }
189
+ },
190
+
191
+ methods: {
192
+ getOptionKey(key) {
193
+ const [option] = this.activeOptions
194
+ return isObject(option) && key in option ? key : null
195
+ },
196
+
197
+ processOptions(options) {
198
+ if (options.length) {
199
+ if (this.relate) {
200
+ // If ids are missing and we want to relate, set temporary ids.
201
+ // NOTE: We need to modify the actual data, making a copy won't work
202
+ // as it won't propagate.
203
+ // NOTE: This only makes sense if the data is from the graph that
204
+ // we're currently editing.
205
+ for (const option of options) {
206
+ if (!('id' in option)) {
207
+ // TODO: Fix side-effects
208
+ setTemporaryId(option, 'id')
209
+ }
210
+ }
211
+ }
212
+ if (this.groupBy) {
213
+ const grouped = {}
214
+ options = options.reduce(
215
+ (results, option) => {
216
+ const group = option[this.groupBy]
217
+ let entry = grouped[group]
218
+ if (!entry) {
219
+ entry = grouped[group] = {
220
+ [this.groupByLabel]: group,
221
+ [this.groupByOptions]: []
222
+ }
223
+ results.push(entry)
224
+ }
225
+ entry[this.groupByOptions].push(option)
226
+ return results
227
+ },
228
+ []
229
+ )
230
+ }
231
+ }
232
+ return options
233
+ },
234
+
235
+ getOptionForValue(value) {
236
+ const findOption = (options, value, groupBy) => {
237
+ // Search for the option object with the given value and return the
238
+ // whole object.
239
+ for (const option of options) {
240
+ if (groupBy) {
241
+ const found = findOption(option.options, value, null)
242
+ if (found) {
243
+ return found
244
+ }
245
+ } else {
246
+ const matches = this.optionEquals
247
+ ? this.optionEquals(new DitoContext(this, { value, option }))
248
+ : value === this.getValueForOption(option)
249
+ if (matches) {
250
+ return option
251
+ }
252
+ }
253
+ }
254
+ }
255
+
256
+ return this.optionValue
257
+ ? findOption(this.activeOptions, value, this.groupBy)
258
+ : value
259
+ },
260
+
261
+ getValueForOption(option) {
262
+ const { optionValue } = this
263
+ return isString(optionValue)
264
+ ? option?.[optionValue] ?? null
265
+ : isFunction(optionValue)
266
+ ? optionValue(new DitoContext(this, { option }))
267
+ : option
268
+ },
269
+
270
+ getLabelForOption(option) {
271
+ const { optionLabel } = this
272
+ return isString(optionLabel)
273
+ ? option?.[optionLabel]
274
+ : isFunction(optionLabel)
275
+ ? optionLabel(new DitoContext(this, { option }))
276
+ : labelize(`${option}`)
277
+ }
278
+ },
279
+
280
+ processValue({ schema, value, dataPath }, graph) {
281
+ if (schema.relate) {
282
+ // For internally relating data (`schema.options.dataPath`), we need to
283
+ // process both the options (for '#ref') and the value ('#id').
284
+ // See `DataMixin.handleDataSchema()`:
285
+ const path = schema.options?.dataPath
286
+ const relatedDataPath = path
287
+ ? normalizeDataPath(`${dataPath}/${path}`)
288
+ : null
289
+ graph.addRelation(dataPath, relatedDataPath, schema)
290
+ if (relatedDataPath) {
291
+ graph.setSourceRelated(relatedDataPath)
292
+ }
293
+ // Convert relating objects to a shallow copy with only the id left.
294
+ // TODO: Convert to using `relateBy`:
295
+ const processRelate = value => (value ? { id: value.id } : value)
296
+ // Selected options can be both objects & arrays, e.g. 'checkboxes':
297
+ value =
298
+ getMultipleValue(schema) && isArray(value)
299
+ ? value.map(processRelate)
300
+ : processRelate(value)
301
+ }
302
+ return value
303
+ }
304
+ }
@@ -0,0 +1,63 @@
1
+ import DomMixin from './DomMixin.js'
2
+
3
+ // @vue/component
4
+ export default {
5
+ mixins: [DomMixin],
6
+
7
+ data() {
8
+ return {
9
+ pulldown: {
10
+ open: false,
11
+ startTime: 0,
12
+ checkTime: true,
13
+ events: {
14
+ mousedown: () => {
15
+ this.setPulldownOpen(false)
16
+ this.pulldown.handlers.remove()
17
+ },
18
+
19
+ mouseup: () => {
20
+ if (this.onPulldownMouseUp()) {
21
+ this.pulldown.handlers.remove()
22
+ }
23
+ }
24
+ },
25
+ handlers: null
26
+ }
27
+ }
28
+ },
29
+
30
+ methods: {
31
+ onPulldownMouseDown(value = null) {
32
+ if (value === null) {
33
+ this.setPulldownOpen(true)
34
+ this.checkTime = true
35
+ } else {
36
+ this.checkTime = false
37
+ }
38
+ },
39
+
40
+ onPulldownMouseUp(value = null) {
41
+ const { startTime } = this.pulldown
42
+ if (!this.checkTime || startTime && (Date.now() - startTime > 250)) {
43
+ this.setPulldownOpen(false)
44
+ if (value !== null) {
45
+ this.onPulldownSelect(value)
46
+ }
47
+ return true
48
+ }
49
+ },
50
+
51
+ onPulldownSelect(/* value */) {
52
+ // NOTE: To be overridden.
53
+ },
54
+
55
+ setPulldownOpen(open) {
56
+ this.pulldown.open = open
57
+ this.pulldown.startTime = open ? Date.now() : 0
58
+ if (open) {
59
+ this.pulldown.handlers = this.domOn(document, this.pulldown.events)
60
+ }
61
+ }
62
+ }
63
+ }