diff --git a/src/ui/client/dashboard/components/Widget/Button.vue b/src/ui/client/dashboard/components/Widget/Button.vue index 3a41dd506..c477f0e5f 100644 --- a/src/ui/client/dashboard/components/Widget/Button.vue +++ b/src/ui/client/dashboard/components/Widget/Button.vue @@ -13,6 +13,8 @@ import { contentIndex } from "@utils/tabindex.js"; import Container from "@components/Widget/Container.vue"; import Icons from "@components/Widget/Icons.vue"; import { useUUID } from "@utils/global.js"; +import { useDisplayStore } from "@store/global.js"; + /** * @name Widget/Button.vue * @description This component is a standard button. @@ -29,12 +31,13 @@ import { useUUID } from "@utils/global.js"; * } * @param {string} [id=uuidv4()] - Unique id of the button * @param {string} text - Content of the button. Can be a translation key or by default raw text. + * @param {array} [display=[]] - Case display, we will update the display store with the given array. Useful when we want to use button as tabs. * @param {string} [type="button"] - Can be of type button || submit * @param {boolean} [disabled=false] * @param {boolean} [hideText=false] - Hide text to only display icon * @param {string} [color="primary"] * @param {string} [iconColor=""] - Color we want to apply to the icon. If falsy value, default icon color is applied. - * @param {string} [size="normal"] - Can be of size sm || normal || lg || xl + * @param {string} [size="normal"] - Can be of size sm || normal || lg || xl or tab * @param {string} [iconName=""] - Name in lowercase of icons store on /Icons. If falsy value, no icon displayed. * @param {Object} [attrs={}] - List of attributes to add to the button. Some attributes will conduct to additional script * @param {Object|boolean} [modal=false] - We can link the button to a Modal component. We need to pass the widgets inside the modal. Button click will open the modal. @@ -54,6 +57,11 @@ const props = defineProps({ required: true, default: "", }, + emitValue: { + type: String, + required: false, + default: "", + }, type: { type: String, required: false, @@ -104,6 +112,11 @@ const props = defineProps({ required: false, default: false, }, + display: { + type: Array, + required: false, + default: [], + }, containerClass: { type: String, required: false, @@ -116,19 +129,61 @@ const props = defineProps({ }, }); +const displayStore = useDisplayStore(); + const btn = reactive({ id: "", openModal: false, modalId: props.modal ? `${props.id}-modal` : "", + class: + props.color === "transparent" + ? `${props.size}` + : `btn ${props.color} ${props.size}`, + isActive: false, }); const btnEl = ref(); -const buttonClass = computed(() => { - // transparent useful when we only want to display icon without background or shadow style - if (props.color === "transparent") return `${props.size}`; - return `btn ${props.color} ${props.size}`; -}); +/** + * @name handleClick + * @description Wrap all the logic to handle the click event on the button. + * This will prevent submit if not a submit button, open a modal if one is attached and update the display store if needed. + * @param {event} e - Event object + * @returns {void} + */ +function handleClick(e) { + if (e.target.getAttribute("type") !== "submit") e.preventDefault(); + if (typeof props.modal === "object") { + btn.openModal = true; + } + if (props.display.length) { + console.log("update", btn.isActive); + displayStore.setDisplay(props.display[0], props.display[1]); + } +} + +// Add a11y attributs and update when needed in case the button is related to a display group +if (props.display.length) { + watch(displayStore.display, (val) => { + const isCurrent = displayStore.isCurrentDisplay( + props.display[0], + props.display[1] + ); + btnEl.value.setAttribute("aria-controls", btn.modalId); + btnEl.value.setAttribute("aria-expanded", isCurrent ? "true" : "false"); + btn.isActive = isCurrent ? true : false; + }); +} + +// watch openModal to add accessibility data +watch( + () => btn.openModal, + (value) => { + if (typeof props.modal === "object") { + btnEl.value.setAttribute("aria-expanded", value ? "true" : "false"); + } + } +); onBeforeMount(() => { btn.id = useUUID(props.id); @@ -141,28 +196,18 @@ onMounted(() => { btnEl.value.setAttribute("aria-controls", btn.modalId); btnEl.value.setAttribute( "aria-expanded", - props.openModal ? "true" : "false", + props.openModal ? "true" : "false" ); } -}); -// watch openModal to add accessibility data -watch( - () => btn.openModal, - (value) => { - if (typeof props.modal === "object") { - btnEl.value.setAttribute("aria-expanded", value ? "true" : "false"); - } - }, -); + if (btnEl.value?.closest("[data-is='tabs']")) { + btnEl.value.setAttribute("role", "tab"); + } +});