@motor-hero/ui-kit 0.23.2 → 0.25.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/dist/components/combobox.d.ts +19 -1
- package/dist/components/combobox.d.ts.map +1 -1
- package/dist/components/multi-combobox.d.ts +13 -1
- package/dist/components/multi-combobox.d.ts.map +1 -1
- package/dist/hooks/use-infinite-scroll-sentinel.d.ts +16 -0
- package/dist/hooks/use-infinite-scroll-sentinel.d.ts.map +1 -0
- package/dist/index.cjs +219 -92
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +224 -97
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/combobox.tsx +112 -14
- package/src/components/multi-combobox.tsx +61 -8
- package/src/hooks/use-infinite-scroll-sentinel.ts +47 -0
package/dist/index.js
CHANGED
|
@@ -615,18 +615,52 @@ PasswordInput.displayName = "PasswordInput";
|
|
|
615
615
|
// src/components/combobox.tsx
|
|
616
616
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
617
617
|
import { Command as CommandPrimitive } from "cmdk";
|
|
618
|
-
import { Check, ChevronsUpDown, Search } from "lucide-react";
|
|
619
|
-
import * as
|
|
618
|
+
import { Check, ChevronsUpDown, Loader2, Plus, Search } from "lucide-react";
|
|
619
|
+
import * as React6 from "react";
|
|
620
620
|
import { Drawer as DrawerPrimitive } from "vaul";
|
|
621
621
|
|
|
622
|
-
// src/hooks/use-
|
|
622
|
+
// src/hooks/use-infinite-scroll-sentinel.ts
|
|
623
623
|
import * as React4 from "react";
|
|
624
|
+
function useInfiniteScrollSentinel({
|
|
625
|
+
enabled,
|
|
626
|
+
loading,
|
|
627
|
+
onLoadMore
|
|
628
|
+
}) {
|
|
629
|
+
const listRef = React4.useRef(null);
|
|
630
|
+
const sentinelRef = React4.useRef(null);
|
|
631
|
+
const loadingRef = React4.useRef(loading);
|
|
632
|
+
const onLoadMoreRef = React4.useRef(onLoadMore);
|
|
633
|
+
React4.useEffect(() => {
|
|
634
|
+
loadingRef.current = loading;
|
|
635
|
+
onLoadMoreRef.current = onLoadMore;
|
|
636
|
+
});
|
|
637
|
+
React4.useEffect(() => {
|
|
638
|
+
if (!enabled) return;
|
|
639
|
+
const root = listRef.current;
|
|
640
|
+
const sentinel = sentinelRef.current;
|
|
641
|
+
if (!root || !sentinel) return;
|
|
642
|
+
const observer = new IntersectionObserver(
|
|
643
|
+
(entries) => {
|
|
644
|
+
if (entries[0]?.isIntersecting && !loadingRef.current) {
|
|
645
|
+
onLoadMoreRef.current?.();
|
|
646
|
+
}
|
|
647
|
+
},
|
|
648
|
+
{ root, rootMargin: "0px 0px 100px 0px" }
|
|
649
|
+
);
|
|
650
|
+
observer.observe(sentinel);
|
|
651
|
+
return () => observer.disconnect();
|
|
652
|
+
}, [enabled]);
|
|
653
|
+
return { listRef, sentinelRef };
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// src/hooks/use-is-desktop.ts
|
|
657
|
+
import * as React5 from "react";
|
|
624
658
|
var DESKTOP_QUERY = "(min-width: 640px)";
|
|
625
659
|
function useIsDesktop() {
|
|
626
|
-
const [isDesktop, setIsDesktop] =
|
|
660
|
+
const [isDesktop, setIsDesktop] = React5.useState(
|
|
627
661
|
() => typeof window !== "undefined" ? window.matchMedia(DESKTOP_QUERY).matches : true
|
|
628
662
|
);
|
|
629
|
-
|
|
663
|
+
React5.useEffect(() => {
|
|
630
664
|
const mql = window.matchMedia(DESKTOP_QUERY);
|
|
631
665
|
const onChange = () => setIsDesktop(mql.matches);
|
|
632
666
|
onChange();
|
|
@@ -649,11 +683,41 @@ function Combobox({
|
|
|
649
683
|
id,
|
|
650
684
|
className,
|
|
651
685
|
"aria-invalid": ariaInvalid,
|
|
652
|
-
"aria-describedby": ariaDescribedby
|
|
686
|
+
"aria-describedby": ariaDescribedby,
|
|
687
|
+
onSearchChange,
|
|
688
|
+
onLoadMore,
|
|
689
|
+
loading,
|
|
690
|
+
hasMore,
|
|
691
|
+
selectedOption,
|
|
692
|
+
creatable,
|
|
693
|
+
formatCreateLabel
|
|
653
694
|
}) {
|
|
654
|
-
const [open, setOpen] =
|
|
695
|
+
const [open, setOpen] = React6.useState(false);
|
|
696
|
+
const [search, setSearch] = React6.useState("");
|
|
655
697
|
const isDesktop = useIsDesktop();
|
|
656
|
-
const
|
|
698
|
+
const isServer = onSearchChange !== void 0;
|
|
699
|
+
const selected = selectedOption?.value === value ? selectedOption : options.find((option) => option.value === value) ?? (creatable && value ? { value, label: value } : void 0);
|
|
700
|
+
const handleOpenChange = (next) => {
|
|
701
|
+
setOpen(next);
|
|
702
|
+
if (!next) setSearch("");
|
|
703
|
+
};
|
|
704
|
+
const handleSelect = (next) => {
|
|
705
|
+
onChange(next);
|
|
706
|
+
handleOpenChange(false);
|
|
707
|
+
};
|
|
708
|
+
const handleSearchChange = (next) => {
|
|
709
|
+
setSearch(next);
|
|
710
|
+
onSearchChange?.(next);
|
|
711
|
+
};
|
|
712
|
+
const trimmedSearch = search.trim();
|
|
713
|
+
const showCreate = !!creatable && trimmedSearch.length > 0 && !options.some(
|
|
714
|
+
(option) => option.value.toLowerCase() === trimmedSearch.toLowerCase()
|
|
715
|
+
);
|
|
716
|
+
const { listRef, sentinelRef } = useInfiniteScrollSentinel({
|
|
717
|
+
enabled: isServer && !!hasMore,
|
|
718
|
+
loading,
|
|
719
|
+
onLoadMore
|
|
720
|
+
});
|
|
657
721
|
const trigger = /* @__PURE__ */ jsxs14(
|
|
658
722
|
"button",
|
|
659
723
|
{
|
|
@@ -674,48 +738,77 @@ function Combobox({
|
|
|
674
738
|
]
|
|
675
739
|
}
|
|
676
740
|
);
|
|
677
|
-
const command = /* @__PURE__ */ jsxs14(
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
741
|
+
const command = /* @__PURE__ */ jsxs14(
|
|
742
|
+
CommandPrimitive,
|
|
743
|
+
{
|
|
744
|
+
shouldFilter: !isServer,
|
|
745
|
+
className: "flex h-full w-full flex-col overflow-hidden",
|
|
746
|
+
children: [
|
|
747
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex items-center border-b px-3", children: [
|
|
748
|
+
/* @__PURE__ */ jsx16(Search, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
|
|
749
|
+
/* @__PURE__ */ jsx16(
|
|
750
|
+
CommandPrimitive.Input,
|
|
751
|
+
{
|
|
752
|
+
placeholder: searchPlaceholder,
|
|
753
|
+
onValueChange: isServer || creatable ? handleSearchChange : void 0,
|
|
754
|
+
className: "flex h-11 w-full bg-transparent py-2 text-base outline-none placeholder:text-muted-foreground sm:h-9 sm:text-sm"
|
|
755
|
+
}
|
|
756
|
+
)
|
|
757
|
+
] }),
|
|
758
|
+
/* @__PURE__ */ jsxs14(
|
|
759
|
+
CommandPrimitive.List,
|
|
760
|
+
{
|
|
761
|
+
ref: listRef,
|
|
762
|
+
className: "max-h-[50vh] overflow-y-auto overflow-x-hidden p-1 sm:max-h-60",
|
|
763
|
+
children: [
|
|
764
|
+
!isServer && !showCreate && /* @__PURE__ */ jsx16(CommandPrimitive.Empty, { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
|
|
765
|
+
showCreate && /* @__PURE__ */ jsxs14(
|
|
766
|
+
CommandPrimitive.Item,
|
|
767
|
+
{
|
|
768
|
+
value: trimmedSearch,
|
|
769
|
+
onSelect: () => handleSelect(trimmedSearch),
|
|
770
|
+
className: "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2.5 text-sm outline-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground sm:py-1.5",
|
|
771
|
+
children: [
|
|
772
|
+
/* @__PURE__ */ jsx16(Plus, { className: "h-4 w-4 shrink-0" }),
|
|
773
|
+
/* @__PURE__ */ jsx16("span", { className: "truncate", children: (formatCreateLabel ?? ((text) => `Usar "${text}"`))(
|
|
774
|
+
trimmedSearch
|
|
775
|
+
) })
|
|
776
|
+
]
|
|
777
|
+
}
|
|
778
|
+
),
|
|
779
|
+
options.map((option) => /* @__PURE__ */ jsxs14(
|
|
780
|
+
CommandPrimitive.Item,
|
|
781
|
+
{
|
|
782
|
+
value: isServer ? option.value : option.label,
|
|
783
|
+
disabled: option.disabled,
|
|
784
|
+
onSelect: () => handleSelect(option.value),
|
|
785
|
+
className: "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2.5 text-sm outline-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 sm:py-1.5",
|
|
786
|
+
children: [
|
|
787
|
+
/* @__PURE__ */ jsx16(
|
|
788
|
+
Check,
|
|
789
|
+
{
|
|
790
|
+
className: cn(
|
|
791
|
+
"h-4 w-4 shrink-0",
|
|
792
|
+
value === option.value ? "opacity-100" : "opacity-0"
|
|
793
|
+
)
|
|
794
|
+
}
|
|
795
|
+
),
|
|
796
|
+
/* @__PURE__ */ jsx16("span", { className: "truncate", children: option.label })
|
|
797
|
+
]
|
|
798
|
+
},
|
|
799
|
+
option.value
|
|
800
|
+
)),
|
|
801
|
+
isServer && !loading && options.length === 0 && /* @__PURE__ */ jsx16("div", { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
|
|
802
|
+
isServer && loading && /* @__PURE__ */ jsx16("div", { className: "flex items-center justify-center py-6", children: /* @__PURE__ */ jsx16(Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }) }),
|
|
803
|
+
isServer && hasMore && /* @__PURE__ */ jsx16("div", { ref: sentinelRef, "aria-hidden": true, className: "h-1" })
|
|
804
|
+
]
|
|
805
|
+
}
|
|
806
|
+
)
|
|
807
|
+
]
|
|
808
|
+
}
|
|
809
|
+
);
|
|
717
810
|
if (isDesktop) {
|
|
718
|
-
return /* @__PURE__ */ jsxs14(PopoverPrimitive.Root, { open, onOpenChange:
|
|
811
|
+
return /* @__PURE__ */ jsxs14(PopoverPrimitive.Root, { open, onOpenChange: handleOpenChange, children: [
|
|
719
812
|
/* @__PURE__ */ jsx16(PopoverPrimitive.Trigger, { asChild: true, children: trigger }),
|
|
720
813
|
/* @__PURE__ */ jsx16(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx16(
|
|
721
814
|
PopoverPrimitive.Content,
|
|
@@ -729,7 +822,7 @@ function Combobox({
|
|
|
729
822
|
) })
|
|
730
823
|
] });
|
|
731
824
|
}
|
|
732
|
-
return /* @__PURE__ */ jsxs14(DrawerPrimitive.Root, { open, onOpenChange:
|
|
825
|
+
return /* @__PURE__ */ jsxs14(DrawerPrimitive.Root, { open, onOpenChange: handleOpenChange, children: [
|
|
733
826
|
/* @__PURE__ */ jsx16(DrawerPrimitive.Trigger, { asChild: true, children: trigger }),
|
|
734
827
|
/* @__PURE__ */ jsxs14(DrawerPrimitive.Portal, { children: [
|
|
735
828
|
/* @__PURE__ */ jsx16(DrawerPrimitive.Overlay, { className: "fixed inset-0 z-50 bg-black/80" }),
|
|
@@ -745,8 +838,8 @@ function Combobox({
|
|
|
745
838
|
// src/components/multi-combobox.tsx
|
|
746
839
|
import * as PopoverPrimitive2 from "@radix-ui/react-popover";
|
|
747
840
|
import { Command as CommandPrimitive2 } from "cmdk";
|
|
748
|
-
import { Check as Check2, ChevronsUpDown as ChevronsUpDown2, Search as Search2, X as X2 } from "lucide-react";
|
|
749
|
-
import * as
|
|
841
|
+
import { Check as Check2, ChevronsUpDown as ChevronsUpDown2, Loader2 as Loader22, Search as Search2, X as X2 } from "lucide-react";
|
|
842
|
+
import * as React7 from "react";
|
|
750
843
|
import { Drawer as DrawerPrimitive2 } from "vaul";
|
|
751
844
|
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
752
845
|
function MultiCombobox({
|
|
@@ -760,11 +853,27 @@ function MultiCombobox({
|
|
|
760
853
|
id,
|
|
761
854
|
className,
|
|
762
855
|
"aria-invalid": ariaInvalid,
|
|
763
|
-
"aria-describedby": ariaDescribedby
|
|
856
|
+
"aria-describedby": ariaDescribedby,
|
|
857
|
+
onSearchChange,
|
|
858
|
+
onLoadMore,
|
|
859
|
+
loading,
|
|
860
|
+
hasMore,
|
|
861
|
+
selectedOptions
|
|
764
862
|
}) {
|
|
765
|
-
const [open, setOpen] =
|
|
863
|
+
const [open, setOpen] = React7.useState(false);
|
|
766
864
|
const isDesktop = useIsDesktop();
|
|
767
|
-
const
|
|
865
|
+
const isServer = onSearchChange !== void 0;
|
|
866
|
+
const seen = /* @__PURE__ */ new Set();
|
|
867
|
+
const selected = [...selectedOptions ?? [], ...options].filter((option) => {
|
|
868
|
+
if (!value.includes(option.value) || seen.has(option.value)) return false;
|
|
869
|
+
seen.add(option.value);
|
|
870
|
+
return true;
|
|
871
|
+
});
|
|
872
|
+
const { listRef, sentinelRef } = useInfiniteScrollSentinel({
|
|
873
|
+
enabled: isServer && !!hasMore,
|
|
874
|
+
loading,
|
|
875
|
+
onLoadMore
|
|
876
|
+
});
|
|
768
877
|
const toggleValue = (optionValue) => {
|
|
769
878
|
onChange(
|
|
770
879
|
value.includes(optionValue) ? value.filter((v) => v !== optionValue) : [...value, optionValue]
|
|
@@ -824,43 +933,61 @@ function MultiCombobox({
|
|
|
824
933
|
]
|
|
825
934
|
}
|
|
826
935
|
);
|
|
827
|
-
const command = /* @__PURE__ */ jsxs15(
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
{
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
936
|
+
const command = /* @__PURE__ */ jsxs15(
|
|
937
|
+
CommandPrimitive2,
|
|
938
|
+
{
|
|
939
|
+
shouldFilter: !isServer,
|
|
940
|
+
className: "flex h-full w-full flex-col overflow-hidden",
|
|
941
|
+
children: [
|
|
942
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center border-b px-3", children: [
|
|
943
|
+
/* @__PURE__ */ jsx17(Search2, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
|
|
944
|
+
/* @__PURE__ */ jsx17(
|
|
945
|
+
CommandPrimitive2.Input,
|
|
946
|
+
{
|
|
947
|
+
placeholder: searchPlaceholder,
|
|
948
|
+
onValueChange: isServer ? onSearchChange : void 0,
|
|
949
|
+
className: "flex h-11 w-full bg-transparent py-2 text-base outline-none placeholder:text-muted-foreground sm:h-9 sm:text-sm"
|
|
950
|
+
}
|
|
951
|
+
)
|
|
952
|
+
] }),
|
|
953
|
+
/* @__PURE__ */ jsxs15(
|
|
954
|
+
CommandPrimitive2.List,
|
|
955
|
+
{
|
|
956
|
+
ref: listRef,
|
|
957
|
+
className: "max-h-[50vh] overflow-y-auto overflow-x-hidden p-1 sm:max-h-60",
|
|
958
|
+
children: [
|
|
959
|
+
!isServer && /* @__PURE__ */ jsx17(CommandPrimitive2.Empty, { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
|
|
960
|
+
options.map((option) => /* @__PURE__ */ jsxs15(
|
|
961
|
+
CommandPrimitive2.Item,
|
|
962
|
+
{
|
|
963
|
+
value: isServer ? option.value : option.label,
|
|
964
|
+
disabled: option.disabled,
|
|
965
|
+
onSelect: () => toggleValue(option.value),
|
|
966
|
+
className: "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2.5 text-sm outline-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 sm:py-1.5",
|
|
967
|
+
children: [
|
|
968
|
+
/* @__PURE__ */ jsx17(
|
|
969
|
+
Check2,
|
|
970
|
+
{
|
|
971
|
+
className: cn(
|
|
972
|
+
"h-4 w-4 shrink-0",
|
|
973
|
+
value.includes(option.value) ? "opacity-100" : "opacity-0"
|
|
974
|
+
)
|
|
975
|
+
}
|
|
976
|
+
),
|
|
977
|
+
/* @__PURE__ */ jsx17("span", { className: "truncate", children: option.label })
|
|
978
|
+
]
|
|
979
|
+
},
|
|
980
|
+
option.value
|
|
981
|
+
)),
|
|
982
|
+
isServer && !loading && options.length === 0 && /* @__PURE__ */ jsx17("div", { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
|
|
983
|
+
isServer && loading && /* @__PURE__ */ jsx17("div", { className: "flex items-center justify-center py-6", children: /* @__PURE__ */ jsx17(Loader22, { className: "h-4 w-4 animate-spin text-muted-foreground" }) }),
|
|
984
|
+
isServer && hasMore && /* @__PURE__ */ jsx17("div", { ref: sentinelRef, "aria-hidden": true, className: "h-1" })
|
|
985
|
+
]
|
|
986
|
+
}
|
|
987
|
+
)
|
|
988
|
+
]
|
|
989
|
+
}
|
|
990
|
+
);
|
|
864
991
|
if (isDesktop) {
|
|
865
992
|
return /* @__PURE__ */ jsxs15(PopoverPrimitive2.Root, { open, onOpenChange: setOpen, children: [
|
|
866
993
|
/* @__PURE__ */ jsx17(PopoverPrimitive2.Trigger, { asChild: true, disabled, children: trigger }),
|
|
@@ -892,7 +1019,7 @@ function MultiCombobox({
|
|
|
892
1019
|
// src/components/color-picker.tsx
|
|
893
1020
|
import * as PopoverPrimitive3 from "@radix-ui/react-popover";
|
|
894
1021
|
import { ChevronsUpDown as ChevronsUpDown3 } from "lucide-react";
|
|
895
|
-
import * as
|
|
1022
|
+
import * as React8 from "react";
|
|
896
1023
|
import { HexColorInput, HexColorPicker } from "react-colorful";
|
|
897
1024
|
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
898
1025
|
function ColorPicker({
|
|
@@ -905,7 +1032,7 @@ function ColorPicker({
|
|
|
905
1032
|
"aria-invalid": ariaInvalid,
|
|
906
1033
|
"aria-describedby": ariaDescribedby
|
|
907
1034
|
}) {
|
|
908
|
-
const [open, setOpen] =
|
|
1035
|
+
const [open, setOpen] = React8.useState(false);
|
|
909
1036
|
const color = value || "";
|
|
910
1037
|
return /* @__PURE__ */ jsxs16(PopoverPrimitive3.Root, { open, onOpenChange: setOpen, modal: true, children: [
|
|
911
1038
|
/* @__PURE__ */ jsx18(PopoverPrimitive3.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs16(
|
|
@@ -1041,7 +1168,7 @@ function DataTableWrapper({
|
|
|
1041
1168
|
}
|
|
1042
1169
|
|
|
1043
1170
|
// src/components/mobile-card-list.tsx
|
|
1044
|
-
import { useRef } from "react";
|
|
1171
|
+
import { useRef as useRef2 } from "react";
|
|
1045
1172
|
import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1046
1173
|
var SCROLL_THRESHOLD = 8;
|
|
1047
1174
|
function MobileCardList({
|
|
@@ -1052,8 +1179,8 @@ function MobileCardList({
|
|
|
1052
1179
|
loadingCount = 5,
|
|
1053
1180
|
className
|
|
1054
1181
|
}) {
|
|
1055
|
-
const start =
|
|
1056
|
-
const scrolled =
|
|
1182
|
+
const start = useRef2(null);
|
|
1183
|
+
const scrolled = useRef2(false);
|
|
1057
1184
|
const onTouchStart = (e) => {
|
|
1058
1185
|
const t = e.touches[0];
|
|
1059
1186
|
start.current = { x: t.clientX, y: t.clientY };
|