paris 0.0.1 → 0.2.0
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/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.eslintrc.json +22 -0
- package/.github/workflows/publish.yml +54 -0
- package/.husky/pre-commit +2 -0
- package/.idea/inspectionProfiles/Project_Default.xml +7 -0
- package/.idea/jsLibraryMappings.xml +6 -0
- package/.idea/jsLinters/eslint.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/paris.iml +13 -0
- package/.idea/vcs.xml +6 -0
- package/.idea/watcherTasks.xml +4 -0
- package/.storybook/main.ts +43 -0
- package/.storybook/manager-head.html +16 -0
- package/.storybook/manager.ts +6 -0
- package/.storybook/preview.ts +74 -0
- package/.storybook/themes.ts +30 -0
- package/CHANGELOG.md +17 -0
- package/README.md +42 -2
- package/cat +2 -0
- package/global.d.ts +2 -0
- package/next.config.js +6 -0
- package/package.json +71 -9
- package/public/favicon.ico +0 -0
- package/public/fira/fira_code.css +48 -0
- package/public/fira/woff/FiraCode-Bold.woff +0 -0
- package/public/fira/woff/FiraCode-Light.woff +0 -0
- package/public/fira/woff/FiraCode-Medium.woff +0 -0
- package/public/fira/woff/FiraCode-Regular.woff +0 -0
- package/public/fira/woff/FiraCode-SemiBold.woff +0 -0
- package/public/fira/woff/FiraCode-VF.woff +0 -0
- package/public/fira/woff2/FiraCode-Bold.woff2 +0 -0
- package/public/fira/woff2/FiraCode-Light.woff2 +0 -0
- package/public/fira/woff2/FiraCode-Medium.woff2 +0 -0
- package/public/fira/woff2/FiraCode-Regular.woff2 +0 -0
- package/public/fira/woff2/FiraCode-SemiBold.woff2 +0 -0
- package/public/fira/woff2/FiraCode-VF.woff2 +0 -0
- package/public/graphik/GraphikSS-Black.woff +0 -0
- package/public/graphik/GraphikSS-Black.woff2 +0 -0
- package/public/graphik/GraphikSS-BlackItalic.woff +0 -0
- package/public/graphik/GraphikSS-BlackItalic.woff2 +0 -0
- package/public/graphik/GraphikSS-Bold.woff +0 -0
- package/public/graphik/GraphikSS-Bold.woff2 +0 -0
- package/public/graphik/GraphikSS-BoldItalic.woff +0 -0
- package/public/graphik/GraphikSS-BoldItalic.woff2 +0 -0
- package/public/graphik/GraphikSS-Extralight.woff +0 -0
- package/public/graphik/GraphikSS-Extralight.woff2 +0 -0
- package/public/graphik/GraphikSS-ExtralightItalic.woff +0 -0
- package/public/graphik/GraphikSS-ExtralightItalic.woff2 +0 -0
- package/public/graphik/GraphikSS-Light.woff +0 -0
- package/public/graphik/GraphikSS-Light.woff2 +0 -0
- package/public/graphik/GraphikSS-LightItalic.woff +0 -0
- package/public/graphik/GraphikSS-LightItalic.woff2 +0 -0
- package/public/graphik/GraphikSS-Medium.woff +0 -0
- package/public/graphik/GraphikSS-Medium.woff2 +0 -0
- package/public/graphik/GraphikSS-MediumItalic.woff +0 -0
- package/public/graphik/GraphikSS-MediumItalic.woff2 +0 -0
- package/public/graphik/GraphikSS-Regular.woff +0 -0
- package/public/graphik/GraphikSS-Regular.woff2 +0 -0
- package/public/graphik/GraphikSS-RegularItalic.woff +0 -0
- package/public/graphik/GraphikSS-RegularItalic.woff2 +0 -0
- package/public/graphik/GraphikSS-Semibold.woff +0 -0
- package/public/graphik/GraphikSS-Semibold.woff2 +0 -0
- package/public/graphik/GraphikSS-SemiboldItalic.woff +0 -0
- package/public/graphik/GraphikSS-SemiboldItalic.woff2 +0 -0
- package/public/graphik/GraphikSS-Super.woff +0 -0
- package/public/graphik/GraphikSS-Super.woff2 +0 -0
- package/public/graphik/GraphikSS-SuperItalic.woff +0 -0
- package/public/graphik/GraphikSS-SuperItalic.woff2 +0 -0
- package/public/graphik/GraphikSS-Thin.woff +0 -0
- package/public/graphik/GraphikSS-Thin.woff2 +0 -0
- package/public/graphik/GraphikSS-ThinItalic.woff +0 -0
- package/public/graphik/GraphikSS-ThinItalic.woff2 +0 -0
- package/public/graphik/graphik.css +174 -0
- package/public/next.svg +1 -0
- package/public/pte.css +219 -0
- package/public/thirteen.svg +1 -0
- package/public/vercel.svg +1 -0
- package/scripts/createComponent.js +100 -0
- package/scripts/generateEntry.js +35 -0
- package/scripts/text.ts +118 -0
- package/src/pages/_app.tsx +7 -0
- package/src/pages/_document.tsx +15 -0
- package/src/pages/index.tsx +132 -0
- package/src/stories/Tokens.mdx +54 -0
- package/src/stories/Welcome.mdx +8 -0
- package/src/stories/button/Button.module.scss +128 -0
- package/src/stories/button/Button.stories.ts +42 -0
- package/src/stories/button/Button.tsx +81 -0
- package/src/stories/button/index.ts +1 -0
- package/src/stories/text/Text.module.scss +3 -0
- package/src/stories/text/Text.stories.ts +155 -0
- package/src/stories/text/Text.tsx +40 -0
- package/src/stories/text/Typography.module.css +164 -0
- package/src/stories/text/index.ts +1 -0
- package/src/stories/theme/index.ts +2 -0
- package/src/stories/theme/themes.ts +409 -0
- package/src/stories/theme/tokens.ts +68 -0
- package/src/styles/Home.module.css +278 -0
- package/src/styles/globals.css +5 -0
- package/src/styles/tw-preflight.css +369 -0
- package/src/styles/util.scss +4 -0
- package/tsconfig.json +27 -0
package/scripts/text.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env ts-node --esm
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Generates CSS modules and Storybook stories for typography classes.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'fs/promises';
|
|
8
|
+
import * as cp from 'child_process';
|
|
9
|
+
import jss from 'jss';
|
|
10
|
+
import preset from 'jss-preset-default';
|
|
11
|
+
import type { StoryObj } from '@storybook/react';
|
|
12
|
+
import { pascalCase } from 'change-case';
|
|
13
|
+
import type { FontDefinition, Theme } from '../src/stories/theme';
|
|
14
|
+
import { theme, pvar, LightTheme } from '../src/stories/theme';
|
|
15
|
+
import type { Text } from '../src/stories/text';
|
|
16
|
+
|
|
17
|
+
jss.setup({
|
|
18
|
+
...preset(),
|
|
19
|
+
createGenerateId: () => (rule) => rule.key,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generates a CSS module with all the typography classes.
|
|
24
|
+
*/
|
|
25
|
+
export const text = async () => {
|
|
26
|
+
const styles = Object.fromEntries(
|
|
27
|
+
(Object.entries(theme.typography.styles) as Array<[keyof Theme['typography']['styles'], FontDefinition]>)
|
|
28
|
+
.map(([fontClass, value]) => [
|
|
29
|
+
fontClass,
|
|
30
|
+
Object.fromEntries(
|
|
31
|
+
(Object.keys(value) as Array<keyof FontDefinition>).map((attr) => [
|
|
32
|
+
attr,
|
|
33
|
+
pvar(`typography.styles.${fontClass}.${attr}`),
|
|
34
|
+
]),
|
|
35
|
+
),
|
|
36
|
+
]),
|
|
37
|
+
);
|
|
38
|
+
// const { styles } = theme.typography;
|
|
39
|
+
const css = `/* Auto-generated with \`pnpm generate:text\` on ${new Date().toString()} */\n/* Do not edit manually; instead, edit the \`generateTextClasses\` function in \`scripts/text.ts\` and run \`pnpm generate:text -c\`. */\n\n${jss.createStyleSheet(styles).toString()}`;
|
|
40
|
+
await fs.writeFile('src/stories/text/Typography.module.css', css
|
|
41
|
+
// Add a newline after each class
|
|
42
|
+
.replaceAll('}', '}\n'));
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Generates Storybook stories for each typography class.
|
|
47
|
+
*/
|
|
48
|
+
export const generateTextStories = async () => {
|
|
49
|
+
const stories: Array<[string, StoryObj<typeof Text>]> = Object.keys(LightTheme.typography.styles)
|
|
50
|
+
.map((style) => ([
|
|
51
|
+
style,
|
|
52
|
+
{
|
|
53
|
+
args: {
|
|
54
|
+
children: 'In an alleyway, drinking champagne',
|
|
55
|
+
kind: style,
|
|
56
|
+
},
|
|
57
|
+
} as StoryObj<typeof Text>,
|
|
58
|
+
]));
|
|
59
|
+
|
|
60
|
+
// Retrieve current stories
|
|
61
|
+
const currentStories = await fs.readFile('src/stories/text/Text.stories.ts', 'utf-8');
|
|
62
|
+
|
|
63
|
+
// Look for `// @auto-generated-start` and `// @auto-generated-end`
|
|
64
|
+
const start = currentStories.indexOf('// @auto-generated-start');
|
|
65
|
+
const end = currentStories.indexOf('// @auto-generated-end');
|
|
66
|
+
|
|
67
|
+
// Generate the new stories
|
|
68
|
+
const out = stories.map((story) => `export const ${pascalCase(story[0] as string).replace('Xx', 'XX')}: Story = ${JSON.stringify(story[1], null, 4)};`).join('\n\n');
|
|
69
|
+
|
|
70
|
+
// If the start and end tags are found, replace the content between them
|
|
71
|
+
if (start !== -1 && end !== -1) {
|
|
72
|
+
const newStories = `${currentStories.slice(0, start + '// @auto-generated-start\n\n'.length)}${
|
|
73
|
+
out
|
|
74
|
+
}\n\n${
|
|
75
|
+
currentStories.slice(end)}`;
|
|
76
|
+
await fs.writeFile('src/stories/text/Text.stories.ts', newStories);
|
|
77
|
+
} else {
|
|
78
|
+
// Otherwise, append the new stories to the end of the file and add the start and end tags
|
|
79
|
+
const newStories = `${currentStories
|
|
80
|
+
}\n\n// @auto-generated-start\n\n${
|
|
81
|
+
out
|
|
82
|
+
}\n\n// @auto-generated-end`;
|
|
83
|
+
await fs.writeFile('src/stories/text/Text.stories.ts', newStories);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// const storyFile = stories.map((story) => `export const ${pascalCase(story.storyName as string)}: Story = ${JSON.stringify(story, null, 4)};`).join('\n\n');
|
|
87
|
+
// await fs.writeFile('src/stories/text/Text.generated-stories.ts', storyFile);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
(async function main() {
|
|
91
|
+
let argReceived = false;
|
|
92
|
+
if (process.argv.includes('--stories') || process.argv.includes('-s')) {
|
|
93
|
+
const startS = Date.now();
|
|
94
|
+
argReceived = true;
|
|
95
|
+
await generateTextStories();
|
|
96
|
+
try {
|
|
97
|
+
cp.execSync('eslint --fix src/stories/text/Text.stories.ts');
|
|
98
|
+
} catch (e: any) {
|
|
99
|
+
console.error('❌ Failed to lint generated stories.');
|
|
100
|
+
if (e?.stdout) {
|
|
101
|
+
console.error(e?.stdout?.toString());
|
|
102
|
+
}
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
console.info(`✅ Successfully generated stories in ${Date.now() - startS}ms`);
|
|
106
|
+
}
|
|
107
|
+
if (process.argv.includes('--classes') || process.argv.includes('-c')) {
|
|
108
|
+
const startC = Date.now();
|
|
109
|
+
argReceived = true;
|
|
110
|
+
await text();
|
|
111
|
+
console.info(`✅ Successfully generated classes in ${Date.now() - startC}ms`);
|
|
112
|
+
}
|
|
113
|
+
if (!argReceived) {
|
|
114
|
+
console.error('❌ No arguments received. Please specify either --stories, --classes, or both.');
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
process.exit(0);
|
|
118
|
+
}());
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import Head from 'next/head';
|
|
2
|
+
import Image from 'next/image';
|
|
3
|
+
import { Inter } from 'next/font/google';
|
|
4
|
+
import styles from '@/styles/Home.module.css';
|
|
5
|
+
|
|
6
|
+
const inter = Inter({ subsets: ['latin'] });
|
|
7
|
+
|
|
8
|
+
export default function Home() {
|
|
9
|
+
return (
|
|
10
|
+
<>
|
|
11
|
+
<Head>
|
|
12
|
+
<title>Create Next App</title>
|
|
13
|
+
<meta name="description" content="Generated by create next app" />
|
|
14
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
15
|
+
<link rel="icon" href="/favicon.ico" />
|
|
16
|
+
</Head>
|
|
17
|
+
<main className={styles.main}>
|
|
18
|
+
<div className={styles.description}>
|
|
19
|
+
<p>
|
|
20
|
+
Get started by editing
|
|
21
|
+
<code className={styles.code}>src/pages/index.tsx</code>
|
|
22
|
+
</p>
|
|
23
|
+
<div>
|
|
24
|
+
<a
|
|
25
|
+
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
|
26
|
+
target="_blank"
|
|
27
|
+
rel="noopener noreferrer"
|
|
28
|
+
>
|
|
29
|
+
By
|
|
30
|
+
{' '}
|
|
31
|
+
<Image
|
|
32
|
+
src="/vercel.svg"
|
|
33
|
+
alt="Vercel Logo"
|
|
34
|
+
className={styles.vercelLogo}
|
|
35
|
+
width={100}
|
|
36
|
+
height={24}
|
|
37
|
+
priority
|
|
38
|
+
/>
|
|
39
|
+
</a>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div className={styles.center}>
|
|
44
|
+
<Image
|
|
45
|
+
className={styles.logo}
|
|
46
|
+
src="/next.svg"
|
|
47
|
+
alt="Next.js Logo"
|
|
48
|
+
width={180}
|
|
49
|
+
height={37}
|
|
50
|
+
priority
|
|
51
|
+
/>
|
|
52
|
+
<div className={styles.thirteen}>
|
|
53
|
+
<Image
|
|
54
|
+
src="/thirteen.svg"
|
|
55
|
+
alt="13"
|
|
56
|
+
width={40}
|
|
57
|
+
height={31}
|
|
58
|
+
priority
|
|
59
|
+
/>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div className={styles.grid}>
|
|
64
|
+
<a
|
|
65
|
+
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
|
66
|
+
className={styles.card}
|
|
67
|
+
target="_blank"
|
|
68
|
+
rel="noopener noreferrer"
|
|
69
|
+
>
|
|
70
|
+
<h2 className={inter.className}>
|
|
71
|
+
Docs
|
|
72
|
+
{' '}
|
|
73
|
+
<span>-></span>
|
|
74
|
+
</h2>
|
|
75
|
+
<p className={inter.className}>
|
|
76
|
+
Find in-depth information about Next.js features and API.
|
|
77
|
+
</p>
|
|
78
|
+
</a>
|
|
79
|
+
|
|
80
|
+
<a
|
|
81
|
+
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
|
82
|
+
className={styles.card}
|
|
83
|
+
target="_blank"
|
|
84
|
+
rel="noopener noreferrer"
|
|
85
|
+
>
|
|
86
|
+
<h2 className={inter.className}>
|
|
87
|
+
Learn
|
|
88
|
+
{' '}
|
|
89
|
+
<span>-></span>
|
|
90
|
+
</h2>
|
|
91
|
+
<p className={inter.className}>
|
|
92
|
+
Learn about Next.js in an interactive course with quizzes!
|
|
93
|
+
</p>
|
|
94
|
+
</a>
|
|
95
|
+
|
|
96
|
+
<a
|
|
97
|
+
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
|
98
|
+
className={styles.card}
|
|
99
|
+
target="_blank"
|
|
100
|
+
rel="noopener noreferrer"
|
|
101
|
+
>
|
|
102
|
+
<h2 className={inter.className}>
|
|
103
|
+
Templates
|
|
104
|
+
{' '}
|
|
105
|
+
<span>-></span>
|
|
106
|
+
</h2>
|
|
107
|
+
<p className={inter.className}>
|
|
108
|
+
Discover and deploy boilerplate example Next.js projects.
|
|
109
|
+
</p>
|
|
110
|
+
</a>
|
|
111
|
+
|
|
112
|
+
<a
|
|
113
|
+
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
|
114
|
+
className={styles.card}
|
|
115
|
+
target="_blank"
|
|
116
|
+
rel="noopener noreferrer"
|
|
117
|
+
>
|
|
118
|
+
<h2 className={inter.className}>
|
|
119
|
+
Deploy
|
|
120
|
+
{' '}
|
|
121
|
+
<span>-></span>
|
|
122
|
+
</h2>
|
|
123
|
+
<p className={inter.className}>
|
|
124
|
+
Instantly deploy your Next.js site to a shareable URL
|
|
125
|
+
with Vercel.
|
|
126
|
+
</p>
|
|
127
|
+
</a>
|
|
128
|
+
</div>
|
|
129
|
+
</main>
|
|
130
|
+
</>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Meta } from '@storybook/blocks';
|
|
2
|
+
import { LightTheme, pget, pvar } from './theme';
|
|
3
|
+
|
|
4
|
+
<Meta title="Tokens" />
|
|
5
|
+
|
|
6
|
+
# Tokens
|
|
7
|
+
|
|
8
|
+
Tokens are the smallest pieces of design language that can be used to build components. They are the building blocks of our design system—you can think of them as the basic variables of our design language.
|
|
9
|
+
|
|
10
|
+
<br />
|
|
11
|
+
|
|
12
|
+
## Colors
|
|
13
|
+
|
|
14
|
+
<div
|
|
15
|
+
style={{
|
|
16
|
+
width: '100%',
|
|
17
|
+
display: 'grid',
|
|
18
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))',
|
|
19
|
+
gridTemplateRows: 'auto',
|
|
20
|
+
alignItems: 'center',
|
|
21
|
+
gap: '1rem',
|
|
22
|
+
}}
|
|
23
|
+
>
|
|
24
|
+
{Object.entries(LightTheme.colors).map(([key, value]) => (
|
|
25
|
+
<div key={key} style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
|
|
26
|
+
<div
|
|
27
|
+
style={{
|
|
28
|
+
width: '2rem',
|
|
29
|
+
height: '2rem',
|
|
30
|
+
backgroundColor: pvar(`colors.${key}`),
|
|
31
|
+
borderColor: pvar(`colors.borderSelected`),
|
|
32
|
+
borderWidth: '1px',
|
|
33
|
+
borderStyle: 'solid',
|
|
34
|
+
marginRight: '1rem',
|
|
35
|
+
borderRadius: '100%',
|
|
36
|
+
}}
|
|
37
|
+
/>
|
|
38
|
+
<div style={{ color: pvar('colors.contentPrimary') }}>
|
|
39
|
+
<span style={{ fontWeight: pvar('typography.boldFontWeight') }}>{key}</span>
|
|
40
|
+
<br />
|
|
41
|
+
<pre style={{ fontSize: '14px' }}>{pget(`colors.${key}`)}</pre>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
))}
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<br />
|
|
48
|
+
|
|
49
|
+
## Typography
|
|
50
|
+
|
|
51
|
+
<div>
|
|
52
|
+
<pre style={{ color: pvar('colors.contentPrimary') }}>{JSON.stringify(LightTheme.typography, null, 4).replaceAll('"', '').replaceAll(',', '\n').replaceAll('{', '\n').replaceAll('}', '\n').replaceAll('\\', '')}</pre>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// Main styles
|
|
2
|
+
.button {
|
|
3
|
+
user-select: none;
|
|
4
|
+
|
|
5
|
+
border: 1px solid;
|
|
6
|
+
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: row;
|
|
9
|
+
align-items: center;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
gap: 8px;
|
|
12
|
+
|
|
13
|
+
transition: var(--pte-animations-interaction);
|
|
14
|
+
|
|
15
|
+
&:hover {
|
|
16
|
+
cursor: default;
|
|
17
|
+
background-color: var(--pte-colors-backgroundInverseTertiary);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&:active {
|
|
21
|
+
opacity: 0.9;
|
|
22
|
+
transform: scale(0.98);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&[disabled] {
|
|
26
|
+
pointer-events: none;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
* KIND
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
.primary {
|
|
36
|
+
color: var(--pte-colors-contentInversePrimary);
|
|
37
|
+
background-color: var(--pte-colors-backgroundInversePrimary);
|
|
38
|
+
border-color: var(--pte-colors-backgroundInversePrimary);
|
|
39
|
+
|
|
40
|
+
&:hover {
|
|
41
|
+
border-color: var(--pte-colors-backgroundInverseTertiary);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&[disabled] {
|
|
45
|
+
color: var(--pte-colors-contentDisabled);
|
|
46
|
+
background-color: var(--pte-colors-backgroundTertiary);
|
|
47
|
+
border-color: var(--pte-colors-backgroundTertiary);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.secondary {
|
|
52
|
+
color: var(--pte-colors-contentPrimary);
|
|
53
|
+
background-color: transparent;
|
|
54
|
+
border-color: var(--pte-colors-contentPrimary);
|
|
55
|
+
|
|
56
|
+
&[disabled] {
|
|
57
|
+
color: var(--pte-colors-contentDisabled);
|
|
58
|
+
border-color: var(--pte-colors-contentDisabled);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.tertiary {
|
|
63
|
+
color: var(--pte-colors-contentPrimary);
|
|
64
|
+
background-color: transparent;
|
|
65
|
+
border-color: transparent;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.secondary, .tertiary {
|
|
69
|
+
&:hover {
|
|
70
|
+
background-color: var(--pte-colors-backgroundTertiary);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
&[disabled] {
|
|
74
|
+
color: var(--pte-colors-contentDisabled);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
/*
|
|
80
|
+
* SIZE
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
.large {
|
|
84
|
+
height: 32px;
|
|
85
|
+
padding: 8px 15px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.small {
|
|
89
|
+
height: 20px;
|
|
90
|
+
padding: 4px 15px;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
/*
|
|
95
|
+
* SHAPE
|
|
96
|
+
*/
|
|
97
|
+
|
|
98
|
+
.pill {
|
|
99
|
+
border-radius: var(--pte-borders-radius-pill);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.circle {
|
|
103
|
+
border-radius: var(--pte-borders-radius-circle);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.rounded {
|
|
107
|
+
border-radius: var(--pte-borders-radius-rounded);
|
|
108
|
+
|
|
109
|
+
&.small {
|
|
110
|
+
border-radius: var(--pte-borders-radius-roundedSmall);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.square, .rectangle {
|
|
115
|
+
border-radius: var(--pte-borders-radius-rectangle);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.circle, .square {
|
|
119
|
+
&.large {
|
|
120
|
+
width: 32px;
|
|
121
|
+
padding: 8px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
&.small {
|
|
125
|
+
width: 20px;
|
|
126
|
+
padding: 4px;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Button } from './Button';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof Button> = {
|
|
5
|
+
title: 'Inputs/Button',
|
|
6
|
+
component: Button,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default meta;
|
|
11
|
+
type Story = StoryObj<typeof Button>;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* By default, the Button component renders a primary large pill.
|
|
15
|
+
*
|
|
16
|
+
* **Primary** buttons are intended to represent primary or leading actions, such as "Submit" or "Save".
|
|
17
|
+
*/
|
|
18
|
+
export const Primary: Story = {
|
|
19
|
+
args: {
|
|
20
|
+
children: 'Button',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* **Secondary** buttons are intended to represent secondary or trailing actions, such as "Cancel" or "Delete".
|
|
26
|
+
*/
|
|
27
|
+
export const Secondary: Story = {
|
|
28
|
+
args: {
|
|
29
|
+
children: 'Button',
|
|
30
|
+
kind: 'secondary',
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* **Tertiary** buttons offer a visual alternative for non-primary actions.
|
|
36
|
+
*/
|
|
37
|
+
export const Tertiary: Story = {
|
|
38
|
+
args: {
|
|
39
|
+
children: 'Button',
|
|
40
|
+
kind: 'tertiary',
|
|
41
|
+
},
|
|
42
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
ButtonHTMLAttributes, FC, MouseEventHandler, ReactNode,
|
|
5
|
+
} from 'react';
|
|
6
|
+
import styles from './Button.module.scss';
|
|
7
|
+
import { Text } from '../text';
|
|
8
|
+
|
|
9
|
+
export type ButtonProps = {
|
|
10
|
+
/**
|
|
11
|
+
* The appearance of the Button.
|
|
12
|
+
* @default primary
|
|
13
|
+
*/
|
|
14
|
+
kind?: 'primary' | 'secondary' | 'tertiary';
|
|
15
|
+
/**
|
|
16
|
+
* The size of the Button.
|
|
17
|
+
* @default large
|
|
18
|
+
*/
|
|
19
|
+
size?: 'large' | 'small';
|
|
20
|
+
/**
|
|
21
|
+
* The shape of the Button.
|
|
22
|
+
* @default pill
|
|
23
|
+
*/
|
|
24
|
+
shape?: 'pill' | 'circle' | 'rectangle' | 'square' | 'rounded';
|
|
25
|
+
/**
|
|
26
|
+
* An icon or other element to render before the Button's text. A `size` argument is passed that should be used to determine the width & height of the content displayed.
|
|
27
|
+
*
|
|
28
|
+
* When Button shape is `circle` or `square`, this element will be the only visible content.
|
|
29
|
+
*/
|
|
30
|
+
startEnhancer?: (size: number) => ReactNode;
|
|
31
|
+
/**
|
|
32
|
+
* An icon or other element to render after the Button's text. A `size` argument is passed that should be used to determine the width & height of the content displayed.
|
|
33
|
+
*/
|
|
34
|
+
endEnhancer?: (size: number) => ReactNode;
|
|
35
|
+
/**
|
|
36
|
+
* Disables the Button, disallowing user interaction.
|
|
37
|
+
* @default false
|
|
38
|
+
*/
|
|
39
|
+
disabled?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* The interaction handler for the Button.
|
|
42
|
+
*/
|
|
43
|
+
onClick?: MouseEventHandler<HTMLButtonElement>;
|
|
44
|
+
/**
|
|
45
|
+
* The contents of the Button.
|
|
46
|
+
*
|
|
47
|
+
* This should be text. When Button shape is `circle` or `square`, the action description should still be passed here for screen readers.
|
|
48
|
+
*/
|
|
49
|
+
children: string;
|
|
50
|
+
} & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'disabled' | 'onClick'>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* A `Button` is used to trigger an action or event, such as submitting a form, opening a dialog, canceling an action, or performing a delete operation.
|
|
54
|
+
*
|
|
55
|
+
* @constructor
|
|
56
|
+
*/
|
|
57
|
+
export const Button: FC<ButtonProps> = ({
|
|
58
|
+
kind,
|
|
59
|
+
size,
|
|
60
|
+
shape,
|
|
61
|
+
type,
|
|
62
|
+
startEnhancer,
|
|
63
|
+
endEnhancer,
|
|
64
|
+
onClick,
|
|
65
|
+
children,
|
|
66
|
+
...props
|
|
67
|
+
}) => (
|
|
68
|
+
<button
|
|
69
|
+
className={`${props.className} ${styles[kind || 'primary']} ${styles[shape || 'pill']} ${styles[size || 'large']} ${styles.button}`}
|
|
70
|
+
type={type || 'button'}
|
|
71
|
+
aria-details={children}
|
|
72
|
+
onClick={onClick}
|
|
73
|
+
{...props}
|
|
74
|
+
>
|
|
75
|
+
{!!startEnhancer && startEnhancer(size === 'large' ? 16 : 12)}
|
|
76
|
+
<Text kind="labelXSmall">
|
|
77
|
+
{children || 'Button'}
|
|
78
|
+
</Text>
|
|
79
|
+
{!!endEnhancer && endEnhancer(size === 'large' ? 16 : 12)}
|
|
80
|
+
</button>
|
|
81
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Button';
|