zabi-components 2.0.4 → 2.2.0

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
@@ -69,12 +69,14 @@ import type { ButtonEvents, InputEvents } from 'zabi-components/types';
69
69
  message: '',
70
70
  };
71
71
 
72
- function handleFormSubmit(event: CustomEvent) {
73
- console.log('Form submitted:', event.detail.data);
72
+ function handleFormSubmit(event: SubmitEvent) {
73
+ const formData = new FormData(event.target as HTMLFormElement);
74
+ const data = Object.fromEntries(formData.entries());
75
+ console.log('Form submitted:', data);
74
76
  }
75
77
 
76
- function handleCardClick(event: CustomEvent) {
77
- console.log('Card clicked:', event.detail);
78
+ function handleCardClick(event: MouseEvent) {
79
+ console.log('Card clicked:', event);
78
80
  }
79
81
 
80
82
  const navItems = [
@@ -93,19 +95,19 @@ import type { ButtonEvents, InputEvents } from 'zabi-components/types';
93
95
  <main class="container mx-auto p-6">
94
96
  <!-- Semantic Color Variants -->
95
97
  <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mb-8">
96
- <Card title="Default Card" variant="default">
98
+ <Card title="Default Card" variant="default" on:click={handleCardClick}>
97
99
  This is a default card with semantic colors.
98
100
  </Card>
99
- <Card title="Success Card" variant="success">
101
+ <Card title="Success Card" variant="success" on:click={handleCardClick}>
100
102
  This card indicates a successful action.
101
103
  </Card>
102
- <Card title="Warning Card" variant="warning">
104
+ <Card title="Warning Card" variant="warning" on:click={handleCardClick}>
103
105
  This card shows a warning state.
104
106
  </Card>
105
- <Card title="Error Card" variant="error">
107
+ <Card title="Error Card" variant="error" on:click={handleCardClick}>
106
108
  This card indicates an error state.
107
109
  </Card>
108
- <Card title="Info Card" variant="info">
110
+ <Card title="Info Card" variant="info" on:click={handleCardClick}>
109
111
  This card provides informational content.
110
112
  </Card>
111
113
  </div>
@@ -115,7 +117,8 @@ import type { ButtonEvents, InputEvents } from 'zabi-components/types';
115
117
  <Input
116
118
  id="name"
117
119
  name="name"
118
- bind:value={formData.name}
120
+ value={formData.name}
121
+ on:input={(e) => formData.name = e.target.value}
119
122
  label="Name"
120
123
  placeholder="Enter your name"
121
124
  variant="default"
@@ -127,7 +130,8 @@ import type { ButtonEvents, InputEvents } from 'zabi-components/types';
127
130
  id="email"
128
131
  name="email"
129
132
  type="email"
130
- bind:value={formData.email}
133
+ value={formData.email}
134
+ on:input={(e) => formData.email = e.target.value}
131
135
  label="Email"
132
136
  placeholder="Enter your email"
133
137
  variant="success"
@@ -138,7 +142,8 @@ import type { ButtonEvents, InputEvents } from 'zabi-components/types';
138
142
  <Textarea
139
143
  id="message"
140
144
  name="message"
141
- bind:value={formData.message}
145
+ value={formData.message}
146
+ on:input={(e) => formData.message = e.target.value}
142
147
  label="Message"
143
148
  placeholder="Enter your message"
144
149
  variant="default"
@@ -294,7 +299,7 @@ All components will automatically switch to their dark mode variants without any
294
299
  method="get" | "post"
295
300
  action={string}
296
301
  className={string}
297
- on:submit={(e) => console.log(e.detail.data, e.detail.formData)}
302
+ on:submit={(e) => console.log('Form submitted')}
298
303
  >
299
304
  <div class="form-field">
300
305
  <label for="field" class="form-label">Label</label>
@@ -312,7 +317,7 @@ All components will automatically switch to their dark mode variants without any
312
317
  - `className`: Additional CSS classes
313
318
 
314
319
  **Events:**
315
- - `submit`: Fired on form submission - `{ detail: { data: Record<string, FormDataEntryValue>, formData: FormData } }`
320
+ - `submit`: Native form submit event - use `FormData` to get form data
316
321
 
317
322
  **CSS Classes:**
318
323
  - `.form-field`: Field container
@@ -350,7 +355,7 @@ All components will automatically switch to their dark mode variants without any
350
355
  items={Array<{label: string, href: string, icon?: any}>}
351
356
  currentPath={string}
352
357
  className={string}
353
- on:navigate={(e) => console.log(e.detail.item, e.detail.href)}
358
+ on:click={(e) => console.log('Navigation clicked')}
354
359
  />
355
360
  ```
356
361
 
@@ -361,7 +366,7 @@ All components will automatically switch to their dark mode variants without any
361
366
  - `className`: Additional CSS classes
362
367
 
363
368
  **Events:**
364
- - `navigate`: Fired when navigation item is clicked - `{ detail: { item: NavigationItem, href: string } }`
369
+ - `click`: Native click event on navigation items
365
370
 
366
371
  ### Button Component
367
372
 
@@ -373,7 +378,7 @@ All components will automatically switch to their dark mode variants without any
373
378
  loading={boolean}
374
379
  type="button" | "submit" | "reset"
375
380
  className={string}
376
- on:click={(e) => console.log(e.detail.value, e.detail.event)}
381
+ on:click={(e) => console.log('Button clicked')}
377
382
  >
378
383
  Button Content
379
384
  </Button>
@@ -388,13 +393,13 @@ All components will automatically switch to their dark mode variants without any
388
393
  - `className`: Additional CSS classes
389
394
 
390
395
  **Events:**
391
- - `click`: Fired when button is clicked - `{ detail: { value: true, event: MouseEvent } }`
396
+ - `click`: Native click event - `MouseEvent`
392
397
 
393
398
  ### Input Component
394
399
 
395
400
  ```svelte
396
401
  <Input
397
- bind:value={string}
402
+ value={string}
398
403
  type={string}
399
404
  label={string}
400
405
  placeholder={string}
@@ -402,13 +407,13 @@ All components will automatically switch to their dark mode variants without any
402
407
  size="sm" | "md" | "lg"
403
408
  variant="default" | "success" | "warning" | "error"
404
409
  className={string}
405
- on:input={(e) => console.log(e.detail.value, e.detail.event)}
406
- on:change={(e) => console.log(e.detail.value, e.detail.event)}
410
+ on:input={(e) => console.log('Input changed:', e.target.value)}
411
+ on:change={(e) => console.log('Input changed:', e.target.value)}
407
412
  />
408
413
  ```
409
414
 
410
415
  **Props:**
411
- - `value`: Input value (bindable)
416
+ - `value`: Input value (controlled)
412
417
  - `type`: Input type (default: "text")
413
418
  - `label`: Input label
414
419
  - `placeholder`: Input placeholder
@@ -418,14 +423,14 @@ All components will automatically switch to their dark mode variants without any
418
423
  - `className`: Additional CSS classes
419
424
 
420
425
  **Events:**
421
- - `input`: Fired on input - `{ detail: { value: string, event: InputEvent } }`
422
- - `change`: Fired on change - `{ detail: { value: string, event: Event } }`
426
+ - `input`: Native input event - `InputEvent`
427
+ - `change`: Native change event - `Event`
423
428
 
424
429
  ### Textarea Component
425
430
 
426
431
  ```svelte
427
432
  <Textarea
428
- bind:value={string}
433
+ value={string}
429
434
  label={string}
430
435
  placeholder={string}
431
436
  disabled={boolean}
@@ -433,13 +438,13 @@ All components will automatically switch to their dark mode variants without any
433
438
  size="sm" | "md" | "lg"
434
439
  variant="default" | "success" | "warning" | "error"
435
440
  className={string}
436
- on:input={(e) => console.log(e.detail.value, e.detail.event)}
437
- on:change={(e) => console.log(e.detail.value, e.detail.event)}
441
+ on:input={(e) => console.log('Textarea changed:', e.target.value)}
442
+ on:change={(e) => console.log('Textarea changed:', e.target.value)}
438
443
  />
439
444
  ```
440
445
 
441
446
  **Props:**
442
- - `value`: Textarea value (bindable)
447
+ - `value`: Textarea value (controlled)
443
448
  - `label`: Textarea label
444
449
  - `placeholder`: Textarea placeholder
445
450
  - `disabled`: Disable the textarea (default: false)
@@ -449,8 +454,8 @@ All components will automatically switch to their dark mode variants without any
449
454
  - `className`: Additional CSS classes
450
455
 
451
456
  **Events:**
452
- - `input`: Fired on input - `{ detail: { value: string, event: InputEvent } }`
453
- - `change`: Fired on change - `{ detail: { value: string, event: Event } }`
457
+ - `input`: Native input event - `InputEvent`
458
+ - `change`: Native change event - `Event`
454
459
 
455
460
  ### Card Component
456
461
 
@@ -621,127 +626,125 @@ Dark mode is automatically supported through CSS custom properties:
621
626
  }
622
627
  ```
623
628
 
624
- ## Event Structure
625
-
626
- All components follow a consistent event structure:
629
+ ## Event Handling
627
630
 
628
- ```typescript
629
- interface BaseEventDetail<T = any> {
630
- value: T;
631
- event?: Event;
632
- }
633
- ```
631
+ Zabi Components now use **native DOM events** with **event forwarding** for maximum compatibility across frameworks.
634
632
 
635
- **Examples:**
636
- - Button click: `{ detail: { value: true, event: MouseEvent } }`
637
- - Input change: `{ detail: { value: string, event: Event } }`
638
- - Checkbox change: `{ detail: { value: boolean, event: Event } }`
633
+ ### Event Forwarding
639
634
 
640
- ## TypeScript Support
635
+ All components use `{...$$restProps}` to forward native DOM events, making them compatible with React, Vue, Svelte, and vanilla JavaScript.
641
636
 
642
- Full TypeScript definitions are included with comprehensive type safety:
637
+ ```svelte
638
+ <!-- All these work the same way -->
639
+ <Button on:click={handleClick}>Click me</Button>
640
+ <Input on:input={handleInput} on:change={handleChange} />
641
+ <Modal on:click={handleClose} on:keydown={handleKeydown} />
642
+ ```
643
643
 
644
- ### Event Types
645
- ```typescript
646
- import type {
647
- ButtonEvents,
648
- InputEvents,
649
- CardEvents,
650
- FormEvents,
651
- NavigationEvents,
652
- KeyValueFormEvents
653
- } from 'zabi-components';
644
+ ### Form Components
654
645
 
655
- // Properly typed event handlers
656
- function handleButtonClick(event: CustomEvent<{ value: boolean; event?: MouseEvent }>) {
657
- console.log('Button clicked:', event.detail.value);
658
- }
646
+ Form components use **controlled components** pattern instead of two-way binding:
659
647
 
660
- function handleFormSubmit(event: CustomEvent<{
661
- data: Record<string, FormDataEntryValue>;
662
- formData: FormData
663
- }>) {
664
- console.log('Form data:', event.detail.data);
665
- }
648
+ ```svelte
649
+ <script lang="ts">
650
+ let inputValue = '';
651
+ let checkboxValue = false;
652
+
653
+ function handleInput(event: Event) {
654
+ inputValue = (event.target as HTMLInputElement).value;
655
+ }
656
+
657
+ function handleCheckbox(event: Event) {
658
+ checkboxValue = (event.target as HTMLInputElement).checked;
659
+ }
660
+ </script>
666
661
 
667
- function handleNavigation(event: CustomEvent<{
668
- item: NavigationItem;
669
- href: string
670
- }>) {
671
- console.log('Navigate to:', event.detail.href);
672
- }
662
+ <Input
663
+ value={inputValue}
664
+ on:input={handleInput}
665
+ label="Name"
666
+ />
667
+ <Checkbox
668
+ checked={checkboxValue}
669
+ on:change={handleCheckbox}
670
+ label="Subscribe"
671
+ />
673
672
  ```
674
673
 
675
- ### Component Props
676
- ```typescript
677
- // All components have proper prop typing
678
- interface CardProps {
679
- title?: string;
680
- subtitle?: string;
681
- description?: string;
682
- image?: string;
683
- variant?: "default" | "elevated";
684
- interactive?: boolean;
685
- className?: string;
686
- }
674
+ ### Migration from Previous Versions
687
675
 
688
- interface FormProps {
689
- method?: "get" | "post";
690
- action?: string;
691
- className?: string;
692
- }
676
+ **Before (v2.0.x):**
677
+ ```svelte
678
+ <Input bind:value={inputValue} />
679
+ <Button on:click={handleClick}>Click</Button>
680
+ <Modal bind:isOpen on:close={handleClose} />
693
681
  ```
694
682
 
695
- ### Event Dispatchers
696
- ```typescript
697
- // Components use typed event dispatchers
698
- const dispatch = createEventDispatcher<{
699
- click: { event: MouseEvent };
700
- submit: { data: Record<string, FormDataEntryValue>; formData: FormData };
701
- navigate: { item: NavigationItem; href: string };
702
- }>();
683
+ **After (v2.1.x):**
684
+ ```svelte
685
+ <Input value={inputValue} on:input={(e) => inputValue = e.target.value} />
686
+ <Button on:click={handleClick}>Click</Button>
687
+ <Modal bind:isOpen on:click={handleClose} />
703
688
  ```
704
689
 
690
+ ### Benefits
691
+
692
+ - ✅ **SSR Safe**: No more hydration errors in production
693
+ - ✅ **Cross-Framework**: Works in React, Vue, Svelte, vanilla JS
694
+ - ✅ **Standards Compliant**: Uses native DOM events
695
+ - ✅ **Better Performance**: Reduced JavaScript overhead
696
+
697
+ ## TypeScript Support
698
+
699
+ Full TypeScript definitions are included with comprehensive type safety:
700
+
705
701
  ### Event Types
706
702
 
707
- All components use standardized event types:
703
+ All components now use native DOM events with proper TypeScript typing:
708
704
 
709
705
  ```typescript
710
- // Base event structure
711
- interface BaseEventDetail<T = any> {
712
- value: T;
713
- event?: Event;
714
- }
715
-
716
- // Specific event types
717
- interface ClickEventDetail extends BaseEventDetail<boolean> {
718
- event?: MouseEvent | KeyboardEvent;
706
+ // Native event handlers with proper typing
707
+ function handleButtonClick(event: MouseEvent) {
708
+ console.log('Button clicked:', event);
719
709
  }
720
710
 
721
- interface InputEventDetail extends BaseEventDetail<string> {
722
- event?: InputEvent;
711
+ function handleInputChange(event: Event) {
712
+ const target = event.target as HTMLInputElement;
713
+ console.log('Input value:', target.value);
723
714
  }
724
715
 
725
- interface ChangeEventDetail extends BaseEventDetail<string> {
726
- event?: Event;
716
+ function handleFormSubmit(event: SubmitEvent) {
717
+ const formData = new FormData(event.target as HTMLFormElement);
718
+ const data = Object.fromEntries(formData.entries());
719
+ console.log('Form data:', data);
727
720
  }
728
721
  ```
729
722
 
730
- ### Component Event Interfaces
723
+ ### Component Props
724
+
725
+ All components have proper prop typing with event forwarding:
731
726
 
732
727
  ```typescript
733
- interface ButtonEvents {
734
- click: ClickEventDetail;
728
+ // All components support event forwarding
729
+ interface ButtonProps {
730
+ variant?: "primary" | "secondary" | "danger";
731
+ size?: "sm" | "md" | "lg";
732
+ disabled?: boolean;
733
+ type?: "button" | "submit" | "reset";
734
+ className?: string;
735
+ // All native button events are forwarded via {...$$restProps}
735
736
  }
736
737
 
737
- interface InputEvents {
738
- input: InputEventDetail;
739
- change: ChangeEventDetail;
740
- focus: { event: FocusEvent };
741
- blur: { event: FocusEvent };
742
- keydown: { event: KeyboardEvent };
743
- keyup: { event: KeyboardEvent };
744
- clear: { event: Event };
738
+ interface InputProps {
739
+ value?: string;
740
+ type?: string;
741
+ label?: string;
742
+ placeholder?: string;
743
+ disabled?: boolean;
744
+ size?: "sm" | "md" | "lg";
745
+ variant?: "default" | "success" | "warning" | "error";
746
+ className?: string;
747
+ // All native input events are forwarded via {...$$restProps}
745
748
  }
746
749
  ```
747
750
 
@@ -754,7 +757,7 @@ interface InputEvents {
754
757
  variant="primary"
755
758
  size="lg"
756
759
  className="w-full shadow-lg hover:shadow-xl"
757
- on:click={(e) => console.log('Clicked!', e.detail.value)}
760
+ on:click={(e) => console.log('Clicked!', e)}
758
761
  >
759
762
  Custom Button
760
763
  </Button>
@@ -794,7 +797,7 @@ interface InputEvents {
794
797
  return Object.keys(errors).length === 0;
795
798
  }
796
799
 
797
- function handleSubmit(event: CustomEvent) {
800
+ function handleSubmit(event: SubmitEvent) {
798
801
  if (validateForm()) {
799
802
  showSuccess = true;
800
803
  // Submit form
@@ -810,27 +813,27 @@ interface InputEvents {
810
813
 
811
814
  <form on:submit|preventDefault={handleSubmit}>
812
815
  <Input
813
- bind:value={formData.name}
816
+ value={formData.name}
817
+ on:input={(e) => formData.name = e.target.value}
814
818
  label="Name"
815
819
  placeholder="Enter your name"
816
820
  required
817
- error={errors.name}
818
821
  />
819
822
 
820
823
  <Input
821
- bind:value={formData.email}
824
+ value={formData.email}
822
825
  type="email"
826
+ on:input={(e) => formData.email = e.target.value}
823
827
  label="Email"
824
828
  placeholder="Enter your email"
825
829
  required
826
- error={errors.email}
827
830
  />
828
831
 
829
832
  <Input
830
- bind:value={formData.message}
833
+ value={formData.message}
834
+ on:input={(e) => formData.message = e.target.value}
831
835
  label="Message"
832
836
  placeholder="Enter your message"
833
- helpText="Tell us what you think"
834
837
  />
835
838
 
836
839
  <Button type="submit" variant="primary">
@@ -839,9 +842,11 @@ interface InputEvents {
839
842
  </form>
840
843
 
841
844
  <div slot="footer">
842
- <Alert variant="success" closable bind:show={showSuccess}>
843
- Message sent successfully!
844
- </Alert>
845
+ {#if showSuccess}
846
+ <Alert variant="success" closable>
847
+ Message sent successfully!
848
+ </Alert>
849
+ {/if}
845
850
  </div>
846
851
  </Card>
847
852
  ```
@@ -860,50 +865,32 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
860
865
 
861
866
  ## Changelog
862
867
 
863
- ### v1.1.1 (Latest) - "Enhanced Type Safety" Edition
864
-
865
- #### 🔧 TypeScript Improvements
866
- - **Enhanced Type Definitions**: Updated generated TypeScript definitions for better type safety
867
- - **Improved Package Structure**: Enhanced package structure with improved type exports
868
- - **Build Consistency**: Fixed build consistency and versioning across all generated files
869
- - **Better Type Exports**: Improved TypeScript declaration file generation
870
-
871
- #### 🎯 Philosophy Change
872
- - **Clean & Simple**: Adopted "less is more" philosophy - removed unnecessary complexity
873
- - **Focused Components**: Streamlined to essential components that just work
874
- - **Clean Naming**: Removed "Simple" prefixes - it's just Card, Form, Layout, Navigation
875
-
876
- #### ✨ New Clean Components
877
- - **Card**: Clean, semantic card container with interactive support
878
- - **Form**: Simple form wrapper with FormData handling and validation
879
- - **Layout**: Page layout system with header, main, footer slots
880
- - **Navigation**: Clean navigation with header/sidebar variants
881
-
882
- #### 🐛 Bug Fixes
883
- - **Fixed TypeScript Errors**: Resolved all event handler type mismatches
884
- - **Fixed Import Paths**: Corrected .js extensions in lib exports
885
- - **Fixed CSS Issues**: Resolved `:global()` selector placement errors
886
- - **Fixed Variant Types**: Corrected component variant type mismatches
887
- - **Fixed Accessibility**: Resolved tabindex warnings for non-interactive elements
888
-
889
- #### 🚀 Modern CSS Features
890
- - **Container Queries**: Added support for container-based responsive design
891
- - **CSS Grid & Subgrid**: Implemented modern grid layouts
892
- - **CSS Logical Properties**: Added RTL support with logical properties
893
- - **CSS Cascade Layers**: Organized styles with cascade layers
894
- - **CSS Containment**: Added performance optimizations
895
-
896
- #### 📦 TypeScript Improvements
897
- - **Event Type Safety**: All components now have proper event typing
898
- - **Component Props**: Comprehensive prop type definitions
899
- - **Event Dispatchers**: Typed event dispatchers for all components
900
- - **Type Generation**: Proper TypeScript declaration generation
901
-
902
- #### 🎨 Design System
903
- - **Semantic HTML**: All components use proper semantic elements
904
- - **Accessibility**: ARIA compliant with keyboard navigation
905
- - **Dark Mode**: Built-in dark mode support with CSS custom properties
906
- - **Responsive**: Mobile-first responsive design
868
+ ### v2.1.0 (Latest) - "Cross-Framework Compatible" Edition
869
+
870
+ #### 🚀 **MAJOR BREAKING CHANGES** - Event Handling Overhaul
871
+
872
+ This is a **major breaking change** that affects how all components handle events. The refactoring eliminates SSR/production errors and makes components compatible with React, Vue, and vanilla JavaScript applications.
873
+
874
+ #### ✅ **What's Fixed**
875
+ - **SSR/Production Errors**: Eliminated all `createEventDispatcher` hydration errors
876
+ - **Cross-Framework Compatibility**: Components now work in React, Vue, Svelte, and vanilla JS
877
+ - **Event Forwarding**: All components use `{...$$restProps}` for native DOM events
878
+ - **Standards Compliance**: Uses web standards instead of framework-specific events
879
+
880
+ #### 🔄 **Migration Required**
881
+ - **Form Components**: Replace `bind:value` with `value` prop + event handlers
882
+ - **Event Names**: Some custom events replaced with native DOM events
883
+ - **Event Structure**: Simplified event structures across all components
884
+
885
+ #### 📋 **Breaking Changes**
886
+ 1. **Form Components**: Must use `value` prop + event handlers instead of `bind:value`
887
+ 2. **Event Names**: Some custom events replaced with native DOM events
888
+ 3. **Event Structure**: Simplified event structures across all components
889
+ 4. **SSR Compatibility**: Components now work correctly in SSR environments
890
+
891
+ See the [Migration Guide](#migration-from-previous-versions) above for detailed examples.
892
+
893
+ ### v2.0.2 - "Less is More" Edition
907
894
 
908
895
  ## Development Setup
909
896