@nattui/react-components 0.0.1
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/.prettierignore +2 -0
- package/.prettierrc +9 -0
- package/.turbo/turbo-build.log +29 -0
- package/LICENSE +21 -0
- package/dist/button-background.module-FK4ABTRO.module.css +38 -0
- package/dist/button-spinner.module-IRIJPNSF.module.css +95 -0
- package/dist/button.module-QR72PPSM.module.css +238 -0
- package/dist/index.d.mts +48 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +124 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +115 -0
- package/dist/index.mjs.map +1 -0
- package/eslint.config.mjs +96 -0
- package/global.d.ts +4 -0
- package/package.json +59 -0
- package/src/button-background.module.css +38 -0
- package/src/button-background.tsx +40 -0
- package/src/button-spinner.module.css +95 -0
- package/src/button-spinner.tsx +21 -0
- package/src/button.module.css +238 -0
- package/src/button.tsx +97 -0
- package/src/index.ts +1 -0
- package/tsconfig.json +13 -0
- package/tsup.config.ts +13 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import styles from './button-background.module-FK4ABTRO.module.css';
|
|
2
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import styles2 from './button-spinner.module-IRIJPNSF.module.css';
|
|
4
|
+
import styles3 from './button.module-QR72PPSM.module.css';
|
|
5
|
+
|
|
6
|
+
// src/button-background.tsx
|
|
7
|
+
function ButtonBackground(props) {
|
|
8
|
+
const { rounded = false, variant = "primary" } = props;
|
|
9
|
+
const combinedBackgroundStyles = `
|
|
10
|
+
${BUTTON_BACKGROUND_CLASS_NAME.BASE}
|
|
11
|
+
${rounded ? BUTTON_BACKGROUND_CLASS_NAME.ROUNDED.FULL : BUTTON_BACKGROUND_CLASS_NAME.ROUNDED.BASE}
|
|
12
|
+
${variant === "accent" ? BUTTON_BACKGROUND_CLASS_NAME.VARIANT.ACCENT : ""}
|
|
13
|
+
${variant === "primary" ? BUTTON_BACKGROUND_CLASS_NAME.VARIANT.PRIMARY : ""}
|
|
14
|
+
`.replaceAll(/\s+/g, " ").trim();
|
|
15
|
+
if (!(variant === "accent" || variant === "primary")) return /* @__PURE__ */ jsx(Fragment, {});
|
|
16
|
+
return /* @__PURE__ */ jsx(
|
|
17
|
+
"div",
|
|
18
|
+
{
|
|
19
|
+
className: combinedBackgroundStyles,
|
|
20
|
+
"data-element": "button-background"
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
var BUTTON_BACKGROUND_CLASS_NAME = {
|
|
25
|
+
BASE: styles.button_background,
|
|
26
|
+
ROUNDED: {
|
|
27
|
+
BASE: styles.button_background__rounded_base,
|
|
28
|
+
FULL: styles.button_background__rounded_full
|
|
29
|
+
},
|
|
30
|
+
VARIANT: {
|
|
31
|
+
ACCENT: styles.button_background__variant_accent,
|
|
32
|
+
PRIMARY: styles.button_background__variant_primary
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
function ButtonSpinner(props) {
|
|
36
|
+
const { size = 16 } = props;
|
|
37
|
+
return /* @__PURE__ */ jsx(
|
|
38
|
+
"div",
|
|
39
|
+
{
|
|
40
|
+
className: styles2.button_spinner,
|
|
41
|
+
style: { "--size": `${size}px` },
|
|
42
|
+
children: Array.from({ length: 12 }).map((_, index) => /* @__PURE__ */ jsx("div", {}, index))
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
function Button(props) {
|
|
47
|
+
const {
|
|
48
|
+
children = "",
|
|
49
|
+
className: customClassName = "",
|
|
50
|
+
disabled = false,
|
|
51
|
+
fullWidth = false,
|
|
52
|
+
iconEnd = "",
|
|
53
|
+
iconOnly = false,
|
|
54
|
+
iconStart = "",
|
|
55
|
+
isLoading = false,
|
|
56
|
+
rounded = false,
|
|
57
|
+
size = 36,
|
|
58
|
+
type = "button",
|
|
59
|
+
variant = "primary",
|
|
60
|
+
...rest
|
|
61
|
+
} = props;
|
|
62
|
+
const combinedClassName = `
|
|
63
|
+
${BUTTON_CLASS_NAME.BASE}
|
|
64
|
+
${BUTTON_CLASS_NAME.SIZE[size]}
|
|
65
|
+
${BUTTON_CLASS_NAME.VARIANT[variant.toUpperCase()]}
|
|
66
|
+
${fullWidth ? BUTTON_CLASS_NAME.WIDTH.FULL : BUTTON_CLASS_NAME.WIDTH.BASE}
|
|
67
|
+
${iconOnly ? BUTTON_CLASS_NAME.ICON_ONLY : ""}
|
|
68
|
+
${rounded ? BUTTON_CLASS_NAME.ROUNDED.FULL : BUTTON_CLASS_NAME.ROUNDED.BASE}
|
|
69
|
+
${customClassName}
|
|
70
|
+
`.replaceAll(/\s+/g, " ").trim();
|
|
71
|
+
return /* @__PURE__ */ jsxs(
|
|
72
|
+
"button",
|
|
73
|
+
{
|
|
74
|
+
className: combinedClassName,
|
|
75
|
+
disabled: disabled || isLoading,
|
|
76
|
+
type,
|
|
77
|
+
...rest,
|
|
78
|
+
children: [
|
|
79
|
+
/* @__PURE__ */ jsx(ButtonBackground, { rounded, variant }),
|
|
80
|
+
isLoading && /* @__PURE__ */ jsx(ButtonSpinner, {}),
|
|
81
|
+
!isLoading && iconStart,
|
|
82
|
+
children,
|
|
83
|
+
!isLoading && iconEnd
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
var BUTTON_CLASS_NAME = {
|
|
89
|
+
BASE: styles3.button,
|
|
90
|
+
ICON_ONLY: styles3.button__icon_only,
|
|
91
|
+
ROUNDED: {
|
|
92
|
+
BASE: styles3.button__rounded_base,
|
|
93
|
+
FULL: styles3.button__rounded_full
|
|
94
|
+
},
|
|
95
|
+
SIZE: {
|
|
96
|
+
32: styles3.button__size_32,
|
|
97
|
+
36: styles3.button__size_36,
|
|
98
|
+
40: styles3.button__size_40,
|
|
99
|
+
48: styles3.button__size_48
|
|
100
|
+
},
|
|
101
|
+
VARIANT: {
|
|
102
|
+
ACCENT: styles3.button__variant_accent,
|
|
103
|
+
GHOST: styles3.button__variant_ghost,
|
|
104
|
+
PRIMARY: styles3.button__variant_primary,
|
|
105
|
+
SECONDARY: styles3.button__variant_secondary
|
|
106
|
+
},
|
|
107
|
+
WIDTH: {
|
|
108
|
+
BASE: styles3.button__width_base,
|
|
109
|
+
FULL: styles3.button__width_full
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export { BUTTON_CLASS_NAME, Button };
|
|
114
|
+
//# sourceMappingURL=index.mjs.map
|
|
115
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/button-background.tsx","../src/button-spinner.tsx","../src/button.tsx"],"names":["jsx","styles"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { JSX } from \"react\"\nimport type { ButtonProps } from \"@/button\"\nimport styles from \"@/button-background.module.css\"\n\nexport interface ButtonBackgroundProps\n extends Pick<ButtonProps, \"rounded\" | \"variant\"> {}\n\nexport function ButtonBackground(props: ButtonBackgroundProps): JSX.Element {\n const { rounded = false, variant = \"primary\" } = props\n\n const combinedBackgroundStyles = `\n ${BUTTON_BACKGROUND_CLASS_NAME.BASE}\n ${rounded ? BUTTON_BACKGROUND_CLASS_NAME.ROUNDED.FULL : BUTTON_BACKGROUND_CLASS_NAME.ROUNDED.BASE}\n ${variant === \"accent\" ? BUTTON_BACKGROUND_CLASS_NAME.VARIANT.ACCENT : \"\"}\n ${variant === \"primary\" ? BUTTON_BACKGROUND_CLASS_NAME.VARIANT.PRIMARY : \"\"}\n `\n .replaceAll(/\\s+/g, \" \")\n .trim()\n\n if (!(variant === \"accent\" || variant === \"primary\")) return <></>\n\n return (\n <div\n className={combinedBackgroundStyles}\n data-element=\"button-background\"\n />\n )\n}\n\nexport const BUTTON_BACKGROUND_CLASS_NAME = {\n BASE: styles.button_background,\n ROUNDED: {\n BASE: styles.button_background__rounded_base,\n FULL: styles.button_background__rounded_full,\n },\n VARIANT: {\n ACCENT: styles.button_background__variant_accent,\n PRIMARY: styles.button_background__variant_primary,\n },\n} as const\n","import type { CSSProperties, JSX } from \"react\"\nimport styles from \"@/button-spinner.module.css\"\n\nexport interface ButtonSpinnerProps {\n size?: number\n}\n\nexport function ButtonSpinner(props: ButtonSpinnerProps): JSX.Element {\n const { size = 16 } = props\n\n return (\n <div\n className={styles.button_spinner}\n style={{ \"--size\": `${size}px` } as CSSProperties}\n >\n {Array.from({ length: 12 }).map((_, index) => (\n <div key={index} />\n ))}\n </div>\n )\n}\n","import type { ComponentProps, JSX, ReactNode } from \"react\"\nimport { ButtonBackground } from \"@/button-background\"\nimport { ButtonSpinner } from \"@/button-spinner\"\nimport styles from \"@/button.module.css\"\n\nexport interface ButtonProps extends ComponentProps<\"button\"> {\n fullWidth?: boolean\n iconEnd?: ReactNode\n iconOnly?: boolean\n iconStart?: ReactNode\n isLoading?: boolean\n rounded?: boolean\n size?: 32 | 36 | 40 | 48\n variant?: \"accent\" | \"ghost\" | \"primary\" | \"secondary\"\n}\n\ntype ButtonPropsInternal = ButtonPropsWithIcon | ButtonPropsWithText\n\ninterface ButtonPropsWithIcon extends ButtonProps {\n children?: ReactNode\n iconOnly: true\n}\n\ninterface ButtonPropsWithText extends ButtonProps {\n children?: string\n iconOnly?: false\n}\n\nexport function Button(props: ButtonPropsInternal): JSX.Element {\n const {\n children = \"\",\n className: customClassName = \"\",\n disabled = false,\n fullWidth = false,\n iconEnd = \"\",\n iconOnly = false,\n iconStart = \"\",\n isLoading = false,\n rounded = false,\n size = 36,\n type = \"button\",\n variant = \"primary\",\n ...rest\n } = props\n\n const combinedClassName = `\n ${BUTTON_CLASS_NAME.BASE}\n ${BUTTON_CLASS_NAME.SIZE[size]}\n ${BUTTON_CLASS_NAME.VARIANT[variant.toUpperCase() as keyof typeof BUTTON_CLASS_NAME.VARIANT]}\n ${fullWidth ? BUTTON_CLASS_NAME.WIDTH.FULL : BUTTON_CLASS_NAME.WIDTH.BASE}\n ${iconOnly ? BUTTON_CLASS_NAME.ICON_ONLY : \"\"}\n ${rounded ? BUTTON_CLASS_NAME.ROUNDED.FULL : BUTTON_CLASS_NAME.ROUNDED.BASE}\n ${customClassName}\n `\n .replaceAll(/\\s+/g, \" \")\n .trim()\n\n return (\n <button\n className={combinedClassName}\n disabled={disabled || isLoading}\n type={type}\n {...rest}\n >\n <ButtonBackground rounded={rounded} variant={variant} />\n {isLoading && <ButtonSpinner />}\n {!isLoading && iconStart}\n {children}\n {!isLoading && iconEnd}\n </button>\n )\n}\n\nexport const BUTTON_CLASS_NAME = {\n BASE: styles.button,\n ICON_ONLY: styles.button__icon_only,\n ROUNDED: {\n BASE: styles.button__rounded_base,\n FULL: styles.button__rounded_full,\n },\n SIZE: {\n 32: styles.button__size_32,\n 36: styles.button__size_36,\n 40: styles.button__size_40,\n 48: styles.button__size_48,\n },\n VARIANT: {\n ACCENT: styles.button__variant_accent,\n GHOST: styles.button__variant_ghost,\n PRIMARY: styles.button__variant_primary,\n SECONDARY: styles.button__variant_secondary,\n },\n WIDTH: {\n BASE: styles.button__width_base,\n FULL: styles.button__width_full,\n },\n} as const\n"]}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import css from "@eslint/css"
|
|
2
|
+
import js from "@eslint/js"
|
|
3
|
+
import pluginPerfectionist from "eslint-plugin-perfectionist"
|
|
4
|
+
import pluginReact from "eslint-plugin-react"
|
|
5
|
+
import pluginUnicorn from "eslint-plugin-unicorn"
|
|
6
|
+
import pluginUnusedImports from "eslint-plugin-unused-imports"
|
|
7
|
+
import { defineConfig } from "eslint/config"
|
|
8
|
+
import globals from "globals"
|
|
9
|
+
import tseslint from "typescript-eslint"
|
|
10
|
+
|
|
11
|
+
export default defineConfig([
|
|
12
|
+
// Global ignores
|
|
13
|
+
{
|
|
14
|
+
ignores: ["dist/"],
|
|
15
|
+
},
|
|
16
|
+
// Base configurations for JS/TS files only
|
|
17
|
+
{
|
|
18
|
+
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
19
|
+
...pluginPerfectionist.configs["recommended-natural"],
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
23
|
+
...pluginReact.configs.flat.recommended,
|
|
24
|
+
settings: {
|
|
25
|
+
react: {
|
|
26
|
+
version: "detect",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
32
|
+
...pluginUnicorn.configs.all,
|
|
33
|
+
},
|
|
34
|
+
...tseslint.configs.recommended.map((config) => ({
|
|
35
|
+
...config,
|
|
36
|
+
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
37
|
+
})),
|
|
38
|
+
{
|
|
39
|
+
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
40
|
+
languageOptions: { globals: globals.browser },
|
|
41
|
+
},
|
|
42
|
+
// CSS configuration
|
|
43
|
+
{
|
|
44
|
+
extends: ["css/recommended"],
|
|
45
|
+
files: ["**/*.css"],
|
|
46
|
+
language: "css/css",
|
|
47
|
+
plugins: { css },
|
|
48
|
+
rules: {
|
|
49
|
+
"css/use-baseline": "off",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
// JavaScript configuration
|
|
53
|
+
{
|
|
54
|
+
extends: ["js/recommended"],
|
|
55
|
+
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
56
|
+
plugins: { js },
|
|
57
|
+
},
|
|
58
|
+
// Custom rules for JS/TS files only
|
|
59
|
+
{
|
|
60
|
+
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
61
|
+
plugins: {
|
|
62
|
+
"unused-imports": pluginUnusedImports,
|
|
63
|
+
},
|
|
64
|
+
rules: {
|
|
65
|
+
"@typescript-eslint/no-empty-object-type": [
|
|
66
|
+
"error",
|
|
67
|
+
{
|
|
68
|
+
allowInterfaces: "with-single-extends",
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
"perfectionist/sort-imports": [
|
|
72
|
+
"error",
|
|
73
|
+
{
|
|
74
|
+
newlinesBetween: "never",
|
|
75
|
+
sortSideEffects: true,
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
"react/react-in-jsx-scope": "off",
|
|
79
|
+
"unicorn/consistent-function-scoping": "off",
|
|
80
|
+
"unicorn/import-style": "off",
|
|
81
|
+
"unicorn/no-keyword-prefix": "off",
|
|
82
|
+
"unicorn/no-unused-properties": "warn",
|
|
83
|
+
"unicorn/prevent-abbreviations": "off",
|
|
84
|
+
"unused-imports/no-unused-imports": "error",
|
|
85
|
+
"unused-imports/no-unused-vars": [
|
|
86
|
+
"warn",
|
|
87
|
+
{
|
|
88
|
+
args: "after-used",
|
|
89
|
+
argsIgnorePattern: "^_",
|
|
90
|
+
vars: "all",
|
|
91
|
+
varsIgnorePattern: "^_",
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
])
|
package/global.d.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nattui/react-components",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A collection of reusable React components built with TypeScript and CSS Modules",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"components",
|
|
7
|
+
"react"
|
|
8
|
+
],
|
|
9
|
+
"homepage": "https://github.com/nattui/react-components#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/nattui/react-components/issues"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/nattui/react-components.git"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "Natt Nguyen <hello@natt.sh> (https://natt.sh)",
|
|
19
|
+
"exports": "./dist/index.js",
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"module": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@eslint/css": "^0.9.0",
|
|
25
|
+
"@eslint/js": "^9.29.0",
|
|
26
|
+
"@types/react": "^19.1.8",
|
|
27
|
+
"eslint": "^9.29.0",
|
|
28
|
+
"eslint-plugin-perfectionist": "^4.14.0",
|
|
29
|
+
"eslint-plugin-react": "^7.37.5",
|
|
30
|
+
"eslint-plugin-unicorn": "^59.0.1",
|
|
31
|
+
"eslint-plugin-unused-imports": "^4.1.4",
|
|
32
|
+
"globals": "^16.2.0",
|
|
33
|
+
"prettier": "^3.5.3",
|
|
34
|
+
"prettier-plugin-css-order": "^2.1.2",
|
|
35
|
+
"prettier-plugin-packagejson": "^2.5.15",
|
|
36
|
+
"prettier-plugin-sort-json": "^4.1.1",
|
|
37
|
+
"tsup": "^8.5.0",
|
|
38
|
+
"typescript": "^5.8.3",
|
|
39
|
+
"typescript-eslint": "^8.34.0"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
43
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsup",
|
|
50
|
+
"check": "pnpm check:format && pnpm check:lint",
|
|
51
|
+
"check:fix": "pnpm check:format:fix && pnpm check:lint:fix",
|
|
52
|
+
"check:format": "prettier --check .",
|
|
53
|
+
"check:format:fix": "prettier --write .",
|
|
54
|
+
"check:lint": "eslint .",
|
|
55
|
+
"check:lint:fix": "eslint --fix .",
|
|
56
|
+
"dev": "tsup --watch",
|
|
57
|
+
"update": "pnpx npm-check-updates --upgrade"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/* Base */
|
|
2
|
+
.button_background {
|
|
3
|
+
position: absolute;
|
|
4
|
+
top: 0;
|
|
5
|
+
right: 0;
|
|
6
|
+
bottom: 50%;
|
|
7
|
+
left: 0;
|
|
8
|
+
opacity: 0.2;
|
|
9
|
+
z-index: -1;
|
|
10
|
+
filter: none !important;
|
|
11
|
+
transition: opacity 150ms;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* Rounded */
|
|
15
|
+
.button_background__rounded_base {
|
|
16
|
+
border-radius: 7px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.button_background__rounded_full {
|
|
20
|
+
border-radius: 9999px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* Variant */
|
|
24
|
+
.button_background__variant_accent {
|
|
25
|
+
background: linear-gradient(
|
|
26
|
+
to bottom,
|
|
27
|
+
var(--color-primary-7, #edadc8),
|
|
28
|
+
var(--color-primary-8, #e58fb1)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.button_background__variant_primary {
|
|
33
|
+
background: linear-gradient(
|
|
34
|
+
to bottom,
|
|
35
|
+
var(--color-gray-10, #86848d),
|
|
36
|
+
var(--color-gray-11, #6f6e77)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { JSX } from "react"
|
|
2
|
+
import type { ButtonProps } from "@/button"
|
|
3
|
+
import styles from "@/button-background.module.css"
|
|
4
|
+
|
|
5
|
+
export interface ButtonBackgroundProps
|
|
6
|
+
extends Pick<ButtonProps, "rounded" | "variant"> {}
|
|
7
|
+
|
|
8
|
+
export function ButtonBackground(props: ButtonBackgroundProps): JSX.Element {
|
|
9
|
+
const { rounded = false, variant = "primary" } = props
|
|
10
|
+
|
|
11
|
+
const combinedBackgroundStyles = `
|
|
12
|
+
${BUTTON_BACKGROUND_CLASS_NAME.BASE}
|
|
13
|
+
${rounded ? BUTTON_BACKGROUND_CLASS_NAME.ROUNDED.FULL : BUTTON_BACKGROUND_CLASS_NAME.ROUNDED.BASE}
|
|
14
|
+
${variant === "accent" ? BUTTON_BACKGROUND_CLASS_NAME.VARIANT.ACCENT : ""}
|
|
15
|
+
${variant === "primary" ? BUTTON_BACKGROUND_CLASS_NAME.VARIANT.PRIMARY : ""}
|
|
16
|
+
`
|
|
17
|
+
.replaceAll(/\s+/g, " ")
|
|
18
|
+
.trim()
|
|
19
|
+
|
|
20
|
+
if (!(variant === "accent" || variant === "primary")) return <></>
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
className={combinedBackgroundStyles}
|
|
25
|
+
data-element="button-background"
|
|
26
|
+
/>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const BUTTON_BACKGROUND_CLASS_NAME = {
|
|
31
|
+
BASE: styles.button_background,
|
|
32
|
+
ROUNDED: {
|
|
33
|
+
BASE: styles.button_background__rounded_base,
|
|
34
|
+
FULL: styles.button_background__rounded_full,
|
|
35
|
+
},
|
|
36
|
+
VARIANT: {
|
|
37
|
+
ACCENT: styles.button_background__variant_accent,
|
|
38
|
+
PRIMARY: styles.button_background__variant_primary,
|
|
39
|
+
},
|
|
40
|
+
} as const
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
.button_spinner {
|
|
2
|
+
position: relative;
|
|
3
|
+
scale: -1 1;
|
|
4
|
+
animation: spinner 1000ms steps(12, end) infinite;
|
|
5
|
+
width: var(--size);
|
|
6
|
+
height: var(--size);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
@keyframes spinner {
|
|
10
|
+
to {
|
|
11
|
+
rotate: 1turn;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.button_spinner > div {
|
|
16
|
+
position: absolute;
|
|
17
|
+
top: 50%;
|
|
18
|
+
right: 0;
|
|
19
|
+
transform-origin: center left;
|
|
20
|
+
translate: 0 -50%;
|
|
21
|
+
transition: all 150ms;
|
|
22
|
+
width: calc(var(--size) / 2);
|
|
23
|
+
height: calc(var(--size) / 12);
|
|
24
|
+
pointer-events: none;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.button_spinner > div::after {
|
|
28
|
+
position: absolute;
|
|
29
|
+
right: 0;
|
|
30
|
+
border-radius: 9999px;
|
|
31
|
+
background-color: currentColor;
|
|
32
|
+
width: 50%;
|
|
33
|
+
height: 100%;
|
|
34
|
+
content: "";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.button_spinner > div:nth-child(1) {
|
|
38
|
+
rotate: 0deg;
|
|
39
|
+
opacity: 1;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.button_spinner > div:nth-child(2) {
|
|
43
|
+
rotate: 30deg;
|
|
44
|
+
opacity: 0.925;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.button_spinner > div:nth-child(3) {
|
|
48
|
+
rotate: 60deg;
|
|
49
|
+
opacity: 0.85;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.button_spinner > div:nth-child(4) {
|
|
53
|
+
rotate: 90deg;
|
|
54
|
+
opacity: 0.775;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.button_spinner > div:nth-child(5) {
|
|
58
|
+
rotate: 120deg;
|
|
59
|
+
opacity: 0.7;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.button_spinner > div:nth-child(6) {
|
|
63
|
+
rotate: 150deg;
|
|
64
|
+
opacity: 0.625;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.button_spinner > div:nth-child(7) {
|
|
68
|
+
rotate: 180deg;
|
|
69
|
+
opacity: 0.55;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.button_spinner > div:nth-child(8) {
|
|
73
|
+
rotate: 210deg;
|
|
74
|
+
opacity: 0.475;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.button_spinner > div:nth-child(9) {
|
|
78
|
+
rotate: 240deg;
|
|
79
|
+
opacity: 0.4;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.button_spinner > div:nth-child(10) {
|
|
83
|
+
rotate: 270deg;
|
|
84
|
+
opacity: 0.325;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.button_spinner > div:nth-child(11) {
|
|
88
|
+
rotate: 300deg;
|
|
89
|
+
opacity: 0.25;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.button_spinner > div:nth-child(12) {
|
|
93
|
+
rotate: 330deg;
|
|
94
|
+
opacity: 0.15;
|
|
95
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CSSProperties, JSX } from "react"
|
|
2
|
+
import styles from "@/button-spinner.module.css"
|
|
3
|
+
|
|
4
|
+
export interface ButtonSpinnerProps {
|
|
5
|
+
size?: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function ButtonSpinner(props: ButtonSpinnerProps): JSX.Element {
|
|
9
|
+
const { size = 16 } = props
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<div
|
|
13
|
+
className={styles.button_spinner}
|
|
14
|
+
style={{ "--size": `${size}px` } as CSSProperties}
|
|
15
|
+
>
|
|
16
|
+
{Array.from({ length: 12 }).map((_, index) => (
|
|
17
|
+
<div key={index} />
|
|
18
|
+
))}
|
|
19
|
+
</div>
|
|
20
|
+
)
|
|
21
|
+
}
|