@appsbd/vue3-appsbd-ui 1.0.18 → 1.0.20

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.
@@ -0,0 +1,69 @@
1
+ # AbAccordion — AI Reference
2
+
3
+ Group container for a vertically stacked set of collapsible sections (shadcn-style accordion). Controls open/close behavior (single vs. multiple open) and the shared icon position / title / body background colors for every child. Wrap `AbAccordionItem` children inside it. Use it instead of `AbTabs` when content should stack vertically and reveal on demand, rather than switching between panels.
4
+
5
+ ## Installation
6
+
7
+ Globally registered by the plugin — use `<ab-accordion>` directly, or `import { AbAccordion } from "vue3-appsbd-ui"`. No extra peer dependency required; the default trigger icon uses Bootstrap Icons (`bi bi-chevron-down`), already a peer dependency of this library.
8
+
9
+ ## Usage
10
+
11
+ ```vue
12
+ <template>
13
+ <ab-accordion>
14
+ <ab-accordion-item title="Is it accessible?" default-open>
15
+ <p>Yes. It follows the WAI-ARIA design pattern.</p>
16
+ </ab-accordion-item>
17
+ <ab-accordion-item title="Is it styled?">
18
+ <p>Yes. It ships with modern default styles.</p>
19
+ </ab-accordion-item>
20
+ </ab-accordion>
21
+ </template>
22
+ ```
23
+
24
+ Multiple items open at once, icon on the left, custom colors:
25
+
26
+ ```vue
27
+ <ab-accordion multiple icon-position="left" title-bg-color="#f8f5ff" body-bg-color="#fdfcff">
28
+ <ab-accordion-item title="First">...</ab-accordion-item>
29
+ <ab-accordion-item title="Second">...</ab-accordion-item>
30
+ </ab-accordion>
31
+ ```
32
+
33
+ Responsive: expanded, non-collapsible sections on large screens, accordion on small screens:
34
+
35
+ ```vue
36
+ <ab-accordion variant="responsive" breakpoint="md">
37
+ <ab-accordion-item title="Overview">...</ab-accordion-item>
38
+ <ab-accordion-item title="Details">...</ab-accordion-item>
39
+ </ab-accordion>
40
+ ```
41
+
42
+ ## Props
43
+
44
+ | Name | Type | Default | Description |
45
+ | --- | --- | --- | --- |
46
+ | `multiple` | `Boolean` | `false` | When `true`, more than one item can be open at once. When `false` (default), opening an item closes any other open item in the group. |
47
+ | `variant` | `String` | `"default"` | `"default"` (always an accordion) or `"responsive"`. With `"responsive"`, at viewport widths >= `breakpoint` every item is always expanded and shows no toggle icon/button (static sections, not clickable); below it, it behaves as a normal accordion, collapsed by default (unless an item has `defaultOpen`). |
48
+ | `breakpoint` | `String` | `"lg"` | Only used by `variant="responsive"`. Bootstrap breakpoint at/above which items become static: `"sm"` (576px), `"md"` (768px), `"lg"` (992px), `"xl"` (1200px), `"xxl"` (1400px). |
49
+ | `iconPosition` | `String` | `"right"` | Where the expand/collapse icon renders on every child item's trigger: `"left"` or `"right"`. Applies to the whole group, not set per item. |
50
+ | `titleBgColor` | `String` | `"#fff"` | Background color applied to every child item's title/trigger row. Accepts a hex or `rgb()`/`rgba()` string; the trigger's text color is automatically switched to a light or dark shade based on this background's luminance, so it stays readable regardless of the surrounding app theme (light or dark mode). |
51
+ | `bodyBgColor` | `String` | `"#fff"` | Background color applied to every child item's expanded body panel. Same automatic text-contrast behavior as `titleBgColor`. |
52
+
53
+ ## Events
54
+
55
+ None — open/close state is managed internally via `provide`/`inject` with child `AbAccordionItem`s.
56
+
57
+ ## Slots
58
+
59
+ | Name | Description |
60
+ | --- | --- |
61
+ | `default` | Accepts `AbAccordionItem` children. |
62
+
63
+ ## v-model
64
+
65
+ No — open/close state is internal per item (see [`AbAccordionItem`](./ai_ref_AbAccordionItem.md)'s `defaultOpen`), not bound on `AbAccordion`.
66
+
67
+ ## Provides
68
+
69
+ Provides an `apbdAccordion` context (`iconPosition`, `titleBgColor`, `bodyBgColor`, internal `isStatic`/`toggleItem`/`isItemOpen`) consumed by every descendant `AbAccordionItem`. An `AbAccordionItem` rendered outside an `AbAccordion` has nothing to inject and will not work.
@@ -0,0 +1,48 @@
1
+ # AbAccordionItem — AI Reference
2
+
3
+ Single collapsible row inside an [`AbAccordion`](./ai_ref_AbAccordion.md) group. Must be used inside an `AbAccordion` parent — it injects shared context (icon position, colors, open/close control) from there. The body slot accepts any content: plain text, an `AbCard`, or any other component.
4
+
5
+ ## Usage
6
+
7
+ ```vue
8
+ <ab-accordion>
9
+ <ab-accordion-item title="Is it accessible?" default-open>
10
+ <p>Yes. It follows the WAI-ARIA design pattern.</p>
11
+ </ab-accordion-item>
12
+ </ab-accordion>
13
+ ```
14
+
15
+ Custom icon (scoped slot receives `{ isOpen }`):
16
+
17
+ ```vue
18
+ <ab-accordion-item title="Custom icon">
19
+ <template #icon="{ isOpen }">
20
+ <i :class="isOpen ? 'bi bi-dash-lg' : 'bi bi-plus-lg'"></i>
21
+ </template>
22
+ <p>Body content...</p>
23
+ </ab-accordion-item>
24
+ ```
25
+
26
+ ## Props
27
+
28
+ | Name | Type | Default | Description |
29
+ | --- | --- | --- | --- |
30
+ | `title` | `String` | `""` | Label shown in the trigger row. Ignored if the `title` slot is provided. |
31
+ | `disabled` | `Boolean` | `false` | Prevents the item from being toggled (trigger renders as a disabled `<button>`). |
32
+ | `defaultOpen` | `Boolean` | `false` | Opens the item on mount. |
33
+
34
+ ## Slots
35
+
36
+ | Name | Description |
37
+ | --- | --- |
38
+ | `default` | The expandable body content. Accepts any markup or component. Animates open/closed with a smooth height transition (not an abrupt toggle). |
39
+ | `title` | Overrides the trigger label instead of using the `title` prop. |
40
+ | `icon` | Overrides the default chevron icon. Receives `{ isOpen: Boolean }` so a custom icon can reflect the item's expanded state. |
41
+
42
+ ## v-model
43
+
44
+ No — open/close state is internal, driven by `defaultOpen` on mount and toggled by clicking the trigger (or via the parent `AbAccordion`'s `multiple`/single-open rule).
45
+
46
+ ## Injects
47
+
48
+ Injects the `apbdAccordion` context provided by the parent `AbAccordion` (`iconPosition`, `titleBgColor`, `bodyBgColor`, `toggleItem`, `isItemOpen`).
@@ -0,0 +1,151 @@
1
+ # AbActionButton — AI Reference
2
+
3
+ Thin wrapper around `AbButton` for CRUD-style actions (add, edit, save, delete, cancel, and more). Each action resolves to a default label/icon/color preset; the component emits a single `action` event on click (after an optional confirmation step for actions like `delete`) and never performs the underlying business logic itself — the parent owns the workflow. Two modes, mutually exclusive:
4
+
5
+ - **Single** (`action` prop, a string) — renders one button. Typically used for a state-changing button where the parent changes `action` in response (e.g. `edit` → `save` → `add`).
6
+ - **Group** (`actions` prop, an array) — renders a whole row of action buttons from **one** component instance instead of repeating `<AbActionButton action="..." />` per action. Use this whenever a row/card needs several fixed actions at once (e.g. View + Edit + Delete on a table row).
7
+
8
+ When `actions` is a non-empty array it takes over rendering and `action`/`label`/`icon`/`color`/`variant`/`confirm`/`confirmOptions` (the single-mode props) are ignored — set those per-item inside the array instead.
9
+
10
+ Prefer this over a raw `AbButton` whenever a button's meaning is one of the CRUD-style actions, whether alone or as part of a fixed group.
11
+
12
+ ## Installation
13
+
14
+ Not globally registered — import explicitly. Icons are rendered via `@lucide/vue` (already a peer dependency).
15
+
16
+ ```js
17
+ import { AbActionButton } from "vue3-appsbd-ui";
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ Single action:
23
+
24
+ ```vue
25
+ <template>
26
+ <ab-action-button action="edit" @action="handleAction" />
27
+ </template>
28
+
29
+ <script setup>
30
+ function handleAction(action) {
31
+ console.log(action); // "edit"
32
+ }
33
+ </script>
34
+ ```
35
+
36
+ Group of actions — one component renders the whole row:
37
+
38
+ ```vue
39
+ <template>
40
+ <ab-action-button :actions="['view', 'edit', 'delete']" @action="handleRowAction" />
41
+ </template>
42
+
43
+ <script setup>
44
+ function handleRowAction(action) {
45
+ // "view" | "edit" | "delete"
46
+ }
47
+ </script>
48
+ ```
49
+
50
+ Per-item overrides (array items can be plain strings or objects — mix freely):
51
+
52
+ ```vue
53
+ <template>
54
+ <ab-action-button
55
+ :actions="[
56
+ 'view',
57
+ { action: 'edit', disabled: !canEdit },
58
+ { action: 'delete', confirmOptions: { message: 'This user will be permanently removed.' } },
59
+ { action: 'approve', label: 'Approve', icon: CircleCheckBig, color: 'success', show: isPending },
60
+ ]"
61
+ @action="handleRowAction"
62
+ />
63
+ </template>
64
+
65
+ <script setup>
66
+ import { CircleCheckBig } from '@lucide/vue';
67
+ </script>
68
+ ```
69
+
70
+ State-change workflow (single mode, parent decides what the button becomes next):
71
+
72
+ ```vue
73
+ <template>
74
+ <ab-action-button :action="rowAction" :loading="isSaving" @action="handleRowAction" />
75
+ </template>
76
+
77
+ <script setup>
78
+ import { ref } from 'vue';
79
+
80
+ const rowAction = ref('edit');
81
+ const isSaving = ref(false);
82
+
83
+ function handleRowAction(action) {
84
+ if (action === 'edit') {
85
+ rowAction.value = 'save';
86
+ } else if (action === 'save') {
87
+ isSaving.value = true;
88
+ saveToServer().then(() => {
89
+ isSaving.value = false;
90
+ rowAction.value = 'add';
91
+ });
92
+ }
93
+ }
94
+ </script>
95
+ ```
96
+
97
+ Delete with a custom confirmation message (built-in confirm uses `useAlert`):
98
+
99
+ ```vue
100
+ <ab-action-button
101
+ action="delete"
102
+ :confirm-options="{ message: 'This user will be permanently removed.' }"
103
+ @action="handleDelete"
104
+ />
105
+ ```
106
+
107
+ Custom action (not in the predefined set):
108
+
109
+ ```vue
110
+ <script setup>
111
+ import { CircleCheckBig } from '@lucide/vue';
112
+ </script>
113
+
114
+ <template>
115
+ <ab-action-button action="approve" label="Approve" :icon="CircleCheckBig" color="success" @action="handleApprove" />
116
+ </template>
117
+ ```
118
+
119
+ ## Props
120
+
121
+ | Name | Type | Default | Description |
122
+ | --- | --- | --- | --- |
123
+ | `action` | `String` | `null` | Single-mode action key. Presets: `add`, `edit`, `save`, `delete`, `cancel`, `view`, `close`, `submit`. Any other string is accepted as a custom action. Ignored when `actions` is a non-empty array. |
124
+ | `actions` | `Array` | `[]` | Group mode. Each item is either a plain action-key `String`, or an `Object`: `{ action, label?, icon?, color?, variant?, loading?, disabled?, confirm?, confirmOptions?, show?, ...otherAbButtonProps }`. `action` is required per item; every other key falls back the same way the single-mode props do (item override → preset → built-in default). `show` (`Boolean`, default `true`) conditionally excludes that button from the row. Unrecognized keys on an item (e.g. `size`, `isRounded`) are forwarded straight through to that item's `AbButton`, same as extra attrs in single mode. |
125
+ | `label` | `String` | `null` | Single mode only. Overrides the preset label. Falls back to the preset's label, then to the raw `action` string. |
126
+ | `icon` | `Component` \| `Boolean` | `null` | Single mode only. Overrides the preset icon (a `@lucide/vue` icon component). Pass `false` to force no icon. |
127
+ | `color` | `String` | `null` | Single mode only. Overrides the preset `AbButton` `color`. Falls back to the preset's color, then `"primary"`. |
128
+ | `variant` | `String` | `null` | Single mode only. Overrides the preset `AbButton` `variant` (`solid`, `outline`, `animated-round`). Falls back to the preset's variant, then `"solid"`. |
129
+ | `loading` | `Boolean` | `false` | Single mode only. Maps to `AbButton`'s `is-animated`. Also disables the button while `true`. In group mode, set `loading` per item instead. |
130
+ | `disabled` | `Boolean` | `false` | Single mode only. Disables the button (combined with `loading`). In group mode, set `disabled` per item instead. |
131
+ | `confirm` | `Boolean` | `null` | Single mode only. Whether to show a confirmation dialog before emitting the action. Falls back to the preset's default (`true` only for `delete`), then `false`. |
132
+ | `confirmOptions` | `Object` | `{}` | Single mode only. Shallow-merged into the confirmation dialog's options (`title`, `message`, `icon`, `confirmText`, `cancelText`, …) — same shape `useAlert`'s `alert()` accepts. |
133
+
134
+ Any other prop supported by `AbButton` (`size`, `mode`, `isRounded`, `isIconBtn`, `iconPosition`, `showIconDivider`, …) can be passed directly on `<AbActionButton>` and is forwarded through unchanged (standard Vue attrs fallthrough) — applied to the single button in single mode, or to **every** button in group mode (overridable per item, since an item's own matching key wins).
135
+
136
+ ## Events
137
+
138
+ | Event | Payload | Description |
139
+ | --- | --- | --- |
140
+ | `action` | `(action: String, event: MouseEvent)` | Fired once an action is approved — immediately, or after the user confirms (for actions with `confirm` truthy). In group mode, fired per-button with that button's own action key. The component performs no business logic itself. |
141
+
142
+ ## Slots
143
+
144
+ | Name | Description |
145
+ | --- | --- |
146
+ | `default` | Single mode only. Overrides the button's label content (defaults to the resolved label). |
147
+ | `action` | Group mode only. Overrides each button's label content. Scoped: `{ item, action }` — `item` is the fully resolved `{ action, label, icon, color, variant, loading, disabled, confirm, confirmOptions, show }` object for that button, `action` is its key. Defaults to `item.label`. |
148
+
149
+ ## v-model
150
+
151
+ None.
@@ -2,13 +2,18 @@
2
2
 
3
3
  Bootstrap badge wrapper for statuses or counts with size, variant, shape, and icon variations.
4
4
 
5
+ **Default variant is `solid`** — when asked to generate `AbBadge` with no specific style requested, generate it as-is (don't pass `variant` at all) and it renders as a plain filled badge, the way it's used everywhere in this library.
6
+
5
7
  ## Usage
6
8
 
7
9
  ```vue
8
10
  <template>
11
+ <!-- Default: solid variant (no variant prop needed) -->
9
12
  <ab-badge color="primary">New</ab-badge>
10
13
  <ab-badge color="success" is-rounded-pill>12</ab-badge>
11
- <ab-badge color="warning" is-outline>Pending</ab-badge>
14
+
15
+ <!-- Outline variant -->
16
+ <ab-badge color="warning" variant="outline">Pending</ab-badge>
12
17
  </template>
13
18
  ```
14
19
 
@@ -18,7 +23,8 @@ Bootstrap badge wrapper for statuses or counts with size, variant, shape, and ic
18
23
  | --- | --- | --- | --- |
19
24
  | `size` | `String` | `"md"` | Size of the badge (`sm`, `md`, `lg`). |
20
25
  | `color` | `String` | `"primary"` | Color theme (`primary`, `secondary`, `danger`, `warning`, `success`, `info`). |
21
- | `isOutline` | `Boolean` | `false` | Outlined style with transparent background. |
26
+ | `variant` | `String` | `"solid"` | Design variant — `"solid"` (plain filled badge) or `"outline"` (bordered, transparent background; matches `isOutline`). |
27
+ | `isOutline` | `Boolean` | `false` | Deprecated — equivalent to `variant="outline"`, kept for backward compatibility. Prefer `variant="outline"` in new code. |
22
28
  | `isRoundedPill` | `Boolean` | `false` | Transforms badge to a fully rounded pill shape. |
23
29
  | `isDot` | `Boolean` | `false` | Prepends a dot indicator layout. |
24
30
  | `isAdd` | `Boolean` | `false` | Adjusts styling for an add/plus icon badge. |
@@ -2,13 +2,17 @@
2
2
 
3
3
  Customizable button with optional loader animation and leading icon slot.
4
4
 
5
+ **Default variant is `solid`** — when asked to generate `AbButton` with no specific style requested, generate it as-is (don't pass `variant` at all) and it renders as a plain filled button, the way it's used everywhere in this library.
6
+
5
7
  ## Usage
6
8
 
7
9
  ```vue
8
10
  <template>
11
+ <!-- Default: solid variant (no variant prop needed) -->
9
12
  <ab-button color="primary">Save</ab-button>
10
13
 
11
- <ab-button color="secondary" is-outline show-icon-divider>
14
+ <!-- Outline variant -->
15
+ <ab-button color="secondary" variant="outline" show-icon-divider>
12
16
  <template #icon><i class="bi bi-plus-lg"></i></template>
13
17
  New Item
14
18
  </ab-button>
@@ -16,6 +20,9 @@ Customizable button with optional loader animation and leading icon slot.
16
20
  <ab-button color="primary" :is-animated="isSaving" is-hide-text-on-animate>
17
21
  Save
18
22
  </ab-button>
23
+
24
+ <!-- Preset: rounded + animated (text auto-hidden), no extra props -->
25
+ <ab-button color="success" variant="animated-round" :is-animated="isSaving">Save</ab-button>
19
26
  </template>
20
27
 
21
28
  <script setup>
@@ -31,12 +38,13 @@ const isSaving = ref(false);
31
38
  | `mode` | `String` | `"button"` | Sets the root tag (`button`, `link`, `router-link`). |
32
39
  | `type` | `String` | `"button"` | Native button type (`button`, `submit`, `reset`). |
33
40
  | `color` | `String` | `"primary"` | Color variant (primary, secondary, success, danger, warning, info, light, dark). |
41
+ | `variant` | `String` | `"solid"` | Design variant — `"solid"` (plain filled button), `"outline"` (border-only, matches `isOutline`) or `"animated-round"` (preset: acts as `isRounded` + text hidden while animating, without passing those props; the loader still shows only while `isAnimated` is `true`; combine with `isOutline` for an outline look). Drives which class is generated for `color` (e.g. `"outline"` → `btn-outline-{color}`). |
34
42
  | `size` | `String` | `"md"` | Button size (`xs`, `sm`, `md`, `lg`, `xl`, `xxl`). |
35
- | `isOutline` | `Boolean` | `false` | Applies the outline style for the selected color. |
43
+ | `isOutline` | `Boolean` | `false` | Deprecated — equivalent to `variant="outline"`, kept for backward compatibility. Prefer `variant="outline"` in new code. |
36
44
  | `isIconBtn` | `Boolean` | `false` | Formats the button styling for a single icon. |
37
45
  | `isRounded` | `Boolean` | `false` | Applies a fully rounded, pill-like border radius to the button. |
38
46
  | `isAnimated` | `Boolean` | `false` | When `true`, renders the loader SVG and optionally hides the label. |
39
- | `isHideTextOnAnimate` | `Boolean` | `false` | Hides the default slot content while `isAnimated` is `true`. |
47
+ | `isHideTextOnAnimate` | `Boolean` | `false` | Hides the default slot content while `isAnimated` is `true`. Forced to `true` whenever the button is rounded (`isRounded`, or `variant="animated-round"`) — an explicit `false` is ignored in that case. |
40
48
  | `showIconDivider` | `Boolean` | `false` | Renders a vertical divider between the `#icon` slot and the label. |
41
49
  | `iconPosition` | `String` | `"left"` | Placement of the icon and divider (`"left"` or `"right"`). |
42
50
 
@@ -1,33 +1,30 @@
1
1
  # AbCard — AI Reference
2
2
 
3
- Bootstrap-style card container with `header`, `body`, and `footer` slots. Visual variations (`tile-card`, `item-card`, `insight-card`, …) are applied through CSS classes on `containerClass` rather than separate components.
3
+ Bootstrap-style card container with `header`, `body`, and `footer` slots. Visual variations (`tile-card`, `item-card`, `insight-card`, …) are applied through CSS classes rather than separate components.
4
+
5
+ **Default variant is `default`** (a plain card, no layout class) — when asked to generate `AbCard` with no specific style requested, generate it as-is (don't pass `variant` at all).
4
6
 
5
7
  ## Props
6
8
 
7
9
  | Name | Type | Default | Description |
8
10
  | --- | --- | --- | --- |
9
- | `containerClass` | `String` | `undefined` | CSS class applied to the card root. |
11
+ | `containerClass` | `String` | `undefined` | CSS class applied to the card root. General-purpose — also still the way to reach a custom, one-off class that isn't one of the built-in `variant` values. |
10
12
  | `headerClass` | `String` | `""` | CSS class for the header section. |
11
13
  | `bodyClass` | `String` | `""` | CSS class for the body section. |
12
14
  | `footerClass` | `String` | `""` | CSS class for the footer section. |
15
+ | `variant` | `String` | `"default"` | Design variant — `"default"` (plain card), `"tile"` (→ `.tile-card`, stat blocks), `"item"` (→ `.item-card`, list rows), or `"insight"` (→ `.insight-card`, insight panels). |
13
16
  | `isBorderCard` | `Boolean` | `true` | Whether to display the default card border. |
14
17
  | `bgColorVariant` | `String` | `""` | Bootstrap color variant for background (`primary`, `success`, etc.). |
15
18
  | `borderBottomVariant` | `String` | `""` | Adds a colored bottom border with the specified variant. |
16
- | `isTileCard` | `Boolean` | `false` | Applies the `.tile-card` layout styles. |
19
+ | `isTileCard` | `Boolean` | `false` | Deprecated — equivalent to `variant="tile"`, kept for backward compatibility. Prefer `variant="tile"` in new code. |
17
20
  | `showBorder` | `Boolean` | `false` | Whether to display the header and footer borders. |
18
- | `variation` | `String` | `""` | Generic variation class to append to the root. |
21
+ | `variation` | `String` | `""` | Generic escape hatch: any string passed here is appended as a raw class on the root, unvalidated — for one-off/custom classes beyond the four `variant` values. |
19
22
 
20
23
  ## Usage
21
24
 
22
25
  ```vue
23
26
  <template>
24
- <ab-card is-tile-card :is-border-card="false">
25
- <template #body>
26
- <span class="tile-title">Total Revenue</span>
27
- <span class="tile-value">$12,480</span>
28
- </template>
29
- </ab-card>
30
-
27
+ <!-- Default: plain card (no variant prop needed) -->
31
28
  <ab-card container-class="shadow-sm" border-bottom-variant="primary" header-class="bg-light">
32
29
  <template #header>Card Title</template>
33
30
  <template #body>Card Content</template>
@@ -35,6 +32,25 @@ Bootstrap-style card container with `header`, `body`, and `footer` slots. Visual
35
32
  <ab-button size="sm">Action</ab-button>
36
33
  </template>
37
34
  </ab-card>
35
+
36
+ <!-- Tile variant: high-level stat blocks -->
37
+ <ab-card variant="tile" :is-border-card="false">
38
+ <template #body>
39
+ <span class="tile-title">Total Revenue</span>
40
+ <span class="tile-value">$12,480</span>
41
+ </template>
42
+ </ab-card>
43
+
44
+ <!-- Item variant: flexible list-row layout -->
45
+ <ab-card variant="item">
46
+ <template #body>...</template>
47
+ </ab-card>
48
+
49
+ <!-- Insight variant: insight/suggestion panel -->
50
+ <ab-card variant="insight">
51
+ <template #header>...</template>
52
+ <template #body>...</template>
53
+ </ab-card>
38
54
  </template>
39
55
  ```
40
56
 
@@ -48,4 +64,4 @@ Bootstrap-style card container with `header`, `body`, and `footer` slots. Visual
48
64
 
49
65
  ## Notes
50
66
 
51
- Do **not** create a new `.vue` file for card variations — define the variant as a CSS class in `src/styles/components/_card.scss` and pass it via `containerClass`.
67
+ Do **not** create a new `.vue` file for card variations — define the variant as a CSS class in `src/styles/components/_card.scss` and expose it through the `variant` enum (or `containerClass`/`variation` for a one-off class).
@@ -32,7 +32,7 @@ const themeColor = ref('blue');
32
32
  | --- | --- | --- | --- |
33
33
  | `modelValue` | `String` | `""` | Selected color `name` (v-model). |
34
34
  | `name` | `String` | `"color"` | Radio group name. |
35
- | `colors` | `Array` | `[]` | Each: `{ name, color, title? }`. |
35
+ | `colors` | `Array` | `[]` | Each: `{ name, color, title? }`. The selected swatch's outline ring uses that swatch's own `color` (gradient/`url()` values fall back to the theme color). |
36
36
  | `align` | `String` | `"left"` | Flex alignment (`left`, `center`, `right`, …). |
37
37
  | `borderRadius` | `String` | `"50%"` | Swatch border-radius. |
38
38
  | `size` | `String` | `"md"` | Item size (`xs`, `sm`, `md`, `lg`, `xl`, `xxl`). |
@@ -21,11 +21,26 @@ Confirmation popover with an async `onConfirm` handler and built-in loader. Usef
21
21
  <script setup>
22
22
  async function handleDelete(record) {
23
23
  await api.delete(record.id);
24
- // loader and popover close handled by the component
24
+ // loader is handled by the component; returning nothing here closes the
25
+ // popover automatically — see "onConfirm return contract" below for the
26
+ // other return shapes (chaining a second confirm step, a success/error alert).
25
27
  }
26
28
  </script>
27
29
  ```
28
30
 
31
+ ## `onConfirm` return contract
32
+
33
+ `onConfirm(itemData)` is awaited; what it resolves to (or throws) decides what happens next:
34
+
35
+ | Resolves to | Result |
36
+ | --- | --- |
37
+ | Nothing (`undefined`/`null`) — the common case, a plain `async () => { await doWork(); }` | Popover closes. |
38
+ | `{ next: 'close' }` | Popover closes (same as returning nothing; use when you also want to pass through other fields, but no other field is read here). |
39
+ | `{ next: 'confirm', title?, message?, icon?, confirmText?, cancelText?, onConfirm? }` | Popover swaps to a new `type: "confirm"` step (Cancel button shown) — for a secondary confirmation. |
40
+ | `{ next: 'confirm-ajax', ...same fields, onConfirm }` | Same as above but `type: "confirm-ajax"` for the next step. |
41
+ | Any other truthy object, e.g. `{ status: true \| false, message? }` | Popover swaps to a terminal `type: "alert"` panel (icon/color from `status`, message from `message`/`msg`, default "Completed successfully" / falls back to "Something went wrong" when `status === false`) — the user must click OK to dismiss. Use this only when you deliberately want that extra confirmation screen. |
42
+ | Throws | Popover shows an `type: "alert"` error panel ("Unexpected error"), dismissed by OK. |
43
+
29
44
  ## Props
30
45
 
31
46
  | Name | Type | Default | Description |
@@ -33,9 +33,9 @@ const datetime = ref(null);
33
33
  | `isRange` | `Boolean` | `false` | Enable date-range mode. |
34
34
  | `size` | `String` | `"md"` | Adjusts component size (`xs`, `sm`, `md`, `lg`, `xl`, `xxl`). |
35
35
  | `containerClass` | `String` | `"mb-3"` | Wrapper class. |
36
- | `width` | `String \| Number` | `undefined` | Explicit width on the `.apbd-date-time-container` wrapper. A number is treated as px (e.g. `220` -> `220px`); a string is used as-is (e.g. `"50%"`). |
37
- | `minWidth` | `String \| Number` | `undefined` | `min-width` on the wrapper (same number/string rules as `width`). |
38
- | `maxWidth` | `String \| Number` | `undefined` | `max-width` on the wrapper (same number/string rules as `width`) — caps growth inside a flex/grid parent without a fixed `width`. |
36
+ | `width` | `String \| Number` | `undefined` | Explicit width on the `.apbd-date-time-container` wrapper. A number is treated as px (e.g. `220` -> `220px`); a string is used as-is (e.g. `"50%"`). Applied as `min(<value>, 100%)`, so it shrinks to fit a narrower parent on small screens instead of overflowing it. |
37
+ | `minWidth` | `String \| Number` | `undefined` | `min-width` on the wrapper (same number/string rules as `width`, same `min(<value>, 100%)` clamp). |
38
+ | `maxWidth` | `String \| Number` | `undefined` | `max-width` on the wrapper (same number/string rules as `width`, same `min(<value>, 100%)` clamp) — caps growth inside a flex/grid parent without a fixed `width`. |
39
39
  | `hints` | `String` | `""` | Helper text. |
40
40
  | `isDisable` | `Boolean` | `false` | Disable the picker. |
41
41
  | `visibility` | `String` | `"click"` | v-calendar popover trigger. |
@@ -1,6 +1,6 @@
1
1
  # AbField — AI Reference
2
2
 
3
- Polymorphic field wrapper — renders text, textarea, select, multiselect, tag, checkbox, radio, toggle, or switch based on the `type` prop.
3
+ Polymorphic field wrapper — renders text, textarea, select, multiselect, tag, checkbox, radio, toggle, or switch based on the `type` prop. For `type="number"` it renders `AbInputField` (a plain native number input by default); add `variant="stepper"` to get `AbInputField`'s numeric-stepper behavior (min/max/step clamping, +/- buttons) instead.
4
4
 
5
5
  ## Usage
6
6
 
@@ -29,6 +29,26 @@ Polymorphic field wrapper — renders text, textarea, select, multiselect, tag,
29
29
  </template>
30
30
  ```
31
31
 
32
+ Number field — plain by default, stepper via `variant`:
33
+
34
+ ```vue
35
+ <template>
36
+ <!-- Plain native number input (default) -->
37
+ <ab-field type="number" v-model="form.age" name="age" label="Age" />
38
+
39
+ <!-- Numeric stepper: +/- buttons, min/max/step clamping -->
40
+ <ab-field
41
+ type="number"
42
+ variant="stepper"
43
+ v-model="form.qty"
44
+ name="qty"
45
+ label="Quantity"
46
+ :min="1"
47
+ :max="10"
48
+ />
49
+ </template>
50
+ ```
51
+
32
52
  ## Props
33
53
 
34
54
  | Name | Type | Default | Description |
@@ -50,7 +70,7 @@ Polymorphic field wrapper — renders text, textarea, select, multiselect, tag,
50
70
  | `options` | `Array` | `[]` | Options for select / checkbox / radio. |
51
71
  | `labelKey` | `String` | `"title"` | Option label property. |
52
72
  | `valueKey` | `String` | `"val"` | Option value property. |
53
- | `max` | `Number` | `-1` | Max selections (multiselect/tag); `-1` = unlimited. |
73
+ | `max` | `Number` | `-1` | Max selections (multiselect/tag); `-1` = unlimited. For a `type="number"` field, this doubles as the stepper's numeric ceiling (`min`/`max`/`step` clamping) — `-1`/unset means no ceiling. |
54
74
  | `size` | `String` | `undefined` | Field size. |
55
75
  | `object` | `Boolean` | `false` | Return full objects instead of values (multiselect). |
56
76
  | `searchable` | `Boolean` | `false` | Enable search (select). |
@@ -70,6 +90,11 @@ Polymorphic field wrapper — renders text, textarea, select, multiselect, tag,
70
90
  | `hideSelected` | `Boolean` | `true` | Hide already-selected items from dropdown. |
71
91
  | `loading` | `Boolean` | `false` | Show a loading spinner. |
72
92
  | `appendToBody` | `Boolean` | `true` | Teleport the dropdown to `<body>`. |
93
+ | `variant` | `String` | `undefined` | `type="number"` only. `"stepper"` renders `AbInputField`'s numeric stepper (forces a native number input, shows minus/plus buttons, enables `min`/`max`/`step` clamping) instead of a plain number input. |
94
+ | `min` | `Number \| String` | `null` | `type="number"` only. Minimum allowed value (native constraint always; also clamped + disables the minus button when `variant="stepper"`). |
95
+ | `step` | `Number \| String` | `1` | `type="number"` only. Increment/decrement amount (stepper variant) / native `step` attribute. |
96
+ | `showButtons` | `Boolean` | `true` | `type="number"` + `variant="stepper"` only. Whether to render the minus/plus buttons. |
97
+ | `isBorder` | `Boolean` | `false` | `type="number"` + `variant="stepper"` only. Show inner borders between minus/input/plus. Default is a seamless pill. |
73
98
 
74
99
  ## Events
75
100
 
@@ -20,6 +20,27 @@ UI or accept a custom one via slots.
20
20
  :max-size="5"
21
21
  />
22
22
 
23
+ <!-- isCrop: optional crop dialog after picking an image (Cancel = nothing is selected) -->
24
+ <ab-file-uploader v-model="avatar" is-crop :crop-aspect-ratio="1" />
25
+
26
+ <!-- maxWidth/maxHeight: the picked image file itself is downscaled to fit within 300x200
27
+ before it's emitted; the container keeps its normal width/height box either way -->
28
+ <ab-file-uploader v-model="avatar" :max-width="300" :max-height="200" />
29
+
30
+ <!-- variant="dropzone": icon on top, title + description, AbButton trigger, drag & drop.
31
+ :is-border="false" drops the dashed border and uses a box-shadow instead -->
32
+ <ab-file-uploader
33
+ v-model="avatar"
34
+ variant="dropzone"
35
+ :is-border="false"
36
+ title="Upload pictures"
37
+ description="Videos must be less than 30 MB and photos must be less than 2 MB in size."
38
+ button-text="Upload"
39
+ :width="360"
40
+ >
41
+ <template #icon><i class="bi bi-cloud-arrow-up"></i></template>
42
+ </ab-file-uploader>
43
+
23
44
  <ab-file-uploader v-model="avatar" :max-size="5">
24
45
  <template #dial>
25
46
  <div class="my-drop-zone">Drop files here</div>
@@ -40,14 +61,25 @@ function handleFiles(files) { console.log('Selected files:', files); }
40
61
  | Name | Type | Default | Description |
41
62
  | --- | --- | --- | --- |
42
63
  | `modelValue` | `File \| Array \| String` | `null` | Selected file (or URL string / array). |
64
+ | `isCrop` | `Boolean` | `false` | Image mode only (ignored for `type="file"`): after an image is picked a crop dialog opens with **Crop** and **Cancel** buttons. Crop selects the cropped image (jpeg/png/webp keep their format, others such as gif become png); Cancel closes the dialog and selects nothing (a previously selected image stays). |
65
+ | `cropAspectRatio` | `Number` | `null` | Width / height ratio the crop box is locked to (`1` = square, `16 / 9`, …). `null` = free-form. Only used with `isCrop`. |
43
66
  | `maxSize` | `Number` | `2.0` | Max file size in MB. |
44
67
  | `label` | `String` | `""` | Field label. |
45
68
  | `containerClass` | `String` | `undefined` | Wrapper class (falls back to globalConfig.inputContainerClass). |
46
69
  | `type` | `'image' \| 'file'` | `'image'` | Upload mode. `image` only accepts images and always shows a thumbnail preview. `file` accepts any file listed in `allowedTypes`; non-image files render an extension icon instead of a preview. |
47
70
  | `allowedTypes` | `Array<String>` | `[]` | Allowed extensions, no dot (e.g. `['pdf', 'docx']`). **Required when `type="file"`** — logs a console error and rejects every selected file when empty. Also drives the input's `accept` attribute. Ignored in `image` mode. |
48
71
  | `showFileName` | `Boolean` | `null` | Whether to render the filename below the container. `null` auto-picks by `type` (off for `image`, on for `file`); pass `true`/`false` to override either mode. |
49
- | `width` | `String \| Number` | `undefined` | Container width. Number is treated as px. Falls back to the default `100px`. |
50
- | `height` | `String \| Number` | `undefined` | Container height. Number is treated as px. Falls back to the default `73px`. |
72
+ | `width` | `String \| Number` | `undefined` | Container width. Number is treated as px. Falls back to the default `100px`. Not affected by `maxWidth`/`maxHeight` — the preview box always fits the image via `object-fit: contain`. |
73
+ | `height` | `String \| Number` | `undefined` | Container height. Number is treated as px. Falls back to the default `73px`. Not affected by `maxWidth`/`maxHeight`. |
74
+ | `maxWidth` | `String \| Number` | `undefined` | Applies to any picked image file (number = px). If the image's actual width exceeds this, the file itself is downscaled (aspect ratio kept, canvas-based, never upscaled) before it's shown/emitted — so the file a consumer later uploads is already capped. Does not resize the preview container. |
75
+ | `maxHeight` | `String \| Number` | `undefined` | Same as `maxWidth`, for height. Both are applied together as a "contain" cap — the image is scaled down by whichever ratio is smaller so it fits within `maxWidth x maxHeight`. |
76
+ | `variant` | `'default' \| 'dropzone'` | `'default'` | `dropzone` renders a larger card: icon on top, `title`, `description`, then an `AbButton` trigger; clicking the card or dropping a file on it selects a file. `default` and the custom-slot designs are unchanged. |
77
+ | `isBorder` | `Boolean` | `true` | `variant="dropzone"` only. `true` = dashed border, `false` = borderless with a box-shadow. |
78
+ | `title` | `String` | `""` | `variant="dropzone"` only. Bold heading under the icon; hidden when empty (unless the `title` slot is used). |
79
+ | `description` | `String` | `""` | `variant="dropzone"` only. Muted helper text under the title; hidden when empty (unless the `description` slot is used). |
80
+ | `buttonText` | `String` | `"Upload"` | `variant="dropzone"` only. Label of the trigger button. |
81
+ | `buttonColor` | `String` | `"primary"` | `variant="dropzone"` only. `AbButton` `color` of the trigger button. |
82
+ | `buttonSize` | `String` | `undefined` | `variant="dropzone"` only. `AbButton` `size` of the trigger button; falls back to the global `size`. |
51
83
 
52
84
  ## Events
53
85
 
@@ -63,6 +95,14 @@ function handleFiles(files) { console.log('Selected files:', files); }
63
95
  | `label` | Custom label. |
64
96
  | `dial` | Custom uploader UI (replaces the default design). |
65
97
  | `default` | Alternative custom UI slot. |
98
+ | `icon` | Replaces the empty-state icon — the top icon in `variant="dropzone"`, the image/file icon in the default design. Not shown once a file is picked. |
99
+ | `remove-icon` | Replaces the icon on the hover-to-remove overlay over a picked image / file (both designs). |
100
+ | `title` | `variant="dropzone"` only. Replaces the `title` text. |
101
+ | `description` | `variant="dropzone"` only. Replaces the `description` text. |
102
+ | `button` | `variant="dropzone"` only. Replaces the trigger button's label. |
103
+ | `crop-title` | `isCrop` only. Replaces the crop dialog title (default `Crop image`). |
104
+ | `crop-cancel` | `isCrop` only. Replaces the crop dialog's Cancel button label. |
105
+ | `crop-apply` | `isCrop` only. Replaces the crop dialog's Crop button label. |
66
106
 
67
107
  ## v-model
68
108
 
@@ -71,6 +111,7 @@ previews), or `null`.
71
111
 
72
112
  ## Notes
73
113
 
114
+ - In `variant="dropzone"` the icon area has a fixed height (88px) that a picked image fills (aspect ratio kept via `object-fit: contain`, never wider than the card), so the card has the same size with and without an image; override the height with the `--afu-preview-height` CSS variable. A picked non-image file shows its extension icon at 64px.
74
115
  - Icon mapping for non-image files (pdf, zip, doc/docx, xls/xlsx, ppt/pptx, video) comes from the
75
116
  shared `useFileValidator()` composable's `getFileIconByExt`, the same mapping `AbChatInput` uses.
76
117
  - In `image` mode, validation is unchanged from before: only jpg/jpeg/png/gif/webp are accepted and