nuxt-unified-ui 0.5.12 → 0.5.13

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.
@@ -74,6 +74,20 @@ const tableUi = computed(() => {
74
74
 
75
75
  /* actions */
76
76
 
77
+ const actionButtonOmitKeys = [
78
+ 'actionType',
79
+ 'vIf',
80
+ 'tooltip',
81
+ 'warning',
82
+ 'to',
83
+ 'href',
84
+ 'disabled',
85
+ 'onClick',
86
+ 'label',
87
+ 'items',
88
+ ];
89
+
90
+
77
91
  function resolveActionValue(value, row) {
78
92
  if (typeof value === 'function') {
79
93
  return value(row.original);
@@ -83,6 +97,23 @@ function resolveActionValue(value, row) {
83
97
  }
84
98
  }
85
99
 
100
+ function getActionWarning(action, row) {
101
+ return resolveActionValue(action.warning, row);
102
+ }
103
+
104
+ function getSplitActionItems(action, row) {
105
+ return (resolveActionValue(action.items, row) || []).map(it => {
106
+ return {
107
+ ...radOmit(it, [
108
+ 'onClick',
109
+ 'onSelect',
110
+ ]),
111
+ label: resolveActionValue(it.label, row),
112
+ onSelect: () => it.onSelect?.(row.original),
113
+ };
114
+ });
115
+ }
116
+
86
117
  function getExtraActionItems(row) {
87
118
  return (props.extraActions || [])
88
119
  .filter(it => !it.vIf || it.vIf(row.original))
@@ -92,6 +123,7 @@ function getExtraActionItems(row) {
92
123
  'vIf',
93
124
  'actionType',
94
125
  'tooltip',
126
+ 'warning',
95
127
  'to',
96
128
  'href',
97
129
  'disabled',
@@ -145,17 +177,61 @@ const pageSizeItems = [
145
177
  <template v-if="!action.vIf || action.vIf(row.original)">
146
178
 
147
179
  <template v-if="!action.actionType || action.actionType === 'button'">
148
- <u-tooltip :text="action.tooltip">
149
- <u-button
150
- variant="subtle"
151
- v-bind="radOmit(action, [ 'actionType', 'vIf', 'tooltip', 'to', 'href', 'disabled', 'onClick' ])"
152
- :to="resolveActionValue(action.to, row)"
153
- :href="resolveActionValue(action.href, row)"
154
- :disabled="resolveActionValue(action.disabled, row)"
155
- loading-auto
156
- @click="action.onClick?.(row.original)"
157
- />
158
- </u-tooltip>
180
+ <div class="flex flex-col items-end gap-1.5">
181
+ <u-tooltip :text="resolveActionValue(action.tooltip, row)">
182
+ <span class="inline-flex">
183
+ <u-button
184
+ variant="subtle"
185
+ v-bind="radOmit(action, actionButtonOmitKeys)"
186
+ :label="resolveActionValue(action.label, row)"
187
+ :to="resolveActionValue(action.to, row)"
188
+ :href="resolveActionValue(action.href, row)"
189
+ :disabled="resolveActionValue(action.disabled, row)"
190
+ loading-auto
191
+ @click.stop="action.onClick?.(row.original)"
192
+ />
193
+ </span>
194
+ </u-tooltip>
195
+ <template v-if="getActionWarning(action, row)">
196
+ <span class="flex items-center gap-1.5 text-sm text-warning max-w-sm">
197
+ <u-icon
198
+ name="lucide:triangle-alert"
199
+ class="shrink-0 size-4"
200
+ />
201
+ <span>
202
+ {{ getActionWarning(action, row) }}
203
+ </span>
204
+ </span>
205
+ </template>
206
+ </div>
207
+ </template>
208
+
209
+ <template v-else-if="action.actionType === 'split'">
210
+ <div class="flex">
211
+ <u-tooltip :text="resolveActionValue(action.tooltip, row)">
212
+ <span class="inline-flex">
213
+ <u-button
214
+ variant="subtle"
215
+ v-bind="radOmit(action, actionButtonOmitKeys)"
216
+ class="rounded-e-none"
217
+ :label="resolveActionValue(action.label, row)"
218
+ :disabled="resolveActionValue(action.disabled, row)"
219
+ loading-auto
220
+ @click.stop="action.onClick?.(row.original)"
221
+ />
222
+ </span>
223
+ </u-tooltip>
224
+ <u-dropdown-menu :items="getSplitActionItems(action, row)">
225
+ <u-button
226
+ variant="subtle"
227
+ :color="action.color"
228
+ icon="lucide:chevron-down"
229
+ class="rounded-s-none"
230
+ :disabled="resolveActionValue(action.disabled, row)"
231
+ @click.stop
232
+ />
233
+ </u-dropdown-menu>
234
+ </div>
159
235
  </template>
160
236
 
161
237
  <template v-else-if="action.actionType === 'separator'">
@@ -181,6 +257,7 @@ const pageSizeItems = [
181
257
  <u-button
182
258
  variant="subtle"
183
259
  icon="lucide:ellipsis-vertical"
260
+ @click.stop
184
261
  />
185
262
  </u-dropdown-menu>
186
263
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-unified-ui",
3
3
  "type": "module",
4
- "version": "0.5.12",
4
+ "version": "0.5.13",
5
5
  "main": "./nuxt.config.ts",
6
6
  "types": "./index.d.ts",
7
7
  "exports": {
@@ -522,7 +522,7 @@ Practical shortcuts:
522
522
 
523
523
  - `u-button`: `variant` → `color` → `size` → `icon` → label/value → `block` → `disabled` → `loading-auto` → events
524
524
  - `u-input` / `u-select*`: user-facing props (`:placeholder`, `:label`) → transient state (`:loading`, `:disabled`) → data source (`:items`) → `class` → `v-model` → events
525
- - Action objects (`:actions`, `:append-actions`, table row actions): `vIf` → `actionType` → `color` → `icon` → `label` → `tooltip` → `disabled` → `to` → `href` → `onClick`
525
+ - Action objects (`:actions`, `:append-actions`, table row actions): `vIf` → `actionType` → `color` → `icon` → `label` → `tooltip` → `warning` → `disabled` → `to` → `href` → `onClick` → `items`
526
526
  - `un-table`: `:columns` → `class` / `:ui` → `:loading` → `:data` → `hide-pagination` → `:total-items` → `v-model:items-per-page` → `v-model:current-page` → `sticky-actions` → `:actions` → `:extra-actions` → `:meta` (omit unused). Full table rules → [tables.md](tables.md)
527
527
  - Tab / select item objects: `value` → `icon` → `label`
528
528
 
@@ -12,7 +12,7 @@ Reference components in **kebab-case** in templates.
12
12
  | `un-card` | `un-card.vue` | Card + typography + action rows |
13
13
  | `un-typography` | `un-typography.vue` | Icon / title / subtitle / text / append |
14
14
  | `un-spinner` | `un-spinner.vue` | Spinning Lucide loader icon |
15
- | `un-table` | `un-table.vue` | `u-table` + row actions + pagination footer → [tables.md](tables.md) |
15
+ | `un-table` | `un-table.vue` | `u-table` + row actions (button / split / warning) + pagination footer → [tables.md](tables.md) |
16
16
 
17
17
  ## Composables
18
18
 
@@ -34,7 +34,7 @@ Do **not** add sort, filter, or selection props to `un-table`. Resource dashboar
34
34
 
35
35
  The actions column is added when **either** `actions` or `extraActions` has length. `#actions-cell` is then owned by the wrapper — do not override it.
36
36
 
37
- `to` / `href` / `disabled` on an action may be a value or `(row) => …`. `vIf(row)` hides the item. `onClick(row)` receives the original row. Buttons use `loading-auto`.
37
+ `to` / `href` / `disabled` / `label` / `tooltip` / `warning` on an action may be a value or `(row) => …`. `vIf(row)` hides the item. `onClick(row)` receives the original row. Action clicks use `@click.stop` so they do not select the row. Buttons use `loading-auto`.
38
38
 
39
39
  ## Attribute order on `<un-table>`
40
40
 
@@ -160,9 +160,19 @@ Two channels:
160
160
 
161
161
  Use `actions` for the one or two primary row operations (view, edit, delete). Use `extraActions` for the rest (assign, revoke, copy, archive). A vertical separator is inserted between the two groups automatically.
162
162
 
163
+ `actionType` values on `actions`:
164
+
165
+ | `actionType` | UI |
166
+ |--------------|----|
167
+ | omitted / `'button'` | Inline `u-button` |
168
+ | `'split'` | Primary button plus a chevron `u-dropdown-menu` |
169
+ | `'separator'` | Vertical rule between button groups |
170
+
171
+ `warning` is a string or `(row) => string | undefined` rendered under the button (triangle + text). Split `items` may be an array or `(row) => array`. Each item uses `label` (value or `(row) => …`) and `onSelect(row)` — do not put `onClick` on split items.
172
+
163
173
  Field order on **every** action object (omit unused):
164
174
 
165
- `vIf` → `actionType` → `color` → `icon` → `label` → `tooltip` → `disabled` → `to` → `href` → `onClick`
175
+ `vIf` → `actionType` → `color` → `icon` → `label` → `tooltip` → `warning` → `disabled` → `to` → `href` → `onClick` → `items`
166
176
 
167
177
  ```js
168
178
  const itemActions = computed(() => {
@@ -180,11 +190,30 @@ const itemActions = computed(() => {
180
190
  {
181
191
  actionType: 'separator',
182
192
  },
193
+ {
194
+ actionType: 'split',
195
+ icon: 'lucide:download',
196
+ tooltip: 'Download',
197
+ onClick: handleItemDownloadFile,
198
+ items: [
199
+ {
200
+ icon: 'lucide:file-text',
201
+ label: 'Download file',
202
+ onSelect: handleItemDownloadFile,
203
+ },
204
+ {
205
+ icon: 'lucide:file-archive',
206
+ label: 'Download archive',
207
+ onSelect: handleItemDownloadArchive,
208
+ },
209
+ ],
210
+ },
183
211
  {
184
212
  vIf: it => it.status !== 'archived',
185
213
  color: 'error',
186
214
  icon: 'lucide:trash',
187
- tooltip: 'Delete',
215
+ tooltip: it => it.role === 'admin' ? 'Admins cannot be deleted' : 'Delete',
216
+ warning: it => it.role === 'admin' ? 'Admins cannot be deleted' : undefined,
188
217
  disabled: it => it.role === 'admin',
189
218
  onClick: handleItemDelete,
190
219
  },
@@ -216,8 +245,9 @@ Rules:
216
245
  - Destructive: `color: 'error'` before `icon`.
217
246
  - Emphasized extra action: `color: 'primary'` before `icon`.
218
247
  - `{ actionType: 'separator' }` is a lone-key object between visual groups in `actions`.
248
+ - `{ actionType: 'split', items, onClick }` is a default click plus overflow choices; item handlers are `onSelect`.
219
249
  - Omit `variant: 'subtle'` — that is the button default.
220
- - `vIf` / `disabled` / `to` / `href` take `(row) => …` when they depend on the row.
250
+ - `vIf` / `disabled` / `to` / `href` / `label` / `tooltip` / `warning` take `(row) => …` when they depend on the row.
221
251
  - Do not put toolbar Create / Refresh on the row. Those belong on the parent `un-card` (`:actions` / `:append-actions`).
222
252
 
223
253
  Resource managers prepend custom row actions, then default Edit / Delete: