@ditojs/admin 2.2.13 → 2.2.15

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.2.13",
3
+ "version": "2.2.15",
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.2.10",
36
+ "@ditojs/ui": "^2.2.14",
37
37
  "@ditojs/utils": "^2.2.0",
38
38
  "@kyvg/vue3-notification": "^2.9.0",
39
39
  "@lk77/vue3-color": "^3.0.6",
@@ -66,6 +66,7 @@
66
66
  "nanoid": "^4.0.2",
67
67
  "sortablejs": "^1.15.0",
68
68
  "tinycolor2": "^1.6.0",
69
+ "tippy.js": "^6.3.7",
69
70
  "type-fest": "^3.8.0",
70
71
  "vue": "^3.2.47",
71
72
  "vue-multiselect": "^3.0.0-beta.1",
@@ -82,7 +83,7 @@
82
83
  "vite": "^4.3.1"
83
84
  },
84
85
  "types": "types",
85
- "gitHead": "cb2613f69dcb1837db22d95c736ea2d414326f5c",
86
+ "gitHead": "e56f0341b752f2aecf822e0680cc99c8403ecbe1",
86
87
  "scripts": {
87
88
  "build": "vite build",
88
89
  "watch": "yarn build --mode 'development' --watch",
@@ -6,21 +6,24 @@
6
6
  )
7
7
  DitoLabel(
8
8
  v-if="hasLabel"
9
+ :class="componentClass"
9
10
  :label="label"
10
11
  :dataPath="labelDataPath"
11
- :class="componentClass"
12
+ :info="info"
12
13
  )
13
14
  component.dito-component(
14
15
  :is="typeComponent"
16
+ :class="componentClass"
15
17
  :schema="schema"
16
18
  :dataPath="dataPath"
17
19
  :data="data"
18
20
  :meta="meta"
19
21
  :store="store"
22
+ :width="width"
23
+ :label="label"
20
24
  :single="single"
21
25
  :nested="nested"
22
26
  :disabled="componentDisabled"
23
- :class="componentClass"
24
27
  @errors="onErrors"
25
28
  )
26
29
  DitoErrors(:errors="errors")
@@ -84,7 +87,12 @@ export default DitoComponent.component('DitoContainer', {
84
87
  return this.nested ? this.dataPath : null
85
88
  },
86
89
 
87
- componentWidth: getSchemaAccessor('width', {
90
+ info: getSchemaAccessor('info', {
91
+ type: String,
92
+ default: null
93
+ }),
94
+
95
+ width: getSchemaAccessor('width', {
88
96
  type: [String, Number],
89
97
  default() {
90
98
  return this.typeComponent?.defaultWidth
@@ -99,7 +107,7 @@ export default DitoComponent.component('DitoContainer', {
99
107
  }
100
108
  }),
101
109
 
102
- componentWidthOperator: getSchemaAccessor('width', {
110
+ widthOperator: getSchemaAccessor('width', {
103
111
  type: String,
104
112
  get(width) {
105
113
  return isString(width)
@@ -143,7 +151,7 @@ export default DitoComponent.component('DitoContainer', {
143
151
  },
144
152
 
145
153
  componentBasis() {
146
- const width = this.componentWidth
154
+ const width = this.width
147
155
  // 'auto' = no fitting:
148
156
  const basis = [null, 'auto', 'fill'].includes(width)
149
157
  ? 'auto'
@@ -158,11 +166,11 @@ export default DitoComponent.component('DitoContainer', {
158
166
  containerStyle() {
159
167
  // Interpret '>50%' as '50%, flex-grow: 1`
160
168
  const grow = (
161
- this.componentWidthOperator === '>' ||
162
- this.componentWidth === 'fill'
169
+ this.widthOperator === '>' ||
170
+ this.width === 'fill'
163
171
  )
164
172
  // Interpret '<50%' as '50%, flex-shrink: 1`
165
- const shrink = this.componentWidthOperator === '<'
173
+ const shrink = this.widthOperator === '<'
166
174
  return {
167
175
  flex: `${grow ? 1 : 0} ${shrink ? 1 : 0} ${this.componentBasis}`
168
176
  }
@@ -174,7 +182,7 @@ export default DitoComponent.component('DitoContainer', {
174
182
  // TODO: BEM?
175
183
  'dito-single': this.single,
176
184
  'dito-disabled': this.componentDisabled,
177
- 'dito-width-fill': !basisIsAuto || this.componentWidth === 'fill',
185
+ 'dito-width-fill': !basisIsAuto || this.width === 'fill',
178
186
  'dito-has-errors': !!this.errors
179
187
  }
180
188
  }
@@ -285,11 +285,14 @@ export default DitoComponent.component('DitoForm', {
285
285
  watch: {
286
286
  $route(to, from) {
287
287
  // Reload form data when navigating to a different entity in same form.
288
- if (this.providesData) {
289
- const { param } = this.meta
290
- if (param && to.params[param] !== from.params[param]) {
291
- this.loadData(true)
292
- }
288
+ const { param } = this.meta
289
+ if (
290
+ param &&
291
+ this.providesData &&
292
+ from.params[param] !== 'create' &&
293
+ to.params[param] !== from.params[param]
294
+ ) {
295
+ this.loadData(true)
293
296
  }
294
297
  },
295
298
 
@@ -9,22 +9,28 @@ component.dito-label(
9
9
  v-if="collapsible"
10
10
  :class="{ 'dito-opened': !collapsed }"
11
11
  )
12
- DitoElement.dito-label-prefix(
13
- v-for="(prefix, index) of prefixes"
14
- :key="`prefix-${index}`"
15
- tag="span"
16
- :content="prefix"
17
- )
18
- label(
19
- :for="dataPath"
20
- v-html="text"
21
- )
22
- DitoElement.dito-label-suffix(
23
- v-for="(suffix, index) of suffixes"
24
- :key="`suffix-${index}`"
25
- tag="span"
26
- :content="suffix"
27
- )
12
+ .dito-label__inner
13
+ DitoElement.dito-label-prefix(
14
+ v-for="(prefix, index) of prefixes"
15
+ :key="`prefix-${index}`"
16
+ tag="span"
17
+ :content="prefix"
18
+ )
19
+ label(
20
+ :for="dataPath"
21
+ v-html="text"
22
+ )
23
+ DitoElement.dito-label-suffix(
24
+ v-for="(suffix, index) of suffixes"
25
+ :key="`suffix-${index}`"
26
+ tag="span"
27
+ :content="suffix"
28
+ )
29
+ .dito-info(
30
+ v-if="info"
31
+ :data-tippy-content="info"
32
+ data-tippy-theme="info"
33
+ )
28
34
  slot(name="edit-buttons")
29
35
  </template>
30
36
 
@@ -40,7 +46,8 @@ export default DitoComponent.component('DitoLabel', {
40
46
  label: { type: [String, Object], default: null },
41
47
  dataPath: { type: String, default: null },
42
48
  collapsed: { type: Boolean, default: false },
43
- collapsible: { type: Boolean, default: false }
49
+ collapsible: { type: Boolean, default: false },
50
+ info: { type: String, default: null }
44
51
  },
45
52
 
46
53
  computed: {
@@ -83,6 +90,8 @@ export default DitoComponent.component('DitoLabel', {
83
90
  @import '../styles/_imports';
84
91
 
85
92
  .dito-label {
93
+ $self: &;
94
+
86
95
  --label-padding: 0;
87
96
  // For buttons and chevron to align right:
88
97
  display: flex;
@@ -92,8 +101,13 @@ export default DitoComponent.component('DitoLabel', {
92
101
  padding: var(--label-padding);
93
102
  margin: 0 0 $form-spacing-half 0;
94
103
 
104
+ &__inner {
105
+ display: flex;
106
+ // Stretch to full available width so that buttons appear right-aligned:
107
+ flex: 1 1 auto;
108
+ }
109
+
95
110
  label {
96
- display: inline;
97
111
  cursor: inherit;
98
112
  font-weight: bold;
99
113
  white-space: nowrap;
@@ -102,23 +116,14 @@ export default DitoComponent.component('DitoLabel', {
102
116
  label,
103
117
  .dito-label-prefix,
104
118
  .dito-label-suffix {
105
- &:nth-last-child(2) {
106
- // To stretch either label or .dito-label-suffix to full available width
107
- // so that buttons always appear right-aligned:
108
- flex: 1 1 auto;
109
- }
119
+ @include user-select(none);
120
+ @include ellipsis;
110
121
 
111
122
  &::after {
112
- content: '\a0'; // &nbsp;;
123
+ content: '\a0'; // &nbsp;
113
124
  }
114
125
  }
115
126
 
116
- .dito-label-prefix,
117
- .dito-label-suffix {
118
- @include user-select(none);
119
- @include ellipsis;
120
- }
121
-
122
127
  .dito-buttons {
123
128
  // Move the label padding inside .dito-buttons, so that it captures all
124
129
  // near mouse events:
@@ -131,11 +136,9 @@ export default DitoComponent.component('DitoLabel', {
131
136
  width: 100%;
132
137
  // In order for ellipsis to work on labels without affecting other layout,
133
138
  // we need to position it absolutely inside its container.
134
- label {
135
- @include ellipsis;
136
-
139
+ #{$self}__inner {
137
140
  position: absolute;
138
- max-width: 100%;
141
+ inset: 0;
139
142
  }
140
143
 
141
144
  &::after {
@@ -144,6 +147,10 @@ export default DitoComponent.component('DitoLabel', {
144
147
  content: '\200b'; // zero-width space;
145
148
  }
146
149
  }
150
+
151
+ .dito-info {
152
+ margin-left: 0.35em;
153
+ }
147
154
  }
148
155
 
149
156
  a.dito-label {
@@ -34,6 +34,7 @@
34
34
  </template>
35
35
 
36
36
  <script>
37
+ import { delegate as tippyDelegate } from 'tippy.js'
37
38
  import { asArray, mapConcurrently, stripTags } from '@ditojs/utils'
38
39
  import DitoComponent from '../DitoComponent.js'
39
40
  import DitoUser from '../DitoUser.js'
@@ -90,6 +91,9 @@ export default DitoComponent.component('DitoRoot', {
90
91
  },
91
92
 
92
93
  async mounted() {
94
+ tippyDelegate(this.$el, {
95
+ target: '[data-tippy-content]'
96
+ })
93
97
  // Clear the label marked as active on all mouse and keyboard events, except
94
98
  // the ones that DitoLabel itself intercepts.
95
99
  this.domOn(document, {
@@ -3,7 +3,7 @@ import ValidationMixin from './ValidationMixin.js'
3
3
  import { getSchemaAccessor } from '../utils/accessor.js'
4
4
  import { computeValue } from '../utils/schema.js'
5
5
  import { getItem, getParentItem } from '../utils/data.js'
6
- import { isString, asArray, camelize } from '@ditojs/utils'
6
+ import { asArray, camelize } from '@ditojs/utils'
7
7
 
8
8
  // @vue/component
9
9
  export default {
@@ -17,6 +17,8 @@ export default {
17
17
  data: { type: [Object, Array], required: true },
18
18
  meta: { type: Object, required: true },
19
19
  store: { type: Object, required: true },
20
+ width: { type: [Number, String], default: null },
21
+ label: { type: String, default: null },
20
22
  single: { type: Boolean, default: false },
21
23
  nested: { type: Boolean, default: true },
22
24
  disabled: { type: Boolean, default: false }
@@ -109,21 +111,6 @@ export default {
109
111
  return this.processedData
110
112
  },
111
113
 
112
- label: getSchemaAccessor('label', {
113
- type: [String, Boolean],
114
- get(label) {
115
- return isString(label)
116
- ? label
117
- : label !== false && this.$options.generateLabel
118
- ? this.getLabel(this.schema)
119
- : null
120
- }
121
- }),
122
-
123
- width: getSchemaAccessor('width', {
124
- type: [String, Number]
125
- }),
126
-
127
114
  visible: getSchemaAccessor('visible', {
128
115
  type: Boolean,
129
116
  default() {
@@ -0,0 +1,32 @@
1
+ .dito-info {
2
+ --size: calc(1em * var(--line-height));
3
+
4
+ display: inline-block;
5
+ position: relative;
6
+ flex: 0 0 var(--size);
7
+ width: var(--size);
8
+ height: var(--size);
9
+ text-align: center;
10
+ vertical-align: top;
11
+ margin-left: 0.35em;
12
+ color: $color-active;
13
+
14
+ &::before {
15
+ @extend %icon-info;
16
+
17
+ width: var(--size);
18
+ }
19
+ }
20
+
21
+ .tippy-box[data-theme~='info'] {
22
+ background-color: $color-active;
23
+ color: $color-white;
24
+
25
+ > .tippy-arrow::before {
26
+ color: $color-active;
27
+ }
28
+
29
+ .tippy-content {
30
+ white-space: pre-line;
31
+ }
32
+ }
@@ -7,3 +7,4 @@
7
7
  @import '_sortable';
8
8
  @import '_table';
9
9
  @import '_notifications';
10
+ @import '_info';
@@ -6,7 +6,20 @@ button.dito-button(
6
6
  :title="title"
7
7
  :class="buttonClass"
8
8
  v-bind="attributes"
9
- ) {{ text }}
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-tippy-content="info"
18
+ data-tippy-theme="info"
19
+ )
20
+ template(
21
+ v-else
22
+ ) {{ text }}
10
23
  </template>
11
24
 
12
25
  <script>
@@ -41,6 +54,11 @@ export default DitoTypeComponent.register(
41
54
  return this.text || labelize(this.verb)
42
55
  },
43
56
 
57
+ info: getSchemaAccessor('info', {
58
+ type: String,
59
+ default: null
60
+ }),
61
+
44
62
  closeForm: getSchemaAccessor('closeForm', {
45
63
  type: Boolean,
46
64
  default: false
@@ -74,3 +92,25 @@ export default DitoTypeComponent.register(
74
92
  }
75
93
  )
76
94
  </script>
95
+
96
+ <style lang="scss">
97
+ @import '../styles/_imports';
98
+
99
+ .dito-button {
100
+ display: flex;
101
+
102
+ &__text {
103
+ position: relative;
104
+ width: 100%;
105
+ min-width: min-content;
106
+ height: calc(1em * var(--line-height));
107
+
108
+ span {
109
+ @include ellipsis;
110
+
111
+ position: absolute;
112
+ inset: 0;
113
+ }
114
+ }
115
+ }
116
+ </style>