@regardio/react 0.4.7 → 0.5.1
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 +1 -1
- package/README.md +5 -5
- package/dist/{components/background-slideshow.js → background-slideshow/index.js} +2 -11
- package/dist/{components/blurry-gradient.js → blurry-gradient/index.js} +15 -9
- package/dist/{components/carousel.d.ts → carousel/index.d.ts} +17 -9
- package/dist/{components/carousel.js → carousel/index.js} +34 -30
- package/dist/{components/countdown.js → countdown/index.js} +2 -11
- package/dist/{components/generic-error.js → generic-error/index.js} +1 -1
- package/dist/grid/index.d.ts +1196 -0
- package/dist/grid/index.js +239 -0
- package/dist/heading/index.d.ts +24 -0
- package/dist/{components/heading.js → heading/index.js} +15 -34
- package/dist/highlight/index.d.ts +13 -0
- package/dist/{components/highlight.js → highlight/index.js} +9 -17
- package/dist/hooks/{use-current-route-data.js → use-current-route-data/index.js} +1 -1
- package/dist/hooks/{use-focus-search.js → use-focus-search/index.js} +1 -1
- package/dist/hooks/{use-matches-data.js → use-matches-data/index.js} +1 -1
- package/dist/hooks/{use-media-query.js → use-media-query/index.js} +1 -1
- package/dist/hooks/{use-mobile.js → use-mobile/index.js} +1 -1
- package/dist/hooks/use-nonce/index.d.ts +6 -0
- package/dist/hooks/use-nonce/index.js +8 -0
- package/dist/hooks/{use-orientation.d.ts → use-orientation/index.d.ts} +1 -1
- package/dist/hooks/{use-orientation.js → use-orientation/index.js} +1 -1
- package/dist/hooks/{use-user.js → use-user/index.js} +1 -1
- package/dist/{components/icon-button.js → icon-button/index.js} +1 -1
- package/dist/{components/if.js → if/index.js} +1 -1
- package/dist/{components/iframe.js → iframe/index.js} +2 -11
- package/dist/{components/link.d.ts → link/index.d.ts} +19 -13
- package/dist/{components/link.js → link/index.js} +31 -36
- package/dist/list/index.d.ts +69 -0
- package/dist/list/index.js +65 -0
- package/dist/{components/markdown-container.js → markdown-container/index.js} +3 -67
- package/dist/{components/password-input.js → password-input/index.js} +2 -11
- package/dist/{components/picture.js → picture/index.js} +2 -11
- package/dist/{components/protected-email.d.ts → protected-email/index.d.ts} +1 -1
- package/dist/{components/protected-email.js → protected-email/index.js} +1 -1
- package/dist/text/index.d.ts +20 -0
- package/dist/text/index.js +38 -0
- package/dist/utils/author/index.d.ts +3 -0
- package/dist/utils/author/index.js +33 -0
- package/dist/utils/text/index.d.ts +15 -0
- package/dist/utils/text/index.js +73 -0
- package/package.json +92 -121
- package/src/{stories/BackgroundSlideshow.stories.tsx → background-slideshow/background-slideshow.stories.tsx} +1 -1
- package/src/{components → background-slideshow}/background-slideshow.tsx +3 -1
- package/src/background-slideshow/index.ts +2 -0
- package/src/{stories/BlurryGradient.stories.tsx → blurry-gradient/blurry-gradient.stories.tsx} +1 -1
- package/src/{components → blurry-gradient}/blurry-gradient.tsx +14 -8
- package/src/blurry-gradient/index.ts +2 -0
- package/src/carousel/carousel-content.tsx +16 -0
- package/src/carousel/carousel-item.tsx +23 -0
- package/src/carousel/carousel-next.tsx +22 -0
- package/src/carousel/carousel-previous.tsx +22 -0
- package/src/{components/carousel.tsx → carousel/carousel-root.tsx} +8 -78
- package/src/carousel/carousel.stories.tsx +89 -0
- package/src/carousel/index.parts.ts +5 -0
- package/src/carousel/index.ts +4 -0
- package/src/{stories/Countdown.stories.tsx → countdown/countdown.stories.tsx} +1 -1
- package/src/{components → countdown}/countdown.tsx +3 -7
- package/src/countdown/index.ts +1 -0
- package/src/{stories/GenericError.stories.tsx → generic-error/generic-error.stories.tsx} +1 -1
- package/src/{components → generic-error}/generic-error.tsx +2 -0
- package/src/generic-error/index.ts +2 -0
- package/src/grid/grid-item.tsx +188 -0
- package/src/grid/grid-root.tsx +72 -0
- package/src/grid/grid.stories.tsx +236 -0
- package/src/grid/index.parts.ts +2 -0
- package/src/grid/index.ts +5 -0
- package/src/{stories/Heading.stories.tsx → heading/heading.stories.tsx} +1 -1
- package/src/{components → heading}/heading.tsx +17 -25
- package/src/heading/index.ts +2 -0
- package/src/{stories/Highlight.stories.tsx → highlight/highlight.stories.tsx} +1 -1
- package/src/{components → highlight}/highlight.tsx +13 -9
- package/src/highlight/index.ts +2 -0
- package/src/hooks/use-current-route-data/index.ts +1 -0
- package/src/hooks/use-focus-search/index.ts +1 -0
- package/src/hooks/use-matches-data/index.ts +1 -0
- package/src/hooks/use-media-query/index.ts +1 -0
- package/src/hooks/use-mobile/index.ts +1 -0
- package/src/hooks/use-nonce/index.ts +1 -0
- package/src/hooks/use-orientation/index.ts +1 -0
- package/src/hooks/use-user/index.ts +2 -0
- package/src/{stories/IconButton.stories.tsx → icon-button/icon-button.stories.tsx} +1 -1
- package/src/icon-button/index.ts +2 -0
- package/src/{stories/If.stories.tsx → if/if.stories.tsx} +1 -1
- package/src/if/index.ts +1 -0
- package/src/{stories/Iframe.stories.tsx → iframe/iframe.stories.tsx} +1 -1
- package/src/{components → iframe}/iframe.tsx +1 -1
- package/src/iframe/index.ts +2 -0
- package/src/link/index.ts +2 -0
- package/src/{stories/Link.stories.tsx → link/link.stories.tsx} +1 -1
- package/src/{components → link}/link.tsx +39 -28
- package/src/list/index.parts.ts +2 -0
- package/src/list/index.ts +4 -0
- package/src/list/list-item.tsx +63 -0
- package/src/list/list-root-context.ts +21 -0
- package/src/list/list-root.tsx +81 -0
- package/src/list/list.css +32 -0
- package/src/list/list.stories.tsx +119 -0
- package/src/list/list.test.tsx +168 -0
- package/src/markdown-container/index.ts +2 -0
- package/src/{stories/MarkdownContainer.stories.tsx → markdown-container/markdown-container.stories.tsx} +1 -1
- package/src/{components → markdown-container}/markdown-container.tsx +3 -1
- package/src/password-input/index.ts +2 -0
- package/src/{stories/PasswordInput.stories.tsx → password-input/password-input.stories.tsx} +1 -1
- package/src/{components → password-input}/password-input.tsx +4 -4
- package/src/picture/index.ts +2 -0
- package/src/{stories/Picture.stories.tsx → picture/picture.stories.tsx} +1 -1
- package/src/{components → picture}/picture.tsx +2 -4
- package/src/protected-email/index.ts +2 -0
- package/src/{stories/ProtectedEmail.stories.tsx → protected-email/protected-email.stories.tsx} +1 -1
- package/src/{components → protected-email}/protected-email.tsx +3 -1
- package/src/tailwind.css +10 -0
- package/src/text/index.ts +2 -0
- package/src/{stories/Text.stories.tsx → text/text.stories.tsx} +1 -1
- package/src/text/text.tsx +46 -0
- package/src/utils/author/author.tsx +36 -0
- package/src/utils/author/index.ts +1 -0
- package/src/utils/text/index.ts +1 -0
- package/src/utils/text/text.tsx +103 -0
- package/dist/components/box.d.ts +0 -20
- package/dist/components/box.js +0 -50
- package/dist/components/definition-list.d.ts +0 -43
- package/dist/components/definition-list.js +0 -89
- package/dist/components/heading.d.ts +0 -27
- package/dist/components/highlight.d.ts +0 -19
- package/dist/components/item.d.ts +0 -70
- package/dist/components/item.js +0 -512
- package/dist/components/leaflet-map.d.ts +0 -34
- package/dist/components/leaflet-map.js +0 -201
- package/dist/components/list-item.d.ts +0 -19
- package/dist/components/list-item.js +0 -37
- package/dist/components/maptiler-map.d.ts +0 -27
- package/dist/components/maptiler-map.js +0 -129
- package/dist/components/text.d.ts +0 -20
- package/dist/components/text.js +0 -45
- package/dist/components/unordered-list.d.ts +0 -19
- package/dist/components/unordered-list.js +0 -39
- package/dist/hooks/use-nonce.d.ts +0 -12
- package/dist/hooks/use-nonce.js +0 -13
- package/dist/utils/author.d.ts +0 -9
- package/dist/utils/author.js +0 -55
- package/dist/utils/cn.d.ts +0 -9
- package/dist/utils/cn.js +0 -14
- package/dist/utils/is-route-active.d.ts +0 -19
- package/dist/utils/is-route-active.js +0 -56
- package/dist/utils/text.d.ts +0 -24
- package/dist/utils/text.js +0 -127
- package/src/components/box.tsx +0 -45
- package/src/components/definition-list.tsx +0 -90
- package/src/components/item.tsx +0 -340
- package/src/components/leaflet-map.tsx +0 -294
- package/src/components/link.test.tsx +0 -387
- package/src/components/list-item.tsx +0 -30
- package/src/components/maptiler-map.tsx +0 -181
- package/src/components/text.tsx +0 -38
- package/src/components/unordered-list.tsx +0 -32
- package/src/hooks/use-nonce.test.ts +0 -35
- package/src/stories/Box.stories.tsx +0 -83
- package/src/stories/Carousel.stories.tsx +0 -95
- package/src/stories/DefinitionList.stories.tsx +0 -51
- package/src/stories/Item.stories.tsx +0 -79
- package/src/stories/ListItem.stories.tsx +0 -38
- package/src/stories/UnorderedList.stories.tsx +0 -73
- package/src/styles/tailwind.css +0 -7
- package/src/test-setup.ts +0 -1
- package/src/utils/author.test.ts +0 -54
- package/src/utils/author.tsx +0 -73
- package/src/utils/cn.test.ts +0 -48
- package/src/utils/cn.ts +0 -14
- package/src/utils/is-route-active.test.ts +0 -80
- package/src/utils/is-route-active.ts +0 -100
- package/src/utils/text.test.ts +0 -152
- package/src/utils/text.tsx +0 -209
- package/src/vite-env.d.ts +0 -1
- /package/dist/{components/background-slideshow.d.ts → background-slideshow/index.d.ts} +0 -0
- /package/dist/{components/blurry-gradient.d.ts → blurry-gradient/index.d.ts} +0 -0
- /package/dist/{components/countdown.d.ts → countdown/index.d.ts} +0 -0
- /package/dist/{components/generic-error.d.ts → generic-error/index.d.ts} +0 -0
- /package/dist/hooks/{use-current-route-data.d.ts → use-current-route-data/index.d.ts} +0 -0
- /package/dist/hooks/{use-focus-search.d.ts → use-focus-search/index.d.ts} +0 -0
- /package/dist/hooks/{use-matches-data.d.ts → use-matches-data/index.d.ts} +0 -0
- /package/dist/hooks/{use-media-query.d.ts → use-media-query/index.d.ts} +0 -0
- /package/dist/hooks/{use-mobile.d.ts → use-mobile/index.d.ts} +0 -0
- /package/dist/hooks/{use-user.d.ts → use-user/index.d.ts} +0 -0
- /package/dist/{components/icon-button.d.ts → icon-button/index.d.ts} +0 -0
- /package/dist/{components/if.d.ts → if/index.d.ts} +0 -0
- /package/dist/{components/iframe.d.ts → iframe/index.d.ts} +0 -0
- /package/dist/{components/markdown-container.d.ts → markdown-container/index.d.ts} +0 -0
- /package/dist/{components/password-input.d.ts → password-input/index.d.ts} +0 -0
- /package/dist/{components/picture.d.ts → picture/index.d.ts} +0 -0
- /package/src/hooks/{use-current-route-data.ts → use-current-route-data/use-current-route-data.ts} +0 -0
- /package/src/hooks/{use-focus-search.ts → use-focus-search/use-focus-search.ts} +0 -0
- /package/src/hooks/{use-matches-data.ts → use-matches-data/use-matches-data.ts} +0 -0
- /package/src/hooks/{use-media-query.ts → use-media-query/use-media-query.ts} +0 -0
- /package/src/hooks/{use-mobile.ts → use-mobile/use-mobile.ts} +0 -0
- /package/src/hooks/{use-nonce.ts → use-nonce/use-nonce.ts} +0 -0
- /package/src/hooks/{use-orientation.ts → use-orientation/use-orientation.ts} +0 -0
- /package/src/hooks/{use-user.tsx → use-user/use-user.tsx} +0 -0
- /package/src/{components → icon-button}/icon-button.tsx +0 -0
- /package/src/{components → if}/if.tsx +0 -0
- /package/src/{styles/storybook.css → storybook.css} +0 -0
|
@@ -1,43 +1,36 @@
|
|
|
1
|
+
import { cn, tv } from '@regardio/tailwind/utils';
|
|
1
2
|
import type { ElementType, HTMLAttributes } from 'react';
|
|
2
|
-
import { cn, cva, type VariantProps } from '../utils/cn';
|
|
3
3
|
import { lowerCaseSzett, shy } from '../utils/text';
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const levelVariants = {
|
|
6
|
+
1: ['text-2xl'],
|
|
7
|
+
2: ['text-xl'],
|
|
8
|
+
3: ['text-lg'],
|
|
9
|
+
4: ['text-md'],
|
|
10
|
+
5: ['text-sm'],
|
|
11
|
+
6: ['text-xs'],
|
|
12
|
+
} as const;
|
|
13
|
+
|
|
14
|
+
const heading = tv({
|
|
6
15
|
base: [],
|
|
7
16
|
defaultVariants: {
|
|
8
17
|
level: 3,
|
|
9
18
|
},
|
|
10
19
|
variants: {
|
|
11
|
-
level:
|
|
12
|
-
1: ['text-2xl'],
|
|
13
|
-
2: ['text-xl'],
|
|
14
|
-
3: ['text-lg'],
|
|
15
|
-
4: ['text-md'],
|
|
16
|
-
5: ['text-sm'],
|
|
17
|
-
6: ['text-xs'],
|
|
18
|
-
},
|
|
19
|
-
variant: {},
|
|
20
|
+
level: levelVariants,
|
|
20
21
|
},
|
|
21
22
|
});
|
|
22
23
|
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
export type HeadingLevel = keyof typeof levelVariants;
|
|
25
|
+
|
|
26
|
+
export interface HeadingProps extends HTMLAttributes<HTMLHeadingElement> {
|
|
26
27
|
as?: ElementType;
|
|
27
28
|
className?: string;
|
|
29
|
+
level?: HeadingLevel;
|
|
28
30
|
locale?: string;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
export
|
|
32
|
-
|
|
33
|
-
export const Heading = ({
|
|
34
|
-
as,
|
|
35
|
-
children,
|
|
36
|
-
className,
|
|
37
|
-
level = 2,
|
|
38
|
-
variant,
|
|
39
|
-
...props
|
|
40
|
-
}: HeadingProps) => {
|
|
33
|
+
export const Heading = ({ as, children, className, level = 2, ...props }: HeadingProps) => {
|
|
41
34
|
const word = lowerCaseSzett(shy(children));
|
|
42
35
|
const Component: ElementType = as || `h${level}`;
|
|
43
36
|
|
|
@@ -46,7 +39,6 @@ export const Heading = ({
|
|
|
46
39
|
className={cn(
|
|
47
40
|
heading({
|
|
48
41
|
level,
|
|
49
|
-
variant,
|
|
50
42
|
}),
|
|
51
43
|
className,
|
|
52
44
|
)}
|
|
@@ -1,25 +1,29 @@
|
|
|
1
|
+
import { tv } from '@regardio/tailwind/utils';
|
|
1
2
|
import type { ComponentProps } from 'react';
|
|
2
|
-
import { cva, type VariantProps } from '../utils/cn';
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const highlightVariants = {
|
|
5
|
+
primary: ['highlight'],
|
|
6
|
+
} as const;
|
|
7
|
+
|
|
8
|
+
const highlight = tv({
|
|
5
9
|
defaultVariants: {
|
|
6
10
|
variant: 'primary',
|
|
7
11
|
},
|
|
8
12
|
variants: {
|
|
9
|
-
variant:
|
|
10
|
-
primary: ['highlight'],
|
|
11
|
-
},
|
|
13
|
+
variant: highlightVariants,
|
|
12
14
|
},
|
|
13
15
|
});
|
|
14
16
|
|
|
15
|
-
export
|
|
17
|
+
export type HighlightVariant = keyof typeof highlightVariants;
|
|
16
18
|
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
+
export interface HighlightProps extends ComponentProps<'mark'> {
|
|
20
|
+
variant?: HighlightVariant;
|
|
21
|
+
}
|
|
19
22
|
|
|
23
|
+
export const Highlight = ({ children, className, variant }: HighlightProps) => {
|
|
20
24
|
return (
|
|
21
25
|
<mark
|
|
22
|
-
className={
|
|
26
|
+
className={highlight({
|
|
23
27
|
className,
|
|
24
28
|
variant,
|
|
25
29
|
})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useCurrentRouteData } from './use-current-route-data';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useFocusSearch } from './use-focus-search';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useMatchesData } from './use-matches-data';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useMediaQuery } from './use-media-query';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useIsMobile } from './use-mobile';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { NonceProvider, useNonce } from './use-nonce';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useOrientation } from './use-orientation';
|
package/src/if/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { If } from './if';
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { tv } from '@regardio/tailwind/utils';
|
|
1
4
|
import { createContext, useCallback, useContext } from 'react';
|
|
2
5
|
import type { NavLinkProps, NavLinkRenderProps } from 'react-router';
|
|
3
6
|
import { NavLink } from 'react-router';
|
|
4
|
-
import { cva, type VariantProps } from '../utils/cn';
|
|
5
7
|
import { lowerCaseSzett } from '../utils/text';
|
|
6
8
|
|
|
7
9
|
/**
|
|
@@ -120,42 +122,51 @@ export const LinkBase = ({
|
|
|
120
122
|
);
|
|
121
123
|
};
|
|
122
124
|
|
|
123
|
-
const
|
|
125
|
+
const arrowVariants = {
|
|
126
|
+
darr: 'darr',
|
|
127
|
+
larr: 'larr',
|
|
128
|
+
rarr: 'rarr',
|
|
129
|
+
uarr: 'uarr',
|
|
130
|
+
} as const;
|
|
131
|
+
|
|
132
|
+
const linkVariants = {
|
|
133
|
+
button: [
|
|
134
|
+
'block',
|
|
135
|
+
'button',
|
|
136
|
+
'mt-s',
|
|
137
|
+
'relative',
|
|
138
|
+
'rarr',
|
|
139
|
+
'text-right',
|
|
140
|
+
'text-sm',
|
|
141
|
+
'tracking-wider',
|
|
142
|
+
'uppercase',
|
|
143
|
+
],
|
|
144
|
+
code: ['font-monospace'],
|
|
145
|
+
link: ['rarr', '!bg-transparent', 'uppercase', '!tracking-wider'],
|
|
146
|
+
navtitle: ['block', 'uppercase', 'tracking-wider'],
|
|
147
|
+
primary: [],
|
|
148
|
+
subtitle: ['text-lg'],
|
|
149
|
+
} as const;
|
|
150
|
+
|
|
151
|
+
const link = tv({
|
|
124
152
|
base: [],
|
|
125
153
|
defaultVariants: {
|
|
126
154
|
variant: 'primary',
|
|
127
155
|
},
|
|
128
156
|
variants: {
|
|
129
|
-
arrow:
|
|
130
|
-
|
|
131
|
-
larr: 'larr',
|
|
132
|
-
rarr: 'rarr',
|
|
133
|
-
uarr: 'uarr',
|
|
134
|
-
},
|
|
135
|
-
variant: {
|
|
136
|
-
button: [
|
|
137
|
-
'block',
|
|
138
|
-
'button',
|
|
139
|
-
'mt-s',
|
|
140
|
-
'relative',
|
|
141
|
-
'rarr',
|
|
142
|
-
'text-right',
|
|
143
|
-
'text-sm',
|
|
144
|
-
'tracking-wider',
|
|
145
|
-
'uppercase',
|
|
146
|
-
],
|
|
147
|
-
code: ['font-monospace'],
|
|
148
|
-
link: ['rarr', '!bg-transparent', 'uppercase', '!tracking-wider'],
|
|
149
|
-
navtitle: ['block', 'uppercase', 'tracking-wider'],
|
|
150
|
-
primary: [],
|
|
151
|
-
subtitle: ['text-lg'],
|
|
152
|
-
},
|
|
157
|
+
arrow: arrowVariants,
|
|
158
|
+
variant: linkVariants,
|
|
153
159
|
},
|
|
154
160
|
});
|
|
155
161
|
|
|
156
|
-
export
|
|
162
|
+
export type LinkArrow = keyof typeof arrowVariants;
|
|
163
|
+
export type LinkVariant = keyof typeof linkVariants;
|
|
164
|
+
|
|
165
|
+
export interface LinkProps extends Omit<NavLinkProps, 'to'> {
|
|
166
|
+
arrow?: LinkArrow;
|
|
157
167
|
to?: string | Partial<{ pathname?: string; search?: string; hash?: string }>;
|
|
158
168
|
routeKey?: string;
|
|
169
|
+
variant?: LinkVariant;
|
|
159
170
|
viewTransition?: boolean;
|
|
160
171
|
}
|
|
161
172
|
|
|
@@ -174,7 +185,7 @@ export const Link = ({
|
|
|
174
185
|
{...props}
|
|
175
186
|
className={link({
|
|
176
187
|
arrow,
|
|
177
|
-
className,
|
|
188
|
+
className: typeof className === 'string' ? className : undefined,
|
|
178
189
|
variant,
|
|
179
190
|
})}
|
|
180
191
|
routeKey={routeKey}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type ComponentPropsWithoutRef,
|
|
5
|
+
type ElementType,
|
|
6
|
+
type ForwardedRef,
|
|
7
|
+
forwardRef,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
} from 'react';
|
|
10
|
+
import { useListRootContext } from './list-root-context';
|
|
11
|
+
|
|
12
|
+
type ListItemElement = 'li' | 'dd' | 'dt' | 'div' | 'span';
|
|
13
|
+
|
|
14
|
+
export type ListItemProps<T extends ListItemElement = 'li'> = Omit<
|
|
15
|
+
ComponentPropsWithoutRef<T>,
|
|
16
|
+
'children'
|
|
17
|
+
> & {
|
|
18
|
+
/**
|
|
19
|
+
* The element type to render.
|
|
20
|
+
* Falls back to the defaultItemElement from ListRoot context, or 'li'.
|
|
21
|
+
*/
|
|
22
|
+
render?: T;
|
|
23
|
+
/**
|
|
24
|
+
* The content of the list item.
|
|
25
|
+
*/
|
|
26
|
+
children?: ReactNode;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function ListItemImpl<T extends ListItemElement = 'li'>(
|
|
30
|
+
props: ListItemProps<T>,
|
|
31
|
+
ref: ForwardedRef<HTMLElement>,
|
|
32
|
+
) {
|
|
33
|
+
const context = useListRootContext();
|
|
34
|
+
|
|
35
|
+
const { render, children, className, ...elementProps } = props;
|
|
36
|
+
|
|
37
|
+
const resolvedElement = render ?? context?.defaultItemElement ?? 'li';
|
|
38
|
+
const resolvedClassName = context?.defaultItemClassName
|
|
39
|
+
? className
|
|
40
|
+
? `${context.defaultItemClassName} ${className}`
|
|
41
|
+
: context.defaultItemClassName
|
|
42
|
+
: className;
|
|
43
|
+
|
|
44
|
+
const Component = resolvedElement as ElementType;
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<Component
|
|
48
|
+
className={resolvedClassName}
|
|
49
|
+
ref={ref}
|
|
50
|
+
{...elementProps}
|
|
51
|
+
>
|
|
52
|
+
{children}
|
|
53
|
+
</Component>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const ListItem = forwardRef(ListItemImpl) as <T extends ListItemElement = 'li'>(
|
|
58
|
+
props: ListItemProps<T> & { ref?: ForwardedRef<HTMLElement> },
|
|
59
|
+
) => ReturnType<typeof ListItemImpl>;
|
|
60
|
+
|
|
61
|
+
export namespace ListItem {
|
|
62
|
+
export type Props<T extends ListItemElement = 'li'> = ListItemProps<T>;
|
|
63
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { createContext, useContext } from 'react';
|
|
4
|
+
|
|
5
|
+
export interface ListRootContextValue {
|
|
6
|
+
/**
|
|
7
|
+
* Default element type for list items.
|
|
8
|
+
* @default 'li'
|
|
9
|
+
*/
|
|
10
|
+
defaultItemElement: 'li' | 'dd' | 'dt' | 'div' | 'span';
|
|
11
|
+
/**
|
|
12
|
+
* Default className to apply to all list items.
|
|
13
|
+
*/
|
|
14
|
+
defaultItemClassName?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const ListRootContext = createContext<ListRootContextValue | undefined>(undefined);
|
|
18
|
+
|
|
19
|
+
export function useListRootContext(): ListRootContextValue | undefined {
|
|
20
|
+
return useContext(ListRootContext);
|
|
21
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type ComponentPropsWithoutRef,
|
|
5
|
+
type ElementType,
|
|
6
|
+
type ForwardedRef,
|
|
7
|
+
forwardRef,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
useMemo,
|
|
10
|
+
} from 'react';
|
|
11
|
+
import { ListRootContext, type ListRootContextValue } from './list-root-context';
|
|
12
|
+
|
|
13
|
+
type ListRootElement = 'ul' | 'ol' | 'dl' | 'div' | 'menu' | 'nav';
|
|
14
|
+
|
|
15
|
+
export type ListRootProps<T extends ListRootElement = 'ul'> = Omit<
|
|
16
|
+
ComponentPropsWithoutRef<T>,
|
|
17
|
+
'children'
|
|
18
|
+
> & {
|
|
19
|
+
/**
|
|
20
|
+
* The element type to render.
|
|
21
|
+
* @default 'ul'
|
|
22
|
+
*/
|
|
23
|
+
render?: T;
|
|
24
|
+
/**
|
|
25
|
+
* The content of the list.
|
|
26
|
+
*/
|
|
27
|
+
children?: ReactNode;
|
|
28
|
+
/**
|
|
29
|
+
* Default element type for list items.
|
|
30
|
+
* When render is 'dl', defaults to 'dd'. Otherwise defaults to 'li'.
|
|
31
|
+
*/
|
|
32
|
+
defaultItemElement?: ListRootContextValue['defaultItemElement'];
|
|
33
|
+
/**
|
|
34
|
+
* Default className to apply to all list items.
|
|
35
|
+
*/
|
|
36
|
+
defaultItemClassName?: string;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function ListRootImpl<T extends ListRootElement = 'ul'>(
|
|
40
|
+
props: ListRootProps<T>,
|
|
41
|
+
ref: ForwardedRef<HTMLElement>,
|
|
42
|
+
) {
|
|
43
|
+
const {
|
|
44
|
+
render = 'ul' as T,
|
|
45
|
+
children,
|
|
46
|
+
defaultItemElement,
|
|
47
|
+
defaultItemClassName,
|
|
48
|
+
...elementProps
|
|
49
|
+
} = props;
|
|
50
|
+
|
|
51
|
+
const resolvedDefaultItemElement = defaultItemElement ?? (render === 'dl' ? 'dd' : 'li');
|
|
52
|
+
|
|
53
|
+
const contextValue = useMemo<ListRootContextValue>(
|
|
54
|
+
() => ({
|
|
55
|
+
defaultItemClassName,
|
|
56
|
+
defaultItemElement: resolvedDefaultItemElement,
|
|
57
|
+
}),
|
|
58
|
+
[resolvedDefaultItemElement, defaultItemClassName],
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const Component = render as ElementType;
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<ListRootContext.Provider value={contextValue}>
|
|
65
|
+
<Component
|
|
66
|
+
ref={ref}
|
|
67
|
+
{...elementProps}
|
|
68
|
+
>
|
|
69
|
+
{children}
|
|
70
|
+
</Component>
|
|
71
|
+
</ListRootContext.Provider>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const ListRoot = forwardRef(ListRootImpl) as <T extends ListRootElement = 'ul'>(
|
|
76
|
+
props: ListRootProps<T> & { ref?: ForwardedRef<HTMLElement> },
|
|
77
|
+
) => ReturnType<typeof ListRootImpl>;
|
|
78
|
+
|
|
79
|
+
export namespace ListRoot {
|
|
80
|
+
export type Props<T extends ListRootElement = 'ul'> = ListRootProps<T>;
|
|
81
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS custom properties for List component styling.
|
|
3
|
+
* These can be overridden at any level to customize the appearance.
|
|
4
|
+
*
|
|
5
|
+
* Usage with CSS Modules or plain CSS:
|
|
6
|
+
* .my-list {
|
|
7
|
+
* --list-gap: 1rem;
|
|
8
|
+
* --list-padding: 0;
|
|
9
|
+
* }
|
|
10
|
+
*
|
|
11
|
+
* Usage with Tailwind (via arbitrary properties):
|
|
12
|
+
* <List.Root className="[--list-gap:1rem]">
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
:root {
|
|
16
|
+
/* List Root */
|
|
17
|
+
--list-gap: 0;
|
|
18
|
+
--list-padding: 0;
|
|
19
|
+
--list-margin: 0;
|
|
20
|
+
--list-style: none;
|
|
21
|
+
|
|
22
|
+
/* List Item */
|
|
23
|
+
--list-item-padding: 0;
|
|
24
|
+
--list-item-margin: 0;
|
|
25
|
+
|
|
26
|
+
/* Definition List specific */
|
|
27
|
+
--list-dl-grid-columns: auto 1fr;
|
|
28
|
+
--list-dl-gap-x: 0.5rem;
|
|
29
|
+
--list-dl-gap-y: 0.25rem;
|
|
30
|
+
--list-dt-font-weight: 600;
|
|
31
|
+
--list-dd-margin: 0;
|
|
32
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import { List } from './index';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof List.Root> = {
|
|
5
|
+
component: List.Root,
|
|
6
|
+
parameters: {
|
|
7
|
+
layout: 'padded',
|
|
8
|
+
},
|
|
9
|
+
tags: ['autodocs'],
|
|
10
|
+
title: 'Components/List',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof List.Root>;
|
|
15
|
+
|
|
16
|
+
export const UnorderedList: Story = {
|
|
17
|
+
render: () => (
|
|
18
|
+
<List.Root>
|
|
19
|
+
<List.Item>First item</List.Item>
|
|
20
|
+
<List.Item>Second item</List.Item>
|
|
21
|
+
<List.Item>Third item</List.Item>
|
|
22
|
+
</List.Root>
|
|
23
|
+
),
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const OrderedList: Story = {
|
|
27
|
+
render: () => (
|
|
28
|
+
<List.Root render="ol">
|
|
29
|
+
<List.Item>Step one</List.Item>
|
|
30
|
+
<List.Item>Step two</List.Item>
|
|
31
|
+
<List.Item>Step three</List.Item>
|
|
32
|
+
</List.Root>
|
|
33
|
+
),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const DefinitionList: Story = {
|
|
37
|
+
render: () => (
|
|
38
|
+
<List.Root
|
|
39
|
+
className="grid grid-cols-[auto_1fr] gap-x-4 gap-y-2"
|
|
40
|
+
render="dl"
|
|
41
|
+
>
|
|
42
|
+
<List.Item
|
|
43
|
+
className="font-semibold"
|
|
44
|
+
render="dt"
|
|
45
|
+
>
|
|
46
|
+
Email
|
|
47
|
+
</List.Item>
|
|
48
|
+
<List.Item>contact@example.com</List.Item>
|
|
49
|
+
<List.Item
|
|
50
|
+
className="font-semibold"
|
|
51
|
+
render="dt"
|
|
52
|
+
>
|
|
53
|
+
Phone
|
|
54
|
+
</List.Item>
|
|
55
|
+
<List.Item>+1 234 567 890</List.Item>
|
|
56
|
+
<List.Item
|
|
57
|
+
className="font-semibold"
|
|
58
|
+
render="dt"
|
|
59
|
+
>
|
|
60
|
+
Address
|
|
61
|
+
</List.Item>
|
|
62
|
+
<List.Item>123 Main Street, City, Country</List.Item>
|
|
63
|
+
</List.Root>
|
|
64
|
+
),
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const WithDefaultItemClassName: Story = {
|
|
68
|
+
render: () => (
|
|
69
|
+
<List.Root defaultItemClassName="py-2 border-b border-gray-200 last:border-0">
|
|
70
|
+
<List.Item>Styled item one</List.Item>
|
|
71
|
+
<List.Item>Styled item two</List.Item>
|
|
72
|
+
<List.Item>Styled item three</List.Item>
|
|
73
|
+
</List.Root>
|
|
74
|
+
),
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const InlineList: Story = {
|
|
78
|
+
render: () => (
|
|
79
|
+
<List.Root className="flex flex-wrap gap-2 list-none p-0">
|
|
80
|
+
<List.Item className="px-2 py-1 bg-gray-100 rounded">Tag 1</List.Item>
|
|
81
|
+
<List.Item className="px-2 py-1 bg-gray-100 rounded">Tag 2</List.Item>
|
|
82
|
+
<List.Item className="px-2 py-1 bg-gray-100 rounded">Tag 3</List.Item>
|
|
83
|
+
</List.Root>
|
|
84
|
+
),
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const NavigationMenu: Story = {
|
|
88
|
+
render: () => (
|
|
89
|
+
<List.Root
|
|
90
|
+
className="flex gap-4"
|
|
91
|
+
defaultItemElement="div"
|
|
92
|
+
render="nav"
|
|
93
|
+
>
|
|
94
|
+
<List.Item className="hover:text-blue-600 cursor-pointer">Home</List.Item>
|
|
95
|
+
<List.Item className="hover:text-blue-600 cursor-pointer">About</List.Item>
|
|
96
|
+
<List.Item className="hover:text-blue-600 cursor-pointer">Contact</List.Item>
|
|
97
|
+
</List.Root>
|
|
98
|
+
),
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const CustomElements: Story = {
|
|
102
|
+
render: () => (
|
|
103
|
+
<List.Root
|
|
104
|
+
className="flex gap-2"
|
|
105
|
+
defaultItemElement="span"
|
|
106
|
+
render="div"
|
|
107
|
+
>
|
|
108
|
+
<List.Item className="px-3 py-1 bg-blue-100 text-blue-800 rounded-full text-sm">
|
|
109
|
+
React
|
|
110
|
+
</List.Item>
|
|
111
|
+
<List.Item className="px-3 py-1 bg-green-100 text-green-800 rounded-full text-sm">
|
|
112
|
+
TypeScript
|
|
113
|
+
</List.Item>
|
|
114
|
+
<List.Item className="px-3 py-1 bg-purple-100 text-purple-800 rounded-full text-sm">
|
|
115
|
+
Tailwind
|
|
116
|
+
</List.Item>
|
|
117
|
+
</List.Root>
|
|
118
|
+
),
|
|
119
|
+
};
|