@fpkit/acss 0.4.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/LICENSE +21 -0
- package/README.md +52 -0
- package/dist/chunk-77CZU5XZ.cjs +9 -0
- package/dist/chunk-77CZU5XZ.cjs.map +1 -0
- package/dist/chunk-D43FJIRQ.cjs +31 -0
- package/dist/chunk-D43FJIRQ.cjs.map +1 -0
- package/dist/chunk-GJWMCDFS.js +9 -0
- package/dist/chunk-GJWMCDFS.js.map +1 -0
- package/dist/chunk-PCDUGD3C.js +5 -0
- package/dist/chunk-PCDUGD3C.js.map +1 -0
- package/dist/hooks.cjs +10 -0
- package/dist/hooks.cjs.map +1 -0
- package/dist/hooks.d.cts +32 -0
- package/dist/hooks.d.ts +32 -0
- package/dist/hooks.js +8 -0
- package/dist/hooks.js.map +1 -0
- package/dist/icon-e6044c73.d.ts +227 -0
- package/dist/icons.cjs +73 -0
- package/dist/icons.cjs.map +1 -0
- package/dist/icons.d.cts +252 -0
- package/dist/icons.d.ts +252 -0
- package/dist/icons.js +4 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.cjs +59 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +566 -0
- package/dist/index.d.ts +566 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/libs/chunk-GCGKYLDG.js +7 -0
- package/libs/chunk-GCGKYLDG.js.map +1 -0
- package/libs/chunk-PDD4N5P5.cjs +10 -0
- package/libs/chunk-PDD4N5P5.cjs.map +1 -0
- package/libs/chunk-QHIABQNQ.js +8 -0
- package/libs/chunk-QHIABQNQ.js.map +1 -0
- package/libs/chunk-ZOHIKF6I.cjs +31 -0
- package/libs/chunk-ZOHIKF6I.cjs.map +1 -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/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/hooks.cjs +12 -0
- package/libs/hooks.cjs.map +1 -0
- package/libs/hooks.d.cts +32 -0
- package/libs/hooks.d.ts +32 -0
- package/libs/hooks.js +3 -0
- package/libs/hooks.js.map +1 -0
- package/libs/icons-1f5afc0c.d.ts +318 -0
- package/libs/icons.cjs +12 -0
- package/libs/icons.cjs.map +1 -0
- package/libs/icons.d.cts +2 -0
- package/libs/icons.d.ts +2 -0
- package/libs/icons.js +3 -0
- package/libs/icons.js.map +1 -0
- package/libs/index.cjs +71 -0
- package/libs/index.cjs.map +1 -0
- package/libs/index.css +1 -0
- package/libs/index.css.map +1 -0
- package/libs/index.d.cts +551 -0
- package/libs/index.d.ts +551 -0
- package/libs/index.js +11 -0
- package/libs/index.js.map +1 -0
- package/package.json +125 -0
- package/src/App.css +42 -0
- package/src/App.tsx +35 -0
- package/src/__snapshots__/App.test.tsx.snap +56 -0
- package/src/components/.gitkeep +0 -0
- package/src/components/__snapshots__/fp.test.tsx.snap +3 -0
- package/src/components/badge/badge.scss +20 -0
- package/src/components/badge/badge.stories.tsx +54 -0
- package/src/components/badge/badge.tsx +17 -0
- package/src/components/breadcrumbs/bc-item.tsx +20 -0
- package/src/components/breadcrumbs/breadcrumb.scss +35 -0
- package/src/components/breadcrumbs/breadcrumb.stories.tsx +92 -0
- package/src/components/breadcrumbs/breadcrumb.tsx +218 -0
- package/src/components/buttons/button.scss +115 -0
- package/src/components/buttons/button.stories.tsx +57 -0
- package/src/components/buttons/button.test.tsx +104 -0
- package/src/components/buttons/button.tsx +64 -0
- package/src/components/cards/card-style.scss +0 -0
- package/src/components/cards/card.scss +43 -0
- package/src/components/cards/card.stories.tsx +114 -0
- package/src/components/cards/card.test.tsx +30 -0
- package/src/components/cards/card.tsx +135 -0
- package/src/components/cards/flex-card.tsx +15 -0
- package/src/components/details/details.scss +75 -0
- package/src/components/details/details.stories.tsx +122 -0
- package/src/components/details/details.tsx +77 -0
- package/src/components/form/README.mdx +70 -0
- package/src/components/form/fields.tsx +45 -0
- package/src/components/form/form.scss +87 -0
- package/src/components/form/form.stories.tsx +49 -0
- package/src/components/form/form.tsx +71 -0
- package/src/components/form/input.stories.tsx +155 -0
- package/src/components/form/inputs.tsx +84 -0
- package/src/components/form/select.stories.tsx +38 -0
- package/src/components/form/select.tsx +112 -0
- package/src/components/form/textarea.tsx +87 -0
- package/src/components/fp.test.tsx +56 -0
- package/src/components/fp.tsx +78 -0
- package/src/components/heading/heading.stories.tsx +75 -0
- package/src/components/heading/heading.tsx +27 -0
- package/src/components/icons/components/add.tsx +42 -0
- package/src/components/icons/components/arrow-down.tsx +52 -0
- package/src/components/icons/components/arrow-left.tsx +49 -0
- package/src/components/icons/components/arrow-right.tsx +52 -0
- package/src/components/icons/components/arrow-up.tsx +49 -0
- package/src/components/icons/components/chat.tsx +44 -0
- package/src/components/icons/components/code.tsx +50 -0
- package/src/components/icons/components/copy.tsx +51 -0
- package/src/components/icons/components/down.tsx +33 -0
- package/src/components/icons/components/home.tsx +57 -0
- package/src/components/icons/components/left.tsx +43 -0
- package/src/components/icons/components/minus.tsx +42 -0
- package/src/components/icons/components/pause-solid.tsx +48 -0
- package/src/components/icons/components/pause.tsx +63 -0
- package/src/components/icons/components/play-solid.tsx +44 -0
- package/src/components/icons/components/play.tsx +51 -0
- package/src/components/icons/components/remove.tsx +42 -0
- package/src/components/icons/components/resume-solid.tsx +52 -0
- package/src/components/icons/components/resume.tsx +57 -0
- package/src/components/icons/components/right.tsx +43 -0
- package/src/components/icons/components/star.tsx +38 -0
- package/src/components/icons/components/stop-solid.tsx +44 -0
- package/src/components/icons/components/stop.tsx +54 -0
- package/src/components/icons/components/svg.tsx +44 -0
- package/src/components/icons/components/up.tsx +31 -0
- package/src/components/icons/components/user.tsx +46 -0
- package/src/components/icons/icon.scss +15 -0
- package/src/components/icons/icon.stories.tsx +208 -0
- package/src/components/icons/icon.tsx +100 -0
- package/src/components/icons/index.ts +29 -0
- package/src/components/icons/types.ts +12 -0
- package/src/components/images/README.mdx +43 -0
- package/src/components/images/figure.stories.tsx +34 -0
- package/src/components/images/figure.tsx +44 -0
- package/src/components/images/img.scss +43 -0
- package/src/components/images/img.stories.tsx +24 -0
- package/src/components/images/img.test.tsx +43 -0
- package/src/components/images/img.tsx +93 -0
- package/src/components/images/place-holder.png +0 -0
- package/src/components/kit.tsx +56 -0
- package/src/components/layout/_header.scss +72 -0
- package/src/components/layout/footer.stories.tsx +34 -0
- package/src/components/layout/landmarks.scss +51 -0
- package/src/components/layout/landmarks.stories.tsx +54 -0
- package/src/components/layout/landmarks.tsx +149 -0
- package/src/components/layout/main.stories.tsx +90 -0
- package/src/components/link/link.scss +92 -0
- package/src/components/link/link.stories.tsx +74 -0
- package/src/components/link/link.tsx +48 -0
- package/src/components/list/list.stories.tsx +52 -0
- package/src/components/list/list.tsx +74 -0
- package/src/components/modal/dialog.tsx +50 -0
- package/src/components/modal/modal.tsx +85 -0
- package/src/components/nav/nav.scss +90 -0
- package/src/components/nav/nav.stories.tsx +96 -0
- package/src/components/nav/nav.tsx +76 -0
- package/src/components/popover/node_modules/.vitest/results.json +1 -0
- package/src/components/popover/popover.stories.tsx +31 -0
- package/src/components/popover/popover.test.tsx +39 -0
- package/src/components/popover/popover.tsx +85 -0
- package/src/components/progress/progress.scss +70 -0
- package/src/components/progress/progress.stories.tsx +51 -0
- package/src/components/progress/progress.tsx +82 -0
- package/src/components/readme.stories.mdx +7 -0
- package/src/components/styles/index.css +520 -0
- package/src/components/styles/index.css.map +1 -0
- package/src/components/tables/table-elements.tsx +57 -0
- package/src/components/tables/table.tsx +57 -0
- package/src/components/tag/tag.scss +56 -0
- package/src/components/tag/tag.stories.tsx +39 -0
- package/src/components/tag/tag.tsx +25 -0
- package/src/components/text/text.stories.tsx +67 -0
- package/src/components/text/text.tsx +93 -0
- package/src/components/text-to-speech/README.mdx +192 -0
- package/src/components/text-to-speech/TextInput.tsx +19 -0
- package/src/components/text-to-speech/TextToSpeech.stories.tsx +145 -0
- package/src/components/text-to-speech/TextToSpeech.tsx +94 -0
- package/src/components/text-to-speech/text-to-speech.scss +31 -0
- package/src/components/text-to-speech/useTextToSpeech.mdx +182 -0
- package/src/components/text-to-speech/useTextToSpeech.tsx +176 -0
- package/src/components/text-to-speech/views/TextToSpeechControls.tsx +117 -0
- package/src/components/ui.tsx +67 -0
- package/src/favicon.svg +15 -0
- package/src/hooks/popover/__snapshots__/popover.test.tsx.snap +88 -0
- package/src/hooks/popover/node_modules/.vitest/results.json +1 -0
- package/src/hooks/popover/popover.tsx +71 -0
- package/src/hooks/popover/use-popover.tsx +83 -0
- package/src/hooks.ts +1 -0
- package/src/icons.ts +1 -0
- package/src/index.css +13 -0
- package/src/index.scss +19 -0
- package/src/index.ts +35 -0
- package/src/libs/content.ts +30 -0
- package/src/logo.svg +7 -0
- package/src/main.tsx +10 -0
- package/src/patterns/.gitkeep +0 -0
- package/src/patterns/page/page-header.stories.tsx +44 -0
- package/src/patterns/page/page-header.tsx +78 -0
- package/src/sass/_elements.scss +17 -0
- package/src/sass/_globals.scss +162 -0
- package/src/sass/_layout.scss +51 -0
- package/src/sass/_loading-animation.scss +35 -0
- package/src/sass/_mixins.scss +10 -0
- package/src/sass/_properties.scss +106 -0
- package/src/sass/_reset.scss +183 -0
- package/src/sass/_type.scss +43 -0
- package/src/setupTest.ts +1 -0
- package/src/styles/badge/badge.css +22 -0
- package/src/styles/badge/badge.css.map +1 -0
- package/src/styles/breadcrumbs/breadcrumb.css +42 -0
- package/src/styles/breadcrumbs/breadcrumb.css.map +1 -0
- package/src/styles/buttons/button.css +93 -0
- package/src/styles/buttons/button.css.map +1 -0
- package/src/styles/cards/card-style.css +3 -0
- package/src/styles/cards/card-style.css.map +1 -0
- package/src/styles/cards/card.css +48 -0
- package/src/styles/cards/card.css.map +1 -0
- package/src/styles/details/details.css +69 -0
- package/src/styles/details/details.css.map +1 -0
- package/src/styles/dropdowns/dropdown.css.map +1 -0
- package/src/styles/form/form.css +93 -0
- package/src/styles/form/form.css.map +1 -0
- package/src/styles/form/style.css.map +1 -0
- package/src/styles/icons/icon.css +16 -0
- package/src/styles/icons/icon.css.map +1 -0
- package/src/styles/images/img.css +42 -0
- package/src/styles/images/img.css.map +1 -0
- package/src/styles/index.css +1330 -0
- package/src/styles/index.css.map +1 -0
- package/src/styles/layout/landmarks.css +155 -0
- package/src/styles/layout/landmarks.css.map +1 -0
- package/src/styles/link/link.css +88 -0
- package/src/styles/link/link.css.map +1 -0
- package/src/styles/nav/nav.css +85 -0
- package/src/styles/nav/nav.css.map +1 -0
- package/src/styles/progress/progress.css +54 -0
- package/src/styles/progress/progress.css.map +1 -0
- package/src/styles/progress/sass/progress.css.map +1 -0
- package/src/styles/styles/index.css +562 -0
- package/src/styles/styles/index.css.map +1 -0
- package/src/styles/tag/badge.css.map +1 -0
- package/src/styles/tag/tag.css +71 -0
- package/src/styles/tag/tag.css.map +1 -0
- package/src/styles/text-to-speech/text-to-speech.css +32 -0
- package/src/styles/text-to-speech/text-to-speech.css.map +1 -0
- package/src/test/setup.ts +6 -0
- package/src/types/component-props.ts +36 -0
- package/src/types/index.ts +2 -0
- package/src/types/input-props.ts +28 -0
- package/src/types/shared.ts +57 -0
- package/src/vite-env.d.ts +1 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { StoryObj, Meta } from '@storybook/react'
|
|
2
|
+
import { within, userEvent, screen } from '@storybook/testing-library'
|
|
3
|
+
import { expect } from '@storybook/jest'
|
|
4
|
+
|
|
5
|
+
import Card from './card'
|
|
6
|
+
import './card.scss'
|
|
7
|
+
|
|
8
|
+
const content =
|
|
9
|
+
'Enim aliquip excepteur veniam esse culpa. Et exercitation incididunt occaecat incididunt proident consectetur. Voluptate elit reprehenderit nulla reprehenderit excepteur tempor adipisicing officia eiusmod est id aute. Nisi do et nulla fugiat enim id pariatur ex. Culpa aliquip excepteur velit fugiat qui magna deserunt adipisicing dolore quis. Esse proident qui consectetur Lorem id fugiat elit amet proident enim deserunt dolore sit.'
|
|
10
|
+
|
|
11
|
+
const meta: Meta<typeof Card> = {
|
|
12
|
+
title: 'FP.REACT Components/Card',
|
|
13
|
+
component: Card,
|
|
14
|
+
args: {
|
|
15
|
+
children: <p>{content}</p>,
|
|
16
|
+
},
|
|
17
|
+
} as Story
|
|
18
|
+
|
|
19
|
+
export default meta
|
|
20
|
+
type Story = StoryObj<typeof Card>
|
|
21
|
+
|
|
22
|
+
export const CardComponent: Story = {
|
|
23
|
+
args: {},
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const Multiple: Story = {
|
|
27
|
+
args: {
|
|
28
|
+
styles: {
|
|
29
|
+
'--theme': 'warm',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
render: (args) => (
|
|
33
|
+
<>
|
|
34
|
+
<Card {...args}>
|
|
35
|
+
<p>
|
|
36
|
+
Proident et amet aliqua excepteur sunt qui deserunt commodo tempor
|
|
37
|
+
esse. Et aliqua nulla ea amet nisi consequat id adipisicing culpa
|
|
38
|
+
ipsum minim voluptate est Lorem. Amet qui laboris incididunt commodo
|
|
39
|
+
culpa aliqua veniam.
|
|
40
|
+
</p>
|
|
41
|
+
</Card>
|
|
42
|
+
<Card>
|
|
43
|
+
<p>
|
|
44
|
+
Proident et amet aliqua excepteur sunt qui deserunt commodo tempor
|
|
45
|
+
esse. Et aliqua nulla ea amet nisi consequat id adipisicing culpa
|
|
46
|
+
ipsum minim voluptate est Lorem. Amet qui laboris incididunt commodo
|
|
47
|
+
culpa aliqua veniam.
|
|
48
|
+
</p>
|
|
49
|
+
</Card>
|
|
50
|
+
<Card>
|
|
51
|
+
<p>
|
|
52
|
+
Proident et amet aliqua excepteur sunt qui deserunt commodo tempor
|
|
53
|
+
esse. Et aliqua nulla ea amet nisi consequat id adipisicing culpa
|
|
54
|
+
ipsum minim voluptate est Lorem. Amet qui laboris incididunt commodo
|
|
55
|
+
culpa aliqua veniam.
|
|
56
|
+
</p>
|
|
57
|
+
</Card>
|
|
58
|
+
</>
|
|
59
|
+
),
|
|
60
|
+
} as Story
|
|
61
|
+
|
|
62
|
+
export const CardWithTitle: Story = {
|
|
63
|
+
args: {},
|
|
64
|
+
render: (args) => (
|
|
65
|
+
<Card {...args}>
|
|
66
|
+
<Card.Title>Card Title</Card.Title>
|
|
67
|
+
<Card.Content>
|
|
68
|
+
<p>
|
|
69
|
+
This card demonstrates the usage of the CardTitle component. It shows
|
|
70
|
+
how a title can be added to a card for better organization and visual
|
|
71
|
+
hierarchy.
|
|
72
|
+
</p>
|
|
73
|
+
</Card.Content>
|
|
74
|
+
</Card>
|
|
75
|
+
),
|
|
76
|
+
} as Story
|
|
77
|
+
|
|
78
|
+
export const FlexibleContent: Story = {
|
|
79
|
+
args: {
|
|
80
|
+
styles: {
|
|
81
|
+
// '--card-bg': '#f0f0f0',
|
|
82
|
+
},
|
|
83
|
+
title: <Card.Title>Card Title</Card.Title>,
|
|
84
|
+
},
|
|
85
|
+
render: (args) => (
|
|
86
|
+
<div style={{ display: 'flex', gap: '1rem' }}>
|
|
87
|
+
<Card {...args}>
|
|
88
|
+
<Card.Content>
|
|
89
|
+
<p>
|
|
90
|
+
This card demonstrates the usage of the CardTitle component. It
|
|
91
|
+
shows how a title can be added to a card for better organization and
|
|
92
|
+
visual hierarchy.
|
|
93
|
+
</p>
|
|
94
|
+
</Card.Content>
|
|
95
|
+
<div>Footer Content</div>
|
|
96
|
+
</Card>
|
|
97
|
+
<Card {...args}>
|
|
98
|
+
<Card.Content>
|
|
99
|
+
<p>
|
|
100
|
+
This card demonstrates the usage of the CardTitle component. It
|
|
101
|
+
shows how a title can be added to a card for better organization and
|
|
102
|
+
visual hierarchy.
|
|
103
|
+
</p>
|
|
104
|
+
<p>
|
|
105
|
+
This card demonstrates the usage of the CardTitle component. It
|
|
106
|
+
shows how a title can be added to a card for better organization and
|
|
107
|
+
visual hierarchy.
|
|
108
|
+
</p>
|
|
109
|
+
</Card.Content>
|
|
110
|
+
<div>Footer Content</div>
|
|
111
|
+
</Card>
|
|
112
|
+
</div>
|
|
113
|
+
),
|
|
114
|
+
} as Story
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react'
|
|
2
|
+
import { Card } from './card'
|
|
3
|
+
|
|
4
|
+
describe('Card', () => {
|
|
5
|
+
it('renders children', () => {
|
|
6
|
+
render(<Card>Hello World</Card>)
|
|
7
|
+
expect(screen.getByText('Hello World')).toBeInTheDocument()
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('renders with custom styles', () => {
|
|
11
|
+
const style = { backgroundColor: '#000;' }
|
|
12
|
+
render(
|
|
13
|
+
<Card data-testid="card" styles={style}>
|
|
14
|
+
Hello World
|
|
15
|
+
</Card>,
|
|
16
|
+
)
|
|
17
|
+
const card = screen.getByTestId('card')
|
|
18
|
+
expect(card).toHaveStyle(style)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('renders with custom element', () => {
|
|
22
|
+
render(
|
|
23
|
+
<Card data-testid="card" elm="section">
|
|
24
|
+
Hello World
|
|
25
|
+
</Card>,
|
|
26
|
+
)
|
|
27
|
+
const card = screen.getByTestId('card')
|
|
28
|
+
expect(card.tagName.toLowerCase()).toBe('section')
|
|
29
|
+
})
|
|
30
|
+
})
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import UI from '#components/ui'
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* CardProps interface
|
|
6
|
+
*
|
|
7
|
+
* Extends ComponentProps. Defines props for the Card component.
|
|
8
|
+
*
|
|
9
|
+
* @property {('div' | 'aside' | 'section' | 'article')} [elm='div'] - HTML element to render as
|
|
10
|
+
*/
|
|
11
|
+
export type CardProps = {
|
|
12
|
+
elm?: 'div' | 'aside' | 'section' | 'article'
|
|
13
|
+
title?: React.ReactNode
|
|
14
|
+
footer?: React.ReactNode
|
|
15
|
+
} & React.ComponentProps<typeof UI>
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* Title component
|
|
19
|
+
*
|
|
20
|
+
* Renders a title for the Card component using the UI component.
|
|
21
|
+
*
|
|
22
|
+
* @param {Object} props - Component props
|
|
23
|
+
* @param {ReactNode} props.children - Title content
|
|
24
|
+
* @param {string} [props.className] - Additional CSS classes
|
|
25
|
+
* @param {Object} [props.styles] - Inline styles
|
|
26
|
+
*
|
|
27
|
+
* @returns {ReactElement} Title component
|
|
28
|
+
*/
|
|
29
|
+
export const Title = ({
|
|
30
|
+
children,
|
|
31
|
+
className,
|
|
32
|
+
styles,
|
|
33
|
+
as = 'h3',
|
|
34
|
+
...props
|
|
35
|
+
}: React.PropsWithChildren<{
|
|
36
|
+
className?: string
|
|
37
|
+
styles?: React.CSSProperties
|
|
38
|
+
as?: React.ElementType
|
|
39
|
+
}>) => {
|
|
40
|
+
return (
|
|
41
|
+
<UI
|
|
42
|
+
as={as}
|
|
43
|
+
className={`card-title ${className || ''}`}
|
|
44
|
+
styles={styles}
|
|
45
|
+
{...props}
|
|
46
|
+
>
|
|
47
|
+
{children}
|
|
48
|
+
</UI>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
Title.displayName = 'Title'
|
|
53
|
+
|
|
54
|
+
/*
|
|
55
|
+
* CardContent component
|
|
56
|
+
*
|
|
57
|
+
* Renders the content of the Card component using the UI component with an article element.
|
|
58
|
+
*
|
|
59
|
+
* @param {Object} props - Component props
|
|
60
|
+
* @param {ReactNode} props.children - Content
|
|
61
|
+
* @param {string} [props.className] - Additional CSS classes
|
|
62
|
+
* @param {Object} [props.styles] - Inline styles
|
|
63
|
+
*
|
|
64
|
+
* @returns {ReactElement} CardContent component
|
|
65
|
+
*/
|
|
66
|
+
export const Content = ({
|
|
67
|
+
children,
|
|
68
|
+
className,
|
|
69
|
+
styles,
|
|
70
|
+
...props
|
|
71
|
+
}: React.PropsWithChildren<{
|
|
72
|
+
className?: string
|
|
73
|
+
styles?: React.CSSProperties
|
|
74
|
+
}>) => {
|
|
75
|
+
return (
|
|
76
|
+
<UI
|
|
77
|
+
as="article"
|
|
78
|
+
className={`card-content ${className || ''}`}
|
|
79
|
+
styles={styles}
|
|
80
|
+
{...props}
|
|
81
|
+
>
|
|
82
|
+
{children}
|
|
83
|
+
</UI>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
Content.displayName = 'Content'
|
|
88
|
+
|
|
89
|
+
/*
|
|
90
|
+
* Card component
|
|
91
|
+
*
|
|
92
|
+
* Renders a card container.
|
|
93
|
+
*
|
|
94
|
+
* @param {CardProps} props - Component props
|
|
95
|
+
* @param {('div' | 'aside' | 'section' | 'article')} [props.elm='div'] - Element to render as
|
|
96
|
+
* @param {Object} [props.styles] - CSS styles to apply
|
|
97
|
+
* @param {ReactNode} props.children - Card content
|
|
98
|
+
* @param {boolean} [props.renderStyles=true] - Whether to render default styles
|
|
99
|
+
* @param {string} [props.dataStyle] - data-card attribute value
|
|
100
|
+
* @param {string} [props.id] - Unique ID
|
|
101
|
+
*
|
|
102
|
+
* @returns {ReactElement} Card component
|
|
103
|
+
*/
|
|
104
|
+
export const Card = ({
|
|
105
|
+
elm = 'div',
|
|
106
|
+
styles,
|
|
107
|
+
children,
|
|
108
|
+
classes,
|
|
109
|
+
id,
|
|
110
|
+
footer,
|
|
111
|
+
title,
|
|
112
|
+
...props
|
|
113
|
+
}: CardProps) => {
|
|
114
|
+
return (
|
|
115
|
+
<UI
|
|
116
|
+
as={elm}
|
|
117
|
+
id={id}
|
|
118
|
+
styles={styles}
|
|
119
|
+
className={classes}
|
|
120
|
+
data-card
|
|
121
|
+
{...props}
|
|
122
|
+
>
|
|
123
|
+
<UI as="div" data-card-content>
|
|
124
|
+
{title && title}
|
|
125
|
+
{children}
|
|
126
|
+
{footer && footer}
|
|
127
|
+
</UI>
|
|
128
|
+
</UI>
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export default Card
|
|
133
|
+
Card.displayName = 'Card'
|
|
134
|
+
Card.Title = Title
|
|
135
|
+
Card.Content = Content
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Card from './card'
|
|
2
|
+
|
|
3
|
+
const FlexCard = () => {
|
|
4
|
+
return (
|
|
5
|
+
<Card>
|
|
6
|
+
<Card.Title />
|
|
7
|
+
<Card.Content>
|
|
8
|
+
<div>Flexible Content</div>
|
|
9
|
+
</Card.Content>
|
|
10
|
+
<div style={{ padding: '1rem' }}>Footer</div>
|
|
11
|
+
</Card>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default FlexCard
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
details {
|
|
2
|
+
--details-w: 100%;
|
|
3
|
+
--details-h: fit-content;
|
|
4
|
+
--details-border: 1px solid #dfdfdf;
|
|
5
|
+
--details-display: flex;
|
|
6
|
+
--details-justify: flex-start;
|
|
7
|
+
--details-direction: columns;
|
|
8
|
+
--details-gap: 5rem;
|
|
9
|
+
--details-px: 1.5rem;
|
|
10
|
+
--details-py: 1.5rem;
|
|
11
|
+
--details-radius: 0.5rem;
|
|
12
|
+
--summary-cursor: pointer;
|
|
13
|
+
--summary-transitions: all 0.75s linear;
|
|
14
|
+
--summary-display: flex;
|
|
15
|
+
--summary-justify: flex-start;
|
|
16
|
+
--summary-align: center;
|
|
17
|
+
--summary-gap: 0.5rem;
|
|
18
|
+
--max-h-closed: 6.25rem;
|
|
19
|
+
--max-h-open: 50rem;
|
|
20
|
+
|
|
21
|
+
display: var(--details-display);
|
|
22
|
+
flex-direction: var(--details-direction);
|
|
23
|
+
justify-content: var(--details-justify);
|
|
24
|
+
gap: var(--details-gap);
|
|
25
|
+
width: var(--details-w);
|
|
26
|
+
border: var(--details-border);
|
|
27
|
+
transition: var(--summary-transitions);
|
|
28
|
+
max-height: var(--max-h-closed);
|
|
29
|
+
overflow: clip;
|
|
30
|
+
border-radius: var(--details-radius);
|
|
31
|
+
|
|
32
|
+
&::marker {
|
|
33
|
+
content: none;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
summary {
|
|
37
|
+
display: var(--summary-display);
|
|
38
|
+
justify-content: var(--summary-justify);
|
|
39
|
+
align-items: var(--summary-align);
|
|
40
|
+
padding-inline: var(--summary-px, var(--details-px));
|
|
41
|
+
padding-block: var(--summary-py, var(--details-py));
|
|
42
|
+
gap: var(--summary-gap);
|
|
43
|
+
list-style: none;
|
|
44
|
+
|
|
45
|
+
&::-webkit-details-marker {
|
|
46
|
+
display: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* This ensures no bullet points are shown */
|
|
50
|
+
|
|
51
|
+
&:hover {
|
|
52
|
+
cursor: var(--summary-cursor);
|
|
53
|
+
}
|
|
54
|
+
> section {
|
|
55
|
+
width: var(--details-w);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
> section {
|
|
60
|
+
padding-inline: var(--details-px);
|
|
61
|
+
padding-block: var(--details-py);
|
|
62
|
+
border: 1px transparent solid;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
&[open] {
|
|
66
|
+
max-height: var(--max-h-open);
|
|
67
|
+
transition: var(--summary-transitions);
|
|
68
|
+
> summary {
|
|
69
|
+
border-bottom: var(--details-border);
|
|
70
|
+
}
|
|
71
|
+
> section {
|
|
72
|
+
max-height: var(--max-h-open);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { StoryObj, Meta } from '@storybook/react'
|
|
2
|
+
import { within, userEvent, screen } from '@storybook/testing-library'
|
|
3
|
+
import { expect } from '@storybook/jest'
|
|
4
|
+
|
|
5
|
+
import Details from './details'
|
|
6
|
+
import Icons from '../icons/icon'
|
|
7
|
+
import '../../styles/details/details.css'
|
|
8
|
+
|
|
9
|
+
const content = (
|
|
10
|
+
<>
|
|
11
|
+
<p>
|
|
12
|
+
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Accusantium
|
|
13
|
+
accusamus molestiae, qui omnis illum iste asperiores fugit doloribus
|
|
14
|
+
voluptatem numquam voluptatibus nisi blanditiis quidem sint optio. Dicta
|
|
15
|
+
officia commodi numquam?
|
|
16
|
+
</p>
|
|
17
|
+
<p>
|
|
18
|
+
Impedit, libero ea. Repellendus doloribus possimus magni ullam natus
|
|
19
|
+
voluptates, magnam ad iure quas eum adipisci! Repellat vel placeat commodi
|
|
20
|
+
voluptatem optio odit, voluptatum id, magnam architecto at est ipsa.
|
|
21
|
+
</p>
|
|
22
|
+
<p>
|
|
23
|
+
Vitae, laudantium libero, dolorem enim architecto consectetur qui vero
|
|
24
|
+
error possimus beatae iusto, labore praesentium. Assumenda recusandae
|
|
25
|
+
labore aliquam omnis, aliquid in impedit possimus! Rerum consequuntur non
|
|
26
|
+
hic est placeat!
|
|
27
|
+
</p>
|
|
28
|
+
</>
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
const icon = <Icons.Add />
|
|
32
|
+
|
|
33
|
+
const meta: Meta<typeof Details> = {
|
|
34
|
+
title: 'FP.REACT Components/Details',
|
|
35
|
+
component: Details,
|
|
36
|
+
args: {
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
children: content,
|
|
39
|
+
icon: icon,
|
|
40
|
+
summary: <>Summary Section</>,
|
|
41
|
+
},
|
|
42
|
+
actions: { argTypesRegex: '^on.*' },
|
|
43
|
+
decorators: [
|
|
44
|
+
(Story) => (
|
|
45
|
+
<div className="container" style={{ minWidth: '50vw' }}>
|
|
46
|
+
<Story />
|
|
47
|
+
</div>
|
|
48
|
+
),
|
|
49
|
+
],
|
|
50
|
+
} as Story
|
|
51
|
+
|
|
52
|
+
export default meta
|
|
53
|
+
type Story = StoryObj<typeof Details>
|
|
54
|
+
|
|
55
|
+
export const DetailsDropdown: Story = {
|
|
56
|
+
args: {},
|
|
57
|
+
play: async ({ canvasElement }) => {
|
|
58
|
+
const canvas = within(canvasElement)
|
|
59
|
+
expect(canvas.getByRole('group')).toBeInTheDocument()
|
|
60
|
+
},
|
|
61
|
+
} as Story
|
|
62
|
+
|
|
63
|
+
export const DetailsOpen: Story = {
|
|
64
|
+
args: {
|
|
65
|
+
open: true,
|
|
66
|
+
},
|
|
67
|
+
play: async ({ canvasElement }) => {
|
|
68
|
+
const canvas = within(canvasElement)
|
|
69
|
+
expect(canvas.getByRole('group')).toBeInTheDocument()
|
|
70
|
+
},
|
|
71
|
+
} as Story
|
|
72
|
+
|
|
73
|
+
export const CustomDropdown: Story = {
|
|
74
|
+
render: () => (
|
|
75
|
+
<>
|
|
76
|
+
<Details
|
|
77
|
+
summary="Summary Section"
|
|
78
|
+
icon={icon}
|
|
79
|
+
ariaLabel="Details Section"
|
|
80
|
+
>
|
|
81
|
+
{content}
|
|
82
|
+
</Details>
|
|
83
|
+
<p>
|
|
84
|
+
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Dolorum quasi
|
|
85
|
+
maiores placeat voluptate voluptatem, tenetur consectetur earum modi,
|
|
86
|
+
quam pariatur, quas porro iste quo ipsum rem rerum fuga incidunt?
|
|
87
|
+
Suscipit!
|
|
88
|
+
</p>
|
|
89
|
+
</>
|
|
90
|
+
),
|
|
91
|
+
} as Story
|
|
92
|
+
|
|
93
|
+
export const DetailsAccordion: Story = {
|
|
94
|
+
render: () => (
|
|
95
|
+
<>
|
|
96
|
+
<Details
|
|
97
|
+
summary="Summary Section"
|
|
98
|
+
icon={icon}
|
|
99
|
+
ariaLabel="Details Section"
|
|
100
|
+
name="accordion-details"
|
|
101
|
+
>
|
|
102
|
+
{content}
|
|
103
|
+
</Details>
|
|
104
|
+
<Details
|
|
105
|
+
summary="Summary Section"
|
|
106
|
+
icon={icon}
|
|
107
|
+
ariaLabel="Details Section"
|
|
108
|
+
name="accordion-details"
|
|
109
|
+
>
|
|
110
|
+
{content}
|
|
111
|
+
</Details>
|
|
112
|
+
<Details
|
|
113
|
+
summary="Summary Section"
|
|
114
|
+
icon={icon}
|
|
115
|
+
ariaLabel="Details Section"
|
|
116
|
+
name="accordion-details"
|
|
117
|
+
>
|
|
118
|
+
{content}
|
|
119
|
+
</Details>
|
|
120
|
+
</>
|
|
121
|
+
)
|
|
122
|
+
} as Story
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import UI from '#components/ui'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
type DetailsProps = {
|
|
5
|
+
/**
|
|
6
|
+
* The summary text shown for the details.
|
|
7
|
+
* Required.
|
|
8
|
+
*/
|
|
9
|
+
summary: React.ReactNode
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The aria-label element for accessibility.
|
|
13
|
+
*/
|
|
14
|
+
ariaLabel: string
|
|
15
|
+
} & React.ComponentProps<'details'> &
|
|
16
|
+
Partial<React.ComponentProps<typeof UI>>
|
|
17
|
+
|
|
18
|
+
/**3
|
|
19
|
+
* Details component props interface.
|
|
20
|
+
*
|
|
21
|
+
* @param {React.CSSProperties} [styles] - CSS styles object.
|
|
22
|
+
* @param {string} [classes] - Classnames string.
|
|
23
|
+
* @param {boolean} [open] - Whether the details is open.
|
|
24
|
+
* @param {(e: React.PointerEvent<HTMLDetailsElement>) => void} [onToggle] - onToggle callback.
|
|
25
|
+
* @param {(e: React.PointerEvent<HTMLDetailsElement>) => void} [onPointerDown] - onPointerDown callback.
|
|
26
|
+
* @param {ReactNode} children - The content inside the details.
|
|
27
|
+
* @param {string} [ariaLabel] - aria-label for accessibility.
|
|
28
|
+
* @param {React.Ref<any>} [ref] - Ref object.
|
|
29
|
+
* @param {Object} props - Other props.
|
|
30
|
+
*/
|
|
31
|
+
export const Details = ({
|
|
32
|
+
summary,
|
|
33
|
+
icon,
|
|
34
|
+
styles,
|
|
35
|
+
classes,
|
|
36
|
+
ariaLabel,
|
|
37
|
+
name,
|
|
38
|
+
open,
|
|
39
|
+
onPointerDown,
|
|
40
|
+
onToggle,
|
|
41
|
+
children,
|
|
42
|
+
ref,
|
|
43
|
+
...props
|
|
44
|
+
}: DetailsProps) => {
|
|
45
|
+
const defaultStyles: React.CSSProperties = { ...styles }
|
|
46
|
+
|
|
47
|
+
const onPointerDownCallback = (e: React.PointerEvent<HTMLDetailsElement>) => {
|
|
48
|
+
if (onPointerDown) onPointerDown?.(e)
|
|
49
|
+
if (onPointerDown) onPointerDown?.(e)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const onToggleCallback = (e: React.PointerEvent<HTMLDetailsElement>) => {
|
|
53
|
+
if (onToggle) onPointerDown?.(e)
|
|
54
|
+
}
|
|
55
|
+
return (
|
|
56
|
+
<UI
|
|
57
|
+
as="details"
|
|
58
|
+
style={defaultStyles}
|
|
59
|
+
className={classes}
|
|
60
|
+
onToggle={onToggleCallback}
|
|
61
|
+
ref={ref}
|
|
62
|
+
open={open}
|
|
63
|
+
aria-label={ariaLabel || 'Details dropdown'}
|
|
64
|
+
name={name}
|
|
65
|
+
{...props}
|
|
66
|
+
>
|
|
67
|
+
<UI as="summary" role="group" onPointerDown={onPointerDownCallback}>
|
|
68
|
+
{icon}
|
|
69
|
+
{summary}
|
|
70
|
+
</UI>
|
|
71
|
+
<UI as="section">{children}</UI>
|
|
72
|
+
</UI>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default Details
|
|
77
|
+
Details.displayName = 'Details'
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Form Components
|
|
2
|
+
|
|
3
|
+
This directory contains a set of React components for building forms in web applications. The components are designed to be reusable, accessible, and customizable.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The main components in this directory are:
|
|
8
|
+
|
|
9
|
+
- `Form`: A wrapper component for creating HTML forms with various input fields.
|
|
10
|
+
- `Input`: A component for rendering input fields of different types (text, email, password, etc.).
|
|
11
|
+
- `Textarea`: A component for rendering a textarea input field.
|
|
12
|
+
- `Select`: A component for rendering a dropdown select input field with options.
|
|
13
|
+
- `Field`: A component for rendering a label and an input field together.
|
|
14
|
+
|
|
15
|
+
These components are built with accessibility and customization in mind, providing props for setting labels, placeholders, validation, and styling.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
To use these components in your React application, import them from the respective files:
|
|
20
|
+
|
|
21
|
+
```jsx
|
|
22
|
+
import { Form, Input, Textarea, Select, Field } from './path/to/form/components';
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Then, you can use them in your JSX like any other React component:
|
|
26
|
+
|
|
27
|
+
```jsx
|
|
28
|
+
|
|
29
|
+
<Form onSubmit={handleSubmit}>
|
|
30
|
+
<Field label="Name" labelFor="name">
|
|
31
|
+
<Input id="name" name="name" required />
|
|
32
|
+
</Field>
|
|
33
|
+
<Field label="Email" labelFor="email">
|
|
34
|
+
<Input id="email" name="email" type="email" required />
|
|
35
|
+
</Field>
|
|
36
|
+
<Field label="Message" labelFor="message">
|
|
37
|
+
<Textarea id="message" name="message" required />
|
|
38
|
+
</Field>
|
|
39
|
+
<Select id="option" name="option" required>
|
|
40
|
+
<Select.Option value="option1">Option 1</Select.Option>
|
|
41
|
+
<Select.Option value="option2">Option 2</Select.Option>
|
|
42
|
+
</Select>
|
|
43
|
+
<button type="submit">Submit</button>
|
|
44
|
+
</Form>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Key Features
|
|
48
|
+
|
|
49
|
+
- **Accessibility**: The components are built with accessibility in mind, providing props for setting labels, placeholders, and ARIA attributes.
|
|
50
|
+
- **Validation**: The `Input`, `Textarea`, and `Select` components support validation through the `required` prop.
|
|
51
|
+
- **Styling**: The components can be styled using CSS classes or inline styles passed through props.
|
|
52
|
+
- **Customization**: The components are designed to be flexible and customizable, allowing you to pass additional props or render custom content within them.
|
|
53
|
+
|
|
54
|
+
## Styling
|
|
55
|
+
|
|
56
|
+
The components in this directory are styled using a combination of CSS modules and inline styles. The styles can be overridden or extended by importing the corresponding CSS files or by passing custom styles through the `styles` prop.
|
|
57
|
+
|
|
58
|
+
For example, to override the styles for the `Input` component, you can import the CSS file and define your custom styles:
|
|
59
|
+
|
|
60
|
+
```jsx
|
|
61
|
+
import './input.css';
|
|
62
|
+
|
|
63
|
+
// ...
|
|
64
|
+
|
|
65
|
+
<Input id="name" name="name" required styles={{ color: 'red' }} />
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Contributing
|
|
69
|
+
|
|
70
|
+
If you find any issues or have suggestions for improvements, please open an issue or submit a pull request on the project's repository.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import UI from '../ui'
|
|
3
|
+
|
|
4
|
+
export type FieldProps = {
|
|
5
|
+
/**
|
|
6
|
+
* The label content
|
|
7
|
+
*/
|
|
8
|
+
label: React.ReactNode
|
|
9
|
+
children: React.ReactNode
|
|
10
|
+
} & React.ComponentProps<'label'> &
|
|
11
|
+
Partial<React.ComponentProps<typeof UI>>
|
|
12
|
+
/**
|
|
13
|
+
* Field component that renders a label and children wrapped in a div element.
|
|
14
|
+
* @param labelFor Defines the for attribute of the label element
|
|
15
|
+
* @param styles Custom styles to be applied to the component
|
|
16
|
+
* @param label The label content
|
|
17
|
+
* @param children The children to be rendered inside the component
|
|
18
|
+
* @param props Additional props to be spread to the component
|
|
19
|
+
*/
|
|
20
|
+
export const Field = ({
|
|
21
|
+
label,
|
|
22
|
+
labelFor,
|
|
23
|
+
id,
|
|
24
|
+
styles,
|
|
25
|
+
classes,
|
|
26
|
+
children,
|
|
27
|
+
...props
|
|
28
|
+
}: FieldProps) => {
|
|
29
|
+
return (
|
|
30
|
+
<UI
|
|
31
|
+
as="div"
|
|
32
|
+
id={id}
|
|
33
|
+
styles={styles}
|
|
34
|
+
className={classes}
|
|
35
|
+
data-style="fields"
|
|
36
|
+
{...props}
|
|
37
|
+
>
|
|
38
|
+
<label htmlFor={labelFor}>{label}</label>
|
|
39
|
+
{children}
|
|
40
|
+
</UI>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default Field
|
|
45
|
+
Field.displayName = 'Field'
|