From 0c304cee7b01a71c749b21cba0994d1f0f04cb61 Mon Sep 17 00:00:00 2001 From: Pongstr Date: Tue, 24 Dec 2024 14:01:11 +0200 Subject: [PATCH 1/7] stub: modal-dialog improvements - feat: improve modal transitions on open/close - docs: modal dialog stories+docs --- src/components/modal/Modal.stories.tsx | 72 ++++++++++ src/components/modal/Modal.tsx | 126 ++++++++++++++++++ src/components/modal/ModalContent.stories.tsx | 43 ++++++ src/components/modal/ModalContext.tsx | 14 ++ src/components/modal/useModalRef.tsx | 6 + 5 files changed, 261 insertions(+) create mode 100644 src/components/modal/Modal.stories.tsx create mode 100644 src/components/modal/Modal.tsx create mode 100644 src/components/modal/ModalContent.stories.tsx create mode 100644 src/components/modal/ModalContext.tsx create mode 100644 src/components/modal/useModalRef.tsx diff --git a/src/components/modal/Modal.stories.tsx b/src/components/modal/Modal.stories.tsx new file mode 100644 index 00000000..9b096eb1 --- /dev/null +++ b/src/components/modal/Modal.stories.tsx @@ -0,0 +1,72 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Modal as ModalComponent, ModalContent as Content } from "./Modal"; + +import { useState } from "react"; +import { ModalContent } from "./ModalContent.stories"; + +const meta = { + title: "UI/Modal", + component: ModalComponent, + subcomponents: { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + ModalContent: Content, + }, + tags: ["autodocs"], + parameters: { + layout: "centered", + }, + args: { + open: false, + onOpenChange: () => {}, + onBackdropClose: false, + onEscapeClose: true, + }, + argTypes: { + open: { + control: { + type: "boolean", + }, + }, + onBackdropClose: { + control: { + type: "boolean", + }, + }, + onEscapeClose: { + control: { + type: "boolean", + }, + }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Modal: Story = { + args: { + onBackdropClose: false, + onEscapeClose: false, + }, + + render: (args) => { + const [open, setOpen] = useState(args.open); + return ( + <> + + + +
Hello World
+
+
+ + ); + }, +}; diff --git a/src/components/modal/Modal.tsx b/src/components/modal/Modal.tsx new file mode 100644 index 00000000..b0417ba5 --- /dev/null +++ b/src/components/modal/Modal.tsx @@ -0,0 +1,126 @@ +import { X } from "lucide-react"; +import { + FC, + PropsWithChildren, + useContext, + useEffect, + useRef, + forwardRef, + useId, +} from "react"; +import { ModalContext, ModalContextType } from "./ModalContext"; + +export const Modal: FC>> = ({ + children, + onEscapeClose = true, + onBackdropClose = true, + open, + onOpenChange, +}) => { + const dialogId = useId(); + const dialogRef = useRef(null); + + useEffect(() => { + const dialog = dialogRef.current!; + + if (open) { + dialog.showModal(); + requestAnimationFrame(() => { + dialog.dataset.open = ""; + delete dialog.dataset.closing; + }); + + const handleEscape = (e: KeyboardEvent) => { + e.preventDefault(); + + if (!onEscapeClose) return; + if (e.key !== "Escape") return; + onOpenChange(false); + }; + + dialog.addEventListener("keydown", handleEscape); + return () => void dialog.removeEventListener("keydown", handleEscape); + } else { + dialog.dataset.closing = ""; + delete dialog.dataset.open; + + const backdrop = dialog.firstElementChild as HTMLElement; + const content = backdrop?.firstElementChild as HTMLElement; + + let transitionsComplete = 0; + + const handleTransitionEnd = () => { + // Increment counter to track when both backdrop and content transitions are complete + transitionsComplete++; + + // If both transitions are completee the dialog + if (transitionsComplete >= 2) { + dialog.close(); + backdrop?.removeEventListener("transitionend", handleTransitionEnd); + content?.removeEventListener("transitionend", handleTransitionEnd); + } + }; + + backdrop?.addEventListener("transitionend", handleTransitionEnd); + content?.addEventListener("transitionend", handleTransitionEnd); + + return () => { + backdrop.removeEventListener("transitionend", handleTransitionEnd); + content?.removeEventListener("transitionend", handleTransitionEnd); + }; + } + }, [onEscapeClose, onOpenChange, open]); + + const handleBackdropClick = (e: React.MouseEvent) => { + if (!onBackdropClose) return; + if (e.target === e.currentTarget) { + onOpenChange(false); + } + }; + + return ( + + +
+
+ {children} +
+
+
+
+ ); +}; + +type ModalContentProps = PropsWithChildren<{ + className?: string; + showCloseButton?: boolean; +}>; + +export const ModalContent = forwardRef( + function ModalContent({ children, className, showCloseButton = true }, ref) { + const { onOpenChange } = useContext(ModalContext); + return ( +
+ {children} + {showCloseButton && ( + + )} +
+ ); + }, +); diff --git a/src/components/modal/ModalContent.stories.tsx b/src/components/modal/ModalContent.stories.tsx new file mode 100644 index 00000000..e4c34095 --- /dev/null +++ b/src/components/modal/ModalContent.stories.tsx @@ -0,0 +1,43 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Modal as ModalComponent, ModalContent as Content } from "./Modal"; + +const meta = { + title: "UI/Modal/ModalContent", + component: Content, + parameters: { + layout: "centered", + }, + tags: [], + args: { + showCloseButton: true, + className: "max-w-2xl min-h-48", + }, + argTypes: { + className: { + control: { + type: "text", + }, + }, + showCloseButton: { + defaultValue: true, + control: { + type: "boolean", + }, + }, + }, +} satisfies Meta; + +export default meta; +type ModalContentStory = StoryObj; + +export const ModalContent: ModalContentStory = { + args: { + showCloseButton: true, + className: "max-w-2xl min-h-48", + }, + render: (args) => ( + {}}> + Hello + + ), +}; diff --git a/src/components/modal/ModalContext.tsx b/src/components/modal/ModalContext.tsx new file mode 100644 index 00000000..2ada3d51 --- /dev/null +++ b/src/components/modal/ModalContext.tsx @@ -0,0 +1,14 @@ +import React from "react"; +import { Dispatch, PropsWithChildren, SetStateAction } from "react"; + +export type ModalContextType = PropsWithChildren<{ + id: string; + open: boolean; + onEscapeClose?: boolean; + onBackdropClose?: boolean; + onOpenChange: (open: boolean) => void | Dispatch>; +}>; + +export const ModalContext = React.createContext( + {} as ModalContextType, +); diff --git a/src/components/modal/useModalRef.tsx b/src/components/modal/useModalRef.tsx new file mode 100644 index 00000000..1bfc3584 --- /dev/null +++ b/src/components/modal/useModalRef.tsx @@ -0,0 +1,6 @@ +import { ModalContext, ModalContextType } from "./ModalContext"; +import { useContext } from "react"; + +export function useModalRef(): ModalContextType { + return useContext(ModalContext); +} From d456a06a205ef586eb98211f9edec90b29b072ce Mon Sep 17 00:00:00 2001 From: Pongstr Date: Wed, 25 Dec 2024 13:44:03 +0200 Subject: [PATCH 2/7] feat: introduce zmk logo for use on modals feat: zmk studio component for use on modals --- src/components/ZmkStudio.tsx | 71 +++++++++++++++++++ src/components/modal/Modal.stories.tsx | 2 + src/components/modal/ModalContent.stories.tsx | 6 +- 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/components/ZmkStudio.tsx diff --git a/src/components/ZmkStudio.tsx b/src/components/ZmkStudio.tsx new file mode 100644 index 00000000..4de27295 --- /dev/null +++ b/src/components/ZmkStudio.tsx @@ -0,0 +1,71 @@ +import { FC, SVGProps, useId } from "react"; + +const ZmkLogo: FC> = (props) => { + const gradientId = useId(); + return ( + + + + + + + + + + + + + + + + ); +}; + +type ZmkStudioProps = { + containerClassName?: string; + logoProps?: SVGProps; + textClassName?: string; +}; + +export const ZmkStudio: FC = ({ + containerClassName, + logoProps, + textClassName, +}) => ( +
+ + + Studio + +
+); diff --git a/src/components/modal/Modal.stories.tsx b/src/components/modal/Modal.stories.tsx index 9b096eb1..2be18d7f 100644 --- a/src/components/modal/Modal.stories.tsx +++ b/src/components/modal/Modal.stories.tsx @@ -3,6 +3,7 @@ import { Modal as ModalComponent, ModalContent as Content } from "./Modal"; import { useState } from "react"; import { ModalContent } from "./ModalContent.stories"; +import { ZmkStudio } from "../ZmkStudio"; const meta = { title: "UI/Modal", @@ -63,6 +64,7 @@ export const Modal: Story = { onEscapeClose={args.onEscapeClose} > +
Hello World
diff --git a/src/components/modal/ModalContent.stories.tsx b/src/components/modal/ModalContent.stories.tsx index e4c34095..369e320e 100644 --- a/src/components/modal/ModalContent.stories.tsx +++ b/src/components/modal/ModalContent.stories.tsx @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react"; import { Modal as ModalComponent, ModalContent as Content } from "./Modal"; +import { ZmkStudio } from "../ZmkStudio"; const meta = { title: "UI/Modal/ModalContent", @@ -37,7 +38,10 @@ export const ModalContent: ModalContentStory = { }, render: (args) => ( {}}> - Hello + + +
Hello World
+
), }; From 03f8eb913d2d15a24ff364f890aebab52d20563e Mon Sep 17 00:00:00 2001 From: Pongstr Date: Wed, 25 Dec 2024 16:20:33 +0200 Subject: [PATCH 3/7] feat(improve-modal): migrate connect-modal to new modal component --- src/ConnectModal.tsx | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/ConnectModal.tsx b/src/ConnectModal.tsx index e84d6ae9..c81bd7b0 100644 --- a/src/ConnectModal.tsx +++ b/src/ConnectModal.tsx @@ -5,9 +5,10 @@ import { UserCancelledError } from "@zmkfirmware/zmk-studio-ts-client/transport/ import type { AvailableDevice } from "./tauri/index"; import { Bluetooth, RefreshCw } from "lucide-react"; import { Key, ListBox, ListBoxItem, Selection } from "react-aria-components"; -import { useModalRef } from "./misc/useModalRef"; import { ExternalLink } from "./misc/ExternalLink"; -import { GenericModal } from "./GenericModal"; +import { Modal, ModalContent } from "./components/modal/Modal"; +import { ZmkStudio } from "./components/ZmkStudio"; +import { AppFooter } from './AppFooter' export type TransportFactory = { label: string; @@ -200,7 +201,7 @@ function simpleDevicePicker( return (

Select a connection type.

-
    {connections}
+
    {connections}
{selectedTransport && availableDevices && (
    {availableDevices.map((d) => ( @@ -278,16 +279,20 @@ export const ConnectModal = ({ transports, onTransportCreated, }: ConnectModalProps) => { - const dialog = useModalRef(open || false, false, false); - const haveTransports = useMemo(() => transports.length > 0, [transports]); return ( - -

    Welcome to ZMK Studio

    - {haveTransports - ? connectOptions(transports, onTransportCreated, open) - : noTransportsOptionsPrompt()} -
    + {}} onEscapeClose={false} onBackdropClose={false}> + + + {haveTransports + ? connectOptions(transports, onTransportCreated, open) + : noTransportsOptionsPrompt()} + +
    + +
    +
    +
    ); }; From 7dc101f9823a31b0abb5748792f2bbe909227035 Mon Sep 17 00:00:00 2001 From: Pongstr Date: Wed, 25 Dec 2024 16:27:37 +0200 Subject: [PATCH 4/7] feat(improve-modal): migrate about+license modals --- src/AboutModal.tsx | 165 +++++++++++++------------ src/App.tsx | 14 +-- src/AppFooter.tsx | 34 +++-- src/components/modal/Modal.stories.tsx | 4 +- src/misc/LicenseNoticeModal.tsx | 61 ++++----- 5 files changed, 126 insertions(+), 152 deletions(-) diff --git a/src/AboutModal.tsx b/src/AboutModal.tsx index 8ecf5940..9bd97dc4 100644 --- a/src/AboutModal.tsx +++ b/src/AboutModal.tsx @@ -1,5 +1,4 @@ -import React from "react"; -import { useModalRef } from "./misc/useModalRef"; +import React, { FC, PropsWithChildren, useState } from "react"; import cannonKeys from "./assets/cannonkeys.png"; import cannonKeysDarkMode from "./assets/cannonkeys-dark-mode.png"; @@ -40,13 +39,8 @@ import mekiboDarkMode from "./assets/mekibo-dark-mode.png"; import splitkb from "./assets/splitkb.png"; import splitkbDarkMode from "./assets/splitkb-dark-mode.png"; -import { GenericModal } from "./GenericModal"; import { ExternalLink } from "./misc/ExternalLink"; - -export interface AboutModalProps { - open: boolean; - onClose: () => void; -} +import { Modal, ModalContent } from "./components/modal/Modal"; enum SponsorSize { Large, @@ -175,80 +169,87 @@ const sponsors = [ }, ]; -export const AboutModal = ({ open, onClose }: AboutModalProps) => { - const ref = useModalRef(open, true); - +export const AboutModal: FC = ({ children }) => { + const [open, setOpen] = useState(false); return ( - -
    -

    - The ZMK Project:{" "} - website,{" "} - - GitHub Issues - - ,{" "} - - Discord Server - -

    - -
    -
    -

    - ZMK Studio is made possible thanks to the generous donation of time - from our contributors, as well as the financial sponsorship from the - following vendors: -

    -
    -
    - {sponsors.map((s) => { - const heightVariants = { - [SponsorSize.Large]: "h-16", - [SponsorSize.Medium]: "h-12", - [SponsorSize.Small]: "h-8", - }; - - return ( - - -
    - {s.vendors.map((v) => { - const maxSizeVariants = { - [SponsorSize.Large]: "max-h-16", - [SponsorSize.Medium]: "max-h-12", - [SponsorSize.Small]: "max-h-8", - }; - - return ( - - - {v.darkModeImg && ( - - )} - - - - ); - })} -
    -
    - ); - })} -
    -
    + <> + setOpen(true)} + > + {children} + + + +
    +

    + The ZMK Project:{" "} + website,{" "} + + GitHub Issues + + ,{" "} + + Discord Server + +

    +
    +
    +

    + ZMK Studio is made possible thanks to the generous donation of + time from our contributors, as well as the financial sponsorship + from the following vendors: +

    +
    +
    + {sponsors.map((s) => { + const heightVariants = { + [SponsorSize.Large]: "h-16", + [SponsorSize.Medium]: "h-12", + [SponsorSize.Small]: "h-8", + }; + + return ( + + +
    + {s.vendors.map((v) => { + const maxSizeVariants = { + [SponsorSize.Large]: "max-h-16", + [SponsorSize.Medium]: "max-h-12", + [SponsorSize.Small]: "max-h-8", + }; + + return ( + + + {v.darkModeImg && ( + + )} + + + + ); + })} +
    +
    + ); + })} +
    +
    +
    + ); }; diff --git a/src/App.tsx b/src/App.tsx index e09ed0cb..15b29371 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -27,8 +27,6 @@ import { LockStateContext } from "./rpc/LockStateContext"; import { UnlockModal } from "./UnlockModal"; import { valueAfter } from "./misc/async"; import { AppFooter } from "./AppFooter"; -import { AboutModal } from "./AboutModal"; -import { LicenseNoticeModal } from "./misc/LicenseNoticeModal"; declare global { interface Window { @@ -166,8 +164,6 @@ function App() { string | undefined >(undefined); const [doIt, undo, redo, canUndo, canRedo, reset] = useUndoRedo(); - const [showAbout, setShowAbout] = useState(false); - const [showLicenseNotice, setShowLicenseNotice] = useState(false); const [connectionAbort, setConnectionAbort] = useState(new AbortController()); const [lockState, setLockState] = useState( @@ -290,11 +286,6 @@ function App() { transports={TRANSPORTS} onTransportCreated={onConnect} /> - setShowAbout(false)} /> - setShowLicenseNotice(false)} - />
    - setShowAbout(true)} - onShowLicenseNotice={() => setShowLicenseNotice(true)} - /> +
    diff --git a/src/AppFooter.tsx b/src/AppFooter.tsx index e0d9af43..319f8800 100644 --- a/src/AppFooter.tsx +++ b/src/AppFooter.tsx @@ -1,24 +1,20 @@ -export interface AppFooterProps { - onShowAbout: () => void; - onShowLicenseNotice: () => void; -} +import { AboutModal } from "./AboutModal"; +import { LicenseNoticeModal } from "./misc/LicenseNoticeModal"; -export const AppFooter = ({ - onShowAbout, - onShowLicenseNotice, -}: AppFooterProps) => { +export const AppFooter = () => { return ( -
    -
    - © 2024 - The ZMK Contributors -{" "} - - About ZMK Studio - {" "} - -{" "} - - License NOTICE - + <> +
    + © 2024 - The ZMK Contributors + + + About ZMK Studio + + + + License NOTICE +
    -
    + ); }; diff --git a/src/components/modal/Modal.stories.tsx b/src/components/modal/Modal.stories.tsx index 2be18d7f..9e47ae25 100644 --- a/src/components/modal/Modal.stories.tsx +++ b/src/components/modal/Modal.stories.tsx @@ -48,8 +48,8 @@ type Story = StoryObj; export const Modal: Story = { args: { - onBackdropClose: false, - onEscapeClose: false, + onBackdropClose: true, + onEscapeClose: true, }, render: (args) => { diff --git a/src/misc/LicenseNoticeModal.tsx b/src/misc/LicenseNoticeModal.tsx index 62500a65..4beb4ef7 100644 --- a/src/misc/LicenseNoticeModal.tsx +++ b/src/misc/LicenseNoticeModal.tsx @@ -1,41 +1,30 @@ -import { useModalRef } from "./useModalRef"; - +import { FC, PropsWithChildren, useState } from "react"; import NOTICE from "../../NOTICE?raw"; -import { GenericModal } from "../GenericModal"; - -export interface LicenseNoticeModalProps { - open: boolean; - onClose: () => void; -} - -export const LicenseNoticeModal = ({ - open, - onClose, -}: LicenseNoticeModalProps) => { - const ref = useModalRef(open, true); +import { Modal, ModalContent } from "../components/modal/Modal"; +export const LicenseNoticeModal: FC = ({ children }) => { + const [open, setOpen] = useState(false); return ( - -
    -
    -

    - ZMK Studio is released under the open source Apache 2.0 license. A - copy of the NOTICE file from the ZMK Studio repository is included - here: -

    - -
    -
    {NOTICE}
    -
    -
    + <> + setOpen(true)} + > + {children} + + + +
    +

    + ZMK Studio is released under the open source Apache 2.0 license. A + copy of the NOTICE file from the ZMK Studio repository is included + here: +

    +
    +
    {NOTICE}
    +
    +
    + ); }; From 5bfe6cebce8040a1f9d84c8faabeeb3d8c9472dd Mon Sep 17 00:00:00 2001 From: Pongstr Date: Wed, 25 Dec 2024 16:34:36 +0200 Subject: [PATCH 5/7] feat(improve-modal): migrate restore-to-stock modal --- src/AppHeader.tsx | 117 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 82 insertions(+), 35 deletions(-) diff --git a/src/AppHeader.tsx b/src/AppHeader.tsx index 52a6658d..2fd4fbe3 100644 --- a/src/AppHeader.tsx +++ b/src/AppHeader.tsx @@ -7,14 +7,28 @@ import { } from "react-aria-components"; import { useConnectedDeviceData } from "./rpc/useConnectedDeviceData"; import { useSub } from "./usePubSub"; -import { useContext, useEffect, useState } from "react"; -import { useModalRef } from "./misc/useModalRef"; +import { + Dispatch, + FC, + SetStateAction, + useCallback, + useContext, + useEffect, + useState, +} from "react"; import { LockStateContext } from "./rpc/LockStateContext"; import { LockState } from "@zmkfirmware/zmk-studio-ts-client/core"; import { ConnectionContext } from "./rpc/ConnectionContext"; -import { ChevronDown, Undo2, Redo2, Save, Trash2 } from "lucide-react"; +import { + ChevronDown, + Undo2, + Redo2, + Save, + Trash2, + AlertTriangle, +} from "lucide-react"; import { Tooltip } from "./misc/Tooltip"; -import { GenericModal } from "./GenericModal"; +import { Modal, ModalContent } from "./components/modal/Modal"; export interface AppHeaderProps { connectedDeviceLabel?: string; @@ -28,6 +42,57 @@ export interface AppHeaderProps { canRedo?: boolean; } +const RestoreSettingsPrompt: FC< + Pick & { + open: boolean; + onOpenChange: (value: boolean) => void | Dispatch>; + } +> = ({ onResetSettings, open, onOpenChange }) => { + const handleContinue = useCallback(() => { + onOpenChange(false); + onResetSettings?.(); + }, [onOpenChange, onResetSettings]); + + return ( + + +
    +
    + + + Restore stock settings. + +
    +
    +

    + Reset will restore the default keymap and remove all ZMK Studio + customizations. +

    + +

    + Are you sure you want to continue? +

    +
    +
    + + +
    +
    +
    +
    + ); +}; + export const AppHeader = ({ connectedDeviceLabel, canRedo, @@ -44,6 +109,8 @@ export const AppHeader = ({ const lockState = useContext(LockStateContext); const connectionState = useContext(ConnectionContext); + const [promptRestoreSettings, setPromptRestoreSettings] = useState(false); + useEffect(() => { if ( (!connectionState.conn || @@ -54,14 +121,14 @@ export const AppHeader = ({ } }, [lockState, showSettingsReset]); - const showSettingsRef = useModalRef(showSettingsReset); + const [unsaved, setUnsaved] = useConnectedDeviceData( { keymap: { checkUnsavedChanges: true } }, - (r) => r.keymap?.checkUnsavedChanges + (r) => r.keymap?.checkUnsavedChanges, ); useSub("rpc_notification.keymap.unsavedChangesStatusChanged", (unsaved) => - setUnsaved(unsaved) + setUnsaved(unsaved), ); return ( @@ -70,33 +137,7 @@ export const AppHeader = ({ ZMK Logo

    Studio

    - -

    Restore Stock Settings

    -
    -

    - Settings reset will remove any customizations previously made in ZMK - Studio and restore the stock keymap -

    -

    Continue?

    -
    - - -
    -
    -
    +
+ + ); }; From ba2f551d33f36b63ac59d4d28bdeb6239f202518 Mon Sep 17 00:00:00 2001 From: Pongstr Date: Wed, 25 Dec 2024 16:49:32 +0200 Subject: [PATCH 6/7] feat(improve-modal): migrate edit-layer-name modal --- src/keyboard/LayerPicker.tsx | 103 ++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 49 deletions(-) diff --git a/src/keyboard/LayerPicker.tsx b/src/keyboard/LayerPicker.tsx index 1584191d..da0011bb 100644 --- a/src/keyboard/LayerPicker.tsx +++ b/src/keyboard/LayerPicker.tsx @@ -8,8 +8,7 @@ import { Selection, useDragAndDrop, } from "react-aria-components"; -import { useModalRef } from "../misc/useModalRef"; -import { GenericModal } from "../GenericModal"; +import { Modal, ModalContent } from "../components/modal/Modal.tsx"; interface Layer { id: number; @@ -49,56 +48,62 @@ const EditLabelModal = ({ }: { open: boolean; onClose: () => void; - editLabelData: EditLabelData; + editLabelData: EditLabelData | null; handleSaveNewLabel: ( id: number, oldName: string, newName: string | null ) => void; }) => { - const ref = useModalRef(open); - const [newLabelName, setNewLabelName] = useState(editLabelData.name); + const [newLabelName, setNewLabelName] = useState(editLabelData?.name ?? ''); - const handleSave = () => { + const handleSave = useCallback(() => { + if (!editLabelData) return + handleSaveNewLabel(editLabelData.id, editLabelData.name, newLabelName); onClose(); - }; + }, [editLabelData]); return ( - - New Layer Name - setNewLabelName(e.target.value)} - onKeyDown={(e) => { - if (e.key === "Enter") { - e.preventDefault(); - handleSave(); - } - }} - /> -
- - -
-
+ + + {editLabelData && ( + <> + New Layer Name + setNewLabelName(e.target.value)} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + handleSave(); + } + }} + /> +
+ + +
+ + )} +
+
); }; @@ -190,14 +195,14 @@ export const LayerPicker = ({ )} - {editLabelData !== null && ( - setEditLabelData(null)} - editLabelData={editLabelData} - handleSaveNewLabel={handleSaveNewLabel} - /> - )} + + setEditLabelData(null)} + editLabelData={editLabelData} + handleSaveNewLabel={handleSaveNewLabel} + /> + Date: Sun, 29 Dec 2024 22:58:41 +0200 Subject: [PATCH 7/7] chore: small tweak to fix LicenseModal content --- src/ConnectModal.tsx | 5 ++--- src/misc/LicenseNoticeModal.tsx | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ConnectModal.tsx b/src/ConnectModal.tsx index c81bd7b0..f48269f2 100644 --- a/src/ConnectModal.tsx +++ b/src/ConnectModal.tsx @@ -8,7 +8,6 @@ import { Key, ListBox, ListBoxItem, Selection } from "react-aria-components"; import { ExternalLink } from "./misc/ExternalLink"; import { Modal, ModalContent } from "./components/modal/Modal"; import { ZmkStudio } from "./components/ZmkStudio"; -import { AppFooter } from './AppFooter' export type TransportFactory = { label: string; @@ -289,8 +288,8 @@ export const ConnectModal = ({ ? connectOptions(transports, onTransportCreated, open) : noTransportsOptionsPrompt()} -
- +
+ © 2024 - The ZMK Contributors
diff --git a/src/misc/LicenseNoticeModal.tsx b/src/misc/LicenseNoticeModal.tsx index 4beb4ef7..ae429848 100644 --- a/src/misc/LicenseNoticeModal.tsx +++ b/src/misc/LicenseNoticeModal.tsx @@ -14,7 +14,7 @@ export const LicenseNoticeModal: FC = ({ children }) => { {children} - +

ZMK Studio is released under the open source Apache 2.0 license. A @@ -22,7 +22,7 @@ export const LicenseNoticeModal: FC = ({ children }) => { here:

-
{NOTICE}
+
{NOTICE}