vueless 0.0.175 → 0.0.176

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": "vueless",
3
- "version": "0.0.175",
3
+ "version": "0.0.176",
4
4
  "license": "MIT",
5
5
  "description": "Vue Styleless Component Framework.",
6
6
  "homepage": "https://vueless.com",
@@ -0,0 +1,170 @@
1
+ <template>
2
+ <tr v-bind="$attrs" @click="onClick(props.row)">
3
+ <td
4
+ v-if="selectable"
5
+ :style="getNestedCheckboxShift()"
6
+ v-bind="attrs.bodyCellAttrs(config.bodyCellCheckbox)"
7
+ >
8
+ <UCheckbox
9
+ v-model="selectedRows"
10
+ :data-id="row.id"
11
+ :value="row.id"
12
+ size="sm"
13
+ :data-cy="`${dataCy}-body-checkbox`"
14
+ v-bind="attrs.bodyCheckboxAttrs"
15
+ @click.stop
16
+ />
17
+ </td>
18
+
19
+ <td
20
+ v-for="(value, key, index) in getFilteredRow(row, columns)"
21
+ :key="index"
22
+ v-bind="attrs.bodyCellAttrs(getCellClasses(key, row, index))"
23
+ >
24
+ <div
25
+ v-if="(row.row || nestedLevel) && index === 0"
26
+ :style="getNestedShift()"
27
+ v-bind="attrs.bodyCellNestedAttrs"
28
+ >
29
+ <UIcon
30
+ v-if="row.row"
31
+ size="xs"
32
+ internal
33
+ interactive
34
+ :name="
35
+ row?.row?.isHidden
36
+ ? config.bodyCellNestedExpandIconName
37
+ : config.bodyCellNestedCollapseIconName
38
+ "
39
+ color="brand"
40
+ v-bind="toggleIconConfig"
41
+ @click="onClickToggleRowChild(row.row.id)"
42
+ />
43
+ </div>
44
+
45
+ <div v-if="value?.hasOwnProperty('secondary')">
46
+ <slot :name="`cell-${key}`" :value="value" :row="row">
47
+ <div :data-cy="`${dataCy}-${key}-cell`">
48
+ {{ value.primary || HYPHEN_SYMBOL }}
49
+ </div>
50
+
51
+ <div v-bind="attrs.bodyCellSecondaryAttrs">
52
+ <template v-if="Array.isArray(value.secondary)">
53
+ <div v-for="(secondary, idx) in value.secondary" :key="idx">
54
+ <span v-bind="attrs.bodyCellSecondaryEmptyAttrs">
55
+ {{ secondary }}
56
+ </span>
57
+ </div>
58
+ </template>
59
+
60
+ <template v-else>
61
+ {{ value.secondary }}
62
+ </template>
63
+ </div>
64
+ </slot>
65
+ </div>
66
+
67
+ <template v-else>
68
+ <slot :name="`cell-${key}`" :value="value" :row="row">
69
+ <div :data-cy="`${dataCy}-${key}-cell`">
70
+ {{ value || HYPHEN_SYMBOL }}
71
+ </div>
72
+ </slot>
73
+ </template>
74
+ </td>
75
+ </tr>
76
+
77
+ <TableRow
78
+ v-if="row.row && !row.row.isHidden"
79
+ v-bind="$attrs"
80
+ v-model:selected-rows="selectedRows"
81
+ :attrs="attrs"
82
+ :columns="columns"
83
+ :row="row.row"
84
+ :data-cy="dataCy"
85
+ :nested-level="nestedLevel + 1"
86
+ :config="config"
87
+ :selectable="selectable"
88
+ @toggle-row-visibility="onClickToggleRowChild"
89
+ @click="onClick"
90
+ />
91
+ </template>
92
+
93
+ <script setup>
94
+ import { computed } from "vue";
95
+
96
+ import { HYPHEN_SYMBOL } from "../../service.ui";
97
+ import { getFilteredRow } from "../services/table.service.js";
98
+
99
+ import UIcon from "../../ui.image-icon";
100
+ import UCheckbox from "../../ui.form-checkbox";
101
+
102
+ const props = defineProps({
103
+ row: {
104
+ type: Object,
105
+ required: true,
106
+ },
107
+ columns: {
108
+ type: Array,
109
+ required: true,
110
+ },
111
+ tag: {
112
+ type: String,
113
+ default: "tr",
114
+ },
115
+ selectable: {
116
+ type: Boolean,
117
+ default: false,
118
+ },
119
+ nestedLevel: {
120
+ type: Number,
121
+ default: 0,
122
+ },
123
+ dataCy: {
124
+ type: String,
125
+ required: true,
126
+ },
127
+ attrs: {
128
+ type: Object,
129
+ required: true,
130
+ },
131
+ config: {
132
+ type: Object,
133
+ required: true,
134
+ },
135
+ });
136
+
137
+ const emit = defineEmits(["toggleRowVisibility", "click"]);
138
+
139
+ const selectedRows = defineModel("selectedRows", { type: Array, default: () => [] });
140
+
141
+ const toggleIconConfig = computed(() =>
142
+ props.row?.row?.isHidden
143
+ ? props.attrs.bodyCellNestedExpandIconAttrs
144
+ : props.attrs.bodyCellNestedCollapseIconAttrs,
145
+ );
146
+
147
+ const shift = computed(() => (props.row.row ? 1.5 : 2));
148
+
149
+ function getCellClasses(key, row, cellIndex) {
150
+ const isNestedRow = (row.row || props.nestedLevel) && cellIndex === 0;
151
+
152
+ return [props.columns.find((column) => column.key === key)?.tdClass, isNestedRow && "flex"];
153
+ }
154
+
155
+ function getNestedShift() {
156
+ return { marginLeft: `${props.nestedLevel * shift.value}rem` };
157
+ }
158
+
159
+ function getNestedCheckboxShift() {
160
+ return { transform: `translateX(${props.nestedLevel * shift.value}rem)` };
161
+ }
162
+
163
+ function onClickToggleRowChild(rowId) {
164
+ emit("toggleRowVisibility", rowId);
165
+ }
166
+
167
+ function onClick(row) {
168
+ emit("click", row);
169
+ }
170
+ </script>
@@ -5,10 +5,18 @@ import { computed } from "vue";
5
5
 
6
6
  export function useAttrs(
7
7
  props,
8
- { tableRows, isNesting, isShownActionsHeader, isHeaderSticky, isFooterSticky },
8
+ { tableRows, isShownActionsHeader, isHeaderSticky, isFooterSticky },
9
9
  ) {
10
10
  const { config, getAttrs, hasSlotContent } = useUI(defaultConfig, () => props.config);
11
- const { stickyHeaderCell, headerCell, footerRow, bodyCell, headerCellGeneral } = config.value;
11
+ const {
12
+ stickyHeaderCell,
13
+ headerCell,
14
+ footerRow,
15
+ bodyCell,
16
+ headerCellGeneral,
17
+ stickyHeaderCounter,
18
+ headerCounter,
19
+ } = config.value;
12
20
 
13
21
  const cvaHeaderCellGeneral = cva({
14
22
  base: headerCellGeneral.base,
@@ -40,19 +48,37 @@ export function useAttrs(
40
48
  compoundVariants: bodyCell.compoundVariants,
41
49
  });
42
50
 
51
+ const cvaStickyHeaderCounter = cva({
52
+ base: stickyHeaderCounter.base,
53
+ variants: stickyHeaderCounter.variants,
54
+ compoundVariants: stickyHeaderCounter.compoundVariants,
55
+ });
56
+
57
+ const cvaHeaderCounter = cva({
58
+ base: headerCounter.base,
59
+ variants: headerCounter.variants,
60
+ compoundVariants: headerCounter.compoundVariants,
61
+ });
62
+
43
63
  const stickyHeaderCellClasses = computed(() => cvaCustomHeaderItem({ compact: props.compact }));
44
64
  const headerCellClasses = computed(() => cvaHeaderCell({ compact: props.compact }));
45
65
  const footerRowClasses = computed(() => cvaFooterRow({ compact: props.compact }));
46
66
  const bodyCellClasses = computed(() => cvaBodyCell({ compact: props.compact }));
47
67
  const headerCellGeneralClasses = computed(() => cvaHeaderCellGeneral({ compact: props.compact }));
68
+ const headerCounterClasses = computed(() => cvaHeaderCounter({ compact: props.compact }));
69
+ const stickyHeaderCounterClasses = computed(() =>
70
+ cvaStickyHeaderCounter({ compact: props.compact }),
71
+ );
48
72
 
49
73
  const wrapperAttrs = getAttrs("wrapper");
50
74
  const stickyHeaderAttrsRaw = getAttrs("stickyHeader");
51
75
  const stickyHeaderCellAttrsRaw = getAttrs("stickyHeaderCell", {
52
76
  classes: stickyHeaderCellClasses,
53
77
  });
54
- const headerCounterAttrsRaw = getAttrs("headerCounter");
55
- const stickyHeaderCounterAttrsRaw = getAttrs("stickyHeaderCounter");
78
+ const headerCounterAttrsRaw = getAttrs("headerCounter", { classes: headerCounterClasses });
79
+ const stickyHeaderCounterAttrsRaw = getAttrs("stickyHeaderCounter", {
80
+ classes: stickyHeaderCounterClasses,
81
+ });
56
82
  const stickyHeaderActionsCounterAttrsRaw = getAttrs("stickyHeaderActionsCounter");
57
83
  const stickyHeaderCheckboxAttrs = getAttrs("stickyHeaderCheckbox", {
58
84
  isComponent: true,
@@ -88,7 +114,6 @@ export function useAttrs(
88
114
  const bodyRowBeforeCellAttrsRaw = getAttrs("bodyRowBeforeCell");
89
115
  const bodyRowAfterAttrs = getAttrs("bodyRowAfter");
90
116
  const bodyRowAfterCellAttrsRaw = getAttrs("bodyRowAfterCell");
91
- const bodyCellNestedWrapperAttrsRaw = getAttrs("bodyCellNestedWrapper");
92
117
 
93
118
  const bodyRowAttrsRaw = getAttrs("bodyRow");
94
119
 
@@ -195,11 +220,6 @@ export function useAttrs(
195
220
  return getAttrs("bodyRowDateSeparator", { classes: activeClass }).value;
196
221
  };
197
222
 
198
- const bodyCellNestedWrapperAttrs = computed(() => (index) => ({
199
- ...bodyCellNestedWrapperAttrsRaw.value,
200
- class: index === 0 && isNesting.value ? config.value.bodyCellNestedWrapper : "",
201
- }));
202
-
203
223
  return {
204
224
  config,
205
225
  wrapperAttrs,
@@ -215,7 +235,6 @@ export function useAttrs(
215
235
  bodyRowBeforeAttrs,
216
236
  bodyRowBeforeCellAttrs,
217
237
  bodyRowDateSeparatorAttrs,
218
- bodyCellNestedWrapperAttrs,
219
238
  bodyCellAttrs,
220
239
  stickyHeaderCounterAttrs,
221
240
  stickyHeaderActionsCounterAttrs,
@@ -13,7 +13,14 @@ export default /*tw*/ {
13
13
  stickyHeaderRow: "border-gray-200 bg-white",
14
14
  stickyHeaderCell: "flex-none whitespace-nowrap",
15
15
  stickyHeaderCheckbox: "",
16
- stickyHeaderCounter: "absolute top-4 left-11 bg-gradient-to-r from-white from-80%",
16
+ stickyHeaderCounter: {
17
+ base: "absolute top-5 left-11 bg-gradient-to-r from-white from-80%",
18
+ variants: {
19
+ compact: {
20
+ true: "top-3",
21
+ },
22
+ },
23
+ },
17
24
  stickyHeaderLoader: "",
18
25
  stickyHeaderActions: "absolute rounded-t-lg border-blue-200 bg-blue-50",
19
26
  stickyHeaderActionsCheckbox: "",
@@ -25,7 +32,14 @@ export default /*tw*/ {
25
32
  headerCell: "",
26
33
  headerCellCheckbox: "w-10",
27
34
  headerCheckbox: "",
28
- headerCounter: "absolute top-4 left-11 bg-gradient-to-r from-white from-80% mt-px ml-px",
35
+ headerCounter: {
36
+ base: "absolute top-5 mt-px left-11 bg-gradient-to-r from-white from-80% ml-px",
37
+ variants: {
38
+ compact: {
39
+ true: "top-3",
40
+ },
41
+ },
42
+ },
29
43
  headerLoader: "absolute !top-auto",
30
44
  body: "group/body divide-none",
31
45
  bodyRow: "hover:bg-gray-50",
@@ -36,10 +50,10 @@ export default /*tw*/ {
36
50
  bodyRowAfterCell: "py-1",
37
51
  bodyRowDateSeparator: "",
38
52
  bodyCell: {
39
- base: "p-[1.125rem] py-5 first:p-5 truncate align-top last:p-5",
53
+ base: "p-[1.125rem] py-5 first:!p-5 truncate align-top last:p-5",
40
54
  variants: {
41
55
  compact: {
42
- true: "px-4 py-3 last:px-4 last:py-3 first:px-4 first:py-3",
56
+ true: "px-4 py-3 last:px-4 last:py-3 first:!px-3.5 first:py-3",
43
57
  },
44
58
  },
45
59
  },
@@ -47,11 +61,16 @@ export default /*tw*/ {
47
61
  bodyCellSecondaryEmpty: "inline-block",
48
62
  bodyCellCheckbox: "first:px-4", // try to remove first
49
63
  bodyCellDateSeparator: "",
50
- bodyCellNestedWrapper: "flex items-center",
51
- bodyCellNested: "flex relative -top-px",
52
- bodyCellNestedExpandIcon: "mr-2 rounded-sm bg-gray-200",
64
+ bodyCellNested: "mr-2 mt-0.5",
65
+ bodyCellNestedExpandIcon: {
66
+ wrapper: "rounded-sm",
67
+ container: "bg-gray-200",
68
+ },
53
69
  bodyCellNestedExpandIconName: "add",
54
- bodyCellNestedCollapseIcon: "mr-2 rounded-sm bg-gray-200",
70
+ bodyCellNestedCollapseIcon: {
71
+ wrapper: "rounded-sm",
72
+ container: "bg-gray-200",
73
+ },
55
74
  bodyCellNestedCollapseIconName: "remove",
56
75
  bodyCheckbox: "",
57
76
  bodyDateSeparator: "",
@@ -42,29 +42,119 @@ export default {
42
42
  { key: "key_3", label: "title 3" },
43
43
  { key: "key_4", label: "title 4" },
44
44
  ],
45
+ row: getRow,
46
+ numberOfRows: 5,
47
+ },
48
+ };
49
+
50
+ function getNestedRow() {
51
+ return {
52
+ id: getRandomId(),
53
+ isChecked: false,
54
+ key_1: {
55
+ primary: "primary",
56
+ secondary: "secondary",
57
+ },
58
+ key_2: {
59
+ primary: "primary",
60
+ secondary: "secondary",
61
+ },
62
+ key_3: {
63
+ primary: "primary",
64
+ secondary: "secondary",
65
+ },
66
+ key_4: {
67
+ primary: "primary",
68
+ secondary: "secondary",
69
+ },
45
70
  row: {
46
- id: 1,
71
+ id: getRandomId(),
47
72
  isChecked: false,
73
+ isHidden: true,
48
74
  key_1: {
49
- primary: "primary",
75
+ primary: "Nesting",
50
76
  secondary: "secondary",
51
77
  },
52
78
  key_2: {
53
- primary: "primary",
79
+ primary: "Nesting",
54
80
  secondary: "secondary",
55
81
  },
56
82
  key_3: {
57
- primary: "primary",
83
+ primary: "Nesting",
58
84
  secondary: "secondary",
59
85
  },
60
86
  key_4: {
61
- primary: "primary",
87
+ primary: "Nesting",
62
88
  secondary: "secondary",
63
89
  },
90
+ row: {
91
+ id: getRandomId(),
92
+ isChecked: false,
93
+ isHidden: true,
94
+ key_1: {
95
+ primary: "Two level nesting",
96
+ secondary: "secondary",
97
+ },
98
+ key_2: {
99
+ primary: "Two level nesting",
100
+ secondary: "secondary",
101
+ },
102
+ key_3: {
103
+ primary: "Two level nesting",
104
+ secondary: "secondary",
105
+ },
106
+ key_4: {
107
+ primary: "Two level nesting",
108
+ secondary: "secondary",
109
+ },
110
+ row: {
111
+ id: getRandomId(),
112
+ isChecked: false,
113
+ isHidden: true,
114
+ key_1: {
115
+ primary: "Three level nesting",
116
+ secondary: "secondary",
117
+ },
118
+ key_2: {
119
+ primary: "Three level nesting",
120
+ secondary: "secondary",
121
+ },
122
+ key_3: {
123
+ primary: "Three level nesting",
124
+ secondary: "secondary",
125
+ },
126
+ key_4: {
127
+ primary: "Three level nesting",
128
+ secondary: "secondary",
129
+ },
130
+ },
131
+ },
64
132
  },
65
- numberOfRows: 5,
66
- },
67
- };
133
+ };
134
+ }
135
+
136
+ function getRow() {
137
+ return {
138
+ id: getRandomId(),
139
+ isChecked: false,
140
+ key_1: {
141
+ primary: "primary",
142
+ secondary: "secondary",
143
+ },
144
+ key_2: {
145
+ primary: "primary",
146
+ secondary: "secondary",
147
+ },
148
+ key_3: {
149
+ primary: "primary",
150
+ secondary: "secondary",
151
+ },
152
+ key_4: {
153
+ primary: "primary",
154
+ secondary: "secondary",
155
+ },
156
+ };
157
+ }
68
158
 
69
159
  const DefaultTemplate = (args) => ({
70
160
  components: { UTable },
@@ -85,10 +175,7 @@ const DefaultTemplate = (args) => ({
85
175
  let rows = [];
86
176
 
87
177
  for (let i = 0; i < args.numberOfRows; i++) {
88
- const newRow = { ...args.row };
89
-
90
- newRow.id = getRandomId();
91
- rows.push(newRow);
178
+ rows.push(args.row());
92
179
  }
93
180
 
94
181
  return rows;
@@ -126,10 +213,7 @@ const SlotTemplate = (args) => ({
126
213
  let rows = [];
127
214
 
128
215
  for (let i = 0; i < args.numberOfRows; i++) {
129
- const newRow = { ...args.row };
130
-
131
- newRow.id = getRandomId();
132
- rows.push(newRow);
216
+ rows.push(args.row());
133
217
  }
134
218
 
135
219
  return rows;
@@ -140,6 +224,12 @@ const SlotTemplate = (args) => ({
140
224
  export const Default = DefaultTemplate.bind({});
141
225
  Default.args = {};
142
226
 
227
+ export const Nesting = DefaultTemplate.bind({});
228
+ Nesting.args = {
229
+ row: getNestedRow,
230
+ selectable: true,
231
+ };
232
+
143
233
  export const Empty = EmptyTemplate.bind({});
144
234
  Empty.args = {};
145
235
 
@@ -154,89 +154,33 @@
154
154
  </td>
155
155
  </tr>
156
156
 
157
- <tr
158
- v-if="!isShownRow(row)"
157
+ <TableRow
159
158
  v-bind="bodyRowAttrs(getRowClasses(row))"
159
+ v-model:selectedRows="selectedRows"
160
+ :selectable="selectable"
160
161
  :data-cy="`${dataCy}-row`"
161
- @click="onClickRow(row)"
162
+ :row="row"
163
+ :columns="columns"
164
+ :config="config"
165
+ :attrs="{
166
+ bodyCellAttrs,
167
+ bodyCellSecondaryAttrs,
168
+ bodyCellSecondaryEmptyAttrs,
169
+ bodyCellNestedCollapseIconAttrs,
170
+ bodyCellNestedExpandIconAttrs,
171
+ bodyCellNestedAttrs,
172
+ }"
173
+ @click="onClickRow"
174
+ @toggle-row-visibility="onToggleRowVisibility"
162
175
  >
163
- <td v-if="selectable" v-bind="bodyCellAttrs(config.bodyCellCheckbox)">
164
- <UCheckbox
165
- v-model="selectedRows"
166
- :data-id="row.id"
167
- :value="row.id"
168
- size="sm"
169
- :data-cy="`${dataCy}-body-checkbox`"
170
- v-bind="bodyCheckboxAttrs"
171
- @click.stop
172
- />
173
- </td>
174
-
175
- <td
176
- v-for="(value, key, index) in TableService.getFilteredRow(row, columns)"
176
+ <template
177
+ v-for="(value, key, index) in getFilteredRow(row, columns)"
177
178
  :key="index"
178
- v-bind="bodyCellAttrs(getCellClasses(key))"
179
+ #[`cell-${key}`]="slotValues"
179
180
  >
180
- <template v-if="hasSlotContent($slots[`cell-${key}`])">
181
- <div
182
- v-if="isNesting"
183
- :style="getNestedShift(row.nestedLevel)"
184
- v-bind="bodyCellNestedWrapperAttrs(index)"
185
- @click="onClickNestedWrapper(row)"
186
- >
187
- <div v-if="isShownNestedIcon({ index, row })" v-bind="bodyCellNestedAttrs">
188
- <UIcon
189
- v-if="row.isHidden"
190
- size="xs"
191
- internal
192
- interactive
193
- :name="config.bodyCellNestedExpandIconName"
194
- :color="isActiveNestedIcon(row)"
195
- v-bind="bodyCellNestedExpandIconAttrs"
196
- />
197
-
198
- <UIcon
199
- v-else
200
- size="xs"
201
- internal
202
- interactive
203
- :name="config.bodyCellNestedCollapseIconName"
204
- v-bind="bodyCellNestedCollapseIconAttrs"
205
- />
206
- </div>
207
- </div>
208
-
209
- <!-- @slot Use it to customise table cell item (in whole column). -->
210
- <slot :name="`cell-${key}`" :value="value" :row="row" />
211
- </template>
212
-
213
- <template v-else-if="value?.hasOwnProperty('secondary')">
214
- <div :data-cy="`${dataCy}-${key}-cell`">
215
- {{ value.primary || HYPHEN_SYMBOL }}
216
- </div>
217
-
218
- <div v-bind="bodyCellSecondaryAttrs">
219
- <template v-if="Array.isArray(value.secondary)">
220
- <div v-for="(secondary, idx) in value.secondary" :key="idx">
221
- <span v-bind="bodyCellSecondaryEmptyAttrs">
222
- {{ secondary }}
223
- </span>
224
- </div>
225
- </template>
226
-
227
- <template v-else>
228
- {{ value.secondary }}
229
- </template>
230
- </div>
231
- </template>
232
-
233
- <template v-else>
234
- <div :data-cy="`${dataCy}-${key}-cell`">
235
- {{ value || HYPHEN_SYMBOL }}
236
- </div>
237
- </template>
238
- </td>
239
- </tr>
181
+ <slot :name="`cell-${key}`" :value="slotValues.value" :row="slotValues.row" />
182
+ </template>
183
+ </TableRow>
240
184
 
241
185
  <tr
242
186
  v-if="rowIndex === lastRow && hasSlotContent($slots['after-last-row'])"
@@ -300,18 +244,25 @@ import {
300
244
  } from "vue";
301
245
  import { merge } from "lodash-es";
302
246
 
303
- import UIcon from "../ui.image-icon";
304
247
  import UEmpty from "../ui.text-empty";
305
248
  import UDivider from "../ui.container-divider";
306
249
  import UCheckbox from "../ui.form-checkbox";
307
250
  import ULoaderTop from "../ui.loader-top";
251
+ import TableRow from "./components/TableRow";
308
252
 
309
253
  import UIService from "../service.ui";
310
254
 
311
255
  import defaultConfig from "./configs/default.config";
312
- import TableService from "./services/table.service";
313
-
314
- import { HYPHEN_SYMBOL, PX_IN_REM } from "../service.ui";
256
+ import {
257
+ normalizeColumns,
258
+ getFilteredRow,
259
+ syncRowCheck,
260
+ toggleRowVisibility,
261
+ switchRowCheck,
262
+ getFlatRows,
263
+ } from "./services/table.service";
264
+
265
+ import { PX_IN_REM } from "../service.ui";
315
266
  import { UTable } from "./constants";
316
267
  import { useAttrs } from "./composables/attrs.composable";
317
268
  import { useLocale } from "../composable.locale";
@@ -376,14 +327,6 @@ const props = defineProps({
376
327
  default: UIService.get(defaultConfig, UTable).default.stickyFooter,
377
328
  },
378
329
 
379
- /**
380
- * Sets the nesting level from which folding button need to be shown.
381
- */
382
- nesting: {
383
- type: [Number, Boolean],
384
- default: UIService.get(defaultConfig, UTable).default.nesting,
385
- },
386
-
387
330
  /**
388
331
  * Set loader resource name to activate table top loader exact for that resource.
389
332
  */
@@ -420,7 +363,6 @@ const selectAll = ref(false);
420
363
  const canSelectAll = ref(true);
421
364
  const selectedRows = ref([]);
422
365
  const tableRows = ref([]);
423
- const hiddenIds = ref([]);
424
366
  const firstRow = ref(0);
425
367
  const tableWidth = ref(0);
426
368
  const tableHeight = ref(0);
@@ -443,11 +385,7 @@ const isFooterSticky = computed(
443
385
  isCheckedMoreOneTableItems.value,
444
386
  );
445
387
 
446
- const normalizedColumns = computed(() => TableService.normalizeColumns(props.columns));
447
-
448
- const isSelectedAllRows = computed(() => {
449
- return selectedRows.value.length === tableRows.value.length;
450
- });
388
+ const normalizedColumns = computed(() => normalizeColumns(props.columns));
451
389
 
452
390
  const colsCount = computed(() => {
453
391
  return props.columns.length + 1;
@@ -458,7 +396,7 @@ const lastRow = computed(() => {
458
396
  });
459
397
 
460
398
  const isShownActionsHeader = computed(
461
- () => hasSlotContent(slots["header-actions"]) && selectedRows.value.length,
399
+ () => hasSlotContent(slots["header-actions"]) && Boolean(selectedRows.value.length),
462
400
  );
463
401
 
464
402
  const isHeaderSticky = computed(() => {
@@ -487,8 +425,10 @@ const hasSlotContentBeforeFirstRow = computed(() => {
487
425
  : false;
488
426
  });
489
427
 
490
- const isNesting = computed(() => {
491
- return Boolean(props.nesting) || props.nesting === 0;
428
+ const isSelectedAllRows = computed(() => {
429
+ const rows = getFlatRows(tableRows.value);
430
+
431
+ return selectedRows.value.length === rows.length;
492
432
  });
493
433
 
494
434
  const {
@@ -505,14 +445,12 @@ const {
505
445
  bodyRowAttrs,
506
446
  footerClassesAttrs,
507
447
  bodyRowDateSeparatorAttrs,
508
- bodyCellNestedWrapperAttrs,
509
448
  headerCellAttrs,
510
449
  bodyCellAttrs,
511
450
  stickyHeaderActionsCheckboxAttrs,
512
451
  stickyHeaderCheckboxAttrs,
513
452
  headerCheckboxAttrs,
514
453
  headerCounterAttrs,
515
- bodyCheckboxAttrs,
516
454
  bodyCellNestedCollapseIconAttrs,
517
455
  bodyCellNestedExpandIconAttrs,
518
456
  bodyEmptyStateAttrs,
@@ -533,7 +471,6 @@ const {
533
471
  headerAttrs,
534
472
  } = useAttrs(props, {
535
473
  tableRows,
536
- isNesting,
537
474
  isShownActionsHeader,
538
475
  isHeaderSticky,
539
476
  isFooterSticky,
@@ -551,11 +488,7 @@ watch(isFooterSticky, (newValue) =>
551
488
  watch(
552
489
  () => selectedRows.value.length,
553
490
  () => {
554
- tableRows.value = tableRows.value.map((row) => {
555
- row.isChecked = selectedRows.value.includes(row.id);
556
-
557
- return row;
558
- });
491
+ tableRows.value = tableRows.value.map((row) => syncRowCheck(row, selectedRows.value));
559
492
  },
560
493
  );
561
494
 
@@ -585,56 +518,12 @@ function onWindowResize() {
585
518
  setFooterCellWidth();
586
519
  }
587
520
 
588
- function isShownNestedIcon({ index, row }) {
589
- const nestedLevel = props.nesting === true ? 0 : Number(props.nesting);
590
- const isWithinNestingLevel = row.nestedLevel >= nestedLevel;
591
- const isChildren = row.childrenIds?.length > 0;
592
-
593
- const isFirstRow = index === 0;
594
-
595
- return isFirstRow && (isChildren || row.isNestingRow) && isNesting.value && isWithinNestingLevel;
596
- }
597
-
598
- function isActiveNestedIcon(row) {
599
- return !row.childrenIds?.length ? "grayscale" : "";
600
- }
601
-
602
- function onClickNestedWrapper(row) {
603
- if (!isNesting.value || !row.childrenIds.length) return;
604
- const [firstElement] = row.childrenIds;
605
-
606
- row.isHidden = !row.isHidden;
607
-
608
- if (row.isHidden && row.childrenIds.length) {
609
- hiddenIds.value.push(...row.childrenIds);
610
- } else {
611
- const nestedLevel = props.nesting === true ? 0 : Number(props.nesting);
612
-
613
- hiddenIds.value =
614
- row.nestedLevel === nestedLevel
615
- ? row.childrenIds.filter((item) => !hiddenIds.value.includes(item))
616
- : hiddenIds.value.filter((item) => item !== firstElement);
617
- }
618
- }
619
-
620
- function getNestedShift(nestedLevel) {
621
- return { marginLeft: `${nestedLevel * 1.5}rem` };
622
- }
623
-
624
521
  function getDateSeparatorLabel(separatorDate) {
625
522
  return Array.isArray(props.dateDivider)
626
523
  ? props.dateDivider.find((dateItem) => dateItem.date === separatorDate)?.label || separatorDate
627
524
  : separatorDate;
628
525
  }
629
526
 
630
- function isShownRow(row) {
631
- if (hiddenIds.value.includes(row.id)) {
632
- row.isHidden = true;
633
- }
634
-
635
- return hiddenIds.value.includes(row.id);
636
- }
637
-
638
527
  function setFooterCellWidth(width) {
639
528
  const ZERO_WIDTH = 0;
640
529
 
@@ -670,12 +559,6 @@ function synchronizeTableItemsWithProps() {
670
559
  }
671
560
 
672
561
  tableRows.value = props.rows;
673
-
674
- tableRows.value.forEach((item) => {
675
- if (isNesting.value && item.isHidden && item.childrenIds?.length) {
676
- hiddenIds.value.push(...item.childrenIds);
677
- }
678
- });
679
562
  }
680
563
 
681
564
  function updateSelectedRows() {
@@ -715,19 +598,15 @@ function getRowClasses(row) {
715
598
  return selectedRows.value.includes(row.id) ? config.value.bodyRowChecked : "";
716
599
  }
717
600
 
718
- function getCellClasses(key) {
719
- return props.columns.find((column) => column.key === key)?.tdClass;
720
- }
721
-
722
601
  function onChangeSelectAll(selectAll) {
723
602
  if (selectAll && canSelectAll.value) {
724
- selectedRows.value = tableRows.value.map((item) => item.id);
603
+ selectedRows.value = getFlatRows(tableRows.value).map((row) => row.id);
725
604
 
726
- tableRows.value.forEach((item) => (item.isChecked = true));
605
+ tableRows.value.forEach((row) => switchRowCheck(row, true));
727
606
  } else if (!selectAll) {
728
607
  selectedRows.value = [];
729
608
 
730
- tableRows.value.forEach((item) => (item.isChecked = false));
609
+ tableRows.value.forEach((row) => switchRowCheck(row, false));
731
610
  }
732
611
 
733
612
  canSelectAll.value = true;
@@ -748,4 +627,8 @@ function onChangeSelectedRows(selectedRows) {
748
627
  function clearSelectedItems() {
749
628
  selectedRows.value = [];
750
629
  }
630
+
631
+ function onToggleRowVisibility(rowId) {
632
+ tableRows.value.forEach((row) => toggleRowVisibility(row, rowId));
633
+ }
751
634
  </script>
@@ -1,15 +1,55 @@
1
- export default class TableService {
2
- static normalizeColumns(columns) {
3
- return columns.map((column) => (typeof column === "string" ? { label: column } : column));
1
+ export function normalizeColumns(columns) {
2
+ return columns.map((column) => (typeof column === "string" ? { label: column } : column));
3
+ }
4
+
5
+ export function getFilteredRow(row, columns) {
6
+ const filteredRow = Object.entries(row).filter((item) => {
7
+ const isShownColumn = columns.some((column) => column.key === item[0]);
8
+
9
+ if (isShownColumn) return item;
10
+ });
11
+
12
+ return Object.fromEntries(filteredRow);
13
+ }
14
+
15
+ export function syncRowCheck(row, selectedRows) {
16
+ row.isChecked = selectedRows.includes(row.id);
17
+
18
+ if (row.row) {
19
+ row.row = syncRowCheck(row.row, selectedRows);
4
20
  }
5
21
 
6
- static getFilteredRow(row, columns) {
7
- const filteredRow = Object.entries(row).filter((item) => {
8
- const isShownColumn = columns.some((column) => column.key === item[0]);
22
+ return row;
23
+ }
9
24
 
10
- if (isShownColumn) return item;
11
- });
25
+ export function toggleRowVisibility(row, targetRowId) {
26
+ if (row.id === targetRowId) row.isHidden = !row.isHidden;
12
27
 
13
- return Object.fromEntries(filteredRow);
28
+ if (row.row) {
29
+ toggleRowVisibility(row.row, targetRowId);
14
30
  }
15
31
  }
32
+
33
+ export function switchRowCheck(row, isChecked) {
34
+ row.isChecked = isChecked;
35
+
36
+ if (row.row) {
37
+ switchRowCheck(row.row, isChecked);
38
+ }
39
+ }
40
+
41
+ export function getFlatRows(tableRows) {
42
+ const rows = [];
43
+
44
+ function addRow(row) {
45
+ rows.push(row);
46
+
47
+ if (row.row) {
48
+ addRow(row.row);
49
+ }
50
+ }
51
+
52
+ tableRows.forEach((row) => addRow(row));
53
+
54
+ return rows;
55
+ }
package/web-types.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "framework": "vue",
3
3
  "name": "vueless",
4
- "version": "0.0.175",
4
+ "version": "0.0.176",
5
5
  "contributions": {
6
6
  "html": {
7
7
  "description-markup": "markdown",
@@ -181,6 +181,93 @@
181
181
  "symbol": "default"
182
182
  }
183
183
  },
184
+ {
185
+ "name": "TableRow",
186
+ "description": "",
187
+ "attributes": [
188
+ {
189
+ "name": "row",
190
+ "required": true,
191
+ "value": {
192
+ "kind": "expression",
193
+ "type": "object"
194
+ }
195
+ },
196
+ {
197
+ "name": "columns",
198
+ "required": true,
199
+ "value": {
200
+ "kind": "expression",
201
+ "type": "array"
202
+ }
203
+ },
204
+ {
205
+ "name": "tag",
206
+ "value": {
207
+ "kind": "expression",
208
+ "type": "string"
209
+ },
210
+ "default": "\"tr\""
211
+ },
212
+ {
213
+ "name": "selectable",
214
+ "value": {
215
+ "kind": "expression",
216
+ "type": "boolean"
217
+ },
218
+ "default": "false"
219
+ },
220
+ {
221
+ "name": "nestedLevel",
222
+ "value": {
223
+ "kind": "expression",
224
+ "type": "number"
225
+ },
226
+ "default": "0"
227
+ },
228
+ {
229
+ "name": "dataCy",
230
+ "required": true,
231
+ "value": {
232
+ "kind": "expression",
233
+ "type": "string"
234
+ }
235
+ },
236
+ {
237
+ "name": "attrs",
238
+ "required": true,
239
+ "value": {
240
+ "kind": "expression",
241
+ "type": "object"
242
+ }
243
+ },
244
+ {
245
+ "name": "config",
246
+ "required": true,
247
+ "value": {
248
+ "kind": "expression",
249
+ "type": "object"
250
+ }
251
+ }
252
+ ],
253
+ "events": [
254
+ {
255
+ "name": "toggleRowVisibility"
256
+ },
257
+ {
258
+ "name": "click"
259
+ }
260
+ ],
261
+ "slots": [
262
+ {
263
+ "name": "`cell-${key}`"
264
+ }
265
+ ],
266
+ "source": {
267
+ "module": "./src/ui.data-table/components/TableRow.vue",
268
+ "symbol": "default"
269
+ }
270
+ },
184
271
  {
185
272
  "name": "UAccordion",
186
273
  "description": "",
@@ -6642,15 +6729,6 @@
6642
6729
  },
6643
6730
  "default": "false"
6644
6731
  },
6645
- {
6646
- "name": "nesting",
6647
- "description": "Sets the nesting level from which folding button need to be shown.",
6648
- "value": {
6649
- "kind": "expression",
6650
- "type": "number|boolean"
6651
- },
6652
- "default": "false"
6653
- },
6654
6732
  {
6655
6733
  "name": "resource",
6656
6734
  "description": "Set loader resource name to activate table top loader exact for that resource.",
@@ -6709,8 +6787,7 @@
6709
6787
  "description": "Use it to add something before first row."
6710
6788
  },
6711
6789
  {
6712
- "name": "`cell-${key}`",
6713
- "description": "Use it to customise table cell item (in whole column)."
6790
+ "name": "`cell-${key}`"
6714
6791
  },
6715
6792
  {
6716
6793
  "name": "after-last-row",