jattac.libs.web.zest-button 1.2.2 → 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/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.)*
@@ -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
+