From da915b0716e9a53bf5d09fc54d5da050716f63fb Mon Sep 17 00:00:00 2001 From: Jason Henriquez Date: Mon, 23 Oct 2023 02:14:17 -0500 Subject: [PATCH 01/14] Implement iconButton radioButton dropdown handling & related props --- .../ft-icon-button/ft-icon-button.js | 71 ++++++++++++++++++- .../ft-icon-button/ft-icon-button.scss | 16 ++++- .../ft-icon-button/ft-icon-button.vue | 69 ++++++++++++++++-- 3 files changed, 146 insertions(+), 10 deletions(-) diff --git a/src/renderer/components/ft-icon-button/ft-icon-button.js b/src/renderer/components/ft-icon-button/ft-icon-button.js index 93c4db4df142..ed3c469a0c08 100644 --- a/src/renderer/components/ft-icon-button/ft-icon-button.js +++ b/src/renderer/components/ft-icon-button/ft-icon-button.js @@ -1,10 +1,12 @@ import { defineComponent } from 'vue' import FtPrompt from '../ft-prompt/ft-prompt.vue' +import FtButton from '../ft-button/ft-button.vue' import { sanitizeForHtmlId } from '../../helpers/accessibility' export default defineComponent({ name: 'FtIconButton', components: { + 'ft-button': FtButton, 'ft-prompt': FtPrompt }, props: { @@ -50,7 +52,9 @@ export default defineComponent({ }, dropdownOptions: { // Array of objects with these properties - // - type: ('labelValue'|'divider', default to 'labelValue' for less typing) + // - type: ('labelValue'|'divider'|'radiogroup', default to 'labelValue' for less typing) + // - radios: ({ type?: 'radio', label: String, value: String, checked: Boolean } | { type: divider })[] + // (if type == 'radiogroup', representing a separate group of checkboxes) // - label: String (if type == 'labelValue') // - value: String (if type == 'labelValue') type: Array, @@ -59,6 +63,18 @@ export default defineComponent({ dropdownModalOnMobile: { type: Boolean, default: false + }, + closeOnClick: { + type: Boolean, + default: true + }, + hideIcon: { + type: Boolean, + default: false + }, + useFtButton: { + type: Boolean, + default: false } }, data: function () { @@ -123,7 +139,58 @@ export default defineComponent({ this.$emit('click', url) } - this.dropdownShown = false + if (this.closeOnClick) { + this.dropdownShown = false + } + }, + + handleRadioDropdownKeydown: function({ url, index, groupIndex }, event) { + if (!(event instanceof KeyboardEvent) || event.altKey) { + return + } + + let isNext = null + switch (event.key) { + case ' ': + case 'Spacebar': + this.handleDropdownClick({ url, index }) + return + case 'ArrowRight': + case 'ArrowDown': + isNext = true + break + case 'ArrowLeft': + case 'ArrowUp': + isNext = false + break + default: + return + } + + this.focusElement( + { + isNext, + index, + list: this.dropdownOptions[groupIndex].radios, + idPrefix: this.title, + groupIndex + } + ) + }, + + focusElement: function ({ isNext, index, list, idPrefix, groupIndex }) { + let newIndex = index + const max = list.length - 1 + do { + newIndex += (isNext ? 1 : -1) + if (newIndex === -1) { + newIndex = max + } else if (newIndex > max) { + newIndex = 0 + } + } while (list[newIndex].type === 'divider') + const newElement = document.getElementById(sanitizeForHtmlId(idPrefix + groupIndex + '-' + newIndex)) + newElement?.focus() }, handleResize: function () { diff --git a/src/renderer/components/ft-icon-button/ft-icon-button.scss b/src/renderer/components/ft-icon-button/ft-icon-button.scss index 58f776dd6414..89314910e36a 100644 --- a/src/renderer/components/ft-icon-button/ft-icon-button.scss +++ b/src/renderer/components/ft-icon-button/ft-icon-button.scss @@ -110,13 +110,13 @@ inset-block-start: 45px; } - .list { + .list, .radiogroup { list-style-type: none; margin: 0; padding: 0; } - .listItem { + .listItem, .radioItem { cursor: pointer; margin: 0; padding-block: 8px; @@ -138,6 +138,18 @@ } } + .radioItem { + padding-inline: 10px; + display: flex; + gap: 15px; + text-align: start; + justify-content: space-between; + } + + .uncheckedFiller { + inline-size: 10.5px; + } + .listItemDivider { border-block-start: 1px solid var(--tertiary-text-color); margin-block: 1px; diff --git a/src/renderer/components/ft-icon-button/ft-icon-button.vue b/src/renderer/components/ft-icon-button/ft-icon-button.vue index b1760e528e60..11aeb64d7350 100644 --- a/src/renderer/components/ft-icon-button/ft-icon-button.vue +++ b/src/renderer/components/ft-icon-button/ft-icon-button.vue @@ -1,6 +1,7 @@