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 CHANGED
@@ -1,345 +1,53 @@
1
- # `jattac.libs.web.zest-button`
1
+ # ZestButton: The Interactive React Button That Does More
2
2
 
3
- A highly customizable and interactive React button component designed for modern web applications. It provides built-in features for handling asynchronous operations (loading states), visual feedback (success/failure animations), and confirmation flows, all while ensuring a delightful user experience.
3
+ A highly customizable and interactive React button component designed for modern web applications. It provides built-in features for handling asynchronous operations, visual feedback, and confirmation flows, all while ensuring a delightful user experience.
4
4
 
5
- ## Table of Contents
5
+ ### Key Features
6
6
 
7
- - [Features](#features)
8
- - [Installation](#installation)
9
- - [Usage](#usage)
10
- - [Basic Usage](#basic-usage)
11
- - [Variants and Sizes](#variants-and-sizes)
12
- - [Icons](#icons)
13
- - [Asynchronous Operations (Busy State)](#asynchronous-operations-busy-state)
14
- - [Success and Failure Feedback](#success-and-failure-feedback)
15
- - [Confirmation Dialog](#confirmation-dialog)
16
- - [Full Width Button](#full-width-button)
17
- - [Default Button (Enter Key)](#default-button-enter-key)
18
- - [Theme Support](#theme-support)
19
- - [Button Styles](#button-styles)
20
- - [Props](#props)
21
- - [Styling](#styling)
22
- - [Development](#development)
23
- - [Local Setup](#local-setup)
24
- - [Building the Package](#building-the-package)
25
- - [Running Tests](#running-tests)
26
- - [Contributing](#contributing)
27
- - [License](#license)
7
+ * **Automatic Busy/Loading States**: Simply return a promise from your `onClick` handler and the button will automatically manage loading spinners and prevent "rage clicks."
8
+ * **Success & Failure Feedback**: Provide instant visual feedback with animated checkmarks for success or an animated 'X' with a shake for failures and timeouts.
9
+ * **Built-in Confirmation Flow**: Protect critical actions with a configurable "click-to-confirm" mechanism, complete with a countdown timer.
10
+ * **Richly Styleable**: Comes with `solid`, `outline`, `text`, and `dashed` styles, multiple color variants, and automatic light/dark mode support.
28
11
 
29
- ## Features
30
-
31
- - **Customizable Visuals**: Supports different variants (standard, success, danger) and sizes (sm, md, lg).
32
- - **Icon Support**: Easily add left or right icons to the button.
33
- - **Asynchronous Handling**: Manages busy/loading states automatically, preventing "rage clicks" and ensuring a minimum busy duration for better UX.
34
- - **Visual Feedback**: Provides animated checkmarks for success and 'X' marks with shake animation for failure/timeout.
35
- - **Confirmation Flow**: Implements a configurable "click to confirm" mechanism with a countdown timer and auto-reset.
36
- - **CSS Modules**: Styles are encapsulated using CSS Modules and automatically injected into the component, requiring no separate CSS imports for consumers.
37
- - **TypeScript Support**: Fully typed with comprehensive `index.d.ts` declarations.
38
- - **Dark/Light Mode Support**: Automatically adapts to system theme with an override prop.
39
- - **Multiple Button Styles**: Supports `solid`, `outline`, `text`, and `dashed` button styles.
40
-
41
- ## Installation
42
-
43
- To install the component, use npm or yarn:
12
+ ### Installation
44
13
 
45
14
  ```bash
46
- npm install jattac.libs.web.zest-button react react-dom react-icons
47
- # or
48
- yarn add jattac.libs.web.zest-button react react-dom react-icons
49
- ```
50
-
51
- **Note:** `react`, `react-dom`, and `react-icons` are peer dependencies and must be installed in your project.
52
-
53
- ## Usage
54
-
55
- Import the `ZestButton` component:
56
-
57
- ```typescript
58
- import ZestButton from 'jattac.libs.web.zest-button';
59
- import { FaSave, FaTrash } from 'react-icons/fa6'; // Example icons
60
- ```
61
-
62
- ### Basic Usage
63
-
64
- ```tsx
65
- <ZestButton onClick={() => alert('Button clicked!')}>
66
- Click Me
67
- </ZestButton>
68
- ```
69
-
70
- ### Variants and Sizes
71
-
72
- ```tsx
73
- <ZestButton zest={{ visualOptions: { variant: 'success' } }}>
74
- Success Button
75
- </ZestButton>
76
- <ZestButton zest={{ visualOptions: { variant: 'danger', size: 'sm' } }}>
77
- Small Danger
78
- </ZestButton>
79
- <ZestButton zest={{ visualOptions: { size: 'lg' } }}>
80
- Large Button
81
- </ZestButton>
82
- ```
83
-
84
- ### Icons
85
-
86
- ```tsx
87
- <ZestButton zest={{ visualOptions: { iconLeft: <FaSave /> } }}>
88
- Save
89
- </ZestButton>
90
- <ZestButton zest={{ visualOptions: { iconRight: <FaTrash /> } }}>
91
- Delete
92
- </ZestButton>
93
- <ZestButton zest={{ visualOptions: { iconLeft: <FaSave />, iconRight: <FaTrash /> } }}>
94
- Save & Delete
95
- </ZestButton>
96
- ```
97
-
98
- ### Asynchronous Operations (Busy State)
99
-
100
- The button can automatically manage busy states for `onClick` handlers that return a Promise. It prevents multiple clicks during the busy period and ensures a minimum busy duration for a smoother user experience.
101
-
102
- ```tsx
103
- const handleAsyncClick = async () => {
104
- console.log('Starting async operation...');
105
- await new Promise(resolve => setTimeout(resolve, 2000)); // Simulate API call
106
- console.log('Async operation finished!');
107
- };
108
-
109
- <ZestButton onClick={handleAsyncClick}>
110
- Perform Async Action
111
- </ZestButton>
112
-
113
- // You can also control the busy state externally
114
- const [isSaving, setIsSaving] = useState(false);
115
- const handleExternalAsyncClick = async () => {
116
- setIsSaving(true);
117
- await new Promise(resolve => setTimeout(resolve, 2000));
118
- setIsSaving(false);
119
- };
120
-
121
- <ZestButton onClick={handleExternalAsyncClick} aria-busy={isSaving}>
122
- {isSaving ? 'Saving...' : 'Save Externally Controlled'}
123
- </ZestButton>
15
+ npm install jattac.libs.web.zest-button react-icons
124
16
  ```
17
+ *Note: `react`, `react-dom`, and `react-icons` are peer dependencies and must be installed in your project.*
125
18
 
126
- ### Success and Failure Feedback
19
+ ### Basic Usage (The "Hello World")
127
20
 
128
- After an asynchronous operation, the button can display a checkmark for success or an 'X' for failure, then automatically reset.
21
+ Here's the simplest way to get `ZestButton` up and running:
129
22
 
130
23
  ```tsx
131
- const handleSuccess = async () => {
132
- await new Promise(resolve => setTimeout(resolve, 1500));
133
- // Simulate success
134
- };
135
-
136
- const handleFailure = async () => {
137
- await new Promise((_, reject) => setTimeout(() => reject('Error!'), 1500));
138
- // Simulate failure
139
- };
140
-
141
- <ZestButton onClick={handleSuccess} zest={{ successOptions: { showCheckmark: true } }}>
142
- Submit (Success)
143
- </ZestButton>
144
- <ZestButton onClick={handleFailure} zest={{ successOptions: { showFailIcon: true } }}>
145
- Submit (Failure)
146
- </ZestButton>
147
- ```
148
-
149
- ### Confirmation Dialog
150
-
151
- Implement a "click to confirm" mechanism to prevent accidental actions.
24
+ import React from 'react';
25
+ import ZestButton from 'jattac.libs.web.zest-button';
152
26
 
153
- ```tsx
154
- const handleDelete = () => {
155
- alert('Item deleted!');
27
+ const App = () => {
28
+ return (
29
+ <ZestButton onClick={() => alert('Zestfully clicked!')}>
30
+ Click Me
31
+ </ZestButton>
32
+ );
156
33
  };
157
34
 
158
- <ZestButton
159
- onClick={handleDelete}
160
- zest={{
161
- confirmOptions: { displayLabel: 'Confirm Delete', timeoutSecs: 5 },
162
- visualOptions: { variant: 'danger' }
163
- }}
164
- >
165
- Delete Item
166
- </ZestButton>
167
- ```
168
-
169
- ### Full Width Button
170
-
171
- ```tsx
172
- <ZestButton zest={{ visualOptions: { fullWidth: true } }}>
173
- Full Width Button
174
- </ZestButton>
175
- ```
176
-
177
- ### Default Button (Enter Key)
178
-
179
- A button marked as `isDefault` will be triggered when the user presses the `Enter` key, unless another interactive element (like a textarea) has focus.
180
-
181
- ```tsx
182
- <ZestButton zest={{ isDefault: true }} onClick={() => alert('Default action!')}>
183
- Submit Form
184
- </ZestButton>
185
- ```
186
-
187
- ### Theme Support
188
-
189
- The `ZestButton` automatically adapts to the user's system theme (light or dark) by default. You can override this behavior using the `zest.theme` prop.
190
-
191
- ```tsx
192
- // Button will follow system theme (default behavior)
193
- <ZestButton onClick={() => alert('System theme!')}>
194
- System Theme Button
195
- </ZestButton>
196
-
197
- // Force light theme
198
- <ZestButton zest={{ theme: "light" }} onClick={() => alert('Light theme!')}>
199
- Light Theme Button
200
- </ZestButton>
201
-
202
- // Force dark theme
203
- <ZestButton zest={{ theme: "dark" }} onClick={() => alert('Dark theme!')}>
204
- Dark Theme Button
205
- </ZestButton>
206
- ```
207
-
208
- ### Button Styles
209
-
210
- Beyond the default solid button, `ZestButton` supports `outline`, `text`, and `dashed` styles.
211
-
212
- ```tsx
213
- // Solid (default)
214
- <ZestButton>Solid Button</ZestButton>
215
-
216
- // Outline button
217
- <ZestButton zest={{ buttonStyle: "outline", visualOptions: { variant: 'standard' } }}>
218
- Outline Button
219
- </ZestButton>
220
-
221
- // Text button
222
- <ZestButton zest={{ buttonStyle: "text", visualOptions: { variant: 'success' } }}>
223
- Text Button
224
- </ZestButton>
225
-
226
- // Dashed button
227
- <ZestButton zest={{ buttonStyle: "dashed", visualOptions: { variant: 'danger' } }}>
228
- Dashed Button
229
- </ZestButton>
230
- ```
231
-
232
- ## Props
233
-
234
- The `ZestButton` component extends standard HTML `button` attributes and introduces a single `zest` prop to encapsulate all custom functionality.
235
-
236
- ```typescript
237
- export type ZestVariant = "standard" | "success" | "danger";
238
- export type ZestSize = "sm" | "md" | "lg";
239
- export type ZestTheme = 'light' | 'dark' | 'system';
240
- export type ZestButtonStyle = 'solid' | 'outline' | 'text' | 'dashed';
241
-
242
- interface VisualOptions {
243
- variant?: ZestVariant; // Visual style of the button (default: "standard")
244
- size?: ZestSize; // Size of the button (default: "md")
245
- fullWidth?: boolean; // If true, button takes full width of its parent (default: false)
246
- iconLeft?: React.ReactNode; // Icon to display on the left side of the label
247
- iconRight?: React.ReactNode; // Icon to display on the right side of the label
248
- }
249
-
250
- interface BusyOptions {
251
- handleInternally?: boolean; // If true, onClick's Promise resolves/rejects control busy state (default: true)
252
- preventRageClick?: boolean; // If true, prevents multiple clicks during busy/success/fail states (default: true)
253
- minBusyDurationMs?: number; // Minimum duration button stays busy, even if Promise resolves faster (default: 500)
254
- }
255
-
256
- interface SuccessOptions {
257
- showCheckmark?: boolean; // If true, shows animated checkmark on success (default: true)
258
- showFailIcon?: boolean; // If true, shows animated 'X' on failure (default: true)
259
- autoResetAfterMs?: number; // Time in ms after which success/fail state resets (default: 2000)
260
- }
261
-
262
- interface ConfirmOptions {
263
- displayLabel: string; // The text to display during the confirmation phase (e.g., "Confirm Delete")
264
- timeoutSecs: number; // The number of seconds to wait for a second click to confirm
265
- }
266
-
267
- // New interface to encapsulate all custom ZestButton props
268
- interface ZestCustomProps {
269
- visualOptions?: VisualOptions;
270
- busyOptions?: BusyOptions;
271
- successOptions?: SuccessOptions;
272
- confirmOptions?: ConfirmOptions;
273
- isDefault?: boolean; // If true, button is triggered by Enter key (default: false)
274
- theme?: ZestTheme; // Theme override for the button (default: "system")
275
- buttonStyle?: ZestButtonStyle; // Style of the button (default: "solid")
276
- }
277
-
278
- export interface ZestButtonProps
279
- extends React.ButtonHTMLAttributes<HTMLButtonElement> {
280
- zest?: ZestCustomProps; // Encapsulate all custom props under 'zest'
281
- // All standard HTML button attributes are also supported (e.g., disabled, type, etc.)
282
- }
35
+ export default App;
283
36
  ```
284
37
 
285
- ## Styling
286
-
287
- The `ZestButton` component uses CSS Modules for styling, ensuring that styles are scoped and do not conflict with other parts of your application. The styles are automatically injected into the JavaScript bundle, so you do not need to import any CSS files separately.
288
-
289
- You can override styles by providing your own `className` to the `ZestButton` component. This will be appended to the component's internal class names, allowing you to add or override specific styles.
290
-
291
- ```tsx
292
- // In your component's CSS file (e.g., MyComponent.module.css)
293
- .myCustomButton {
294
- background-color: purple !important;
295
- color: yellow !important;
296
- border-radius: 20px;
297
- }
298
-
299
- // In your React component
300
- import styles from './MyComponent.module.css';
301
-
302
- <ZestButton className={styles.myCustomButton}>
303
- Custom Styled Button
304
- </ZestButton>
305
- ```
306
-
307
- ## Development
308
-
309
- ### Local Setup
310
-
311
- 1. **Clone the repository:**
312
- ```bash
313
- git clone https://github.com/jattac/jattac.libs.web.zest-button.git
314
- cd jattac.libs.web.zest-button
315
- ```
316
- 2. **Install dependencies:**
317
- ```bash
318
- npm install
319
- ```
320
- 3. **Start development mode (watches for changes and rebuilds):**
321
- ```bash
322
- npm run dev
323
- ```
324
-
325
- ### Building the Package
326
-
327
- To build the production-ready package, run:
328
-
329
- ```bash
330
- npm run build
331
- ```
332
-
333
- This will compile the TypeScript, bundle the component and its styles, and generate type declarations into the `dist` folder.
334
-
335
- ### Running Tests
336
-
337
- *(Currently, there are no automated tests. Please refer to the `WORKPLAN.md` for future testing plans.)*
38
+ ### Documentation
338
39
 
339
- ## Contributing
40
+ To get started, check out our **Cookbook** of practical recipes.
340
41
 
341
- Contributions are welcome! Please refer to the `DIRECTIVES.md` and `WORKPLAN.md` for guidelines on contributing to this project.
42
+ | Topic | Description |
43
+ | :--- | :--- |
44
+ | **[The Cookbook](./docs/examples.md)** | **(Start Here)** A collection of practical, real-world recipes to master `ZestButton`. |
45
+ | **[Features Showcase](./docs/features.md)** | A high-level visual tour of what's possible. |
46
+ | **[API Reference](./docs/api.md)** | An exhaustive technical reference for all props and types. |
47
+ | **[Configuration Guide](./docs/configuration.md)**| A deep dive into global configuration using the `ZestProvider`. |
48
+ | **[Development Guide](./docs/development.md)** | Information for contributors on the project's architecture and setup. |
49
+ | **[Breaking Changes](./docs/breaking-changes.md)** | A log of breaking changes to assist with version upgrades. |
342
50
 
343
- ## License
51
+ ### License
344
52
 
345
- This project is licensed under the MIT License. See the `LICENSE` file for details.
53
+ Licensed under [MIT](./LICENSE).
@@ -3,6 +3,9 @@ export type ZestVariant = "standard" | "success" | "danger";
3
3
  export type ZestSize = "sm" | "md" | "lg";
4
4
  export type ZestTheme = 'light' | 'dark' | 'system';
5
5
  export type ZestButtonStyle = 'solid' | 'outline' | 'text' | 'dashed';
6
+ export interface CustomZestSemanticTypes {
7
+ }
8
+ export type SemanticType = 'add' | 'save' | 'submit' | 'edit' | 'update' | 'delete' | 'remove' | 'cancel' | 'close' | 'view' | 'details' | 'download' | 'upload' | 'refresh' | 'reload' | 'print' | 'share' | 'confirm' | keyof CustomZestSemanticTypes;
6
9
  /**
7
10
  * Visual appearance of the button
8
11
  */
@@ -29,11 +32,11 @@ interface SuccessOptions {
29
32
  showFailIcon?: boolean;
30
33
  autoResetAfterMs?: number;
31
34
  }
32
- interface ConfirmOptions {
35
+ export interface ConfirmOptions {
33
36
  displayLabel: string;
34
37
  timeoutSecs: number;
35
38
  }
36
- interface ZestCustomProps {
39
+ export interface ZestCustomProps {
37
40
  visualOptions?: VisualOptions;
38
41
  busyOptions?: BusyOptions;
39
42
  successOptions?: SuccessOptions;
@@ -41,6 +44,7 @@ interface ZestCustomProps {
41
44
  isDefault?: boolean;
42
45
  theme?: ZestTheme;
43
46
  buttonStyle?: ZestButtonStyle;
47
+ semanticType?: SemanticType;
44
48
  }
45
49
  /**
46
50
  * All supported props
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { ZestCustomProps } from './ZestButton';
3
+ export interface ZestGlobalConfig {
4
+ defaultProps?: ZestCustomProps;
5
+ semanticTypeDefaults?: Partial<Record<string, Partial<ZestCustomProps>>>;
6
+ }
7
+ declare const ZestContext: React.Context<ZestGlobalConfig | undefined>;
8
+ export declare const useZest: () => ZestGlobalConfig | undefined;
9
+ export default ZestContext;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { ZestGlobalConfig } from './ZestContext';
3
+ interface ZestProviderProps {
4
+ config: ZestGlobalConfig;
5
+ children: React.ReactNode;
6
+ }
7
+ declare const ZestProvider: React.FC<ZestProviderProps>;
8
+ export default ZestProvider;
@@ -0,0 +1,20 @@
1
+ import { ZestCustomProps } from '../ZestButton';
2
+ interface UseBusyStateProps {
3
+ busyOptions: ZestCustomProps['busyOptions'];
4
+ successOptions: ZestCustomProps['successOptions'];
5
+ }
6
+ export declare const useBusyState: ({ busyOptions, successOptions }: UseBusyStateProps) => {
7
+ internalBusy: boolean;
8
+ wasSuccessful: boolean;
9
+ wasFailed: boolean;
10
+ startBusy: () => void;
11
+ endBusy: (isSuccess: boolean) => void;
12
+ handleInternally: boolean;
13
+ preventRageClick: boolean;
14
+ minBusyDurationMs: number;
15
+ showCheckmark: boolean;
16
+ showFailIcon: boolean;
17
+ autoResetAfterMs: number;
18
+ failTimeoutRef: import("react").MutableRefObject<NodeJS.Timeout | null>;
19
+ };
20
+ export {};
@@ -0,0 +1,13 @@
1
+ import { ZestCustomProps } from '../ZestButton';
2
+ interface UseConfirmationProps {
3
+ confirmOptions?: ZestCustomProps['confirmOptions'];
4
+ originalChildren: React.ReactNode;
5
+ onConfirmFail?: () => void;
6
+ }
7
+ export declare const useConfirmation: ({ confirmOptions, originalChildren, onConfirmFail }: UseConfirmationProps) => {
8
+ awaitingConfirm: boolean;
9
+ currentChildren: string | number | boolean | import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | Iterable<import("react").ReactNode> | import("react").ReactPortal | null | undefined;
10
+ startConfirmation: () => void;
11
+ stopConfirmation: () => void;
12
+ };
13
+ export {};
@@ -0,0 +1 @@
1
+ export declare const useThemeDetection: () => "light" | "dark";
@@ -0,0 +1,2 @@
1
+ import { ZestCustomProps } from '../ZestButton';
2
+ export declare const useZestConfig: (localZestProps?: ZestCustomProps) => ZestCustomProps;