@ditojs/admin 2.7.0 → 2.7.2

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.0",
3
+ "version": "2.7.2",
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,8 +33,8 @@
33
33
  "not ie_mob > 0"
34
34
  ],
35
35
  "dependencies": {
36
- "@ditojs/ui": "^2.7.0",
37
- "@ditojs/utils": "^2.7.0",
36
+ "@ditojs/ui": "^2.7.2",
37
+ "@ditojs/utils": "^2.7.1",
38
38
  "@kyvg/vue3-notification": "^2.9.0",
39
39
  "@lk77/vue3-color": "^3.0.6",
40
40
  "@tiptap/core": "^2.0.3",
@@ -83,7 +83,7 @@
83
83
  "vite": "^4.3.4"
84
84
  },
85
85
  "types": "types",
86
- "gitHead": "874c68d5807ba97b67867f6b8d13f8fcb4990533",
86
+ "gitHead": "1e84bcce13c988b1d388c128e6adf6ad9cb5517f",
87
87
  "scripts": {
88
88
  "build": "vite build",
89
89
  "watch": "yarn build --mode 'development' --watch",
package/src/DitoAdmin.js CHANGED
@@ -4,7 +4,7 @@ import VueNotifications from '@kyvg/vue3-notification'
4
4
  import {
5
5
  isString,
6
6
  isAbsoluteUrl,
7
- merge,
7
+ assignDeeply,
8
8
  hyphenate,
9
9
  camelize,
10
10
  defaultFormats,
@@ -31,12 +31,12 @@ export default class DitoAdmin {
31
31
  // Merge in `api` settings as passed from `config.admin` and through the
32
32
  // `AdminController` with `api` values from from 'admin/index.js'
33
33
  // NOTE: `AdminController` provides `dito.api.base`
34
- this.api = api = merge({ base: '/' }, dito.api, api)
34
+ this.api = api = assignDeeply({ base: '/' }, dito.api, api)
35
35
  this.options = options
36
36
 
37
37
  // Setup default api settings:
38
38
  api.locale ||= 'en-US'
39
- api.formats = merge({}, defaultFormats, api.formats)
39
+ api.formats = assignDeeply({}, defaultFormats, api.formats)
40
40
  api.request ||= options => request(api, options)
41
41
  api.getApiUrl ||= options => getApiUrl(api, options)
42
42
  api.isApiUrl ||= url => isApiUrl(api, url)
@@ -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
 
@@ -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;
@@ -48,7 +48,7 @@
48
48
  </template>
49
49
 
50
50
  <script>
51
- import { clone, capitalize, parseDataPath, merge } from '@ditojs/utils'
51
+ import { clone, capitalize, parseDataPath, assignDeeply } from '@ditojs/utils'
52
52
  import DitoComponent from '../DitoComponent.js'
53
53
  import RouteMixin from '../mixins/RouteMixin.js'
54
54
  import ResourceMixin from '../mixins/ResourceMixin.js'
@@ -99,7 +99,7 @@ export default DitoComponent.component('DitoForm', {
99
99
 
100
100
  buttonSchemas() {
101
101
  return getButtonSchemas(
102
- merge(
102
+ assignDeeply(
103
103
  {
104
104
  cancel: {
105
105
  type: 'button',
@@ -9,7 +9,7 @@ export default {
9
9
  })
10
10
  },
11
11
 
12
- processValue(schema, value) {
12
+ parseValue(schema, value) {
13
13
  return schema.trim && value != null ? value.trim() : value
14
14
  }
15
15
  }
@@ -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
  },
@@ -22,7 +22,7 @@
22
22
  import DitoTypeComponent from '../DitoTypeComponent.js'
23
23
  import { getSchemaAccessor } from '../utils/accessor.js'
24
24
  import { DatePicker, TimePicker, DateTimePicker } from '@ditojs/ui/src'
25
- import { isDate, merge } from '@ditojs/utils'
25
+ import { isDate, assignDeeply } from '@ditojs/utils'
26
26
 
27
27
  export default DitoTypeComponent.register(
28
28
  ['date', 'datetime', 'time'],
@@ -53,7 +53,7 @@ export default DitoTypeComponent.register(
53
53
  type: Object,
54
54
  default: null,
55
55
  get(formats) {
56
- const { date, time } = merge({}, this.api.formats, formats)
56
+ const { date, time } = assignDeeply({}, this.api.formats, formats)
57
57
  return {
58
58
  date: ['date', 'datetime'].includes(this.type) ? date : null,
59
59
  time: ['time', 'datetime'].includes(this.type) ? time : null
@@ -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,54 @@ $tag-line-height: 1em;
490
441
  border: $border-style;
491
442
  border-radius: $border-radius;
492
443
  }
444
+
445
+ &__content-wrapper {
446
+ border-color: $color-active;
447
+ }
448
+
449
+ &:not(&--above) #{$self}__content-wrapper {
450
+ margin: (-$border-width) 0 0;
451
+ border-top-color: $border-color;
452
+ border-top-left-radius: 0;
453
+ border-top-right-radius: 0;
454
+ }
455
+
456
+ &--above #{$self}__content-wrapper {
457
+ margin: 0 0 (-$border-width);
458
+ border-bottom-color: $border-color;
459
+ border-bottom-left-radius: 0;
460
+ border-bottom-right-radius: 0;
461
+ }
462
+
463
+ &--active {
464
+ #{$self}__placeholder {
465
+ // Don't use `display: none` to hide place-holder, as the layout would
466
+ // collapse.
467
+ display: inline-block;
468
+ visibility: hidden;
469
+ }
470
+
471
+ #{$self}__single,
472
+ #{$self}__input {
473
+ // Sadly, vue-select sets `style="width"` in addition to using classes
474
+ // so `!important` is necessary:
475
+ width: var(--input-width) !important;
476
+ }
477
+
478
+ #{$self}__tags {
479
+ border-color: $color-active;
480
+ border-bottom-left-radius: 0;
481
+ border-bottom-right-radius: 0;
482
+ }
483
+
484
+ &#{$self}--above {
485
+ #{$self}__tags {
486
+ border-radius: $border-radius;
487
+ border-top-left-radius: 0;
488
+ border-top-right-radius: 0;
489
+ }
490
+ }
491
+ }
493
492
  }
494
493
  }
495
494
  </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
94
  &::after {
91
- position: absolute;
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',
@@ -14,8 +14,8 @@ import {
14
14
  isModule,
15
15
  asArray,
16
16
  clone,
17
- merge,
18
17
  camelize,
18
+ assignDeeply,
19
19
  mapConcurrently,
20
20
  getValueAtDataPath
21
21
  } from '@ditojs/utils'
@@ -321,7 +321,7 @@ export function processSchemaDefaults(api, schema) {
321
321
  if (schema[key] === undefined) {
322
322
  schema[key] = value
323
323
  } else {
324
- schema[key] = merge(value, schema[key])
324
+ schema[key] = assignDeeply(value, schema[key])
325
325
  }
326
326
  }
327
327
  }
@@ -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
  }