fluentui-webcomponents 0.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.
Files changed (59) hide show
  1. package/AGENTS.md +212 -0
  2. package/README.md +99 -0
  3. package/components/avatar/fluent-avatar.css +481 -0
  4. package/components/avatar/fluent-avatar.js +80 -0
  5. package/components/badge/fluent-badge.css +289 -0
  6. package/components/badge/fluent-badge.js +20 -0
  7. package/components/breadcrumb/fluent-breadcrumb.css +29 -0
  8. package/components/breadcrumb/fluent-breadcrumb.js +33 -0
  9. package/components/breadcrumb-item/fluent-breadcrumb-item.css +70 -0
  10. package/components/breadcrumb-item/fluent-breadcrumb-item.js +77 -0
  11. package/components/button/fluent-button.css +265 -0
  12. package/components/button/fluent-button.js +326 -0
  13. package/components/card/fluent-card.css +85 -0
  14. package/components/card/fluent-card.js +21 -0
  15. package/components/checkbox/fluent-checkbox.css +171 -0
  16. package/components/checkbox/fluent-checkbox.js +294 -0
  17. package/components/dialog/fluent-dialog.css +82 -0
  18. package/components/dialog/fluent-dialog.js +137 -0
  19. package/components/divider/fluent-divider.css +124 -0
  20. package/components/divider/fluent-divider.js +14 -0
  21. package/components/image/fluent-image.css +73 -0
  22. package/components/image/fluent-image.js +36 -0
  23. package/components/label/fluent-label.css +49 -0
  24. package/components/label/fluent-label.js +61 -0
  25. package/components/link/fluent-link.css +72 -0
  26. package/components/link/fluent-link.js +109 -0
  27. package/components/menu/fluent-menu.css +57 -0
  28. package/components/menu/fluent-menu.js +202 -0
  29. package/components/menu-item/fluent-menu-item.css +152 -0
  30. package/components/menu-item/fluent-menu-item.js +177 -0
  31. package/components/popover/fluent-popover.css +95 -0
  32. package/components/popover/fluent-popover.js +93 -0
  33. package/components/radio/fluent-radio.css +123 -0
  34. package/components/radio/fluent-radio.js +257 -0
  35. package/components/select/fluent-select.css +194 -0
  36. package/components/select/fluent-select.js +245 -0
  37. package/components/slider/fluent-slider.css +199 -0
  38. package/components/slider/fluent-slider.js +438 -0
  39. package/components/spinner/fluent-spinner.css +160 -0
  40. package/components/spinner/fluent-spinner.js +30 -0
  41. package/components/switch/fluent-switch.css +154 -0
  42. package/components/switch/fluent-switch.js +260 -0
  43. package/components/text/fluent-text.css +128 -0
  44. package/components/text/fluent-text.js +21 -0
  45. package/components/text-input/fluent-text-input.css +227 -0
  46. package/components/text-input/fluent-text-input.js +298 -0
  47. package/components/textarea/fluent-textarea.css +227 -0
  48. package/components/textarea/fluent-textarea.js +400 -0
  49. package/components/tooltip/fluent-tooltip.css +65 -0
  50. package/components/tooltip/fluent-tooltip.js +102 -0
  51. package/components/tree/fluent-tree.css +16 -0
  52. package/components/tree/fluent-tree.js +167 -0
  53. package/components/tree-item/fluent-tree-item.css +147 -0
  54. package/components/tree-item/fluent-tree-item.js +163 -0
  55. package/core/fluent-element.js +34 -0
  56. package/gallery.html +492 -0
  57. package/package.json +19 -0
  58. package/theme/theme-picker.js +38 -0
  59. package/tokens.css +724 -0
@@ -0,0 +1,227 @@
1
+ @import url('../../tokens.css');
2
+
3
+ :host { display: block; }
4
+
5
+ .root {
6
+ --font-size: var(--fontSizeBase300);
7
+ --line-height: var(--lineHeightBase300);
8
+ --padding-inline: var(--spacingHorizontalMNudge);
9
+ --padding-block: var(--spacingVerticalSNudge);
10
+ --min-block-size: 52px;
11
+ --block-size: var(--min-block-size);
12
+ --inline-size: 18rem;
13
+ --border-width: var(--strokeWidthThin);
14
+ --control-padding-inline: var(--spacingHorizontalXXS);
15
+ --color: var(--colorNeutralForeground1);
16
+ --background-color: var(--colorNeutralBackground1);
17
+ --border-color: var(--colorNeutralStroke1);
18
+ --border-block-end-color: var(--colorNeutralStrokeAccessible);
19
+ --placeholder-color: var(--colorNeutralForeground4);
20
+ --focus-indicator-color: var(--colorCompoundBrandStroke);
21
+ --box-shadow: none;
22
+ --contain-size: size;
23
+ --resize: none;
24
+
25
+ color: var(--color);
26
+ font-family: var(--fontFamilyBase);
27
+ font-size: var(--font-size);
28
+ font-weight: var(--fontWeightRegular);
29
+ line-height: var(--line-height);
30
+ background-color: var(--background-color);
31
+ border: var(--border-width) solid var(--border-color);
32
+ border-block-end-color: var(--border-block-end-color);
33
+ border-radius: var(--borderRadiusMedium);
34
+ box-sizing: border-box;
35
+ box-shadow: var(--box-shadow);
36
+ display: grid;
37
+ grid-template: 1fr / 1fr;
38
+ inline-size: var(--inline-size);
39
+ min-block-size: var(--min-block-size);
40
+ block-size: var(--block-size);
41
+ overflow: hidden;
42
+ padding: var(--padding-block) var(--padding-inline);
43
+ position: relative;
44
+ resize: var(--resize);
45
+ }
46
+
47
+ .root::after {
48
+ border-bottom: 2px solid var(--focus-indicator-color);
49
+ border-radius: 0 0 var(--borderRadiusMedium) var(--borderRadiusMedium);
50
+ box-sizing: border-box;
51
+ clip-path: inset(calc(100% - 2px) 1px 0px);
52
+ content: '';
53
+ height: max(2px, var(--borderRadiusMedium));
54
+ inset: auto -1px 0;
55
+ position: absolute;
56
+ transform: scaleX(0);
57
+ transition-delay: var(--curveAccelerateMid);
58
+ transition-duration: var(--durationUltraFast);
59
+ transition-property: transform;
60
+ }
61
+
62
+ .root:hover {
63
+ --border-color: var(--colorNeutralStroke1Hover);
64
+ --border-block-end-color: var(--colorNeutralStrokeAccessibleHover);
65
+ }
66
+
67
+ .root:active {
68
+ --border-color: var(--colorNeutralStroke1Pressed);
69
+ --border-block-end-color: var(--colorNeutralStrokeAccessiblePressed);
70
+ }
71
+
72
+ .root:focus-within {
73
+ outline: none;
74
+ }
75
+
76
+ :host([block]:not([hidden])) .root {
77
+ display: block;
78
+ }
79
+
80
+ :host([size='small']) .root {
81
+ --font-size: var(--fontSizeBase200);
82
+ --line-height: var(--lineHeightBase200);
83
+ --min-block-size: 40px;
84
+ --padding-block: var(--spacingVerticalXS);
85
+ --padding-inline: var(--spacingHorizontalSNudge);
86
+ --control-padding-inline: var(--spacingHorizontalXXS);
87
+ }
88
+
89
+ :host([size='large']) .root {
90
+ --font-size: var(--fontSizeBase400);
91
+ --line-height: var(--lineHeightBase400);
92
+ --min-block-size: 64px;
93
+ --padding-block: var(--spacingVerticalS);
94
+ --padding-inline: var(--spacingHorizontalM);
95
+ --control-padding-inline: var(--spacingHorizontalSNudge);
96
+ }
97
+
98
+ :host([resize='both']:not(:disabled)) .root {
99
+ --resize: both;
100
+ }
101
+
102
+ :host([resize='horizontal']:not(:disabled)) .root {
103
+ --resize: horizontal;
104
+ }
105
+
106
+ :host([resize='vertical']:not(:disabled)) .root {
107
+ --resize: vertical;
108
+ }
109
+
110
+ :host([auto-resize]) .root {
111
+ --block-size: auto;
112
+ --contain-size: inline-size;
113
+ }
114
+
115
+ :host([appearance='filled-darker']) .root {
116
+ --background-color: var(--colorNeutralBackground3);
117
+ --border-color: var(--background-color);
118
+ --border-block-end-color: var(--border-color);
119
+ }
120
+
121
+ :host([appearance='filled-lighter']) .root {
122
+ --border-color: var(--background-color);
123
+ --border-block-end-color: var(--border-color);
124
+ }
125
+
126
+ :host([appearance='filled-darker'][display-shadow]) .root,
127
+ :host([appearance='filled-lighter'][display-shadow]) .root {
128
+ --box-shadow: var(--shadow2);
129
+ }
130
+
131
+ .root.user-invalid {
132
+ --border-color: var(--colorPaletteRedBorder2);
133
+ --border-block-end-color: var(--colorPaletteRedBorder2);
134
+ }
135
+
136
+ .root:disabled {
137
+ --color: var(--colorNeutralForegroundDisabled);
138
+ --background-color: var(--colorTransparentBackground);
139
+ --border-color: var(--colorNeutralStrokeDisabled);
140
+ --border-block-end-color: var(--border-color);
141
+ --box-shadow: none;
142
+ --placeholder-color: var(--colorNeutralForegroundDisabled);
143
+ cursor: no-drop;
144
+ user-select: none;
145
+ }
146
+
147
+ :host([block]) .root {
148
+ inline-size: auto;
149
+ }
150
+
151
+ .root:focus-within::after {
152
+ transform: scaleX(1);
153
+ transition-property: transform;
154
+ transition-duration: var(--durationNormal);
155
+ transition-delay: var(--curveDecelerateMid);
156
+ }
157
+
158
+ :host([readonly]) .root::after,
159
+ .root:disabled::after {
160
+ content: none;
161
+ }
162
+
163
+ label {
164
+ color: var(--color);
165
+ display: flex;
166
+ inline-size: fit-content;
167
+ padding-block-end: var(--spacingVerticalXS);
168
+ padding-inline-end: var(--spacingHorizontalXS);
169
+ }
170
+
171
+ :host(:empty) label,
172
+ label[hidden] {
173
+ display: none;
174
+ }
175
+
176
+ .control {
177
+ appearance: none;
178
+ background-color: transparent;
179
+ border: 0;
180
+ color: inherit;
181
+ field-sizing: content;
182
+ max-block-size: 100%;
183
+ outline: 0;
184
+ resize: none;
185
+ text-align: inherit;
186
+ box-sizing: border-box;
187
+ font: inherit;
188
+ grid-column: 1 / -1;
189
+ grid-row: 1 / -1;
190
+ padding: 0 var(--control-padding-inline);
191
+ }
192
+
193
+ .control:disabled {
194
+ cursor: inherit;
195
+ }
196
+
197
+ .control::placeholder {
198
+ color: var(--placeholder-color);
199
+ }
200
+
201
+ ::selection {
202
+ color: var(--colorNeutralForegroundInverted);
203
+ background-color: var(--colorNeutralBackgroundInverted);
204
+ }
205
+
206
+ @media (forced-colors: active) {
207
+ .root {
208
+ --border-color: FieldText;
209
+ --border-block-end-color: FieldText;
210
+ --focus-indicator-color: Highlight;
211
+ --placeholder-color: FieldText;
212
+ }
213
+
214
+ .root:hover,
215
+ .root:active,
216
+ .root:focus-within {
217
+ --border-color: Highlight;
218
+ --border-block-end-color: Highlight;
219
+ }
220
+
221
+ .root:disabled {
222
+ --color: GrayText;
223
+ --border-color: GrayText;
224
+ --border-block-end-color: GrayText;
225
+ --placeholder-color: GrayText;
226
+ }
227
+ }
@@ -0,0 +1,400 @@
1
+ import { FluentElement } from '../../core/fluent-element.js';
2
+
3
+ const stylesUrl = new URL('./fluent-textarea.css', import.meta.url).href;
4
+
5
+ class FluentTextArea extends FluentElement {
6
+ static stylesUrl = stylesUrl;
7
+ static formAssociated = true;
8
+
9
+ static template = `
10
+ <label for="control" part="label">
11
+ <slot name="label"></slot>
12
+ </label>
13
+ <div class="root" part="root">
14
+ <textarea
15
+ id="control"
16
+ class="control"
17
+ part="control"
18
+ ></textarea>
19
+ </div>
20
+ <div hidden>
21
+ <slot></slot>
22
+ </div>
23
+ `;
24
+
25
+ static get observedAttributes() {
26
+ return [
27
+ 'disabled', 'readonly', 'placeholder', 'value',
28
+ 'appearance', 'size', 'resize', 'rows', 'cols',
29
+ 'maxlength', 'minlength', 'name', 'required',
30
+ 'autocomplete', 'spellcheck', 'block', 'auto-resize',
31
+ 'display-shadow', 'form', 'dirname'
32
+ ];
33
+ }
34
+
35
+ constructor() {
36
+ super();
37
+ this._internals = this.attachInternals();
38
+ this._userInteracted = false;
39
+ this._preConnectEl = document.createElement('textarea');
40
+ this._autoSizerEl = null;
41
+ this._autoSizerObserver = null;
42
+ this._boundHandleInput = this._handleControlInput.bind(this);
43
+ this._boundHandleChange = this._handleControlChange.bind(this);
44
+ this._boundHandleSelect = this._handleControlSelect.bind(this);
45
+ }
46
+
47
+ connectedCallback() {
48
+ super.connectedCallback();
49
+ this._shadowRoot = this._root;
50
+
51
+ requestAnimationFrame(() => {
52
+ if (!this.isConnected) return;
53
+
54
+ const textarea = this._shadowRoot.querySelector('.control');
55
+ if (!textarea) return;
56
+ this._textarea = textarea;
57
+
58
+ const content = this._getContent();
59
+ this._defaultValue = content || this._preConnectEl.defaultValue || '';
60
+ this._textarea.defaultValue = this._defaultValue;
61
+ this._textarea.value = this._preConnectEl.value || this._defaultValue;
62
+
63
+ this._syncAllAttrs();
64
+ this._setFormValue(this._textarea.value);
65
+ this._setValidity();
66
+ this._preConnectEl = null;
67
+
68
+ this._textarea.addEventListener('input', this._boundHandleInput);
69
+ this._textarea.addEventListener('change', this._boundHandleChange);
70
+ this._textarea.addEventListener('select', this._boundHandleSelect);
71
+
72
+ new MutationObserver(() => this._setValidity()).observe(this._textarea, {
73
+ attributes: true,
74
+ attributeFilter: ['disabled', 'required', 'readonly', 'maxlength', 'minlength']
75
+ });
76
+
77
+ this._updateLabelVisibility();
78
+ this._updateResize();
79
+ this._maybeCreateAutoSizer();
80
+ });
81
+ }
82
+
83
+ disconnectedCallback() {
84
+ super.disconnectedCallback();
85
+ this._autoSizerObserver?.disconnect();
86
+ this._autoSizerObserver = null;
87
+ }
88
+
89
+ changed(name, oldVal, newVal) {
90
+ if (!this._textarea) return;
91
+ switch (name) {
92
+ case 'disabled':
93
+ this._textarea.disabled = newVal !== null;
94
+ this._internals.ariaDisabled = newVal !== null ? 'true' : 'false';
95
+ if (this._labelSlottedNodes) {
96
+ this._labelSlottedNodes.forEach(n => n.disabled = newVal !== null);
97
+ }
98
+ break;
99
+ case 'readonly':
100
+ this._textarea.readOnly = newVal !== null;
101
+ this._internals.ariaReadOnly = newVal !== null ? 'true' : 'false';
102
+ this._setValidity();
103
+ break;
104
+ case 'placeholder':
105
+ this._textarea.placeholder = newVal || '';
106
+ break;
107
+ case 'value':
108
+ if (!this._userInteracted) {
109
+ this._textarea.value = newVal || '';
110
+ }
111
+ break;
112
+ case 'resize':
113
+ this._updateResize();
114
+ break;
115
+ case 'required':
116
+ this._textarea.required = newVal !== null;
117
+ this._internals.ariaRequired = newVal !== null ? 'true' : 'false';
118
+ if (this._filteredLabelSlottedNodes) {
119
+ this._filteredLabelSlottedNodes.forEach(n => n.required = newVal !== null);
120
+ }
121
+ break;
122
+ case 'maxlength':
123
+ this._textarea.maxLength = newVal ? parseInt(newVal) : -1;
124
+ break;
125
+ case 'minlength':
126
+ this._textarea.minLength = newVal ? parseInt(newVal) : -1;
127
+ break;
128
+ case 'name':
129
+ this._textarea.name = newVal || '';
130
+ break;
131
+ case 'autocomplete':
132
+ this._textarea.autocomplete = newVal || '';
133
+ break;
134
+ case 'spellcheck':
135
+ this._textarea.spellcheck = newVal !== null;
136
+ break;
137
+ case 'rows':
138
+ this._textarea.rows = newVal ? parseInt(newVal) : 2;
139
+ break;
140
+ case 'cols':
141
+ this._textarea.cols = newVal ? parseInt(newVal) : 20;
142
+ break;
143
+ case 'appearance':
144
+ case 'size':
145
+ case 'block':
146
+ break;
147
+ case 'auto-resize':
148
+ this._maybeCreateAutoSizer();
149
+ break;
150
+ case 'display-shadow':
151
+ case 'dirname':
152
+ break;
153
+ }
154
+ }
155
+
156
+ get value() {
157
+ return this._textarea ? this._textarea.value : (this._preConnectEl ? this._preConnectEl.value : '');
158
+ }
159
+
160
+ set value(val) {
161
+ if (this._textarea) {
162
+ this._textarea.value = val;
163
+ this._setFormValue(val);
164
+ this._setValidity();
165
+ } else if (this._preConnectEl) {
166
+ this._preConnectEl.value = val;
167
+ }
168
+ }
169
+
170
+ get defaultValue() {
171
+ return this._textarea ? this._textarea.defaultValue : (this._preConnectEl ? this._preConnectEl.defaultValue : '');
172
+ }
173
+
174
+ set defaultValue(val) {
175
+ if (this._textarea) {
176
+ this._textarea.defaultValue = val;
177
+ if (!this._userInteracted) this._textarea.value = val;
178
+ } else if (this._preConnectEl) {
179
+ this._preConnectEl.defaultValue = val;
180
+ }
181
+ }
182
+
183
+ get disabled() {
184
+ return this.hasAttribute('disabled');
185
+ }
186
+
187
+ get form() {
188
+ return this._internals.form;
189
+ }
190
+
191
+ get labels() {
192
+ return this._internals.labels;
193
+ }
194
+
195
+ get validity() {
196
+ return this._internals.validity;
197
+ }
198
+
199
+ get validationMessage() {
200
+ return this._internals.validationMessage || (this._textarea ? this._textarea.validationMessage : '');
201
+ }
202
+
203
+ get willValidate() {
204
+ return this._internals.willValidate;
205
+ }
206
+
207
+ get textLength() {
208
+ return this._textarea ? this._textarea.textLength : 0;
209
+ }
210
+
211
+ get type() {
212
+ return 'textarea';
213
+ }
214
+
215
+ checkValidity() {
216
+ return this._internals.checkValidity();
217
+ }
218
+
219
+ reportValidity() {
220
+ return this._internals.reportValidity();
221
+ }
222
+
223
+ setCustomValidity(message) {
224
+ this._internals.setValidity({ customError: !!message }, message || undefined);
225
+ this.reportValidity();
226
+ }
227
+
228
+ select() {
229
+ if (this._textarea) this._textarea.select();
230
+ }
231
+
232
+ _syncAllAttrs() {
233
+ const ta = this._textarea;
234
+ if (!ta) return;
235
+ ta.disabled = this.hasAttribute('disabled');
236
+ ta.readOnly = this.hasAttribute('readonly');
237
+ ta.placeholder = this.getAttribute('placeholder') || '';
238
+ ta.required = this.hasAttribute('required');
239
+ ta.autocomplete = this.getAttribute('autocomplete') || '';
240
+ ta.spellcheck = this.hasAttribute('spellcheck');
241
+ ta.name = this.getAttribute('name') || '';
242
+ const ml = this.getAttribute('maxlength');
243
+ if (ml) ta.maxLength = parseInt(ml);
244
+ const minl = this.getAttribute('minlength');
245
+ if (minl) ta.minLength = parseInt(minl);
246
+ const r = this.getAttribute('rows');
247
+ if (r) ta.rows = parseInt(r);
248
+ const c = this.getAttribute('cols');
249
+ if (c) ta.cols = parseInt(c);
250
+ this._internals.ariaDisabled = this.hasAttribute('disabled') ? 'true' : 'false';
251
+ this._internals.ariaReadOnly = this.hasAttribute('readonly') ? 'true' : 'false';
252
+ this._internals.ariaRequired = this.hasAttribute('required') ? 'true' : 'false';
253
+ }
254
+
255
+ _handleControlInput() {
256
+ this._userInteracted = true;
257
+ if (this._autoSizerEl && this._textarea) {
258
+ this._autoSizerEl.textContent = this._textarea.value + ' ';
259
+ }
260
+ this._setFormValue(this._textarea.value);
261
+ this._setValidity();
262
+ }
263
+
264
+ _handleControlChange() {
265
+ this._toggleUserValidityState();
266
+ this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
267
+ }
268
+
269
+ _handleControlSelect() {
270
+ this.dispatchEvent(new Event('select', { bubbles: true, composed: true }));
271
+ }
272
+
273
+ _getContent() {
274
+ const slot = this._root.querySelector('slot:not([name])');
275
+ if (!slot) return '';
276
+ return slot.assignedNodes().map(node => {
277
+ if (node.nodeType === Node.ELEMENT_NODE) return node.outerHTML;
278
+ if (node.nodeType === Node.TEXT_NODE) return node.textContent.trim();
279
+ return '';
280
+ }).join('');
281
+ }
282
+
283
+ _setFormValue(value) {
284
+ this._internals.setFormValue(value, value);
285
+ }
286
+
287
+ _setValidity() {
288
+ if (!this.isConnected) return;
289
+ if (this.disabled || this.hasAttribute('readonly')) {
290
+ this._internals.setValidity({});
291
+ } else if (this._textarea) {
292
+ const { valid, valueMissing, typeMismatch, patternMismatch, tooLong, tooShort } = this._textarea.validity;
293
+ if (!valid) {
294
+ const msg = this._textarea.validationMessage || 'Invalid value';
295
+ this._internals.setValidity(
296
+ { valueMissing, typeMismatch, patternMismatch, tooLong, tooShort },
297
+ msg,
298
+ this._textarea
299
+ );
300
+ } else {
301
+ this._internals.setValidity({});
302
+ }
303
+ }
304
+ if (this._userInteracted) {
305
+ this._toggleUserValidityState();
306
+ }
307
+ }
308
+
309
+ _toggleUserValidityState() {
310
+ const valid = this._internals.validity.valid;
311
+ if (!valid) {
312
+ this.classList.add('user-invalid');
313
+ this.classList.remove('user-valid');
314
+ } else {
315
+ this.classList.add('user-valid');
316
+ this.classList.remove('user-invalid');
317
+ }
318
+ }
319
+
320
+ _updateLabelVisibility() {
321
+ const label = this._shadowRoot.querySelector('label');
322
+ if (!label) return;
323
+ const labelSlot = this._root.querySelector('slot[name="label"]');
324
+ if (!labelSlot) return;
325
+ const nodes = labelSlot.assignedNodes();
326
+ const hasContent = nodes.some(n =>
327
+ n.nodeType === Node.ELEMENT_NODE ||
328
+ (n.nodeType === Node.TEXT_NODE && n.textContent.trim())
329
+ );
330
+ label.hidden = !hasContent;
331
+ }
332
+
333
+ _updateResize() {
334
+ const ta = this._textarea;
335
+ if (!ta) return;
336
+ const resize = this.getAttribute('resize');
337
+ ta.style.resize = resize || 'none';
338
+ }
339
+
340
+ _maybeCreateAutoSizer() {
341
+ if (CSS.supports('field-sizing: content')) {
342
+ if (this._autoSizerEl) {
343
+ this._autoSizerEl.remove();
344
+ this._autoSizerEl = null;
345
+ }
346
+ return;
347
+ }
348
+
349
+ const autoResize = this.hasAttribute('auto-resize');
350
+ if (!autoResize) {
351
+ if (this._autoSizerEl) {
352
+ this._autoSizerEl.remove();
353
+ this._autoSizerEl = null;
354
+ }
355
+ this._autoSizerObserver?.disconnect();
356
+ return;
357
+ }
358
+
359
+ if (!this._autoSizerEl) {
360
+ this._autoSizerEl = document.createElement('div');
361
+ this._autoSizerEl.classList.add('auto-sizer');
362
+ this._autoSizerEl.setAttribute('aria-hidden', 'true');
363
+ }
364
+
365
+ const root = this._shadowRoot?.querySelector('.root');
366
+ if (root) {
367
+ root.insertBefore(this._autoSizerEl, root.firstChild);
368
+ }
369
+
370
+ if (this._textarea) {
371
+ this._autoSizerEl.textContent = this._textarea.value + ' ';
372
+ }
373
+
374
+ if (!this._autoSizerObserver) {
375
+ this._autoSizerObserver = new ResizeObserver(() => {
376
+ if (this._autoSizerEl && this._textarea) {
377
+ this._autoSizerEl.textContent = this._textarea.value + ' ';
378
+ }
379
+ });
380
+ }
381
+ this._autoSizerObserver.observe(this._textarea);
382
+ }
383
+
384
+ formResetCallback() {
385
+ if (this._textarea) {
386
+ this._textarea.value = this.defaultValue;
387
+ this._userInteracted = false;
388
+ }
389
+ }
390
+
391
+ formDisabledCallback(disabled) {
392
+ if (this._textarea) {
393
+ this._textarea.disabled = disabled;
394
+ }
395
+ this._internals.ariaDisabled = disabled ? 'true' : 'false';
396
+ this._setValidity();
397
+ }
398
+ }
399
+
400
+ customElements.define('fluent-textarea', FluentTextArea);
@@ -0,0 +1,65 @@
1
+ @import url('../../tokens.css');
2
+
3
+ :host(:not(:popover-open)) {
4
+ display: none;
5
+ }
6
+
7
+ :host {
8
+ inset-area: block-start;
9
+ position-try-options: flip-block;
10
+ inset: unset;
11
+ margin: 0;
12
+ width: max-content;
13
+ }
14
+
15
+ .root {
16
+ background: var(--colorNeutralBackground1);
17
+ border-radius: var(--borderRadiusMedium);
18
+ border: var(--strokeWidthThin) solid var(--colorTransparentStroke);
19
+ box-sizing: border-box;
20
+ color: var(--colorNeutralForeground1);
21
+ font-family: var(--fontFamilyBase);
22
+ font-size: var(--fontSizeBase200);
23
+ line-height: var(--lineHeightBase200);
24
+ max-width: 240px;
25
+ padding: 4px var(--spacingHorizontalMNudge) 6px;
26
+ box-shadow: var(--shadow4);
27
+ }
28
+
29
+ :host([positioning='above-start']) { inset-area: block-start span-inline-end; }
30
+ :host([positioning='above']) { inset-area: block-start; }
31
+ :host([positioning='above-end']) { inset-area: block-start span-inline-start; }
32
+ :host([positioning='below-start']) { inset-area: block-end span-inline-end; }
33
+ :host([positioning='below']) { inset-area: block-end; }
34
+ :host([positioning='below-end']) { inset-area: block-end span-inline-start; }
35
+ :host([positioning='before-top']) { inset-area: inline-start span-block-end; }
36
+ :host([positioning='before']) { inset-area: inline-start; }
37
+ :host([positioning='before-bottom']) { inset-area: inline-start span-block-start; }
38
+ :host([positioning='after-top']) { inset-area: inline-end span-block-end; }
39
+ :host([positioning='after']) { inset-area: inline-end; }
40
+ :host([positioning='after-bottom']) { inset-area: inline-end span-block-start; }
41
+
42
+ @supports not (inset-area: block-start) {
43
+ :host {
44
+ position-area: block-start;
45
+ position-try-options: flip-block;
46
+ }
47
+ :host([positioning='above-start']) { position-area: block-start span-inline-end; }
48
+ :host([positioning='above']) { position-area: block-start; }
49
+ :host([positioning='above-end']) { position-area: block-start span-inline-start; }
50
+ :host([positioning='below-start']) { position-area: block-end span-inline-end; }
51
+ :host([positioning='below']) { position-area: block-end; }
52
+ :host([positioning='below-end']) { position-area: block-end span-inline-start; }
53
+ :host([positioning='before-top']) { position-area: inline-start span-block-end; }
54
+ :host([positioning='before']) { position-area: inline-start; }
55
+ :host([positioning='before-bottom']) { position-area: inline-start span-block-start; }
56
+ :host([positioning='after-top']) { position-area: inline-end span-block-end; }
57
+ :host([positioning='after']) { position-area: inline-end; }
58
+ :host([positioning='after-bottom']) { position-area: inline-end span-block-start; }
59
+ }
60
+
61
+ @media (forced-colors: active) {
62
+ .root {
63
+ border-color: ButtonText;
64
+ }
65
+ }