@fpkit/acss 0.5.7 → 0.5.9
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/components/alert/alert.css +1 -0
- package/libs/components/alert/alert.css.map +1 -0
- package/libs/components/alert/alert.min.css +3 -0
- package/libs/components/badge/badge.css +1 -0
- package/libs/components/badge/badge.css.map +1 -0
- package/libs/components/badge/badge.min.css +3 -0
- package/libs/components/breadcrumbs/breadcrumb.css +1 -0
- package/libs/components/breadcrumbs/breadcrumb.css.map +1 -0
- package/libs/components/breadcrumbs/breadcrumb.min.css +3 -0
- package/libs/components/buttons/button.css +1 -0
- package/libs/components/buttons/button.css.map +1 -0
- package/libs/components/buttons/button.min.css +3 -0
- package/libs/components/cards/card-style.css +1 -0
- package/libs/components/cards/card-style.css.map +1 -0
- package/libs/components/cards/card-style.min.css +3 -0
- package/libs/components/cards/card.css +1 -0
- package/libs/components/cards/card.css.map +1 -0
- package/libs/components/cards/card.min.css +3 -0
- package/libs/components/details/details.css +1 -0
- package/libs/components/details/details.css.map +1 -0
- package/libs/components/details/details.min.css +3 -0
- package/libs/components/dialog/dialog.css +1 -0
- package/libs/components/dialog/dialog.css.map +1 -0
- package/libs/components/dialog/dialog.min.css +3 -0
- package/libs/components/form/form.css +1 -0
- package/libs/components/form/form.css.map +1 -0
- package/libs/components/form/form.min.css +3 -0
- package/libs/components/icons/icon.css +1 -0
- package/libs/components/icons/icon.css.map +1 -0
- package/libs/components/icons/icon.min.css +3 -0
- package/libs/components/images/img.css +1 -0
- package/libs/components/images/img.css.map +1 -0
- package/libs/components/images/img.min.css +3 -0
- package/libs/components/layout/landmarks.css +1 -0
- package/libs/components/layout/landmarks.css.map +1 -0
- package/libs/components/layout/landmarks.min.css +3 -0
- package/libs/components/link/link.css +1 -0
- package/libs/components/link/link.css.map +1 -0
- package/libs/components/link/link.min.css +3 -0
- package/libs/components/nav/nav.css +1 -0
- package/libs/components/nav/nav.css.map +1 -0
- package/libs/components/nav/nav.min.css +3 -0
- package/libs/components/progress/progress.css +1 -0
- package/libs/components/progress/progress.css.map +1 -0
- package/libs/components/progress/progress.min.css +3 -0
- package/libs/components/styles/index.css +1 -0
- package/libs/components/styles/index.css.map +1 -0
- package/libs/components/styles/index.min.css +3 -0
- package/libs/components/tag/tag.css +1 -0
- package/libs/components/tag/tag.css.map +1 -0
- package/libs/components/tag/tag.min.css +3 -0
- package/libs/components/text-to-speech/text-to-speech.css +1 -0
- package/libs/components/text-to-speech/text-to-speech.css.map +1 -0
- package/libs/components/text-to-speech/text-to-speech.min.css +3 -0
- package/libs/index.cjs +2 -2
- package/libs/index.cjs.map +1 -1
- package/libs/index.css +1 -0
- package/libs/index.css.map +1 -0
- package/libs/index.d.cts +23 -22
- package/libs/index.d.ts +23 -22
- package/libs/index.js +2 -2
- package/libs/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/alert/README.mdx +44 -56
- package/src/components/alert/alert.scss +1 -1
- package/src/components/alert/alert.stories.tsx +7 -7
- package/src/components/alert/alert.tsx +10 -2
- package/src/components/badge/badge.tsx +19 -11
- package/src/components/breadcrumbs/README.mdx +91 -0
- package/src/components/breadcrumbs/breadcrumb.tsx +92 -87
- package/src/components/buttons/README.mdx +96 -0
- package/src/components/buttons/button.scss +4 -2
- package/src/components/cards/README.mdx +133 -0
- package/src/components/details/README.mdx +101 -0
- package/src/components/details/details.scss +21 -15
- package/src/components/details/details.stories.tsx +35 -7
- package/src/components/details/details.tsx +18 -11
- package/src/components/dialog/dialog-modal.stories.tsx +1 -1
- package/src/components/form/inputs.tsx +18 -24
- package/src/components/heading/heading.tsx +24 -12
- package/src/components/text/README.mdx +98 -0
- package/src/components/text/text.tsx +49 -50
- package/src/styles/alert/alert.css +0 -1
- package/src/styles/alert/alert.css.map +1 -1
- package/src/styles/buttons/button.css +4 -2
- package/src/styles/buttons/button.css.map +1 -1
- package/src/styles/details/details.css +18 -13
- package/src/styles/details/details.css.map +1 -1
- package/src/styles/index.css +22 -16
- package/src/styles/index.css.map +1 -1
- package/src/components/alert/alert.mdx +0 -74
- package/src/components/cards/README.md +0 -80
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Meta } from "@storybook/blocks";
|
|
2
|
+
|
|
3
|
+
<Meta title="FP.REACT Components/Card/Readme" />
|
|
4
|
+
|
|
5
|
+
# Card Component
|
|
6
|
+
|
|
7
|
+
The Card component is a versatile and reusable React component for creating
|
|
8
|
+
card-like UI elements. It's part of the FPKit React component library.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
import Card from "@fpkit/cards";
|
|
14
|
+
|
|
15
|
+
<Card elm="div">
|
|
16
|
+
<Card.Title>Card Title</Card.Title>
|
|
17
|
+
<Card.Content
|
|
18
|
+
className="custom-card-content"
|
|
19
|
+
styles={{ color: "blue", padding: "1rem" }}
|
|
20
|
+
>
|
|
21
|
+
This is the content of the card.
|
|
22
|
+
</Card.Content>
|
|
23
|
+
</Card>;
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Components
|
|
27
|
+
|
|
28
|
+
### Card
|
|
29
|
+
|
|
30
|
+
The main container component for the card.
|
|
31
|
+
|
|
32
|
+
#### Props
|
|
33
|
+
|
|
34
|
+
- `elm?: 'div' | 'aside' | 'section' | 'article'` - HTML element to render as
|
|
35
|
+
(default: 'div')
|
|
36
|
+
- `title?: React.ReactNode` - Card title
|
|
37
|
+
- `footer?: React.ReactNode` - Card footer
|
|
38
|
+
- `styles?: React.CSSProperties` - Inline styles
|
|
39
|
+
- `classes?: string` - Additional CSS classes
|
|
40
|
+
- `id?: string` - Unique ID for the card
|
|
41
|
+
|
|
42
|
+
All other props, such as `aria-*` attributes, `data-*` attributes, and event
|
|
43
|
+
handlers (e.g., `onClick`, `onMouseEnter`), are passed through to the underlying
|
|
44
|
+
UI component. This allows you to customize the behavior and accessibility of the
|
|
45
|
+
Card component as needed.
|
|
46
|
+
|
|
47
|
+
### Card.Title
|
|
48
|
+
|
|
49
|
+
A sub-component for rendering the card's title.
|
|
50
|
+
|
|
51
|
+
#### Props
|
|
52
|
+
|
|
53
|
+
- `as?: React.ElementType` - HTML element to render as (default: 'h3')
|
|
54
|
+
- `className?: string` - Additional CSS classes
|
|
55
|
+
- `styles?: React.CSSProperties` - Inline styles
|
|
56
|
+
|
|
57
|
+
#### Example
|
|
58
|
+
|
|
59
|
+
### Card.Content
|
|
60
|
+
|
|
61
|
+
A sub-component for rendering the card's main content.
|
|
62
|
+
|
|
63
|
+
#### Props
|
|
64
|
+
|
|
65
|
+
- `className?: string` - Additional CSS classes
|
|
66
|
+
- `styles?: React.CSSProperties` - Inline styles
|
|
67
|
+
|
|
68
|
+
## Styling
|
|
69
|
+
|
|
70
|
+
The component uses CSS classes for styling:
|
|
71
|
+
|
|
72
|
+
- `.card-title` for the title
|
|
73
|
+
- `.card-content` for the content
|
|
74
|
+
|
|
75
|
+
To integrate these styles with CSS Modules or SASS/SCSS:
|
|
76
|
+
|
|
77
|
+
1. Create a CSS Module file (e.g., `Card.module.scss`) or a SASS/SCSS file
|
|
78
|
+
(e.g., `Card.scss`).
|
|
79
|
+
|
|
80
|
+
## Accessibility
|
|
81
|
+
|
|
82
|
+
The Card component is designed with accessibility in mind:
|
|
83
|
+
|
|
84
|
+
- It uses semantic HTML elements (`div`, `aside`, `section`, or `article`) for
|
|
85
|
+
the main container.
|
|
86
|
+
- The Title component defaults to using an `h3` element, which can be changed if
|
|
87
|
+
needed.
|
|
88
|
+
- The Content component uses an `article` element for semantic structure.
|
|
89
|
+
|
|
90
|
+
### Example with ARIA Attributes
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<Card classes={styles.card}>
|
|
94
|
+
<Card.Title className={styles.cardTitle}>Card Title</Card.Title>
|
|
95
|
+
<Card.Content className={styles.cardContent}>
|
|
96
|
+
This is the content of the card.
|
|
97
|
+
</Card.Content>
|
|
98
|
+
</Card>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
You can override these classes or provide additional styling through the
|
|
102
|
+
`className` and `styles` props.
|
|
103
|
+
|
|
104
|
+
## Accessibility
|
|
105
|
+
|
|
106
|
+
The Card component is designed with accessibility in mind:
|
|
107
|
+
|
|
108
|
+
- It uses semantic HTML elements (`div`, `aside`, `section`, or `article`) for
|
|
109
|
+
the main container.
|
|
110
|
+
- The Title component defaults to using an `h3` element, which can be changed if
|
|
111
|
+
needed.
|
|
112
|
+
- The Content component uses an `article` element for semantic structure.
|
|
113
|
+
|
|
114
|
+
## TypeScript
|
|
115
|
+
|
|
116
|
+
This component is written in TypeScript and provides type definitions for all
|
|
117
|
+
props and sub-components.
|
|
118
|
+
|
|
119
|
+
## Contributing
|
|
120
|
+
|
|
121
|
+
When contributing to this component, please follow the established code style
|
|
122
|
+
and conventions. Ensure all changes are well-tested using **Vitest** and
|
|
123
|
+
documented. Additionally, use **ESLint** and **Prettier** for code formatting
|
|
124
|
+
and linting to maintain consistency.
|
|
125
|
+
|
|
126
|
+
This README provides an overview of the Card component, its usage, available
|
|
127
|
+
props, styling information, and accessibility considerations. It also mentions
|
|
128
|
+
that the component is written in TypeScript and provides guidance for
|
|
129
|
+
contributors.
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Meta } from "@storybook/blocks";
|
|
2
|
+
|
|
3
|
+
<Meta title="FP.REACT Components/Details/Readme" />
|
|
4
|
+
|
|
5
|
+
# Details Component
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
The `Details` component is a versatile and accessible component that provides a
|
|
10
|
+
collapsible section for displaying content. It is built using functional
|
|
11
|
+
components and hooks, ensuring reusability and performance optimization.
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- Accessible with aria-label support.
|
|
16
|
+
- Customizable with styles and class names.
|
|
17
|
+
- Supports icons and custom summary content.
|
|
18
|
+
- Easy to integrate and use in any React application.
|
|
19
|
+
|
|
20
|
+
## Props
|
|
21
|
+
|
|
22
|
+
| Name | Type | Description |
|
|
23
|
+
| --------------- | ----------------------------------------------------- | ------------------------------------------------- |
|
|
24
|
+
| `summary` | `React.ReactNode` | The summary text shown for the details. Required. |
|
|
25
|
+
| `ariaLabel` | `string` | The aria-label element for accessibility. |
|
|
26
|
+
| `styles` | `React.CSSProperties` | CSS styles object. |
|
|
27
|
+
| `classes` | `string` | Classnames string. |
|
|
28
|
+
| `open` | `boolean` | Whether the details is open. |
|
|
29
|
+
| `onToggle` | `(e: React.PointerEvent<HTMLDetailsElement>) => void` | onToggle callback. |
|
|
30
|
+
| `onPointerDown` | `(e: React.PointerEvent<HTMLDetailsElement>) => void` | onPointerDown callback. |
|
|
31
|
+
| `children` | `React.ReactNode` | The content inside the details. |
|
|
32
|
+
| `ref` | `React.Ref<any>` | Ref object. |
|
|
33
|
+
| `name` | `string` | Name attribute for the details element. |
|
|
34
|
+
|
|
35
|
+
## Technical Details
|
|
36
|
+
|
|
37
|
+
The `Details` component is built using TypeScript for type-checking and enhanced
|
|
38
|
+
developer experience. It uses functional components and hooks to ensure
|
|
39
|
+
performance and reusability.
|
|
40
|
+
|
|
41
|
+
## Usage Example
|
|
42
|
+
|
|
43
|
+
### Basic Usage
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import React from "react";
|
|
47
|
+
import Details from "./details";
|
|
48
|
+
import Icons from "../icons/icon";
|
|
49
|
+
|
|
50
|
+
const content = (
|
|
51
|
+
<>
|
|
52
|
+
<p>Example content inside the details component.</p>
|
|
53
|
+
</>
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const icon = <Icons.Add />;
|
|
57
|
+
|
|
58
|
+
const Example = () => (
|
|
59
|
+
<Details summary="Summary Section" icon={icon} ariaLabel="Details Section">
|
|
60
|
+
{content}
|
|
61
|
+
</Details>
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
export default Example;
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Advanced Usage
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
import React from "react";
|
|
71
|
+
import Details from "./details";
|
|
72
|
+
import Icons from "../icons/icon";
|
|
73
|
+
|
|
74
|
+
const content = (
|
|
75
|
+
<>
|
|
76
|
+
<p>Advanced example content inside the details component.</p>
|
|
77
|
+
</>
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const icon = <Icons.Add />;
|
|
81
|
+
|
|
82
|
+
const AdvancedExample = () => (
|
|
83
|
+
<Details
|
|
84
|
+
summary="Advanced Summary Section"
|
|
85
|
+
icon={icon}
|
|
86
|
+
ariaLabel="Advanced Details Section"
|
|
87
|
+
open={true}
|
|
88
|
+
onToggle={(e) => console.log("Toggled", e)}
|
|
89
|
+
>
|
|
90
|
+
{content}
|
|
91
|
+
</Details>
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
export default AdvancedExample;
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Additional Notes
|
|
98
|
+
|
|
99
|
+
- Ensure to provide meaningful aria-labels for accessibility.
|
|
100
|
+
- Customize the component using the `styles` and `classes` props.
|
|
101
|
+
- Use the `onToggle` and `onPointerDown` callbacks for custom interactions.
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
details {
|
|
2
|
-
--details-
|
|
3
|
-
--details-h: max-content;
|
|
4
|
-
--details-border: 1px solid #dfdfdf;
|
|
5
|
-
--details-display: flex;
|
|
6
|
-
--details-justify: flex-start;
|
|
2
|
+
--details-border: 0.0625rem solid #dfdfdf;
|
|
7
3
|
--details-direction: column;
|
|
4
|
+
--details-display: flex;
|
|
8
5
|
--details-gap: 0rem;
|
|
6
|
+
--details-h: max-content;
|
|
7
|
+
--details-justify: flex-start;
|
|
9
8
|
--details-px: 1.5rem;
|
|
10
9
|
--details-py: 1rem;
|
|
11
|
-
--details-radius:
|
|
10
|
+
--details-radius: 0;
|
|
11
|
+
--details-w: 100%;
|
|
12
|
+
--max-h-closed: 6.25rem;
|
|
13
|
+
--max-h-open: 50rem;
|
|
14
|
+
--summary-align: center;
|
|
12
15
|
--summary-cursor: pointer;
|
|
13
|
-
--summary-transitions: all 0.75s ease-in-out;
|
|
14
16
|
--summary-display: flex;
|
|
15
|
-
--summary-justify: flex-start;
|
|
16
|
-
--summary-align: center;
|
|
17
17
|
--summary-gap: 0.5rem;
|
|
18
|
-
--
|
|
19
|
-
--
|
|
18
|
+
--summary-justify: flex-start;
|
|
19
|
+
--summary-transitions: all 0.75s ease-in-out;
|
|
20
20
|
|
|
21
21
|
interpolate-size: allow-keywords;
|
|
22
22
|
display: var(--details-display);
|
|
@@ -25,12 +25,11 @@ details {
|
|
|
25
25
|
gap: var(--details-gap);
|
|
26
26
|
width: var(--details-w);
|
|
27
27
|
border: var(--details-border);
|
|
28
|
+
border-left: none;
|
|
29
|
+
border-right: none;
|
|
28
30
|
transition: var(--summary-transitions);
|
|
29
31
|
max-height: var(--max-h-closed);
|
|
30
32
|
overflow: clip;
|
|
31
|
-
border-radius: var(--details-radius);
|
|
32
|
-
|
|
33
|
-
// Handle multiple details elements
|
|
34
33
|
& + details {
|
|
35
34
|
border-radius: 0; // remove radius from middle elements
|
|
36
35
|
border-top: none; // optional: remove double borders
|
|
@@ -71,7 +70,7 @@ details {
|
|
|
71
70
|
|
|
72
71
|
&:focus-within {
|
|
73
72
|
outline: none;
|
|
74
|
-
border-bottom: solid 2px
|
|
73
|
+
border-bottom: solid 2px currentColor;
|
|
75
74
|
background-color: whitesmoke;
|
|
76
75
|
}
|
|
77
76
|
|
|
@@ -84,6 +83,13 @@ details {
|
|
|
84
83
|
}
|
|
85
84
|
}
|
|
86
85
|
|
|
86
|
+
.list-styles {
|
|
87
|
+
summary {
|
|
88
|
+
border-left: none;
|
|
89
|
+
border-right: none;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
87
93
|
> section {
|
|
88
94
|
padding-inline: var(--details-px);
|
|
89
95
|
padding-block: var(--details-py);
|
|
@@ -60,6 +60,12 @@ export const DetailsDropdown: Story = {
|
|
|
60
60
|
},
|
|
61
61
|
} as Story;
|
|
62
62
|
|
|
63
|
+
export const DetailsStyles: Story = {
|
|
64
|
+
args: {
|
|
65
|
+
classes: "list-style",
|
|
66
|
+
},
|
|
67
|
+
} as Story;
|
|
68
|
+
|
|
63
69
|
export const DetailsOpen: Story = {
|
|
64
70
|
args: {
|
|
65
71
|
open: true,
|
|
@@ -123,19 +129,41 @@ export const DetailsAccordion: Story = {
|
|
|
123
129
|
|
|
124
130
|
export const DetailsInteractionTest: Story = {
|
|
125
131
|
args: {},
|
|
126
|
-
play: async ({ canvasElement }) => {
|
|
132
|
+
play: async ({ canvasElement, step }) => {
|
|
127
133
|
const canvas = within(canvasElement);
|
|
128
134
|
|
|
129
135
|
// Find the summary element
|
|
130
136
|
const summaryElement = canvas.getByText("Summary Section");
|
|
137
|
+
// add an open step
|
|
138
|
+
await step("Open the details", async () => {
|
|
139
|
+
// Simulate a click on the summary element
|
|
140
|
+
await userEvent.click(summaryElement, { delay: 500 });
|
|
141
|
+
|
|
142
|
+
// Assert that the details element is open
|
|
143
|
+
const detailsElement = canvas.getByRole("group", {
|
|
144
|
+
name: /details dropdown/i,
|
|
145
|
+
});
|
|
146
|
+
expect(detailsElement).toHaveAttribute("open");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
await step("Close the detail panel", async () => {
|
|
150
|
+
await userEvent.click(summaryElement, { delay: 500 });
|
|
151
|
+
|
|
152
|
+
expect(summaryElement).not.toHaveAttribute("open");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// test if it works with the space bar
|
|
156
|
+
await step("Open the details with space", async () => {
|
|
157
|
+
summaryElement.focus();
|
|
158
|
+
expect(summaryElement).toHaveFocus();
|
|
131
159
|
|
|
132
|
-
|
|
133
|
-
await userEvent.click(summaryElement);
|
|
160
|
+
await userEvent.type(summaryElement, "{space}", { delay: 500 });
|
|
134
161
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
162
|
+
// Assert that the details element is open
|
|
163
|
+
const detailsElement = canvas.getByRole("group", {
|
|
164
|
+
name: /details dropdown/i,
|
|
165
|
+
});
|
|
166
|
+
expect(detailsElement).toHaveAttribute("open");
|
|
138
167
|
});
|
|
139
|
-
expect(detailsElement).toHaveAttribute("open");
|
|
140
168
|
},
|
|
141
169
|
};
|
|
@@ -15,18 +15,25 @@ type DetailsProps = {
|
|
|
15
15
|
} & React.ComponentProps<"details"> &
|
|
16
16
|
Partial<React.ComponentProps<typeof UI>>;
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
18
|
+
/**
|
|
19
|
+
* A React component that renders a details element with a summary and content.
|
|
20
20
|
*
|
|
21
|
-
* @param
|
|
22
|
-
* @param
|
|
23
|
-
* @param
|
|
24
|
-
* @param
|
|
25
|
-
* @param
|
|
26
|
-
* @param
|
|
27
|
-
* @param
|
|
28
|
-
* @param
|
|
29
|
-
* @param
|
|
21
|
+
* @param summary - The summary text shown for the details.
|
|
22
|
+
* @param ariaLabel - The aria-label element for accessibility.
|
|
23
|
+
* @param icon - An optional icon to display in the summary.
|
|
24
|
+
* @param styles - Optional styles to apply to the details element.
|
|
25
|
+
* @param classes - Optional CSS classes to apply to the details element.
|
|
26
|
+
* @param name - An optional name for the details element.
|
|
27
|
+
* @param open - Whether the details element should be initially open.
|
|
28
|
+
* @param onPointerDown - A callback function to be called when the summary is clicked.
|
|
29
|
+
* @param onToggle - A callback function to be called when the details element is toggled.
|
|
30
|
+
* @param children - The content to be displayed inside the details element.
|
|
31
|
+
* @param ref - A ref to the details element.
|
|
32
|
+
* @param props - Additional props to be passed to the details element.
|
|
33
|
+
* @example
|
|
34
|
+
* <Details summary="Details" ariaLabel="Details">
|
|
35
|
+
* <p>Details content</p>
|
|
36
|
+
* </Details>
|
|
30
37
|
*/
|
|
31
38
|
export const Details = ({
|
|
32
39
|
summary,
|
|
@@ -104,7 +104,7 @@ export const ModalInteractions: Story = {
|
|
|
104
104
|
expect(openButton).not.toHaveFocus();
|
|
105
105
|
|
|
106
106
|
const dialog = canvas.getByRole("dialog");
|
|
107
|
-
await userEvent.
|
|
107
|
+
await userEvent.type(dialog, "{Escape}", { delay: 500 }); // Close the dialog with the keyboard
|
|
108
108
|
await waitFor(() => {
|
|
109
109
|
expect(dialog).not.toBeVisible();
|
|
110
110
|
});
|
|
@@ -1,25 +1,20 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import FP from
|
|
1
|
+
import React from "react";
|
|
2
|
+
import FP from "../fp";
|
|
3
3
|
|
|
4
4
|
export type InputProps = {
|
|
5
5
|
/**
|
|
6
6
|
* The type of the input.
|
|
7
7
|
*/
|
|
8
|
-
type?:
|
|
8
|
+
type?: "text" | "password" | "email" | "number" | "tel" | "url" | "search";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Set the element as disabled
|
|
12
12
|
*/
|
|
13
|
-
isDisabled?: boolean
|
|
14
|
-
} & React.ComponentProps<typeof FP
|
|
13
|
+
isDisabled?: boolean;
|
|
14
|
+
} & React.ComponentProps<typeof FP>;
|
|
15
15
|
|
|
16
|
-
/**
|
|
17
|
-
* Input component that renders an HTML input element.
|
|
18
|
-
* @param {InputProps} props - The input component props.
|
|
19
|
-
* @returns {JSX.Element} - The input component.
|
|
20
|
-
*/
|
|
21
16
|
export const Input = ({
|
|
22
|
-
type =
|
|
17
|
+
type = "text",
|
|
23
18
|
name,
|
|
24
19
|
value,
|
|
25
20
|
placeholder,
|
|
@@ -38,29 +33,29 @@ export const Input = ({
|
|
|
38
33
|
}: InputProps): JSX.Element => {
|
|
39
34
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
40
35
|
if (onChange && !disabled) {
|
|
41
|
-
onChange?.(e)
|
|
36
|
+
onChange?.(e);
|
|
42
37
|
}
|
|
43
|
-
}
|
|
38
|
+
};
|
|
44
39
|
|
|
45
40
|
const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
|
|
46
41
|
if (onBlur && !disabled) {
|
|
47
|
-
onBlur?.(e)
|
|
42
|
+
onBlur?.(e);
|
|
48
43
|
}
|
|
49
|
-
}
|
|
44
|
+
};
|
|
50
45
|
|
|
51
46
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
52
47
|
if (onPointerDown && !disabled) {
|
|
53
|
-
e.preventDefault()
|
|
54
|
-
onPointerDown?.(e)
|
|
48
|
+
e.preventDefault();
|
|
49
|
+
onPointerDown?.(e);
|
|
55
50
|
}
|
|
56
|
-
}
|
|
51
|
+
};
|
|
57
52
|
|
|
58
53
|
return (
|
|
59
54
|
<FP
|
|
60
55
|
as="input"
|
|
61
56
|
id={id}
|
|
62
57
|
type={type}
|
|
63
|
-
placeholder={placeholder || `${required ?
|
|
58
|
+
placeholder={placeholder || `${required ? "*" : ""} ${type} input `}
|
|
64
59
|
className={classes}
|
|
65
60
|
styles={styles}
|
|
66
61
|
onChange={handleChange}
|
|
@@ -77,8 +72,7 @@ export const Input = ({
|
|
|
77
72
|
readOnly={readonly}
|
|
78
73
|
{...props}
|
|
79
74
|
/>
|
|
80
|
-
)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
export default Input
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
Input.displayName = "Input";
|
|
78
|
+
export default Input;
|
|
@@ -1,15 +1,27 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import UI from
|
|
3
|
-
import { type } from 'os'
|
|
1
|
+
import React from "react";
|
|
2
|
+
import UI from "#components/ui";
|
|
4
3
|
|
|
5
4
|
export type TitleProps = {
|
|
6
|
-
children: React.ReactNode
|
|
7
|
-
type:
|
|
8
|
-
ui?: string
|
|
9
|
-
} & React.ComponentProps<typeof UI
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
type: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
|
|
7
|
+
ui?: string;
|
|
8
|
+
} & React.ComponentProps<typeof UI>;
|
|
10
9
|
|
|
10
|
+
/**
|
|
11
|
+
* A flexible heading component that renders different heading levels.
|
|
12
|
+
*
|
|
13
|
+
* @component
|
|
14
|
+
* @param {'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'} [props.type='h3'] - The heading level to render
|
|
15
|
+
* @param {string} [props.id] - Optional ID attribute for the heading
|
|
16
|
+
* @param {React.CSSProperties} [props.styles] - Custom styles to apply to the heading
|
|
17
|
+
* @param {string} [props.ui] - Custom UI modifier to be added as a data attribute
|
|
18
|
+
* @param {ReactNode} props.children - The content to be rendered within the heading
|
|
19
|
+
* @param {Object} [props] - Additional props to be spread onto the heading element
|
|
20
|
+
*
|
|
21
|
+
* @returns {JSX.Element} A heading element of the specified type
|
|
22
|
+
*/
|
|
11
23
|
const Heading = ({
|
|
12
|
-
type =
|
|
24
|
+
type = "h3",
|
|
13
25
|
id,
|
|
14
26
|
styles,
|
|
15
27
|
ui,
|
|
@@ -20,8 +32,8 @@ const Heading = ({
|
|
|
20
32
|
<UI as={type} id={id} styles={styles} data-ui={ui} {...props}>
|
|
21
33
|
{children}
|
|
22
34
|
</UI>
|
|
23
|
-
)
|
|
24
|
-
}
|
|
35
|
+
);
|
|
36
|
+
};
|
|
25
37
|
|
|
26
|
-
export default Heading
|
|
27
|
-
Heading.displayName =
|
|
38
|
+
export default Heading;
|
|
39
|
+
Heading.displayName = "Heading";
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Meta } from "@storybook/blocks";
|
|
2
|
+
|
|
3
|
+
<Meta title="FP.REACT Components/Text/Readme" />
|
|
4
|
+
|
|
5
|
+
# Text Component
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
The `Text` component is a flexible wrapper for rendering various text elements
|
|
10
|
+
such as paragraphs, spans, and other inline or block-level elements. It supports
|
|
11
|
+
customization through props like `elm`, `text`, and additional styles or
|
|
12
|
+
classes.
|
|
13
|
+
|
|
14
|
+
The `Title` component is a specialized version of `Text` for rendering HTML
|
|
15
|
+
headings (`h1` to `h6`).
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- Render any valid HTML text element.
|
|
20
|
+
- Pass text content directly or use children for nested elements.
|
|
21
|
+
- Fully customizable with styles and classes.
|
|
22
|
+
- Supports accessibility with `id` and other attributes.
|
|
23
|
+
|
|
24
|
+
## Props
|
|
25
|
+
|
|
26
|
+
### Text Props
|
|
27
|
+
|
|
28
|
+
| Name | Type | Default | Description |
|
|
29
|
+
| ---------- | --------------------- | ------- | ----------------------------------- |
|
|
30
|
+
| `elm` | `TextElements` | `'p'` | The HTML element to render. |
|
|
31
|
+
| `text` | `string` | `''` | Text content to display. |
|
|
32
|
+
| `id` | `string` | `''` | Unique identifier for the element. |
|
|
33
|
+
| `styles` | `React.CSSProperties` | `null` | Inline styles for the element. |
|
|
34
|
+
| `classes` | `string` | `''` | Additional CSS classes for styling. |
|
|
35
|
+
| `children` | `React.ReactNode` | `null` | Nested content inside the element. |
|
|
36
|
+
|
|
37
|
+
### Title Props
|
|
38
|
+
|
|
39
|
+
| Name | Type | Default | Description |
|
|
40
|
+
| ---------- | ---------------------------------------------- | ------- | ----------------------------------- |
|
|
41
|
+
| `elm` | `'h1' \| 'h2' \| 'h3' \| 'h4' \| 'h5' \| 'h6'` | `'h3'` | The HTML heading element to render. |
|
|
42
|
+
| `id` | `string` | `''` | Unique identifier for the element. |
|
|
43
|
+
| `styles` | `React.CSSProperties` | `null` | Inline styles for the element. |
|
|
44
|
+
| `classes` | `string` | `''` | Additional CSS classes for styling. |
|
|
45
|
+
| `children` | `React.ReactNode` | `null` | Nested content inside the element. |
|
|
46
|
+
|
|
47
|
+
## Technical Details
|
|
48
|
+
|
|
49
|
+
- The `Text` component uses the `UI` component internally to render the
|
|
50
|
+
specified element.
|
|
51
|
+
- The `Title` component is a wrapper around `Text` with default settings for
|
|
52
|
+
headings.
|
|
53
|
+
- Both components support additional props inherited from the `UI` component.
|
|
54
|
+
|
|
55
|
+
## Usage Examples
|
|
56
|
+
|
|
57
|
+
### Basic Usage
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
import { Text, Title } from "./text";
|
|
61
|
+
|
|
62
|
+
const App = () => (
|
|
63
|
+
<>
|
|
64
|
+
<Text elm="p" text="This is a paragraph." />
|
|
65
|
+
<Text elm="span" text="This is a span." />
|
|
66
|
+
<Title elm="h1">This is a heading</Title>
|
|
67
|
+
</>
|
|
68
|
+
);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Advanced Usage
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import { Text, Title } from "./text";
|
|
75
|
+
|
|
76
|
+
const App = () => (
|
|
77
|
+
<>
|
|
78
|
+
<Text
|
|
79
|
+
elm="blockquote"
|
|
80
|
+
styles={{ fontStyle: "italic", color: "gray" }}
|
|
81
|
+
text="This is a blockquote."
|
|
82
|
+
/>
|
|
83
|
+
<Title
|
|
84
|
+
elm="h2"
|
|
85
|
+
classes="custom-heading"
|
|
86
|
+
styles={{ fontWeight: "bold", fontSize: "2rem" }}
|
|
87
|
+
>
|
|
88
|
+
Custom Heading
|
|
89
|
+
</Title>
|
|
90
|
+
</>
|
|
91
|
+
);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Additional Notes
|
|
95
|
+
|
|
96
|
+
- Use the `elm` prop to specify the desired HTML element.
|
|
97
|
+
- Combine `styles` and `classes` for advanced styling.
|
|
98
|
+
- Use `children` for nested content when `text` is not sufficient.
|