@fpkit/acss 0.4.19 → 0.5.2
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/libs/chunk-TBM2QIVT.js +8 -0
- package/libs/chunk-TBM2QIVT.js.map +1 -0
- package/libs/chunk-VAH6X2DZ.cjs +31 -0
- package/libs/chunk-VAH6X2DZ.cjs.map +1 -0
- package/libs/components/badge/badge.css +1 -1
- package/libs/components/badge/badge.css.map +1 -1
- package/libs/components/badge/badge.min.css +2 -2
- package/libs/components/buttons/button.css +1 -1
- package/libs/components/buttons/button.css.map +1 -1
- package/libs/components/buttons/button.min.css +2 -2
- package/libs/components/cards/card.css +1 -1
- package/libs/components/cards/card.css.map +1 -1
- package/libs/components/cards/card.min.css +2 -2
- package/libs/components/details/details.css +1 -1
- package/libs/components/details/details.css.map +1 -1
- package/libs/components/details/details.min.css +2 -2
- package/libs/components/icons/icon.css +1 -1
- package/libs/components/icons/icon.css.map +1 -1
- package/libs/components/icons/icon.min.css +2 -2
- package/libs/{icons-1f5afc0c.d.ts → icons-2f29127c.d.ts} +32 -1
- package/libs/icons.cjs +2 -2
- package/libs/icons.d.cts +1 -1
- package/libs/icons.d.ts +1 -1
- package/libs/icons.js +1 -1
- package/libs/index.cjs +37 -37
- package/libs/index.cjs.map +1 -1
- package/libs/index.css +1 -1
- package/libs/index.css.map +1 -1
- package/libs/index.d.cts +8 -5
- package/libs/index.d.ts +8 -5
- package/libs/index.js +6 -6
- package/libs/index.js.map +1 -1
- package/package.json +3 -2
- package/src/components/badge/badge.scss +1 -0
- package/src/components/badge/badge.stories.tsx +3 -3
- package/src/components/breadcrumbs/breadcrumb.stories.tsx +26 -10
- package/src/components/breadcrumbs/breadcrumb.tsx +48 -40
- package/src/components/buttons/button.scss +3 -4
- package/src/components/buttons/button.stories.tsx +50 -28
- package/src/components/buttons/button.test.tsx +1 -1
- package/src/components/buttons/button.tsx +31 -4
- package/src/components/cards/card.scss +5 -3
- package/src/components/cards/card.stories.tsx +4 -4
- package/src/components/cards/card.tsx +0 -1
- package/src/components/details/details.scss +12 -3
- package/src/components/details/details.stories.tsx +20 -4
- package/src/components/details/details.tsx +2 -1
- package/src/components/form/form.stories.tsx +2 -2
- package/src/components/form/input.stories.tsx +2 -2
- package/src/components/form/select.stories.tsx +2 -2
- package/src/components/form/select.tsx +23 -33
- package/src/components/fp.test.tsx +1 -1
- package/src/components/heading/heading.stories.tsx +2 -2
- package/src/components/heading/heading.tsx +2 -2
- package/src/components/icons/components/svg.tsx +1 -0
- package/src/components/icons/icon.scss +2 -0
- package/src/components/icons/icon.stories.tsx +23 -3
- package/src/components/icons/icon.tsx +11 -0
- package/src/components/icons/types.ts +1 -1
- package/src/components/images/figure.stories.tsx +3 -6
- package/src/components/images/img.stories.tsx +3 -3
- package/src/components/layout/footer.stories.tsx +2 -2
- package/src/components/layout/landmarks.stories.tsx +2 -2
- package/src/components/layout/main.stories.tsx +2 -2
- package/src/components/link/link.stories.tsx +2 -2
- package/src/components/list/list.stories.tsx +7 -2
- package/src/components/nav/nav.stories.tsx +4 -3
- package/src/components/popover/popover.stories.tsx +2 -2
- package/src/components/progress/progress.stories.tsx +2 -2
- package/src/components/tag/tag.stories.tsx +3 -3
- package/src/components/text/text.stories.tsx +6 -6
- package/src/patterns/page/page-header.stories.tsx +2 -2
- package/src/sass/_globals.scss +9 -7
- package/src/styles/badge/badge.css +1 -0
- package/src/styles/badge/badge.css.map +1 -1
- package/src/styles/buttons/button.css +3 -3
- package/src/styles/buttons/button.css.map +1 -1
- package/src/styles/cards/card.css +2 -3
- package/src/styles/cards/card.css.map +1 -1
- package/src/styles/details/details.css +11 -3
- package/src/styles/details/details.css.map +1 -1
- package/src/styles/icons/icon.css +2 -0
- package/src/styles/icons/icon.css.map +1 -1
- package/src/styles/index.css +26 -16
- package/src/styles/index.css.map +1 -1
- package/LICENSE +0 -21
- package/dist/chunk-77CZU5XZ.cjs +0 -9
- package/dist/chunk-77CZU5XZ.cjs.map +0 -1
- package/dist/chunk-D43FJIRQ.cjs +0 -31
- package/dist/chunk-D43FJIRQ.cjs.map +0 -1
- package/dist/chunk-GJWMCDFS.js +0 -9
- package/dist/chunk-GJWMCDFS.js.map +0 -1
- package/dist/chunk-PCDUGD3C.js +0 -5
- package/dist/chunk-PCDUGD3C.js.map +0 -1
- package/dist/hooks.cjs +0 -10
- package/dist/hooks.cjs.map +0 -1
- package/dist/hooks.d.cts +0 -32
- package/dist/hooks.d.ts +0 -32
- package/dist/hooks.js +0 -8
- package/dist/hooks.js.map +0 -1
- package/dist/icon-e6044c73.d.ts +0 -227
- package/dist/icons.cjs +0 -73
- package/dist/icons.cjs.map +0 -1
- package/dist/icons.d.cts +0 -252
- package/dist/icons.d.ts +0 -252
- package/dist/icons.js +0 -4
- package/dist/icons.js.map +0 -1
- package/dist/index.cjs +0 -59
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -566
- package/dist/index.d.ts +0 -566
- package/dist/index.js +0 -11
- package/dist/index.js.map +0 -1
- package/libs/chunk-QHIABQNQ.js +0 -8
- package/libs/chunk-QHIABQNQ.js.map +0 -1
- package/libs/chunk-ZOHIKF6I.cjs +0 -31
- package/libs/chunk-ZOHIKF6I.cjs.map +0 -1
- package/src/components/popover/node_modules/.vitest/results.json +0 -1
- package/src/hooks/popover/node_modules/.vitest/results.json +0 -1
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@fpkit/acss",
|
|
3
3
|
"description": "A lightweight React UI library for building modern and accessible components that leverage CSS custom properties for reactive Styles.",
|
|
4
4
|
"private": false,
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.5.2",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"start": "run-p package:watch sass:watch",
|
|
8
8
|
"dev": "vite --open",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"focus-trap": "^7.5.2",
|
|
29
|
+
"jest-mock": "^29.7.0",
|
|
29
30
|
"react": "^18.0.0",
|
|
30
31
|
"react-dom": "^18.0.0"
|
|
31
32
|
},
|
|
@@ -121,5 +122,5 @@
|
|
|
121
122
|
"publishConfig": {
|
|
122
123
|
"access": "public"
|
|
123
124
|
},
|
|
124
|
-
"gitHead": "
|
|
125
|
+
"gitHead": "2278d7751dcd37ed1799b84773926d9b0268e329"
|
|
125
126
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { StoryObj, Meta } from '@storybook/react'
|
|
2
|
-
import { within,
|
|
3
|
-
|
|
2
|
+
import { within, expect } from '@storybook/test'
|
|
3
|
+
|
|
4
4
|
|
|
5
5
|
import Badge from './badge'
|
|
6
|
-
import './badge.scss'
|
|
6
|
+
// import './badge.scss'
|
|
7
7
|
|
|
8
8
|
const meta: Meta<typeof Badge> = {
|
|
9
9
|
title: 'FP.REACT Components/Badge',
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { StoryObj, Meta } from '@storybook/react'
|
|
2
|
-
import { within, userEvent,
|
|
3
|
-
|
|
1
|
+
import type { StoryObj, Meta } from '@storybook/react'
|
|
2
|
+
import { within, userEvent, fn, expect } from '@storybook/test'
|
|
3
|
+
|
|
4
4
|
|
|
5
5
|
import Breadcrumb from './breadcrumb'
|
|
6
6
|
|
|
7
|
+
const linkClicked = fn()
|
|
8
|
+
|
|
7
9
|
const meta: Meta<typeof Breadcrumb> = {
|
|
8
10
|
title: 'FP.REACT Components/Breadcrumb',
|
|
9
11
|
component: Breadcrumb,
|
|
@@ -16,10 +18,9 @@ const meta: Meta<typeof Breadcrumb> = {
|
|
|
16
18
|
},
|
|
17
19
|
},
|
|
18
20
|
args: {
|
|
19
|
-
// @ts-ignore
|
|
20
21
|
children: 'Link',
|
|
21
22
|
},
|
|
22
|
-
} as
|
|
23
|
+
} as Meta
|
|
23
24
|
|
|
24
25
|
export default meta
|
|
25
26
|
type Story = StoryObj<typeof Breadcrumb>
|
|
@@ -75,13 +76,9 @@ export const EncodedBreadcrumbs: Story = {
|
|
|
75
76
|
},
|
|
76
77
|
],
|
|
77
78
|
currentRoute: '/products/learning%20in%20public',
|
|
79
|
+
|
|
78
80
|
},
|
|
79
81
|
|
|
80
|
-
play: async ({ canvasElement }) => {
|
|
81
|
-
const canvas = within(canvasElement)
|
|
82
|
-
await userEvent.click(screen.getByText('Shirts'))
|
|
83
|
-
expect(screen.getByText('Shirts')).toBeInTheDocument()
|
|
84
|
-
},
|
|
85
82
|
} as Story
|
|
86
83
|
|
|
87
84
|
export const TruncateName: Story = {
|
|
@@ -90,3 +87,22 @@ export const TruncateName: Story = {
|
|
|
90
87
|
currentRoute: '/products/AveryLongNameTruncate',
|
|
91
88
|
},
|
|
92
89
|
} as Story
|
|
90
|
+
|
|
91
|
+
export const ClickHomeLink: Story = {
|
|
92
|
+
args: {
|
|
93
|
+
...CustomURL.args,
|
|
94
|
+
currentRoute: '/products/shirts',
|
|
95
|
+
startRouteUrl: "#",
|
|
96
|
+
linkProps: {
|
|
97
|
+
onClick: linkClicked,
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
play: async ({ canvasElement }) => {
|
|
102
|
+
const canvas = within(canvasElement)
|
|
103
|
+
const homeLink = canvas.getByRole('link', { name: 'Home' })
|
|
104
|
+
expect(homeLink).toHaveAttribute('href', '#')
|
|
105
|
+
// await userEvent.click(homeLink)
|
|
106
|
+
// expect(linkClicked).toHaveBeenCalled()
|
|
107
|
+
},
|
|
108
|
+
} as Story
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import UI from '#components/ui'
|
|
4
4
|
import { Truncate } from '#libs/content'
|
|
5
|
+
import Link from '#components/link/link'
|
|
5
6
|
|
|
6
7
|
// TYPES
|
|
7
8
|
|
|
@@ -19,6 +20,8 @@ type BreadcrumbProps = {
|
|
|
19
20
|
routes?: customRoute[]
|
|
20
21
|
/** Starting route node */
|
|
21
22
|
startRoute?: React.ReactNode
|
|
23
|
+
/* Starting route url */
|
|
24
|
+
startRouteUrl?: string
|
|
22
25
|
/** Spacer node between routes */
|
|
23
26
|
spacer?: React.ReactNode
|
|
24
27
|
/** String representing current route */
|
|
@@ -27,6 +30,8 @@ type BreadcrumbProps = {
|
|
|
27
30
|
ariaLabelPrefix?: string
|
|
28
31
|
/** Truncate breadcrumb text after this length */
|
|
29
32
|
truncateLength?: number
|
|
33
|
+
/** Link props for breadcrumb links */
|
|
34
|
+
linkProps?: React.ComponentProps<typeof Link>
|
|
30
35
|
} & React.ComponentProps<typeof UI>
|
|
31
36
|
|
|
32
37
|
// Components
|
|
@@ -106,6 +111,7 @@ const Nav = ({
|
|
|
106
111
|
*/
|
|
107
112
|
export const Breadcrumb = ({
|
|
108
113
|
startRoute = 'Home',
|
|
114
|
+
startRouteUrl = "/",
|
|
109
115
|
currentRoute,
|
|
110
116
|
spacer = <>/</>,
|
|
111
117
|
routes,
|
|
@@ -114,6 +120,7 @@ export const Breadcrumb = ({
|
|
|
114
120
|
classes,
|
|
115
121
|
ariaLabelPrefix,
|
|
116
122
|
truncateLength = 15,
|
|
123
|
+
linkProps,
|
|
117
124
|
...props
|
|
118
125
|
}: BreadcrumbProps): React.JSX.Element => {
|
|
119
126
|
const [currentPath, setCurrentPath] = React.useState('')
|
|
@@ -122,7 +129,7 @@ export const Breadcrumb = ({
|
|
|
122
129
|
if (path.length) {
|
|
123
130
|
setCurrentPath(path)
|
|
124
131
|
}
|
|
125
|
-
}, [])
|
|
132
|
+
}, [currentRoute])
|
|
126
133
|
|
|
127
134
|
/**
|
|
128
135
|
* Gets the path name for the given path segment.
|
|
@@ -148,6 +155,7 @@ export const Breadcrumb = ({
|
|
|
148
155
|
/** Unique id for breadcrumb */
|
|
149
156
|
const uuid = React.useId()
|
|
150
157
|
|
|
158
|
+
|
|
151
159
|
return currentPath.length ? (
|
|
152
160
|
<Nav
|
|
153
161
|
id={id}
|
|
@@ -157,53 +165,53 @@ export const Breadcrumb = ({
|
|
|
157
165
|
aria-label={ariaLabelPrefix}
|
|
158
166
|
>
|
|
159
167
|
<Items key={`${startRoute}-${uuid}`}>
|
|
160
|
-
<
|
|
168
|
+
<Link href={startRouteUrl} {...linkProps}>{startRoute}</Link>
|
|
161
169
|
</Items>
|
|
170
|
+
<>
|
|
162
171
|
{segments.length ? (
|
|
163
172
|
segments.map((segment: any, index: number) => {
|
|
164
173
|
const currentSegment = getPathName(segment)
|
|
165
174
|
const { name, url, path } = currentSegment
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
<
|
|
191
|
-
<
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
)
|
|
202
|
-
}
|
|
175
|
+
return index === lastSegment ? (
|
|
176
|
+
<>
|
|
177
|
+
{typeof segments[lastSegment] === 'string' &&
|
|
178
|
+
segments[lastSegment].length > 3 &&
|
|
179
|
+
segments[lastSegment] !== segments[lastSegment - 1] && (
|
|
180
|
+
<Items key={`${path || index}-${uuid}`}>
|
|
181
|
+
|
|
182
|
+
<span aria-hidden="true">{spacer}</span>
|
|
183
|
+
<a
|
|
184
|
+
href="#"
|
|
185
|
+
aria-current="page"
|
|
186
|
+
aria-label={
|
|
187
|
+
name.length > truncateLength ? name : undefined
|
|
188
|
+
}
|
|
189
|
+
>
|
|
190
|
+
{Truncate(decodeURIComponent(name), truncateLength)}
|
|
191
|
+
</a>
|
|
192
|
+
|
|
193
|
+
</Items>
|
|
194
|
+
)}
|
|
195
|
+
</>
|
|
196
|
+
) : (
|
|
197
|
+
<Items key={`${currentSegment?.name}-${uuid}`}>
|
|
198
|
+
<span aria-hidden="true">{spacer}</span>
|
|
199
|
+
<span>
|
|
200
|
+
<Link
|
|
201
|
+
href={url}
|
|
202
|
+
aria-label={name.length > truncateLength ? name : undefined}
|
|
203
|
+
{...linkProps}
|
|
204
|
+
>
|
|
205
|
+
{Truncate(decodeURIComponent(name), truncateLength)}
|
|
206
|
+
</Link>
|
|
207
|
+
</span>
|
|
208
|
+
</Items>
|
|
209
|
+
);
|
|
203
210
|
})
|
|
204
211
|
) : (
|
|
205
|
-
|
|
212
|
+
null
|
|
206
213
|
)}
|
|
214
|
+
</>
|
|
207
215
|
</Nav>
|
|
208
216
|
) : (
|
|
209
217
|
<></>
|
|
@@ -3,9 +3,9 @@ button {
|
|
|
3
3
|
--btn-md: calc(16rem / 16);
|
|
4
4
|
--btn-lg: calc(21rem / 16);
|
|
5
5
|
--btn-pill: 100rem;
|
|
6
|
-
--btn-height:
|
|
6
|
+
--btn-height: 2.5rem;
|
|
7
7
|
--fs: 0.95rem;
|
|
8
|
-
--btn-fs:
|
|
8
|
+
--btn-fs: 0.9375rem;
|
|
9
9
|
--btn-bg: lightgray;
|
|
10
10
|
--btn-width: max-content;
|
|
11
11
|
|
|
@@ -58,7 +58,7 @@ button {
|
|
|
58
58
|
background-color: var(--btn-bg, var(--btn, lightgray));
|
|
59
59
|
filter: invert(1) hue-rotate (180deg);
|
|
60
60
|
transform: scale(0.95) var(--line-style, solid);
|
|
61
|
-
outline-offset: var(--line-offset,
|
|
61
|
+
outline-offset: var(--line-offset, 1px);
|
|
62
62
|
|
|
63
63
|
&[aria-disabled='true'] {
|
|
64
64
|
transform: none;
|
|
@@ -105,7 +105,6 @@ button {
|
|
|
105
105
|
--btn-width: unset;
|
|
106
106
|
--btn-py: 0.75rem;
|
|
107
107
|
--btn-px: 0.75rem;
|
|
108
|
-
|
|
109
108
|
&:is(:hover, :focus) {
|
|
110
109
|
background-color: transparent;
|
|
111
110
|
outline: 0.07rem solid var(--btn-cl);
|
|
@@ -1,57 +1,79 @@
|
|
|
1
|
-
import { StoryObj, Meta } from
|
|
2
|
-
import { within, userEvent } from
|
|
3
|
-
import { expect } from '@storybook/jest'
|
|
1
|
+
import type { StoryObj, Meta } from "@storybook/react";
|
|
2
|
+
import { within, userEvent, expect, fn } from "@storybook/test";
|
|
4
3
|
|
|
5
|
-
import Button from
|
|
6
|
-
import
|
|
4
|
+
import Button from "./button";
|
|
5
|
+
import "./button.scss";
|
|
7
6
|
|
|
8
|
-
const
|
|
9
|
-
|
|
7
|
+
const buttonClicked = fn();
|
|
8
|
+
|
|
9
|
+
const meta = {
|
|
10
|
+
title: "FP.React Components/Buttons",
|
|
10
11
|
component: Button,
|
|
11
12
|
args: {
|
|
12
|
-
children:
|
|
13
|
+
children: "Click me",
|
|
14
|
+
onClick: buttonClicked,
|
|
13
15
|
},
|
|
14
16
|
parameters: {
|
|
15
|
-
|
|
17
|
+
actions: { argTypesRegex: '^on.*' },
|
|
16
18
|
},
|
|
17
|
-
|
|
18
|
-
} as Meta
|
|
19
|
+
} as Meta;
|
|
19
20
|
|
|
20
|
-
export default meta
|
|
21
|
-
type Story = StoryObj<typeof Button
|
|
21
|
+
export default meta;
|
|
22
|
+
type Story = StoryObj<typeof Button>;
|
|
22
23
|
|
|
23
24
|
export const ButtonComponent: Story = {
|
|
24
|
-
args: {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
args: {
|
|
26
|
+
onClick: buttonClicked,
|
|
27
|
+
},
|
|
28
|
+
play: async ({ canvasElement, step }) => {
|
|
29
|
+
const canvas = within(canvasElement);
|
|
30
|
+
const button = canvas.getByRole("button");
|
|
31
|
+
await step("Button is rendered", async () => {
|
|
32
|
+
expect(button).toBeInTheDocument();
|
|
33
|
+
});
|
|
34
|
+
await step("Button gets focus on tab", async () => {
|
|
35
|
+
await userEvent.tab();
|
|
36
|
+
expect(button).toHaveFocus();
|
|
37
|
+
});
|
|
38
|
+
await step("Button is clicked", async () => {
|
|
39
|
+
await userEvent.click(button);
|
|
40
|
+
expect(buttonClicked).toHaveBeenCalled();
|
|
41
|
+
});
|
|
42
|
+
// step to check for enter key press
|
|
43
|
+
await step("Button is clicked with enter key", async () => {
|
|
44
|
+
await userEvent.type(button, "{enter}");
|
|
45
|
+
expect(buttonClicked).toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
// step check for space key press
|
|
48
|
+
await step("Button is clicked with space key", async () => {
|
|
49
|
+
await userEvent.type(button, "{space}");
|
|
50
|
+
expect(buttonClicked).toHaveBeenCalled();
|
|
51
|
+
});
|
|
30
52
|
},
|
|
31
|
-
} as Story
|
|
53
|
+
} as Story;
|
|
32
54
|
|
|
33
55
|
export const Small: Story = {
|
|
34
56
|
args: {
|
|
35
|
-
|
|
57
|
+
"data-btn": "sm",
|
|
36
58
|
},
|
|
37
|
-
} as Story
|
|
59
|
+
} as Story;
|
|
38
60
|
|
|
39
61
|
export const Medium: Story = {
|
|
40
62
|
args: {
|
|
41
|
-
|
|
63
|
+
"data-btn": "md",
|
|
42
64
|
},
|
|
43
|
-
} as Story
|
|
65
|
+
} as Story;
|
|
44
66
|
|
|
45
67
|
export const Large: Story = {
|
|
46
68
|
args: {
|
|
47
|
-
|
|
69
|
+
"data-btn": "lg",
|
|
48
70
|
},
|
|
49
|
-
} as Story
|
|
71
|
+
} as Story;
|
|
50
72
|
|
|
51
73
|
export const Custom: Story = {
|
|
52
74
|
args: {
|
|
53
75
|
styles: {
|
|
54
|
-
|
|
76
|
+
"--btn-fs": "2rem",
|
|
55
77
|
},
|
|
56
78
|
},
|
|
57
|
-
} as Story
|
|
79
|
+
} as Story;
|
|
@@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react'
|
|
|
3
3
|
import { Button } from './button'
|
|
4
4
|
import user from '@testing-library/user-event'
|
|
5
5
|
import jest from 'jest-mock'
|
|
6
|
-
import { userEvent } from '@storybook/
|
|
6
|
+
import { userEvent } from '@storybook/test'
|
|
7
7
|
|
|
8
8
|
describe('Button', () => {
|
|
9
9
|
it('renders a button element with the correct label', () => {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import UI from '../ui'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
|
|
4
|
-
export type ButtonProps = React.
|
|
5
|
-
Partial<React.ComponentProps<typeof UI>> & {
|
|
4
|
+
export type ButtonProps = Partial<React.ComponentProps<typeof UI>> & {
|
|
6
5
|
/**
|
|
7
6
|
* The button type
|
|
8
7
|
* Required - 'button' | 'submit' | 'reset'
|
|
@@ -19,27 +18,54 @@ export const Button = ({
|
|
|
19
18
|
onPointerDown,
|
|
20
19
|
onPointerOver,
|
|
21
20
|
onPointerLeave,
|
|
22
|
-
|
|
21
|
+
onClick,
|
|
23
22
|
...props
|
|
24
23
|
}: ButtonProps) => {
|
|
24
|
+
/**
|
|
25
|
+
* Handles the pointer down event on the button.
|
|
26
|
+
* Only triggers the onPointerDown callback if the button is not disabled.
|
|
27
|
+
* @param e The pointer event object from the button element
|
|
28
|
+
*/
|
|
25
29
|
const handlePointerDown = (e: React.PointerEvent<HTMLButtonElement>) => {
|
|
26
30
|
if (!disabled) {
|
|
27
31
|
onPointerDown?.(e)
|
|
28
32
|
}
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Handles the pointer over event on the button.
|
|
37
|
+
* Only triggers the onPointerOver callback if the button is not disabled.
|
|
38
|
+
* @param e The pointer event object from the button element
|
|
39
|
+
*/
|
|
31
40
|
const handlePointerOver = (e: React.PointerEvent<HTMLButtonElement>) => {
|
|
32
41
|
if (!disabled) {
|
|
33
42
|
onPointerOver?.(e)
|
|
34
43
|
}
|
|
35
44
|
}
|
|
36
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Handles the pointer leave event on the button.
|
|
48
|
+
* Only triggers the onPointerLeave callback if the button is not disabled.
|
|
49
|
+
* @param e The pointer event object from the button element
|
|
50
|
+
*/
|
|
37
51
|
const handlePointerLeave = (e: React.PointerEvent<HTMLButtonElement>) => {
|
|
38
52
|
if (!disabled) {
|
|
39
53
|
onPointerLeave?.(e)
|
|
40
54
|
}
|
|
41
55
|
}
|
|
42
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Handles the click event on the button.
|
|
59
|
+
* Only triggers the onClick callback if the button is not disabled.
|
|
60
|
+
* @param e The mouse event object from the button element
|
|
61
|
+
*/
|
|
62
|
+
const handleOnClick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
|
63
|
+
if (!disabled) {
|
|
64
|
+
onClick?.(e)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
43
69
|
/* Returning a button element. */
|
|
44
70
|
return (
|
|
45
71
|
<UI
|
|
@@ -48,10 +74,11 @@ export const Button = ({
|
|
|
48
74
|
onPointerOver={handlePointerOver}
|
|
49
75
|
onPointerDown={handlePointerDown}
|
|
50
76
|
onPointerLeave={handlePointerLeave}
|
|
77
|
+
onKeyDown={handlePointerDown}
|
|
51
78
|
style={styles}
|
|
52
79
|
className={classes}
|
|
53
80
|
aria-disabled={disabled}
|
|
54
|
-
onClick={
|
|
81
|
+
onClick={handleOnClick}
|
|
55
82
|
{...props}
|
|
56
83
|
>
|
|
57
84
|
{children}
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
--card-position: relative;
|
|
6
6
|
--card-display: flex;
|
|
7
7
|
--card-direction: column;
|
|
8
|
-
--card-gap:
|
|
8
|
+
--card-gap: 1rem;
|
|
9
9
|
}
|
|
10
|
+
|
|
10
11
|
[data-card],
|
|
11
12
|
[data-component~='card'] {
|
|
12
13
|
display: var(--card-display);
|
|
@@ -15,11 +16,11 @@
|
|
|
15
16
|
border-radius: var(--card-radius);
|
|
16
17
|
background-color: var(--card-bg);
|
|
17
18
|
text-align: var(--card-align, left);
|
|
18
|
-
|
|
19
|
-
[data-card-content],
|
|
19
|
+
|
|
20
20
|
h3,
|
|
21
21
|
h2 {
|
|
22
22
|
margin-block-end: 0;
|
|
23
|
+
padding-block-end: 0;
|
|
23
24
|
}
|
|
24
25
|
+ div {
|
|
25
26
|
margin-block-start: 0;
|
|
@@ -41,3 +42,4 @@
|
|
|
41
42
|
padding-block-start: calc(var(--card-p) - 0.5rem);
|
|
42
43
|
}
|
|
43
44
|
}
|
|
45
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StoryObj, Meta } from '@storybook/react'
|
|
2
|
-
import { within, userEvent, screen } from '@storybook/
|
|
3
|
-
|
|
2
|
+
import { within, userEvent, screen } from '@storybook/test'
|
|
3
|
+
|
|
4
4
|
|
|
5
5
|
import Card from './card'
|
|
6
6
|
// import './card.scss'
|
|
@@ -30,7 +30,7 @@ export const Multiple: Story = {
|
|
|
30
30
|
},
|
|
31
31
|
},
|
|
32
32
|
render: (args) => (
|
|
33
|
-
|
|
33
|
+
<div style={{ display: 'flex', gap: '1rem', flexDirection: 'column' }}>
|
|
34
34
|
<Card {...args}>
|
|
35
35
|
<p>
|
|
36
36
|
Proident et amet aliqua excepteur sunt qui deserunt commodo tempor
|
|
@@ -55,7 +55,7 @@ export const Multiple: Story = {
|
|
|
55
55
|
culpa aliqua veniam.
|
|
56
56
|
</p>
|
|
57
57
|
</Card>
|
|
58
|
-
|
|
58
|
+
</div>
|
|
59
59
|
),
|
|
60
60
|
} as Story
|
|
61
61
|
|
|
@@ -133,7 +133,6 @@ Footer.displayName = 'Footer'
|
|
|
133
133
|
* @param {boolean} [props.renderStyles=true] - Whether to render default styles
|
|
134
134
|
* @param {string} [props.dataStyle] - data-card attribute value
|
|
135
135
|
* @param {string} [props.id] - Unique ID
|
|
136
|
-
*
|
|
137
136
|
* @returns {ReactElement} Card component
|
|
138
137
|
*/
|
|
139
138
|
export const Card = ({
|
|
@@ -4,10 +4,10 @@ details {
|
|
|
4
4
|
--details-border: 1px solid #dfdfdf;
|
|
5
5
|
--details-display: flex;
|
|
6
6
|
--details-justify: flex-start;
|
|
7
|
-
--details-direction:
|
|
8
|
-
--details-gap:
|
|
7
|
+
--details-direction: column;
|
|
8
|
+
--details-gap: 0rem;
|
|
9
9
|
--details-px: 1.5rem;
|
|
10
|
-
--details-py:
|
|
10
|
+
--details-py: 1rem;
|
|
11
11
|
--details-radius: 0.5rem;
|
|
12
12
|
--summary-cursor: pointer;
|
|
13
13
|
--summary-transitions: all 0.75s linear;
|
|
@@ -41,11 +41,19 @@ details {
|
|
|
41
41
|
padding-block: var(--summary-py, var(--details-py));
|
|
42
42
|
gap: var(--summary-gap);
|
|
43
43
|
list-style: none;
|
|
44
|
+
border-top-left-radius: var(--details-radius);
|
|
45
|
+
border-top-right-radius: var(--details-radius);
|
|
44
46
|
|
|
45
47
|
&::-webkit-details-marker {
|
|
46
48
|
display: none;
|
|
47
49
|
}
|
|
48
50
|
|
|
51
|
+
&:focus-within {
|
|
52
|
+
outline: none;
|
|
53
|
+
border-bottom: solid 2px var(--details-border);
|
|
54
|
+
background-color: whitesmoke;
|
|
55
|
+
}
|
|
56
|
+
|
|
49
57
|
/* This ensures no bullet points are shown */
|
|
50
58
|
|
|
51
59
|
&:hover {
|
|
@@ -59,6 +67,7 @@ details {
|
|
|
59
67
|
> section {
|
|
60
68
|
padding-inline: var(--details-px);
|
|
61
69
|
padding-block: var(--details-py);
|
|
70
|
+
margin-block-start: 0;
|
|
62
71
|
border: 1px transparent solid;
|
|
63
72
|
}
|
|
64
73
|
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { StoryObj, Meta } from '@storybook/react'
|
|
2
|
-
import { within,
|
|
3
|
-
|
|
2
|
+
import { within, expect, userEvent } from '@storybook/test'
|
|
3
|
+
|
|
4
4
|
|
|
5
5
|
import Details from './details'
|
|
6
6
|
import Icons from '../icons/icon'
|
|
7
|
-
import '../../styles/details/details.css'
|
|
8
7
|
|
|
9
8
|
const content = (
|
|
10
9
|
<>
|
|
@@ -56,7 +55,7 @@ export const DetailsDropdown: Story = {
|
|
|
56
55
|
args: {},
|
|
57
56
|
play: async ({ canvasElement }) => {
|
|
58
57
|
const canvas = within(canvasElement)
|
|
59
|
-
expect(canvas.getByRole('group')).toBeInTheDocument()
|
|
58
|
+
expect(canvas.getByRole('group', { name: /details dropdown/i })).toBeInTheDocument()
|
|
60
59
|
},
|
|
61
60
|
} as Story
|
|
62
61
|
|
|
@@ -120,3 +119,20 @@ export const DetailsAccordion: Story = {
|
|
|
120
119
|
</>
|
|
121
120
|
)
|
|
122
121
|
} as Story
|
|
122
|
+
|
|
123
|
+
export const DetailsInteractionTest: Story = {
|
|
124
|
+
args: {},
|
|
125
|
+
play: async ({ canvasElement }) => {
|
|
126
|
+
const canvas = within(canvasElement);
|
|
127
|
+
|
|
128
|
+
// Find the summary element
|
|
129
|
+
const summaryElement = canvas.getByText('Summary Section');
|
|
130
|
+
|
|
131
|
+
// Simulate a click on the summary element
|
|
132
|
+
await userEvent.click(summaryElement);
|
|
133
|
+
|
|
134
|
+
// Assert that the details element is open
|
|
135
|
+
const detailsElement = canvas.getByRole('group', { name: /details dropdown/i });
|
|
136
|
+
expect(detailsElement).toHaveAttribute('open');
|
|
137
|
+
},
|
|
138
|
+
}
|
|
@@ -61,10 +61,11 @@ export const Details = ({
|
|
|
61
61
|
ref={ref}
|
|
62
62
|
open={open}
|
|
63
63
|
aria-label={ariaLabel || 'Details dropdown'}
|
|
64
|
+
// aria-roledescription="detail accordion"
|
|
64
65
|
name={name}
|
|
65
66
|
{...props}
|
|
66
67
|
>
|
|
67
|
-
<UI as="summary"
|
|
68
|
+
<UI as="summary" onPointerDown={onPointerDownCallback}>
|
|
68
69
|
{icon}
|
|
69
70
|
{summary}
|
|
70
71
|
</UI>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StoryObj, Meta } from '@storybook/react'
|
|
2
|
-
import { within,
|
|
3
|
-
|
|
2
|
+
import { within, expect } from '@storybook/test'
|
|
3
|
+
|
|
4
4
|
|
|
5
5
|
import Form from './form'
|
|
6
6
|
import './form.scss'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StoryObj, Meta } from '@storybook/react'
|
|
2
|
-
import { within, userEvent,
|
|
3
|
-
|
|
2
|
+
import { within, userEvent, expect } from '@storybook/test'
|
|
3
|
+
|
|
4
4
|
|
|
5
5
|
import Input from './inputs'
|
|
6
6
|
import './form.scss'
|