@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 +393 -94
- package/dist/404.html +14 -0
- package/dist/assets/app-layout-D81L3er1.js +37 -0
- package/dist/assets/checkbox-demo-page-n4kXIN81.js +157 -0
- package/dist/assets/{dashboard-page-DTpb-4y2.js → dashboard-page-D9gcDgAT.js} +1 -1
- package/dist/assets/{date-picker-demo-BjOsNBcV.js → date-picker-demo-AQIyV-D4.js} +7 -120
- package/dist/assets/index-DJpTIOwN.js +2 -0
- package/dist/assets/index-uHZenGtA.css +1 -0
- package/dist/assets/{input-demo-lSk0zPP7.js → input-demo-DX3FkdO8.js} +1 -1
- package/dist/assets/modal-demo-page-A4aRApyB.js +199 -0
- package/dist/assets/select-demo-page-Dg5ajGaj.js +186 -0
- package/dist/assets/{table-CB6WCNz5.js → table-BoHSrBty.js} +1 -1
- package/dist/assets/{table-demo-BB9ggIfA.js → table-demo-D0gN-zGB.js} +12 -88
- package/dist/index.html +2 -2
- package/package.json +2 -1
- package/dist/assets/app-layout-BWpUyzvG.js +0 -34
- package/dist/assets/index-BSRW6NCx.css +0 -1
- package/dist/assets/index-BZ8Wp8z7.js +0 -2
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
|
-
##
|
|
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
|
|
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 ©
|
|
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};
|