@taicode/common-web 1.0.2 → 1.0.4
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/package.json +17 -5
- package/source/catalyst/CHANGELOG.md +136 -0
- package/source/catalyst/README.md +65 -0
- package/source/catalyst/alert.tsx +95 -0
- package/source/catalyst/auth-layout.tsx +11 -0
- package/source/catalyst/avatar.tsx +84 -0
- package/source/catalyst/badge.tsx +82 -0
- package/source/catalyst/button.tsx +204 -0
- package/source/catalyst/checkbox.tsx +157 -0
- package/source/catalyst/combobox.tsx +188 -0
- package/source/catalyst/description-list.tsx +37 -0
- package/source/catalyst/dialog.tsx +86 -0
- package/source/catalyst/divider.tsx +20 -0
- package/source/catalyst/dropdown.tsx +183 -0
- package/source/catalyst/fieldset.tsx +91 -0
- package/source/catalyst/heading.tsx +27 -0
- package/source/catalyst/input.tsx +94 -0
- package/source/catalyst/link.tsx +21 -0
- package/source/catalyst/listbox.tsx +177 -0
- package/source/catalyst/navbar.tsx +96 -0
- package/source/catalyst/pagination.tsx +98 -0
- package/source/catalyst/radio.tsx +142 -0
- package/source/catalyst/select.tsx +68 -0
- package/source/catalyst/sidebar-layout.tsx +82 -0
- package/source/catalyst/sidebar.tsx +142 -0
- package/source/catalyst/stacked-layout.tsx +79 -0
- package/source/catalyst/switch.tsx +195 -0
- package/source/catalyst/table.tsx +124 -0
- package/source/catalyst/text.tsx +40 -0
- package/source/catalyst/textarea.tsx +54 -0
- package/tsconfig.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taicode/common-web",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"author": "Alain",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"description": "",
|
|
@@ -9,12 +9,24 @@
|
|
|
9
9
|
"dev": "tsc -p tsconfig.json --watch"
|
|
10
10
|
},
|
|
11
11
|
"peerDependencies": {
|
|
12
|
+
"@types/react": ">=18",
|
|
12
13
|
"mobx": ">=6",
|
|
13
|
-
"react": ">=18"
|
|
14
|
-
"@types/react": ">=18"
|
|
14
|
+
"react": ">=18"
|
|
15
15
|
},
|
|
16
16
|
"exports": {
|
|
17
|
-
"./utils/*": [
|
|
18
|
-
|
|
17
|
+
"./utils/*": [
|
|
18
|
+
"./output/utils/*"
|
|
19
|
+
],
|
|
20
|
+
"./hooks/*": [
|
|
21
|
+
"./output/hooks/*"
|
|
22
|
+
],
|
|
23
|
+
"./catalyst/*": [
|
|
24
|
+
"./output/catalyst/*"
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@headlessui/react": "^2.2.4",
|
|
29
|
+
"clsx": "^2.1.1",
|
|
30
|
+
"framer-motion": "^12.19.2"
|
|
19
31
|
}
|
|
20
32
|
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 2025-06-05
|
|
4
|
+
|
|
5
|
+
- Update `DropdownLabel` to extend a plain `<div>` instead of the `Headless.Label` ([#1699](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1699))
|
|
6
|
+
|
|
7
|
+
## 2025-04-28
|
|
8
|
+
|
|
9
|
+
- Update template to Tailwind CSS v4.1.4
|
|
10
|
+
|
|
11
|
+
## 2025-04-22
|
|
12
|
+
|
|
13
|
+
- Fix focus styles in the `Avatar`, `Badge`, `Button`, `Checkbox`, and `Switch` components ([#1693](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1693))
|
|
14
|
+
|
|
15
|
+
## 2025-04-17
|
|
16
|
+
|
|
17
|
+
- Update `@headlessui/react` dependency to `v2.2.2` to fix listbox performance issues ([#1667](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1667))
|
|
18
|
+
|
|
19
|
+
## 2025-04-04
|
|
20
|
+
|
|
21
|
+
- Add new `Combobox` component
|
|
22
|
+
- Add new `AuthLayout` component, with example login page, registration page, and forgot password page
|
|
23
|
+
- Fix centering of checkboxes, radios, and switches in fields with multi-line labels
|
|
24
|
+
- Update template to Tailwind CSS v4.1.3
|
|
25
|
+
- Update template to Headless UI v2.2.1 (required for new `Combobox` component)
|
|
26
|
+
|
|
27
|
+
## 2025-03-24
|
|
28
|
+
|
|
29
|
+
- Adjust avatar ring opacity from 20% to 10%
|
|
30
|
+
|
|
31
|
+
## 2025-03-22
|
|
32
|
+
|
|
33
|
+
- Update template to Tailwind CSS v4.0.15
|
|
34
|
+
|
|
35
|
+
## 2025-02-22
|
|
36
|
+
|
|
37
|
+
- Fix border radius of avatars in navbar items
|
|
38
|
+
|
|
39
|
+
## 2025-02-12
|
|
40
|
+
|
|
41
|
+
- Fix baseline alignment for buttons with icons ([#1668](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1668))
|
|
42
|
+
|
|
43
|
+
## 2025-02-10
|
|
44
|
+
|
|
45
|
+
- Update template to Tailwind CSS v4.0.6
|
|
46
|
+
|
|
47
|
+
## 2025-01-29
|
|
48
|
+
|
|
49
|
+
- Fix conflicting outline utilities ([#1661](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1661))
|
|
50
|
+
|
|
51
|
+
## 2025-01-23
|
|
52
|
+
|
|
53
|
+
- Update template to Tailwind CSS v4.0
|
|
54
|
+
|
|
55
|
+
## 2024-10-31
|
|
56
|
+
|
|
57
|
+
- Fix `disabled` prop in `DropdownItem` component ([#1640](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1640))
|
|
58
|
+
- Update types in `SidebarItem` component
|
|
59
|
+
|
|
60
|
+
## 2024-06-09
|
|
61
|
+
|
|
62
|
+
- Omit `as` prop from types for Headless UI-based components
|
|
63
|
+
|
|
64
|
+
## 2024-06-26
|
|
65
|
+
|
|
66
|
+
- Update `@headlessui/react` dependency to `v2.1.1`
|
|
67
|
+
- Update `Dialog`, `Alert`, and `Listbox` to new data-attribute-based transition API
|
|
68
|
+
|
|
69
|
+
## 2024-06-21
|
|
70
|
+
|
|
71
|
+
- Update `@headlessui/react` dependency to `v2.1.0`
|
|
72
|
+
- Use `DialogBackdrop` in `Alert` and `Dialog` components
|
|
73
|
+
- Update to new data-attribute-based transition API
|
|
74
|
+
|
|
75
|
+
## 2024-06-19
|
|
76
|
+
|
|
77
|
+
- Prevent content from overflowing the mobile sidebar
|
|
78
|
+
|
|
79
|
+
## 2024-06-18
|
|
80
|
+
|
|
81
|
+
- Use consistent `let` and `const` declarations
|
|
82
|
+
- Use consistent `clsx` import
|
|
83
|
+
- Use consistent `forwardRef` instead of `React.forwardRef` import
|
|
84
|
+
- Update `tailwindcss`, `prettier` and `prettier-plugin-tailwindcss` dependencies in Next.js demo app
|
|
85
|
+
- Fix class order in `Dropdown` component
|
|
86
|
+
|
|
87
|
+
## 2024-06-10
|
|
88
|
+
|
|
89
|
+
- Add `dark:[color-scheme:dark]` class to `Input` component ([#1596](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1596))
|
|
90
|
+
|
|
91
|
+
## 2024-05-31
|
|
92
|
+
|
|
93
|
+
- Add Next.js demo app ([#1580](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1580))
|
|
94
|
+
- Fix `Avatar` sizing and padding ([#1588](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1588))
|
|
95
|
+
|
|
96
|
+
## 2024-05-27
|
|
97
|
+
|
|
98
|
+
- Add `pointer-events-none` to `InputGroup` icon ([#1594](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1594))
|
|
99
|
+
- Add default text color to `Table` component ([#1581](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1581))
|
|
100
|
+
- Fix TypeScript issues when using `as={Link}` ([#1582](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1582))
|
|
101
|
+
- Fix `SidebarItem` import ([#1582](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1582))
|
|
102
|
+
- Add `isolate` class to `InputGroup`, `SidebarLayout`, and `StackedLayout` components
|
|
103
|
+
- Fix comment indentation and use proper DocBlocks
|
|
104
|
+
|
|
105
|
+
## 2024-05-24
|
|
106
|
+
|
|
107
|
+
- Add new `SidebarLayout` component
|
|
108
|
+
- Add new `StackedLayout` component
|
|
109
|
+
- Add new `Navbar` component
|
|
110
|
+
- Add new `Sidebar` component
|
|
111
|
+
- Add new `DescriptionList` component
|
|
112
|
+
- Add new `Heading` component
|
|
113
|
+
- Add new `Divider` component
|
|
114
|
+
- Add new `framer-motion` dependency
|
|
115
|
+
- Update `@headlessui/react` dependency to `v2.0`
|
|
116
|
+
- Remove `as={Fragment}` from the transition components
|
|
117
|
+
- Improve and fix a number of types
|
|
118
|
+
- Made formatting of `className` and `{...prop}` more consistent across all components
|
|
119
|
+
- Made formatting of `forwardRef` consistent across all components
|
|
120
|
+
- Update `PaginationGap` component to use a `span` instead of a `div`
|
|
121
|
+
- Update the `SidebarHeading` to render use an `h3` instead of a `d`iv
|
|
122
|
+
- Remove `children` prop from `Switch` component
|
|
123
|
+
|
|
124
|
+
## 2024-01-08
|
|
125
|
+
|
|
126
|
+
- Add `resizable` prop to `Textarea` component ([#1543](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1543))
|
|
127
|
+
|
|
128
|
+
## 2024-01-03
|
|
129
|
+
|
|
130
|
+
- Change top-level `let` declarations to `const`
|
|
131
|
+
- Fix `--btn-hover-overlay` color for dark/white button ([#1538](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1538))
|
|
132
|
+
- Add `forwardRef` to `Input`, `Select`, and `Textarea` components ([#1540](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1540))
|
|
133
|
+
|
|
134
|
+
## 2023-12-20
|
|
135
|
+
|
|
136
|
+
- Initial release
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Catalyst UI Kit
|
|
2
|
+
|
|
3
|
+
Catalyst is a modern application UI kit built with [Tailwind CSS](https://tailwindcss.com) and [React](https://react.dev/), designed and built by the Tailwind CSS team and included as part of [Tailwind Plus](https://tailwindcss.com/plus).
|
|
4
|
+
|
|
5
|
+
## Getting started
|
|
6
|
+
|
|
7
|
+
To get started, first copy the component files included in the downloaded ZIP file into wherever you keep components in your own project. The components are provided in both TypeScript and plain JavaScript, pick whichever set you prefer.
|
|
8
|
+
|
|
9
|
+
Next, install the dependencies used by the components in Catalyst:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install @headlessui/react framer-motion clsx
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Catalyst is also designed for the latest version of Tailwind CSS, which is currently Tailwind CSS v4.0. To make sure that you are on the latest version of Tailwind, update it via npm:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install tailwindcss@latest
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Now you're ready to start using the components in your project — just import them from wherever you're keeping your components and start using them like any of your other React components:
|
|
22
|
+
|
|
23
|
+
```jsx
|
|
24
|
+
import { Input } from './components/input'
|
|
25
|
+
import { Field, FieldGroup, Label } from './components/fieldset'
|
|
26
|
+
import { Button } from './components/button'
|
|
27
|
+
|
|
28
|
+
export default function SettingsForm() {
|
|
29
|
+
return (
|
|
30
|
+
<form>
|
|
31
|
+
<FieldGroup>
|
|
32
|
+
<Field>
|
|
33
|
+
<Label>Name</Label>
|
|
34
|
+
<Input name="name" />
|
|
35
|
+
</Field>
|
|
36
|
+
<Field>
|
|
37
|
+
<Label>Email</Label>
|
|
38
|
+
<Input type="email" name="email" />
|
|
39
|
+
</Field>
|
|
40
|
+
<Button type="submit">Save changes</Button>
|
|
41
|
+
</FieldGroup>
|
|
42
|
+
</form>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Additional installation instructions can be found in the Catalyst documentation.
|
|
48
|
+
|
|
49
|
+
## Documentation
|
|
50
|
+
|
|
51
|
+
You can find the Catalyst documentation at https://catalyst.tailwindui.com/docs.
|
|
52
|
+
|
|
53
|
+
## License
|
|
54
|
+
|
|
55
|
+
This site template is a commercial product and is licensed under the [Tailwind Plus license](https://tailwindcss.com/plus/license).
|
|
56
|
+
|
|
57
|
+
## Learn more
|
|
58
|
+
|
|
59
|
+
To learn more about the technologies used in this site template, see the following resources:
|
|
60
|
+
|
|
61
|
+
- [Tailwind CSS](https://tailwindcss.com/docs) - the official Tailwind CSS documentation
|
|
62
|
+
- [Headless UI](https://headlessui.dev) - the official Headless UI documentation
|
|
63
|
+
- [React](https://react.dev) - the official React documentation
|
|
64
|
+
- [Framer Motion](https://www.framer.com/docs/) - the official Framer Motion documentation
|
|
65
|
+
- [clsx](https://github.com/lukeed/clsx) - the GitHub repo for the `clsx` helper
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import * as Headless from '@headlessui/react'
|
|
2
|
+
import clsx from 'clsx'
|
|
3
|
+
import type React from 'react'
|
|
4
|
+
import { Text } from './text'
|
|
5
|
+
|
|
6
|
+
const sizes = {
|
|
7
|
+
xs: 'sm:max-w-xs',
|
|
8
|
+
sm: 'sm:max-w-sm',
|
|
9
|
+
md: 'sm:max-w-md',
|
|
10
|
+
lg: 'sm:max-w-lg',
|
|
11
|
+
xl: 'sm:max-w-xl',
|
|
12
|
+
'2xl': 'sm:max-w-2xl',
|
|
13
|
+
'3xl': 'sm:max-w-3xl',
|
|
14
|
+
'4xl': 'sm:max-w-4xl',
|
|
15
|
+
'5xl': 'sm:max-w-5xl',
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function Alert({
|
|
19
|
+
size = 'md',
|
|
20
|
+
className,
|
|
21
|
+
children,
|
|
22
|
+
...props
|
|
23
|
+
}: { size?: keyof typeof sizes; className?: string; children: React.ReactNode } & Omit<
|
|
24
|
+
Headless.DialogProps,
|
|
25
|
+
'as' | 'className'
|
|
26
|
+
>) {
|
|
27
|
+
return (
|
|
28
|
+
<Headless.Dialog {...props}>
|
|
29
|
+
<Headless.DialogBackdrop
|
|
30
|
+
transition
|
|
31
|
+
className="fixed inset-0 flex w-screen justify-center overflow-y-auto bg-zinc-950/15 px-2 py-2 transition duration-100 focus:outline-0 data-closed:opacity-0 data-enter:ease-out data-leave:ease-in sm:px-6 sm:py-8 lg:px-8 lg:py-16 dark:bg-zinc-950/50"
|
|
32
|
+
/>
|
|
33
|
+
|
|
34
|
+
<div className="fixed inset-0 w-screen overflow-y-auto pt-6 sm:pt-0">
|
|
35
|
+
<div className="grid min-h-full grid-rows-[1fr_auto_1fr] justify-items-center p-8 sm:grid-rows-[1fr_auto_3fr] sm:p-4">
|
|
36
|
+
<Headless.DialogPanel
|
|
37
|
+
transition
|
|
38
|
+
className={clsx(
|
|
39
|
+
className,
|
|
40
|
+
sizes[size],
|
|
41
|
+
'row-start-2 w-full rounded-2xl bg-white p-8 shadow-lg ring-1 ring-zinc-950/10 sm:rounded-2xl sm:p-6 dark:bg-zinc-900 dark:ring-white/10 forced-colors:outline',
|
|
42
|
+
'transition duration-100 will-change-transform data-closed:opacity-0 data-enter:ease-out data-closed:data-enter:scale-95 data-leave:ease-in'
|
|
43
|
+
)}
|
|
44
|
+
>
|
|
45
|
+
{children}
|
|
46
|
+
</Headless.DialogPanel>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</Headless.Dialog>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function AlertTitle({
|
|
54
|
+
className,
|
|
55
|
+
...props
|
|
56
|
+
}: { className?: string } & Omit<Headless.DialogTitleProps, 'as' | 'className'>) {
|
|
57
|
+
return (
|
|
58
|
+
<Headless.DialogTitle
|
|
59
|
+
{...props}
|
|
60
|
+
className={clsx(
|
|
61
|
+
className,
|
|
62
|
+
'text-center text-base/6 font-semibold text-balance text-zinc-950 sm:text-left sm:text-sm/6 sm:text-wrap dark:text-white'
|
|
63
|
+
)}
|
|
64
|
+
/>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function AlertDescription({
|
|
69
|
+
className,
|
|
70
|
+
...props
|
|
71
|
+
}: { className?: string } & Omit<Headless.DescriptionProps<typeof Text>, 'as' | 'className'>) {
|
|
72
|
+
return (
|
|
73
|
+
<Headless.Description
|
|
74
|
+
as={Text}
|
|
75
|
+
{...props}
|
|
76
|
+
className={clsx(className, 'mt-2 text-center text-pretty sm:text-left')}
|
|
77
|
+
/>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function AlertBody({ className, ...props }: React.ComponentPropsWithoutRef<'div'>) {
|
|
82
|
+
return <div {...props} className={clsx(className, 'mt-4')} />
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function AlertActions({ className, ...props }: React.ComponentPropsWithoutRef<'div'>) {
|
|
86
|
+
return (
|
|
87
|
+
<div
|
|
88
|
+
{...props}
|
|
89
|
+
className={clsx(
|
|
90
|
+
className,
|
|
91
|
+
'mt-6 flex flex-col-reverse items-center justify-end gap-3 *:w-full sm:mt-4 sm:flex-row sm:*:w-auto'
|
|
92
|
+
)}
|
|
93
|
+
/>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type React from 'react'
|
|
2
|
+
|
|
3
|
+
export function AuthLayout({ children }: { children: React.ReactNode }) {
|
|
4
|
+
return (
|
|
5
|
+
<main className="flex min-h-dvh flex-col p-2">
|
|
6
|
+
<div className="flex grow items-center justify-center p-6 lg:rounded-lg lg:bg-white lg:p-10 lg:shadow-xs lg:ring-1 lg:ring-zinc-950/5 dark:lg:bg-zinc-900 dark:lg:ring-white/10">
|
|
7
|
+
{children}
|
|
8
|
+
</div>
|
|
9
|
+
</main>
|
|
10
|
+
)
|
|
11
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as Headless from '@headlessui/react'
|
|
2
|
+
import clsx from 'clsx'
|
|
3
|
+
import React, { forwardRef } from 'react'
|
|
4
|
+
import { TouchTarget } from './button'
|
|
5
|
+
import { Link } from './link'
|
|
6
|
+
|
|
7
|
+
type AvatarProps = {
|
|
8
|
+
src?: string | null
|
|
9
|
+
square?: boolean
|
|
10
|
+
initials?: string
|
|
11
|
+
alt?: string
|
|
12
|
+
className?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function Avatar({
|
|
16
|
+
src = null,
|
|
17
|
+
square = false,
|
|
18
|
+
initials,
|
|
19
|
+
alt = '',
|
|
20
|
+
className,
|
|
21
|
+
...props
|
|
22
|
+
}: AvatarProps & React.ComponentPropsWithoutRef<'span'>) {
|
|
23
|
+
return (
|
|
24
|
+
<span
|
|
25
|
+
data-slot="avatar"
|
|
26
|
+
{...props}
|
|
27
|
+
className={clsx(
|
|
28
|
+
className,
|
|
29
|
+
// Basic layout
|
|
30
|
+
'inline-grid shrink-0 align-middle [--avatar-radius:20%] *:col-start-1 *:row-start-1',
|
|
31
|
+
'outline -outline-offset-1 outline-black/10 dark:outline-white/10',
|
|
32
|
+
// Border radius
|
|
33
|
+
square ? 'rounded-(--avatar-radius) *:rounded-(--avatar-radius)' : 'rounded-full *:rounded-full'
|
|
34
|
+
)}
|
|
35
|
+
>
|
|
36
|
+
{initials && (
|
|
37
|
+
<svg
|
|
38
|
+
className="size-full fill-current p-[5%] text-[48px] font-medium uppercase select-none"
|
|
39
|
+
viewBox="0 0 100 100"
|
|
40
|
+
aria-hidden={alt ? undefined : 'true'}
|
|
41
|
+
>
|
|
42
|
+
{alt && <title>{alt}</title>}
|
|
43
|
+
<text x="50%" y="50%" alignmentBaseline="middle" dominantBaseline="middle" textAnchor="middle" dy=".125em">
|
|
44
|
+
{initials}
|
|
45
|
+
</text>
|
|
46
|
+
</svg>
|
|
47
|
+
)}
|
|
48
|
+
{src && <img className="size-full" src={src} alt={alt} />}
|
|
49
|
+
</span>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const AvatarButton = forwardRef(function AvatarButton(
|
|
54
|
+
{
|
|
55
|
+
src,
|
|
56
|
+
square = false,
|
|
57
|
+
initials,
|
|
58
|
+
alt,
|
|
59
|
+
className,
|
|
60
|
+
...props
|
|
61
|
+
}: AvatarProps &
|
|
62
|
+
(Omit<Headless.ButtonProps, 'as' | 'className'> | Omit<React.ComponentPropsWithoutRef<typeof Link>, 'className'>),
|
|
63
|
+
ref: React.ForwardedRef<HTMLElement>
|
|
64
|
+
) {
|
|
65
|
+
let classes = clsx(
|
|
66
|
+
className,
|
|
67
|
+
square ? 'rounded-[20%]' : 'rounded-full',
|
|
68
|
+
'relative inline-grid focus:not-data-focus:outline-hidden data-focus:outline-2 data-focus:outline-offset-2 data-focus:outline-blue-500'
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
return 'href' in props ? (
|
|
72
|
+
<Link {...props} className={classes} ref={ref as React.ForwardedRef<HTMLAnchorElement>}>
|
|
73
|
+
<TouchTarget>
|
|
74
|
+
<Avatar src={src} square={square} initials={initials} alt={alt} />
|
|
75
|
+
</TouchTarget>
|
|
76
|
+
</Link>
|
|
77
|
+
) : (
|
|
78
|
+
<Headless.Button {...props} className={classes} ref={ref}>
|
|
79
|
+
<TouchTarget>
|
|
80
|
+
<Avatar src={src} square={square} initials={initials} alt={alt} />
|
|
81
|
+
</TouchTarget>
|
|
82
|
+
</Headless.Button>
|
|
83
|
+
)
|
|
84
|
+
})
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as Headless from '@headlessui/react'
|
|
2
|
+
import clsx from 'clsx'
|
|
3
|
+
import React, { forwardRef } from 'react'
|
|
4
|
+
import { TouchTarget } from './button'
|
|
5
|
+
import { Link } from './link'
|
|
6
|
+
|
|
7
|
+
const colors = {
|
|
8
|
+
red: 'bg-red-500/15 text-red-700 group-data-hover:bg-red-500/25 dark:bg-red-500/10 dark:text-red-400 dark:group-data-hover:bg-red-500/20',
|
|
9
|
+
orange:
|
|
10
|
+
'bg-orange-500/15 text-orange-700 group-data-hover:bg-orange-500/25 dark:bg-orange-500/10 dark:text-orange-400 dark:group-data-hover:bg-orange-500/20',
|
|
11
|
+
amber:
|
|
12
|
+
'bg-amber-400/20 text-amber-700 group-data-hover:bg-amber-400/30 dark:bg-amber-400/10 dark:text-amber-400 dark:group-data-hover:bg-amber-400/15',
|
|
13
|
+
yellow:
|
|
14
|
+
'bg-yellow-400/20 text-yellow-700 group-data-hover:bg-yellow-400/30 dark:bg-yellow-400/10 dark:text-yellow-300 dark:group-data-hover:bg-yellow-400/15',
|
|
15
|
+
lime: 'bg-lime-400/20 text-lime-700 group-data-hover:bg-lime-400/30 dark:bg-lime-400/10 dark:text-lime-300 dark:group-data-hover:bg-lime-400/15',
|
|
16
|
+
green:
|
|
17
|
+
'bg-green-500/15 text-green-700 group-data-hover:bg-green-500/25 dark:bg-green-500/10 dark:text-green-400 dark:group-data-hover:bg-green-500/20',
|
|
18
|
+
emerald:
|
|
19
|
+
'bg-emerald-500/15 text-emerald-700 group-data-hover:bg-emerald-500/25 dark:bg-emerald-500/10 dark:text-emerald-400 dark:group-data-hover:bg-emerald-500/20',
|
|
20
|
+
teal: 'bg-teal-500/15 text-teal-700 group-data-hover:bg-teal-500/25 dark:bg-teal-500/10 dark:text-teal-300 dark:group-data-hover:bg-teal-500/20',
|
|
21
|
+
cyan: 'bg-cyan-400/20 text-cyan-700 group-data-hover:bg-cyan-400/30 dark:bg-cyan-400/10 dark:text-cyan-300 dark:group-data-hover:bg-cyan-400/15',
|
|
22
|
+
sky: 'bg-sky-500/15 text-sky-700 group-data-hover:bg-sky-500/25 dark:bg-sky-500/10 dark:text-sky-300 dark:group-data-hover:bg-sky-500/20',
|
|
23
|
+
blue: 'bg-blue-500/15 text-blue-700 group-data-hover:bg-blue-500/25 dark:text-blue-400 dark:group-data-hover:bg-blue-500/25',
|
|
24
|
+
indigo:
|
|
25
|
+
'bg-indigo-500/15 text-indigo-700 group-data-hover:bg-indigo-500/25 dark:text-indigo-400 dark:group-data-hover:bg-indigo-500/20',
|
|
26
|
+
violet:
|
|
27
|
+
'bg-violet-500/15 text-violet-700 group-data-hover:bg-violet-500/25 dark:text-violet-400 dark:group-data-hover:bg-violet-500/20',
|
|
28
|
+
purple:
|
|
29
|
+
'bg-purple-500/15 text-purple-700 group-data-hover:bg-purple-500/25 dark:text-purple-400 dark:group-data-hover:bg-purple-500/20',
|
|
30
|
+
fuchsia:
|
|
31
|
+
'bg-fuchsia-400/15 text-fuchsia-700 group-data-hover:bg-fuchsia-400/25 dark:bg-fuchsia-400/10 dark:text-fuchsia-400 dark:group-data-hover:bg-fuchsia-400/20',
|
|
32
|
+
pink: 'bg-pink-400/15 text-pink-700 group-data-hover:bg-pink-400/25 dark:bg-pink-400/10 dark:text-pink-400 dark:group-data-hover:bg-pink-400/20',
|
|
33
|
+
rose: 'bg-rose-400/15 text-rose-700 group-data-hover:bg-rose-400/25 dark:bg-rose-400/10 dark:text-rose-400 dark:group-data-hover:bg-rose-400/20',
|
|
34
|
+
zinc: 'bg-zinc-600/10 text-zinc-700 group-data-hover:bg-zinc-600/20 dark:bg-white/5 dark:text-zinc-400 dark:group-data-hover:bg-white/10',
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type BadgeProps = { color?: keyof typeof colors }
|
|
38
|
+
|
|
39
|
+
export function Badge({ color = 'zinc', className, ...props }: BadgeProps & React.ComponentPropsWithoutRef<'span'>) {
|
|
40
|
+
return (
|
|
41
|
+
<span
|
|
42
|
+
{...props}
|
|
43
|
+
className={clsx(
|
|
44
|
+
className,
|
|
45
|
+
'inline-flex items-center gap-x-1.5 rounded-md px-1.5 py-0.5 text-sm/5 font-medium sm:text-xs/5 forced-colors:outline',
|
|
46
|
+
colors[color]
|
|
47
|
+
)}
|
|
48
|
+
/>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const BadgeButton = forwardRef(function BadgeButton(
|
|
53
|
+
{
|
|
54
|
+
color = 'zinc',
|
|
55
|
+
className,
|
|
56
|
+
children,
|
|
57
|
+
...props
|
|
58
|
+
}: BadgeProps & { className?: string; children: React.ReactNode } & (
|
|
59
|
+
| Omit<Headless.ButtonProps, 'as' | 'className'>
|
|
60
|
+
| Omit<React.ComponentPropsWithoutRef<typeof Link>, 'className'>
|
|
61
|
+
),
|
|
62
|
+
ref: React.ForwardedRef<HTMLElement>
|
|
63
|
+
) {
|
|
64
|
+
let classes = clsx(
|
|
65
|
+
className,
|
|
66
|
+
'group relative inline-flex rounded-md focus:not-data-focus:outline-hidden data-focus:outline-2 data-focus:outline-offset-2 data-focus:outline-blue-500'
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
return 'href' in props ? (
|
|
70
|
+
<Link {...props} className={classes} ref={ref as React.ForwardedRef<HTMLAnchorElement>}>
|
|
71
|
+
<TouchTarget>
|
|
72
|
+
<Badge color={color}>{children}</Badge>
|
|
73
|
+
</TouchTarget>
|
|
74
|
+
</Link>
|
|
75
|
+
) : (
|
|
76
|
+
<Headless.Button {...props} className={classes} ref={ref}>
|
|
77
|
+
<TouchTarget>
|
|
78
|
+
<Badge color={color}>{children}</Badge>
|
|
79
|
+
</TouchTarget>
|
|
80
|
+
</Headless.Button>
|
|
81
|
+
)
|
|
82
|
+
})
|