aural-ui 4.0.1 → 4.1.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 (174) hide show
  1. package/dist/components/aspect-ratio/AspectRatio.stories.tsx +290 -1228
  2. package/dist/components/avatar/Avatar.stories.tsx +219 -235
  3. package/dist/components/badge/Badge.stories.tsx +379 -116
  4. package/dist/components/banner/Banner.stories.tsx +445 -391
  5. package/dist/components/breadcrumb/Breadcrumb.stories.tsx +453 -199
  6. package/dist/components/button/Button.stories.tsx +585 -230
  7. package/dist/components/card/Card.stories.tsx +619 -301
  8. package/dist/components/char-count/CharCount.stories.tsx +350 -248
  9. package/dist/components/checkbox/Checkbox.stories.tsx +309 -167
  10. package/dist/components/chip/Chip.stories.tsx +362 -168
  11. package/dist/components/circular-loader/CircularLoader.stories.tsx +221 -636
  12. package/dist/components/clamp-lines/ClampLines.stories.tsx +246 -117
  13. package/dist/components/collapsible/Collapsible.stories.tsx +391 -252
  14. package/dist/components/command/Command.stories.tsx +530 -867
  15. package/dist/components/dialog/Dialog.stories.tsx +501 -950
  16. package/dist/components/divider/Divider.stories.tsx +264 -527
  17. package/dist/components/dot-loader/DotLoader.stories.tsx +256 -257
  18. package/dist/components/drawer/Drawer.stories.tsx +659 -1023
  19. package/dist/components/dropdown/Dropdown.stories.tsx +643 -1028
  20. package/dist/components/form/Form.stories.tsx +560 -274
  21. package/dist/components/helper-text/HelperText.stories.tsx +199 -200
  22. package/dist/components/hover-card/HoverCard.stories.tsx +318 -1254
  23. package/dist/components/icon-button/IconButton.stories.tsx +837 -194
  24. package/dist/components/if-else/if-else.stories.tsx +370 -83
  25. package/dist/components/input/Input.stories.tsx +436 -368
  26. package/dist/components/label/Label.stories.tsx +156 -154
  27. package/dist/components/list/List.stories.tsx +484 -835
  28. package/dist/components/marquee/Marquee.stories.tsx +356 -712
  29. package/dist/components/otp-inputs/OtpInputs.stories.tsx +352 -422
  30. package/dist/components/overlay/Overlay.stories.tsx +452 -824
  31. package/dist/components/pagination/Pagination.stories.tsx +721 -210
  32. package/dist/components/popover/Popover.stories.tsx +481 -896
  33. package/dist/components/radio/Radio.stories.tsx +432 -124
  34. package/dist/components/resizable/Resizable.stories.tsx +495 -799
  35. package/dist/components/scroll-area/ScrollArea.stories.tsx +383 -1059
  36. package/dist/components/search/Search.stories.tsx +312 -595
  37. package/dist/components/select/Select.stories.tsx +684 -789
  38. package/dist/components/sheet/Sheet.stories.tsx +671 -950
  39. package/dist/components/skelton/Skelton.stories.tsx +230 -764
  40. package/dist/components/slider/Slider.stories.tsx +383 -760
  41. package/dist/components/stepper/Stepper.stories.tsx +371 -514
  42. package/dist/components/switch/Switch.stories.tsx +461 -208
  43. package/dist/components/switch-case/SwitchCase.stories.tsx +367 -188
  44. package/dist/components/table/Table.stories.tsx +770 -916
  45. package/dist/components/tabs/Tabs.stories.tsx +458 -1455
  46. package/dist/components/tag/Tag.stories.tsx +714 -542
  47. package/dist/components/textarea/TextArea.stories.tsx +621 -562
  48. package/dist/components/thumbnail-tags/ThumbnailTags.stories.tsx +228 -154
  49. package/dist/components/toast/Toast.stories.tsx +452 -1339
  50. package/dist/components/toggle/Toggle.stories.tsx +488 -931
  51. package/dist/components/tooltip/Tooltip.stories.tsx +344 -1388
  52. package/dist/components/typography/Typography.stories.tsx +406 -89
  53. package/dist/hooks/use-change-state/UseChangeState.stories.tsx +309 -606
  54. package/dist/hooks/use-previous/UsePrevious.stories.tsx +367 -917
  55. package/dist/hooks/use-standalone-pagination/UseStandalonePagination.stories.tsx +639 -867
  56. package/dist/icons/Icons.stories.tsx +0 -12
  57. package/dist/icons/ai-avatar-icon/AiAvatarIcon.stories.tsx +223 -1060
  58. package/dist/icons/alert-icon/AlertIcon.stories.tsx +106 -968
  59. package/dist/icons/all-icons.tsx +37 -16
  60. package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +137 -1010
  61. package/dist/icons/apple-logo-icon/AppleLogoIcon.stories.tsx +145 -935
  62. package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +132 -1046
  63. package/dist/icons/arrow-corner-up-left-icon/ArrowCornerUpLeftIcon.stories.tsx +134 -986
  64. package/dist/icons/arrow-corner-up-right-icon/ArrowCornerUpRightIcon.stories.tsx +135 -1028
  65. package/dist/icons/arrow-left-icon/ArrowLeftIcon.stories.tsx +133 -971
  66. package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +145 -1123
  67. package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +143 -1252
  68. package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +123 -632
  69. package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +141 -1223
  70. package/dist/icons/backward-ten-seconds-icon/BackwardTenSecondsIcon.stories.tsx +164 -1018
  71. package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +121 -1236
  72. package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +121 -1213
  73. package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +116 -893
  74. package/dist/icons/camera-icon/CameraIcon.stories.tsx +109 -1254
  75. package/dist/icons/capital-a-letter-icon/CapitalALetterIcon.stories.tsx +114 -975
  76. package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +157 -994
  77. package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +160 -992
  78. package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +140 -970
  79. package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +126 -993
  80. package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +144 -987
  81. package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +141 -1007
  82. package/dist/icons/circle-tick-icon/CircleTickIcon.stories.tsx +147 -1187
  83. package/dist/icons/circular-play-icon/CircularPlayIcon.stories.tsx +110 -476
  84. package/dist/icons/coin-icon/CoinIcon.stories.tsx +120 -1364
  85. package/dist/icons/coin-toons-icon/CoinToonsIcon.stories.tsx +113 -1360
  86. package/dist/icons/column-wide-add-icon/ColumnWideAddIcon.stories.tsx +111 -942
  87. package/dist/icons/command-icon/CommandIcon.stories.tsx +124 -1087
  88. package/dist/icons/copy-icon/CopyIcon.stories.tsx +119 -996
  89. package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +144 -1046
  90. package/dist/icons/cross-icon/CrossIcon.stories.tsx +136 -999
  91. package/dist/icons/download-icon/DownloadIcon.stories.tsx +123 -857
  92. package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +121 -1080
  93. package/dist/icons/email-icon/EmailIcon.stories.tsx +112 -979
  94. package/dist/icons/expand-icon/ExpandIcon.stories.tsx +109 -1146
  95. package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +141 -1068
  96. package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +140 -1081
  97. package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +124 -1050
  98. package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +123 -1091
  99. package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +122 -633
  100. package/dist/icons/filter-bar-row-icon/FilterBarRowIcon.stories.tsx +116 -1087
  101. package/dist/icons/forward-ten-seconds-icon/ForwardTenSecondsIcon.stories.tsx +166 -1020
  102. package/dist/icons/git-branch-icon/GitBranchIcon.stories.tsx +112 -1182
  103. package/dist/icons/git-fork-icon/GitForkIcon.stories.tsx +112 -1155
  104. package/dist/icons/globe-icon/GlobeIcon.stories.tsx +127 -325
  105. package/dist/icons/google-logo-icon/GoogleLogoIcon.stories.tsx +142 -985
  106. package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +116 -1217
  107. package/dist/icons/head-icon/HeadIcon.stories.tsx +108 -953
  108. package/dist/icons/heart-icon/HeartIcon.stories.tsx +117 -1060
  109. package/dist/icons/image-avatar-sparkle-icon/ImageAvatarSparkleIcon.stories.tsx +116 -716
  110. package/dist/icons/image-icon/ImageIcon.stories.tsx +102 -1164
  111. package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +108 -1233
  112. package/dist/icons/import-left-arrow-folder-icon/ImportLeftArrowFolderIcon.stories.tsx +133 -1289
  113. package/dist/icons/indian-flag-icon/IndianFlagIcon.stories.tsx +155 -1012
  114. package/dist/icons/instagram-icon/InstagramIcon.stories.tsx +158 -1438
  115. package/dist/icons/layout-column-icon/LayoutColumnIcon.stories.tsx +121 -1011
  116. package/dist/icons/layout-left-icon/LayoutLeftIcon.stories.tsx +116 -981
  117. package/dist/icons/layout-right-icon/LayoutRightIcon.stories.tsx +116 -979
  118. package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +105 -1252
  119. package/dist/icons/linked-in-icon/LinkedInIcon.stories.tsx +151 -1554
  120. package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +107 -1227
  121. package/dist/icons/magic-edit-icon/MagicEditIcon.stories.tsx +116 -707
  122. package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +119 -1226
  123. package/dist/icons/message-icon/MessageIcon.stories.tsx +111 -557
  124. package/dist/icons/minimize-icon/MinimizeIcon.stories.tsx +112 -1198
  125. package/dist/icons/moon-icon/MoonIcon.stories.tsx +117 -557
  126. package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +106 -1235
  127. package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +112 -1185
  128. package/dist/icons/musical-note-icon/MusicalNoteIcon.stories.tsx +116 -1012
  129. package/dist/icons/notepad-icon/NotepadIcon.stories.tsx +108 -1137
  130. package/dist/icons/notes-icon/NotesIcon.stories.tsx +116 -1138
  131. package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +106 -1146
  132. package/dist/icons/page-text-icon/PageTextIcon.stories.tsx +119 -719
  133. package/dist/icons/paint-roll-icon/PaintRollIcon.stories.tsx +110 -999
  134. package/dist/icons/paper-plane-icon/PaperPlaneIcon.stories.tsx +109 -912
  135. package/dist/icons/pause-icon/PauseIcon.stories.tsx +110 -1041
  136. package/dist/icons/pencil-icon/PencilIcon.stories.tsx +112 -1109
  137. package/dist/icons/phone-icon/PhoneIcon.stories.tsx +112 -1023
  138. package/dist/icons/plus-icon/PlusIcon.stories.tsx +103 -1132
  139. package/dist/icons/pocket-studio-icon/PocketStudioIcon.stories.tsx +104 -870
  140. package/dist/icons/scroll-down-icon/ScrollDownIcon.stories.tsx +99 -476
  141. package/dist/icons/search-icon/SearchIcon.stories.tsx +108 -1161
  142. package/dist/icons/setting-icon/SettingIcon.stories.tsx +104 -1009
  143. package/dist/icons/share-icon/ShareIcon.stories.tsx +117 -1064
  144. package/dist/icons/shield-icon/ShieldIcon.stories.tsx +114 -974
  145. package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +134 -1160
  146. package/dist/icons/skip-backward-icon/SkipBackwardIcon.stories.tsx +169 -1017
  147. package/dist/icons/skip-forward-icon/SkipForwardIcon.stories.tsx +161 -1016
  148. package/dist/icons/sparkles-soft-icon/SparklesSoftIcon.stories.tsx +102 -1001
  149. package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +155 -593
  150. package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +155 -608
  151. package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +142 -712
  152. package/dist/icons/star-icon/StarIcon.stories.tsx +120 -946
  153. package/dist/icons/store-coin-icon/StoreCoinIcon.stories.tsx +109 -1013
  154. package/dist/icons/suggestion-icon/SuggestionIcon.stories.tsx +113 -891
  155. package/dist/icons/sun-icon/SunIcon.stories.tsx +117 -864
  156. package/dist/icons/text-color-icon/TextColorIcon.stories.tsx +113 -989
  157. package/dist/icons/text-indicator-icon/TextIndicatorIcon.stories.tsx +120 -1027
  158. package/dist/icons/threads-icon/ThreadsIcon.stories.tsx +153 -1476
  159. package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +143 -1187
  160. package/dist/icons/tick-icon/TickIcon.stories.tsx +142 -1322
  161. package/dist/icons/trash-icon/TrashIcon.stories.tsx +105 -970
  162. package/dist/icons/twitter-x-icon/TwitterXIcon.stories.tsx +154 -1457
  163. package/dist/icons/upload-icon/UploadIcon.stories.tsx +112 -930
  164. package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +115 -1019
  165. package/dist/icons/video-play-list-icon/VideoPlaylistIcon.stories.tsx +122 -1092
  166. package/dist/icons/voice-playing-icon/VoicePlayingIcon.stories.tsx +120 -1401
  167. package/dist/icons/volume-full-icon/VolumeFullIcon.stories.tsx +107 -1212
  168. package/dist/icons/volume-half-icon/VolumeHalfIcon.stories.tsx +109 -1122
  169. package/dist/icons/volume-off-icon/VolumeOffIcon.stories.tsx +112 -1124
  170. package/dist/icons/warning-icon/WarningIcon.stories.tsx +119 -1083
  171. package/dist/icons/youtube-icon/YoutubeIcon.stories.tsx +158 -983
  172. package/dist/index.cjs +1 -1
  173. package/dist/index.js +1 -1
  174. package/package.json +1 -1
@@ -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
  }