@francofantomius/material-components 1.0.0 → 1.0.1

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/CHANGELOG.md CHANGED
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.0.1] - 2026-08-22
9
+
10
+ ### Added
11
+ - **LLM / AI Developer Specification (`llms.txt`)**: Complete API specifications, component hierarchies, properties, events, slots, and ready-to-use patterns for AI coding assistants.
12
+ - **CDN Support & Documentation**: Added CDN quick-start guides and ESM links (`esm.sh`, `jsdelivr`, `unpkg`) in `README.md`.
13
+ - **Framework Integration Guides**: Expanded usage examples and recipes for React (18 & 19), Next.js, Vue 3, Nuxt, Angular, and Svelte.
14
+ - **Modular Test Suites**: Refactored monolithic component tests into dedicated modular test files covering all 21 core component modules.
15
+
16
+ ### Fixed
17
+ - **npm Deployment Configuration**: Configured `allowScripts` in `package.json` to streamline automated npm publishing and package installation.
18
+ - **TypeScript Typecheck**: Resolved strict TypeScript type issues across `app-drawer`, `code`, and `search-bar`.
19
+ - **Vite & Custom Elements Manifest Build**: Fixed build script pipeline and Custom Elements Manifest generation output.
20
+
21
+ ### Changed
22
+ - **Documentation (`README.md`)**: Comprehensive documentation overhaul with structured Table of Contents, full Component Index matrix, FACE form validation examples, and theming guide.
23
+
24
+ ---
25
+
8
26
  ## [1.0.0] - 2026-08-21
9
27
 
10
28
  ### Added
package/README.md CHANGED
@@ -12,25 +12,96 @@
12
12
 
13
13
  A modern, accessible, and lightweight **Material Design 3 (M3)** Web Components library built with [Lit](https://lit.dev/), [Vite](https://vite.dev/), and [TypeScript](https://www.typescriptlang.org/).
14
14
 
15
- Works natively across all modern browsers and seamlessly integrates with **React**, **Vue**, **Angular**, **Svelte**, **Solid**, or plain HTML/JavaScript.
15
+ Runs natively in all modern browsers and integrates seamlessly with **React** (18 & 19), **Vue 3**, **Angular**, **Svelte**, **Solid**, or vanilla HTML/JavaScript without requiring framework-specific wrappers.
16
+
17
+ ---
18
+
19
+ ## Table of Contents
20
+
21
+ - [Features](#features)
22
+ - [Installation](#installation)
23
+ - [CDN Quick Start](#cdn-quick-start)
24
+ - [Quick Start](#quick-start)
25
+ - [1. Load Fonts & Icons](#1-load-fonts-and-icons-recommended)
26
+ - [2. Import Components](#2-import-components)
27
+ - [Component Index](#component-index)
28
+ - [Usage Examples](#usage-examples)
29
+ - [Buttons, FABs & Icons](#buttons-fabs--icons)
30
+ - [Form Controls & Native Validation (FACE)](#form-controls-native-form-association)
31
+ - [Top App Bar & Navigation Drawer](#navigation--top-app-bar)
32
+ - [App Drawer & Account Menu](#app-drawer--account-menu)
33
+ - [Data Table](#data-table)
34
+ - [Search Bar with Live Suggestions](#search-bar-with-live-suggestions)
35
+ - [Code Block & Syntax Linter](#code-block--syntax-linter)
36
+ - [Media Player (Audio & Video)](#media-player-audio--video)
37
+ - [Form-Associated Custom Elements (FACE)](#form-integration-face)
38
+ - [Theming & Color Palettes](#theming-and-dark-mode)
39
+ - [CSS Custom Properties](#dynamic-theming-via-css-custom-properties)
40
+ - [TypeScript Theme Helper API](#typescript-theme-helper)
41
+ - [Subpath Exports Reference](#subpath-exports-reference)
42
+ - [Framework Integration](#framework-integration)
43
+ - [React (18 / 19 / Next.js)](#react)
44
+ - [Vue 3 / Nuxt](#vue)
45
+ - [Angular](#angular)
46
+ - [Svelte](#svelte)
47
+ - [LLM & AI Assistant Documentation](#llm--ai-assistant-documentation)
48
+ - [Development Scripts](#development-scripts)
49
+ - [Automated Publishing](#automated-publishing-trusted-publishing)
50
+ - [License](#license)
16
51
 
17
52
  ---
18
53
 
19
54
  ## Features
20
55
 
21
- - **Material Design 3**: Fully tokenized CSS design tokens for dynamic theming (Light/Dark mode and custom color palettes).
22
- - **23+ Core Components**: Complete suite of components including Top App Bars, Navigation Drawers, Data Tables, Media Players, Code Blocks/Linters, Search Bars, Form Elements, Dialogs, Cards, and more.
23
- - **Form-Associated Custom Elements (FACE)**: Native form participation, constraint validation, and `FormData` compatibility.
24
- - **Lightweight and Tree-Shakeable**: Pure ESM with granular subpath exports (`@francofantomius/material-components/button`).
25
- - **TypeScript & Custom Elements Manifest**: First-class type definitions (`.d.ts`), source maps, and standard `custom-elements.json` for IDE autocomplete.
26
- - **Accessible (a11y)**: WCAG-compliant contrast ratios, high-visibility focus rings, ARIA roles, and full keyboard navigation.
56
+ - 🎨 **Material Design 3**: Fully tokenized CSS design tokens for dynamic theming, tonal color palettes, surface containers, elevations 0–5, and light/dark modes.
57
+ - 🧩 **23+ Core Components**: Complete suite including Top App Bars, Navigation Drawers, Data Tables, Media Players, Code Blocks/Linters, Search Bars, Form Elements, Dialogs, Cards, and more.
58
+ - 📋 **Form-Associated Custom Elements (FACE)**: Native `<form>` integration, `FormData` compatibility, and standard constraint validation (`required`, `checkValidity()`, `reportValidity()`).
59
+ - **Lightweight & Tree-Shakeable**: Pure ESM modules with granular subpath exports (e.g. `@francofantomius/material-components/button`).
60
+ - 🔷 **TypeScript & Custom Elements Manifest**: First-class TypeScript declarations (`.d.ts`), inline sourcemaps, and standard `custom-elements.json` for IDE autocomplete.
61
+ - **Accessible (a11y)**: WCAG 2.1 AA compliant contrast ratios, high-visibility focus rings (`<md-focus-ring>`), keyboard navigation, and ARIA state handling.
62
+ - 🌐 **Framework Agnostic**: Works out of the box with React, Vue, Angular, Svelte, Solid, or vanilla HTML/JS.
27
63
 
28
64
  ---
29
65
 
30
66
  ## Installation
31
67
 
32
68
  ```bash
69
+ # npm
33
70
  npm install @francofantomius/material-components lit
71
+
72
+ # pnpm
73
+ pnpm add @francofantomius/material-components lit
74
+
75
+ # yarn
76
+ yarn add @francofantomius/material-components lit
77
+
78
+ # bun
79
+ bun add @francofantomius/material-components lit
80
+ ```
81
+
82
+ ---
83
+
84
+ ## CDN Quick Start
85
+
86
+ For quick prototyping or usage directly in HTML without a bundler, import from an ESM CDN:
87
+
88
+ ```html
89
+ <!DOCTYPE html>
90
+ <html lang="en">
91
+ <head>
92
+ <meta charset="UTF-8" />
93
+ <title>Material Components Demo</title>
94
+ <!-- Fonts & Icons -->
95
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
96
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" />
97
+
98
+ <!-- Import from CDN (esm.sh / jsdelivr / unpkg) -->
99
+ <script type="module" src="https://esm.sh/@francofantomius/material-components"></script>
100
+ </head>
101
+ <body>
102
+ <md-button variant="filled" icon="send">Get Started</md-button>
103
+ </body>
104
+ </html>
34
105
  ```
35
106
 
36
107
  ---
@@ -38,15 +109,22 @@ npm install @francofantomius/material-components lit
38
109
  ## Quick Start
39
110
 
40
111
  ### 1. Load Fonts and Icons (Recommended)
41
- Add Google Roboto and Material Symbols to your HTML:
112
+
113
+ Add Google Roboto and Material Symbols Outlined to your HTML `<head>`:
114
+
42
115
  ```html
116
+ <!-- Material Symbols Outlined font -->
43
117
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
118
+
119
+ <!-- Roboto font -->
44
120
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" />
45
121
  ```
46
122
 
47
123
  ### 2. Import Components
48
124
 
49
125
  #### Granular Subpath Imports (Recommended for production)
126
+ Import only the components you use to optimize bundle sizes:
127
+
50
128
  ```typescript
51
129
  import '@francofantomius/material-components/button';
52
130
  import '@francofantomius/material-components/text-field';
@@ -61,64 +139,163 @@ import '@francofantomius/material-components/player';
61
139
  ```
62
140
 
63
141
  #### Global Bundle Import (Ideal for prototyping)
142
+ Registers all components at once:
143
+
64
144
  ```typescript
65
145
  import '@francofantomius/material-components';
66
146
  ```
67
147
 
68
148
  ---
69
149
 
70
- ## Usage Examples
150
+ ## Component Index
71
151
 
72
- ### Navigation & Top App Bar
73
- ```html
74
- <!-- Top App Bar -->
75
- <md-top-app-bar variant="center-aligned" headline="My Application">
76
- <md-icon-button slot="navigation" icon="menu" aria-label="Open menu"></md-icon-button>
77
- <md-icon-button slot="actions" icon="search" aria-label="Search"></md-icon-button>
78
- <md-icon-button slot="actions" icon="account_circle" aria-label="Account"></md-icon-button>
79
- </md-top-app-bar>
152
+ | Category | Component Tag(s) | Subpath Export | Key Properties & Attributes |
153
+ | :--- | :--- | :--- | :--- |
154
+ | **Actions** | `<md-button>` | `/button` | `variant` (filled, elevated, tonal, outlined, text), `icon`, `trailing-icon`, `loading`, `disabled`, `href`, `target`, `type` |
155
+ | **Actions** | `<md-icon-button>` | `/icon-button` | `variant` (standard, filled, tonal, outlined), `icon`, `selected-icon`, `toggle`, `selected`, `disabled` |
156
+ | **Actions** | `<md-fab>` | `/fab` | `size` (small, medium, large), `label`, `icon`, `lowered`, `disabled` |
157
+ | **Actions** | `<md-icon>` | `/icon` | `name`, `filled`, `size` |
158
+ | **Inputs & Controls** | `<md-text-field>` | `/text-field` | `variant` (filled, outlined), `label`, `value`, `type`, `placeholder`, `prefix-text`, `suffix-text`, `error`, `error-text`, `supporting-text`, `leading-icon`, `trailing-icon`, `maxlength`, `required` |
159
+ | **Inputs & Controls** | `<md-checkbox>` | `/checkbox` | `checked`, `indeterminate`, `error`, `disabled`, `required`, `name`, `value` |
160
+ | **Inputs & Controls** | `<md-switch>` | `/switch` | `selected`, `icons`, `disabled`, `name`, `value` |
161
+ | **Inputs & Controls** | `<md-radio>`, `<md-radio-group>` | `/radio` | `checked`, `value`, `name`, `row`, `disabled` |
162
+ | **Inputs & Controls** | `<md-chip>`, `<md-chip-set>` | `/chip` | `variant` (assist, filter, input, suggestion), `label`, `icon`, `selected`, `removable`, `disabled` |
163
+ | **Inputs & Controls** | `<md-search-bar>`, `<md-search>` | `/search-bar` | `value`, `placeholder`, `active`, `suggestions`, `leading-icon`, `trailing-icon`, `responsive`, `collapse-on-mobile`, `fullscreen` |
164
+ | **Surfaces & Layout** | `<md-card>` | `/card` | `variant` (elevated, filled, outlined), `interactive`, `disabled`, `href`, `target` |
165
+ | **Surfaces & Layout** | `<md-dialog>` | `/dialog` | `open`, `headline`, `icon`, `cancelable`, `showModal()`, `close()` |
166
+ | **Surfaces & Layout** | `<md-divider>` | `/divider` | `vertical`, `inset`, `inset-start`, `inset-end` |
167
+ | **Surfaces & Layout** | `<md-list>`, `<md-list-item>` | `/list` | `headline`, `supporting-text`, `trailing-supporting-text`, `interactive`, `disabled`, `href` |
168
+ | **Surfaces & Layout** | `<md-table>`, `<md-data-table>` | `/table` | `columns`, `rows`, `selectable`, `sortable`, `paginated`, `page`, `page-size`, `bordered`, `striped`, `sticky-header`, `loading` |
169
+ | **Communication** | `<md-badge>` | `/badge` | `value`, `dot`, `max` |
170
+ | **Communication** | `<md-progress>` | `/progress` | `type` (linear, circular), `value` (0 to 1, or indeterminate), `buffer`, `wavy` |
171
+ | **Communication** | `<md-snackbar>` | `/snackbar` | `open`, `message`, `action-text`, `closeable`, `timeout-ms`, `stacked` |
172
+ | **Navigation** | `<md-top-app-bar>`, `<md-top-bar>` | `/top-app-bar` | `variant` (center-aligned, small, medium, large), `headline`, `subtitle`, `elevated`, `fixed` |
173
+ | **Navigation** | `<md-navigation-drawer>`, `<md-drawer>` | `/navigation-drawer` | `open`, `type` (modal, standard, responsive), `pivot` (left, right), `headline`, `responsive` |
174
+ | **Navigation** | `<md-tabs>`, `<md-tab>` | `/tabs` | `active-index`, `icon`, `label`, `secondary` |
175
+ | **Navigation** | `<md-app-drawer>`, `<md-app-launcher>` | `/app-drawer` | `open`, `headline`, `icon`, `columns`, `reorderable`, `editable`, `modal`, `alignment`, `pivot` |
176
+ | **Navigation** | `<md-account-menu>`, `<md-account-drawer>` | `/account-menu` | `open`, `name`, `email`, `avatar`, `initials`, `storage-used`, `storage-total`, `storage-progress`, `show-tabs`, `modal`, `alignment` |
177
+ | **Media & Dev Tools** | `<md-code>`, `<md-code-block>` | `/code` | `code`, `language`, `filename`, `line-numbers`, `highlight-lines`, `lint`, `copyable`, `wrap-lines`, `max-height` |
178
+ | **Media & Dev Tools** | `<md-player>`, `<md-media-player>` | `/player` | `type` (audio, video), `variant` (elevated, filled, outlined, compact, full), `src`, `track-title`, `artist`, `poster` |
179
+ | **Internal Helpers** | `<md-ripple>`, `<md-focus-ring>` | `/ripple`, `/focus-ring` | Interactive ripple effect & accessible WCAG focus indicator |
80
180
 
81
- <!-- Navigation Drawer -->
82
- <md-navigation-drawer headline="Navigation" type="modal">
83
- <md-navigation-drawer-item icon="inbox" label="Inbox" badge="24" active></md-navigation-drawer-item>
84
- <md-navigation-drawer-item icon="send" label="Outbox"></md-navigation-drawer-item>
85
- <md-navigation-drawer-item icon="favorite" label="Favorites"></md-navigation-drawer-item>
86
- <md-navigation-drawer-item icon="settings" label="Settings"></md-navigation-drawer-item>
87
- </md-navigation-drawer>
88
- ```
181
+ ---
182
+
183
+ ## Usage Examples
89
184
 
90
185
  ### Buttons, FABs & Icons
186
+
91
187
  ```html
188
+ <!-- Buttons with 5 visual variants -->
92
189
  <md-button variant="filled" icon="send">Send</md-button>
93
190
  <md-button variant="elevated">Elevated</md-button>
94
191
  <md-button variant="tonal">Tonal</md-button>
95
192
  <md-button variant="outlined">Outlined</md-button>
96
193
  <md-button variant="text">Text</md-button>
97
194
 
195
+ <!-- Loading State -->
196
+ <md-button variant="filled" loading>Saving...</md-button>
197
+
198
+ <!-- Icon Buttons (Standard, Filled, Tonal, Outlined, Toggle) -->
98
199
  <md-icon-button icon="favorite" aria-label="Favorite"></md-icon-button>
200
+ <md-icon-button toggle icon="bookmark_border" selected-icon="bookmark" aria-label="Bookmark"></md-icon-button>
201
+
202
+ <!-- Floating Action Button -->
99
203
  <md-fab icon="edit" label="Compose"></md-fab>
204
+ <md-fab size="small" icon="add" aria-label="Add"></md-fab>
205
+
206
+ <!-- Material Symbols Icon -->
100
207
  <md-icon name="star" filled></md-icon>
101
208
  ```
102
209
 
103
210
  ### Form Controls (Native Form Association)
211
+
212
+ All input components are **Form-Associated Custom Elements (FACE)** that natively integrate with standard `<form>` submission, reset, and `FormData`.
213
+
104
214
  ```html
105
215
  <form id="login-form">
106
- <md-text-field label="Full Name" name="name" required leading-icon="person"></md-text-field>
107
- <md-text-field label="Email" name="email" type="email" required leading-icon="email"></md-text-field>
108
-
109
- <md-checkbox name="newsletter" checked>Subscribe to newsletter</md-checkbox>
110
- <md-switch name="notifications" selected icons>Enable notifications</md-switch>
111
-
112
- <md-radio-group name="tier">
113
- <md-radio value="free" label="Free" checked></md-radio>
216
+ <md-text-field
217
+ label="Full Name"
218
+ name="name"
219
+ required
220
+ leading-icon="person"
221
+ supporting-text="Your legal name"
222
+ ></md-text-field>
223
+
224
+ <md-text-field
225
+ label="Email"
226
+ name="email"
227
+ type="email"
228
+ required
229
+ leading-icon="email"
230
+ ></md-text-field>
231
+
232
+ <md-checkbox name="newsletter" checked>
233
+ Subscribe to newsletter
234
+ </md-checkbox>
235
+
236
+ <md-switch name="notifications" selected icons>
237
+ Enable notifications
238
+ </md-switch>
239
+
240
+ <md-radio-group name="tier" value="pro">
241
+ <md-radio value="free" label="Free"></md-radio>
114
242
  <md-radio value="pro" label="Pro"></md-radio>
115
243
  </md-radio-group>
116
244
 
117
- <md-button type="submit" variant="filled">Log In</md-button>
245
+ <div style="display: flex; gap: 8px; margin-top: 16px;">
246
+ <md-button type="reset" variant="outlined">Reset</md-button>
247
+ <md-button type="submit" variant="filled">Log In</md-button>
248
+ </div>
118
249
  </form>
119
250
  ```
120
251
 
252
+ ### Navigation & Top App Bar
253
+
254
+ ```html
255
+ <!-- Top App Bar -->
256
+ <md-top-app-bar variant="center-aligned" headline="My Application">
257
+ <md-icon-button slot="navigation" icon="menu" aria-label="Open menu"></md-icon-button>
258
+ <md-icon-button slot="actions" icon="search" aria-label="Search"></md-icon-button>
259
+ <md-icon-button slot="actions" icon="account_circle" aria-label="Account"></md-icon-button>
260
+ </md-top-app-bar>
261
+
262
+ <!-- Navigation Drawer -->
263
+ <md-navigation-drawer headline="Navigation" type="modal" id="nav-drawer">
264
+ <md-navigation-drawer-item icon="inbox" label="Inbox" badge="24" active></md-navigation-drawer-item>
265
+ <md-navigation-drawer-item icon="send" label="Outbox"></md-navigation-drawer-item>
266
+ <md-navigation-drawer-item icon="favorite" label="Favorites"></md-navigation-drawer-item>
267
+ <md-navigation-drawer-item icon="settings" label="Settings"></md-navigation-drawer-item>
268
+ </md-navigation-drawer>
269
+ ```
270
+
271
+ ### App Drawer & Account Menu
272
+
273
+ ```html
274
+ <!-- Google Apps style Launcher Grid -->
275
+ <md-app-drawer headline="Apps">
276
+ <md-app-drawer-item icon="mail" label="Mail" badge="3"></md-app-drawer-item>
277
+ <md-app-drawer-item icon="calendar_today" label="Calendar"></md-app-drawer-item>
278
+ <md-app-drawer-item icon="folder" label="Drive"></md-app-drawer-item>
279
+ </md-app-drawer>
280
+
281
+ <!-- Account Menu & Switcher -->
282
+ <md-account-menu
283
+ name="Franco Fantomius"
284
+ email="franco.fantomius@example.com"
285
+ initials="F"
286
+ role-title="Lead Architect"
287
+ organization="Material Components Team"
288
+ storage-used="10.4 GB"
289
+ storage-total="15 GB"
290
+ storage-progress="0.69"
291
+ >
292
+ <md-account-item slot="accounts" name="Franco Fantomius" email="franco.fantomius@example.com" initials="F" active></md-account-item>
293
+ <md-account-item slot="accounts" name="Work Profile" email="franco@company.com" initials="W"></md-account-item>
294
+ </md-account-menu>
295
+ ```
296
+
121
297
  ### Data Table
298
+
122
299
  ```html
123
300
  <md-table bordered striped hoverable id="my-table"></md-table>
124
301
 
@@ -139,8 +316,9 @@ import '@francofantomius/material-components';
139
316
  ```
140
317
 
141
318
  ### Search Bar with Live Suggestions
319
+
142
320
  ```html
143
- <md-search-bar placeholder="Search products..." id="search-bar"></md-search-bar>
321
+ <md-search-bar placeholder="Search products..." id="search-bar" responsive></md-search-bar>
144
322
 
145
323
  <script>
146
324
  const search = document.getElementById('search-bar');
@@ -153,6 +331,7 @@ import '@francofantomius/material-components';
153
331
  ```
154
332
 
155
333
  ### Code Block & Syntax Linter
334
+
156
335
  ```html
157
336
  <md-code
158
337
  language="typescript"
@@ -166,6 +345,7 @@ import '@francofantomius/material-components';
166
345
  ```
167
346
 
168
347
  ### Media Player (Audio & Video)
348
+
169
349
  ```html
170
350
  <!-- Audio Player -->
171
351
  <md-player
@@ -184,29 +364,26 @@ import '@francofantomius/material-components';
184
364
  ></md-player>
185
365
  ```
186
366
 
187
- ### App Drawer & Account Menu
188
- ```html
189
- <!-- App Launcher Grid -->
190
- <md-app-drawer headline="Apps">
191
- <md-app-drawer-item icon="mail" label="Mail" badge="3"></md-app-drawer-item>
192
- <md-app-drawer-item icon="calendar_today" label="Calendar"></md-app-drawer-item>
193
- <md-app-drawer-item icon="folder" label="Drive"></md-app-drawer-item>
194
- </md-app-drawer>
367
+ ---
195
368
 
196
- <!-- Account Menu & Switcher -->
197
- <md-account-menu
198
- name="Franco Fantomius"
199
- email="franco.fantomius@example.com"
200
- initials="F"
201
- role-title="Lead Architect"
202
- organization="Material Components Team"
203
- storage-used="10.4 GB"
204
- storage-total="15 GB"
205
- storage-progress="0.69"
206
- >
207
- <md-account-item slot="accounts" name="Franco Fantomius" email="franco.fantomius@example.com" initials="F" active></md-account-item>
208
- <md-account-item slot="accounts" name="Work Profile" email="franco@company.com" initials="W"></md-account-item>
209
- </md-account-menu>
369
+ ## Form Integration (FACE)
370
+
371
+ Form elements (`<md-text-field>`, `<md-checkbox>`, `<md-switch>`, `<md-radio>`) use standard browser `ElementInternals`. They participate seamlessly in form life-cycles:
372
+
373
+ ```javascript
374
+ const form = document.getElementById('login-form');
375
+
376
+ form.addEventListener('submit', (e) => {
377
+ e.preventDefault();
378
+
379
+ if (!form.checkValidity()) {
380
+ form.reportValidity();
381
+ return;
382
+ }
383
+
384
+ const formData = new FormData(form);
385
+ console.log('Payload:', Object.fromEntries(formData.entries()));
386
+ });
210
387
  ```
211
388
 
212
389
  ---
@@ -214,12 +391,15 @@ import '@francofantomius/material-components';
214
391
  ## Theming and Dark Mode
215
392
 
216
393
  ### Dynamic Theming via CSS Custom Properties
217
- The library uses standard CSS custom properties adhering to Material Design 3 specifications:
394
+
395
+ The library uses standard Material Design 3 design tokens. Override them globally on `:root` or scope them to any container:
218
396
 
219
397
  ```css
220
398
  :root {
221
399
  --md-sys-color-primary: #6750A4;
222
400
  --md-sys-color-on-primary: #FFFFFF;
401
+ --md-sys-color-primary-container: #EADDFF;
402
+ --md-sys-color-on-primary-container: #21005D;
223
403
  --md-sys-color-surface: #FEF7FF;
224
404
  --md-sys-color-on-surface: #1D1B20;
225
405
  }
@@ -227,62 +407,39 @@ The library uses standard CSS custom properties adhering to Material Design 3 sp
227
407
  [data-theme='dark'] {
228
408
  --md-sys-color-primary: #D0BCFF;
229
409
  --md-sys-color-on-primary: #381E72;
410
+ --md-sys-color-primary-container: #4F378B;
411
+ --md-sys-color-on-primary-container: #EADDFF;
230
412
  --md-sys-color-surface: #141218;
231
413
  --md-sys-color-on-surface: #E6E0E9;
232
414
  }
233
415
  ```
234
416
 
235
417
  ### TypeScript Theme Helper
418
+
236
419
  ```typescript
237
- import { applyTheme, darkColorScheme } from '@francofantomius/material-components/theme';
420
+ import { applyTheme, darkColorScheme, lightColorScheme } from '@francofantomius/material-components/theme';
238
421
 
239
- // Apply dark theme
422
+ // Switch to dark theme
240
423
  applyTheme(darkColorScheme);
241
424
 
242
- // Apply custom brand colors
425
+ // Switch back to light theme
426
+ applyTheme(lightColorScheme);
427
+
428
+ // Apply custom brand palette
243
429
  applyTheme({
244
430
  primary: '#006A60',
245
431
  onPrimary: '#FFFFFF',
432
+ primaryContainer: '#74F8E5',
433
+ onPrimaryContainer: '#00201C',
246
434
  });
247
435
  ```
248
436
 
249
437
  ---
250
438
 
251
- ## Component List
252
-
253
- | Component | Tag(s) | Subpath Export | Key Properties & Attributes |
254
- | :--- | :--- | :--- | :--- |
255
- | **Button** | `<md-button>` | `/button` | `variant` (filled, elevated, tonal, outlined, text), `icon`, `loading`, `disabled`, `href`, `type` |
256
- | **Icon Button** | `<md-icon-button>` | `/icon-button` | `variant` (standard, filled, tonal, outlined), `icon`, `toggle`, `selected`, `disabled` |
257
- | **FAB** | `<md-fab>` | `/fab` | `size` (small, medium, large), `label`, `icon`, `lowered` |
258
- | **Icon** | `<md-icon>` | `/icon` | `name`, `filled`, `size` |
259
- | **Text Field** | `<md-text-field>` | `/text-field` | `variant` (filled, outlined), `label`, `value`, `prefix-text`, `suffix-text`, `error`, `supporting-text`, `leading-icon`, `trailing-icon` |
260
- | **Checkbox** | `<md-checkbox>` | `/checkbox` | `checked`, `indeterminate`, `error`, `disabled`, `name`, `value` |
261
- | **Switch** | `<md-switch>` | `/switch` | `selected`, `icons`, `disabled`, `name`, `value` |
262
- | **Radio** | `<md-radio>`, `<md-radio-group>` | `/radio` | `checked`, `value`, `name`, `row`, `disabled` |
263
- | **Card** | `<md-card>` | `/card` | `variant` (elevated, filled, outlined), `interactive`, `href` |
264
- | **Dialog** | `<md-dialog>` | `/dialog` | `open`, `headline`, `icon`, `showModal()`, `close()`, `cancelable` |
265
- | **Divider** | `<md-divider>` | `/divider` | `vertical`, `inset`, `inset-start`, `inset-end` |
266
- | **Progress** | `<md-progress>` | `/progress` | `type` (linear, circular), `value` (0 to 1, or indeterminate), `buffer` |
267
- | **Badge** | `<md-badge>` | `/badge` | `value`, `dot`, `max` |
268
- | **Chip** | `<md-chip>`, `<md-chip-set>` | `/chip` | `variant` (assist, filter, input, suggestion), `label`, `selected`, `removable`, `elevated` |
269
- | **Tabs** | `<md-tabs>`, `<md-tab>` | `/tabs` | `active-index`, `icon`, `label`, `secondary` |
270
- | **List** | `<md-list>`, `<md-list-item>` | `/list` | `headline`, `supporting-text`, `trailing-supporting-text`, `interactive`, `href`, `lines` |
271
- | **Snackbar** | `<md-snackbar>` | `/snackbar` | `open`, `message`, `action-text`, `closeable`, `timeout-ms`, `stacked` |
272
- | **Top App Bar** | `<md-top-app-bar>`, `<md-top-bar>` | `/top-app-bar` | `variant` (center-aligned, small, medium, large), `headline`, `subtitle`, `elevated`, `fixed` |
273
- | **Navigation Drawer** | `<md-navigation-drawer>`, `<md-drawer>`, `<md-menu-bar>`, `<md-navigation-drawer-item>` | `/navigation-drawer` | `open`, `type` (modal, standard, responsive), `pivot` (left, right), `headline`, `responsive`, `closed` |
274
- | **App Drawer** | `<md-app-drawer>`, `<md-app-launcher>`, `<md-apps-menu>`, `<md-app-drawer-item>`, `<md-app-item>` | `/app-drawer` | `open`, `headline`, `icon`, `columns`, `reorderable`, `editable`, `modal`, `alignment`, `pivot` |
275
- | **Account Menu** | `<md-account-menu>`, `<md-account-drawer>`, `<md-account-profile>`, `<md-account-item>` | `/account-menu` | `open`, `name`, `email`, `avatar`, `initials`, `storage-used`, `storage-total`, `show-tabs`, `modal`, `alignment` |
276
- | **Table / Data Table** | `<md-table>`, `<md-data-table>`, `<md-table-head>`, `<md-table-body>`, `<md-table-row>`, `<md-table-cell>`, `<md-table-header-cell>`, `<md-table-pagination>` | `/table` | `columns`, `rows`, `selectable`, `sortable`, `paginated`, `page`, `page-size`, `bordered`, `striped`, `sticky-header`, `loading` |
277
- | **Search Bar** | `<md-search-bar>`, `<md-search>` | `/search-bar` | `value`, `placeholder`, `active`, `suggestions`, `leading-icon`, `trailing-icon`, `responsive`, `fullscreen` |
278
- | **Code Block & Linter** | `<md-code>`, `<md-code-block>` | `/code` | `code`, `language`, `label` / `filename`, `line-numbers`, `highlight-lines`, `lint`, `copyable`, `wrap-lines`, `max-height` |
279
- | **Media Player** | `<md-player>`, `<md-media-player>`, `<md-audio-player>`, `<md-video-player>` | `/player` | `type` (audio, video), `variant` (elevated, filled, outlined, compact, full), `src`, `track-title`, `artist`, `poster`, `currentTime`, `duration`, `volume`, `playback-rate` |
280
- | **Internal Helpers** | `<md-ripple>`, `<md-focus-ring>` | `/ripple`, `/focus-ring` | Interactive ripple effect & WCAG focus indicators |
281
-
282
- ---
283
-
284
439
  ## Subpath Exports Reference
285
440
 
441
+ Each component can be imported individually with full TypeScript type definitions:
442
+
286
443
  ```typescript
287
444
  import { applyTheme } from '@francofantomius/material-components/theme';
288
445
  import { MdButton } from '@francofantomius/material-components/button';
@@ -316,36 +473,145 @@ import { MdPlayer, MdMediaPlayer, MdAudioPlayer, MdVideoPlayer } from '@francofa
316
473
 
317
474
  ## Framework Integration
318
475
 
319
- Because Web Components are browser standards, they work seamlessly with any framework:
476
+ Because Web Components are standard custom elements, they work natively across all frameworks:
320
477
 
321
478
  ### React
479
+
480
+ #### React 19
481
+ React 19 supports Custom Elements natively (attributes, properties, and custom events):
482
+
322
483
  ```tsx
323
484
  import '@francofantomius/material-components/button';
324
485
  import '@francofantomius/material-components/text-field';
486
+ import '@francofantomius/material-components/switch';
325
487
 
326
- export function LoginForm() {
488
+ export function SettingsForm() {
327
489
  return (
328
490
  <div>
329
- <md-text-field label="Username" onInput={(e: any) => console.log(e.target.value)}></md-text-field>
330
- <md-button variant="filled" onClick={() => alert('Clicked')}>Submit</md-button>
491
+ <md-text-field
492
+ label="Username"
493
+ onInput={(e: any) => console.log(e.target.value)}
494
+ />
495
+ <md-switch
496
+ selected
497
+ onChange={(e: any) => console.log(e.target.selected)}
498
+ >
499
+ Enable Notifications
500
+ </md-switch>
501
+ <md-button variant="filled" onClick={() => alert('Saved!')}>
502
+ Save
503
+ </md-button>
331
504
  </div>
332
505
  );
333
506
  }
334
507
  ```
335
508
 
509
+ #### React 18 / Next.js
510
+ In React 18, assign complex object/array properties (such as `table.columns` or `search.suggestions`) via React `ref`:
511
+
512
+ ```tsx
513
+ import React, { useRef, useEffect } from 'react';
514
+ import '@francofantomius/material-components/table';
515
+
516
+ export function UserTable({ users }) {
517
+ const tableRef = useRef<any>(null);
518
+
519
+ useEffect(() => {
520
+ if (tableRef.current) {
521
+ tableRef.current.columns = [
522
+ { key: 'name', label: 'Name', sortable: true },
523
+ { key: 'email', label: 'Email' }
524
+ ];
525
+ tableRef.current.rows = users;
526
+ }
527
+ }, [users]);
528
+
529
+ return <md-table ref={tableRef} bordered hoverable />;
530
+ }
531
+ ```
532
+
336
533
  ### Vue
534
+
535
+ In Vue 3 / Nuxt, configure compiler options so Vue doesn't treat `md-*` elements as missing components:
536
+
537
+ ```javascript
538
+ // vite.config.js
539
+ import { defineConfig } from 'vite';
540
+ import vue from '@vitejs/plugin-vue';
541
+
542
+ export default defineConfig({
543
+ plugins: [
544
+ vue({
545
+ template: {
546
+ compilerOptions: {
547
+ isCustomElement: (tag) => tag.startsWith('md-')
548
+ }
549
+ }
550
+ })
551
+ ]
552
+ });
553
+ ```
554
+
337
555
  ```vue
338
556
  <script setup>
557
+ import { ref } from 'vue';
339
558
  import '@francofantomius/material-components/button';
340
559
  import '@francofantomius/material-components/switch';
560
+
561
+ const isEnabled = ref(true);
341
562
  </script>
342
563
 
343
564
  <template>
344
- <md-switch selected icons>Notifications</md-switch>
345
- <md-button variant="tonal">Save</md-button>
565
+ <div>
566
+ <md-switch :selected="isEnabled" @change="isEnabled = !isEnabled">
567
+ Enable Feature
568
+ </md-switch>
569
+ <md-button variant="filled" :disabled="!isEnabled">
570
+ Proceed
571
+ </md-button>
572
+ </div>
346
573
  </template>
347
574
  ```
348
575
 
576
+ ### Angular
577
+
578
+ Include `CUSTOM_ELEMENTS_SCHEMA` in your standalone component or `@NgModule`:
579
+
580
+ ```typescript
581
+ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
582
+ import '@francofantomius/material-components/button';
583
+
584
+ @Component({
585
+ selector: 'app-root',
586
+ standalone: true,
587
+ template: `<md-button variant="filled">Click Me</md-button>`,
588
+ schemas: [CUSTOM_ELEMENTS_SCHEMA]
589
+ })
590
+ export class AppComponent {}
591
+ ```
592
+
593
+ ### Svelte
594
+
595
+ Custom elements work out-of-the-box with standard Svelte bindings:
596
+
597
+ ```svelte
598
+ <script>
599
+ import '@francofantomius/material-components/button';
600
+ import '@francofantomius/material-components/text-field';
601
+
602
+ let name = '';
603
+ </script>
604
+
605
+ <md-text-field label="Name" value={name} on:input={(e) => name = e.target.value}></md-text-field>
606
+ <md-button variant="filled" on:click={() => alert(`Hello ${name}`)}>Submit</md-button>
607
+ ```
608
+
609
+ ---
610
+
611
+ ## LLM & AI Assistant Documentation
612
+
613
+ This repository provides an [`llms.txt`](./llms.txt) file structured for AI coding assistants (such as Antigravity, Cursor, GitHub Copilot, ChatGPT, and Claude). It provides complete API specifications, component hierarchies, and ready-to-use code patterns.
614
+
349
615
  ---
350
616
 
351
617
  ## Development Scripts
@@ -357,13 +623,13 @@ npm run dev
357
623
  # Run unit tests with Vitest
358
624
  npm test
359
625
 
360
- # Type check TypeScript codebase
626
+ # Type-check TypeScript codebase
361
627
  npm run typecheck
362
628
 
363
629
  # Build ESM library, docs & generate Custom Elements Manifest
364
630
  npm run build
365
631
 
366
- # Preview docs site build
632
+ # Preview documentation site build
367
633
  npm run preview
368
634
  ```
369
635
 
@@ -371,13 +637,13 @@ npm run preview
371
637
 
372
638
  ## Automated Publishing (Trusted Publishing)
373
639
 
374
- This repository is configured for **npm Trusted Publishing** using GitHub Actions OpenID Connect (OIDC). No long-lived static tokens or secrets are required.
640
+ This repository is configured for **npm Trusted Publishing** using GitHub Actions OpenID Connect (OIDC).
375
641
 
376
642
  ### How it works:
377
- 1. When changes are pushed to `main`, the workflow checks the `version` field in `package.json`.
643
+ 1. When changes are merged to `main`, the CI workflow checks the `version` field in `package.json`.
378
644
  2. It queries npm to verify if this version is already published.
379
- 3. If the version is new, it runs typecheck, tests, builds the library, exchanges an OIDC token with npm, and publishes the package with cryptographic provenance (`--provenance`).
380
- 4. It automatically creates a Git tag (`v<version>`) and a GitHub Release.
645
+ 3. If the version is new, it executes type checking, automated tests, builds the library, exchanges an OIDC token with npm, and publishes the package with cryptographic provenance (`--provenance`).
646
+ 4. It automatically creates a Git release and tag (`v<version>`).
381
647
 
382
648
  ---
383
649
 
@@ -2932,149 +2932,6 @@
2932
2932
  }
2933
2933
  ]
2934
2934
  },
2935
- {
2936
- "kind": "javascript-module",
2937
- "path": "src/components/badge/badge.ts",
2938
- "declarations": [
2939
- {
2940
- "kind": "class",
2941
- "description": "",
2942
- "name": "MdBadge",
2943
- "members": [
2944
- {
2945
- "kind": "field",
2946
- "name": "value",
2947
- "type": {
2948
- "text": "string"
2949
- },
2950
- "default": "''",
2951
- "attribute": "value",
2952
- "reflects": true
2953
- },
2954
- {
2955
- "kind": "field",
2956
- "name": "dot",
2957
- "type": {
2958
- "text": "boolean"
2959
- },
2960
- "default": "false",
2961
- "attribute": "dot",
2962
- "reflects": true
2963
- },
2964
- {
2965
- "kind": "field",
2966
- "name": "anchored",
2967
- "type": {
2968
- "text": "boolean"
2969
- },
2970
- "default": "false",
2971
- "attribute": "anchored",
2972
- "reflects": true
2973
- },
2974
- {
2975
- "kind": "field",
2976
- "name": "assignedChildren",
2977
- "type": {
2978
- "text": "HTMLElement[]"
2979
- },
2980
- "privacy": "private"
2981
- },
2982
- {
2983
- "kind": "field",
2984
- "name": "handleSlotChange",
2985
- "privacy": "private"
2986
- },
2987
- {
2988
- "kind": "method",
2989
- "name": "emitEvent",
2990
- "privacy": "protected",
2991
- "return": {
2992
- "type": {
2993
- "text": "boolean"
2994
- }
2995
- },
2996
- "parameters": [
2997
- {
2998
- "name": "name",
2999
- "type": {
3000
- "text": "string"
3001
- }
3002
- },
3003
- {
3004
- "name": "detail",
3005
- "optional": true,
3006
- "type": {
3007
- "text": "T"
3008
- }
3009
- },
3010
- {
3011
- "name": "options",
3012
- "default": "{}",
3013
- "type": {
3014
- "text": "CustomEventInit<T>"
3015
- }
3016
- }
3017
- ],
3018
- "description": "Helper to dispatch custom events with standard bubbles/composed defaults.",
3019
- "inheritedFrom": {
3020
- "name": "MdBaseElement",
3021
- "module": "src/internal/base-component.ts"
3022
- }
3023
- }
3024
- ],
3025
- "attributes": [
3026
- {
3027
- "name": "value",
3028
- "type": {
3029
- "text": "string"
3030
- },
3031
- "default": "''",
3032
- "fieldName": "value"
3033
- },
3034
- {
3035
- "name": "dot",
3036
- "type": {
3037
- "text": "boolean"
3038
- },
3039
- "default": "false",
3040
- "fieldName": "dot"
3041
- },
3042
- {
3043
- "name": "anchored",
3044
- "type": {
3045
- "text": "boolean"
3046
- },
3047
- "default": "false",
3048
- "fieldName": "anchored"
3049
- }
3050
- ],
3051
- "superclass": {
3052
- "name": "MdBaseElement",
3053
- "module": "/src/internal/base-component.js"
3054
- },
3055
- "tagName": "md-badge",
3056
- "customElement": true
3057
- }
3058
- ],
3059
- "exports": [
3060
- {
3061
- "kind": "js",
3062
- "name": "MdBadge",
3063
- "declaration": {
3064
- "name": "MdBadge",
3065
- "module": "src/components/badge/badge.ts"
3066
- }
3067
- },
3068
- {
3069
- "kind": "custom-element-definition",
3070
- "name": "md-badge",
3071
- "declaration": {
3072
- "name": "MdBadge",
3073
- "module": "src/components/badge/badge.ts"
3074
- }
3075
- }
3076
- ]
3077
- },
3078
2935
  {
3079
2936
  "kind": "javascript-module",
3080
2937
  "path": "src/components/app-drawer/app-drawer.ts",
@@ -6805,6 +6662,149 @@
6805
6662
  }
6806
6663
  ]
6807
6664
  },
6665
+ {
6666
+ "kind": "javascript-module",
6667
+ "path": "src/components/badge/badge.ts",
6668
+ "declarations": [
6669
+ {
6670
+ "kind": "class",
6671
+ "description": "",
6672
+ "name": "MdBadge",
6673
+ "members": [
6674
+ {
6675
+ "kind": "field",
6676
+ "name": "value",
6677
+ "type": {
6678
+ "text": "string"
6679
+ },
6680
+ "default": "''",
6681
+ "attribute": "value",
6682
+ "reflects": true
6683
+ },
6684
+ {
6685
+ "kind": "field",
6686
+ "name": "dot",
6687
+ "type": {
6688
+ "text": "boolean"
6689
+ },
6690
+ "default": "false",
6691
+ "attribute": "dot",
6692
+ "reflects": true
6693
+ },
6694
+ {
6695
+ "kind": "field",
6696
+ "name": "anchored",
6697
+ "type": {
6698
+ "text": "boolean"
6699
+ },
6700
+ "default": "false",
6701
+ "attribute": "anchored",
6702
+ "reflects": true
6703
+ },
6704
+ {
6705
+ "kind": "field",
6706
+ "name": "assignedChildren",
6707
+ "type": {
6708
+ "text": "HTMLElement[]"
6709
+ },
6710
+ "privacy": "private"
6711
+ },
6712
+ {
6713
+ "kind": "field",
6714
+ "name": "handleSlotChange",
6715
+ "privacy": "private"
6716
+ },
6717
+ {
6718
+ "kind": "method",
6719
+ "name": "emitEvent",
6720
+ "privacy": "protected",
6721
+ "return": {
6722
+ "type": {
6723
+ "text": "boolean"
6724
+ }
6725
+ },
6726
+ "parameters": [
6727
+ {
6728
+ "name": "name",
6729
+ "type": {
6730
+ "text": "string"
6731
+ }
6732
+ },
6733
+ {
6734
+ "name": "detail",
6735
+ "optional": true,
6736
+ "type": {
6737
+ "text": "T"
6738
+ }
6739
+ },
6740
+ {
6741
+ "name": "options",
6742
+ "default": "{}",
6743
+ "type": {
6744
+ "text": "CustomEventInit<T>"
6745
+ }
6746
+ }
6747
+ ],
6748
+ "description": "Helper to dispatch custom events with standard bubbles/composed defaults.",
6749
+ "inheritedFrom": {
6750
+ "name": "MdBaseElement",
6751
+ "module": "src/internal/base-component.ts"
6752
+ }
6753
+ }
6754
+ ],
6755
+ "attributes": [
6756
+ {
6757
+ "name": "value",
6758
+ "type": {
6759
+ "text": "string"
6760
+ },
6761
+ "default": "''",
6762
+ "fieldName": "value"
6763
+ },
6764
+ {
6765
+ "name": "dot",
6766
+ "type": {
6767
+ "text": "boolean"
6768
+ },
6769
+ "default": "false",
6770
+ "fieldName": "dot"
6771
+ },
6772
+ {
6773
+ "name": "anchored",
6774
+ "type": {
6775
+ "text": "boolean"
6776
+ },
6777
+ "default": "false",
6778
+ "fieldName": "anchored"
6779
+ }
6780
+ ],
6781
+ "superclass": {
6782
+ "name": "MdBaseElement",
6783
+ "module": "/src/internal/base-component.js"
6784
+ },
6785
+ "tagName": "md-badge",
6786
+ "customElement": true
6787
+ }
6788
+ ],
6789
+ "exports": [
6790
+ {
6791
+ "kind": "js",
6792
+ "name": "MdBadge",
6793
+ "declaration": {
6794
+ "name": "MdBadge",
6795
+ "module": "src/components/badge/badge.ts"
6796
+ }
6797
+ },
6798
+ {
6799
+ "kind": "custom-element-definition",
6800
+ "name": "md-badge",
6801
+ "declaration": {
6802
+ "name": "MdBadge",
6803
+ "module": "src/components/badge/badge.ts"
6804
+ }
6805
+ }
6806
+ ]
6807
+ },
6808
6808
  {
6809
6809
  "kind": "javascript-module",
6810
6810
  "path": "src/components/button/button.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@francofantomius/material-components",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Reusable, accessible, and lightweight Material Design 3 Web Components built with Lit.",
5
5
  "repository": {
6
6
  "type": "git",