@vialiq/web-components 0.4.0 → 0.5.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
@@ -15,16 +15,589 @@ Buildable and publishable Lit web component library for the Vi design system.
15
15
  npm install @vialiq/web-components lit
16
16
  ```
17
17
 
18
- ## Usage
18
+ ## Integration Guide
19
+
20
+ Since these components are built using standard Custom Elements APIs, they are compatible with any web framework or vanilla web stack.
21
+
22
+ ### Subpath Exports & Tree-Shaking
23
+ To keep your bundle sizes minimal, import only the components you need:
24
+
25
+ ```ts
26
+ // Good: Imports only the button component
27
+ import '@vialiq/web-components/button';
28
+
29
+ // Good: Imports only the input component
30
+ import '@vialiq/web-components/input';
31
+ ```
32
+
33
+ If you prefer to import all components, or if you need helper classes and TypeScript types, you can import from the main package entrypoint:
19
34
 
20
35
  ```ts
36
+ import { registerIcons, ViButton } from '@vialiq/web-components';
37
+ ```
38
+
39
+ ### Framework Guides
40
+
41
+ #### 1. React
42
+ React 19 supports Custom Elements natively. If you are using React <19, you must set properties and custom events manually via `ref` or use custom wrapper packages.
43
+
44
+ **React 19 Example:**
45
+ ```tsx
46
+ import React from 'react';
21
47
  import '@vialiq/web-components/button';
48
+ import '@vialiq/web-components/input';
49
+
50
+ export function SearchForm() {
51
+ return (
52
+ <form onSubmit={(e) => { e.preventDefault(); console.log('Submitted'); }}>
53
+ <vi-input
54
+ name="query"
55
+ placeholder="Search..."
56
+ required
57
+ onvialiq-input={(e: any) => console.log(e.detail.value)}
58
+ />
59
+ <vi-button type="submit" variant="primary">Search</vi-button>
60
+ </form>
61
+ );
62
+ }
63
+ ```
64
+
65
+ #### 2. Vue
66
+ Vue supports custom elements seamlessly out-of-the-box. Register the tags so Vue's compiler knows not to treat them as Vue components:
67
+
68
+ **vite.config.ts:**
69
+ ```ts
70
+ export default defineConfig({
71
+ plugins: [
72
+ vue({
73
+ template: {
74
+ compilerOptions: {
75
+ isCustomElement: (tag) => tag.startsWith('vi-')
76
+ }
77
+ }
78
+ })
79
+ ]
80
+ });
81
+ ```
82
+
83
+ **Vue Component Template:**
84
+ ```html
85
+ <template>
86
+ <div>
87
+ <vi-input :value="username" @vialiq-input="onInput" />
88
+ <vi-button variant="success">Register</vi-button>
89
+ </div>
90
+ </template>
91
+ ```
92
+
93
+ #### 3. Angular
94
+ To use Custom Elements in Angular, you must add the `CUSTOM_ELEMENTS_SCHEMA` to the `schemas` array of the `@Component` (for standalone components) or `@NgModule` where they are consumed.
95
+
96
+ **Standalone Component Setup:**
97
+ ```typescript
98
+ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
99
+
100
+ @Component({
101
+ selector: 'app-search-form',
102
+ standalone: true,
103
+ templateUrl: './search-form.component.html',
104
+ schemas: [CUSTOM_ELEMENTS_SCHEMA]
105
+ })
106
+ export class SearchFormComponent {
107
+ searchQuery = '';
108
+
109
+ onInput(event: Event) {
110
+ const customEvent = event as CustomEvent<{ value: string }>;
111
+ this.searchQuery = customEvent.detail.value;
112
+ }
113
+ }
114
+ ```
115
+
116
+ **search-form.component.html Template:**
117
+ ```html
118
+ <div>
119
+ <vi-input
120
+ [value]="searchQuery"
121
+ (vialiq-input)="onInput($event)"
122
+ placeholder="Search catalog..."
123
+ ></vi-input>
124
+
125
+ <vi-button variant="primary">Search</vi-button>
126
+ </div>
127
+ ```
128
+
129
+ #### 4. Next.js (SSR / React Server Components)
130
+ Custom Elements must register on the browser's `window` object. Next.js and server-side rendering environments require lazy-loading or dynamic imports to ensure registration occurs client-side.
131
+
132
+ ```tsx
133
+ 'use client';
134
+
135
+ import { useEffect } from 'react';
136
+
137
+ export default function MyClientComponent() {
138
+ useEffect(() => {
139
+ // Import dynamically on the client
140
+ import('@vialiq/web-components/button');
141
+ }, []);
142
+
143
+ return <vi-button>Save</vi-button>;
144
+ }
145
+ ```
146
+
147
+
148
+ ---
149
+
150
+ ## Component API & Detailed Examples
151
+
152
+ ### Button ([vi-button](./src/button/vi-button.ts))
153
+ The [ViButton](./src/button/vi-button.ts) is a versatile button component that wraps a native `<button>` element with keyboard interaction, focus indicators, visual variations, and slot options.
154
+
155
+ #### Properties & Attributes
156
+ | Attribute | Property | Type | Default | Description |
157
+ | :--- | :--- | :--- | :--- | :--- |
158
+ | `variant` | `variant` | `'primary'\|'secondary'\|'danger'\|'success'\|'info'\|'ghost'` | `'primary'` | Visual design style. |
159
+ | `size` | `size` | `'xs'\|'sm'\|'md'\|'lg'` | `'md'` | Sizing scale. |
160
+ | `icon-placement` | `iconPlacement` | `'start'\|'end'` | `'start'` | Location of the icon relative to the label. |
161
+ | `full-width` | `fullWidth` | `boolean` | `false` | Sets width to 100% of container. |
162
+ | `icon-only` | `iconOnly` | `boolean` | `false` | Squares padding and matches dimensions for an icon-only layout. |
163
+ | `disabled` | `disabled` | `boolean` | `false` | Disables button interactions and sets `tabindex="-1"`. |
164
+
165
+ #### Slots
166
+ - **Default Slot**: Button label (text/content).
167
+ - **`icon` Slot**: Container for standard icons.
168
+
169
+ #### CSS Parts
170
+ - `button`: The native internal `<button>` element.
171
+ - `icon`: The icon wrapper element.
172
+ - `label`: The text label span wrapper.
173
+
174
+ #### Snippets
175
+
176
+ **Standard Button Variants:**
177
+ ```html
178
+ <vi-button variant="primary">Primary Action</vi-button>
179
+ <vi-button variant="secondary">Secondary Action</vi-button>
180
+ <vi-button variant="danger">Delete Item</vi-button>
181
+ <vi-button variant="ghost">Cancel</vi-button>
182
+ ```
183
+
184
+ **Sizes & Layouts:**
185
+ ```html
186
+ <vi-button size="xs">Extra Small</vi-button>
187
+ <vi-button size="sm">Small</vi-button>
188
+ <vi-button size="md">Medium (Default)</vi-button>
189
+ <vi-button size="lg">Large</vi-button>
190
+
191
+ <!-- Stretches width to 100% -->
192
+ <vi-button full-width variant="primary">Submit Order</vi-button>
22
193
  ```
23
194
 
195
+ **Icons Support:**
24
196
  ```html
25
- <vi-button variant="primary">Save</vi-button>
197
+ <!-- Icon at start (default) -->
198
+ <vi-button>
199
+ <vi-icon slot="icon" name="plus"></vi-icon>
200
+ Add User
201
+ </vi-button>
202
+
203
+ <!-- Icon at end -->
204
+ <vi-button icon-placement="end">
205
+ <vi-icon slot="icon" name="arrow-right"></vi-icon>
206
+ Next Step
207
+ </vi-button>
208
+
209
+ <!-- Icon-only configuration -->
210
+ <vi-button icon-only aria-label="Settings">
211
+ <vi-icon slot="icon" name="settings"></vi-icon>
212
+ </vi-button>
213
+ ```
214
+
215
+ ---
216
+
217
+ ### Input ([vi-input](./src/input/vi-input.ts))
218
+ The [ViInput](./src/input/vi-input.ts) component is a form-associated custom text input control. It wraps a native single-line input field and automatically supports accessibility features, validation states, helper text slots, and custom style configuration.
219
+
220
+ #### Properties & Attributes
221
+ | Attribute | Property | Type | Default | Description |
222
+ | :--- | :--- | :--- | :--- | :--- |
223
+ | `type` | `type` | `'text'\|'email'\|'password'\|'search'\|'tel'\|'url'\|'number'` | `'text'` | Renders appropriate input format. |
224
+ | `placeholder` | `placeholder` | `string` | `''` | Input placeholder text. |
225
+ | `name` | `name` | `string` | `''` | Form participation field name. |
226
+ | `value` | `value` | `string` | `''` | Controlled input value. |
227
+ | `disabled` | `disabled` | `boolean` | `false` | Disables field interactions. |
228
+ | `readonly` | `readonly` | `boolean` | `false` | Disables keyboard editing. |
229
+ | `required` | `required` | `boolean` | `false` | Marks field validation as mandatory. |
230
+ | `status` | `status` | `'default'\|'valid'\|'invalid'` | `'default'` | Controls validation visual presentation. |
231
+ | `validity-message` | `validityMessage` | `string` | `''` | Native or custom error message to display in UI. |
232
+ | `size` | `size` | `'xs'\|'sm'\|'md'\|'lg'` | `'md'` | Controls font sizes and paddings. |
233
+ | `aria-label` | `ariaLabel` | `string` | `''` | Accessibility label. |
234
+ | `aria-labelledby` | `ariaLabelledby` | `string` | `''` | ID reference of accessible label. |
235
+
236
+ #### Slots
237
+ - **`helper` Slot**: Location to insert description text below the input field.
238
+
239
+ #### Events
240
+ - `vialiq-input`: Fires on every keypress. Detail: `{ value: string }`.
241
+ - `vialiq-change`: Fires when element loses focus (blur). Detail: `{ value: string }`.
242
+ - `invalid`: Native HTML5 validation failed event.
243
+
244
+ #### CSS Custom Properties
245
+ Exposes variables for custom theme styling:
246
+ ```css
247
+ vi-input {
248
+ --vi-input-border-color: #d1d5db;
249
+ --vi-input-focus-ring-color: #3b82f6;
250
+ --vi-input-background-color: #ffffff;
251
+ --vi-input-text-color: #1f2937;
252
+ --vi-input-placeholder-color: #9ca3af;
253
+ --vi-input-helper-color: #6b7280;
254
+ --vi-input-error-color: #ef4444;
255
+ --vi-input-success-color: #10b981;
256
+ --vi-input-shape-border-radius: 6px;
257
+ }
26
258
  ```
27
259
 
260
+ #### Snippets
261
+
262
+ **Basic Text & Password Inputs:**
263
+ ```html
264
+ <vi-input name="username" placeholder="Enter username"></vi-input>
265
+
266
+ <!-- Password input -->
267
+ <vi-input type="password" name="password" placeholder="••••••••"></vi-input>
268
+ ```
269
+
270
+ **Required with Helper Text & Validation:**
271
+ ```html
272
+ <vi-input
273
+ type="email"
274
+ name="email"
275
+ placeholder="you@vialiq.com"
276
+ required
277
+ >
278
+ <span slot="helper">We will never share your email address.</span>
279
+ </vi-input>
280
+ ```
281
+
282
+ ---
283
+
284
+ ### Checkbox ([vi-checkbox](./src/checkbox/vi-checkbox.ts))
285
+ The [ViCheckbox](./src/checkbox/vi-checkbox.ts) is a customizable form-associated checkbox control using SVG graphics for checkmarks and supporting the indeterminate (mixed) validation state.
286
+
287
+ #### Properties & Attributes
288
+ | Attribute | Property | Type | Default | Description |
289
+ | :--- | :--- | :--- | :--- | :--- |
290
+ | `checked` | `checked` | `boolean` | `false` | Checked state. |
291
+ | `indeterminate` | `indeterminate` | `boolean` | `false` | Indeterminate (mixed) dash state. |
292
+ | `value` | `value` | `string` | `'on'` | Submitted form value. |
293
+ | `name` | `name` | `string` | `''` | Form field identifier. |
294
+ | `disabled` | `disabled` | `boolean` | `false` | Disables checkbox toggles. |
295
+ | `required` | `required` | `boolean` | `false` | Makes checking field mandatory. |
296
+ | `status` | `status` | `'default'\|'valid'\|'invalid'` | `'default'` | Controls validation visual border colors. |
297
+ | `size` | `size` | `'xs'\|'sm'\|'md'\|'lg'` | `'md'` | Controls dimension metrics. |
298
+
299
+ #### Events
300
+ - `vialiq-change`: Fired on user toggle. Detail: `{ checked: boolean, value: string }`.
301
+
302
+ #### Snippets
303
+
304
+ **Simple Configurations:**
305
+ ```html
306
+ <vi-checkbox name="agree" required>I accept the terms and conditions</vi-checkbox>
307
+
308
+ <vi-checkbox name="newsletter" checked>Subscribe to newsletter</vi-checkbox>
309
+ ```
310
+
311
+ **Indeterminate State (Parent/Child controls):**
312
+ ```html
313
+ <vi-checkbox id="select-all" indeterminate>Select All Modules</vi-checkbox>
314
+ ```
315
+
316
+ ---
317
+
318
+ ### Radio Group & Radio ([vi-radio-group](./src/radio/vi-radio-group.ts) & [vi-radio](./src/radio/vi-radio.ts))
319
+ The [ViRadioGroup](./src/radio/vi-radio-group.ts) and [ViRadio](./src/radio/vi-radio.ts) work in tandem. The group container handles form-association, propagation of attributes (`name`, `disabled`, `size`), roving tabindexes, and WAI-ARIA compliant keyboard navigation via arrow keys.
320
+
321
+ #### `<vi-radio-group>` Properties & Attributes
322
+ | Attribute | Property | Type | Default | Description |
323
+ | :--- | :--- | :--- | :--- | :--- |
324
+ | `value` | `value` | `string` | `''` | Selection value. |
325
+ | `name` | `name` | `string` | `''` | Shared name propagated to children. |
326
+ | `disabled` | `disabled` | `boolean` | `false` | Disables entire selection array. |
327
+ | `required` | `required` | `boolean` | `false` | Marks group validation as mandatory. |
328
+ | `status` | `status` | `'default'\|'valid'\|'invalid'` | `'default'` | Group visual status. |
329
+ | `validity-message` | `validity-message` | `string` | `''` | Helper error label when validation triggers. |
330
+ | `orientation` | `orientation` | `'vertical'\|'horizontal'` | `'vertical'` | Direction grid layout. |
331
+ | `size` | `size` | `'xs'\|'sm'\|'md'\|'lg'` | `'md'` | Shared size propagated to children. |
332
+ | `allow-dblclick-clear` | `allowDblclickClear` | `boolean` | `false` | Double clicking a selected radio deselects it. |
333
+
334
+ #### `<vi-radio>` Properties & Attributes
335
+ | Attribute | Property | Type | Default | Description |
336
+ | :--- | :--- | :--- | :--- | :--- |
337
+ | `value` | `value` | `string` | `''` | Value this radio represents. |
338
+ | `checked` | `checked` | `boolean` | `false` | Checked selection status. |
339
+ | `disabled` | `disabled` | `boolean` | `false` | Local disable flag override. |
340
+
341
+ #### Slots (`<vi-radio-group>`)
342
+ - **Default Slot**: Holds the list of `<vi-radio>` child tags.
343
+ - **`label` Slot**: Legend label displayed above the list.
344
+ - **`helper` Slot**: Support text shown below the components.
345
+
346
+ #### Snippets
347
+
348
+ **Vertical Layout (Default):**
349
+ ```html
350
+ <vi-radio-group name="shipping" value="standard">
351
+ <span slot="label">Choose Shipping Method</span>
352
+ <vi-radio value="standard">Standard Shipping (3-5 days)</vi-radio>
353
+ <vi-radio value="express">Express Shipping (1-2 days)</vi-radio>
354
+ <vi-radio value="overnight" disabled>Overnight Shipping (Unavailable)</vi-radio>
355
+ <span slot="helper">Shipping options vary by location.</span>
356
+ </vi-radio-group>
357
+ ```
358
+
359
+ **Horizontal Layout with Double-Click Clear:**
360
+ ```html
361
+ <vi-radio-group
362
+ name="rating"
363
+ orientation="horizontal"
364
+ size="lg"
365
+ allow-dblclick-clear
366
+ >
367
+ <span slot="label">Score rating (Double-click to clear)</span>
368
+ <vi-radio value="1">1 Star</vi-radio>
369
+ <vi-radio value="2">2 Stars</vi-radio>
370
+ <vi-radio value="3">3 Stars</vi-radio>
371
+ <vi-radio value="4">4 Stars</vi-radio>
372
+ <vi-radio value="5">5 Stars</vi-radio>
373
+ </vi-radio-group>
374
+ ```
375
+
376
+ ---
377
+
378
+ ### Tooltip ([vi-tooltip](./src/tooltip/vi-tooltip.ts))
379
+ The [ViTooltip](./src/tooltip/vi-tooltip.ts) manages floating help text. It leverages `@floating-ui/dom` under the hood for collision-detection, auto-flipping, dynamic viewport alignments, and manual trigger controls.
380
+
381
+ #### Properties & Attributes
382
+ | Attribute | Property | Type | Default | Description |
383
+ | :--- | :--- | :--- | :--- | :--- |
384
+ | `content` | `content` | `string` | `''` | Plain text tooltip label. Overridden if the `content` slot is populated. |
385
+ | `placement` | `placement` | `TooltipPlacement` | `'top'` | Direction: `top`\|`top-start`\|`top-end`\|`bottom`\|`bottom-start`\|`bottom-end`\|`left`\|`right`. |
386
+ | `trigger` | `trigger` | `TooltipTrigger` | `'hover focus'` | Trigger events: `hover focus`\|`hover`\|`focus`\|`click`. |
387
+ | `delay` | `delay` | `number` | `500` | Wait delay before displaying in ms. |
388
+ | `hide-delay` | `hide-delay` | `number` | `100` | Hide delay after trigger lost in ms. |
389
+ | `max-width` | `max-width` | `number` | `240` | Max width bounds size in pixels. |
390
+ | `disabled` | `disabled` | `boolean` | `false` | Prevents rendering/open operations. |
391
+ | `popper-options` | `popperOptions` | `object` | `{}` | Custom options passed directly to Floating UI's `computePosition`. |
392
+
393
+ #### Slots
394
+ - **Default Slot**: The target anchor element (e.g. `<vi-button>`).
395
+ - **`content` Slot**: Holds rich interactive HTML content. (When used, automatically updates ARIA parameters from `aria-describedby` to `aria-details` for screen readers).
396
+
397
+ #### Methods
398
+ - `show()`: Force displays the tooltip pane.
399
+ - `hide(immediate = false)`: Force hides the tooltip pane.
400
+
401
+ #### Snippets
402
+
403
+ **Basic Text Tooltip:**
404
+ ```html
405
+ <vi-tooltip content="Press to permanently remove configuration" placement="right">
406
+ <vi-button variant="danger">Delete Account</vi-button>
407
+ </vi-tooltip>
408
+ ```
409
+
410
+ **Rich Interactive Content (Aria-Details compliant):**
411
+ ```html
412
+ <vi-tooltip placement="bottom-start" trigger="click">
413
+ <vi-button>View Pricing Plan</vi-button>
414
+ <div slot="content" style="padding: 8px;">
415
+ <strong>Enterprise Subscription</strong>
416
+ <p style="margin: 4px 0 8px;">Includes 24/7 dedicated support team access.</p>
417
+ <a href="/pricing" style="color: #60a5fa; text-decoration: underline;">Read More</a>
418
+ </div>
419
+ </vi-tooltip>
420
+ ```
421
+
422
+ **Auto-Placement (Collision Detection & Opposite Side Flipping):**
423
+ By default, the tooltip uses the Floating UI `flip()` and `shift()` middlewares. If the preferred placement (e.g. `top`) does not have sufficient space within the viewport, it automatically flips to the opposite side (`bottom`) and shifts along the axis to remain completely visible.
424
+
425
+ ```html
426
+ <!-- Automatically flips to bottom if top space is restricted at runtime -->
427
+ <vi-tooltip content="Flipped placement when near top boundary" placement="top">
428
+ <vi-button>Hover Me near Window Edge</vi-button>
429
+ </vi-tooltip>
430
+ ```
431
+
432
+ **Custom Advanced Auto-Placement Middleware:**
433
+ If you want the tooltip to dynamically choose the absolute best side (e.g., auto-detecting the side with the most space, rather than just flipping to the opposite side), you can provide custom middleware via the `popper-options` property.
434
+
435
+ ```html
436
+ <!-- Passing custom autoPlacement middleware via popper-options property -->
437
+ <vi-tooltip
438
+ id="auto-placement-tooltip"
439
+ content="Dynamic placement based on available viewport space"
440
+ >
441
+ <vi-button>Auto placement</vi-button>
442
+ </vi-tooltip>
443
+
444
+ <script>
445
+ import { autoPlacement, offset, shift } from '@floating-ui/dom';
446
+
447
+ const tooltip = document.getElementById('auto-placement-tooltip');
448
+ // Configure custom options directly to override default middleware list
449
+ tooltip.popperOptions = {
450
+ middleware: [
451
+ offset(12),
452
+ autoPlacement({ padding: 8 }),
453
+ shift({ padding: 8 })
454
+ ]
455
+ };
456
+ </script>
457
+ ```
458
+
459
+ ---
460
+
461
+ ### Icon ([vi-icon](./src/icons/vi-icon.ts))
462
+ The [ViIcon](./src/icons/vi-icon.ts) component renders named inline SVG elements. It depends on a dynamic map store, registering only the icons utilized in your project to allow bundlers to prune unused assets (tree-shaking).
463
+
464
+ #### Properties & Attributes
465
+ | Attribute | Property | Type | Default | Description |
466
+ | :--- | :--- | :--- | :--- | :--- |
467
+ | `name` | `name` | `string` | `''` | Name identifier inside the registry. |
468
+ | `size` | `size` | `number` | `24` | Width/height footprint dimension in pixels. |
469
+ | `label` | `label` | `string` | `''` | Accessibility label. When set, renders as an interactive image with `role="img"`. When empty, marks element as `aria-hidden="true"`. |
470
+
471
+ #### Icon Registration API
472
+ Before rendering `<vi-icon>`, you must register the required icon definitions using the [registerIcons](./src/icons/registry.ts) function:
473
+
474
+ ```ts
475
+ import { registerIcons } from '@vialiq/web-components';
476
+ import { checkIcon } from '@vialiq/icons/check';
477
+ import { settingsIcon } from '@vialiq/icons/settings';
478
+
479
+ // Register single or batch lists
480
+ registerIcons([checkIcon, settingsIcon]);
481
+ ```
482
+
483
+ *Note: For security, `registerIcons` includes internal sanity checks that filter out inline `<script>` tags or event handlers (e.g. `onload=`) to prevent XSS exploits.*
484
+
485
+ #### Snippets
486
+
487
+ **Usage Example:**
488
+ ```html
489
+ <!-- Decorative usage (aria-hidden is true) -->
490
+ <vi-icon name="check" size="20"></vi-icon>
491
+
492
+ <!-- Accessible interactive usage -->
493
+ <vi-icon name="settings" size="32" label="Open workspace settings"></vi-icon>
494
+ ```
495
+
496
+ ---
497
+
498
+ ## Form Validation & ElementInternals
499
+
500
+ Custom controls inside this library utilize the native browser [ValidityMixin](./src/base/validity-mixin.ts) to integrate with standard `<form>` features like `.elements`, `.checkValidity()`, and `.reportValidity()`.
501
+
502
+ ### Handling Submit Validation
503
+ ```html
504
+ <form id="profile-form">
505
+ <vi-input
506
+ type="text"
507
+ name="fullname"
508
+ placeholder="John Doe"
509
+ required
510
+ >
511
+ <span slot="helper">Enter your full name.</span>
512
+ </vi-input>
513
+
514
+ <vi-checkbox name="newsletter" required>
515
+ Confirm subscription policy
516
+ </vi-checkbox>
517
+
518
+ <vi-button type="submit" variant="primary">Submit</vi-button>
519
+ </form>
520
+
521
+ <script>
522
+ const form = document.getElementById('profile-form');
523
+ form.addEventListener('submit', (e) => {
524
+ e.preventDefault();
525
+
526
+ // Checks validity for all elements in the form
527
+ if (form.checkValidity()) {
528
+ const formData = new FormData(form);
529
+ console.log('Valid data submitted: ', Object.fromEntries(formData));
530
+ } else {
531
+ console.warn('Form validation failed.');
532
+ }
533
+ });
534
+ </script>
535
+ ```
536
+
537
+ ### Custom Error Reporting
538
+ Use `setCustomValidity` to configure custom error messages or run manual server-side validation responses:
539
+
540
+ ```javascript
541
+ const emailField = document.querySelector('vi-input[name="email"]');
542
+
543
+ emailField.addEventListener('vialiq-change', (e) => {
544
+ const email = e.detail.value;
545
+
546
+ if (email.endsWith('@forbidden-domain.com')) {
547
+ emailField.setCustomValidity('Registrations from this domain are forbidden.');
548
+ emailField.reportValidity(); // Displays the custom validation message tooltip
549
+ } else {
550
+ emailField.setCustomValidity(''); // Clear errors
551
+ }
552
+ });
553
+ ```
554
+
555
+ ---
556
+
557
+ ## CSS Styling & Shadow Parts
558
+
559
+ Web Components utilize CSS Shadow Roots to encapsulate logic and layout styles. To override designs safely without bleeding global configurations, use **CSS Shadow Parts** or **CSS Variables**.
560
+
561
+ ### CSS Shadow Parts (`::part`)
562
+ Elements expose internal sub-nodes through the `part="..."` syntax. Customize these nodes using the CSS `::part()` selector:
563
+
564
+ ```css
565
+ /* Change focus border styles on the vi-input inner input tag */
566
+ vi-input::part(input) {
567
+ border-radius: 8px;
568
+ background: #f9fafb;
569
+ }
570
+
571
+ /* Customise helper text color */
572
+ vi-input::part(helper) {
573
+ color: #4b5563;
574
+ }
575
+
576
+ /* Style the checkbox custom drawn frame box */
577
+ vi-checkbox::part(box) {
578
+ border: 2px solid #6b7280;
579
+ }
580
+ ```
581
+
582
+ ### CSS Variables Custom Properties
583
+ For variables used repeatedly, custom elements offer direct CSS property bindings. Customize them globally or on single layouts:
584
+
585
+ ```css
586
+ /* Custom variables declared on theme layers */
587
+ :root {
588
+ --vi-input-border-color: #6366f1;
589
+ --vi-input-focus-ring-color: #818cf8;
590
+ }
591
+
592
+ /* Specific class styling override */
593
+ .danger-zone {
594
+ --vi-input-border-color: #ef4444;
595
+ --vi-input-focus-ring-color: #fca5a5;
596
+ }
597
+ ```
598
+
599
+ ---
600
+
28
601
  ## Token strategy
29
602
 
30
603
  Component styles use BEM + state CSS variable naming and Flux UI fallbacks.
@@ -0,0 +1,3 @@
1
+ export { ViCheckbox } from './vi-checkbox.js';
2
+ export type { CheckboxSize } from './vi-checkbox.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../libs/web-components/src/checkbox/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1 @@
1
+ export { ViCheckbox } from './vi-checkbox.js';
@@ -0,0 +1,68 @@
1
+ import { type PropertyValues, type TemplateResult } from 'lit';
2
+ import { type ControlStatus } from '../base/validity-mixin.js';
3
+ import { ViElement } from '../base/vi-element.js';
4
+ export type CheckboxSize = 'xs' | 'sm' | 'md' | 'lg';
5
+ declare const ViCheckbox_base: typeof ViElement & (new (...args: any[]) => import("../base/focusable-mixin.js").FocusableInterface) & (new (...args: any[]) => import("../base/validity-mixin.js").ValidityInterface);
6
+ /**
7
+ * vi-checkbox
8
+ * Form-associated checkbox control using Flux UI tokens.
9
+ *
10
+ * NOTE: vi-checkbox is form-associated and participates in form submission and constraint validation.
11
+ * Each checkbox is independently focusable (no roving tabindex / mutual-exclusivity behavior).
12
+ *
13
+ * @element vi-checkbox
14
+ *
15
+ * @attr {boolean} checked - Checked state of the checkbox
16
+ * @attr {boolean} indeterminate - Indeterminate (partial) state of the checkbox
17
+ * @attr {string} value - Form submission value when checked (default: 'on')
18
+ * @attr {string} name - Form field name
19
+ * @attr {boolean} disabled - Disables the checkbox
20
+ * @attr {boolean} required - Marks the field as required
21
+ * @attr {ControlStatus} status - Validation state: 'default' | 'valid' | 'invalid'
22
+ *
23
+ * @slot - Label text/content.
24
+ *
25
+ * @fires {CustomEvent<{checked:boolean; value:string}>} vialiq-change - Fires when user toggles checked state.
26
+ *
27
+ * @csspart box - The visual checkbox square (custom-drawn box).
28
+ * @csspart check - The SVG checkmark/indeterminate dash container.
29
+ * @csspart label - The label text wrapper.
30
+ */
31
+ export declare class ViCheckbox extends ViCheckbox_base {
32
+ static formAssociated: boolean;
33
+ static styles: import("lit").CSSResult;
34
+ protected readonly _internals: ElementInternals;
35
+ private _initialChecked;
36
+ protected get _focusableElement(): HTMLInputElement | null;
37
+ accessor status: ControlStatus;
38
+ accessor required: boolean;
39
+ accessor validityMessage: string;
40
+ /** Checked state. */
41
+ accessor checked: boolean;
42
+ /** Indeterminate (partial) state. */
43
+ accessor indeterminate: boolean;
44
+ /** Size scale — controls size, padding, and font-size. */
45
+ accessor size: CheckboxSize;
46
+ /** Form submission value when checked. */
47
+ accessor value: string;
48
+ /** Form field name. */
49
+ accessor name: string;
50
+ /** Disables the checkbox. */
51
+ accessor disabled: boolean;
52
+ protected _testValidity(): Partial<ValidityStateFlags>;
53
+ connectedCallback(): void;
54
+ updated(changed: PropertyValues): void;
55
+ /** Resets value and validation state when the associated form resets. */
56
+ formResetCallback(): void;
57
+ /** Keeps disabled in sync when a containing fieldset or form is disabled. */
58
+ formDisabledCallback(disabled: boolean): void;
59
+ private _onChange;
60
+ render(): TemplateResult;
61
+ }
62
+ declare global {
63
+ interface HTMLElementTagNameMap {
64
+ 'vi-checkbox': ViCheckbox;
65
+ }
66
+ }
67
+ export {};
68
+ //# sourceMappingURL=vi-checkbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vi-checkbox.d.ts","sourceRoot":"","sources":["../../../../libs/web-components/src/checkbox/vi-checkbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAGb,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAIlD,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;;AAErD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBACa,UAAW,SAAQ,eAAwC;IACtE,MAAM,CAAC,cAAc,UAAQ;IAC7B,OAAgB,MAAM,0BAEpB;IAEF,SAAS,CAAC,QAAQ,CAAC,UAAU,mBAA0B;IACvD,OAAO,CAAC,eAAe,CAAS;IAEhC,cAAuB,iBAAiB,IAAI,gBAAgB,GAAG,IAAI,CAElE;IAI4B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAa;IAC5B,QAAQ,CAAC,QAAQ,UAAS;IAC1D,QAAQ,CAAC,eAAe,SAAM;IAI1C,qBAAqB;IACuB,QAAQ,CAAC,OAAO,UAAS;IAErE,qCAAqC;IACO,QAAQ,CAAC,aAAa,UAAS;IAE3E,0DAA0D;IACf,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAQ;IAE9E,0CAA0C;IAC9B,QAAQ,CAAC,KAAK,SAAQ;IAElC,uBAAuB;IACX,QAAQ,CAAC,IAAI,SAAM;IAE/B,6BAA6B;IACe,QAAQ,CAAC,QAAQ,UAAS;IAItE,SAAS,CAAC,aAAa,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAU7C,iBAAiB,IAAI,IAAI;IAKzB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAoB/C,yEAAyE;IACzE,iBAAiB,IAAI,IAAI;IAOzB,6EAA6E;IAC7E,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAM7C,OAAO,CAAC,SAAS;IAmBR,MAAM,IAAI,cAAc;CA0ClC;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,UAAU,CAAC;KAC3B;CACF"}