pentatrion-design 0.0.1
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/.storybook/main.ts +33 -0
- package/.storybook/manager.ts +8 -0
- package/.storybook/preview-head.html +2 -0
- package/.storybook/preview.ts +26 -0
- package/.storybook/public/bg-map.jpg +0 -0
- package/.storybook/public/favicon-32x32.png +0 -0
- package/.storybook/public/favicon.svg +28 -0
- package/.storybook/public/movies.json +2153 -0
- package/.storybook/public/population.json +1178 -0
- package/.storybook/public/town-74.geojson +8995 -0
- package/.storybook/public/town-74.json +4062 -0
- package/.storybook/theme.ts +14 -0
- package/Makefile +14 -0
- package/README.md +40 -0
- package/TODO.md +5 -0
- package/dist/index.d.ts +1110 -0
- package/dist/index.js +3707 -0
- package/dist/redux/index.d.ts +43 -0
- package/dist/redux/index.js +583 -0
- package/dist/types.d-DlHa_IaW.d.ts +14 -0
- package/images/logo-shadow.svg +173 -0
- package/images/logo.svg +76 -0
- package/package.json +85 -0
- package/postcss.config.js +7 -0
- package/src/components/autocomplete/Autocomplete.stories.tsx +89 -0
- package/src/components/autocomplete/Autocomplete.tsx +316 -0
- package/src/components/autocomplete/AutocompleteOption.tsx +35 -0
- package/src/components/autocomplete/LazyAutocomplete.tsx +130 -0
- package/src/components/autocomplete/SimpleAutocomplete.tsx +74 -0
- package/src/components/autocomplete/index.ts +6 -0
- package/src/components/autocomplete/useAutocompleteContext.ts +20 -0
- package/src/components/autocomplete/util.ts +19 -0
- package/src/components/badge/Badge.stories.tsx +72 -0
- package/src/components/badge/Badge.tsx +70 -0
- package/src/components/button/Button.stories.tsx +189 -0
- package/src/components/button/Button.test.tsx +20 -0
- package/src/components/button/Button.tsx +200 -0
- package/src/components/button/ButtonGroup.stories.tsx +46 -0
- package/src/components/button/ButtonGroup.tsx +29 -0
- package/src/components/button/index.ts +2 -0
- package/src/components/card/Card.stories.tsx +21 -0
- package/src/components/card/config.ts +4 -0
- package/src/components/card/index.ts +1 -0
- package/src/components/code/Code.tsx +15 -0
- package/src/components/context-menu/ContextMenu.stories.tsx +22 -0
- package/src/components/context-menu/ContextMenu.tsx +175 -0
- package/src/components/context-menu/ContextMenuItem.tsx +34 -0
- package/src/components/context-menu/index.ts +2 -0
- package/src/components/dialog/Dialog.stories.tsx +270 -0
- package/src/components/dialog/Dialog.tsx +46 -0
- package/src/components/dialog/index.ts +1 -0
- package/src/components/dialog/util.ts +29 -0
- package/src/components/dropdown-menu/DropdownMenu.stories.tsx +19 -0
- package/src/components/dropdown-menu/DropdownMenu.tsx +12 -0
- package/src/components/dropdown-menu/DropdownMenuContent.tsx +46 -0
- package/src/components/dropdown-menu/DropdownMenuItem.tsx +33 -0
- package/src/components/dropdown-menu/DropdownMenuTrigger.tsx +42 -0
- package/src/components/dropdown-menu/index.ts +7 -0
- package/src/components/dropdown-menu/interface.d.ts +13 -0
- package/src/components/dropdown-menu/useDropdownMenu.tsx +115 -0
- package/src/components/dropdown-menu/useDropdownMenuContext.ts +16 -0
- package/src/components/dropdown-menu-nested/DropdownMenuNested.stories.tsx +33 -0
- package/src/components/dropdown-menu-nested/DropdownMenuNested.tsx +19 -0
- package/src/components/dropdown-menu-nested/MenuContext.ts +15 -0
- package/src/components/dropdown-menu-nested/MenuItem.tsx +43 -0
- package/src/components/dropdown-menu-nested/MenuItemWithChildren.tsx +204 -0
- package/src/components/dropdown-menu-nested/index.ts +3 -0
- package/src/components/flash/Flash.stories.tsx +34 -0
- package/src/components/flash/Flash.tsx +24 -0
- package/src/components/highlight/Highlight.stories.tsx +128 -0
- package/src/components/highlight/Highlight.tsx +29 -0
- package/src/components/href/Href.stories.tsx +55 -0
- package/src/components/href/Href.tsx +18 -0
- package/src/components/input/Checkbox.stories.tsx +52 -0
- package/src/components/input/Checkbox.tsx +41 -0
- package/src/components/input/Input.stories.tsx +103 -0
- package/src/components/input/Input.test.tsx +10 -0
- package/src/components/input/Input.tsx +60 -0
- package/src/components/input/RadioGroup.stories.tsx +76 -0
- package/src/components/input/RadioGroup.tsx +84 -0
- package/src/components/input/Toggle.stories.tsx +29 -0
- package/src/components/input/Toggle.tsx +35 -0
- package/src/components/input/index.ts +4 -0
- package/src/components/input-field/InputField.stories.tsx +227 -0
- package/src/components/input-field/InputField.tsx +62 -0
- package/src/components/loader/Loader.stories.tsx +37 -0
- package/src/components/loader/Loader.tsx +54 -0
- package/src/components/modal/Components.tsx +58 -0
- package/src/components/modal/Modal.stories.tsx +113 -0
- package/src/components/modal/Modal.tsx +13 -0
- package/src/components/modal/ModalContent.tsx +46 -0
- package/src/components/modal/ModalTrigger.tsx +41 -0
- package/src/components/modal/index.ts +7 -0
- package/src/components/modal/interface.d.ts +10 -0
- package/src/components/modal/useModal.ts +48 -0
- package/src/components/modal/useModalContext.ts +16 -0
- package/src/components/notification/Notification.stories.tsx +51 -0
- package/src/components/notification/NotificationsContext.ts +79 -0
- package/src/components/notification/NotificationsProvider.tsx +58 -0
- package/src/components/notification/index.ts +2 -0
- package/src/components/popover/Components.tsx +45 -0
- package/src/components/popover/Popover.stories.tsx +46 -0
- package/src/components/popover/Popover.test.tsx +21 -0
- package/src/components/popover/Popover.tsx +12 -0
- package/src/components/popover/PopoverContent.tsx +46 -0
- package/src/components/popover/PopoverTrigger.tsx +42 -0
- package/src/components/popover/index.ts +7 -0
- package/src/components/popover/interface.d.ts +13 -0
- package/src/components/popover/usePopover.tsx +80 -0
- package/src/components/popover/usePopoverContext.ts +16 -0
- package/src/components/portal/Portal.tsx +12 -0
- package/src/components/quick-settings/QuickSettings.stories.tsx +182 -0
- package/src/components/resize-area/ResizeArea.stories.css +40 -0
- package/src/components/resize-area/ResizeArea.stories.tsx +30 -0
- package/src/components/resize-area/ResizeArea.tsx +79 -0
- package/src/components/scroll/Scroll.stories.tsx +81 -0
- package/src/components/scroll/Scroll.tsx +111 -0
- package/src/components/select/Select.stories.tsx +248 -0
- package/src/components/select/Select.tsx +362 -0
- package/src/components/select/SelectOption.tsx +29 -0
- package/src/components/select/SelectSelection.tsx +13 -0
- package/src/components/select/index.ts +5 -0
- package/src/components/select/interface.d.ts +36 -0
- package/src/components/select/useSelectContext.ts +19 -0
- package/src/components/select/util.ts +12 -0
- package/src/components/snack/Snack.stories.tsx +33 -0
- package/src/components/snack/Snack.tsx +47 -0
- package/src/components/sortable/Sortable.stories.tsx +98 -0
- package/src/components/sortable/Sortable.tsx +37 -0
- package/src/components/sortable/index.ts +2 -0
- package/src/components/sortable/types.d.ts +12 -0
- package/src/components/steps/Step.tsx +41 -0
- package/src/components/steps/Steps.stories.tsx +141 -0
- package/src/components/steps/Steps.tsx +49 -0
- package/src/components/steps/index.ts +3 -0
- package/src/components/steps/util.ts +3 -0
- package/src/components/table/Table.stories.tsx +36 -0
- package/src/components/table/Table.tsx +13 -0
- package/src/components/table/TableBody.tsx +9 -0
- package/src/components/table/TableCell.tsx +16 -0
- package/src/components/table/TableFooter.tsx +9 -0
- package/src/components/table/TableHeader.tsx +14 -0
- package/src/components/table/TableHeaderCell.tsx +14 -0
- package/src/components/table/TableRow.tsx +14 -0
- package/src/components/table/index.ts +7 -0
- package/src/components/tabs/Tabs.stories.tsx +66 -0
- package/src/components/tabs/Tabs.tsx +80 -0
- package/src/components/tooltip/SimpleTooltip.tsx +17 -0
- package/src/components/tooltip/Tooltip.stories.tsx +129 -0
- package/src/components/tooltip/Tooltip.test.tsx +18 -0
- package/src/components/tooltip/Tooltip.tsx +13 -0
- package/src/components/tooltip/TooltipContent.tsx +41 -0
- package/src/components/tooltip/TooltipTrigger.tsx +36 -0
- package/src/components/tooltip/index.ts +6 -0
- package/src/components/tooltip/interface.d.ts +15 -0
- package/src/components/tooltip/useTooltip.ts +87 -0
- package/src/components/tooltip/useTooltipContext.ts +16 -0
- package/src/env.d.ts +27 -0
- package/src/hooks/index.ts +13 -0
- package/src/hooks/useCombinedRefs.test.tsx +42 -0
- package/src/hooks/useCombinedRefs.ts +21 -0
- package/src/hooks/useCopyToClipboard.ts +28 -0
- package/src/hooks/useDebounce.ts +59 -0
- package/src/hooks/useEventCallback.ts +13 -0
- package/src/hooks/useEventListener.ts +86 -0
- package/src/hooks/useFetch.tsx +21 -0
- package/src/hooks/useIsClosing.ts +25 -0
- package/src/hooks/useIsMounted.tsx +16 -0
- package/src/hooks/useIsomorphicLayoutEffect.ts +4 -0
- package/src/hooks/useNotifications.tsx +13 -0
- package/src/hooks/useOnClickOutside.ts +35 -0
- package/src/hooks/usePrevious.ts +9 -0
- package/src/hooks/useRipple.test.tsx +52 -0
- package/src/hooks/useRipple.tsx +79 -0
- package/src/index.css +14 -0
- package/src/index.ts +39 -0
- package/src/lib/arrUtil.ts +8 -0
- package/src/lib/error.ts +18 -0
- package/src/lib/fetch.test.ts +107 -0
- package/src/lib/fetch.ts +115 -0
- package/src/lib/index.ts +3 -0
- package/src/lib/tailwindVariants.ts +35 -0
- package/src/redux/index.ts +1 -0
- package/src/redux/notification/components/NotificationConsumer.tsx +52 -0
- package/src/redux/notification/errorCatcherMiddleware.ts +17 -0
- package/src/redux/notification/hooks/useNotification.ts +26 -0
- package/src/redux/notification/index.ts +5 -0
- package/src/redux/notification/notificationSlice.ts +68 -0
- package/src/styles/Animation.stories.tsx +43 -0
- package/src/styles/Shadow.stories.tsx +43 -0
- package/src/styles/Themes.stories.tsx +31 -0
- package/src/styles/Typography.stories.tsx +101 -0
- package/src/tailwind/base.css +188 -0
- package/src/tailwind/components-input-outline.css +62 -0
- package/src/tailwind/components-resize-area.css +112 -0
- package/src/tailwind/components-step.css +161 -0
- package/src/tailwind/components.css +51 -0
- package/src/tailwind/keyframes.ts +69 -0
- package/src/tailwind/pentatrionTw.ts +147 -0
- package/src/tailwind/utilities-dialog.css +103 -0
- package/src/tailwind/utilities.css +3 -0
- package/src/types.d.ts +12 -0
- package/tailwind.config.js +18 -0
- package/tests/README.md +32 -0
- package/tests/setup.ts +1 -0
- package/tsconfig.json +14 -0
- package/tsup.config.ts +23 -0
- package/vite.config.ts +24 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { Meta } from "@storybook/react";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { Button } from "../button";
|
|
4
|
+
import { Checkbox, Input } from "../input";
|
|
5
|
+
import { Select } from "../select";
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: "Components/QuickSettings",
|
|
9
|
+
decorators: (Story) => (
|
|
10
|
+
<div className="grid grid-cols-1 gap-8" style={{ width: "350px" }}>
|
|
11
|
+
<Story />
|
|
12
|
+
</div>
|
|
13
|
+
),
|
|
14
|
+
} satisfies Meta;
|
|
15
|
+
export default meta;
|
|
16
|
+
|
|
17
|
+
const profileOptions = [
|
|
18
|
+
{ value: "car", label: "Voiture" },
|
|
19
|
+
{ value: "pedestrian", label: "Piéton" },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
const directionOptions = [
|
|
23
|
+
{ value: "departure", label: "Départ" },
|
|
24
|
+
{ value: "arrival", label: "Arrivée" },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
// const quicksettingConfig = {
|
|
28
|
+
// setting: "flex items-center justify-between first:text-gray-6 first:text-sm",
|
|
29
|
+
// };
|
|
30
|
+
|
|
31
|
+
export const Basic = () => {
|
|
32
|
+
const [profile, setProfile] = useState<string | null>("car");
|
|
33
|
+
const [direction, setDirection] = useState<string | null>("departure");
|
|
34
|
+
return (
|
|
35
|
+
<div className="grid grid-cols-1 gap-2">
|
|
36
|
+
<div>
|
|
37
|
+
<div className="p8n-setting">
|
|
38
|
+
<div>Coordonnées</div>
|
|
39
|
+
<div>
|
|
40
|
+
<span className="text-gray-6 text-sm">lon/lat </span>
|
|
41
|
+
6.497886, 46.091857
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
<div className="p8n-setting">
|
|
45
|
+
<div>Altitude</div>
|
|
46
|
+
<div>
|
|
47
|
+
500 <span className="text-gray-6 text-sm">m</span>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
<div className="actions flex gap-2">
|
|
52
|
+
<Button variant="text" color="gray" size="large" className="flex-1 min-w-0">
|
|
53
|
+
<span className="flex-center w-full">
|
|
54
|
+
<i className="fe-isochrone text-2xl"></i>
|
|
55
|
+
</span>
|
|
56
|
+
</Button>
|
|
57
|
+
<Button variant="text" color="gray" size="large" className="flex-1 min-w-0">
|
|
58
|
+
<span className="flex-center w-full">
|
|
59
|
+
<i className="fe-route text-2xl"></i>
|
|
60
|
+
</span>
|
|
61
|
+
</Button>
|
|
62
|
+
<Button variant="text" color="gray" size="large" className="flex-1 min-w-0">
|
|
63
|
+
<span className="flex-center w-full">RAW</span>
|
|
64
|
+
</Button>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div className="actions flex gap-2">
|
|
68
|
+
<Button variant="text" color="gray" size="large" className="flex-1 min-w-0">
|
|
69
|
+
<span className="flex-center w-full">
|
|
70
|
+
<i className="fe-stopwatch"></i>
|
|
71
|
+
isochrone
|
|
72
|
+
</span>
|
|
73
|
+
</Button>
|
|
74
|
+
<Button variant="text" color="gray" size="large" className="flex-1 min-w-0">
|
|
75
|
+
<span className="flex-center w-full">
|
|
76
|
+
<i className="fe-ruler"></i>
|
|
77
|
+
isodistance
|
|
78
|
+
</span>
|
|
79
|
+
</Button>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div className="ll-steps-extra">
|
|
83
|
+
<Button variant="ghost" color="gray">
|
|
84
|
+
<span
|
|
85
|
+
className="ll-marker"
|
|
86
|
+
style={{ "--marker-color": "#c0c0c0", "--marker-size": "34px" }}
|
|
87
|
+
>
|
|
88
|
+
<span className="marker">
|
|
89
|
+
<span className="ovale"></span>
|
|
90
|
+
<i className="fe-plus"></i>
|
|
91
|
+
</span>
|
|
92
|
+
<span className="target"></span>
|
|
93
|
+
</span>
|
|
94
|
+
<span>Ajouter un point</span>
|
|
95
|
+
</Button>
|
|
96
|
+
|
|
97
|
+
<Button icon variant="text" color="gray">
|
|
98
|
+
<i className="fe-sliders"></i>
|
|
99
|
+
</Button>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div className="p8n-setting">
|
|
103
|
+
<div>Temps</div>
|
|
104
|
+
<Input suffix="min" defaultValue="0" />
|
|
105
|
+
</div>
|
|
106
|
+
<div className="p8n-setting">
|
|
107
|
+
<div>Distance</div>
|
|
108
|
+
<div>
|
|
109
|
+
<Input suffix="km" />
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<div className="p8n-setting">
|
|
114
|
+
<div>Mode de transport</div>
|
|
115
|
+
<div>
|
|
116
|
+
<Select
|
|
117
|
+
variant="ghost"
|
|
118
|
+
options={profileOptions}
|
|
119
|
+
value={profile}
|
|
120
|
+
onChange={(o) => {
|
|
121
|
+
// @ts-ignore
|
|
122
|
+
setProfile(o.target.value);
|
|
123
|
+
}}
|
|
124
|
+
></Select>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
<div className="p8n-setting">
|
|
128
|
+
<div>Sens de parcours</div>
|
|
129
|
+
<Select
|
|
130
|
+
variant="ghost"
|
|
131
|
+
options={directionOptions}
|
|
132
|
+
value={direction}
|
|
133
|
+
onChange={(o) => {
|
|
134
|
+
// @ts-ignore
|
|
135
|
+
setDirection(o.target.value);
|
|
136
|
+
}}
|
|
137
|
+
></Select>
|
|
138
|
+
</div>
|
|
139
|
+
<div className="p8n-setting multiple">
|
|
140
|
+
<div>Passages autorisés</div>
|
|
141
|
+
<div className="">
|
|
142
|
+
<Checkbox checked={true}>Péages</Checkbox>
|
|
143
|
+
<Checkbox checked={false}>Ponts</Checkbox>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<div className="p8n-setting multiple">
|
|
148
|
+
<div>Éviter</div>
|
|
149
|
+
<div className="">
|
|
150
|
+
<Checkbox checked={true}>
|
|
151
|
+
<span>Sections à péage</span>
|
|
152
|
+
</Checkbox>
|
|
153
|
+
<Checkbox checked={false}>
|
|
154
|
+
<span>Ponts</span>
|
|
155
|
+
</Checkbox>
|
|
156
|
+
<Checkbox checked={false}>
|
|
157
|
+
<span>Tunnels</span>
|
|
158
|
+
</Checkbox>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
<div className="p8n-separator"></div>
|
|
163
|
+
|
|
164
|
+
<div>
|
|
165
|
+
<div className="p8n-setting">
|
|
166
|
+
<div>Distance</div>
|
|
167
|
+
<div>
|
|
168
|
+
325 <span className="text-gray-6 text-sm">km</span>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
<div className="p8n-setting">
|
|
172
|
+
<div>Durée</div>
|
|
173
|
+
<div>3h 25min</div>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
<div className="text-right">
|
|
178
|
+
<Button>Calculer</Button>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
);
|
|
182
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
html {
|
|
2
|
+
--sidebar-extra-height: 200px;
|
|
3
|
+
--sidebar-menu-width: 200px;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
html,
|
|
7
|
+
body,
|
|
8
|
+
#storybook-root,
|
|
9
|
+
#app {
|
|
10
|
+
margin: 0;
|
|
11
|
+
padding: 0;
|
|
12
|
+
width: 100%;
|
|
13
|
+
height: 100%;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#app {
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
#principal {
|
|
22
|
+
flex: 1;
|
|
23
|
+
display: flex;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#content {
|
|
27
|
+
flex: 1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#menu-col {
|
|
31
|
+
border-right: 1px solid rgb(var(--color-gray-2));
|
|
32
|
+
flex: 0 0 var(--sidebar-menu-width);
|
|
33
|
+
position: relative;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#extra-row {
|
|
37
|
+
border-top: 1px solid rgb(var(--color-gray-2));
|
|
38
|
+
flex: 0 0 var(--sidebar-extra-height);
|
|
39
|
+
position: relative;
|
|
40
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Meta } from "@storybook/react";
|
|
2
|
+
import ResizeArea from "./ResizeArea";
|
|
3
|
+
import "./ResizeArea.stories.css";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: "Components/ResizeArea",
|
|
7
|
+
component: ResizeArea,
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: "fullscreen",
|
|
10
|
+
},
|
|
11
|
+
} satisfies Meta<typeof ResizeArea>;
|
|
12
|
+
export default meta;
|
|
13
|
+
|
|
14
|
+
export const Basic = () => {
|
|
15
|
+
return (
|
|
16
|
+
<div id="app">
|
|
17
|
+
<div id="principal">
|
|
18
|
+
<div id="menu-col">
|
|
19
|
+
<ResizeArea name="menu" position="right" />
|
|
20
|
+
<div>Menu</div>
|
|
21
|
+
</div>
|
|
22
|
+
<div id="content">Content</div>
|
|
23
|
+
</div>
|
|
24
|
+
<div id="extra-row">
|
|
25
|
+
<ResizeArea name="extra" position="top" />
|
|
26
|
+
<div>Extra row</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useCallback, useEffect } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
name: string;
|
|
6
|
+
position: "top" | "bottom" | "left" | "right";
|
|
7
|
+
initialValue?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default function ResizeArea({ name, position, initialValue }: Props) {
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const cssVarName = `--sidebar-${name}-${["top", "bottom"].includes(position) ? "height" : "width"}`;
|
|
13
|
+
if (initialValue) {
|
|
14
|
+
document.documentElement.style.setProperty(cssVarName, `${initialValue}px`);
|
|
15
|
+
}
|
|
16
|
+
// we want to set the initial value, we don't want this value to be updated after
|
|
17
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
18
|
+
}, []);
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const cssVarName = `--sidebar-${name}-${["top", "bottom"].includes(position) ? "height" : "width"}`;
|
|
22
|
+
return () => {
|
|
23
|
+
// some cleanup
|
|
24
|
+
document.documentElement.style.removeProperty(cssVarName);
|
|
25
|
+
};
|
|
26
|
+
}, [name, position]);
|
|
27
|
+
|
|
28
|
+
const handlePointerMove = useCallback(
|
|
29
|
+
(e: MouseEvent) => {
|
|
30
|
+
const cssVarName = `--sidebar-${name}-${["top", "bottom"].includes(position) ? "height" : "width"}`;
|
|
31
|
+
let cssVarValue;
|
|
32
|
+
switch (position) {
|
|
33
|
+
case "top":
|
|
34
|
+
cssVarValue = document.documentElement.clientHeight - e.pageY;
|
|
35
|
+
break;
|
|
36
|
+
case "right":
|
|
37
|
+
cssVarValue = e.pageX;
|
|
38
|
+
break;
|
|
39
|
+
case "left":
|
|
40
|
+
cssVarValue = document.documentElement.clientWidth - e.pageX;
|
|
41
|
+
break;
|
|
42
|
+
case "bottom":
|
|
43
|
+
cssVarValue = e.pageY;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
document.documentElement.style.setProperty(cssVarName, `${cssVarValue}px`);
|
|
47
|
+
return () => {
|
|
48
|
+
document.documentElement.style.removeProperty(cssVarName);
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
[name, position],
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const handlePointerUp = useCallback(() => {
|
|
55
|
+
const handler = handlePointerMove;
|
|
56
|
+
document.removeEventListener("pointermove", handler);
|
|
57
|
+
document.documentElement.classList.remove("cursor-row-resize", "cursor-col-resize");
|
|
58
|
+
|
|
59
|
+
return () => {
|
|
60
|
+
document.removeEventListener("pointermove", handler);
|
|
61
|
+
};
|
|
62
|
+
}, [handlePointerMove]);
|
|
63
|
+
|
|
64
|
+
function handlePointerDown() {
|
|
65
|
+
document.addEventListener("pointerup", handlePointerUp, { once: true });
|
|
66
|
+
document.addEventListener("pointermove", handlePointerMove);
|
|
67
|
+
if (["top", "bottom"].includes(position)) {
|
|
68
|
+
document.documentElement.classList.add(`cursor-row-resize`);
|
|
69
|
+
} else {
|
|
70
|
+
document.documentElement.classList.add(`cursor-col-resize`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div className={clsx(["p8n-resize-area", position])}>
|
|
76
|
+
<button className="area-button" type="button" onPointerDown={handlePointerDown}></button>
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import Scroll from "./Scroll";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
component: Scroll,
|
|
5
|
+
title: "Components/Scroll",
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const Basic = () => {
|
|
9
|
+
return (
|
|
10
|
+
<div className="flex flex-col gap-2">
|
|
11
|
+
<Scroll className="border border-gray-2" style={{ height: "160px", width: "400px" }}>
|
|
12
|
+
<div className="px-4 text-justify">
|
|
13
|
+
<p>
|
|
14
|
+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium unde, blanditiis
|
|
15
|
+
rem accusamus obcaecati enim amet, voluptatibus nemo facilis illum aut itaque in?
|
|
16
|
+
Deleniti iure amet qui vero, blanditiis quos?
|
|
17
|
+
</p>
|
|
18
|
+
<p>
|
|
19
|
+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium unde, blanditiis
|
|
20
|
+
rem accusamus obcaecati enim amet, voluptatibus nemo facilis illum aut itaque in?
|
|
21
|
+
Deleniti iure amet qui vero, blanditiis quos?
|
|
22
|
+
</p>
|
|
23
|
+
<p>
|
|
24
|
+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium unde, blanditiis
|
|
25
|
+
rem accusamus obcaecati enim amet, voluptatibus nemo facilis illum aut itaque in?
|
|
26
|
+
Deleniti iure amet qui vero, blanditiis quos?
|
|
27
|
+
</p>
|
|
28
|
+
<p>
|
|
29
|
+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium unde, blanditiis
|
|
30
|
+
rem accusamus obcaecati enim amet, voluptatibus nemo facilis illum aut itaque in?
|
|
31
|
+
Deleniti iure amet qui vero, blanditiis quos?
|
|
32
|
+
</p>
|
|
33
|
+
</div>
|
|
34
|
+
</Scroll>
|
|
35
|
+
<Scroll horizontal className="border border-gray-2">
|
|
36
|
+
<div className="p-4 flex flex-nowrap">
|
|
37
|
+
<p className="pr-7" style={{ minWidth: 400 }}>
|
|
38
|
+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium unde, blanditiis
|
|
39
|
+
rem accusamus obcaecati enim amet, voluptatibus nemo facilis illum aut itaque in?
|
|
40
|
+
Deleniti iure amet qui vero, blanditiis quos?
|
|
41
|
+
</p>
|
|
42
|
+
<p className="pr-7" style={{ minWidth: 400 }}>
|
|
43
|
+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium unde, blanditiis
|
|
44
|
+
rem accusamus obcaecati enim amet, voluptatibus nemo facilis illum aut itaque in?
|
|
45
|
+
Deleniti iure amet qui vero, blanditiis quos?
|
|
46
|
+
</p>
|
|
47
|
+
<p className="pr-7" style={{ minWidth: 400 }}>
|
|
48
|
+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium unde, blanditiis
|
|
49
|
+
rem accusamus obcaecati enim amet, voluptatibus nemo facilis illum aut itaque in?
|
|
50
|
+
Deleniti iure amet qui vero, blanditiis quos?
|
|
51
|
+
</p>
|
|
52
|
+
<p className="pr-7" style={{ minWidth: 400 }}>
|
|
53
|
+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium unde, blanditiis
|
|
54
|
+
rem accusamus obcaecati enim amet, voluptatibus nemo facilis illum aut itaque in?
|
|
55
|
+
Deleniti iure amet qui vero, blanditiis quos?
|
|
56
|
+
</p>
|
|
57
|
+
<p className="pr-7" style={{ minWidth: 400 }}>
|
|
58
|
+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium unde, blanditiis
|
|
59
|
+
rem accusamus obcaecati enim amet, voluptatibus nemo facilis illum aut itaque in?
|
|
60
|
+
Deleniti iure amet qui vero, blanditiis quos?
|
|
61
|
+
</p>
|
|
62
|
+
<p className="pr-7" style={{ minWidth: 400 }}>
|
|
63
|
+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium unde, blanditiis
|
|
64
|
+
rem accusamus obcaecati enim amet, voluptatibus nemo facilis illum aut itaque in?
|
|
65
|
+
Deleniti iure amet qui vero, blanditiis quos?
|
|
66
|
+
</p>
|
|
67
|
+
<p className="pr-7" style={{ minWidth: 400 }}>
|
|
68
|
+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium unde, blanditiis
|
|
69
|
+
rem accusamus obcaecati enim amet, voluptatibus nemo facilis illum aut itaque in?
|
|
70
|
+
Deleniti iure amet qui vero, blanditiis quos?
|
|
71
|
+
</p>
|
|
72
|
+
<p style={{ minWidth: 400 }}>
|
|
73
|
+
Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium unde, blanditiis
|
|
74
|
+
rem accusamus obcaecati enim amet, voluptatibus nemo facilis illum aut itaque in?
|
|
75
|
+
Deleniti iure amet qui vero, blanditiis quos?
|
|
76
|
+
</p>
|
|
77
|
+
</div>
|
|
78
|
+
</Scroll>
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
81
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, useEffect, useRef, useState } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
const TOLERANCE = 5;
|
|
5
|
+
|
|
6
|
+
interface Props extends ComponentPropsWithoutRef<"div"> {
|
|
7
|
+
horizontal?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const scrollVariants = {
|
|
11
|
+
vertical: {
|
|
12
|
+
inner: "overflow-y-auto h-full",
|
|
13
|
+
shadow: "h-1 left-0 right-0",
|
|
14
|
+
shadowStart: "top-0 bg-gradient-to-b from-gray-8/10",
|
|
15
|
+
shadowEnd: "bottom-0 bg-gradient-to-t from-gray-8/10",
|
|
16
|
+
child: "",
|
|
17
|
+
},
|
|
18
|
+
horizontal: {
|
|
19
|
+
inner: "overflow-x-auto",
|
|
20
|
+
shadow: "w-1 top-0 bottom-0",
|
|
21
|
+
shadowStart: "left-0 bg-gradient-to-r from-gray-8/10",
|
|
22
|
+
shadowEnd: "right-0 bg-gradient-to-l from-gray-8/10",
|
|
23
|
+
child: "inline-block",
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default function Scroll({ horizontal = false, className, children, ...rest }: Props) {
|
|
28
|
+
const [showStartShadow, setShowStartShadow] = useState(false);
|
|
29
|
+
const [showEndShadow, setShowEndShadow] = useState(false);
|
|
30
|
+
const scrollChildRef = useRef<HTMLDivElement>(null);
|
|
31
|
+
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
32
|
+
|
|
33
|
+
const position = horizontal ? "horizontal" : "vertical";
|
|
34
|
+
|
|
35
|
+
const setShadows = (container: HTMLDivElement | null, child: HTMLDivElement | null) => {
|
|
36
|
+
if (!container || !child) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const containerRect = container.getBoundingClientRect();
|
|
41
|
+
|
|
42
|
+
const childRect = child.getBoundingClientRect();
|
|
43
|
+
|
|
44
|
+
const isOnStartEdge = horizontal
|
|
45
|
+
? containerRect.left - childRect.left < TOLERANCE
|
|
46
|
+
: containerRect.top - childRect.top < TOLERANCE;
|
|
47
|
+
|
|
48
|
+
const isOnEndEdge = horizontal
|
|
49
|
+
? childRect.right - containerRect.right < TOLERANCE
|
|
50
|
+
: childRect.bottom - containerRect.bottom < TOLERANCE;
|
|
51
|
+
|
|
52
|
+
setShowStartShadow((previousShowStartShadow) =>
|
|
53
|
+
isOnStartEdge === previousShowStartShadow
|
|
54
|
+
? !previousShowStartShadow
|
|
55
|
+
: previousShowStartShadow,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
setShowEndShadow((previousShowEndShadow) =>
|
|
59
|
+
isOnEndEdge === previousShowEndShadow ? !previousShowEndShadow : previousShowEndShadow,
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
65
|
+
setShadows(scrollContainerRef.current, scrollChildRef.current);
|
|
66
|
+
});
|
|
67
|
+
resizeObserver.observe(scrollChildRef.current!);
|
|
68
|
+
resizeObserver.observe(scrollContainerRef.current!);
|
|
69
|
+
|
|
70
|
+
return () => {
|
|
71
|
+
resizeObserver.disconnect();
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
function handleScroll(event: React.UIEvent<HTMLDivElement, UIEvent>) {
|
|
76
|
+
if (!scrollChildRef?.current) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
setShadows(event.currentTarget, scrollChildRef.current);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div className={clsx("ll-scroll-zone", "relative", className)} {...rest}>
|
|
84
|
+
<div
|
|
85
|
+
className={clsx(
|
|
86
|
+
"scroll-shadow z-[1] absolute opacity-0 transition-all",
|
|
87
|
+
scrollVariants[position].shadow,
|
|
88
|
+
scrollVariants[position].shadowStart,
|
|
89
|
+
showStartShadow && "opacity-100",
|
|
90
|
+
)}
|
|
91
|
+
></div>
|
|
92
|
+
<div
|
|
93
|
+
className={clsx(
|
|
94
|
+
"scroll-shadow z-[1] absolute opacity-0 transition-all",
|
|
95
|
+
scrollVariants[position].shadow,
|
|
96
|
+
scrollVariants[position].shadowEnd,
|
|
97
|
+
showEndShadow && "opacity-100",
|
|
98
|
+
)}
|
|
99
|
+
></div>
|
|
100
|
+
<div
|
|
101
|
+
className={scrollVariants[position].inner}
|
|
102
|
+
ref={scrollContainerRef}
|
|
103
|
+
onScroll={handleScroll}
|
|
104
|
+
>
|
|
105
|
+
<div className={scrollVariants[position].child} ref={scrollChildRef}>
|
|
106
|
+
{children}
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
);
|
|
111
|
+
}
|