@diniz/webcomponents 1.0.2 → 1.0.4

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
@@ -12,13 +12,198 @@ A lightweight, framework-agnostic web components library built with vanilla Type
12
12
  🎯 **Tree-shakeable** - Import only what you need
13
13
  ♿ **Accessible** - ARIA attributes and keyboard navigation
14
14
 
15
+ ## 🚀 Live Demo
16
+
17
+ Check out the interactive demo and component examples:
18
+
19
+ **[View Live Demo →](https://rodiniz.github.io/webcomponents/)**
20
+
15
21
  ## Installation
16
22
 
17
23
  ```bash
18
24
  npm install @diniz/webcomponents
19
25
  ```
20
26
 
21
- ## Quick Start
27
+ ## Using with Vite (No Framework)
28
+
29
+ This library works seamlessly with Vite without requiring any framework. Here's how to set up a vanilla JavaScript/TypeScript project:
30
+
31
+ ### 1. Create a New Vite Project
32
+
33
+ ```bash
34
+ # Create a new Vite project with vanilla TypeScript template
35
+ npm create vite@latest my-app -- --template vanilla-ts
36
+ cd my-app
37
+ npm install
38
+ ```
39
+
40
+ ### 2. Install the Library
41
+
42
+ ```bash
43
+ npm install @diniz/webcomponents
44
+ ```
45
+
46
+ ### 3. Import Components in Your Main File
47
+
48
+ In your `src/main.ts` file:
49
+
50
+ ```typescript
51
+ import '@diniz/webcomponents';
52
+ import '@diniz/webcomponents/dist/style.css'; // Import styles
53
+
54
+ // Now you can use the components in your HTML
55
+ document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
56
+ <div>
57
+ <h1>My Web Components App</h1>
58
+ <ui-button variant="primary" size="md">Click Me</ui-button>
59
+ <ui-date-picker format="DD/MM/YYYY"></ui-date-picker>
60
+ </div>
61
+ `;
62
+ ```
63
+
64
+ ### 4. Use Components in HTML
65
+
66
+ In your `index.html`:
67
+
68
+ ```html
69
+ <!DOCTYPE html>
70
+ <html lang="en">
71
+ <head>
72
+ <meta charset="UTF-8" />
73
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
74
+ <title>My App</title>
75
+ </head>
76
+ <body>
77
+ <div id="app">
78
+ <ui-button variant="primary">Click Me</ui-button>
79
+ <ui-date-picker format="DD/MM/YYYY"></ui-date-picker>
80
+ <ui-table></ui-table>
81
+ </div>
82
+ <script type="module" src="/src/main.ts"></script>
83
+ </body>
84
+ </html>
85
+ ```
86
+
87
+ ### 5. Add Event Listeners (Optional)
88
+
89
+ ```typescript
90
+ // Wait for components to be defined
91
+ customElements.whenDefined('ui-button').then(() => {
92
+ const button = document.querySelector('ui-button');
93
+ button?.addEventListener('click', () => {
94
+ console.log('Button clicked!');
95
+ });
96
+ });
97
+
98
+ // Listen to custom events
99
+ const picker = document.querySelector('ui-date-picker');
100
+ picker?.addEventListener('date-change', ((e: CustomEvent) => {
101
+ console.log('Date selected:', e.detail.value);
102
+ }) as EventListener);
103
+ ```
104
+
105
+ ### 6. TypeScript Support
106
+
107
+ For full TypeScript support, create a `src/types.d.ts` file:
108
+
109
+ ```typescript
110
+ declare module '@diniz/webcomponents' {
111
+ export interface UIButton extends HTMLElement {
112
+ variant: 'primary' | 'secondary' | 'ghost';
113
+ size: 'sm' | 'md' | 'lg';
114
+ icon?: string;
115
+ disabled?: boolean;
116
+ }
117
+
118
+ export interface UIDatePicker extends HTMLElement {
119
+ format: string;
120
+ value: string;
121
+ min?: string;
122
+ max?: string;
123
+ }
124
+
125
+ // Add other component interfaces as needed
126
+ }
127
+
128
+ declare global {
129
+ interface HTMLElementTagNameMap {
130
+ 'ui-button': import('@diniz/webcomponents').UIButton;
131
+ 'ui-date-picker': import('@diniz/webcomponents').UIDatePicker;
132
+ // Add other components as needed
133
+ }
134
+ }
135
+ ```
136
+
137
+ ### 7. Build for Production
138
+
139
+ ```bash
140
+ npm run build
141
+ ```
142
+
143
+ The build output will be in the `dist` folder, ready to deploy to any static hosting service.
144
+
145
+ ### Tree-shaking (Import Only What You Need)
146
+
147
+ You can import individual components to reduce bundle size:
148
+
149
+ ```typescript
150
+ // Import only specific components
151
+ import { UIButton } from '@diniz/webcomponents';
152
+ import '@diniz/webcomponents/dist/style.css';
153
+
154
+ // The component is automatically registered
155
+ // Now you can use <ui-button> in your HTML
156
+ ```
157
+
158
+ ### Configuration Tips
159
+
160
+ **Vite Config** - No special configuration needed! Web Components work out of the box with Vite.
161
+
162
+ **CSS Customization** - Override CSS custom properties to match your theme:
163
+
164
+ ```css
165
+ :root {
166
+ --color-primary: #3b82f6;
167
+ --color-secondary: #8b5cf6;
168
+ --color-success: #10b981;
169
+ --color-danger: #ef4444;
170
+ --color-warning: #f59e0b;
171
+ --color-info: #06b6d4;
172
+
173
+ --radius-sm: 0.25rem;
174
+ --radius-md: 0.375rem;
175
+ --radius-lg: 0.5rem;
176
+ }
177
+ ```
178
+ **Update `src/main.ts`:**
179
+ ```typescript
180
+ import '@diniz/webcomponents';
181
+ import '@diniz/webcomponents/dist/style.css';
182
+
183
+ document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
184
+ <div>
185
+ <h1>My Web Components App</h1>
186
+ <ui-button variant="primary">Click Me</ui-button>
187
+ <ui-date-picker format="DD/MM/YYYY"></ui-date-picker>
188
+ <ui-table id="myTable"></ui-table>
189
+ </div>
190
+ `;
191
+
192
+ // Add some data to the table
193
+ const table = document.getElementById('myTable') as any;
194
+ table.data = {
195
+ columns: [
196
+ { key: 'name', label: 'Name' },
197
+ { key: 'role', label: 'Role' }
198
+ ],
199
+ rows: [
200
+ { name: 'Alice', role: 'Admin' },
201
+ { name: 'Bob', role: 'User' }
202
+ ]
203
+ };
204
+ ```
205
+
206
+ ### Using via CDN or Direct Import
22
207
 
23
208
  ```html
24
209
  <script type="module">
@@ -34,11 +219,14 @@ npm install @diniz/webcomponents
34
219
 
35
220
  ### 🔘 Button (`ui-button`)
36
221
 
37
- A versatile button component with multiple variants and sizes.
222
+ A versatile button component with multiple variants, sizes, and icon support.
38
223
 
39
224
  **Features:**
40
225
  - 3 variants: `primary`, `secondary`, `ghost`
41
226
  - 3 sizes: `sm`, `md`, `lg`
227
+ - Icon support with [Feather Icons](https://feathericons.com/)
228
+ - Icon positioning (left/right)
229
+ - Icon-only buttons
42
230
  - Disabled state support
43
231
  - Button type support
44
232
  - Smooth transitions and hover effects
@@ -48,11 +236,18 @@ A versatile button component with multiple variants and sizes.
48
236
  <ui-button variant="primary" size="md">Primary Button</ui-button>
49
237
  <ui-button variant="secondary" size="sm">Secondary</ui-button>
50
238
  <ui-button variant="ghost" disabled>Disabled</ui-button>
239
+
240
+ <!-- With icons -->
241
+ <ui-button variant="primary" icon="check">Save</ui-button>
242
+ <ui-button variant="secondary" icon="trash-2" icon-position="right">Delete</ui-button>
243
+ <ui-button variant="ghost" icon="settings"></ui-button>
51
244
  ```
52
245
 
53
246
  **Attributes:**
54
247
  - `variant` - Button style (`primary` | `secondary` | `ghost`)
55
248
  - `size` - Button size (`sm` | `md` | `lg`)
249
+ - `icon` - Icon name from Feather Icons
250
+ - `icon-position` - Icon position (`left` | `right`, default: `left`)
56
251
  - `disabled` - Disable the button
57
252
  - `type` - Button type (`button` | `submit` | `reset`)
58
253
 
@@ -250,6 +445,198 @@ Advanced form input with built-in validation and error handling.
250
445
 
251
446
  ---
252
447
 
448
+ ### 🪟 Modal (`ui-modal`)
449
+
450
+ Responsive modal dialog with customizable sizes and behaviors.
451
+
452
+ **Features:**
453
+ - 5 size options: `sm`, `md`, `lg`, `xl`, `full`
454
+ - Auto-close on Escape key (configurable)
455
+ - Auto-close on backdrop click (configurable)
456
+ - Smooth animations (fade in, slide up)
457
+ - Header, body, and footer slots
458
+ - Programmatic open/close API
459
+ - Custom events
460
+ - Body scroll lock when open
461
+
462
+ **Usage:**
463
+ ```html
464
+ <ui-button id="openModal">Open Modal</ui-button>
465
+
466
+ <ui-modal id="myModal" title="Welcome!" size="md">
467
+ <p>This is the modal content.</p>
468
+ <p>You can include any HTML here.</p>
469
+
470
+ <div slot="footer">
471
+ <ui-button id="closeBtn" variant="secondary">Cancel</ui-button>
472
+ <ui-button id="confirmBtn" variant="primary">Confirm</ui-button>
473
+ </div>
474
+ </ui-modal>
475
+
476
+ <script>
477
+ const modal = document.getElementById('myModal');
478
+ const openBtn = document.getElementById('openModal');
479
+ const closeBtn = document.getElementById('closeBtn');
480
+
481
+ openBtn.addEventListener('click', () => modal.open());
482
+ closeBtn.addEventListener('click', () => modal.close());
483
+
484
+ modal.addEventListener('modal-close', () => {
485
+ console.log('Modal closed');
486
+ });
487
+ </script>
488
+ ```
489
+
490
+ **Attributes:**
491
+ - `title` - Modal title text
492
+ - `size` - Modal size (`sm` | `md` | `lg` | `xl` | `full`)
493
+ - `open` - Open state attribute
494
+ - `no-close-on-escape` - Disable closing on Escape key
495
+ - `no-close-on-backdrop` - Disable closing on backdrop click
496
+
497
+ **Methods:**
498
+ - `open()` - Open the modal
499
+ - `close()` - Close the modal
500
+
501
+ **Events:**
502
+ - `modal-open` - Fired when modal opens
503
+ - `modal-close` - Fired when modal closes
504
+
505
+ ---
506
+
507
+ ### 📋 Select (`ui-select`)
508
+
509
+ Customizable dropdown select with search capability.
510
+
511
+ **Features:**
512
+ - JSON-based options configuration
513
+ - Searchable dropdown (optional)
514
+ - Keyboard navigation
515
+ - Disabled options support
516
+ - Custom placeholder text
517
+ - Change events with full option details
518
+ - Click-outside to close
519
+ - Smooth animations
520
+ - Theme-aware styling
521
+
522
+ **Usage:**
523
+ ```html
524
+ <ui-select
525
+ id="mySelect"
526
+ label="Choose a Country"
527
+ placeholder="Select country..."
528
+ searchable
529
+ ></ui-select>
530
+
531
+ <script>
532
+ const select = document.getElementById('mySelect');
533
+
534
+ // Set options
535
+ const options = [
536
+ { value: 'us', label: 'United States' },
537
+ { value: 'uk', label: 'United Kingdom' },
538
+ { value: 'ca', label: 'Canada' },
539
+ { value: 'au', label: 'Australia', disabled: true }
540
+ ];
541
+
542
+ select.setAttribute('options', JSON.stringify(options));
543
+
544
+ // Set initial value
545
+ select.setAttribute('value', 'us');
546
+
547
+ // Listen for changes
548
+ select.addEventListener('select-change', (e) => {
549
+ console.log('Value:', e.detail.value);
550
+ console.log('Option:', e.detail.option);
551
+ });
552
+ </script>
553
+ ```
554
+
555
+ **Attributes:**
556
+ - `label` - Label text above select
557
+ - `placeholder` - Placeholder when no selection
558
+ - `options` - JSON string of options array
559
+ - `value` - Currently selected value
560
+ - `disabled` - Disable the select
561
+ - `searchable` - Enable search functionality
562
+
563
+ **Option Format:**
564
+ ```typescript
565
+ {
566
+ value: string; // The option value
567
+ label: string; // Display text
568
+ disabled?: boolean; // Optional: disable option
569
+ }
570
+ ```
571
+
572
+ **Events:**
573
+ - `select-change` - Fired when selection changes
574
+ - `detail.value` - Selected value
575
+ - `detail.option` - Full option object
576
+
577
+ ---
578
+
579
+ ### ☑️ Checkbox (`ui-checkbox`)
580
+
581
+ Flexible checkbox with indeterminate state support.
582
+
583
+ **Features:**
584
+ - 3 sizes: `sm`, `md`, `lg`
585
+ - Checked/unchecked states
586
+ - Indeterminate state (useful for "select all")
587
+ - Disabled state
588
+ - Label support (attribute or slot)
589
+ - Programmatic API
590
+ - Custom events
591
+ - Smooth animations and transitions
592
+ - Theme-aware styling
593
+
594
+ **Usage:**
595
+ ```html
596
+ <!-- Basic usage -->
597
+ <ui-checkbox label="Accept terms"></ui-checkbox>
598
+ <ui-checkbox label="Subscribe" checked></ui-checkbox>
599
+ <ui-checkbox label="Disabled" disabled></ui-checkbox>
600
+
601
+ <!-- With sizes -->
602
+ <ui-checkbox label="Small" size="sm"></ui-checkbox>
603
+ <ui-checkbox label="Medium" size="md"></ui-checkbox>
604
+ <ui-checkbox label="Large" size="lg"></ui-checkbox>
605
+
606
+ <!-- Programmatic usage -->
607
+ <ui-checkbox id="myCheckbox" label="Select All"></ui-checkbox>
608
+
609
+ <script>
610
+ const checkbox = document.getElementById('myCheckbox');
611
+
612
+ // Listen for changes
613
+ checkbox.addEventListener('checkbox-change', (e) => {
614
+ console.log('Checked:', e.detail.checked);
615
+ });
616
+
617
+ // Set states programmatically
618
+ checkbox.setChecked(true);
619
+ checkbox.setIndeterminate(true);
620
+ </script>
621
+ ```
622
+
623
+ **Attributes:**
624
+ - `label` - Label text
625
+ - `checked` - Checked state
626
+ - `indeterminate` - Indeterminate state
627
+ - `disabled` - Disable checkbox
628
+ - `size` - Checkbox size (`sm` | `md` | `lg`)
629
+
630
+ **Methods:**
631
+ - `setChecked(checked: boolean)` - Set checked state
632
+ - `setIndeterminate(indeterminate: boolean)` - Set indeterminate state
633
+
634
+ **Events:**
635
+ - `checkbox-change` - Fired when state changes
636
+ - `detail.checked` - New checked state
637
+
638
+ ---
639
+
253
640
  ### 🎯 Sidebar (`app-sidebar`)
254
641
 
255
642
  Navigation sidebar component with links.
@@ -406,9 +793,12 @@ src/
406
793
  ├── shared/
407
794
  │ └── components/ # Reusable UI components
408
795
  │ ├── button.ts
796
+ │ ├── checkbox.ts
409
797
  │ ├── date-picker.ts
410
798
  │ ├── input.ts
799
+ │ ├── modal.ts
411
800
  │ ├── pagination.ts
801
+ │ ├── select.ts
412
802
  │ └── table.ts
413
803
  ├── layouts/
414
804
  │ └── app-layout.ts # Application shell
@@ -416,90 +806,6 @@ src/
416
806
  └── styles/
417
807
  └── theme.css # Global theme variables
418
808
  ```
419
-
420
- ---
421
-
422
- ## Examples
423
-
424
- ### Form with Validation
425
-
426
- ```html
427
- <form id="myForm">
428
- <ui-input
429
- type="email"
430
- name="email"
431
- label="Email"
432
- required
433
- ></ui-input>
434
-
435
- <ui-input
436
- type="password"
437
- name="password"
438
- label="Password"
439
- minlength="8"
440
- required
441
- ></ui-input>
442
-
443
- <ui-button type="submit">Submit</ui-button>
444
- </form>
445
- ```
446
-
447
- ### Data Table with Pagination
448
-
449
- ```html
450
- <ui-table id="dataTable"></ui-table>
451
- <ui-pagination id="pagination" page-size="10"></ui-pagination>
452
-
453
- <script type="module">
454
- const table = document.getElementById('dataTable');
455
- const pagination = document.getElementById('pagination');
456
-
457
- async function loadData(page = 1) {
458
- const response = await fetch(`/api/data?page=${page}`);
459
- const data = await response.json();
460
-
461
- table.data = {
462
- columns: [
463
- { key: 'name', label: 'Name' },
464
- { key: 'email', label: 'Email' }
465
- ],
466
- rows: data.items
467
- };
468
-
469
- pagination.total = data.total;
470
- pagination.currentPage = page;
471
- }
472
-
473
- pagination.addEventListener('page-change', (e) => {
474
- loadData(e.detail.page);
475
- });
476
-
477
- loadData(1);
478
- </script>
479
- ```
480
-
481
- ### Date Range Picker
482
-
483
- ```html
484
- <ui-date-picker id="startDate" format="DD/MM/YYYY"></ui-date-picker>
485
- <ui-date-picker id="endDate" format="DD/MM/YYYY"></ui-date-picker>
486
-
487
- <script>
488
- const start = document.getElementById('startDate');
489
- const end = document.getElementById('endDate');
490
-
491
- start.addEventListener('date-change', (e) => {
492
- end.setAttribute('min', e.detail.value);
493
- });
494
-
495
- end.addEventListener('date-change', (e) => {
496
- start.setAttribute('max', e.detail.value);
497
- });
498
- </script>
499
- ```
500
-
501
- ---
502
-
503
809
  ## Contributing
504
810
 
505
811
  Contributions are welcome! Please feel free to submit a Pull Request.
@@ -508,13 +814,6 @@ Contributions are welcome! Please feel free to submit a Pull Request.
508
814
 
509
815
  ## License
510
816
 
511
- MIT © [Your Name]
512
-
513
- ---
817
+ MIT © Rodrigo Diniz
514
818
 
515
- ## Links
516
819
 
517
- - [Demo](https://your-demo-url.com)
518
- - [Documentation](https://your-docs-url.com)
519
- - [GitHub](https://github.com/yourusername/webcomponents)
520
- - [npm](https://www.npmjs.com/package/@diniz/webcomponents)
package/dist/404.html ADDED
@@ -0,0 +1,14 @@
1
+
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Web Components SPA Starter</title>
8
+ <script type="module" crossorigin src="/webcomponents/assets/index-DJpTIOwN.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/webcomponents/assets/index-uHZenGtA.css">
10
+ </head>
11
+ <body>
12
+ <div id="app"></div>
13
+ </body>
14
+ </html>
@@ -0,0 +1,37 @@
1
+ var f=Object.defineProperty;var g=(r,e,o)=>e in r?f(r,e,{enumerable:!0,configurable:!0,writable:!0,value:o}):r[e]=o;var c=(r,e,o)=>g(r,typeof e!="symbol"?e+"":e,o);import{s as m}from"./index-DJpTIOwN.js";import{f as x}from"./vendor-BvJLUv9i.js";function v(r){let e=r;const o=new Set;return{get:()=>e,set:t=>{Object.is(e,t)||(e=t,o.forEach(a=>a(e)))},subscribe:t=>(o.add(t),()=>o.delete(t))}}class p extends HTMLElement{constructor(){super();c(this,"state");c(this,"signalUnsubs");this.attachShadow({mode:"open"}),this.state={},this.signalUnsubs=new Set}useSignal(o){const t=v(o),a=t.subscribe(()=>this.render());return this.signalUnsubs.add(a),t}setState(o){this.state={...this.state,...o},this.render()}connectedCallback(){this.render()}disconnectedCallback(){this.signalUnsubs.forEach(o=>o()),this.signalUnsubs.clear()}render(){}}const b=':root{--color-primary: #24ec71;--color-primary-contrast: #ffffff;--color-ink: #0f172a;--color-muted: #f1f5f9;--color-header: #f8fafc;--color-border: #e2e8f0;--color-border-strong: #cbd5f5;--color-nav-bg: #222222;--color-nav-text: #ffffff;--shadow-primary: 0 8px 18px rgba(31, 111, 235, .25);--focus-ring: #9ec5ff;--radius-pill: 999px;--radius-md: 12px;--color-page-bg: #ffffff;--color-page-text: #0f172a}body{background:var(--color-page-bg);color:var(--color-page-text);margin:0;font-family:Segoe UI,system-ui,-apple-system,sans-serif}:host([data-ui="button"]){display:inline-block}:host([data-ui="table"]){display:block}:host([data-ui="layout"]){display:block}:host([data-ui="sidebar"]){display:block}.btn{align-items:center;border:1px solid transparent;border-radius:var(--radius-pill);cursor:pointer;display:inline-flex;font-family:inherit;font-size:.95rem;font-weight:600;gap:.5rem;line-height:1;padding:.65rem 1.2rem;transition:transform .12s ease,box-shadow .12s ease,background-color .12s ease}.btn:focus-visible{outline:3px solid var(--focus-ring);outline-offset:2px}.btn:active:not(:disabled){transform:translateY(1px)}.btn:disabled{cursor:not-allowed;opacity:.6}.btn.primary{background:var(--color-primary);color:var(--color-primary-contrast);box-shadow:var(--shadow-primary)}.btn.secondary{background:var(--color-muted);color:var(--color-ink);border-color:var(--color-border-strong)}.btn.ghost{background:transparent;color:var(--color-primary);border-color:var(--color-border-strong)}.btn.has-icon{line-height:1.2}.btn .btn-icon{width:18px;height:18px;flex-shrink:0}.btn .btn-icon svg{width:100%;height:100%}.btn.icon-only{padding:.65rem;aspect-ratio:1}.btn.icon-only.sm{padding:.45rem}.btn.icon-only.lg{padding:.8rem}.btn.sm .btn-icon{width:14px;height:14px}.btn.lg .btn-icon{width:22px;height:22px}.btn.sm{font-size:.85rem;padding:.45rem .9rem;box-shadow:0 4px 12px #a7124426}.btn.md{font-size:.95rem;padding:.65rem 1.2rem}.btn.lg{font-size:1.05rem;padding:.8rem 1.5rem}.table-wrap{border:1px solid var(--color-border);border-radius:var(--radius-md);overflow:hidden}table{border-collapse:collapse;width:100%}thead{background:var(--color-header)}th,td{padding:.75rem 1rem;text-align:left;border-bottom:1px solid var(--color-border);font-size:.95rem;border-right:1px solid var(--color-border)}tr:last-child td{border-bottom:none}.align-left{text-align:left}.align-center{text-align:center}.align-right{text-align:right}.actions-cell{display:flex;gap:.5rem;justify-content:center}.action-btn{padding:.35rem .7rem;font-size:.8rem;border-radius:4px;cursor:pointer;border:1px solid var(--color-border-strong);background:var(--color-muted);color:var(--color-ink);transition:background-color .12s ease}.action-btn:hover{background:var(--color-border)}.action-btn.edit-btn{background:var(--color-primary);color:var(--color-primary-contrast);border-color:var(--color-primary)}.action-btn.edit-btn:hover{opacity:.85}.action-btn.delete-btn{background:#ef4444;color:#fff;border-color:#ef4444}.action-btn.delete-btn:hover{opacity:.85}.app-nav{padding:1rem;background:var(--color-nav-bg);color:var(--color-nav-text)}.app-link{color:var(--color-nav-text);margin-right:1rem;text-decoration:none}.signal-demo,.theme-toggle{margin-top:16px;display:flex;align-items:center;gap:12px}.data-table{margin-top:15px}.dashboard-layout{display:grid;grid-template-columns:220px minmax(0,1fr);gap:24px;padding:24px}.dashboard-sidebar{background:var(--color-muted);border:1px solid var(--color-border);border-radius:var(--radius-md);padding:18px}.sidebar-title{margin:0 0 12px;font-size:1rem}.sidebar-nav{display:flex;flex-direction:column;gap:10px}.sidebar-link{color:var(--color-ink);text-decoration:none;font-weight:600}.dashboard-main{display:flex;flex-direction:column;gap:12px}.dashboard-actions{display:flex;flex-wrap:wrap;gap:12px}@media (max-width: 900px){.dashboard-layout{grid-template-columns:1fr}}:host([data-ui="input"]){display:block}.input-wrapper{display:flex;flex-direction:column;gap:.35rem}.input-label{font-size:.9rem;font-weight:600;color:var(--color-ink)}.input-field{padding:.6rem .85rem;font-size:.95rem;font-family:inherit;border:1.5px solid var(--color-border);border-radius:6px;background:var(--color-page-bg);color:var(--color-page-text);transition:border-color .15s ease,box-shadow .15s ease;outline:none}.input-field::placeholder{color:#94a3b8}.input-field:focus{border-color:var(--color-primary);box-shadow:0 0 0 3px #24ec7126}.input-field:disabled{background:var(--color-muted);cursor:not-allowed;opacity:.7}.input-wrapper.invalid .input-field{border-color:#ef4444}.input-wrapper.invalid .input-field:focus{box-shadow:0 0 0 3px #ef444426}.input-error{font-size:.8rem;color:#ef4444;display:flex;align-items:center;gap:.25rem}.input-error.hidden{display:none}:host([data-ui="checkbox"]){display:inline-flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none}:host([data-ui="checkbox"][disabled]){cursor:not-allowed;opacity:.6}.checkbox-container{display:inline-flex;align-items:center;gap:.75rem}.checkbox-box{position:relative;display:inline-flex;align-items:center;justify-content:center;border:2px solid var(--color-border, #cbd5e1);border-radius:var(--radius-sm, 4px);background:#fff;transition:all .2s;flex-shrink:0;box-sizing:border-box}.checkbox-box.size-sm{min-width:16px;max-width:16px;min-height:16px;max-height:16px}.checkbox-box.size-md{min-width:18px;max-width:18px;min-height:18px;max-height:18px}.checkbox-box.size-lg{min-width:20px;max-width:20px;min-height:20px;max-height:20px}.checkbox-box:hover:not(.disabled){border-color:var(--color-primary, #24ec71)}.checkbox-box.checked,.checkbox-box.indeterminate{background:var(--color-primary, #24ec71);border-color:var(--color-primary, #24ec71)}.checkbox-box.disabled{background:var(--color-muted, #f1f5f9);cursor:not-allowed}.checkbox-icon{display:none;color:#fff;position:absolute}.checkbox-box.checked .checkbox-icon.check,.checkbox-box.indeterminate .checkbox-icon.minus{display:block}.checkbox-icon.check{width:12px;height:12px}.checkbox-icon.minus{width:10px;height:10px}.checkbox-label{font-size:.95rem;color:var(--color-ink, #0f172a);line-height:1.5}.checkbox-container.size-sm .checkbox-label{font-size:.875rem}.checkbox-container.size-lg .checkbox-label{font-size:1rem}input[type=checkbox]{position:absolute;opacity:0;pointer-events:none}.modal-backdrop{display:none;position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:9999;animation:fadeIn .2s ease-out}.modal-backdrop.open{display:flex;align-items:center;justify-content:center;padding:1rem}.modal-content{background:var(--color-surface, white);border-radius:var(--radius-lg, 16px);box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a;max-height:90vh;display:flex;flex-direction:column;width:100%;animation:slideUp .2s ease-out}.modal-content.sm{max-width:400px}.modal-content.md{max-width:600px}.modal-content.lg{max-width:800px}.modal-content.xl{max-width:1200px}.modal-content.full{max-width:95vw}.modal-header{padding:1.5rem;border-bottom:1px solid var(--color-border, #e2e8f0);display:flex;align-items:center;justify-content:space-between}.modal-title{font-size:1.25rem;font-weight:600;color:var(--color-ink, #0f172a);margin:0}.modal-close{background:none;border:none;cursor:pointer;padding:.5rem;display:flex;align-items:center;justify-content:center;border-radius:var(--radius-md, 8px);color:var(--color-text-muted, #64748b);transition:all .2s}.modal-close:hover{background:var(--color-muted, #f1f5f9);color:var(--color-ink, #0f172a)}.modal-body{padding:1.5rem;overflow-y:auto;flex:1}.modal-footer{padding:1.5rem;border-top:1px solid var(--color-border, #e2e8f0);display:flex;gap:.75rem;justify-content:flex-end}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}:host([data-ui="select"]){display:block;width:90%}.select-container{position:relative;width:100%}.select-label{display:block;margin-bottom:.5rem;font-size:.875rem;font-weight:500;color:var(--color-ink, #0f172a)}.select-trigger{width:100%;padding:.625rem 1rem;background:#fff;border:1px solid var(--color-border, #e2e8f0);border-radius:var(--radius-md, 8px);display:flex;align-items:center;justify-content:space-between;cursor:pointer;transition:all .2s;font-size:.95rem;color:var(--color-ink, #0f172a)}.select-trigger:hover:not(:disabled){border-color:var(--color-primary, #24ec71)}.select-trigger:focus{outline:none;border-color:var(--color-primary, #24ec71);box-shadow:0 0 0 3px #24ec711a}.select-trigger:disabled{background:var(--color-muted, #f1f5f9);cursor:not-allowed;opacity:.6}.select-trigger.open{border-color:var(--color-primary, #24ec71)}.select-placeholder{color:var(--color-text-muted, #94a3b8);flex:1;text-align:left}.select-placeholder.has-selection{color:var(--color-ink, #0f172a)}.select-arrow{display:flex;transition:transform .2s;color:var(--color-text-muted, #64748b)}.select-arrow.open{transform:rotate(180deg)}.select-dropdown{position:absolute;top:calc(100% + .25rem);left:0;right:0;background:#fff;border:1px solid var(--color-border, #e2e8f0);border-radius:var(--radius-md, 8px);box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -2px #0000000d;max-height:300px;overflow-y:auto;z-index:1000;display:none;animation:slideDown .15s ease-out}.select-dropdown.open{display:block}.select-search{width:100%;padding:.625rem 1rem;border:none;border-bottom:1px solid var(--color-border, #e2e8f0);font-size:.95rem;outline:none}.select-search:focus{background:var(--color-muted, #f1f5f9)}.select-option{padding:.625rem 1rem;cursor:pointer;transition:background .15s;color:var(--color-ink, #0f172a);font-size:.95rem}.select-option:hover:not(.disabled){background:var(--color-muted, #f1f5f9)}.select-option.selected{background:#24ec711a;color:var(--color-primary, #24ec71);font-weight:500}.select-option.disabled{opacity:.5;cursor:not-allowed}.select-empty{padding:1rem;text-align:center;color:var(--color-text-muted, #94a3b8);font-size:.875rem}@keyframes slideDown{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}:host([data-ui="pagination"]){display:block}.pagination-container{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap}.pagination-info{font-size:.9rem;color:var(--color-ink);opacity:.7}.pagination{display:flex;align-items:center;gap:.25rem}.page-btn{min-width:2.5rem;height:2.5rem;padding:.5rem;border:1px solid var(--color-border);background:#fff;color:var(--color-ink);font-size:.9rem;font-weight:500;border-radius:6px;cursor:pointer;transition:all .2s ease;display:flex;align-items:center;justify-content:center}.page-btn:hover:not(:disabled):not(.active){background:var(--color-muted);border-color:var(--color-border-strong)}.page-btn:disabled{opacity:.4;cursor:not-allowed}.page-btn.active{background:var(--color-primary);color:var(--color-primary-contrast);border-color:var(--color-primary);font-weight:600}.page-btn.ellipsis{border:none;background:transparent;cursor:default;pointer-events:none}.nav-btn{padding:.5rem .75rem}.nav-btn svg{width:16px;height:16px}:host([data-ui="date-picker"]){display:inline-block;width:100%;max-width:300px}.date-picker-container{position:relative;display:flex;flex-direction:column;gap:.5rem}.date-input-wrapper{position:relative;display:flex;align-items:center;border:1px solid var(--color-border);border-radius:var(--radius-md);background:#fff;transition:all .2s ease}.date-input-wrapper:hover:not(.disabled){border-color:var(--color-border-strong)}.date-input-wrapper:focus-within{border-color:var(--color-primary);box-shadow:0 0 0 3px #24ec711a;outline:none}.date-input-wrapper.disabled{background:var(--color-muted);cursor:not-allowed;opacity:.6}.formatted-input{flex:1;border:none;padding:.75rem 1rem;font-size:.95rem;font-family:inherit;background:transparent;color:var(--color-ink);outline:none}.formatted-input:disabled{cursor:not-allowed;color:var(--color-ink);opacity:.7}.formatted-input::placeholder{color:#94a3b8;opacity:.7}.formatted-input.invalid{color:#dc2626}.hidden-date-input{position:absolute;opacity:0;pointer-events:none;width:0;height:0}.calendar-btn{padding:.5rem;margin-right:.5rem;border:none;background:transparent;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--color-ink);opacity:.6;transition:all .2s ease;border-radius:6px}.calendar-btn:hover:not(:disabled){background:var(--color-muted);opacity:1}.calendar-btn:disabled{cursor:not-allowed;opacity:.3}.calendar-icon{width:20px;height:20px}.format-label{font-size:.75rem;color:var(--color-ink);opacity:.6;padding:0 .25rem;font-weight:500}';class y extends p{connectedCallback(){this.setAttribute("data-ui","sidebar"),super.connectedCallback()}render(){this.shadowRoot.innerHTML=`
2
+ <style>${b}</style>
3
+ <aside class="dashboard-sidebar">
4
+ <h2 class="sidebar-title">Workspace</h2>
5
+ <nav class="sidebar-nav">
6
+ <a class="sidebar-link" href="/" data-link>Button Demo</a>
7
+ <a class="sidebar-link" href="/input-demo" data-link>Input Demo</a>
8
+ <a class="sidebar-link" href="/date-picker" data-link>Date Picker Demo</a>
9
+ <a class="sidebar-link" href="/table-demo" data-link>Table Demo</a>
10
+ <a class="sidebar-link" href="/modal" data-link>Modal Demo</a>
11
+ <a class="sidebar-link" href="/select" data-link>Select Demo</a>
12
+ <a class="sidebar-link" href="/checkbox" data-link>Checkbox Demo</a>
13
+ </nav>
14
+ </aside>
15
+ `}}customElements.define("app-sidebar",y);class k extends p{connectedCallback(){this.setAttribute("data-ui","button"),super.connectedCallback()}static get observedAttributes(){return["variant","size","disabled","type","icon","icon-position"]}attributeChangedCallback(){this.render()}getVariant(){const e=this.getAttribute("variant");return e==="secondary"||e==="ghost"?e:"primary"}getSize(){const e=this.getAttribute("size");return e==="sm"||e==="lg"?e:"md"}getType(){return this.getAttribute("type")??"button"}getIcon(){var a;const e=this.getAttribute("icon");if(!e)return null;const o=e.trim();return{html:`<span class="btn-icon">${((a=x.icons[o])==null?void 0:a.toSvg())||""}</span>`,name:o}}getIconPosition(){return this.getAttribute("icon-position")==="right"?"right":"left"}render(){const e=this.getVariant(),o=this.getSize(),t=this.hasAttribute("disabled"),a=this.getType(),s=this.getIcon(),u=this.getIconPosition(),n=s!==null,d=s?s.html:"",i=this.innerHTML.trim(),h=n&&!i;let l;n&&i?l=u==="left"?`${d}<span>${i}</span>`:`<span>${i}</span>${d}`:n?l=d:l=i,this.shadowRoot.innerHTML=`
16
+ <style>${b}</style>
17
+ <button
18
+ part="button"
19
+ class="btn ${e} ${o}${n?" has-icon":""}${h?" icon-only":""}"
20
+ type="${a}"
21
+ ${t?"disabled":""}
22
+ >
23
+ ${l}
24
+ </button>
25
+ `}}customElements.define("ui-button",k);class w extends p{connectedCallback(){this.setAttribute("data-ui","layout"),super.connectedCallback()}render(){this.shadowRoot.innerHTML=`
26
+ <style>${b}</style>
27
+ <nav class="app-nav">
28
+ Dashboard
29
+ <ui-button id="theme-toggle" variant="ghost" size="sm">Toggle Theme</ui-button>
30
+ </nav>
31
+ <div class="dashboard-layout">
32
+ <app-sidebar></app-sidebar>
33
+ <main class="dashboard-main">
34
+ <slot></slot>
35
+ </main>
36
+ </div>
37
+ `;const e=this.shadowRoot.querySelector("#theme-toggle");e&&e.addEventListener("click",()=>{const o=m.getState().theme==="shadcn"?"light":"shadcn";m.setState({theme:o}),this.render()})}}customElements.define("app-layout",w);export{p as B,b as s};