@dmsi/wedgekit-react 0.0.551 → 0.0.552
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/package.json +2 -3
- package/src/brand.css +0 -125
- package/src/classNames.ts +0 -174
- package/src/components/AccessChangerTabItem.tsx +0 -71
- package/src/components/Accordion.tsx +0 -108
- package/src/components/Alert.tsx +0 -81
- package/src/components/Breadcrumbs.tsx +0 -142
- package/src/components/Button.tsx +0 -216
- package/src/components/CalendarRange.tsx +0 -628
- package/src/components/Caption.tsx +0 -144
- package/src/components/Card.tsx +0 -88
- package/src/components/Checkbox.tsx +0 -206
- package/src/components/CompactImagesPreview.tsx +0 -135
- package/src/components/ContentTab.tsx +0 -84
- package/src/components/ContentTabs.tsx +0 -136
- package/src/components/DMSiLogo.tsx +0 -33
- package/src/components/DataGrid/ColumnSelectorHeaderCell/ColumnSelectorMenuOption.tsx +0 -35
- package/src/components/DataGrid/ColumnSelectorHeaderCell/index.tsx +0 -74
- package/src/components/DataGrid/PinnedColumns.tsx +0 -183
- package/src/components/DataGrid/TableBody/LoadingCell.tsx +0 -44
- package/src/components/DataGrid/TableBody/TableBodyRow.tsx +0 -157
- package/src/components/DataGrid/TableBody/index.tsx +0 -185
- package/src/components/DataGrid/index.tsx +0 -756
- package/src/components/DataGrid/types.ts +0 -98
- package/src/components/DataGrid/utils.tsx +0 -15
- package/src/components/DataGridCell.tsx +0 -526
- package/src/components/DataTable.tsx +0 -881
- package/src/components/DateInput.tsx +0 -306
- package/src/components/DateRangeInput.tsx +0 -758
- package/src/components/DebugJson.tsx +0 -28
- package/src/components/Display.tsx +0 -66
- package/src/components/EditingContext.tsx +0 -43
- package/src/components/EmptyCartIcon.tsx +0 -18
- package/src/components/FilterGroup.tsx +0 -264
- package/src/components/FullViewportBox.tsx +0 -19
- package/src/components/Grid.tsx +0 -97
- package/src/components/Heading.tsx +0 -72
- package/src/components/HorizontalDivider.tsx +0 -22
- package/src/components/Icon.tsx +0 -39
- package/src/components/ImagePlaceholder.tsx +0 -22
- package/src/components/Input.tsx +0 -609
- package/src/components/InputGroup.tsx +0 -59
- package/src/components/Label.tsx +0 -46
- package/src/components/Link.tsx +0 -117
- package/src/components/List.tsx +0 -18
- package/src/components/ListGroup.tsx +0 -82
- package/src/components/LiveChatComponent.tsx +0 -56
- package/src/components/LoadingScrim.tsx +0 -33
- package/src/components/LogoAgilityTopBar.tsx +0 -54
- package/src/components/LogoDMSiTopBar.tsx +0 -33
- package/src/components/LogoMillworkTopBar.tsx +0 -119
- package/src/components/MainBar.tsx +0 -91
- package/src/components/MaxViewportBox.tsx +0 -19
- package/src/components/Menu.tsx +0 -316
- package/src/components/MenuOption.tsx +0 -330
- package/src/components/MobileDataGrid/ColumnList.tsx +0 -66
- package/src/components/MobileDataGrid/ColumnSelector/index.tsx +0 -97
- package/src/components/MobileDataGrid/GridContextProvider/GridContext.tsx +0 -25
- package/src/components/MobileDataGrid/GridContextProvider/index.tsx +0 -132
- package/src/components/MobileDataGrid/GridContextProvider/useGridContext.ts +0 -10
- package/src/components/MobileDataGrid/MobileDataGridCard/MobileDataGridColumn.tsx +0 -27
- package/src/components/MobileDataGrid/MobileDataGridCard/index.tsx +0 -138
- package/src/components/MobileDataGrid/MobileDataGridHeader.tsx +0 -81
- package/src/components/MobileDataGrid/RowDetailModalProvider/ModalContent.tsx +0 -42
- package/src/components/MobileDataGrid/RowDetailModalProvider/index.tsx +0 -68
- package/src/components/MobileDataGrid/dataGridReducer.ts +0 -55
- package/src/components/MobileDataGrid/index.tsx +0 -92
- package/src/components/MobileDataGrid/types.ts +0 -4
- package/src/components/Modal.tsx +0 -312
- package/src/components/ModalButtons.tsx +0 -62
- package/src/components/ModalContent.tsx +0 -31
- package/src/components/ModalHeader.tsx +0 -78
- package/src/components/ModalScrim.tsx +0 -42
- package/src/components/NavigationTab.tsx +0 -95
- package/src/components/NavigationTabs.tsx +0 -70
- package/src/components/NestedMenu.tsx +0 -131
- package/src/components/Notification.tsx +0 -128
- package/src/components/OptionPill.tsx +0 -139
- package/src/components/OrderCheckIcon.tsx +0 -19
- package/src/components/PDFViewer/DownloadIcon.tsx +0 -25
- package/src/components/PDFViewer/PDFElement.tsx +0 -90
- package/src/components/PDFViewer/PDFNavigation.tsx +0 -68
- package/src/components/PDFViewer/PDFPage.tsx +0 -34
- package/src/components/PDFViewer/index.tsx +0 -128
- package/src/components/Pagination.tsx +0 -182
- package/src/components/Paragraph.tsx +0 -55
- package/src/components/Password.tsx +0 -62
- package/src/components/ProductImagePreview/CarouselPagination.tsx +0 -54
- package/src/components/ProductImagePreview/MobileImageCarousel.tsx +0 -226
- package/src/components/ProductImagePreview/ProductPrimaryImage.tsx +0 -219
- package/src/components/ProductImagePreview/Thumbnail.tsx +0 -55
- package/src/components/ProductImagePreview/ZoomWindow.tsx +0 -136
- package/src/components/ProductImagePreview/index.tsx +0 -182
- package/src/components/ProductImagePreview/useProductImagePreview.ts +0 -211
- package/src/components/ProjectBar.tsx +0 -82
- package/src/components/Radio.tsx +0 -146
- package/src/components/Search.tsx +0 -152
- package/src/components/SearchResultImage/index.tsx +0 -39
- package/src/components/Select.tsx +0 -114
- package/src/components/SideMenu.tsx +0 -30
- package/src/components/SideMenuGroup.tsx +0 -95
- package/src/components/SideMenuItem.tsx +0 -109
- package/src/components/SimpleTable.tsx +0 -77
- package/src/components/SkeletonParagraph.tsx +0 -31
- package/src/components/Spinner.tsx +0 -32
- package/src/components/Stack.tsx +0 -347
- package/src/components/StatusPill.tsx +0 -59
- package/src/components/Stepper.tsx +0 -128
- package/src/components/Subheader.tsx +0 -50
- package/src/components/Surface.tsx +0 -37
- package/src/components/Swatch.tsx +0 -1341
- package/src/components/Textarea.tsx +0 -102
- package/src/components/Theme.tsx +0 -27
- package/src/components/Time.tsx +0 -460
- package/src/components/Toast.tsx +0 -268
- package/src/components/Tooltip.tsx +0 -159
- package/src/components/TopBar.tsx +0 -139
- package/src/components/Upload.tsx +0 -107
- package/src/components/WorldpayIframe.tsx +0 -7
- package/src/components/index.ts +0 -34
- package/src/components/useMenuSystem.tsx +0 -456
- package/src/components/useMounted.tsx +0 -14
- package/src/darkmode.css +0 -278
- package/src/fonts.css +0 -23
- package/src/hooks/index.ts +0 -4
- package/src/hooks/useInfiniteScroll.tsx +0 -40
- package/src/hooks/useKeydown.ts +0 -42
- package/src/hooks/useMatchesMedia.ts +0 -18
- package/src/hooks/useTableLayout.ts +0 -106
- package/src/index.css +0 -800
- package/src/index.tsx +0 -5
- package/src/types.ts +0 -150
- package/src/utils/date.ts +0 -236
- package/src/utils/formatting.tsx +0 -81
- package/src/utils/index.ts +0 -4
- package/src/utils/mergeObjectArrays.ts +0 -18
- package/src/utils.ts +0 -24
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
import { Thumbnail } from "./Thumbnail";
|
|
2
|
-
import { Stack } from "../Stack";
|
|
3
|
-
import { Grid } from "../Grid";
|
|
4
|
-
import { ProductPrimaryImage } from "./ProductPrimaryImage";
|
|
5
|
-
import { ZoomWindow } from "./ZoomWindow";
|
|
6
|
-
import { CarouselPagination } from "./CarouselPagination";
|
|
7
|
-
import { MobileImageCarousel } from "./MobileImageCarousel";
|
|
8
|
-
import { useMatchesMobile } from "../../hooks";
|
|
9
|
-
import { useProductImagePreview } from "./useProductImagePreview";
|
|
10
|
-
|
|
11
|
-
export type ProductPreviewImage = {
|
|
12
|
-
src: string;
|
|
13
|
-
alt?: string;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export type ProductImagePreviewProps = {
|
|
17
|
-
width?: number;
|
|
18
|
-
height?: number;
|
|
19
|
-
images: ProductPreviewImage[];
|
|
20
|
-
currentIndex: number;
|
|
21
|
-
zoomEnabled?: boolean;
|
|
22
|
-
zoomLensSize?: number;
|
|
23
|
-
zoomFactor?: number;
|
|
24
|
-
zoomWindowScaleFactor?: number;
|
|
25
|
-
zoomWindowOffset?: number;
|
|
26
|
-
scrollToZoomEnabled?: boolean;
|
|
27
|
-
thumbsPerRow?: 8 | 5 | 2 | 4 | 1 | 3 | 6 | 7 | 9 | 10 | 11 | 12;
|
|
28
|
-
isMobile?: boolean; // Must be used for functionality only
|
|
29
|
-
onChangeIndex: (next: number) => void;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const PLACEHOLDER_IMAGES = [
|
|
33
|
-
{ src: "", alt: "placeholder" },
|
|
34
|
-
{ src: "", alt: "placeholder" },
|
|
35
|
-
];
|
|
36
|
-
/** Product image gallery with primary image display, thumbnail navigation, and optional zoom functionality */
|
|
37
|
-
export function ProductImagePreview(props: ProductImagePreviewProps) {
|
|
38
|
-
const {
|
|
39
|
-
width = 483,
|
|
40
|
-
height = 483,
|
|
41
|
-
thumbsPerRow = 4,
|
|
42
|
-
zoomEnabled = false,
|
|
43
|
-
scrollToZoomEnabled = false,
|
|
44
|
-
images,
|
|
45
|
-
currentIndex,
|
|
46
|
-
onChangeIndex,
|
|
47
|
-
zoomLensSize,
|
|
48
|
-
zoomFactor = 2,
|
|
49
|
-
zoomWindowScaleFactor = 2.5,
|
|
50
|
-
zoomWindowOffset = 10,
|
|
51
|
-
} = props;
|
|
52
|
-
|
|
53
|
-
const isMobile = useMatchesMobile();
|
|
54
|
-
|
|
55
|
-
const {
|
|
56
|
-
zoomPoint,
|
|
57
|
-
zoomActive,
|
|
58
|
-
currentZoomFactor,
|
|
59
|
-
primaryImagePosition,
|
|
60
|
-
safeIndex,
|
|
61
|
-
active,
|
|
62
|
-
primaryImageRef,
|
|
63
|
-
handleSelect,
|
|
64
|
-
handleZoomPositionChange,
|
|
65
|
-
handleScrollZoom,
|
|
66
|
-
} = useProductImagePreview({
|
|
67
|
-
images,
|
|
68
|
-
currentIndex,
|
|
69
|
-
zoomEnabled,
|
|
70
|
-
zoomFactor,
|
|
71
|
-
scrollToZoomEnabled,
|
|
72
|
-
onChangeIndex,
|
|
73
|
-
isMobile,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
if (typeof isMobile === "undefined") return null;
|
|
77
|
-
|
|
78
|
-
// Disable zoom on mobile
|
|
79
|
-
const effectiveZoomEnabled = zoomEnabled && !isMobile;
|
|
80
|
-
|
|
81
|
-
return (
|
|
82
|
-
<Stack sizing="layout" style={{ width, position: "relative" }}>
|
|
83
|
-
{/* Desktop layout - hidden on mobile */}
|
|
84
|
-
<div className="hidden md:block">
|
|
85
|
-
<div className="flex gap-4 items-start">
|
|
86
|
-
<div ref={primaryImageRef}>
|
|
87
|
-
<ProductPrimaryImage
|
|
88
|
-
image={active}
|
|
89
|
-
width={width}
|
|
90
|
-
height={height}
|
|
91
|
-
zoomEnabled={effectiveZoomEnabled}
|
|
92
|
-
zoomLensSize={zoomLensSize}
|
|
93
|
-
scrollToZoomEnabled={scrollToZoomEnabled && !isMobile}
|
|
94
|
-
onZoomPositionChange={handleZoomPositionChange}
|
|
95
|
-
onScrollZoom={handleScrollZoom}
|
|
96
|
-
isPlaceholder={images.length === 0}
|
|
97
|
-
/>
|
|
98
|
-
</div>
|
|
99
|
-
{effectiveZoomEnabled && (
|
|
100
|
-
<ZoomWindow
|
|
101
|
-
image={active}
|
|
102
|
-
width={width}
|
|
103
|
-
height={height}
|
|
104
|
-
pointer={zoomPoint}
|
|
105
|
-
active={zoomActive}
|
|
106
|
-
zoomFactor={currentZoomFactor}
|
|
107
|
-
scaleFactor={zoomWindowScaleFactor}
|
|
108
|
-
primaryImagePosition={primaryImagePosition}
|
|
109
|
-
offset={zoomWindowOffset}
|
|
110
|
-
/>
|
|
111
|
-
)}
|
|
112
|
-
</div>
|
|
113
|
-
</div>
|
|
114
|
-
|
|
115
|
-
{/* Mobile carousel - only visible on mobile */}
|
|
116
|
-
<MobileImageCarousel
|
|
117
|
-
images={images}
|
|
118
|
-
currentIndex={safeIndex}
|
|
119
|
-
width={width}
|
|
120
|
-
height={height}
|
|
121
|
-
onChangeIndex={handleSelect}
|
|
122
|
-
/>
|
|
123
|
-
|
|
124
|
-
{/* Desktop thumbnail grid - hidden on mobile */}
|
|
125
|
-
<div className="hidden md:block">
|
|
126
|
-
{images.length <= 3 ? (
|
|
127
|
-
<div
|
|
128
|
-
className="flex justify-center gap-4"
|
|
129
|
-
style={{ width: "100%", maxWidth: width }}
|
|
130
|
-
aria-label="Product image thumbnails"
|
|
131
|
-
>
|
|
132
|
-
{(images.length === 0 ? PLACEHOLDER_IMAGES : images).map(
|
|
133
|
-
(img, i) => (
|
|
134
|
-
<div key={img.src + i} style={{ maxWidth: "115px" }}>
|
|
135
|
-
<Thumbnail
|
|
136
|
-
src={img.src}
|
|
137
|
-
alt={img.alt || `Thumbnail ${i + 1}`}
|
|
138
|
-
isActive={i === safeIndex}
|
|
139
|
-
onClick={() => handleSelect(i)}
|
|
140
|
-
isPlaceholder={images.length === 0}
|
|
141
|
-
/>
|
|
142
|
-
</div>
|
|
143
|
-
),
|
|
144
|
-
)}
|
|
145
|
-
</div>
|
|
146
|
-
) : (
|
|
147
|
-
<Grid
|
|
148
|
-
sizing="layout-group"
|
|
149
|
-
aria-label="Product image thumbnails"
|
|
150
|
-
style={{
|
|
151
|
-
width: "100%",
|
|
152
|
-
maxWidth: width,
|
|
153
|
-
}}
|
|
154
|
-
columns={
|
|
155
|
-
thumbsPerRow > 12 ? 12 : thumbsPerRow < 1 ? 1 : thumbsPerRow
|
|
156
|
-
}
|
|
157
|
-
>
|
|
158
|
-
{(images.length === 0 ? PLACEHOLDER_IMAGES : images).map(
|
|
159
|
-
(img, i) => (
|
|
160
|
-
<Thumbnail
|
|
161
|
-
key={img.src + i}
|
|
162
|
-
src={img.src}
|
|
163
|
-
alt={img.alt || `Thumbnail ${i + 1}`}
|
|
164
|
-
isActive={i === safeIndex}
|
|
165
|
-
onClick={() => handleSelect(i)}
|
|
166
|
-
isPlaceholder={images.length === 0}
|
|
167
|
-
/>
|
|
168
|
-
),
|
|
169
|
-
)}
|
|
170
|
-
</Grid>
|
|
171
|
-
)}
|
|
172
|
-
</div>
|
|
173
|
-
|
|
174
|
-
{/* Mobile carousel pagination - only visible on mobile */}
|
|
175
|
-
<CarouselPagination
|
|
176
|
-
images={images}
|
|
177
|
-
currentIndex={safeIndex}
|
|
178
|
-
onSelect={handleSelect}
|
|
179
|
-
/>
|
|
180
|
-
</Stack>
|
|
181
|
-
);
|
|
182
|
-
}
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef, useState, useMemo } from "react";
|
|
2
|
-
import type { ProductPreviewImage } from ".";
|
|
3
|
-
|
|
4
|
-
export type UseProductImagePreviewProps = {
|
|
5
|
-
images: ProductPreviewImage[];
|
|
6
|
-
currentIndex: number;
|
|
7
|
-
zoomEnabled?: boolean;
|
|
8
|
-
zoomFactor?: number;
|
|
9
|
-
scrollToZoomEnabled?: boolean;
|
|
10
|
-
onChangeIndex: (next: number) => void;
|
|
11
|
-
isMobile?: boolean;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export type UseProductImagePreviewReturn = {
|
|
15
|
-
// State
|
|
16
|
-
zoomPoint: {
|
|
17
|
-
x: number;
|
|
18
|
-
y: number;
|
|
19
|
-
w: number;
|
|
20
|
-
h: number;
|
|
21
|
-
lensSize: number;
|
|
22
|
-
} | null;
|
|
23
|
-
zoomActive: boolean;
|
|
24
|
-
currentZoomFactor: number;
|
|
25
|
-
primaryImagePosition: DOMRect | null;
|
|
26
|
-
hasImages: boolean;
|
|
27
|
-
safeIndex: number;
|
|
28
|
-
active: ProductPreviewImage | undefined;
|
|
29
|
-
|
|
30
|
-
// Refs
|
|
31
|
-
primaryImageRef: React.RefObject<HTMLDivElement | null>;
|
|
32
|
-
|
|
33
|
-
// Handlers
|
|
34
|
-
handleSelect: (idx: number) => void;
|
|
35
|
-
handleZoomPositionChange: (
|
|
36
|
-
p: {
|
|
37
|
-
x: number;
|
|
38
|
-
y: number;
|
|
39
|
-
w: number;
|
|
40
|
-
h: number;
|
|
41
|
-
lensSize: number;
|
|
42
|
-
} | null,
|
|
43
|
-
active: boolean,
|
|
44
|
-
) => void;
|
|
45
|
-
handleScrollZoom: (delta: number) => void;
|
|
46
|
-
handleNext: () => void;
|
|
47
|
-
handlePrevious: () => void;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Custom hook for managing product image preview logic including zoom, navigation, and mobile behavior
|
|
52
|
-
*/
|
|
53
|
-
export function useProductImagePreview(
|
|
54
|
-
props: UseProductImagePreviewProps,
|
|
55
|
-
): UseProductImagePreviewReturn {
|
|
56
|
-
const {
|
|
57
|
-
images,
|
|
58
|
-
currentIndex,
|
|
59
|
-
zoomEnabled = false,
|
|
60
|
-
zoomFactor = 2,
|
|
61
|
-
scrollToZoomEnabled = false,
|
|
62
|
-
onChangeIndex,
|
|
63
|
-
isMobile = false,
|
|
64
|
-
} = props;
|
|
65
|
-
|
|
66
|
-
// Derived state
|
|
67
|
-
const hasImages = !!images?.length;
|
|
68
|
-
const safeIndex =
|
|
69
|
-
hasImages && currentIndex >= 0 && currentIndex < images.length
|
|
70
|
-
? currentIndex
|
|
71
|
-
: 0;
|
|
72
|
-
|
|
73
|
-
// Memoize active image to prevent unnecessary re-renders
|
|
74
|
-
const active = useMemo(() => {
|
|
75
|
-
return hasImages ? images[safeIndex] : undefined;
|
|
76
|
-
}, [hasImages, images, safeIndex]);
|
|
77
|
-
|
|
78
|
-
// Zoom state
|
|
79
|
-
const [zoomPoint, setZoomPoint] = useState<{
|
|
80
|
-
x: number;
|
|
81
|
-
y: number;
|
|
82
|
-
w: number;
|
|
83
|
-
h: number;
|
|
84
|
-
lensSize: number;
|
|
85
|
-
} | null>(null);
|
|
86
|
-
const [zoomActive, setZoomActive] = useState(false);
|
|
87
|
-
const [currentZoomFactor, setCurrentZoomFactor] = useState(zoomFactor);
|
|
88
|
-
const [primaryImagePosition, setPrimaryImagePosition] =
|
|
89
|
-
useState<DOMRect | null>(null);
|
|
90
|
-
|
|
91
|
-
// Refs
|
|
92
|
-
const primaryImageRef = useRef<HTMLDivElement>(null);
|
|
93
|
-
const cleanupRef = useRef<(() => void) | null>(null);
|
|
94
|
-
|
|
95
|
-
// Disable zoom functionality on mobile
|
|
96
|
-
const effectiveZoomEnabled = zoomEnabled && !isMobile;
|
|
97
|
-
const effectiveScrollToZoomEnabled = scrollToZoomEnabled && !isMobile;
|
|
98
|
-
|
|
99
|
-
// Track primary image position for zoom window
|
|
100
|
-
useEffect(() => {
|
|
101
|
-
if (!effectiveZoomEnabled) return;
|
|
102
|
-
|
|
103
|
-
const setupTracking = () => {
|
|
104
|
-
const element = primaryImageRef.current;
|
|
105
|
-
if (!element) return;
|
|
106
|
-
|
|
107
|
-
const updatePosition = () => {
|
|
108
|
-
if (element) {
|
|
109
|
-
setPrimaryImagePosition(element.getBoundingClientRect());
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
updatePosition();
|
|
114
|
-
|
|
115
|
-
const resizeObserver = new ResizeObserver(updatePosition);
|
|
116
|
-
resizeObserver.observe(element);
|
|
117
|
-
|
|
118
|
-
window.addEventListener("scroll", updatePosition);
|
|
119
|
-
window.addEventListener("resize", updatePosition);
|
|
120
|
-
|
|
121
|
-
cleanupRef.current = () => {
|
|
122
|
-
resizeObserver.disconnect();
|
|
123
|
-
window.removeEventListener("scroll", updatePosition);
|
|
124
|
-
window.removeEventListener("resize", updatePosition);
|
|
125
|
-
};
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
if (primaryImageRef.current) {
|
|
129
|
-
setupTracking();
|
|
130
|
-
} else {
|
|
131
|
-
const frameId = requestAnimationFrame(setupTracking);
|
|
132
|
-
return () => cancelAnimationFrame(frameId);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return () => {
|
|
136
|
-
if (cleanupRef.current) {
|
|
137
|
-
cleanupRef.current();
|
|
138
|
-
cleanupRef.current = null;
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
}, [effectiveZoomEnabled]);
|
|
142
|
-
|
|
143
|
-
// Navigation handlers
|
|
144
|
-
const handleSelect = useCallback(
|
|
145
|
-
(idx: number) => {
|
|
146
|
-
if (idx === safeIndex) return;
|
|
147
|
-
onChangeIndex(idx);
|
|
148
|
-
},
|
|
149
|
-
[safeIndex, onChangeIndex],
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
const handleNext = useCallback(() => {
|
|
153
|
-
if (!hasImages) return;
|
|
154
|
-
const nextIndex = (safeIndex + 1) % images.length;
|
|
155
|
-
onChangeIndex(nextIndex);
|
|
156
|
-
}, [hasImages, safeIndex, images.length, onChangeIndex]);
|
|
157
|
-
|
|
158
|
-
const handlePrevious = useCallback(() => {
|
|
159
|
-
if (!hasImages) return;
|
|
160
|
-
const previousIndex = safeIndex === 0 ? images.length - 1 : safeIndex - 1;
|
|
161
|
-
onChangeIndex(previousIndex);
|
|
162
|
-
}, [hasImages, safeIndex, images.length, onChangeIndex]);
|
|
163
|
-
|
|
164
|
-
// Zoom handlers
|
|
165
|
-
const handleZoomPositionChange = useCallback(
|
|
166
|
-
(p: typeof zoomPoint, active: boolean) => {
|
|
167
|
-
// Only allow zoom on non-mobile devices
|
|
168
|
-
if (isMobile) return;
|
|
169
|
-
setZoomPoint(p);
|
|
170
|
-
setZoomActive(active);
|
|
171
|
-
},
|
|
172
|
-
[isMobile],
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
const handleScrollZoom = useCallback(
|
|
176
|
-
(delta: number) => {
|
|
177
|
-
if (!effectiveScrollToZoomEnabled) return;
|
|
178
|
-
|
|
179
|
-
// Calculate new zoom factor with bounds (1x to 5x)
|
|
180
|
-
const newZoomFactor = Math.max(1, Math.min(5, currentZoomFactor + delta));
|
|
181
|
-
setCurrentZoomFactor(newZoomFactor);
|
|
182
|
-
},
|
|
183
|
-
[effectiveScrollToZoomEnabled, currentZoomFactor],
|
|
184
|
-
);
|
|
185
|
-
|
|
186
|
-
// Reset zoom factor when base zoom factor changes
|
|
187
|
-
useEffect(() => {
|
|
188
|
-
setCurrentZoomFactor(zoomFactor);
|
|
189
|
-
}, [zoomFactor]);
|
|
190
|
-
|
|
191
|
-
return {
|
|
192
|
-
// State
|
|
193
|
-
zoomPoint,
|
|
194
|
-
zoomActive,
|
|
195
|
-
currentZoomFactor,
|
|
196
|
-
primaryImagePosition,
|
|
197
|
-
hasImages,
|
|
198
|
-
safeIndex,
|
|
199
|
-
active,
|
|
200
|
-
|
|
201
|
-
// Refs
|
|
202
|
-
primaryImageRef,
|
|
203
|
-
|
|
204
|
-
// Handlers
|
|
205
|
-
handleSelect,
|
|
206
|
-
handleZoomPositionChange,
|
|
207
|
-
handleScrollZoom,
|
|
208
|
-
handleNext,
|
|
209
|
-
handlePrevious,
|
|
210
|
-
};
|
|
211
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import clsx from "clsx";
|
|
2
|
-
import { ComponentProps, ReactNode } from "react";
|
|
3
|
-
import {
|
|
4
|
-
containerPaddingX,
|
|
5
|
-
layoutGap,
|
|
6
|
-
layoutGroupGap,
|
|
7
|
-
paddingYUsingLayoutGroupGap,
|
|
8
|
-
} from "../classNames";
|
|
9
|
-
import { useMatchesMobile } from "../hooks";
|
|
10
|
-
|
|
11
|
-
type ProjectBarProps = {
|
|
12
|
-
left: ReactNode;
|
|
13
|
-
right: ReactNode;
|
|
14
|
-
mobileLeft: ReactNode;
|
|
15
|
-
mobileRight: ReactNode;
|
|
16
|
-
id?: string;
|
|
17
|
-
testid?: string;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export const ProjectBar = ({
|
|
21
|
-
left,
|
|
22
|
-
right,
|
|
23
|
-
mobileLeft,
|
|
24
|
-
mobileRight,
|
|
25
|
-
id,
|
|
26
|
-
testid,
|
|
27
|
-
}: ComponentProps<"div"> & ProjectBarProps) => {
|
|
28
|
-
const isMobile = useMatchesMobile();
|
|
29
|
-
|
|
30
|
-
const tokenOverrides = isMobile
|
|
31
|
-
? {
|
|
32
|
-
"--color-background-primary-normal": "var(--color-brand-400)",
|
|
33
|
-
"--color-background-action-primary-normal": "var(--color-neutral-000)",
|
|
34
|
-
"--color-background-action-primary-hover": "var(--color-critical-100)",
|
|
35
|
-
"--color-background-action-primary-active": "var(--color-neutral-200)",
|
|
36
|
-
"--color-background-action-secondary-normal": "var(--color-brand-400)",
|
|
37
|
-
"--color-background-action-secondary-hover":
|
|
38
|
-
"var(--color-critical-100)",
|
|
39
|
-
|
|
40
|
-
"--color-text-on-action-primary-normal": "var(--color-brand-400)",
|
|
41
|
-
"--color-text-primary-normal": "var(--color-neutral-000)",
|
|
42
|
-
"--color-text-action-primary-normal": "var(--color-neutral-000)",
|
|
43
|
-
"--color-text-action-primary-hover": "var(--color-critical-500)",
|
|
44
|
-
"--color-text-action-primary-active": "var(--color-critical-300)",
|
|
45
|
-
|
|
46
|
-
"--color-border-action-normal": "var(--color-neutral-000)",
|
|
47
|
-
"--color-border-action-hover": "var(--color-critical-500)",
|
|
48
|
-
"--color-border-action-active": "var(--color-critical-300)",
|
|
49
|
-
}
|
|
50
|
-
: {};
|
|
51
|
-
|
|
52
|
-
return (
|
|
53
|
-
<div
|
|
54
|
-
id={id}
|
|
55
|
-
data-testid={testid}
|
|
56
|
-
style={{ ...tokenOverrides } as React.CSSProperties}
|
|
57
|
-
className={clsx(
|
|
58
|
-
"flex items-center justify-between",
|
|
59
|
-
"bg-background-primary-normal",
|
|
60
|
-
paddingYUsingLayoutGroupGap,
|
|
61
|
-
containerPaddingX,
|
|
62
|
-
layoutGap,
|
|
63
|
-
)}
|
|
64
|
-
>
|
|
65
|
-
<div className={clsx("hidden desktop:block flex-1 leading-[1]")}>
|
|
66
|
-
{left}
|
|
67
|
-
</div>
|
|
68
|
-
|
|
69
|
-
<div className={clsx("hidden desktop:flex items-center", layoutGroupGap)}>
|
|
70
|
-
{right}
|
|
71
|
-
</div>
|
|
72
|
-
|
|
73
|
-
<div className={clsx("flex flex-col desktop:hidden")}>{mobileLeft}</div>
|
|
74
|
-
|
|
75
|
-
<div className={clsx("flex items-center desktop:hidden", layoutGroupGap)}>
|
|
76
|
-
{mobileRight}
|
|
77
|
-
</div>
|
|
78
|
-
</div>
|
|
79
|
-
);
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
ProjectBar.displayName = "ProjectBar";
|
package/src/components/Radio.tsx
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import clsx from "clsx";
|
|
4
|
-
import { ComponentProps } from "react";
|
|
5
|
-
import { baseTransition, componentGap } from "../classNames";
|
|
6
|
-
import { Paragraph } from "./Paragraph";
|
|
7
|
-
import { TextColorTokens } from "../types";
|
|
8
|
-
|
|
9
|
-
interface RadioProps
|
|
10
|
-
extends Omit<
|
|
11
|
-
ComponentProps<"input">,
|
|
12
|
-
"type" | "children" | "dangerouslySetInnerHTML"
|
|
13
|
-
> {
|
|
14
|
-
label?: string;
|
|
15
|
-
error?: boolean;
|
|
16
|
-
readOnly?: boolean;
|
|
17
|
-
testid?: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const Radio = ({
|
|
21
|
-
className,
|
|
22
|
-
label,
|
|
23
|
-
error,
|
|
24
|
-
disabled,
|
|
25
|
-
checked,
|
|
26
|
-
readOnly,
|
|
27
|
-
id,
|
|
28
|
-
testid,
|
|
29
|
-
...props
|
|
30
|
-
}: RadioProps) => {
|
|
31
|
-
const radioId = id;
|
|
32
|
-
|
|
33
|
-
const paragraphColor: TextColorTokens = disabled
|
|
34
|
-
? "text-primary-disabled"
|
|
35
|
-
: error
|
|
36
|
-
? "text-primary-error"
|
|
37
|
-
: "text-primary-normal";
|
|
38
|
-
|
|
39
|
-
const defaultClassName = clsx(
|
|
40
|
-
!error &&
|
|
41
|
-
!disabled &&
|
|
42
|
-
"border-border-primary-normal peer-hover:border-border-action-hover peer-hover:bg-background-action-secondary-hover peer-focus:border-border-action-hover peer-focus:bg-background-action-secondary-hover peer-active:border-border-action-active peer-active:bg-background-action-secondary-active peer-checked:border-0 peer-checked:bg-background-action-secondary-hover",
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
const errorClassName = clsx(
|
|
46
|
-
error &&
|
|
47
|
-
!disabled &&
|
|
48
|
-
"border-border-action-critical-normal peer-hover:border-border-action-critical-hover peer-hover:bg-background-action-critical-secondary-hover peer-focus:border-border-action-critical-hover peer-focus:bg-background-action-critical-secondary-hover peer-active:border-border-action-critical-active peer-active:bg-background-action-secondary-active peer-checked:bg-background-action-critical-secondary-hover peer-checked:border-0 ",
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
const disabledClassName = clsx(
|
|
52
|
-
disabled &&
|
|
53
|
-
"peer-disabled:bg-background-action-secondary-disabled peer-disabled:border-border-primary-normal peer-checked:border-0",
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
const readonlyClassName = clsx(
|
|
57
|
-
readOnly &&
|
|
58
|
-
"peer-read-only:bg-background-action-secondary-disabled peer-read-only:border-border-primary-normal peer-checked:border-0",
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<label
|
|
63
|
-
htmlFor={radioId}
|
|
64
|
-
data-testid={testid}
|
|
65
|
-
className={clsx(
|
|
66
|
-
"flex items-center",
|
|
67
|
-
componentGap,
|
|
68
|
-
disabled ? "cursor-default" : "cursor-pointer",
|
|
69
|
-
className,
|
|
70
|
-
)}
|
|
71
|
-
>
|
|
72
|
-
<div className="relative">
|
|
73
|
-
<input
|
|
74
|
-
id={radioId}
|
|
75
|
-
data-testid={testid ? `${testid}-input` : undefined}
|
|
76
|
-
type="radio"
|
|
77
|
-
className="sr-only peer"
|
|
78
|
-
disabled={disabled}
|
|
79
|
-
checked={checked}
|
|
80
|
-
readOnly={readOnly}
|
|
81
|
-
{...props}
|
|
82
|
-
/>
|
|
83
|
-
<div
|
|
84
|
-
className={clsx(
|
|
85
|
-
"size-6 rounded-full border flex items-center justify-center",
|
|
86
|
-
baseTransition,
|
|
87
|
-
defaultClassName,
|
|
88
|
-
errorClassName,
|
|
89
|
-
disabledClassName,
|
|
90
|
-
readonlyClassName,
|
|
91
|
-
)}
|
|
92
|
-
>
|
|
93
|
-
{checked && (
|
|
94
|
-
<RadioIcon
|
|
95
|
-
className={clsx(
|
|
96
|
-
"transition-colors",
|
|
97
|
-
!error &&
|
|
98
|
-
!disabled &&
|
|
99
|
-
"text-icon-on-action-secondary-normal hover:text-icon-on-action-secondary-hover active:text-icon-on-action-secondary-active peer-hover:text-icon-on-action-secondary-hover peer-focus:text-icon-on-action-secondary-hover peer-active:text-icon-on-action-secondary-active",
|
|
100
|
-
error &&
|
|
101
|
-
!disabled &&
|
|
102
|
-
"text-icon-action-critical-secondary-normal hover:text-icon-action-critical-secondary-hover active:text-icon-action-critical-secondary-active peer-hover:text-icon-action-critical-secondary-hover peer-focus:text-icon-action-critical-secondary-hover peer-active:text-icon-action-critical-secondary-active",
|
|
103
|
-
disabled && "text-icon-on-action-secondary-disabled",
|
|
104
|
-
readOnly && "text-icon-on-action-secondary-disabled",
|
|
105
|
-
)}
|
|
106
|
-
/>
|
|
107
|
-
)}
|
|
108
|
-
</div>
|
|
109
|
-
</div>
|
|
110
|
-
|
|
111
|
-
{label && (
|
|
112
|
-
<Paragraph id={radioId ? `${radioId}-label` : undefined} testid={testid ? `${testid}-label` : undefined} padded color={paragraphColor}>
|
|
113
|
-
{label}
|
|
114
|
-
</Paragraph>
|
|
115
|
-
)}
|
|
116
|
-
</label>
|
|
117
|
-
);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
Radio.displayName = "Radio";
|
|
121
|
-
|
|
122
|
-
const RadioIcon = ({ className }: { className: string }) => {
|
|
123
|
-
return (
|
|
124
|
-
<svg
|
|
125
|
-
className={className}
|
|
126
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
127
|
-
width="24"
|
|
128
|
-
height="24"
|
|
129
|
-
viewBox="0 0 24 24"
|
|
130
|
-
fill="none"
|
|
131
|
-
>
|
|
132
|
-
<rect
|
|
133
|
-
x="1"
|
|
134
|
-
y="1"
|
|
135
|
-
width="22"
|
|
136
|
-
height="22"
|
|
137
|
-
rx="11"
|
|
138
|
-
stroke="currentColor"
|
|
139
|
-
strokeWidth="2"
|
|
140
|
-
/>
|
|
141
|
-
<rect x="4" y="4" width="16" height="16" rx="8" fill="currentColor" />
|
|
142
|
-
</svg>
|
|
143
|
-
);
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
RadioIcon.displayName = "RadioIcon";
|