@spacesync/client 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,11 +4,12 @@ interface FloorSwitcherFloor {
4
4
  id: string;
5
5
  name: string;
6
6
  }
7
- declare function FloorSwitcher({ floors, activeFloorId, onFloorChange, onAddFloor, }: {
7
+ declare function FloorSwitcher({ floors, activeFloorId, onFloorChange, onAddFloor, onDeleteFloor, }: {
8
8
  floors: FloorSwitcherFloor[];
9
9
  activeFloorId: string;
10
10
  onFloorChange: (floorId: string) => void;
11
11
  onAddFloor?: (name: string) => void;
12
+ onDeleteFloor?: (floorId: string) => void;
12
13
  }): React.JSX.Element;
13
14
 
14
15
  export { FloorSwitcher, type FloorSwitcherFloor };
@@ -10,7 +10,7 @@ import { Button } from './chunk-VHINHHZQ.js';
10
10
  import { shellTopBarMutedIconClass, shellTopBarSecondaryButtonClass } from './chunk-FCY5FYJB.js';
11
11
  import './chunk-OWNUMPUC.js';
12
12
  import { cn } from './chunk-DMPSQ22Q.js';
13
- import { Layers, ChevronDown, Check, Plus } from 'lucide-react';
13
+ import { Layers, ChevronDown, Check, Plus, Trash2 } from 'lucide-react';
14
14
  import { useState, useEffect } from 'react';
15
15
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
16
16
 
@@ -18,11 +18,13 @@ function FloorSwitcher({
18
18
  floors,
19
19
  activeFloorId,
20
20
  onFloorChange,
21
- onAddFloor
21
+ onAddFloor,
22
+ onDeleteFloor
22
23
  }) {
23
24
  const activeFloor = floors.find((f) => f.id === activeFloorId) ?? floors[0];
24
25
  const [addOpen, setAddOpen] = useState(false);
25
26
  const [name, setName] = useState("");
27
+ const canDeleteFloor = Boolean(onDeleteFloor) && floors.length > 1;
26
28
  useEffect(() => {
27
29
  if (addOpen) {
28
30
  setName(`Floor ${floors.length + 1}`);
@@ -63,12 +65,23 @@ function FloorSwitcher({
63
65
  },
64
66
  floor.id
65
67
  )),
66
- onAddFloor ? /* @__PURE__ */ jsxs(Fragment, { children: [
68
+ onAddFloor || canDeleteFloor ? /* @__PURE__ */ jsxs(Fragment, { children: [
67
69
  /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
68
- /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => setAddOpen(true), children: [
70
+ onAddFloor ? /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => setAddOpen(true), children: [
69
71
  /* @__PURE__ */ jsx(Plus, { size: 14, className: "mr-1.5" }),
70
72
  "Add floor\u2026"
71
- ] })
73
+ ] }) : null,
74
+ canDeleteFloor ? /* @__PURE__ */ jsxs(
75
+ DropdownMenuItem,
76
+ {
77
+ variant: "destructive",
78
+ onClick: () => onDeleteFloor?.(activeFloorId),
79
+ children: [
80
+ /* @__PURE__ */ jsx(Trash2, { size: 14, className: "mr-1.5" }),
81
+ "Delete floor\u2026"
82
+ ]
83
+ }
84
+ ) : null
72
85
  ] }) : null
73
86
  ] })
74
87
  ] }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/live-space/floor-switcher.tsx"],"names":[],"mappings":"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","file":"floor-switcher.js","sourcesContent":["import { Check, ChevronDown, Layers, Plus } from \"lucide-react\";\nimport { shellTopBarMutedIconClass, shellTopBarSecondaryButtonClass } from \"../shell/shell-top-bar-chrome\";\nimport {\n Button,\n cn,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Input,\n Label,\n} from \"../ui\";\nimport { useEffect, useState } from \"react\";\n\nexport interface FloorSwitcherFloor {\n id: string;\n name: string;\n}\n\nexport function FloorSwitcher({\n floors,\n activeFloorId,\n onFloorChange,\n onAddFloor,\n}: {\n floors: FloorSwitcherFloor[];\n activeFloorId: string;\n onFloorChange: (floorId: string) => void;\n onAddFloor?: (name: string) => void;\n}) {\n const activeFloor = floors.find((f) => f.id === activeFloorId) ?? floors[0];\n const [addOpen, setAddOpen] = useState(false);\n const [name, setName] = useState(\"\");\n\n useEffect(() => {\n if (addOpen) {\n setName(`Floor ${floors.length + 1}`);\n }\n }, [addOpen, floors.length]);\n\n const handleAdd = () => {\n onAddFloor?.(name.trim() || `Floor ${floors.length + 1}`);\n setAddOpen(false);\n };\n\n return (\n <>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={cn(\n shellTopBarSecondaryButtonClass,\n \"min-w-0 max-w-[10rem] outline-none focus-visible:ring-2 focus-visible:ring-blue-500/30\",\n )}\n aria-label=\"Switch floor\"\n >\n <Layers size={12} className={cn(\"shrink-0\", shellTopBarMutedIconClass)} aria-hidden />\n <span className=\"truncate\">{activeFloor?.name ?? \"Floor\"}</span>\n <ChevronDown size={12} className={cn(\"shrink-0\", shellTopBarMutedIconClass)} aria-hidden />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-48\">\n {floors.map((floor) => (\n <DropdownMenuItem\n key={floor.id}\n onClick={() => onFloorChange(floor.id)}\n className=\"flex items-center justify-between gap-2\"\n >\n <span className=\"truncate\">{floor.name}</span>\n {floor.id === activeFloorId ? (\n <Check size={14} className=\"shrink-0 text-blue-600\" aria-hidden />\n ) : (\n <span className=\"size-3.5 shrink-0\" aria-hidden />\n )}\n </DropdownMenuItem>\n ))}\n {onAddFloor ? (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem onClick={() => setAddOpen(true)}>\n <Plus size={14} className=\"mr-1.5\" />\n Add floor…\n </DropdownMenuItem>\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n\n {onAddFloor ? (\n <Dialog open={addOpen} onOpenChange={setAddOpen}>\n <DialogContent className=\"sm:max-w-md border-border\">\n <DialogHeader>\n <DialogTitle>Add floor</DialogTitle>\n <DialogDescription>\n Create a new floor with its own resources and 2D layout.\n </DialogDescription>\n </DialogHeader>\n <div className=\"py-1\">\n <Label htmlFor=\"new-floor-name\">Name</Label>\n <Input\n id=\"new-floor-name\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Floor 2\"\n className=\"mt-2 h-9\"\n autoFocus\n onKeyDown={(e) => {\n if (e.key === \"Enter\") handleAdd();\n }}\n />\n </div>\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setAddOpen(false)}>\n Cancel\n </Button>\n <Button type=\"button\" onClick={handleAdd}>\n Add floor\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n ) : null}\n </>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/live-space/floor-switcher.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;AA0BO,SAAS,aAAA,CAAc;AAAA,EAC5B,MAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF,CAAA,EAMG;AACD,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,EAAE,EAAA,KAAO,aAAa,CAAA,IAAK,MAAA,CAAO,CAAC,CAAA;AAC1E,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,EAAE,CAAA;AACnC,EAAA,MAAM,cAAA,GAAiB,OAAA,CAAQ,aAAa,CAAA,IAAK,OAAO,MAAA,GAAS,CAAA;AAEjE,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,OAAA,CAAQ,CAAA,MAAA,EAAS,MAAA,CAAO,MAAA,GAAS,CAAC,CAAA,CAAE,CAAA;AAAA,IACtC;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,EAAS,MAAA,CAAO,MAAM,CAAC,CAAA;AAE3B,EAAA,MAAM,YAAY,MAAM;AACtB,IAAA,UAAA,GAAa,KAAK,IAAA,EAAK,IAAK,SAAS,MAAA,CAAO,MAAA,GAAS,CAAC,CAAA,CAAE,CAAA;AACxD,IAAA,UAAA,CAAW,KAAK,CAAA;AAAA,EAClB,CAAA;AAEA,EAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,mBAAA,EAAA,EAAoB,SAAO,IAAA,EAC1B,QAAA,kBAAA,IAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,SAAA,EAAW,EAAA;AAAA,YACT,+BAAA;AAAA,YACA;AAAA,WACF;AAAA,UACA,YAAA,EAAW,cAAA;AAAA,UAEX,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,MAAA,EAAA,EAAO,MAAM,EAAA,EAAI,SAAA,EAAW,GAAG,UAAA,EAAY,yBAAyB,CAAA,EAAG,aAAA,EAAW,IAAA,EAAC,CAAA;AAAA,gCACnF,MAAA,EAAA,EAAK,SAAA,EAAU,UAAA,EAAY,QAAA,EAAA,WAAA,EAAa,QAAQ,OAAA,EAAQ,CAAA;AAAA,4BACzD,GAAA,CAAC,WAAA,EAAA,EAAY,IAAA,EAAM,EAAA,EAAI,SAAA,EAAW,GAAG,UAAA,EAAY,yBAAyB,CAAA,EAAG,aAAA,EAAW,IAAA,EAAC;AAAA;AAAA;AAAA,OAC3F,EACF,CAAA;AAAA,sBACA,IAAA,CAAC,mBAAA,EAAA,EAAoB,KAAA,EAAM,OAAA,EAAQ,WAAU,MAAA,EAC1C,QAAA,EAAA;AAAA,QAAA,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,qBACX,IAAA;AAAA,UAAC,gBAAA;AAAA,UAAA;AAAA,YAEC,OAAA,EAAS,MAAM,aAAA,CAAc,KAAA,CAAM,EAAE,CAAA;AAAA,YACrC,SAAA,EAAU,yCAAA;AAAA,YAEV,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,UAAA,EAAY,QAAA,EAAA,KAAA,CAAM,IAAA,EAAK,CAAA;AAAA,cACtC,MAAM,EAAA,KAAO,aAAA,mBACZ,GAAA,CAAC,KAAA,EAAA,EAAM,MAAM,EAAA,EAAI,SAAA,EAAU,wBAAA,EAAyB,aAAA,EAAW,MAAC,CAAA,mBAEhE,GAAA,CAAC,UAAK,SAAA,EAAU,mBAAA,EAAoB,eAAW,IAAA,EAAC;AAAA;AAAA,WAAA;AAAA,UAR7C,KAAA,CAAM;AAAA,SAWd,CAAA;AAAA,QACA,UAAA,IAAc,iCACb,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,qBAAA,EAAA,EAAsB,CAAA;AAAA,UACtB,6BACC,IAAA,CAAC,gBAAA,EAAA,EAAiB,SAAS,MAAM,UAAA,CAAW,IAAI,CAAA,EAC9C,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAM,EAAA,EAAI,SAAA,EAAU,QAAA,EAAS,CAAA;AAAA,YAAE;AAAA,WAAA,EAEvC,CAAA,GACE,IAAA;AAAA,UACH,cAAA,mBACC,IAAA;AAAA,YAAC,gBAAA;AAAA,YAAA;AAAA,cACC,OAAA,EAAQ,aAAA;AAAA,cACR,OAAA,EAAS,MAAM,aAAA,GAAgB,aAAa,CAAA;AAAA,cAE5C,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAM,EAAA,EAAI,SAAA,EAAU,QAAA,EAAS,CAAA;AAAA,gBAAE;AAAA;AAAA;AAAA,WAEzC,GACE;AAAA,SAAA,EACN,CAAA,GACE;AAAA,OAAA,EACN;AAAA,KAAA,EACF,CAAA;AAAA,IAEC,UAAA,mBACC,GAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAM,OAAA,EAAS,cAAc,UAAA,EACnC,QAAA,kBAAA,IAAA,CAAC,aAAA,EAAA,EAAc,SAAA,EAAU,2BAAA,EACvB,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,eAAY,QAAA,EAAA,WAAA,EAAS,CAAA;AAAA,wBACtB,GAAA,CAAC,qBAAkB,QAAA,EAAA,0DAAA,EAEnB;AAAA,OAAA,EACF,CAAA;AAAA,sBACA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,MAAA,EACb,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,EAAA,EAAM,OAAA,EAAQ,gBAAA,EAAiB,QAAA,EAAA,MAAA,EAAI,CAAA;AAAA,wBACpC,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,EAAA,EAAG,gBAAA;AAAA,YACH,KAAA,EAAO,IAAA;AAAA,YACP,UAAU,CAAC,CAAA,KAAM,OAAA,CAAQ,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,YACvC,WAAA,EAAY,cAAA;AAAA,YACZ,SAAA,EAAU,UAAA;AAAA,YACV,SAAA,EAAS,IAAA;AAAA,YACT,SAAA,EAAW,CAAC,CAAA,KAAM;AAChB,cAAA,IAAI,CAAA,CAAE,GAAA,KAAQ,OAAA,EAAS,SAAA,EAAU;AAAA,YACnC;AAAA;AAAA;AACF,OAAA,EACF,CAAA;AAAA,2BACC,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,OAAA,EAAQ,SAAA,EAAU,SAAS,MAAM,UAAA,CAAW,KAAK,CAAA,EAAG,QAAA,EAAA,QAAA,EAE1E,CAAA;AAAA,4BACC,MAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,OAAA,EAAS,WAAW,QAAA,EAAA,WAAA,EAE1C;AAAA,OAAA,EACF;AAAA,KAAA,EACF,GACF,CAAA,GACE;AAAA,GAAA,EACN,CAAA;AAEJ","file":"floor-switcher.js","sourcesContent":["import { Check, ChevronDown, Layers, Plus, Trash2 } from \"lucide-react\";\nimport { shellTopBarMutedIconClass, shellTopBarSecondaryButtonClass } from \"../shell/shell-top-bar-chrome\";\nimport {\n Button,\n cn,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Input,\n Label,\n} from \"../ui\";\nimport { useEffect, useState } from \"react\";\n\nexport interface FloorSwitcherFloor {\n id: string;\n name: string;\n}\n\nexport function FloorSwitcher({\n floors,\n activeFloorId,\n onFloorChange,\n onAddFloor,\n onDeleteFloor,\n}: {\n floors: FloorSwitcherFloor[];\n activeFloorId: string;\n onFloorChange: (floorId: string) => void;\n onAddFloor?: (name: string) => void;\n onDeleteFloor?: (floorId: string) => void;\n}) {\n const activeFloor = floors.find((f) => f.id === activeFloorId) ?? floors[0];\n const [addOpen, setAddOpen] = useState(false);\n const [name, setName] = useState(\"\");\n const canDeleteFloor = Boolean(onDeleteFloor) && floors.length > 1;\n\n useEffect(() => {\n if (addOpen) {\n setName(`Floor ${floors.length + 1}`);\n }\n }, [addOpen, floors.length]);\n\n const handleAdd = () => {\n onAddFloor?.(name.trim() || `Floor ${floors.length + 1}`);\n setAddOpen(false);\n };\n\n return (\n <>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={cn(\n shellTopBarSecondaryButtonClass,\n \"min-w-0 max-w-[10rem] outline-none focus-visible:ring-2 focus-visible:ring-blue-500/30\",\n )}\n aria-label=\"Switch floor\"\n >\n <Layers size={12} className={cn(\"shrink-0\", shellTopBarMutedIconClass)} aria-hidden />\n <span className=\"truncate\">{activeFloor?.name ?? \"Floor\"}</span>\n <ChevronDown size={12} className={cn(\"shrink-0\", shellTopBarMutedIconClass)} aria-hidden />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-48\">\n {floors.map((floor) => (\n <DropdownMenuItem\n key={floor.id}\n onClick={() => onFloorChange(floor.id)}\n className=\"flex items-center justify-between gap-2\"\n >\n <span className=\"truncate\">{floor.name}</span>\n {floor.id === activeFloorId ? (\n <Check size={14} className=\"shrink-0 text-blue-600\" aria-hidden />\n ) : (\n <span className=\"size-3.5 shrink-0\" aria-hidden />\n )}\n </DropdownMenuItem>\n ))}\n {onAddFloor || canDeleteFloor ? (\n <>\n <DropdownMenuSeparator />\n {onAddFloor ? (\n <DropdownMenuItem onClick={() => setAddOpen(true)}>\n <Plus size={14} className=\"mr-1.5\" />\n Add floor…\n </DropdownMenuItem>\n ) : null}\n {canDeleteFloor ? (\n <DropdownMenuItem\n variant=\"destructive\"\n onClick={() => onDeleteFloor?.(activeFloorId)}\n >\n <Trash2 size={14} className=\"mr-1.5\" />\n Delete floor…\n </DropdownMenuItem>\n ) : null}\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n\n {onAddFloor ? (\n <Dialog open={addOpen} onOpenChange={setAddOpen}>\n <DialogContent className=\"sm:max-w-md border-border\">\n <DialogHeader>\n <DialogTitle>Add floor</DialogTitle>\n <DialogDescription>\n Create a new floor with its own resources and 2D layout.\n </DialogDescription>\n </DialogHeader>\n <div className=\"py-1\">\n <Label htmlFor=\"new-floor-name\">Name</Label>\n <Input\n id=\"new-floor-name\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Floor 2\"\n className=\"mt-2 h-9\"\n autoFocus\n onKeyDown={(e) => {\n if (e.key === \"Enter\") handleAdd();\n }}\n />\n </div>\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setAddOpen(false)}>\n Cancel\n </Button>\n <Button type=\"button\" onClick={handleAdd}>\n Add floor\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n ) : null}\n </>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spacesync/client",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Reusable SpaceSync React UI, shell, theme, and API client primitives.",
5
5
  "type": "module",
6
6
  "files": [