DefinitionActions
uses useState
What a definition's page does with it in the studio: Edit it (in a scratch file), Rename it (or move it: a name
of another namespace), as tcm mv, or Delete its name, as tcm rm, asking first and saying what uses it (which
keeps working, by hash). usedBy: the named definitions that use it; editable: whether it's code or text to edit.
import { navigate } from "#codebase/tcmts/react"; import { codeHref, toasts } from "#codebase/tcmts/share"; import { EditButton, removeDefinition, renameDefinition } from "#codebase/tcmts/studio"; import { useState } from "react"; import { Button, Dialog, DialogTrigger, Heading, Input, Label, Popover, TextField } from "react-aria-components"; export function DefinitionActions({ name, usedBy, editable, }: { name: string; usedBy: string[]; editable: boolean; }) { const [to, setTo] = useState(name); const [busy, setBusy] = useState(false); const parent = name.includes(".") ? name.slice(0, name.lastIndexOf(".")) : ""; return ( <> {editable && <EditButton name={name} />} <DialogTrigger onOpenChange={(open) => open && setTo(name)}> <Button className="btn">Rename</Button> <Popover className="menu-pop getit" placement="bottom end" offset={6}> <Dialog className="getit-body" aria-label={`Rename ${name}`}> {({ close }) => ( <form className="prodform" onSubmit={async (e) => { e.preventDefault(); const want = to.trim(); if (want === name) return close(); setBusy(true); try { const said = await renameDefinition(name, want); close(); toasts.add( { title: said || `Renamed to ${want}`, tone: "ok" }, { timeout: 4000 }, ); navigate(codeHref(want)); } catch (err) { toasts.add( { title: `Couldn't rename ${name}`, description: (err as Error).message, tone: "bad", }, { timeout: 8000 }, ); } setBusy(false); }} > <Heading slot="title" className="getit-title"> Rename {name} </Heading> <TextField className="fieldrow" value={to} onChange={setTo} autoFocus> <Label>Its name</Label> <Input className="field mono" /> </TextField> <p> Its code stays as it is, and what uses it follows (by hash). Another namespace moves it there. </p> <div className="actions"> <Button className="btn" onPress={close}> Cancel </Button> <Button className="btn primary" type="submit" isPending={busy}> Rename </Button> </div> </form> )} </Dialog> </Popover> </DialogTrigger> <DialogTrigger> <Button className="btn danger">Delete</Button> <Popover className="menu-pop getit" placement="bottom end" offset={6}> <Dialog className="getit-body" aria-label={`Delete ${name}`}> {({ close }) => ( <> <Heading slot="title" className="getit-title"> Delete {name}? </Heading> {usedBy.length ? ( <p> {`${usedBy.length} named definition${usedBy.length === 1 ? " uses" : "s use"} it (${usedBy.slice(0, 4).join(", ")}${usedBy.length > 4 ? ", …" : ""}). ${usedBy.length === 1 ? "It keeps" : "They keep"} working, by its hash, but its name goes: history keeps it.`} </p> ) : ( <p>Nothing named uses it. Its name goes; history keeps it.</p> )} <div className="actions"> <Button className="btn" onPress={close}> Keep it </Button> <Button className="btn danger" onPress={async () => { close(); try { const said = await removeDefinition(name, usedBy.length > 0); toasts.add( { title: said || `Deleted ${name}`, tone: "ok" }, { timeout: 4000 }, ); navigate(codeHref(parent)); } catch (err) { toasts.add( { title: `Couldn't delete ${name}`, description: (err as Error).message, tone: "bad", }, { timeout: 8000 }, ); } }} > Delete </Button> </div> </> )} </Dialog> </Popover> </DialogTrigger> </> ); }
uses
- tcmts.react.navigate
- tcmts.share.codeHref
- tcmts.share.toasts
- tcmts.studio.EditButton
- tcmts.studio.removeDefinition
- tcmts.studio.renameDefinition