@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.
Files changed (297) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +52 -0
  3. package/dist/chunk-77CZU5XZ.cjs +9 -0
  4. package/dist/chunk-77CZU5XZ.cjs.map +1 -0
  5. package/dist/chunk-D43FJIRQ.cjs +31 -0
  6. package/dist/chunk-D43FJIRQ.cjs.map +1 -0
  7. package/dist/chunk-GJWMCDFS.js +9 -0
  8. package/dist/chunk-GJWMCDFS.js.map +1 -0
  9. package/dist/chunk-PCDUGD3C.js +5 -0
  10. package/dist/chunk-PCDUGD3C.js.map +1 -0
  11. package/dist/hooks.cjs +10 -0
  12. package/dist/hooks.cjs.map +1 -0
  13. package/dist/hooks.d.cts +32 -0
  14. package/dist/hooks.d.ts +32 -0
  15. package/dist/hooks.js +8 -0
  16. package/dist/hooks.js.map +1 -0
  17. package/dist/icon-e6044c73.d.ts +227 -0
  18. package/dist/icons.cjs +73 -0
  19. package/dist/icons.cjs.map +1 -0
  20. package/dist/icons.d.cts +252 -0
  21. package/dist/icons.d.ts +252 -0
  22. package/dist/icons.js +4 -0
  23. package/dist/icons.js.map +1 -0
  24. package/dist/index.cjs +59 -0
  25. package/dist/index.cjs.map +1 -0
  26. package/dist/index.d.cts +566 -0
  27. package/dist/index.d.ts +566 -0
  28. package/dist/index.js +11 -0
  29. package/dist/index.js.map +1 -0
  30. package/libs/chunk-GCGKYLDG.js +7 -0
  31. package/libs/chunk-GCGKYLDG.js.map +1 -0
  32. package/libs/chunk-PDD4N5P5.cjs +10 -0
  33. package/libs/chunk-PDD4N5P5.cjs.map +1 -0
  34. package/libs/chunk-QHIABQNQ.js +8 -0
  35. package/libs/chunk-QHIABQNQ.js.map +1 -0
  36. package/libs/chunk-ZOHIKF6I.cjs +31 -0
  37. package/libs/chunk-ZOHIKF6I.cjs.map +1 -0
  38. package/libs/components/badge/badge.css +1 -0
  39. package/libs/components/badge/badge.css.map +1 -0
  40. package/libs/components/badge/badge.min.css +3 -0
  41. package/libs/components/breadcrumbs/breadcrumb.css +1 -0
  42. package/libs/components/breadcrumbs/breadcrumb.css.map +1 -0
  43. package/libs/components/breadcrumbs/breadcrumb.min.css +3 -0
  44. package/libs/components/buttons/button.css +1 -0
  45. package/libs/components/buttons/button.css.map +1 -0
  46. package/libs/components/buttons/button.min.css +3 -0
  47. package/libs/components/cards/card-style.css +1 -0
  48. package/libs/components/cards/card-style.css.map +1 -0
  49. package/libs/components/cards/card-style.min.css +3 -0
  50. package/libs/components/cards/card.css +1 -0
  51. package/libs/components/cards/card.css.map +1 -0
  52. package/libs/components/cards/card.min.css +3 -0
  53. package/libs/components/details/details.css +1 -0
  54. package/libs/components/details/details.css.map +1 -0
  55. package/libs/components/details/details.min.css +3 -0
  56. package/libs/components/form/form.css +1 -0
  57. package/libs/components/form/form.css.map +1 -0
  58. package/libs/components/form/form.min.css +3 -0
  59. package/libs/components/icons/icon.css +1 -0
  60. package/libs/components/icons/icon.css.map +1 -0
  61. package/libs/components/icons/icon.min.css +3 -0
  62. package/libs/components/images/img.css +1 -0
  63. package/libs/components/images/img.css.map +1 -0
  64. package/libs/components/images/img.min.css +3 -0
  65. package/libs/components/layout/landmarks.css +1 -0
  66. package/libs/components/layout/landmarks.css.map +1 -0
  67. package/libs/components/layout/landmarks.min.css +3 -0
  68. package/libs/components/link/link.css +1 -0
  69. package/libs/components/link/link.css.map +1 -0
  70. package/libs/components/link/link.min.css +3 -0
  71. package/libs/components/nav/nav.css +1 -0
  72. package/libs/components/nav/nav.css.map +1 -0
  73. package/libs/components/nav/nav.min.css +3 -0
  74. package/libs/components/progress/progress.css +1 -0
  75. package/libs/components/progress/progress.css.map +1 -0
  76. package/libs/components/progress/progress.min.css +3 -0
  77. package/libs/components/styles/index.css +1 -0
  78. package/libs/components/styles/index.css.map +1 -0
  79. package/libs/components/styles/index.min.css +3 -0
  80. package/libs/components/tag/tag.css +1 -0
  81. package/libs/components/tag/tag.css.map +1 -0
  82. package/libs/components/tag/tag.min.css +3 -0
  83. package/libs/components/text-to-speech/text-to-speech.css +1 -0
  84. package/libs/components/text-to-speech/text-to-speech.css.map +1 -0
  85. package/libs/components/text-to-speech/text-to-speech.min.css +3 -0
  86. package/libs/hooks.cjs +12 -0
  87. package/libs/hooks.cjs.map +1 -0
  88. package/libs/hooks.d.cts +32 -0
  89. package/libs/hooks.d.ts +32 -0
  90. package/libs/hooks.js +3 -0
  91. package/libs/hooks.js.map +1 -0
  92. package/libs/icons-1f5afc0c.d.ts +318 -0
  93. package/libs/icons.cjs +12 -0
  94. package/libs/icons.cjs.map +1 -0
  95. package/libs/icons.d.cts +2 -0
  96. package/libs/icons.d.ts +2 -0
  97. package/libs/icons.js +3 -0
  98. package/libs/icons.js.map +1 -0
  99. package/libs/index.cjs +71 -0
  100. package/libs/index.cjs.map +1 -0
  101. package/libs/index.css +1 -0
  102. package/libs/index.css.map +1 -0
  103. package/libs/index.d.cts +551 -0
  104. package/libs/index.d.ts +551 -0
  105. package/libs/index.js +11 -0
  106. package/libs/index.js.map +1 -0
  107. package/package.json +125 -0
  108. package/src/App.css +42 -0
  109. package/src/App.tsx +35 -0
  110. package/src/__snapshots__/App.test.tsx.snap +56 -0
  111. package/src/components/.gitkeep +0 -0
  112. package/src/components/__snapshots__/fp.test.tsx.snap +3 -0
  113. package/src/components/badge/badge.scss +20 -0
  114. package/src/components/badge/badge.stories.tsx +54 -0
  115. package/src/components/badge/badge.tsx +17 -0
  116. package/src/components/breadcrumbs/bc-item.tsx +20 -0
  117. package/src/components/breadcrumbs/breadcrumb.scss +35 -0
  118. package/src/components/breadcrumbs/breadcrumb.stories.tsx +92 -0
  119. package/src/components/breadcrumbs/breadcrumb.tsx +218 -0
  120. package/src/components/buttons/button.scss +115 -0
  121. package/src/components/buttons/button.stories.tsx +57 -0
  122. package/src/components/buttons/button.test.tsx +104 -0
  123. package/src/components/buttons/button.tsx +64 -0
  124. package/src/components/cards/card-style.scss +0 -0
  125. package/src/components/cards/card.scss +43 -0
  126. package/src/components/cards/card.stories.tsx +114 -0
  127. package/src/components/cards/card.test.tsx +30 -0
  128. package/src/components/cards/card.tsx +135 -0
  129. package/src/components/cards/flex-card.tsx +15 -0
  130. package/src/components/details/details.scss +75 -0
  131. package/src/components/details/details.stories.tsx +122 -0
  132. package/src/components/details/details.tsx +77 -0
  133. package/src/components/form/README.mdx +70 -0
  134. package/src/components/form/fields.tsx +45 -0
  135. package/src/components/form/form.scss +87 -0
  136. package/src/components/form/form.stories.tsx +49 -0
  137. package/src/components/form/form.tsx +71 -0
  138. package/src/components/form/input.stories.tsx +155 -0
  139. package/src/components/form/inputs.tsx +84 -0
  140. package/src/components/form/select.stories.tsx +38 -0
  141. package/src/components/form/select.tsx +112 -0
  142. package/src/components/form/textarea.tsx +87 -0
  143. package/src/components/fp.test.tsx +56 -0
  144. package/src/components/fp.tsx +78 -0
  145. package/src/components/heading/heading.stories.tsx +75 -0
  146. package/src/components/heading/heading.tsx +27 -0
  147. package/src/components/icons/components/add.tsx +42 -0
  148. package/src/components/icons/components/arrow-down.tsx +52 -0
  149. package/src/components/icons/components/arrow-left.tsx +49 -0
  150. package/src/components/icons/components/arrow-right.tsx +52 -0
  151. package/src/components/icons/components/arrow-up.tsx +49 -0
  152. package/src/components/icons/components/chat.tsx +44 -0
  153. package/src/components/icons/components/code.tsx +50 -0
  154. package/src/components/icons/components/copy.tsx +51 -0
  155. package/src/components/icons/components/down.tsx +33 -0
  156. package/src/components/icons/components/home.tsx +57 -0
  157. package/src/components/icons/components/left.tsx +43 -0
  158. package/src/components/icons/components/minus.tsx +42 -0
  159. package/src/components/icons/components/pause-solid.tsx +48 -0
  160. package/src/components/icons/components/pause.tsx +63 -0
  161. package/src/components/icons/components/play-solid.tsx +44 -0
  162. package/src/components/icons/components/play.tsx +51 -0
  163. package/src/components/icons/components/remove.tsx +42 -0
  164. package/src/components/icons/components/resume-solid.tsx +52 -0
  165. package/src/components/icons/components/resume.tsx +57 -0
  166. package/src/components/icons/components/right.tsx +43 -0
  167. package/src/components/icons/components/star.tsx +38 -0
  168. package/src/components/icons/components/stop-solid.tsx +44 -0
  169. package/src/components/icons/components/stop.tsx +54 -0
  170. package/src/components/icons/components/svg.tsx +44 -0
  171. package/src/components/icons/components/up.tsx +31 -0
  172. package/src/components/icons/components/user.tsx +46 -0
  173. package/src/components/icons/icon.scss +15 -0
  174. package/src/components/icons/icon.stories.tsx +208 -0
  175. package/src/components/icons/icon.tsx +100 -0
  176. package/src/components/icons/index.ts +29 -0
  177. package/src/components/icons/types.ts +12 -0
  178. package/src/components/images/README.mdx +43 -0
  179. package/src/components/images/figure.stories.tsx +34 -0
  180. package/src/components/images/figure.tsx +44 -0
  181. package/src/components/images/img.scss +43 -0
  182. package/src/components/images/img.stories.tsx +24 -0
  183. package/src/components/images/img.test.tsx +43 -0
  184. package/src/components/images/img.tsx +93 -0
  185. package/src/components/images/place-holder.png +0 -0
  186. package/src/components/kit.tsx +56 -0
  187. package/src/components/layout/_header.scss +72 -0
  188. package/src/components/layout/footer.stories.tsx +34 -0
  189. package/src/components/layout/landmarks.scss +51 -0
  190. package/src/components/layout/landmarks.stories.tsx +54 -0
  191. package/src/components/layout/landmarks.tsx +149 -0
  192. package/src/components/layout/main.stories.tsx +90 -0
  193. package/src/components/link/link.scss +92 -0
  194. package/src/components/link/link.stories.tsx +74 -0
  195. package/src/components/link/link.tsx +48 -0
  196. package/src/components/list/list.stories.tsx +52 -0
  197. package/src/components/list/list.tsx +74 -0
  198. package/src/components/modal/dialog.tsx +50 -0
  199. package/src/components/modal/modal.tsx +85 -0
  200. package/src/components/nav/nav.scss +90 -0
  201. package/src/components/nav/nav.stories.tsx +96 -0
  202. package/src/components/nav/nav.tsx +76 -0
  203. package/src/components/popover/node_modules/.vitest/results.json +1 -0
  204. package/src/components/popover/popover.stories.tsx +31 -0
  205. package/src/components/popover/popover.test.tsx +39 -0
  206. package/src/components/popover/popover.tsx +85 -0
  207. package/src/components/progress/progress.scss +70 -0
  208. package/src/components/progress/progress.stories.tsx +51 -0
  209. package/src/components/progress/progress.tsx +82 -0
  210. package/src/components/readme.stories.mdx +7 -0
  211. package/src/components/styles/index.css +520 -0
  212. package/src/components/styles/index.css.map +1 -0
  213. package/src/components/tables/table-elements.tsx +57 -0
  214. package/src/components/tables/table.tsx +57 -0
  215. package/src/components/tag/tag.scss +56 -0
  216. package/src/components/tag/tag.stories.tsx +39 -0
  217. package/src/components/tag/tag.tsx +25 -0
  218. package/src/components/text/text.stories.tsx +67 -0
  219. package/src/components/text/text.tsx +93 -0
  220. package/src/components/text-to-speech/README.mdx +192 -0
  221. package/src/components/text-to-speech/TextInput.tsx +19 -0
  222. package/src/components/text-to-speech/TextToSpeech.stories.tsx +145 -0
  223. package/src/components/text-to-speech/TextToSpeech.tsx +94 -0
  224. package/src/components/text-to-speech/text-to-speech.scss +31 -0
  225. package/src/components/text-to-speech/useTextToSpeech.mdx +182 -0
  226. package/src/components/text-to-speech/useTextToSpeech.tsx +176 -0
  227. package/src/components/text-to-speech/views/TextToSpeechControls.tsx +117 -0
  228. package/src/components/ui.tsx +67 -0
  229. package/src/favicon.svg +15 -0
  230. package/src/hooks/popover/__snapshots__/popover.test.tsx.snap +88 -0
  231. package/src/hooks/popover/node_modules/.vitest/results.json +1 -0
  232. package/src/hooks/popover/popover.tsx +71 -0
  233. package/src/hooks/popover/use-popover.tsx +83 -0
  234. package/src/hooks.ts +1 -0
  235. package/src/icons.ts +1 -0
  236. package/src/index.css +13 -0
  237. package/src/index.scss +19 -0
  238. package/src/index.ts +35 -0
  239. package/src/libs/content.ts +30 -0
  240. package/src/logo.svg +7 -0
  241. package/src/main.tsx +10 -0
  242. package/src/patterns/.gitkeep +0 -0
  243. package/src/patterns/page/page-header.stories.tsx +44 -0
  244. package/src/patterns/page/page-header.tsx +78 -0
  245. package/src/sass/_elements.scss +17 -0
  246. package/src/sass/_globals.scss +162 -0
  247. package/src/sass/_layout.scss +51 -0
  248. package/src/sass/_loading-animation.scss +35 -0
  249. package/src/sass/_mixins.scss +10 -0
  250. package/src/sass/_properties.scss +106 -0
  251. package/src/sass/_reset.scss +183 -0
  252. package/src/sass/_type.scss +43 -0
  253. package/src/setupTest.ts +1 -0
  254. package/src/styles/badge/badge.css +22 -0
  255. package/src/styles/badge/badge.css.map +1 -0
  256. package/src/styles/breadcrumbs/breadcrumb.css +42 -0
  257. package/src/styles/breadcrumbs/breadcrumb.css.map +1 -0
  258. package/src/styles/buttons/button.css +93 -0
  259. package/src/styles/buttons/button.css.map +1 -0
  260. package/src/styles/cards/card-style.css +3 -0
  261. package/src/styles/cards/card-style.css.map +1 -0
  262. package/src/styles/cards/card.css +48 -0
  263. package/src/styles/cards/card.css.map +1 -0
  264. package/src/styles/details/details.css +69 -0
  265. package/src/styles/details/details.css.map +1 -0
  266. package/src/styles/dropdowns/dropdown.css.map +1 -0
  267. package/src/styles/form/form.css +93 -0
  268. package/src/styles/form/form.css.map +1 -0
  269. package/src/styles/form/style.css.map +1 -0
  270. package/src/styles/icons/icon.css +16 -0
  271. package/src/styles/icons/icon.css.map +1 -0
  272. package/src/styles/images/img.css +42 -0
  273. package/src/styles/images/img.css.map +1 -0
  274. package/src/styles/index.css +1330 -0
  275. package/src/styles/index.css.map +1 -0
  276. package/src/styles/layout/landmarks.css +155 -0
  277. package/src/styles/layout/landmarks.css.map +1 -0
  278. package/src/styles/link/link.css +88 -0
  279. package/src/styles/link/link.css.map +1 -0
  280. package/src/styles/nav/nav.css +85 -0
  281. package/src/styles/nav/nav.css.map +1 -0
  282. package/src/styles/progress/progress.css +54 -0
  283. package/src/styles/progress/progress.css.map +1 -0
  284. package/src/styles/progress/sass/progress.css.map +1 -0
  285. package/src/styles/styles/index.css +562 -0
  286. package/src/styles/styles/index.css.map +1 -0
  287. package/src/styles/tag/badge.css.map +1 -0
  288. package/src/styles/tag/tag.css +71 -0
  289. package/src/styles/tag/tag.css.map +1 -0
  290. package/src/styles/text-to-speech/text-to-speech.css +32 -0
  291. package/src/styles/text-to-speech/text-to-speech.css.map +1 -0
  292. package/src/test/setup.ts +6 -0
  293. package/src/types/component-props.ts +36 -0
  294. package/src/types/index.ts +2 -0
  295. package/src/types/input-props.ts +28 -0
  296. package/src/types/shared.ts +57 -0
  297. 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'