@demos-europe/demosplan-ui 0.0.1

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 (133) hide show
  1. package/LICENSE +21 -0
  2. package/buildTokens.js +59 -0
  3. package/components/DpButton/DpButton.stories.mdx +136 -0
  4. package/components/DpButton/DpButton.vue +118 -0
  5. package/components/DpDetails/DpDetails.stories.mdx +55 -0
  6. package/components/DpDetails/DpDetails.vue +58 -0
  7. package/components/DpIcon/DpIcon.stories.mdx +396 -0
  8. package/components/DpIcon/DpIcon.vue +51 -0
  9. package/components/DpIcon/util/iconVariables.js +148 -0
  10. package/components/DpInput/DpInput.stories.mdx +127 -0
  11. package/components/DpInput/DpInput.vue +284 -0
  12. package/components/DpLabel/DpLabel.stories.mdx +103 -0
  13. package/components/DpLabel/DpLabel.vue +112 -0
  14. package/components/DpLoading/DpLoading.stories.mdx +63 -0
  15. package/components/DpLoading/DpLoading.vue +63 -0
  16. package/components/core/DpAccordion.vue +108 -0
  17. package/components/core/DpAnonymizeText.vue +136 -0
  18. package/components/core/DpAutocomplete.vue +133 -0
  19. package/components/core/DpBulkEditHeader.vue +53 -0
  20. package/components/core/DpButtonIcon.vue +47 -0
  21. package/components/core/DpButtonRow.vue +155 -0
  22. package/components/core/DpCard.vue +54 -0
  23. package/components/core/DpChangeStateAtDate.vue +223 -0
  24. package/components/core/DpCheckboxGroup.vue +93 -0
  25. package/components/core/DpContextualHelp.vue +54 -0
  26. package/components/core/DpCopyPasteButton.vue +47 -0
  27. package/components/core/DpDashboardTaskCard.vue +123 -0
  28. package/components/core/DpDataTable/DataTableSearch.js +44 -0
  29. package/components/core/DpDataTable/DpColumnSelector.vue +133 -0
  30. package/components/core/DpDataTable/DpDataTable.vue +647 -0
  31. package/components/core/DpDataTable/DpDataTableExtended.vue +377 -0
  32. package/components/core/DpDataTable/DpResizeHandle.vue +37 -0
  33. package/components/core/DpDataTable/DpSelectPageItemCount.vue +70 -0
  34. package/components/core/DpDataTable/DpTableHeader.vue +197 -0
  35. package/components/core/DpDataTable/DpTableRow.vue +355 -0
  36. package/components/core/DpDataTable/DpWrapTrigger.vue +48 -0
  37. package/components/core/DpDataTable/lib/ResizableColumns.js +83 -0
  38. package/components/core/DpEditableList.vue +161 -0
  39. package/components/core/DpEditor/DpBoilerPlate.vue +140 -0
  40. package/components/core/DpEditor/DpBoilerPlateModal.vue +166 -0
  41. package/components/core/DpEditor/DpEditor.vue +1281 -0
  42. package/components/core/DpEditor/DpLinkModal.vue +117 -0
  43. package/components/core/DpEditor/DpRecommendationModal/DpInsertableRecommendation.vue +137 -0
  44. package/components/core/DpEditor/DpRecommendationModal.vue +283 -0
  45. package/components/core/DpEditor/DpResizableImage.vue +121 -0
  46. package/components/core/DpEditor/DpUploadModal.vue +121 -0
  47. package/components/core/DpEditor/libs/Decoration.js +66 -0
  48. package/components/core/DpEditor/libs/SegmentRangeChangePlugin.js +35 -0
  49. package/components/core/DpEditor/libs/editorAnonymize.js +66 -0
  50. package/components/core/DpEditor/libs/editorBuildSuggestion.js +269 -0
  51. package/components/core/DpEditor/libs/editorCustomDelete.js +32 -0
  52. package/components/core/DpEditor/libs/editorCustomImage.js +100 -0
  53. package/components/core/DpEditor/libs/editorCustomInsert.js +32 -0
  54. package/components/core/DpEditor/libs/editorCustomLink.js +46 -0
  55. package/components/core/DpEditor/libs/editorCustomMark.js +32 -0
  56. package/components/core/DpEditor/libs/editorInsertAtCursorPos.js +41 -0
  57. package/components/core/DpEditor/libs/editorObscure.js +60 -0
  58. package/components/core/DpEditor/libs/editorUnAnonymize.js +56 -0
  59. package/components/core/DpEditor/libs/handleWordPaste.js +360 -0
  60. package/components/core/DpEditor/libs/preventDrop.js +31 -0
  61. package/components/core/DpEditor/libs/preventKeyboardInput.js +27 -0
  62. package/components/core/DpEditor/libs/preventPaste.js +28 -0
  63. package/components/core/DpFlyout.vue +119 -0
  64. package/components/core/DpInlineNotification.vue +116 -0
  65. package/components/core/DpModal.vue +208 -0
  66. package/components/core/DpObscure.vue +29 -0
  67. package/components/core/DpPager.vue +139 -0
  68. package/components/core/DpProgressBar.vue +67 -0
  69. package/components/core/DpRegisterFlyout.vue +58 -0
  70. package/components/core/DpResettableInput.vue +140 -0
  71. package/components/core/DpSkeletonBox.vue +32 -0
  72. package/components/core/DpSlidebar.vue +86 -0
  73. package/components/core/DpSlidingPagination.vue +45 -0
  74. package/components/core/DpSplitButton.vue +77 -0
  75. package/components/core/DpSwitcher.vue +62 -0
  76. package/components/core/DpTableCardList/DpTableCard.vue +61 -0
  77. package/components/core/DpTableCardList/DpTableCardListHeader.vue +83 -0
  78. package/components/core/DpTabs/DpTab.vue +52 -0
  79. package/components/core/DpTabs/DpTabs.vue +165 -0
  80. package/components/core/DpTextWrapper.vue +65 -0
  81. package/components/core/DpToggleForm.vue +72 -0
  82. package/components/core/DpTooltipIcon.vue +52 -0
  83. package/components/core/DpTransitionExpand.vue +87 -0
  84. package/components/core/DpTreeList/DpTreeList.vue +334 -0
  85. package/components/core/DpTreeList/DpTreeListCheckbox.vue +79 -0
  86. package/components/core/DpTreeList/DpTreeListNode.vue +348 -0
  87. package/components/core/DpTreeList/DpTreeListToggle.vue +71 -0
  88. package/components/core/DpTreeList/utils/constants.js +14 -0
  89. package/components/core/DpUpload/DpUpload.vue +223 -0
  90. package/components/core/DpUpload/DpUploadFiles.vue +269 -0
  91. package/components/core/DpUpload/DpUploadedFile.vue +80 -0
  92. package/components/core/DpUpload/DpUploadedFileList.vue +56 -0
  93. package/components/core/DpUpload/utils/GetFileIdsByHash.js +42 -0
  94. package/components/core/DpUpload/utils/UppyTranslations.js +31 -0
  95. package/components/core/DpVideoPlayer.vue +115 -0
  96. package/components/core/HeightLimit.vue +121 -0
  97. package/components/core/MultistepNav.vue +89 -0
  98. package/components/core/form/DpCheckbox.vue +108 -0
  99. package/components/core/form/DpDateRangePicker.vue +186 -0
  100. package/components/core/form/DpDatepicker.vue +160 -0
  101. package/components/core/form/DpDatetimePicker.vue +194 -0
  102. package/components/core/form/DpFormRow.vue +79 -0
  103. package/components/core/form/DpMultiselect.vue +164 -0
  104. package/components/core/form/DpRadio.vue +128 -0
  105. package/components/core/form/DpSearchField.vue +110 -0
  106. package/components/core/form/DpSelect.vue +149 -0
  107. package/components/core/form/DpTextArea.vue +152 -0
  108. package/components/core/form/DpTimePicker.vue +374 -0
  109. package/components/core/form/DpToggle.vue +78 -0
  110. package/components/core/index.js +132 -0
  111. package/components/core/notify/DpNotifyContainer.vue +122 -0
  112. package/components/core/notify/DpNotifyMessage.vue +95 -0
  113. package/components/core/shared/DpStickyElement.vue +95 -0
  114. package/components/index.js +24 -0
  115. package/components/shared/translations.js +15 -0
  116. package/directives/CleanHtml/CleanHtml.js +50 -0
  117. package/directives/CleanHtml/CleanHtml.stories.mdx +64 -0
  118. package/directives/Tooltip/Tooltip.js +40 -0
  119. package/directives/Tooltip/Tooltip.stories.mdx +42 -0
  120. package/directives/index.js +17 -0
  121. package/lib/index.js +14 -0
  122. package/lib/prefixClass.js +47 -0
  123. package/mixins/index.js +14 -0
  124. package/mixins/prefixClassMixin.js +22 -0
  125. package/package.json +52 -0
  126. package/shared/props.js +86 -0
  127. package/style/index.css +7 -0
  128. package/tailwind.config.js +24 -0
  129. package/tokens/color.json +358 -0
  130. package/tokens/color.stories.mdx +45 -0
  131. package/tokens/fontSize.json +100 -0
  132. package/tokens/space.json +33 -0
  133. package/utils/lengthHint.js +69 -0
@@ -0,0 +1,377 @@
1
+ <license>
2
+ (c) 2010-present DEMOS E-Partizipation GmbH.
3
+
4
+ This file is part of the package @demos-europe/demosplan-ui,
5
+ for more information see the license file.
6
+
7
+ All rights reserved
8
+ </license>
9
+
10
+ <documentation>
11
+ <!--
12
+ This is a Wrapper for DpDataTable.
13
+ It comes with a sticky header where a search Bar and a pager including items-per-page are placed
14
+ Additional Actions can be placed in the sticky footer
15
+
16
+ !!!
17
+ As in DpDataTable, be aware of the data structure for header-fields and table-items.
18
+ the Keys in the table-Items have to match the field values of the header-fields
19
+ !!!
20
+ -->
21
+ <usage discription="minimal version">
22
+ <dp-data-table-extended
23
+ :header-fields="[{field, label},{field, label}]"
24
+ :table-items="[{fieldName}, {fieldName2}]" />
25
+ </usage>
26
+ <usage discription="all options">
27
+ <dp-data-table-extended
28
+ :header-fields="[{field, label},{field, label}]"
29
+ is-selectable
30
+ is-sortable
31
+ :init-items-per-page="50"
32
+ :items-per-page-options="[10, 50, 100, 200]"
33
+ :table-items="[{fieldName}, {fieldName2}]"
34
+ @items-selected="emitsSelectedItemIds"
35
+ track-by="id">
36
+ <template v-slot:footer>
37
+ <!-- Stuff for the footer -->
38
+ </template>
39
+ </dp-data-table-extended>
40
+ </usage>
41
+ </documentation>
42
+
43
+ <template>
44
+ <div class="u-mt-0_5">
45
+ <dp-sticky-element>
46
+ <div class="layout u-pv-0_5">
47
+ <div class="layout__item u-10-of-12">
48
+ <!-- Search field -->
49
+ <label
50
+ class="display--inline"
51
+ for="search">
52
+ {{ Translator.trans('search') }}
53
+ </label>
54
+ <input
55
+ type="text"
56
+ id="search"
57
+ name="search"
58
+ class="o-form__control-input"
59
+ v-model="searchString"
60
+ @input="updateFields(null)">
61
+
62
+ <!-- pager -->
63
+ <sliding-pagination
64
+ v-if="totalPages > 1"
65
+ class="display--inline-block u-ml-0_5 u-mt-0_125"
66
+ :current="currentPage"
67
+ :total="totalPages"
68
+ @page-change="handlePageChange" />
69
+ <dp-select-page-item-count
70
+ class="display--inline-block u-mt-0_125 u-ml-0_5"
71
+ @changed-count="setPageItemCount"
72
+ :page-count-options="itemsPerPageOptions"
73
+ :current-item-count="itemsPerPage"
74
+ :translations="{ pagerElementsPerPage: Translator.trans('pager.per.page') }" />
75
+ </div>
76
+ </div>
77
+ </dp-sticky-element>
78
+
79
+ <dp-data-table
80
+ :has-flyout="hasFlyout"
81
+ :header-fields="headerFields"
82
+ :is-expandable="isExpandable"
83
+ :is-loading="isLoading"
84
+ :is-resizable="isResizable"
85
+ :is-selectable="isSelectable"
86
+ :is-truncatable="isTruncatable"
87
+ @items-selected="emitSelectedItems"
88
+ :items="onPageItems"
89
+ :search-string="searchString"
90
+ :should-be-selected-items="currentlySelectedItems"
91
+ :track-by="trackBy">
92
+ <template
93
+ v-for="el in sortableFilteredFields"
94
+ v-slot:[`header-${el.field}`]="element">
95
+ <slot
96
+ :name="`header-${element.field}`"
97
+ v-bind="element">
98
+ <div
99
+ :key="element.field"
100
+ class="o-hellip--nowrap position--relative u-pr-0_75">
101
+ <button
102
+ :aria-label="Translator.trans('table.cols.sort') + ': ' + element.label"
103
+ :title="Translator.trans('table.cols.sort') + ': ' + element.label"
104
+ class="btn--blank u-top-0 u-right-0 position--absolute"
105
+ @click="setOrder(element.field)"
106
+ type="button">
107
+ <i
108
+ class="fa"
109
+ :class="(element.field === sortOrder.key) ? (sortOrder.direction < 0 ? 'fa-sort-up color--highlight' : 'fa-sort-down color--highlight') : 'fa-sort color--grey'" />
110
+ </button>
111
+ {{ element.label }}
112
+ </div>
113
+ </slot>
114
+ </template>
115
+ <template
116
+ v-for="(el, i) in filteredFields"
117
+ v-slot:[filteredFields[i].field]="element">
118
+ <!-- table cells (TDs) -->
119
+ <slot
120
+ :name="filteredFields[i].field"
121
+ v-bind="element" />
122
+ </template>
123
+ <template v-slot:expandedContent="element">
124
+ <!-- expanded content area -->
125
+ <slot
126
+ name="expandedContent"
127
+ v-bind="element" />
128
+ </template>
129
+ <template v-slot:flyout="element">
130
+ <!-- flyout content area -->
131
+ <slot
132
+ name="flyout"
133
+ v-bind="element" />
134
+ </template>
135
+ </dp-data-table>
136
+
137
+ <dp-sticky-element direction="bottom">
138
+ <slot name="footer" />
139
+ </dp-sticky-element>
140
+ </div>
141
+ </template>
142
+
143
+ <script>
144
+ import dataTableSearch from './DataTableSearch'
145
+ import DomPurify from 'dompurify'
146
+ import DpDataTable from './DpDataTable'
147
+ import DpSelectPageItemCount from './DpSelectPageItemCount'
148
+ import DpStickyElement from '../shared/DpStickyElement'
149
+ import { hasOwnProp } from 'demosplan-utils'
150
+ import SlidingPagination from 'vue-sliding-pagination'
151
+ import { tableSelectAllItems } from 'demosplan-utils/mixins'
152
+
153
+ export default {
154
+ name: 'DpDataTableExtended',
155
+
156
+ components: {
157
+ DpDataTable,
158
+ DpSelectPageItemCount,
159
+ DpStickyElement,
160
+ SlidingPagination
161
+ },
162
+
163
+ mixins: [tableSelectAllItems],
164
+
165
+ props: {
166
+ defaultSortOrder: {
167
+ type: [Object, null],
168
+ required: false,
169
+ default: null,
170
+ validator: data => {
171
+ if (typeof data === 'object' && data !== null) {
172
+ return hasOwnProp(data, 'key') && hasOwnProp(data, 'direction')
173
+ }
174
+ return data === null
175
+ }
176
+ },
177
+
178
+ hasFlyout: {
179
+ type: Boolean,
180
+ required: false,
181
+ default: false
182
+ },
183
+
184
+ /**
185
+ * {Array<Object>} { field, label } object fields with Label
186
+ */
187
+ headerFields: {
188
+ type: Array,
189
+ required: true,
190
+ default: () => []
191
+ },
192
+
193
+ initItemsPerPage: {
194
+ type: Number,
195
+ required: false,
196
+ default: 50
197
+ },
198
+
199
+ isExpandable: {
200
+ type: Boolean,
201
+ required: false,
202
+ default: false
203
+ },
204
+
205
+ isLoading: {
206
+ type: Boolean,
207
+ required: false,
208
+ default: false
209
+ },
210
+
211
+ isResizable: {
212
+ type: Boolean,
213
+ required: false,
214
+ default: false
215
+ },
216
+
217
+ isSelectable: {
218
+ type: Boolean,
219
+ required: false,
220
+ default: false
221
+ },
222
+
223
+ isSortable: {
224
+ type: Boolean,
225
+ required: false,
226
+ default: false
227
+ },
228
+
229
+ isTruncatable: {
230
+ type: Boolean,
231
+ required: false,
232
+ default: false
233
+ },
234
+
235
+ itemsPerPageOptions: {
236
+ type: Array,
237
+ required: false,
238
+ default: () => [10, 50, 100, 200]
239
+ },
240
+
241
+ /**
242
+ * {Array{Object} {fieldName1, fieldName2, ...} The field names have to match the field values from the headerFields.
243
+ * has to be a computed in the parent (can't be in data)
244
+ */
245
+ tableItems: {
246
+ type: Array,
247
+ required: false,
248
+ default: () => []
249
+ },
250
+
251
+ trackBy: {
252
+ type: String,
253
+ required: false,
254
+ default: 'id'
255
+ }
256
+ },
257
+
258
+ data () {
259
+ return {
260
+ currentPage: 1,
261
+ filteredItems: [],
262
+ filters: this.headerFields.reduce((obj, item) => {
263
+ obj[item.field] = true
264
+ return obj
265
+ }, {}),
266
+ isHighlighted: '',
267
+ itemsPerPage: this.initItemsPerPage,
268
+ searchString: '',
269
+ sortOrder: (this.defaultSortOrder !== null) ? this.defaultSortOrder : (this.headerFields.length > 0) ? { key: this.headerFields[0].field, direction: -1 } : null
270
+ }
271
+ },
272
+
273
+ computed: {
274
+ filteredFields () {
275
+ const filteredFields = this.headerFields.filter(el => this.filters[el.field])
276
+ this.$emit('updated:filteredItems', filteredFields)
277
+ return filteredFields
278
+ },
279
+
280
+ onPageItems () {
281
+ let last = this.currentPage * this.itemsPerPage
282
+ const first = last - this.itemsPerPage
283
+ last = last <= this.filteredItems.length ? last : this.filteredItems.length
284
+ const result = this.filteredItems.slice(first, last)
285
+ this.$emit('updated:onPageItems', result)
286
+ return result
287
+ },
288
+
289
+ /*
290
+ * This is to prevent having both a v-if and a v-for on the template. If isSortable is set,
291
+ * there should be some sorting arrows in the header, which get passed in the slot.
292
+ */
293
+ sortableFilteredFields () {
294
+ return this.isSortable ? this.filteredFields : []
295
+ },
296
+
297
+ totalPages () {
298
+ return this.filteredItems.length > 0 ? Math.ceil(this.filteredItems.length / this.itemsPerPage) : 1
299
+ }
300
+ },
301
+
302
+ watch: {
303
+ tableItems () {
304
+ this.updateFields()
305
+ }
306
+ },
307
+
308
+ methods: {
309
+ emitSelectedItems (selectedItems) {
310
+ this.$emit('items-selected', selectedItems)
311
+ },
312
+
313
+ handlePageChange (page) {
314
+ this.currentPage = page
315
+ this.updateFields()
316
+ },
317
+
318
+ highlightText (value) {
319
+ let displayText = DomPurify.sanitize(value.replace('<br>', '__br__')).replace('__br__', '<br>')
320
+ if (this.searchString.length) {
321
+ const regex = new RegExp(this.searchString, 'ig')
322
+ displayText = value.replace(regex, '<span style="background-color: yellow;">$&</span>')
323
+ }
324
+ return displayText
325
+ },
326
+
327
+ setOrder (field) {
328
+ // If clicked on one button multiple times, toggle the order direction
329
+ if (field === this.sortOrder.key) {
330
+ this.sortOrder.direction = this.sortOrder.direction * -1
331
+ } else {
332
+ // Otherwise reset the direction and set the field
333
+ this.sortOrder = { key: field, direction: 1 }
334
+ }
335
+ this.updateFields()
336
+ this.$emit('updated:sortOrder', this.sortOrder)
337
+ },
338
+
339
+ setPageItemCount (count) {
340
+ this.itemsPerPage = count
341
+ this.currentPage = this.currentPage > this.totalPages ? this.totalPages : this.currentPage
342
+ this.updateFields()
343
+ },
344
+
345
+ updateFields (items = null) {
346
+ let sortedList = items || this.tableItems
347
+
348
+ // Sort by selected col
349
+ if (this.sortOrder) {
350
+ sortedList.sort((a, b) => {
351
+ /**
352
+ * In JS is `null > 'string' === null < 'string'`
353
+ * so we have to do such weird stuff
354
+ */
355
+ if (a[this.sortOrder.key] === null || typeof a[this.sortOrder.key] === 'undefined') {
356
+ return this.sortOrder.direction * 1
357
+ }
358
+ if (b[this.sortOrder.key] === null || typeof b[this.sortOrder.key] === 'undefined') {
359
+ return this.sortOrder.direction * -1
360
+ }
361
+ return a[this.sortOrder.key].localeCompare(b[this.sortOrder.key], 'de', { sensitivity: 'base' }) * this.sortOrder.direction
362
+ })
363
+ }
364
+
365
+ // Filter by search string
366
+ if (this.searchString.length > 0) {
367
+ sortedList = dataTableSearch(this.searchString, sortedList, this.headerFields.map(el => el.field))
368
+ }
369
+ this.filteredItems = sortedList
370
+ }
371
+ },
372
+
373
+ mounted () {
374
+ this.updateFields()
375
+ }
376
+ }
377
+ </script>
@@ -0,0 +1,37 @@
1
+ <license>
2
+ (c) 2010-present DEMOS E-Partizipation GmbH.
3
+
4
+ This file is part of the package @demos-europe/demosplan-ui,
5
+ for more information see the license file.
6
+
7
+ All rights reserved
8
+ </license>
9
+
10
+ <template>
11
+ <div
12
+ class="c-data-table__resize-handle"
13
+ @mousedown.stop.prevent="(e) => $emit('mousedown', e)">
14
+ <template v-if="displayIcon">
15
+ <i
16
+ class="fa fa-angle-left resize-handle__icon"
17
+ aria-hidden="true" />
18
+ <i
19
+ class="fa fa-angle-right resize-handle__icon"
20
+ aria-hidden="true" />
21
+ </template>
22
+ </div>
23
+ </template>
24
+
25
+ <script>
26
+ export default {
27
+ name: 'ResizeHandle',
28
+
29
+ props: {
30
+ displayIcon: {
31
+ required: false,
32
+ type: Boolean,
33
+ default: true
34
+ }
35
+ }
36
+ }
37
+ </script>
@@ -0,0 +1,70 @@
1
+ <license>
2
+ (c) 2010-present DEMOS E-Partizipation GmbH.
3
+
4
+ This file is part of the package @demos-europe/demosplan-ui,
5
+ for more information see the license file.
6
+
7
+ All rights reserved
8
+ </license>
9
+
10
+ <script>
11
+ export default {
12
+ name: 'DpSelectPageItemCount',
13
+
14
+ functional: true,
15
+
16
+ props: {
17
+ currentItemCount: {
18
+ type: Number,
19
+ required: true
20
+ },
21
+
22
+ pageCountOptions: {
23
+ type: Array,
24
+ required: true
25
+ },
26
+
27
+ translations: {
28
+ type: Object,
29
+ required: true
30
+ }
31
+ },
32
+
33
+ render: function (h, { props, listeners, data }) {
34
+ const selectEl = h('select', {
35
+ attrs: {
36
+ id: 'item-count',
37
+ class: 'o-form__control-select width-auto u-mr-0_25'
38
+ },
39
+ on: {
40
+ change: (e) => {
41
+ listeners['changed-count'](parseInt(e.target.value))
42
+ }
43
+ }
44
+ }, [
45
+ ...props.pageCountOptions.map(option => {
46
+ return h('option', {
47
+ domProps: {
48
+ value: option,
49
+ selected: option === props.currentItemCount
50
+ }
51
+ }, option)
52
+ })
53
+ ])
54
+
55
+ const selectHintEl = h('label', {
56
+ attrs: {
57
+ for: 'item-count',
58
+ class: 'display--inline u-mb-0'
59
+ }
60
+ },
61
+ props.translations.pagerElementsPerPage)
62
+
63
+ return h('div', {
64
+ attrs: {
65
+ class: data.staticClass
66
+ }
67
+ }, [selectEl, selectHintEl])
68
+ }
69
+ }
70
+ </script>
@@ -0,0 +1,197 @@
1
+ <license>
2
+ (c) 2010-present DEMOS E-Partizipation GmbH.
3
+
4
+ This file is part of the package @demos-europe/demosplan-ui,
5
+ for more information see the license file.
6
+
7
+ All rights reserved
8
+ </license>
9
+
10
+ <script>
11
+ import { DpIcon } from 'demosplan-ui/components'
12
+ import DpWrapTrigger from './DpWrapTrigger'
13
+ import { hasOwnProp } from 'demosplan-utils'
14
+ import { renderResizeWrapper } from './lib/ResizableColumns'
15
+
16
+ export default {
17
+ name: 'DpTableHeader',
18
+
19
+ functional: true,
20
+
21
+ props: {
22
+ checked: {
23
+ type: Boolean,
24
+ required: true
25
+ },
26
+
27
+ hasFlyout: {
28
+ type: Boolean,
29
+ required: true
30
+ },
31
+
32
+ headerFields: {
33
+ type: Array,
34
+ required: true
35
+ },
36
+
37
+ isDraggable: {
38
+ type: Boolean,
39
+ required: false,
40
+ default: false
41
+ },
42
+
43
+ isExpandable: {
44
+ type: Boolean,
45
+ required: false,
46
+ default: false
47
+ },
48
+
49
+ isResizable: {
50
+ type: Boolean,
51
+ required: false,
52
+ default: false
53
+ },
54
+
55
+ isSelectable: {
56
+ type: Boolean,
57
+ required: true
58
+ },
59
+
60
+ isSticky: {
61
+ type: Boolean,
62
+ required: false,
63
+ default: false
64
+ },
65
+
66
+ isTruncatable: {
67
+ type: Boolean,
68
+ required: false,
69
+ default: false
70
+ },
71
+
72
+ translations: {
73
+ type: Object,
74
+ required: true
75
+ }
76
+ },
77
+
78
+ render: function (h, { props, listeners, scopedSlots }) {
79
+ const {
80
+ checked,
81
+ headerFields,
82
+ hasFlyout,
83
+ indeterminate,
84
+ isDraggable,
85
+ isExpandable,
86
+ isResizable,
87
+ isSelectable,
88
+ isSticky,
89
+ isTruncatable,
90
+ translations
91
+ } = props
92
+
93
+ let draggableCell = []
94
+ if (isDraggable) {
95
+ draggableCell = [
96
+ h('th', {
97
+ attrs: {
98
+ class: 'c-data-table__cell--narrow'
99
+ }
100
+ }, [
101
+ h(DpIcon, {
102
+ attrs: {
103
+ class: 'c-data-table__drag-handle'
104
+ },
105
+ props: {
106
+ icon: 'drag-handle'
107
+ }
108
+ })
109
+ ])
110
+ ]
111
+ }
112
+
113
+ const checkboxData = {}
114
+ let checkboxCell = []
115
+ if (isSelectable) {
116
+ checkboxData.attrs = {
117
+ 'aria-label': translations.headerSelectHint,
118
+ title: translations.headerSelectHint,
119
+ type: 'checkbox',
120
+ 'data-cy': 'selectAll'
121
+ }
122
+ checkboxData.ref = 'selectAll'
123
+ checkboxData.on = { click: () => listeners.toggleSelectAll() }
124
+ checkboxData.domProps = { checked: checked, indeterminate: indeterminate }
125
+ checkboxCell = [h('th', {
126
+ attrs: {
127
+ class: 'c-data-table__cell--narrow'
128
+ }
129
+ }, [h('input', checkboxData)])]
130
+ }
131
+
132
+ let flyoutCell = []
133
+ if (hasFlyout) {
134
+ flyoutCell = [h('th')]
135
+ }
136
+
137
+ let expandableCell = []
138
+ if (isExpandable) {
139
+ DpWrapTrigger.attrs = {
140
+ title: translations.headerExpandHint
141
+ }
142
+ expandableCell = [h('th', {
143
+ attrs: {
144
+ class: 'c-data-table__cell--narrow'
145
+ },
146
+ on: {
147
+ click: () => listeners.toggleExpandAll()
148
+ }
149
+ }, [h(DpWrapTrigger)])]
150
+ }
151
+
152
+ let truncatableCell = []
153
+ if (isTruncatable) {
154
+ DpWrapTrigger.attrs = {
155
+ title: translations.headerExpandHint
156
+ }
157
+ truncatableCell = [h('th', {
158
+ attrs: {
159
+ class: 'c-data-table__cell--narrow'
160
+ },
161
+ on: {
162
+ click: () => listeners.toggleWrapAll()
163
+ }
164
+ }, [h(DpWrapTrigger)])]
165
+ }
166
+
167
+ const headerCells = headerFields.map((hf, idx) => {
168
+ const isLast = idx === (headerFields.length - 1)
169
+ const resizeable = hasOwnProp(hf, 'resizeable') ? hf.resizeable : true
170
+ const headerContent = [(scopedSlots[`header-${hf.field}`] && scopedSlots[`header-${hf.field}`](hf)) || hf.label]
171
+ const content = isResizable ? renderResizeWrapper(h, headerContent, idx, isLast, resizeable, hf.label, hf.tooltip) : headerContent
172
+
173
+ return isResizable
174
+ ? content
175
+ : h('th', {
176
+ scopedSlots: {
177
+ [`header-${hf.field}`]: scopedSlots[`header-${hf.field}`]
178
+ }
179
+ }, headerContent)
180
+ })
181
+
182
+ return h('tr', {
183
+ ref: 'tableHeader',
184
+ attrs: isSticky
185
+ ? { class: 'c-data-table__sticky-header' }
186
+ : {}
187
+ }, [
188
+ ...draggableCell,
189
+ ...checkboxCell,
190
+ ...headerCells,
191
+ ...flyoutCell,
192
+ ...expandableCell,
193
+ ...truncatableCell
194
+ ])
195
+ }
196
+ }
197
+ </script>