diff --git a/frontend/src/component/map-editor/map-editor.tsx b/frontend/src/component/map-editor/map-editor.tsx index 6a32fd87e..1b5e774b6 100644 --- a/frontend/src/component/map-editor/map-editor.tsx +++ b/frontend/src/component/map-editor/map-editor.tsx @@ -1,6 +1,7 @@ import './map-editor.scss'; import {KeyboardEvent, useCallback, useEffect, useMemo, useState} from "react"; +import {genUuid} from "../../utils/uuid"; interface KeyValue { key: string; @@ -17,7 +18,7 @@ interface MapEditorProps { export default function MapEditor(props: MapEditorProps) { const {name, values, onChange} = props; - const uuid = useMemo(() => Date.now() + '-' + Math.floor(Math.random() * 99999), []); + const uuid = useMemo(() => genUuid(), []); const [data, setData] = useState(mapToList(values) || []); useEffect(() => { diff --git a/frontend/src/component/tab-set/tab-set.scss b/frontend/src/component/tab-set/tab-set.scss index f031db307..8fa8663d9 100644 --- a/frontend/src/component/tab-set/tab-set.scss +++ b/frontend/src/component/tab-set/tab-set.scss @@ -34,5 +34,9 @@ background-color: var(--tab-active-background-color); color: var(--tab-active-color); } + + &:focus-visible { + outline: none; + } } } \ No newline at end of file diff --git a/frontend/src/component/tab-set/tab-set.tsx b/frontend/src/component/tab-set/tab-set.tsx index cdee3947a..aa5314bec 100644 --- a/frontend/src/component/tab-set/tab-set.tsx +++ b/frontend/src/component/tab-set/tab-set.tsx @@ -1,6 +1,7 @@ -import React, {useCallback} from "react"; +import React, {useCallback, useMemo} from "react"; import './tab-set.scss'; +import {genUuid} from "../../utils/uuid"; export interface TabSetTab { label: string; @@ -15,15 +16,46 @@ interface TabSetProps { export default function TabSet(props: TabSetProps) { const {tabs, active, onTabChange} = props; + const uuid = useMemo(() => genUuid(), []); const handleTabClick = useCallback((evt: any) => { const key = evt.target.dataset.key; onTabChange(key); }, [onTabChange]); + const handleTabPress = useCallback((evt: any) => { + let key = (evt as any).key; + if (key === 'Enter' || key === ' ') { + handleTabClick(evt) + } + const rightArrow = key === 'ArrowRight'; + const leftArrow = key === 'ArrowLeft'; + if (rightArrow || leftArrow) { + const key = evt.target.dataset.key; + let idx = tabs?.findIndex( t => t.key === key); + if (idx >= 0) { + if (leftArrow) { + idx -= 1; + } else if (rightArrow) { + idx += 1; + } + if (idx > tabs.length-1) { + idx = 0; + } else if (idx < 0) { + idx = tabs.length-1; + } + } + let elem = document.getElementById(uuid + '-tab-' + idx) + elem?.focus(); + } + }, [uuid, tabs, handleTabClick]); + return } \ No newline at end of file diff --git a/frontend/src/component/tag-select/tags-select.tsx b/frontend/src/component/tag-select/tags-select.tsx index 0b5331a5f..5881e3ee0 100644 --- a/frontend/src/component/tag-select/tags-select.tsx +++ b/frontend/src/component/tag-select/tags-select.tsx @@ -1,6 +1,7 @@ import './tag-select.scss'; import {useCallback, useEffect, useMemo, useState} from "react"; import {noop} from "rxjs"; +import {genUuid} from "../../utils/uuid"; interface TagSelectProps { name: string; @@ -13,7 +14,7 @@ interface TagSelectProps { export default function TagSelect(props: TagSelectProps) { const {name, multi, options, defaultValues, onSelect} = props; const [selected, setSelected] = useState>({}); - const uuid = useMemo(() => Date.now() + '-' + Math.floor(Math.random() * 99999), []); + const uuid = useMemo(() => genUuid(), []); useEffect(() => { if (defaultValues && options) { diff --git a/frontend/src/utils/uuid.ts b/frontend/src/utils/uuid.ts new file mode 100644 index 000000000..637619e27 --- /dev/null +++ b/frontend/src/utils/uuid.ts @@ -0,0 +1,17 @@ +// yes, i know this is a fake this is not a real uuid +export const genUuid = () => { + let d = new Date().getTime();//Timestamp + // Time in microseconds since page-load or 0 if unsupported + let d2 = ((typeof performance !== 'undefined') && performance.now && (performance.now()*1000)) || 0; + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + let r = Math.random() * 16;//random number between 0 and 16 + if(d > 0){//Use timestamp until depleted + r = (d + r)%16 | 0; + d = Math.floor(d/16); + } else {//Use microseconds since page-load if supported + r = (d2 + r)%16 | 0; + d2 = Math.floor(d2/16); + } + return (c === 'x' ? r : ((r & 0x3) | 0x8)).toString(16); + }); +} \ No newline at end of file