@geoinsight/react-components 0.1.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/.babelrc.json +16 -0
- package/.storybook/main.js +11 -0
- package/.storybook/preview.js +43 -0
- package/README.md +26 -0
- package/dist/cjs/index.css +111 -0
- package/dist/cjs/index.js +15 -0
- package/dist/esm/index.css +111 -0
- package/dist/esm/index.js +12 -0
- package/package.json +44 -0
- package/rollup.config.js +40 -0
- package/src/components/accordion/index.css +40 -0
- package/src/components/accordion/index.stories.tsx +55 -0
- package/src/components/accordion/index.tsx +78 -0
- package/src/components/accordion/index.types.ts +44 -0
- package/src/components/button/index.css +80 -0
- package/src/components/button/index.stories.tsx +46 -0
- package/src/components/button/index.tsx +45 -0
- package/src/components/button/index.types.ts +41 -0
- package/src/components/input/index.css +30 -0
- package/src/components/input/index.stories.tsx +34 -0
- package/src/components/input/index.tsx +25 -0
- package/src/components/input/index.types.ts +29 -0
- package/src/components/text-area/index.css +53 -0
- package/src/components/text-area/index.stories.tsx +30 -0
- package/src/components/text-area/index.tsx +62 -0
- package/src/components/text-area/index.types.ts +37 -0
- package/src/decorators/withColorScheme.tsx +34 -0
- package/src/index.ts +2 -0
- package/src/stories/Introduction.stories.mdx +211 -0
- package/src/stories/assets/code-brackets.svg +1 -0
- package/src/stories/assets/colors.svg +1 -0
- package/src/stories/assets/comments.svg +1 -0
- package/src/stories/assets/direction.svg +1 -0
- package/src/stories/assets/flow.svg +1 -0
- package/src/stories/assets/plugin.svg +1 -0
- package/src/stories/assets/repo.svg +1 -0
- package/src/stories/assets/stackalt.svg +1 -0
- package/src/styles/variables.css +100 -0
- package/src/types/data-theme.d.ts +5 -0
- package/src/utils/themes.ts +1 -0
- package/tsconfig.json +21 -0
package/.babelrc.json
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
"stories": ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
|
|
3
|
+
"addons": ["@storybook/addon-links", "@storybook/addon-essentials", "@storybook/addon-interactions", "@storybook/addon-mdx-gfm"],
|
|
4
|
+
"framework": {
|
|
5
|
+
name: "@storybook/react-webpack5",
|
|
6
|
+
options: {}
|
|
7
|
+
},
|
|
8
|
+
docs: {
|
|
9
|
+
autodocs: true
|
|
10
|
+
}
|
|
11
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import "../src/styles/variables.css";
|
|
2
|
+
|
|
3
|
+
export const parameters = {
|
|
4
|
+
actions: { argTypesRegex: "^on[A-Z].*" },
|
|
5
|
+
controls: {
|
|
6
|
+
matchers: {
|
|
7
|
+
color: /(background|color)$/i,
|
|
8
|
+
date: /Date$/,
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const globalTypes = {
|
|
14
|
+
theme: {
|
|
15
|
+
name: 'Theme',
|
|
16
|
+
description: 'Global theme for components',
|
|
17
|
+
defaultValue: 'light',
|
|
18
|
+
toolbar: {
|
|
19
|
+
icon: 'circlehollow',
|
|
20
|
+
// Array of plain string values or MenuItem shape (see below)
|
|
21
|
+
items: ['light', 'dark'],
|
|
22
|
+
// Property that specifies if the name of the item will be displayed
|
|
23
|
+
showName: true,
|
|
24
|
+
// Change title based on selected value
|
|
25
|
+
dynamicTitle: true,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
palette: {
|
|
29
|
+
name: 'Palette',
|
|
30
|
+
description: 'Global theme for components',
|
|
31
|
+
defaultValue: 'water',
|
|
32
|
+
toolbar: {
|
|
33
|
+
icon: 'circlehollow',
|
|
34
|
+
// Array of plain string values or MenuItem shape (see below)
|
|
35
|
+
items: ['water', 'forest', 'earth'],
|
|
36
|
+
// Property that specifies if the name of the item will be displayed
|
|
37
|
+
showName: true,
|
|
38
|
+
// Change title based on selected value
|
|
39
|
+
dynamicTitle: true,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Introduction
|
|
2
|
+
This library is used for Geoinsight, on their websites.
|
|
3
|
+
|
|
4
|
+
## Install
|
|
5
|
+
Install with npm:
|
|
6
|
+
`npm install @geoinsight/react-components`
|
|
7
|
+
|
|
8
|
+
Install with yarn:
|
|
9
|
+
`yarn add @geoinsight/react-components`
|
|
10
|
+
|
|
11
|
+
## Use
|
|
12
|
+
As an example:
|
|
13
|
+
`import { Button } from "@geoinsight/react-components";`
|
|
14
|
+
|
|
15
|
+
## Docs
|
|
16
|
+
### Basic components
|
|
17
|
+
#### Button
|
|
18
|
+
`<Button />`
|
|
19
|
+
|
|
20
|
+
#### Input
|
|
21
|
+
`<Input />`
|
|
22
|
+
|
|
23
|
+
#### TextArea
|
|
24
|
+
`<TextArea />`
|
|
25
|
+
|
|
26
|
+
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
.button {
|
|
2
|
+
align-items: center;
|
|
3
|
+
border-radius: var(--spacing-32);
|
|
4
|
+
border: none;
|
|
5
|
+
cursor: pointer;
|
|
6
|
+
display: flex;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
gap: var(--spacing-8);
|
|
9
|
+
font-size: var(--font-size-16);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
.button--active {
|
|
14
|
+
background-color: var(--color-neutral-500) !important;
|
|
15
|
+
} */
|
|
16
|
+
|
|
17
|
+
.button:disabled {
|
|
18
|
+
cursor: unset;
|
|
19
|
+
opacity: 0.5;
|
|
20
|
+
pointer-events: none;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.button:hover {
|
|
24
|
+
background-color: var(--color-primary);
|
|
25
|
+
transition: var(--transition-bg-cubic-bezier);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.button__link {
|
|
29
|
+
background-color: unset !important;
|
|
30
|
+
color: var(--color-neutral-100);
|
|
31
|
+
text-decoration: underline transparent;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.button__link:hover {
|
|
35
|
+
color: var(--color-primary);
|
|
36
|
+
text-decoration: underline 0.1rem var(--color-primary);
|
|
37
|
+
text-underline-offset: var(--spacing-8);
|
|
38
|
+
transition: var(--transition-color-cubic-bezier),
|
|
39
|
+
var(--transition-text-decoration-cubic-bezier);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.button__primary {
|
|
43
|
+
background-color: var(--color-secondary);
|
|
44
|
+
border: 3px solid var(--color-primary);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.button__primary:hover {
|
|
48
|
+
box-shadow: 0 4px 4px 0 var(--color-neutral-400);
|
|
49
|
+
transition: var(--transition-bg-cubic-bezier), var(--transition-box-shadow-cubic-bezier);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.button__secondary {
|
|
53
|
+
background-color: var(--color-neutral-900);
|
|
54
|
+
border: 3px solid var(--color-primary);
|
|
55
|
+
color: var(--color-neutral-100);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.button__secondary:hover {
|
|
59
|
+
background-color: var(--color-primary);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.button__icon {
|
|
63
|
+
background-color: unset;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.button__icon:hover {
|
|
67
|
+
box-shadow: unset;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.button__small {
|
|
71
|
+
padding: var(--spacing-4);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.button__medium {
|
|
75
|
+
padding: var(--spacing-8) var(--spacing-24);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.button__large {
|
|
79
|
+
padding: var(--spacing-16);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.input-group {
|
|
83
|
+
display: flex;
|
|
84
|
+
flex-direction: column;
|
|
85
|
+
align-items: flex-start;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.input {
|
|
89
|
+
border-radius: var(--spacing-8);
|
|
90
|
+
border: 2px solid var(--color-primary);
|
|
91
|
+
color: var(--color-black);
|
|
92
|
+
padding: var(--spacing-16) var(--spacing-24);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.input:hover {
|
|
96
|
+
border: 3px solid var(--color-primary-700);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.input:focus {
|
|
100
|
+
border: 3px solid var(--color-primary-700);
|
|
101
|
+
outline: none;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.input--error {
|
|
105
|
+
border: 3px solid var(--color-danger);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.error {
|
|
109
|
+
font-size: 12px;
|
|
110
|
+
color: var(--color-danger);
|
|
111
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var clsx = require('clsx');
|
|
5
|
+
|
|
6
|
+
function Button({ children = "Click me", className = "", icon = undefined, isNewWindow = false, mode = "primary", size = "medium", as = "button", ...rest }) {
|
|
7
|
+
return as === "link" ? (jsxRuntime.jsxs("a", { ...(isNewWindow && { target: "_blank" }), className: clsx(className, "button", mode === "secondary" ? `button button__${mode}` : "button__link", `button__${size}`), ...rest, children: [children, icon] })) : (jsxRuntime.jsxs("button", { className: clsx(className, "button", `button__${mode}`, `button__${size}`), ...rest, children: [children, icon] }));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function Input({ className = "", classNameGroup = "", errorMessage = "", inputRef, styleGroup, ...rest }) {
|
|
11
|
+
return (jsxRuntime.jsxs("div", { className: `input-group ${classNameGroup}`, style: styleGroup, children: [jsxRuntime.jsx("input", { ref: inputRef, className: `input ${errorMessage ? "input--error" : ""} ${className}`, ...rest }), errorMessage && jsxRuntime.jsx("span", { className: "error", children: errorMessage })] }));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
exports.Button = Button;
|
|
15
|
+
exports.Input = Input;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
.button {
|
|
2
|
+
align-items: center;
|
|
3
|
+
border-radius: var(--spacing-32);
|
|
4
|
+
border: none;
|
|
5
|
+
cursor: pointer;
|
|
6
|
+
display: flex;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
gap: var(--spacing-8);
|
|
9
|
+
font-size: var(--font-size-16);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
.button--active {
|
|
14
|
+
background-color: var(--color-neutral-500) !important;
|
|
15
|
+
} */
|
|
16
|
+
|
|
17
|
+
.button:disabled {
|
|
18
|
+
cursor: unset;
|
|
19
|
+
opacity: 0.5;
|
|
20
|
+
pointer-events: none;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.button:hover {
|
|
24
|
+
background-color: var(--color-primary);
|
|
25
|
+
transition: var(--transition-bg-cubic-bezier);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.button__link {
|
|
29
|
+
background-color: unset !important;
|
|
30
|
+
color: var(--color-neutral-100);
|
|
31
|
+
text-decoration: underline transparent;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.button__link:hover {
|
|
35
|
+
color: var(--color-primary);
|
|
36
|
+
text-decoration: underline 0.1rem var(--color-primary);
|
|
37
|
+
text-underline-offset: var(--spacing-8);
|
|
38
|
+
transition: var(--transition-color-cubic-bezier),
|
|
39
|
+
var(--transition-text-decoration-cubic-bezier);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.button__primary {
|
|
43
|
+
background-color: var(--color-secondary);
|
|
44
|
+
border: 3px solid var(--color-primary);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.button__primary:hover {
|
|
48
|
+
box-shadow: 0 4px 4px 0 var(--color-neutral-400);
|
|
49
|
+
transition: var(--transition-bg-cubic-bezier), var(--transition-box-shadow-cubic-bezier);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.button__secondary {
|
|
53
|
+
background-color: var(--color-neutral-900);
|
|
54
|
+
border: 3px solid var(--color-primary);
|
|
55
|
+
color: var(--color-neutral-100);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.button__secondary:hover {
|
|
59
|
+
background-color: var(--color-primary);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.button__icon {
|
|
63
|
+
background-color: unset;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.button__icon:hover {
|
|
67
|
+
box-shadow: unset;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.button__small {
|
|
71
|
+
padding: var(--spacing-4);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.button__medium {
|
|
75
|
+
padding: var(--spacing-8) var(--spacing-24);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.button__large {
|
|
79
|
+
padding: var(--spacing-16);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.input-group {
|
|
83
|
+
display: flex;
|
|
84
|
+
flex-direction: column;
|
|
85
|
+
align-items: flex-start;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.input {
|
|
89
|
+
border-radius: var(--spacing-8);
|
|
90
|
+
border: 2px solid var(--color-primary);
|
|
91
|
+
color: var(--color-black);
|
|
92
|
+
padding: var(--spacing-16) var(--spacing-24);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.input:hover {
|
|
96
|
+
border: 3px solid var(--color-primary-700);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.input:focus {
|
|
100
|
+
border: 3px solid var(--color-primary-700);
|
|
101
|
+
outline: none;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.input--error {
|
|
105
|
+
border: 3px solid var(--color-danger);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.error {
|
|
109
|
+
font-size: 12px;
|
|
110
|
+
color: var(--color-danger);
|
|
111
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
|
|
4
|
+
function Button({ children = "Click me", className = "", icon = undefined, isNewWindow = false, mode = "primary", size = "medium", as = "button", ...rest }) {
|
|
5
|
+
return as === "link" ? (jsxs("a", { ...(isNewWindow && { target: "_blank" }), className: clsx(className, "button", mode === "secondary" ? `button button__${mode}` : "button__link", `button__${size}`), ...rest, children: [children, icon] })) : (jsxs("button", { className: clsx(className, "button", `button__${mode}`, `button__${size}`), ...rest, children: [children, icon] }));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function Input({ className = "", classNameGroup = "", errorMessage = "", inputRef, styleGroup, ...rest }) {
|
|
9
|
+
return (jsxs("div", { className: `input-group ${classNameGroup}`, style: styleGroup, children: [jsx("input", { ref: inputRef, className: `input ${errorMessage ? "input--error" : ""} ${className}`, ...rest }), errorMessage && jsx("span", { className: "error", children: errorMessage })] }));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { Button, Input };
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@geoinsight/react-components",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "This library is the main UI component library for geoinsight",
|
|
5
|
+
"main": "dist/cjs/index.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"author": "Geoinsight",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "rollup -c rollup.config.js --bundleConfigAsCjs",
|
|
11
|
+
"storybook": "storybook dev -p 6006",
|
|
12
|
+
"build-storybook": "storybook build"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@types/react": "^18.0.27",
|
|
16
|
+
"clsx": "^1.2.1",
|
|
17
|
+
"react": "^18.2.0",
|
|
18
|
+
"react-dom": "^18.2.0",
|
|
19
|
+
"react-icons": "^4.7.1",
|
|
20
|
+
"typescript": "^4.9.4"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@babel/core": "^7.20.12",
|
|
24
|
+
"@babel/preset-env": "^7.21.4",
|
|
25
|
+
"@babel/preset-react": "^7.18.6",
|
|
26
|
+
"@babel/preset-typescript": "^7.21.4",
|
|
27
|
+
"@rollup/plugin-commonjs": "^24.0.1",
|
|
28
|
+
"@rollup/plugin-node-resolve": "^15.0.1",
|
|
29
|
+
"@rollup/plugin-typescript": "^11.0.0",
|
|
30
|
+
"@storybook/addon-actions": "^7.0.7",
|
|
31
|
+
"@storybook/addon-essentials": "^7.0.7",
|
|
32
|
+
"@storybook/addon-interactions": "^7.0.7",
|
|
33
|
+
"@storybook/addon-links": "^7.0.7",
|
|
34
|
+
"@storybook/addon-mdx-gfm": "^7.0.7",
|
|
35
|
+
"@storybook/react": "^7.0.7",
|
|
36
|
+
"@storybook/react-webpack5": "^7.0.7",
|
|
37
|
+
"@storybook/testing-library": "^0.1.0",
|
|
38
|
+
"babel-loader": "^8.3.0",
|
|
39
|
+
"rollup": "^3.12.0",
|
|
40
|
+
"rollup-plugin-import-css": "^3.1.0",
|
|
41
|
+
"storybook": "^7.0.7",
|
|
42
|
+
"tslib": "^2.5.0"
|
|
43
|
+
}
|
|
44
|
+
}
|
package/rollup.config.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// rollup.config.js
|
|
2
|
+
import resolve from "@rollup/plugin-node-resolve";
|
|
3
|
+
import commonjs from "@rollup/plugin-commonjs";
|
|
4
|
+
import typescript from "@rollup/plugin-typescript";
|
|
5
|
+
import pkg from "./package.json";
|
|
6
|
+
import css from "rollup-plugin-import-css";
|
|
7
|
+
|
|
8
|
+
export default [
|
|
9
|
+
{
|
|
10
|
+
input: "src/index.ts",
|
|
11
|
+
output: {
|
|
12
|
+
name: "mapinsight",
|
|
13
|
+
file: pkg.browser,
|
|
14
|
+
format: "umd",
|
|
15
|
+
},
|
|
16
|
+
plugins: [
|
|
17
|
+
resolve(),
|
|
18
|
+
commonjs(),
|
|
19
|
+
typescript({ tsconfig: "./tsconfig.json" }),
|
|
20
|
+
css()
|
|
21
|
+
],
|
|
22
|
+
external: ["react", "react-dom"]
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
// CommonJS (for Node) and ES module (for bundlers) build.
|
|
26
|
+
// (We could have three entries in the configuration array
|
|
27
|
+
// instead of two, but it's quicker to generate multiple
|
|
28
|
+
// builds from a single configuration where possible, using
|
|
29
|
+
// an array for the `output` option, where we can specify
|
|
30
|
+
// `file` and `format` for each target)
|
|
31
|
+
{
|
|
32
|
+
input: "src/index.ts",
|
|
33
|
+
output: [
|
|
34
|
+
{ file: pkg.main, format: "cjs" },
|
|
35
|
+
{ file: pkg.module, format: "es" },
|
|
36
|
+
],
|
|
37
|
+
plugins: [typescript({ tsconfig: "./tsconfig.json" }),
|
|
38
|
+
css()],
|
|
39
|
+
}
|
|
40
|
+
];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
.accordion {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
gap: var(--spacing-4)
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.accordion__title {
|
|
8
|
+
border-radius: var(--spacing-8);
|
|
9
|
+
background-color: var(--color-neutral-700);
|
|
10
|
+
color: var(--color-neutral-100);
|
|
11
|
+
justify-content: flex-end;
|
|
12
|
+
gap: 8px;
|
|
13
|
+
padding: var(--spacing-8) var(--spacing-8) var(--spacing-8) var(--spacing-16);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.accordion__menu {
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
gap: var(--spacing-4);
|
|
20
|
+
padding: 0 0 var(--spacing-8) var(--spacing-16);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.accordion__child {
|
|
24
|
+
border-radius: var(--spacing-8);
|
|
25
|
+
background-color: var(--color-neutral-200);
|
|
26
|
+
color: var(--color-neutral-900);
|
|
27
|
+
/* background: none !important; */
|
|
28
|
+
font-size: var(--font-size-14);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.accordion__child--active {
|
|
32
|
+
background-color: var(--color-neutral-500);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.accordion__check {
|
|
36
|
+
color: var(--color-neutral-500);
|
|
37
|
+
margin-right: calc(var(--spacing-24)*-1);
|
|
38
|
+
position: absolute;
|
|
39
|
+
right: 0;
|
|
40
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ComponentStory, ComponentMeta } from "@storybook/react";
|
|
2
|
+
import { Accordion } from "./index";
|
|
3
|
+
|
|
4
|
+
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
|
|
5
|
+
export default {
|
|
6
|
+
title: "Example/Accordion",
|
|
7
|
+
component: Accordion,
|
|
8
|
+
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes
|
|
9
|
+
argTypes: {
|
|
10
|
+
backgroundColor: { control: "color" },
|
|
11
|
+
},
|
|
12
|
+
} as ComponentMeta<typeof Accordion>;
|
|
13
|
+
|
|
14
|
+
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
|
|
15
|
+
const Template: ComponentStory<typeof Accordion> = (args) => (
|
|
16
|
+
<Accordion {...args} />
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export const Primary = Template.bind({});
|
|
20
|
+
// More on args: https://storybook.js.org/docs/react/writing-stories/args
|
|
21
|
+
Primary.args = {
|
|
22
|
+
menu: {
|
|
23
|
+
water: {
|
|
24
|
+
label: "Water",
|
|
25
|
+
isExpanded: true,
|
|
26
|
+
dataTheme: "water",
|
|
27
|
+
children: [
|
|
28
|
+
{
|
|
29
|
+
id: "water_1",
|
|
30
|
+
label: "Water 1",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "water_2",
|
|
34
|
+
label: "Water 1",
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
fire: {
|
|
39
|
+
label: "Fire",
|
|
40
|
+
dataTheme: "earth",
|
|
41
|
+
children: [
|
|
42
|
+
{
|
|
43
|
+
id: "fire_1",
|
|
44
|
+
label: "Fire 1",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: "fire_2",
|
|
48
|
+
label: "Fire 2",
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
defaultValue: "fire_1",
|
|
54
|
+
allExpanded: true
|
|
55
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import Button from "../button";
|
|
3
|
+
import "./index.css";
|
|
4
|
+
import { TfiAngleUp, TfiAngleDown } from "react-icons/tfi";
|
|
5
|
+
import { BsCheckLg } from "react-icons/bs";
|
|
6
|
+
import { Accordion as AccordionProps } from "./index.types";
|
|
7
|
+
|
|
8
|
+
export function Accordion({
|
|
9
|
+
menu,
|
|
10
|
+
allExpanded,
|
|
11
|
+
defaultValue,
|
|
12
|
+
selectValue,
|
|
13
|
+
}: AccordionProps) {
|
|
14
|
+
const [toggle, setToggle] = useState<{ [key: string]: boolean | undefined }>(
|
|
15
|
+
Object.fromEntries(
|
|
16
|
+
Object.entries(menu).map(([key, { isExpanded = false }]) => [
|
|
17
|
+
key,
|
|
18
|
+
allExpanded !== undefined ? allExpanded : isExpanded,
|
|
19
|
+
])
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
const [selected, setSelected] = useState<string>(defaultValue);
|
|
23
|
+
|
|
24
|
+
const handleToggle = (name: string) => {
|
|
25
|
+
setToggle((prev) => {
|
|
26
|
+
return { ...prev, [name]: !prev[name] };
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div className={"accordion"}>
|
|
32
|
+
{Object.keys(menu).map((item) => (
|
|
33
|
+
<>
|
|
34
|
+
<Button
|
|
35
|
+
className={"accordion__title"}
|
|
36
|
+
data-theme={menu[item].dataTheme}
|
|
37
|
+
icon={toggle[item] ? <TfiAngleDown /> : <TfiAngleUp />}
|
|
38
|
+
handleClick={() => handleToggle(item)}
|
|
39
|
+
>
|
|
40
|
+
{menu[item].label}
|
|
41
|
+
</Button>
|
|
42
|
+
{toggle[item] && (
|
|
43
|
+
<div className="accordion__menu">
|
|
44
|
+
{menu[item].children.map((child) => (
|
|
45
|
+
<Button
|
|
46
|
+
mode="secondary"
|
|
47
|
+
data-theme={menu[item].dataTheme}
|
|
48
|
+
className={`accordion__child ${
|
|
49
|
+
child.id === selected &&
|
|
50
|
+
` accordion__child--active`
|
|
51
|
+
}`}
|
|
52
|
+
handleClick={() => {
|
|
53
|
+
setSelected(child.id);
|
|
54
|
+
selectValue && selectValue(item, child);
|
|
55
|
+
}}
|
|
56
|
+
>
|
|
57
|
+
<>
|
|
58
|
+
{child.label}
|
|
59
|
+
{child.id === selected ? (
|
|
60
|
+
<BsCheckLg
|
|
61
|
+
className={"accordion__check"}
|
|
62
|
+
size={"1rem"}
|
|
63
|
+
/>
|
|
64
|
+
) : (
|
|
65
|
+
""
|
|
66
|
+
)}
|
|
67
|
+
</>
|
|
68
|
+
</Button>
|
|
69
|
+
))}
|
|
70
|
+
</div>
|
|
71
|
+
)}
|
|
72
|
+
</>
|
|
73
|
+
))}
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export default Accordion;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {dataTheme} from "data-theme";
|
|
2
|
+
|
|
3
|
+
export interface Accordion {
|
|
4
|
+
/**
|
|
5
|
+
* What to put inside the menu
|
|
6
|
+
*/
|
|
7
|
+
menu: layers;
|
|
8
|
+
/**
|
|
9
|
+
* Default value that is chosen. Must use on the of the children ids on the menu prop.
|
|
10
|
+
*/
|
|
11
|
+
defaultValue: string;
|
|
12
|
+
/**
|
|
13
|
+
* Callback function for extra leg work outside the component. It takes two arguments:
|
|
14
|
+
* - item - parent ID.
|
|
15
|
+
* - object with the child ID and label.
|
|
16
|
+
*/
|
|
17
|
+
selectValue?: (
|
|
18
|
+
parentId: string,
|
|
19
|
+
child: {
|
|
20
|
+
id: string;
|
|
21
|
+
label: string;
|
|
22
|
+
// field: string;
|
|
23
|
+
// tempValue: number;
|
|
24
|
+
// description: (value: number | string | undefined) => string;
|
|
25
|
+
// style: any;
|
|
26
|
+
}
|
|
27
|
+
) => void;
|
|
28
|
+
|
|
29
|
+
allExpanded?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface layer {
|
|
33
|
+
id: string;
|
|
34
|
+
label: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface layers {
|
|
38
|
+
[key: string]: {
|
|
39
|
+
label: string;
|
|
40
|
+
isExpanded?: boolean;
|
|
41
|
+
dataTheme?: dataTheme;
|
|
42
|
+
children: layer[];
|
|
43
|
+
};
|
|
44
|
+
}
|