@ditojs/admin 2.7.1 → 2.7.3

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": "@ditojs/admin",
3
- "version": "2.7.1",
3
+ "version": "2.7.3",
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",
@@ -33,7 +33,7 @@
33
33
  "not ie_mob > 0"
34
34
  ],
35
35
  "dependencies": {
36
- "@ditojs/ui": "^2.7.1",
36
+ "@ditojs/ui": "^2.7.3",
37
37
  "@ditojs/utils": "^2.7.1",
38
38
  "@kyvg/vue3-notification": "^2.9.0",
39
39
  "@lk77/vue3-color": "^3.0.6",
@@ -67,7 +67,7 @@
67
67
  "sortablejs": "^1.15.0",
68
68
  "tinycolor2": "^1.6.0",
69
69
  "tippy.js": "^6.3.7",
70
- "type-fest": "^3.9.0",
70
+ "type-fest": "^3.10.0",
71
71
  "vue": "^3.2.47",
72
72
  "vue-multiselect": "^3.0.0-beta.1",
73
73
  "vue-router": "^4.1.6",
@@ -80,10 +80,10 @@
80
80
  "pug": "^3.0.2",
81
81
  "sass": "1.62.1",
82
82
  "typescript": "^5.0.4",
83
- "vite": "^4.3.4"
83
+ "vite": "^4.3.5"
84
84
  },
85
85
  "types": "types",
86
- "gitHead": "3fe49034af7e93f2cc61da3f2add40c4e41893d5",
86
+ "gitHead": "13bec1eda290997bdc10d110652180cdc9d3653b",
87
87
  "scripts": {
88
88
  "build": "vite build",
89
89
  "watch": "yarn build --mode 'development' --watch",
@@ -1,8 +1,8 @@
1
1
  <template lang="pug">
2
2
  .dito-container(
3
3
  v-show="componentVisible"
4
- :class="containerClass"
5
- :style="containerStyle"
4
+ :class="containerClasses"
5
+ :style="containerStyles"
6
6
  )
7
7
  Teleport(
8
8
  v-if="isMounted && panelEntries.length > 0"
@@ -17,7 +17,7 @@
17
17
  )
18
18
  DitoLabel(
19
19
  v-if="hasLabel"
20
- :class="componentClass"
20
+ :class="layoutClasses"
21
21
  :label="label"
22
22
  :dataPath="labelDataPath"
23
23
  :info="info"
@@ -25,7 +25,7 @@
25
25
  component.dito-component(
26
26
  :is="typeComponent"
27
27
  ref="component"
28
- :class="componentClass"
28
+ :class="componentClasses"
29
29
  :schema="schema"
30
30
  :dataPath="dataPath"
31
31
  :data="data"
@@ -176,22 +176,20 @@ export default DitoComponent.component('DitoContainer', {
176
176
  : null
177
177
  },
178
178
 
179
- containerClass() {
180
- const { class: containerClass } = this.schema
179
+ containerClasses() {
180
+ const { class: classes } = this.schema
181
181
  const prefix = 'dito-container'
182
182
  return {
183
183
  [`${prefix}--single`]: this.single,
184
+ 'dito-disabled': this.componentDisabled,
185
+ 'dito-has-errors': !!this.errors,
184
186
  [`${prefix}--label-vertical`]: this.verticalLabels,
185
187
  [`${prefix}--omit-padding`]: omitPadding(this.schema),
186
- ...(
187
- isString(containerClass)
188
- ? { [containerClass]: true }
189
- : containerClass
190
- )
188
+ ...(isString(classes) ? { [classes]: true } : classes)
191
189
  }
192
190
  },
193
191
 
194
- containerStyle() {
192
+ containerStyles() {
195
193
  const { flexBasis, combinedBasis } = this
196
194
  return {
197
195
  '--grow': this.flexGrow ? 1 : 0,
@@ -204,15 +202,18 @@ export default DitoComponent.component('DitoContainer', {
204
202
  }
205
203
  },
206
204
 
207
- componentClass() {
205
+ componentClasses() {
208
206
  return {
209
- // TODO: BEM?
210
207
  'dito-single': this.single,
211
- 'dito-disabled': this.componentDisabled,
208
+ ...this.layoutClasses
209
+ }
210
+ },
211
+
212
+ layoutClasses() {
213
+ return {
212
214
  'dito-width-fill': this.width === 'fill' || this.flexBasis !== 'auto',
213
215
  'dito-width-grow': this.flexGrow,
214
- 'dito-width-shrink': this.flexShrink,
215
- 'dito-has-errors': !!this.errors
216
+ 'dito-width-shrink': this.flexShrink
216
217
  }
217
218
  },
218
219
 
@@ -172,7 +172,7 @@ export default DitoComponent.component('DitoDialog', {
172
172
  position: fixed;
173
173
  display: flex;
174
174
  inset: 0;
175
- z-index: 2000;
175
+ z-index: $z-index-dialog;
176
176
  padding: $content-padding;
177
177
  align-items: center;
178
178
  justify-content: center;
@@ -59,7 +59,7 @@ export default DitoComponent.component('DitoErrors', {
59
59
  interactive: true,
60
60
  hideOnClick: false,
61
61
  offset: [3, 3], // 1/2 form-spacing
62
- zIndex: 1
62
+ zIndex: ''
63
63
  })
64
64
  tip.popper.addEventListener('mousedown', () => tip.hide())
65
65
  tip.show()
@@ -74,7 +74,7 @@ export default DitoComponent.component('DitoErrors', {
74
74
 
75
75
  .dito-errors {
76
76
  position: absolute;
77
- opacity: 0;
77
+ visibility: hidden;
78
78
 
79
79
  ul {
80
80
  color: $color-error;
@@ -24,7 +24,7 @@
24
24
  :meta="meta"
25
25
  :store="store"
26
26
  :disabled="isLoading"
27
- scrollable
27
+ :scrollable="!isNestedRoute"
28
28
  headerInMenu
29
29
  generateLabels
30
30
  )
@@ -81,7 +81,7 @@ export default DitoComponent.component('DitoHeader', {
81
81
  background: $color-black;
82
82
  font-size: $header-font-size;
83
83
  line-height: $header-line-height;
84
- z-index: $header-z-index;
84
+ z-index: $z-index-header;
85
85
  @include user-select(none);
86
86
 
87
87
  &::after {
@@ -109,7 +109,7 @@ export default DitoComponent.component('DitoMenu', {
109
109
  display: block;
110
110
  position: absolute;
111
111
  width: var(--width);
112
- z-index: $header-z-index;
112
+ z-index: $z-index-header;
113
113
  transform: translateX(calc(var(--width) + 2 * $menu-spacing))
114
114
  translateY(-$item-height);
115
115
 
@@ -104,14 +104,14 @@ export default DitoComponent.component('DitoRoot', {
104
104
 
105
105
  tippyDelegate(this.$el, {
106
106
  target: '.dito-info',
107
+ theme: 'info',
108
+ appendTo: 'parent',
109
+ animation: 'shift-away-subtle',
110
+ interactive: true,
111
+ delay: 250,
112
+ zIndex: '',
107
113
  onCreate(instance) {
108
114
  instance.setContent(instance.reference.dataset.info)
109
- instance.setProps({
110
- theme: 'info',
111
- interactive: true,
112
- animation: 'shift-away-subtle',
113
- delay: 250
114
- })
115
115
  }
116
116
  })
117
117
 
@@ -506,7 +506,7 @@ function addRoutes(router, routes) {
506
506
  position: fixed;
507
507
  top: 0;
508
508
  left: 0;
509
- z-index: $drag-overlay-z-index;
509
+ z-index: $z-index-drag-overlay;
510
510
  width: 100%;
511
511
  height: 100%;
512
512
  background: rgba(0, 0, 0, 0.25);
@@ -519,7 +519,7 @@ function addRoutes(router, routes) {
519
519
 
520
520
  background: $content-color-background;
521
521
  border-radius: $border-radius;
522
- z-index: $drag-overlay-z-index + 1;
522
+ z-index: $z-index-drag-overlay + 1;
523
523
  filter: drop-shadow(0 4px 8px rgba(0, 0, 0, var(--shadow-alpha)));
524
524
  }
525
525
 
@@ -811,7 +811,7 @@ export default DitoComponent.component('DitoSchema', {
811
811
  top: 0;
812
812
  left: 0;
813
813
  right: 0;
814
- z-index: $header-z-index;
814
+ z-index: $z-index-header;
815
815
  // Turn off pointer events so that DitoTrail keeps receiving events...
816
816
  pointer-events: none;
817
817
  // ...but allow interaction with the tabs and buttons (e.g. clipboard)
@@ -1,3 +1,5 @@
1
+ import { isString } from '@ditojs/utils'
2
+ import { getDefaultValue } from '../utils/schema.js'
1
3
  import { getSchemaAccessor } from '../utils/accessor.js'
2
4
 
3
5
  // @vue/component
@@ -10,6 +12,14 @@ export default {
10
12
  },
11
13
 
12
14
  processValue(schema, value) {
13
- return schema.trim && value != null ? value.trim() : value
15
+ if (schema.trim && value != null && isString(value)) {
16
+ // Text fields don't necessarily have a `String` value when `format()`
17
+ // without `parse()` is used.
18
+ value = value.trim()
19
+ }
20
+ if (value === '') {
21
+ value = getDefaultValue(schema)
22
+ }
23
+ return value
14
24
  }
15
25
  }
@@ -48,26 +48,36 @@ export default {
48
48
 
49
49
  value: {
50
50
  get() {
51
- const value = computeValue(
51
+ let value = computeValue(
52
52
  this.schema,
53
53
  this.data,
54
54
  this.name,
55
55
  this.dataPath,
56
56
  { component: this }
57
57
  )
58
+ const { formatValue } = this.$options
59
+ if (formatValue) {
60
+ value = formatValue(this.schema, value, this.dataPath)
61
+ }
58
62
  const { format } = this.schema
59
- return format
60
- ? format(new DitoContext(this, { value }))
61
- : value
63
+ if (format) {
64
+ value = format(new DitoContext(this, { value }))
65
+ }
66
+ return value
62
67
  },
63
68
 
64
69
  set(value) {
70
+ const { parseValue } = this.$options
71
+ if (parseValue) {
72
+ value = parseValue(this.schema, value, this.dataPath)
73
+ }
65
74
  const { parse } = this.schema
66
- this.parsedValue = parse
67
- ? parse(new DitoContext(this, { value }))
68
- : value
75
+ if (parse) {
76
+ value = parse(new DitoContext(this, { value }))
77
+ }
69
78
  // eslint-disable-next-line vue/no-mutating-props
70
- this.data[this.name] = this.parsedValue
79
+ this.data[this.name] = value
80
+ this.parsedValue = value
71
81
  this.changedValue = undefined
72
82
  }
73
83
  },
@@ -131,17 +131,21 @@
131
131
  }
132
132
  }
133
133
 
134
- &.dito-buttons-main:not(:empty) {
135
- position: sticky;
136
- bottom: 0;
137
- width: 100%;
138
- align-self: flex-end;
139
- z-index: 500;
140
- margin-bottom: -$content-padding;
141
- margin-top: 2 * $content-padding;
142
- box-shadow: 0 (-$content-padding) $content-padding (-$content-padding)
143
- $color-shadow;
144
- background: $content-color-background;
134
+ &.dito-buttons-main {
135
+ border-top: $border-style;
136
+
137
+ .dito-scroll > &:not(:empty) {
138
+ position: sticky;
139
+ bottom: 0;
140
+ width: 100%;
141
+ align-self: flex-end;
142
+ z-index: $z-index-main-buttons;
143
+ margin-bottom: -$content-padding;
144
+ margin-top: 2 * $content-padding;
145
+ box-shadow: 0 (-$content-padding) $content-padding (-$content-padding)
146
+ $color-shadow;
147
+ background: $content-color-background;
148
+ }
145
149
  }
146
150
 
147
151
  &.dito-buttons-round,
@@ -192,7 +196,6 @@
192
196
 
193
197
  &.dito-button-clear {
194
198
  width: 2em;
195
- z-index: 1;
196
199
  background: $color-white;
197
200
  display: none;
198
201
 
@@ -4,7 +4,7 @@ ul.dito-pulldown {
4
4
  display: none;
5
5
  position: absolute;
6
6
  top: 0;
7
- z-index: 1000;
7
+ z-index: $z-index-popup;
8
8
  border-radius: $pulldown-radius;
9
9
  box-shadow: $shadow-window;
10
10
  overflow: hidden;
@@ -50,7 +50,6 @@ $form-spacing-half: calc($form-spacing / 2);
50
50
  // Header
51
51
  $header-font-size: 14px;
52
52
  $header-line-height: 1;
53
- $header-z-index: 1000;
54
53
  $header-padding-ver: $header-font-size;
55
54
  $header-padding-hor: $content-padding;
56
55
  $header-padding: $header-padding-ver $header-padding-hor;
@@ -70,8 +69,12 @@ $menu-padding-ver: $header-padding-ver - $menu-spacing;
70
69
  $menu-padding-hor: $header-padding-hor - $menu-spacing;
71
70
  $menu-padding: $menu-padding-ver $menu-padding-hor;
72
71
 
73
- // Drag & Drop
74
- $drag-overlay-z-index: 2000;
72
+ // Z-Indices
73
+ $z-index-dialog: 4000;
74
+ $z-index-drag-overlay: 3000;
75
+ $z-index-header: 2000;
76
+ $z-index-tippy: 750;
77
+ $z-index-main-buttons: 500;
75
78
 
76
79
  // Patterns
77
80
  $pattern-transparency-size: ($font-size - $border-width) * $input-height-factor;
@@ -3,6 +3,11 @@
3
3
  @import 'tippy.js/animations/shift-away-subtle.css';
4
4
 
5
5
  .tippy-box {
6
+ .tippy-content,
7
+ .tippy-arrow {
8
+ z-index: $z-index-tippy;
9
+ }
10
+
6
11
  &[data-theme] {
7
12
  --color: #{$color-active};
8
13
 
@@ -251,12 +251,6 @@ $tag-line-height: 1em;
251
251
  --input-width: auto;
252
252
  }
253
253
 
254
- &.dito-has-errors {
255
- &__tags {
256
- border-color: $color-error;
257
- }
258
- }
259
-
260
254
  .dito-edit-buttons {
261
255
  margin-left: $form-spacing-half;
262
256
  }
@@ -268,53 +262,6 @@ $tag-line-height: 1em;
268
262
  min-height: inherit;
269
263
  color: $color-black;
270
264
 
271
- &--active {
272
- #{$self}__placeholder {
273
- // Don't use `display: none` to hide place-holder, as the layout would
274
- // collapse.
275
- display: inline-block;
276
- visibility: hidden;
277
- }
278
-
279
- #{$self}__single,
280
- #{$self}__input {
281
- // Sadly, vue-select sets `style="width"` in addition to using classes
282
- // so `!important` is necessary:
283
- width: var(--input-width) !important;
284
- }
285
-
286
- #{$self}__tags {
287
- border-color: $color-active;
288
- border-bottom-left-radius: 0;
289
- border-bottom-right-radius: 0;
290
- }
291
-
292
- #{$self}__content-wrapper {
293
- border: $border-width solid $color-active;
294
- border-top-color: $border-color;
295
- margin: -1px 0 0;
296
- border-top-left-radius: 0;
297
- border-top-right-radius: 0;
298
- }
299
-
300
- &#{$self}--above {
301
- #{$self}__tags {
302
- border-radius: $border-radius;
303
- border-top-left-radius: 0;
304
- border-top-right-radius: 0;
305
- }
306
-
307
- #{$self}__content-wrapper {
308
- border: $border-width solid $color-active;
309
- border-bottom-color: $border-color;
310
- margin: 0 0 -1px;
311
- border-radius: $border-radius;
312
- border-bottom-left-radius: 0;
313
- border-bottom-right-radius: 0;
314
- }
315
- }
316
- }
317
-
318
265
  &__tags {
319
266
  display: flex;
320
267
  font-size: inherit;
@@ -323,6 +270,10 @@ $tag-line-height: 1em;
323
270
  padding: 0 $spinner-width 0 0;
324
271
  // So tags can float on multiple lines and have proper margins:
325
272
  padding-bottom: $tag-margin;
273
+
274
+ .dito-has-errors & {
275
+ border-color: $color-error;
276
+ }
326
277
  }
327
278
 
328
279
  &__tag {
@@ -412,7 +363,7 @@ $tag-line-height: 1em;
412
363
 
413
364
  min-height: unset;
414
365
  height: unset;
415
- line-height: $tag-line-height;
366
+ line-height: $line-height;
416
367
  padding: $input-padding;
417
368
 
418
369
  &::after {
@@ -451,7 +402,7 @@ $tag-line-height: 1em;
451
402
  color: $color-text;
452
403
  background: $color-highlight;
453
404
 
454
- &#{$option}--highlight {
405
+ @at-root #{$self}#{$self}--show-highlight &#{$option}--highlight {
455
406
  color: $color-text-inverted;
456
407
  }
457
408
  }
@@ -490,6 +441,55 @@ $tag-line-height: 1em;
490
441
  border: $border-style;
491
442
  border-radius: $border-radius;
492
443
  }
444
+
445
+ &__content-wrapper {
446
+ z-index: $z-index-popup;
447
+ border-color: $color-active;
448
+ }
449
+
450
+ &:not(&--above) #{$self}__content-wrapper {
451
+ margin: (-$border-width) 0 0;
452
+ border-top-color: $border-color;
453
+ border-top-left-radius: 0;
454
+ border-top-right-radius: 0;
455
+ }
456
+
457
+ &--above #{$self}__content-wrapper {
458
+ margin: 0 0 (-$border-width);
459
+ border-bottom-color: $border-color;
460
+ border-bottom-left-radius: 0;
461
+ border-bottom-right-radius: 0;
462
+ }
463
+
464
+ &--active {
465
+ #{$self}__placeholder {
466
+ // Don't use `display: none` to hide place-holder, as the layout would
467
+ // collapse.
468
+ display: inline-block;
469
+ visibility: hidden;
470
+ }
471
+
472
+ #{$self}__single,
473
+ #{$self}__input {
474
+ // Sadly, vue-select sets `style="width"` in addition to using classes
475
+ // so `!important` is necessary:
476
+ width: var(--input-width) !important;
477
+ }
478
+
479
+ #{$self}__tags {
480
+ border-color: $color-active;
481
+ border-bottom-left-radius: 0;
482
+ border-bottom-right-radius: 0;
483
+ }
484
+
485
+ &#{$self}--above {
486
+ #{$self}__tags {
487
+ border-radius: $border-radius;
488
+ border-top-left-radius: 0;
489
+ border-top-right-radius: 0;
490
+ }
491
+ }
492
+ }
493
493
  }
494
494
  }
495
495
  </style>
@@ -80,17 +80,21 @@ $select-arrow-right: calc(($select-arrow-width - $select-arrow-size) / 2);
80
80
  position: relative;
81
81
 
82
82
  select {
83
+ @extend %input;
84
+
83
85
  padding-right: $select-arrow-width;
84
86
  }
85
87
 
88
+ // `&___inner` is needed to make the edit buttons appear to the right of the
89
+ // select:
86
90
  &__inner {
87
91
  flex: 1;
88
92
  position: relative;
89
93
 
90
- &::after {
91
- position: absolute;
94
+ &::before {
92
95
  @include arrow($select-arrow-size);
93
96
 
97
+ position: absolute;
94
98
  bottom: $select-arrow-bottom;
95
99
  right: calc(#{$select-arrow-right} + #{$border-width});
96
100
  }
@@ -37,6 +37,8 @@ const ditoOptionKeys = [
37
37
  'excludeValue',
38
38
  'ignoreMissingValue',
39
39
  'omitPadding',
40
+ 'formatValue',
41
+ 'parseValue',
40
42
  'processValue',
41
43
  'processSchema',
42
44
  'getPanelSchema',
@@ -765,7 +765,14 @@ export function processData(schema, sourceSchema, data, dataPath, {
765
765
  value = value.map(object => object[wrapPrimitives])
766
766
  }
767
767
 
768
- // Handle the user's `process()` callback first, if one is provided, so that
768
+ // Each component type can provide its own static `processValue()` method
769
+ // to convert the data for storage.
770
+ const processValue = typeOptions?.processValue
771
+ if (processValue) {
772
+ value = processValue(schema, value, dataPath, graph)
773
+ }
774
+
775
+ // Handle the user's `process()` callback next, if one is provided, so that
769
776
  // it can modify data in `processedData` even if it provides `exclude: true`
770
777
  if (process) {
771
778
  value = process(getContext())
@@ -779,12 +786,6 @@ export function processData(schema, sourceSchema, data, dataPath, {
779
786
  ) {
780
787
  delete processedData[name]
781
788
  } else {
782
- // Each component type can provide its own static `processValue()` method
783
- // to convert the data for storage.
784
- const processValue = typeOptions?.processValue
785
- if (processValue) {
786
- value = processValue(schema, value, dataPath, graph)
787
- }
788
789
  processedData[name] = value
789
790
  }
790
791
  }