fluentui-webcomponents 0.0.1 → 0.0.3

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/AGENTS.md CHANGED
@@ -127,21 +127,40 @@ Semantic tokens alias these stops:
127
127
  --colorBrandBackgroundPressed → --brand-40
128
128
  ```
129
129
 
130
- ### Runtime Accent Change
130
+ ### Theme Switching (light-dark() + color-scheme)
131
131
 
132
- ```js
133
- document.documentElement.style.setProperty('--accent-base', '#e3008c');
132
+ Tokens use CSS `light-dark(lightValue, darkValue)` — a single declaration per token. No duplicate dark blocks, no `@media` queries, no `.dark` classes.
133
+
134
+ ```css
135
+ :host, :root {
136
+ color-scheme: light dark;
137
+ --accent-base: light-dark(#0f6cbd, #479ef5);
138
+ --neutral-base: light-dark(#808080, #b0b0b0);
139
+ --colorNeutralBackground1: light-dark(white, var(--neutral-shade-24));
140
+ }
134
141
  ```
135
142
 
136
- One line. Entire palette and all dependent tokens update instantly. Zero JS math.
143
+ Palette stops (`--neutral-10`…`160`, `--brand-10`…`160`, tints, shades) auto-adapt from the `light-dark()` base colors via `color-mix()` — no changes needed.
137
144
 
138
- ### Theme Switching
145
+ Page-level overrides use the `color-scheme` CSS property on `:root`:
139
146
 
140
- ```css
141
- :root.dark { --accent-base: #479ef5; --neutral-base: #b0b0b0; }
142
- body.dark { /* overrides for dark theme tokens */ }
147
+ ```js
148
+ // Light mode
149
+ document.documentElement.style.colorScheme = 'light';
150
+ // Dark mode
151
+ document.documentElement.style.colorScheme = 'dark';
152
+ // Follow system
153
+ document.documentElement.style.colorScheme = 'light dark';
143
154
  ```
144
155
 
156
+ ### Runtime Accent Change
157
+
158
+ ```js
159
+ document.documentElement.style.setProperty('--accent-base', '#e3008c');
160
+ ```
161
+
162
+ One line. Overrides the `light-dark()` value. Entire palette and all dependent tokens update instantly. Zero JS math.
163
+
145
164
  ## Form Association
146
165
 
147
166
  ```js
package/README.md CHANGED
@@ -1,99 +1,105 @@
1
- # fluentui-webcomponents
2
-
3
- Vanilla Custom Elements rewrite of `@fluentui/web-components` — zero dependencies, zero build tools.
4
-
5
- ## Quick Start
6
-
7
- ```html
8
- <script type="module" src="core/fluent-element.js"></script>
9
- <script type="module" src="components/button/fluent-button.js"></script>
10
- <script type="module" src="components/badge/fluent-badge.js"></script>
11
-
12
- <fluent-button appearance="primary">Click me</fluent-button>
13
- <fluent-badge color="danger">New</fluent-badge>
14
- ```
15
-
16
- CSS design tokens are defined in `tokens.css`. Each component's CSS imports it via `@import` — no `<link>` needed in your page.
17
-
18
- ## Gallery
19
-
20
- ```bash
21
- npx serve .
22
- ```
23
-
24
- Open `http://localhost:3000/gallery.html` — a single-page showcase of all 26 components with a theme picker.
25
-
26
- ## Customization
27
-
28
- **Accent color** (instant, no JS math):
29
- ```css
30
- :root { --accent-base: #e3008c; }
31
- ```
32
-
33
- The entire 16-stop brand palette derives from this single CSS variable via `color-mix(in oklch, ...)`. All component colors update automatically.
34
-
35
- **Dark theme**:
36
- ```html
37
- <body class="dark">
38
- ```
39
-
40
- **Theme picker** (optional):
41
- ```html
42
- <script type="module" src="theme/theme-picker.js"></script>
43
- <fluent-theme-picker></fluent-theme-picker>
44
- ```
45
-
46
- ## Components
47
-
48
- | Component | Tag |
49
- |---|---|
50
- | Button | `<fluent-button>` |
51
- | Badge | `<fluent-badge>` |
52
- | Link | `<fluent-link>` |
53
- | Divider | `<fluent-divider>` |
54
- | Spinner | `<fluent-spinner>` |
55
- | Avatar | `<fluent-avatar>` |
56
- | Checkbox | `<fluent-checkbox>` |
57
- | Radio | `<fluent-radio>` |
58
- | Switch | `<fluent-switch>` |
59
- | Slider | `<fluent-slider>` |
60
- | TextInput | `<fluent-text-input>` |
61
- | Textarea | `<fluent-textarea>` |
62
- | Select | `<fluent-select>` |
63
- | Card | `<fluent-card>` |
64
- | Label | `<fluent-label>` |
65
- | Text | `<fluent-text>` |
66
- | Image | `<fluent-image>` |
67
- | Dialog | `<fluent-dialog trigger="#btn" close-on="#cancel">` |
68
- | Tooltip | `<fluent-tooltip anchor="btn-id">` |
69
- | Menu | `<fluent-menu>` |
70
- | Breadcrumb | `<fluent-breadcrumb>` |
71
- | Tree | `<fluent-tree>` |
72
-
73
- ## File Structure
74
-
75
- ```
76
- fluentui-webcomponents/
77
- ├── tokens.css # All design tokens (colors, spacing, type, shadows...)
78
- ├── gallery.html # Component showcase
79
- ├── core/
80
- │ └── fluent-element.js # Base class (~30 lines)
81
- ├── components/
82
- ├── button/
83
- │ │ ├── fluent-button.js
84
- │ │ └── fluent-button.css # @import url('../../tokens.css');
85
- ├── badge/
86
- ├── ...
87
- │ └── tree/
88
- └── theme/
89
- └── theme-picker.js # Optional accent/theme switcher
90
- ```
91
-
92
- Each component is self-contained: one `.js` file (class + `customElements.define`) and one `.css` file. No bundler, no framework, no external dependencies.
93
-
94
- ## Architecture
95
-
96
- - **`FluentElement`** — base class extends `HTMLElement`, attaches shadow DOM, injects `<link rel="stylesheet">` for the component's CSS
97
- - **CSS-only state** — `:host([disabled])`, `:host([appearance="primary"])`, etc. Zero JS for visual updates
98
- - **Form association** native `this.attachInternals()` + `setFormValue` + `setValidity`
99
- - **Design tokens** — `color-mix(in oklch, var(--accent-base), ...)` palette, CSS `var()` throughout
1
+ # fluentui-webcomponents
2
+ <img src="https://nodei.co/npm/fluentui-webcomponents.svg?style=shields&data=n,v&color=blue"/>
3
+
4
+ Vanilla Custom Elements rewrite of `@fluentui/web-components` — zero dependencies, zero build tools.
5
+
6
+ ## Quick Start
7
+
8
+ ```html
9
+ <script type="module" src="core/fluent-element.js"></script>
10
+ <script type="module" src="components/button/fluent-button.js"></script>
11
+ <script type="module" src="components/badge/fluent-badge.js"></script>
12
+
13
+ <fluent-button appearance="primary">Click me</fluent-button>
14
+ <fluent-badge color="danger">New</fluent-badge>
15
+ ```
16
+
17
+ CSS design tokens are defined in `tokens.css`. Each component's CSS imports it via `@import` — no `<link>` needed in your page.
18
+
19
+ ## Gallery
20
+
21
+ ```bash
22
+ npx serve .
23
+ ```
24
+
25
+ Open `http://localhost:3000/gallery.html` — a single-page showcase of all 26 components with a theme picker.
26
+
27
+ ## Customization
28
+
29
+ **Accent color** (instant, no JS math):
30
+ ```css
31
+ :root { --accent-base: #e3008c; }
32
+ ```
33
+
34
+ The entire 16-stop brand palette derives from this single CSS variable via `color-mix(in srgb, ...)`. All component colors update automatically.
35
+
36
+ **Dark theme** (via `color-scheme` CSS property):
37
+ ```css
38
+ :root { color-scheme: dark; }
39
+ ```
40
+ ```js
41
+ document.documentElement.style.colorScheme = 'dark';
42
+ ```
43
+ Tokens use `light-dark(lightValue, darkValue)` — no class toggling needed.
44
+
45
+ **Theme picker** (optional):
46
+ ```html
47
+ <script type="module" src="theme/theme-picker.js"></script>
48
+ <fluent-theme-picker></fluent-theme-picker>
49
+ ```
50
+
51
+ ## Components
52
+
53
+ | Component | Tag |
54
+ |---|---|
55
+ | Button | `<fluent-button>` |
56
+ | Badge | `<fluent-badge>` |
57
+ | Link | `<fluent-link>` |
58
+ | Divider | `<fluent-divider>` |
59
+ | Spinner | `<fluent-spinner>` |
60
+ | Avatar | `<fluent-avatar>` |
61
+ | Checkbox | `<fluent-checkbox>` |
62
+ | Radio | `<fluent-radio>` |
63
+ | Switch | `<fluent-switch>` |
64
+ | Slider | `<fluent-slider>` |
65
+ | TextInput | `<fluent-text-input>` |
66
+ | Textarea | `<fluent-textarea>` |
67
+ | Select | `<fluent-select>` |
68
+ | Card | `<fluent-card>` |
69
+ | Label | `<fluent-label>` |
70
+ | Text | `<fluent-text>` |
71
+ | Image | `<fluent-image>` |
72
+ | Dialog | `<fluent-dialog trigger="#btn" close-on="#cancel">` |
73
+ | Tooltip | `<fluent-tooltip anchor="btn-id">` |
74
+ | Menu | `<fluent-menu>` |
75
+ | Breadcrumb | `<fluent-breadcrumb>` |
76
+ | Tree | `<fluent-tree>` |
77
+
78
+ ## File Structure
79
+
80
+ ```
81
+ fluentui-webcomponents/
82
+ ├── tokens.css # All design tokens (colors, spacing, type, shadows...)
83
+ ├── gallery.html # Component showcase
84
+ ├── standalone-example.html # Minimal usage (no page CSS needed)
85
+ ├── core/
86
+ └── fluent-element.js # Base class (~30 lines)
87
+ ├── components/
88
+ │ ├── button/
89
+ │ │ ├── fluent-button.js
90
+ │ │ └── fluent-button.css # @import url('../../tokens.css');
91
+ │ ├── badge/
92
+ │ ├── ...
93
+ │ └── tree/
94
+ └── theme/
95
+ └── theme-picker.js # Optional accent/theme switcher
96
+ ```
97
+
98
+ Each component is self-contained: one `.js` file (class + `customElements.define`) and one `.css` file. No bundler, no framework, no external dependencies.
99
+
100
+ ## Architecture
101
+
102
+ - **`FluentElement`** — base class extends `HTMLElement`, attaches shadow DOM, injects `<link rel="stylesheet">` for the component's CSS
103
+ - **CSS-only state** — `:host([disabled])`, `:host([appearance="primary"])`, etc. Zero JS for visual updates
104
+ - **Form association** — native `this.attachInternals()` + `setFormValue` + `setValidity`
105
+ - **Design tokens** — `color-mix(in oklch, var(--accent-base), ...)` palette, CSS `var()` throughout
@@ -1,21 +1,21 @@
1
1
  class FluentElement extends HTMLElement {
2
- static stylesUrl = '';
3
- static template = '';
2
+ static stylesUrl = "";
3
+ static template = "";
4
4
 
5
5
  constructor() {
6
6
  super();
7
- this._root = this.attachShadow({ mode: 'open' });
7
+ this._root = this.attachShadow({ mode: "open" });
8
8
  }
9
9
 
10
10
  connectedCallback() {
11
11
  if (this.constructor.stylesUrl) {
12
- const link = document.createElement('link');
13
- link.rel = 'stylesheet';
12
+ const link = document.createElement("link");
13
+ link.rel = "stylesheet";
14
14
  link.href = this.constructor.stylesUrl;
15
15
  this._root.appendChild(link);
16
16
  }
17
17
 
18
- const tmpl = document.createElement('template');
18
+ const tmpl = document.createElement("template");
19
19
  tmpl.innerHTML = this.constructor.template;
20
20
  this._root.appendChild(tmpl.content.cloneNode(true));
21
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluentui-webcomponents",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "fully vibe-coded @microsoft/fluentui to get rid of FAST frameworks.",
5
5
  "homepage": "https://github.com/cheese233/fluentui-webcomponents#readme",
6
6
  "bugs": {
@@ -18,7 +18,7 @@ class FluentThemePicker extends HTMLElement {
18
18
  <select id="theme-select" title="Theme">
19
19
  <option value="light">Light</option>
20
20
  <option value="dark">Dark</option>
21
- <option value="system">System</option>
21
+ <option value="system" selected>System</option>
22
22
  </select>
23
23
  Theme
24
24
  </label>
@@ -26,12 +26,31 @@ class FluentThemePicker extends HTMLElement {
26
26
  this.querySelector('#accent-picker').addEventListener('input', e => {
27
27
  document.documentElement.style.setProperty('--accent-base', e.target.value);
28
28
  });
29
- this.querySelector('#theme-select').addEventListener('change', e => {
30
- document.body.classList.remove('light', 'dark');
31
- if (e.target.value !== 'system') {
32
- document.body.classList.add(e.target.value);
29
+ const themeSelect = this.querySelector('#theme-select');
30
+
31
+ const applyTheme = (theme) => {
32
+ const root = document.documentElement;
33
+ if (theme === 'system') {
34
+ root.style.colorScheme = 'light dark';
35
+ } else {
36
+ root.style.colorScheme = theme;
33
37
  }
38
+ };
39
+
40
+ themeSelect.addEventListener('change', e => {
41
+ applyTheme(e.target.value);
34
42
  });
43
+
44
+ if (window.matchMedia) {
45
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
46
+ if (themeSelect.value === 'system') {
47
+ applyTheme('system');
48
+ }
49
+ });
50
+ }
51
+
52
+ // Initialize with the current selection
53
+ applyTheme(themeSelect.value);
35
54
  }
36
55
  }
37
56