@bronzelabs/oakma-ui 0.0.1 → 0.0.3
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/dist/index.d.ts +345 -0
- package/dist/index.js +2 -0
- package/dist/oakma-ui.css +2 -0
- package/package.json +7 -2
- package/.prettierrc.cjs +0 -25
- package/.storybook/components/ActionButton.tsx +0 -44
- package/.storybook/components/DummyIcons.tsx +0 -47
- package/.storybook/components/index.ts +0 -2
- package/.storybook/docs/blocks/ImportStatement.tsx +0 -52
- package/.storybook/docs/blocks/index.ts +0 -1
- package/.storybook/docs/page.tsx +0 -41
- package/.storybook/main.ts +0 -21
- package/.storybook/postcss.config.cjs +0 -8
- package/.storybook/preview-body.html +0 -20
- package/.storybook/preview-head.html +0 -6
- package/.storybook/preview.tsx +0 -30
- package/.storybook/tailwind.css +0 -6
- package/.storybook/utils/index.ts +0 -2
- package/.storybook/utils/renderAsReact.tsx +0 -30
- package/.storybook/utils/renderDocsWithProps.tsx +0 -22
- package/@types/markdown.d.ts +0 -4
- package/eslint.config.js +0 -91
- package/postcss.config.cjs +0 -8
- package/scripts/release.sh +0 -76
- package/src/components/Button/Button.stories.tsx +0 -314
- package/src/components/Button/Button.tsx +0 -132
- package/src/components/Button/index.ts +0 -2
- package/src/components/Button/types.ts +0 -19
- package/src/components/Checkbox/Checkbox.stories.tsx +0 -152
- package/src/components/Checkbox/Checkbox.tsx +0 -90
- package/src/components/Checkbox/index.ts +0 -2
- package/src/components/Checkbox/types.ts +0 -6
- package/src/components/Chip/Chip.stories.tsx +0 -146
- package/src/components/Chip/Chip.tsx +0 -59
- package/src/components/Chip/index.ts +0 -2
- package/src/components/Chip/types.ts +0 -6
- package/src/components/Drawer/Drawer.docs.md +0 -88
- package/src/components/Drawer/Drawer.stories.tsx +0 -239
- package/src/components/Drawer/Drawer.tsx +0 -194
- package/src/components/Drawer/index.ts +0 -3
- package/src/components/Drawer/types.ts +0 -3
- package/src/components/Dropdown/AsyncDropdown.tsx +0 -105
- package/src/components/Dropdown/Dropdown.docs.md +0 -33
- package/src/components/Dropdown/Dropdown.stories.tsx +0 -419
- package/src/components/Dropdown/Dropdown.tsx +0 -104
- package/src/components/Dropdown/MultiValue.tsx +0 -19
- package/src/components/Dropdown/ValueContainer.tsx +0 -114
- package/src/components/Dropdown/index.ts +0 -4
- package/src/components/Dropdown/types.ts +0 -29
- package/src/components/Dropdown/useDropdown.tsx +0 -257
- package/src/components/Logo/Logo.stories.tsx +0 -130
- package/src/components/Logo/Logo.tsx +0 -80
- package/src/components/Logo/index.ts +0 -2
- package/src/components/Modal/Modal.docs.md +0 -94
- package/src/components/Modal/Modal.stories.tsx +0 -318
- package/src/components/Modal/Modal.tsx +0 -217
- package/src/components/Modal/index.ts +0 -1
- package/src/components/MultiSelect/AsyncMultiSelect.tsx +0 -47
- package/src/components/MultiSelect/MultiSelect.docs.md +0 -37
- package/src/components/MultiSelect/MultiSelect.stories.tsx +0 -493
- package/src/components/MultiSelect/MultiSelect.tsx +0 -81
- package/src/components/MultiSelect/index.ts +0 -2
- package/src/components/Notification/Notification.stories.tsx +0 -158
- package/src/components/Notification/Notification.tsx +0 -110
- package/src/components/Notification/index.ts +0 -1
- package/src/components/Notification/types.ts +0 -11
- package/src/components/Notifications/Notifications.docs.md +0 -103
- package/src/components/Notifications/Notifications.stories.tsx +0 -159
- package/src/components/Notifications/Notifications.tsx +0 -90
- package/src/components/Notifications/NotificationsContext.tsx +0 -90
- package/src/components/Notifications/index.ts +0 -7
- package/src/components/Select/Select.stories.tsx +0 -234
- package/src/components/Select/Select.tsx +0 -129
- package/src/components/Select/index.ts +0 -2
- package/src/components/Select/types.ts +0 -1
- package/src/components/Spinner/Spinner.stories.tsx +0 -55
- package/src/components/Spinner/Spinner.tsx +0 -48
- package/src/components/Spinner/index.ts +0 -2
- package/src/components/Spinner/types.ts +0 -8
- package/src/components/TextArea/TextArea.stories.tsx +0 -243
- package/src/components/TextArea/TextArea.tsx +0 -133
- package/src/components/TextArea/index.ts +0 -2
- package/src/components/TextArea/types.ts +0 -4
- package/src/components/TextField/Container.tsx +0 -68
- package/src/components/TextField/ErrorMessage.tsx +0 -37
- package/src/components/TextField/Icon.tsx +0 -77
- package/src/components/TextField/Label.tsx +0 -56
- package/src/components/TextField/NotchBorder.tsx +0 -67
- package/src/components/TextField/index.ts +0 -14
- package/src/components/TextField/types.ts +0 -15
- package/src/components/TextField/useInputKeyboardFocus.tsx +0 -63
- package/src/components/TextInput/TextInput.stories.tsx +0 -384
- package/src/components/TextInput/TextInput.tsx +0 -255
- package/src/components/TextInput/index.ts +0 -2
- package/src/components/TextInput/types.ts +0 -4
- package/src/components/Toggle/Toggle.stories.tsx +0 -142
- package/src/components/Toggle/Toggle.tsx +0 -69
- package/src/components/Toggle/index.ts +0 -1
- package/src/hooks/index.ts +0 -6
- package/src/hooks/useCombinedRefs.ts +0 -37
- package/src/hooks/useEventListener.ts +0 -87
- package/src/hooks/useFocusTrap/createAriaHider.ts +0 -62
- package/src/hooks/useFocusTrap/index.ts +0 -1
- package/src/hooks/useFocusTrap/scopeTab.ts +0 -46
- package/src/hooks/useFocusTrap/tabbable.ts +0 -107
- package/src/hooks/useFocusTrap/useFocusTrap.ts +0 -97
- package/src/hooks/useIsomorphicLayoutEffect.ts +0 -14
- package/src/hooks/useLockBodyScroll.ts +0 -24
- package/src/hooks/useOnClickOutside.ts +0 -53
- package/src/index.ts +0 -22
- package/src/tailwind.css +0 -4
- package/src/types/helpers.ts +0 -11
- package/src/types/polymorphic.ts +0 -39
- package/src/utils/animation/variants.ts +0 -21
- package/src/utils/array/index.ts +0 -1
- package/src/utils/array/uniqBy.ts +0 -12
- package/src/utils/common/index.ts +0 -1
- package/src/utils/common/isFunction.ts +0 -17
- package/src/utils/react/extractDisplayName.ts +0 -15
- package/src/utils/react/index.ts +0 -1
- package/tsconfig.json +0 -16
- package/tsconfig.production.json +0 -19
- package/tsup.config.ts +0 -16
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import React, { useState } from "react"
|
|
4
|
-
|
|
5
|
-
// Components
|
|
6
|
-
import Button, { ButtonProps } from "../Button"
|
|
7
|
-
import { Container, ErrorMessage, Icon, Label, useInputKeyboardFocus } from "../TextField"
|
|
8
|
-
import {
|
|
9
|
-
EyeSlashIcon,
|
|
10
|
-
EyeIcon,
|
|
11
|
-
CalendarIcon,
|
|
12
|
-
CalendarDaysIcon,
|
|
13
|
-
CalendarDateRangeIcon,
|
|
14
|
-
ClockIcon,
|
|
15
|
-
} from "@heroicons/react/24/solid"
|
|
16
|
-
|
|
17
|
-
// Types
|
|
18
|
-
import type { TextInputSize, TextInputVariant } from "./types"
|
|
19
|
-
|
|
20
|
-
// Utils
|
|
21
|
-
import { clsx } from "clsx"
|
|
22
|
-
|
|
23
|
-
// Params
|
|
24
|
-
const INPUT_TYPES = {
|
|
25
|
-
calendar: ["date", "datetime-local", "week", "month", "time"],
|
|
26
|
-
text: ["text", "email", "number", "password", "search", "tel", "url"],
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface TextInputProps extends Omit<
|
|
30
|
-
React.InputHTMLAttributes<HTMLInputElement>,
|
|
31
|
-
"id" | "type" | "size"
|
|
32
|
-
> {
|
|
33
|
-
id: string
|
|
34
|
-
label?: string
|
|
35
|
-
size?: TextInputSize
|
|
36
|
-
variant?: TextInputVariant
|
|
37
|
-
type?: React.HTMLInputTypeAttribute
|
|
38
|
-
leadingIcon?: {
|
|
39
|
-
icon: React.ReactNode
|
|
40
|
-
onClick?: React.MouseEventHandler<HTMLButtonElement>
|
|
41
|
-
type?: "button" | "submit" | "reset"
|
|
42
|
-
disabled?: boolean
|
|
43
|
-
name?: string
|
|
44
|
-
}
|
|
45
|
-
trailingIcon?: {
|
|
46
|
-
icon: React.ReactNode
|
|
47
|
-
onClick?: React.MouseEventHandler<HTMLButtonElement>
|
|
48
|
-
type?: "button" | "submit" | "reset"
|
|
49
|
-
disabled?: boolean
|
|
50
|
-
name?: string
|
|
51
|
-
}
|
|
52
|
-
showOptional?: boolean
|
|
53
|
-
error?: {
|
|
54
|
-
message: string
|
|
55
|
-
}
|
|
56
|
-
button?: Omit<ButtonProps, "children"> & { label: string }
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/*
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
*/
|
|
66
|
-
|
|
67
|
-
const TextInput: React.FC<TextInputProps> = ({
|
|
68
|
-
id,
|
|
69
|
-
label,
|
|
70
|
-
size = "md",
|
|
71
|
-
variant = "dark",
|
|
72
|
-
type = "text",
|
|
73
|
-
button,
|
|
74
|
-
error,
|
|
75
|
-
leadingIcon,
|
|
76
|
-
trailingIcon,
|
|
77
|
-
showOptional = true,
|
|
78
|
-
className,
|
|
79
|
-
required,
|
|
80
|
-
disabled,
|
|
81
|
-
onFocus,
|
|
82
|
-
onBlur,
|
|
83
|
-
...rest
|
|
84
|
-
}) => {
|
|
85
|
-
const { keyboardFocused, handleMouseDown, handleMouseUp, handleFocus, handleBlur } =
|
|
86
|
-
useInputKeyboardFocus({ onFocus, onBlur })
|
|
87
|
-
|
|
88
|
-
// State
|
|
89
|
-
const [dynamicType, setDynamicType] = useState<React.HTMLInputTypeAttribute>(type)
|
|
90
|
-
|
|
91
|
-
// Functions
|
|
92
|
-
function handleTrailingIconClick(e: React.MouseEvent<HTMLButtonElement>) {
|
|
93
|
-
if (type === "password") {
|
|
94
|
-
setDynamicType(dynamicType === "password" ? "text" : "password")
|
|
95
|
-
}
|
|
96
|
-
return trailingIcon?.onClick?.(e)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function handleLeadingIconClick(e: React.MouseEvent<HTMLButtonElement>) {
|
|
100
|
-
if (INPUT_TYPES.calendar.includes(dynamicType)) {
|
|
101
|
-
return e.currentTarget?.closest("div")?.querySelector("input")?.showPicker()
|
|
102
|
-
}
|
|
103
|
-
return leadingIcon?.onClick?.(e)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return (
|
|
107
|
-
<div className={className}>
|
|
108
|
-
<Container
|
|
109
|
-
keyboardFocused={keyboardFocused}
|
|
110
|
-
onMouseDown={handleMouseDown}
|
|
111
|
-
onMouseUp={handleMouseUp}
|
|
112
|
-
size={size}
|
|
113
|
-
hasButton={!!button?.label}
|
|
114
|
-
variant={variant}
|
|
115
|
-
label={label}
|
|
116
|
-
showOptional={showOptional}
|
|
117
|
-
required={required}
|
|
118
|
-
>
|
|
119
|
-
{label && (
|
|
120
|
-
<Label
|
|
121
|
-
inputId={id}
|
|
122
|
-
label={label}
|
|
123
|
-
showOptional={showOptional}
|
|
124
|
-
required={required}
|
|
125
|
-
variant={variant}
|
|
126
|
-
/>
|
|
127
|
-
)}
|
|
128
|
-
{INPUT_TYPES.calendar.includes(dynamicType) && (
|
|
129
|
-
<Icon
|
|
130
|
-
position="leading"
|
|
131
|
-
fieldSize={size}
|
|
132
|
-
variant={variant}
|
|
133
|
-
disabled={disabled}
|
|
134
|
-
onClick={handleLeadingIconClick}
|
|
135
|
-
name={leadingIcon?.name}
|
|
136
|
-
buttonType={leadingIcon?.type}
|
|
137
|
-
>
|
|
138
|
-
{dynamicType === "time" && (
|
|
139
|
-
<ClockIcon className={clsx(size === "md" && "size-6", size === "sm" && "size-5")} />
|
|
140
|
-
)}
|
|
141
|
-
{dynamicType === "date" && (
|
|
142
|
-
<CalendarIcon
|
|
143
|
-
className={clsx(size === "md" && "size-6", size === "sm" && "size-5")}
|
|
144
|
-
/>
|
|
145
|
-
)}
|
|
146
|
-
{dynamicType === "datetime-local" && (
|
|
147
|
-
<CalendarIcon
|
|
148
|
-
className={clsx(size === "md" && "size-6", size === "sm" && "size-5")}
|
|
149
|
-
/>
|
|
150
|
-
)}
|
|
151
|
-
{dynamicType === "week" && (
|
|
152
|
-
<CalendarDateRangeIcon
|
|
153
|
-
className={clsx(size === "md" && "size-6", size === "sm" && "size-5")}
|
|
154
|
-
/>
|
|
155
|
-
)}
|
|
156
|
-
{dynamicType === "month" && (
|
|
157
|
-
<CalendarDaysIcon
|
|
158
|
-
className={clsx(size === "md" && "size-6", size === "sm" && "size-5")}
|
|
159
|
-
/>
|
|
160
|
-
)}
|
|
161
|
-
</Icon>
|
|
162
|
-
)}
|
|
163
|
-
{leadingIcon?.icon && !INPUT_TYPES.calendar.includes(dynamicType) && (
|
|
164
|
-
<Icon
|
|
165
|
-
position="leading"
|
|
166
|
-
fieldSize={size}
|
|
167
|
-
variant={variant}
|
|
168
|
-
disabled={leadingIcon?.disabled || disabled}
|
|
169
|
-
onClick={leadingIcon?.onClick}
|
|
170
|
-
name={leadingIcon?.name}
|
|
171
|
-
buttonType={leadingIcon?.type}
|
|
172
|
-
>
|
|
173
|
-
{leadingIcon.icon}
|
|
174
|
-
</Icon>
|
|
175
|
-
)}
|
|
176
|
-
|
|
177
|
-
<input
|
|
178
|
-
id={id}
|
|
179
|
-
className={clsx(
|
|
180
|
-
"size-full min-w-0 placeholder:text-neutral-30 focus:outline-hidden",
|
|
181
|
-
variant === "dark" && "text-neutral-100",
|
|
182
|
-
variant === "light" && "text-white",
|
|
183
|
-
size === "sm" && [
|
|
184
|
-
"min-h-6 text-sm",
|
|
185
|
-
!!(leadingIcon?.icon || INPUT_TYPES.calendar.includes(dynamicType))
|
|
186
|
-
? "pl-11.5"
|
|
187
|
-
: "pl-3",
|
|
188
|
-
!!(trailingIcon?.icon || type === "password") ? "pr-10" : "pr-3",
|
|
189
|
-
],
|
|
190
|
-
size === "md" && [
|
|
191
|
-
"min-h-12 text-base",
|
|
192
|
-
!!(leadingIcon?.icon || INPUT_TYPES.calendar.includes(dynamicType))
|
|
193
|
-
? "pl-12.75"
|
|
194
|
-
: "pl-5",
|
|
195
|
-
!!(trailingIcon?.icon || type === "password") ? "pr-12" : "pr-5",
|
|
196
|
-
],
|
|
197
|
-
)}
|
|
198
|
-
aria-describedby={error ? `${id}-error` : undefined}
|
|
199
|
-
aria-invalid={!!error}
|
|
200
|
-
required={required}
|
|
201
|
-
onFocus={handleFocus}
|
|
202
|
-
onBlur={handleBlur}
|
|
203
|
-
disabled={disabled}
|
|
204
|
-
type={dynamicType}
|
|
205
|
-
{...rest}
|
|
206
|
-
/>
|
|
207
|
-
|
|
208
|
-
{type === "password" && (
|
|
209
|
-
<Icon
|
|
210
|
-
position="trailing"
|
|
211
|
-
onClick={handleTrailingIconClick}
|
|
212
|
-
disabled={disabled}
|
|
213
|
-
fieldSize={size}
|
|
214
|
-
variant={variant}
|
|
215
|
-
name="Toggle password visibility"
|
|
216
|
-
>
|
|
217
|
-
{dynamicType === "password" ? (
|
|
218
|
-
<EyeSlashIcon className="size-5" />
|
|
219
|
-
) : (
|
|
220
|
-
<EyeIcon className="size-5" />
|
|
221
|
-
)}
|
|
222
|
-
</Icon>
|
|
223
|
-
)}
|
|
224
|
-
|
|
225
|
-
{trailingIcon?.icon && dynamicType !== "password" && (
|
|
226
|
-
<Icon
|
|
227
|
-
position="trailing"
|
|
228
|
-
onClick={trailingIcon?.onClick}
|
|
229
|
-
disabled={trailingIcon?.disabled || disabled}
|
|
230
|
-
fieldSize={size}
|
|
231
|
-
variant={variant}
|
|
232
|
-
name={trailingIcon?.name}
|
|
233
|
-
>
|
|
234
|
-
{trailingIcon.icon}
|
|
235
|
-
</Icon>
|
|
236
|
-
)}
|
|
237
|
-
|
|
238
|
-
{button?.label && (
|
|
239
|
-
<Button
|
|
240
|
-
size={size}
|
|
241
|
-
{...button}
|
|
242
|
-
disabled={disabled || button.disabled}
|
|
243
|
-
className={clsx("shrink-0", size === "sm" && "min-h-7.5!", button.className)}
|
|
244
|
-
>
|
|
245
|
-
{button.label}
|
|
246
|
-
</Button>
|
|
247
|
-
)}
|
|
248
|
-
</Container>
|
|
249
|
-
{error && <ErrorMessage id={id} error={error} />}
|
|
250
|
-
</div>
|
|
251
|
-
)
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
export default TextInput
|
|
255
|
-
export type { TextInputProps }
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import React from "react"
|
|
2
|
-
|
|
3
|
-
// Components
|
|
4
|
-
import Toggle from "./Toggle"
|
|
5
|
-
|
|
6
|
-
// Types
|
|
7
|
-
import type { Meta, StoryFn } from "@storybook/react-webpack5"
|
|
8
|
-
import type { ToggleProps } from "./Toggle"
|
|
9
|
-
|
|
10
|
-
/*
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
const meta: Meta<ToggleProps> = {
|
|
18
|
-
title: "Components/Toggle",
|
|
19
|
-
component: Toggle,
|
|
20
|
-
parameters: {
|
|
21
|
-
docs: {
|
|
22
|
-
description: {
|
|
23
|
-
component: "A switch control for toggling a boolean setting on or off.",
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
controls: {
|
|
27
|
-
exclude: ["className", "ref"],
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
argTypes: {
|
|
31
|
-
label: {
|
|
32
|
-
type: "string",
|
|
33
|
-
description: "Label text displayed next to the Toggle.",
|
|
34
|
-
table: {
|
|
35
|
-
type: { summary: "string" },
|
|
36
|
-
defaultValue: { summary: "undefined" },
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
meta: {
|
|
40
|
-
type: "string",
|
|
41
|
-
description: "Secondary text displayed below the label.",
|
|
42
|
-
table: {
|
|
43
|
-
type: { summary: "string" },
|
|
44
|
-
defaultValue: { summary: "undefined" },
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
activeText: {
|
|
48
|
-
type: "string",
|
|
49
|
-
description: "Alternate label shown when the toggle is on. Falls back to label if not set.",
|
|
50
|
-
table: {
|
|
51
|
-
type: { summary: "string" },
|
|
52
|
-
defaultValue: { summary: "undefined" },
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
disabled: {
|
|
56
|
-
description: "Disables the toggle.",
|
|
57
|
-
table: {
|
|
58
|
-
type: { summary: "boolean" },
|
|
59
|
-
defaultValue: { summary: "false" },
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
args: {},
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const Template: StoryFn<ToggleProps> = args => <Toggle {...args} />
|
|
67
|
-
|
|
68
|
-
const Default = Template.bind({})
|
|
69
|
-
const Checked = Template.bind({})
|
|
70
|
-
const WithLabel = Template.bind({})
|
|
71
|
-
const WithLabelAndMeta = Template.bind({})
|
|
72
|
-
const WithActiveText = Template.bind({})
|
|
73
|
-
const Disabled = Template.bind({})
|
|
74
|
-
const DisabledChecked = Template.bind({})
|
|
75
|
-
|
|
76
|
-
// Args
|
|
77
|
-
Checked.args = { defaultChecked: true }
|
|
78
|
-
WithLabel.args = { label: "Enable notifications" }
|
|
79
|
-
WithLabelAndMeta.args = {
|
|
80
|
-
label: "Enable notifications",
|
|
81
|
-
meta: "Receive alerts for important account activity.",
|
|
82
|
-
}
|
|
83
|
-
WithActiveText.args = {
|
|
84
|
-
label: "Notifications off",
|
|
85
|
-
activeText: "Notifications on",
|
|
86
|
-
defaultChecked: true,
|
|
87
|
-
}
|
|
88
|
-
Disabled.args = { disabled: true, label: "Disabled option" }
|
|
89
|
-
DisabledChecked.args = { disabled: true, defaultChecked: true, label: "Disabled on" }
|
|
90
|
-
|
|
91
|
-
// Parameters
|
|
92
|
-
WithLabel.parameters = {
|
|
93
|
-
docs: {
|
|
94
|
-
description: {
|
|
95
|
-
story: "Pass a `label` prop to display text alongside the toggle.",
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
WithLabelAndMeta.parameters = {
|
|
101
|
-
docs: {
|
|
102
|
-
description: {
|
|
103
|
-
story: "The `meta` prop renders secondary descriptive text below the label.",
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
WithActiveText.parameters = {
|
|
109
|
-
docs: {
|
|
110
|
-
description: {
|
|
111
|
-
story:
|
|
112
|
-
"The `activeText` prop swaps the label when the toggle is on. Useful for showing context-sensitive state.",
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
Disabled.parameters = {
|
|
118
|
-
docs: {
|
|
119
|
-
description: {
|
|
120
|
-
story: "Setting `disabled` reduces opacity and prevents interaction.",
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Decorators
|
|
126
|
-
Default.decorators = [
|
|
127
|
-
Story => (
|
|
128
|
-
<div className="flex flex-wrap items-center gap-4">
|
|
129
|
-
<Story />
|
|
130
|
-
</div>
|
|
131
|
-
),
|
|
132
|
-
]
|
|
133
|
-
|
|
134
|
-
Checked.decorators = [...Default.decorators]
|
|
135
|
-
WithLabel.decorators = [...Default.decorators]
|
|
136
|
-
WithLabelAndMeta.decorators = [...Default.decorators]
|
|
137
|
-
WithActiveText.decorators = [...Default.decorators]
|
|
138
|
-
Disabled.decorators = [...Default.decorators]
|
|
139
|
-
DisabledChecked.decorators = [...Default.decorators]
|
|
140
|
-
|
|
141
|
-
export { Default, Checked, WithLabel, WithLabelAndMeta, WithActiveText, Disabled, DisabledChecked }
|
|
142
|
-
export default meta
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import React from "react"
|
|
2
|
-
|
|
3
|
-
// Utils
|
|
4
|
-
import { clsx } from "clsx"
|
|
5
|
-
|
|
6
|
-
// Params
|
|
7
|
-
interface ToggleProps extends Omit<React.ComponentPropsWithRef<"input">, "size" | "children"> {
|
|
8
|
-
/** Label text displayed next to the Toggle. */
|
|
9
|
-
label?: string
|
|
10
|
-
/** Secondary text displayed below the label. */
|
|
11
|
-
meta?: string
|
|
12
|
-
/** Alternate label shown when the toggle is on. Falls back to label if not set. */
|
|
13
|
-
activeText?: string
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/*
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
const Toggle: React.FC<ToggleProps> = ({
|
|
24
|
-
className,
|
|
25
|
-
label,
|
|
26
|
-
meta,
|
|
27
|
-
activeText,
|
|
28
|
-
disabled,
|
|
29
|
-
ref,
|
|
30
|
-
...rest
|
|
31
|
-
}) => {
|
|
32
|
-
return (
|
|
33
|
-
<label
|
|
34
|
-
className={clsx(
|
|
35
|
-
"group/toggle flex cursor-pointer items-start gap-3",
|
|
36
|
-
disabled && "pointer-events-none opacity-40",
|
|
37
|
-
className,
|
|
38
|
-
)}
|
|
39
|
-
>
|
|
40
|
-
<input
|
|
41
|
-
ref={ref}
|
|
42
|
-
type="checkbox"
|
|
43
|
-
role="switch"
|
|
44
|
-
className="peer absolute opacity-0"
|
|
45
|
-
aria-label={label ?? "Toggle"}
|
|
46
|
-
disabled={disabled}
|
|
47
|
-
{...rest}
|
|
48
|
-
/>
|
|
49
|
-
<div className="relative h-6 w-12 shrink-0 rounded-full bg-neutral-100/20 p-1 transition-colors group-hover/toggle:bg-neutral-100/30 group-has-checked/toggle:bg-lime-180/20 group-has-checked/toggle:group-hover/toggle:bg-lime-180/30 peer-focus-visible:ring-2 peer-focus-visible:ring-teal-100 peer-focus-visible:ring-offset-1">
|
|
50
|
-
<div className="absolute left-1 size-4 rounded-full bg-white transition-all group-active/toggle:w-5 group-has-checked/toggle:left-7 group-has-checked/toggle:bg-lime-180 group-has-checked/toggle:group-active/toggle:left-6!" />
|
|
51
|
-
</div>
|
|
52
|
-
{(activeText || label || meta) && (
|
|
53
|
-
<div className="flex flex-1 flex-col gap-0.5 select-none">
|
|
54
|
-
{(activeText || label) && (
|
|
55
|
-
<span className="text-sm/snug font-medium text-neutral-100">
|
|
56
|
-
<span className="hidden group-has-checked/toggle:inline">{activeText || label}</span>
|
|
57
|
-
<span className="inline group-has-checked/toggle:hidden">{label}</span>
|
|
58
|
-
</span>
|
|
59
|
-
)}
|
|
60
|
-
{meta && <span className="text-xs/snug text-neutral-50">{meta}</span>}
|
|
61
|
-
</div>
|
|
62
|
-
)}
|
|
63
|
-
</label>
|
|
64
|
-
)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
Toggle.displayName = "Toggle"
|
|
68
|
-
export default Toggle
|
|
69
|
-
export type { ToggleProps }
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default, type ToggleProps } from "./Toggle"
|
package/src/hooks/index.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { useCombinedRefs } from "./useCombinedRefs"
|
|
2
|
-
export { useEventListener } from "./useEventListener"
|
|
3
|
-
export { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect"
|
|
4
|
-
export { useLockBodyScroll } from "./useLockBodyScroll"
|
|
5
|
-
export { useOnClickOutside } from "./useOnClickOutside"
|
|
6
|
-
export { useFocusTrap } from "./useFocusTrap"
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import { useRef, useEffect } from "react"
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* useCombinedRefs
|
|
7
|
-
*
|
|
8
|
-
* @template T
|
|
9
|
-
*
|
|
10
|
-
* @param {any[]} refs
|
|
11
|
-
* @returns {React.RefObject<T>}
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/*
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
const useCombinedRefs = <T>(...refs: any[]): React.RefObject<T | null> => {
|
|
18
|
-
// Refs
|
|
19
|
-
const targetRef = useRef<T | null>(null)
|
|
20
|
-
|
|
21
|
-
// Effects
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
refs.forEach(ref => {
|
|
24
|
-
if (!ref) return
|
|
25
|
-
|
|
26
|
-
if (typeof ref === "function") {
|
|
27
|
-
ref(targetRef.current)
|
|
28
|
-
} else {
|
|
29
|
-
ref.current = targetRef.current
|
|
30
|
-
}
|
|
31
|
-
})
|
|
32
|
-
}, [refs])
|
|
33
|
-
|
|
34
|
-
return targetRef
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export { useCombinedRefs }
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import { RefObject, useEffect, useRef } from "react"
|
|
4
|
-
|
|
5
|
-
import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect"
|
|
6
|
-
|
|
7
|
-
// MediaQueryList Event based useEventListener interface
|
|
8
|
-
function useEventListener<K extends keyof MediaQueryListEventMap>(
|
|
9
|
-
eventName: K,
|
|
10
|
-
handler: (event: MediaQueryListEventMap[K]) => void,
|
|
11
|
-
element: RefObject<MediaQueryList>,
|
|
12
|
-
options?: boolean | AddEventListenerOptions,
|
|
13
|
-
): void
|
|
14
|
-
|
|
15
|
-
// Window Event based useEventListener interface
|
|
16
|
-
function useEventListener<K extends keyof WindowEventMap>(
|
|
17
|
-
eventName: K,
|
|
18
|
-
handler: (event: WindowEventMap[K]) => void,
|
|
19
|
-
element?: undefined,
|
|
20
|
-
options?: boolean | AddEventListenerOptions,
|
|
21
|
-
): void
|
|
22
|
-
|
|
23
|
-
// Element Event based useEventListener interface
|
|
24
|
-
function useEventListener<
|
|
25
|
-
K extends keyof HTMLElementEventMap,
|
|
26
|
-
T extends HTMLElement = HTMLDivElement,
|
|
27
|
-
>(
|
|
28
|
-
eventName: K,
|
|
29
|
-
handler: (event: HTMLElementEventMap[K]) => void,
|
|
30
|
-
element: RefObject<T>,
|
|
31
|
-
options?: boolean | AddEventListenerOptions,
|
|
32
|
-
): void
|
|
33
|
-
|
|
34
|
-
// Document Event based useEventListener interface
|
|
35
|
-
function useEventListener<K extends keyof DocumentEventMap>(
|
|
36
|
-
eventName: K,
|
|
37
|
-
handler: (event: DocumentEventMap[K]) => void,
|
|
38
|
-
element: RefObject<Document>,
|
|
39
|
-
options?: boolean | AddEventListenerOptions,
|
|
40
|
-
): void
|
|
41
|
-
|
|
42
|
-
/*
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
*/
|
|
48
|
-
|
|
49
|
-
function useEventListener<
|
|
50
|
-
KW extends keyof WindowEventMap,
|
|
51
|
-
KH extends keyof HTMLElementEventMap,
|
|
52
|
-
KM extends keyof MediaQueryListEventMap,
|
|
53
|
-
T extends HTMLElement | MediaQueryList | void = void,
|
|
54
|
-
>(
|
|
55
|
-
eventName: KW | KH | KM,
|
|
56
|
-
handler: (
|
|
57
|
-
event: WindowEventMap[KW] | HTMLElementEventMap[KH] | MediaQueryListEventMap[KM] | Event,
|
|
58
|
-
) => void,
|
|
59
|
-
element?: RefObject<T>,
|
|
60
|
-
options?: boolean | AddEventListenerOptions,
|
|
61
|
-
): void {
|
|
62
|
-
// Create a ref that stores handler
|
|
63
|
-
const savedHandler = useRef(handler)
|
|
64
|
-
|
|
65
|
-
useIsomorphicLayoutEffect(() => {
|
|
66
|
-
savedHandler.current = handler
|
|
67
|
-
}, [handler])
|
|
68
|
-
|
|
69
|
-
useEffect(() => {
|
|
70
|
-
// Define the listening target
|
|
71
|
-
const targetElement: T | Window = element?.current ?? window
|
|
72
|
-
|
|
73
|
-
if (!(targetElement && targetElement.addEventListener)) return
|
|
74
|
-
|
|
75
|
-
// Create event listener that calls handler function stored in ref
|
|
76
|
-
const listener: typeof handler = event => savedHandler.current(event)
|
|
77
|
-
|
|
78
|
-
targetElement.addEventListener(eventName, listener, options)
|
|
79
|
-
|
|
80
|
-
// Remove event listener on cleanup
|
|
81
|
-
return () => {
|
|
82
|
-
targetElement.removeEventListener(eventName, listener, options)
|
|
83
|
-
}
|
|
84
|
-
}, [eventName, element, options])
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export { useEventListener }
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
interface Value {
|
|
2
|
-
node: HTMLElement
|
|
3
|
-
ariaHidden: string | null
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
/*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
const createAriaHider = (
|
|
14
|
-
containerNode: HTMLElement,
|
|
15
|
-
selector: string = "body > :not(script)",
|
|
16
|
-
): (() => void) => {
|
|
17
|
-
const id = `tribe-${Math.random().toString(36).slice(2, 11)}`
|
|
18
|
-
|
|
19
|
-
const rootNodes: (Value | undefined)[] = Array.from<HTMLElement>(
|
|
20
|
-
document?.querySelectorAll(selector),
|
|
21
|
-
).map(node => {
|
|
22
|
-
if (node?.shadowRoot?.contains(containerNode) || node.contains(containerNode)) {
|
|
23
|
-
return undefined
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const ariaHidden = node.getAttribute("aria-hidden")
|
|
27
|
-
const prevAriaHidden = node.getAttribute("data-hidden")
|
|
28
|
-
const prevFocusId = node.getAttribute("data-focus-id")
|
|
29
|
-
|
|
30
|
-
node.setAttribute("data-focus-id", id)
|
|
31
|
-
|
|
32
|
-
if (ariaHidden === null || ariaHidden === "false") {
|
|
33
|
-
node.setAttribute("aria-hidden", "true")
|
|
34
|
-
} else if (!prevAriaHidden && !prevFocusId) {
|
|
35
|
-
node.setAttribute("data-hidden", ariaHidden)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
node,
|
|
40
|
-
ariaHidden: prevAriaHidden || null,
|
|
41
|
-
}
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
return () => {
|
|
45
|
-
rootNodes.forEach(item => {
|
|
46
|
-
if (!item || id !== item.node.getAttribute("data-focus-id")) {
|
|
47
|
-
return
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (item.ariaHidden === null) {
|
|
51
|
-
item.node.removeAttribute("aria-hidden")
|
|
52
|
-
} else {
|
|
53
|
-
item.node.setAttribute("aria-hidden", item.ariaHidden)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
item.node.removeAttribute("data-focus-id")
|
|
57
|
-
item.node.removeAttribute("data-hidden")
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export { createAriaHider }
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { useFocusTrap } from "./useFocusTrap"
|