@ditojs/admin 2.94.1 → 2.96.0

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.94.1",
3
+ "version": "2.96.0",
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/main/packages/admin",
@@ -24,6 +24,12 @@
24
24
  "dist/",
25
25
  "types/"
26
26
  ],
27
+ "scripts": {
28
+ "build": "vite build",
29
+ "watch": "pnpm run build --mode 'development' --watch",
30
+ "prepare": "pnpm run build",
31
+ "types": "tsc --noEmit types/index.d.ts"
32
+ },
27
33
  "engines": {
28
34
  "node": ">= 24.0.0"
29
35
  },
@@ -34,8 +40,8 @@
34
40
  "not ie_mob > 0"
35
41
  ],
36
42
  "dependencies": {
37
- "@ditojs/ui": "^2.94.0",
38
- "@ditojs/utils": "^2.94.0"
43
+ "@ditojs/ui": "^2.96.0",
44
+ "@ditojs/utils": "^2.96.0"
39
45
  },
40
46
  "peerDependencies": {
41
47
  "@kyvg/vue3-notification": "^3.4.2",
@@ -83,14 +89,9 @@
83
89
  "vue-upload-component": "^3.1.17"
84
90
  },
85
91
  "devDependencies": {
86
- "@ditojs/build": "^2.94.0",
87
- "typescript": "^6.0.2",
88
- "vite": "^8.0.3"
92
+ "@ditojs/build": "^2.96.0",
93
+ "typescript": "^6.0.3",
94
+ "vite": "^8.0.10"
89
95
  },
90
- "gitHead": "7bb40e9e490632e20ceaf92907b4ff7b27484e26",
91
- "scripts": {
92
- "build": "vite build",
93
- "watch": "pnpm run build --mode 'development' --watch",
94
- "types": "tsc --noEmit types/index.d.ts"
95
- }
96
- }
96
+ "gitHead": "689f4d061088500884114c5ced79d68209717bc5"
97
+ }
@@ -63,12 +63,20 @@ export default DitoComponent.component('DitoCreateButton', {
63
63
  path: { type: String, required: true },
64
64
  verb: { type: String, required: true },
65
65
  text: { type: String, default: null },
66
- disabled: { type: Boolean, required: true }
66
+ disabled: { type: Boolean, required: true },
67
+ insertIndex: { type: Number, default: null }
67
68
  },
68
69
 
69
70
  computed: {
70
71
  forms() {
71
- return getFormSchemas(this.schema, this.context)
72
+ // When inserting per-item, `this.schema` is the item's form, not the
73
+ // list schema. Fall back to `sourceSchema` (the parent list's schema via
74
+ // `meta.schema`) so all creatable forms are discoverable in the pulldown.
75
+ const schema =
76
+ this.insertIndex != null
77
+ ? this.sourceSchema || this.schema
78
+ : this.schema
79
+ return getFormSchemas(schema, this.context)
72
80
  },
73
81
 
74
82
  creatableForms() {
@@ -107,7 +115,7 @@ export default DitoComponent.component('DitoCreateButton', {
107
115
  createItem(form, type = null) {
108
116
  if (!this.shouldDisableSchema(form)) {
109
117
  if (this.isInlined) {
110
- this.sourceComponent.createItem(form, type)
118
+ this.sourceComponent.createItem(form, type, this.insertIndex)
111
119
  } else {
112
120
  const { creatable } = this.schema
113
121
  const query = {
@@ -31,8 +31,9 @@ DitoButtons.dito-edit-buttons.dito-buttons--round(
31
31
  :nested="nested"
32
32
  :path="createPath"
33
33
  :verb="verbs.create"
34
- :text="createButtonText"
34
+ :text="insertIndex != null ? null : createButtonText"
35
35
  :disabled="isCreatableDisabled"
36
+ :insertIndex="insertIndex"
36
37
  )
37
38
  button.dito-button(
38
39
  v-if="deletable"
@@ -67,7 +68,8 @@ export default DitoComponent.component('DitoEditButtons', {
67
68
  creatable: { type: Boolean, default: false },
68
69
  deletable: { type: Boolean, default: false },
69
70
  editPath: { type: String, default: null },
70
- createPath: { type: String, default: null }
71
+ createPath: { type: String, default: null },
72
+ insertIndex: { type: Number, default: null }
71
73
  },
72
74
 
73
75
  computed: {
@@ -102,6 +102,8 @@ export default DitoComponent.component('DitoLabel', {
102
102
  position: relative;
103
103
  // Vertically center all items in the label, e.g. chevron, edit-buttons.
104
104
  align-items: center;
105
+ // Let nested labels with ellipsis shrink below their content width.
106
+ min-width: 0;
105
107
  min-height: $input-height;
106
108
  margin-right: $form-spacing-half; // When inlined.
107
109
 
@@ -825,6 +825,8 @@ export default DitoComponent.component('DitoSchema', {
825
825
  .dito-schema-header {
826
826
  display: flex;
827
827
  justify-content: space-between;
828
+ // Let nested labels with ellipsis shrink below their content width.
829
+ min-width: 0;
828
830
 
829
831
  .dito-header & {
830
832
  // When teleported into main header.
@@ -21,7 +21,7 @@ DitoSchema.dito-schema-inlined(
21
21
  //- others in `TypeList` as a scope, for better handling of layout.
22
22
  template(#edit-buttons)
23
23
  DitoEditButtons(
24
- v-if="deletable || draggable || editable"
24
+ v-if="deletable || draggable || editable || insertIndex != null"
25
25
  :schema="schema"
26
26
  :dataPath="dataPath"
27
27
  :data="data"
@@ -32,6 +32,9 @@ DitoSchema.dito-schema-inlined(
32
32
  :draggable="draggable"
33
33
  :editable="editable"
34
34
  :editPath="editPath"
35
+ :creatable="insertIndex != null"
36
+ :createPath="createPath"
37
+ :insertIndex="insertIndex"
35
38
  @delete="$emit('delete')"
36
39
  )
37
40
  </template>
@@ -59,6 +62,8 @@ export default DitoComponent.component('DitoSchemaInlined', {
59
62
  editable: { type: Boolean, default: false },
60
63
  deletable: { type: Boolean, default: false },
61
64
  editPath: { type: String, default: null },
65
+ createPath: { type: String, default: null },
66
+ insertIndex: { type: Number, default: null },
62
67
  labelNode: { type: HTMLElement, default: null },
63
68
  accumulatedBasis: { type: Number, default: null }
64
69
  },
@@ -87,10 +92,9 @@ export default DitoComponent.component('DitoSchemaInlined', {
87
92
  grid-template-columns: 100%;
88
93
 
89
94
  &:not(:hover, .dito-schema--open) {
90
- > .dito-schema-header {
91
- > .dito-clipboard {
92
- display: none;
93
- }
95
+ > .dito-schema-header
96
+ .dito-button:not(.dito-button--edit, .dito-button--remove) {
97
+ display: none;
94
98
  }
95
99
  }
96
100
  }
@@ -321,8 +321,14 @@ export default DitoComponent.component('DitoTreeItem', {
321
321
  --chevron-indent: #{$chevron-indent};
322
322
 
323
323
  overflow: hidden;
324
+ padding: 0 $input-padding-hor;
325
+ margin: 0 (-$input-padding-hor);
324
326
 
325
327
  > .dito-tree-header {
328
+ // Extend header into item padding so active background reaches the edge:
329
+ margin: 0 (-$input-padding-hor);
330
+ padding: 0 $input-padding-hor;
331
+
326
332
  > .dito-tree-branch,
327
333
  > .dito-tree-leaf {
328
334
  // Use `--level` CSS variable to calculated the accumulated indent
@@ -356,8 +362,13 @@ export default DitoComponent.component('DitoTreeItem', {
356
362
  display: flex;
357
363
  align-items: baseline;
358
364
  gap: 0.25em;
359
- overflow: hidden;
365
+ min-width: 0;
360
366
  white-space: nowrap;
367
+
368
+ > :first-child {
369
+ overflow: hidden;
370
+ text-overflow: ellipsis;
371
+ }
361
372
  }
362
373
 
363
374
  .dito-tree-info {
@@ -395,8 +406,6 @@ export default DitoComponent.component('DitoTreeItem', {
395
406
  &--active {
396
407
  > .dito-tree-header {
397
408
  background: $color-active;
398
- padding: 0 $input-padding-hor;
399
- margin: 0 (-$input-padding-hor);
400
409
 
401
410
  > .dito-tree-branch {
402
411
  > .dito-chevron::before {
@@ -318,7 +318,7 @@ export default {
318
318
  type: Boolean,
319
319
  default: false,
320
320
  get(draggable) {
321
- return this.isListSource && this.listData.length > 1 && draggable
321
+ return this.isListSource && draggable
322
322
  }
323
323
  }),
324
324
 
@@ -450,15 +450,17 @@ export default {
450
450
  }
451
451
  },
452
452
 
453
- createItem(schema, type) {
453
+ createItem(schema, type, index = null) {
454
454
  const item = this.createData(schema, type)
455
455
  if (this.isObjectSource) {
456
456
  this.objectData = item
457
+ } else if (index != null) {
458
+ this.listData.splice(index, 0, item)
457
459
  } else {
458
460
  this.listData.push(item)
459
461
  }
460
462
  if (this.collapsible) {
461
- this.$nextTick(() => this.openSchemaComponent(-1))
463
+ this.$nextTick(() => this.openSchemaComponent(index ?? -1))
462
464
  }
463
465
  this.onChange()
464
466
  return item
@@ -531,9 +533,20 @@ export default {
531
533
  },
532
534
 
533
535
  getSchemaComponent(index) {
534
- const { schemaComponents } = this
535
- const { length } = schemaComponents
536
- return schemaComponents[((index % length) + length) % length]
536
+ const { listData, schemaComponents } = this
537
+ const candidate = schemaComponents.at(index)
538
+ if (listData?.length) {
539
+ // Fast path: registration order usually matches `listData`. Fall back
540
+ // to a search by reference when it doesn't (non-tail inserts, drag
541
+ // reorders), since `schemaComponents` is filled by mount-order pushes.
542
+ const item = listData.at(index)
543
+ return item == null
544
+ ? null
545
+ : candidate?.data === item
546
+ ? candidate
547
+ : schemaComponents.find(c => c.data === item)
548
+ }
549
+ return candidate
537
550
  },
538
551
 
539
552
  openSchemaComponent(index) {
@@ -155,9 +155,12 @@
155
155
 
156
156
  &--round,
157
157
  &--small {
158
- // For now, nothing for these:
159
- // .dito-button--create:empty::before,
160
- // .dito-button--add:empty::before
158
+ // For now, nothing for create:
159
+ // .dito-button--create:empty::before
160
+
161
+ .dito-button--add:empty::before {
162
+ @extend %icon-add;
163
+ }
161
164
 
162
165
  .dito-button--upload:empty::before {
163
166
  @extend %icon-upload;
@@ -85,9 +85,11 @@
85
85
  :collapsed="collapsed"
86
86
  :collapsible="collapsible"
87
87
  :deletable="deletable"
88
- :draggable="draggable"
88
+ :draggable="draggable && listData.length > 1"
89
89
  :editable="editable"
90
90
  :editPath="getEditPath(item, index)"
91
+ :createPath="createPath"
92
+ :insertIndex="creatable && draggable ? index : null"
91
93
  @delete="deleteItem(item, index)"
92
94
  )
93
95
  component(