@iankibetsh/sh-tailwind 0.1.2 → 0.1.3
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 +36 -314
- package/dist/sh-tailwind.cjs.js +1 -1
- package/dist/sh-tailwind.es.js +723 -492
- package/documentation/actions.md +26 -0
- package/documentation/forms.md +96 -0
- package/documentation/getting-started.md +62 -0
- package/documentation/inputs.md +55 -0
- package/documentation/overlays.md +42 -0
- package/documentation/table.md +98 -0
- package/documentation/tabs.md +138 -0
- package/documentation/theming.md +42 -0
- package/package.json +3 -2
- package/src/components/navigation/ShTabs.vue +246 -0
- package/src/index.js +3 -0
- package/src/theme/defaultTheme.js +20 -0
package/README.md
CHANGED
|
@@ -1,26 +1,21 @@
|
|
|
1
1
|
# @iankibetsh/sh-tailwind
|
|
2
2
|
|
|
3
|
-
Vue 3 + Tailwind CSS v4 component library for Laravel backends, built on [`@iankibetsh/sh-core`](https://www.npmjs.com/package/@iankibetsh/sh-core). The Tailwind twin of `@iankibetsh/shframework` (Bootstrap): schema-driven forms, a server-driven data table with an offline cache, Tailwind-native dialogs/drawers, and confirm/silent action buttons — **zero runtime dependencies** beyond its peers.
|
|
3
|
+
Vue 3 + Tailwind CSS v4 component library for Laravel backends, built on [`@iankibetsh/sh-core`](https://www.npmjs.com/package/@iankibetsh/sh-core). The Tailwind twin of `@iankibetsh/shframework` (Bootstrap): schema-driven forms, a server-driven data table with an offline cache, Tailwind-native dialogs/drawers, tabs, and confirm/silent action buttons — **zero runtime dependencies** beyond its peers.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- [ShForm](#shform) · [Inputs & masks](#inputs--masks) · [PIN](#pin-input)
|
|
7
|
-
- [ShTable](#shtable) (+ [offline cache](#offline-first-cache))
|
|
8
|
-
- [Dialogs & drawers](#dialogs--drawers)
|
|
9
|
-
- [Actions](#actions)
|
|
10
|
-
- [Theming](#theming)
|
|
11
|
-
- [Exports](#exports) · [Migrating from shframework](#coming-from-shframework)
|
|
5
|
+
## Documentation
|
|
12
6
|
|
|
13
|
-
|
|
7
|
+
Each module has its own guide under [`documentation/`](documentation/):
|
|
14
8
|
|
|
15
|
-
|
|
|
9
|
+
| Module | What it covers |
|
|
16
10
|
|---|---|
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
| `
|
|
23
|
-
|
|
|
11
|
+
| [Getting started](documentation/getting-started.md) | Install, Tailwind `@source`, the plugin |
|
|
12
|
+
| [Forms](documentation/forms.md) | `ShForm` — schema, type inference, validation, wizard |
|
|
13
|
+
| [Inputs & masks](documentation/inputs.md) | Standalone inputs, money/pattern masks, PIN |
|
|
14
|
+
| [Table](documentation/table.md) | `ShTable` — actions, columns, offline-first cache |
|
|
15
|
+
| [Tabs](documentation/tabs.md) | `ShTabs` — slot / component / router modes |
|
|
16
|
+
| [Overlays](documentation/overlays.md) | `ShDialog` / `ShDrawer` and trigger/form helpers |
|
|
17
|
+
| [Actions](documentation/actions.md) | `ShConfirmAction` / `ShSilentAction` |
|
|
18
|
+
| [Theming](documentation/theming.md) | The three override layers + full export list |
|
|
24
19
|
|
|
25
20
|
## Install
|
|
26
21
|
|
|
@@ -28,335 +23,61 @@ Vue 3 + Tailwind CSS v4 component library for Laravel backends, built on [`@iank
|
|
|
28
23
|
npm i @iankibetsh/sh-tailwind @iankibetsh/sh-core pinia
|
|
29
24
|
```
|
|
30
25
|
|
|
31
|
-
Peers: `@iankibetsh/sh-core@^1`, `vue@^3.5`, `pinia@^3`, and `vue-router@^4||^5` (optional
|
|
32
|
-
|
|
33
|
-
### Tailwind CSS setup
|
|
34
|
-
|
|
35
|
-
With **`@tailwindcss/vite`** the library's classes are picked up automatically from the module graph — no extra config.
|
|
36
|
-
|
|
37
|
-
With the **PostCSS plugin or CLI**, add an `@source` directive so Tailwind scans the package:
|
|
38
|
-
|
|
39
|
-
```css
|
|
40
|
-
@import "tailwindcss";
|
|
41
|
-
@source "../node_modules/@iankibetsh/sh-tailwind";
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
The path is relative to the CSS file. **If components render unstyled, this line is what's missing.** The package ships its `src/` for exactly this reason.
|
|
45
|
-
|
|
46
|
-
The default theme is **light only** — it never emits `dark:` variants, so it won't fight your app's theme. Dark mode is opt-in via the [theme](#theming) option.
|
|
47
|
-
|
|
48
|
-
### Plugin
|
|
26
|
+
Peers: `@iankibetsh/sh-core@^1`, `vue@^3.5`, `pinia@^3`, and `vue-router@^4||^5` (optional). Register the plugin, then point Tailwind at the package — full steps in [Getting started](documentation/getting-started.md).
|
|
49
27
|
|
|
50
28
|
```js
|
|
51
|
-
import { createApp } from 'vue'
|
|
52
|
-
import { createPinia } from 'pinia'
|
|
53
29
|
import { ShTailwind } from '@iankibetsh/sh-tailwind'
|
|
54
|
-
|
|
55
|
-
const app = createApp(App)
|
|
56
|
-
app.use(createPinia())
|
|
57
|
-
app.use(ShTailwind, {
|
|
58
|
-
// every @iankibetsh/sh-core option passes through (API client, auth, session):
|
|
59
|
-
baseApiUrl: import.meta.env.VITE_APP_API_URL,
|
|
60
|
-
authMode: 'bearer', // or 'cookie' (Laravel Sanctum SPA)
|
|
61
|
-
sessionTimeout: 400,
|
|
62
|
-
enableTableCache: true, // default cache flag for ShTable
|
|
63
|
-
|
|
64
|
-
// sh-tailwind options:
|
|
65
|
-
theme: { form: { submitBtn: 'rounded-lg bg-indigo-600 px-4 py-2 text-white ...' } },
|
|
66
|
-
formComponents: { /* date: MyDatePicker */ } // replace input types globally
|
|
67
|
-
})
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
`createShTailwind(options)` is also exported (returns an installable plugin object). Installing the plugin also wires sh-core's API client, the `v-if-user-can` directive and auth-endpoint provides.
|
|
71
|
-
|
|
72
|
-
## ShForm
|
|
73
|
-
|
|
74
|
-
```vue
|
|
75
|
-
<ShForm
|
|
76
|
-
action="users"
|
|
77
|
-
method="post"
|
|
78
|
-
:fields="[
|
|
79
|
-
'name', // type inferred → text
|
|
80
|
-
'email', // inferred → email
|
|
81
|
-
{ name: 'amount', mask: 'money' }, // auto-formatted
|
|
82
|
-
{ name: 'role_id', label: 'Role', options: { url: 'roles' } },
|
|
83
|
-
{ name: 'tags', type: 'suggest', multiple: true, options: [...] },
|
|
84
|
-
{ name: 'bio', type: 'textarea', rows: 5, helper: 'Shown publicly' }
|
|
85
|
-
]"
|
|
86
|
-
:current-data="editingUser"
|
|
87
|
-
success-message="Saved!"
|
|
88
|
-
@success="reload"
|
|
89
|
-
/>
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Props
|
|
93
|
-
|
|
94
|
-
| Prop | Default | Notes |
|
|
95
|
-
|---|---|---|
|
|
96
|
-
| `action` | — (required) | endpoint |
|
|
97
|
-
| `method` | `'post'` | `post` \| `put` \| `patch` \| `delete` |
|
|
98
|
-
| `fields` | — (required) | array of strings or [field objects](#field-schema) |
|
|
99
|
-
| `currentData` | — | prefill for edit flows (seeds values, adds hidden `id`) |
|
|
100
|
-
| `steps` | — | `[{ title, fields: ['name', ...] }]` → wizard |
|
|
101
|
-
| `submitLabel` | `'Submit'` | submit button text |
|
|
102
|
-
| `successMessage` | — | toast on success |
|
|
103
|
-
| `retainData` | `false` | keep values after a successful submit |
|
|
104
|
-
| `preSubmit` | — | `(data) => false` aborts, an object replaces the payload, else proceeds |
|
|
105
|
-
| `hiddenId` | `true` | auto-append a hidden `id` when `currentData.id` exists |
|
|
106
|
-
| `disabled` | `false` | disable the whole form |
|
|
107
|
-
| `classes` | — | per-instance override of the `form` theme section |
|
|
108
|
-
|
|
109
|
-
**Events:** `success(data)`, `error(reason)`, `fieldChanged(name, value, data)`, `preSubmit(data)` — plus legacy aliases `formSubmitted` / `formError`.
|
|
110
|
-
|
|
111
|
-
### Field schema
|
|
112
|
-
|
|
113
|
-
```ts
|
|
114
|
-
{
|
|
115
|
-
name, // required (string shorthand → { name })
|
|
116
|
-
type, // omitted → inferred (see below)
|
|
117
|
-
label, // default startCase(name); false hides it
|
|
118
|
-
placeholder, helper, // helper renders as html under the field
|
|
119
|
-
required, // shows a * marker (server still validates)
|
|
120
|
-
value, // initial value (else from currentData[name])
|
|
121
|
-
options, // array | { url } → select/suggest data
|
|
122
|
-
multiple, allowCustom,// suggest behaviour
|
|
123
|
-
optionTemplate, // component to render each suggest option
|
|
124
|
-
min, max, step, // number / date
|
|
125
|
-
rows, // textarea
|
|
126
|
-
withTime, // date → datetime-local
|
|
127
|
-
mask, // input mask (see Inputs & masks)
|
|
128
|
-
digits, secret, // pin: box count / dot-mask
|
|
129
|
-
countryCode, detectCountry, // phone
|
|
130
|
-
component, // use a custom component for this field
|
|
131
|
-
props, // extra props v-bound onto the input
|
|
132
|
-
class // extra classes appended to the input
|
|
133
|
-
}
|
|
30
|
+
app.use(ShTailwind, { baseApiUrl: import.meta.env.VITE_APP_API_URL, authMode: 'bearer' })
|
|
134
31
|
```
|
|
135
32
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
**Validation:** Laravel `422` errors (`reason.response.data.errors`) render under each field and clear on focus; in a wizard the form jumps to the first step containing an error.
|
|
139
|
-
|
|
140
|
-
**Inside a dialog:** a successful submit auto-closes the host `ShDialog` (set `retain-on-success` on the dialog, or `retain-dialog` on `ShDialogForm`, to keep it open).
|
|
141
|
-
|
|
142
|
-
## Inputs & masks
|
|
143
|
-
|
|
144
|
-
Every input is standalone-usable with a `v-model` contract (`modelValue` + `update:modelValue`, and a `clearValidationErrors` emit used by ShForm). Override any type globally with the plugin's `formComponents`, or per-field with `component`.
|
|
145
|
-
|
|
146
|
-
### Input masks
|
|
147
|
-
|
|
148
|
-
Set `mask` on a field (or use `MaskedInput` directly) to auto-format as the user types:
|
|
33
|
+
## Components at a glance
|
|
149
34
|
|
|
150
|
-
|
|
151
|
-
|---|---|---|
|
|
152
|
-
| `'money'` | `1,234,567.89` | raw number `1234567.89` |
|
|
153
|
-
| `'integer'` | `1,234,567` | `1234567` |
|
|
154
|
-
| `{ type: 'money', prefix: 'KES ', decimals: 0 }` | `KES 50,000` | `50000` |
|
|
155
|
-
| `'#### #### #### ####'` | `4111 1111 1111 1111` | formatted string |
|
|
156
|
-
| `{ pattern: '#### ####', unmask: true }` | `1234 5678` | `12345678` (stripped) |
|
|
157
|
-
| `(value) => value.toUpperCase()` | `ABC` | `ABC` |
|
|
35
|
+
A small taste of each — follow the doc link for the full API.
|
|
158
36
|
|
|
159
|
-
|
|
37
|
+
### [Forms](documentation/forms.md)
|
|
160
38
|
|
|
161
39
|
```vue
|
|
162
|
-
<
|
|
163
|
-
<MaskedInput v-model="card" mask="#### #### #### ####" />
|
|
40
|
+
<ShForm action="users" :fields="['name', 'email', { name: 'amount', mask: 'money' }]" success-message="Saved!" />
|
|
164
41
|
```
|
|
165
42
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
### PIN input
|
|
169
|
-
|
|
170
|
-
`type: 'pin'` (or the standalone `PinInput`) renders segmented digit boxes — auto-advance, backspace-to-previous, arrow nav, and paste-distributes-a-code.
|
|
43
|
+
### [Inputs & masks](documentation/inputs.md)
|
|
171
44
|
|
|
172
45
|
```vue
|
|
173
|
-
|
|
174
|
-
{ name: 'otp', type: 'pin', digits: 6 }
|
|
175
|
-
{ name: 'wallet_pin', type: 'pin', digits: 4, secret: true }
|
|
176
|
-
|
|
177
|
-
<!-- standalone -->
|
|
46
|
+
<MaskedInput v-model="amount" mask="money" />
|
|
178
47
|
<PinInput v-model="otp" :length="6" />
|
|
179
|
-
<PinInput v-model="pin" :length="4" secret />
|
|
180
48
|
```
|
|
181
49
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
### Other inputs
|
|
185
|
-
|
|
186
|
-
| Component | Key props |
|
|
187
|
-
|---|---|
|
|
188
|
-
| `PhoneInput` | `countryCode` (default `'KE'`), `detectCountry` (opt-in `sh-country-code` lookup). Searchable country dropdown, **offline emoji flags** — no assets, no native select |
|
|
189
|
-
| `SelectInput` | `options` (array) **or** `url` (fetched with `{ all: 1 }`); coerces `{ id, label }` from loose shapes |
|
|
190
|
-
| `ShSuggest` | `options`/`url`, `multiple`, `allowCustom`, `optionTemplate`; debounced remote search, badges, keyboard nav |
|
|
191
|
-
| `PasswordInput` | show/hide eye toggle, `autocomplete` |
|
|
192
|
-
| `DateInput` | `withTime` → `datetime-local`, `min`, `max` |
|
|
193
|
-
| `NumberInput` | `min`, `max`, `step` |
|
|
194
|
-
| `TextInput` / `TextAreaInput` / `EmailInput` | `rows` (textarea) |
|
|
195
|
-
|
|
196
|
-
## ShTable
|
|
50
|
+
### [Table](documentation/table.md)
|
|
197
51
|
|
|
198
52
|
```vue
|
|
199
53
|
<ShTable
|
|
200
54
|
endpoint="users"
|
|
201
|
-
:columns="[
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
{ name: 'amount', format: 'money' }, // money | number | date | datetime
|
|
205
|
-
{ name: 'owner.name', label: 'Owner' }, // dot paths
|
|
206
|
-
{ name: 'status', component: StatusBadge } // custom cell (:row, :value)
|
|
207
|
-
]"
|
|
208
|
-
:actions="[
|
|
209
|
-
{ label: 'Edit', handler: row => (editing = row) }, // direct callback (no @event)
|
|
210
|
-
{ label: 'View', link: '/users/{id}' }, // router push / location
|
|
211
|
-
{ label: 'Suspend', url: 'users/{id}/suspend', confirm: 'Sure?' }, // swal confirm → POST → reload
|
|
212
|
-
{ label: 'Promote', emit: 'promote' } // → @promote(row), if you prefer events
|
|
213
|
-
]"
|
|
214
|
-
:multi-actions="[{ label: 'Archive', handler: rows => archive(rows), permission: 'archive-users' }]"
|
|
215
|
-
searchable has-range cache
|
|
216
|
-
row-link="/users/{id}"
|
|
217
|
-
@promote="onPromote"
|
|
55
|
+
:columns="['name', { name: 'amount', format: 'money' }]"
|
|
56
|
+
:actions="[{ label: 'Edit', handler: row => (editing = row) }]"
|
|
57
|
+
searchable cache
|
|
218
58
|
/>
|
|
219
59
|
```
|
|
220
60
|
|
|
221
|
-
###
|
|
222
|
-
|
|
223
|
-
An action runs the **first** matching key, so you pick the style per action:
|
|
224
|
-
|
|
225
|
-
| Key | Behaviour |
|
|
226
|
-
|---|---|
|
|
227
|
-
| `handler: (row) => {}` | **call your callback directly** — close over component state, mutate, then `table.reload()` via a ref |
|
|
228
|
-
| `emit: 'name'` | emits `@name(row)` (and a generic `@action('name', row)`) |
|
|
229
|
-
| `link: '/x/{id}'` | router push (or `location` without vue-router); `{id}` filled from the row |
|
|
230
|
-
| `url: 'x/{id}'` | POST (optionally behind `confirm: 'msg'`), toast the result, reload |
|
|
231
|
-
|
|
232
|
-
```js
|
|
233
|
-
const userActions = [
|
|
234
|
-
{ label: 'View', handler: (row) => openProfile(row) },
|
|
235
|
-
{ label: 'Promote', handler: (row) => { row.role = 'Manager'; table.value.reload() } },
|
|
236
|
-
{ label: 'Delete', class: 'text-red-600', handler: (row) => removeUser(row) }
|
|
237
|
-
]
|
|
238
|
-
// multi-actions get the selected rows array:
|
|
239
|
-
const bulk = [{ label: 'Email selected', handler: (rows) => emailAll(rows) }]
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### Props
|
|
243
|
-
|
|
244
|
-
| Prop | Default | Notes |
|
|
245
|
-
|---|---|---|
|
|
246
|
-
| `endpoint` | — (required) | data endpoint |
|
|
247
|
-
| `columns` | — (required) | [column schema](#column--action-schema) |
|
|
248
|
-
| `actions` | `[]` | row actions |
|
|
249
|
-
| `multiActions` | `[]` | bulk actions over selected rows (adds checkboxes + a floating bar) |
|
|
250
|
-
| `searchable` | `true` | debounced search box with an Exact toggle |
|
|
251
|
-
| `searchPlaceholder` | `'Search'` | |
|
|
252
|
-
| `hasRange` | `false` | from/to date filters |
|
|
253
|
-
| `perPage` | ShConfig `tablePerPage` (10) | persisted per table |
|
|
254
|
-
| `sortBy` / `sortMethod` | — / `'desc'` | initial sort |
|
|
255
|
-
| `paginationStyle` | ShConfig `tablePaginationStyle` | `'pages'` \| `'loadMore'` |
|
|
256
|
-
| `rowLink` | — | `'/users/{id}'` — whole row navigates |
|
|
257
|
-
| `cache` | `null` → ShConfig `enableTableCache` | offline cache (see below) |
|
|
258
|
-
| `networkTimeout` | `10000` | ms before falling back to cache |
|
|
259
|
-
| `reload` | — | change the value to force a reload |
|
|
260
|
-
| `emptyMessage` | `'No records found'` | |
|
|
261
|
-
| `classes` | — | override the `table` theme section |
|
|
262
|
-
|
|
263
|
-
**Events:** `rowClick(row)`, `loaded(response)`, `action(name, row)`, plus each action's own `emit` name. **Slots:** `#cell-<name>="{ row, value, index }"`, `#actions="{ row }"`, `#empty`. **Exposes:** `reload()`, `records`.
|
|
264
|
-
|
|
265
|
-
### Column / action schema
|
|
266
|
-
|
|
267
|
-
```ts
|
|
268
|
-
// column
|
|
269
|
-
{ name, label, format: 'money'|'number'|'date'|'datetime', sortable, component, show: () => bool, class }
|
|
270
|
-
// action
|
|
271
|
-
{ label, emit, handler: (row)=>{}, link: '/x/{id}', url: 'x/{id}', confirm: 'msg',
|
|
272
|
-
data, permission, show: (row)=>bool, class, failMessage }
|
|
273
|
-
// multi-action
|
|
274
|
-
{ label, handler: (rows)=>{}, permission, class }
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
The table sends the classic server contract — `page`, `per_page`, `filter_value`, `order_by`, `order_method`, `from`, `to`, `exact`, `paginated` — and expects a Laravel paginator response, so existing backends work unchanged.
|
|
278
|
-
|
|
279
|
-
### Offline-first cache
|
|
280
|
-
|
|
281
|
-
With `cache` (or the global `enableTableCache`):
|
|
282
|
-
|
|
283
|
-
1. The exact query's last response renders instantly from IndexedDB, then revalidates over the network.
|
|
284
|
-
2. Every fetched row is merged into a per-endpoint pool (capped at 3000, scoped per user id).
|
|
285
|
-
3. If the network is unreachable or slower than `network-timeout`, the query — **including search, sort and pagination** — runs locally against the pool and an amber offline banner shows. The next successful response clears it.
|
|
286
|
-
|
|
287
|
-
Helpers are exported for custom tables: `useTableData({ query, cacheEnabled, networkTimeout })`, `localQuery(rows, opts)`, and `clearTableCache()` (call on logout).
|
|
288
|
-
|
|
289
|
-
## Dialogs & drawers
|
|
61
|
+
### [Tabs](documentation/tabs.md)
|
|
290
62
|
|
|
291
63
|
```vue
|
|
292
|
-
<
|
|
293
|
-
<
|
|
294
|
-
<template #
|
|
295
|
-
</
|
|
296
|
-
|
|
297
|
-
<ShDrawer v-model:open="side" position="end" size="md" title="Filters">…</ShDrawer>
|
|
298
|
-
|
|
299
|
-
<ShDialogBtn title="Quick view"><template #trigger>Open</template> … </ShDialogBtn>
|
|
300
|
-
|
|
301
|
-
<ShDialogForm title="New user" action="users" :fields="['name','email']">
|
|
302
|
-
<template #trigger>Add user</template>
|
|
303
|
-
</ShDialogForm>
|
|
64
|
+
<ShTabs v-model:tab="active" :tabs="['overview', { key: 'activity', count: 12 }]" variant="pills">
|
|
65
|
+
<template #tab-overview>…</template>
|
|
66
|
+
<template #tab-activity>…</template>
|
|
67
|
+
</ShTabs>
|
|
304
68
|
```
|
|
305
69
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
**ShDrawer** adds `position` (`start|end|top|bottom`, default `end`); same size/static/events/slots.
|
|
309
|
-
|
|
310
|
-
**ShDialogBtn / ShDrawerBtn** render a trigger button + the overlay; props add `btnClass` and a `#trigger` slot. **ShDialogForm** = trigger + dialog + `ShForm` (all ShForm props pass through), re-keys the form on `currentData`, auto-closes ~600ms after success unless `retain-dialog`.
|
|
311
|
-
|
|
312
|
-
Dialogs stack — Escape closes the topmost first; body scroll locks while open; focus returns to the trigger on close. The low-level `useDialog({ isStatic, onOpen, onClose })` → `{ isOpen, zIndex, show, close, onBackdrop }` is exported if you're building your own overlay.
|
|
313
|
-
|
|
314
|
-
## Actions
|
|
70
|
+
### [Overlays](documentation/overlays.md)
|
|
315
71
|
|
|
316
72
|
```vue
|
|
317
|
-
<
|
|
318
|
-
|
|
319
|
-
</ShConfirmAction>
|
|
320
|
-
|
|
321
|
-
<ShSilentAction url="cache/flush" method="POST" success-message="Cache cleared">Flush cache</ShSilentAction>
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
- **ShConfirmAction** — swal confirm → POST → toast. Props: `url`, `data`, `title`, `message`, `loadingMessage`, `successMessage`, `failMessage`, `tag` (default `button`), `btnClass`. Events: `success` / `failed` / `canceled` (+ `actionSuccessful` / `actionFailed` / `actionCanceled` aliases).
|
|
325
|
-
- **ShSilentAction** — direct request, no confirm. Adds `method` (`GET|POST|PUT|DELETE`) and `disableSuccessMessage`.
|
|
326
|
-
|
|
327
|
-
## Theming
|
|
328
|
-
|
|
329
|
-
Three layers, most specific wins:
|
|
330
|
-
|
|
331
|
-
1. **Plugin `theme`** — deep-merged over `defaultTheme`. Sections: `form` (incl. `steps`), `inputs` (`select`, `pin`, `phone`, `suggest`, password toggle), `dialog`, `drawer`, `table` (incl. `pagination`), `buttons`. Import `defaultTheme` to see every key.
|
|
332
|
-
2. **Per-component `classes` prop** — overrides one section for that instance.
|
|
333
|
-
3. **Per-field `class`** — appended to that input.
|
|
334
|
-
|
|
335
|
-
```js
|
|
336
|
-
app.use(ShTailwind, { theme: { buttons: { primary: 'rounded-full bg-black px-5 py-2 text-white' } } })
|
|
73
|
+
<ShDialog v-model:open="open" title="Edit user" size="lg">…</ShDialog>
|
|
74
|
+
<ShDrawer v-model:open="side" position="end" title="Filters">…</ShDrawer>
|
|
337
75
|
```
|
|
338
76
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
## Exports
|
|
77
|
+
### [Actions](documentation/actions.md)
|
|
342
78
|
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
ShTailwind, createShTailwind, defaultTheme, useTheme,
|
|
346
|
-
SH_TW_THEME, SH_TW_COMPONENTS, SH_DIALOG_CONTEXT
|
|
347
|
-
// form
|
|
348
|
-
ShForm, ShFormSteps
|
|
349
|
-
// overlays
|
|
350
|
-
ShDialog, ShDrawer, ShDialogBtn, ShDrawerBtn, ShDialogForm, useDialog
|
|
351
|
-
// table
|
|
352
|
-
ShTable, ShTablePagination, useTableData, localQuery, shTableCache, clearTableCache
|
|
353
|
-
// actions
|
|
354
|
-
ShConfirmAction, ShSilentAction, ShSpinner
|
|
355
|
-
// inputs
|
|
356
|
-
TextInput, TextAreaInput, EmailInput, PasswordInput, PinInput, MaskedInput,
|
|
357
|
-
NumberInput, DateInput, SelectInput, PhoneInput, ShSuggest
|
|
358
|
-
// utilities & data
|
|
359
|
-
applyMask, maskMoney, maskPattern, countries
|
|
79
|
+
```vue
|
|
80
|
+
<ShConfirmAction url="users/9/suspend" title="Suspend user?" @success="reload">Suspend</ShConfirmAction>
|
|
360
81
|
```
|
|
361
82
|
|
|
362
83
|
## Coming from shframework
|
|
@@ -367,6 +88,7 @@ applyMask, maskMoney, maskPattern, countries
|
|
|
367
88
|
| `placeHolders` / `labels` / `helperTexts` objects | per-field `placeholder` / `label` / `helper` |
|
|
368
89
|
| `fillSelects` | `options: { url }` on the field |
|
|
369
90
|
| `ShTable` (Bootstrap, prop-heavy) | `ShTable` — `columns`/`actions` objects + offline cache |
|
|
91
|
+
| `ShTabs` + `ShDynamicTabs` | one `ShTabs` (slot / component / router modes) |
|
|
370
92
|
| `ShModal` / `ShModalBtn` / `ShModalForm` | `ShDialog` / `ShDialogBtn` / `ShDialogForm` |
|
|
371
93
|
| `ShCanvas` / `ShCanvasBtn` | `ShDrawer` / `ShDrawerBtn` |
|
|
372
94
|
| `shFormElementClasses` injection | `theme` plugin option |
|