jattac.libs.web.zest-button 1.2.1 → 1.2.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 +33 -325
- package/dist/ZestButton.d.ts +6 -2
- package/dist/ZestContext.d.ts +9 -0
- package/dist/ZestProvider.d.ts +8 -0
- package/dist/hooks/useBusyState.d.ts +20 -0
- package/dist/hooks/useConfirmation.d.ts +13 -0
- package/dist/hooks/useThemeDetection.d.ts +1 -0
- package/dist/hooks/useZestConfig.d.ts +2 -0
- package/dist/index.cjs.js +376 -110
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +18 -2
- package/dist/index.esm.js +375 -111
- package/dist/index.esm.js.map +1 -1
- package/dist/semanticTypeDefaults.d.ts +4 -0
- package/docs/api.md +119 -0
- package/docs/breaking-changes.md +52 -0
- package/docs/configuration.md +192 -0
- package/docs/development.md +77 -0
- package/docs/examples.md +215 -0
- package/docs/features.md +113 -0
- package/package.json +24 -7
package/docs/api.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# API Reference: The Technical Blueprint
|
|
2
|
+
|
|
3
|
+
This document provides an exhaustive reference for all `ZestButton` props and type definitions.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
### `ZestButtonProps`
|
|
8
|
+
|
|
9
|
+
The `ZestButton` component accepts all standard HTML `<button>` attributes (e.g., `disabled`, `type`, `name`, `className`) in addition to its own custom configuration prop, `zest`.
|
|
10
|
+
|
|
11
|
+
| Prop Name | Type | Default | Description |
|
|
12
|
+
| :--- | :--- | :--- | :--- |
|
|
13
|
+
| `zest` | `ZestCustomProps` | `{}` | An object containing all custom configuration for the button's behavior and appearance. See `ZestCustomProps` below for details. |
|
|
14
|
+
| `...rest`| `React.ButtonHTMLAttributes` | | All other standard button props are passed directly to the underlying `<button>` element. |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
### Type Definitions
|
|
19
|
+
|
|
20
|
+
The `zest` prop is a configuration object that follows the `ZestCustomProps` interface. Its properties are detailed below.
|
|
21
|
+
|
|
22
|
+
#### `ZestCustomProps`
|
|
23
|
+
|
|
24
|
+
This is the main configuration object passed to the `zest` prop.
|
|
25
|
+
|
|
26
|
+
| Prop Name | Type | Default | Description |
|
|
27
|
+
| :--- | :--- | :--- | :--- |
|
|
28
|
+
| `visualOptions` | `VisualOptions` | `{}` | Controls the button's appearance, including variant, size, and icons. |
|
|
29
|
+
| `busyOptions` | `BusyOptions` | `{}` | Configures behavior for asynchronous operations. |
|
|
30
|
+
| `successOptions` | `SuccessOptions` | `{}` | Configures feedback after a successful or failed operation. |
|
|
31
|
+
| `confirmOptions` | `ConfirmOptions` | `undefined` | If provided, enables the "click-to-confirm" workflow. |
|
|
32
|
+
| `isDefault` | `boolean` | `false` | If true, the button can be triggered by the `Enter` key. |
|
|
33
|
+
| `theme` | `'light' \| 'dark' \| 'system'` | `'system'` | Overrides the automatic theme detection. |
|
|
34
|
+
| `buttonStyle` | `'solid' \| 'outline' \| 'text' \| 'dashed'`| `'solid'` | Defines the visual style of the button. |
|
|
35
|
+
| `semanticType` | `SemanticType` | `undefined` | Defines the semantic type of the button, providing default visuals and behaviors. Extensible via module augmentation. |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
#### `ZestGlobalConfig`
|
|
40
|
+
|
|
41
|
+
This is the configuration object passed to the `config` prop of the `ZestProvider`.
|
|
42
|
+
|
|
43
|
+
| Prop Name | Type | Default | Description |
|
|
44
|
+
| :--- | :--- | :--- | :--- |
|
|
45
|
+
| `defaultProps` | `ZestCustomProps` | `{}` | A set of `ZestCustomProps` that will be applied to all `ZestButton` instances within the provider's scope. |
|
|
46
|
+
| `semanticTypeDefaults` | `Partial<Record<string, Partial<ZestCustomProps>>>` | `{}` | A map of semantic types to `ZestCustomProps`. This allows you to define defaults for custom semantic types or override the library's built-in defaults. |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
#### `VisualOptions`
|
|
51
|
+
|
|
52
|
+
Controls the button's appearance.
|
|
53
|
+
|
|
54
|
+
| Prop Name | Type | Default | Description |
|
|
55
|
+
| :--- | :--- | :--- | :--- |
|
|
56
|
+
| `variant` | `'standard' \| 'success' \| 'danger'` | `'standard'`| The color scheme of the button. |
|
|
57
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | The size of the button, affecting padding and font size. |
|
|
58
|
+
| `fullWidth` | `boolean` | `false` | If true, the button expands to the full width of its parent. |
|
|
59
|
+
| `iconLeft` | `React.ReactNode` | `undefined` | A React node (e.g., an icon component) to display on the left. |
|
|
60
|
+
| `iconRight` | `React.ReactNode` | `undefined` | A React node to display on the right. |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
#### `BusyOptions`
|
|
65
|
+
|
|
66
|
+
Configures behavior during asynchronous `onClick` operations.
|
|
67
|
+
|
|
68
|
+
| Prop Name | Type | Default | Description |
|
|
69
|
+
| :--- | :--- | :--- | :--- |
|
|
70
|
+
| `handleInternally` | `boolean` | `true` | If true, automatically manages busy state when `onClick` returns a Promise. |
|
|
71
|
+
| `preventRageClick` | `boolean` | `true` | If true, disables the button while it is in a busy, success, or fail state. |
|
|
72
|
+
| `minBusyDurationMs`| `number` | `500` | Ensures the spinner is shown for at least this long (in ms) to prevent visual flickering on fast network requests. |
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
#### `SuccessOptions`
|
|
77
|
+
|
|
78
|
+
Configures the visual feedback after an operation completes.
|
|
79
|
+
|
|
80
|
+
| Prop Name | Type | Default | Description |
|
|
81
|
+
| :--- | :--- | :--- | :--- |
|
|
82
|
+
| `showCheckmark` | `boolean` | `true` | If true, displays an animated checkmark when the `onClick` Promise resolves successfully. |
|
|
83
|
+
| `showFailIcon` | `boolean` | `true` | If true, displays an animated 'X' when the `onClick` Promise rejects or the confirmation timer expires. |
|
|
84
|
+
| `autoResetAfterMs`| `number` | `2000` | The duration (in ms) to show the success/fail icon before the button resets to its normal state. |
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
#### `ConfirmOptions`
|
|
89
|
+
|
|
90
|
+
If this object is provided, the button will require two clicks to fire the `onClick` event.
|
|
91
|
+
|
|
92
|
+
| Prop Name | Type | Default | Description |
|
|
93
|
+
| :--- | :--- | :--- | :--- |
|
|
94
|
+
| `displayLabel` | `string` | **(Required)**| The text to show during the confirmation phase (e.g., "Confirm?"). The countdown timer is appended automatically. |
|
|
95
|
+
| `timeoutSecs` | `number` | **(Required)**| The number of seconds the user has to click the button a second time to confirm the action. |
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
#### `SemanticType`
|
|
100
|
+
|
|
101
|
+
The `SemanticType` defines common button actions, allowing `ZestButton` to automatically apply default visuals (e.g., icons, variants) and behaviors (e.g., confirmation prompts). This type is extensible through TypeScript module augmentation.
|
|
102
|
+
|
|
103
|
+
**Built-in Semantic Types:**
|
|
104
|
+
`'add'`, `'save'`, `'submit'`, `'edit'`, `'update'`, `'delete'`, `'remove'`, `'cancel'`, `'close'`, `'view'`, `'details'`, `'download'`, `'upload'`, `'refresh'`, `'reload'`, `'print'`, `'share'`, `'confirm'`.
|
|
105
|
+
|
|
106
|
+
**Extensibility:** Developers can extend this list to include custom semantic types by augmenting the `CustomZestSemanticTypes` interface in their project. For example:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// your-project/src/typings/zest-button.d.ts
|
|
110
|
+
import 'jattac.libs.web.zest-button';
|
|
111
|
+
|
|
112
|
+
declare module 'jattac.libs.web.zest-button' {
|
|
113
|
+
export interface CustomZestSemanticTypes {
|
|
114
|
+
archive: 'archive';
|
|
115
|
+
publish: 'publish';
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
After augmentation, `'archive'` and `'publish'` would be valid `SemanticType` values, available for autocompletion and type-checking.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Breaking Changes: The Upgrade Path
|
|
2
|
+
|
|
3
|
+
This document lists significant changes between versions that might require modifications to your existing codebase.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Version 1.2.0
|
|
8
|
+
|
|
9
|
+
### Encapsulated Custom Props under `zest` Object
|
|
10
|
+
|
|
11
|
+
To improve maintainability, reduce prop-drilling, and provide a clearer API surface, all custom `ZestButton` properties have been consolidated under a single `zest` prop. Previously, these properties were passed directly to the `ZestButton` component.
|
|
12
|
+
|
|
13
|
+
This change allows for better organization of configuration options (e.g., `visualOptions`, `busyOptions`, `confirmOptions`) and prepares the component for future global configuration contexts.
|
|
14
|
+
|
|
15
|
+
**Before:**
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
<ZestButton
|
|
19
|
+
variant="success"
|
|
20
|
+
size="lg"
|
|
21
|
+
fullWidth={true}
|
|
22
|
+
minBusyDurationMs={1000}
|
|
23
|
+
preventRageClick={false}
|
|
24
|
+
confirmOptions={{ displayLabel: "Delete?", timeoutSecs: 5 }}
|
|
25
|
+
>
|
|
26
|
+
My Button
|
|
27
|
+
</ZestButton>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**After:**
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
<ZestButton
|
|
34
|
+
zest={{
|
|
35
|
+
visualOptions: {
|
|
36
|
+
variant: "success",
|
|
37
|
+
size: "lg",
|
|
38
|
+
fullWidth: true,
|
|
39
|
+
},
|
|
40
|
+
busyOptions: {
|
|
41
|
+
minBusyDurationMs: 1000,
|
|
42
|
+
preventRageClick: false,
|
|
43
|
+
},
|
|
44
|
+
confirmOptions: {
|
|
45
|
+
displayLabel: "Delete?",
|
|
46
|
+
timeoutSecs: 5,
|
|
47
|
+
},
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
50
|
+
My Button
|
|
51
|
+
</ZestButton>
|
|
52
|
+
```
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Configuration: The Control Panel
|
|
2
|
+
|
|
3
|
+
This document explains how to configure `ZestButton` on a component and global level.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
### Overview
|
|
8
|
+
|
|
9
|
+
Currently, `ZestButton` is primarily configured on a per-component basis via the `zest` prop. This provides the most explicit and direct control over each button's behavior and appearance.
|
|
10
|
+
|
|
11
|
+
However, there are ways to manage themes and a clear path for future global configuration.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
### Theme Configuration
|
|
16
|
+
|
|
17
|
+
One of the most powerful configuration options is theme control. `ZestButton` can automatically adapt to the user's operating system preferences, or you can lock it to a specific theme.
|
|
18
|
+
|
|
19
|
+
The `theme` prop within the `zest` object accepts one of three values:
|
|
20
|
+
|
|
21
|
+
- `'system'` (Default): The button listens for the system's color scheme (`prefers-color-scheme`) and applies the `light` or `dark` theme automatically.
|
|
22
|
+
- `'light'`: Forces the button to use the light theme, regardless of system settings.
|
|
23
|
+
- `'dark'`: Forces the button to use the dark theme, regardless of system settings.
|
|
24
|
+
|
|
25
|
+
#### Order of Precedence
|
|
26
|
+
|
|
27
|
+
The `zest.theme` prop has the highest precedence.
|
|
28
|
+
|
|
29
|
+
1. **`zest.theme` Prop (`light` or `dark`)**: If set, this value is always used.
|
|
30
|
+
2. **`zest.theme` Prop (`system`)**: If set to `system` (or if undefined), the button will defer to the user's OS-level preference.
|
|
31
|
+
|
|
32
|
+
#### Example: Forcing a Theme
|
|
33
|
+
|
|
34
|
+
This is useful for sections of your UI that have a fixed background color, where you need the button's theme to match its immediate parent rather than the overall page theme.
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import ZestButton from 'jattac.libs.web.zest-button';
|
|
38
|
+
|
|
39
|
+
const PinnedFooter = () => (
|
|
40
|
+
<div style={{ background: '#333', padding: '1rem' }}>
|
|
41
|
+
{/* This button's text will be light, matching the dark background */}
|
|
42
|
+
<ZestButton zest={{ theme: 'dark' }}>
|
|
43
|
+
Action in Dark Footer
|
|
44
|
+
</ZestButton>
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
### Global Configuration with `ZestProvider`
|
|
52
|
+
|
|
53
|
+
The `ZestProvider` component is now implemented, allowing you to streamline `ZestButton` configuration across your entire application. You can define a set of default `zest` properties that all `ZestButton` instances within its scope will inherit.
|
|
54
|
+
|
|
55
|
+
#### Usage
|
|
56
|
+
|
|
57
|
+
Wrap your application (or specific sections) with the `ZestProvider` and pass a configuration object to its `config` prop. The `config` prop expects an object of type `ZestGlobalConfig`, which contains a `defaultProps` field of type `ZestCustomProps`.
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
// In your main App.tsx file
|
|
61
|
+
|
|
62
|
+
import { ZestProvider } from 'jattac.libs.web.zest-button';
|
|
63
|
+
import MyRoutes from './MyRoutes';
|
|
64
|
+
|
|
65
|
+
const appZestConfig = {
|
|
66
|
+
defaultProps: {
|
|
67
|
+
visualOptions: {
|
|
68
|
+
size: 'sm', // Make all buttons small by default
|
|
69
|
+
},
|
|
70
|
+
busyOptions: {
|
|
71
|
+
minBusyDurationMs: 300, // Shorten the busy duration app-wide
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const App = () => (
|
|
77
|
+
<ZestProvider config={appZestConfig}>
|
|
78
|
+
<MyRoutes />
|
|
79
|
+
</ZestProvider>
|
|
80
|
+
);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### Precedence with the `ZestProvider`
|
|
84
|
+
|
|
85
|
+
Property configurations are merged in a "deep merge" fashion with the following order of precedence (where the last one wins):
|
|
86
|
+
|
|
87
|
+
1. **Global `defaultProps`**: Props defined in the `ZestProvider`'s `config.defaultProps` object. This is the base layer of styling.
|
|
88
|
+
2. **Built-in Semantic Defaults**: The library's own defaults for a given `semanticType` (e.g., the `success` variant for `save`).
|
|
89
|
+
3. **Custom Semantic Defaults**: **(New!)** Defaults for a `semanticType` that you provide in the `ZestProvider`'s `config.semanticTypeDefaults` object. This allows you to override the library's defaults or create new ones.
|
|
90
|
+
4. **Local `zest` Props**: The props passed directly to a specific `<ZestButton>` instance. This gives you the ultimate granular control.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### Advanced: Customizing Semantic Defaults
|
|
95
|
+
|
|
96
|
+
This is one of the most powerful features of the `ZestProvider`. You can define application-wide styles and behaviors for any `semanticType`. This is perfect for creating a consistent design system.
|
|
97
|
+
|
|
98
|
+
The `ZestProvider`'s `config` prop accepts a `semanticTypeDefaults` object. You can use this to **override** built-in defaults or **define** defaults for your own custom types.
|
|
99
|
+
|
|
100
|
+
#### Example: Defining a Custom 'archive' Type
|
|
101
|
+
|
|
102
|
+
First, let's imagine you've used module augmentation to create a new `semanticType` called `'archive'`, as explained in the [Development Guide](./development.md). Now, you want all `'archive'` buttons to have a specific look and feel across your app.
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
// your-project/src/typings/zest-button-extensions.d.ts
|
|
106
|
+
import 'jattac.libs.web.zest-button';
|
|
107
|
+
|
|
108
|
+
declare module 'jattac.libs.web.zest-button' {
|
|
109
|
+
export interface CustomZestSemanticTypes {
|
|
110
|
+
archive: 'archive';
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Now, configure the defaults in your `ZestProvider`:
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
// In your main App.tsx file
|
|
119
|
+
import { ZestProvider } from 'jattac.libs.web.zest-button';
|
|
120
|
+
import { FaArchive } from 'react-icons/fa';
|
|
121
|
+
import MyRoutes from './MyRoutes';
|
|
122
|
+
|
|
123
|
+
const appZestConfig = {
|
|
124
|
+
// Define defaults for our new custom semantic type
|
|
125
|
+
semanticTypeDefaults: {
|
|
126
|
+
archive: {
|
|
127
|
+
buttonStyle: 'outline',
|
|
128
|
+
visualOptions: {
|
|
129
|
+
iconLeft: <FaArchive />,
|
|
130
|
+
variant: 'standard',
|
|
131
|
+
},
|
|
132
|
+
confirmOptions: {
|
|
133
|
+
displayLabel: 'Confirm Archive?',
|
|
134
|
+
timeoutSecs: 10,
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const App = () => (
|
|
141
|
+
<ZestProvider config={appZestConfig}>
|
|
142
|
+
<MyRoutes />
|
|
143
|
+
</ZestProvider>
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
// --- Later, in some other component ---
|
|
147
|
+
|
|
148
|
+
// This button will automatically get the icon, style, and confirmation behavior!
|
|
149
|
+
<ZestButton zest={{ semanticType: 'archive' }} onClick={handleArchiveAction}>
|
|
150
|
+
Archive Record
|
|
151
|
+
</ZestButton>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### Example: Overriding a Built-in 'delete' Default
|
|
155
|
+
|
|
156
|
+
Let's say you like the built-in `delete` type, but for your application, you want the button style to be `outline` instead of `solid`, and you want a shorter confirmation time.
|
|
157
|
+
|
|
158
|
+
```tsx
|
|
159
|
+
// In your main App.tsx file
|
|
160
|
+
import { ZestProvider } from 'jattac.libs.web.zest-button';
|
|
161
|
+
import MyRoutes from './MyRoutes';
|
|
162
|
+
|
|
163
|
+
const appZestConfig = {
|
|
164
|
+
// Override specific props for a built-in semantic type
|
|
165
|
+
semanticTypeDefaults: {
|
|
166
|
+
delete: {
|
|
167
|
+
// We only specify what we want to change.
|
|
168
|
+
// The icon and 'danger' variant will still be inherited from the built-in default.
|
|
169
|
+
buttonStyle: 'outline',
|
|
170
|
+
confirmOptions: {
|
|
171
|
+
// We must provide the full object to override, not just one property.
|
|
172
|
+
displayLabel: 'Confirm Deletion',
|
|
173
|
+
timeoutSecs: 3, // Shorter timeout
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const App = () => (
|
|
180
|
+
<ZestProvider config={appZestConfig}>
|
|
181
|
+
<MyRoutes />
|
|
182
|
+
</ZestProvider>
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
// --- Later, in some other component ---
|
|
186
|
+
|
|
187
|
+
// This button will now be an 'outline' button with a 3-second confirmation.
|
|
188
|
+
<ZestButton zest={{ semanticType: 'delete' }} onClick={handleDeleteAction}>
|
|
189
|
+
Delete Record
|
|
190
|
+
</ZestButton>
|
|
191
|
+
```
|
|
192
|
+
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Development: The Contributor's Guide
|
|
2
|
+
|
|
3
|
+
This guide provides an overview of the project's internal structure and instructions for setting up your development environment.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
### Internal Architecture
|
|
8
|
+
|
|
9
|
+
The `jattac.libs.web.zest-button` project is structured to be a self-contained React component library.
|
|
10
|
+
|
|
11
|
+
- **`UI/ZestButton.tsx`**: This is the heart of the component. It contains the main React functional component, state management logic, event handlers, and renders the button's UI based on its props and internal state. Auxiliary components like `AnimatedCheckmark` and `AnimatedX` are also defined here.
|
|
12
|
+
- **`UI/SpinnerIcon.tsx`**: A small, dedicated component for rendering the loading spinner, utilizing `react-icons`.
|
|
13
|
+
- **`Styles/ZestButton.module.css`**: All the CSS for the component is defined in this file. It leverages CSS Modules to ensure styles are scoped and prevent conflicts. It also includes global CSS variables for theming and animations.
|
|
14
|
+
- **`dist/`**: This directory is the output of the build process. It contains the compiled JavaScript files (CommonJS and ES Modules), the TypeScript declaration file (`index.d.ts`), and potentially source maps. This is the content that gets published to npm.
|
|
15
|
+
- **`rollup.config.mjs`**: The configuration file for Rollup, the module bundler used for this project. It defines how the TypeScript and CSS are transpiled, bundled, and how the declaration files are generated.
|
|
16
|
+
- **`tsconfig.json`**: The TypeScript compiler configuration. It specifies compiler options, such as target JavaScript version, module resolution strategy, JSX factory, and files to include/exclude from compilation.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
### Setup Instructions
|
|
21
|
+
|
|
22
|
+
To get the development environment running on your local machine, follow these steps:
|
|
23
|
+
|
|
24
|
+
1. **Clone the repository:**
|
|
25
|
+
```bash
|
|
26
|
+
git clone https://github.com/jattac/jattac.libs.web.zest-button.git
|
|
27
|
+
cd jattac.libs.web.zest-button
|
|
28
|
+
```
|
|
29
|
+
2. **Install dependencies:**
|
|
30
|
+
```bash
|
|
31
|
+
npm install
|
|
32
|
+
```
|
|
33
|
+
This command will install all the necessary `devDependencies` listed in `package.json`.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
### Scripts
|
|
38
|
+
|
|
39
|
+
The `package.json` includes several scripts to help with development and building the package:
|
|
40
|
+
|
|
41
|
+
- **`npm run build`**:
|
|
42
|
+
* **Purpose**: Compiles the TypeScript code, processes CSS Modules, and bundles the component into production-ready CommonJS and ES Module formats. It also generates the TypeScript declaration file (`index.d.ts`).
|
|
43
|
+
* **Output**: Creates the `dist/` directory with all the necessary files for publishing.
|
|
44
|
+
* **Command**: `rollup -c rollup.config.mjs`
|
|
45
|
+
|
|
46
|
+
- **`npm run dev`**:
|
|
47
|
+
* **Purpose**: Starts Rollup in watch mode. This command is ideal for development as it automatically recompiles the component whenever source files are changed, allowing for rapid iteration.
|
|
48
|
+
* **Output**: Similar to `build`, but also keeps the process running to watch for changes.
|
|
49
|
+
* **Command**: `rollup -c rollup.config.mjs -w`
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### Extending Semantic Types
|
|
54
|
+
|
|
55
|
+
The `ZestButton` provides a mechanism for developers to extend the built-in `SemanticType` union with their own custom semantic types. This is achieved through TypeScript's [module augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation) feature.
|
|
56
|
+
|
|
57
|
+
To add your own custom semantic types:
|
|
58
|
+
|
|
59
|
+
1. Create a TypeScript declaration file in your project (e.g., `your-project/src/typings/zest-button-extensions.d.ts`).
|
|
60
|
+
2. Augment the `jattac.libs.web.zest-button` module and define your custom semantic types within the `CustomZestSemanticTypes` interface. The keys of this interface will become available as new `SemanticType` values.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// your-project/src/typings/zest-button-extensions.d.ts
|
|
64
|
+
import 'jattac.libs.web.zest-button'; // Important: Extend the module
|
|
65
|
+
|
|
66
|
+
declare module 'jattac.libs.web.zest-button' {
|
|
67
|
+
export interface CustomZestSemanticTypes {
|
|
68
|
+
archive: 'archive';
|
|
69
|
+
publish: 'publish';
|
|
70
|
+
// Add any other custom semantic types here
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Once augmented, these new semantic types (`'archive'`, `'publish'`) will be available for autocompletion and type-checking when using the `semanticType` prop on your `ZestButton` instances.
|
|
76
|
+
|
|
77
|
+
*(Note: Currently, there are no dedicated test scripts defined in `package.json`. Testing is typically done manually in a consuming project during development, or through dedicated test runners that would be added in the future.)*
|
package/docs/examples.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# The Cookbook: From First Button to Design System
|
|
2
|
+
|
|
3
|
+
Welcome to the ZestButton Cookbook! This is the core learning path for mastering `ZestButton`. Each recipe solves a real-world problem and builds on the concepts from the previous one. Start here to go from zero to expert.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
### Recipe 1: Your First Async Button
|
|
8
|
+
|
|
9
|
+
**Goal:** Create a button that automatically shows a loading spinner during an operation and gives feedback when it's done.
|
|
10
|
+
|
|
11
|
+
**Problem:** You have an API call that takes time. You need to prevent the user from clicking the button multiple times and clearly show when the action is complete.
|
|
12
|
+
|
|
13
|
+
**Solution:** Simply have your `onClick` handler return a `Promise`. `ZestButton` handles the rest. This example also shows success and failure states.
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import React, { useState } from 'react';
|
|
17
|
+
import ZestButton from 'jattac.libs.web.zest-button';
|
|
18
|
+
import { FaSave } from 'react-icons/fa';
|
|
19
|
+
|
|
20
|
+
const SaveButton = () => {
|
|
21
|
+
const [shouldSucceed, setShouldSucceed] = useState(true);
|
|
22
|
+
|
|
23
|
+
const handleSave = async () => {
|
|
24
|
+
console.log('Saving...');
|
|
25
|
+
// Simulate an API call
|
|
26
|
+
await new Promise((resolve, reject) => {
|
|
27
|
+
setTimeout(() => {
|
|
28
|
+
shouldSucceed ? resolve('Success!') : reject('Error!');
|
|
29
|
+
}, 1500);
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem', maxWidth: '300px' }}>
|
|
35
|
+
<label>
|
|
36
|
+
<input
|
|
37
|
+
type="checkbox"
|
|
38
|
+
checked={shouldSucceed}
|
|
39
|
+
onChange={() => setShouldSucceed(e => !e)}
|
|
40
|
+
/>
|
|
41
|
+
Simulate Success
|
|
42
|
+
</label>
|
|
43
|
+
<ZestButton
|
|
44
|
+
onClick={handleSave}
|
|
45
|
+
zest={{
|
|
46
|
+
visualOptions: { iconLeft: <FaSave />, fullWidth: true },
|
|
47
|
+
}}
|
|
48
|
+
>
|
|
49
|
+
Save Settings
|
|
50
|
+
</ZestButton>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
```
|
|
55
|
+
*For more details on all available options, see the [`BusyOptions`](./api.md#busyoptions) and [`SuccessOptions`](./api.md#successoptions) in our API reference.*
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
### Recipe 2: The Safe "Delete" Button
|
|
60
|
+
|
|
61
|
+
**Goal:** Create a button for a destructive action that requires a second click to confirm.
|
|
62
|
+
|
|
63
|
+
**Problem:** Destructive actions like deleting data are dangerous. A user might click the button by accident.
|
|
64
|
+
|
|
65
|
+
**Solution:** Use the `confirmOptions` prop. This forces the user to click once to start a countdown, and a second time to execute the action. Combining this with a `danger` variant provides a clear visual warning.
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import React from 'react';
|
|
69
|
+
import ZestButton from 'jattac.libs.web.zest-button';
|
|
70
|
+
import { FaTrash } from 'react-icons/fa';
|
|
71
|
+
|
|
72
|
+
const DeleteButton = () => {
|
|
73
|
+
const handleDelete = () => {
|
|
74
|
+
alert('Item has been permanently deleted.');
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<ZestButton
|
|
79
|
+
onClick={handleDelete}
|
|
80
|
+
zest={{
|
|
81
|
+
visualOptions: {
|
|
82
|
+
variant: 'danger',
|
|
83
|
+
iconLeft: <FaTrash />,
|
|
84
|
+
},
|
|
85
|
+
confirmOptions: {
|
|
86
|
+
displayLabel: 'Confirm Deletion',
|
|
87
|
+
timeoutSecs: 5,
|
|
88
|
+
},
|
|
89
|
+
}}
|
|
90
|
+
>
|
|
91
|
+
Delete Account
|
|
92
|
+
</ZestButton>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
```
|
|
96
|
+
*For more details, see the [`ConfirmOptions`](./api.md#confirmoptions) in our API reference.*
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
### Recipe 3: Standardizing Your Buttons with a Global Config
|
|
101
|
+
|
|
102
|
+
**Goal:** Define a consistent look and feel for all buttons in your application without repeating props.
|
|
103
|
+
|
|
104
|
+
**Problem:** Your app has dozens of buttons. Specifying `size: 'sm'` or `buttonStyle: 'outline'` on every single one is tedious and error-prone.
|
|
105
|
+
|
|
106
|
+
**Solution:** Wrap your application in the `ZestProvider` and pass a `config` object. Any props in `defaultProps` will be applied to every `ZestButton` within the provider. Local props on a button will always override the global default.
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
// In your main App.tsx
|
|
110
|
+
import React from 'react';
|
|
111
|
+
import { ZestProvider, ZestButton } from 'jattac.libs.web.zest-button';
|
|
112
|
+
|
|
113
|
+
const appZestConfig = {
|
|
114
|
+
defaultProps: {
|
|
115
|
+
visualOptions: {
|
|
116
|
+
size: 'sm', // Make all buttons small by default
|
|
117
|
+
},
|
|
118
|
+
buttonStyle: 'outline', // Make all buttons outline by default
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const App = () => (
|
|
123
|
+
<ZestProvider config={appZestConfig}>
|
|
124
|
+
<div style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
|
|
125
|
+
<ZestButton>I'm a small outline button</ZestButton>
|
|
126
|
+
<ZestButton>So am I</ZestButton>
|
|
127
|
+
<ZestButton zest={{ visualOptions: { size: 'lg' }, buttonStyle: 'solid' }}>
|
|
128
|
+
I'm a large solid button! (Local override)
|
|
129
|
+
</ZestButton>
|
|
130
|
+
</div>
|
|
131
|
+
</ZestProvider>
|
|
132
|
+
);
|
|
133
|
+
```
|
|
134
|
+
*For a full list of provider settings, see the [`ZestGlobalConfig`](./api.md#zestglobalconfig) documentation. To understand the precedence rules, see the [Configuration Guide](./configuration.md).*
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### Recipe 4: Creating a Custom "Archive" Button
|
|
139
|
+
|
|
140
|
+
**Goal:** Create a new, reusable button "type" with its own specific icon, style, and behavior that can be used anywhere in the app.
|
|
141
|
+
|
|
142
|
+
**Problem:** You have a common action in your app, like "Archive," that should always look and feel the same. You want to avoid configuring it manually each time and just be able to write `zest={{ semanticType: 'archive' }}`.
|
|
143
|
+
|
|
144
|
+
**Solution:** This is a two-step process that combines **TypeScript Module Augmentation** with the **`ZestProvider`**.
|
|
145
|
+
|
|
146
|
+
**Step 1: Define the new type**
|
|
147
|
+
In your project's type declarations file (e.g., `src/zest.d.ts`), augment the `CustomZestSemanticTypes` interface.
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// src/zest.d.ts
|
|
151
|
+
import 'jattac.libs.web.zest-button';
|
|
152
|
+
import { FaArchive } from 'react-icons/fa';
|
|
153
|
+
|
|
154
|
+
// 1. Tell ZestButton that 'archive' is a valid semantic type
|
|
155
|
+
declare module 'jattac.libs.web.zest-button' {
|
|
156
|
+
export interface CustomZestSemanticTypes {
|
|
157
|
+
archive: 'archive';
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
*(For more on this, see the [Contributor's Guide](./development.md#extending-semantic-types).)*
|
|
162
|
+
|
|
163
|
+
**Step 2: Provide the default configuration**
|
|
164
|
+
In your `App.tsx`, use the `semanticTypeDefaults` property in the `ZestProvider` to define the default props for your new `'archive'` type.
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
// In your main App.tsx
|
|
168
|
+
import React from 'react';
|
|
169
|
+
import { ZestProvider, ZestButton } from 'jattac.libs.web.zest-button';
|
|
170
|
+
import { FaArchive } from 'react-icons/fa';
|
|
171
|
+
|
|
172
|
+
const appZestConfig = {
|
|
173
|
+
semanticTypeDefaults: {
|
|
174
|
+
// 2. Define the default props for the 'archive' type
|
|
175
|
+
archive: {
|
|
176
|
+
buttonStyle: 'outline',
|
|
177
|
+
visualOptions: {
|
|
178
|
+
iconLeft: <FaArchive />,
|
|
179
|
+
variant: 'standard',
|
|
180
|
+
},
|
|
181
|
+
confirmOptions: {
|
|
182
|
+
displayLabel: 'Confirm Archive?',
|
|
183
|
+
timeoutSecs: 10,
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
// You can also override built-in types here!
|
|
187
|
+
delete: {
|
|
188
|
+
buttonStyle: 'outline', // Make all delete buttons 'outline'
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const App = () => (
|
|
194
|
+
<ZestProvider config={appZestConfig}>
|
|
195
|
+
<div style={{ display: 'flex', gap: '1rem' }}>
|
|
196
|
+
{/* 3. Now just use it! */}
|
|
197
|
+
<ZestButton
|
|
198
|
+
zest={{ semanticType: 'archive' }}
|
|
199
|
+
onClick={() => alert('Archived!')}
|
|
200
|
+
>
|
|
201
|
+
Archive
|
|
202
|
+
</ZestButton>
|
|
203
|
+
|
|
204
|
+
<ZestButton
|
|
205
|
+
zest={{ semanticType: 'delete' }}
|
|
206
|
+
onClick={() => alert('Deleted!')}
|
|
207
|
+
>
|
|
208
|
+
Delete
|
|
209
|
+
</ZestButton>
|
|
210
|
+
</div>
|
|
211
|
+
</ZestProvider>
|
|
212
|
+
);
|
|
213
|
+
```
|
|
214
|
+
This powerful pattern allows you to build a complete, consistent design system for all button actions in your application. For more details on configuration, see the [Configuration Guide](./configuration.md).
|
|
215
|
+
|