@studio-west/component-sw 0.11.23 → 0.11.24

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/README.md CHANGED
@@ -698,7 +698,7 @@ model - состояние чекбокса (checked ) булевое знач
698
698
 
699
699
  ## SwTable
700
700
 
701
- Разработка! Компонент `SwTable` представляет собой динамическую таблицу. Шаблон шапки задается вложением компонентов `SwTablecolumn` друг в друга. Содержание таблицы берется из свойства `data` - массив объектов, а слияние столбцов и строк задается подобъектом с соответствующими параметрами.
701
+ Компонент `SwTable` представляет собой динамическую таблицу с поддержкой сложных заголовков, объединения ячеек и кастомизации содержимого через слоты.
702
702
 
703
703
  ### Свойства / Properties
704
704
 
@@ -708,15 +708,24 @@ model - состояние чекбокса (checked ) булевое знач
708
708
 
709
709
  ### Слоты / Slots
710
710
 
711
- #`<name>` - пре определение шаблона столбца
711
+ #`<prop>` - именованный слот для конкретной колонки (приоритет выше default). Доступные параметры: `{ row, $index, value }`
712
+
713
+ #default - универсальный слот для всех колонок. Доступные параметры: `{ row, $index, column, value }`
714
+
715
+ - `row` - весь объект строки данных
716
+ - `$index` - индекс строки (начиная с 0)
717
+ - `column` - имя колонки (prop)
718
+ - `value` - значение ячейки
712
719
 
713
720
  ### Пример использования / Example Usage
714
721
 
722
+ #### Базовый пример с вложенными колонками:
723
+
715
724
  ```html
716
725
  <script>
717
726
  let table = [
718
- {city:{label:'Moscow', rowspan:2},district:'Center'},
719
- {city:'Moscow',district:'MRCR'},
727
+ {city:{label:'Moscow', rowspan:2},district:'Center',speed:{max:80,min:50,midl:70}},
728
+ {city:'Moscow',district:'MRCR',speed:{max:130,min:90,midl:120}},
720
729
  ]
721
730
  </script>
722
731
  <sw-table :data="table">
@@ -724,6 +733,145 @@ model - состояние чекбокса (checked ) булевое знач
724
733
  <sw-table-column label="City" prop="city"/>
725
734
  <sw-table-column label="District" prop="district"/>
726
735
  </sw-table-column>
736
+ <sw-table-column label="Speed" prop="speed.midl"/>
737
+ </sw-table>
738
+ ```
739
+
740
+ #### Пример с v-for для динамических колонок:
741
+
742
+ ```html
743
+ <script setup>
744
+ import { ref } from 'vue'
745
+
746
+ const columns = ref([
747
+ { prop: 'name', label: 'Имя', width: '150px' },
748
+ { prop: 'age', label: 'Возраст', width: '100px' },
749
+ { prop: 'email', label: 'Email', width: '200px' }
750
+ ])
751
+
752
+ const tableData = ref([
753
+ { name: 'Иван', age: 25, email: 'ivan@example.com' },
754
+ { name: 'Мария', age: 30, email: 'maria@example.com' },
755
+ { name: 'Петр', age: 35, email: 'petr@example.com' }
756
+ ])
757
+ </script>
758
+
759
+ <sw-table :data="tableData">
760
+ <sw-table-column
761
+ v-for="column in columns"
762
+ :key="column.prop"
763
+ :prop="column.prop"
764
+ :label="column.label"
765
+ :width="column.width"
766
+ />
767
+ </sw-table>
768
+ ```
769
+
770
+ #### Пример с кастомизацией через слоты:
771
+
772
+ ```html
773
+ <script setup>
774
+ import { ref } from 'vue'
775
+
776
+ const users = ref([
777
+ { id: 1, name: 'Иван Петров', age: 25, status: 'active', email: 'ivan@example.com' },
778
+ { id: 2, name: 'Мария Сидорова', age: 30, status: 'inactive', email: 'maria@example.com' },
779
+ { id: 3, name: 'Петр Иванов', age: 35, status: 'active', email: 'petr@example.com' }
780
+ ])
781
+
782
+ const deleteUser = (id) => {
783
+ console.log('Delete user:', id)
784
+ }
785
+ </script>
786
+
787
+ <sw-table :data="users">
788
+ <sw-table-column prop="name" label="Имя" />
789
+ <sw-table-column prop="age" label="Возраст" />
790
+ <sw-table-column prop="status" label="Статус" />
791
+ <sw-table-column prop="actions" label="Действия" width="150px" />
792
+
793
+ <!-- Именованный слот для конкретной колонки -->
794
+ <template #name="{ row, value }">
795
+ <strong>{{ value }}</strong>
796
+ </template>
797
+
798
+ <template #age="{ value }">
799
+ <span style="color: blue">{{ value }} лет</span>
800
+ </template>
801
+
802
+ <template #status="{ value }">
803
+ <span :style="{ color: value === 'active' ? 'green' : 'red' }">
804
+ {{ value === 'active' ? '✓ Активен' : '✗ Неактивен' }}
805
+ </span>
806
+ </template>
807
+
808
+ <!-- Default слот для колонки actions -->
809
+ <template #actions="{ row }">
810
+ <button @click="deleteUser(row.id)">Удалить</button>
811
+ <a :href="`mailto:${row.email}`">Написать</a>
812
+ </template>
813
+ </sw-table>
814
+ ```
815
+
816
+ #### Пример с универсальным default слотом:
817
+
818
+ ```html
819
+ <script setup>
820
+ import { ref } from 'vue'
821
+
822
+ const products = ref([
823
+ { name: 'Товар 1', price: 1000, quantity: 5 },
824
+ { name: 'Товар 2', price: 2500, quantity: 3 },
825
+ { name: 'Товар 3', price: 750, quantity: 10 }
826
+ ])
827
+ </script>
828
+
829
+ <sw-table :data="products">
830
+ <sw-table-column prop="name" label="Название" />
831
+ <sw-table-column prop="price" label="Цена" />
832
+ <sw-table-column prop="quantity" label="Количество" />
833
+
834
+ <!-- Универсальный слот для всех колонок -->
835
+ <template #default="{ row, column, value }">
836
+ <span v-if="column === 'price'" style="font-weight: bold">
837
+ {{ value }} ₽
838
+ </span>
839
+ <span v-else-if="column === 'quantity' && value < 5" style="color: red">
840
+ {{ value }} ⚠️ Мало
841
+ </span>
842
+ <span v-else>{{ value }}</span>
843
+ </template>
844
+ </sw-table>
845
+ ```
846
+
847
+ #### Пример с объединением ячеек (rowspan/colspan):
848
+
849
+ ```html
850
+ <script setup>
851
+ import { ref } from 'vue'
852
+
853
+ const complexData = ref([
854
+ {
855
+ city: { label: 'Москва', rowspan: 2 },
856
+ district: 'Центр',
857
+ population: 500000
858
+ },
859
+ {
860
+ city: 'Москва', // будет скрыта из-за rowspan
861
+ district: 'Север',
862
+ population: 300000
863
+ },
864
+ {
865
+ region: { label: 'Общая статистика', colspan: 2 },
866
+ total: 800000
867
+ }
868
+ ])
869
+ </script>
870
+
871
+ <sw-table :data="complexData">
872
+ <sw-table-column label="Город" prop="city" />
873
+ <sw-table-column label="Район" prop="district" />
874
+ <sw-table-column label="Население" prop="population" />
727
875
  </sw-table>
728
876
  ```
729
877
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studio-west/component-sw",
3
- "version": "0.11.23",
3
+ "version": "0.11.24",
4
4
  "description": "Vue components of Component-SW collection.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -22,13 +22,29 @@
22
22
  :rowspan="cell.rowspan"
23
23
  :style="cell.style"
24
24
  >
25
+ <!-- Сначала пробуем именованный слот по prop -->
25
26
  <slot
27
+ v-if="slots[cell.prop]"
26
28
  :name="cell.prop"
27
29
  :row="cell.originalRow"
28
30
  :$index="cell.rowIndex"
31
+ :value="cell.label"
32
+ />
33
+ <!-- Затем пробуем слот default с данными конкретной ячейки -->
34
+ <slot
35
+ v-else-if="slots.default"
36
+ name="default"
37
+ :row="cell.originalRow"
38
+ :$index="cell.rowIndex"
39
+ :column="cell.prop"
40
+ :value="cell.label"
29
41
  >
30
42
  {{ cell.label }}
31
43
  </slot>
44
+ <!-- Fallback на простое значение -->
45
+ <template v-else>
46
+ {{ cell.label }}
47
+ </template>
32
48
  </td>
33
49
  </tr>
34
50
  </tbody>
@@ -79,20 +95,12 @@ function buildColumnTree(vnodes) {
79
95
  // Handle both function and array children
80
96
  let children = []
81
97
  if (typeof vnode.children?.default === 'function') {
82
- try {
83
- children = vnode.children.default()
84
- } catch (e) {
85
- console.warn('Error calling default slot:', e)
86
- }
87
- } else if (Array.isArray(vnode.children)) {
88
- children = vnode.children
89
- }
90
-
98
+ try {children = vnode.children.default()}
99
+ catch (e) {console.warn('Error calling default slot:', e)}
100
+ } else if (Array.isArray(vnode.children)) children = vnode.children
91
101
  if (children && children.length > 0) {
92
102
  const childColumns = buildColumnTree(children)
93
- if (childColumns.length > 0) {
94
- column.children = childColumns
95
- }
103
+ if (childColumns.length > 0) column.children = childColumns
96
104
  }
97
105
  result.push(column)
98
106
  }
@@ -183,46 +191,29 @@ function extractLeafColumns(columns) {
183
191
  // Обработка данных для tbody с поддержкой colspan
184
192
  function processBodyData(data, columns) {
185
193
  // Защита от undefined/null значений
186
- if (!data || !Array.isArray(data)) {
187
- return []
188
- }
189
- if (!columns || !Array.isArray(columns)) {
190
- return []
191
- }
192
-
194
+ if (!data || !Array.isArray(data)) return []
195
+ if (!columns || !Array.isArray(columns)) return []
193
196
  // Функция для получения значения по пути (например, "gant.0")
194
197
  function getValueByPath(obj, path) {
195
198
  if (!obj || !path) return undefined
196
-
197
199
  // Разбиваем путь по точкам
198
200
  const keys = path.split('.')
199
201
  let value = obj
200
-
201
202
  for (const key of keys) {
202
- if (value === null || value === undefined) {
203
- return undefined
204
- }
205
-
203
+ if (value === null || value === undefined) return undefined
206
204
  // Пробуем обратиться как к свойству объекта или элементу массива
207
205
  value = value[key]
208
206
  }
209
-
210
207
  return value
211
208
  }
212
-
213
209
  const processedRows = []
214
210
  const cellMap = new Map() // Для отслеживания объединенных ячеек
215
211
  data.forEach((row, rowIndex) => {
216
212
  const processedRow = []
217
-
218
213
  columns.forEach((column, colIndex) => {
219
214
  const key = `${rowIndex}-${column.prop}`
220
-
221
215
  // Проверяем, не занята ли эта ячейка из-за rowspan/colspan
222
- if (cellMap.has(key)) {
223
- return
224
- }
225
-
216
+ if (cellMap.has(key)) return
226
217
  // Получаем значение по пути (поддержка "gant.0", "gant.1" и т.д.)
227
218
  const cellData = getValueByPath(row, column.prop)
228
219
  let cellValue = cellData
@@ -237,7 +228,6 @@ function processBodyData(data, columns) {
237
228
  rowspan = cellData.rowspan || 1
238
229
  style = cellData.style || {}
239
230
  }
240
-
241
231
  const cell = {
242
232
  key,
243
233
  label: cellValue,
@@ -248,23 +238,17 @@ function processBodyData(data, columns) {
248
238
  originalRow: row,
249
239
  rowIndex
250
240
  }
251
-
252
241
  processedRow.push(cell)
253
-
254
-
255
242
  // Помечаем объединенные ячейки
256
243
  for (let r = 0; r < rowspan; r++) {
257
244
  for (let c = 0; c < colspan; c++) {
258
245
  if (r === 0 && c === 0) continue // Основная ячейка
259
246
  const cellKey = `${rowIndex + r}-${columns[colIndex + c]?.prop}`
260
- if (cellKey) {
261
- cellMap.set(cellKey, true)
262
- }
247
+ if (cellKey) cellMap.set(cellKey, true)
263
248
  }
264
249
  }
265
250
  })
266
251
 
267
- // Добавляем строку только если в ней есть ячейки
268
252
  if (processedRow.length > 0) {
269
253
  processedRows.push(processedRow)
270
254
  }