@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,92 @@
|
|
|
1
|
+
@use '../../sass/mixins';
|
|
2
|
+
|
|
3
|
+
a[href] {
|
|
4
|
+
--link-decoration: none;
|
|
5
|
+
--link-color: #085ab7;
|
|
6
|
+
--link-bg: transparent;
|
|
7
|
+
--link-px: 0;
|
|
8
|
+
--link-py: 0;
|
|
9
|
+
--link-transition: all 0.75s ease-in-out;
|
|
10
|
+
--link-fs: 1rem;
|
|
11
|
+
--link-radius: 0.25rem;
|
|
12
|
+
--link-skip-ink: auto;
|
|
13
|
+
--link-decoration-offset: 1.5px;
|
|
14
|
+
--link-decoration-thickness: 3px;
|
|
15
|
+
--link-decoration: color: var(--link-color) var(--link-decoration-offset)
|
|
16
|
+
var(--link-decoration-thickness) var(--link-skip-ink);
|
|
17
|
+
--link-decoration-thickness: 3px;
|
|
18
|
+
--link-decoration: color: var(--link-color) var(--link-decoration-offset)
|
|
19
|
+
var(--link-decoration-thickness) var(--link-skip-ink);
|
|
20
|
+
|
|
21
|
+
color: var(--link-color);
|
|
22
|
+
font-size: var(--link-fs);
|
|
23
|
+
text-decoration: var(--link-decoration);
|
|
24
|
+
text-underline-offset: var(--link-decoration-offset);
|
|
25
|
+
text-decoration-skip-ink: var(--link-skip-ink);
|
|
26
|
+
background-color: var(--link-bg);
|
|
27
|
+
border-radius: var(--link-radius);
|
|
28
|
+
background-color: var(--link-bg);
|
|
29
|
+
border-radius: var(--link-radius);
|
|
30
|
+
font-weight: var(--link-weight);
|
|
31
|
+
|
|
32
|
+
> i,
|
|
33
|
+
> b {
|
|
34
|
+
font-weight: var(--link-weight);
|
|
35
|
+
font-style: normal;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&:hover {
|
|
39
|
+
--link-decoration: underline;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&:focus {
|
|
43
|
+
outline: none;
|
|
44
|
+
--link-decoration: underline;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&:visited,
|
|
48
|
+
&:active {
|
|
49
|
+
--link-color: currentColor;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&:has(> b),
|
|
53
|
+
&[data-link~='btn'],
|
|
54
|
+
&:has(> i) {
|
|
55
|
+
--link-button-color: var(--link-color);
|
|
56
|
+
--link-bg: transparent;
|
|
57
|
+
--link-decoration: none;
|
|
58
|
+
--link-border: 2px currentColor solid;
|
|
59
|
+
--link-fs: 0.9rem;
|
|
60
|
+
background-color: var(--link-bg);
|
|
61
|
+
font-style: normal;
|
|
62
|
+
font-size: var(--link-fs);
|
|
63
|
+
color: var(--link-button-color);
|
|
64
|
+
padding-inline: var(--link-fs);
|
|
65
|
+
padding-block: calc(var(--link-fs) - 0.4rem);
|
|
66
|
+
border-radius: var(--link-radius, 99rem);
|
|
67
|
+
display: inline-flex;
|
|
68
|
+
outline: var(--link-border);
|
|
69
|
+
&:focus {
|
|
70
|
+
outline: var(--link-border);
|
|
71
|
+
--link-decoration: none;
|
|
72
|
+
}
|
|
73
|
+
&:hover {
|
|
74
|
+
--link-decoration: none;
|
|
75
|
+
}
|
|
76
|
+
@include mixins.scale-transitions;
|
|
77
|
+
}
|
|
78
|
+
&[data-link~='pill'],
|
|
79
|
+
&:has(> i) {
|
|
80
|
+
--link-radius: 99rem;
|
|
81
|
+
--link-decoration: none;
|
|
82
|
+
font-style: normal;
|
|
83
|
+
&:hover,
|
|
84
|
+
&:focus {
|
|
85
|
+
--link-decoration: none;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
header > section {
|
|
91
|
+
width: auto;
|
|
92
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { StoryObj, Meta } from '@storybook/react'
|
|
2
|
+
|
|
3
|
+
import { within, userEvent, screen } from '@storybook/testing-library'
|
|
4
|
+
|
|
5
|
+
import { expect } from '@storybook/jest'
|
|
6
|
+
|
|
7
|
+
import Link from './link'
|
|
8
|
+
import '../../styles/link/link.css'
|
|
9
|
+
|
|
10
|
+
const meta: Meta<typeof Link> = {
|
|
11
|
+
title: 'FP.React Components/Links',
|
|
12
|
+
component: Link,
|
|
13
|
+
args: {
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
href: '/',
|
|
16
|
+
children: 'Link',
|
|
17
|
+
},
|
|
18
|
+
} as Meta
|
|
19
|
+
|
|
20
|
+
export default meta
|
|
21
|
+
type Story = StoryObj<typeof Link>
|
|
22
|
+
|
|
23
|
+
export const LinkComponent: Story = {
|
|
24
|
+
args: {},
|
|
25
|
+
play: async ({ canvasElement }) => {
|
|
26
|
+
const canvas = within(canvasElement)
|
|
27
|
+
const link = canvas.getByRole('link')
|
|
28
|
+
expect(link).toBeInTheDocument()
|
|
29
|
+
expect(link).toHaveTextContent('Link')
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const ExternalLink: Story = {
|
|
34
|
+
args: {
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
href: 'https://www.google.com',
|
|
37
|
+
target: '_blank',
|
|
38
|
+
rel: 'noopener noreferrer',
|
|
39
|
+
prefetch: true,
|
|
40
|
+
children: 'Google',
|
|
41
|
+
},
|
|
42
|
+
play: async ({ canvasElement }) => {
|
|
43
|
+
const canvas = within(canvasElement)
|
|
44
|
+
const link = canvas.getByRole('link')
|
|
45
|
+
expect(link).toBeInTheDocument()
|
|
46
|
+
expect(link).toHaveTextContent('Google')
|
|
47
|
+
expect(link).toHaveAttribute('href', 'https://www.google.com')
|
|
48
|
+
expect(link).toHaveAttribute('target', '_blank')
|
|
49
|
+
expect(link).toHaveAttribute('rel', 'noopener noreferrer prefetch')
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const ButtonLink: Story = {
|
|
54
|
+
args: {
|
|
55
|
+
...LinkComponent.args,
|
|
56
|
+
children: <b>Button Link</b>,
|
|
57
|
+
},
|
|
58
|
+
} as Story
|
|
59
|
+
|
|
60
|
+
export const ButtonPill: Story = {
|
|
61
|
+
args: {
|
|
62
|
+
...LinkComponent.args,
|
|
63
|
+
children: <i>Button Link</i>,
|
|
64
|
+
},
|
|
65
|
+
} as Story
|
|
66
|
+
|
|
67
|
+
export const ButtonRounded: Story = {
|
|
68
|
+
args: {
|
|
69
|
+
...ButtonLink.args,
|
|
70
|
+
styles: {
|
|
71
|
+
'--link-radius': 'initial',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
} as Story
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import UI from '../ui'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
export type LinkProps = {
|
|
5
|
+
/** Applies button styling to the link */
|
|
6
|
+
btnStyle?: boolean
|
|
7
|
+
} & React.ComponentProps<typeof UI> &
|
|
8
|
+
React.ComponentProps<'a'>
|
|
9
|
+
|
|
10
|
+
export const Link = ({
|
|
11
|
+
href,
|
|
12
|
+
target,
|
|
13
|
+
rel,
|
|
14
|
+
children,
|
|
15
|
+
styles,
|
|
16
|
+
prefetch,
|
|
17
|
+
btnStyle,
|
|
18
|
+
onPointerDown,
|
|
19
|
+
...props
|
|
20
|
+
}: LinkProps) => {
|
|
21
|
+
let relValue = rel
|
|
22
|
+
|
|
23
|
+
if (target === '_blank')
|
|
24
|
+
relValue = `noopener noreferrer ${prefetch ? 'prefetch' : ''}`
|
|
25
|
+
|
|
26
|
+
const handleOnpointerDown = (e: React.PointerEvent<HTMLAnchorElement>) => {
|
|
27
|
+
if (onPointerDown) onPointerDown?.(e)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<UI
|
|
32
|
+
as="a"
|
|
33
|
+
href={href}
|
|
34
|
+
target={target}
|
|
35
|
+
styles={styles}
|
|
36
|
+
rel={relValue}
|
|
37
|
+
onPointerDown={handleOnpointerDown}
|
|
38
|
+
data-btn={btnStyle}
|
|
39
|
+
prefetch={prefetch}
|
|
40
|
+
{...props}
|
|
41
|
+
>
|
|
42
|
+
{children}
|
|
43
|
+
</UI>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default Link
|
|
48
|
+
Link.displayName = 'Link'
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { StoryObj, Meta } from '@storybook/react'
|
|
4
|
+
|
|
5
|
+
import { within, userEvent } from '@storybook/testing-library'
|
|
6
|
+
|
|
7
|
+
import { expect } from '@storybook/jest'
|
|
8
|
+
|
|
9
|
+
import List from './list'
|
|
10
|
+
|
|
11
|
+
const meta: Meta<typeof List> = {
|
|
12
|
+
title: 'FP.React Components/List',
|
|
13
|
+
component: List,
|
|
14
|
+
} as Meta
|
|
15
|
+
|
|
16
|
+
const listElm = (
|
|
17
|
+
<>
|
|
18
|
+
<List.ListItem>Home</List.ListItem>
|
|
19
|
+
<List.ListItem>About</List.ListItem>
|
|
20
|
+
<List.ListItem>Contact</List.ListItem>
|
|
21
|
+
</>
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
export default meta
|
|
25
|
+
type Story = StoryObj<typeof List>
|
|
26
|
+
|
|
27
|
+
export const DefaultList: Story = {
|
|
28
|
+
args: {
|
|
29
|
+
children: listElm,
|
|
30
|
+
},
|
|
31
|
+
} as Story
|
|
32
|
+
|
|
33
|
+
export const UnstyledList: Story = {
|
|
34
|
+
args: {
|
|
35
|
+
...DefaultList.args,
|
|
36
|
+
role: 'list',
|
|
37
|
+
},
|
|
38
|
+
parameters: {
|
|
39
|
+
docs: {
|
|
40
|
+
description: {
|
|
41
|
+
story: 'Another description `on the story`, with some markdown',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
} as Story
|
|
46
|
+
|
|
47
|
+
export const InlineList: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
...UnstyledList.args,
|
|
50
|
+
'data-list': 'inline',
|
|
51
|
+
},
|
|
52
|
+
} as Story
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import UI from '../ui'
|
|
3
|
+
|
|
4
|
+
type ListProps = {
|
|
5
|
+
/** Type of list to render (default: 'ul') */
|
|
6
|
+
type?: 'ul' | 'ol' | 'dl'
|
|
7
|
+
/** variant of list to render (default: 'none') */
|
|
8
|
+
variant?: string
|
|
9
|
+
} & React.ComponentProps<typeof UI>
|
|
10
|
+
|
|
11
|
+
export type ListItemProps = {
|
|
12
|
+
/** Type of list item to render (default: 'li') */
|
|
13
|
+
type?: 'li' | 'dt' | 'dd'
|
|
14
|
+
} & React.ComponentProps<typeof UI>
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* ListItem component
|
|
18
|
+
* @param type - HTML tag type for the list item (default: 'li')
|
|
19
|
+
* @param styles - CSS styles object
|
|
20
|
+
* @param children - Child elements to be rendered inside the list item
|
|
21
|
+
* @param props - Additional props to be passed to the underlying HTML element
|
|
22
|
+
* @returns A React component that renders a list item
|
|
23
|
+
*/
|
|
24
|
+
export const ListItem = ({
|
|
25
|
+
type = 'li',
|
|
26
|
+
id,
|
|
27
|
+
styles,
|
|
28
|
+
children,
|
|
29
|
+
classes,
|
|
30
|
+
...props
|
|
31
|
+
}: ListItemProps) => {
|
|
32
|
+
return (
|
|
33
|
+
<UI id={id} as={type} className={classes} {...props} style={styles}>
|
|
34
|
+
{children}
|
|
35
|
+
</UI>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* List component renders a list element with provided props
|
|
41
|
+
* @param children - Child elements to render inside the list
|
|
42
|
+
* @param classes - CSS classes to apply
|
|
43
|
+
* @param type - Type of list element (default: 'ul')
|
|
44
|
+
* @param variant - Variant for styling purposes
|
|
45
|
+
* @param styles - Inline styles object
|
|
46
|
+
* @param role - ARIA role
|
|
47
|
+
* @param props - Additional props to pass to underlying element
|
|
48
|
+
*/
|
|
49
|
+
export const List = ({
|
|
50
|
+
children,
|
|
51
|
+
classes,
|
|
52
|
+
type = 'ul',
|
|
53
|
+
variant,
|
|
54
|
+
styles,
|
|
55
|
+
role,
|
|
56
|
+
...props
|
|
57
|
+
}: ListProps) => {
|
|
58
|
+
return (
|
|
59
|
+
<UI
|
|
60
|
+
as={type}
|
|
61
|
+
data-variant={variant}
|
|
62
|
+
className={classes}
|
|
63
|
+
style={styles}
|
|
64
|
+
role={role}
|
|
65
|
+
{...props}
|
|
66
|
+
>
|
|
67
|
+
{children}
|
|
68
|
+
</UI>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export default List
|
|
73
|
+
List.displayName = 'List'
|
|
74
|
+
List.ListItem = ListItem
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import UI from '../ui'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
export type DialogProps = {
|
|
5
|
+
/**
|
|
6
|
+
* React ref for dialog element
|
|
7
|
+
*/
|
|
8
|
+
modalRef: React.RefObject<HTMLDialogElement>
|
|
9
|
+
/**
|
|
10
|
+
* Handle close modal event
|
|
11
|
+
*/
|
|
12
|
+
closeModal?: (e: React.SyntheticEvent<HTMLDialogElement>) => void
|
|
13
|
+
/**
|
|
14
|
+
* open modal on mount
|
|
15
|
+
*/
|
|
16
|
+
openOnMount?: boolean
|
|
17
|
+
} & React.ComponentProps<typeof UI>
|
|
18
|
+
/**
|
|
19
|
+
* Dialog component
|
|
20
|
+
*/
|
|
21
|
+
export const Dialog = ({
|
|
22
|
+
id,
|
|
23
|
+
children,
|
|
24
|
+
classes,
|
|
25
|
+
modalRef,
|
|
26
|
+
openOnMount,
|
|
27
|
+
...props
|
|
28
|
+
}: DialogProps) => {
|
|
29
|
+
const handleCloseModal = (e: React.SyntheticEvent<HTMLDialogElement>) => {
|
|
30
|
+
if (e.currentTarget === e.target) {
|
|
31
|
+
e.currentTarget.close()
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<UI
|
|
37
|
+
as="dialog"
|
|
38
|
+
id={id}
|
|
39
|
+
classes={classes}
|
|
40
|
+
ref={modalRef}
|
|
41
|
+
open={openOnMount}
|
|
42
|
+
onClick={handleCloseModal}
|
|
43
|
+
{...props}
|
|
44
|
+
>
|
|
45
|
+
{children}
|
|
46
|
+
</UI>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
Dialog.displayName = 'Dialog'
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { ComponentProps } from '../../types'
|
|
3
|
+
import { Button } from '../buttons/button'
|
|
4
|
+
import { Dialog } from './dialog'
|
|
5
|
+
|
|
6
|
+
export interface ModalProps extends ComponentProps {
|
|
7
|
+
/**
|
|
8
|
+
* The child component/content for open button
|
|
9
|
+
*/
|
|
10
|
+
openChild?: React.ReactNode
|
|
11
|
+
/**
|
|
12
|
+
* The child component/content for close button
|
|
13
|
+
*/
|
|
14
|
+
closeChild?: React.ReactNode
|
|
15
|
+
/**
|
|
16
|
+
* The child component/content for modal header
|
|
17
|
+
*/
|
|
18
|
+
modalHeader?: React.ReactNode
|
|
19
|
+
/**
|
|
20
|
+
* The child component/content for modal footer
|
|
21
|
+
*/
|
|
22
|
+
modalFooter?: React.ReactNode
|
|
23
|
+
/**
|
|
24
|
+
* The child component/content for modal body
|
|
25
|
+
*/
|
|
26
|
+
children: React.ReactNode
|
|
27
|
+
/**
|
|
28
|
+
* Open modal on mount when set to true
|
|
29
|
+
*/
|
|
30
|
+
showOpen?: boolean
|
|
31
|
+
}
|
|
32
|
+
export const Modal = ({
|
|
33
|
+
openChild,
|
|
34
|
+
closeChild,
|
|
35
|
+
modalHeader,
|
|
36
|
+
modalFooter,
|
|
37
|
+
children,
|
|
38
|
+
showOpen = false,
|
|
39
|
+
...props
|
|
40
|
+
}: ModalProps) => {
|
|
41
|
+
const dialogRef = React.useRef<HTMLDialogElement>(null)
|
|
42
|
+
const openModal = (): void => {
|
|
43
|
+
if (dialogRef.current) {
|
|
44
|
+
if(showOpen)
|
|
45
|
+
dialogRef.current.show()
|
|
46
|
+
else
|
|
47
|
+
dialogRef.current.showModal()
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const closeModal = () => {
|
|
51
|
+
if (dialogRef.current) {
|
|
52
|
+
dialogRef.current.close()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<>
|
|
58
|
+
<Dialog modalRef={dialogRef} openOnMount={showOpen} {...props}>
|
|
59
|
+
<section>
|
|
60
|
+
{modalHeader}
|
|
61
|
+
{children}
|
|
62
|
+
{modalFooter ?? (
|
|
63
|
+
<div>
|
|
64
|
+
<Button
|
|
65
|
+
type="button"
|
|
66
|
+
pointerDown={() => {
|
|
67
|
+
closeModal()
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
{closeChild || 'Close'}
|
|
71
|
+
</Button>{' '}
|
|
72
|
+
</div>
|
|
73
|
+
)}
|
|
74
|
+
</section>
|
|
75
|
+
</Dialog>
|
|
76
|
+
{ !showOpen && (
|
|
77
|
+
<Button type="button" pointerDown={openModal}>
|
|
78
|
+
{openChild || 'Open Modal'}
|
|
79
|
+
</Button>
|
|
80
|
+
)}
|
|
81
|
+
</>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
Modal.displayName = 'Modal'
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
body > nav,
|
|
2
|
+
[aria-label~='navbar'], .navbar {
|
|
3
|
+
padding-inline: var(--nav-px, 1rem);
|
|
4
|
+
min-height: var(--nav-h, fit-content);
|
|
5
|
+
|
|
6
|
+
@media(max-width: 580px) {
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
height: fit-content;
|
|
9
|
+
min-height: fit-content;
|
|
10
|
+
padding-block: unset;
|
|
11
|
+
gap: 0.5rem;
|
|
12
|
+
}
|
|
13
|
+
ul {
|
|
14
|
+
> li {
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
list-style: none;
|
|
18
|
+
margin: 0;
|
|
19
|
+
padding: 0;
|
|
20
|
+
min-height: 100%;
|
|
21
|
+
padding-inline: var(--nav-px, 0.75rem);
|
|
22
|
+
|
|
23
|
+
&:hover {
|
|
24
|
+
background-color: var(--nav-hov-bg, whitesmoke);
|
|
25
|
+
}
|
|
26
|
+
&:hover:where(img) {
|
|
27
|
+
background-color: transparent;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
nav {
|
|
34
|
+
display: var(--nav-dsp, flex);
|
|
35
|
+
flex-direction: var(--nav-direction, row);
|
|
36
|
+
width: var(--nav-w, auto);
|
|
37
|
+
place-items: var(--nav-align, center);
|
|
38
|
+
justify-content: var(--nav-justify, space-between);
|
|
39
|
+
margin-inline: var(--nav-mx, 0);
|
|
40
|
+
background-color: var(--nav-bg, initial);
|
|
41
|
+
|
|
42
|
+
> section,
|
|
43
|
+
> ul {
|
|
44
|
+
--nav-dsp: flex;
|
|
45
|
+
flex-direction: var(--nav-direction, row);
|
|
46
|
+
display: var(--nav-dsp, flex);
|
|
47
|
+
gap: var(--nav-gap, 0);
|
|
48
|
+
font-size: var(--nav-fs, 0.9rem);
|
|
49
|
+
align-items: var(--nav-align, center);
|
|
50
|
+
padding-inline: var(--nav-px, 1rem);
|
|
51
|
+
padding-block: var(--nav-py, 0);
|
|
52
|
+
height: 100%;
|
|
53
|
+
&[data-list~='block'] {
|
|
54
|
+
--nav-direction: column;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
> section {
|
|
59
|
+
> div {
|
|
60
|
+
--py: 0;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
ul {
|
|
65
|
+
> li {
|
|
66
|
+
display: flex;
|
|
67
|
+
align-items: center;
|
|
68
|
+
list-style: none;
|
|
69
|
+
margin: 0;
|
|
70
|
+
padding: 0;
|
|
71
|
+
min-height: 100%;
|
|
72
|
+
padding-inline: var(--nav-px, 1rem);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
img[alt] {
|
|
77
|
+
--px: 0 var(--s1);
|
|
78
|
+
--w: var(--brand-w, 3.6rem);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
&[data-variant] {
|
|
82
|
+
background-color: var(--nav-bg);
|
|
83
|
+
color: var(--nav-cl);
|
|
84
|
+
font-size: var(--nav-fs, 0.9rem);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
> div {
|
|
88
|
+
margin-block-start: 0;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { StoryObj, Meta } from '@storybook/react'
|
|
2
|
+
import { within } from '@storybook/testing-library'
|
|
3
|
+
import { expect } from '@storybook/jest'
|
|
4
|
+
import React from 'react'
|
|
5
|
+
|
|
6
|
+
import Nav from './nav'
|
|
7
|
+
import Link from '../link/link'
|
|
8
|
+
|
|
9
|
+
const meta: Meta<typeof Nav> = {
|
|
10
|
+
title: 'FP.REACT Components/Nav',
|
|
11
|
+
component: Nav,
|
|
12
|
+
parameters: {
|
|
13
|
+
actions: { argTypesRegex: '^on.*' },
|
|
14
|
+
docs: {
|
|
15
|
+
description: {
|
|
16
|
+
component: 'Nav description here...',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
args: {
|
|
21
|
+
children: (
|
|
22
|
+
<Nav.List>
|
|
23
|
+
<Nav.Item>
|
|
24
|
+
<Link href="/">Link 1</Link>
|
|
25
|
+
</Nav.Item>
|
|
26
|
+
<Nav.Item>
|
|
27
|
+
<Link href="/">Link 2</Link>
|
|
28
|
+
</Nav.Item>
|
|
29
|
+
</Nav.List>
|
|
30
|
+
),
|
|
31
|
+
id: 'nav',
|
|
32
|
+
classes: 'nav',
|
|
33
|
+
},
|
|
34
|
+
} as Story
|
|
35
|
+
|
|
36
|
+
export default meta
|
|
37
|
+
type Story = StoryObj<typeof Nav>
|
|
38
|
+
|
|
39
|
+
export const NavComponent: Story = {
|
|
40
|
+
args: {},
|
|
41
|
+
play: async ({ canvasElement }) => {
|
|
42
|
+
const canvas = within(canvasElement)
|
|
43
|
+
expect(canvas.getByText(/link/i)).toBeInTheDocument()
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const NavSection: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
children: (
|
|
50
|
+
<>
|
|
51
|
+
<Nav.List>
|
|
52
|
+
<Nav.Item>Link 1</Nav.Item>
|
|
53
|
+
<Nav.Item>Link 2</Nav.Item>
|
|
54
|
+
</Nav.List>
|
|
55
|
+
</>
|
|
56
|
+
),
|
|
57
|
+
},
|
|
58
|
+
play: async ({ canvasElement }) => {
|
|
59
|
+
const canvas = within(canvasElement)
|
|
60
|
+
expect(canvas.getByText('Link 1')).toBeInTheDocument()
|
|
61
|
+
expect(canvas.getByText('Link 2')).toBeInTheDocument()
|
|
62
|
+
},
|
|
63
|
+
} as Story
|
|
64
|
+
|
|
65
|
+
export const NavBlock: Story = {
|
|
66
|
+
args: {
|
|
67
|
+
...NavSection.args,
|
|
68
|
+
children: (
|
|
69
|
+
<>
|
|
70
|
+
<Nav.List isBlock={true}>
|
|
71
|
+
<Nav.Item>Link 1</Nav.Item>
|
|
72
|
+
<Nav.Item>Link 2</Nav.Item>
|
|
73
|
+
</Nav.List>
|
|
74
|
+
</>
|
|
75
|
+
),
|
|
76
|
+
},
|
|
77
|
+
} as Story
|
|
78
|
+
|
|
79
|
+
export const MultipleNavs: Story = {
|
|
80
|
+
args: {
|
|
81
|
+
...NavSection.args,
|
|
82
|
+
classes: 'navbar',
|
|
83
|
+
children: (
|
|
84
|
+
<>
|
|
85
|
+
<Nav.List>
|
|
86
|
+
<Nav.Item>Link 1</Nav.Item>
|
|
87
|
+
<Nav.Item>Link 2</Nav.Item>
|
|
88
|
+
</Nav.List>
|
|
89
|
+
<Nav.List>
|
|
90
|
+
<Nav.Item>Link 1</Nav.Item>
|
|
91
|
+
<Nav.Item>Link 2</Nav.Item>
|
|
92
|
+
</Nav.List>
|
|
93
|
+
</>
|
|
94
|
+
),
|
|
95
|
+
},
|
|
96
|
+
} as Story
|