@threadlabs/looma 0.14.7 → 0.15.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/components/shared/icons.js +5 -0
- package/components/shared/menu-navigation.js +49 -0
- package/components/shared/overlay.js +33 -60
- package/components/ui-avatar/ui-avatar.html +19 -2
- package/components/ui-avatar/ui-avatar.js +7 -1
- package/components/ui-avatar-group/ui-avatar-group.html +8 -3
- package/components/ui-avatar-group/ui-avatar-group.js +6 -2
- package/components/ui-badge/ui-badge.html +70 -4
- package/components/ui-button/ui-button.html +21 -5
- package/components/ui-button/ui-button.js +10 -0
- package/components/ui-callout/ui-callout.html +13 -5
- package/components/ui-checkbox/ui-checkbox.html +11 -0
- package/components/ui-combobox/ui-combobox.html +50 -10
- package/components/ui-combobox/ui-combobox.js +11 -8
- package/components/ui-context-menu/ui-context-menu.html +33 -5
- package/components/ui-context-menu/ui-context-menu.js +26 -17
- package/components/ui-dialog/ui-dialog.html +51 -8
- package/components/ui-dialog/ui-dialog.js +28 -7
- package/components/ui-disclosure/ui-disclosure.html +14 -5
- package/components/ui-disclosure/ui-disclosure.js +51 -4
- package/components/ui-editable/ui-editable.html +17 -3
- package/components/ui-editable/ui-editable.js +7 -0
- package/components/ui-editor-insert-table-grid/ui-editor-insert-table-grid.html +48 -14
- package/components/ui-editor-insert-table-grid/ui-editor-insert-table-grid.js +40 -6
- package/components/ui-editor-mention-menu/ui-editor-mention-menu.html +22 -9
- package/components/ui-editor-mention-menu/ui-editor-mention-menu.js +33 -11
- package/components/ui-editor-mention-menu-item/ui-editor-mention-menu-item.html +67 -0
- package/components/ui-editor-slash-menu/ui-editor-slash-menu.html +33 -30
- package/components/ui-editor-slash-menu/ui-editor-slash-menu.js +42 -8
- package/components/ui-editor-slash-menu-group/ui-editor-slash-menu-group.html +31 -0
- package/components/ui-editor-slash-menu-item/ui-editor-slash-menu-item.html +75 -0
- package/components/ui-editor-table-context-menu/ui-editor-table-context-menu.html +16 -5
- package/components/ui-editor-table-context-menu/ui-editor-table-context-menu.js +10 -2
- package/components/ui-editor-table-overlay/ui-editor-table-overlay.html +5 -5
- package/components/ui-editor-table-overlay/ui-editor-table-overlay.js +5 -2
- package/components/ui-editor-table-toolbar/ui-editor-table-toolbar.html +14 -4
- package/components/ui-editor-table-toolbar/ui-editor-table-toolbar.js +2 -2
- package/components/ui-editor-toolbar/ui-editor-toolbar.html +1 -1
- package/components/ui-editor-toolbar/ui-editor-toolbar.js +46 -0
- package/components/ui-floating-action-button/ui-floating-action-button.html +1 -1
- package/components/ui-form-field/ui-form-field.html +16 -3
- package/components/ui-form-field/ui-form-field.js +1 -1
- package/components/ui-grid/ui-grid.html +17 -2
- package/components/ui-icon/ui-icon.html +5 -0
- package/components/ui-icon-button/ui-icon-button.html +25 -6
- package/components/ui-icon-button/ui-icon-button.js +11 -1
- package/components/ui-input/ui-input.html +3 -3
- package/components/ui-input-group/ui-input-group.html +18 -4
- package/components/ui-listbox/ui-listbox.html +81 -0
- package/components/ui-listbox/ui-listbox.js +27 -0
- package/components/ui-menu/ui-menu.html +33 -5
- package/components/ui-menu/ui-menu.js +18 -12
- package/components/ui-menu-group/ui-menu-group.html +27 -0
- package/components/ui-menu-item/ui-menu-item.html +80 -8
- package/components/ui-menu-item/ui-menu-item.js +47 -0
- package/components/ui-popover/ui-popover.html +33 -5
- package/components/ui-popover/ui-popover.js +9 -1
- package/components/ui-radio-group/ui-radio-group.html +13 -1
- package/components/ui-search-shell/ui-search-shell.html +6 -6
- package/components/ui-search-shell/ui-search-shell.js +21 -5
- package/components/ui-select/ui-select.html +14 -4
- package/components/ui-switch/ui-switch.html +2 -2
- package/components/ui-switcher/ui-switcher.html +8 -1
- package/components/ui-switcher/ui-switcher.js +15 -0
- package/components/ui-tabs/ui-tabs.html +17 -12
- package/components/ui-tabs/ui-tabs.js +43 -7
- package/components/ui-textarea/ui-textarea.html +28 -5
- package/components/ui-toast/ui-toast.html +88 -0
- package/components/ui-toast/ui-toast.js +68 -0
- package/components/ui-toast-region/ui-toast-region.html +102 -19
- package/components/ui-toast-region/ui-toast-region.js +10 -18
- package/components/ui-tooltip/ui-tooltip.html +51 -7
- package/components/ui-tooltip/ui-tooltip.js +29 -3
- package/components/ui-tree/ui-tree.html +12 -0
- package/components/ui-tree/ui-tree.js +191 -12
- package/components/ui-tree-item/ui-tree-item.html +87 -8
- package/components/ui-tree-item/ui-tree-item.js +3 -1
- package/dist/index.js +38 -32
- package/editor/chunks/extensions.js +82 -2
- package/editor/extensions/table-commands.d.ts +8 -0
- package/editor/icons.d.ts +5 -0
- package/editor/index.js +7 -2
- package/editor/insert-table-grid.d.ts +1 -1
- package/editor/mention-menu.d.ts +2 -0
- package/editor/slash-menu.d.ts +3 -0
- package/editor/table-context-menu.d.ts +1 -1
- package/editor/table-overlay.d.ts +2 -2
- package/package.json +1 -1
- package/styles/ui-avatar-group.css +1 -2
- package/styles/ui-avatar.css +11 -1
- package/styles/ui-badge.css +73 -1
- package/styles/ui-button.css +9 -1
- package/styles/ui-callout.css +1 -1
- package/styles/ui-checkbox.css +9 -0
- package/styles/ui-combobox.css +38 -7
- package/styles/ui-context-menu.css +32 -4
- package/styles/ui-dialog.css +42 -5
- package/styles/ui-editor-insert-table-grid.css +48 -11
- package/styles/ui-editor-mention-menu-item.css +57 -0
- package/styles/ui-editor-mention-menu.css +11 -1
- package/styles/ui-editor-slash-menu-group.css +21 -0
- package/styles/ui-editor-slash-menu-item.css +62 -0
- package/styles/ui-editor-slash-menu.css +10 -21
- package/styles/ui-editor-table-context-menu.css +1 -1
- package/styles/ui-floating-action-button.css +1 -1
- package/styles/ui-form-field.css +14 -1
- package/styles/ui-grid.css +14 -1
- package/styles/ui-icon-button.css +17 -5
- package/styles/ui-input-group.css +18 -4
- package/styles/ui-input.css +3 -3
- package/styles/ui-listbox.css +69 -0
- package/styles/ui-menu-group.css +19 -0
- package/styles/ui-menu-item.css +48 -9
- package/styles/ui-menu.css +32 -4
- package/styles/ui-popover.css +28 -4
- package/styles/ui-radio-group.css +9 -0
- package/styles/ui-search-shell.css +5 -5
- package/styles/ui-select.css +14 -4
- package/styles/ui-switch.css +2 -2
- package/styles/ui-switcher.css +4 -0
- package/styles/ui-textarea.css +27 -4
- package/styles/ui-toast-region.css +88 -4
- package/styles/ui-toast.css +74 -0
- package/styles/ui-tooltip.css +46 -6
- package/styles/ui-tree-item.css +72 -4
- package/styles/ui-tree.css +8 -0
- package/tokens.css +3 -0
- package/vanilla/UiAvatar.d.ts +2 -0
- package/vanilla/UiAvatar.js +8 -1
- package/vanilla/UiAvatarGroup.d.ts +2 -0
- package/vanilla/UiAvatarGroup.js +1 -1
- package/vanilla/UiBadge.d.ts +1 -1
- package/vanilla/UiBadge.js +1 -1
- package/vanilla/UiButton.d.ts +1 -0
- package/vanilla/UiButton.js +22 -6
- package/vanilla/UiCallout.d.ts +1 -1
- package/vanilla/UiCallout.js +1 -1
- package/vanilla/UiCheckbox.d.ts +1 -0
- package/vanilla/UiCheckbox.js +12 -9
- package/vanilla/UiCombobox.d.ts +4 -0
- package/vanilla/UiCombobox.js +30 -15
- package/vanilla/UiContextMenu.d.ts +1 -1
- package/vanilla/UiContextMenu.js +1 -1
- package/vanilla/UiDialog.d.ts +5 -2
- package/vanilla/UiDialog.js +1 -1
- package/vanilla/UiDisclosure.d.ts +2 -0
- package/vanilla/UiDisclosure.js +32 -18
- package/vanilla/UiEditable.d.ts +5 -0
- package/vanilla/UiEditable.js +7 -3
- package/vanilla/UiEditorInsertTableGrid.js +1 -6
- package/vanilla/UiEditorMentionMenu.d.ts +4 -2
- package/vanilla/UiEditorMentionMenu.js +49 -31
- package/vanilla/UiEditorMentionMenuItem.d.ts +16 -0
- package/vanilla/UiEditorMentionMenuItem.js +56 -0
- package/vanilla/UiEditorSlashMenu.d.ts +4 -3
- package/vanilla/UiEditorSlashMenu.js +59 -46
- package/vanilla/UiEditorSlashMenuGroup.d.ts +14 -0
- package/vanilla/UiEditorSlashMenuGroup.js +48 -0
- package/vanilla/UiEditorSlashMenuItem.d.ts +18 -0
- package/vanilla/UiEditorSlashMenuItem.js +57 -0
- package/vanilla/UiEditorTableContextMenu.d.ts +5 -2
- package/vanilla/UiEditorTableContextMenu.js +1 -2
- package/vanilla/UiEditorTableOverlay.d.ts +1 -1
- package/vanilla/UiEditorTableOverlay.js +5 -5
- package/vanilla/UiEditorTableToolbar.d.ts +4 -2
- package/vanilla/UiEditorTableToolbar.js +1 -2
- package/vanilla/UiEditorToolbar.js +2 -0
- package/vanilla/UiGrid.d.ts +1 -0
- package/vanilla/UiGrid.js +8 -7
- package/vanilla/UiIcon.js +1 -1
- package/vanilla/UiIconButton.d.ts +1 -0
- package/vanilla/UiIconButton.js +11 -2
- package/vanilla/UiListbox.d.ts +20 -0
- package/vanilla/UiListbox.js +45 -0
- package/vanilla/UiMenu.d.ts +1 -1
- package/vanilla/UiMenu.js +1 -1
- package/vanilla/UiMenuGroup.d.ts +14 -0
- package/vanilla/UiMenuGroup.js +35 -0
- package/vanilla/UiMenuItem.d.ts +5 -1
- package/vanilla/UiMenuItem.js +91 -30
- package/vanilla/UiPopover.d.ts +1 -1
- package/vanilla/UiPopover.js +1 -1
- package/vanilla/UiRadioGroup.d.ts +1 -0
- package/vanilla/UiRadioGroup.js +6 -3
- package/vanilla/UiSwitcher.d.ts +1 -0
- package/vanilla/UiSwitcher.js +7 -9
- package/vanilla/UiTabs.d.ts +1 -0
- package/vanilla/UiTabs.js +9 -1
- package/vanilla/UiTextarea.d.ts +1 -0
- package/vanilla/UiTextarea.js +4 -1
- package/vanilla/UiToast.d.ts +16 -0
- package/vanilla/UiToast.js +53 -0
- package/vanilla/UiToastRegion.d.ts +1 -4
- package/vanilla/UiToastRegion.js +3 -11
- package/vanilla/UiTooltip.d.ts +1 -1
- package/vanilla/UiTooltip.js +1 -1
- package/vanilla/UiTree.d.ts +2 -0
- package/vanilla/UiTree.js +1 -1
- package/vanilla/UiTreeItem.d.ts +1 -0
- package/vanilla/UiTreeItem.js +45 -31
- package/vanilla/index.js +6 -0
- package/vue/UiAvatar.d.ts +4 -0
- package/vue/UiAvatar.vue +23 -3
- package/vue/UiAvatarGroup.d.ts +3 -0
- package/vue/UiAvatarGroup.vue +7 -4
- package/vue/UiBadge.d.ts +2 -2
- package/vue/UiBadge.vue +74 -2
- package/vue/UiButton.d.ts +5 -3
- package/vue/UiButton.vue +41 -7
- package/vue/UiCallout.d.ts +2 -2
- package/vue/UiCallout.vue +3 -2
- package/vue/UiCheckbox.d.ts +2 -0
- package/vue/UiCheckbox.vue +16 -0
- package/vue/UiCombobox.d.ts +13 -3
- package/vue/UiCombobox.vue +62 -11
- package/vue/UiContextMenu.d.ts +2 -0
- package/vue/UiContextMenu.vue +47 -6
- package/vue/UiDialog.d.ts +18 -4
- package/vue/UiDialog.vue +86 -11
- package/vue/UiDisclosure.d.ts +8 -2
- package/vue/UiDisclosure.vue +38 -14
- package/vue/UiEditable.d.ts +10 -0
- package/vue/UiEditable.vue +14 -2
- package/vue/UiEditorInsertTableGrid.vue +52 -15
- package/vue/UiEditorMentionMenu.d.ts +24 -2
- package/vue/UiEditorMentionMenu.vue +27 -11
- package/vue/UiEditorMentionMenuItem.d.ts +24 -0
- package/vue/UiEditorMentionMenuItem.js +2 -0
- package/vue/UiEditorMentionMenuItem.vue +88 -0
- package/vue/UiEditorSlashMenu.d.ts +24 -1
- package/vue/UiEditorSlashMenu.vue +33 -33
- package/vue/UiEditorSlashMenuGroup.d.ts +18 -0
- package/vue/UiEditorSlashMenuGroup.js +2 -0
- package/vue/UiEditorSlashMenuGroup.vue +43 -0
- package/vue/UiEditorSlashMenuItem.d.ts +26 -0
- package/vue/UiEditorSlashMenuItem.js +2 -0
- package/vue/UiEditorSlashMenuItem.vue +101 -0
- package/vue/UiEditorTableContextMenu.d.ts +9 -3
- package/vue/UiEditorTableContextMenu.vue +53 -3
- package/vue/UiEditorTableOverlay.d.ts +2 -2
- package/vue/UiEditorTableOverlay.vue +8 -6
- package/vue/UiEditorTableToolbar.d.ts +7 -3
- package/vue/UiEditorTableToolbar.vue +50 -2
- package/vue/UiEditorToolbar.vue +14 -1
- package/vue/UiFloatingActionButton.vue +1 -1
- package/vue/UiFormField.vue +28 -3
- package/vue/UiGrid.d.ts +1 -0
- package/vue/UiGrid.vue +26 -2
- package/vue/UiIcon.vue +16 -0
- package/vue/UiIconButton.d.ts +5 -3
- package/vue/UiIconButton.vue +40 -6
- package/vue/UiInput.vue +10 -3
- package/vue/UiInputGroup.vue +32 -11
- package/vue/UiListbox.d.ts +33 -0
- package/vue/UiListbox.js +2 -0
- package/vue/UiListbox.vue +131 -0
- package/vue/UiMenu.d.ts +2 -0
- package/vue/UiMenu.vue +43 -6
- package/vue/UiMenuGroup.d.ts +18 -0
- package/vue/UiMenuGroup.js +2 -0
- package/vue/UiMenuGroup.vue +39 -0
- package/vue/UiMenuItem.d.ts +34 -2
- package/vue/UiMenuItem.vue +145 -9
- package/vue/UiPopover.d.ts +2 -2
- package/vue/UiPopover.vue +44 -5
- package/vue/UiRadioGroup.d.ts +2 -0
- package/vue/UiRadioGroup.vue +17 -0
- package/vue/UiSearchShell.vue +12 -5
- package/vue/UiSelect.vue +18 -4
- package/vue/UiSwitch.vue +2 -2
- package/vue/UiSwitcher.d.ts +1 -0
- package/vue/UiSwitcher.vue +22 -1
- package/vue/UiTabs.d.ts +6 -2
- package/vue/UiTabs.vue +14 -12
- package/vue/UiTextarea.d.ts +2 -0
- package/vue/UiTextarea.vue +32 -4
- package/vue/UiToast.d.ts +34 -0
- package/vue/UiToast.js +2 -0
- package/vue/UiToast.vue +173 -0
- package/vue/UiToastRegion.d.ts +2 -18
- package/vue/UiToastRegion.vue +123 -48
- package/vue/UiTooltip.d.ts +2 -2
- package/vue/UiTooltip.vue +67 -12
- package/vue/UiTree.d.ts +10 -0
- package/vue/UiTree.vue +27 -0
- package/vue/UiTreeItem.d.ts +2 -0
- package/vue/UiTreeItem.vue +96 -4
- package/vue/chunks/UiAvatar.js +19 -5
- package/vue/chunks/UiAvatarGroup.js +10 -4
- package/vue/chunks/UiBadge.js +1 -1
- package/vue/chunks/UiButton.js +58 -11
- package/vue/chunks/UiCallout.js +2 -2
- package/vue/chunks/UiCheckbox.js +12 -2
- package/vue/chunks/UiCombobox.js +30 -13
- package/vue/chunks/UiContextMenu.js +6 -2
- package/vue/chunks/UiDialog.js +25 -8
- package/vue/chunks/UiDisclosure.js +36 -12
- package/vue/chunks/UiEditable.js +22 -8
- package/vue/chunks/UiEditorInsertTableGrid.js +11 -14
- package/vue/chunks/UiEditorMentionMenu.js +30 -19
- package/vue/chunks/UiEditorMentionMenuItem.js +36 -0
- package/vue/chunks/UiEditorSlashMenu.js +33 -35
- package/vue/chunks/UiEditorSlashMenuGroup.js +26 -0
- package/vue/chunks/UiEditorSlashMenuItem.js +51 -0
- package/vue/chunks/UiEditorTableContextMenu.js +39 -5
- package/vue/chunks/UiEditorTableOverlay.js +6 -6
- package/vue/chunks/UiEditorTableToolbar.js +37 -4
- package/vue/chunks/UiEditorToolbar.js +18 -4
- package/vue/chunks/UiFloatingActionButton.js +1 -1
- package/vue/chunks/UiFormField.js +13 -9
- package/vue/chunks/UiGrid.js +6 -2
- package/vue/chunks/UiIcon.js +40 -2
- package/vue/chunks/UiIconButton.js +35 -4
- package/vue/chunks/UiInput.js +1 -1
- package/vue/chunks/UiInputGroup.js +1 -1
- package/vue/chunks/UiListbox.js +70 -0
- package/vue/chunks/UiMenu.js +6 -2
- package/vue/chunks/UiMenuGroup.js +25 -0
- package/vue/chunks/UiMenuItem.js +128 -7
- package/vue/chunks/UiPopover.js +1 -1
- package/vue/chunks/UiRadioGroup.js +8 -2
- package/vue/chunks/UiSearchShell.js +1 -1
- package/vue/chunks/UiSelect.js +1 -1
- package/vue/chunks/UiSwitch.js +1 -1
- package/vue/chunks/UiSwitcher.js +20 -3
- package/vue/chunks/UiTabs.js +4 -3
- package/vue/chunks/UiTextarea.js +7 -2
- package/vue/chunks/UiToast.js +81 -0
- package/vue/chunks/UiToastRegion.js +25 -49
- package/vue/chunks/UiTooltip.js +3 -7
- package/vue/chunks/UiTree.js +8 -4
- package/vue/chunks/UiTreeItem.js +28 -10
- package/vue/components.css +1840 -851
- package/vue/editor/index.js +263 -2
- package/vue/index.d.ts +6 -0
- package/vue/index.js +9 -3
|
@@ -1,28 +1,75 @@
|
|
|
1
1
|
import { trackTrigger } from "../shared/trigger.js";
|
|
2
2
|
|
|
3
3
|
let disclosures = 0;
|
|
4
|
+
const groups = new WeakMap();
|
|
5
|
+
|
|
6
|
+
function groupFor(document, name) {
|
|
7
|
+
let byName = groups.get(document);
|
|
8
|
+
if (!byName) { byName = new Map(); groups.set(document, byName); }
|
|
9
|
+
let members = byName.get(name);
|
|
10
|
+
if (!members) { members = new Set(); byName.set(name, members); }
|
|
11
|
+
return members;
|
|
12
|
+
}
|
|
4
13
|
|
|
5
14
|
// `open` sets the disclosure initially and whenever it changes; the trigger toggles the state.
|
|
6
15
|
export default function controller(host) {
|
|
16
|
+
const document = host.element.ownerDocument;
|
|
7
17
|
const [trigger, stopTracking] = trackTrigger(host);
|
|
8
18
|
host.state.contentId = `ui-disclosure-${++disclosures}`;
|
|
9
19
|
let external = host.state.open;
|
|
10
20
|
host.state.internalOpen = Boolean(external);
|
|
21
|
+
let groupName = "";
|
|
22
|
+
const member = {
|
|
23
|
+
close(reason, how) {
|
|
24
|
+
if (!host.state.internalOpen) return;
|
|
25
|
+
host.state.internalOpen = false;
|
|
26
|
+
host.dispatch("close", { open: false, reason, trigger: how });
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
const syncGroup = (reason, how) => {
|
|
30
|
+
const name = String(host.state.name || "");
|
|
31
|
+
if (name !== groupName) {
|
|
32
|
+
if (groupName) groupFor(document, groupName).delete(member);
|
|
33
|
+
groupName = name;
|
|
34
|
+
if (groupName) groupFor(document, groupName).add(member);
|
|
35
|
+
}
|
|
36
|
+
if (name && host.state.internalOpen) {
|
|
37
|
+
for (const peer of groupFor(document, name)) if (peer !== member) peer.close(reason, how);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
11
40
|
const stop = host.effect(() => {
|
|
12
|
-
if (host.state.open
|
|
13
|
-
|
|
14
|
-
|
|
41
|
+
if (host.state.open !== external) {
|
|
42
|
+
external = host.state.open;
|
|
43
|
+
host.state.internalOpen = Boolean(external);
|
|
44
|
+
}
|
|
45
|
+
const level = Number(host.state.headingLevel);
|
|
46
|
+
host.state.headingRole = Number.isInteger(level) && level >= 2 && level <= 6 ? "heading" : null;
|
|
47
|
+
host.state.headingAriaLevel = host.state.headingRole ? level : null;
|
|
48
|
+
syncGroup("programmatic", "programmatic");
|
|
49
|
+
if (host.state.internalOpen) host.refs.panel.removeAttribute("hidden");
|
|
50
|
+
else host.refs.panel.setAttribute("hidden", "until-found");
|
|
15
51
|
});
|
|
16
52
|
const onClick = () => {
|
|
17
53
|
if (host.state.disabled) return;
|
|
18
54
|
const open = !host.state.internalOpen;
|
|
55
|
+
const how = trigger();
|
|
19
56
|
host.state.internalOpen = open;
|
|
20
|
-
|
|
57
|
+
if (open) syncGroup("action", how);
|
|
58
|
+
host.dispatch(open ? "open" : "close", { open, reason: "action", trigger: how });
|
|
21
59
|
};
|
|
60
|
+
const onBeforematch = () => queueMicrotask(() => {
|
|
61
|
+
if (host.state.internalOpen) return;
|
|
62
|
+
host.state.internalOpen = true;
|
|
63
|
+
syncGroup("programmatic", "programmatic");
|
|
64
|
+
host.dispatch("open", { open: true, reason: "programmatic", trigger: "programmatic" });
|
|
65
|
+
});
|
|
22
66
|
host.refs.trigger.addEventListener("click", onClick);
|
|
67
|
+
host.refs.panel.addEventListener("beforematch", onBeforematch);
|
|
23
68
|
return () => {
|
|
24
69
|
stop();
|
|
25
70
|
stopTracking();
|
|
71
|
+
if (groupName) groupFor(document, groupName).delete(member);
|
|
26
72
|
host.refs.trigger.removeEventListener("click", onClick);
|
|
73
|
+
host.refs.panel.removeEventListener("beforematch", onBeforematch);
|
|
27
74
|
};
|
|
28
75
|
}
|
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
<prop name="hint" type="string" default="">Optional text shown beside the value to signal it is editable (for example "Edit").</prop>
|
|
10
10
|
<prop name="actions" type="boolean" default="false"
|
|
11
11
|
>Show explicit Save and Cancel buttons while editing. Without them, Enter or leaving the field saves and Escape cancels.</prop>
|
|
12
|
+
<prop name="saveLabel" type="string" default="Save">Visible text for the Save action.</prop>
|
|
13
|
+
<prop name="cancelLabel" type="string" default="Cancel">Visible text for the Cancel action.</prop>
|
|
14
|
+
<prop name="placeholder" type="string" default="">Hint shown in the text input while the draft is empty.</prop>
|
|
15
|
+
<prop name="required" type="boolean" default="false">Prevent an empty draft from being saved.</prop>
|
|
16
|
+
<prop name="maxLength" type="number" default="0">Maximum draft length; 0 leaves the length unrestricted.</prop>
|
|
12
17
|
<state name="internalEdit" :value="false"></state>
|
|
13
18
|
<state name="internalValue" :value="''"></state>
|
|
14
19
|
<state name="draft" :value="''"></state>
|
|
@@ -25,11 +30,20 @@
|
|
|
25
30
|
<span class="text" $value="internalValue"></span>
|
|
26
31
|
<span $if="hint" class="hint" aria-hidden="true" $value="hint"></span>
|
|
27
32
|
</button>
|
|
28
|
-
<input
|
|
33
|
+
<input
|
|
34
|
+
class="input"
|
|
35
|
+
$ref="input"
|
|
36
|
+
type="text"
|
|
37
|
+
.value="draft"
|
|
38
|
+
:aria-label="label"
|
|
39
|
+
:placeholder="placeholder"
|
|
40
|
+
:required="required"
|
|
41
|
+
:disabled="disabled or not internalEdit"
|
|
42
|
+
>
|
|
29
43
|
</div>
|
|
30
44
|
<div $if="actions" class="actions">
|
|
31
|
-
<button class="save" type="button"
|
|
32
|
-
<button class="cancel" type="button"
|
|
45
|
+
<button class="save" type="button" $value="saveLabel"></button>
|
|
46
|
+
<button class="cancel" type="button" $value="cancelLabel"></button>
|
|
33
47
|
</div>
|
|
34
48
|
</div>
|
|
35
49
|
<style>
|
|
@@ -29,6 +29,9 @@ export default function controller(host) {
|
|
|
29
29
|
}
|
|
30
30
|
// The inactive input stays in layout (it shares the value's cell) but out of the tab order.
|
|
31
31
|
input.tabIndex = host.state.internalEdit ? 0 : -1;
|
|
32
|
+
const maxLength = Number(host.state.maxLength);
|
|
33
|
+
if (Number.isFinite(maxLength) && maxLength > 0) input.maxLength = Math.floor(maxLength);
|
|
34
|
+
else input.removeAttribute("maxlength");
|
|
32
35
|
};
|
|
33
36
|
|
|
34
37
|
const setEditing = (next, reason, trigger, returnFocus = true) => {
|
|
@@ -55,6 +58,10 @@ export default function controller(host) {
|
|
|
55
58
|
const commit = (trigger, returnFocus) => {
|
|
56
59
|
const previousValue = String(host.state.internalValue ?? "");
|
|
57
60
|
const value = String(host.state.draft ?? "");
|
|
61
|
+
if (!input.checkValidity() || (input.maxLength >= 0 && value.length > input.maxLength)) {
|
|
62
|
+
input.reportValidity();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
58
65
|
host.state.internalValue = value;
|
|
59
66
|
setEditing(false, "commit", trigger, returnFocus);
|
|
60
67
|
if (value !== previousValue) host.dispatch("change", { value, previousValue, trigger });
|
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
<prop name="maxRows" type="integer" default="8">The most rows the grid offers (at most 10).</prop>
|
|
5
5
|
<prop name="maxCols" type="integer" default="8">The most columns the grid offers (at most 10).</prop>
|
|
6
6
|
<prop name="headerRow" type="boolean" default="false">Whether table insertion initially includes a header row.</prop>
|
|
7
|
-
<state
|
|
7
|
+
<state
|
|
8
|
+
name="cells"
|
|
9
|
+
type="list(object({ key: string, row: integer, col: integer, label: string, selected: boolean, tabIndex: integer }))"
|
|
10
|
+
:value="[]"
|
|
11
|
+
></state>
|
|
8
12
|
<state name="rows" :value="8"></state>
|
|
9
13
|
<state name="cols" :value="8"></state>
|
|
10
14
|
<state name="hint" :value="''"></state>
|
|
@@ -13,7 +17,7 @@
|
|
|
13
17
|
</defs>
|
|
14
18
|
<div :hidden="not open">
|
|
15
19
|
<p class="hint" $value="hint"></p>
|
|
16
|
-
<div class="grid" role="group" aria-label="Table dimensions" style:--_rows="rows" style:--_cols="cols">
|
|
20
|
+
<div class="grid" $ref="grid" role="group" aria-label="Table dimensions" style:--_rows="rows" style:--_cols="cols">
|
|
17
21
|
<button
|
|
18
22
|
$each="cell of cells"
|
|
19
23
|
$key="cell.key"
|
|
@@ -24,11 +28,11 @@
|
|
|
24
28
|
:data-col="cell.col"
|
|
25
29
|
:aria-label="cell.label"
|
|
26
30
|
:aria-pressed="cell.selected"
|
|
31
|
+
:tabindex="cell.tabIndex"
|
|
27
32
|
>
|
|
28
33
|
</button>
|
|
29
34
|
</div>
|
|
30
35
|
<label class="header"><input type="checkbox" $ref="header" .checked="withHeaderRow"> Header row</label>
|
|
31
|
-
<button type="button" class="insert" $ref="insert">Insert table</button>
|
|
32
36
|
</div>
|
|
33
37
|
<style>
|
|
34
38
|
:host {
|
|
@@ -51,6 +55,28 @@
|
|
|
51
55
|
grid-template-rows: repeat(var(--_rows, 8), 1.25rem);
|
|
52
56
|
gap: 2px;
|
|
53
57
|
margin-bottom: var(--ui-space-2);
|
|
58
|
+
max-inline-size: 100%;
|
|
59
|
+
overflow: auto;
|
|
60
|
+
--_ui-scroll-fade-direction: to right;
|
|
61
|
+
--_ui-scroll-fade-size: var(--ui-scroll-fade-size, 24px);
|
|
62
|
+
mask-image: linear-gradient(
|
|
63
|
+
var(--_ui-scroll-fade-direction),
|
|
64
|
+
transparent,
|
|
65
|
+
#000 var(--_ui-scroll-fade-start),
|
|
66
|
+
#000 calc(100% - var(--_ui-scroll-fade-end)),
|
|
67
|
+
transparent
|
|
68
|
+
);
|
|
69
|
+
animation: ui-scroll-fade-start linear, ui-scroll-fade-start-hold linear, ui-scroll-fade-end-hold linear, ui-scroll-fade-end linear;
|
|
70
|
+
animation-timeline: scroll(self inline);
|
|
71
|
+
animation-range:
|
|
72
|
+
0 var(--_ui-scroll-fade-size),
|
|
73
|
+
var(--_ui-scroll-fade-size) calc(100% + 1px),
|
|
74
|
+
-1px calc(100% - var(--_ui-scroll-fade-size)),
|
|
75
|
+
calc(100% - var(--_ui-scroll-fade-size)) 100%;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
:host:dir(rtl) .grid {
|
|
79
|
+
--_ui-scroll-fade-direction: to left;
|
|
54
80
|
}
|
|
55
81
|
|
|
56
82
|
.cell {
|
|
@@ -68,6 +94,11 @@
|
|
|
68
94
|
border-color: var(--ui-accent-solid, var(--ui-accent));
|
|
69
95
|
}
|
|
70
96
|
|
|
97
|
+
.cell:focus-visible {
|
|
98
|
+
outline: 2px solid var(--ui-focus-ring);
|
|
99
|
+
outline-offset: -2px;
|
|
100
|
+
}
|
|
101
|
+
|
|
71
102
|
.header {
|
|
72
103
|
display: block;
|
|
73
104
|
margin-bottom: var(--ui-space-2);
|
|
@@ -75,19 +106,22 @@
|
|
|
75
106
|
cursor: pointer;
|
|
76
107
|
}
|
|
77
108
|
|
|
78
|
-
:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
109
|
+
@media (pointer: coarse) {
|
|
110
|
+
.grid {
|
|
111
|
+
grid-template-columns: repeat(var(--_cols, 8), 44px);
|
|
112
|
+
grid-template-rows: repeat(var(--_rows, 8), 44px);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.cell {
|
|
116
|
+
width: 44px;
|
|
117
|
+
height: 44px;
|
|
118
|
+
}
|
|
87
119
|
}
|
|
88
120
|
|
|
89
|
-
|
|
90
|
-
|
|
121
|
+
@media (forced-colors: active) {
|
|
122
|
+
.cell:focus-visible {
|
|
123
|
+
outline-color: Highlight;
|
|
124
|
+
}
|
|
91
125
|
}
|
|
92
126
|
|
|
93
127
|
:host[hidden] {
|
|
@@ -3,26 +3,26 @@ function bounded(value, fallback) {
|
|
|
3
3
|
return Math.min(10, Math.max(1, Number.isFinite(parsed) ? parsed : fallback));
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
// Lays out the grid cells
|
|
6
|
+
// Lays out the grid cells and inserts the chosen size by pointer or keyboard.
|
|
7
7
|
export default function controller(host) {
|
|
8
8
|
const element = host.element;
|
|
9
9
|
let selected = { rows: 3, cols: 3 };
|
|
10
10
|
let preview = null;
|
|
11
|
-
let committed = false;
|
|
12
11
|
let lastHeaderRow = Boolean(host.state.headerRow);
|
|
13
12
|
host.state.withHeaderRow = lastHeaderRow;
|
|
14
13
|
|
|
15
14
|
const update = () => {
|
|
16
15
|
const rows = bounded(host.state.maxRows, 8);
|
|
17
16
|
const cols = bounded(host.state.maxCols, 8);
|
|
17
|
+
selected = { rows: Math.min(selected.rows, rows), cols: Math.min(selected.cols, cols) };
|
|
18
18
|
const active = preview ?? selected;
|
|
19
19
|
host.state.rows = rows;
|
|
20
20
|
host.state.cols = cols;
|
|
21
|
-
host.state.hint =
|
|
21
|
+
host.state.hint = `${active.rows} × ${active.cols}`;
|
|
22
22
|
host.state.cells = Array.from({ length: rows * cols }, (_, index) => {
|
|
23
23
|
const row = Math.floor(index / cols) + 1;
|
|
24
24
|
const col = (index % cols) + 1;
|
|
25
|
-
return { key: `${row}:${col}`, row, col, label: `${row} rows by ${col} columns`, selected: row <= active.rows && col <= active.cols };
|
|
25
|
+
return { key: `${row}:${col}`, row, col, label: `${row} rows by ${col} columns`, selected: row <= active.rows && col <= active.cols, tabIndex: row === active.rows && col === active.cols ? 0 : -1 };
|
|
26
26
|
});
|
|
27
27
|
};
|
|
28
28
|
const stop = host.effect(() => {
|
|
@@ -42,9 +42,7 @@ export default function controller(host) {
|
|
|
42
42
|
if (cell) {
|
|
43
43
|
selected = cell;
|
|
44
44
|
preview = null;
|
|
45
|
-
committed = true;
|
|
46
45
|
update();
|
|
47
|
-
} else if (host.refs.insert.contains(event.target)) {
|
|
48
46
|
host.dispatch("insert", { ...selected, withHeaderRow: host.state.withHeaderRow });
|
|
49
47
|
}
|
|
50
48
|
};
|
|
@@ -54,18 +52,54 @@ export default function controller(host) {
|
|
|
54
52
|
update();
|
|
55
53
|
};
|
|
56
54
|
const onMouseleave = () => {
|
|
55
|
+
if (host.refs.grid.contains(element.ownerDocument.activeElement)) return;
|
|
57
56
|
preview = null;
|
|
58
57
|
update();
|
|
59
58
|
};
|
|
59
|
+
const onFocusin = (event) => {
|
|
60
|
+
const cell = cellOf(event);
|
|
61
|
+
if (!cell) return;
|
|
62
|
+
preview = cell;
|
|
63
|
+
update();
|
|
64
|
+
};
|
|
65
|
+
const onFocusout = () => queueMicrotask(() => {
|
|
66
|
+
if (host.refs.grid.contains(element.ownerDocument.activeElement)) return;
|
|
67
|
+
preview = null;
|
|
68
|
+
update();
|
|
69
|
+
});
|
|
70
|
+
const onKeydown = (event) => {
|
|
71
|
+
const current = cellOf(event);
|
|
72
|
+
if (!current) return;
|
|
73
|
+
const rows = host.state.rows;
|
|
74
|
+
const cols = host.state.cols;
|
|
75
|
+
let next = current;
|
|
76
|
+
if (event.key === "ArrowRight") next = { ...current, cols: Math.min(cols, current.cols + 1) };
|
|
77
|
+
else if (event.key === "ArrowLeft") next = { ...current, cols: Math.max(1, current.cols - 1) };
|
|
78
|
+
else if (event.key === "ArrowDown") next = { ...current, rows: Math.min(rows, current.rows + 1) };
|
|
79
|
+
else if (event.key === "ArrowUp") next = { ...current, rows: Math.max(1, current.rows - 1) };
|
|
80
|
+
else if (event.key === "Home") next = { ...current, cols: 1 };
|
|
81
|
+
else if (event.key === "End") next = { ...current, cols };
|
|
82
|
+
else return;
|
|
83
|
+
event.preventDefault();
|
|
84
|
+
const cell = Array.from(host.refs.grid.querySelectorAll("[data-row][data-col]")).find((candidate) =>
|
|
85
|
+
Number(candidate.dataset.row) === next.rows && Number(candidate.dataset.col) === next.cols);
|
|
86
|
+
cell?.focus();
|
|
87
|
+
};
|
|
60
88
|
element.addEventListener("click", onClick);
|
|
61
89
|
element.addEventListener("mouseover", onMouseover);
|
|
62
90
|
element.addEventListener("mouseleave", onMouseleave);
|
|
91
|
+
element.addEventListener("focusin", onFocusin);
|
|
92
|
+
element.addEventListener("focusout", onFocusout);
|
|
93
|
+
element.addEventListener("keydown", onKeydown);
|
|
63
94
|
host.refs.header.addEventListener("change", onChange);
|
|
64
95
|
return () => {
|
|
65
96
|
stop();
|
|
66
97
|
element.removeEventListener("click", onClick);
|
|
67
98
|
element.removeEventListener("mouseover", onMouseover);
|
|
68
99
|
element.removeEventListener("mouseleave", onMouseleave);
|
|
100
|
+
element.removeEventListener("focusin", onFocusin);
|
|
101
|
+
element.removeEventListener("focusout", onFocusout);
|
|
102
|
+
element.removeEventListener("keydown", onKeydown);
|
|
69
103
|
host.refs.header.removeEventListener("change", onChange);
|
|
70
104
|
};
|
|
71
105
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<link rel="component" href="../ui-editor-mention-menu-item/ui-editor-mention-menu-item.html">
|
|
1
2
|
<template component="ui-editor-mention-menu" controller="./ui-editor-mention-menu.js">
|
|
2
3
|
<defs>
|
|
3
4
|
<prop name="open" type="boolean" default="false">Whether the menu is open.</prop>
|
|
@@ -7,6 +8,8 @@
|
|
|
7
8
|
>The zero-based index of the highlighted person, capped at the last one shown, and announced through aria-activedescendant. The menu does not handle arrow
|
|
8
9
|
keys itself: the editor sets this as the user moves, while hovering a person highlights them and reports a highlight event.</prop>
|
|
9
10
|
<prop name="loading" type="boolean" default="false">Whether a search is in progress.</prop>
|
|
11
|
+
<prop name="label" type="string" default="Mentions">Accessible name of the suggestion list.</prop>
|
|
12
|
+
<prop name="loadingLabel" type="string" default="Searching…">Status text shown while loading an empty result list.</prop>
|
|
10
13
|
<prop
|
|
11
14
|
name="anchorRect"
|
|
12
15
|
type="object({ left?: number, top?: number, right?: number, bottom?: number, x?: number, y?: number, width?: number, height?: number }) | null"
|
|
@@ -16,15 +19,12 @@
|
|
|
16
19
|
<state name="searching" :value="false"></state>
|
|
17
20
|
<state name="active" :value="0"></state>
|
|
18
21
|
<state name="prefix" :value="'ui-editor-mention-menu'"></state>
|
|
19
|
-
<event name="highlight" type="object({ index: integer })"></event>
|
|
20
|
-
<event name="select" type="object({ index: integer })"></event>
|
|
22
|
+
<event name="highlight" type="object({ index: integer, value: string })"></event>
|
|
23
|
+
<event name="select" type="object({ index: integer, value: string })"></event>
|
|
21
24
|
</defs>
|
|
22
|
-
<div role="listbox"
|
|
23
|
-
<div class="header">
|
|
24
|
-
|
|
25
|
-
<span class="hint">Type after @ to search</span>
|
|
26
|
-
</div>
|
|
27
|
-
<div $if="searching" class="loading" role="status">Searching…</div>
|
|
25
|
+
<div role="listbox" :aria-busy="loading" :hidden="not visible">
|
|
26
|
+
<div class="header"><slot name="header"></slot></div>
|
|
27
|
+
<div $if="searching" class="loading" role="status" $value="loadingLabel"></div>
|
|
28
28
|
<ul $if="not searching" class="list" role="presentation">
|
|
29
29
|
<li
|
|
30
30
|
$each="row, index of rows"
|
|
@@ -34,11 +34,14 @@
|
|
|
34
34
|
role="option"
|
|
35
35
|
:aria-selected="index = active"
|
|
36
36
|
:data-index="index"
|
|
37
|
+
:data-value="row.id"
|
|
37
38
|
>
|
|
38
39
|
<span class="avatar" aria-hidden="true" $value="row.initials"></span>
|
|
39
40
|
<span class="body"><span class="label" $value="row.label"></span><span $if="row.detail" class="detail" $value="row.detail"></span></span>
|
|
40
41
|
</li>
|
|
42
|
+
<slot></slot>
|
|
41
43
|
</ul>
|
|
44
|
+
<div class="empty" $ref="empty"><slot name="empty"></slot></div>
|
|
42
45
|
</div>
|
|
43
46
|
<style>
|
|
44
47
|
:host {
|
|
@@ -67,6 +70,16 @@
|
|
|
67
70
|
font-weight: var(--ui-font-semibold);
|
|
68
71
|
}
|
|
69
72
|
|
|
73
|
+
.header:not(:has(> *)), .empty:not(:has(> *)) {
|
|
74
|
+
display: none;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.empty {
|
|
78
|
+
padding: var(--ui-space-3);
|
|
79
|
+
color: var(--ui-text-muted);
|
|
80
|
+
font-size: var(--ui-font-size-sm);
|
|
81
|
+
}
|
|
82
|
+
|
|
70
83
|
.hint {
|
|
71
84
|
overflow: hidden;
|
|
72
85
|
color: var(--ui-text-muted);
|
|
@@ -123,7 +136,7 @@
|
|
|
123
136
|
flex: 0 0 auto;
|
|
124
137
|
color: var(--ui-accent-active, var(--ui-accent-solid));
|
|
125
138
|
background: var(--ui-accent-soft, var(--ui-accent-subtle));
|
|
126
|
-
border-radius:
|
|
139
|
+
border-radius: var(--ui-radius-round);
|
|
127
140
|
font-size: var(--ui-font-size-xs);
|
|
128
141
|
font-weight: var(--ui-font-semibold);
|
|
129
142
|
}
|
|
@@ -3,33 +3,54 @@ import { normalizeAnchor, positionMenu } from "../shared/editor.js";
|
|
|
3
3
|
// Places the menu at the @ and derives its rows; the template renders them.
|
|
4
4
|
export default function controller(host) {
|
|
5
5
|
const element = host.element;
|
|
6
|
+
const authoredLabel = element.hasAttribute("aria-label") || element.hasAttribute("aria-labelledby");
|
|
6
7
|
const place = () => {
|
|
7
8
|
if (host.state.visible) positionMenu(element, normalizeAnchor(host.state.anchorRect), 320);
|
|
8
9
|
};
|
|
10
|
+
const options = () => Array.from(element.querySelectorAll('[role="option"]'));
|
|
11
|
+
const syncOptions = () => {
|
|
12
|
+
const rows = options();
|
|
13
|
+
const active = Math.min(Math.max(0, host.state.active), Math.max(0, rows.length - 1));
|
|
14
|
+
rows.forEach((row, index) => {
|
|
15
|
+
row.dataset.index = String(index);
|
|
16
|
+
row.id = `${host.state.prefix}-option-${index}`;
|
|
17
|
+
row.setAttribute("aria-selected", String(index === active));
|
|
18
|
+
});
|
|
19
|
+
if (rows.length) element.setAttribute("aria-activedescendant", rows[active].id);
|
|
20
|
+
else element.removeAttribute("aria-activedescendant");
|
|
21
|
+
const empty = Boolean(host.refs.empty.children.length);
|
|
22
|
+
host.refs.empty.hidden = rows.length > 0 || host.state.loading;
|
|
23
|
+
const visible = Boolean(host.state.open && normalizeAnchor(host.state.anchorRect)
|
|
24
|
+
&& (host.state.loading || rows.length > 0 || empty));
|
|
25
|
+
if (host.state.visible !== visible) host.state.visible = visible;
|
|
26
|
+
place();
|
|
27
|
+
};
|
|
9
28
|
const stop = host.effect(() => {
|
|
29
|
+
if (!authoredLabel) element.setAttribute("aria-label", String(host.state.label || "Mentions"));
|
|
10
30
|
const items = (Array.isArray(host.state.items) ? host.state.items : []).slice(0, 20);
|
|
11
31
|
host.state.rows = items.map((item) => ({ ...item, initials: item.initials ?? String(item.label).slice(0, 2).toUpperCase() }));
|
|
12
32
|
host.state.searching = Boolean(host.state.loading && !items.length);
|
|
13
33
|
host.state.active = Math.min(Number(host.state.selectedIndex ?? 0), Math.max(0, items.length - 1));
|
|
14
34
|
host.state.prefix = element.id || "ui-editor-mention-menu";
|
|
15
|
-
|
|
16
|
-
if (items.length) element.setAttribute("aria-activedescendant", `${host.state.prefix}-option-${host.state.active}`);
|
|
17
|
-
else element.removeAttribute("aria-activedescendant");
|
|
18
|
-
place();
|
|
35
|
+
queueMicrotask(syncOptions);
|
|
19
36
|
});
|
|
20
|
-
const
|
|
37
|
+
const rowOf = (event) => event.target.closest?.('[role="option"]');
|
|
21
38
|
const onMousedown = (event) => event.preventDefault();
|
|
22
39
|
const onClick = (event) => {
|
|
23
|
-
const
|
|
24
|
-
if (
|
|
40
|
+
const row = rowOf(event);
|
|
41
|
+
if (row) host.dispatch("select", { index: Number(row.dataset.index), value: row.dataset.value ?? "" });
|
|
25
42
|
};
|
|
26
43
|
const onMouseover = (event) => {
|
|
27
|
-
const
|
|
28
|
-
if (!
|
|
44
|
+
const row = rowOf(event);
|
|
45
|
+
if (!row) return;
|
|
46
|
+
const index = Number(row.dataset.index);
|
|
47
|
+
if (index === host.state.active) return;
|
|
29
48
|
host.state.active = index;
|
|
30
|
-
|
|
31
|
-
host.dispatch("highlight", { index });
|
|
49
|
+
syncOptions();
|
|
50
|
+
host.dispatch("highlight", { index, value: row.dataset.value ?? "" });
|
|
32
51
|
};
|
|
52
|
+
const observer = new MutationObserver(syncOptions);
|
|
53
|
+
observer.observe(element, { childList: true, subtree: true });
|
|
33
54
|
element.addEventListener("mousedown", onMousedown);
|
|
34
55
|
element.addEventListener("click", onClick);
|
|
35
56
|
element.addEventListener("mouseover", onMouseover);
|
|
@@ -39,6 +60,7 @@ export default function controller(host) {
|
|
|
39
60
|
window.visualViewport?.addEventListener("scroll", place);
|
|
40
61
|
return () => {
|
|
41
62
|
stop();
|
|
63
|
+
observer.disconnect();
|
|
42
64
|
element.removeEventListener("mousedown", onMousedown);
|
|
43
65
|
element.removeEventListener("click", onClick);
|
|
44
66
|
element.removeEventListener("mouseover", onMouseover);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<template component="ui-editor-mention-menu-item">
|
|
2
|
+
<defs>
|
|
3
|
+
<prop name="value" type="string" default="">Stable identifier reported by the containing Mention Menu when this person is chosen.</prop>
|
|
4
|
+
<prop name="detail" type="string" default="">Secondary text, such as a team or role.</prop>
|
|
5
|
+
<prop name="initials" type="string" default="">Text fallback for the start slot when no avatar is supplied.</prop>
|
|
6
|
+
</defs>
|
|
7
|
+
<li role="option" tabindex="-1" :data-value="value">
|
|
8
|
+
<span class="avatar" aria-hidden="true"><slot name="start"><template $value="initials"></template></slot></span>
|
|
9
|
+
<span class="body"><span class="label"><slot></slot></span><span $if="detail" class="detail" $value="detail"></span></span>
|
|
10
|
+
</li>
|
|
11
|
+
<style>
|
|
12
|
+
:host {
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
min-block-size: 44px;
|
|
16
|
+
padding: var(--ui-space-2) var(--ui-space-3);
|
|
17
|
+
gap: var(--ui-space-3);
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
list-style: none;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
:host[aria-selected="true"] {
|
|
23
|
+
background: var(--ui-accent-subtle);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.avatar {
|
|
27
|
+
display: inline-flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
justify-content: center;
|
|
30
|
+
inline-size: 32px;
|
|
31
|
+
block-size: 32px;
|
|
32
|
+
flex: 0 0 auto;
|
|
33
|
+
color: var(--ui-accent-active);
|
|
34
|
+
background: var(--ui-accent-soft);
|
|
35
|
+
border-radius: var(--ui-radius-round);
|
|
36
|
+
font-size: var(--ui-font-size-xs);
|
|
37
|
+
font-weight: var(--ui-font-semibold);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.body {
|
|
41
|
+
display: flex;
|
|
42
|
+
min-inline-size: 0;
|
|
43
|
+
flex-direction: column;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.label, .detail {
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
text-overflow: ellipsis;
|
|
49
|
+
white-space: nowrap;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.label {
|
|
53
|
+
color: var(--ui-text-primary);
|
|
54
|
+
font-size: var(--ui-font-size-sm);
|
|
55
|
+
font-weight: var(--ui-font-medium);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.detail {
|
|
59
|
+
color: var(--ui-text-muted);
|
|
60
|
+
font-size: var(--ui-font-size-xs);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
:host[hidden] {
|
|
64
|
+
display: none;
|
|
65
|
+
}
|
|
66
|
+
</style>
|
|
67
|
+
</template>
|