diff --git a/packages/components/src/form/Button/Button.styles.js b/packages/components/src/form/Button/Button.styles.js
index 8b90f958e..67a33b5bc 100644
--- a/packages/components/src/form/Button/Button.styles.js
+++ b/packages/components/src/form/Button/Button.styles.js
@@ -179,6 +179,10 @@ export const ButtonStyles = createStyles(
const buttonTheme = theme.other.button;
const iconStyles = {
padding: 3,
+ '& > svg': {
+ width: 18,
+ height: 18,
+ },
};
const getTextAlign = () => {
diff --git a/packages/components/src/form/ImagePreviewInput/ImagePreviewInput.js b/packages/components/src/form/ImagePreviewInput/ImagePreviewInput.js
index 28e0172c0..6418c0a22 100644
--- a/packages/components/src/form/ImagePreviewInput/ImagePreviewInput.js
+++ b/packages/components/src/form/ImagePreviewInput/ImagePreviewInput.js
@@ -1,7 +1,8 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { isFunction, isString, isNil } from 'lodash';
-import { CloudUploadIcon, DeleteBinIcon } from '@bubbles-ui/icons/outline/';
+import { CloudUploadIcon } from '@bubbles-ui/icons/outline/';
+import { DeleteBinIcon } from '@bubbles-ui/icons/solid/';
import { Box } from '../../layout/Box';
import { Stack } from '../../layout/Stack';
import { Button } from '../Button';
@@ -98,7 +99,7 @@ const ImagePreviewInput = ({
}
}, [imageValue]);
- const { classes, cx } = ImagePreviewInputStyles({});
+ const { classes } = ImagePreviewInputStyles({});
return (
{!imagePreview ? (
@@ -113,6 +114,7 @@ const ImagePreviewInput = ({
radius={4}
style={{ ...previewStyle }}
useAria={useAria}
+ bordered
/>
{!readonly && !disabled ? (
diff --git a/packages/components/src/form/ListInput/ListInput.js b/packages/components/src/form/ListInput/ListInput.js
index 4c1e20586..830a7fe14 100644
--- a/packages/components/src/form/ListInput/ListInput.js
+++ b/packages/components/src/form/ListInput/ListInput.js
@@ -3,19 +3,17 @@ import { v4 as uuidv4 } from 'uuid';
import PropTypes from 'prop-types';
import { findIndex, isFunction, map } from 'lodash';
import { AddCircleIcon } from '@bubbles-ui/icons/outline';
+import { useId } from '@mantine/hooks';
import { Box } from '../../layout';
import { ListInputStyles } from './ListInput.styles';
import { InputWrapper } from '../InputWrapper';
-import { useId } from '@mantine/hooks';
import { TextInput } from '../TextInput';
import { Button } from '../Button';
import { SortableList } from '../../informative';
-import { ListItem } from './components/ListItem';
+import { ListItem, ItemWrapperWithBorder } from './components/ListItem';
export const LIST_INPUT_DEFAULT_PROPS = {
- inputRender: (props) => {
- return ;
- },
+ inputRender: (props) => ,
listRender: ,
onChange: () => {},
valueKey: 'value',
@@ -23,10 +21,32 @@ export const LIST_INPUT_DEFAULT_PROPS = {
errorRequiredMessage: 'Required',
hideAddButton: false,
useAria: true,
+ hideInput: false,
+ withItemBorder: false,
+ withInputBorder: false,
};
export const LIST_INPUT_PROP_TYPES = {
hideAddButton: PropTypes.bool,
useAria: PropTypes.bool,
+ valueKey: PropTypes.string,
+ addButtonLabel: PropTypes.string,
+ errorRequiredMessage: PropTypes.string,
+ inputRender: PropTypes.func,
+ listRender: PropTypes.func,
+ onChange: PropTypes.func,
+ required: PropTypes.bool,
+ readonly: PropTypes.bool,
+ disabled: PropTypes.bool,
+ canAdd: PropTypes.bool,
+ size: PropTypes.any,
+ value: PropTypes.arrayOf(PropTypes.object),
+ error: PropTypes.string,
+ help: PropTypes.string,
+ description: PropTypes.string,
+ label: PropTypes.string,
+ hideInput: PropTypes.bool,
+ withItemBorder: PropTypes.bool,
+ withInputBorder: PropTypes.bool,
};
const ListInput = ({
@@ -48,6 +68,9 @@ const ListInput = ({
value: originalValue,
onChange,
useAria,
+ hideInput,
+ withItemBorder,
+ withInputBorder,
}) => {
const { classes, cx } = ListInputStyles({});
@@ -64,7 +87,7 @@ const ListInput = ({
...item,
__key: uuidv4(),
}))
- : []
+ : [],
);
const uuid = useId();
@@ -101,7 +124,7 @@ const ListInput = ({
...item,
__key: uuidv4(),
})),
- true
+ true,
);
}, [originalValue]);
@@ -115,6 +138,8 @@ const ListInput = ({
}
}, [value]);
+ const ListInputWrapper = withInputBorder ? ItemWrapperWithBorder : React.Fragment;
+
return (
{
- return React.cloneElement(ListRender, {
- ...props,
+ itemRender={(itemProps) =>
+ React.cloneElement(ListRender, {
+ ...itemProps,
readonly,
+ withBorder: withItemBorder,
inputRender: InputRender,
editingKey,
valueKey,
errorRequiredMessage,
- editItem: () => editItem(props.item),
+ editItem: () => editItem(itemProps.item),
stopEdit: () => setEditingKey(null),
onChange: (event) => {
- const index = findIndex(value, { __key: props.item.__key });
+ const index = findIndex(value, { __key: itemProps.item.__key });
value[index][valueKey] = event;
setValue([...value]);
setEditingKey(null);
},
- });
- }}
+ })
+ }
useAria={useAria}
/>
@@ -158,32 +184,36 @@ const ListInput = ({
? {
display: 'flex',
flexDirection: 'row',
- gap: theme.spacing[4],
+ gap: theme.spacing[2],
width: '100%',
flex: 1,
}
: {}
}
>
-
- {React.cloneElement(InputRender, {
- value: valueKey ? activeItem[valueKey] : activeItem,
- onChange: (event) => {
- setActiveItem(valueKey ? { ...activeItem, [valueKey]: event } : event);
- if (event) setHasError(false);
- },
- required: true,
- error: hasError ? errorRequiredMessage : null,
- addItem,
- })}
-
- {!hideAddButton ? (
-
- } onClick={addItem}>
- {addButtonLabel}
-
-
- ) : null}
+ {hideInput ? null : (
+
+
+ {React.cloneElement(InputRender, {
+ value: valueKey ? activeItem[valueKey] : activeItem,
+ onChange: (event) => {
+ setActiveItem(valueKey ? { ...activeItem, [valueKey]: event } : event);
+ if (event) setHasError(false);
+ },
+ required: true,
+ error: hasError ? errorRequiredMessage : null,
+ addItem,
+ })}
+
+ {!hideAddButton ? (
+
+ } onClick={addItem}>
+ {addButtonLabel}
+
+
+ ) : null}
+
+ )}
) : null}
diff --git a/packages/components/src/form/ListInput/ListInput.stories.js b/packages/components/src/form/ListInput/ListInput.stories.js
index 422589b0b..4b4506570 100644
--- a/packages/components/src/form/ListInput/ListInput.stories.js
+++ b/packages/components/src/form/ListInput/ListInput.stories.js
@@ -1,6 +1,8 @@
import React from 'react';
import { LIST_INPUT_DEFAULT_PROPS, ListInput } from './ListInput';
import mdx from './ListInput.mdx';
+import { Box } from '../../layout/Box';
+import { Button } from '../Button';
export default {
title: 'Molecules/Form/ListInput',
@@ -26,10 +28,16 @@ function ListInputRender({ t, ...props }) {
}
const Template = ({ children, ...props }) => {
+ const [showInput, setShowInput] = React.useState(false);
return (
-
- {children}
-
+
+
+ {children}
+
+
+
);
};
@@ -39,4 +47,5 @@ Playground.args = {
// myBooleanProp: false,
// mySelectProp: 'Hello'
...LIST_INPUT_DEFAULT_PROPS,
+ value: [{ value: 'Hola' }, { value: 'Mundo' }],
};
diff --git a/packages/components/src/form/ListInput/components/ListItem.js b/packages/components/src/form/ListInput/components/ListItem.js
index 69ba32676..f6da0fabf 100644
--- a/packages/components/src/form/ListInput/components/ListItem.js
+++ b/packages/components/src/form/ListInput/components/ListItem.js
@@ -1,14 +1,40 @@
import React, { forwardRef, useEffect, useState } from 'react';
+import PropTypes from 'prop-types';
import { RemoveIcon, SortDragIcon } from '@bubbles-ui/icons/outline';
import { CheckIcon, DeleteBinIcon, EditWriteIcon } from '@bubbles-ui/icons/solid';
+import { isFunction } from 'lodash';
import { Box, Stack } from '../../../layout';
import { ActionButton } from '../../ActionButton';
-import { isFunction } from 'lodash';
-const ItemValueRender2 = ({ item }) => {
- return ({ width: '100%' })} dangerouslySetInnerHTML={{ __html: item }} />;
+const ItemValueRender2 = ({ item }) => (
+ ({ width: '100%' })} dangerouslySetInnerHTML={{ __html: item }} />
+);
+
+ItemValueRender2.propTypes = {
+ item: PropTypes.string,
};
+export const ItemWrapperWithBorder = ({ children }) => (
+ ({ width: '100%', padding: '4px 0' })}>
+ ({
+ border: `1px solid ${theme.other.global.border.color.line.subtle}`,
+ borderRadius: 4,
+ padding: theme.spacing[4],
+ backgroundColor: 'white',
+ })}
+ >
+ {children}
+
+
+);
+
+ItemWrapperWithBorder.propTypes = {
+ children: PropTypes.node,
+};
+
+const getRenderComponent = (Component) => (isFunction(Component) ? : Component);
+
const ListItem = forwardRef(
(
{
@@ -27,20 +53,16 @@ const ListItem = forwardRef(
readonly,
errorRequiredMessage,
index,
+ withBorder,
},
- ref
+ ref,
) => {
const [value, setValue] = useState(item[valueKey]);
const [hasError, setHasError] = useState(false);
- const InputRender = isFunction(IInputRender) ? : IInputRender;
-
- const ItemContainerRender = isFunction(IItemContainerRender) ? (
-
- ) : (
- IItemContainerRender
- );
- const ItemValueRender = isFunction(IItemValueRender) ? : IItemValueRender;
+ const InputRender = getRenderComponent(IInputRender);
+ const ItemContainerRender = getRenderComponent(IItemContainerRender);
+ const ItemValueRender = getRenderComponent(IItemValueRender);
function update() {
if (value) {
@@ -55,34 +77,42 @@ const ListItem = forwardRef(
setValue(item[valueKey]);
}, [item]);
- let children = React.cloneElement(ItemContainerRender, {
- children: [
- !readonly ? (
- ({ marginRight: theme.spacing[4] })}>
-
-
- ) : null,
+ const renderSortableIcon = () => (
+ ({ marginRight: theme.spacing[4] })}>
+
+
+ );
+ const renderActionButtons = () => (
+
+ }
+ disabled={!!editingKey}
+ onClick={editItem}
+ />
+ }
+ disabled={!!editingKey}
+ onClick={removeItem}
+ />
+
+ );
+
+ const renderChildren = () => {
+ let children = [
+ !readonly ? renderSortableIcon() : null,
React.cloneElement(ItemValueRender, {
item: item[valueKey],
index,
key: 2,
}),
- !readonly ? (
-
- } disabled={!!editingKey} onClick={editItem} />
- } disabled={!!editingKey} onClick={removeItem} />
-
- ) : null,
- ],
- });
- if (editingKey === item.__key) {
- children = React.cloneElement(ItemContainerRender, {
- children: [
- ({ marginRight: theme.spacing[4] })}>
-
- ,
- ({ width: '100%', marginRight: theme.spacing[4] })}>
+ !readonly ? renderActionButtons() : null,
+ ];
+
+ if (editingKey === item.__key) {
+ children = [
+ renderSortableIcon(),
+ ({ width: '100%', marginRight: theme.spacing[4] })} key={2}>
{React.cloneElement(InputRender, {
value,
onChange: (event) => {
@@ -94,7 +124,7 @@ const ListItem = forwardRef(
error: hasError ? errorRequiredMessage : null,
})}
,
-
+
} onClick={update} />
}
@@ -104,9 +134,13 @@ const ListItem = forwardRef(
}}
/>
,
- ],
- });
- }
+ ];
+ }
+
+ return React.cloneElement(ItemContainerRender, { children });
+ };
+
+ const Wrapper = withBorder ? ItemWrapperWithBorder : React.Fragment;
return (
({ display: 'flex' })}
>
- {children}
+ {renderChildren()}
);
- }
+ },
);
+ListItem.displayName = 'ListItem';
+ListItem.propTypes = {
+ provided: PropTypes.any,
+ item: PropTypes.any,
+ removeItem: PropTypes.any,
+ editItem: PropTypes.any,
+ inputRender: PropTypes.any,
+ itemContainerRender: PropTypes.any,
+ itemValueRender: PropTypes.any,
+ editingKey: PropTypes.any,
+ valueKey: PropTypes.any,
+ stopEdit: PropTypes.any,
+ classes: PropTypes.any,
+ onChange: PropTypes.any,
+ readonly: PropTypes.any,
+ errorRequiredMessage: PropTypes.any,
+ index: PropTypes.any,
+ withBorder: PropTypes.bool,
+};
+
export { ListItem };
diff --git a/packages/icons/optimized/outline/sort-drag.svg b/packages/icons/optimized/outline/sort-drag.svg
index 07464e6f0..969c73b89 100644
--- a/packages/icons/optimized/outline/sort-drag.svg
+++ b/packages/icons/optimized/outline/sort-drag.svg
@@ -1,3 +1,3 @@
diff --git a/packages/icons/optimized/solid/delete-bin.svg b/packages/icons/optimized/solid/delete-bin.svg
index aa877aedb..010a39217 100644
--- a/packages/icons/optimized/solid/delete-bin.svg
+++ b/packages/icons/optimized/solid/delete-bin.svg
@@ -1,3 +1,3 @@
-