@ditojs/admin 2.1.3 → 2.2.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.
Files changed (38) hide show
  1. package/dist/dito-admin.es.js +1498 -1409
  2. package/dist/dito-admin.umd.js +4 -4
  3. package/dist/style.css +1 -1
  4. package/package.json +5 -5
  5. package/src/DitoContext.js +10 -10
  6. package/src/DitoTypeComponent.js +1 -0
  7. package/src/components/DitoContainer.vue +21 -10
  8. package/src/components/DitoCreateButton.vue +11 -8
  9. package/src/components/DitoDraggable.vue +45 -0
  10. package/src/components/DitoPane.vue +1 -1
  11. package/src/components/DitoPanel.vue +1 -1
  12. package/src/components/DitoSchema.vue +11 -6
  13. package/src/components/DitoSchemaInlined.vue +1 -0
  14. package/src/components/DitoTreeItem.vue +3 -2
  15. package/src/components/index.js +1 -0
  16. package/src/mixins/DataMixin.js +3 -3
  17. package/src/mixins/DitoMixin.js +23 -10
  18. package/src/mixins/RouteMixin.js +1 -1
  19. package/src/mixins/SortableMixin.js +2 -6
  20. package/src/mixins/SourceMixin.js +0 -5
  21. package/src/mixins/TypeMixin.js +22 -13
  22. package/src/styles/_pulldown.scss +9 -12
  23. package/src/types/DitoTypeButton.vue +7 -4
  24. package/src/types/DitoTypeCode.vue +1 -0
  25. package/src/types/DitoTypeComponent.vue +1 -0
  26. package/src/types/DitoTypeLabel.vue +2 -1
  27. package/src/types/DitoTypeList.vue +4 -2
  28. package/src/types/DitoTypeMarkup.vue +2 -0
  29. package/src/types/DitoTypeObject.vue +2 -0
  30. package/src/types/DitoTypePanel.vue +1 -0
  31. package/src/types/DitoTypeSection.vue +1 -1
  32. package/src/types/DitoTypeTextarea.vue +1 -0
  33. package/src/types/DitoTypeTreeList.vue +2 -0
  34. package/src/types/DitoTypeUpload.vue +5 -2
  35. package/src/utils/accessor.js +1 -1
  36. package/src/utils/options.js +1 -0
  37. package/src/utils/schema.js +5 -15
  38. package/types/index.d.ts +3 -24
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ditojs/admin",
3
- "version": "2.1.3",
3
+ "version": "2.2.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/master/packages/admin",
@@ -33,8 +33,8 @@
33
33
  "not ie_mob > 0"
34
34
  ],
35
35
  "dependencies": {
36
- "@ditojs/ui": "^2.1.2",
37
- "@ditojs/utils": "^2.1.1",
36
+ "@ditojs/ui": "^2.2.0",
37
+ "@ditojs/utils": "^2.2.0",
38
38
  "@kyvg/vue3-notification": "^2.9.0",
39
39
  "@lk77/vue3-color": "^3.0.6",
40
40
  "@tiptap/core": "^2.0.3",
@@ -73,7 +73,7 @@
73
73
  "vue-upload-component": "^3.1.8"
74
74
  },
75
75
  "devDependencies": {
76
- "@ditojs/build": "^2.1.1",
76
+ "@ditojs/build": "^2.2.0",
77
77
  "@vitejs/plugin-vue": "^4.1.0",
78
78
  "@vue/compiler-sfc": "^3.2.47",
79
79
  "pug": "^3.0.2",
@@ -82,7 +82,7 @@
82
82
  "vite": "^4.2.1"
83
83
  },
84
84
  "types": "types",
85
- "gitHead": "39cbb715f40b8c3c657ca8d6790def22f170b31b",
85
+ "gitHead": "fc81c8e9a64e76549d26bd94774a3b1c92afa49f",
86
86
  "scripts": {
87
87
  "build": "vite build",
88
88
  "watch": "yarn build --mode 'development' --watch",
@@ -103,27 +103,27 @@ export default class DitoContext {
103
103
  return getLastDataPathIndex(this.parentItemDataPath)
104
104
  }
105
105
 
106
+ // NOTE: While internally, we speak of `data`, in the API surface the
107
+ // term `item` is used for the data that relates to editing objects:
108
+ // If `data` isn't provided, we can determine it from rootData & dataPath:
106
109
  get item() {
107
- // NOTE: While internally, we speak of `data`, in the API surface the
108
- // term `item` is used for the data that relates to editing objects:
109
- // If `data` isn't provided, we can determine it from rootData & dataPath:
110
110
  return get(this, 'data', () =>
111
111
  getItem(this.rootItem, this.dataPath, this.nested)
112
112
  )
113
113
  }
114
114
 
115
115
  // NOTE: `parentItem` isn't the closest data parent to `item`, it's the
116
- // closest parent that isn't an array, e.g. for relations or nested JSON
117
- // data. This is why the term `item` was chosen over `data`, e.g. VS the
118
- // use of `parentData` in server-sided validation, which is the closest
119
- // parent. If needed, we could expose this data here too, as we can do all
120
- // sorts of data processing with `rootData` and `dataPath`.
116
+ // closest parent that isn't an array, e.g. for relations or nested JSON data.
117
+ // This is why the term `item` was chosen over `data`, e.g. VS the use of
118
+ // `parentData` in server-sided validation, which is the closest parent. If
119
+ // needed, we could expose this data here too, as we can do all sorts of data
120
+ // processing with `rootData` and `dataPath`.
121
121
  get parentItem() {
122
- const parentItem = (
122
+ const item = (
123
123
  getParentItem(this.rootItem, this.dataPath, this.nested) ||
124
124
  null
125
125
  )
126
- return parentItem !== this.item ? parentItem : null
126
+ return item !== this.item ? item : null
127
127
  }
128
128
 
129
129
  get rootItem() {
@@ -21,6 +21,7 @@ export default {
21
21
  generateLabel: true,
22
22
  excludeValue: false,
23
23
  ignoreMissingValue: null,
24
+ alignBottom: true,
24
25
  omitPadding: false,
25
26
 
26
27
  component: DitoComponent.component,
@@ -5,7 +5,7 @@
5
5
  :style="containerStyle"
6
6
  )
7
7
  DitoLabel(
8
- v-if="label"
8
+ v-if="hasLabel"
9
9
  :label="label"
10
10
  :dataPath="labelDataPath"
11
11
  :class="componentClass"
@@ -31,7 +31,7 @@ import { isString, isNumber } from '@ditojs/utils'
31
31
  import DitoComponent from '../DitoComponent.js'
32
32
  import DitoContext from '../DitoContext.js'
33
33
  import { getSchemaAccessor } from '../utils/accessor.js'
34
- import { getTypeComponent, shouldOmitPadding } from '../utils/schema.js'
34
+ import { getTypeComponent, alignBottom, omitPadding } from '../utils/schema.js'
35
35
  import { parseFraction } from '../utils/math.js'
36
36
 
37
37
  // @vue/component
@@ -64,11 +64,12 @@ export default DitoComponent.component('DitoContainer', {
64
64
  },
65
65
 
66
66
  hasLabel() {
67
- const { schema } = this
68
- const { label } = schema
67
+ const { label } = this.schema
69
68
  return (
70
- label !== false &&
71
- (!!label || this.typeComponent?.generateLabel && this.generateLabels)
69
+ label !== false && (
70
+ !!label ||
71
+ this.generateLabels && this.typeComponent?.generateLabel
72
+ )
72
73
  )
73
74
  },
74
75
 
@@ -122,9 +123,12 @@ export default DitoComponent.component('DitoContainer', {
122
123
 
123
124
  containerClass() {
124
125
  const { class: containerClass } = this.schema
126
+ const prefix = 'dito-container'
125
127
  return {
126
- 'dito-single': this.single,
127
- 'dito-omit-padding': shouldOmitPadding(this.schema),
128
+ [`${prefix}--single`]: this.single,
129
+ [`${prefix}--has-label`]: this.hasLabel,
130
+ [`${prefix}--align-bottom`]: alignBottom(this.schema),
131
+ [`${prefix}--omit-padding`]: omitPadding(this.schema),
128
132
  ...(
129
133
  isString(containerClass)
130
134
  ? { [containerClass]: true }
@@ -162,6 +166,7 @@ export default DitoComponent.component('DitoContainer', {
162
166
  componentClass() {
163
167
  const basisIsAuto = this.componentBasis === 'auto'
164
168
  return {
169
+ // TODO: BEM
165
170
  'dito-single': this.single,
166
171
  'dito-disabled': this.componentDisabled,
167
172
  'dito-width-fill': !basisIsAuto || this.componentWidth === 'fill',
@@ -183,6 +188,8 @@ export default DitoComponent.component('DitoContainer', {
183
188
  @import '../styles/_imports';
184
189
 
185
190
  .dito-container {
191
+ display: flex;
192
+ flex-flow: column;
186
193
  // Needed for better vertical alignment:
187
194
  align-self: stretch;
188
195
  box-sizing: border-box;
@@ -196,7 +203,11 @@ export default DitoComponent.component('DitoContainer', {
196
203
  padding: 0;
197
204
  }
198
205
 
199
- &.dito-omit-padding {
206
+ &--align-bottom {
207
+ justify-content: end; // To align components with and without labels.
208
+ }
209
+
210
+ &--omit-padding {
200
211
  padding: 0;
201
212
 
202
213
  > .dito-label {
@@ -204,7 +215,7 @@ export default DitoComponent.component('DitoContainer', {
204
215
  }
205
216
  }
206
217
 
207
- &.dito-single {
218
+ &--single {
208
219
  height: 100%; // So that list buttons can be sticky at the bottom;
209
220
  }
210
221
  }
@@ -14,8 +14,9 @@
14
14
  v-for="(form, type) in forms"
15
15
  )
16
16
  a(
17
- v-if="isCreatable(form)"
18
- :class="`dito-type-${type}`"
17
+ v-if="shouldRender(form)"
18
+ v-show="shouldShow(form)"
19
+ :class="getFormClass(form, type)"
19
20
  @mousedown.stop="onPulldownMouseDown(type)"
20
21
  @mouseup="onPulldownMouseUp(type)"
21
22
  ) {{ getLabel(form) }}
@@ -59,13 +60,8 @@ export default DitoComponent.component('DitoCreateButton', {
59
60
  },
60
61
 
61
62
  methods: {
62
- isCreatable(form) {
63
- // Forms can be excluded from the list by providing `creatable: false`
64
- return form.creatable !== false
65
- },
66
-
67
63
  createItem(form, type = null) {
68
- if (this.isCreatable(form)) {
64
+ if (this.shouldRender(form) && !this.shouldDisable(form)) {
69
65
  if (this.isInlined) {
70
66
  this.sourceComponent.createItem(form, type)
71
67
  } else {
@@ -79,6 +75,13 @@ export default DitoComponent.component('DitoCreateButton', {
79
75
  }
80
76
  },
81
77
 
78
+ getFormClass(form, type) {
79
+ return {
80
+ [`dito-type-${type}`]: true,
81
+ 'dito-disabled': this.shouldDisable(form)
82
+ }
83
+ },
84
+
82
85
  onPulldownSelect(type) {
83
86
  this.createItem(this.forms[type], type)
84
87
  this.setPulldownOpen(false)
@@ -0,0 +1,45 @@
1
+ <template lang="pug">
2
+ UseSortable(
3
+ v-if="draggable"
4
+ :tag="tag"
5
+ :modelValue="modelValue"
6
+ :options="options"
7
+ @update:modelValue="$emit('update:modelValue', $event)"
8
+ )
9
+ slot
10
+ component(
11
+ v-else
12
+ :is="tag"
13
+ )
14
+ slot
15
+ </template>
16
+
17
+ <script>
18
+ import DitoComponent from '../DitoComponent'
19
+ import { UseSortable } from '@vueuse/integrations/useSortable/component'
20
+
21
+ // @vue/component
22
+ export default DitoComponent.component('DitoDraggable', {
23
+ components: { UseSortable },
24
+ emits: ['update:modelValue'],
25
+
26
+ props: {
27
+ modelValue: {
28
+ type: Array,
29
+ required: true
30
+ },
31
+ tag: {
32
+ type: String,
33
+ default: 'div'
34
+ },
35
+ options: {
36
+ type: Object,
37
+ required: true
38
+ },
39
+ draggable: {
40
+ type: Boolean,
41
+ default: true
42
+ }
43
+ }
44
+ })
45
+ </script>
@@ -162,7 +162,7 @@ export default DitoComponent.component('DitoPane', {
162
162
  margin-top: 0;
163
163
  }
164
164
 
165
- .dito-container.dito-omit-padding > & {
165
+ .dito-container--omit-padding > & {
166
166
  // Clear margins set above again if parent is omitting padding.
167
167
  margin: 0;
168
168
  max-width: unset;
@@ -121,7 +121,7 @@ export default DitoComponent.component('DitoPanel', {
121
121
  const { data } = this.schema
122
122
  if (data) {
123
123
  this.ownData = isFunction(data)
124
- ? data.call(this, this.context)
124
+ ? data(this.context)
125
125
  : data
126
126
  }
127
127
  },
@@ -142,7 +142,7 @@ export default DitoComponent.component('DitoSchema', {
142
142
  // Allow schema to provide more data through `schema.data`, vue-style:
143
143
  ...(
144
144
  data && isFunction(data)
145
- ? data.call(this, this.context)
145
+ ? data(this.context)
146
146
  : data
147
147
  ),
148
148
  componentsRegistry: {},
@@ -197,7 +197,7 @@ export default DitoComponent.component('DitoSchema', {
197
197
  const { defaultTab } = tab
198
198
  if (
199
199
  isFunction(defaultTab)
200
- ? defaultTab.call(this, this.context)
200
+ ? defaultTab(this.context)
201
201
  : defaultTab
202
202
  ) {
203
203
  return tab
@@ -214,6 +214,11 @@ export default DitoComponent.component('DitoSchema', {
214
214
  return this.schema?.clipboard
215
215
  },
216
216
 
217
+ parentData() {
218
+ const data = getParentItem(this.rootData, this.dataPath, false)
219
+ return data !== this.data ? data : null
220
+ },
221
+
217
222
  processedData() {
218
223
  return this.processData({ target: 'server', schemaOnly: true })
219
224
  },
@@ -235,6 +240,10 @@ export default DitoComponent.component('DitoSchema', {
235
240
  return this.data
236
241
  },
237
242
 
243
+ parentItem() {
244
+ return this.parentData
245
+ },
246
+
238
247
  rootItem() {
239
248
  return this.rootData
240
249
  },
@@ -247,10 +256,6 @@ export default DitoComponent.component('DitoSchema', {
247
256
  return this.clipboardData
248
257
  },
249
258
 
250
- parentItem() {
251
- return getParentItem(this.rootData, this.dataPath, false)
252
- },
253
-
254
259
  formLabel() {
255
260
  return this.getLabel(
256
261
  this.getItemFormSchema(this.sourceSchema, this.data, this.context)
@@ -10,6 +10,7 @@ DitoSchema.dito-schema-inlined(
10
10
  :disabled="disabled"
11
11
  :collapsed="collapsed"
12
12
  :collapsible="collapsible"
13
+ :generateLabels="!isCompact"
13
14
  :class="{ 'dito-schema-compact': isCompact }"
14
15
  )
15
16
  //- Render dito-edit-buttons for inlined schemas separately from all
@@ -72,11 +72,12 @@
72
72
  :store="store"
73
73
  :disabled="disabled"
74
74
  )
75
- UseSortable(
75
+ DitoDraggable(
76
76
  v-if="childrenSchema"
77
77
  v-show="opened"
78
78
  :modelValue="updateOrder(childrenSchema, childrenList)"
79
- :options="getSortableOptions(childrenDraggable, true)"
79
+ :options="getSortableOptions(true)"
80
+ :draggable="childrenDraggable"
80
81
  @update:modelValue="value => (childrenList = value)"
81
82
  )
82
83
  DitoTreeItem(
@@ -30,4 +30,5 @@ export { default as DitoPagination } from './DitoPagination.vue'
30
30
  export { default as DitoTreeItem } from './DitoTreeItem.vue'
31
31
  export { default as DitoTableHead } from './DitoTableHead.vue'
32
32
  export { default as DitoTableCell } from './DitoTableCell.vue'
33
+ export { default as DitoDraggable } from './DitoDraggable.vue'
33
34
  export { default as DitoVNode } from './DitoVNode.vue'
@@ -38,7 +38,7 @@ export default {
38
38
  // If the data callback provided a dependency function when it was called,
39
39
  // cal it in every call of `handleDataSchema()` to force Vue to keep track
40
40
  // of the async dependencies.
41
- asyncEntry.dependencyFunction?.call(this, this.context)
41
+ asyncEntry.dependencyFunction?.(this.context)
42
42
 
43
43
  if (asyncEntry.resolveCounter > 0) {
44
44
  // If the data was resolved already, return it and clear the value once
@@ -59,7 +59,7 @@ export default {
59
59
  data = null
60
60
  } else if (data) {
61
61
  if (isFunction(data)) {
62
- const result = data.call(this, this.context)
62
+ const result = data(this.context)
63
63
  // If the result of the data function is another function, then the
64
64
  // first data function is there to track dependencies and the real
65
65
  // data loading happens in the function that it returned. Keep track
@@ -68,7 +68,7 @@ export default {
68
68
  // the function that it returned once to get the actual data:
69
69
  if (isFunction(result)) {
70
70
  asyncEntry.dependencyFunction = data
71
- data = result.call(this, this.context)
71
+ data = result(this.context)
72
72
  } else {
73
73
  data = result
74
74
  }
@@ -213,7 +213,7 @@ export default {
213
213
  if (value === undefined && def !== undefined) {
214
214
  if (callback && isFunction(def) && !isMatchingType(types, def)) {
215
215
  // Support `default()` functions for any type except `Function`:
216
- def = def.call(this, this.context)
216
+ def = def.call(this)
217
217
  }
218
218
  return def
219
219
  }
@@ -224,7 +224,7 @@ export default {
224
224
  // Any schema value handled through `getSchemaValue()` can provide
225
225
  // a function that's resolved when the value is evaluated:
226
226
  if (callback && isFunction(value)) {
227
- value = value.call(this, this.context)
227
+ value = value(this.context)
228
228
  }
229
229
  // Now finally see if we can convert to the expect types.
230
230
  if (types && value != null && !isMatchingType(types, value)) {
@@ -265,14 +265,27 @@ export default {
265
265
  },
266
266
 
267
267
  shouldRender(schema = null) {
268
- return (
269
- !!schema &&
270
- this.getSchemaValue('if', {
271
- type: Boolean,
272
- default: true,
273
- schema
274
- })
275
- )
268
+ return this.getSchemaValue('if', {
269
+ type: Boolean,
270
+ default: true,
271
+ schema
272
+ })
273
+ },
274
+
275
+ shouldShow(schema = null) {
276
+ return this.getSchemaValue('visible', {
277
+ type: Boolean,
278
+ default: true,
279
+ schema
280
+ })
281
+ },
282
+
283
+ shouldDisable(schema = null) {
284
+ return this.getSchemaValue('disabled', {
285
+ type: Boolean,
286
+ default: false,
287
+ schema
288
+ })
276
289
  },
277
290
 
278
291
  getResourcePath(resource) {
@@ -69,7 +69,7 @@ export default {
69
69
  },
70
70
 
71
71
  meta() {
72
- return this.routeRecord.meta
72
+ return this.routeRecord?.meta
73
73
  },
74
74
 
75
75
  path() {
@@ -1,10 +1,8 @@
1
1
  import ItemMixin from './ItemMixin.js'
2
- import { UseSortable } from '@vueuse/integrations/useSortable/component'
3
2
 
4
3
  // @vue/component
5
4
  export default {
6
5
  mixins: [ItemMixin],
7
- components: { UseSortable },
8
6
 
9
7
  data() {
10
8
  return {
@@ -13,17 +11,15 @@ export default {
13
11
  },
14
12
 
15
13
  methods: {
16
- getSortableOptions(draggable, fallback = false) {
14
+ getSortableOptions(forceFallback = false) {
17
15
  return {
18
16
  animation: 150,
19
- // TODO: This is broken in VueSortable, always enable it for now.
20
- // disabled: !draggable,
21
17
  handle: '.dito-button-drag',
22
18
  dragClass: 'dito-sortable-active',
23
19
  chosenClass: 'dito-sortable-chosen',
24
20
  ghostClass: 'dito-sortable-ghost',
25
21
  fallbackClass: 'dito-sortable-fallback',
26
- forceFallback: fallback,
22
+ forceFallback,
27
23
  onStart: this.onStartDrag,
28
24
  onEnd: this.onEndDrag
29
25
  }
@@ -11,7 +11,6 @@ import {
11
11
  hasFormSchema,
12
12
  getFormSchemas,
13
13
  getViewSchema,
14
- hasLabels,
15
14
  isCompact,
16
15
  isInlined,
17
16
  isObjectSource,
@@ -249,10 +248,6 @@ export default {
249
248
  return getButtonSchemas(this.schema.buttons)
250
249
  },
251
250
 
252
- hasLabels() {
253
- return this.forms.some(hasLabels)
254
- },
255
-
256
251
  isCompact() {
257
252
  return this.forms.every(isCompact)
258
253
  },
@@ -71,14 +71,32 @@ export default {
71
71
  }
72
72
  },
73
73
 
74
+ parentData() {
75
+ const data = getParentItem(this.rootData, this.dataPath, this.nested)
76
+ return data !== this.data ? data : null
77
+ },
78
+
79
+ processedData() {
80
+ // We can only get the processed data through the schemaComponent, but
81
+ // that's not necessarily the item represented by this component.
82
+ // Solution: Find the relative path and the processed sub-item from there:
83
+ const { schemaComponent } = this
84
+ return getItem(
85
+ schemaComponent.processedData,
86
+ // Get the dataPath relative to the schemaComponent's data:
87
+ this.dataPath.slice(schemaComponent.dataPath.length),
88
+ this.nested
89
+ )
90
+ },
91
+
74
92
  // The following computed properties are similar to `DitoContext`
75
93
  // properties, so that we can access these on `this` as well:
76
94
  item() {
77
- return getItem(this.rootItem, this.dataPath, this.nested)
95
+ return this.data
78
96
  },
79
97
 
80
98
  parentItem() {
81
- return getParentItem(this.rootItem, this.dataPath, this.nested)
99
+ return this.parentData
82
100
  },
83
101
 
84
102
  rootItem() {
@@ -86,16 +104,7 @@ export default {
86
104
  },
87
105
 
88
106
  processedItem() {
89
- // We can only get the processed items through the schemaComponent, but
90
- // that's not necessarily the item represented by this component.
91
- // Solution: Find the relative path and the processed sub-item from there:
92
- const { schemaComponent } = this
93
- return getItem(
94
- schemaComponent.processedItem,
95
- // Get the dataPath relative to the schemaComponent's data:
96
- this.dataPath.slice(schemaComponent.dataPath.length),
97
- this.nested
98
- )
107
+ return this.processedData
99
108
  },
100
109
 
101
110
  label: getSchemaAccessor('label', {
@@ -120,7 +129,7 @@ export default {
120
129
  }
121
130
  }),
122
131
 
123
- // TODO: Rename to `excluded` for consistent naming
132
+ // TODO: Rename to `excluded` for consistent naming?
124
133
  exclude: getSchemaAccessor('exclude', {
125
134
  type: Boolean,
126
135
  default: false
@@ -1,3 +1,5 @@
1
+ @import '../styles/_imports';
2
+
1
3
  ul.dito-pulldown {
2
4
  display: none;
3
5
  position: absolute;
@@ -5,6 +7,7 @@ ul.dito-pulldown {
5
7
  z-index: 1000;
6
8
  border-radius: $pulldown-radius;
7
9
  box-shadow: $shadow-window;
10
+ overflow: hidden;
8
11
 
9
12
  &.dito-open {
10
13
  display: block;
@@ -15,25 +18,19 @@ ul.dito-pulldown {
15
18
 
16
19
  a {
17
20
  display: block;
18
- text-align: center;
19
21
  padding: $pulldown-padding;
20
22
  line-height: 1;
21
23
  background: $button-color;
22
24
 
23
- &:hover {
25
+ &.dito-disabled {
26
+ color: $color-disabled;
27
+ cursor: default;
28
+ }
29
+
30
+ &:not(.dito-disabled):hover {
24
31
  background: $color-active;
25
32
  color: $color-white;
26
33
  }
27
34
  }
28
-
29
- &:first-child a {
30
- border-top-left-radius: $pulldown-radius;
31
- border-top-right-radius: $pulldown-radius;
32
- }
33
-
34
- &:last-child a {
35
- border-bottom-left-radius: $pulldown-radius;
36
- border-bottom-right-radius: $pulldown-radius;
37
- }
38
35
  }
39
36
  }
@@ -4,7 +4,7 @@ button.dito-button(
4
4
  ref="element"
5
5
  :type="type"
6
6
  :title="text"
7
- :class="`dito-button-${verb}`"
7
+ :class="buttonClass"
8
8
  v-bind="attributes"
9
9
  ) {{ text }}
10
10
  </template>
@@ -21,13 +21,16 @@ export default DitoTypeComponent.register(
21
21
  {
22
22
  defaultValue: () => undefined, // Callback to override `defaultValue: null`
23
23
  excludeValue: true,
24
+ generateLabel: false,
24
25
  defaultWidth: 'auto',
25
- // TODO: Consider making this work nicely:
26
- // omitFlexGrow: true,
27
26
 
28
27
  computed: {
29
28
  verb() {
30
- return this.verbs[this.name] || this.name
29
+ return this.verbs[this.name]
30
+ },
31
+
32
+ buttonClass() {
33
+ return this.verb ? `dito-button-${this.verb}` : null
31
34
  },
32
35
 
33
36
  text: getSchemaAccessor('text', {
@@ -14,6 +14,7 @@ import CodeFlask from 'codeflask'
14
14
  // @vue/component
15
15
  export default DitoTypeComponent.register('code', {
16
16
  mixins: [DomMixin],
17
+ alignBottom: false,
17
18
 
18
19
  computed: {
19
20
  lines() {
@@ -22,6 +22,7 @@ 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
+ alignBottom: false,
25
26
  ignoreMissingValue: schema => !('default' in schema),
26
27
 
27
28
  async processSchema(api, schema) {
@@ -11,7 +11,8 @@ import DitoTypeComponent from '../DitoTypeComponent.js'
11
11
  // @vue/component
12
12
  export default DitoTypeComponent.register('label', {
13
13
  excludeValue: true,
14
- generateLabel: false
14
+ generateLabel: false,
15
+ alignBottom: false
15
16
  })
16
17
  </script>
17
18