remove event store for vanilla JS

This commit is contained in:
Jordan Blasenhauer 2024-06-05 19:12:28 +02:00
parent 180a014644
commit 4ddceff055
5 changed files with 78 additions and 104 deletions

View file

@ -1,7 +1,6 @@
<script setup>
import { computed, ref, watch, onBeforeMount, onMounted } from "vue";
import { contentIndex } from "@utils/tabindex.js";
import { useEventStore } from "@store/event.js";
import Container from "@components/Widget/Container.vue";
import Icons from "@components/Widget/Icons.vue";
import { v4 as uuidv4 } from "uuid";
@ -11,9 +10,7 @@ import { v4 as uuidv4 } from "uuid";
@description This component is a standard button.
You can link this button to the event store with the clickAttr object.
This will allow you to share a value with other components, for example switching form on a click.
The clickAttr object must contain at least the key, defaultValue and value to work with the event store.
It can also contain the targetId element in case the button is linked to another element, like a modal or a sidebar.
We can specify a valueExpanded value, we will check the current value in the store and the valueExpanded, this will update the aria-expanded attribute of the button.
The prop attrs is an object that can contain multiple attributes to add to the button.
@example
{
id: "open-modal-btn",
@ -24,7 +21,9 @@ import { v4 as uuidv4 } from "uuid";
size: "normal",
iconName: "modal",
iconColor: "white",
clickAttr: {"key" : "modal-config", "defaultValue" : "close", "clickValue" : "open", "targetId" : "modal_id", "valueExpanded" : "open"},
attrs: [
{ key: "modal", defaultValue: "close", clickValue: "open", targetId: "modal_id", valueExpanded: "open" },
],
}
@param {string} [id=uuid()] - Unique id of the button
@param {string} text - Content of the button. Can be a translation key or by default raw text.
@ -35,13 +34,10 @@ import { v4 as uuidv4 } from "uuid";
@param {string} [size="normal"] - Can be of size sm || normal || lg || xl
@param {string} [iconName=""] - Name in lowercase of icons store on /Icons. If falsy value, no icon displayed.
@param {string} [iconColor=""]
@param {object} [clickAttr={}] - Click event manage with event store {"key" : <key_name>, "defaultValue" : <defaultValue = "set this value to store if not done">, "clickValue" : <value_set_on_click>, "targetId"<optional> : <targetId_element="id of element link to the button event">, "valueExpanded<optional>" : <expanded_value="check current value in store and this value to determine a expanded true or false">}
@param {array} [staticAttr=[]] - Static attributes that can be useful to do some check with script (for example {"data-attr" : "value"} will add data-attr="value" to the button)
@param {Object} [attrs={}] - List of attributs to add to the button. Some attributs will conduct to additionnal script
@param {string|number} [tabId=contentIndex] - The tabindex of the field, by default it is the contentIndex
*/
const eventStore = useEventStore();
const props = defineProps({
id: {
type: String,
@ -94,13 +90,7 @@ const props = defineProps({
required: false,
default: "",
},
// Example of button opening a modal : {"key" : "modal", "defaultValue" : "close", "clickValue" : "open", "targetId" : "modal_id", "valueExpanded" : "open"}
clickAttr: {
type: Object,
required: false,
default: {},
},
staticAttr: {
attrs: {
type: Object,
required: false,
default: {},
@ -124,59 +114,14 @@ const buttonClass = computed(() => {
});
onMounted(() => {
setStaticAttr();
updateData();
setAttrs();
});
watch(eventStore, () => {
updateData();
});
function setStaticAttr() {
for (const [key, value] of Object.entries(props.staticAttr)) {
function setAttrs() {
for (const [key, value] of Object.entries(props.attrs)) {
btnEl.value.setAttribute(key, value);
}
}
function updateData(isClick = false) {
const isKey = props.clickAttr?.key ? true : false;
const isValue = props.clickAttr?.clickValue ? true : false;
const isDefault = props.clickAttr?.defaultValue ? true : false;
if (!isKey || !isValue || !isDefault) return;
isClick
? eventStore.updateEvent(props.clickAttr.key, props.clickAttr.clickValue)
: eventStore.addEvent(props.clickAttr.key, props.clickAttr.defaultValue);
try {
const expanded = props.clickAttr?.valueExpanded
? props.clickAttr.valueExpanded ===
eventStore.getEvent(props.clickAttr.key)
? "true"
: "false"
: false;
if (expanded) {
btnEl.value.setAttribute("aria-expanded", expanded);
}
if (!expanded) {
btnEl.value.removeAttribute("aria-expanded");
}
} catch (e) {}
try {
const controls = props.clickAttr?.targetId
? props.clickAttr.targetId
: false;
if (controls) {
btnEl.value.setAttribute("aria-controls", controls);
}
if (!controls) {
btnEl.value.removeAttribute("aria-controls");
}
} catch (e) {}
}
</script>
<template>
@ -187,15 +132,19 @@ function updateData(isClick = false) {
<button
:type="props.type"
ref="btnEl"
@click="updateData(true)"
:id="props.id"
@click.prevent=""
:tabindex="props.tabId"
:class="[buttonClass]"
:disabled="props.disabled || false"
:aria-describedby="`text-${props.id}`"
>
<span
:class="[props.hideText ? 'sr-only' : '', props.iconName ? 'mr-2' : '']"
:class="[
props.hideText ? 'sr-only' : '',
props.iconName ? 'mr-2' : '',
'pointer-events-none',
]"
:id="`text-${props.id}`"
>{{ $t(props.text, props.text) }}</span
>

View file

@ -1,7 +1,8 @@
<script setup>
import { reactive, onBeforeMount } from "vue";
import { reactive, onBeforeMount, onMounted } from "vue";
import DashboardLayout from "@components/Dashboard/Layout.vue";
import Builder from "@components/Builder.vue";
import { useGlobal } from "@utils/global.js";
/**
@name Page/Home.vue
@ -24,6 +25,10 @@ onBeforeMount(() => {
home.builder = data;
});
onMounted(() => {
useGlobal();
});
// const data = [
// {
// type: "Instance",
@ -51,5 +56,6 @@ onBeforeMount(() => {
<template>
<DashboardLayout>
<Builder v-if="home.builder" :builder="home.builder" />
<div id="test-el"></div>
</DashboardLayout>
</template>

View file

@ -14,7 +14,7 @@
data-server-flash='[{"type" : "success", "title" : "title", "message" : "Success feedback"}, {"type" : "error", "title" : "title", "message" : "Error feedback"}, {"type" : "warning", "title" : "title", "message" : "Warning feedback"}, {"type" : "info", "title" : "title", "message" : "Info feedback"}]'>
</div>
<div class="hidden"
data-server-builder='[{"type":"card","link":"/services","containerClass":"","containerColumns":{"pc":6,"tablet":6,"mobile":12},"widgets":[{"type":"Instance","data":{"details":[{"key":"instances_hostname","value":"www.example.com"},{"key":"instances_method","value":"dashboard_ui"},{"key":"instances_port","value":"1084"},{"key":"instances_status","value":"instances_active"}],"status":"success","title":"www.example.com","buttons":[{"type" : "submit", "text":"action_edit","color":"edit","size":"normal"}]}}]},{"type":"card","link":"/services","containerClass":"","containerColumns":{"pc":6,"tablet":6,"mobile":12},"widgets":[{"type":"Instance","data":{"details":[{"key":"instances_hostname","value":"www.example.com"},{"key":"instances_method","value":"dashboard_ui"},{"key":"instances_port","value":"1084"},{"key":"instances_status","value":"instances_active"}],"status":"error","title":"www.example.com","buttons":[{"type" : "submit", "text":"action_start","color":"valid","size":"normal"}]}}]}]'>
data-server-builder='[{"type":"card","link":"/services","containerClass":"","containerColumns":{"pc":6,"tablet":6,"mobile":12},"widgets":[{"type":"Instance","data":{"details":[{"key":"instances_hostname","value":"www.example.com"},{"key":"instances_method","value":"dashboard_ui"},{"key":"instances_port","value":"1084"},{"key":"instances_status","value":"instances_active"}],"status":"success","title":"www.example.com","buttons":[{"attrs" : {"aria-controls" : "test-el", "aria-expanded" : "false"}, "text":"action_edit","color":"edit","size":"normal"}]}}]},{"type":"card","link":"/services","containerClass":"","containerColumns":{"pc":6,"tablet":6,"mobile":12},"widgets":[{"type":"Instance","data":{"details":[{"key":"instances_hostname","value":"www.example.com"},{"key":"instances_method","value":"dashboard_ui"},{"key":"instances_port","value":"1084"},{"key":"instances_status","value":"instances_active"}],"status":"error","title":"www.example.com","buttons":[{ "text":"action_start","color":"valid","size":"normal"}]}}]}]'>
</div>
<div id="app"></div>
<script type="module" src="instances.js"></script>

View file

@ -1,36 +0,0 @@
import { data } from "autoprefixer";
import { defineStore } from "pinia";
import { ref } from "vue";
/**
@name useEventStore
@description Store to share data between components related to events (click, change, ...).
We can toggle a component visibility, change a value, etc... using this store.
Be aware that this store better work using primitive values (string, number, boolean) and not objects.
*/
export const useEventStore = defineStore("event", () => {
const event = ref({});
// add only if the event is not already in the store
function addEvent(name, value) {
if (!(name in event.value)) event.value[name] = value;
}
function updateEvent(name, value) {
event.value[name] = value;
}
function getEvent(name) {
return event.value[name];
}
function deleteEvent(name) {
delete event.value[name];
}
function $reset() {
data.value = {};
}
return { event, $reset, addEvent, updateEvent, deleteEvent, getEvent };
});

View file

@ -0,0 +1,55 @@
/**
@name global.js
@description This file contains global utils that will be used in the application by default.
This file contains functions related to accessibilities, cookies, and other global utils.
*/
// This function is a wrapper that contains all the global utils functions.
function useGlobal() {
window.addEventListener("click", (e) => {
updateExpanded();
});
}
// This function updates the aria-expanded attribute of an element in case we have an aria-controls attribute.
function updateExpanded() {
// Wait for previous event and element visibility update
setTimeout(() => {
// Check state for all elements that have aria-controls and aria-expanded attributes
const controlEls = document.querySelectorAll(
"[aria-controls][aria-expanded]"
);
if (!controlEls) return;
controlEls.forEach((el) => {
try {
const targetEl = document.getElementById(
el.getAttribute("aria-controls")
);
if (!targetEl) return el.setAttribute("aria-expanded", "false");
el.setAttribute(
"aria-expanded",
isElHidden(targetEl) ? "false" : "true"
);
} catch (err) {}
});
}, 50);
}
// Check all the possible ways to hide an element
function isElHidden(el) {
return el.hasAttribute("aria-hidden")
? el.getAttribute("aria-hidden") === "true"
? true
: false
: el.classList.contains("hidden")
? true
: el.style.display === "none"
? true
: el.style.visibility === "hidden"
? true
: el.classList.contains("!hidden")
? true
: false;
}
export { useGlobal };