aural-ui 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +456 -0
- package/dist/components/aspect-ratio/AspectRatio.stories.tsx +1327 -0
- package/dist/components/aspect-ratio/index.tsx +10 -0
- package/dist/components/aspect-ratio/meta.ts +8 -0
- package/dist/components/avatar/Avatar.stories.tsx +645 -0
- package/dist/components/avatar/index.tsx +50 -0
- package/dist/components/avatar/meta.ts +8 -0
- package/dist/components/badge/Badge.stories.tsx +169 -0
- package/dist/components/badge/index.tsx +28 -0
- package/dist/components/badge/meta.ts +6 -0
- package/dist/components/banner/Banner.stories.tsx +475 -0
- package/dist/components/banner/index.tsx +256 -0
- package/dist/components/banner/meta.ts +36 -0
- package/dist/components/button/Button.stories.tsx +74 -0
- package/dist/components/button/index.tsx +158 -0
- package/dist/components/button/meta.ts +33 -0
- package/dist/components/card/Card.stories.tsx +377 -0
- package/dist/components/card/index.tsx +85 -0
- package/dist/components/card/meta.ts +14 -0
- package/dist/components/char-count/CharCount.stories.tsx +334 -0
- package/dist/components/char-count/index.tsx +51 -0
- package/dist/components/char-count/meta.ts +13 -0
- package/dist/components/checkbox/Checkbox.stories.tsx +209 -0
- package/dist/components/checkbox/index.tsx +34 -0
- package/dist/components/checkbox/meta.ts +19 -0
- package/dist/components/chip/Chip.stories.tsx +207 -0
- package/dist/components/chip/index.tsx +92 -0
- package/dist/components/chip/meta.ts +17 -0
- package/dist/components/circular-loader/CircularLoader.stories.tsx +741 -0
- package/dist/components/circular-loader/index.tsx +138 -0
- package/dist/components/circular-loader/meta.ts +11 -0
- package/dist/components/collapsible/Collapsible.stories.tsx +319 -0
- package/dist/components/collapsible/index.tsx +158 -0
- package/dist/components/collapsible/meta.ts +22 -0
- package/dist/components/command/Command.stories.tsx +996 -0
- package/dist/components/command/index.tsx +324 -0
- package/dist/components/command/meta.ts +18 -0
- package/dist/components/dialog/Dialog.stories.tsx +963 -0
- package/dist/components/dialog/index.tsx +250 -0
- package/dist/components/dialog/meta.ts +28 -0
- package/dist/components/divider/Divider.stories.tsx +633 -0
- package/dist/components/divider/index.tsx +181 -0
- package/dist/components/divider/meta.ts +12 -0
- package/dist/components/dot-loader/DotLoader.stories.tsx +352 -0
- package/dist/components/dot-loader/index.tsx +78 -0
- package/dist/components/dot-loader/meta.ts +14 -0
- package/dist/components/dropdown/Dropdown.stories.tsx +1210 -0
- package/dist/components/dropdown/index.tsx +479 -0
- package/dist/components/dropdown/meta.ts +21 -0
- package/dist/components/form/Form.stories.tsx +320 -0
- package/dist/components/form/index.tsx +183 -0
- package/dist/components/form/meta.ts +11 -0
- package/dist/components/helper-text/HelperText.stories.tsx +254 -0
- package/dist/components/helper-text/index.tsx +102 -0
- package/dist/components/helper-text/meta.ts +18 -0
- package/dist/components/hover-card/HoverCard.stories.tsx +1328 -0
- package/dist/components/hover-card/index.tsx +42 -0
- package/dist/components/hover-card/meta.ts +12 -0
- package/dist/components/icon-button/IconButton.stories.tsx +252 -0
- package/dist/components/icon-button/index.tsx +130 -0
- package/dist/components/icon-button/meta.ts +20 -0
- package/dist/components/if-else/if-else.stories.tsx +100 -0
- package/dist/components/if-else/index.tsx +56 -0
- package/dist/components/if-else/meta.ts +6 -0
- package/dist/components/index.ts +70 -0
- package/dist/components/input/Input.stories.tsx +431 -0
- package/dist/components/input/index.tsx +487 -0
- package/dist/components/input/meta.ts +28 -0
- package/dist/components/label/Label.stories.tsx +200 -0
- package/dist/components/label/index.tsx +43 -0
- package/dist/components/label/meta.ts +14 -0
- package/dist/components/list/List.stories.tsx +963 -0
- package/dist/components/list/index.tsx +567 -0
- package/dist/components/list/meta.ts +24 -0
- package/dist/components/marquee/Marquee.stories.tsx +819 -0
- package/dist/components/marquee/index.tsx +107 -0
- package/dist/components/marquee/meta.ts +6 -0
- package/dist/components/overlay/Overlay.stories.tsx +954 -0
- package/dist/components/overlay/index.tsx +58 -0
- package/dist/components/overlay/meta.ts +10 -0
- package/dist/components/pagination/Pagination.stories.tsx +354 -0
- package/dist/components/pagination/index.tsx +455 -0
- package/dist/components/pagination/meta.ts +29 -0
- package/dist/components/popover/Popover.stories.tsx +1037 -0
- package/dist/components/popover/index.tsx +67 -0
- package/dist/components/popover/meta.ts +12 -0
- package/dist/components/radio/Radio.stories.tsx +146 -0
- package/dist/components/radio/index.tsx +41 -0
- package/dist/components/radio/meta.ts +19 -0
- package/dist/components/resizable/Resizable.stories.tsx +866 -0
- package/dist/components/resizable/index.tsx +55 -0
- package/dist/components/resizable/meta.ts +12 -0
- package/dist/components/scroll-area/ScrollArea.stories.tsx +1104 -0
- package/dist/components/scroll-area/index.tsx +55 -0
- package/dist/components/scroll-area/meta.ts +8 -0
- package/dist/components/search/Search.stories.tsx +678 -0
- package/dist/components/search/index.tsx +141 -0
- package/dist/components/search/meta.ts +6 -0
- package/dist/components/select/Select.stories.tsx +962 -0
- package/dist/components/select/index.tsx +512 -0
- package/dist/components/select/meta.ts +40 -0
- package/dist/components/sheet/Sheet.stories.tsx +1060 -0
- package/dist/components/sheet/index.tsx +440 -0
- package/dist/components/sheet/meta.ts +38 -0
- package/dist/components/skelton/Skelton.stories.tsx +859 -0
- package/dist/components/skelton/index.tsx +17 -0
- package/dist/components/skelton/meta.ts +6 -0
- package/dist/components/slider/Slider.stories.tsx +876 -0
- package/dist/components/slider/index.tsx +156 -0
- package/dist/components/slider/meta.ts +29 -0
- package/dist/components/stepper/Stepper.stories.tsx +639 -0
- package/dist/components/stepper/index.tsx +650 -0
- package/dist/components/stepper/meta.ts +19 -0
- package/dist/components/switch/Switch.stories.tsx +85 -0
- package/dist/components/switch/index.tsx +37 -0
- package/dist/components/switch/meta.ts +24 -0
- package/dist/components/switch-case/SwitchCase.stories.tsx +209 -0
- package/dist/components/switch-case/index.tsx +89 -0
- package/dist/components/switch-case/meta.ts +6 -0
- package/dist/components/table/Table.stories.tsx +1095 -0
- package/dist/components/table/index.tsx +113 -0
- package/dist/components/table/meta.ts +20 -0
- package/dist/components/tabs/Tabs.stories.tsx +1379 -0
- package/dist/components/tabs/index.tsx +186 -0
- package/dist/components/tabs/meta.ts +25 -0
- package/dist/components/tag/Tag.stories.tsx +625 -0
- package/dist/components/tag/index.tsx +320 -0
- package/dist/components/tag/meta.ts +52 -0
- package/dist/components/textarea/TextArea.stories.tsx +723 -0
- package/dist/components/textarea/index.tsx +480 -0
- package/dist/components/textarea/meta.ts +23 -0
- package/dist/components/toast/Toast.stories.tsx +1427 -0
- package/dist/components/toast/index.tsx +26 -0
- package/dist/components/toast/meta.ts +19 -0
- package/dist/components/toggle/Toggle.stories.tsx +1093 -0
- package/dist/components/toggle/index.tsx +44 -0
- package/dist/components/toggle/meta.ts +19 -0
- package/dist/components/tooltip/Tooltip.stories.tsx +1548 -0
- package/dist/components/tooltip/index.tsx +304 -0
- package/dist/components/tooltip/meta.ts +21 -0
- package/dist/components/typography/Typography.stories.tsx +197 -0
- package/dist/components/typography/index.tsx +184 -0
- package/dist/components/typography/meta.ts +38 -0
- package/dist/fonts/LabGrotesque-Regular.ttf +0 -0
- package/dist/fonts/LabGrotesqueTRIAL-Bold.otf +0 -0
- package/dist/fonts/LabGrotesqueTRIAL-Light.otf +0 -0
- package/dist/fonts/LabGrotesqueTRIAL-Medium.otf +0 -0
- package/dist/fonts/LabGrotesqueTRIAL-Regular.otf +0 -0
- package/dist/fonts/PPSupplySans-Regular (1).otf +0 -0
- package/dist/fonts/PPSupplySans-Regular.otf +0 -0
- package/dist/fonts/PPSupplySans-Ultralight.otf +0 -0
- package/dist/hooks/index.ts +3 -0
- package/dist/hooks/use-previous/UsePrevious.stories.tsx +997 -0
- package/dist/hooks/use-previous/index.ts +15 -0
- package/dist/hooks/use-previous/meta.ts +6 -0
- package/dist/hooks/use-standalone-pagination/UseStandalonePagination.stories.tsx +983 -0
- package/dist/hooks/use-standalone-pagination/index.ts +146 -0
- package/dist/hooks/use-standalone-pagination/meta.ts +6 -0
- package/dist/icons/Icons.stories.tsx +29 -0
- package/dist/icons/alert-icon/AlertIcon.stories.tsx +991 -0
- package/dist/icons/alert-icon/index.tsx +48 -0
- package/dist/icons/alert-icon/meta.ts +8 -0
- package/dist/icons/all-icons.tsx +738 -0
- package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +1031 -0
- package/dist/icons/angle-down-icon/index.tsx +25 -0
- package/dist/icons/angle-down-icon/meta.ts +8 -0
- package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +1080 -0
- package/dist/icons/arrow-box-left-icon/index.tsx +24 -0
- package/dist/icons/arrow-box-left-icon/meta.ts +8 -0
- package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +1151 -0
- package/dist/icons/arrow-right-icon/index.tsx +26 -0
- package/dist/icons/arrow-right-icon/meta.ts +8 -0
- package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +1273 -0
- package/dist/icons/arrow-right-up-icon/index.tsx +24 -0
- package/dist/icons/arrow-right-up-icon/meta.ts +8 -0
- package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +670 -0
- package/dist/icons/art-board-icon/index.tsx +24 -0
- package/dist/icons/art-board-icon/meta.ts +7 -0
- package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +1244 -0
- package/dist/icons/audio-bar-icon/index.tsx +19 -0
- package/dist/icons/audio-bar-icon/meta.ts +8 -0
- package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +1239 -0
- package/dist/icons/bubble-check-icon/index.tsx +24 -0
- package/dist/icons/bubble-check-icon/meta.ts +8 -0
- package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +1228 -0
- package/dist/icons/bubble-crossed-icon/index.tsx +24 -0
- package/dist/icons/bubble-crossed-icon/meta.ts +8 -0
- package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +912 -0
- package/dist/icons/bubble-sparkle-icon/index.tsx +26 -0
- package/dist/icons/bubble-sparkle-icon/meta.ts +8 -0
- package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +1021 -0
- package/dist/icons/chevron-double-left-icon/index.tsx +34 -0
- package/dist/icons/chevron-double-left-icon/meta.ts +8 -0
- package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +1021 -0
- package/dist/icons/chevron-double-right-icon/index.tsx +34 -0
- package/dist/icons/chevron-double-right-icon/meta.ts +8 -0
- package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +1001 -0
- package/dist/icons/chevron-down-icon/index.tsx +27 -0
- package/dist/icons/chevron-down-icon/meta.ts +8 -0
- package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +1029 -0
- package/dist/icons/chevron-left-icon/index.tsx +27 -0
- package/dist/icons/chevron-left-icon/meta.ts +8 -0
- package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +1021 -0
- package/dist/icons/chevron-right-icon/index.tsx +27 -0
- package/dist/icons/chevron-right-icon/meta.ts +8 -0
- package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +1036 -0
- package/dist/icons/chevron-up-icon/index.tsx +27 -0
- package/dist/icons/chevron-up-icon/meta.ts +8 -0
- package/dist/icons/command-icon/CommandIcon.stories.tsx +1098 -0
- package/dist/icons/command-icon/index.tsx +24 -0
- package/dist/icons/command-icon/meta.ts +8 -0
- package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +1061 -0
- package/dist/icons/cross-circle-icon/index.tsx +23 -0
- package/dist/icons/cross-circle-icon/meta.ts +8 -0
- package/dist/icons/cross-icon/CrossIcon.stories.tsx +1027 -0
- package/dist/icons/cross-icon/index.tsx +24 -0
- package/dist/icons/cross-icon/meta.ts +8 -0
- package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +1092 -0
- package/dist/icons/edit-big-icon/index.tsx +22 -0
- package/dist/icons/edit-big-icon/meta.ts +8 -0
- package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +1090 -0
- package/dist/icons/eye-close-icon/index.tsx +26 -0
- package/dist/icons/eye-close-icon/meta.ts +8 -0
- package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +1098 -0
- package/dist/icons/eye-open-icon/index.tsx +24 -0
- package/dist/icons/eye-open-icon/meta.ts +8 -0
- package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +1071 -0
- package/dist/icons/feature-shine-icon/index.tsx +29 -0
- package/dist/icons/feature-shine-icon/meta.ts +8 -0
- package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +1115 -0
- package/dist/icons/file-chart-icon/index.tsx +24 -0
- package/dist/icons/file-chart-icon/meta.ts +8 -0
- package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +668 -0
- package/dist/icons/file-text-icon/index.tsx +24 -0
- package/dist/icons/file-text-icon/meta.ts +8 -0
- package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +1239 -0
- package/dist/icons/grip-vertical-icon/index.tsx +28 -0
- package/dist/icons/grip-vertical-icon/meta.ts +8 -0
- package/dist/icons/image-icon/ImageIcon.stories.tsx +1181 -0
- package/dist/icons/image-icon/index.tsx +24 -0
- package/dist/icons/image-icon/meta.ts +8 -0
- package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +1248 -0
- package/dist/icons/import-folder-icon/index.tsx +22 -0
- package/dist/icons/import-folder-icon/meta.ts +8 -0
- package/dist/icons/index.ts +46 -0
- package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +1272 -0
- package/dist/icons/light-bulb-simple-icon/index.tsx +24 -0
- package/dist/icons/light-bulb-simple-icon/meta.ts +8 -0
- package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +1245 -0
- package/dist/icons/magic-book-icon/index.tsx +32 -0
- package/dist/icons/magic-book-icon/meta.ts +8 -0
- package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +1251 -0
- package/dist/icons/maintenance-icon/index.tsx +23 -0
- package/dist/icons/maintenance-icon/meta.ts +8 -0
- package/dist/icons/message-icon/MessageIcon.stories.tsx +595 -0
- package/dist/icons/message-icon/index.tsx +30 -0
- package/dist/icons/message-icon/meta.ts +8 -0
- package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +1245 -0
- package/dist/icons/move-horizontal-icon/index.tsx +23 -0
- package/dist/icons/move-horizontal-icon/meta.ts +8 -0
- package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +1196 -0
- package/dist/icons/move-vertical-icon/index.tsx +23 -0
- package/dist/icons/move-vertical-icon/meta.ts +8 -0
- package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +1167 -0
- package/dist/icons/page-search-icon/index.tsx +21 -0
- package/dist/icons/page-search-icon/meta.ts +8 -0
- package/dist/icons/pencil-icon/PencilIcon.stories.tsx +1131 -0
- package/dist/icons/pencil-icon/index.tsx +21 -0
- package/dist/icons/pencil-icon/meta.ts +8 -0
- package/dist/icons/plus-icon/PlusIcon.stories.tsx +1151 -0
- package/dist/icons/plus-icon/index.tsx +24 -0
- package/dist/icons/plus-icon/meta.ts +8 -0
- package/dist/icons/search-icon/SearchIcon.stories.tsx +1181 -0
- package/dist/icons/search-icon/index.tsx +24 -0
- package/dist/icons/search-icon/meta.ts +8 -0
- package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +1167 -0
- package/dist/icons/site-logo-icon/index.tsx +79 -0
- package/dist/icons/site-logo-icon/meta.ts +8 -0
- package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +637 -0
- package/dist/icons/spinner-gradient-icon/index.tsx +53 -0
- package/dist/icons/spinner-gradient-icon/meta.ts +8 -0
- package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +644 -0
- package/dist/icons/spinner-solid-icon/index.tsx +59 -0
- package/dist/icons/spinner-solid-icon/meta.ts +8 -0
- package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +736 -0
- package/dist/icons/spinner-solid-neutral-icon/index.tsx +53 -0
- package/dist/icons/spinner-solid-neutral-icon/meta.ts +8 -0
- package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +1204 -0
- package/dist/icons/tick-circle-icon/index.tsx +23 -0
- package/dist/icons/tick-circle-icon/meta.ts +8 -0
- package/dist/icons/tick-icon/TickIcon.stories.tsx +1340 -0
- package/dist/icons/tick-icon/index.tsx +24 -0
- package/dist/icons/tick-icon/meta.ts +8 -0
- package/dist/icons/trash-icon/TrashIcon.stories.tsx +996 -0
- package/dist/icons/trash-icon/index.tsx +24 -0
- package/dist/icons/trash-icon/meta.ts +8 -0
- package/dist/icons/upload-icon/UploadIcon.stories.tsx +947 -0
- package/dist/icons/upload-icon/index.tsx +24 -0
- package/dist/icons/upload-icon/meta.ts +8 -0
- package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +1045 -0
- package/dist/icons/vertical-menu-icon/index.tsx +27 -0
- package/dist/icons/vertical-menu-icon/meta.ts +8 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +206 -0
- package/dist/lib/utils.ts +6 -0
- package/dist/styles/aural-theme.css +1008 -0
- package/package.json +142 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import React, { useState } from "react"
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
3
|
+
|
|
4
|
+
import CharCount from "."
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof CharCount> = {
|
|
7
|
+
title: "Components/UI/CharCount",
|
|
8
|
+
component: CharCount,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: "centered",
|
|
11
|
+
},
|
|
12
|
+
tags: ["autodocs"],
|
|
13
|
+
argTypes: {
|
|
14
|
+
currentLength: {
|
|
15
|
+
control: { type: "number", min: 0 },
|
|
16
|
+
description: "Current character count",
|
|
17
|
+
},
|
|
18
|
+
maxLength: {
|
|
19
|
+
control: { type: "number", min: 0 },
|
|
20
|
+
description: "Maximum allowed characters (optional)",
|
|
21
|
+
},
|
|
22
|
+
className: {
|
|
23
|
+
control: { type: "text" },
|
|
24
|
+
description: "Additional CSS classes to apply",
|
|
25
|
+
},
|
|
26
|
+
"aria-live": {
|
|
27
|
+
control: { type: "select" },
|
|
28
|
+
options: ["polite", "assertive", "off"],
|
|
29
|
+
description: "ARIA live region announcement behavior",
|
|
30
|
+
},
|
|
31
|
+
id: {
|
|
32
|
+
control: { type: "text" },
|
|
33
|
+
description: "HTML id attribute for accessibility",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default meta
|
|
39
|
+
type Story = StoryObj<typeof meta>
|
|
40
|
+
|
|
41
|
+
export const Default: Story = {
|
|
42
|
+
args: {
|
|
43
|
+
currentLength: 25,
|
|
44
|
+
maxLength: 100,
|
|
45
|
+
"aria-live": "polite",
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const WithoutMaxLength: Story = {
|
|
50
|
+
args: {
|
|
51
|
+
currentLength: 42,
|
|
52
|
+
"aria-live": "polite",
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const NearLimit: Story = {
|
|
57
|
+
args: {
|
|
58
|
+
currentLength: 92,
|
|
59
|
+
maxLength: 100,
|
|
60
|
+
"aria-live": "polite",
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const OverLimit: Story = {
|
|
65
|
+
args: {
|
|
66
|
+
currentLength: 105,
|
|
67
|
+
maxLength: 100,
|
|
68
|
+
"aria-live": "assertive",
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const Zero: Story = {
|
|
73
|
+
args: {
|
|
74
|
+
currentLength: 0,
|
|
75
|
+
maxLength: 50,
|
|
76
|
+
"aria-live": "polite",
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const ExactLimit: Story = {
|
|
81
|
+
args: {
|
|
82
|
+
currentLength: 100,
|
|
83
|
+
maxLength: 100,
|
|
84
|
+
"aria-live": "polite",
|
|
85
|
+
},
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export const LargeNumbers: Story = {
|
|
89
|
+
args: {
|
|
90
|
+
currentLength: 2847,
|
|
91
|
+
maxLength: 5000,
|
|
92
|
+
"aria-live": "polite",
|
|
93
|
+
},
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const WithCustomClassName: Story = {
|
|
97
|
+
args: {
|
|
98
|
+
currentLength: 30,
|
|
99
|
+
maxLength: 100,
|
|
100
|
+
className: "!text-blue-600 !text-lg",
|
|
101
|
+
"aria-live": "polite",
|
|
102
|
+
},
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Showcase all states together
|
|
106
|
+
export const AllStates: Story = {
|
|
107
|
+
render: () => (
|
|
108
|
+
<div className="w-96 space-y-6">
|
|
109
|
+
<div>
|
|
110
|
+
<h3 className="mb-2 text-sm font-medium">Normal State (25/100)</h3>
|
|
111
|
+
<CharCount currentLength={25} maxLength={100} />
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<div>
|
|
115
|
+
<h3 className="mb-2 text-sm font-medium">Warning State (92/100)</h3>
|
|
116
|
+
<CharCount currentLength={92} maxLength={100} />
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<div>
|
|
120
|
+
<h3 className="mb-2 text-sm font-medium">Error State (105/100)</h3>
|
|
121
|
+
<CharCount currentLength={105} maxLength={100} />
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div>
|
|
125
|
+
<h3 className="mb-2 text-sm font-medium">Without Max Length (42)</h3>
|
|
126
|
+
<CharCount currentLength={42} />
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<div>
|
|
130
|
+
<h3 className="mb-2 text-sm font-medium">Zero Characters (0/50)</h3>
|
|
131
|
+
<CharCount currentLength={0} maxLength={50} />
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
<div>
|
|
135
|
+
<h3 className="mb-2 text-sm font-medium">Exact Limit (100/100)</h3>
|
|
136
|
+
<CharCount currentLength={100} maxLength={100} />
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
),
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Interactive example with textarea
|
|
143
|
+
export const WithTextarea: Story = {
|
|
144
|
+
render: () => {
|
|
145
|
+
const [text, setText] = useState("")
|
|
146
|
+
const maxLength = 140
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<div className="w-96 space-y-4">
|
|
150
|
+
<div>
|
|
151
|
+
<label className="mb-2 block text-sm font-medium">
|
|
152
|
+
Tweet Message
|
|
153
|
+
</label>
|
|
154
|
+
<textarea
|
|
155
|
+
value={text}
|
|
156
|
+
onChange={(e) => setText(e.target.value)}
|
|
157
|
+
className="w-full resize-none rounded-md border border-gray-300 px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
158
|
+
placeholder="What's happening?"
|
|
159
|
+
rows={4}
|
|
160
|
+
aria-describedby="tweet-count"
|
|
161
|
+
/>
|
|
162
|
+
<div className="mt-2 flex justify-end">
|
|
163
|
+
<CharCount
|
|
164
|
+
currentLength={text.length}
|
|
165
|
+
maxLength={maxLength}
|
|
166
|
+
id="tweet-count"
|
|
167
|
+
aria-live="polite"
|
|
168
|
+
/>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
)
|
|
173
|
+
},
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Interactive example with input
|
|
177
|
+
export const WithInput: Story = {
|
|
178
|
+
render: () => {
|
|
179
|
+
const [username, setUsername] = useState("")
|
|
180
|
+
const maxLength = 20
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<div className="w-96 space-y-4">
|
|
184
|
+
<div>
|
|
185
|
+
<label className="mb-2 block text-sm font-medium">Username</label>
|
|
186
|
+
<input
|
|
187
|
+
type="text"
|
|
188
|
+
value={username}
|
|
189
|
+
onChange={(e) => setUsername(e.target.value)}
|
|
190
|
+
className="w-full rounded-md border border-gray-300 px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
191
|
+
placeholder="Enter username"
|
|
192
|
+
aria-describedby="username-count"
|
|
193
|
+
/>
|
|
194
|
+
<div className="mt-2 flex items-center justify-between">
|
|
195
|
+
<span className="text-sm text-gray-500">
|
|
196
|
+
Must be unique and memorable
|
|
197
|
+
</span>
|
|
198
|
+
<CharCount
|
|
199
|
+
currentLength={username.length}
|
|
200
|
+
maxLength={maxLength}
|
|
201
|
+
id="username-count"
|
|
202
|
+
aria-live="polite"
|
|
203
|
+
/>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
)
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Multiple inputs with different limits
|
|
212
|
+
export const MultipleInputs: Story = {
|
|
213
|
+
render: () => {
|
|
214
|
+
const [title, setTitle] = useState("")
|
|
215
|
+
const [description, setDescription] = useState("")
|
|
216
|
+
const [tags, setTags] = useState("")
|
|
217
|
+
|
|
218
|
+
return (
|
|
219
|
+
<div className="w-96 space-y-6">
|
|
220
|
+
<div>
|
|
221
|
+
<label className="mb-2 block text-sm font-medium">Post Title</label>
|
|
222
|
+
<input
|
|
223
|
+
type="text"
|
|
224
|
+
value={title}
|
|
225
|
+
onChange={(e) => setTitle(e.target.value)}
|
|
226
|
+
className="w-full rounded-md border border-gray-300 px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
227
|
+
placeholder="Enter post title"
|
|
228
|
+
aria-describedby="title-count"
|
|
229
|
+
/>
|
|
230
|
+
<div className="mt-1 flex justify-end">
|
|
231
|
+
<CharCount
|
|
232
|
+
currentLength={title.length}
|
|
233
|
+
maxLength={60}
|
|
234
|
+
id="title-count"
|
|
235
|
+
/>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
|
|
239
|
+
<div>
|
|
240
|
+
<label className="mb-2 block text-sm font-medium">Description</label>
|
|
241
|
+
<textarea
|
|
242
|
+
value={description}
|
|
243
|
+
onChange={(e) => setDescription(e.target.value)}
|
|
244
|
+
className="w-full resize-none rounded-md border border-gray-300 px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
245
|
+
placeholder="Describe your post"
|
|
246
|
+
rows={3}
|
|
247
|
+
aria-describedby="description-count"
|
|
248
|
+
/>
|
|
249
|
+
<div className="mt-1 flex justify-end">
|
|
250
|
+
<CharCount
|
|
251
|
+
currentLength={description.length}
|
|
252
|
+
maxLength={200}
|
|
253
|
+
id="description-count"
|
|
254
|
+
/>
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
|
|
258
|
+
<div>
|
|
259
|
+
<label className="mb-2 block text-sm font-medium">
|
|
260
|
+
Tags (comma separated)
|
|
261
|
+
</label>
|
|
262
|
+
<input
|
|
263
|
+
type="text"
|
|
264
|
+
value={tags}
|
|
265
|
+
onChange={(e) => setTags(e.target.value)}
|
|
266
|
+
className="w-full rounded-md border border-gray-300 px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
267
|
+
placeholder="react, typescript, ui"
|
|
268
|
+
aria-describedby="tags-count"
|
|
269
|
+
/>
|
|
270
|
+
<div className="mt-1 flex items-center justify-between">
|
|
271
|
+
<span className="text-xs text-gray-500">
|
|
272
|
+
Separate tags with commas
|
|
273
|
+
</span>
|
|
274
|
+
<CharCount
|
|
275
|
+
currentLength={tags.length}
|
|
276
|
+
maxLength={50}
|
|
277
|
+
id="tags-count"
|
|
278
|
+
/>
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
</div>
|
|
282
|
+
)
|
|
283
|
+
},
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Accessibility demonstration
|
|
287
|
+
export const AccessibilityExample: Story = {
|
|
288
|
+
render: () => {
|
|
289
|
+
const [message, setMessage] = useState("")
|
|
290
|
+
const maxLength = 100
|
|
291
|
+
const isOverLimit = message.length > maxLength
|
|
292
|
+
|
|
293
|
+
return (
|
|
294
|
+
<div className="w-96 space-y-4">
|
|
295
|
+
<div>
|
|
296
|
+
<label
|
|
297
|
+
htmlFor="accessible-message"
|
|
298
|
+
className="mb-2 block text-sm font-medium"
|
|
299
|
+
>
|
|
300
|
+
Message *
|
|
301
|
+
</label>
|
|
302
|
+
<textarea
|
|
303
|
+
id="accessible-message"
|
|
304
|
+
value={message}
|
|
305
|
+
onChange={(e) => setMessage(e.target.value)}
|
|
306
|
+
className={`w-full resize-none rounded-md border px-3 py-2 focus:ring-2 focus:outline-none ${
|
|
307
|
+
isOverLimit
|
|
308
|
+
? "border-red-300 focus:ring-red-500"
|
|
309
|
+
: "border-gray-300 focus:ring-blue-500"
|
|
310
|
+
}`}
|
|
311
|
+
placeholder="Enter your message"
|
|
312
|
+
rows={4}
|
|
313
|
+
aria-describedby="message-count message-help"
|
|
314
|
+
aria-invalid={isOverLimit}
|
|
315
|
+
required
|
|
316
|
+
/>
|
|
317
|
+
<div className="mt-2 flex items-start justify-between">
|
|
318
|
+
<div id="message-help" className="text-sm text-gray-500">
|
|
319
|
+
{isOverLimit
|
|
320
|
+
? "Message is too long. Please shorten it."
|
|
321
|
+
: "Share your thoughts with the community."}
|
|
322
|
+
</div>
|
|
323
|
+
<CharCount
|
|
324
|
+
currentLength={message.length}
|
|
325
|
+
maxLength={maxLength}
|
|
326
|
+
id="message-count"
|
|
327
|
+
aria-live={isOverLimit ? "assertive" : "polite"}
|
|
328
|
+
/>
|
|
329
|
+
</div>
|
|
330
|
+
</div>
|
|
331
|
+
</div>
|
|
332
|
+
)
|
|
333
|
+
},
|
|
334
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React, { forwardRef } from "react"
|
|
2
|
+
import { cn } from "@lib/utils"
|
|
3
|
+
|
|
4
|
+
interface CharCountProps {
|
|
5
|
+
currentLength: number
|
|
6
|
+
maxLength?: number
|
|
7
|
+
className?: string
|
|
8
|
+
"aria-live"?: "polite" | "assertive" | "off"
|
|
9
|
+
id?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const CharCount = forwardRef<HTMLSpanElement, CharCountProps>(
|
|
13
|
+
(
|
|
14
|
+
{
|
|
15
|
+
currentLength,
|
|
16
|
+
maxLength,
|
|
17
|
+
className = "",
|
|
18
|
+
"aria-live": ariaLive = "polite",
|
|
19
|
+
id,
|
|
20
|
+
},
|
|
21
|
+
ref
|
|
22
|
+
) => {
|
|
23
|
+
// Determine if we should show warning/error styling
|
|
24
|
+
const isNearLimit = maxLength && currentLength > maxLength * 0.9
|
|
25
|
+
const isOverLimit = maxLength && currentLength > maxLength
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<span
|
|
29
|
+
ref={ref}
|
|
30
|
+
id={id}
|
|
31
|
+
className={cn(
|
|
32
|
+
"leading-fm-sm font-fm-brand [font-size:var(--text-fm-sm)] tracking-wide uppercase",
|
|
33
|
+
{
|
|
34
|
+
"text-fm-warning": isNearLimit && !isOverLimit,
|
|
35
|
+
"text-fm-negative": isOverLimit,
|
|
36
|
+
"text-fm-tertiary": !isNearLimit && !isOverLimit,
|
|
37
|
+
},
|
|
38
|
+
className
|
|
39
|
+
)}
|
|
40
|
+
aria-live={ariaLive}
|
|
41
|
+
>
|
|
42
|
+
{maxLength ? `${currentLength}/${maxLength}` : currentLength}
|
|
43
|
+
</span>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
CharCount.displayName = "CharCount"
|
|
48
|
+
|
|
49
|
+
export default CharCount
|
|
50
|
+
export { CharCount }
|
|
51
|
+
export type { CharCountProps }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
dependencies: {},
|
|
3
|
+
devDependencies: {},
|
|
4
|
+
internalDependencies: [],
|
|
5
|
+
tokens: [
|
|
6
|
+
"--color-fm-text-warning",
|
|
7
|
+
"--color-fm-text-negative",
|
|
8
|
+
"--color-fm-text-tertiary",
|
|
9
|
+
"--text-fm-sm",
|
|
10
|
+
"--leading-fm-sm",
|
|
11
|
+
"--font-fm-brand",
|
|
12
|
+
],
|
|
13
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { Button } from "@components/button"
|
|
3
|
+
import { Label } from "@components/label"
|
|
4
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
5
|
+
|
|
6
|
+
import { Checkbox } from "."
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof Checkbox> = {
|
|
9
|
+
title: "Components/UI/Checkbox",
|
|
10
|
+
component: Checkbox,
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: "centered",
|
|
13
|
+
},
|
|
14
|
+
tags: ["autodocs"],
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default meta
|
|
18
|
+
type Story = StoryObj<typeof Checkbox>
|
|
19
|
+
|
|
20
|
+
export const Default: Story = {
|
|
21
|
+
render: () => (
|
|
22
|
+
<div className="flex items-center space-x-2">
|
|
23
|
+
<Checkbox id="terms" />
|
|
24
|
+
<Label htmlFor="terms">Accept terms and conditions</Label>
|
|
25
|
+
</div>
|
|
26
|
+
),
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const States: Story = {
|
|
30
|
+
render: () => (
|
|
31
|
+
<div className="text-fm-primary flex flex-col space-y-8">
|
|
32
|
+
{/* Unchecked */}
|
|
33
|
+
<div className="space-y-2">
|
|
34
|
+
<h3 className="text-lg font-medium">Unchecked</h3>
|
|
35
|
+
<div className="flex items-center space-x-2">
|
|
36
|
+
<Checkbox id="unchecked" />
|
|
37
|
+
<Label htmlFor="unchecked">Unchecked</Label>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
{/* Checked */}
|
|
42
|
+
<div className="space-y-2">
|
|
43
|
+
<h3 className="text-lg font-medium">Checked</h3>
|
|
44
|
+
<div className="flex items-center space-x-2">
|
|
45
|
+
<Checkbox id="checked" defaultChecked />
|
|
46
|
+
<Label htmlFor="checked">Checked</Label>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
{/* Indeterminate */}
|
|
51
|
+
<div className="space-y-2">
|
|
52
|
+
<h3 className="text-lg font-medium">Indeterminate</h3>
|
|
53
|
+
<div className="flex items-center space-x-2">
|
|
54
|
+
<Checkbox id="indeterminate" indeterminate />
|
|
55
|
+
<Label htmlFor="indeterminate">Indeterminate</Label>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
{/* Disabled Unchecked */}
|
|
60
|
+
<div className="space-y-2">
|
|
61
|
+
<h3 className="text-lg font-medium">Disabled Unchecked</h3>
|
|
62
|
+
<div className="flex items-center space-x-2">
|
|
63
|
+
<Checkbox id="disabled" disabled />
|
|
64
|
+
<Label htmlFor="disabled" disabled>
|
|
65
|
+
Disabled Unchecked
|
|
66
|
+
</Label>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
{/* Disabled Checked */}
|
|
71
|
+
<div className="space-y-2">
|
|
72
|
+
<h3 className="text-lg font-medium">Disabled Checked</h3>
|
|
73
|
+
<div className="flex items-center space-x-2">
|
|
74
|
+
<Checkbox id="disabled-checked" disabled defaultChecked />
|
|
75
|
+
<Label htmlFor="disabled-checked" disabled>
|
|
76
|
+
Disabled Checked
|
|
77
|
+
</Label>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
{/* Disabled Indeterminate Unchecked */}
|
|
82
|
+
<div className="space-y-2">
|
|
83
|
+
<h3 className="text-lg font-medium">
|
|
84
|
+
Disabled Indeterminate Unchecked
|
|
85
|
+
</h3>
|
|
86
|
+
<div className="flex items-center space-x-2">
|
|
87
|
+
<Checkbox id="disabled-indeterminate" disabled indeterminate />
|
|
88
|
+
<Label htmlFor="disabled-indeterminate" disabled>
|
|
89
|
+
Disabled Indeterminate Unchecked
|
|
90
|
+
</Label>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
{/* Disabled Indeterminate Checked */}
|
|
95
|
+
<div className="space-y-2">
|
|
96
|
+
<h3 className="text-lg font-medium">Disabled Indeterminate Checked</h3>
|
|
97
|
+
<div className="flex items-center space-x-2">
|
|
98
|
+
<Checkbox
|
|
99
|
+
id="disabled-indeterminate"
|
|
100
|
+
disabled
|
|
101
|
+
indeterminate
|
|
102
|
+
defaultChecked
|
|
103
|
+
/>
|
|
104
|
+
<Label htmlFor="disabled-indeterminate" disabled>
|
|
105
|
+
Disabled Indeterminate Checked
|
|
106
|
+
</Label>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
),
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export const WithForm: Story = {
|
|
114
|
+
render: () => (
|
|
115
|
+
<form
|
|
116
|
+
onSubmit={(e) => {
|
|
117
|
+
e.preventDefault()
|
|
118
|
+
alert("Form submitted!")
|
|
119
|
+
}}
|
|
120
|
+
className="space-y-6"
|
|
121
|
+
>
|
|
122
|
+
<div className="space-y-4">
|
|
123
|
+
<div className="flex items-center space-x-2">
|
|
124
|
+
<Checkbox id="newsletter" />
|
|
125
|
+
<Label htmlFor="newsletter">Subscribe to newsletter</Label>
|
|
126
|
+
</div>
|
|
127
|
+
<div className="flex items-center space-x-2">
|
|
128
|
+
<Checkbox id="marketing" />
|
|
129
|
+
<Label htmlFor="marketing">Receive marketing emails</Label>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
<Button type="submit">Submit</Button>
|
|
133
|
+
</form>
|
|
134
|
+
),
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const IndeterminateExample: Story = {
|
|
138
|
+
render: () => {
|
|
139
|
+
// This example shows a parent-child relationship where the parent checkbox
|
|
140
|
+
// becomes indeterminate when some but not all children are checked
|
|
141
|
+
const [checkedItems, setCheckedItems] = React.useState({
|
|
142
|
+
option1: false,
|
|
143
|
+
option2: false,
|
|
144
|
+
option3: false,
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
const allChecked = Object.values(checkedItems).every(Boolean)
|
|
148
|
+
const indeterminate =
|
|
149
|
+
Object.values(checkedItems).some(Boolean) && !allChecked
|
|
150
|
+
|
|
151
|
+
const handleParentChange = () => {
|
|
152
|
+
const newValue = !allChecked
|
|
153
|
+
setCheckedItems({
|
|
154
|
+
option1: newValue,
|
|
155
|
+
option2: newValue,
|
|
156
|
+
option3: newValue,
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const handleChildChange = (option: keyof typeof checkedItems) => {
|
|
161
|
+
setCheckedItems((prev) => ({
|
|
162
|
+
...prev,
|
|
163
|
+
[option]: !prev[option],
|
|
164
|
+
}))
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return (
|
|
168
|
+
<div className="space-y-4">
|
|
169
|
+
<div className="flex items-center space-x-2">
|
|
170
|
+
<Checkbox
|
|
171
|
+
id="parent"
|
|
172
|
+
checked={allChecked || indeterminate}
|
|
173
|
+
indeterminate={indeterminate}
|
|
174
|
+
onCheckedChange={handleParentChange}
|
|
175
|
+
/>
|
|
176
|
+
<Label htmlFor="parent" className="font-medium">
|
|
177
|
+
Select all options
|
|
178
|
+
</Label>
|
|
179
|
+
</div>
|
|
180
|
+
<div className="ml-6 space-y-2">
|
|
181
|
+
<div className="flex items-center space-x-2">
|
|
182
|
+
<Checkbox
|
|
183
|
+
id="option1"
|
|
184
|
+
checked={checkedItems.option1}
|
|
185
|
+
onCheckedChange={() => handleChildChange("option1")}
|
|
186
|
+
/>
|
|
187
|
+
<Label htmlFor="option1">Option 1</Label>
|
|
188
|
+
</div>
|
|
189
|
+
<div className="flex items-center space-x-2">
|
|
190
|
+
<Checkbox
|
|
191
|
+
id="option2"
|
|
192
|
+
checked={checkedItems.option2}
|
|
193
|
+
onCheckedChange={() => handleChildChange("option2")}
|
|
194
|
+
/>
|
|
195
|
+
<Label htmlFor="option2">Option 2</Label>
|
|
196
|
+
</div>
|
|
197
|
+
<div className="flex items-center space-x-2">
|
|
198
|
+
<Checkbox
|
|
199
|
+
id="option3"
|
|
200
|
+
checked={checkedItems.option3}
|
|
201
|
+
onCheckedChange={() => handleChildChange("option3")}
|
|
202
|
+
/>
|
|
203
|
+
<Label htmlFor="option3">Option 3</Label>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
)
|
|
208
|
+
},
|
|
209
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { TickIcon } from "@icons/tick-icon"
|
|
3
|
+
import { cn } from "@lib/utils"
|
|
4
|
+
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
|
|
5
|
+
|
|
6
|
+
type CheckboxProps = React.ComponentPropsWithoutRef<
|
|
7
|
+
typeof CheckboxPrimitive.Root
|
|
8
|
+
> & {
|
|
9
|
+
indeterminate?: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const Checkbox = React.forwardRef<
|
|
13
|
+
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
|
14
|
+
CheckboxProps
|
|
15
|
+
>(({ className, indeterminate = false, ...props }, ref) => (
|
|
16
|
+
<CheckboxPrimitive.Root
|
|
17
|
+
ref={ref}
|
|
18
|
+
className={cn(
|
|
19
|
+
"data-[state=checked]:not-[:disabled]:border-fm-divider-positive data-[state=checked]:not-[:disabled]:bg-fm-green-50 data-[state=unchecked]:not-[:disabled]:border-fm-divider-primary data-[state=unchecked]:not-[:disabled]:bg-fm-surface-primary data-[state=unchecked]:disabled:border-fm-divider-tertiary data-[state=unchecked]:disabled:bg-fm-surface-secondary data-[state=checked]:disabled:border-fm-green-100 data-[state=checked]:disabled:bg-fm-green-50 text-fm-icon-active disabled:text-fm-icon-inactive focus-visible:ring-fm-primary focus-visible:ring-offset-fm-green-50 hover:bg-fm-surface-secondary data-[state=unchecked]:not-[:disabled]:hover:bg-fm-surface-secondary rounded-fm-l size-8 border border-solid transition-all duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
|
|
20
|
+
"data-[state=unchecked]:not-[:disabled]:hover:border-fm-divider-primary disabled:cursor-not-allowed",
|
|
21
|
+
className
|
|
22
|
+
)}
|
|
23
|
+
{...props}
|
|
24
|
+
>
|
|
25
|
+
<CheckboxPrimitive.Indicator className="flex items-center justify-center text-current">
|
|
26
|
+
{indeterminate ? <span className="h-0.5 w-4 bg-current" /> : <TickIcon />}
|
|
27
|
+
</CheckboxPrimitive.Indicator>
|
|
28
|
+
</CheckboxPrimitive.Root>
|
|
29
|
+
))
|
|
30
|
+
Checkbox.displayName = CheckboxPrimitive.Root.displayName
|
|
31
|
+
|
|
32
|
+
// Add a custom prop type for the indeterminate state
|
|
33
|
+
export type { CheckboxProps }
|
|
34
|
+
export { Checkbox }
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
dependencies: {
|
|
3
|
+
"@radix-ui/react-checkbox": "^1.3.2",
|
|
4
|
+
},
|
|
5
|
+
devDependencies: {},
|
|
6
|
+
internalDependencies: ["tick-icon"],
|
|
7
|
+
tokens: [
|
|
8
|
+
"--color-fm-divider-positive",
|
|
9
|
+
"--color-fm-divider-primary",
|
|
10
|
+
"--color-fm-divider-tertiary",
|
|
11
|
+
"--color-fm-green-50",
|
|
12
|
+
"--color-fm-green-100",
|
|
13
|
+
"--color-fm-icon-active",
|
|
14
|
+
"--color-fm-icon-inactive",
|
|
15
|
+
"--color-fm-primary",
|
|
16
|
+
"--color-fm-surface-primary",
|
|
17
|
+
"--color-fm-surface-secondary",
|
|
18
|
+
],
|
|
19
|
+
}
|