aural-ui 4.0.1 → 4.2.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.
Files changed (175) hide show
  1. package/README.md +8 -1
  2. package/dist/components/aspect-ratio/AspectRatio.stories.tsx +290 -1228
  3. package/dist/components/avatar/Avatar.stories.tsx +219 -235
  4. package/dist/components/badge/Badge.stories.tsx +379 -116
  5. package/dist/components/banner/Banner.stories.tsx +445 -391
  6. package/dist/components/breadcrumb/Breadcrumb.stories.tsx +453 -199
  7. package/dist/components/button/Button.stories.tsx +585 -230
  8. package/dist/components/card/Card.stories.tsx +619 -301
  9. package/dist/components/char-count/CharCount.stories.tsx +350 -248
  10. package/dist/components/checkbox/Checkbox.stories.tsx +309 -167
  11. package/dist/components/chip/Chip.stories.tsx +362 -168
  12. package/dist/components/circular-loader/CircularLoader.stories.tsx +221 -636
  13. package/dist/components/clamp-lines/ClampLines.stories.tsx +246 -117
  14. package/dist/components/collapsible/Collapsible.stories.tsx +391 -252
  15. package/dist/components/command/Command.stories.tsx +530 -867
  16. package/dist/components/dialog/Dialog.stories.tsx +501 -950
  17. package/dist/components/divider/Divider.stories.tsx +264 -527
  18. package/dist/components/dot-loader/DotLoader.stories.tsx +256 -257
  19. package/dist/components/drawer/Drawer.stories.tsx +659 -1023
  20. package/dist/components/dropdown/Dropdown.stories.tsx +643 -1028
  21. package/dist/components/form/Form.stories.tsx +560 -274
  22. package/dist/components/helper-text/HelperText.stories.tsx +199 -200
  23. package/dist/components/hover-card/HoverCard.stories.tsx +318 -1254
  24. package/dist/components/icon-button/IconButton.stories.tsx +837 -194
  25. package/dist/components/if-else/if-else.stories.tsx +370 -83
  26. package/dist/components/input/Input.stories.tsx +436 -368
  27. package/dist/components/label/Label.stories.tsx +156 -154
  28. package/dist/components/list/List.stories.tsx +484 -835
  29. package/dist/components/marquee/Marquee.stories.tsx +356 -712
  30. package/dist/components/otp-inputs/OtpInputs.stories.tsx +352 -422
  31. package/dist/components/overlay/Overlay.stories.tsx +452 -824
  32. package/dist/components/pagination/Pagination.stories.tsx +721 -210
  33. package/dist/components/popover/Popover.stories.tsx +481 -896
  34. package/dist/components/radio/Radio.stories.tsx +432 -124
  35. package/dist/components/resizable/Resizable.stories.tsx +495 -799
  36. package/dist/components/scroll-area/ScrollArea.stories.tsx +383 -1059
  37. package/dist/components/search/Search.stories.tsx +312 -595
  38. package/dist/components/select/Select.stories.tsx +684 -789
  39. package/dist/components/sheet/Sheet.stories.tsx +671 -950
  40. package/dist/components/skelton/Skelton.stories.tsx +230 -764
  41. package/dist/components/slider/Slider.stories.tsx +383 -760
  42. package/dist/components/stepper/Stepper.stories.tsx +371 -514
  43. package/dist/components/switch/Switch.stories.tsx +461 -208
  44. package/dist/components/switch-case/SwitchCase.stories.tsx +367 -188
  45. package/dist/components/table/Table.stories.tsx +770 -916
  46. package/dist/components/tabs/Tabs.stories.tsx +458 -1455
  47. package/dist/components/tag/Tag.stories.tsx +714 -542
  48. package/dist/components/textarea/TextArea.stories.tsx +621 -562
  49. package/dist/components/thumbnail-tags/ThumbnailTags.stories.tsx +228 -154
  50. package/dist/components/toast/Toast.stories.tsx +452 -1339
  51. package/dist/components/toggle/Toggle.stories.tsx +488 -931
  52. package/dist/components/tooltip/Tooltip.stories.tsx +344 -1388
  53. package/dist/components/typography/Typography.stories.tsx +406 -89
  54. package/dist/hooks/use-change-state/UseChangeState.stories.tsx +309 -606
  55. package/dist/hooks/use-previous/UsePrevious.stories.tsx +367 -917
  56. package/dist/hooks/use-standalone-pagination/UseStandalonePagination.stories.tsx +639 -867
  57. package/dist/icons/Icons.stories.tsx +0 -12
  58. package/dist/icons/ai-avatar-icon/AiAvatarIcon.stories.tsx +223 -1060
  59. package/dist/icons/alert-icon/AlertIcon.stories.tsx +106 -968
  60. package/dist/icons/all-icons.tsx +37 -16
  61. package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +137 -1010
  62. package/dist/icons/apple-logo-icon/AppleLogoIcon.stories.tsx +145 -935
  63. package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +132 -1046
  64. package/dist/icons/arrow-corner-up-left-icon/ArrowCornerUpLeftIcon.stories.tsx +134 -986
  65. package/dist/icons/arrow-corner-up-right-icon/ArrowCornerUpRightIcon.stories.tsx +135 -1028
  66. package/dist/icons/arrow-left-icon/ArrowLeftIcon.stories.tsx +133 -971
  67. package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +145 -1123
  68. package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +143 -1252
  69. package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +123 -632
  70. package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +141 -1223
  71. package/dist/icons/backward-ten-seconds-icon/BackwardTenSecondsIcon.stories.tsx +164 -1018
  72. package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +121 -1236
  73. package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +121 -1213
  74. package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +116 -893
  75. package/dist/icons/camera-icon/CameraIcon.stories.tsx +109 -1254
  76. package/dist/icons/capital-a-letter-icon/CapitalALetterIcon.stories.tsx +114 -975
  77. package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +157 -994
  78. package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +160 -992
  79. package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +140 -970
  80. package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +126 -993
  81. package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +144 -987
  82. package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +141 -1007
  83. package/dist/icons/circle-tick-icon/CircleTickIcon.stories.tsx +147 -1187
  84. package/dist/icons/circular-play-icon/CircularPlayIcon.stories.tsx +110 -476
  85. package/dist/icons/coin-icon/CoinIcon.stories.tsx +120 -1364
  86. package/dist/icons/coin-toons-icon/CoinToonsIcon.stories.tsx +113 -1360
  87. package/dist/icons/column-wide-add-icon/ColumnWideAddIcon.stories.tsx +111 -942
  88. package/dist/icons/command-icon/CommandIcon.stories.tsx +124 -1087
  89. package/dist/icons/copy-icon/CopyIcon.stories.tsx +119 -996
  90. package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +144 -1046
  91. package/dist/icons/cross-icon/CrossIcon.stories.tsx +136 -999
  92. package/dist/icons/download-icon/DownloadIcon.stories.tsx +123 -857
  93. package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +121 -1080
  94. package/dist/icons/email-icon/EmailIcon.stories.tsx +112 -979
  95. package/dist/icons/expand-icon/ExpandIcon.stories.tsx +109 -1146
  96. package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +141 -1068
  97. package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +140 -1081
  98. package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +124 -1050
  99. package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +123 -1091
  100. package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +122 -633
  101. package/dist/icons/filter-bar-row-icon/FilterBarRowIcon.stories.tsx +116 -1087
  102. package/dist/icons/forward-ten-seconds-icon/ForwardTenSecondsIcon.stories.tsx +166 -1020
  103. package/dist/icons/git-branch-icon/GitBranchIcon.stories.tsx +112 -1182
  104. package/dist/icons/git-fork-icon/GitForkIcon.stories.tsx +112 -1155
  105. package/dist/icons/globe-icon/GlobeIcon.stories.tsx +127 -325
  106. package/dist/icons/google-logo-icon/GoogleLogoIcon.stories.tsx +142 -985
  107. package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +116 -1217
  108. package/dist/icons/head-icon/HeadIcon.stories.tsx +108 -953
  109. package/dist/icons/heart-icon/HeartIcon.stories.tsx +117 -1060
  110. package/dist/icons/image-avatar-sparkle-icon/ImageAvatarSparkleIcon.stories.tsx +116 -716
  111. package/dist/icons/image-icon/ImageIcon.stories.tsx +102 -1164
  112. package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +108 -1233
  113. package/dist/icons/import-left-arrow-folder-icon/ImportLeftArrowFolderIcon.stories.tsx +133 -1289
  114. package/dist/icons/indian-flag-icon/IndianFlagIcon.stories.tsx +155 -1012
  115. package/dist/icons/instagram-icon/InstagramIcon.stories.tsx +158 -1438
  116. package/dist/icons/layout-column-icon/LayoutColumnIcon.stories.tsx +121 -1011
  117. package/dist/icons/layout-left-icon/LayoutLeftIcon.stories.tsx +116 -981
  118. package/dist/icons/layout-right-icon/LayoutRightIcon.stories.tsx +116 -979
  119. package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +105 -1252
  120. package/dist/icons/linked-in-icon/LinkedInIcon.stories.tsx +151 -1554
  121. package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +107 -1227
  122. package/dist/icons/magic-edit-icon/MagicEditIcon.stories.tsx +116 -707
  123. package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +119 -1226
  124. package/dist/icons/message-icon/MessageIcon.stories.tsx +111 -557
  125. package/dist/icons/minimize-icon/MinimizeIcon.stories.tsx +112 -1198
  126. package/dist/icons/moon-icon/MoonIcon.stories.tsx +117 -557
  127. package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +106 -1235
  128. package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +112 -1185
  129. package/dist/icons/musical-note-icon/MusicalNoteIcon.stories.tsx +116 -1012
  130. package/dist/icons/notepad-icon/NotepadIcon.stories.tsx +108 -1137
  131. package/dist/icons/notes-icon/NotesIcon.stories.tsx +116 -1138
  132. package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +106 -1146
  133. package/dist/icons/page-text-icon/PageTextIcon.stories.tsx +119 -719
  134. package/dist/icons/paint-roll-icon/PaintRollIcon.stories.tsx +110 -999
  135. package/dist/icons/paper-plane-icon/PaperPlaneIcon.stories.tsx +109 -912
  136. package/dist/icons/pause-icon/PauseIcon.stories.tsx +110 -1041
  137. package/dist/icons/pencil-icon/PencilIcon.stories.tsx +112 -1109
  138. package/dist/icons/phone-icon/PhoneIcon.stories.tsx +112 -1023
  139. package/dist/icons/plus-icon/PlusIcon.stories.tsx +103 -1132
  140. package/dist/icons/pocket-studio-icon/PocketStudioIcon.stories.tsx +104 -870
  141. package/dist/icons/scroll-down-icon/ScrollDownIcon.stories.tsx +99 -476
  142. package/dist/icons/search-icon/SearchIcon.stories.tsx +108 -1161
  143. package/dist/icons/setting-icon/SettingIcon.stories.tsx +104 -1009
  144. package/dist/icons/share-icon/ShareIcon.stories.tsx +117 -1064
  145. package/dist/icons/shield-icon/ShieldIcon.stories.tsx +114 -974
  146. package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +134 -1160
  147. package/dist/icons/skip-backward-icon/SkipBackwardIcon.stories.tsx +169 -1017
  148. package/dist/icons/skip-forward-icon/SkipForwardIcon.stories.tsx +161 -1016
  149. package/dist/icons/sparkles-soft-icon/SparklesSoftIcon.stories.tsx +102 -1001
  150. package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +155 -593
  151. package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +155 -608
  152. package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +142 -712
  153. package/dist/icons/star-icon/StarIcon.stories.tsx +120 -946
  154. package/dist/icons/store-coin-icon/StoreCoinIcon.stories.tsx +109 -1013
  155. package/dist/icons/suggestion-icon/SuggestionIcon.stories.tsx +113 -891
  156. package/dist/icons/sun-icon/SunIcon.stories.tsx +117 -864
  157. package/dist/icons/text-color-icon/TextColorIcon.stories.tsx +113 -989
  158. package/dist/icons/text-indicator-icon/TextIndicatorIcon.stories.tsx +120 -1027
  159. package/dist/icons/threads-icon/ThreadsIcon.stories.tsx +153 -1476
  160. package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +143 -1187
  161. package/dist/icons/tick-icon/TickIcon.stories.tsx +142 -1322
  162. package/dist/icons/trash-icon/TrashIcon.stories.tsx +105 -970
  163. package/dist/icons/twitter-x-icon/TwitterXIcon.stories.tsx +154 -1457
  164. package/dist/icons/upload-icon/UploadIcon.stories.tsx +112 -930
  165. package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +115 -1019
  166. package/dist/icons/video-play-list-icon/VideoPlaylistIcon.stories.tsx +122 -1092
  167. package/dist/icons/voice-playing-icon/VoicePlayingIcon.stories.tsx +120 -1401
  168. package/dist/icons/volume-full-icon/VolumeFullIcon.stories.tsx +107 -1212
  169. package/dist/icons/volume-half-icon/VolumeHalfIcon.stories.tsx +109 -1122
  170. package/dist/icons/volume-off-icon/VolumeOffIcon.stories.tsx +112 -1124
  171. package/dist/icons/warning-icon/WarningIcon.stories.tsx +119 -1083
  172. package/dist/icons/youtube-icon/YoutubeIcon.stories.tsx +158 -983
  173. package/dist/index.cjs +90 -90
  174. package/dist/index.js +90 -90
  175. package/package.json +8 -3
@@ -1,585 +1,294 @@
1
1
  import React from "react"
2
2
  import type { Meta, StoryObj } from "@storybook/react-vite"
3
3
 
4
- import { LightBulbSimpleIcon } from "src/ui/icons"
4
+ import {
5
+ ChevronDownIcon,
6
+ EyeOpenIcon,
7
+ FeatureShineIcon,
8
+ LayoutColumnIcon,
9
+ LightBulbSimpleIcon,
10
+ NotepadIcon,
11
+ SettingIcon,
12
+ } from "src/ui/icons"
13
+ import {
14
+ HookCodeBlock,
15
+ HookControlButton,
16
+ HookPanel,
17
+ HookPlaygroundCanvas,
18
+ HookStateCard,
19
+ HookStateGrid,
20
+ HookUsageCanvas,
21
+ HookUsageSection,
22
+ } from "src/ui/story-spec/hooks/hook-story-canvas"
23
+ import { AuralHookDocsPage } from "src/ui/story-spec/hooks/hook-story-docs-page"
5
24
 
6
25
  import { useChangeState } from "."
7
26
 
8
- const ChangeStateDemo: React.FC<{
9
- title?: string
10
- }> = ({ title = "useChangeState Demo" }) => {
27
+ // ─────────────────────────────────────────────────────────────────────────────
28
+ // Demo components
29
+ // ─────────────────────────────────────────────────────────────────────────────
30
+
31
+ const ChangeStatePlaygroundDemo: React.FC<{ label?: string }> = ({
32
+ label = "State Label",
33
+ }) => {
11
34
  const { open, onOpenChange } = useChangeState()
12
35
 
13
36
  return (
14
- <div className="!space-y-6 rounded-lg border border-white/10 bg-white/5 !p-6">
15
- <h3 className="!text-xl font-semibold !text-white">{title}</h3>
16
-
17
- {/* State Display */}
18
- <div className="rounded-lg border border-blue-500/20 bg-blue-500/10 !p-4">
19
- <h4 className="!mb-3 !text-lg font-semibold !text-blue-300">
20
- Current State
21
- </h4>
22
- <div className="flex items-center justify-between rounded-lg bg-black/20 !p-3">
23
- <span className="!text-sm !text-white/70">Open:</span>
24
- <span
25
- className={`font-mono !text-lg font-bold ${
26
- open ? "!text-green-300" : "!text-red-300"
27
- }`}
28
- >
29
- {String(open)}
30
- </span>
31
- </div>
37
+ <HookPlaygroundCanvas>
38
+ <div className="mx-auto w-full max-w-sm space-y-6 p-8">
39
+ <HookStateGrid>
40
+ <HookStateCard label="open" value={String(open)} />
41
+ <HookStateCard label={label} value={open ? "Active" : "Inactive"} />
42
+ </HookStateGrid>
43
+ <HookPanel title="Controls">
44
+ <div className="flex flex-wrap gap-3">
45
+ <HookControlButton onClick={() => onOpenChange()}>
46
+ Toggle
47
+ </HookControlButton>
48
+ <HookControlButton
49
+ onClick={() => onOpenChange(true)}
50
+ variant="positive"
51
+ >
52
+ Set True
53
+ </HookControlButton>
54
+ <HookControlButton
55
+ onClick={() => onOpenChange(false)}
56
+ variant="negative"
57
+ >
58
+ Set False
59
+ </HookControlButton>
60
+ </div>
61
+ </HookPanel>
32
62
  </div>
63
+ </HookPlaygroundCanvas>
64
+ )
65
+ }
33
66
 
34
- {/* Controls */}
35
- <div className="!space-y-3">
36
- <button
37
- onClick={() => onOpenChange()}
38
- className={`w-full rounded-lg border !px-4 !py-3 !text-sm font-medium transition-colors ${
39
- open
40
- ? "border-green-500/30 bg-green-500/20 !text-green-300 hover:bg-green-500/30"
41
- : "border-red-500/30 bg-red-500/20 !text-red-300 hover:bg-red-500/30"
42
- }`}
43
- >
44
- Toggle State ({open ? "ON" : "OFF"})
45
- </button>
46
-
47
- <div className="grid grid-cols-2 gap-3">
48
- <button
49
- onClick={() => onOpenChange(true)}
50
- className="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"
51
- >
52
- Set True
53
- </button>
54
- <button
55
- onClick={() => onOpenChange(false)}
56
- className="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"
57
- >
58
- Set False
59
- </button>
60
- </div>
61
- </div>
67
+ const ChangeStateInteractiveDemo: React.FC = () => {
68
+ const { open, onOpenChange } = useChangeState()
62
69
 
63
- {/* Usage Information */}
64
- <div className="rounded-lg border border-white/10 bg-black/20 !p-4">
65
- <h4 className="!mb-3 !text-lg font-semibold !text-white">Hook Usage</h4>
66
- <div className="!space-y-2 !text-sm">
67
- <div className="!text-white/70">
68
- <span className="font-medium !text-white">Pattern:</span> const{" "}
69
- {`{ open, onOpenChange }`} = useChangeState()
70
- </div>
71
- <div className="!text-white/70">
72
- <span className="font-medium !text-white">Toggle:</span>{" "}
73
- onOpenChange() - toggles current state
74
- </div>
75
- <div className="!text-white/70">
76
- <span className="font-medium !text-white">Set value:</span>{" "}
77
- onOpenChange(true/false) - sets specific value
70
+ return (
71
+ <HookPlaygroundCanvas>
72
+ <div className="mx-auto w-full max-w-lg space-y-6 p-8">
73
+ <HookStateGrid>
74
+ <HookStateCard label="open" value={String(open)} />
75
+ <HookStateCard label="Status" value={open ? "Open" : "Closed"} />
76
+ </HookStateGrid>
77
+
78
+ <HookPanel title="Controls">
79
+ <div className="flex flex-wrap gap-3">
80
+ <HookControlButton
81
+ onClick={() => onOpenChange()}
82
+ className="flex-1"
83
+ >
84
+ Toggle
85
+ </HookControlButton>
86
+ <HookControlButton
87
+ onClick={() => onOpenChange(true)}
88
+ variant="positive"
89
+ className="flex-1"
90
+ >
91
+ Set True
92
+ </HookControlButton>
93
+ <HookControlButton
94
+ onClick={() => onOpenChange(false)}
95
+ variant="negative"
96
+ className="flex-1"
97
+ >
98
+ Set False
99
+ </HookControlButton>
78
100
  </div>
79
- </div>
101
+ </HookPanel>
102
+
103
+ <HookCodeBlock
104
+ code={`const { open, onOpenChange } = useChangeState()
105
+
106
+ onOpenChange() // toggles current state
107
+ onOpenChange(true) // sets open = true
108
+ onOpenChange(false) // sets open = false`}
109
+ />
80
110
  </div>
81
- </div>
111
+ </HookPlaygroundCanvas>
82
112
  )
83
113
  }
84
114
 
85
- const meta: Meta<typeof ChangeStateDemo> = {
115
+ // ─────────────────────────────────────────────────────────────────────────────
116
+ // Meta
117
+ // ─────────────────────────────────────────────────────────────────────────────
118
+
119
+ const meta: Meta<typeof ChangeStatePlaygroundDemo> = {
86
120
  title: "Hooks/useChangeState",
87
- component: ChangeStateDemo,
121
+ component: ChangeStatePlaygroundDemo,
88
122
  parameters: {
89
123
  layout: "fullscreen",
90
124
  backgrounds: {
91
125
  default: "dark",
92
126
  values: [
93
- { name: "dark", value: "#0a0a0a" },
94
- { name: "darker", value: "#000000" },
95
- { name: "light", value: "#ffffff" },
127
+ { name: "dark", value: "var(--color-fm-surface-primary)" },
128
+ { name: "darker", value: "var(--color-fm-neutral-0)" },
129
+ { name: "light", value: "var(--color-fm-neutral-1100)" },
96
130
  ],
97
131
  },
98
132
  docs: {
99
133
  page: () => (
100
- <>
101
- {/* Override default docs styling */}
102
- <style>
103
- {`
104
- .sbdocs-wrapper {
105
- padding: 0 !important;
106
- max-width: none !important;
107
- background: transparent !important;
108
- }
109
- .sbdocs-content {
110
- max-width: none !important;
111
- padding: 0 !important;
112
- margin: 0 !important;
113
- background: transparent !important;
114
- }
115
- .docs-story {
116
- background: transparent !important;
117
- }
118
- .sbdocs {
119
- background: transparent !important;
120
- }
121
- body {
122
- background: #0a0a0a !important;
123
- }
124
- #storybook-docs {
125
- background: #0a0a0a !important;
126
- }
127
- .sbdocs-preview {
128
- background: transparent !important;
129
- border: none !important;
130
- }
131
- .sbdocs-h1, .sbdocs-h2, .sbdocs-h3, .sbdocs-h4, .sbdocs-h5, .sbdocs-h6 {
132
- color: white !important;
133
- }
134
- .sbdocs-p, .sbdocs-li {
135
- color: rgba(255, 255, 255, 0.7) !important;
136
- }
137
- .sbdocs-code {
138
- background: rgba(255, 255, 255, 0.1) !important;
139
- color: rgba(168, 85, 247, 1) !important;
140
- border: 1px solid rgba(255, 255, 255, 0.1) !important;
141
- }
142
- .sbdocs-pre {
143
- background: rgba(0, 0, 0, 0.4) !important;
144
- border: 1px solid rgba(255, 255, 255, 0.1) !important;
145
- }
146
- .sbdocs-table {
147
- background: rgba(255, 255, 255, 0.05) !important;
148
- border: 1px solid rgba(255, 255, 255, 0.1) !important;
149
- }
150
- .sbdocs-table th {
151
- background: rgba(255, 255, 255, 0.05) !important;
152
- color: white !important;
153
- border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important;
154
- }
155
- .sbdocs-table td {
156
- color: rgba(255, 255, 255, 0.7) !important;
157
- border-bottom: 1px solid rgba(255, 255, 255, 0.05) !important;
158
- }
159
- `}
160
- </style>
161
-
162
- <div className="min-h-screen bg-gradient-to-br from-gray-900 via-purple-900/20 to-gray-900">
163
- {/* Header */}
164
- <div className="relative overflow-hidden border-b border-white/10 bg-black/20 backdrop-blur-xl">
165
- <div className="absolute inset-0 bg-gradient-to-r from-purple-500/10 via-transparent to-indigo-500/10" />
166
- <div className="relative !mx-auto max-w-7xl !px-6 !py-16">
167
- <div className="!space-y-6 text-center">
168
- <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">
169
- <span className="!text-4xl">
170
- <LightBulbSimpleIcon className="text-fm-primary size-10" />
171
- </span>
172
- </div>
173
- <h1 className="!text-fm-primary !text-5xl font-bold">
174
- useChangeState
175
- </h1>
176
- <p className="!mx-auto max-w-3xl !text-xl leading-relaxed !text-white/70">
177
- A versatile React hook that manages boolean state with a
178
- flexible toggle function. Perfect for modals, dropdowns,
179
- accordions, and any component that needs show/hide
180
- functionality with customizable state control.
181
- </p>
182
-
183
- {/* Stats */}
184
- <div className="flex items-center justify-center gap-8 !pt-8">
185
- <div className="text-center">
186
- <div className="!text-3xl font-bold !text-purple-300">
187
- Flexible
188
- </div>
189
- <div className="!text-sm !text-white/60">
190
- Toggle or set specific value
191
- </div>
192
- </div>
193
- <div className="!h-8 !w-px bg-white/20" />
194
- <div className="text-center">
195
- <div className="!text-3xl font-bold !text-indigo-300">
196
- Optimized
197
- </div>
198
- <div className="!text-sm !text-white/60">
199
- Memoized callbacks
200
- </div>
201
- </div>
202
- <div className="!h-8 !w-px bg-white/20" />
203
- <div className="text-center">
204
- <div className="!text-3xl font-bold !text-cyan-300">
205
- Intuitive
206
- </div>
207
- <div className="!text-sm !text-white/60">
208
- Natural API design
209
- </div>
210
- </div>
211
- </div>
212
- </div>
213
- </div>
214
- </div>
215
-
216
- {/* Content */}
217
- <div className="!mx-auto max-w-7xl !space-y-16 !px-6 !py-12">
218
- {/* Quick Usage */}
219
- <div className="!space-y-8">
220
- <h2 className="text-center !text-3xl font-bold !text-white">
221
- Quick Start
222
- </h2>
223
- <div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
224
- <div className="!space-y-4">
225
- <h3 className="!text-xl font-semibold !text-purple-300">
226
- Basic Usage
227
- </h3>
228
- <div className="rounded-lg bg-black/40 !p-4">
229
- <pre className="overflow-x-auto !text-sm !text-green-300">
230
- {`import { useChangeState } from "@hooks/use-change-state"
134
+ <AuralHookDocsPage
135
+ icon={LightBulbSimpleIcon}
136
+ features={[
137
+ { title: "Flexible", description: "Toggle or set specific value" },
138
+ { title: "Optimized", description: "Memoized callbacks" },
139
+ { title: "Intuitive", description: "Natural API design" },
140
+ ]}
141
+ quickStart={{
142
+ codeExample: `import { useChangeState } from "src/ui/hooks/use-change-state"
231
143
 
232
144
  function Modal() {
233
145
  const { open, onOpenChange } = useChangeState()
234
146
 
235
147
  return (
236
148
  <>
237
- <button onClick={() => onOpenChange(true)}>
238
- Open Modal
239
- </button>
240
-
149
+ <button onClick={() => onOpenChange(true)}>Open Modal</button>
150
+
241
151
  {open && (
242
- <div className="modal-overlay">
243
- <div className="modal-content">
244
- <h2>Modal Title</h2>
245
- <button onClick={() => onOpenChange(false)}>
246
- Close
247
- </button>
248
- <button onClick={() => onOpenChange()}>
249
- Toggle
250
- </button>
251
- </div>
152
+ <div>
153
+ <h2>Modal Title</h2>
154
+ <button onClick={() => onOpenChange(false)}>Close</button>
155
+ <button onClick={() => onOpenChange()}>Toggle</button>
252
156
  </div>
253
157
  )}
254
158
  </>
255
159
  )
256
- }`}
257
- </pre>
258
- </div>
259
- </div>
260
-
261
- <div className="!space-y-4">
262
- <h3 className="!text-xl font-semibold !text-purple-300">
263
- Hook Properties
264
- </h3>
265
- <div className="!space-y-3 rounded-lg border border-white/10 bg-white/5 !p-4">
266
- <div className="flex justify-between">
267
- <span className="!text-sm !text-white/70">
268
- Returns:
269
- </span>
270
- <span className="!text-sm font-medium !text-white">
271
- Object with state & handler
272
- </span>
273
- </div>
274
- <div className="flex justify-between">
275
- <span className="!text-sm !text-white/70">
276
- Initial state:
277
- </span>
278
- <span className="!text-sm font-medium !text-white">
279
- false
280
- </span>
281
- </div>
282
- <div className="flex justify-between">
283
- <span className="!text-sm !text-white/70">
284
- Toggle behavior:
285
- </span>
286
- <span className="!text-sm font-medium !text-white">
287
- Smart default
288
- </span>
289
- </div>
290
- <div className="flex justify-between">
291
- <span className="!text-sm !text-white/70">
292
- Performance:
293
- </span>
294
- <span className="!text-sm font-medium !text-white">
295
- Memoized callback
296
- </span>
297
- </div>
298
- </div>
299
- </div>
300
- </div>
301
- </div>
302
-
303
- {/* API Documentation */}
304
- <div className="!space-y-8">
305
- <h2 className="text-center !text-3xl font-bold !text-white">
306
- API Reference
307
- </h2>
308
-
309
- <div className="overflow-hidden rounded-lg border border-white/10 bg-white/5">
310
- <div className="bg-white/5 !p-4">
311
- <h3 className="!text-xl font-semibold !text-white">
312
- Hook Signature
313
- </h3>
314
- </div>
315
- <div className="!p-6">
316
- <div className="rounded-lg bg-black/40 !p-4">
317
- <pre className="!text-sm !text-green-300">
318
- {`function useChangeState(): {
160
+ }`,
161
+ hookProperties: [
162
+ { label: "Returns", value: "Object with state & handler" },
163
+ { label: "Initial state", value: "false" },
164
+ { label: "Toggle behavior", value: "Smart default" },
165
+ { label: "Performance", value: "Memoized callback" },
166
+ ],
167
+ }}
168
+ hookSignature={`function useChangeState(): {
319
169
  open: boolean
320
170
  onOpenChange: (value?: boolean) => void
321
171
  }`}
322
- </pre>
323
- </div>
324
- </div>
325
- </div>
326
-
327
- <div className="overflow-hidden rounded-lg border border-white/10 bg-white/5">
328
- <div className="bg-white/5 !p-4">
329
- <h3 className="!text-xl font-semibold !text-white">
330
- Return Value & Methods
331
- </h3>
332
- </div>
333
- <table className="!my-0 w-full">
334
- <thead className="bg-white/5">
335
- <tr className="border-b border-white/10">
336
- <th className="!px-6 !py-4 text-left !text-sm font-semibold !text-white">
337
- Property
338
- </th>
339
- <th className="!px-6 !py-4 text-left !text-sm font-semibold !text-white">
340
- Type
341
- </th>
342
- <th className="!px-6 !py-4 text-left !text-sm font-semibold !text-white">
343
- Description
344
- </th>
345
- </tr>
346
- </thead>
347
- <tbody>
348
- <tr className="border-b border-white/5">
349
- <td className="!px-6 !py-4 font-mono !text-sm !text-purple-300">
350
- open
351
- </td>
352
- <td className="!px-6 !py-4 !text-sm !text-white/70">
353
- boolean
354
- </td>
355
- <td className="!px-6 !py-4 !text-sm !text-white/70">
356
- Current state value (initially false)
357
- </td>
358
- </tr>
359
- <tr className="!bg-black/10">
360
- <td className="!px-6 !py-4 font-mono !text-sm !text-purple-300">
361
- onOpenChange
362
- </td>
363
- <td className="!px-6 !py-4 !text-sm !text-white/70">
364
- (value?: boolean) ={">"} void
365
- </td>
366
- <td className="!px-6 !py-4 !text-sm !text-white/70">
367
- Function to update state. Toggles if no value
368
- provided, sets specific value if provided
369
- </td>
370
- </tr>
371
- </tbody>
372
- </table>
373
- </div>
374
- </div>
375
-
376
- {/* Use Cases */}
377
- <div className="!space-y-8">
378
- <h2 className="text-center !text-3xl font-bold !text-white">
379
- Common Use Cases
380
- </h2>
381
- <div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
382
- <div className="rounded-lg border border-white/10 bg-white/5 !p-6">
383
- <div className="!mb-4 flex !h-12 !w-12 items-center justify-center rounded-lg bg-blue-500/20">
384
- <span className="!text-2xl">🪟</span>
385
- </div>
386
- <h3 className="!mb-2 !text-lg font-semibold !text-white">
387
- Modals & Dialogs
388
- </h3>
389
- <p className="!text-sm !text-white/70">
390
- Control modal visibility with precise open/close
391
- functionality and smooth toggle behavior.
392
- </p>
393
- </div>
394
-
395
- <div className="rounded-lg border border-white/10 bg-white/5 !p-6">
396
- <div className="!mb-4 flex !h-12 !w-12 items-center justify-center rounded-lg bg-green-500/20">
397
- <span className="!text-2xl">📋</span>
398
- </div>
399
- <h3 className="!mb-2 !text-lg font-semibold !text-white">
400
- Dropdowns
401
- </h3>
402
- <p className="!text-sm !text-white/70">
403
- Manage dropdown menu states with intelligent toggle and
404
- explicit control methods.
405
- </p>
406
- </div>
407
-
408
- <div className="rounded-lg border border-white/10 bg-white/5 !p-6">
409
- <div className="!mb-4 flex !h-12 !w-12 items-center justify-center rounded-lg bg-purple-500/20">
410
- <span className="!text-2xl">📖</span>
411
- </div>
412
- <h3 className="!mb-2 !text-lg font-semibold !text-white">
413
- Accordions
414
- </h3>
415
- <p className="!text-sm !text-white/70">
416
- Handle expand/collapse states for accordion components and
417
- collapsible content sections.
418
- </p>
419
- </div>
420
-
421
- <div className="rounded-lg border border-white/10 bg-white/5 !p-6">
422
- <div className="!mb-4 flex !h-12 !w-12 items-center justify-center rounded-lg bg-orange-500/20">
423
- <span className="!text-2xl">👁️</span>
424
- </div>
425
- <h3 className="!mb-2 !text-lg font-semibold !text-white">
426
- Show/Hide Content
427
- </h3>
428
- <p className="!text-sm !text-white/70">
429
- Toggle visibility of any content with flexible control
430
- over show and hide operations.
431
- </p>
432
- </div>
433
-
434
- <div className="rounded-lg border border-white/10 bg-white/5 !p-6">
435
- <div className="!mb-4 flex !h-12 !w-12 items-center justify-center rounded-lg bg-cyan-500/20">
436
- <span className="!text-2xl">🎛️</span>
437
- </div>
438
- <h3 className="!mb-2 !text-lg font-semibold !text-white">
439
- UI Controls
440
- </h3>
441
- <p className="!text-sm !text-white/70">
442
- Power switches, toggles, and other boolean-based UI
443
- components with optimized state management.
444
- </p>
445
- </div>
446
-
447
- <div className="rounded-lg border border-white/10 bg-white/5 !p-6">
448
- <div className="!mb-4 flex !h-12 !w-12 items-center justify-center rounded-lg bg-pink-500/20">
449
- <span className="!text-2xl">🔧</span>
450
- </div>
451
- <h3 className="!mb-2 !text-lg font-semibold !text-white">
452
- Feature Flags
453
- </h3>
454
- <p className="!text-sm !text-white/70">
455
- Implement feature toggles and conditional rendering with
456
- clean state management patterns.
457
- </p>
458
- </div>
459
- </div>
460
- </div>
461
-
462
- {/* Usage Patterns */}
463
- <div className="!space-y-8">
464
- <h2 className="text-center !text-3xl font-bold !text-white">
465
- Usage Patterns
466
- </h2>
467
- <div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
468
- <div className="!space-y-4">
469
- <h3 className="!text-xl font-semibold !text-purple-300">
470
- Modal with Backdrop Close
471
- </h3>
472
- <div className="rounded-lg bg-black/40 !p-4">
473
- <pre className="overflow-x-auto !text-sm !text-green-300">
474
- {`function ConfirmDialog({ message, onConfirm }) {
172
+ returns={[
173
+ {
174
+ name: "open",
175
+ type: "boolean",
176
+ description: "Current state value, initially false.",
177
+ },
178
+ {
179
+ name: "onOpenChange",
180
+ type: "(value?: boolean) => void",
181
+ description:
182
+ "Toggles the state when called with no argument; sets a specific value when a boolean is passed.",
183
+ },
184
+ ]}
185
+ useCases={[
186
+ {
187
+ icon: NotepadIcon,
188
+ title: "Modals & Dialogs",
189
+ description:
190
+ "Control modal visibility with precise open/close and toggle behavior.",
191
+ },
192
+ {
193
+ icon: ChevronDownIcon,
194
+ title: "Dropdowns",
195
+ description:
196
+ "Manage dropdown menu states with intelligent toggle and explicit control.",
197
+ },
198
+ {
199
+ icon: LayoutColumnIcon,
200
+ title: "Accordions",
201
+ description:
202
+ "Handle expand/collapse states for accordion and collapsible sections.",
203
+ },
204
+ {
205
+ icon: EyeOpenIcon,
206
+ title: "Show / Hide",
207
+ description:
208
+ "Toggle visibility of any content with flexible show and hide control.",
209
+ },
210
+ {
211
+ icon: SettingIcon,
212
+ title: "UI Controls",
213
+ description:
214
+ "Power switches, toggles, and other boolean-based UI components.",
215
+ },
216
+ {
217
+ icon: FeatureShineIcon,
218
+ title: "Feature Flags",
219
+ description:
220
+ "Implement feature toggles and conditional rendering patterns.",
221
+ },
222
+ ]}
223
+ usagePatterns={[
224
+ {
225
+ title: "Modal with Backdrop Close",
226
+ code: `function ConfirmDialog({ message, onConfirm }) {
475
227
  const { open, onOpenChange } = useChangeState()
476
228
 
477
229
  const handleBackdropClick = (e) => {
478
- if (e.target === e.currentTarget) {
479
- onOpenChange(false)
480
- }
230
+ if (e.target === e.currentTarget) onOpenChange(false)
481
231
  }
482
232
 
483
233
  return (
484
234
  <>
485
- <button onClick={() => onOpenChange(true)}>
486
- Delete Item
487
- </button>
488
-
235
+ <button onClick={() => onOpenChange(true)}>Delete Item</button>
236
+
489
237
  {open && (
490
- <div
491
- className="modal-overlay"
492
- onClick={handleBackdropClick}
493
- >
238
+ <div className="modal-overlay" onClick={handleBackdropClick}>
494
239
  <div className="modal-content">
495
240
  <p>{message}</p>
496
241
  <button onClick={onConfirm}>Confirm</button>
497
- <button onClick={() => onOpenChange(false)}>
498
- Cancel
499
- </button>
242
+ <button onClick={() => onOpenChange(false)}>Cancel</button>
500
243
  </div>
501
244
  </div>
502
245
  )}
503
246
  </>
504
247
  )
505
- }`}
506
- </pre>
507
- </div>
508
- </div>
509
-
510
- <div className="!space-y-4">
511
- <h3 className="!text-xl font-semibold !text-purple-300">
512
- Collapsible Section
513
- </h3>
514
- <div className="rounded-lg bg-black/40 !p-4">
515
- <pre className="overflow-x-auto !text-sm !text-green-300">
516
- {`function CollapsibleCard({ title, children }) {
248
+ }`,
249
+ },
250
+ {
251
+ title: "Collapsible Section",
252
+ code: `function CollapsibleCard({ title, children }) {
517
253
  const { open, onOpenChange } = useChangeState()
518
254
 
519
255
  return (
520
256
  <div className="card">
521
- <div
522
- className="card-header"
523
- onClick={() => onOpenChange()}
524
- >
257
+ <div className="card-header" onClick={() => onOpenChange()}>
525
258
  <h3>{title}</h3>
526
- <span className={\`icon \${open ? 'rotate' : ''}\`}>
527
-
528
- </span>
259
+ <span className={\`icon \${open ? "rotate" : ""}\`}>▼</span>
529
260
  </div>
530
-
531
- {open && (
532
- <div className="card-content">
533
- {children}
534
- </div>
535
- )}
261
+
262
+ {open && <div className="card-content">{children}</div>}
536
263
  </div>
537
264
  )
538
- }`}
539
- </pre>
540
- </div>
541
- </div>
542
-
543
- <div className="!space-y-4">
544
- <h3 className="!text-xl font-semibold !text-purple-300">
545
- Controlled Dropdown Menu
546
- </h3>
547
- <div className="rounded-lg bg-black/40 !p-4">
548
- <pre className="overflow-x-auto !text-sm !text-green-300">
549
- {`function DropdownMenu({ trigger, items }) {
265
+ }`,
266
+ },
267
+ {
268
+ title: "Controlled Dropdown",
269
+ code: `function DropdownMenu({ trigger, items }) {
550
270
  const { open, onOpenChange } = useChangeState()
551
271
  const menuRef = useRef()
552
272
 
553
273
  useEffect(() => {
554
- const handleClickOutside = (event) => {
555
- if (menuRef.current &&
556
- !menuRef.current.contains(event.target)) {
274
+ const handleOutside = (e) => {
275
+ if (menuRef.current && !menuRef.current.contains(e.target)) {
557
276
  onOpenChange(false)
558
277
  }
559
278
  }
560
-
561
279
  if (open) {
562
- document.addEventListener('click', handleClickOutside)
563
- return () => document.removeEventListener('click', handleClickOutside)
280
+ document.addEventListener("click", handleOutside)
281
+ return () => document.removeEventListener("click", handleOutside)
564
282
  }
565
283
  }, [open, onOpenChange])
566
284
 
567
285
  return (
568
- <div className="dropdown" ref={menuRef}>
569
- <button onClick={() => onOpenChange()}>
570
- {trigger}
571
- </button>
572
-
286
+ <div ref={menuRef}>
287
+ <button onClick={() => onOpenChange()}>{trigger}</button>
573
288
  {open && (
574
289
  <div className="dropdown-menu">
575
- {items.map(item => (
576
- <div
577
- key={item.id}
578
- onClick={() => {
579
- item.onClick()
580
- onOpenChange(false)
581
- }}
582
- >
290
+ {items.map((item) => (
291
+ <div key={item.id} onClick={() => { item.onClick(); onOpenChange(false) }}>
583
292
  {item.label}
584
293
  </div>
585
294
  ))}
@@ -587,73 +296,41 @@ function Modal() {
587
296
  )}
588
297
  </div>
589
298
  )
590
- }`}
591
- </pre>
592
- </div>
593
- </div>
594
-
595
- <div className="!space-y-4">
596
- <h3 className="!text-xl font-semibold !text-purple-300">
597
- Conditional Form Section
598
- </h3>
599
- <div className="rounded-lg bg-black/40 !p-4">
600
- <pre className="overflow-x-auto !text-sm !text-green-300">
601
- {`function ProfileForm() {
299
+ }`,
300
+ },
301
+ {
302
+ title: "Conditional Form Section",
303
+ code: `function ProfileForm() {
602
304
  const { open: showAdvanced, onOpenChange } = useChangeState()
603
305
  const [formData, setFormData] = useState({})
604
306
 
605
- const toggleAdvancedOptions = () => {
606
- onOpenChange()
607
-
608
- // Reset advanced fields when hiding
307
+ const toggleAdvanced = () => {
609
308
  if (showAdvanced) {
610
- setFormData(prev => ({
611
- ...prev,
612
- advancedField1: '',
613
- advancedField2: ''
614
- }))
309
+ setFormData((prev) => ({ ...prev, advField1: "", advField2: "" }))
615
310
  }
311
+ onOpenChange()
616
312
  }
617
313
 
618
314
  return (
619
315
  <div>
620
316
  <input placeholder="Name" />
621
317
  <input placeholder="Email" />
622
-
623
- <button
624
- type="button"
625
- onClick={toggleAdvancedOptions}
626
- >
627
- {showAdvanced ? 'Hide' : 'Show'} Advanced Options
318
+ <button type="button" onClick={toggleAdvanced}>
319
+ {showAdvanced ? "Hide" : "Show"} Advanced Options
628
320
  </button>
629
-
630
321
  {showAdvanced && (
631
- <div className="advanced-section">
322
+ <div>
632
323
  <input placeholder="Advanced Field 1" />
633
324
  <input placeholder="Advanced Field 2" />
634
325
  </div>
635
326
  )}
636
327
  </div>
637
328
  )
638
- }`}
639
- </pre>
640
- </div>
641
- </div>
642
- </div>
643
- </div>
644
-
645
- {/* Implementation Details */}
646
- <div className="!space-y-8">
647
- <h2 className="text-center !text-3xl font-bold !text-white">
648
- Implementation
649
- </h2>
650
- <div className="rounded-lg border border-white/10 bg-white/5 !p-6">
651
- <h3 className="!mb-4 !text-xl font-semibold !text-white">
652
- Hook Implementation
653
- </h3>
654
- <div className="rounded-lg bg-black/40 !p-4">
655
- <pre className="overflow-x-auto !text-sm !text-blue-300">
656
- {`import React from "react"
329
+ }`,
330
+ },
331
+ ]}
332
+ implementation={{
333
+ code: `import React from "react"
657
334
 
658
335
  export const useChangeState = () => {
659
336
  const [open, setOpen] = React.useState(false)
@@ -669,61 +346,22 @@ export const useChangeState = () => {
669
346
  open,
670
347
  onOpenChange,
671
348
  }
672
- }`}
673
- </pre>
674
- </div>
675
- <div className="!mt-4 !space-y-2 !text-sm !text-white/70">
676
- <p className="!text-white">
677
- The hook combines{" "}
678
- <code className="!text-purple-300">useState</code> for
679
- boolean state management with{" "}
680
- <code className="!text-purple-300">useCallback</code> for
681
- optimized performance.
682
- </p>
683
- <p className="!text-white">
684
- The <code className="!text-purple-300">onOpenChange</code>{" "}
685
- function defaults to toggling the current state when no
686
- parameter is provided, or sets the exact value when a
687
- boolean is passed.
688
- </p>
689
- <p className="!text-white">
690
- <code className="!text-purple-300">useCallback</code>{" "}
691
- prevents unnecessary re-renders by memoizing the state
692
- updater function.
693
- </p>
694
- </div>
695
- </div>
696
- </div>
697
- </div>
698
-
699
- {/* Footer */}
700
- <div className="border-t border-white/10 bg-black/20 backdrop-blur-xl">
701
- <div className="!mx-auto max-w-7xl !px-6 !py-8">
702
- <div className="!space-y-4 text-center">
703
- <p className="!text-white/60">
704
- useChangeState provides an elegant solution for boolean
705
- state management with intelligent defaults and flexible
706
- control options, perfect for any show/hide UI pattern in
707
- React applications.
708
- </p>
709
- <p className="!text-sm !text-white/40">
710
- Optimized, intuitive, and versatile - the essential hook for
711
- managing toggleable component states with precision.
712
- </p>
713
- </div>
714
- </div>
715
- </div>
716
- </div>
717
- </>
349
+ }`,
350
+ notes: [
351
+ "Combines useState for boolean state management with useCallback to produce a stable, memoized handler that avoids unnecessary re-renders.",
352
+ "onOpenChange toggles the current state when called with no argument, or sets the exact boolean value when one is passed — a single function covers both use cases.",
353
+ "Because the default parameter is evaluated at call time, passing undefined explicitly also triggers the toggle behavior, keeping the API predictable.",
354
+ ],
355
+ }}
356
+ />
718
357
  ),
719
358
  },
720
359
  },
721
-
722
360
  tags: ["autodocs"],
723
361
  argTypes: {
724
- title: {
362
+ label: {
725
363
  control: "text",
726
- description: "Title for the demo component",
364
+ description: "Label shown on the status card in the playground",
727
365
  },
728
366
  },
729
367
  }
@@ -731,14 +369,79 @@ export const useChangeState = () => {
731
369
  export default meta
732
370
  type Story = StoryObj<typeof meta>
733
371
 
734
- export const Default: Story = {
735
- args: {
736
- title: "useChangeState Demo",
737
- },
738
- }
372
+ // ─────────────────────────────────────────────────────────────────────────────
373
+ // Story exports
374
+ // ─────────────────────────────────────────────────────────────────────────────
739
375
 
740
376
  export const Playground: Story = {
741
377
  args: {
742
- title: "Toggle State Hook",
378
+ label: "State Label",
743
379
  },
380
+ render: (args) => <ChangeStatePlaygroundDemo {...args} />,
381
+ }
382
+
383
+ export const Interactive: Story = {
384
+ render: () => <ChangeStateInteractiveDemo />,
385
+ }
386
+
387
+ export const UseCases: Story = {
388
+ render: () => (
389
+ <HookUsageCanvas>
390
+ <HookUsageSection title="Modal with Backdrop Close">
391
+ <HookCodeBlock
392
+ code={`function Modal() {
393
+ const { open, onOpenChange } = useChangeState()
394
+ return (
395
+ <>
396
+ <button onClick={() => onOpenChange(true)}>Open</button>
397
+ {open && (
398
+ <div onClick={(e) => e.target === e.currentTarget && onOpenChange(false)}>
399
+ <div>
400
+ <h2>Modal</h2>
401
+ <button onClick={() => onOpenChange(false)}>Close</button>
402
+ </div>
403
+ </div>
404
+ )}
405
+ </>
406
+ )
407
+ }`}
408
+ />
409
+ </HookUsageSection>
410
+
411
+ <HookUsageSection title="Collapsible Section">
412
+ <HookCodeBlock
413
+ code={`function Collapsible({ title, children }) {
414
+ const { open, onOpenChange } = useChangeState()
415
+ return (
416
+ <div>
417
+ <button onClick={() => onOpenChange()}>{title} {open ? "▲" : "▼"}</button>
418
+ {open && <div>{children}</div>}
419
+ </div>
420
+ )
421
+ }`}
422
+ />
423
+ </HookUsageSection>
424
+
425
+ <HookUsageSection title="Feature Flag Toggle">
426
+ <HookCodeBlock
427
+ code={`function FeatureGate({ children }) {
428
+ const { open: enabled, onOpenChange } = useChangeState()
429
+ return (
430
+ <div>
431
+ <label>
432
+ <input
433
+ type="checkbox"
434
+ checked={enabled}
435
+ onChange={(e) => onOpenChange(e.target.checked)}
436
+ />
437
+ Enable feature
438
+ </label>
439
+ {enabled && children}
440
+ </div>
441
+ )
442
+ }`}
443
+ />
444
+ </HookUsageSection>
445
+ </HookUsageCanvas>
446
+ ),
744
447
  }