@threadlabs/looma 0.14.8 → 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 +46 -10
- package/components/ui-combobox/ui-combobox.js +5 -5
- 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 +3 -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 +11 -3
- package/vue/UiCombobox.vue +60 -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 +29 -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
|
@@ -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>
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
<link rel="component" href="../ui-icon/ui-icon.html">
|
|
2
|
+
<link rel="component" href="../ui-editor-slash-menu-item/ui-editor-slash-menu-item.html">
|
|
3
|
+
<link rel="component" href="../ui-editor-slash-menu-group/ui-editor-slash-menu-group.html">
|
|
2
4
|
<template component="ui-editor-slash-menu" controller="./ui-editor-slash-menu.js">
|
|
3
5
|
<defs>
|
|
4
6
|
<prop name="open" type="boolean" default="false">Whether the menu is open.</prop>
|
|
5
7
|
<prop name="query" type="string" default="">The text typed after the slash.</prop>
|
|
6
|
-
<prop name="items" type="list(object({ title: string, description: string, icon: string }))"
|
|
8
|
+
<prop name="items" type="list(object({ value?: string, title: string, description: string, icon: string }))"
|
|
9
|
+
>Integration-supplied commands. Authored Slash Menu Item children are the markup alternative.</prop>
|
|
10
|
+
<prop name="label" type="string" default="Insert block"
|
|
11
|
+
>Accessible name of the suggestion list, used unless an aria-label or aria-labelledby is authored.</prop>
|
|
7
12
|
<prop name="selectedIndex" type="integer" default="0"
|
|
8
13
|
>The zero-based index of the highlighted item. The menu does not handle arrow keys itself: the editor sets this as the user moves, while hovering an item
|
|
9
14
|
highlights it and reports a highlight event.</prop>
|
|
@@ -13,23 +18,29 @@
|
|
|
13
18
|
>Where the slash was typed, in viewport coordinates.</prop>
|
|
14
19
|
<state name="visible" :value="false"></state>
|
|
15
20
|
<state name="active" :value="0"></state>
|
|
16
|
-
<
|
|
17
|
-
<event name="
|
|
21
|
+
<state name="rows" type="list(object({ value: string, title: string, description: string, icon: string }))" :value="[]"></state>
|
|
22
|
+
<event name="highlight" type="object({ index: integer, value: string })"></event>
|
|
23
|
+
<event name="select" type="object({ index: integer, value: string })"></event>
|
|
18
24
|
</defs>
|
|
19
|
-
<div role="listbox"
|
|
20
|
-
<div class="header"
|
|
21
|
-
<span class="header-label">Insert</span>
|
|
22
|
-
<span $if="query" class="header-query" $value="query"></span>
|
|
23
|
-
</div>
|
|
25
|
+
<div role="listbox" :hidden="not visible">
|
|
26
|
+
<div class="header"><slot name="header"></slot></div>
|
|
24
27
|
<ul class="list" role="presentation">
|
|
25
|
-
<li
|
|
28
|
+
<li
|
|
29
|
+
$each="item, index of rows"
|
|
30
|
+
class="item"
|
|
31
|
+
class:active="index = active"
|
|
32
|
+
role="option"
|
|
33
|
+
:aria-selected="index = active"
|
|
34
|
+
:data-index="index"
|
|
35
|
+
:data-value="item.value"
|
|
36
|
+
>
|
|
26
37
|
<span class="icon" aria-hidden="true"><ui-icon :name="item.icon"></ui-icon></span>
|
|
27
38
|
<span class="body"><span class="title" $value="item.title"></span><span class="description" $value="item.description"></span></span>
|
|
28
39
|
</li>
|
|
40
|
+
<slot></slot>
|
|
29
41
|
</ul>
|
|
30
|
-
<div class="
|
|
31
|
-
|
|
32
|
-
</div>
|
|
42
|
+
<div class="empty" $ref="empty"><slot name="empty"></slot></div>
|
|
43
|
+
<div class="footer"><slot name="footer"></slot></div>
|
|
33
44
|
</div>
|
|
34
45
|
<style>
|
|
35
46
|
:host {
|
|
@@ -66,23 +77,22 @@
|
|
|
66
77
|
letter-spacing: 0.05em;
|
|
67
78
|
}
|
|
68
79
|
|
|
80
|
+
.header:not(:has(> *)), .footer:not(:has(> *)), .empty:not(:has(> *)) {
|
|
81
|
+
display: none;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.empty {
|
|
85
|
+
padding: var(--ui-space-3);
|
|
86
|
+
color: var(--ui-text-muted);
|
|
87
|
+
font-size: var(--ui-font-size-sm);
|
|
88
|
+
}
|
|
89
|
+
|
|
69
90
|
@media (max-width: 767px) {
|
|
70
91
|
.header {
|
|
71
92
|
display: flex;
|
|
72
93
|
}
|
|
73
94
|
}
|
|
74
95
|
|
|
75
|
-
.header-query {
|
|
76
|
-
background: var(--ui-surface-hover);
|
|
77
|
-
border-radius: var(--ui-radius-sm);
|
|
78
|
-
padding: 0.1em 0.4em;
|
|
79
|
-
font-family: var(--ui-font-family-mono, ui-monospace, monospace);
|
|
80
|
-
font-size: var(--ui-font-size-xs);
|
|
81
|
-
color: var(--ui-accent);
|
|
82
|
-
text-transform: none;
|
|
83
|
-
letter-spacing: 0;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
96
|
.list {
|
|
87
97
|
list-style: none;
|
|
88
98
|
margin: 0;
|
|
@@ -183,19 +193,12 @@
|
|
|
183
193
|
}
|
|
184
194
|
|
|
185
195
|
.footer {
|
|
186
|
-
display: none;
|
|
187
196
|
padding: var(--ui-space-2) var(--ui-space-3);
|
|
188
197
|
border-top: 1px solid var(--ui-border);
|
|
189
198
|
font-size: var(--ui-font-size-xs);
|
|
190
199
|
color: var(--ui-text-muted);
|
|
191
200
|
}
|
|
192
201
|
|
|
193
|
-
@media (min-width: 768px) {
|
|
194
|
-
.footer {
|
|
195
|
-
display: block;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
202
|
:host kbd {
|
|
200
203
|
display: inline-flex;
|
|
201
204
|
align-items: center;
|