@razerspine/pug-ui-kit 1.0.0 → 1.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.
- package/CHANGELOG.md +26 -0
- package/mixins/data-table.pug +67 -56
- package/package.json +8 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
## [1.0.1] - 2026-02-03
|
|
2
|
+
|
|
3
|
+
### Changed
|
|
4
|
+
- **dataTable**: Refactored the `dataTable` mixin to improve configuration consistency.
|
|
5
|
+
- **dataTable**: The `options` parameter now accepts an `actions` array to define row actions (links/buttons) dynamically.
|
|
6
|
+
|
|
7
|
+
### Removed
|
|
8
|
+
- **dataTable**: Removed support for the Pug `block` (slot) content for rendering actions. The `showActions` boolean option has also been removed.
|
|
9
|
+
|
|
10
|
+
### Migration Guide
|
|
11
|
+
If you were using the block content for actions:
|
|
12
|
+
```pug
|
|
13
|
+
// Old version (v1.0.0)
|
|
14
|
+
+dataTable(items, cols, { showActions: true })
|
|
15
|
+
a(href=`/edit/${item.id}`) Edit
|
|
16
|
+
```
|
|
17
|
+
You should now update to:
|
|
18
|
+
|
|
19
|
+
```pug
|
|
20
|
+
// New version (v1.0.1)
|
|
21
|
+
+dataTable(items, cols, {
|
|
22
|
+
actions: [
|
|
23
|
+
{ label: 'Edit', url: (item) => `/edit/${item.id}` }
|
|
24
|
+
]
|
|
25
|
+
})
|
|
26
|
+
```
|
package/mixins/data-table.pug
CHANGED
|
@@ -1,80 +1,87 @@
|
|
|
1
1
|
//- dataTable mixin
|
|
2
2
|
//- Renders a flexible table from an array of objects. Columns are derived
|
|
3
3
|
//- from the provided `columns` array or automatically collected from object keys.
|
|
4
|
-
//- Supports optional index column, optional actions column (slot), per-column
|
|
5
|
-
//- formatters and custom header labels.
|
|
6
4
|
//-
|
|
7
5
|
//- Parameters:
|
|
8
6
|
//- items - **Array** — Array of objects to render as rows. Each object
|
|
9
|
-
//- represents one row
|
|
10
|
-
//- array, an empty table is rendered.
|
|
11
|
-
//- Example: [{ id:1, name:'Olya' }, { id:2, name:'Ivan' }]
|
|
7
|
+
//- represents one row.
|
|
12
8
|
//- Default: []
|
|
13
9
|
//- columns - **Array | undefined** — Optional ordered list of keys to use
|
|
14
|
-
//- as columns. If omitted
|
|
15
|
-
//- from all objects in `items` and used in insertion order.
|
|
16
|
-
//- Example: ['id','name','email']
|
|
10
|
+
//- as columns. If omitted, unique keys are collected from `items`.
|
|
17
11
|
//- Default: auto-collected from items
|
|
18
|
-
//- options - **Object | undefined** —
|
|
12
|
+
//- options - **Object | undefined** — Configuration options:
|
|
19
13
|
//- - emptyText: **String** — Text shown when no rows; Default: 'No data'.
|
|
20
14
|
//- - showIndex: **Boolean** — Render leading index column; Default: false.
|
|
21
|
-
//- - showActions: **Boolean** — Render trailing Actions column (slot); Default: true.
|
|
22
15
|
//- - formatters: **Object** — Map of column -> function(value) for custom rendering.
|
|
23
16
|
//- Example: { createdAt: v => new Date(v).toLocaleDateString() }.
|
|
24
|
-
//- - labels: **Object** — Map of column -> header label string.
|
|
25
|
-
//-
|
|
26
|
-
//-
|
|
17
|
+
//- - labels: **Object** — Map of column -> header label string.
|
|
18
|
+
//- Example: { id: 'ID', user_name: 'Name' }.
|
|
19
|
+
//- - actions: **Array** — List of action objects to render in the last column.
|
|
20
|
+
//- Replaces the deprecated block/slot mechanism.
|
|
21
|
+
//- Structure:
|
|
22
|
+
//- [
|
|
23
|
+
//- {
|
|
24
|
+
//- label: String, // Text of the link/button
|
|
25
|
+
//- url: Function(item), // Callback returning the URL string based on the row item
|
|
26
|
+
//- class: String (optional) // CSS classes for the link
|
|
27
|
+
//- }
|
|
28
|
+
//- ]
|
|
29
|
+
//- Default: []
|
|
27
30
|
//-
|
|
28
31
|
//- Behavior:
|
|
29
|
-
//- -
|
|
30
|
-
//- -
|
|
31
|
-
//-
|
|
32
|
-
//- - For each cell, `formatters[col]` is used when present; otherwise arrays are joined,
|
|
33
|
-
//- objects are JSON-stringified, and primitives are stringified.
|
|
34
|
-
//- - The Actions column is a slot: when `showActions` is true, the mixin renders a `td`
|
|
35
|
-
//- containing the caller-provided block. Inside the block the current row object is
|
|
36
|
-
//- available as `item` and the row index as `i`.
|
|
37
|
-
//-
|
|
38
|
-
//- Notes and best practices:
|
|
39
|
-
//- - Prefer passing an explicit `columns` array when you need stable column order.
|
|
40
|
-
//- - Use `labels` for human-friendly or localized header text instead of renaming keys.
|
|
41
|
-
//- - Keep `formatters` pure and return safe strings; if returning HTML, use `!=` in the mixin call
|
|
42
|
-
//- or return already-escaped content carefully to avoid XSS.
|
|
43
|
-
//- - To hide the Actions column entirely, set `showActions: false` in `options`.
|
|
44
|
-
//- - For large datasets, consider server-side pagination or client-side slicing before passing `items`.
|
|
32
|
+
//- - Renders a table with Bootstrap-like classes (`table`).
|
|
33
|
+
//- - If `items` is empty, displays a unified row with `emptyText`.
|
|
34
|
+
//- - Actions are rendered as `<a>` tags in a separate column if `options.actions` is provided.
|
|
45
35
|
//-
|
|
46
36
|
//- Examples:
|
|
47
|
-
//-
|
|
48
|
-
//-
|
|
37
|
+
//- const data = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
|
|
38
|
+
//-
|
|
39
|
+
//- // 1. Basic usage
|
|
49
40
|
//- +dataTable(data)
|
|
50
41
|
//-
|
|
51
|
-
//- //
|
|
52
|
-
//- +dataTable(data, ['id','name'], {
|
|
42
|
+
//- // 2. Advanced usage with Actions and Custom Labels
|
|
43
|
+
//- +dataTable(data, ['id', 'name'], {
|
|
53
44
|
//- showIndex: true,
|
|
54
|
-
//-
|
|
55
|
-
//-
|
|
56
|
-
//-
|
|
45
|
+
//- labels: { name: 'Full Name' },
|
|
46
|
+
//- actions: [
|
|
47
|
+
//- {
|
|
48
|
+
//- label: 'Edit',
|
|
49
|
+
//- class: 'btn btn--text-primary btn--medium',
|
|
50
|
+
//- url: (item) => `/users/${item.id}/edit`
|
|
51
|
+
//- },
|
|
52
|
+
//- {
|
|
53
|
+
//- label: 'Delete',
|
|
54
|
+
//- class: 'btn btn--text-secondary btn--medium',
|
|
55
|
+
//- url: (item) => `/users/${item.id}/delete`
|
|
56
|
+
//- }
|
|
57
|
+
//- ]
|
|
57
58
|
//- })
|
|
58
59
|
//-
|
|
59
|
-
//- //
|
|
60
|
-
//-
|
|
61
|
-
//-
|
|
62
|
-
//-
|
|
63
|
-
//-
|
|
60
|
+
//- // 3. Explicit columns, labels and formatters
|
|
61
|
+
//- +dataTable(data, ['id','name'], {
|
|
62
|
+
//- showIndex: false,
|
|
63
|
+
//- labels: { id: 'ID', name: 'Full name' },
|
|
64
|
+
//- formatters: { id: v => '#' + v }
|
|
65
|
+
//- })
|
|
64
66
|
//-
|
|
65
|
-
//- Keep this docblock updated when you change parameter names, defaults, or
|
|
66
|
-
//- the mixin behavior so editor hover comments remain accurate.
|
|
67
67
|
mixin dataTable(items, columns, options)
|
|
68
68
|
- const _items = Array.isArray(items) ? items : [];
|
|
69
69
|
- const cols = Array.isArray(columns) && columns.length ? columns : Array.from(new Set(_items.reduce((acc, it) => acc.concat(Object.keys(it || {})), [])));
|
|
70
|
-
- const opts = Object.assign({ emptyText: 'No data', showIndex: false, showActions: false, formatters: {}, labels: {} }, options || {});
|
|
71
70
|
|
|
71
|
+
//- Default options
|
|
72
|
+
- const opts = Object.assign({ emptyText: 'No data', showIndex: false, actions: [], formatters: {}, labels: {} }, options || {});
|
|
73
|
+
|
|
74
|
+
//- Check if actions column is needed
|
|
75
|
+
- const hasActions = Array.isArray(opts.actions) && opts.actions.length > 0;
|
|
76
|
+
|
|
77
|
+
//- Helper: Humanize keys (user_id -> User id)
|
|
72
78
|
- const humanize = function(key) {
|
|
73
79
|
- if (!key && key !== 0) return '';
|
|
74
80
|
- const s = String(key).replace(/_/g, ' ');
|
|
75
81
|
- return s.charAt(0).toUpperCase() + s.slice(1);
|
|
76
82
|
- }
|
|
77
83
|
|
|
84
|
+
//- Helper: Format cell values
|
|
78
85
|
- const formatValue = function(v, col) {
|
|
79
86
|
- if (v === null || v === undefined || v === '') return '';
|
|
80
87
|
- if (opts.formatters && typeof opts.formatters[col] === 'function') return opts.formatters[col](v);
|
|
@@ -84,29 +91,33 @@ mixin dataTable(items, columns, options)
|
|
|
84
91
|
- }
|
|
85
92
|
|
|
86
93
|
if !_items.length
|
|
87
|
-
table.table
|
|
94
|
+
table.table.data-table
|
|
88
95
|
thead
|
|
89
96
|
tr
|
|
90
|
-
th(colspan=cols.length + (opts.showIndex ? 1 : 0) + (
|
|
97
|
+
th(colspan=cols.length + (opts.showIndex ? 1 : 0) + (hasActions ? 1 : 0)) #{opts.emptyText}
|
|
91
98
|
else
|
|
92
|
-
table.table
|
|
99
|
+
table.table.data-table
|
|
93
100
|
thead
|
|
94
101
|
tr
|
|
95
102
|
if opts.showIndex
|
|
96
|
-
th #
|
|
103
|
+
th.data-table__index #
|
|
97
104
|
each col in cols
|
|
98
105
|
- const label = (opts.labels && Object.prototype.hasOwnProperty.call(opts.labels, col)) ? opts.labels[col] : humanize(col)
|
|
99
|
-
th #{label}
|
|
100
|
-
if
|
|
101
|
-
th Actions
|
|
106
|
+
th.data-table__header #{label}
|
|
107
|
+
if hasActions
|
|
108
|
+
th.data-table__actions Actions
|
|
102
109
|
tbody
|
|
103
110
|
each item, i in _items
|
|
104
111
|
tr
|
|
105
112
|
if opts.showIndex
|
|
106
|
-
td #{i + 1}
|
|
113
|
+
td.data-table__index #{i + 1}
|
|
107
114
|
each col in cols
|
|
108
115
|
- const val = (item && Object.prototype.hasOwnProperty.call(item, col)) ? item[col] : ''
|
|
109
|
-
td!= formatValue(val, col)
|
|
110
|
-
if
|
|
111
|
-
td
|
|
112
|
-
|
|
116
|
+
td.data-table__cell!= formatValue(val, col)
|
|
117
|
+
if hasActions
|
|
118
|
+
td.data-table__actions-cell
|
|
119
|
+
each action in opts.actions
|
|
120
|
+
- const href = (typeof action.url === 'function') ? action.url(item) : '#'
|
|
121
|
+
- const className = action.class || ''
|
|
122
|
+
a(href=href class=className) #{action.label}
|
|
123
|
+
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@razerspine/pug-ui-kit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Shared Pug mixins for Webpack Starter templates",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pug",
|
|
7
|
+
"components",
|
|
8
|
+
"mixins"
|
|
9
|
+
],
|
|
5
10
|
"main": "index.js",
|
|
6
11
|
"files": [
|
|
7
12
|
"mixins",
|
|
8
13
|
"index.js",
|
|
9
14
|
"README.md",
|
|
10
|
-
"LICENSE"
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"CHANGELOG.md"
|
|
11
17
|
],
|
|
12
18
|
"author": "Razerspine",
|
|
13
19
|
"repository": {
|