@spfx-fast/sharepoint-ui 0.4.3 → 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.
Files changed (282) hide show
  1. package/QUICKSTART.md +13 -128
  2. package/README.md +19 -26
  3. package/components.json +240 -5834
  4. package/dist/accordion.d.ts +11 -0
  5. package/dist/accordion.js +4 -0
  6. package/dist/alert.d.ts +3 -0
  7. package/dist/alert.js +4 -0
  8. package/dist/attachment-list.d.ts +15 -0
  9. package/dist/attachment-list.js +14 -0
  10. package/dist/avatar-group.d.ts +12 -0
  11. package/dist/avatar-group.js +7 -0
  12. package/dist/avatar.d.ts +6 -0
  13. package/dist/avatar.js +5 -0
  14. package/dist/badge.d.ts +3 -0
  15. package/dist/badge.js +4 -0
  16. package/dist/breadcrumb.d.ts +10 -0
  17. package/dist/breadcrumb.js +9 -0
  18. package/dist/button-group.d.ts +6 -0
  19. package/dist/button-group.js +4 -0
  20. package/dist/button.d.ts +3 -0
  21. package/dist/button.js +4 -0
  22. package/dist/card.d.ts +3 -0
  23. package/dist/card.js +4 -0
  24. package/dist/carousel.d.ts +11 -0
  25. package/dist/carousel.js +6 -0
  26. package/dist/checkbox.d.ts +3 -0
  27. package/dist/checkbox.js +4 -0
  28. package/dist/combobox.d.ts +9 -0
  29. package/dist/combobox.js +6 -0
  30. package/dist/command-bar.d.ts +6 -0
  31. package/dist/command-bar.js +4 -0
  32. package/dist/copy-button.d.ts +7 -0
  33. package/dist/copy-button.js +19 -0
  34. package/dist/data-grid.d.ts +25 -0
  35. package/dist/data-grid.js +39 -0
  36. package/dist/date-range-picker.d.ts +12 -0
  37. package/dist/date-range-picker.js +4 -0
  38. package/dist/dialog.d.ts +9 -0
  39. package/dist/dialog.js +21 -0
  40. package/dist/divider.d.ts +3 -0
  41. package/dist/divider.js +4 -0
  42. package/dist/drawer.d.ts +6 -0
  43. package/dist/drawer.js +5 -0
  44. package/dist/empty-state.d.ts +7 -0
  45. package/dist/empty-state.js +5 -0
  46. package/dist/field.d.ts +15 -0
  47. package/dist/field.js +11 -0
  48. package/dist/file-dropzone.d.ts +15 -0
  49. package/dist/file-dropzone.js +21 -0
  50. package/dist/filter-bar.d.ts +9 -0
  51. package/dist/filter-bar.js +9 -0
  52. package/dist/image.d.ts +5 -0
  53. package/dist/image.js +4 -0
  54. package/dist/index.d.ts +68 -78
  55. package/dist/index.js +60 -68
  56. package/dist/input.d.ts +3 -0
  57. package/dist/input.js +4 -0
  58. package/dist/label.d.ts +3 -0
  59. package/dist/label.js +4 -0
  60. package/dist/link.d.ts +3 -0
  61. package/dist/link.js +9 -0
  62. package/dist/list-view.d.ts +29 -0
  63. package/dist/list-view.js +14 -0
  64. package/dist/list.d.ts +6 -0
  65. package/dist/list.js +5 -0
  66. package/dist/lookup-picker.d.ts +12 -0
  67. package/dist/lookup-picker.js +4 -0
  68. package/dist/menu.d.ts +6 -0
  69. package/dist/menu.js +4 -0
  70. package/dist/nav.d.ts +12 -0
  71. package/dist/nav.js +4 -0
  72. package/dist/pagination.d.ts +11 -0
  73. package/dist/pagination.js +5 -0
  74. package/dist/person-picker.d.ts +13 -0
  75. package/dist/person-picker.js +4 -0
  76. package/dist/persona.d.ts +7 -0
  77. package/dist/persona.js +5 -0
  78. package/dist/popover.d.ts +6 -0
  79. package/dist/popover.js +4 -0
  80. package/dist/progress-bar.d.ts +5 -0
  81. package/dist/progress-bar.js +5 -0
  82. package/dist/radio-group.d.ts +6 -0
  83. package/dist/radio-group.js +4 -0
  84. package/dist/radio.d.ts +3 -0
  85. package/dist/radio.js +4 -0
  86. package/dist/rating.d.ts +8 -0
  87. package/dist/rating.js +5 -0
  88. package/dist/react.d.ts +1 -4715
  89. package/dist/react.js +1 -7097
  90. package/dist/select.d.ts +3 -0
  91. package/dist/select.js +4 -0
  92. package/dist/sharepoint-field.d.ts +18 -0
  93. package/dist/sharepoint-field.js +54 -0
  94. package/dist/skeleton.d.ts +6 -0
  95. package/dist/skeleton.js +9 -0
  96. package/dist/spinner.d.ts +5 -0
  97. package/dist/spinner.js +4 -0
  98. package/dist/swatch-picker.d.ts +17 -0
  99. package/dist/swatch-picker.js +11 -0
  100. package/dist/switch.d.ts +3 -0
  101. package/dist/switch.js +4 -0
  102. package/dist/table.d.ts +6 -0
  103. package/dist/table.js +4 -0
  104. package/dist/tabs.d.ts +14 -0
  105. package/dist/tabs.js +30 -0
  106. package/dist/tag-group.d.ts +6 -0
  107. package/dist/tag-group.js +4 -0
  108. package/dist/tag-picker.d.ts +12 -0
  109. package/dist/tag-picker.js +4 -0
  110. package/dist/tag.d.ts +7 -0
  111. package/dist/tag.js +5 -0
  112. package/dist/text.d.ts +5 -0
  113. package/dist/text.js +4 -0
  114. package/dist/textarea.d.ts +3 -0
  115. package/dist/textarea.js +4 -0
  116. package/dist/theme.d.ts +15 -175
  117. package/dist/theme.js +36 -239
  118. package/dist/toast.d.ts +9 -0
  119. package/dist/toast.js +12 -0
  120. package/dist/tree.d.ts +13 -0
  121. package/dist/tree.js +9 -0
  122. package/dist/view-card.d.ts +8 -0
  123. package/dist/view-card.js +4 -0
  124. package/dist/view-switcher.d.ts +13 -0
  125. package/dist/view-switcher.js +7 -0
  126. package/dist/virtual-list.d.ts +11 -0
  127. package/dist/virtual-list.js +25 -0
  128. package/measurements.json +365 -0
  129. package/package.json +14 -46
  130. package/src/theme.css +125 -0
  131. package/AGENTS.md +0 -231
  132. package/dist/appearance.d.ts +0 -6
  133. package/dist/appearance.js +0 -217
  134. package/dist/elements/accordion.d.ts +0 -9
  135. package/dist/elements/accordion.js +0 -338
  136. package/dist/elements/alert.d.ts +0 -2
  137. package/dist/elements/alert.js +0 -86
  138. package/dist/elements/avatar-group-primitives.d.ts +0 -3
  139. package/dist/elements/avatar-group-primitives.js +0 -189
  140. package/dist/elements/avatar-group.d.ts +0 -2
  141. package/dist/elements/avatar-group.js +0 -110
  142. package/dist/elements/avatar.d.ts +0 -4
  143. package/dist/elements/avatar.js +0 -251
  144. package/dist/elements/badge.d.ts +0 -8
  145. package/dist/elements/badge.js +0 -182
  146. package/dist/elements/breadcrumb.d.ts +0 -4
  147. package/dist/elements/breadcrumb.js +0 -233
  148. package/dist/elements/button-group.d.ts +0 -1
  149. package/dist/elements/button-group.js +0 -20
  150. package/dist/elements/button-variants.d.ts +0 -6
  151. package/dist/elements/button-variants.js +0 -339
  152. package/dist/elements/button.d.ts +0 -5
  153. package/dist/elements/button.js +0 -233
  154. package/dist/elements/card-primitives.d.ts +0 -3
  155. package/dist/elements/card-primitives.js +0 -83
  156. package/dist/elements/card.d.ts +0 -5
  157. package/dist/elements/card.js +0 -213
  158. package/dist/elements/carousel.d.ts +0 -92
  159. package/dist/elements/carousel.js +0 -1115
  160. package/dist/elements/color-picker.d.ts +0 -24
  161. package/dist/elements/color-picker.js +0 -1004
  162. package/dist/elements/combobox.d.ts +0 -1
  163. package/dist/elements/combobox.js +0 -1012
  164. package/dist/elements/data-grid-model.d.ts +0 -120
  165. package/dist/elements/data-grid-model.js +0 -294
  166. package/dist/elements/data-grid.d.ts +0 -30
  167. package/dist/elements/data-grid.js +0 -1576
  168. package/dist/elements/date-picker.d.ts +0 -1
  169. package/dist/elements/date-picker.js +0 -486
  170. package/dist/elements/dialog.d.ts +0 -23
  171. package/dist/elements/dialog.js +0 -409
  172. package/dist/elements/divider.d.ts +0 -2
  173. package/dist/elements/divider.js +0 -66
  174. package/dist/elements/drawer.d.ts +0 -3
  175. package/dist/elements/drawer.js +0 -308
  176. package/dist/elements/field-composition.d.ts +0 -26
  177. package/dist/elements/field-composition.js +0 -133
  178. package/dist/elements/field.d.ts +0 -1
  179. package/dist/elements/field.js +0 -67
  180. package/dist/elements/file-upload.d.ts +0 -6
  181. package/dist/elements/file-upload.js +0 -211
  182. package/dist/elements/floating-position.d.ts +0 -36
  183. package/dist/elements/floating-position.js +0 -92
  184. package/dist/elements/image.d.ts +0 -28
  185. package/dist/elements/image.js +0 -38
  186. package/dist/elements/info.d.ts +0 -9
  187. package/dist/elements/info.js +0 -102
  188. package/dist/elements/input.d.ts +0 -5
  189. package/dist/elements/input.js +0 -255
  190. package/dist/elements/label.d.ts +0 -15
  191. package/dist/elements/label.js +0 -56
  192. package/dist/elements/link.d.ts +0 -1
  193. package/dist/elements/link.js +0 -92
  194. package/dist/elements/list.d.ts +0 -19
  195. package/dist/elements/list.js +0 -297
  196. package/dist/elements/menu.d.ts +0 -33
  197. package/dist/elements/menu.js +0 -1103
  198. package/dist/elements/message-bar.d.ts +0 -10
  199. package/dist/elements/message-bar.js +0 -327
  200. package/dist/elements/nav.d.ts +0 -32
  201. package/dist/elements/nav.js +0 -794
  202. package/dist/elements/overflow.d.ts +0 -10
  203. package/dist/elements/overflow.js +0 -218
  204. package/dist/elements/persona.d.ts +0 -3
  205. package/dist/elements/persona.js +0 -125
  206. package/dist/elements/popover.d.ts +0 -77
  207. package/dist/elements/popover.js +0 -840
  208. package/dist/elements/progress-bar.d.ts +0 -4
  209. package/dist/elements/progress-bar.js +0 -82
  210. package/dist/elements/radio-group.d.ts +0 -1
  211. package/dist/elements/radio-group.js +0 -303
  212. package/dist/elements/rating-display.d.ts +0 -2
  213. package/dist/elements/rating-display.js +0 -125
  214. package/dist/elements/rating.d.ts +0 -2
  215. package/dist/elements/rating.js +0 -206
  216. package/dist/elements/rich-text-editor.d.ts +0 -32
  217. package/dist/elements/rich-text-editor.js +0 -1367
  218. package/dist/elements/search.d.ts +0 -3
  219. package/dist/elements/search.js +0 -200
  220. package/dist/elements/select.d.ts +0 -6
  221. package/dist/elements/select.js +0 -291
  222. package/dist/elements/shared.d.ts +0 -22
  223. package/dist/elements/shared.js +0 -409
  224. package/dist/elements/sharepoint-field-basic-controls.d.ts +0 -1
  225. package/dist/elements/sharepoint-field-basic-controls.js +0 -14
  226. package/dist/elements/sharepoint-fields.d.ts +0 -29
  227. package/dist/elements/sharepoint-fields.js +0 -460
  228. package/dist/elements/skeleton.d.ts +0 -6
  229. package/dist/elements/skeleton.js +0 -91
  230. package/dist/elements/slider.d.ts +0 -1
  231. package/dist/elements/slider.js +0 -248
  232. package/dist/elements/spin-button.d.ts +0 -7
  233. package/dist/elements/spin-button.js +0 -499
  234. package/dist/elements/spinner.d.ts +0 -4
  235. package/dist/elements/spinner.js +0 -124
  236. package/dist/elements/swatch-picker.d.ts +0 -5
  237. package/dist/elements/swatch-picker.js +0 -363
  238. package/dist/elements/table.d.ts +0 -21
  239. package/dist/elements/table.js +0 -261
  240. package/dist/elements/tabs.d.ts +0 -1
  241. package/dist/elements/tabs.js +0 -276
  242. package/dist/elements/tag-picker.d.ts +0 -29
  243. package/dist/elements/tag-picker.js +0 -715
  244. package/dist/elements/tags.d.ts +0 -21
  245. package/dist/elements/tags.js +0 -421
  246. package/dist/elements/teaching-popover.d.ts +0 -32
  247. package/dist/elements/teaching-popover.js +0 -412
  248. package/dist/elements/text.d.ts +0 -9
  249. package/dist/elements/text.js +0 -75
  250. package/dist/elements/textarea.d.ts +0 -1
  251. package/dist/elements/textarea.js +0 -182
  252. package/dist/elements/toast.d.ts +0 -25
  253. package/dist/elements/toast.js +0 -337
  254. package/dist/elements/toaster.d.ts +0 -6
  255. package/dist/elements/toaster.js +0 -357
  256. package/dist/elements/toggle.d.ts +0 -2
  257. package/dist/elements/toggle.js +0 -246
  258. package/dist/elements/toolbar.d.ts +0 -12
  259. package/dist/elements/toolbar.js +0 -381
  260. package/dist/elements/tooltip.d.ts +0 -76
  261. package/dist/elements/tooltip.js +0 -527
  262. package/dist/elements/tree-model.d.ts +0 -19
  263. package/dist/elements/tree-model.js +0 -34
  264. package/dist/elements/tree.d.ts +0 -5
  265. package/dist/elements/tree.js +0 -273
  266. package/dist/elements/view-card.d.ts +0 -2
  267. package/dist/elements/view-card.js +0 -78
  268. package/dist/elements/virtual-list.d.ts +0 -41
  269. package/dist/elements/virtual-list.js +0 -369
  270. package/dist/elements.d.ts +0 -73
  271. package/dist/elements.js +0 -210
  272. package/dist/sharepoint-fields.d.ts +0 -135
  273. package/dist/sharepoint-fields.js +0 -402
  274. package/dist/virtualizer-hooks.d.ts +0 -80
  275. package/dist/virtualizer-hooks.js +0 -253
  276. package/scripts/generate-token-index.mjs +0 -43
  277. package/scripts/sync-component-catalog-signatures.mjs +0 -55
  278. package/scripts/validate-component-catalog.mjs +0 -44
  279. package/skills/sharepoint-ui/SKILL.md +0 -12
  280. package/skills/sharepoint-ui/references/choosing-components.md +0 -20
  281. package/skills/sharepoint-ui/references/sharepoint-patterns.md +0 -17
  282. package/tokens.json +0 -3777
@@ -1,255 +0,0 @@
1
- import { base, rememberNativeFormControlDefaults, stopHostAccessibleNameSync, syncHostAccessibleName } from "./shared.js";
2
- /** Bare, form-associated input; pair it with Label or Field for an accessible name. */
3
- export function defineInput() {
4
- if (customElements.get("spui-input"))
5
- return;
6
- class SpuiInput extends HTMLElement {
7
- static formAssociated = true;
8
- static observedAttributes = ["value", "type", "placeholder", "disabled", "required", "read-only", "name", "size", "appearance", "autocomplete", "inputmode", "min", "max", "step", "minlength", "maxlength", "pattern", "multiple", "accept", "alt", "capture", "checked", "default-checked", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "height", "list", "src", "width", "aria-label", "aria-labelledby", "aria-description", "aria-describedby", "aria-invalid"];
9
- internals;
10
- currentValue = "";
11
- dirty = false;
12
- formDisabled = false;
13
- customError = "";
14
- boundInput;
15
- slotInputDefaults;
16
- handleInput = (event) => {
17
- const input = this.input();
18
- if (!input)
19
- return;
20
- this.currentValue = input.value;
21
- this.dirty = true;
22
- this.syncForm(input);
23
- this.dispatchEvent(new CustomEvent("spui-input", { detail: { value: input.value, checked: input.checked, sourceEvent: event }, bubbles: true, composed: true }));
24
- };
25
- handleChange = () => {
26
- const input = this.input();
27
- if (input)
28
- this.dispatchEvent(new CustomEvent("spui-change", { detail: { value: input.value }, bubbles: true, composed: true }));
29
- };
30
- constructor() {
31
- super();
32
- try {
33
- this.internals = this.attachInternals();
34
- }
35
- catch { /* Native input remains usable where form-associated custom elements are unavailable. */ }
36
- }
37
- get value() { return this.input()?.value ?? this.currentValue; }
38
- set value(value) { this.currentValue = String(value ?? ""); this.dirty = true; const input = this.input(); if (input && (input.type !== "file" || !this.currentValue))
39
- input.value = this.currentValue; this.syncForm(input); }
40
- get defaultValue() { return this.getAttribute("value") ?? this.input()?.defaultValue ?? ""; }
41
- set defaultValue(value) { this.setAttribute("value", String(value ?? "")); }
42
- get name() { return this.getAttribute("name") ?? ""; }
43
- set name(value) { this.setAttribute("name", value); }
44
- get type() { return this.input()?.type ?? this.getAttribute("type") ?? "text"; }
45
- set type(value) { this.setAttribute("type", value); }
46
- get checked() { return Boolean(this.input()?.checked); }
47
- set checked(value) { const input = this.input(); if (input)
48
- input.checked = Boolean(value);
49
- else
50
- this.toggleAttribute("checked", Boolean(value)); this.syncForm(input); }
51
- get disabled() { return this.hasAttribute("disabled"); }
52
- set disabled(value) { this.toggleAttribute("disabled", Boolean(value)); }
53
- get required() { return this.hasAttribute("required"); }
54
- set required(value) { this.toggleAttribute("required", Boolean(value)); }
55
- get readOnly() { return this.hasAttribute("read-only"); }
56
- set readOnly(value) { this.toggleAttribute("read-only", Boolean(value)); }
57
- get form() { return this.internals?.form ?? null; }
58
- get validity() { return this.internals?.validity ?? this.input()?.validity; }
59
- get validationMessage() { return this.internals?.validationMessage ?? this.input()?.validationMessage ?? ""; }
60
- get willValidate() { return this.internals?.willValidate ?? Boolean(this.input() && !this.input().disabled && !this.input().readOnly); }
61
- connectedCallback() {
62
- if (!this.shadowRoot)
63
- this.render();
64
- const input = this.input();
65
- if (!input)
66
- return;
67
- if (!this.dirty) {
68
- if (this.hasAttribute("value")) {
69
- this.currentValue = this.defaultValue;
70
- if (input.type !== "file")
71
- input.value = this.currentValue;
72
- }
73
- else
74
- this.currentValue = input.type === "file" ? "" : input.value;
75
- }
76
- this.syncForm(input);
77
- }
78
- disconnectedCallback() { stopHostAccessibleNameSync(this); }
79
- attributeChangedCallback(name, _oldValue, value) {
80
- if (!this.isConnected || !this.shadowRoot)
81
- return;
82
- const input = this.input();
83
- if (!input)
84
- return;
85
- if (name === "value") {
86
- if (!this.dirty && input.type !== "file") {
87
- this.currentValue = value ?? "";
88
- input.value = this.currentValue;
89
- this.syncForm(input);
90
- }
91
- return;
92
- }
93
- if (name === "size" || name === "appearance")
94
- this.shadowRoot.querySelector(".control").dataset[name] = value || (name === "size" ? "medium" : "outline");
95
- else if (name === "type") {
96
- try {
97
- input.type = value || "text";
98
- }
99
- catch {
100
- input.type = "text";
101
- }
102
- }
103
- else if (name === "checked")
104
- input.checked = value !== null || (!this.dirty && Boolean(this.slotInputDefaults?.checked));
105
- else if (name === "default-checked") {
106
- input.defaultChecked = value !== null || Boolean(this.slotInputDefaults?.defaultChecked);
107
- if (!this.dirty)
108
- input.checked = value !== null || Boolean(this.slotInputDefaults?.checked);
109
- }
110
- else if (["placeholder", "autocomplete", "inputmode", "min", "max", "step", "minlength", "maxlength", "pattern", "multiple"].includes(name)) {
111
- const target = name === "read-only" ? "readonly" : name;
112
- if (value === null)
113
- input.removeAttribute(target);
114
- else
115
- input.setAttribute(target, value);
116
- }
117
- else if (["accept", "alt", "capture", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "height", "list", "src", "width"].includes(name)) {
118
- if (value === null)
119
- input.removeAttribute(name);
120
- else
121
- input.setAttribute(name, value);
122
- }
123
- else if (["aria-label", "aria-labelledby", "aria-description", "aria-describedby", "aria-invalid"].includes(name)) {
124
- if (value === null)
125
- input.removeAttribute(name);
126
- else
127
- input.setAttribute(name, value);
128
- }
129
- this.syncInputSlot();
130
- }
131
- formDisabledCallback(disabled) { this.formDisabled = disabled; this.syncInputSlot(); }
132
- formResetCallback() { this.dirty = false; const input = this.input(); this.currentValue = input?.type === "file" ? "" : this.defaultValue; if (input) {
133
- input.value = this.currentValue;
134
- input.checked = input.defaultChecked;
135
- this.syncForm(input);
136
- } }
137
- formStateRestoreCallback(state) { if (typeof state === "string")
138
- this.value = state; }
139
- focus(options) { this.input()?.focus(options); }
140
- select() { this.input()?.select(); }
141
- checkValidity() { return this.internals?.checkValidity() ?? this.input()?.checkValidity() ?? true; }
142
- reportValidity() { return this.internals?.reportValidity() ?? this.input()?.reportValidity() ?? true; }
143
- setCustomValidity(message) { this.customError = message; this.syncForm(this.input()); }
144
- input() {
145
- const slotted = Array.from(this.children).find((element) => element instanceof HTMLInputElement && element.slot === "input");
146
- return slotted ?? this.shadowRoot?.querySelector(".input-fallback") ?? undefined;
147
- }
148
- syncInputSlot() {
149
- const input = this.input();
150
- if (!input)
151
- return;
152
- const fallback = this.shadowRoot?.querySelector(".input-fallback");
153
- if (fallback)
154
- fallback.hidden = input !== fallback;
155
- if (input !== fallback)
156
- this.slotInputDefaults = rememberNativeFormControlDefaults(this.slotInputDefaults, input);
157
- if (this.boundInput !== input) {
158
- this.boundInput?.removeEventListener("input", this.handleInput);
159
- this.boundInput?.removeEventListener("change", this.handleChange);
160
- input.addEventListener("input", this.handleInput);
161
- input.addEventListener("change", this.handleChange);
162
- this.boundInput = input;
163
- }
164
- if (this.hasAttribute("name"))
165
- input.removeAttribute("name");
166
- for (const name of ["type", "placeholder", "autocomplete", "inputmode", "min", "max", "step", "minlength", "maxlength", "pattern", "multiple", "accept", "alt", "capture", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "height", "list", "src", "width", "aria-label", "aria-labelledby", "aria-description", "aria-describedby", "aria-invalid"]) {
167
- if (input.hasAttribute(name))
168
- continue;
169
- const value = this.getAttribute(name);
170
- if (value !== null)
171
- input.setAttribute(name, value);
172
- }
173
- const defaults = input === fallback ? undefined : this.slotInputDefaults;
174
- input.disabled = this.disabled || this.formDisabled || Boolean(defaults?.disabled);
175
- input.required = this.required || Boolean(defaults?.required);
176
- input.readOnly = this.readOnly || Boolean(defaults?.readOnly);
177
- if (this.hasAttribute("default-checked"))
178
- input.defaultChecked = true;
179
- if (this.hasAttribute("checked"))
180
- input.checked = true;
181
- if (!this.dirty && input.type !== "file" && this.hasAttribute("value"))
182
- input.value = this.currentValue || this.defaultValue;
183
- syncHostAccessibleName(this, input);
184
- this.syncForm(input);
185
- }
186
- syncForm(input) {
187
- if (!input)
188
- return;
189
- let value = input.disabled || this.formDisabled || ((input.type === "checkbox" || input.type === "radio") && !input.checked) ? null : input.value;
190
- if (input.type === "file") {
191
- value = null;
192
- const files = input.disabled || this.formDisabled ? null : input.files;
193
- if (files?.length && this.name) {
194
- const formData = new FormData();
195
- for (const file of Array.from(files))
196
- formData.append(this.name, file);
197
- value = formData;
198
- }
199
- }
200
- this.internals?.setFormValue(value, input.type === "file" ? null : input.value);
201
- const v = input.validity;
202
- const flags = { badInput: v.badInput, patternMismatch: v.patternMismatch, rangeOverflow: v.rangeOverflow, rangeUnderflow: v.rangeUnderflow, stepMismatch: v.stepMismatch, tooLong: v.tooLong, tooShort: v.tooShort, typeMismatch: v.typeMismatch, valueMissing: v.valueMissing, customError: Boolean(this.customError) };
203
- const message = this.customError || input.validationMessage;
204
- try {
205
- this.internals?.setValidity(input.validity.valid && !this.customError ? {} : flags, message, input);
206
- }
207
- catch { /* Native validation remains available inside the shadow root. */ }
208
- }
209
- render() {
210
- const shadow = this.attachShadow({ mode: "open" });
211
- const style = document.createElement("style");
212
- style.textContent = `${base}:host{display:inline-block;min-width:0;vertical-align:middle}.control{box-sizing:border-box;display:flex;align-items:center;gap:var(--spui-input-content-gap,8px);min-width:0;width:100%;border:1px solid var(--spui-input-border,var(--spui-control-border,var(--spui-ui-stroke,var(--spui-semantic-input-border,#8a8886))));border-radius:var(--spui-input-radius,var(--spui-control-radius,4px));background:var(--spui-input-background,var(--spui-control-background,var(--spui-ui-surface,var(--spui-semantic-input-background,#fff))));box-shadow:var(--spui-input-shadow,var(--spui-control-shadow,none));color:var(--spui-ui-text,var(--spui-semantic-body-text,inherit));font-family:var(--spui-font-family,inherit);font-size:var(--fontSizeBase200,14px);transition:border-color var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1)),box-shadow var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1))}.control:focus-within{border-color:var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));box-shadow:none}.control:has(input[aria-invalid]:not([aria-invalid=false])){border-color:var(--spui-input-invalid-border,var(--spui-ui-danger,var(--colorPaletteRedBorder2,#c50f1f)))}.control[data-size=small]{min-height:24px;font-size:var(--fontSizeBase100,12px)}.control[data-size=medium]{min-height:32px}.control[data-size=large]{min-height:40px;font-size:var(--fontSizeBase200,14px)}.control[data-appearance=underline]{border-width:0 0 1px;border-radius:0;box-shadow:none}.control[data-appearance=underline]:focus-within{border-width:0 0 1px}.control[data-appearance=filled-darker],.control[data-appearance=filled-darker-shadow]{background:var(--spui-input-filled-darker,var(--spui-ui-surface-hover,var(--colorNeutralBackground3,#f0f0f0)));border-color:transparent}.control[data-appearance=filled-lighter],.control[data-appearance=filled-lighter-shadow]{background:var(--spui-input-filled-lighter,var(--spui-ui-canvas,var(--colorNeutralBackground1,#fafafa)));border-color:transparent}.control[data-appearance=filled-darker-shadow],.control[data-appearance=filled-lighter-shadow]{box-shadow:var(--spui-input-filled-shadow,var(--shadow2,0 1px 2px rgb(0 0 0 / 20%)))}input{box-sizing:border-box;flex:1;min-width:0;width:100%;height:100%;padding-inline:var(--spui-input-padding-inline,var(--spui-control-padding-inline,12px));border:0!important;outline:0!important;box-shadow:none!important;background:transparent;color:inherit;font:var(--spui-input-font,var(--spui-font-family,inherit));font-size:inherit}input:focus-visible{outline:0!important;outline-offset:0;box-shadow:none!important}input::placeholder{color:var(--spui-ui-muted,var(--spui-semantic-body-subtext,#616161));opacity:1}input:disabled{cursor:not-allowed;opacity:.55}.control:has(input:disabled){opacity:.65}slot[name=before],slot[name=after]{display:inline-flex;align-items:center;flex:none;color:var(--spui-input-content-color,var(--spui-ui-muted,var(--spui-semantic-body-subtext,#616161)))}slot[name=before]{padding-inline-start:12px}slot[name=after]{padding-inline-end:12px}:host([data-spui-appearance=glass]) .control,:host-context([data-spui-appearance=glass]) .control{backdrop-filter:blur(12px) saturate(1.2)}@media(prefers-reduced-motion:reduce){.control{transition:none}}@media(forced-colors:active){.control{border-color:FieldText;background:Field;color:FieldText}.control:focus-within{border:1px solid Highlight;outline:0;box-shadow:none}.control:has(input[aria-invalid]:not([aria-invalid=false])){border-color:CanvasText}.control:has(input[aria-invalid]:not([aria-invalid=false])):focus-within{border-color:Highlight}.control[data-appearance=underline]:focus-within{border-width:0 0 1px}input::placeholder{color:GrayText}}`;
213
- style.textContent += `slot[name=input]{display:contents}slot[name=input]::slotted(input){box-sizing:border-box;flex:1;min-width:0;width:100%;height:100%;padding-inline:var(--spui-input-padding-inline,var(--spui-control-padding-inline,12px));border:0!important;outline:0!important;box-shadow:none!important;background:transparent;color:inherit;font:var(--spui-input-font,var(--spui-font-family,inherit));font-size:inherit}slot[name=input]::slotted(input:focus-visible){border:0!important;outline:0!important;outline-offset:0;box-shadow:none!important}slot[name=input]::slotted(input:disabled){cursor:not-allowed;opacity:.55}`;
214
- style.textContent += `input[type=checkbox],input[type=radio],slot[name=input]::slotted(input[type=checkbox]),slot[name=input]::slotted(input[type=radio]){box-sizing:border-box;flex:none;width:16px;height:16px;padding:0}`;
215
- const control = document.createElement("div");
216
- control.className = "control";
217
- control.part.add("control");
218
- control.dataset.size = this.getAttribute("size") || "medium";
219
- control.dataset.appearance = this.getAttribute("appearance") || "outline";
220
- const before = document.createElement("slot");
221
- before.name = "before";
222
- before.setAttribute("aria-hidden", "true");
223
- const input = document.createElement("input");
224
- input.className = "input-fallback";
225
- input.type = this.getAttribute("type") || "text";
226
- if (input.type !== "file")
227
- input.value = this.defaultValue;
228
- input.placeholder = this.getAttribute("placeholder") || "";
229
- input.disabled = this.disabled || this.formDisabled;
230
- input.required = this.required;
231
- input.readOnly = this.readOnly;
232
- input.part.add("input");
233
- for (const name of ["autocomplete", "inputmode", "min", "max", "step", "minlength", "maxlength", "pattern", "accept", "alt", "capture", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "height", "list", "src", "width", "aria-label", "aria-labelledby", "aria-description", "aria-describedby", "aria-invalid"]) {
234
- const value = this.getAttribute(name);
235
- if (value !== null)
236
- input.setAttribute(name, value);
237
- }
238
- if (this.hasAttribute("multiple"))
239
- input.multiple = true;
240
- input.defaultChecked = this.hasAttribute("default-checked");
241
- input.checked = this.hasAttribute("checked") || input.defaultChecked;
242
- const inputSlot = document.createElement("slot");
243
- inputSlot.name = "input";
244
- inputSlot.part.add("input");
245
- inputSlot.addEventListener("slotchange", () => this.syncInputSlot());
246
- const after = document.createElement("slot");
247
- after.name = "after";
248
- after.setAttribute("aria-hidden", "true");
249
- control.append(before, input, inputSlot, after);
250
- shadow.append(style, control);
251
- this.syncInputSlot();
252
- }
253
- }
254
- customElements.define("spui-input", SpuiInput);
255
- }
@@ -1,15 +0,0 @@
1
- export type LabelSize = "small" | "medium" | "large";
2
- export type LabelWeight = "regular" | "semibold";
3
- export type LabelOptions = {
4
- htmlFor?: string;
5
- size?: LabelSize;
6
- weight?: LabelWeight;
7
- required?: boolean | string | Node;
8
- disabled?: boolean;
9
- id?: string;
10
- title?: string;
11
- };
12
- export declare function ensureLabelStyles(document: Document): void;
13
- export declare function getLabelStyle(size?: LabelSize, disabled?: boolean, weight?: LabelWeight): Record<string, string | number>;
14
- /** Create a real native label so `for` association and click-to-focus work across frameworks. */
15
- export declare function createLabel(content: string | Node, options?: LabelOptions): HTMLLabelElement;
@@ -1,56 +0,0 @@
1
- const styledDocuments = new WeakSet();
2
- export function ensureLabelStyles(document) {
3
- if (styledDocuments.has(document))
4
- return;
5
- if (document.querySelector("style[data-spui-label-styles]")) {
6
- styledDocuments.add(document);
7
- return;
8
- }
9
- const style = document.createElement("style");
10
- style.dataset.spuiLabelStyles = "";
11
- style.textContent = "@media(forced-colors:active){.spui-label[data-disabled=true],.spui-label[data-disabled=true] .spui-label-required{color:GrayText!important}}";
12
- (document.head ?? document.documentElement).append(style);
13
- styledDocuments.add(document);
14
- }
15
- const sizes = {
16
- small: ["200", "12px", "16px"], medium: ["300", "14px", "20px"], large: ["400", "16px", "22px"],
17
- };
18
- export function getLabelStyle(size = "medium", disabled = false, weight = "regular") {
19
- const [token, fallback, line] = sizes[size];
20
- return {
21
- display: "inline-flex", alignItems: "baseline", gap: "0.25em",
22
- fontFamily: "var(--spui-font-family,var(--fontFamilyBase,inherit))", fontSize: `var(--fontSizeBase${token},${fallback})`,
23
- fontWeight: weight === "semibold" || size === "large" ? "var(--fontWeightSemibold,600)" : "var(--fontWeightRegular,400)", lineHeight: `var(--lineHeightBase${token},${line})`, cursor: disabled ? "default" : "pointer",
24
- color: disabled ? "var(--spui-ui-foreground-disabled,var(--spui-semantic-disabled-text,var(--colorNeutralForegroundDisabled,#bdbdbd)))" : "var(--spui-ui-text,var(--spui-semantic-body-text,inherit))",
25
- };
26
- }
27
- /** Create a real native label so `for` association and click-to-focus work across frameworks. */
28
- export function createLabel(content, options = {}) {
29
- const label = document.createElement("label");
30
- ensureLabelStyles(label.ownerDocument);
31
- label.className = "spui-label";
32
- if (options.htmlFor)
33
- label.htmlFor = options.htmlFor;
34
- if (options.id)
35
- label.id = options.id;
36
- if (options.title)
37
- label.title = options.title;
38
- label.dataset.size = options.size ?? "medium";
39
- label.dataset.disabled = String(Boolean(options.disabled));
40
- Object.assign(label.style, getLabelStyle(options.size, options.disabled, options.weight));
41
- label.append(typeof content === "string" ? document.createTextNode(content) : content);
42
- if (options.required) {
43
- const marker = document.createElement("span");
44
- marker.className = "spui-label-required";
45
- marker.setAttribute("aria-hidden", "true");
46
- if (options.required === true)
47
- marker.textContent = "*";
48
- else if (typeof options.required === "string")
49
- marker.textContent = options.required;
50
- else
51
- marker.append(options.required);
52
- Object.assign(marker.style, { color: options.disabled ? "var(--spui-ui-foreground-disabled,var(--spui-semantic-disabled-text,var(--colorNeutralForegroundDisabled,#bdbdbd)))" : "var(--spui-label-required-color,var(--colorPaletteRedForeground3,var(--spui-semantic-error-text,#c50f1f)))", paddingInlineStart: "var(--spui-label-required-gap,var(--spacingHorizontalXS,4px))" });
53
- label.append(marker);
54
- }
55
- return label;
56
- }
@@ -1 +0,0 @@
1
- export declare function defineLink(): void;
@@ -1,92 +0,0 @@
1
- import { base } from "./shared.js";
2
- const forwarded = ["href", "target", "rel", "download", "hreflang", "referrerpolicy", "title", "type", "media", "ping", "role", "aria-label", "aria-describedby", "aria-current", "tabindex"];
3
- const unsafeSchemes = /^(?:javascript|data|vbscript):/i;
4
- export function defineLink() {
5
- if (customElements.get("spui-link"))
6
- return;
7
- class SpuiLink extends HTMLElement {
8
- static observedAttributes = [...forwarded, "disabled", "disabled-focusable", "appearance", "underline", "inline", "as"];
9
- connectedCallback() { if (!this.shadowRoot)
10
- this.render(); this.sync(); }
11
- attributeChangedCallback() { if (this.isConnected)
12
- this.sync(); }
13
- sync() {
14
- const root = this.shadowRoot?.querySelector("a,button,span");
15
- if (!root)
16
- return;
17
- const href = this.getAttribute("href")?.trim() ?? "";
18
- const as = this.getAttribute("as") || (href ? "a" : "button");
19
- if (root.localName !== as) {
20
- this.renderRoot(as);
21
- return;
22
- }
23
- for (const name of forwarded) {
24
- const value = this.getAttribute(name);
25
- if (value === null)
26
- root.removeAttribute(name);
27
- else
28
- root.setAttribute(name, value);
29
- }
30
- if (as !== "a")
31
- root.removeAttribute("href");
32
- const disabled = this.hasAttribute("disabled") || (as === "a" && (!href || unsafeSchemes.test(href)));
33
- if (root instanceof HTMLAnchorElement && (disabled || as !== "a"))
34
- root.removeAttribute("href");
35
- if (as === "span")
36
- root.setAttribute("role", this.getAttribute("role") || "button");
37
- if (as === "a" && (disabled || this.hasAttribute("disabled-focusable")))
38
- root.setAttribute("role", this.getAttribute("role") || "link");
39
- const disabledFocusable = this.hasAttribute("disabled") && this.hasAttribute("disabled-focusable") && (as !== "a" || (!!href && !unsafeSchemes.test(href)));
40
- if (as === "span" || as === "a")
41
- root.tabIndex = this.hasAttribute("tabindex") ? Number(this.getAttribute("tabindex")) : disabled && !disabledFocusable ? -1 : 0;
42
- else if (this.hasAttribute("tabindex"))
43
- root.tabIndex = Number(this.getAttribute("tabindex"));
44
- if (disabled || this.hasAttribute("disabled-focusable"))
45
- root.setAttribute("aria-disabled", "true");
46
- else
47
- root.removeAttribute("aria-disabled");
48
- if (root instanceof HTMLButtonElement)
49
- root.disabled = disabled && !disabledFocusable;
50
- if (root instanceof HTMLButtonElement && !root.hasAttribute("type"))
51
- root.type = "button";
52
- if (disabled)
53
- root.removeAttribute("target");
54
- if (!disabled && this.getAttribute("target")?.toLowerCase() === "_blank") {
55
- const rel = new Set((this.getAttribute("rel") ?? "").split(/\s+/).filter(Boolean));
56
- rel.add("noopener");
57
- rel.add("noreferrer");
58
- root.setAttribute("rel", [...rel].join(" "));
59
- }
60
- }
61
- render() {
62
- const shadow = this.attachShadow({ mode: "open" });
63
- const style = document.createElement("style");
64
- style.textContent = `${base}:host{display:inline;color:var(--spui-link-color,var(--spui-semantic-link,var(--colorBrandForeground1,#115ea3)))}a,button,span{box-sizing:border-box;background:transparent;border:0;color:inherit;font:inherit;text-align:inherit;text-decoration:none;cursor:pointer;padding:0;margin:0}a,span{display:inline}button{display:inline}a:visited{color:var(--spui-link-visited,var(--spui-semantic-link-visited,var(--colorBrandForeground2,#4f52b2)))}a:hover,button:hover,span:hover{text-decoration:underline}a:focus-visible,button:focus-visible,span:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-semantic-focus-border,#005a9e));outline-offset:2px} [aria-disabled=true]{color:var(--spui-ui-foreground-disabled,var(--spui-ui-muted,#777));cursor:not-allowed;text-decoration:none}[aria-disabled=true]:hover,[aria-disabled=true]:active{text-decoration:none}@media(forced-colors:active){[aria-disabled=true]{color:GrayText}}:host([underline=always]) a,:host([underline=always]) button,:host([underline=always]) span{text-decoration:underline;text-decoration-thickness:from-font;text-underline-offset:2px}:host([underline=hover]) a,:host([underline=hover]) button,:host([underline=hover]) span{text-decoration:none}:host([underline=hover]) a:hover,:host([underline=hover]) button:hover,:host([underline=hover]) span:hover,:host([underline=hover]) a:focus-visible,:host([underline=hover]) button:focus-visible,:host([underline=hover]) span:focus-visible,:host([inline]) a,:host([inline]) button,:host([inline]) span{text-decoration:underline}:host([appearance=subtle]){color:var(--spui-ui-text,var(--spui-semantic-body-text,#323130))}:host([appearance=subtle]) a:visited{color:inherit}`;
65
- shadow.append(style);
66
- this.renderRoot(this.getAttribute("as") || (this.getAttribute("href") ? "a" : "button"));
67
- this.addEventListener("click", event => { if (this.isDisabled()) {
68
- event.preventDefault();
69
- event.stopImmediatePropagation();
70
- } }, true);
71
- this.addEventListener("keydown", event => { if (this.isDisabled() && (event.key === "Enter" || event.key === " ")) {
72
- event.preventDefault();
73
- event.stopImmediatePropagation();
74
- }
75
- else if (this.shadowRoot?.querySelector("span") && (event.key === "Enter" || event.key === " ")) {
76
- event.preventDefault();
77
- this.shadowRoot.querySelector("span")?.click();
78
- } }, true);
79
- }
80
- isDisabled() { const href = this.getAttribute("href")?.trim() ?? ""; return this.hasAttribute("disabled") || this.hasAttribute("disabled-focusable") || (this.getAttribute("as") === "a" || (!this.hasAttribute("as") && !!href)) && (!href || unsafeSchemes.test(href)); }
81
- renderRoot(as) {
82
- if (!this.shadowRoot)
83
- return;
84
- const root = document.createElement(["a", "button", "span"].includes(as) ? as : "span");
85
- root.part.add("link");
86
- root.append(document.createElement("slot"));
87
- this.shadowRoot.querySelector("a,button,span")?.replaceWith(root) ?? this.shadowRoot.append(root);
88
- this.sync();
89
- }
90
- }
91
- customElements.define("spui-link", SpuiLink);
92
- }
@@ -1,19 +0,0 @@
1
- export type ListItemValue = string | number;
2
- export type ListSelectionMode = "single" | "multiselect";
3
- export type ListNavigationMode = "items" | "composite";
4
- export type ListSelectionChangeData = {
5
- event: Event;
6
- type: "change";
7
- selectedItems: ListItemValue[];
8
- };
9
- export type ListItemActionEvent = CustomEvent<{
10
- originalEvent: Event;
11
- value: ListItemValue;
12
- }>;
13
- export type ListItemActionData = {
14
- event: ListItemActionEvent;
15
- type: "ListItemAction";
16
- value: ListItemValue;
17
- };
18
- export declare function defineListItem(): void;
19
- export declare function defineList(): void;