@spfx-fast/sharepoint-ui 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/QUICKSTART.md +18 -0
- package/README.md +19 -24
- package/components.json +240 -5694
- package/dist/accordion.d.ts +11 -0
- package/dist/accordion.js +4 -0
- package/dist/alert.d.ts +3 -0
- package/dist/alert.js +4 -0
- package/dist/attachment-list.d.ts +15 -0
- package/dist/attachment-list.js +14 -0
- package/dist/avatar-group.d.ts +12 -0
- package/dist/avatar-group.js +7 -0
- package/dist/avatar.d.ts +6 -0
- package/dist/avatar.js +5 -0
- package/dist/badge.d.ts +3 -0
- package/dist/badge.js +4 -0
- package/dist/breadcrumb.d.ts +10 -0
- package/dist/breadcrumb.js +9 -0
- package/dist/button-group.d.ts +6 -0
- package/dist/button-group.js +4 -0
- package/dist/button.d.ts +3 -0
- package/dist/button.js +4 -0
- package/dist/card.d.ts +3 -0
- package/dist/card.js +4 -0
- package/dist/carousel.d.ts +11 -0
- package/dist/carousel.js +6 -0
- package/dist/checkbox.d.ts +3 -0
- package/dist/checkbox.js +4 -0
- package/dist/combobox.d.ts +9 -0
- package/dist/combobox.js +6 -0
- package/dist/command-bar.d.ts +6 -0
- package/dist/command-bar.js +4 -0
- package/dist/copy-button.d.ts +7 -0
- package/dist/copy-button.js +19 -0
- package/dist/data-grid.d.ts +25 -0
- package/dist/data-grid.js +39 -0
- package/dist/date-range-picker.d.ts +12 -0
- package/dist/date-range-picker.js +4 -0
- package/dist/dialog.d.ts +9 -0
- package/dist/dialog.js +21 -0
- package/dist/divider.d.ts +3 -0
- package/dist/divider.js +4 -0
- package/dist/drawer.d.ts +6 -0
- package/dist/drawer.js +5 -0
- package/dist/empty-state.d.ts +7 -0
- package/dist/empty-state.js +5 -0
- package/dist/field.d.ts +15 -0
- package/dist/field.js +11 -0
- package/dist/file-dropzone.d.ts +15 -0
- package/dist/file-dropzone.js +21 -0
- package/dist/filter-bar.d.ts +9 -0
- package/dist/filter-bar.js +9 -0
- package/dist/image.d.ts +5 -0
- package/dist/image.js +4 -0
- package/dist/index.d.ts +68 -76
- package/dist/index.js +60 -66
- package/dist/input.d.ts +3 -0
- package/dist/input.js +4 -0
- package/dist/label.d.ts +3 -0
- package/dist/label.js +4 -0
- package/dist/link.d.ts +3 -0
- package/dist/link.js +9 -0
- package/dist/list-view.d.ts +29 -0
- package/dist/list-view.js +14 -0
- package/dist/list.d.ts +6 -0
- package/dist/list.js +5 -0
- package/dist/lookup-picker.d.ts +12 -0
- package/dist/lookup-picker.js +4 -0
- package/dist/menu.d.ts +6 -0
- package/dist/menu.js +4 -0
- package/dist/nav.d.ts +12 -0
- package/dist/nav.js +4 -0
- package/dist/pagination.d.ts +11 -0
- package/dist/pagination.js +5 -0
- package/dist/person-picker.d.ts +13 -0
- package/dist/person-picker.js +4 -0
- package/dist/persona.d.ts +7 -0
- package/dist/persona.js +5 -0
- package/dist/popover.d.ts +6 -0
- package/dist/popover.js +4 -0
- package/dist/progress-bar.d.ts +5 -0
- package/dist/progress-bar.js +5 -0
- package/dist/radio-group.d.ts +6 -0
- package/dist/radio-group.js +4 -0
- package/dist/radio.d.ts +3 -0
- package/dist/radio.js +4 -0
- package/dist/rating.d.ts +8 -0
- package/dist/rating.js +5 -0
- package/dist/react.d.ts +1 -4583
- package/dist/react.js +1 -6837
- package/dist/select.d.ts +3 -0
- package/dist/select.js +4 -0
- package/dist/sharepoint-field.d.ts +18 -0
- package/dist/sharepoint-field.js +54 -0
- package/dist/skeleton.d.ts +6 -0
- package/dist/skeleton.js +9 -0
- package/dist/spinner.d.ts +5 -0
- package/dist/spinner.js +4 -0
- package/dist/swatch-picker.d.ts +17 -0
- package/dist/swatch-picker.js +11 -0
- package/dist/switch.d.ts +3 -0
- package/dist/switch.js +4 -0
- package/dist/table.d.ts +6 -0
- package/dist/table.js +4 -0
- package/dist/tabs.d.ts +14 -0
- package/dist/tabs.js +30 -0
- package/dist/tag-group.d.ts +6 -0
- package/dist/tag-group.js +4 -0
- package/dist/tag-picker.d.ts +12 -0
- package/dist/tag-picker.js +4 -0
- package/dist/tag.d.ts +7 -0
- package/dist/tag.js +5 -0
- package/dist/text.d.ts +5 -0
- package/dist/text.js +4 -0
- package/dist/textarea.d.ts +3 -0
- package/dist/textarea.js +4 -0
- package/dist/theme.d.ts +15 -167
- package/dist/theme.js +36 -162
- package/dist/toast.d.ts +9 -0
- package/dist/toast.js +12 -0
- package/dist/tree.d.ts +13 -0
- package/dist/tree.js +9 -0
- package/dist/view-card.d.ts +8 -0
- package/dist/view-card.js +4 -0
- package/dist/view-switcher.d.ts +13 -0
- package/dist/view-switcher.js +7 -0
- package/dist/virtual-list.d.ts +11 -0
- package/dist/virtual-list.js +25 -0
- package/measurements.json +365 -0
- package/package.json +19 -42
- package/src/theme.css +125 -0
- package/AGENTS.md +0 -211
- package/dist/appearance.d.ts +0 -6
- package/dist/appearance.js +0 -217
- package/dist/elements/accordion.d.ts +0 -9
- package/dist/elements/accordion.js +0 -338
- package/dist/elements/alert.d.ts +0 -2
- package/dist/elements/alert.js +0 -62
- package/dist/elements/avatar-group-primitives.d.ts +0 -3
- package/dist/elements/avatar-group-primitives.js +0 -189
- package/dist/elements/avatar-group.d.ts +0 -2
- package/dist/elements/avatar-group.js +0 -110
- package/dist/elements/avatar.d.ts +0 -4
- package/dist/elements/avatar.js +0 -251
- package/dist/elements/badge.d.ts +0 -8
- package/dist/elements/badge.js +0 -182
- package/dist/elements/breadcrumb.d.ts +0 -4
- package/dist/elements/breadcrumb.js +0 -233
- package/dist/elements/button-group.d.ts +0 -1
- package/dist/elements/button-group.js +0 -20
- package/dist/elements/button-variants.d.ts +0 -6
- package/dist/elements/button-variants.js +0 -339
- package/dist/elements/button.d.ts +0 -5
- package/dist/elements/button.js +0 -233
- package/dist/elements/card-primitives.d.ts +0 -3
- package/dist/elements/card-primitives.js +0 -83
- package/dist/elements/card.d.ts +0 -5
- package/dist/elements/card.js +0 -213
- package/dist/elements/carousel.d.ts +0 -92
- package/dist/elements/carousel.js +0 -1112
- package/dist/elements/color-picker.d.ts +0 -24
- package/dist/elements/color-picker.js +0 -1004
- package/dist/elements/combobox.d.ts +0 -1
- package/dist/elements/combobox.js +0 -1012
- package/dist/elements/data-grid-model.d.ts +0 -117
- package/dist/elements/data-grid-model.js +0 -294
- package/dist/elements/data-grid.d.ts +0 -29
- package/dist/elements/data-grid.js +0 -1567
- package/dist/elements/date-picker.d.ts +0 -1
- package/dist/elements/date-picker.js +0 -486
- package/dist/elements/dialog.d.ts +0 -23
- package/dist/elements/dialog.js +0 -409
- package/dist/elements/divider.d.ts +0 -2
- package/dist/elements/divider.js +0 -66
- package/dist/elements/drawer.d.ts +0 -3
- package/dist/elements/drawer.js +0 -308
- package/dist/elements/field-composition.d.ts +0 -26
- package/dist/elements/field-composition.js +0 -133
- package/dist/elements/field.d.ts +0 -1
- package/dist/elements/field.js +0 -67
- package/dist/elements/file-upload.d.ts +0 -6
- package/dist/elements/file-upload.js +0 -211
- package/dist/elements/floating-position.d.ts +0 -26
- package/dist/elements/floating-position.js +0 -39
- package/dist/elements/image.d.ts +0 -28
- package/dist/elements/image.js +0 -38
- package/dist/elements/info.d.ts +0 -9
- package/dist/elements/info.js +0 -102
- package/dist/elements/input.d.ts +0 -5
- package/dist/elements/input.js +0 -255
- package/dist/elements/label.d.ts +0 -15
- package/dist/elements/label.js +0 -56
- package/dist/elements/link.d.ts +0 -1
- package/dist/elements/link.js +0 -92
- package/dist/elements/list.d.ts +0 -19
- package/dist/elements/list.js +0 -297
- package/dist/elements/menu.d.ts +0 -33
- package/dist/elements/menu.js +0 -1103
- package/dist/elements/message-bar.d.ts +0 -10
- package/dist/elements/message-bar.js +0 -299
- package/dist/elements/nav.d.ts +0 -32
- package/dist/elements/nav.js +0 -791
- package/dist/elements/overflow.d.ts +0 -9
- package/dist/elements/overflow.js +0 -218
- package/dist/elements/persona.d.ts +0 -3
- package/dist/elements/persona.js +0 -125
- package/dist/elements/popover.d.ts +0 -77
- package/dist/elements/popover.js +0 -840
- package/dist/elements/progress-bar.d.ts +0 -4
- package/dist/elements/progress-bar.js +0 -82
- package/dist/elements/radio-group.d.ts +0 -1
- package/dist/elements/radio-group.js +0 -303
- package/dist/elements/rating-display.d.ts +0 -2
- package/dist/elements/rating-display.js +0 -125
- package/dist/elements/rating.d.ts +0 -2
- package/dist/elements/rating.js +0 -206
- package/dist/elements/rich-text-editor.d.ts +0 -18
- package/dist/elements/rich-text-editor.js +0 -508
- package/dist/elements/search.d.ts +0 -3
- package/dist/elements/search.js +0 -207
- package/dist/elements/select.d.ts +0 -6
- package/dist/elements/select.js +0 -291
- package/dist/elements/shared.d.ts +0 -19
- package/dist/elements/shared.js +0 -396
- package/dist/elements/skeleton.d.ts +0 -6
- package/dist/elements/skeleton.js +0 -91
- package/dist/elements/slider.d.ts +0 -1
- package/dist/elements/slider.js +0 -248
- package/dist/elements/spin-button.d.ts +0 -7
- package/dist/elements/spin-button.js +0 -499
- package/dist/elements/spinner.d.ts +0 -4
- package/dist/elements/spinner.js +0 -124
- package/dist/elements/swatch-picker.d.ts +0 -5
- package/dist/elements/swatch-picker.js +0 -363
- package/dist/elements/table.d.ts +0 -21
- package/dist/elements/table.js +0 -261
- package/dist/elements/tabs.d.ts +0 -1
- package/dist/elements/tabs.js +0 -276
- package/dist/elements/tag-picker.d.ts +0 -29
- package/dist/elements/tag-picker.js +0 -697
- package/dist/elements/tags.d.ts +0 -21
- package/dist/elements/tags.js +0 -421
- package/dist/elements/teaching-popover.d.ts +0 -32
- package/dist/elements/teaching-popover.js +0 -412
- package/dist/elements/text.d.ts +0 -9
- package/dist/elements/text.js +0 -75
- package/dist/elements/textarea.d.ts +0 -1
- package/dist/elements/textarea.js +0 -182
- package/dist/elements/toast.d.ts +0 -25
- package/dist/elements/toast.js +0 -337
- package/dist/elements/toaster.d.ts +0 -6
- package/dist/elements/toaster.js +0 -356
- package/dist/elements/toggle.d.ts +0 -2
- package/dist/elements/toggle.js +0 -246
- package/dist/elements/toolbar.d.ts +0 -12
- package/dist/elements/toolbar.js +0 -381
- package/dist/elements/tooltip.d.ts +0 -76
- package/dist/elements/tooltip.js +0 -510
- package/dist/elements/tree-model.d.ts +0 -19
- package/dist/elements/tree-model.js +0 -34
- package/dist/elements/tree.d.ts +0 -5
- package/dist/elements/tree.js +0 -273
- package/dist/elements/view-card.d.ts +0 -2
- package/dist/elements/view-card.js +0 -78
- package/dist/elements/virtual-list.d.ts +0 -41
- package/dist/elements/virtual-list.js +0 -369
- package/dist/elements.d.ts +0 -72
- package/dist/elements.js +0 -207
- package/dist/virtualizer-hooks.d.ts +0 -80
- package/dist/virtualizer-hooks.js +0 -253
- package/scripts/generate-token-index.mjs +0 -43
- package/scripts/sync-component-catalog-signatures.mjs +0 -55
- package/scripts/validate-component-catalog.mjs +0 -44
- package/skills/sharepoint-ui/SKILL.md +0 -12
- package/skills/sharepoint-ui/references/choosing-components.md +0 -20
- package/skills/sharepoint-ui/references/sharepoint-patterns.md +0 -17
- package/tokens.json +0 -3777
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import { base, syncHostAccessibleName } from "./shared.js";
|
|
2
|
-
/** File selection surface. Uploading and SharePoint persistence remain the consumer's responsibility. */
|
|
3
|
-
export function defineFileUpload() {
|
|
4
|
-
if (customElements.get("spui-file-upload"))
|
|
5
|
-
return;
|
|
6
|
-
class SpuiFileUpload extends HTMLElement {
|
|
7
|
-
static formAssociated = true;
|
|
8
|
-
static observedAttributes = ["accept", "multiple", "disabled", "required", "name", "max-files", "max-file-size", "label", "aria-label", "aria-labelledby", "aria-description", "aria-describedby", "aria-invalid", "browse-label", "remove-label", "drop-label", "selected-label", "invalid-message", "required-message"];
|
|
9
|
-
internals;
|
|
10
|
-
input;
|
|
11
|
-
list;
|
|
12
|
-
status;
|
|
13
|
-
selected = [];
|
|
14
|
-
formDisabled = false;
|
|
15
|
-
get form() { return this.internals?.form ?? null; }
|
|
16
|
-
get files() { return this.selected; }
|
|
17
|
-
constructor() { super(); try {
|
|
18
|
-
this.internals = this.attachInternals();
|
|
19
|
-
}
|
|
20
|
-
catch { /* Native picker continues to work where form-associated elements are unavailable. */ } }
|
|
21
|
-
connectedCallback() { if (!this.shadowRoot)
|
|
22
|
-
this.render(); this.sync(); }
|
|
23
|
-
attributeChangedCallback() { if (this.isConnected && this.input)
|
|
24
|
-
this.sync(); }
|
|
25
|
-
formDisabledCallback(disabled) { this.formDisabled = disabled; if (this.input)
|
|
26
|
-
this.sync(); }
|
|
27
|
-
formResetCallback() { if (this.status)
|
|
28
|
-
this.status.textContent = ""; this.setFiles([], false); }
|
|
29
|
-
formStateRestoreCallback(state) { if (state instanceof File)
|
|
30
|
-
this.setFiles([state], false);
|
|
31
|
-
else if (state instanceof FormData)
|
|
32
|
-
this.setFiles(state.getAll(this.getAttribute("name") || "").filter((value) => value instanceof File), false); }
|
|
33
|
-
render() {
|
|
34
|
-
const shadow = this.attachShadow({ mode: "open" });
|
|
35
|
-
const style = document.createElement("style");
|
|
36
|
-
style.textContent = `${base}:host{display:block;min-width:0;color:var(--spui-ui-text,var(--spui-semantic-body-text,#242424));font-family:var(--spui-font-family,inherit)}.label{display:block;margin-block-end:6px;font-size:14px;font-weight:600}.drop{box-sizing:border-box;display:grid;place-items:center;gap:6px;min-height:104px;padding:16px;border:1px dashed var(--spui-ui-stroke,var(--spui-semantic-input-border,#8a8886));border-radius:var(--spui-control-radius,6px);background:var(--spui-ui-surface,var(--spui-semantic-input-background,#fff));text-align:center;transition:border-color var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1)),background-color var(--spui-motion-duration-fast,120ms) var(--spui-motion-easing-standard,cubic-bezier(.2,0,0,1))}.drop[data-dragging=true]{border-color:var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));background:var(--spui-ui-surface-hover,var(--spui-ui-canvas,#f5f5f5))}.hint{color:var(--spui-ui-muted,var(--spui-semantic-body-subtext,#616161));font-size:12px}.browse{min-height:32px;padding:4px 12px;border:1px solid var(--spui-control-border,var(--spui-ui-stroke,#8a8886));border-radius:var(--spui-control-radius,4px);background:var(--spui-ui-surface,#fff);color:inherit;font:inherit;cursor:pointer}.browse:hover:not(:disabled){background:var(--spui-ui-surface-hover,var(--spui-ui-canvas,#f5f5f5))}.browse:focus-visible,.remove:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#0078d4));outline-offset:2px}.browse:disabled,.remove:disabled{opacity:.55;cursor:not-allowed}.input{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.files{display:grid;gap:4px;margin:8px 0 0;padding:0;list-style:none}.files:empty{display:none}.file{display:flex;align-items:center;gap:8px;min-width:0;padding:6px 8px;border:1px solid var(--spui-ui-stroke,#d1d1d1);border-radius:var(--spui-control-radius,4px)}.filename{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.size{flex:none;color:var(--spui-ui-muted,#616161);font-size:12px;font-variant-numeric:tabular-nums}.remove{min-width:32px;min-height:32px;border:0;border-radius:var(--spui-control-radius,4px);background:transparent;color:inherit;font:inherit;cursor:pointer}.status{margin-block-start:6px;color:var(--spui-semantic-error-text,var(--spui-ui-danger,#b10e1c));font-size:12px}.status:empty{display:none}:host([data-spui-appearance=glass]) .drop{backdrop-filter:var(--spui-card-backdrop,blur(12px) saturate(1.2))}@media(prefers-reduced-motion:reduce){.drop{transition:none}}@media(forced-colors:active){.drop,.file{border-color:CanvasText;background:Canvas;color:CanvasText}.drop[data-dragging=true]{outline:2px solid Highlight}.browse{border-color:ButtonText;background:ButtonFace;color:ButtonText}}`;
|
|
37
|
-
const label = document.createElement("label");
|
|
38
|
-
label.className = "label";
|
|
39
|
-
label.part.add("label");
|
|
40
|
-
const drop = document.createElement("div");
|
|
41
|
-
drop.className = "drop";
|
|
42
|
-
drop.part.add("dropzone");
|
|
43
|
-
drop.tabIndex = -1;
|
|
44
|
-
const hint = document.createElement("span");
|
|
45
|
-
hint.className = "hint";
|
|
46
|
-
const browse = document.createElement("button");
|
|
47
|
-
browse.type = "button";
|
|
48
|
-
browse.className = "browse";
|
|
49
|
-
browse.part.add("browse-button");
|
|
50
|
-
this.input = document.createElement("input");
|
|
51
|
-
this.input.type = "file";
|
|
52
|
-
this.input.className = "input";
|
|
53
|
-
this.input.part.add("input");
|
|
54
|
-
browse.addEventListener("click", () => this.input.click());
|
|
55
|
-
this.input.addEventListener("change", () => { this.addFiles(Array.from(this.input.files ?? [])); this.input.value = ""; });
|
|
56
|
-
drop.addEventListener("dragover", event => { event.preventDefault(); if (!this.isDisabled())
|
|
57
|
-
drop.dataset.dragging = "true"; });
|
|
58
|
-
drop.addEventListener("dragleave", event => { if (!drop.contains(event.relatedTarget))
|
|
59
|
-
delete drop.dataset.dragging; });
|
|
60
|
-
drop.addEventListener("drop", event => { event.preventDefault(); delete drop.dataset.dragging; if (!this.isDisabled())
|
|
61
|
-
this.addFiles(Array.from(event.dataTransfer?.files ?? [])); });
|
|
62
|
-
drop.addEventListener("keydown", event => { if (event.key === "Enter" || event.key === " ") {
|
|
63
|
-
event.preventDefault();
|
|
64
|
-
this.input.click();
|
|
65
|
-
} });
|
|
66
|
-
this.input.addEventListener("focus", () => browse.focus());
|
|
67
|
-
this.list = document.createElement("ul");
|
|
68
|
-
this.list.className = "files";
|
|
69
|
-
this.list.part.add("file-list");
|
|
70
|
-
this.list.setAttribute("aria-label", "Selected files");
|
|
71
|
-
this.status = document.createElement("div");
|
|
72
|
-
this.status.className = "status";
|
|
73
|
-
this.status.part.add("status");
|
|
74
|
-
this.status.setAttribute("role", "status");
|
|
75
|
-
this.status.setAttribute("aria-live", "polite");
|
|
76
|
-
drop.append(hint, browse, this.input);
|
|
77
|
-
shadow.append(style, label, drop, this.list, this.status);
|
|
78
|
-
}
|
|
79
|
-
sync() {
|
|
80
|
-
const disabled = this.isDisabled();
|
|
81
|
-
this.input.accept = this.getAttribute("accept") || "";
|
|
82
|
-
this.input.multiple = this.hasAttribute("multiple");
|
|
83
|
-
this.input.disabled = disabled;
|
|
84
|
-
this.input.required = this.hasAttribute("required") && this.selected.length === 0;
|
|
85
|
-
const label = this.getAttribute("aria-label") || this.getAttribute("label") || "Add files";
|
|
86
|
-
const browse = this.getAttribute("browse-label") || "Browse files";
|
|
87
|
-
if (!this.hasAttribute("role"))
|
|
88
|
-
this.setAttribute("role", "group");
|
|
89
|
-
const labelElement = this.shadowRoot?.querySelector(".label");
|
|
90
|
-
if (labelElement) {
|
|
91
|
-
labelElement.textContent = this.getAttribute("label") || "";
|
|
92
|
-
labelElement.hidden = !this.hasAttribute("label");
|
|
93
|
-
}
|
|
94
|
-
this.input.setAttribute("aria-label", label);
|
|
95
|
-
syncHostAccessibleName(this, this.input);
|
|
96
|
-
const invalid = this.getAttribute("aria-invalid");
|
|
97
|
-
if (invalid === null)
|
|
98
|
-
this.input.removeAttribute("aria-invalid");
|
|
99
|
-
else
|
|
100
|
-
this.input.setAttribute("aria-invalid", invalid);
|
|
101
|
-
const hint = this.shadowRoot?.querySelector(".hint");
|
|
102
|
-
if (hint)
|
|
103
|
-
hint.textContent = this.getAttribute("drop-label") || "Drag files here or browse to select";
|
|
104
|
-
const button = this.shadowRoot?.querySelector(".browse");
|
|
105
|
-
if (button) {
|
|
106
|
-
button.textContent = browse;
|
|
107
|
-
button.disabled = disabled;
|
|
108
|
-
button.setAttribute("aria-label", browse);
|
|
109
|
-
}
|
|
110
|
-
this.list?.setAttribute("aria-label", `${label}: ${this.getAttribute("selected-label") || "selected files"}`);
|
|
111
|
-
this.renderFiles();
|
|
112
|
-
this.syncForm();
|
|
113
|
-
}
|
|
114
|
-
addFiles(files) {
|
|
115
|
-
if (!files.length || this.isDisabled())
|
|
116
|
-
return;
|
|
117
|
-
const max = Number(this.getAttribute("max-files"));
|
|
118
|
-
const limit = Number(this.getAttribute("max-file-size"));
|
|
119
|
-
const next = this.hasAttribute("multiple") ? [...this.selected] : [];
|
|
120
|
-
const errors = [];
|
|
121
|
-
for (const file of files) {
|
|
122
|
-
if (!this.accepts(file)) {
|
|
123
|
-
errors.push({ code: "file-type-not-accepted", file });
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
if (Number.isFinite(limit) && limit > 0 && file.size > limit) {
|
|
127
|
-
errors.push({ code: "file-too-large", file });
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
if (Number.isFinite(max) && max > 0 && next.length >= max) {
|
|
131
|
-
errors.push({ code: "too-many-files", file });
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
if (!next.some(existing => existing.name === file.name && existing.size === file.size && existing.lastModified === file.lastModified))
|
|
135
|
-
next.push(file);
|
|
136
|
-
}
|
|
137
|
-
this.status.textContent = errors.length ? (this.getAttribute("invalid-message") || this.getAttribute(errors[0].code === "file-too-large" ? "file-too-large-message" : errors[0].code === "too-many-files" ? "max-files-message" : "file-type-message") || this.describeError(errors[0])) : "";
|
|
138
|
-
this.setFiles(next, true);
|
|
139
|
-
if (errors.length)
|
|
140
|
-
this.dispatchEvent(new CustomEvent("spui-file-error", { detail: { errors }, bubbles: true, composed: true }));
|
|
141
|
-
}
|
|
142
|
-
describeError(error) {
|
|
143
|
-
if (error.code === "file-too-large")
|
|
144
|
-
return `${error.file?.name || "File"} exceeds the allowed size.`;
|
|
145
|
-
if (error.code === "too-many-files")
|
|
146
|
-
return "The maximum number of files has been reached.";
|
|
147
|
-
return "The selected file type is not accepted.";
|
|
148
|
-
}
|
|
149
|
-
accepts(file) {
|
|
150
|
-
const accepted = (this.getAttribute("accept") || "").split(",").map(value => value.trim().toLowerCase()).filter(Boolean);
|
|
151
|
-
if (!accepted.length)
|
|
152
|
-
return true;
|
|
153
|
-
const name = file.name.toLowerCase();
|
|
154
|
-
const type = file.type.toLowerCase();
|
|
155
|
-
return accepted.some(value => value.startsWith(".") ? name.endsWith(value) : value.endsWith("/*") ? type.startsWith(value.slice(0, -1)) : type === value);
|
|
156
|
-
}
|
|
157
|
-
setFiles(files, emit) {
|
|
158
|
-
this.selected = files;
|
|
159
|
-
this.renderFiles();
|
|
160
|
-
this.syncForm();
|
|
161
|
-
if (emit)
|
|
162
|
-
this.dispatchEvent(new CustomEvent("spui-file-change", { detail: { files: [...files] }, bubbles: true, composed: true }));
|
|
163
|
-
}
|
|
164
|
-
renderFiles() {
|
|
165
|
-
if (!this.list)
|
|
166
|
-
return;
|
|
167
|
-
this.list.replaceChildren(...this.selected.map((file, index) => {
|
|
168
|
-
const item = document.createElement("li");
|
|
169
|
-
item.className = "file";
|
|
170
|
-
item.part.add("file");
|
|
171
|
-
const name = document.createElement("span");
|
|
172
|
-
name.className = "filename";
|
|
173
|
-
name.textContent = file.name;
|
|
174
|
-
const size = document.createElement("span");
|
|
175
|
-
size.className = "size";
|
|
176
|
-
size.textContent = this.formatSize(file.size);
|
|
177
|
-
const remove = document.createElement("button");
|
|
178
|
-
remove.type = "button";
|
|
179
|
-
remove.className = "remove";
|
|
180
|
-
remove.textContent = "×";
|
|
181
|
-
remove.disabled = this.isDisabled();
|
|
182
|
-
remove.setAttribute("aria-label", `${this.getAttribute("remove-label") || "Remove"} ${file.name}`);
|
|
183
|
-
remove.addEventListener("click", () => {
|
|
184
|
-
this.status.textContent = "";
|
|
185
|
-
const next = this.selected.filter((_, i) => i !== index);
|
|
186
|
-
this.setFiles(next, true);
|
|
187
|
-
const nextRemove = this.list.querySelectorAll(".remove")[Math.min(index, next.length - 1)];
|
|
188
|
-
(nextRemove ?? this.shadowRoot?.querySelector(".browse"))?.focus();
|
|
189
|
-
});
|
|
190
|
-
item.append(name, size, remove);
|
|
191
|
-
return item;
|
|
192
|
-
}));
|
|
193
|
-
}
|
|
194
|
-
formatSize(size) { return size < 1024 ? `${size} B` : size < 1024 * 1024 ? `${(size / 1024).toFixed(1)} KB` : `${(size / (1024 * 1024)).toFixed(1)} MB`; }
|
|
195
|
-
syncForm() {
|
|
196
|
-
if (!this.internals)
|
|
197
|
-
return;
|
|
198
|
-
const name = this.getAttribute("name") || "";
|
|
199
|
-
const data = new FormData();
|
|
200
|
-
if (name)
|
|
201
|
-
this.selected.forEach(file => data.append(name, file, file.name));
|
|
202
|
-
this.internals.setFormValue(this.selected.length && name ? data : null, JSON.stringify(this.selected.map(file => ({ name: file.name, size: file.size, lastModified: file.lastModified }))));
|
|
203
|
-
if (this.hasAttribute("required") && !this.selected.length)
|
|
204
|
-
this.internals.setValidity({ valueMissing: true }, this.getAttribute("required-message") || "Select at least one file.", this.shadowRoot?.querySelector(".browse") ?? undefined);
|
|
205
|
-
else
|
|
206
|
-
this.internals.setValidity({});
|
|
207
|
-
}
|
|
208
|
-
isDisabled() { return this.formDisabled || this.hasAttribute("disabled"); }
|
|
209
|
-
}
|
|
210
|
-
customElements.define("spui-file-upload", SpuiFileUpload);
|
|
211
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export type FloatingPlacement = "top" | "bottom" | "start" | "end" | "left" | "right";
|
|
2
|
-
export type FloatingPosition = {
|
|
3
|
-
top: number;
|
|
4
|
-
left: number;
|
|
5
|
-
placement: Exclude<FloatingPlacement, "start" | "end">;
|
|
6
|
-
align: FloatingAlign;
|
|
7
|
-
};
|
|
8
|
-
export type FloatingAlign = "start" | "center" | "end" | "top" | "bottom";
|
|
9
|
-
export type FloatingModifiers = {
|
|
10
|
-
crossAxisOffset?: number;
|
|
11
|
-
coverTarget?: boolean;
|
|
12
|
-
overflowBoundaryPadding?: {
|
|
13
|
-
top?: number;
|
|
14
|
-
right?: number;
|
|
15
|
-
bottom?: number;
|
|
16
|
-
left?: number;
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
export type FloatingAnchorRect = Pick<DOMRectReadOnly, "left" | "top" | "right" | "bottom" | "width" | "height">;
|
|
20
|
-
export declare function getFloatingPosition(anchor: FloatingAnchorRect, surface: Pick<DOMRectReadOnly, "width" | "height">, placement: FloatingPlacement, direction: "ltr" | "rtl", gap?: number, viewport?: {
|
|
21
|
-
width: number;
|
|
22
|
-
height: number;
|
|
23
|
-
}, align?: FloatingAlign, fallbackPlacements?: Array<{
|
|
24
|
-
placement: FloatingPlacement;
|
|
25
|
-
align?: FloatingAlign;
|
|
26
|
-
}>, pinned?: boolean, flipBoundary?: Pick<DOMRectReadOnly, "left" | "top" | "right" | "bottom">, overflowBoundary?: Pick<DOMRectReadOnly, "left" | "top" | "right" | "bottom">, modifiers?: FloatingModifiers): FloatingPosition;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
export function getFloatingPosition(anchor, surface, placement, direction, gap = 8, viewport = { width: innerWidth, height: innerHeight }, align = "center", fallbackPlacements = [], pinned = false, flipBoundary, overflowBoundary, modifiers = {}) {
|
|
2
|
-
const viewportBoundary = { left: 0, top: 0, right: viewport.width, bottom: viewport.height };
|
|
3
|
-
const flipBounds = flipBoundary ?? viewportBoundary;
|
|
4
|
-
const overflowBounds = overflowBoundary ?? viewportBoundary;
|
|
5
|
-
const overflowPadding = modifiers.overflowBoundaryPadding ?? {};
|
|
6
|
-
const side = placement === "start" ? direction === "rtl" ? "right" : "left" : placement === "end" ? direction === "rtl" ? "left" : "right" : placement;
|
|
7
|
-
const opposite = { top: "bottom", bottom: "top", left: "right", right: "left" };
|
|
8
|
-
const coordinates = (candidate, candidateAlign = align) => {
|
|
9
|
-
const candidateInlineAlign = candidateAlign === "start" || candidateAlign === "top" ? "start" : candidateAlign === "end" || candidateAlign === "bottom" ? "end" : "center";
|
|
10
|
-
const candidateBlockAlign = candidateAlign === "start" || candidateAlign === "top" ? "start" : candidateAlign === "end" || candidateAlign === "bottom" ? "end" : "center";
|
|
11
|
-
const inlineStartLeft = direction === "rtl" ? anchor.right - surface.width : anchor.left;
|
|
12
|
-
const inlineEndLeft = direction === "rtl" ? anchor.left : anchor.right - surface.width;
|
|
13
|
-
return candidate === "top" || candidate === "bottom"
|
|
14
|
-
? { top: candidate === "top" ? (modifiers.coverTarget ? anchor.bottom : anchor.top) - surface.height - gap : (modifiers.coverTarget ? anchor.top : anchor.bottom) + gap, left: (candidateInlineAlign === "start" ? inlineStartLeft : candidateInlineAlign === "end" ? inlineEndLeft : anchor.left + (anchor.width - surface.width) / 2) + (modifiers.crossAxisOffset ?? 0) }
|
|
15
|
-
: { top: (candidateBlockAlign === "start" ? anchor.top : candidateBlockAlign === "end" ? anchor.bottom - surface.height : anchor.top + (anchor.height - surface.height) / 2) + (modifiers.crossAxisOffset ?? 0), left: candidate === "left" ? (modifiers.coverTarget ? anchor.right : anchor.left) - surface.width - gap : (modifiers.coverTarget ? anchor.left : anchor.right) + gap };
|
|
16
|
-
};
|
|
17
|
-
const fits = (_candidate, point) => point.top >= flipBounds.top + gap && point.left >= flipBounds.left + gap && point.top + surface.height <= flipBounds.bottom - gap && point.left + surface.width <= flipBounds.right - gap;
|
|
18
|
-
const candidates = [
|
|
19
|
-
{ placement: side, align },
|
|
20
|
-
...(pinned ? [] : fallbackPlacements),
|
|
21
|
-
...(!pinned ? [{ placement: opposite[side], align }] : []),
|
|
22
|
-
].map(candidate => ({ placement: candidate.placement === "start" ? direction === "rtl" ? "right" : "left" : candidate.placement === "end" ? direction === "rtl" ? "left" : "right" : candidate.placement, align: candidate.align ?? align }));
|
|
23
|
-
const unique = candidates.filter((candidate, index) => candidates.findIndex(other => other.placement === candidate.placement && other.align === candidate.align) === index);
|
|
24
|
-
let selected = unique.map(candidate => ({ ...candidate, point: coordinates(candidate.placement, candidate.align) })).find(candidate => fits(candidate.placement, candidate.point));
|
|
25
|
-
if (!selected) {
|
|
26
|
-
selected = unique.map(candidate => ({ ...candidate, point: coordinates(candidate.placement, candidate.align) })).sort((a, b) => {
|
|
27
|
-
const overflow = (candidate) => Math.max(0, flipBounds.left + gap - candidate.point.left) + Math.max(0, candidate.point.left + surface.width - (flipBounds.right - gap)) + Math.max(0, flipBounds.top + gap - candidate.point.top) + Math.max(0, candidate.point.top + surface.height - (flipBounds.bottom - gap));
|
|
28
|
-
return overflow(a) - overflow(b);
|
|
29
|
-
})[0];
|
|
30
|
-
}
|
|
31
|
-
const actual = selected.placement;
|
|
32
|
-
const point = selected.point;
|
|
33
|
-
return {
|
|
34
|
-
placement: actual,
|
|
35
|
-
align: selected.align,
|
|
36
|
-
left: Math.max(overflowBounds.left + gap + (overflowPadding.left ?? 0), Math.min(point.left, overflowBounds.right - surface.width - gap - (overflowPadding.right ?? 0))),
|
|
37
|
-
top: Math.max(overflowBounds.top + gap + (overflowPadding.top ?? 0), Math.min(point.top, overflowBounds.bottom - surface.height - gap - (overflowPadding.bottom ?? 0))),
|
|
38
|
-
};
|
|
39
|
-
}
|
package/dist/elements/image.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
export type ImageFit = "none" | "center" | "contain" | "cover" | "default";
|
|
2
|
-
export type ImageShape = "square" | "rounded" | "circular";
|
|
3
|
-
export type ImageOptions = {
|
|
4
|
-
src: string;
|
|
5
|
-
alt: string;
|
|
6
|
-
srcSet?: string;
|
|
7
|
-
sizes?: string;
|
|
8
|
-
width?: number;
|
|
9
|
-
height?: number;
|
|
10
|
-
title?: string;
|
|
11
|
-
className?: string;
|
|
12
|
-
loading?: "eager" | "lazy";
|
|
13
|
-
decoding?: "async" | "sync" | "auto";
|
|
14
|
-
fetchPriority?: "high" | "low" | "auto";
|
|
15
|
-
fit?: ImageFit;
|
|
16
|
-
shape?: ImageShape;
|
|
17
|
-
block?: boolean;
|
|
18
|
-
bordered?: boolean;
|
|
19
|
-
shadow?: boolean;
|
|
20
|
-
};
|
|
21
|
-
type ImageStyleOptions = Pick<ImageOptions, "fit" | "shape" | "block" | "bordered" | "shadow"> & {
|
|
22
|
-
width?: number | string;
|
|
23
|
-
height?: number | string;
|
|
24
|
-
};
|
|
25
|
-
export declare function getImageStyle({ fit, shape, block, bordered, shadow, width, height }: ImageStyleOptions): Record<string, string>;
|
|
26
|
-
/** Create a native image with browser-native responsive loading and meaningful alt text. */
|
|
27
|
-
export declare function createImage(options: ImageOptions): HTMLImageElement;
|
|
28
|
-
export {};
|
package/dist/elements/image.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export function getImageStyle({ fit = "default", shape = "square", block, bordered, shadow, width, height }) {
|
|
2
|
-
const fitFill = fit !== "default" && width == null && height == null;
|
|
3
|
-
return {
|
|
4
|
-
display: block ? "block" : "inline-block",
|
|
5
|
-
maxWidth: "100%",
|
|
6
|
-
...(block ? { width: "100%" } : {}),
|
|
7
|
-
...(fitFill ? { width: "100%", height: "100%" } : {}),
|
|
8
|
-
...(fit === "default" ? {} : { objectFit: fit === "center" ? "none" : fit }),
|
|
9
|
-
...(fit === "default" ? {} : { objectPosition: fit === "none" ? "left top" : "center" }),
|
|
10
|
-
borderRadius: shape === "circular" ? "50%" : shape === "rounded" ? "var(--spui-image-radius,var(--spui-control-radius,4px))" : "0",
|
|
11
|
-
...(bordered ? { border: "1px solid var(--spui-image-border,var(--spui-ui-stroke,var(--spui-semantic-body-divider,#d1d1d1)))" } : {}),
|
|
12
|
-
...(shadow ? { boxShadow: "var(--spui-image-shadow,var(--spui-card-shadow,0 1px 3px #0002))" } : {}),
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
/** Create a native image with browser-native responsive loading and meaningful alt text. */
|
|
16
|
-
export function createImage(options) {
|
|
17
|
-
const image = document.createElement("img");
|
|
18
|
-
image.alt = options.alt;
|
|
19
|
-
if (options.srcSet)
|
|
20
|
-
image.srcset = options.srcSet;
|
|
21
|
-
if (options.sizes)
|
|
22
|
-
image.sizes = options.sizes;
|
|
23
|
-
if (options.width !== undefined)
|
|
24
|
-
image.width = options.width;
|
|
25
|
-
if (options.height !== undefined)
|
|
26
|
-
image.height = options.height;
|
|
27
|
-
if (options.title)
|
|
28
|
-
image.title = options.title;
|
|
29
|
-
if (options.className)
|
|
30
|
-
image.className = options.className;
|
|
31
|
-
image.loading = options.loading ?? "lazy";
|
|
32
|
-
image.decoding = options.decoding ?? "async";
|
|
33
|
-
image.fetchPriority = options.fetchPriority ?? "auto";
|
|
34
|
-
Object.assign(image.style, getImageStyle(options));
|
|
35
|
-
// Configure the candidate set and intrinsic layout before starting any image request.
|
|
36
|
-
image.src = options.src;
|
|
37
|
-
return image;
|
|
38
|
-
}
|
package/dist/elements/info.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type LabelOptions } from "./label.js";
|
|
2
|
-
export type InfoPlacement = "top" | "bottom" | "start" | "end";
|
|
3
|
-
export type InfoLabelOptions = LabelOptions & {
|
|
4
|
-
infoButtonLabel?: string;
|
|
5
|
-
placement?: InfoPlacement;
|
|
6
|
-
};
|
|
7
|
-
export declare function defineInfoButton(): void;
|
|
8
|
-
/** Build a native form label with an adjacent, separately focusable information button. */
|
|
9
|
-
export declare function createInfoLabel(labelContent: string | Node, info: string | Node, options?: InfoLabelOptions): HTMLSpanElement;
|
package/dist/elements/info.js
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { definePopover } from "./popover.js";
|
|
2
|
-
import { createLabel } from "./label.js";
|
|
3
|
-
export function defineInfoButton() {
|
|
4
|
-
if (customElements.get("spui-info-button"))
|
|
5
|
-
return;
|
|
6
|
-
class SpuiInfoButton extends HTMLElement {
|
|
7
|
-
static observedAttributes = ["label", "info", "placement", "open", "disabled", "size", "inline", "popover-placement", "popover-label", "popover-arrow", "popover-trap-focus"];
|
|
8
|
-
popoverElement;
|
|
9
|
-
trigger;
|
|
10
|
-
contentSlot;
|
|
11
|
-
get open() { return this.popoverElement?.open ?? this.hasAttribute("open"); }
|
|
12
|
-
set open(value) { if (this.popoverElement)
|
|
13
|
-
this.popoverElement.open = Boolean(value);
|
|
14
|
-
else
|
|
15
|
-
this.toggleAttribute("open", Boolean(value)); }
|
|
16
|
-
get inline() { return this.getAttribute("inline") !== "false"; }
|
|
17
|
-
set inline(value) { if (value)
|
|
18
|
-
this.removeAttribute("inline");
|
|
19
|
-
else
|
|
20
|
-
this.setAttribute("inline", "false"); }
|
|
21
|
-
connectedCallback() {
|
|
22
|
-
definePopover();
|
|
23
|
-
if (!this.shadowRoot)
|
|
24
|
-
this.render();
|
|
25
|
-
this.sync();
|
|
26
|
-
}
|
|
27
|
-
attributeChangedCallback() { if (this.isConnected)
|
|
28
|
-
this.sync(); }
|
|
29
|
-
render() {
|
|
30
|
-
const shadow = this.attachShadow({ mode: "open" });
|
|
31
|
-
const style = document.createElement("style");
|
|
32
|
-
style.textContent = `:host{display:inline-flex;vertical-align:middle;line-height:1}:host([hidden]){display:none}button{display:inline-grid;place-items:center;box-sizing:border-box;width:var(--spui-info-button-size,20px);height:var(--spui-info-button-size,20px);padding:2px;border:1px solid transparent;border-radius:50%;background:transparent;color:var(--spui-info-button-color,var(--spui-ui-muted,var(--spui-semantic-body-text,#484644)));cursor:pointer;font:inherit}button:hover:not(:disabled){background:var(--spui-info-button-hover,var(--spui-ui-surface-hover,#f3f2f1));color:var(--spui-ui-accent,var(--spui-semantic-link,#0f6cbd))}button:focus-visible{outline:2px solid var(--spui-focus-ring,var(--spui-ui-accent,#005a9e));outline-offset:2px}button:disabled{opacity:.55;cursor:not-allowed}svg{width:calc(var(--spui-info-button-size,20px) * .8);height:calc(var(--spui-info-button-size,20px) * .8);fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;pointer-events:none}:host([size=small]){--spui-info-button-size:16px}:host([size=large]){--spui-info-button-size:24px}:host([data-spui-appearance=glass]) button{backdrop-filter:blur(8px)}@media(forced-colors:active){button{border-color:ButtonText;color:ButtonText}button:focus-visible{outline-color:Highlight}}`;
|
|
33
|
-
const popover = document.createElement("spui-popover");
|
|
34
|
-
this.popoverElement = popover;
|
|
35
|
-
const trigger = document.createElement("button");
|
|
36
|
-
this.trigger = trigger;
|
|
37
|
-
trigger.type = "button";
|
|
38
|
-
trigger.slot = "trigger";
|
|
39
|
-
trigger.part.add("control");
|
|
40
|
-
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
41
|
-
svg.setAttribute("viewBox", "0 0 20 20");
|
|
42
|
-
svg.setAttribute("aria-hidden", "true");
|
|
43
|
-
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
44
|
-
path.setAttribute("d", "M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm0-9v5m0-8h.01");
|
|
45
|
-
svg.append(path);
|
|
46
|
-
trigger.append(svg);
|
|
47
|
-
const content = document.createElement("div");
|
|
48
|
-
content.slot = "content";
|
|
49
|
-
content.part.add("content");
|
|
50
|
-
const slot = document.createElement("slot");
|
|
51
|
-
this.contentSlot = slot;
|
|
52
|
-
slot.addEventListener("slotchange", () => this.syncContent());
|
|
53
|
-
content.append(slot);
|
|
54
|
-
popover.append(trigger, content);
|
|
55
|
-
popover.addEventListener("spui-open-change", event => {
|
|
56
|
-
if (event.detail.open)
|
|
57
|
-
requestAnimationFrame(() => {
|
|
58
|
-
const surface = popover.shadowRoot?.querySelector(".surface");
|
|
59
|
-
surface?.setAttribute("tabindex", "-1");
|
|
60
|
-
surface?.focus();
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
shadow.append(style, popover);
|
|
64
|
-
}
|
|
65
|
-
sync() {
|
|
66
|
-
if (!this.popoverElement || !this.trigger)
|
|
67
|
-
return;
|
|
68
|
-
const label = this.getAttribute("label") || "More information";
|
|
69
|
-
this.trigger.setAttribute("aria-label", label);
|
|
70
|
-
this.trigger.disabled = this.hasAttribute("disabled");
|
|
71
|
-
this.popoverElement.setAttribute("placement", this.getAttribute("popover-placement") || this.getAttribute("placement") || "top");
|
|
72
|
-
this.popoverElement.setAttribute("label", this.getAttribute("popover-label") || label);
|
|
73
|
-
this.popoverElement.inline = this.inline;
|
|
74
|
-
this.popoverElement.toggleAttribute("arrow", this.hasAttribute("popover-arrow"));
|
|
75
|
-
this.popoverElement.toggleAttribute("trap-focus", this.hasAttribute("popover-trap-focus"));
|
|
76
|
-
if (this.popoverElement.open !== this.hasAttribute("open"))
|
|
77
|
-
this.popoverElement.open = this.hasAttribute("open");
|
|
78
|
-
this.syncContent();
|
|
79
|
-
}
|
|
80
|
-
syncContent() {
|
|
81
|
-
if (!this.contentSlot)
|
|
82
|
-
return;
|
|
83
|
-
this.contentSlot.textContent = !this.childNodes.length && this.hasAttribute("info") ? this.getAttribute("info") ?? "" : "";
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
customElements.define("spui-info-button", SpuiInfoButton);
|
|
87
|
-
}
|
|
88
|
-
/** Build a native form label with an adjacent, separately focusable information button. */
|
|
89
|
-
export function createInfoLabel(labelContent, info, options = {}) {
|
|
90
|
-
defineInfoButton();
|
|
91
|
-
const wrapper = document.createElement("span");
|
|
92
|
-
Object.assign(wrapper.style, { display: "inline-flex", alignItems: "baseline", gap: "0.25em" });
|
|
93
|
-
const label = createLabel(labelContent, options);
|
|
94
|
-
wrapper.append(label);
|
|
95
|
-
const button = document.createElement("spui-info-button");
|
|
96
|
-
button.setAttribute("label", options.infoButtonLabel ?? "More information");
|
|
97
|
-
if (options.placement)
|
|
98
|
-
button.setAttribute("placement", options.placement);
|
|
99
|
-
button.append(typeof info === "string" ? document.createTextNode(info) : info);
|
|
100
|
-
wrapper.append(button);
|
|
101
|
-
return wrapper;
|
|
102
|
-
}
|
package/dist/elements/input.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export type InputSize = "small" | "medium" | "large";
|
|
2
|
-
export type InputAppearance = "outline" | "underline" | "filled-darker" | "filled-lighter" | "filled-darker-shadow" | "filled-lighter-shadow";
|
|
3
|
-
export type InputType = "button" | "checkbox" | "color" | "date" | "datetime-local" | "email" | "file" | "hidden" | "image" | "month" | "number" | "password" | "radio" | "range" | "reset" | "search" | "submit" | "tel" | "text" | "time" | "url" | "week" | (string & {});
|
|
4
|
-
/** Bare, form-associated input; pair it with Label or Field for an accessible name. */
|
|
5
|
-
export declare function defineInput(): void;
|