@ditojs/admin 3.2.4 → 3.2.6
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/dist/dito-admin.css +1 -1
- package/dist/dito-admin.es.js +1202 -1093
- package/dist/dito-admin.umd.js +5 -5
- package/package.json +5 -5
- package/src/DitoAdmin.js +4 -3
- package/src/components/DitoButtons.vue +4 -5
- package/src/components/DitoCreateButton.vue +1 -0
- package/src/components/DitoDialog.vue +17 -16
- package/src/components/DitoForm.vue +1 -3
- package/src/components/DitoLabel.vue +1 -0
- package/src/components/DitoPane.vue +1 -0
- package/src/components/DitoPanel.vue +2 -0
- package/src/components/DitoSchema.vue +1 -0
- package/src/components/DitoTreeItem.vue +52 -2
- package/src/mixins/DitoMixin.js +13 -15
- package/src/mixins/OptionsMixin.js +15 -1
- package/src/mixins/ResourceMixin.js +22 -3
- package/src/styles/_button.scss +45 -46
- package/src/types/DitoTypeCode.vue +6 -3
- package/src/types/DitoTypeMarkup.vue +1 -0
- package/src/types/DitoTypeMultiselect.vue +61 -16
- package/src/types/DitoTypeTreeList.vue +2 -0
- package/src/utils/DataModel.js +100 -15
- package/src/utils/DataSchemaResolver.js +1 -1
- package/src/utils/options.js +2 -2
- package/src/utils/schema/data.js +12 -1
- package/types/index.d.ts +3 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/admin",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.6",
|
|
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",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"not ie_mob > 0"
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@ditojs/ui": "^3.2.
|
|
45
|
-
"@ditojs/utils": "^3.2.
|
|
44
|
+
"@ditojs/ui": "^3.2.6",
|
|
45
|
+
"@ditojs/utils": "^3.2.6"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@kyvg/vue3-notification": "^3.4.2",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"vue-upload-component": "^3.2.2"
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
|
-
"@ditojs/build": "^3.2.
|
|
90
|
+
"@ditojs/build": "^3.2.6",
|
|
91
91
|
"@kyvg/vue3-notification": "^3.4.2",
|
|
92
92
|
"@tiptap/core": "^3.31.4",
|
|
93
93
|
"@tiptap/extension-blockquote": "^3.31.4",
|
|
@@ -131,5 +131,5 @@
|
|
|
131
131
|
"vue-router": "^5.3.1",
|
|
132
132
|
"vue-upload-component": "^3.2.2"
|
|
133
133
|
},
|
|
134
|
-
"gitHead": "
|
|
134
|
+
"gitHead": "d9868ae96d60a70b5e7ba89a5fc91e07b267a0d5"
|
|
135
135
|
}
|
package/src/DitoAdmin.js
CHANGED
|
@@ -150,9 +150,10 @@ export default class DitoAdmin {
|
|
|
150
150
|
components: {
|
|
151
151
|
DitoRoot,
|
|
152
152
|
VueNotifications,
|
|
153
|
-
//
|
|
154
|
-
//
|
|
155
|
-
//
|
|
153
|
+
// Registered globally too, so that the custom components of apps can
|
|
154
|
+
// use them in their templates: Unlike the admin's own components, they
|
|
155
|
+
// don't extend `DitoComponent`, which shares its registry. This also
|
|
156
|
+
// keeps the modules from being tree-shaken.
|
|
156
157
|
...components,
|
|
157
158
|
...types
|
|
158
159
|
},
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
template(
|
|
6
6
|
v-for="(buttonSchema, buttonDataPath) in buttonSchemas"
|
|
7
7
|
)
|
|
8
|
-
DitoContainer(
|
|
8
|
+
DitoContainer.dito-buttons__container(
|
|
9
9
|
v-if="shouldRenderSchema(buttonSchema)"
|
|
10
10
|
:key="buttonDataPath"
|
|
11
11
|
:schema="buttonSchema"
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
)
|
|
22
22
|
//- Render each node in the default slot through `dito-vnode`,
|
|
23
23
|
//- so it can be wrapped in a `.dito-container` class.
|
|
24
|
-
.dito-container(
|
|
24
|
+
.dito-container.dito-buttons__container(
|
|
25
25
|
v-if="hasVNodeContent(vnode)"
|
|
26
26
|
)
|
|
27
27
|
DitoVnode(:vnode="vnode")
|
|
@@ -86,8 +86,7 @@ export default DitoComponent.component('DitoButtons', {
|
|
|
86
86
|
|
|
87
87
|
<style lang="scss">
|
|
88
88
|
.dito-buttons {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
89
|
+
// The containers of the buttons don't add padding around them.
|
|
90
|
+
--container-padding: 0px;
|
|
92
91
|
}
|
|
93
92
|
</style>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
@mouseup="onMouseUp"
|
|
9
9
|
)
|
|
10
10
|
UseFocusTrap.dito-dialog__focus-trap(:options="focusTrapOptions")
|
|
11
|
-
form.dito-scroll-parent(
|
|
11
|
+
form.dito-dialog__form.dito-scroll-parent(
|
|
12
12
|
@submit.prevent="submit"
|
|
13
13
|
@keydown.enter="onEnter"
|
|
14
14
|
)
|
|
@@ -182,7 +182,7 @@ export default DitoComponent.component('DitoDialog', {
|
|
|
182
182
|
|
|
183
183
|
async submit() {
|
|
184
184
|
// Wait for computed values that depend on pending loads, e.g. options.
|
|
185
|
-
await this.
|
|
185
|
+
await this.waitUntilDataModelSettled()
|
|
186
186
|
this.resolve(this.dialogData)
|
|
187
187
|
},
|
|
188
188
|
|
|
@@ -209,6 +209,8 @@ export default DitoComponent.component('DitoDialog', {
|
|
|
209
209
|
@import '../styles/_imports';
|
|
210
210
|
|
|
211
211
|
.dito-dialog {
|
|
212
|
+
$self: &;
|
|
213
|
+
|
|
212
214
|
position: fixed;
|
|
213
215
|
display: flex;
|
|
214
216
|
inset: 0;
|
|
@@ -231,8 +233,7 @@ export default DitoComponent.component('DitoDialog', {
|
|
|
231
233
|
order: -1;
|
|
232
234
|
}
|
|
233
235
|
|
|
234
|
-
|
|
235
|
-
form {
|
|
236
|
+
&__form {
|
|
236
237
|
position: relative;
|
|
237
238
|
display: flex;
|
|
238
239
|
box-sizing: border-box;
|
|
@@ -242,23 +243,23 @@ export default DitoComponent.component('DitoDialog', {
|
|
|
242
243
|
max-height: 100%;
|
|
243
244
|
box-shadow: 0 20px 60px -2px rgb(27, 33, 58, 0.4);
|
|
244
245
|
}
|
|
245
|
-
}
|
|
246
246
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
247
|
+
&-enter-active,
|
|
248
|
+
&-leave-active {
|
|
249
|
+
transition: opacity 0.15s;
|
|
250
250
|
|
|
251
|
-
|
|
252
|
-
|
|
251
|
+
#{$self}__form {
|
|
252
|
+
transition: transform 0.25s;
|
|
253
|
+
}
|
|
253
254
|
}
|
|
254
|
-
}
|
|
255
255
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
256
|
+
&-enter-from,
|
|
257
|
+
&-leave-to {
|
|
258
|
+
opacity: 0;
|
|
259
259
|
|
|
260
|
-
|
|
261
|
-
|
|
260
|
+
#{$self}__form {
|
|
261
|
+
transform: translateY(-20px);
|
|
262
|
+
}
|
|
262
263
|
}
|
|
263
264
|
}
|
|
264
265
|
</style>
|
|
@@ -311,8 +311,6 @@ export default DitoComponent.component('DitoForm', {
|
|
|
311
311
|
if (
|
|
312
312
|
param &&
|
|
313
313
|
this.providesData &&
|
|
314
|
-
// TODO: See if we can remove this due to `flush: 'post'`.
|
|
315
|
-
from.matched[0].path === to.matched[0].path && // Staying on same form
|
|
316
314
|
from.params[param] !== 'create' && // But haven't been creating
|
|
317
315
|
to.params[param] !== from.params[param] // Going to a different entity
|
|
318
316
|
) {
|
|
@@ -465,7 +463,7 @@ export default DitoComponent.component('DitoForm', {
|
|
|
465
463
|
|
|
466
464
|
async submit(button, { validate = true, closeForm = false } = {}) {
|
|
467
465
|
// Wait for computed values that depend on pending loads, e.g. options.
|
|
468
|
-
await this.
|
|
466
|
+
await this.waitUntilDataModelSettled()
|
|
469
467
|
if (validate && !this.validateAll()) {
|
|
470
468
|
return false
|
|
471
469
|
}
|
|
@@ -152,6 +152,7 @@ export default DitoComponent.component('DitoLabel', {
|
|
|
152
152
|
transform: translateY(-4px);
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
// TODO: BEM: Style an element class of this block, e.g. `&__buttons`.
|
|
155
156
|
.dito-buttons {
|
|
156
157
|
// Move the label padding inside .dito-buttons, so that it captures all
|
|
157
158
|
// near mouse events:
|
|
@@ -349,6 +349,7 @@ export default DitoComponent.component('DitoPane', {
|
|
|
349
349
|
}
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
+
// TODO: BEM: Style an element class of this block, e.g. `&__buttons`.
|
|
352
353
|
&__main + .dito-buttons--main {
|
|
353
354
|
// Needed forms with sticky main buttons.
|
|
354
355
|
margin: $content-padding;
|
|
@@ -244,6 +244,7 @@ export default DitoComponent.component('DitoPanel', {
|
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
+
// TODO: BEM: Style an element class of this block, e.g. `&__buttons`.
|
|
247
248
|
.dito-buttons {
|
|
248
249
|
position: absolute;
|
|
249
250
|
right: $input-padding-ver;
|
|
@@ -266,6 +267,7 @@ export default DitoComponent.component('DitoPanel', {
|
|
|
266
267
|
padding: 0;
|
|
267
268
|
}
|
|
268
269
|
|
|
270
|
+
// TODO: BEM: Style an element class of this block, e.g. `&__buttons`.
|
|
269
271
|
> .dito-buttons {
|
|
270
272
|
--button-margin: #{$form-spacing};
|
|
271
273
|
|
|
@@ -97,6 +97,7 @@
|
|
|
97
97
|
:draggable="childrenDraggable"
|
|
98
98
|
:label="getItemLabel(childrenSchema, item.data, { index })"
|
|
99
99
|
:level="level + 1"
|
|
100
|
+
@delete="deleteChild(index)"
|
|
100
101
|
)
|
|
101
102
|
//- TODO: Convert dito-tree-item to use dito-label internally, and then
|
|
102
103
|
//- pass `asObject: true` in the `getItemLabel()` call above.
|
|
@@ -115,7 +116,7 @@ import { stripHtml } from '@ditojs/utils'
|
|
|
115
116
|
// @vue/component
|
|
116
117
|
export default DitoComponent.component('DitoTreeItem', {
|
|
117
118
|
mixins: [ItemMixin, SortableMixin],
|
|
118
|
-
emits: ['update:data'],
|
|
119
|
+
emits: ['update:data', 'delete'],
|
|
119
120
|
inject: ['container'],
|
|
120
121
|
|
|
121
122
|
props: {
|
|
@@ -302,8 +303,56 @@ export default DitoComponent.component('DitoTreeItem', {
|
|
|
302
303
|
this.editPath(this.path)
|
|
303
304
|
},
|
|
304
305
|
|
|
306
|
+
// Items are removed from the children of their parent, see
|
|
307
|
+
// `deleteChild()`.
|
|
305
308
|
onDelete() {
|
|
306
|
-
|
|
309
|
+
this.$emit('delete')
|
|
310
|
+
},
|
|
311
|
+
|
|
312
|
+
// Removes the child after confirming it, like inlined lists do. Open forms
|
|
313
|
+
// of the child or of its later siblings are closed, as the removal shifts
|
|
314
|
+
// the indices in their paths. The removal is transient, as the tree is
|
|
315
|
+
// part of its form's data.
|
|
316
|
+
deleteChild(index) {
|
|
317
|
+
const { childrenSchema, container } = this
|
|
318
|
+
const item = this.childrenList[index]
|
|
319
|
+
const label = this.getItemLabel(childrenSchema, item, {
|
|
320
|
+
index,
|
|
321
|
+
extended: true
|
|
322
|
+
})
|
|
323
|
+
if (
|
|
324
|
+
window.confirm(`Do you really want to ${this.verbs.delete} ${label}?`)
|
|
325
|
+
) {
|
|
326
|
+
if (this.isEditingChildFrom(index)) {
|
|
327
|
+
this.$router.push({
|
|
328
|
+
path: container.path,
|
|
329
|
+
query: this.$route.query
|
|
330
|
+
})
|
|
331
|
+
}
|
|
332
|
+
this.childrenList = this.childrenList.toSpliced(index, 1)
|
|
333
|
+
this.onChange()
|
|
334
|
+
this.notify({
|
|
335
|
+
type: 'info',
|
|
336
|
+
title: 'Successfully Removed',
|
|
337
|
+
text: [`${label} was ${this.verbs.deleted}.`, container.transientNote]
|
|
338
|
+
})
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
|
|
342
|
+
// Returns whether the form of a child at the index or after it is open,
|
|
343
|
+
// or the form of one of their own children.
|
|
344
|
+
isEditingChildFrom(index) {
|
|
345
|
+
const childrenPath = this.childrenSchema.path
|
|
346
|
+
if (!childrenPath) {
|
|
347
|
+
return false
|
|
348
|
+
}
|
|
349
|
+
const prefix = `${this.path}/${childrenPath}/`
|
|
350
|
+
const { editPath } = this.container
|
|
351
|
+
if (!editPath.startsWith(prefix)) {
|
|
352
|
+
return false
|
|
353
|
+
}
|
|
354
|
+
const [childIndex] = editPath.slice(prefix.length).split('/')
|
|
355
|
+
return Number(childIndex) >= index
|
|
307
356
|
},
|
|
308
357
|
|
|
309
358
|
onChange() {
|
|
@@ -391,6 +440,7 @@ export default DitoComponent.component('DitoTreeItem', {
|
|
|
391
440
|
color: rgba($color-black, 0.2);
|
|
392
441
|
}
|
|
393
442
|
|
|
443
|
+
// TODO: BEM: Style an element class of this block, e.g. `&__buttons`.
|
|
394
444
|
.dito-buttons {
|
|
395
445
|
flex: auto;
|
|
396
446
|
display: flex;
|
package/src/mixins/DitoMixin.js
CHANGED
|
@@ -497,17 +497,6 @@ export default {
|
|
|
497
497
|
: parentComponentPath
|
|
498
498
|
},
|
|
499
499
|
|
|
500
|
-
// Waits for the pending loads of the data model, e.g. before submitting,
|
|
501
|
-
// showing the spinner in the header in the meantime, like requests do.
|
|
502
|
-
async waitForPendingLoadsOf(dataModel) {
|
|
503
|
-
this.rootComponent.registerLoading(true)
|
|
504
|
-
try {
|
|
505
|
-
await dataModel.waitForPendingLoads()
|
|
506
|
-
} finally {
|
|
507
|
-
this.rootComponent.registerLoading(false)
|
|
508
|
-
}
|
|
509
|
-
},
|
|
510
|
-
|
|
511
500
|
notify(options) {
|
|
512
501
|
this.rootComponent.notify(options)
|
|
513
502
|
},
|
|
@@ -626,16 +615,25 @@ export default {
|
|
|
626
615
|
// data changes register, e.g. for `processedItem`, and the form
|
|
627
616
|
// model writes the values that it derives from the data.
|
|
628
617
|
// NOTE: The result of `handleListeners()` is returned as expected.
|
|
629
|
-
this.
|
|
618
|
+
this.waitUntilDataModelSettled().then(handleListeners)
|
|
630
619
|
: handleListeners()
|
|
631
620
|
}
|
|
632
621
|
},
|
|
633
622
|
|
|
634
623
|
// Waits until the data model settled: its loads finished, and it wrote the
|
|
635
|
-
// values that it derives from the data.
|
|
636
|
-
|
|
624
|
+
// values that it derives from the data, e.g. before submitting. Shows the
|
|
625
|
+
// spinner in the header while loads are pending, like requests do.
|
|
626
|
+
async waitUntilDataModelSettled() {
|
|
637
627
|
await this.$nextTick()
|
|
638
|
-
|
|
628
|
+
const { dataModel } = this
|
|
629
|
+
if (dataModel?.hasPendingLoads) {
|
|
630
|
+
this.rootComponent.registerLoading(true)
|
|
631
|
+
try {
|
|
632
|
+
await dataModel.waitUntilSettled()
|
|
633
|
+
} finally {
|
|
634
|
+
this.rootComponent.registerLoading(false)
|
|
635
|
+
}
|
|
636
|
+
}
|
|
639
637
|
},
|
|
640
638
|
|
|
641
639
|
emitSchemaEvent(event, params) {
|
|
@@ -5,6 +5,7 @@ import { getMultipleValue } from '../utils/schema/data.js'
|
|
|
5
5
|
import { getSchemaAccessor } from '../utils/accessor.js'
|
|
6
6
|
import { setTemporaryId, isReference } from '../utils/data.js'
|
|
7
7
|
import {
|
|
8
|
+
asArray,
|
|
8
9
|
isObject,
|
|
9
10
|
isArray,
|
|
10
11
|
isString,
|
|
@@ -46,7 +47,12 @@ export default {
|
|
|
46
47
|
if (!this.relate) {
|
|
47
48
|
return value
|
|
48
49
|
}
|
|
49
|
-
|
|
50
|
+
// Keep related objects without options, see
|
|
51
|
+
// `DitoTypeMultiselect.getFallbackOption()`.
|
|
52
|
+
const option = (
|
|
53
|
+
this.getOptionForValue(value) ??
|
|
54
|
+
this.getRelatedObject(value)
|
|
55
|
+
)
|
|
50
56
|
if (this.shouldSetTemporaryId(option)) {
|
|
51
57
|
// Options without ids, e.g. new items of the edited data, get
|
|
52
58
|
// temporary ids when selected, so that the relation can reference
|
|
@@ -325,6 +331,14 @@ export default {
|
|
|
325
331
|
: value
|
|
326
332
|
},
|
|
327
333
|
|
|
334
|
+
// Returns the related object in the value with the given value of its
|
|
335
|
+
// option, e.g. its id.
|
|
336
|
+
getRelatedObject(value) {
|
|
337
|
+
return asArray(this.value).find(
|
|
338
|
+
object => this.getValueForOption(object) === value
|
|
339
|
+
)
|
|
340
|
+
},
|
|
341
|
+
|
|
328
342
|
getValueForOption(option) {
|
|
329
343
|
if (this.shouldSetTemporaryId(option)) {
|
|
330
344
|
// Until they're selected and get temporary ids, options without ids
|
|
@@ -26,6 +26,12 @@ export default {
|
|
|
26
26
|
},
|
|
27
27
|
|
|
28
28
|
computed: {
|
|
29
|
+
// Whether the component is part of a form, e.g. a list that loads its own
|
|
30
|
+
// data, unlike forms and the lists of views.
|
|
31
|
+
isInsideForm() {
|
|
32
|
+
return !this.isForm && !!this.formComponent
|
|
33
|
+
},
|
|
34
|
+
|
|
29
35
|
resourceComponent() {
|
|
30
36
|
return this
|
|
31
37
|
},
|
|
@@ -215,9 +221,15 @@ export default {
|
|
|
215
221
|
this.onFilterErrors?.(data.errors)
|
|
216
222
|
) {
|
|
217
223
|
return true
|
|
218
|
-
} else if (
|
|
219
|
-
|
|
220
|
-
|
|
224
|
+
} else if (
|
|
225
|
+
this.isUnauthorizedError(response) &&
|
|
226
|
+
this.isInsideForm
|
|
227
|
+
) {
|
|
228
|
+
// The user is logged in, see `sendRequest()`, but may not access
|
|
229
|
+
// the resource of a component in a form, e.g. a list that loads
|
|
230
|
+
// its own data. Show it on the component, as several components
|
|
231
|
+
// of the form may be affected. Others notify like for errors.
|
|
232
|
+
this.addUnauthorizedError()
|
|
221
233
|
return true
|
|
222
234
|
}
|
|
223
235
|
}
|
|
@@ -242,6 +254,13 @@ export default {
|
|
|
242
254
|
return response?.status === 401
|
|
243
255
|
},
|
|
244
256
|
|
|
257
|
+
addUnauthorizedError() {
|
|
258
|
+
const error = `You don't have permission to load this data.`
|
|
259
|
+
if (!this.errors?.includes(error)) {
|
|
260
|
+
this.addError(error)
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
|
|
245
264
|
async handleRequest(
|
|
246
265
|
{
|
|
247
266
|
method,
|
package/src/styles/_button.scss
CHANGED
|
@@ -109,10 +109,53 @@
|
|
|
109
109
|
cursor: grabbing;
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
+
|
|
113
|
+
.dito-buttons--large & {
|
|
114
|
+
border-radius: 2em;
|
|
115
|
+
padding: $button-round-padding;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Buttons in round and small button groups show icons instead of text.
|
|
119
|
+
// For now, nothing for create: &--create:empty::before
|
|
120
|
+
.dito-buttons--round &,
|
|
121
|
+
.dito-buttons--small & {
|
|
122
|
+
&--add:empty::before {
|
|
123
|
+
@extend %icon-add;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
&--upload:empty::before {
|
|
127
|
+
@extend %icon-upload;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&--delete:empty::before,
|
|
131
|
+
&--remove:empty::before {
|
|
132
|
+
@extend %icon-remove;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
&--edit:empty::before {
|
|
136
|
+
@extend %icon-edit;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
&--clear:empty::before {
|
|
140
|
+
@extend %icon-clear;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
&--drag:empty::before {
|
|
144
|
+
@extend %icon-drag;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
&--copy:empty::before {
|
|
148
|
+
@extend %icon-copy;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
&--paste:empty::before {
|
|
152
|
+
@extend %icon-paste;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
112
155
|
}
|
|
113
156
|
|
|
114
157
|
.dito-buttons {
|
|
115
|
-
|
|
158
|
+
$self: &;
|
|
116
159
|
|
|
117
160
|
&--large {
|
|
118
161
|
--button-margin: 3px;
|
|
@@ -122,15 +165,10 @@
|
|
|
122
165
|
justify-content: center;
|
|
123
166
|
padding-bottom: $content-padding;
|
|
124
167
|
|
|
125
|
-
|
|
168
|
+
#{$self}__container {
|
|
126
169
|
// Do not specify this on .dito-buttons directly as it would break borders
|
|
127
170
|
margin-top: $content-padding;
|
|
128
171
|
}
|
|
129
|
-
|
|
130
|
-
.dito-button {
|
|
131
|
-
border-radius: 2em;
|
|
132
|
-
padding: $button-round-padding;
|
|
133
|
-
}
|
|
134
172
|
}
|
|
135
173
|
|
|
136
174
|
&--main {
|
|
@@ -152,43 +190,4 @@
|
|
|
152
190
|
display: none;
|
|
153
191
|
}
|
|
154
192
|
}
|
|
155
|
-
|
|
156
|
-
&--round,
|
|
157
|
-
&--small {
|
|
158
|
-
// For now, nothing for create:
|
|
159
|
-
// .dito-button--create:empty::before
|
|
160
|
-
|
|
161
|
-
.dito-button--add:empty::before {
|
|
162
|
-
@extend %icon-add;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
.dito-button--upload:empty::before {
|
|
166
|
-
@extend %icon-upload;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
.dito-button--delete:empty::before,
|
|
170
|
-
.dito-button--remove:empty::before {
|
|
171
|
-
@extend %icon-remove;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
.dito-button--edit:empty::before {
|
|
175
|
-
@extend %icon-edit;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
.dito-button--clear:empty::before {
|
|
179
|
-
@extend %icon-clear;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
.dito-button--drag:empty::before {
|
|
183
|
-
@extend %icon-drag;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
.dito-button--copy:empty::before {
|
|
187
|
-
@extend %icon-copy;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
.dito-button--paste:empty::before {
|
|
191
|
-
@extend %icon-paste;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
193
|
}
|
|
@@ -47,10 +47,10 @@ export default DitoTypeComponent.register('code', {
|
|
|
47
47
|
default: false
|
|
48
48
|
}),
|
|
49
49
|
|
|
50
|
+
// The height of the lines is set through `--lines` and the styles, which
|
|
51
|
+
// add the padding, unless the editor was resized to a height of its own.
|
|
50
52
|
style() {
|
|
51
|
-
return {
|
|
52
|
-
height: this.height || `calc(${this.lines}em * var(--line-height))`
|
|
53
|
-
}
|
|
53
|
+
return this.height ? { height: this.height } : { '--lines': this.lines }
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
|
|
@@ -175,6 +175,9 @@ export default DitoTypeComponent.register('code', {
|
|
|
175
175
|
// For proper sizing of content along with :style="style" setting above,
|
|
176
176
|
// for proper line-height calculation.
|
|
177
177
|
padding: $input-padding;
|
|
178
|
+
height: calc(
|
|
179
|
+
var(--lines) * 1em * var(--line-height) + 2 * #{$input-padding-ver}
|
|
180
|
+
);
|
|
178
181
|
min-height: calc(1em * var(--line-height) + 2 * $input-padding-ver);
|
|
179
182
|
|
|
180
183
|
.codeflask {
|