@ditojs/admin 2.6.0 → 2.6.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.6.0",
3
+ "version": "2.6.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,7 +33,7 @@
33
33
  "not ie_mob > 0"
34
34
  ],
35
35
  "dependencies": {
36
- "@ditojs/ui": "^2.6.0",
36
+ "@ditojs/ui": "^2.6.1",
37
37
  "@ditojs/utils": "^2.6.0",
38
38
  "@kyvg/vue3-notification": "^2.9.0",
39
39
  "@lk77/vue3-color": "^3.0.6",
@@ -83,7 +83,7 @@
83
83
  "vite": "^4.3.4"
84
84
  },
85
85
  "types": "types",
86
- "gitHead": "ce98ce03662c08e040ad7f9cb93cc0f48e11edb9",
86
+ "gitHead": "cfe61efec24e2380ab645f3adf0f9dbd0b815adb",
87
87
  "scripts": {
88
88
  "build": "vite build",
89
89
  "watch": "yarn build --mode 'development' --watch",
@@ -150,6 +150,10 @@ export default class DitoContext {
150
150
  return get(this, 'views', null)
151
151
  }
152
152
 
153
+ get flattenedViews() {
154
+ return get(this, 'flattenedViews', null)
155
+ }
156
+
153
157
  get itemLabel() {
154
158
  return get(this, 'itemLabel', null)
155
159
  }
@@ -49,7 +49,7 @@ export default DitoComponent.component('DitoContainer', {
49
49
  nested: { type: Boolean, default: true },
50
50
  disabled: { type: Boolean, required: true },
51
51
  generateLabels: { type: Boolean, default: false },
52
- inLabeledRow: { type: Boolean, default: false }
52
+ verticalLabels: { type: Boolean, default: false }
53
53
  },
54
54
 
55
55
  data() {
@@ -155,7 +155,7 @@ export default DitoComponent.component('DitoContainer', {
155
155
  const prefix = 'dito-container'
156
156
  return {
157
157
  [`${prefix}--single`]: this.single,
158
- [`${prefix}--labeled-row`]: this.inLabeledRow,
158
+ [`${prefix}--label-vertical`]: this.verticalLabels,
159
159
  [`${prefix}--omit-padding`]: omitPadding(this.schema),
160
160
  ...(
161
161
  isString(containerClass)
@@ -178,12 +178,11 @@ export default DitoComponent.component('DitoContainer', {
178
178
  },
179
179
 
180
180
  componentClass() {
181
- const basisIsAuto = this.flexBasis === 'auto'
182
181
  return {
183
182
  // TODO: BEM?
184
183
  'dito-single': this.single,
185
184
  'dito-disabled': this.componentDisabled,
186
- 'dito-width-fill': !basisIsAuto || this.width === 'fill',
185
+ 'dito-width-fill': this.width === 'fill' || this.flexBasis !== 'auto',
187
186
  'dito-width-grow': this.flexGrow,
188
187
  'dito-width-shrink': this.flexShrink,
189
188
  'dito-has-errors': !!this.errors
@@ -232,7 +231,7 @@ export default DitoComponent.component('DitoContainer', {
232
231
  padding: 0;
233
232
  }
234
233
 
235
- &--labeled-row {
234
+ &--label-vertical {
236
235
  // For components without labels in rows with other components that have
237
236
  // labels, add some spacing to the top to align with the other components:
238
237
  > .dito-component:first-child {
@@ -98,7 +98,11 @@ export default DitoComponent.component('DitoLabel', {
98
98
  // Vertically center all items in the label, e.g. chevron, edit-buttons.
99
99
  align-items: center;
100
100
  padding: var(--label-padding);
101
- margin: 0 0 $form-spacing-half 0;
101
+ margin: 0 $form-spacing-half $form-spacing-half 0;
102
+
103
+ .dito-container:not(.dito-container--label-vertical) > & {
104
+ margin-bottom: 0;
105
+ }
102
106
 
103
107
  &__inner {
104
108
  display: flex;
@@ -175,10 +179,10 @@ a.dito-label {
175
179
  .dito-schema-compact {
176
180
  > .dito-schema-content {
177
181
  > .dito-pane {
178
- > .dito-container {
182
+ > .dito-container:not(.dito-container--label-vertical) {
179
183
  display: flex;
180
184
  flex-flow: row wrap;
181
- align-items: baseline;
185
+ align-items: center;
182
186
  }
183
187
  }
184
188
  }
@@ -32,7 +32,7 @@
32
32
  :nested="nested"
33
33
  :disabled="disabled"
34
34
  :generateLabels="generateLabels"
35
- :inLabeledRow="isInLabeledRow(index)"
35
+ :verticalLabels="isInLabeledRow(index)"
36
36
  )
37
37
  .dito-break(
38
38
  v-if="schema.break === 'after'"
@@ -42,7 +42,7 @@
42
42
  <script>
43
43
  import DitoComponent from '../DitoComponent.js'
44
44
  import { appendDataPath } from '../utils/data.js'
45
- import { getAllPanelEntries, hasLabel, isNested } from '../utils/schema.js'
45
+ import { getAllPanelEntries, isNested } from '../utils/schema.js'
46
46
 
47
47
  // @vue/component
48
48
  export default DitoComponent.component('DitoPane', {
@@ -125,13 +125,13 @@ export default DitoComponent.component('DitoPane', {
125
125
  return this.single && this.componentSchemas.length === 1
126
126
  },
127
127
 
128
- labeledRowsByIndices() {
128
+ verticalLabelsByIndices() {
129
129
  const { positions } = this
130
130
 
131
131
  const isLastInRow = index => (
132
- positions[index] !== null && (
132
+ positions[index] && (
133
133
  index === positions.length - 1 ||
134
- findNextPosition(index) > positions[index]
134
+ findNextPosition(index).top > positions[index].top
135
135
  )
136
136
  )
137
137
 
@@ -155,25 +155,28 @@ export default DitoComponent.component('DitoPane', {
155
155
  rows.push(row)
156
156
  }
157
157
 
158
- const labeledRowsByIndices = []
158
+ const verticalLabelsByIndices = []
159
159
 
160
160
  for (const row of rows) {
161
161
  let hasLabelsInRow = false
162
162
  for (const index of row) {
163
- const { schema } = this.componentSchemas[index]
164
- // TODO: Handle nested schemas, e.g. 'section' or 'object' and detect
165
- // labels there too.
166
- if (hasLabel(schema, this.generateLabels)) {
163
+ const position = this.positions[index]
164
+ if (
165
+ position?.height > 4 &&
166
+ position.node.querySelector(':scope > .dito-label')
167
+ ) {
168
+ // TODO: Handle nested schemas, e.g. 'section' or 'object' and
169
+ // detect labels there too.
167
170
  hasLabelsInRow = true
168
171
  break
169
172
  }
170
173
  }
171
174
  for (const index of row) {
172
- labeledRowsByIndices[index] = hasLabelsInRow
175
+ verticalLabelsByIndices[index] = hasLabelsInRow
173
176
  }
174
177
  }
175
178
 
176
- return labeledRowsByIndices
179
+ return verticalLabelsByIndices
177
180
  }
178
181
  },
179
182
 
@@ -204,11 +207,18 @@ export default DitoComponent.component('DitoPane', {
204
207
 
205
208
  onResizeContainer(index, { target }) {
206
209
  const { y, width, height } = target.getBoundingClientRect()
207
- this.positions[index] = width > 0 && height > 0 ? y : null
210
+ this.positions[index] =
211
+ width > 0 && height > 0
212
+ ? {
213
+ top: y,
214
+ height: height / parseFloat(getComputedStyle(target).fontSize),
215
+ node: target
216
+ }
217
+ : null
208
218
  },
209
219
 
210
220
  isInLabeledRow(index) {
211
- return this.labeledRowsByIndices[index]
221
+ return !!this.verticalLabelsByIndices[index]
212
222
  }
213
223
  }
214
224
  })
@@ -226,12 +236,22 @@ export default DitoComponent.component('DitoPane', {
226
236
  padding: $content-padding;
227
237
  // Remove the padding added by `.dito-container` inside `.dito-pane`:
228
238
  margin: (-$form-spacing) (-$form-spacing-half);
239
+ max-width: calc(var(--max-content-width) + $form-spacing);
229
240
  // Use `flex: 0%` for all `.dito-pane` except `.dito-pane-main`,
230
241
  // so that the `.dito-buttons-main` can be moved all the way to the bottom.
231
242
  flex: 0%;
232
243
 
233
244
  &--single {
234
- // Clear margin from above.
245
+ // Clear negative margin from above.
246
+ margin: 0;
247
+ }
248
+
249
+ .dito-scroll > &:not(&--single) {
250
+ // Root-level panes inside scroll views need to move the negative margin
251
+ // used to remove the padding added by `.dito-container` inside
252
+ // `.dito-pane` to the padding:
253
+ padding: ($content-padding - $form-spacing)
254
+ ($content-padding - $form-spacing-half);
235
255
  margin: 0;
236
256
  }
237
257
 
@@ -247,8 +247,6 @@ export default DitoComponent.component('DitoPanel', {
247
247
  }
248
248
 
249
249
  .dito-label {
250
- margin: 0;
251
-
252
250
  label {
253
251
  font-weight: normal;
254
252
  }
@@ -46,6 +46,7 @@ export default DitoComponent.component('DitoPanels', {
46
46
 
47
47
  .dito-panels {
48
48
  padding: $content-padding;
49
+ padding-left: $form-spacing;
49
50
  // For the `@container` rule in `.dito-container` to work:
50
51
  container-type: inline-size;
51
52
  }
@@ -472,12 +472,14 @@ function addRoutes(router, routes) {
472
472
  }
473
473
 
474
474
  .dito-page {
475
- flex: 1 1 $content-width;
475
+ --max-content-width: #{$content-width};
476
+
477
+ flex: 1 1 var(--max-content-width);
476
478
  background: $content-color-background;
477
- max-width: $content-width;
479
+ max-width: calc(var(--max-content-width) + 2 * #{$content-padding});
478
480
 
479
481
  &--wide {
480
- max-width: $content-width-wide;
482
+ --max-content-width: #{$content-width-wide};
481
483
  }
482
484
  }
483
485
 
@@ -757,8 +757,9 @@ export default DitoComponent.component('DitoSchema', {
757
757
 
758
758
  .dito-schema {
759
759
  box-sizing: border-box;
760
- // To display schema next to panels:
760
+ // To display schema next to buttons:
761
761
  display: flex;
762
+ align-items: flex-start;
762
763
  min-height: 100%;
763
764
 
764
765
  > .dito-schema-content {
@@ -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
  },
@@ -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(
@@ -314,9 +312,11 @@ export default DitoTypeComponent.register('list', {
314
312
  @import '../styles/_imports';
315
313
 
316
314
  .dito-list {
315
+ $self: &;
316
+
317
317
  position: relative;
318
318
 
319
- .dito-navigation {
319
+ &__header {
320
320
  display: flex;
321
321
  justify-content: space-between;
322
322
  padding-bottom: $content-padding-half;
@@ -342,7 +342,7 @@ export default DitoTypeComponent.register('list', {
342
342
 
343
343
  // Make single list header, navigation and buttons sticky to the top and
344
344
  // bottom:
345
- .dito-navigation {
345
+ #{$self}__header {
346
346
  position: sticky;
347
347
  top: 0;
348
348
  margin-top: -$content-padding;
@@ -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"
@@ -125,7 +123,7 @@ export default DitoTypeComponent.register('object', {
125
123
  flex: 0 1 100%;
126
124
  }
127
125
 
128
- > .dito-buttons {
126
+ > .dito-edit-buttons {
129
127
  flex: 1 0 0%;
130
128
  margin-left: $form-spacing;
131
129
  }
@@ -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