@ditojs/admin 2.2.10 → 2.2.12
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/dist/dito-admin.es.js +1461 -1365
- package/dist/dito-admin.umd.js +4 -4
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/DitoAdmin.js +2 -1
- package/src/DitoTypeComponent.js +1 -0
- package/src/components/DitoContainer.vue +32 -23
- package/src/components/DitoLabel.vue +1 -0
- package/src/components/DitoPane.vue +43 -1
- package/src/components/DitoPanel.vue +2 -2
- package/src/directives/resize.js +83 -0
- package/src/mixins/DitoMixin.js +1 -1
- package/src/types/DitoTypeCode.vue +1 -0
- package/src/types/DitoTypeComponent.vue +1 -0
- package/src/types/DitoTypeLabel.vue +2 -1
- package/src/types/DitoTypeList.vue +1 -0
- package/src/types/DitoTypeMarkup.vue +2 -0
- package/src/types/DitoTypeObject.vue +2 -0
- package/src/types/DitoTypePanel.vue +1 -0
- package/src/types/DitoTypeSection.vue +1 -0
- package/src/types/DitoTypeTextarea.vue +1 -0
- package/src/types/DitoTypeTreeList.vue +2 -0
- package/src/types/DitoTypeUpload.vue +2 -0
- package/src/utils/options.js +1 -0
- package/src/utils/schema.js +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/admin",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Dito.js Admin is a schema based admin interface for Dito.js Server, featuring auto-generated views and forms and built with Vue.js",
|
|
6
6
|
"repository": "https://github.com/ditojs/dito/tree/master/packages/admin",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"vite": "^4.3.1"
|
|
83
83
|
},
|
|
84
84
|
"types": "types",
|
|
85
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "062d8d229de60f7c81677b927c5c66ce9f2d2337",
|
|
86
86
|
"scripts": {
|
|
87
87
|
"build": "vite build",
|
|
88
88
|
"watch": "yarn build --mode 'development' --watch",
|
package/src/DitoAdmin.js
CHANGED
|
@@ -13,6 +13,7 @@ import * as components from './components/index.js'
|
|
|
13
13
|
import * as types from './types/index.js'
|
|
14
14
|
import DitoRoot from './components/DitoRoot.vue'
|
|
15
15
|
import DitoTypeComponent from './DitoTypeComponent.js'
|
|
16
|
+
import ResizeDirective from './directives/resize.js'
|
|
16
17
|
import { getResource } from './utils/resource.js'
|
|
17
18
|
import { deprecate } from './utils/deprecate.js'
|
|
18
19
|
import { formatQuery } from './utils/route.js'
|
|
@@ -198,7 +199,7 @@ export default class DitoAdmin {
|
|
|
198
199
|
componentName: 'VueNotifications'
|
|
199
200
|
})
|
|
200
201
|
|
|
201
|
-
|
|
202
|
+
app.directive('resize', ResizeDirective)
|
|
202
203
|
|
|
203
204
|
app.use(
|
|
204
205
|
createRouter({
|
package/src/DitoTypeComponent.js
CHANGED
|
@@ -31,7 +31,7 @@ import { isString, isNumber } from '@ditojs/utils'
|
|
|
31
31
|
import DitoComponent from '../DitoComponent.js'
|
|
32
32
|
import DitoContext from '../DitoContext.js'
|
|
33
33
|
import { getSchemaAccessor } from '../utils/accessor.js'
|
|
34
|
-
import { getTypeComponent, omitPadding } from '../utils/schema.js'
|
|
34
|
+
import { getTypeComponent, keepAligned, omitPadding } from '../utils/schema.js'
|
|
35
35
|
import { parseFraction } from '../utils/math.js'
|
|
36
36
|
|
|
37
37
|
// @vue/component
|
|
@@ -45,7 +45,9 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
45
45
|
single: { type: Boolean, default: false },
|
|
46
46
|
nested: { type: Boolean, default: true },
|
|
47
47
|
disabled: { type: Boolean, required: true },
|
|
48
|
-
generateLabels: { type: Boolean, default: false }
|
|
48
|
+
generateLabels: { type: Boolean, default: false },
|
|
49
|
+
firstInRow: { type: Boolean, default: false },
|
|
50
|
+
lastInRow: { type: Boolean, default: false }
|
|
49
51
|
},
|
|
50
52
|
|
|
51
53
|
data() {
|
|
@@ -68,25 +70,13 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
68
70
|
return (
|
|
69
71
|
label !== false && (
|
|
70
72
|
!!label ||
|
|
71
|
-
this.generateLabels &&
|
|
72
|
-
this.typeComponent?.generateLabel ||
|
|
73
|
-
// If the component has no label but isn't full width, render an
|
|
74
|
-
// empty label for alignment with other components:
|
|
75
|
-
!this.isFullWidth
|
|
76
|
-
)
|
|
73
|
+
this.generateLabels && this.typeComponent?.generateLabel
|
|
77
74
|
)
|
|
78
75
|
)
|
|
79
76
|
},
|
|
80
77
|
|
|
81
78
|
label() {
|
|
82
|
-
return this.hasLabel
|
|
83
|
-
? this.getLabel(
|
|
84
|
-
this.schema,
|
|
85
|
-
// Pass an empty string in case we need an empty label, see
|
|
86
|
-
// `hasLabel()`:
|
|
87
|
-
this.typeComponent?.generateLabel ? this.schema.name : ''
|
|
88
|
-
) || ''
|
|
89
|
-
: null
|
|
79
|
+
return this.hasLabel ? this.getLabel(this.schema) : null
|
|
90
80
|
},
|
|
91
81
|
|
|
92
82
|
labelDataPath() {
|
|
@@ -94,13 +84,6 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
94
84
|
return this.nested ? this.dataPath : null
|
|
95
85
|
},
|
|
96
86
|
|
|
97
|
-
isFullWidth() {
|
|
98
|
-
return (
|
|
99
|
-
!this.componentBasis.endsWith('%') ||
|
|
100
|
-
parseFloat(this.componentBasis) === 100
|
|
101
|
-
)
|
|
102
|
-
},
|
|
103
|
-
|
|
104
87
|
componentWidth: getSchemaAccessor('width', {
|
|
105
88
|
type: [String, Number],
|
|
106
89
|
default() {
|
|
@@ -146,7 +129,11 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
146
129
|
return {
|
|
147
130
|
[`${prefix}--single`]: this.single,
|
|
148
131
|
[`${prefix}--has-label`]: this.hasLabel,
|
|
132
|
+
[`${prefix}--aligned`]: keepAligned(this.schema),
|
|
149
133
|
[`${prefix}--omit-padding`]: omitPadding(this.schema),
|
|
134
|
+
[`${prefix}--first-in-row`]: this.firstInRow,
|
|
135
|
+
[`${prefix}--last-in-row`]: this.lastInRow,
|
|
136
|
+
[`${prefix}--alone-in-row`]: this.firstInRow && this.lastInRow,
|
|
150
137
|
...(
|
|
151
138
|
isString(containerClass)
|
|
152
139
|
? { [containerClass]: true }
|
|
@@ -205,6 +192,8 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
205
192
|
@import '../styles/_imports';
|
|
206
193
|
|
|
207
194
|
.dito-container {
|
|
195
|
+
$self: &;
|
|
196
|
+
|
|
208
197
|
display: flex;
|
|
209
198
|
flex-flow: column;
|
|
210
199
|
align-items: flex-start;
|
|
@@ -227,6 +216,26 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
227
216
|
padding: 0;
|
|
228
217
|
}
|
|
229
218
|
|
|
219
|
+
&--aligned {
|
|
220
|
+
// For components with labels, align the label at the top and the component
|
|
221
|
+
// at the bottom.
|
|
222
|
+
--justify: space-between;
|
|
223
|
+
|
|
224
|
+
&:has(> :only-child) {
|
|
225
|
+
// But if there is no label, still align the component to the bottom.
|
|
226
|
+
--justify: flex-end;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Now only apply alignment if there are neighbouring components no the same
|
|
230
|
+
// row that also align.
|
|
231
|
+
// Look ahead:
|
|
232
|
+
&:not(#{$self}--last-in-row) + #{&}:not(#{$self}--first-in-row),
|
|
233
|
+
// Look behind:
|
|
234
|
+
&:not(#{$self}--last-in-row):has(+ #{&}:not(#{$self}--first-in-row)) {
|
|
235
|
+
justify-content: var(--justify);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
230
239
|
&--omit-padding {
|
|
231
240
|
padding: 0;
|
|
232
241
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
nestedDataPath,
|
|
15
15
|
nested,
|
|
16
16
|
store
|
|
17
|
-
} in componentSchemas`
|
|
17
|
+
}, index in componentSchemas`
|
|
18
18
|
)
|
|
19
19
|
.dito-break(
|
|
20
20
|
v-if="schema.break === 'before'"
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
DitoContainer(
|
|
23
23
|
v-if="shouldRender(schema)"
|
|
24
24
|
:key="nestedDataPath"
|
|
25
|
+
v-resize="event => onResize(index, event)"
|
|
25
26
|
:schema="schema"
|
|
26
27
|
:dataPath="dataPath"
|
|
27
28
|
:data="data"
|
|
@@ -31,6 +32,8 @@
|
|
|
31
32
|
:nested="nested"
|
|
32
33
|
:disabled="disabled"
|
|
33
34
|
:generateLabels="generateLabels"
|
|
35
|
+
:firstInRow="schema.break === 'before' || isFirstInRow(index)"
|
|
36
|
+
:lastInRow="schema.break === 'after' || isLastInRow(index)"
|
|
34
37
|
)
|
|
35
38
|
.dito-break(
|
|
36
39
|
v-if="schema.break === 'after'"
|
|
@@ -63,6 +66,12 @@ export default DitoComponent.component('DitoPane', {
|
|
|
63
66
|
generateLabels: { type: Boolean, default: false }
|
|
64
67
|
},
|
|
65
68
|
|
|
69
|
+
data() {
|
|
70
|
+
return {
|
|
71
|
+
positions: []
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
|
|
66
75
|
computed: {
|
|
67
76
|
tabComponent() {
|
|
68
77
|
return this.tab ? this : this.$tabComponent()
|
|
@@ -135,9 +144,42 @@ export default DitoComponent.component('DitoPane', {
|
|
|
135
144
|
if (this.tab) {
|
|
136
145
|
this.$router.push({ hash: `#${this.tab}` })
|
|
137
146
|
}
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
onResize(index, { target }) {
|
|
150
|
+
const { y, width, height } = target.getBoundingClientRect()
|
|
151
|
+
this.positions[index] = width > 0 && height > 0 ? y : null
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
isFirstInRow(index) {
|
|
155
|
+
const { positions } = this
|
|
156
|
+
return (
|
|
157
|
+
positions[index] !== null && (
|
|
158
|
+
index === 0 ||
|
|
159
|
+
(findNextPosition(positions, index, -1, Infinity) < positions[index])
|
|
160
|
+
)
|
|
161
|
+
)
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
isLastInRow(index) {
|
|
165
|
+
const { positions } = this
|
|
166
|
+
return (
|
|
167
|
+
positions[index] !== null && (
|
|
168
|
+
index === positions.length - 1 ||
|
|
169
|
+
findNextPosition(positions, index, +1, 0) > positions[index]
|
|
170
|
+
)
|
|
171
|
+
)
|
|
138
172
|
}
|
|
139
173
|
}
|
|
140
174
|
})
|
|
175
|
+
|
|
176
|
+
function findNextPosition(positions, index, step, fallback) {
|
|
177
|
+
for (let i = index + step; i >= 0 && i < positions.length; i += step) {
|
|
178
|
+
const position = positions[i]
|
|
179
|
+
if (position) return position
|
|
180
|
+
}
|
|
181
|
+
return fallback
|
|
182
|
+
}
|
|
141
183
|
</script>
|
|
142
184
|
|
|
143
185
|
<style lang="scss">
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { asArray } from '@ditojs/utils'
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
mounted(node, binding) {
|
|
5
|
+
observeResize(node, binding.value, binding.arg)
|
|
6
|
+
},
|
|
7
|
+
|
|
8
|
+
unmounted(node, binding) {
|
|
9
|
+
unobserveResize(node, binding.value, binding.arg)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function observeResize(node, handler, options) {
|
|
14
|
+
Observer.getObserver(options).observe(node, handler)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function unobserveResize(node, handler, options) {
|
|
18
|
+
Observer.getObserver(options).unobserve(node, handler)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const isResizeSupported = typeof ResizeObserver !== 'undefined'
|
|
22
|
+
|
|
23
|
+
const observers = {}
|
|
24
|
+
|
|
25
|
+
class Observer {
|
|
26
|
+
constructor(key, options) {
|
|
27
|
+
this.key = key
|
|
28
|
+
this.options = options
|
|
29
|
+
this.observer = isResizeSupported
|
|
30
|
+
? new ResizeObserver(entries => this.handle(entries))
|
|
31
|
+
: null
|
|
32
|
+
this.handlersByNode = new WeakMap()
|
|
33
|
+
this.nodeCount = 0
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
observe(node, handler) {
|
|
37
|
+
let handlers = this.handlersByNode.get(node)
|
|
38
|
+
if (!handlers) {
|
|
39
|
+
handlers = new Set()
|
|
40
|
+
this.handlersByNode.set(node, handlers)
|
|
41
|
+
this.observer?.observe(node, this.options)
|
|
42
|
+
this.nodeCount++
|
|
43
|
+
}
|
|
44
|
+
handlers.add(handler)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
unobserve(node, handler) {
|
|
48
|
+
const handlers = this.handlersByNode.get(node)
|
|
49
|
+
if (handlers?.delete(handler) && handlers.size === 0) {
|
|
50
|
+
this.handlersByNode.delete(node)
|
|
51
|
+
this.observer?.unobserve(node)
|
|
52
|
+
if (--this.nodeCount === 0) {
|
|
53
|
+
delete observers[this.key]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
handle(entries) {
|
|
59
|
+
for (const entry of entries) {
|
|
60
|
+
const handlers = this.handlersByNode.get(entry.target)
|
|
61
|
+
if (handlers) {
|
|
62
|
+
const event = {
|
|
63
|
+
target: entry.target,
|
|
64
|
+
contentRect: entry.contentRect,
|
|
65
|
+
// Use `asArray` since Firefox before v92 returns these as objects:
|
|
66
|
+
borderBoxSize: asArray(entry.borderBoxSize),
|
|
67
|
+
contentBoxSize: asArray(entry.contentBoxSize),
|
|
68
|
+
devicePixelContentBoxSize: asArray(entry.devicePixelContentBoxSize)
|
|
69
|
+
}
|
|
70
|
+
for (const handler of handlers) {
|
|
71
|
+
handler(event)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static getObserver({ box = 'content-box' } = {}) {
|
|
78
|
+
const options = { box }
|
|
79
|
+
const key = JSON.stringify(options)
|
|
80
|
+
observers[key] ||= new Observer(key, options)
|
|
81
|
+
return observers[key]
|
|
82
|
+
}
|
|
83
|
+
}
|
package/src/mixins/DitoMixin.js
CHANGED
|
@@ -22,6 +22,7 @@ export default DitoTypeComponent.register('component', {
|
|
|
22
22
|
// Override the standard `defaultValue: null` to not set any data for custom
|
|
23
23
|
// components, unless they provide a default value.
|
|
24
24
|
defaultValue: () => undefined, // Callback to override `defaultValue: null`
|
|
25
|
+
keepAligned: false,
|
|
25
26
|
ignoreMissingValue: schema => !('default' in schema),
|
|
26
27
|
|
|
27
28
|
async processSchema(api, schema) {
|
|
@@ -167,6 +167,7 @@ import { pickBy, equals, hyphenate } from '@ditojs/utils'
|
|
|
167
167
|
// @vue/component
|
|
168
168
|
export default DitoTypeComponent.register('list', {
|
|
169
169
|
mixins: [SourceMixin, SortableMixin],
|
|
170
|
+
keepAligned: false,
|
|
170
171
|
|
|
171
172
|
getSourceType(type) {
|
|
172
173
|
// No need for transformation here. See TypeTreeList for details.
|
|
@@ -63,6 +63,8 @@ import { resolveSchemaComponent } from '../utils/schema.js'
|
|
|
63
63
|
export default DitoTypeComponent.register('object', {
|
|
64
64
|
mixins: [SourceMixin],
|
|
65
65
|
|
|
66
|
+
keepAligned: false,
|
|
67
|
+
|
|
66
68
|
getSourceType(type) {
|
|
67
69
|
// No need for transformation here. See TypeTreeList for details.
|
|
68
70
|
return type
|
package/src/utils/options.js
CHANGED
package/src/utils/schema.js
CHANGED
|
@@ -474,6 +474,10 @@ export function omitPadding(schema) {
|
|
|
474
474
|
return !!getTypeOptions(schema)?.omitPadding
|
|
475
475
|
}
|
|
476
476
|
|
|
477
|
+
export function keepAligned(schema) {
|
|
478
|
+
return !!getTypeOptions(schema)?.keepAligned
|
|
479
|
+
}
|
|
480
|
+
|
|
477
481
|
export function getDefaultValue(schema) {
|
|
478
482
|
// Support default values both on schema and on component level.
|
|
479
483
|
// NOTE: At the time of creation, components may not be instantiated, (e.g. if
|