@ditojs/admin 2.5.2 → 2.6.1

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 (42) hide show
  1. package/dist/dito-admin.es.js +1337 -1304
  2. package/dist/dito-admin.umd.js +6 -6
  3. package/dist/style.css +1 -1
  4. package/package.json +4 -4
  5. package/src/DitoContext.js +4 -0
  6. package/src/DitoTypeComponent.js +0 -1
  7. package/src/components/DitoAccount.vue +1 -0
  8. package/src/components/DitoContainer.vue +16 -38
  9. package/src/components/DitoDialog.vue +3 -1
  10. package/src/components/DitoHeader.vue +11 -14
  11. package/src/components/DitoLabel.vue +7 -3
  12. package/src/components/DitoNavigation.vue +40 -0
  13. package/src/components/DitoPane.vue +78 -40
  14. package/src/components/DitoPanel.vue +0 -2
  15. package/src/components/DitoPanels.vue +4 -2
  16. package/src/components/DitoRoot.vue +39 -13
  17. package/src/components/DitoSchema.vue +23 -17
  18. package/src/components/DitoSchemaInlined.vue +1 -3
  19. package/src/components/DitoSidebar.vue +6 -24
  20. package/src/components/DitoView.vue +1 -0
  21. package/src/components/index.js +2 -1
  22. package/src/mixins/DitoMixin.js +9 -1
  23. package/src/mixins/TextMixin.js +1 -1
  24. package/src/styles/_layout.scss +11 -14
  25. package/src/styles/_scroll.scss +1 -2
  26. package/src/styles/_settings.scss +5 -1
  27. package/src/styles/_tippy.scss +1 -0
  28. package/src/types/DitoTypeButton.vue +8 -17
  29. package/src/types/DitoTypeCode.vue +0 -1
  30. package/src/types/DitoTypeComponent.vue +0 -1
  31. package/src/types/DitoTypeLabel.vue +1 -2
  32. package/src/types/DitoTypeList.vue +5 -6
  33. package/src/types/DitoTypeMarkup.vue +14 -16
  34. package/src/types/DitoTypeMultiselect.vue +2 -0
  35. package/src/types/DitoTypeObject.vue +5 -7
  36. package/src/types/DitoTypePanel.vue +0 -1
  37. package/src/types/DitoTypeSection.vue +0 -1
  38. package/src/types/DitoTypeTextarea.vue +0 -1
  39. package/src/types/DitoTypeTreeList.vue +0 -2
  40. package/src/types/DitoTypeUpload.vue +0 -2
  41. package/src/utils/options.js +0 -1
  42. package/src/utils/schema.js +29 -7
@@ -82,11 +82,9 @@ export default DitoComponent.component('DitoSchemaInlined', {
82
82
  margin: 0;
83
83
  width: 100%;
84
84
  box-sizing: content-box;
85
- // Because tables have a funny way of allowing too much width growth:
86
- max-width: $content-width;
87
85
  // Prevent collapsing to min-height when alone in
88
86
  // .dito-schema-content, due to grid-template-rows: min-content
89
- min-height: 2em;
87
+ min-height: $input-height;
90
88
  }
91
89
  }
92
90
 
@@ -1,8 +1,7 @@
1
1
  <template lang="pug">
2
- nav.dito-sidebar.dito-scroll-parent
3
- h1
4
- RouterLink.dito-link(to="/") {{ appState.title }}
5
- DitoMenu.dito-scroll(:items="views")
2
+ aside.dito-sidebar.dito-scroll-parent
3
+ nav.dito-header
4
+ slot
6
5
  </template>
7
6
 
8
7
  <script>
@@ -16,25 +15,8 @@ export default DitoComponent.component('DitoSidebar', {})
16
15
  @import '../styles/_imports';
17
16
 
18
17
  .dito-sidebar {
19
- @include user-select(none);
20
-
21
- flex: initial;
22
- font-size: $menu-font-size;
23
- white-space: nowrap;
24
- background: $color-lighter;
25
-
26
- h1 {
27
- display: block;
28
- line-height: $header-line-height;
29
- font-weight: bold;
30
- background: $color-darker;
31
- border-right: $border-width solid $color-darkest;
32
- color: $color-white;
33
-
34
- .dito-link {
35
- display: block;
36
- padding: $header-padding;
37
- }
38
- }
18
+ flex: 0 4 $sidebar-max-width;
19
+ max-width: $sidebar-max-width;
20
+ min-width: $sidebar-min-width;
39
21
  }
40
22
  </style>
@@ -15,6 +15,7 @@ template(
15
15
  :data-resource="sourceSchema.path"
16
16
  )
17
17
  DitoSchema(
18
+ :key="name"
18
19
  :schema="viewSchema"
19
20
  :data="data"
20
21
  :meta="meta"
@@ -5,8 +5,9 @@
5
5
 
6
6
  export { default as DitoRoot } from './DitoRoot.vue'
7
7
  export { default as DitoMenu } from './DitoMenu.vue'
8
- export { default as DitoSidebar } from './DitoSidebar.vue'
9
8
  export { default as DitoHeader } from './DitoHeader.vue'
9
+ export { default as DitoNavigation } from './DitoNavigation.vue'
10
+ export { default as DitoSidebar } from './DitoSidebar.vue'
10
11
  export { default as DitoAccount } from './DitoAccount.vue'
11
12
  export { default as DitoDialog } from './DitoDialog.vue'
12
13
  export { default as DitoElement } from './DitoElement.vue'
@@ -10,7 +10,11 @@ import {
10
10
  import appState from '../appState.js'
11
11
  import DitoContext from '../DitoContext.js'
12
12
  import EmitterMixin from './EmitterMixin.js'
13
- import { getSchemaValue, shouldRenderSchema } from '../utils/schema.js'
13
+ import {
14
+ flattenViews,
15
+ getSchemaValue,
16
+ shouldRenderSchema
17
+ } from '../utils/schema.js'
14
18
  import { getResource, getMemberResource } from '../utils/resource.js'
15
19
  import { computed, reactive } from 'vue'
16
20
 
@@ -77,6 +81,10 @@ export default {
77
81
  return this.$views()
78
82
  },
79
83
 
84
+ flattenedViews() {
85
+ return flattenViews(this.views)
86
+ },
87
+
80
88
  isPopulated() {
81
89
  return this.$isPopulated()
82
90
  },
@@ -10,6 +10,6 @@ export default {
10
10
  },
11
11
 
12
12
  processValue(schema, value) {
13
- return schema.trim ? value?.trim() : value
13
+ return schema.trim && value != null ? value.trim() : value
14
14
  }
15
15
  }
@@ -1,22 +1,19 @@
1
- // TODO: Convert to flexbox
2
-
3
- .dito-layout-vertical {
4
- display: table;
1
+ .dito-layout-vertical,
2
+ .dito-layout-horizontal {
3
+ display: flex;
5
4
 
6
5
  > * {
7
- display: table-row;
6
+ flex: 1;
7
+ display: flex;
8
8
  }
9
9
  }
10
10
 
11
- .dito-layout-horizontal {
12
- display: table-row;
13
-
14
- > * {
15
- display: table-cell;
11
+ .dito-layout-vertical {
12
+ flex-direction: column;
13
+ }
16
14
 
17
- /* stylelint-disable-next-line selector-max-universal */
18
- & + * {
19
- padding-left: $form-spacing;
20
- }
15
+ .dito-layout-horizontal {
16
+ > *:not(:first-child) {
17
+ padding-left: $form-spacing;
21
18
  }
22
19
  }
@@ -1,8 +1,7 @@
1
1
  .dito-scroll {
2
2
  flex: 1;
3
3
  max-height: 100%;
4
- overflow-x: hidden;
5
- overflow-y: auto;
4
+ overflow: auto;
6
5
  }
7
6
 
8
7
  .dito-scroll-parent {
@@ -34,11 +34,15 @@ $pulldown-padding: $pulldown-padding-ver $pulldown-padding-hor;
34
34
 
35
35
  // Content
36
36
  $content-width: 900px;
37
- $content-sidebar-width: 360px;
37
+ $content-width-wide: 1400px;
38
38
  $content-padding: 16px;
39
39
  $content-padding-half: calc($content-padding / 2);
40
40
  $content-color-background: $color-lightest;
41
41
 
42
+ // Sidebar
43
+ $sidebar-max-width: 360px;
44
+ $sidebar-min-width: 200px;
45
+
42
46
  // Form
43
47
  $form-spacing: $input-padding-hor;
44
48
  $form-spacing-half: calc($form-spacing / 2);
@@ -1,4 +1,5 @@
1
1
  @use 'sass:color';
2
+ @import 'tippy.js/dist/tippy.css';
2
3
  @import 'tippy.js/animations/shift-away-subtle.css';
3
4
 
4
5
  .tippy-box {
@@ -7,18 +7,13 @@ button.dito-button(
7
7
  :class="buttonClass"
8
8
  v-bind="attributes"
9
9
  )
10
- template(
11
- v-if="info || width === 'fill'"
12
- )
13
- .dito-button__text
14
- span {{ text }}
15
- .dito-info(
16
- v-if="!label && info"
17
- :data-info="info"
18
- )
19
- template(
20
- v-else
10
+ .dito-button__text(
11
+ v-if="text"
21
12
  ) {{ text }}
13
+ .dito-info(
14
+ v-if="!label && info"
15
+ :data-info="info"
16
+ )
22
17
  </template>
23
18
 
24
19
  <script>
@@ -99,13 +94,9 @@ export default DitoTypeComponent.register(
99
94
  $self: &;
100
95
 
101
96
  &__text {
102
- position: relative;
103
- min-width: min-content;
104
- height: calc(1em * var(--line-height));
97
+ @include ellipsis;
105
98
 
106
- span {
107
- @include ellipsis;
108
- }
99
+ height: calc(1em * var(--line-height));
109
100
  }
110
101
  }
111
102
  </style>
@@ -14,7 +14,6 @@ import CodeFlask from 'codeflask'
14
14
  // @vue/component
15
15
  export default DitoTypeComponent.register('code', {
16
16
  mixins: [DomMixin],
17
- keepAligned: false,
18
17
 
19
18
  computed: {
20
19
  lines() {
@@ -22,7 +22,6 @@ 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,
26
25
  ignoreMissingValue: schema => !('default' in schema),
27
26
 
28
27
  async processSchema(api, schema) {
@@ -11,8 +11,7 @@ import DitoTypeComponent from '../DitoTypeComponent.js'
11
11
  // @vue/component
12
12
  export default DitoTypeComponent.register('label', {
13
13
  excludeValue: true,
14
- generateLabel: false,
15
- keepAligned: false
14
+ generateLabel: false
16
15
  })
17
16
  </script>
18
17
 
@@ -2,10 +2,8 @@
2
2
  .dito-list(
3
3
  v-if="isReady"
4
4
  :id="dataPath"
5
- :class="schema.class"
6
- :style="schema.style"
7
5
  )
8
- .dito-navigation(
6
+ .dito-list__header(
9
7
  v-if="scopes || hasPagination"
10
8
  )
11
9
  DitoScopes(
@@ -167,7 +165,6 @@ import { pickBy, equals, hyphenate } from '@ditojs/utils'
167
165
  // @vue/component
168
166
  export default DitoTypeComponent.register('list', {
169
167
  mixins: [SourceMixin, SortableMixin],
170
- keepAligned: false,
171
168
 
172
169
  getSourceType(type) {
173
170
  // No need for transformation here. See TypeTreeList for details.
@@ -315,9 +312,11 @@ export default DitoTypeComponent.register('list', {
315
312
  @import '../styles/_imports';
316
313
 
317
314
  .dito-list {
315
+ $self: &;
316
+
318
317
  position: relative;
319
318
 
320
- .dito-navigation {
319
+ &__header {
321
320
  display: flex;
322
321
  justify-content: space-between;
323
322
  padding-bottom: $content-padding-half;
@@ -343,7 +342,7 @@ export default DitoTypeComponent.register('list', {
343
342
 
344
343
  // Make single list header, navigation and buttons sticky to the top and
345
344
  // bottom:
346
- .dito-navigation {
345
+ #{$self}__header {
347
346
  position: sticky;
348
347
  top: 0;
349
348
  margin-top: -$content-padding;
@@ -1,19 +1,18 @@
1
1
  <template lang="pug">
2
2
  .dito-markup(:id="dataPath")
3
- .dito-markup-toolbar
4
- .dito-buttons.dito-buttons-toolbar(
5
- v-if="groupedButtons.length > 0"
3
+ .dito-buttons.dito-buttons-toolbar(
4
+ v-if="groupedButtons.length > 0"
5
+ )
6
+ .dito-button-group(
7
+ v-for="buttons in groupedButtons"
6
8
  )
7
- .dito-button-group(
8
- v-for="buttons in groupedButtons"
9
+ button.dito-button(
10
+ v-for="{ name, icon, isActive, onClick } in buttons"
11
+ :key="name"
12
+ :class="{ 'dito-active': isActive }"
13
+ @click="onClick"
9
14
  )
10
- button.dito-button(
11
- v-for="{ name, icon, isActive, onClick } in buttons"
12
- :key="name"
13
- :class="{ 'dito-active': isActive }"
14
- @click="onClick"
15
- )
16
- Icon(:name="icon")
15
+ Icon(:name="icon")
17
16
  EditorContent.dito-markup-editor(
18
17
  ref="editor"
19
18
  :editor="editor"
@@ -76,8 +75,6 @@ export default DitoTypeComponent.register('markup', {
76
75
  Icon
77
76
  },
78
77
 
79
- keepAligned: false,
80
-
81
78
  data() {
82
79
  return {
83
80
  editor: null,
@@ -317,7 +314,7 @@ export default DitoTypeComponent.register('markup', {
317
314
  }
318
315
  }
319
316
  editor.commands.setLink({ href, title })
320
- } else {
317
+ } else if (attributes === null) {
321
318
  editor.commands.unsetLink()
322
319
  }
323
320
  },
@@ -522,13 +519,14 @@ const LinkWithTitle = Link.extend({
522
519
 
523
520
  .dito-markup-editor {
524
521
  overflow-y: scroll;
522
+ margin-top: $input-padding-ver;
525
523
  // Move padding "inside" editor to correctly position scrollbar
526
524
  margin-right: -$input-padding-hor;
527
525
  padding-right: $input-padding-hor;
528
526
  }
529
527
 
530
528
  .dito-buttons-toolbar {
531
- margin: $input-padding-ver 0;
529
+ margin: 0;
532
530
  }
533
531
 
534
532
  h1,
@@ -360,6 +360,8 @@ $tag-line-height: 1em;
360
360
  }
361
361
 
362
362
  &__placeholder {
363
+ white-space: nowrap;
364
+
363
365
  &::after {
364
366
  // Enforce actual line-height for positioning.
365
367
  content: '\200b';
@@ -2,8 +2,6 @@
2
2
  .dito-object(
3
3
  v-if="isReady"
4
4
  :id="dataPath"
5
- :class="schema.class"
6
- :style="schema.style"
7
5
  )
8
6
  .dito-object-content(
9
7
  v-if="objectData"
@@ -63,8 +61,6 @@ import { resolveSchemaComponent } from '../utils/schema.js'
63
61
  export default DitoTypeComponent.register('object', {
64
62
  mixins: [SourceMixin],
65
63
 
66
- keepAligned: false,
67
-
68
64
  getSourceType(type) {
69
65
  // No need for transformation here. See TypeTreeList for details.
70
66
  return type
@@ -120,16 +116,18 @@ export default DitoTypeComponent.register('object', {
120
116
  border: $border-style;
121
117
  border-radius: $border-radius;
122
118
  margin: 0;
123
- padding: $form-spacing;
119
+ // Only add what's not already added by the nested '.dito-pane' as padding,
120
+ // in order to have `$form-spacing` all around.
121
+ padding: 0 $form-spacing-half;
124
122
  box-sizing: border-box;
125
123
 
126
124
  .dito-object-content {
127
125
  flex: 0 1 100%;
128
126
  }
129
127
 
130
- > .dito-buttons {
128
+ > .dito-edit-buttons {
131
129
  flex: 1 0 0%;
132
- margin-left: $form-spacing;
130
+ padding: $form-spacing;
133
131
  }
134
132
  }
135
133
  </style>
@@ -6,7 +6,6 @@ export default DitoTypeComponent.register('panel', {
6
6
  defaultValue: () => undefined, // Callback to override `defaultValue: null`
7
7
  excludeValue: true,
8
8
  generateLabel: false,
9
- keepAligned: false,
10
9
  omitPadding: true,
11
10
 
12
11
  getPanelSchema(api, schema) {
@@ -20,7 +20,6 @@ export default DitoTypeComponent.register('section', {
20
20
  ignoreMissingValue: schema => !schema.nested && !('default' in schema),
21
21
  defaultNested: false,
22
22
  generateLabel: false,
23
- keepAligned: false,
24
23
 
25
24
  computed: {
26
25
  item() {
@@ -19,7 +19,6 @@ export default DitoTypeComponent.register('textarea', {
19
19
  mixins: [TextMixin],
20
20
  nativeField: true,
21
21
  textField: true,
22
- keepAligned: false,
23
22
 
24
23
  computed: {
25
24
  lines() {
@@ -35,8 +35,6 @@ export default DitoTypeComponent.register(
35
35
  {
36
36
  mixins: [SourceMixin],
37
37
 
38
- keepAligned: false,
39
-
40
38
  provide() {
41
39
  return { container: this }
42
40
  },
@@ -150,8 +150,6 @@ export default DitoTypeComponent.register('upload', {
150
150
  mixins: [SortableMixin],
151
151
  components: { VueUpload },
152
152
 
153
- keepAligned: false,
154
-
155
153
  data() {
156
154
  return {
157
155
  uploads: []
@@ -36,7 +36,6 @@ const ditoOptionKeys = [
36
36
  'generateLabel',
37
37
  'excludeValue',
38
38
  'ignoreMissingValue',
39
- 'keepAligned',
40
39
  'omitPadding',
41
40
  'processValue',
42
41
  'processSchema',
@@ -188,11 +188,28 @@ export async function resolveViews(unresolvedViews) {
188
188
  // NOTE: This is never actually referenced from anywhere, but they need
189
189
  // a name by which they're stored in the parent object.
190
190
  schema.name = camelize(schema.label)
191
+ schema.items = await resolveSchemas(schema.items)
191
192
  }
192
193
  return schema
193
194
  })
194
195
  }
195
196
 
197
+ export function flattenViews(views) {
198
+ return Object.fromEntries(
199
+ Object.entries(views).reduce(
200
+ (entries, [key, schema]) => {
201
+ if (isMenu(schema)) {
202
+ entries.push(...Object.entries(schema.items))
203
+ } else {
204
+ entries.push([key, schema])
205
+ }
206
+ return entries
207
+ },
208
+ []
209
+ )
210
+ )
211
+ }
212
+
196
213
  export async function resolveSchemaComponent(schema) {
197
214
  // Resolves async schema components and adds DitoMixin and TypeMixin to them.
198
215
  let { component } = schema
@@ -283,7 +300,6 @@ export async function processView(component, api, schema, name) {
283
300
  }
284
301
  }
285
302
  } else if (isMenu(schema)) {
286
- schema.items = await resolveSchemas(schema.items)
287
303
  return Promise.all(
288
304
  Object.entries(schema.items).map(async ([name, item]) =>
289
305
  processView(component, api, item, name)
@@ -428,7 +444,7 @@ export function isSingleComponentView(schema) {
428
444
 
429
445
  export function getViewFormSchema(schema, context) {
430
446
  const { view } = schema
431
- const viewSchema = view && context.views[view]
447
+ const viewSchema = view && context.flattenedViews[view]
432
448
  return viewSchema
433
449
  ? // NOTE: Views can have tabs, in which case the view component is nested
434
450
  // in one of the tabs, go find it.
@@ -438,7 +454,7 @@ export function getViewFormSchema(schema, context) {
438
454
 
439
455
  export function getViewSchema(schema, context) {
440
456
  return getViewFormSchema(schema, context)
441
- ? context.views[schema.view]
457
+ ? context.flattenedViews[schema.view]
442
458
  : null
443
459
  }
444
460
 
@@ -510,12 +526,18 @@ export function isNested(schema) {
510
526
  return !!(schema.nested || getTypeOptions(schema)?.defaultNested === true)
511
527
  }
512
528
 
513
- export function omitPadding(schema) {
514
- return !!getTypeOptions(schema)?.omitPadding
529
+ export function hasLabel(schema, generateLabels) {
530
+ const { label } = schema
531
+ return (
532
+ label !== false && (
533
+ !!label ||
534
+ generateLabels && getTypeOptions(schema)?.generateLabel
535
+ )
536
+ )
515
537
  }
516
538
 
517
- export function keepAligned(schema) {
518
- return !!getTypeOptions(schema)?.keepAligned
539
+ export function omitPadding(schema) {
540
+ return !!getTypeOptions(schema)?.omitPadding
519
541
  }
520
542
 
521
543
  export function getSchemaValue(