neogestify-ui-components 2.0.1 → 2.1.0
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.
- package/README.md +108 -19
- package/dist/components/VenueMapEditor/index.d.mts +49 -4
- package/dist/components/VenueMapEditor/index.d.ts +49 -4
- package/dist/components/VenueMapEditor/index.js +124 -31
- package/dist/components/VenueMapEditor/index.js.map +1 -1
- package/dist/components/VenueMapEditor/index.mjs +125 -33
- package/dist/components/VenueMapEditor/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +124 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +125 -33
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/VenueMapEditor/VenueMapEditor.tsx +79 -20
- package/src/components/VenueMapEditor/components/ElementNode.tsx +1 -0
- package/src/components/VenueMapEditor/components/Toolbar.tsx +59 -35
- package/src/components/VenueMapEditor/hooks/useLibraryStorage.ts +46 -0
- package/src/components/VenueMapEditor/index.ts +1 -0
- package/src/components/VenueMapEditor/types.ts +34 -2
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { forwardRef, useState, useEffect, useImperativeHandle, createContext, useContext,
|
|
2
|
+
import { forwardRef, useState, useEffect, useImperativeHandle, createContext, useContext, useCallback, useRef, useMemo } from 'react';
|
|
3
3
|
import Swal from 'sweetalert2';
|
|
4
4
|
|
|
5
5
|
// src/components/icons/icons.tsx
|
|
@@ -902,6 +902,33 @@ function ThemeToggle() {
|
|
|
902
902
|
}
|
|
903
903
|
);
|
|
904
904
|
}
|
|
905
|
+
function useLibraryStorage(storageKey) {
|
|
906
|
+
const [libs, setLibs] = useState(() => {
|
|
907
|
+
if (!storageKey) return {};
|
|
908
|
+
try {
|
|
909
|
+
const raw = localStorage.getItem(storageKey);
|
|
910
|
+
return raw ? JSON.parse(raw) : {};
|
|
911
|
+
} catch {
|
|
912
|
+
return {};
|
|
913
|
+
}
|
|
914
|
+
});
|
|
915
|
+
const setAndPersist = useCallback(
|
|
916
|
+
(newLibs) => {
|
|
917
|
+
setLibs(newLibs);
|
|
918
|
+
if (!storageKey) return;
|
|
919
|
+
try {
|
|
920
|
+
if (Object.keys(newLibs).length === 0) {
|
|
921
|
+
localStorage.removeItem(storageKey);
|
|
922
|
+
} else {
|
|
923
|
+
localStorage.setItem(storageKey, JSON.stringify(newLibs));
|
|
924
|
+
}
|
|
925
|
+
} catch {
|
|
926
|
+
}
|
|
927
|
+
},
|
|
928
|
+
[storageKey]
|
|
929
|
+
);
|
|
930
|
+
return [libs, setAndPersist];
|
|
931
|
+
}
|
|
905
932
|
function ToolButton({ active, disabled, title, onClick, children }) {
|
|
906
933
|
return /* @__PURE__ */ jsx(
|
|
907
934
|
"button",
|
|
@@ -966,6 +993,19 @@ function Toolbar({
|
|
|
966
993
|
onLoadLibrary,
|
|
967
994
|
onRemoveLibraryGroup
|
|
968
995
|
}) {
|
|
996
|
+
const [activeGroupId, setActiveGroupId] = useState(
|
|
997
|
+
() => paletteGroups[0]?.id ?? null
|
|
998
|
+
);
|
|
999
|
+
useEffect(() => {
|
|
1000
|
+
if (paletteGroups.length === 0) {
|
|
1001
|
+
setActiveGroupId(null);
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
if (!paletteGroups.find((g) => g.id === activeGroupId)) {
|
|
1005
|
+
setActiveGroupId(paletteGroups[0].id);
|
|
1006
|
+
}
|
|
1007
|
+
}, [paletteGroups, activeGroupId]);
|
|
1008
|
+
const activeGroup = paletteGroups.find((g) => g.id === activeGroupId) ?? null;
|
|
969
1009
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col bg-white border-b border-slate-200 shadow-sm shrink-0", children: [
|
|
970
1010
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 px-2 py-1.5", children: [
|
|
971
1011
|
/* @__PURE__ */ jsx(ToolButton, { title: "Seleccionar (V)", active: tool === "SELECT", onClick: () => onToolChange("SELECT"), children: /* @__PURE__ */ jsx(IconCursor, { className: "w-4 h-4" }) }),
|
|
@@ -1003,21 +1043,34 @@ function Toolbar({
|
|
|
1003
1043
|
/* @__PURE__ */ jsx(ToolButton, { title: areaShape === "polygon" ? "Cambiar a rect\xE1ngulo" : "Cambiar a pol\xEDgono", onClick: () => onToggleAreaShape?.(), children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: areaShape === "polygon" ? "Poly" : "Rect" }) })
|
|
1004
1044
|
] })
|
|
1005
1045
|
] }),
|
|
1006
|
-
tool === "PLACE" && /* @__PURE__ */
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1046
|
+
tool === "PLACE" && paletteGroups.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-col border-t border-slate-100", children: [
|
|
1047
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-end gap-0 overflow-x-auto bg-slate-50 border-b border-slate-200 px-2 pt-1", children: paletteGroups.map((group) => /* @__PURE__ */ jsx("div", { className: "flex items-center shrink-0", children: /* @__PURE__ */ jsxs(
|
|
1048
|
+
"button",
|
|
1049
|
+
{
|
|
1050
|
+
onClick: () => setActiveGroupId(group.id),
|
|
1051
|
+
className: [
|
|
1052
|
+
"flex items-center gap-1 px-3 py-1 text-xs font-medium rounded-t border-x border-t transition-colors whitespace-nowrap",
|
|
1053
|
+
group.id === activeGroupId ? "bg-white border-slate-200 text-slate-800 -mb-px pb-[5px]" : "bg-slate-50 border-transparent text-slate-400 hover:text-slate-600 hover:bg-slate-100"
|
|
1054
|
+
].join(" "),
|
|
1055
|
+
children: [
|
|
1056
|
+
group.name || "Sin nombre",
|
|
1057
|
+
!group.isBase && onRemoveLibraryGroup && /* @__PURE__ */ jsx(
|
|
1058
|
+
"span",
|
|
1059
|
+
{
|
|
1060
|
+
role: "button",
|
|
1061
|
+
title: `Eliminar "${group.name}"`,
|
|
1062
|
+
onClick: (e) => {
|
|
1063
|
+
e.stopPropagation();
|
|
1064
|
+
onRemoveLibraryGroup(group.id);
|
|
1065
|
+
},
|
|
1066
|
+
className: "ml-0.5 text-slate-300 hover:text-red-400 transition-colors leading-none",
|
|
1067
|
+
children: "\xD7"
|
|
1068
|
+
}
|
|
1069
|
+
)
|
|
1070
|
+
]
|
|
1071
|
+
}
|
|
1072
|
+
) }, group.id)) }),
|
|
1073
|
+
activeGroup && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 flex-wrap px-2 py-1.5 bg-white min-h-[36px]", children: activeGroup.types.map((typeDef) => /* @__PURE__ */ jsx(
|
|
1021
1074
|
TypeChip,
|
|
1022
1075
|
{
|
|
1023
1076
|
typeDef,
|
|
@@ -1026,7 +1079,7 @@ function Toolbar({
|
|
|
1026
1079
|
},
|
|
1027
1080
|
typeDef.id
|
|
1028
1081
|
)) })
|
|
1029
|
-
] }
|
|
1082
|
+
] })
|
|
1030
1083
|
] });
|
|
1031
1084
|
}
|
|
1032
1085
|
var ZOOM_MIN = 0.1;
|
|
@@ -1966,6 +2019,7 @@ function ElementNode({
|
|
|
1966
2019
|
{
|
|
1967
2020
|
d: typeDef.svgPath,
|
|
1968
2021
|
fill: fillColor,
|
|
2022
|
+
fillRule: typeDef.fillRule ?? "nonzero",
|
|
1969
2023
|
stroke: isSelected ? "#3b82f6" : typeDef.strokeColor,
|
|
1970
2024
|
strokeWidth: isSelected ? customPath.strokeWidth * 1.5 : customPath.strokeWidth,
|
|
1971
2025
|
style: { cursor: bodyCursor },
|
|
@@ -2813,7 +2867,23 @@ function createDefaultMap() {
|
|
|
2813
2867
|
]
|
|
2814
2868
|
};
|
|
2815
2869
|
}
|
|
2816
|
-
var
|
|
2870
|
+
var DEFAULT_LIBRARY_KEY = "venueMapEditor:libraries";
|
|
2871
|
+
function mergeLibraries(existing, incoming) {
|
|
2872
|
+
const result = { ...existing };
|
|
2873
|
+
for (const [groupId, incomingGroup] of Object.entries(incoming)) {
|
|
2874
|
+
if (result[groupId]) {
|
|
2875
|
+
const existingIds = new Set(result[groupId].objects.map((o) => o.id));
|
|
2876
|
+
const newObjects = incomingGroup.objects.filter((o) => !existingIds.has(o.id));
|
|
2877
|
+
result[groupId] = {
|
|
2878
|
+
...result[groupId],
|
|
2879
|
+
objects: [...result[groupId].objects, ...newObjects]
|
|
2880
|
+
};
|
|
2881
|
+
} else {
|
|
2882
|
+
result[groupId] = incomingGroup;
|
|
2883
|
+
}
|
|
2884
|
+
}
|
|
2885
|
+
return result;
|
|
2886
|
+
}
|
|
2817
2887
|
function updateFloor(map, updatedFloor) {
|
|
2818
2888
|
return {
|
|
2819
2889
|
...map,
|
|
@@ -2853,7 +2923,9 @@ function polygonToRect(area) {
|
|
|
2853
2923
|
};
|
|
2854
2924
|
}
|
|
2855
2925
|
function VenueMapEditor({
|
|
2856
|
-
|
|
2926
|
+
domainConfigs,
|
|
2927
|
+
domainConfig,
|
|
2928
|
+
libraryStorageKey = DEFAULT_LIBRARY_KEY,
|
|
2857
2929
|
initialMap,
|
|
2858
2930
|
onChange,
|
|
2859
2931
|
width = "100%",
|
|
@@ -2867,7 +2939,13 @@ function VenueMapEditor({
|
|
|
2867
2939
|
onElementClick,
|
|
2868
2940
|
onElementTypeClick
|
|
2869
2941
|
}) {
|
|
2942
|
+
const effectiveConfigs = useMemo(() => {
|
|
2943
|
+
if (domainConfigs && domainConfigs.length > 0) return domainConfigs;
|
|
2944
|
+
if (domainConfig) return [domainConfig];
|
|
2945
|
+
return [];
|
|
2946
|
+
}, [domainConfigs, domainConfig]);
|
|
2870
2947
|
const initialMapRef = useRef(initialMap ?? createDefaultMap());
|
|
2948
|
+
const [persistedLibs, setPersistedLibs] = useLibraryStorage(libraryStorageKey);
|
|
2871
2949
|
const { map, canUndo, canRedo, push, replace, undo, redo } = useHistory(
|
|
2872
2950
|
initialMapRef.current
|
|
2873
2951
|
);
|
|
@@ -2883,31 +2961,40 @@ function VenueMapEditor({
|
|
|
2883
2961
|
const resetViewRef = useRef(() => void 0);
|
|
2884
2962
|
const importInputRef = useRef(null);
|
|
2885
2963
|
const libraryInputRef = useRef(null);
|
|
2964
|
+
const effectiveLibs = useMemo(() => ({
|
|
2965
|
+
...map.libraries ?? {},
|
|
2966
|
+
...persistedLibs
|
|
2967
|
+
}), [map.libraries, persistedLibs]);
|
|
2886
2968
|
const buildTypeDefs = useCallback(() => {
|
|
2887
|
-
const m = new Map(
|
|
2888
|
-
const
|
|
2889
|
-
|
|
2969
|
+
const m = /* @__PURE__ */ new Map();
|
|
2970
|
+
for (const cfg of effectiveConfigs) {
|
|
2971
|
+
for (const t of cfg.elementTypes) {
|
|
2972
|
+
if (!m.has(t.id)) m.set(t.id, t);
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
for (const group of Object.values(effectiveLibs)) {
|
|
2890
2976
|
for (const t of group.objects) {
|
|
2891
2977
|
if (!m.has(t.id)) m.set(t.id, t);
|
|
2892
2978
|
}
|
|
2893
2979
|
}
|
|
2894
2980
|
return m;
|
|
2895
|
-
}, [
|
|
2981
|
+
}, [effectiveConfigs, effectiveLibs]);
|
|
2896
2982
|
const elementTypeDefs = useRef(buildTypeDefs());
|
|
2897
2983
|
useEffect(() => {
|
|
2898
2984
|
elementTypeDefs.current = buildTypeDefs();
|
|
2899
2985
|
}, [buildTypeDefs]);
|
|
2900
2986
|
const paletteGroups = useMemo(() => {
|
|
2901
2987
|
const groups = [];
|
|
2902
|
-
|
|
2903
|
-
|
|
2988
|
+
for (const cfg of effectiveConfigs) {
|
|
2989
|
+
if (cfg.elementTypes.length > 0) {
|
|
2990
|
+
groups.push({ id: cfg.id, name: cfg.name, types: cfg.elementTypes, isBase: true });
|
|
2991
|
+
}
|
|
2904
2992
|
}
|
|
2905
|
-
const
|
|
2906
|
-
for (const [gid, group] of Object.entries(libs)) {
|
|
2993
|
+
for (const [gid, group] of Object.entries(effectiveLibs)) {
|
|
2907
2994
|
groups.push({ id: gid, name: group.name, types: group.objects, isBase: false });
|
|
2908
2995
|
}
|
|
2909
2996
|
return groups;
|
|
2910
|
-
}, [
|
|
2997
|
+
}, [effectiveConfigs, effectiveLibs]);
|
|
2911
2998
|
useEffect(() => {
|
|
2912
2999
|
if (activePlaceTypeId) return;
|
|
2913
3000
|
const firstType = paletteGroups[0]?.types[0];
|
|
@@ -3047,22 +3134,27 @@ function VenueMapEditor({
|
|
|
3047
3134
|
reader.onload = (e) => {
|
|
3048
3135
|
try {
|
|
3049
3136
|
const parsed = JSON.parse(e.target?.result);
|
|
3050
|
-
const
|
|
3051
|
-
|
|
3137
|
+
const mergedPersisted = mergeLibraries(persistedLibs, parsed);
|
|
3138
|
+
setPersistedLibs(mergedPersisted);
|
|
3139
|
+
const mergedMap = mergeLibraries(map.libraries ?? {}, parsed);
|
|
3140
|
+
push({ ...map, libraries: mergedMap });
|
|
3052
3141
|
} catch {
|
|
3053
3142
|
}
|
|
3054
3143
|
};
|
|
3055
3144
|
reader.readAsText(file);
|
|
3056
3145
|
},
|
|
3057
|
-
[map, push]
|
|
3146
|
+
[map, push, persistedLibs, setPersistedLibs]
|
|
3058
3147
|
);
|
|
3059
3148
|
const handleRemoveLibraryGroup = useCallback(
|
|
3060
3149
|
(groupId) => {
|
|
3150
|
+
const newPersistedLibs = { ...persistedLibs };
|
|
3151
|
+
delete newPersistedLibs[groupId];
|
|
3152
|
+
setPersistedLibs(newPersistedLibs);
|
|
3061
3153
|
const libs = { ...map.libraries ?? {} };
|
|
3062
3154
|
delete libs[groupId];
|
|
3063
3155
|
push({ ...map, libraries: Object.keys(libs).length > 0 ? libs : void 0 });
|
|
3064
3156
|
},
|
|
3065
|
-
[map, push]
|
|
3157
|
+
[map, push, persistedLibs, setPersistedLibs]
|
|
3066
3158
|
);
|
|
3067
3159
|
const DEFAULT_WALL_THICKNESS = 8;
|
|
3068
3160
|
const handleAddWall = useCallback(
|
|
@@ -3509,6 +3601,6 @@ function VenueMapViewer({ elementStatus, onElementClick, ...rest }) {
|
|
|
3509
3601
|
);
|
|
3510
3602
|
}
|
|
3511
3603
|
|
|
3512
|
-
export { AddIcon, Alerta, AlertaAdvertencia, AlertaConfirmacion, AlertaError, AlertaExito, AlertaInfo, AlertaToast, AnimateSpin, ArchiveIcon, ArrowIcon, ArrowLeftIcon, ArrowRightIcon, BackIcon, BarsChartsIcon, BoxIcon, BuildingIcon, Button, CajasIcon, CalendarIcon, CamaraIcon, CancelIcon, CashIcon, CategorieIcon, ChartIcon, CheckCircleIcon, CheckIcon, ClockIcon, CloseIcon, CloudIcon, CopyIcon, DeleteIcon, DocumentIcon, EditIcon, FacturacionIcon, FilterIcon, FolderIcon, Form, GearIcon, HomeIcon, IconCursor, IconDownload, IconDuplicate, IconErase, IconGrid, IconHand, IconLayers, IconPlace, IconPolygon, IconRedo, IconReset, IconUndo, IconUpload, IconWall, IconZoomIn, IconZoomOut, InfoAlert, InfoIcon, Input, LifeGuardIcon, LightingIcon, Loading, LocationIcon, LogoutIcon, MenuIcon, MinusIcon, Modal, MoneyIcon, MonitorIcon, MoonIcon, NetworkIcon, NotFoundIcon, PasteIcon, PercentIcon, PrinterIcon, QuestionIcon, RestaurantMenuIcon, SaveIcon, SearchIcon, Select, ShieldIcon, SpinnerIcon, StackIcon, SunIcon, Table, TestIcon, TextArea, ThemeContext, ThemeProvider, ThemeToggle, TrashIcon, TruckIcon, UsersIcon, VenueMapEditor, VenueMapViewer, WhatsAppIcon, findNearestNode, genId, snapPoint, snapToGrid, usePanZoom, useTheme };
|
|
3604
|
+
export { AddIcon, Alerta, AlertaAdvertencia, AlertaConfirmacion, AlertaError, AlertaExito, AlertaInfo, AlertaToast, AnimateSpin, ArchiveIcon, ArrowIcon, ArrowLeftIcon, ArrowRightIcon, BackIcon, BarsChartsIcon, BoxIcon, BuildingIcon, Button, CajasIcon, CalendarIcon, CamaraIcon, CancelIcon, CashIcon, CategorieIcon, ChartIcon, CheckCircleIcon, CheckIcon, ClockIcon, CloseIcon, CloudIcon, CopyIcon, DeleteIcon, DocumentIcon, EditIcon, FacturacionIcon, FilterIcon, FolderIcon, Form, GearIcon, HomeIcon, IconCursor, IconDownload, IconDuplicate, IconErase, IconGrid, IconHand, IconLayers, IconPlace, IconPolygon, IconRedo, IconReset, IconUndo, IconUpload, IconWall, IconZoomIn, IconZoomOut, InfoAlert, InfoIcon, Input, LifeGuardIcon, LightingIcon, Loading, LocationIcon, LogoutIcon, MenuIcon, MinusIcon, Modal, MoneyIcon, MonitorIcon, MoonIcon, NetworkIcon, NotFoundIcon, PasteIcon, PercentIcon, PrinterIcon, QuestionIcon, RestaurantMenuIcon, SaveIcon, SearchIcon, Select, ShieldIcon, SpinnerIcon, StackIcon, SunIcon, Table, TestIcon, TextArea, ThemeContext, ThemeProvider, ThemeToggle, TrashIcon, TruckIcon, UsersIcon, VenueMapEditor, VenueMapViewer, WhatsAppIcon, findNearestNode, genId, snapPoint, snapToGrid, useLibraryStorage, usePanZoom, useTheme };
|
|
3513
3605
|
//# sourceMappingURL=index.mjs.map
|
|
3514
3606
|
//# sourceMappingURL=index.mjs.map
|