@geoinsight/react-components 0.3.6 → 0.4.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.
@@ -114,6 +114,102 @@
114
114
  --color-primary-800: #2c5f1c;
115
115
  --color-primary-900: #1e3f12;
116
116
  }
117
+ .accordion {
118
+ display: flex;
119
+ flex-direction: column;
120
+ gap: var(--spacing-4);
121
+ }
122
+
123
+ .accordion-item {
124
+ display: flex;
125
+ flex-direction: column;
126
+ gap: var(--spacing-4);
127
+ }
128
+
129
+ .accordion-button.button {
130
+ border: unset;
131
+ border-radius: var(--spacing-8);
132
+ color: var(--color-neutral-900);
133
+ justify-content: flex-end;
134
+ }
135
+
136
+ .accordion-button__button.button {
137
+ gap: 8px;
138
+ padding: var(--spacing-8) var(--spacing-8) var(--spacing-8) var(--spacing-16);
139
+ }
140
+
141
+ .accordion-button__link.button {
142
+ padding: var(--spacing-4) var(--spacing-32) var(--spacing-4) var(--spacing-16);
143
+ }
144
+
145
+ .accordion-button__link.button:hover {
146
+ background-color: var(--color-primary) !important;
147
+ box-shadow: 0 4px 4px 0 var(--color-neutral-400);
148
+ transition: var(--transition-bg-cubic-bezier), var(--transition-box-shadow-cubic-bezier);
149
+ color: var(--color-neutral-900);
150
+ text-decoration: unset;
151
+ text-underline-offset: unset;
152
+ }
153
+
154
+ .accordion-button__button--dark.button {
155
+ background-color: var(--color-neutral-200);
156
+ }
157
+
158
+ .accordion-button__button--light.button {
159
+ background-color: var(--color-neutral-800);
160
+ }
161
+
162
+ .accordion-button__link--dark.button {
163
+ background-color: var(--color-neutral-100) !important;
164
+ }
165
+
166
+ .accordion-button__link--light.button {
167
+ background-color: var(--color-neutral-700) !important;
168
+ }
169
+
170
+ .accordion-content {
171
+ border-radius: var(--spacing-8);
172
+ /* color: var(--color-neutral-100); */
173
+ display: flex;
174
+ flex-direction: column;
175
+ gap: var(--spacing-4);
176
+ padding: 0 0 var(--spacing-8) var(--spacing-16);
177
+ }
178
+
179
+ /* .accordion__title {
180
+ border-radius: var(--spacing-8);
181
+ background-color: var(--color-neutral-700);
182
+ color: var(--color-neutral-100);
183
+ justify-content: flex-end;
184
+ gap: 8px;
185
+ padding: var(--spacing-8) var(--spacing-8) var(--spacing-8) var(--spacing-16);
186
+ }
187
+
188
+ .accordion__menu {
189
+ display: flex;
190
+ flex-direction: column;
191
+ gap: var(--spacing-4);
192
+ padding: 0 0 var(--spacing-8) var(--spacing-16);
193
+ } */
194
+ /*
195
+ .accordion__child {
196
+ border-radius: var(--spacing-8);
197
+ background-color: var(--color-neutral-200);
198
+ color: var(--color-neutral-900);
199
+ font-size: var(--font-size-14);
200
+ }
201
+
202
+ .accordion__child--active {
203
+ background-color: var(--color-neutral-500);
204
+ } */
205
+ /*
206
+ .accordion__check {
207
+ color: var(--color-neutral-500);
208
+ margin-right: calc(var(--spacing-24) * -1);
209
+ position: absolute;
210
+ right: 0;
211
+ } */
212
+
117
213
  .button {
118
214
  align-items: center;
119
215
  border-radius: var(--spacing-32);
@@ -195,47 +291,6 @@
195
291
  padding: var(--spacing-16);
196
292
  }
197
293
 
198
- .accordion {
199
- display: flex;
200
- flex-direction: column;
201
- gap: var(--spacing-4)
202
- }
203
-
204
- .accordion__title {
205
- border-radius: var(--spacing-8);
206
- background-color: var(--color-neutral-700);
207
- color: var(--color-neutral-100);
208
- justify-content: flex-end;
209
- gap: 8px;
210
- padding: var(--spacing-8) var(--spacing-8) var(--spacing-8) var(--spacing-16);
211
- }
212
-
213
- .accordion__menu {
214
- display: flex;
215
- flex-direction: column;
216
- gap: var(--spacing-4);
217
- padding: 0 0 var(--spacing-8) var(--spacing-16);
218
- }
219
-
220
- .accordion__child {
221
- border-radius: var(--spacing-8);
222
- background-color: var(--color-neutral-200);
223
- color: var(--color-neutral-900);
224
- /* background: none !important; */
225
- font-size: var(--font-size-14);
226
- }
227
-
228
- .accordion__child--active {
229
- background-color: var(--color-neutral-500);
230
- }
231
-
232
- .accordion__check {
233
- color: var(--color-neutral-500);
234
- margin-right: calc(var(--spacing-24)*-1);
235
- position: absolute;
236
- right: 0;
237
- }
238
-
239
294
  .input-group {
240
295
  display: flex;
241
296
  flex-direction: column;
package/dist/cjs/index.js CHANGED
@@ -4,62 +4,92 @@ var jsxRuntime = require('react/jsx-runtime');
4
4
  var react = require('react');
5
5
  var clsx = require('clsx');
6
6
  var tfi = require('react-icons/tfi');
7
- var bs = require('react-icons/bs');
8
7
  var tb = require('react-icons/tb');
9
8
  var io5 = require('react-icons/io5');
10
9
 
11
- const Anchor = ({ Custom, children, ...rest }) => Custom ? jsxRuntime.jsx(Custom, { ...rest, children: children }) : jsxRuntime.jsx("a", { ...rest, children: children });
12
- function Button({ children = "Click me", className = "", icon = undefined, isNewWindow = false, mode = "primary", size = "medium", as = "button", CustomAnchor, ...rest }) {
13
- return as === "link" ? (jsxRuntime.jsxs(Anchor, { Custom: CustomAnchor, ...(isNewWindow && { target: "_blank" }), className: clsx("button", mode === "secondary" ? `button button__${mode}` : "button__link", `button__${size}`, className), ...rest, children: [children, icon] })) : (jsxRuntime.jsxs("button", { className: clsx("button", `button__${mode}`, `button__${size}`, className), ...rest, children: [children, icon] }));
14
- }
15
-
16
- function Accordion({ menu, allExpanded, defaultValue, selectValue, }) {
17
- const [toggle, setToggle] = react.useState(Object.fromEntries(Object.entries(menu).map(([key, { isExpanded = false }]) => [
18
- key,
19
- allExpanded !== undefined ? allExpanded : isExpanded,
20
- ])));
21
- const [selected, setSelected] = react.useState(defaultValue);
22
- const handleToggle = (name) => {
23
- setToggle((prev) => {
24
- return { ...prev, [name]: !prev[name] };
25
- });
26
- };
27
- return (jsxRuntime.jsx("div", { className: "accordion", children: Object.keys(menu).map((item) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Button, { className: "accordion__title", "data-theme": menu[item].dataTheme, icon: toggle[item] ? jsxRuntime.jsx(tfi.TfiAngleDown, {}) : jsxRuntime.jsx(tfi.TfiAngleUp, {}), onClick: () => handleToggle(item), children: menu[item].label }), toggle[item] && (jsxRuntime.jsx("div", { className: "accordion__menu", children: menu[item].children.map((child) => (jsxRuntime.jsx(Button, { mode: "secondary", "data-theme": menu[item].dataTheme, className: `accordion__child ${child.id === selected &&
28
- ` accordion__child--active`}`, onClick: () => {
29
- setSelected(child.id);
30
- selectValue && selectValue(item, child);
31
- }, children: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [child.label, child.id === selected ? (jsxRuntime.jsx(bs.BsCheckLg, { className: "accordion__check", size: "1rem" })) : ("")] }) }))) }))] }))) }));
32
- }
33
-
34
- function Input({ className = "", classNameGroup = "", errorMessage = "", inputRef, styleGroup, ...rest }) {
35
- 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 })] }));
10
+ function recursiveChildren(children, i = 0) {
11
+ return react.Children.map(children, (child, index) => {
12
+ if (!react.isValidElement(child)) {
13
+ return child;
14
+ }
15
+ if (child.props.children) {
16
+ return react.cloneElement(child, {
17
+ ...child.props,
18
+ children: recursiveChildren(child.props.children, i++),
19
+ ...(child?.type?.displayName === "AccordionItem" && {
20
+ label: `${child?.type?.displayName}-${index}-${i}`,
21
+ }),
22
+ });
23
+ }
24
+ });
36
25
  }
37
-
38
- function TextArea({ className = "", disabled = true, hasToggleButton = true, hideHeight = "5rem", placeholder = "", showHeight = "10rem", style = {}, textareaClassName = "", ...rest }) {
39
- const ref = react.useRef();
40
- const [isShow, setIsShow] = react.useState(false);
41
- const handleClickToggle = () => {
42
- if (ref && ref.current) {
43
- if (isShow) {
44
- ref.current.style.height = hideHeight;
26
+ function recursiveToggle(children, toggleArray = {}, i = 0, props) {
27
+ if ((children && typeof children === "string") ||
28
+ (Array.isArray(children) && typeof children[0] === "string")) {
29
+ return;
30
+ }
31
+ for (const child of children) {
32
+ if (react.isValidElement(child)) {
33
+ if (child?.type?.displayName === "AccordionItem" && child.props.label) {
34
+ toggleArray[child.props.label] = {
35
+ isToggle: props.expanded === "all"
36
+ ? true
37
+ : props.expanded === "none"
38
+ ? false
39
+ : props.expanded === "custom"
40
+ ? child?.props.isExpanded
41
+ : false,
42
+ depth: i,
43
+ paddingLeft: `${16 * i}px`,
44
+ };
45
45
  }
46
- else {
47
- ref.current.style.height = showHeight; //(48 + ref.current.scrollHeight) + 'px';
46
+ if (typeof child.props.children !== "string" &&
47
+ child.props.children.find((v) => v?.type?.displayName === "AccordionItem")) {
48
+ recursiveToggle(Array.isArray(child.props.children)
49
+ ? child.props.children
50
+ : [child.props.children], toggleArray, i + 1, props);
48
51
  }
49
- setIsShow((prev) => !prev);
50
52
  }
51
- };
52
- return (jsxRuntime.jsxs("div", { className: clsx("textarea", className), style: style, children: [jsxRuntime.jsx("textarea", { ref: ref, className: clsx("textarea__input", textareaClassName), style: {
53
- height: hasToggleButton ? hideHeight : showHeight,
54
- }, placeholder: placeholder, disabled: disabled, ...rest }), hasToggleButton && (jsxRuntime.jsx("button", { className: clsx("textarea__button", isShow && "textarea__button--show"), onClick: handleClickToggle, disabled: disabled, children: jsxRuntime.jsx(tb.TbArrowsDiagonal2, { size: "1.5rem" }) }))] }));
53
+ }
54
+ return toggleArray;
55
55
  }
56
56
 
57
- function Modal({ modalref, children, title, subtitle, footer, hasCloseButton = true, handleClose, }) {
58
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "modal-overlay" }), jsxRuntime.jsxs("div", { ref: modalref, className: "modal", children: [hasCloseButton && (jsxRuntime.jsx(Button, { mode: "secondary", className: "modal__close", size: "small", onClick: handleClose, children: jsxRuntime.jsx(io5.IoClose, {}) })), jsxRuntime.jsxs("div", { className: "modal__content", children: [title && (jsxRuntime.jsxs("div", { className: "modal__header", children: [jsxRuntime.jsx("h3", { children: title }), jsxRuntime.jsx("h6", { children: subtitle })] })), jsxRuntime.jsx("div", { className: "modal__children", children: children }), footer && jsxRuntime.jsx("div", { className: "modal__footer", children: footer })] })] })] }));
57
+ const AccordionContext = react.createContext(undefined);
58
+ const AccordionProvider = ({ children, expanded = "all" }) => {
59
+ const newChildren = react.useMemo(() => recursiveChildren(children, 0), []);
60
+ const [toggle, setToggle] = react.useState(recursiveToggle(newChildren, {}, 0, { expanded }));
61
+ return (jsxRuntime.jsx(AccordionContext.Provider, { value: { toggle, setToggle }, children: jsxRuntime.jsx("div", { className: "accordion", children: newChildren }) }));
62
+ };
63
+ const useAccordion = () => {
64
+ const context = react.useContext(AccordionContext);
65
+ if (context === undefined) {
66
+ throw new Error("useTheme must be used within a ThemeProvider");
67
+ }
68
+ return context;
69
+ };
70
+
71
+ function Accordion({ children, expanded = "all", defaultValue, selectValue, }) {
72
+ // const { dataTheme } = useTheme();
73
+ return (jsxRuntime.jsx(AccordionProvider, { expanded: expanded, children: children }));
59
74
  }
60
75
 
61
- function Loading({ img, children }) {
62
- return (jsxRuntime.jsxs("div", { className: "loading", children: [jsxRuntime.jsx("img", { src: img ? img : "../../stories/assets/loading.gif" }), children] }));
76
+ const AccordionItem = react.forwardRef(function AccordionItem({ children, label, isExpanded = false }, ref) {
77
+ const { toggle, setToggle } = useAccordion();
78
+ return (jsxRuntime.jsx("div", { className: "accordion-item", style: {
79
+ paddingLeft: toggle && label && toggle[label].paddingLeft,
80
+ }, children: react.Children.map(children, (child) => react.cloneElement(child, {
81
+ toggle: toggle,
82
+ setToggle: setToggle,
83
+ ...(child?.type?.displayName !== "AccordionItem" && {
84
+ label: label,
85
+ }),
86
+ isExpanded: isExpanded,
87
+ })) }));
88
+ });
89
+
90
+ const Anchor = ({ Custom, children, ...rest }) => Custom ? jsxRuntime.jsx(Custom, { ...rest, children: children }) : jsxRuntime.jsx("a", { ...rest, children: children });
91
+ function Button({ children = "Click me", className = "", icon = undefined, isNewWindow = false, mode = "primary", size = "medium", as = "button", CustomAnchor, ...rest }) {
92
+ return as === "link" ? (jsxRuntime.jsxs(Anchor, { Custom: CustomAnchor, ...(isNewWindow && { target: "_blank" }), className: clsx(`button ${className}`, mode === "secondary" ? `button button__${mode}` : "button__link", `button__${size}`), ...rest, children: [children, icon] })) : (jsxRuntime.jsxs("button", { className: clsx("button", `button__${mode}`, `button__${size}`, className), ...rest, children: [children, icon] }));
63
93
  }
64
94
 
65
95
  const ThemeContext = react.createContext(undefined);
@@ -110,6 +140,64 @@ function useTheme({ dataTheme = undefined, paletteTheme = "water", } = {}) {
110
140
  return context;
111
141
  }
112
142
 
143
+ const AccordionButton = react.forwardRef(function AccordionButton({ children, is = "link", label, toggle, setToggle, ...rest }, ref) {
144
+ const { dataTheme } = useTheme();
145
+ const handleToggle = () => {
146
+ setToggle((prev) => {
147
+ if (label) {
148
+ return {
149
+ ...prev,
150
+ [label]: {
151
+ ...(prev && label && prev[label]),
152
+ isToggle: prev && !prev[label].isToggle,
153
+ },
154
+ };
155
+ }
156
+ else {
157
+ return prev;
158
+ }
159
+ });
160
+ };
161
+ return (jsxRuntime.jsx(Button, { as: is, className: clsx("accordion-button", `accordion-button__${is}`, `accordion-button__${is}--${dataTheme}`), ...(is !== "link" && {
162
+ icon: label && toggle && toggle[label].isToggle ? (jsxRuntime.jsx(tfi.TfiAngleDown, {})) : (jsxRuntime.jsx(tfi.TfiAngleUp, {})),
163
+ }), ...(is !== "link" && { onClick: handleToggle }), ...rest, children: children }));
164
+ });
165
+
166
+ const AccordionContent = react.forwardRef(function AccordionContent({ children, label, toggle, }, ref) {
167
+ return label && toggle && toggle[label].isToggle && jsxRuntime.jsx("div", { className: "accordion-content", children: children });
168
+ });
169
+
170
+ function Input({ className = "", classNameGroup = "", errorMessage = "", inputRef, styleGroup, ...rest }) {
171
+ 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 })] }));
172
+ }
173
+
174
+ function TextArea({ className = "", disabled = true, hasToggleButton = true, hideHeight = "5rem", placeholder = "", showHeight = "10rem", style = {}, textareaClassName = "", ...rest }) {
175
+ const ref = react.useRef();
176
+ const [isShow, setIsShow] = react.useState(false);
177
+ const handleClickToggle = () => {
178
+ if (ref && ref.current) {
179
+ if (isShow) {
180
+ ref.current.style.height = hideHeight;
181
+ }
182
+ else {
183
+ ref.current.style.height = showHeight; //(48 + ref.current.scrollHeight) + 'px';
184
+ }
185
+ setIsShow((prev) => !prev);
186
+ }
187
+ };
188
+ return (jsxRuntime.jsxs("div", { className: clsx("textarea", className), style: style, children: [jsxRuntime.jsx("textarea", { ref: ref, className: clsx("textarea__input", textareaClassName), style: {
189
+ height: hasToggleButton ? hideHeight : showHeight,
190
+ }, placeholder: placeholder, disabled: disabled, ...rest }), hasToggleButton && (jsxRuntime.jsx("button", { className: clsx("textarea__button", isShow && "textarea__button--show"), onClick: handleClickToggle, disabled: disabled, children: jsxRuntime.jsx(tb.TbArrowsDiagonal2, { size: "1.5rem" }) }))] }));
191
+ }
192
+
193
+ function Modal({ modalref, children, title, subtitle, footer, hasCloseButton = true, handleClose, }) {
194
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "modal-overlay" }), jsxRuntime.jsxs("div", { ref: modalref, className: "modal", children: [hasCloseButton && (jsxRuntime.jsx(Button, { mode: "secondary", className: "modal__close", size: "small", onClick: handleClose, children: jsxRuntime.jsx(io5.IoClose, {}) })), jsxRuntime.jsxs("div", { className: "modal__content", children: [title && (jsxRuntime.jsxs("div", { className: "modal__header", children: [jsxRuntime.jsx("h3", { children: title }), jsxRuntime.jsx("h6", { children: subtitle })] })), jsxRuntime.jsx("div", { className: "modal__children", children: children }), footer && jsxRuntime.jsx("div", { className: "modal__footer", children: footer })] })] })] }));
195
+ }
196
+
197
+ function Loading({ img, children }) {
198
+ return (jsxRuntime.jsxs("div", { className: "loading", children: [jsxRuntime.jsx("img", { src: img ? img : "../../stories/assets/loading.gif" }), children] }));
199
+ }
200
+
113
201
  const LoadingContext = react.createContext(undefined);
114
202
  function loadingReducer(state, action) {
115
203
  switch (action.type) {
@@ -232,6 +320,9 @@ function useModal({} = {}) {
232
320
  }
233
321
 
234
322
  exports.Accordion = Accordion;
323
+ exports.AccordionButton = AccordionButton;
324
+ exports.AccordionContent = AccordionContent;
325
+ exports.AccordionItem = AccordionItem;
235
326
  exports.Button = Button;
236
327
  exports.Input = Input;
237
328
  exports.Loading = Loading;
@@ -114,6 +114,102 @@
114
114
  --color-primary-800: #2c5f1c;
115
115
  --color-primary-900: #1e3f12;
116
116
  }
117
+ .accordion {
118
+ display: flex;
119
+ flex-direction: column;
120
+ gap: var(--spacing-4);
121
+ }
122
+
123
+ .accordion-item {
124
+ display: flex;
125
+ flex-direction: column;
126
+ gap: var(--spacing-4);
127
+ }
128
+
129
+ .accordion-button.button {
130
+ border: unset;
131
+ border-radius: var(--spacing-8);
132
+ color: var(--color-neutral-900);
133
+ justify-content: flex-end;
134
+ }
135
+
136
+ .accordion-button__button.button {
137
+ gap: 8px;
138
+ padding: var(--spacing-8) var(--spacing-8) var(--spacing-8) var(--spacing-16);
139
+ }
140
+
141
+ .accordion-button__link.button {
142
+ padding: var(--spacing-4) var(--spacing-32) var(--spacing-4) var(--spacing-16);
143
+ }
144
+
145
+ .accordion-button__link.button:hover {
146
+ background-color: var(--color-primary) !important;
147
+ box-shadow: 0 4px 4px 0 var(--color-neutral-400);
148
+ transition: var(--transition-bg-cubic-bezier), var(--transition-box-shadow-cubic-bezier);
149
+ color: var(--color-neutral-900);
150
+ text-decoration: unset;
151
+ text-underline-offset: unset;
152
+ }
153
+
154
+ .accordion-button__button--dark.button {
155
+ background-color: var(--color-neutral-200);
156
+ }
157
+
158
+ .accordion-button__button--light.button {
159
+ background-color: var(--color-neutral-800);
160
+ }
161
+
162
+ .accordion-button__link--dark.button {
163
+ background-color: var(--color-neutral-100) !important;
164
+ }
165
+
166
+ .accordion-button__link--light.button {
167
+ background-color: var(--color-neutral-700) !important;
168
+ }
169
+
170
+ .accordion-content {
171
+ border-radius: var(--spacing-8);
172
+ /* color: var(--color-neutral-100); */
173
+ display: flex;
174
+ flex-direction: column;
175
+ gap: var(--spacing-4);
176
+ padding: 0 0 var(--spacing-8) var(--spacing-16);
177
+ }
178
+
179
+ /* .accordion__title {
180
+ border-radius: var(--spacing-8);
181
+ background-color: var(--color-neutral-700);
182
+ color: var(--color-neutral-100);
183
+ justify-content: flex-end;
184
+ gap: 8px;
185
+ padding: var(--spacing-8) var(--spacing-8) var(--spacing-8) var(--spacing-16);
186
+ }
187
+
188
+ .accordion__menu {
189
+ display: flex;
190
+ flex-direction: column;
191
+ gap: var(--spacing-4);
192
+ padding: 0 0 var(--spacing-8) var(--spacing-16);
193
+ } */
194
+ /*
195
+ .accordion__child {
196
+ border-radius: var(--spacing-8);
197
+ background-color: var(--color-neutral-200);
198
+ color: var(--color-neutral-900);
199
+ font-size: var(--font-size-14);
200
+ }
201
+
202
+ .accordion__child--active {
203
+ background-color: var(--color-neutral-500);
204
+ } */
205
+ /*
206
+ .accordion__check {
207
+ color: var(--color-neutral-500);
208
+ margin-right: calc(var(--spacing-24) * -1);
209
+ position: absolute;
210
+ right: 0;
211
+ } */
212
+
117
213
  .button {
118
214
  align-items: center;
119
215
  border-radius: var(--spacing-32);
@@ -195,47 +291,6 @@
195
291
  padding: var(--spacing-16);
196
292
  }
197
293
 
198
- .accordion {
199
- display: flex;
200
- flex-direction: column;
201
- gap: var(--spacing-4)
202
- }
203
-
204
- .accordion__title {
205
- border-radius: var(--spacing-8);
206
- background-color: var(--color-neutral-700);
207
- color: var(--color-neutral-100);
208
- justify-content: flex-end;
209
- gap: 8px;
210
- padding: var(--spacing-8) var(--spacing-8) var(--spacing-8) var(--spacing-16);
211
- }
212
-
213
- .accordion__menu {
214
- display: flex;
215
- flex-direction: column;
216
- gap: var(--spacing-4);
217
- padding: 0 0 var(--spacing-8) var(--spacing-16);
218
- }
219
-
220
- .accordion__child {
221
- border-radius: var(--spacing-8);
222
- background-color: var(--color-neutral-200);
223
- color: var(--color-neutral-900);
224
- /* background: none !important; */
225
- font-size: var(--font-size-14);
226
- }
227
-
228
- .accordion__child--active {
229
- background-color: var(--color-neutral-500);
230
- }
231
-
232
- .accordion__check {
233
- color: var(--color-neutral-500);
234
- margin-right: calc(var(--spacing-24)*-1);
235
- position: absolute;
236
- right: 0;
237
- }
238
-
239
294
  .input-group {
240
295
  display: flex;
241
296
  flex-direction: column;
package/dist/esm/index.js CHANGED
@@ -1,63 +1,93 @@
1
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { useState, useRef, createContext, useEffect, useContext, useReducer } from 'react';
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { Children, isValidElement, cloneElement, createContext, useContext, useMemo, useState, forwardRef, useEffect, useRef, useReducer } from 'react';
3
3
  import clsx from 'clsx';
4
4
  import { TfiAngleDown, TfiAngleUp } from 'react-icons/tfi';
5
- import { BsCheckLg } from 'react-icons/bs';
6
5
  import { TbArrowsDiagonal2 } from 'react-icons/tb';
7
6
  import { IoClose } from 'react-icons/io5';
8
7
 
9
- const Anchor = ({ Custom, children, ...rest }) => Custom ? jsx(Custom, { ...rest, children: children }) : jsx("a", { ...rest, children: children });
10
- function Button({ children = "Click me", className = "", icon = undefined, isNewWindow = false, mode = "primary", size = "medium", as = "button", CustomAnchor, ...rest }) {
11
- return as === "link" ? (jsxs(Anchor, { Custom: CustomAnchor, ...(isNewWindow && { target: "_blank" }), className: clsx("button", mode === "secondary" ? `button button__${mode}` : "button__link", `button__${size}`, className), ...rest, children: [children, icon] })) : (jsxs("button", { className: clsx("button", `button__${mode}`, `button__${size}`, className), ...rest, children: [children, icon] }));
12
- }
13
-
14
- function Accordion({ menu, allExpanded, defaultValue, selectValue, }) {
15
- const [toggle, setToggle] = useState(Object.fromEntries(Object.entries(menu).map(([key, { isExpanded = false }]) => [
16
- key,
17
- allExpanded !== undefined ? allExpanded : isExpanded,
18
- ])));
19
- const [selected, setSelected] = useState(defaultValue);
20
- const handleToggle = (name) => {
21
- setToggle((prev) => {
22
- return { ...prev, [name]: !prev[name] };
23
- });
24
- };
25
- return (jsx("div", { className: "accordion", children: Object.keys(menu).map((item) => (jsxs(Fragment, { children: [jsx(Button, { className: "accordion__title", "data-theme": menu[item].dataTheme, icon: toggle[item] ? jsx(TfiAngleDown, {}) : jsx(TfiAngleUp, {}), onClick: () => handleToggle(item), children: menu[item].label }), toggle[item] && (jsx("div", { className: "accordion__menu", children: menu[item].children.map((child) => (jsx(Button, { mode: "secondary", "data-theme": menu[item].dataTheme, className: `accordion__child ${child.id === selected &&
26
- ` accordion__child--active`}`, onClick: () => {
27
- setSelected(child.id);
28
- selectValue && selectValue(item, child);
29
- }, children: jsxs(Fragment, { children: [child.label, child.id === selected ? (jsx(BsCheckLg, { className: "accordion__check", size: "1rem" })) : ("")] }) }))) }))] }))) }));
30
- }
31
-
32
- function Input({ className = "", classNameGroup = "", errorMessage = "", inputRef, styleGroup, ...rest }) {
33
- 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 })] }));
8
+ function recursiveChildren(children, i = 0) {
9
+ return Children.map(children, (child, index) => {
10
+ if (!isValidElement(child)) {
11
+ return child;
12
+ }
13
+ if (child.props.children) {
14
+ return cloneElement(child, {
15
+ ...child.props,
16
+ children: recursiveChildren(child.props.children, i++),
17
+ ...(child?.type?.displayName === "AccordionItem" && {
18
+ label: `${child?.type?.displayName}-${index}-${i}`,
19
+ }),
20
+ });
21
+ }
22
+ });
34
23
  }
35
-
36
- function TextArea({ className = "", disabled = true, hasToggleButton = true, hideHeight = "5rem", placeholder = "", showHeight = "10rem", style = {}, textareaClassName = "", ...rest }) {
37
- const ref = useRef();
38
- const [isShow, setIsShow] = useState(false);
39
- const handleClickToggle = () => {
40
- if (ref && ref.current) {
41
- if (isShow) {
42
- ref.current.style.height = hideHeight;
24
+ function recursiveToggle(children, toggleArray = {}, i = 0, props) {
25
+ if ((children && typeof children === "string") ||
26
+ (Array.isArray(children) && typeof children[0] === "string")) {
27
+ return;
28
+ }
29
+ for (const child of children) {
30
+ if (isValidElement(child)) {
31
+ if (child?.type?.displayName === "AccordionItem" && child.props.label) {
32
+ toggleArray[child.props.label] = {
33
+ isToggle: props.expanded === "all"
34
+ ? true
35
+ : props.expanded === "none"
36
+ ? false
37
+ : props.expanded === "custom"
38
+ ? child?.props.isExpanded
39
+ : false,
40
+ depth: i,
41
+ paddingLeft: `${16 * i}px`,
42
+ };
43
43
  }
44
- else {
45
- ref.current.style.height = showHeight; //(48 + ref.current.scrollHeight) + 'px';
44
+ if (typeof child.props.children !== "string" &&
45
+ child.props.children.find((v) => v?.type?.displayName === "AccordionItem")) {
46
+ recursiveToggle(Array.isArray(child.props.children)
47
+ ? child.props.children
48
+ : [child.props.children], toggleArray, i + 1, props);
46
49
  }
47
- setIsShow((prev) => !prev);
48
50
  }
49
- };
50
- return (jsxs("div", { className: clsx("textarea", className), style: style, children: [jsx("textarea", { ref: ref, className: clsx("textarea__input", textareaClassName), style: {
51
- height: hasToggleButton ? hideHeight : showHeight,
52
- }, placeholder: placeholder, disabled: disabled, ...rest }), hasToggleButton && (jsx("button", { className: clsx("textarea__button", isShow && "textarea__button--show"), onClick: handleClickToggle, disabled: disabled, children: jsx(TbArrowsDiagonal2, { size: "1.5rem" }) }))] }));
51
+ }
52
+ return toggleArray;
53
53
  }
54
54
 
55
- function Modal({ modalref, children, title, subtitle, footer, hasCloseButton = true, handleClose, }) {
56
- return (jsxs(Fragment, { children: [jsx("div", { className: "modal-overlay" }), jsxs("div", { ref: modalref, className: "modal", children: [hasCloseButton && (jsx(Button, { mode: "secondary", className: "modal__close", size: "small", onClick: handleClose, children: jsx(IoClose, {}) })), jsxs("div", { className: "modal__content", children: [title && (jsxs("div", { className: "modal__header", children: [jsx("h3", { children: title }), jsx("h6", { children: subtitle })] })), jsx("div", { className: "modal__children", children: children }), footer && jsx("div", { className: "modal__footer", children: footer })] })] })] }));
55
+ const AccordionContext = createContext(undefined);
56
+ const AccordionProvider = ({ children, expanded = "all" }) => {
57
+ const newChildren = useMemo(() => recursiveChildren(children, 0), []);
58
+ const [toggle, setToggle] = useState(recursiveToggle(newChildren, {}, 0, { expanded }));
59
+ return (jsx(AccordionContext.Provider, { value: { toggle, setToggle }, children: jsx("div", { className: "accordion", children: newChildren }) }));
60
+ };
61
+ const useAccordion = () => {
62
+ const context = useContext(AccordionContext);
63
+ if (context === undefined) {
64
+ throw new Error("useTheme must be used within a ThemeProvider");
65
+ }
66
+ return context;
67
+ };
68
+
69
+ function Accordion({ children, expanded = "all", defaultValue, selectValue, }) {
70
+ // const { dataTheme } = useTheme();
71
+ return (jsx(AccordionProvider, { expanded: expanded, children: children }));
57
72
  }
58
73
 
59
- function Loading({ img, children }) {
60
- return (jsxs("div", { className: "loading", children: [jsx("img", { src: img ? img : "../../stories/assets/loading.gif" }), children] }));
74
+ const AccordionItem = forwardRef(function AccordionItem({ children, label, isExpanded = false }, ref) {
75
+ const { toggle, setToggle } = useAccordion();
76
+ return (jsx("div", { className: "accordion-item", style: {
77
+ paddingLeft: toggle && label && toggle[label].paddingLeft,
78
+ }, children: Children.map(children, (child) => cloneElement(child, {
79
+ toggle: toggle,
80
+ setToggle: setToggle,
81
+ ...(child?.type?.displayName !== "AccordionItem" && {
82
+ label: label,
83
+ }),
84
+ isExpanded: isExpanded,
85
+ })) }));
86
+ });
87
+
88
+ const Anchor = ({ Custom, children, ...rest }) => Custom ? jsx(Custom, { ...rest, children: children }) : jsx("a", { ...rest, children: children });
89
+ function Button({ children = "Click me", className = "", icon = undefined, isNewWindow = false, mode = "primary", size = "medium", as = "button", CustomAnchor, ...rest }) {
90
+ return as === "link" ? (jsxs(Anchor, { Custom: CustomAnchor, ...(isNewWindow && { target: "_blank" }), className: clsx(`button ${className}`, mode === "secondary" ? `button button__${mode}` : "button__link", `button__${size}`), ...rest, children: [children, icon] })) : (jsxs("button", { className: clsx("button", `button__${mode}`, `button__${size}`, className), ...rest, children: [children, icon] }));
61
91
  }
62
92
 
63
93
  const ThemeContext = createContext(undefined);
@@ -108,6 +138,64 @@ function useTheme({ dataTheme = undefined, paletteTheme = "water", } = {}) {
108
138
  return context;
109
139
  }
110
140
 
141
+ const AccordionButton = forwardRef(function AccordionButton({ children, is = "link", label, toggle, setToggle, ...rest }, ref) {
142
+ const { dataTheme } = useTheme();
143
+ const handleToggle = () => {
144
+ setToggle((prev) => {
145
+ if (label) {
146
+ return {
147
+ ...prev,
148
+ [label]: {
149
+ ...(prev && label && prev[label]),
150
+ isToggle: prev && !prev[label].isToggle,
151
+ },
152
+ };
153
+ }
154
+ else {
155
+ return prev;
156
+ }
157
+ });
158
+ };
159
+ return (jsx(Button, { as: is, className: clsx("accordion-button", `accordion-button__${is}`, `accordion-button__${is}--${dataTheme}`), ...(is !== "link" && {
160
+ icon: label && toggle && toggle[label].isToggle ? (jsx(TfiAngleDown, {})) : (jsx(TfiAngleUp, {})),
161
+ }), ...(is !== "link" && { onClick: handleToggle }), ...rest, children: children }));
162
+ });
163
+
164
+ const AccordionContent = forwardRef(function AccordionContent({ children, label, toggle, }, ref) {
165
+ return label && toggle && toggle[label].isToggle && jsx("div", { className: "accordion-content", children: children });
166
+ });
167
+
168
+ function Input({ className = "", classNameGroup = "", errorMessage = "", inputRef, styleGroup, ...rest }) {
169
+ 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 })] }));
170
+ }
171
+
172
+ function TextArea({ className = "", disabled = true, hasToggleButton = true, hideHeight = "5rem", placeholder = "", showHeight = "10rem", style = {}, textareaClassName = "", ...rest }) {
173
+ const ref = useRef();
174
+ const [isShow, setIsShow] = useState(false);
175
+ const handleClickToggle = () => {
176
+ if (ref && ref.current) {
177
+ if (isShow) {
178
+ ref.current.style.height = hideHeight;
179
+ }
180
+ else {
181
+ ref.current.style.height = showHeight; //(48 + ref.current.scrollHeight) + 'px';
182
+ }
183
+ setIsShow((prev) => !prev);
184
+ }
185
+ };
186
+ return (jsxs("div", { className: clsx("textarea", className), style: style, children: [jsx("textarea", { ref: ref, className: clsx("textarea__input", textareaClassName), style: {
187
+ height: hasToggleButton ? hideHeight : showHeight,
188
+ }, placeholder: placeholder, disabled: disabled, ...rest }), hasToggleButton && (jsx("button", { className: clsx("textarea__button", isShow && "textarea__button--show"), onClick: handleClickToggle, disabled: disabled, children: jsx(TbArrowsDiagonal2, { size: "1.5rem" }) }))] }));
189
+ }
190
+
191
+ function Modal({ modalref, children, title, subtitle, footer, hasCloseButton = true, handleClose, }) {
192
+ return (jsxs(Fragment, { children: [jsx("div", { className: "modal-overlay" }), jsxs("div", { ref: modalref, className: "modal", children: [hasCloseButton && (jsx(Button, { mode: "secondary", className: "modal__close", size: "small", onClick: handleClose, children: jsx(IoClose, {}) })), jsxs("div", { className: "modal__content", children: [title && (jsxs("div", { className: "modal__header", children: [jsx("h3", { children: title }), jsx("h6", { children: subtitle })] })), jsx("div", { className: "modal__children", children: children }), footer && jsx("div", { className: "modal__footer", children: footer })] })] })] }));
193
+ }
194
+
195
+ function Loading({ img, children }) {
196
+ return (jsxs("div", { className: "loading", children: [jsx("img", { src: img ? img : "../../stories/assets/loading.gif" }), children] }));
197
+ }
198
+
111
199
  const LoadingContext = createContext(undefined);
112
200
  function loadingReducer(state, action) {
113
201
  switch (action.type) {
@@ -229,4 +317,4 @@ function useModal({} = {}) {
229
317
  return context;
230
318
  }
231
319
 
232
- export { Accordion, Button, Input, Loading, LoadingContext, LoadingProvider, Modal, ModalContext, ModalProvider, TextArea, ThemeContext, ThemeProvider, useLoading, useModal, useTheme };
320
+ export { Accordion, AccordionButton, AccordionContent, AccordionItem, Button, Input, Loading, LoadingContext, LoadingProvider, Modal, ModalContext, ModalProvider, TextArea, ThemeContext, ThemeProvider, useLoading, useModal, useTheme };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geoinsight/react-components",
3
- "version": "0.3.6",
3
+ "version": "0.4.1",
4
4
  "description": "This library is the main UI component library for geoinsight",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",