aural-ui 2.0.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/LICENSE +21 -0
- package/README.md +456 -0
- package/dist/components/aspect-ratio/AspectRatio.stories.tsx +1327 -0
- package/dist/components/aspect-ratio/index.tsx +10 -0
- package/dist/components/aspect-ratio/meta.ts +8 -0
- package/dist/components/avatar/Avatar.stories.tsx +645 -0
- package/dist/components/avatar/index.tsx +50 -0
- package/dist/components/avatar/meta.ts +8 -0
- package/dist/components/badge/Badge.stories.tsx +169 -0
- package/dist/components/badge/index.tsx +28 -0
- package/dist/components/badge/meta.ts +6 -0
- package/dist/components/banner/Banner.stories.tsx +475 -0
- package/dist/components/banner/index.tsx +256 -0
- package/dist/components/banner/meta.ts +36 -0
- package/dist/components/button/Button.stories.tsx +74 -0
- package/dist/components/button/index.tsx +158 -0
- package/dist/components/button/meta.ts +33 -0
- package/dist/components/card/Card.stories.tsx +377 -0
- package/dist/components/card/index.tsx +85 -0
- package/dist/components/card/meta.ts +14 -0
- package/dist/components/char-count/CharCount.stories.tsx +334 -0
- package/dist/components/char-count/index.tsx +51 -0
- package/dist/components/char-count/meta.ts +13 -0
- package/dist/components/checkbox/Checkbox.stories.tsx +209 -0
- package/dist/components/checkbox/index.tsx +34 -0
- package/dist/components/checkbox/meta.ts +19 -0
- package/dist/components/chip/Chip.stories.tsx +207 -0
- package/dist/components/chip/index.tsx +92 -0
- package/dist/components/chip/meta.ts +17 -0
- package/dist/components/circular-loader/CircularLoader.stories.tsx +741 -0
- package/dist/components/circular-loader/index.tsx +138 -0
- package/dist/components/circular-loader/meta.ts +11 -0
- package/dist/components/collapsible/Collapsible.stories.tsx +319 -0
- package/dist/components/collapsible/index.tsx +158 -0
- package/dist/components/collapsible/meta.ts +22 -0
- package/dist/components/command/Command.stories.tsx +996 -0
- package/dist/components/command/index.tsx +324 -0
- package/dist/components/command/meta.ts +18 -0
- package/dist/components/dialog/Dialog.stories.tsx +963 -0
- package/dist/components/dialog/index.tsx +250 -0
- package/dist/components/dialog/meta.ts +28 -0
- package/dist/components/divider/Divider.stories.tsx +633 -0
- package/dist/components/divider/index.tsx +181 -0
- package/dist/components/divider/meta.ts +12 -0
- package/dist/components/dot-loader/DotLoader.stories.tsx +352 -0
- package/dist/components/dot-loader/index.tsx +78 -0
- package/dist/components/dot-loader/meta.ts +14 -0
- package/dist/components/dropdown/Dropdown.stories.tsx +1210 -0
- package/dist/components/dropdown/index.tsx +479 -0
- package/dist/components/dropdown/meta.ts +21 -0
- package/dist/components/form/Form.stories.tsx +320 -0
- package/dist/components/form/index.tsx +183 -0
- package/dist/components/form/meta.ts +11 -0
- package/dist/components/helper-text/HelperText.stories.tsx +254 -0
- package/dist/components/helper-text/index.tsx +102 -0
- package/dist/components/helper-text/meta.ts +18 -0
- package/dist/components/hover-card/HoverCard.stories.tsx +1328 -0
- package/dist/components/hover-card/index.tsx +42 -0
- package/dist/components/hover-card/meta.ts +12 -0
- package/dist/components/icon-button/IconButton.stories.tsx +252 -0
- package/dist/components/icon-button/index.tsx +130 -0
- package/dist/components/icon-button/meta.ts +20 -0
- package/dist/components/if-else/if-else.stories.tsx +100 -0
- package/dist/components/if-else/index.tsx +56 -0
- package/dist/components/if-else/meta.ts +6 -0
- package/dist/components/index.ts +70 -0
- package/dist/components/input/Input.stories.tsx +431 -0
- package/dist/components/input/index.tsx +487 -0
- package/dist/components/input/meta.ts +28 -0
- package/dist/components/label/Label.stories.tsx +200 -0
- package/dist/components/label/index.tsx +43 -0
- package/dist/components/label/meta.ts +14 -0
- package/dist/components/list/List.stories.tsx +963 -0
- package/dist/components/list/index.tsx +567 -0
- package/dist/components/list/meta.ts +24 -0
- package/dist/components/marquee/Marquee.stories.tsx +819 -0
- package/dist/components/marquee/index.tsx +107 -0
- package/dist/components/marquee/meta.ts +6 -0
- package/dist/components/overlay/Overlay.stories.tsx +954 -0
- package/dist/components/overlay/index.tsx +58 -0
- package/dist/components/overlay/meta.ts +10 -0
- package/dist/components/pagination/Pagination.stories.tsx +354 -0
- package/dist/components/pagination/index.tsx +455 -0
- package/dist/components/pagination/meta.ts +29 -0
- package/dist/components/popover/Popover.stories.tsx +1037 -0
- package/dist/components/popover/index.tsx +67 -0
- package/dist/components/popover/meta.ts +12 -0
- package/dist/components/radio/Radio.stories.tsx +146 -0
- package/dist/components/radio/index.tsx +41 -0
- package/dist/components/radio/meta.ts +19 -0
- package/dist/components/resizable/Resizable.stories.tsx +866 -0
- package/dist/components/resizable/index.tsx +55 -0
- package/dist/components/resizable/meta.ts +12 -0
- package/dist/components/scroll-area/ScrollArea.stories.tsx +1104 -0
- package/dist/components/scroll-area/index.tsx +55 -0
- package/dist/components/scroll-area/meta.ts +8 -0
- package/dist/components/search/Search.stories.tsx +678 -0
- package/dist/components/search/index.tsx +141 -0
- package/dist/components/search/meta.ts +6 -0
- package/dist/components/select/Select.stories.tsx +962 -0
- package/dist/components/select/index.tsx +512 -0
- package/dist/components/select/meta.ts +40 -0
- package/dist/components/sheet/Sheet.stories.tsx +1060 -0
- package/dist/components/sheet/index.tsx +440 -0
- package/dist/components/sheet/meta.ts +38 -0
- package/dist/components/skelton/Skelton.stories.tsx +859 -0
- package/dist/components/skelton/index.tsx +17 -0
- package/dist/components/skelton/meta.ts +6 -0
- package/dist/components/slider/Slider.stories.tsx +876 -0
- package/dist/components/slider/index.tsx +156 -0
- package/dist/components/slider/meta.ts +29 -0
- package/dist/components/stepper/Stepper.stories.tsx +639 -0
- package/dist/components/stepper/index.tsx +650 -0
- package/dist/components/stepper/meta.ts +19 -0
- package/dist/components/switch/Switch.stories.tsx +85 -0
- package/dist/components/switch/index.tsx +37 -0
- package/dist/components/switch/meta.ts +24 -0
- package/dist/components/switch-case/SwitchCase.stories.tsx +209 -0
- package/dist/components/switch-case/index.tsx +89 -0
- package/dist/components/switch-case/meta.ts +6 -0
- package/dist/components/table/Table.stories.tsx +1095 -0
- package/dist/components/table/index.tsx +113 -0
- package/dist/components/table/meta.ts +20 -0
- package/dist/components/tabs/Tabs.stories.tsx +1379 -0
- package/dist/components/tabs/index.tsx +186 -0
- package/dist/components/tabs/meta.ts +25 -0
- package/dist/components/tag/Tag.stories.tsx +625 -0
- package/dist/components/tag/index.tsx +320 -0
- package/dist/components/tag/meta.ts +52 -0
- package/dist/components/textarea/TextArea.stories.tsx +723 -0
- package/dist/components/textarea/index.tsx +480 -0
- package/dist/components/textarea/meta.ts +23 -0
- package/dist/components/toast/Toast.stories.tsx +1427 -0
- package/dist/components/toast/index.tsx +26 -0
- package/dist/components/toast/meta.ts +19 -0
- package/dist/components/toggle/Toggle.stories.tsx +1093 -0
- package/dist/components/toggle/index.tsx +44 -0
- package/dist/components/toggle/meta.ts +19 -0
- package/dist/components/tooltip/Tooltip.stories.tsx +1548 -0
- package/dist/components/tooltip/index.tsx +304 -0
- package/dist/components/tooltip/meta.ts +21 -0
- package/dist/components/typography/Typography.stories.tsx +197 -0
- package/dist/components/typography/index.tsx +184 -0
- package/dist/components/typography/meta.ts +38 -0
- package/dist/fonts/LabGrotesque-Regular.ttf +0 -0
- package/dist/fonts/LabGrotesqueTRIAL-Bold.otf +0 -0
- package/dist/fonts/LabGrotesqueTRIAL-Light.otf +0 -0
- package/dist/fonts/LabGrotesqueTRIAL-Medium.otf +0 -0
- package/dist/fonts/LabGrotesqueTRIAL-Regular.otf +0 -0
- package/dist/fonts/PPSupplySans-Regular (1).otf +0 -0
- package/dist/fonts/PPSupplySans-Regular.otf +0 -0
- package/dist/fonts/PPSupplySans-Ultralight.otf +0 -0
- package/dist/hooks/index.ts +3 -0
- package/dist/hooks/use-previous/UsePrevious.stories.tsx +997 -0
- package/dist/hooks/use-previous/index.ts +15 -0
- package/dist/hooks/use-previous/meta.ts +6 -0
- package/dist/hooks/use-standalone-pagination/UseStandalonePagination.stories.tsx +983 -0
- package/dist/hooks/use-standalone-pagination/index.ts +146 -0
- package/dist/hooks/use-standalone-pagination/meta.ts +6 -0
- package/dist/icons/Icons.stories.tsx +29 -0
- package/dist/icons/alert-icon/AlertIcon.stories.tsx +991 -0
- package/dist/icons/alert-icon/index.tsx +48 -0
- package/dist/icons/alert-icon/meta.ts +8 -0
- package/dist/icons/all-icons.tsx +738 -0
- package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +1031 -0
- package/dist/icons/angle-down-icon/index.tsx +25 -0
- package/dist/icons/angle-down-icon/meta.ts +8 -0
- package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +1080 -0
- package/dist/icons/arrow-box-left-icon/index.tsx +24 -0
- package/dist/icons/arrow-box-left-icon/meta.ts +8 -0
- package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +1151 -0
- package/dist/icons/arrow-right-icon/index.tsx +26 -0
- package/dist/icons/arrow-right-icon/meta.ts +8 -0
- package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +1273 -0
- package/dist/icons/arrow-right-up-icon/index.tsx +24 -0
- package/dist/icons/arrow-right-up-icon/meta.ts +8 -0
- package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +670 -0
- package/dist/icons/art-board-icon/index.tsx +24 -0
- package/dist/icons/art-board-icon/meta.ts +7 -0
- package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +1244 -0
- package/dist/icons/audio-bar-icon/index.tsx +19 -0
- package/dist/icons/audio-bar-icon/meta.ts +8 -0
- package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +1239 -0
- package/dist/icons/bubble-check-icon/index.tsx +24 -0
- package/dist/icons/bubble-check-icon/meta.ts +8 -0
- package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +1228 -0
- package/dist/icons/bubble-crossed-icon/index.tsx +24 -0
- package/dist/icons/bubble-crossed-icon/meta.ts +8 -0
- package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +912 -0
- package/dist/icons/bubble-sparkle-icon/index.tsx +26 -0
- package/dist/icons/bubble-sparkle-icon/meta.ts +8 -0
- package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +1021 -0
- package/dist/icons/chevron-double-left-icon/index.tsx +34 -0
- package/dist/icons/chevron-double-left-icon/meta.ts +8 -0
- package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +1021 -0
- package/dist/icons/chevron-double-right-icon/index.tsx +34 -0
- package/dist/icons/chevron-double-right-icon/meta.ts +8 -0
- package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +1001 -0
- package/dist/icons/chevron-down-icon/index.tsx +27 -0
- package/dist/icons/chevron-down-icon/meta.ts +8 -0
- package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +1029 -0
- package/dist/icons/chevron-left-icon/index.tsx +27 -0
- package/dist/icons/chevron-left-icon/meta.ts +8 -0
- package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +1021 -0
- package/dist/icons/chevron-right-icon/index.tsx +27 -0
- package/dist/icons/chevron-right-icon/meta.ts +8 -0
- package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +1036 -0
- package/dist/icons/chevron-up-icon/index.tsx +27 -0
- package/dist/icons/chevron-up-icon/meta.ts +8 -0
- package/dist/icons/command-icon/CommandIcon.stories.tsx +1098 -0
- package/dist/icons/command-icon/index.tsx +24 -0
- package/dist/icons/command-icon/meta.ts +8 -0
- package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +1061 -0
- package/dist/icons/cross-circle-icon/index.tsx +23 -0
- package/dist/icons/cross-circle-icon/meta.ts +8 -0
- package/dist/icons/cross-icon/CrossIcon.stories.tsx +1027 -0
- package/dist/icons/cross-icon/index.tsx +24 -0
- package/dist/icons/cross-icon/meta.ts +8 -0
- package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +1092 -0
- package/dist/icons/edit-big-icon/index.tsx +22 -0
- package/dist/icons/edit-big-icon/meta.ts +8 -0
- package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +1090 -0
- package/dist/icons/eye-close-icon/index.tsx +26 -0
- package/dist/icons/eye-close-icon/meta.ts +8 -0
- package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +1098 -0
- package/dist/icons/eye-open-icon/index.tsx +24 -0
- package/dist/icons/eye-open-icon/meta.ts +8 -0
- package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +1071 -0
- package/dist/icons/feature-shine-icon/index.tsx +29 -0
- package/dist/icons/feature-shine-icon/meta.ts +8 -0
- package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +1115 -0
- package/dist/icons/file-chart-icon/index.tsx +24 -0
- package/dist/icons/file-chart-icon/meta.ts +8 -0
- package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +668 -0
- package/dist/icons/file-text-icon/index.tsx +24 -0
- package/dist/icons/file-text-icon/meta.ts +8 -0
- package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +1239 -0
- package/dist/icons/grip-vertical-icon/index.tsx +28 -0
- package/dist/icons/grip-vertical-icon/meta.ts +8 -0
- package/dist/icons/image-icon/ImageIcon.stories.tsx +1181 -0
- package/dist/icons/image-icon/index.tsx +24 -0
- package/dist/icons/image-icon/meta.ts +8 -0
- package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +1248 -0
- package/dist/icons/import-folder-icon/index.tsx +22 -0
- package/dist/icons/import-folder-icon/meta.ts +8 -0
- package/dist/icons/index.ts +46 -0
- package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +1272 -0
- package/dist/icons/light-bulb-simple-icon/index.tsx +24 -0
- package/dist/icons/light-bulb-simple-icon/meta.ts +8 -0
- package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +1245 -0
- package/dist/icons/magic-book-icon/index.tsx +32 -0
- package/dist/icons/magic-book-icon/meta.ts +8 -0
- package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +1251 -0
- package/dist/icons/maintenance-icon/index.tsx +23 -0
- package/dist/icons/maintenance-icon/meta.ts +8 -0
- package/dist/icons/message-icon/MessageIcon.stories.tsx +595 -0
- package/dist/icons/message-icon/index.tsx +30 -0
- package/dist/icons/message-icon/meta.ts +8 -0
- package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +1245 -0
- package/dist/icons/move-horizontal-icon/index.tsx +23 -0
- package/dist/icons/move-horizontal-icon/meta.ts +8 -0
- package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +1196 -0
- package/dist/icons/move-vertical-icon/index.tsx +23 -0
- package/dist/icons/move-vertical-icon/meta.ts +8 -0
- package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +1167 -0
- package/dist/icons/page-search-icon/index.tsx +21 -0
- package/dist/icons/page-search-icon/meta.ts +8 -0
- package/dist/icons/pencil-icon/PencilIcon.stories.tsx +1131 -0
- package/dist/icons/pencil-icon/index.tsx +21 -0
- package/dist/icons/pencil-icon/meta.ts +8 -0
- package/dist/icons/plus-icon/PlusIcon.stories.tsx +1151 -0
- package/dist/icons/plus-icon/index.tsx +24 -0
- package/dist/icons/plus-icon/meta.ts +8 -0
- package/dist/icons/search-icon/SearchIcon.stories.tsx +1181 -0
- package/dist/icons/search-icon/index.tsx +24 -0
- package/dist/icons/search-icon/meta.ts +8 -0
- package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +1167 -0
- package/dist/icons/site-logo-icon/index.tsx +79 -0
- package/dist/icons/site-logo-icon/meta.ts +8 -0
- package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +637 -0
- package/dist/icons/spinner-gradient-icon/index.tsx +53 -0
- package/dist/icons/spinner-gradient-icon/meta.ts +8 -0
- package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +644 -0
- package/dist/icons/spinner-solid-icon/index.tsx +59 -0
- package/dist/icons/spinner-solid-icon/meta.ts +8 -0
- package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +736 -0
- package/dist/icons/spinner-solid-neutral-icon/index.tsx +53 -0
- package/dist/icons/spinner-solid-neutral-icon/meta.ts +8 -0
- package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +1204 -0
- package/dist/icons/tick-circle-icon/index.tsx +23 -0
- package/dist/icons/tick-circle-icon/meta.ts +8 -0
- package/dist/icons/tick-icon/TickIcon.stories.tsx +1340 -0
- package/dist/icons/tick-icon/index.tsx +24 -0
- package/dist/icons/tick-icon/meta.ts +8 -0
- package/dist/icons/trash-icon/TrashIcon.stories.tsx +996 -0
- package/dist/icons/trash-icon/index.tsx +24 -0
- package/dist/icons/trash-icon/meta.ts +8 -0
- package/dist/icons/upload-icon/UploadIcon.stories.tsx +947 -0
- package/dist/icons/upload-icon/index.tsx +24 -0
- package/dist/icons/upload-icon/meta.ts +8 -0
- package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +1045 -0
- package/dist/icons/vertical-menu-icon/index.tsx +27 -0
- package/dist/icons/vertical-menu-icon/meta.ts +8 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +206 -0
- package/dist/lib/utils.ts +6 -0
- package/dist/styles/aural-theme.css +1008 -0
- package/package.json +142 -0
|
@@ -0,0 +1,997 @@
|
|
|
1
|
+
import React, { useCallback, useState } from "react"
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
3
|
+
|
|
4
|
+
// Import the hook (assuming it exists in the index file)
|
|
5
|
+
import { usePrevious } from "."
|
|
6
|
+
|
|
7
|
+
// Example component that uses the hook
|
|
8
|
+
const PreviousValueDemo: React.FC<{
|
|
9
|
+
title?: string
|
|
10
|
+
initialValue?: number
|
|
11
|
+
}> = ({ title = "usePrevious Demo", initialValue = 0 }) => {
|
|
12
|
+
const [value, setValue] = useState(initialValue)
|
|
13
|
+
const [stringValue, setStringValue] = useState("Hello")
|
|
14
|
+
const [boolValue, setBoolValue] = useState(false)
|
|
15
|
+
const [objectValue, setObjectValue] = useState({ count: 0, name: "test" })
|
|
16
|
+
const [arrayValue, setArrayValue] = useState([1, 2, 3])
|
|
17
|
+
|
|
18
|
+
// Use the hook for different value types
|
|
19
|
+
const previousValue = usePrevious(value)
|
|
20
|
+
const previousStringValue = usePrevious(stringValue)
|
|
21
|
+
const previousBoolValue = usePrevious(boolValue)
|
|
22
|
+
const previousObjectValue = usePrevious(objectValue)
|
|
23
|
+
const previousArrayValue = usePrevious(arrayValue)
|
|
24
|
+
|
|
25
|
+
const incrementValue = useCallback(
|
|
26
|
+
() => setValue((prev: number) => prev + 1),
|
|
27
|
+
[]
|
|
28
|
+
)
|
|
29
|
+
const decrementValue = useCallback(
|
|
30
|
+
() => setValue((prev: number) => prev - 1),
|
|
31
|
+
[]
|
|
32
|
+
)
|
|
33
|
+
const randomValue = useCallback(
|
|
34
|
+
() => setValue(Math.floor(Math.random() * 100)),
|
|
35
|
+
[]
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
const toggleBool = useCallback(() => setBoolValue((prev) => !prev), [])
|
|
39
|
+
|
|
40
|
+
const updateObject = useCallback(() => {
|
|
41
|
+
setObjectValue((prev) => ({
|
|
42
|
+
count: prev.count + 1,
|
|
43
|
+
name: `test-${prev.count + 1}`,
|
|
44
|
+
}))
|
|
45
|
+
}, [])
|
|
46
|
+
|
|
47
|
+
const addToArray = useCallback(() => {
|
|
48
|
+
setArrayValue((prev) => [...prev, prev.length + 1])
|
|
49
|
+
}, [])
|
|
50
|
+
|
|
51
|
+
const removeFromArray = useCallback(() => {
|
|
52
|
+
setArrayValue((prev) => prev.slice(0, -1))
|
|
53
|
+
}, [])
|
|
54
|
+
|
|
55
|
+
const stringOptions = ["Hello", "World", "React", "Hook", "Previous", "Value"]
|
|
56
|
+
const updateString = useCallback(() => {
|
|
57
|
+
const randomString =
|
|
58
|
+
stringOptions[Math.floor(Math.random() * stringOptions.length)]
|
|
59
|
+
setStringValue(randomString)
|
|
60
|
+
}, [])
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<div className="!space-y-6 rounded-lg border border-white/10 bg-white/5 !p-6">
|
|
64
|
+
<div className="!space-y-4">
|
|
65
|
+
<h3 className="!text-xl font-semibold !text-white">{title}</h3>
|
|
66
|
+
|
|
67
|
+
{/* Number Value Demo */}
|
|
68
|
+
<div className="rounded-lg border border-blue-500/20 bg-blue-500/10 !p-4">
|
|
69
|
+
<h4 className="!mb-3 !text-lg font-semibold !text-blue-300">
|
|
70
|
+
Number Value
|
|
71
|
+
</h4>
|
|
72
|
+
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
|
73
|
+
<div className="!space-y-2">
|
|
74
|
+
<div className="flex items-center justify-between rounded-lg bg-black/20 !p-3">
|
|
75
|
+
<span className="!text-sm !text-white/70">Current:</span>
|
|
76
|
+
<span className="!text-xl font-bold !text-blue-100">
|
|
77
|
+
{value}
|
|
78
|
+
</span>
|
|
79
|
+
</div>
|
|
80
|
+
<div className="flex items-center justify-between rounded-lg bg-black/20 !p-3">
|
|
81
|
+
<span className="!text-sm !text-white/70">Previous:</span>
|
|
82
|
+
<span className="!text-xl font-bold !text-blue-300">
|
|
83
|
+
{previousValue !== undefined ? previousValue : "undefined"}
|
|
84
|
+
</span>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
<div className="!space-y-2">
|
|
88
|
+
<button
|
|
89
|
+
onClick={incrementValue}
|
|
90
|
+
className="w-full rounded-lg border border-green-500/30 bg-green-500/20 !px-3 !py-2 !text-sm !text-green-300 transition-colors hover:bg-green-500/30"
|
|
91
|
+
>
|
|
92
|
+
Increment (+1)
|
|
93
|
+
</button>
|
|
94
|
+
<button
|
|
95
|
+
onClick={decrementValue}
|
|
96
|
+
className="w-full rounded-lg border border-red-500/30 bg-red-500/20 !px-3 !py-2 !text-sm !text-red-300 transition-colors hover:bg-red-500/30"
|
|
97
|
+
>
|
|
98
|
+
Decrement (-1)
|
|
99
|
+
</button>
|
|
100
|
+
<button
|
|
101
|
+
onClick={randomValue}
|
|
102
|
+
className="w-full rounded-lg border border-purple-500/30 bg-purple-500/20 !px-3 !py-2 !text-sm !text-purple-300 transition-colors hover:bg-purple-500/30"
|
|
103
|
+
>
|
|
104
|
+
Random Value
|
|
105
|
+
</button>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
{/* String Value Demo */}
|
|
111
|
+
<div className="rounded-lg border border-green-500/20 bg-green-500/10 !p-4">
|
|
112
|
+
<h4 className="!mb-3 !text-lg font-semibold !text-green-300">
|
|
113
|
+
String Value
|
|
114
|
+
</h4>
|
|
115
|
+
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
|
116
|
+
<div className="!space-y-2">
|
|
117
|
+
<div className="flex items-center justify-between rounded-lg bg-black/20 !p-3">
|
|
118
|
+
<span className="!text-sm !text-white/70">Current:</span>
|
|
119
|
+
<span className="font-mono !text-green-100">
|
|
120
|
+
"{stringValue}"
|
|
121
|
+
</span>
|
|
122
|
+
</div>
|
|
123
|
+
<div className="flex items-center justify-between rounded-lg bg-black/20 !p-3">
|
|
124
|
+
<span className="!text-sm !text-white/70">Previous:</span>
|
|
125
|
+
<span className="font-mono !text-green-300">
|
|
126
|
+
{previousStringValue !== undefined
|
|
127
|
+
? `"${previousStringValue}"`
|
|
128
|
+
: "undefined"}
|
|
129
|
+
</span>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
<div className="!space-y-2">
|
|
133
|
+
<button
|
|
134
|
+
onClick={updateString}
|
|
135
|
+
className="w-full rounded-lg border border-green-500/30 bg-green-500/20 !px-3 !py-2 !text-sm !text-green-300 transition-colors hover:bg-green-500/30"
|
|
136
|
+
>
|
|
137
|
+
Random String
|
|
138
|
+
</button>
|
|
139
|
+
<input
|
|
140
|
+
type="text"
|
|
141
|
+
value={stringValue}
|
|
142
|
+
onChange={(e) => setStringValue(e.target.value)}
|
|
143
|
+
className="w-full rounded-lg border border-white/20 bg-white/5 !px-3 !py-2 !text-sm !text-white placeholder-white/50"
|
|
144
|
+
placeholder="Type to update..."
|
|
145
|
+
/>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
{/* Boolean Value Demo */}
|
|
151
|
+
<div className="rounded-lg border border-purple-500/20 bg-purple-500/10 !p-4">
|
|
152
|
+
<h4 className="!mb-3 !text-lg font-semibold !text-purple-300">
|
|
153
|
+
Boolean Value
|
|
154
|
+
</h4>
|
|
155
|
+
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
|
156
|
+
<div className="!space-y-2">
|
|
157
|
+
<div className="flex items-center justify-between rounded-lg bg-black/20 !p-3">
|
|
158
|
+
<span className="!text-sm !text-white/70">Current:</span>
|
|
159
|
+
<span
|
|
160
|
+
className={`font-mono !text-lg font-bold ${boolValue ? "!text-green-300" : "!text-red-300"}`}
|
|
161
|
+
>
|
|
162
|
+
{String(boolValue)}
|
|
163
|
+
</span>
|
|
164
|
+
</div>
|
|
165
|
+
<div className="flex items-center justify-between rounded-lg bg-black/20 !p-3">
|
|
166
|
+
<span className="!text-sm !text-white/70">Previous:</span>
|
|
167
|
+
<span className="font-mono !text-purple-300">
|
|
168
|
+
{previousBoolValue !== undefined
|
|
169
|
+
? String(previousBoolValue)
|
|
170
|
+
: "undefined"}
|
|
171
|
+
</span>
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
<div>
|
|
175
|
+
<button
|
|
176
|
+
onClick={toggleBool}
|
|
177
|
+
className={`w-full rounded-lg border !px-4 !py-3 !text-sm font-medium transition-colors ${
|
|
178
|
+
boolValue
|
|
179
|
+
? "border-green-500/30 bg-green-500/20 !text-green-300 hover:bg-green-500/30"
|
|
180
|
+
: "border-red-500/30 bg-red-500/20 !text-red-300 hover:bg-red-500/30"
|
|
181
|
+
}`}
|
|
182
|
+
>
|
|
183
|
+
Toggle: {boolValue ? "ON" : "OFF"}
|
|
184
|
+
</button>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
|
|
189
|
+
{/* Object Value Demo */}
|
|
190
|
+
<div className="rounded-lg border border-orange-500/20 bg-orange-500/10 !p-4">
|
|
191
|
+
<h4 className="!mb-3 !text-lg font-semibold !text-orange-300">
|
|
192
|
+
Object Value
|
|
193
|
+
</h4>
|
|
194
|
+
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
|
195
|
+
<div className="!space-y-2">
|
|
196
|
+
<div className="rounded-lg bg-black/20 !p-3">
|
|
197
|
+
<div className="!mb-1 !text-sm !text-white/70">Current:</div>
|
|
198
|
+
<pre className="overflow-x-auto !text-xs !text-orange-100">
|
|
199
|
+
{JSON.stringify(objectValue, null, 2)}
|
|
200
|
+
</pre>
|
|
201
|
+
</div>
|
|
202
|
+
<div className="rounded-lg bg-black/20 !p-3">
|
|
203
|
+
<div className="!mb-1 !text-sm !text-white/70">Previous:</div>
|
|
204
|
+
<pre className="overflow-x-auto !text-xs !text-orange-300">
|
|
205
|
+
{previousObjectValue !== undefined
|
|
206
|
+
? JSON.stringify(previousObjectValue, null, 2)
|
|
207
|
+
: "undefined"}
|
|
208
|
+
</pre>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
<div>
|
|
212
|
+
<button
|
|
213
|
+
onClick={updateObject}
|
|
214
|
+
className="w-full rounded-lg border border-orange-500/30 bg-orange-500/20 !px-3 !py-2 !text-sm !text-orange-300 transition-colors hover:bg-orange-500/30"
|
|
215
|
+
>
|
|
216
|
+
Update Object
|
|
217
|
+
</button>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
|
|
222
|
+
{/* Array Value Demo */}
|
|
223
|
+
<div className="rounded-lg border border-cyan-500/20 bg-cyan-500/10 !p-4">
|
|
224
|
+
<h4 className="!mb-3 !text-lg font-semibold !text-cyan-300">
|
|
225
|
+
Array Value
|
|
226
|
+
</h4>
|
|
227
|
+
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
|
228
|
+
<div className="!space-y-2">
|
|
229
|
+
<div className="rounded-lg bg-black/20 !p-3">
|
|
230
|
+
<div className="!mb-1 !text-sm !text-white/70">Current:</div>
|
|
231
|
+
<div className="font-mono !text-cyan-100">
|
|
232
|
+
[{arrayValue.join(", ")}]
|
|
233
|
+
</div>
|
|
234
|
+
<div className="!mt-1 !text-xs !text-white/50">
|
|
235
|
+
Length: {arrayValue.length}
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
<div className="rounded-lg bg-black/20 !p-3">
|
|
239
|
+
<div className="!mb-1 !text-sm !text-white/70">Previous:</div>
|
|
240
|
+
<div className="font-mono !text-cyan-300">
|
|
241
|
+
{previousArrayValue !== undefined
|
|
242
|
+
? `[${previousArrayValue.join(", ")}]`
|
|
243
|
+
: "undefined"}
|
|
244
|
+
</div>
|
|
245
|
+
<div className="!mt-1 !text-xs !text-white/50">
|
|
246
|
+
Length:{" "}
|
|
247
|
+
{previousArrayValue ? previousArrayValue.length : "N/A"}
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
</div>
|
|
251
|
+
<div className="!space-y-2">
|
|
252
|
+
<button
|
|
253
|
+
onClick={addToArray}
|
|
254
|
+
className="w-full rounded-lg border border-cyan-500/30 bg-cyan-500/20 !px-3 !py-2 !text-sm !text-cyan-300 transition-colors hover:bg-cyan-500/30"
|
|
255
|
+
>
|
|
256
|
+
Add Item
|
|
257
|
+
</button>
|
|
258
|
+
<button
|
|
259
|
+
onClick={removeFromArray}
|
|
260
|
+
disabled={arrayValue.length === 0}
|
|
261
|
+
className="w-full rounded-lg border border-red-500/30 bg-red-500/20 !px-3 !py-2 !text-sm !text-red-300 transition-colors hover:bg-red-500/30 disabled:cursor-not-allowed disabled:opacity-50"
|
|
262
|
+
>
|
|
263
|
+
Remove Item
|
|
264
|
+
</button>
|
|
265
|
+
</div>
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
|
|
269
|
+
{/* Usage Information */}
|
|
270
|
+
<div className="rounded-lg border border-white/10 bg-black/20 !p-4">
|
|
271
|
+
<h4 className="!mb-3 !text-lg font-semibold !text-white">
|
|
272
|
+
Hook Usage
|
|
273
|
+
</h4>
|
|
274
|
+
<div className="!space-y-2 !text-sm">
|
|
275
|
+
<div className="!text-white/70">
|
|
276
|
+
<span className="font-medium !text-white">Pattern:</span> const
|
|
277
|
+
previousValue = usePrevious(currentValue)
|
|
278
|
+
</div>
|
|
279
|
+
<div className="!text-white/70">
|
|
280
|
+
<span className="font-medium !text-white">Returns:</span> The
|
|
281
|
+
previous value from the last render, or undefined on first render
|
|
282
|
+
</div>
|
|
283
|
+
<div className="!text-white/70">
|
|
284
|
+
<span className="font-medium !text-white">Use cases:</span>{" "}
|
|
285
|
+
Comparing values, animations, tracking changes, debugging
|
|
286
|
+
</div>
|
|
287
|
+
</div>
|
|
288
|
+
</div>
|
|
289
|
+
</div>
|
|
290
|
+
</div>
|
|
291
|
+
)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const meta: Meta<typeof PreviousValueDemo> = {
|
|
295
|
+
title: "Hooks/usePrevious",
|
|
296
|
+
component: PreviousValueDemo,
|
|
297
|
+
parameters: {
|
|
298
|
+
layout: "fullscreen",
|
|
299
|
+
backgrounds: {
|
|
300
|
+
default: "dark",
|
|
301
|
+
values: [
|
|
302
|
+
{ name: "dark", value: "#0a0a0a" },
|
|
303
|
+
{ name: "darker", value: "#000000" },
|
|
304
|
+
{ name: "light", value: "#ffffff" },
|
|
305
|
+
],
|
|
306
|
+
},
|
|
307
|
+
docs: {
|
|
308
|
+
page: () => (
|
|
309
|
+
<>
|
|
310
|
+
{/* Override default docs styling */}
|
|
311
|
+
<style>
|
|
312
|
+
{`
|
|
313
|
+
.sbdocs-wrapper {
|
|
314
|
+
padding: 0 !important;
|
|
315
|
+
max-width: none !important;
|
|
316
|
+
background: transparent !important;
|
|
317
|
+
}
|
|
318
|
+
.sbdocs-content {
|
|
319
|
+
max-width: none !important;
|
|
320
|
+
padding: 0 !important;
|
|
321
|
+
margin: 0 !important;
|
|
322
|
+
background: transparent !important;
|
|
323
|
+
}
|
|
324
|
+
.docs-story {
|
|
325
|
+
background: transparent !important;
|
|
326
|
+
}
|
|
327
|
+
.sbdocs {
|
|
328
|
+
background: transparent !important;
|
|
329
|
+
}
|
|
330
|
+
body {
|
|
331
|
+
background: #0a0a0a !important;
|
|
332
|
+
}
|
|
333
|
+
#storybook-docs {
|
|
334
|
+
background: #0a0a0a !important;
|
|
335
|
+
}
|
|
336
|
+
.sbdocs-preview {
|
|
337
|
+
background: transparent !important;
|
|
338
|
+
border: none !important;
|
|
339
|
+
}
|
|
340
|
+
.sbdocs-h1, .sbdocs-h2, .sbdocs-h3, .sbdocs-h4, .sbdocs-h5, .sbdocs-h6 {
|
|
341
|
+
color: white !important;
|
|
342
|
+
}
|
|
343
|
+
.sbdocs-p, .sbdocs-li {
|
|
344
|
+
color: rgba(255, 255, 255, 0.7) !important;
|
|
345
|
+
}
|
|
346
|
+
.sbdocs-code {
|
|
347
|
+
background: rgba(255, 255, 255, 0.1) !important;
|
|
348
|
+
color: rgba(168, 85, 247, 1) !important;
|
|
349
|
+
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
|
350
|
+
}
|
|
351
|
+
.sbdocs-pre {
|
|
352
|
+
background: rgba(0, 0, 0, 0.4) !important;
|
|
353
|
+
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
|
354
|
+
}
|
|
355
|
+
.sbdocs-table {
|
|
356
|
+
background: rgba(255, 255, 255, 0.05) !important;
|
|
357
|
+
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
|
358
|
+
}
|
|
359
|
+
.sbdocs-table th {
|
|
360
|
+
background: rgba(255, 255, 255, 0.05) !important;
|
|
361
|
+
color: white !important;
|
|
362
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important;
|
|
363
|
+
}
|
|
364
|
+
.sbdocs-table td {
|
|
365
|
+
color: rgba(255, 255, 255, 0.7) !important;
|
|
366
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.05) !important;
|
|
367
|
+
}
|
|
368
|
+
`}
|
|
369
|
+
</style>
|
|
370
|
+
|
|
371
|
+
<div className="min-h-screen bg-gradient-to-br from-gray-900 via-purple-900/20 to-gray-900">
|
|
372
|
+
{/* Header */}
|
|
373
|
+
<div className="relative overflow-hidden border-b border-white/10 bg-black/20 backdrop-blur-xl">
|
|
374
|
+
<div className="absolute inset-0 bg-gradient-to-r from-purple-500/10 via-transparent to-indigo-500/10" />
|
|
375
|
+
<div className="relative !mx-auto max-w-7xl !px-6 !py-16">
|
|
376
|
+
<div className="!space-y-6 text-center">
|
|
377
|
+
<div className="!mx-auto flex !h-24 !w-24 items-center justify-center rounded-2xl border border-purple-500/30 bg-gradient-to-br from-purple-500/20 to-indigo-500/20">
|
|
378
|
+
<span className="!text-4xl">⏮️</span>
|
|
379
|
+
</div>
|
|
380
|
+
<h1 className="!text-fm-primary !text-5xl font-bold">
|
|
381
|
+
usePrevious
|
|
382
|
+
</h1>
|
|
383
|
+
<p className="!mx-auto max-w-3xl !text-xl leading-relaxed !text-white/70">
|
|
384
|
+
A simple yet powerful React hook that captures and returns
|
|
385
|
+
the previous value of any variable. Essential for tracking
|
|
386
|
+
changes, implementing smooth transitions, and debugging
|
|
387
|
+
state updates.
|
|
388
|
+
</p>
|
|
389
|
+
|
|
390
|
+
{/* Stats */}
|
|
391
|
+
<div className="flex items-center justify-center gap-8 !pt-8">
|
|
392
|
+
<div className="text-center">
|
|
393
|
+
<div className="!text-3xl font-bold !text-purple-300">
|
|
394
|
+
Simple
|
|
395
|
+
</div>
|
|
396
|
+
<div className="!text-sm !text-white/60">
|
|
397
|
+
Easy to use API
|
|
398
|
+
</div>
|
|
399
|
+
</div>
|
|
400
|
+
<div className="!h-8 !w-px bg-white/20" />
|
|
401
|
+
<div className="text-center">
|
|
402
|
+
<div className="!text-3xl font-bold !text-indigo-300">
|
|
403
|
+
Universal
|
|
404
|
+
</div>
|
|
405
|
+
<div className="!text-sm !text-white/60">
|
|
406
|
+
Works with any type
|
|
407
|
+
</div>
|
|
408
|
+
</div>
|
|
409
|
+
<div className="!h-8 !w-px bg-white/20" />
|
|
410
|
+
<div className="text-center">
|
|
411
|
+
<div className="!text-3xl font-bold !text-cyan-300">
|
|
412
|
+
Lightweight
|
|
413
|
+
</div>
|
|
414
|
+
<div className="!text-sm !text-white/60">
|
|
415
|
+
Minimal overhead
|
|
416
|
+
</div>
|
|
417
|
+
</div>
|
|
418
|
+
</div>
|
|
419
|
+
</div>
|
|
420
|
+
</div>
|
|
421
|
+
</div>
|
|
422
|
+
|
|
423
|
+
{/* Content */}
|
|
424
|
+
<div className="!mx-auto max-w-7xl !space-y-16 !px-6 !py-12">
|
|
425
|
+
{/* Quick Usage */}
|
|
426
|
+
<div className="!space-y-8">
|
|
427
|
+
<h2 className="text-center !text-3xl font-bold !text-white">
|
|
428
|
+
Quick Start
|
|
429
|
+
</h2>
|
|
430
|
+
<div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
|
|
431
|
+
<div className="!space-y-4">
|
|
432
|
+
<h3 className="!text-xl font-semibold !text-purple-300">
|
|
433
|
+
Basic Usage
|
|
434
|
+
</h3>
|
|
435
|
+
<div className="rounded-lg bg-black/40 !p-4">
|
|
436
|
+
<pre className="overflow-x-auto !text-sm !text-green-300">
|
|
437
|
+
{`import { usePrevious } from "@hooks/use-previous"
|
|
438
|
+
|
|
439
|
+
function MyComponent() {
|
|
440
|
+
const [count, setCount] = useState(0)
|
|
441
|
+
const [name, setName] = useState("John")
|
|
442
|
+
|
|
443
|
+
// Get previous values
|
|
444
|
+
const previousCount = usePrevious(count)
|
|
445
|
+
const previousName = usePrevious(name)
|
|
446
|
+
|
|
447
|
+
return (
|
|
448
|
+
<div>
|
|
449
|
+
<div>
|
|
450
|
+
Count: {count} (was: {previousCount ?? "N/A"})
|
|
451
|
+
</div>
|
|
452
|
+
<div>
|
|
453
|
+
Name: {name} (was: {previousName ?? "N/A"})
|
|
454
|
+
</div>
|
|
455
|
+
|
|
456
|
+
<button onClick={() => setCount(c => c + 1)}>
|
|
457
|
+
Increment
|
|
458
|
+
</button>
|
|
459
|
+
<button onClick={() => setName("Jane")}>
|
|
460
|
+
Change Name
|
|
461
|
+
</button>
|
|
462
|
+
</div>
|
|
463
|
+
)
|
|
464
|
+
}`}
|
|
465
|
+
</pre>
|
|
466
|
+
</div>
|
|
467
|
+
</div>
|
|
468
|
+
|
|
469
|
+
<div className="!space-y-4">
|
|
470
|
+
<h3 className="!text-xl font-semibold !text-purple-300">
|
|
471
|
+
Hook Properties
|
|
472
|
+
</h3>
|
|
473
|
+
<div className="!space-y-3 rounded-lg border border-white/10 bg-white/5 !p-4">
|
|
474
|
+
<div className="flex justify-between">
|
|
475
|
+
<span className="!text-sm !text-white/70">Input:</span>
|
|
476
|
+
<span className="!text-sm font-medium !text-white">
|
|
477
|
+
Any value
|
|
478
|
+
</span>
|
|
479
|
+
</div>
|
|
480
|
+
<div className="flex justify-between">
|
|
481
|
+
<span className="!text-sm !text-white/70">Output:</span>
|
|
482
|
+
<span className="!text-sm font-medium !text-white">
|
|
483
|
+
Previous value
|
|
484
|
+
</span>
|
|
485
|
+
</div>
|
|
486
|
+
<div className="flex justify-between">
|
|
487
|
+
<span className="!text-sm !text-white/70">
|
|
488
|
+
First render:
|
|
489
|
+
</span>
|
|
490
|
+
<span className="!text-sm font-medium !text-white">
|
|
491
|
+
undefined
|
|
492
|
+
</span>
|
|
493
|
+
</div>
|
|
494
|
+
<div className="flex justify-between">
|
|
495
|
+
<span className="!text-sm !text-white/70">Memory:</span>
|
|
496
|
+
<span className="!text-sm font-medium !text-white">
|
|
497
|
+
One reference
|
|
498
|
+
</span>
|
|
499
|
+
</div>
|
|
500
|
+
</div>
|
|
501
|
+
</div>
|
|
502
|
+
</div>
|
|
503
|
+
</div>
|
|
504
|
+
|
|
505
|
+
{/* API Documentation */}
|
|
506
|
+
<div className="!space-y-8">
|
|
507
|
+
<h2 className="text-center !text-3xl font-bold !text-white">
|
|
508
|
+
API Reference
|
|
509
|
+
</h2>
|
|
510
|
+
|
|
511
|
+
<div className="overflow-hidden rounded-lg border border-white/10 bg-white/5">
|
|
512
|
+
<div className="bg-white/5 !p-4">
|
|
513
|
+
<h3 className="!text-xl font-semibold !text-white">
|
|
514
|
+
Hook Signature
|
|
515
|
+
</h3>
|
|
516
|
+
</div>
|
|
517
|
+
<div className="!p-6">
|
|
518
|
+
<div className="rounded-lg bg-black/40 !p-4">
|
|
519
|
+
<pre className="!text-sm !text-green-300">
|
|
520
|
+
{`function usePrevious<T>(value: T): T | undefined`}
|
|
521
|
+
</pre>
|
|
522
|
+
</div>
|
|
523
|
+
</div>
|
|
524
|
+
</div>
|
|
525
|
+
|
|
526
|
+
<div className="overflow-hidden rounded-lg border border-white/10 bg-white/5">
|
|
527
|
+
<div className="bg-white/5 !p-4">
|
|
528
|
+
<h3 className="!text-xl font-semibold !text-white">
|
|
529
|
+
Parameters & Return
|
|
530
|
+
</h3>
|
|
531
|
+
</div>
|
|
532
|
+
<table className="!my-0 w-full">
|
|
533
|
+
<thead className="bg-white/5">
|
|
534
|
+
<tr className="border-b border-white/10">
|
|
535
|
+
<th className="!px-6 !py-4 text-left !text-sm font-semibold !text-white">
|
|
536
|
+
Parameter
|
|
537
|
+
</th>
|
|
538
|
+
<th className="!px-6 !py-4 text-left !text-sm font-semibold !text-white">
|
|
539
|
+
Type
|
|
540
|
+
</th>
|
|
541
|
+
<th className="!px-6 !py-4 text-left !text-sm font-semibold !text-white">
|
|
542
|
+
Description
|
|
543
|
+
</th>
|
|
544
|
+
</tr>
|
|
545
|
+
</thead>
|
|
546
|
+
<tbody>
|
|
547
|
+
<tr className="border-b border-white/5">
|
|
548
|
+
<td className="!px-6 !py-4 font-mono !text-sm !text-purple-300">
|
|
549
|
+
value
|
|
550
|
+
</td>
|
|
551
|
+
<td className="!px-6 !py-4 !text-sm !text-white/70">
|
|
552
|
+
T (generic)
|
|
553
|
+
</td>
|
|
554
|
+
<td className="!px-6 !py-4 !text-sm !text-white/70">
|
|
555
|
+
The current value to track
|
|
556
|
+
</td>
|
|
557
|
+
</tr>
|
|
558
|
+
<tr className="!bg-black/10">
|
|
559
|
+
<td className="!px-6 !py-4 font-mono !text-sm !text-purple-300">
|
|
560
|
+
returns
|
|
561
|
+
</td>
|
|
562
|
+
<td className="!px-6 !py-4 !text-sm !text-white/70">
|
|
563
|
+
T | undefined
|
|
564
|
+
</td>
|
|
565
|
+
<td className="!px-6 !py-4 !text-sm !text-white/70">
|
|
566
|
+
Previous value from last render, undefined on first
|
|
567
|
+
render
|
|
568
|
+
</td>
|
|
569
|
+
</tr>
|
|
570
|
+
</tbody>
|
|
571
|
+
</table>
|
|
572
|
+
</div>
|
|
573
|
+
</div>
|
|
574
|
+
|
|
575
|
+
{/* Use Cases */}
|
|
576
|
+
<div className="!space-y-8">
|
|
577
|
+
<h2 className="text-center !text-3xl font-bold !text-white">
|
|
578
|
+
Common Use Cases
|
|
579
|
+
</h2>
|
|
580
|
+
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
|
581
|
+
<div className="rounded-lg border border-white/10 bg-white/5 !p-6">
|
|
582
|
+
<div className="!mb-4 flex !h-12 !w-12 items-center justify-center rounded-lg bg-blue-500/20">
|
|
583
|
+
<span className="!text-2xl">📊</span>
|
|
584
|
+
</div>
|
|
585
|
+
<h3 className="!mb-2 !text-lg font-semibold !text-white">
|
|
586
|
+
Value Comparison
|
|
587
|
+
</h3>
|
|
588
|
+
<p className="!text-sm !text-white/70">
|
|
589
|
+
Compare current and previous values to detect changes and
|
|
590
|
+
trigger side effects.
|
|
591
|
+
</p>
|
|
592
|
+
</div>
|
|
593
|
+
|
|
594
|
+
<div className="rounded-lg border border-white/10 bg-white/5 !p-6">
|
|
595
|
+
<div className="!mb-4 flex !h-12 !w-12 items-center justify-center rounded-lg bg-green-500/20">
|
|
596
|
+
<span className="!text-2xl">🎬</span>
|
|
597
|
+
</div>
|
|
598
|
+
<h3 className="!mb-2 !text-lg font-semibold !text-white">
|
|
599
|
+
Animations
|
|
600
|
+
</h3>
|
|
601
|
+
<p className="!text-sm !text-white/70">
|
|
602
|
+
Create smooth transitions by animating between previous
|
|
603
|
+
and current values.
|
|
604
|
+
</p>
|
|
605
|
+
</div>
|
|
606
|
+
|
|
607
|
+
<div className="rounded-lg border border-white/10 bg-white/5 !p-6">
|
|
608
|
+
<div className="!mb-4 flex !h-12 !w-12 items-center justify-center rounded-lg bg-purple-500/20">
|
|
609
|
+
<span className="!text-2xl">🐛</span>
|
|
610
|
+
</div>
|
|
611
|
+
<h3 className="!mb-2 !text-lg font-semibold !text-white">
|
|
612
|
+
Debugging
|
|
613
|
+
</h3>
|
|
614
|
+
<p className="!text-sm !text-white/70">
|
|
615
|
+
Track state changes during development to understand
|
|
616
|
+
component behavior.
|
|
617
|
+
</p>
|
|
618
|
+
</div>
|
|
619
|
+
|
|
620
|
+
<div className="rounded-lg border border-white/10 bg-white/5 !p-6">
|
|
621
|
+
<div className="!mb-4 flex !h-12 !w-12 items-center justify-center rounded-lg bg-orange-500/20">
|
|
622
|
+
<span className="!text-2xl">🔄</span>
|
|
623
|
+
</div>
|
|
624
|
+
<h3 className="!mb-2 !text-lg font-semibold !text-white">
|
|
625
|
+
Undo/Redo
|
|
626
|
+
</h3>
|
|
627
|
+
<p className="!text-sm !text-white/70">
|
|
628
|
+
Implement simple undo functionality by maintaining
|
|
629
|
+
previous state values.
|
|
630
|
+
</p>
|
|
631
|
+
</div>
|
|
632
|
+
|
|
633
|
+
<div className="rounded-lg border border-white/10 bg-white/5 !p-6">
|
|
634
|
+
<div className="!mb-4 flex !h-12 !w-12 items-center justify-center rounded-lg bg-cyan-500/20">
|
|
635
|
+
<span className="!text-2xl">📈</span>
|
|
636
|
+
</div>
|
|
637
|
+
<h3 className="!mb-2 !text-lg font-semibold !text-white">
|
|
638
|
+
Change Tracking
|
|
639
|
+
</h3>
|
|
640
|
+
<p className="!text-sm !text-white/70">
|
|
641
|
+
Monitor value changes for analytics, logging, or
|
|
642
|
+
validation purposes.
|
|
643
|
+
</p>
|
|
644
|
+
</div>
|
|
645
|
+
|
|
646
|
+
<div className="rounded-lg border border-white/10 bg-white/5 !p-6">
|
|
647
|
+
<div className="!mb-4 flex !h-12 !w-12 items-center justify-center rounded-lg bg-pink-500/20">
|
|
648
|
+
<span className="!text-2xl">⚡</span>
|
|
649
|
+
</div>
|
|
650
|
+
<h3 className="!mb-2 !text-lg font-semibold !text-white">
|
|
651
|
+
Performance
|
|
652
|
+
</h3>
|
|
653
|
+
<p className="!text-sm !text-white/70">
|
|
654
|
+
Optimize renders by comparing previous values before
|
|
655
|
+
expensive operations.
|
|
656
|
+
</p>
|
|
657
|
+
</div>
|
|
658
|
+
</div>
|
|
659
|
+
</div>
|
|
660
|
+
|
|
661
|
+
{/* Usage Patterns */}
|
|
662
|
+
<div className="!space-y-8">
|
|
663
|
+
<h2 className="text-center !text-3xl font-bold !text-white">
|
|
664
|
+
Usage Patterns
|
|
665
|
+
</h2>
|
|
666
|
+
<div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
|
|
667
|
+
<div className="!space-y-4">
|
|
668
|
+
<h3 className="!text-xl font-semibold !text-purple-300">
|
|
669
|
+
Conditional Effects
|
|
670
|
+
</h3>
|
|
671
|
+
<div className="rounded-lg bg-black/40 !p-4">
|
|
672
|
+
<pre className="overflow-x-auto !text-sm !text-green-300">
|
|
673
|
+
{`function UserProfile({ userId }) {
|
|
674
|
+
const [user, setUser] = useState(null)
|
|
675
|
+
const previousUserId = usePrevious(userId)
|
|
676
|
+
|
|
677
|
+
useEffect(() => {
|
|
678
|
+
// Only fetch if userId actually changed
|
|
679
|
+
if (userId !== previousUserId) {
|
|
680
|
+
fetchUser(userId).then(setUser)
|
|
681
|
+
}
|
|
682
|
+
}, [userId, previousUserId])
|
|
683
|
+
|
|
684
|
+
return <div>{user?.name}</div>
|
|
685
|
+
}`}
|
|
686
|
+
</pre>
|
|
687
|
+
</div>
|
|
688
|
+
</div>
|
|
689
|
+
|
|
690
|
+
<div className="!space-y-4">
|
|
691
|
+
<h3 className="!text-xl font-semibold !text-purple-300">
|
|
692
|
+
Animation Transitions
|
|
693
|
+
</h3>
|
|
694
|
+
<div className="rounded-lg bg-black/40 !p-4">
|
|
695
|
+
<pre className="overflow-x-auto !text-sm !text-green-300">
|
|
696
|
+
{`function AnimatedCounter({ value }) {
|
|
697
|
+
const previousValue = usePrevious(value)
|
|
698
|
+
const [displayValue, setDisplayValue] = useState(value)
|
|
699
|
+
|
|
700
|
+
useEffect(() => {
|
|
701
|
+
if (previousValue !== undefined) {
|
|
702
|
+
// Animate from previous to current
|
|
703
|
+
animateValue(previousValue, value, setDisplayValue)
|
|
704
|
+
}
|
|
705
|
+
}, [value, previousValue])
|
|
706
|
+
|
|
707
|
+
return <span>{displayValue}</span>
|
|
708
|
+
}`}
|
|
709
|
+
</pre>
|
|
710
|
+
</div>
|
|
711
|
+
</div>
|
|
712
|
+
|
|
713
|
+
<div className="!space-y-4">
|
|
714
|
+
<h3 className="!text-xl font-semibold !text-purple-300">
|
|
715
|
+
Change Detection
|
|
716
|
+
</h3>
|
|
717
|
+
<div className="rounded-lg bg-black/40 !p-4">
|
|
718
|
+
<pre className="overflow-x-auto !text-sm !text-green-300">
|
|
719
|
+
{`function FormField({ value, onChange }) {
|
|
720
|
+
const previousValue = usePrevious(value)
|
|
721
|
+
const [hasChanged, setHasChanged] = useState(false)
|
|
722
|
+
|
|
723
|
+
useEffect(() => {
|
|
724
|
+
if (previousValue !== undefined &&
|
|
725
|
+
previousValue !== value) {
|
|
726
|
+
setHasChanged(true)
|
|
727
|
+
// Log change for analytics
|
|
728
|
+
logFieldChange(previousValue, value)
|
|
729
|
+
}
|
|
730
|
+
}, [value, previousValue])
|
|
731
|
+
|
|
732
|
+
return (
|
|
733
|
+
<input
|
|
734
|
+
value={value}
|
|
735
|
+
onChange={onChange}
|
|
736
|
+
className={hasChanged ? 'changed' : ''}
|
|
737
|
+
/>
|
|
738
|
+
)
|
|
739
|
+
}`}
|
|
740
|
+
</pre>
|
|
741
|
+
</div>
|
|
742
|
+
</div>
|
|
743
|
+
|
|
744
|
+
<div className="!space-y-4">
|
|
745
|
+
<h3 className="!text-xl font-semibold !text-purple-300">
|
|
746
|
+
State Validation
|
|
747
|
+
</h3>
|
|
748
|
+
<div className="rounded-lg bg-black/40 !p-4">
|
|
749
|
+
<pre className="overflow-x-auto !text-sm !text-green-300">
|
|
750
|
+
{`function DataTable({ sortColumn, sortDirection }) {
|
|
751
|
+
const [data, setData] = useState([])
|
|
752
|
+
const previousSort = usePrevious({
|
|
753
|
+
column: sortColumn,
|
|
754
|
+
direction: sortDirection
|
|
755
|
+
})
|
|
756
|
+
|
|
757
|
+
useEffect(() => {
|
|
758
|
+
const currentSort = {
|
|
759
|
+
column: sortColumn,
|
|
760
|
+
direction: sortDirection
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// Only re-sort if sort config changed
|
|
764
|
+
if (!isEqual(currentSort, previousSort)) {
|
|
765
|
+
const sorted = sortData(data, currentSort)
|
|
766
|
+
setData(sorted)
|
|
767
|
+
}
|
|
768
|
+
}, [sortColumn, sortDirection, previousSort])
|
|
769
|
+
|
|
770
|
+
return <Table data={data} />
|
|
771
|
+
}`}
|
|
772
|
+
</pre>
|
|
773
|
+
</div>
|
|
774
|
+
</div>
|
|
775
|
+
</div>
|
|
776
|
+
</div>
|
|
777
|
+
|
|
778
|
+
{/* Implementation Details */}
|
|
779
|
+
<div className="!space-y-8">
|
|
780
|
+
<h2 className="text-center !text-3xl font-bold !text-white">
|
|
781
|
+
Implementation
|
|
782
|
+
</h2>
|
|
783
|
+
<div className="rounded-lg border border-white/10 bg-white/5 !p-6">
|
|
784
|
+
<h3 className="!mb-4 !text-xl font-semibold !text-white">
|
|
785
|
+
Hook Implementation
|
|
786
|
+
</h3>
|
|
787
|
+
<div className="rounded-lg bg-black/40 !p-4">
|
|
788
|
+
<pre className="overflow-x-auto !text-sm !text-blue-300">
|
|
789
|
+
{`import { useRef, useEffect } from 'react'
|
|
790
|
+
|
|
791
|
+
function usePrevious<T>(value: T): T | undefined {
|
|
792
|
+
const ref = useRef<T>()
|
|
793
|
+
|
|
794
|
+
useEffect(() => {
|
|
795
|
+
ref.current = value
|
|
796
|
+
})
|
|
797
|
+
|
|
798
|
+
return ref.current
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
export { usePrevious }`}
|
|
802
|
+
</pre>
|
|
803
|
+
</div>
|
|
804
|
+
<div className="!mt-4 !space-y-2 !text-sm !text-white/70">
|
|
805
|
+
<p className="!text-white">
|
|
806
|
+
The hook uses a{" "}
|
|
807
|
+
<code className="!text-purple-300">useRef</code> to store
|
|
808
|
+
the previous value and{" "}
|
|
809
|
+
<code className="!text-purple-300">useEffect</code> to
|
|
810
|
+
update it after each render.
|
|
811
|
+
</p>
|
|
812
|
+
<p className="!text-white">
|
|
813
|
+
Since <code className="!text-purple-300">useEffect</code>{" "}
|
|
814
|
+
runs after the render, the ref contains the value from the
|
|
815
|
+
previous render cycle.
|
|
816
|
+
</p>
|
|
817
|
+
</div>
|
|
818
|
+
</div>
|
|
819
|
+
</div>
|
|
820
|
+
</div>
|
|
821
|
+
|
|
822
|
+
{/* Footer */}
|
|
823
|
+
<div className="border-t border-white/10 bg-black/20 backdrop-blur-xl">
|
|
824
|
+
<div className="!mx-auto max-w-7xl !px-6 !py-8">
|
|
825
|
+
<div className="!space-y-4 text-center">
|
|
826
|
+
<p className="!text-white/60">
|
|
827
|
+
usePrevious is a fundamental hook that enables powerful
|
|
828
|
+
patterns for state management, animations, and performance
|
|
829
|
+
optimizations in React applications.
|
|
830
|
+
</p>
|
|
831
|
+
<p className="!text-sm !text-white/40">
|
|
832
|
+
Simple, reliable, and type-safe - perfect for tracking any
|
|
833
|
+
value changes across component re-renders.
|
|
834
|
+
</p>
|
|
835
|
+
</div>
|
|
836
|
+
</div>
|
|
837
|
+
</div>
|
|
838
|
+
</div>
|
|
839
|
+
</>
|
|
840
|
+
),
|
|
841
|
+
},
|
|
842
|
+
},
|
|
843
|
+
tags: ["autodocs"],
|
|
844
|
+
argTypes: {
|
|
845
|
+
title: {
|
|
846
|
+
control: "text",
|
|
847
|
+
description: "Title for the demo component",
|
|
848
|
+
},
|
|
849
|
+
initialValue: {
|
|
850
|
+
control: { type: "number" },
|
|
851
|
+
description: "Initial value for the demo",
|
|
852
|
+
},
|
|
853
|
+
},
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
export default meta
|
|
857
|
+
type Story = StoryObj<typeof PreviousValueDemo>
|
|
858
|
+
|
|
859
|
+
// Story parameters for consistent dark theme
|
|
860
|
+
const storyParameters = {
|
|
861
|
+
backgrounds: {
|
|
862
|
+
default: "dark",
|
|
863
|
+
values: [
|
|
864
|
+
{ name: "dark", value: "#0a0a0a" },
|
|
865
|
+
{ name: "darker", value: "#000000" },
|
|
866
|
+
],
|
|
867
|
+
},
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
export const Default: Story = {
|
|
871
|
+
args: {
|
|
872
|
+
title: "usePrevious Hook Demo",
|
|
873
|
+
initialValue: 0,
|
|
874
|
+
},
|
|
875
|
+
parameters: storyParameters,
|
|
876
|
+
render: (args) => (
|
|
877
|
+
<div className="min-h-dvh bg-gradient-to-br from-gray-900 to-gray-800 !p-8">
|
|
878
|
+
<PreviousValueDemo {...args} />
|
|
879
|
+
</div>
|
|
880
|
+
),
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
export const NumberTracking: Story = {
|
|
884
|
+
args: {
|
|
885
|
+
title: "Number Value Tracking",
|
|
886
|
+
initialValue: 42,
|
|
887
|
+
},
|
|
888
|
+
parameters: {
|
|
889
|
+
...storyParameters,
|
|
890
|
+
docs: {
|
|
891
|
+
description: {
|
|
892
|
+
story:
|
|
893
|
+
"Demonstrates tracking numeric values with the usePrevious hook.",
|
|
894
|
+
},
|
|
895
|
+
},
|
|
896
|
+
},
|
|
897
|
+
render: (args) => (
|
|
898
|
+
<div className="min-h-dvh bg-gradient-to-br from-gray-900 to-gray-800 !p-8">
|
|
899
|
+
<PreviousValueDemo {...args} />
|
|
900
|
+
</div>
|
|
901
|
+
),
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
export const TypeVariations: Story = {
|
|
905
|
+
args: {
|
|
906
|
+
title: "Multiple Data Types",
|
|
907
|
+
initialValue: 100,
|
|
908
|
+
},
|
|
909
|
+
parameters: {
|
|
910
|
+
...storyParameters,
|
|
911
|
+
docs: {
|
|
912
|
+
description: {
|
|
913
|
+
story:
|
|
914
|
+
"Shows how usePrevious works with different data types: numbers, strings, booleans, objects, and arrays.",
|
|
915
|
+
},
|
|
916
|
+
},
|
|
917
|
+
},
|
|
918
|
+
render: (args) => (
|
|
919
|
+
<div className="min-h-dvh bg-gradient-to-br from-gray-900 to-gray-800 !p-8">
|
|
920
|
+
<PreviousValueDemo {...args} />
|
|
921
|
+
</div>
|
|
922
|
+
),
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
export const InteractiveDemo: Story = {
|
|
926
|
+
args: {
|
|
927
|
+
title: "Interactive Previous Value Demo",
|
|
928
|
+
initialValue: 0,
|
|
929
|
+
},
|
|
930
|
+
parameters: {
|
|
931
|
+
...storyParameters,
|
|
932
|
+
docs: {
|
|
933
|
+
description: {
|
|
934
|
+
story:
|
|
935
|
+
"Full interactive demo showing the usePrevious hook with real-time value tracking across different data types.",
|
|
936
|
+
},
|
|
937
|
+
},
|
|
938
|
+
},
|
|
939
|
+
render: (args) => (
|
|
940
|
+
<div className="min-h-dvh bg-gradient-to-br from-gray-900 to-gray-800 !p-8">
|
|
941
|
+
<div className="!space-y-8">
|
|
942
|
+
<PreviousValueDemo {...args} />
|
|
943
|
+
|
|
944
|
+
{/* Additional Usage Example */}
|
|
945
|
+
<div className="rounded-lg border border-white/10 bg-white/5 !p-6">
|
|
946
|
+
<h3 className="!mb-4 !text-xl font-semibold !text-white">
|
|
947
|
+
Real-world Example
|
|
948
|
+
</h3>
|
|
949
|
+
<div className="rounded-lg bg-black/40 !p-4">
|
|
950
|
+
<pre className="overflow-x-auto !text-sm !text-blue-300">
|
|
951
|
+
{`// Compare with previous props to avoid unnecessary API calls
|
|
952
|
+
function UserDetails({ userId }) {
|
|
953
|
+
const [user, setUser] = useState(null)
|
|
954
|
+
const [loading, setLoading] = useState(false)
|
|
955
|
+
const previousUserId = usePrevious(userId)
|
|
956
|
+
|
|
957
|
+
useEffect(() => {
|
|
958
|
+
// Only fetch if userId changed (not on every render)
|
|
959
|
+
if (userId && userId !== previousUserId) {
|
|
960
|
+
setLoading(true)
|
|
961
|
+
fetchUserById(userId)
|
|
962
|
+
.then(setUser)
|
|
963
|
+
.finally(() => setLoading(false))
|
|
964
|
+
}
|
|
965
|
+
}, [userId, previousUserId])
|
|
966
|
+
|
|
967
|
+
if (loading) return <div>Loading...</div>
|
|
968
|
+
return <div>{user?.name}</div>
|
|
969
|
+
}`}
|
|
970
|
+
</pre>
|
|
971
|
+
</div>
|
|
972
|
+
</div>
|
|
973
|
+
</div>
|
|
974
|
+
</div>
|
|
975
|
+
),
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
export const Playground: Story = {
|
|
979
|
+
parameters: {
|
|
980
|
+
...storyParameters,
|
|
981
|
+
docs: {
|
|
982
|
+
description: {
|
|
983
|
+
story:
|
|
984
|
+
"Interactive playground to experiment with the usePrevious hook.",
|
|
985
|
+
},
|
|
986
|
+
},
|
|
987
|
+
},
|
|
988
|
+
args: {
|
|
989
|
+
title: "usePrevious Playground",
|
|
990
|
+
initialValue: 50,
|
|
991
|
+
},
|
|
992
|
+
render: (args) => (
|
|
993
|
+
<div className="min-h-dvh bg-gradient-to-br from-gray-900 to-gray-800 !p-8">
|
|
994
|
+
<PreviousValueDemo {...args} />
|
|
995
|
+
</div>
|
|
996
|
+
),
|
|
997
|
+
}
|