@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,158 @@
1
+ import { isArray, isPlainObject } from '@ditojs/utils'
2
+
3
+ // @vue/component
4
+ export default {
5
+ data() {
6
+ return {
7
+ listeners: null
8
+ }
9
+ },
10
+
11
+ methods: {
12
+ // Async on() and $off() methods that keep track of the events added /
13
+ // removed, and provide a hasListeners() method that checks if the component
14
+ // has listeners for a given event.
15
+
16
+ // Also adds proper handling of async events, including a async emit() that
17
+ // deals with proper event queueing.
18
+ on(event, callback) {
19
+ if (isArray(event)) {
20
+ for (const ev of event) {
21
+ this.on(ev, callback)
22
+ }
23
+ } else if (isPlainObject(event)) {
24
+ for (const key in event) {
25
+ this.on(key, event[key])
26
+ }
27
+ } else {
28
+ const listeners = (this.listeners ||= Object.create(null))
29
+ const { callbacks } = (listeners[event] ||= {
30
+ callbacks: [],
31
+ queue: []
32
+ })
33
+ callbacks.push(callback)
34
+ }
35
+ return this
36
+ },
37
+
38
+ once(event, callback) {
39
+ const on = (...args) => {
40
+ this.off(event, on)
41
+ return callback.apply(this, args)
42
+ }
43
+ on.callback = callback // Needed for `off()`, see below.
44
+ return this.on(event, on)
45
+ },
46
+
47
+ off(event, callback) {
48
+ if (!arguments.length) {
49
+ // Remove all events
50
+ delete this.listeners
51
+ } else if (isArray(event)) {
52
+ for (const ev of event) {
53
+ this.off(ev, callback)
54
+ }
55
+ } else if (isPlainObject(event)) {
56
+ for (const key in event) {
57
+ this.off(key, event[key])
58
+ }
59
+ } else {
60
+ // Remove specific event
61
+ const entry = this.listeners?.[event]
62
+ if (entry) {
63
+ if (!callback) {
64
+ // Remove all handlers for this event
65
+ delete this.listeners[event]
66
+ } else {
67
+ // Remove a specific handler: find the index in callbacks
68
+ const { callbacks } = entry
69
+ const index = callbacks.findIndex(
70
+ // Match `cb.callback` also, as used by `once()`, see above:
71
+ cb => cb === callback || cb.callback === callback
72
+ )
73
+ if (index !== -1) {
74
+ callbacks.splice(index, 1)
75
+ }
76
+ }
77
+ }
78
+ }
79
+ return this
80
+ },
81
+
82
+ emit(event, ...args) {
83
+ // Only queue event if there actually are listeners for it.
84
+ const entry = this.listeners?.[event]
85
+ if (entry) {
86
+ const { queue, callbacks } = entry
87
+ return new Promise(resolve => {
88
+ const next = async () => {
89
+ // Emit the next event in the queue with its params.
90
+ // Note that it only gets removed once `next()` is called.
91
+ const entry = queue.shift()
92
+ if (entry) {
93
+ let result
94
+ const errors = []
95
+ for (const callback of callbacks) {
96
+ try {
97
+ const res = await callback.apply(this, entry.args)
98
+ if (res !== undefined) {
99
+ result = res
100
+ }
101
+ } catch (error) {
102
+ errors.push(error)
103
+ }
104
+ }
105
+ if (errors.length > 0) {
106
+ const error = new AggregateError(
107
+ errors,
108
+ `Errors during event handler for '${event}'`
109
+ )
110
+ entry.resolve(Promise.reject(error))
111
+ } else {
112
+ // Resolve the promise that was added to the queue for the event
113
+ // that was just completed by the wrapper that called `next()`
114
+ entry.resolve(result)
115
+ }
116
+ next()
117
+ }
118
+ }
119
+ queue.push({ args, resolve })
120
+ // For new queues (= only one entry) emit the first event immediately,
121
+ // to get the queue running.
122
+ if (queue.length === 1) {
123
+ next()
124
+ }
125
+ })
126
+ }
127
+ // Make sure it's thenable even if there are no listeners.
128
+ return Promise.resolve()
129
+ },
130
+
131
+ // Checks if the component has listeners for a given event type:
132
+ hasListeners(event) {
133
+ if (isArray(event)) {
134
+ for (const ev of event) {
135
+ if (!this.hasListeners(ev)) {
136
+ return false
137
+ }
138
+ }
139
+ return event.length > 0
140
+ } else {
141
+ return !!this.listeners?.[event]
142
+ }
143
+ },
144
+
145
+ delegate(event, target) {
146
+ if (target) {
147
+ if (isArray(event)) {
148
+ for (const ev of event) {
149
+ this.delegate(ev, target)
150
+ }
151
+ } else {
152
+ this.on(event, (...args) => target.emit(event, ...args))
153
+ }
154
+ }
155
+ return this
156
+ }
157
+ }
158
+ }
@@ -0,0 +1,144 @@
1
+ import DitoContext from '../DitoContext.js'
2
+ import {
3
+ getItemFormSchema,
4
+ getItemId,
5
+ getItemUid,
6
+ isListSource
7
+ } from '../utils/schema.js'
8
+ import { appendDataPath } from '../utils/data.js'
9
+ import { isObject, isString, isFunction } from '@ditojs/utils'
10
+
11
+ // @vue/component
12
+ export default {
13
+ methods: {
14
+ getItemFormSchema,
15
+
16
+ getItemUid,
17
+
18
+ getItemId(sourceSchema, item, index = null) {
19
+ return this.isTransient && index !== null
20
+ ? String(index)
21
+ : getItemId(sourceSchema, item)
22
+ },
23
+
24
+ getItemDataPath(sourceSchema, index) {
25
+ let { dataPath } = this
26
+ if (sourceSchema !== this.schema) {
27
+ dataPath = appendDataPath(dataPath, sourceSchema.name)
28
+ }
29
+ if (index != null) {
30
+ dataPath = appendDataPath(dataPath, index)
31
+ }
32
+ return dataPath
33
+ },
34
+
35
+ getItemStore(sourceSchema, item, index) {
36
+ return this.getChildStore(this.getItemUid(sourceSchema, item), index)
37
+ },
38
+
39
+ removeItemStore(sourceSchema, item, index) {
40
+ this.removeChildStore(this.getItemUid(sourceSchema, item), index)
41
+ },
42
+
43
+ findItemIdIndex(sourceSchema, data, itemId) {
44
+ const index = this.isTransient
45
+ ? // For transient data, the index is used as the id
46
+ itemId
47
+ : data?.findIndex(
48
+ (item, index) => (
49
+ this.getItemId(sourceSchema, item, index) === itemId
50
+ )
51
+ )
52
+ return index !== -1 ? index : null
53
+ },
54
+
55
+ getItemLabel(sourceSchema, item, {
56
+ index = null,
57
+ extended = false,
58
+ asObject = false
59
+ } = {}) {
60
+ const { itemLabel } = sourceSchema
61
+ if (!item || !extended && itemLabel === false) {
62
+ return null
63
+ }
64
+
65
+ let dataPath
66
+ const getDataPath = () =>
67
+ (dataPath ??= this.getItemDataPath(sourceSchema, index))
68
+
69
+ let formLabel
70
+ const getFormLabel = () =>
71
+ (formLabel ??= this.getLabel(
72
+ getItemFormSchema(sourceSchema, item, this.context)
73
+ ))
74
+
75
+ let text
76
+ let prefix
77
+ let suffix
78
+ if (isFunction(itemLabel)) {
79
+ const label = itemLabel.call(
80
+ this,
81
+ new DitoContext(this, {
82
+ nested: false,
83
+ data: item,
84
+ value: item,
85
+ index,
86
+
87
+ get dataPath() {
88
+ return getDataPath()
89
+ },
90
+
91
+ get formLabel() {
92
+ return getFormLabel()
93
+ }
94
+ })
95
+ )
96
+ if (isObject(label)) {
97
+ ;({ text, prefix, suffix } = label)
98
+ } else {
99
+ text = label
100
+ }
101
+ // It's up to `itemLabel()` entirely to produce the label:
102
+ extended = false
103
+ } else if (isString(itemLabel) && !(itemLabel in item)) {
104
+ // `itemLabel` can be both a key, or simply a label.
105
+ text = itemLabel
106
+ } else {
107
+ // Look up the name on the item, by these rules:
108
+ // 1. If `itemLabel` is a string, use it as the property key
109
+ // 2. Otherwise, if there are columns, use the value of the first
110
+ // 3. Otherwise, see if the item has a property named 'name'
111
+ const { columns } = sourceSchema
112
+ const key = (
113
+ isString(itemLabel) && itemLabel ||
114
+ isListSource(sourceSchema) && columns && Object.keys(columns)[0] ||
115
+ 'name'
116
+ )
117
+ text = item[key]
118
+ }
119
+ const hadLabel = !!text
120
+ // If no label was found so far, try to produce one from the index.
121
+ if (text == null) {
122
+ // Always use extended style when auto-generating labels from index/id:
123
+ extended = true
124
+ text =
125
+ isListSource(sourceSchema) && index !== null
126
+ ? (text = `${index + 1}`)
127
+ : ''
128
+ }
129
+ if (extended) {
130
+ const formLabel = getFormLabel()
131
+ if (formLabel) {
132
+ // If a label was provided, put in quotes when prefixed with the
133
+ // form label for the extended style:
134
+ text = `${formLabel} ${hadLabel ? `'${text}'` : text}`
135
+ }
136
+ }
137
+ return asObject
138
+ ? text || prefix || suffix
139
+ ? { text, prefix, suffix }
140
+ : null
141
+ : text
142
+ }
143
+ }
144
+ }
@@ -0,0 +1,23 @@
1
+ // @vue/component
2
+ export default {
3
+ data() {
4
+ return {
5
+ isLoading: false
6
+ }
7
+ },
8
+
9
+ methods: {
10
+ setLoading(isLoading, { updateRoot = false, updateView = false } = {}) {
11
+ if (!this.isLoading ^ !isLoading) {
12
+ // Boolean xor
13
+ this.isLoading = !!isLoading
14
+ if (updateRoot) {
15
+ this.rootComponent.registerLoading(isLoading)
16
+ }
17
+ if (updateView) {
18
+ this.viewComponent.setLoading(this.isLoading)
19
+ }
20
+ }
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,118 @@
1
+ import { getSchemaAccessor } from '../utils/accessor.js'
2
+ import { isArray } from '@ditojs/utils'
3
+
4
+ // @vue/component
5
+ export default {
6
+ computed: {
7
+ inputValue: {
8
+ get() {
9
+ return this.value !== null ? this.value : ''
10
+ },
11
+
12
+ set(value) {
13
+ this.value =
14
+ value !== ''
15
+ ? this.isInteger
16
+ ? Number(value)
17
+ : parseFloat(value)
18
+ : null
19
+ }
20
+ },
21
+
22
+ // @overridable
23
+ isInteger() {
24
+ return false
25
+ },
26
+
27
+ stepValue() {
28
+ // Don't show steps if the input is also clearable, since the step buttons
29
+ // would collide with the clear button.
30
+ return this.step == null && !this.isInteger
31
+ ? 'any'
32
+ : this.step
33
+ },
34
+
35
+ decimals: getSchemaAccessor('decimals', {
36
+ type: Number
37
+ }),
38
+
39
+ step: getSchemaAccessor('step', {
40
+ type: Number,
41
+ get(step) {
42
+ // For integers, round the steps to the next bigger integer value:
43
+ return this.isInteger && step != null ? Math.ceil(step) : step
44
+ }
45
+ }),
46
+
47
+ min: getSchemaAccessor('min', {
48
+ type: Number,
49
+ get(min) {
50
+ min =
51
+ min === undefined
52
+ ? this.getSchemaValue('range', { type: Array })?.[0]
53
+ : min
54
+ return this.isInteger && min != null ? Math.floor(min) : min
55
+ }
56
+ }),
57
+
58
+ max: getSchemaAccessor('max', {
59
+ type: Number,
60
+ get(max) {
61
+ max =
62
+ max === undefined
63
+ ? this.getSchemaValue('range', { type: Array })?.[1]
64
+ : max
65
+ return this.isInteger && max != null ? Math.ceil(max) : max
66
+ }
67
+ }),
68
+
69
+ range: getSchemaAccessor('range', {
70
+ type: Array,
71
+ get() {
72
+ // `this.min`, `this.max` already support `schema.range`,
73
+ // so redirect there.
74
+ const { min, max } = this
75
+ return min != null && max != null ? [min, max] : undefined
76
+ },
77
+
78
+ set(range) {
79
+ // Provide a setter that delegates to `[this.min, this.max]`,
80
+ // since those already handle `schema.range`.
81
+ if (isArray(range)) {
82
+ ;[this.min, this.max] = range
83
+ }
84
+ }
85
+ })
86
+ },
87
+
88
+ methods: {
89
+ getValidations() {
90
+ const validations = {}
91
+ const { range, min, max, decimals, step } = this
92
+ if (range) {
93
+ validations.range = range
94
+ } else {
95
+ if (min != null) {
96
+ validations.min = min
97
+ }
98
+ if (max != null) {
99
+ validations.max = max
100
+ }
101
+ }
102
+ if (decimals != null) {
103
+ validations.decimals = decimals
104
+ } else if (step) {
105
+ const decimals = (`${step}`.split('.')[1] || '').length
106
+ if (decimals > 0) {
107
+ validations.decimals = decimals
108
+ } else {
109
+ validations.integer = true
110
+ }
111
+ }
112
+ if (this.isInteger) {
113
+ validations.integer = true
114
+ }
115
+ return validations
116
+ }
117
+ }
118
+ }