diff --git a/front/src/modules/settings/data-model/components/SettingsObjectFormSection.tsx b/front/src/modules/settings/data-model/components/SettingsObjectFormSection.tsx index 2142157ae..ddaa98ef3 100644 --- a/front/src/modules/settings/data-model/components/SettingsObjectFormSection.tsx +++ b/front/src/modules/settings/data-model/components/SettingsObjectFormSection.tsx @@ -1,14 +1,22 @@ import styled from '@emotion/styled'; import { H2Title } from '@/ui/display/typography/components/H2Title'; -import { AutosizeTextInput } from '@/ui/input/components/AutosizeTextInput'; +import { TextArea } from '@/ui/input/components/TextArea'; import { TextInput } from '@/ui/input/components/TextInput'; import { Section } from '@/ui/layout/section/components/Section'; type SettingsObjectFormSectionProps = { + disabled?: boolean; singularName?: string; pluralName?: string; description?: string; + onChange?: ( + formValues: Partial<{ + singularName: string; + pluralName: string; + description: string; + }>, + ) => void; }; const StyledInputsContainer = styled.div` @@ -23,9 +31,11 @@ const StyledTextInput = styled(TextInput)` `; export const SettingsObjectFormSection = ({ - singularName, - pluralName, - description, + disabled, + singularName = '', + pluralName = '', + description = '', + onChange, }: SettingsObjectFormSectionProps) => (
onChange?.({ singularName: value })} + disabled={disabled} /> onChange?.({ pluralName: value })} + disabled={disabled} /> - onChange?.({ description: value })} + disabled={disabled} />
); diff --git a/front/src/modules/settings/data-model/new-object/components/SettingsNewObjectType.tsx b/front/src/modules/settings/data-model/new-object/components/SettingsNewObjectType.tsx index 2399c1181..e1d6545ac 100644 --- a/front/src/modules/settings/data-model/new-object/components/SettingsNewObjectType.tsx +++ b/front/src/modules/settings/data-model/new-object/components/SettingsNewObjectType.tsx @@ -1,4 +1,3 @@ -import { useState } from 'react'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; @@ -6,6 +5,13 @@ import { IconBox, IconDatabase, IconFileCheck } from '@/ui/display/icon'; import { SettingsObjectTypeCard } from './SettingsObjectTypeCard'; +export type NewObjectType = 'Standard' | 'Custom' | 'Remote'; + +type SettingsNewObjectTypeProps = { + selectedType?: NewObjectType; + onTypeSelect?: (type: NewObjectType) => void; +}; + const StyledContainer = styled.div` display: flex; flex-direction: row; @@ -13,12 +19,11 @@ const StyledContainer = styled.div` width: 100%; `; -export const SettingsNewObjectType = () => { +export const SettingsNewObjectType = ({ + selectedType = 'Standard', + onTypeSelect, +}: SettingsNewObjectTypeProps) => { const theme = useTheme(); - const [selectedType, setSelectedType] = useState(null); - const handleCardClick = (selectedType: string) => { - setSelectedType(selectedType); - }; return ( { color={theme.font.color.tertiary} /> } - onClick={() => handleCardClick('Standard')} - > + onClick={() => onTypeSelect?.('Standard')} + /> { color={theme.font.color.tertiary} /> } - onClick={() => handleCardClick('Custom')} - > + onClick={() => onTypeSelect?.('Custom')} + /> { color={theme.font.color.tertiary} /> } - > + /> ); }; diff --git a/front/src/modules/settings/data-model/new-object/components/SettingsObjectTypeCard.tsx b/front/src/modules/settings/data-model/new-object/components/SettingsObjectTypeCard.tsx index 9703215ae..c2ddf18c7 100644 --- a/front/src/modules/settings/data-model/new-object/components/SettingsObjectTypeCard.tsx +++ b/front/src/modules/settings/data-model/new-object/components/SettingsObjectTypeCard.tsx @@ -58,21 +58,19 @@ export const SettingsObjectTypeCard = ({ }: SettingsObjectTypeCardProps) => { const theme = useTheme(); return ( -
onclick}> - - {prefixIcon} - - {soon && } - {!disabled && selected && } - -
+ + {prefixIcon} + + {soon && } + {!disabled && selected && } + ); }; diff --git a/front/src/modules/settings/data-model/object-edit/SettingsObjectIconSection.tsx b/front/src/modules/settings/data-model/object-edit/SettingsObjectIconSection.tsx index 40a349b8c..69c1048f8 100644 --- a/front/src/modules/settings/data-model/object-edit/SettingsObjectIconSection.tsx +++ b/front/src/modules/settings/data-model/object-edit/SettingsObjectIconSection.tsx @@ -1,5 +1,6 @@ import styled from '@emotion/styled'; +import { IconPigMoney } from '@/ui/display/icon'; import { IconComponent } from '@/ui/display/icon/types/IconComponent'; import { H2Title } from '@/ui/display/typography/components/H2Title'; import { IconPicker } from '@/ui/input/components/IconPicker'; @@ -23,15 +24,19 @@ const StyledArrowContainer = styled.div` `; type SettingsObjectIconSectionProps = { - Icon: IconComponent; - iconKey: string; - setIconPicker?: (icon: { Icon: IconComponent; iconKey: string }) => void; + disabled?: boolean; + Icon?: IconComponent; + iconKey?: string; + label?: string; + onChange?: (icon: { Icon: IconComponent; iconKey: string }) => void; }; export const SettingsObjectIconSection = ({ - Icon, - iconKey, - setIconPicker, + disabled, + Icon = IconPigMoney, + iconKey = 'IconPigMoney', + label, + onChange, }: SettingsObjectIconSectionProps) => { return (
@@ -41,15 +46,16 @@ export const SettingsObjectIconSection = ({ /> { - setIconPicker?.({ Icon: icon.Icon, iconKey: icon.iconKey }); + onChange?.({ Icon: icon.Icon, iconKey: icon.iconKey }); }} /> Arrow right - +
); diff --git a/front/src/modules/ui/display/icon/index.ts b/front/src/modules/ui/display/icon/index.ts index 456fb1892..2a528203a 100644 --- a/front/src/modules/ui/display/icon/index.ts +++ b/front/src/modules/ui/display/icon/index.ts @@ -69,6 +69,7 @@ export { IconNumbers, IconPencil, IconPhone, + IconPigMoney, IconPlane, IconPlug, IconPlus, diff --git a/front/src/modules/ui/input/components/IconPicker.tsx b/front/src/modules/ui/input/components/IconPicker.tsx index 9c1759ffe..b29b00e7a 100644 --- a/front/src/modules/ui/input/components/IconPicker.tsx +++ b/front/src/modules/ui/input/components/IconPicker.tsx @@ -17,6 +17,7 @@ import { DropdownMenuSkeletonItem } from '../relation-picker/components/skeleton import { IconPickerHotkeyScope } from '../types/IconPickerHotkeyScope'; type IconPickerProps = { + disabled?: boolean; onChange: (params: { iconKey: string; Icon: IconComponent }) => void; selectedIconKey?: string; onClickOutside?: () => void; @@ -39,6 +40,7 @@ const convertIconKeyToLabel = (iconKey: string) => iconKey.replace(/[A-Z]/g, (letter) => ` ${letter}`).trim(); export const IconPicker = ({ + disabled, onChange, selectedIconKey, onClickOutside, @@ -81,6 +83,7 @@ export const IconPicker = ({ dropdownHotkeyScope={{ scope: IconPickerHotkeyScope.IconPicker }} clickableComponent={ @@ -100,6 +103,7 @@ export const IconPicker = ({ {iconKeys.map((iconKey) => ( void; + placeholder?: string; + value?: string; +}; + +const StyledTextArea = styled(TextareaAutosize)` + background-color: ${({ theme }) => theme.background.transparent.lighter}; + border: 1px solid ${({ theme }) => theme.border.color.medium}; + border-radius: ${({ theme }) => theme.border.radius.sm}; + box-sizing: border-box; + color: ${({ theme }) => theme.font.color.primary}; + font-family: inherit; + font-size: ${({ theme }) => theme.font.size.md}; + font-weight: ${({ theme }) => theme.font.weight.regular}; + line-height: 16px; + overflow: auto; + padding: ${({ theme }) => theme.spacing(2)}; + padding-top: ${({ theme }) => theme.spacing(3)}; + resize: none; + width: 100%; + + &:focus { + outline: none; + } + + &::placeholder { + color: ${({ theme }) => theme.font.color.light}; + font-weight: ${({ theme }) => theme.font.weight.regular}; + } + + &:disabled { + color: ${({ theme }) => theme.font.color.tertiary}; + } +`; + +export const TextArea = ({ + disabled, + placeholder, + minRows = 1, + value = '', + onChange, +}: TextAreaProps) => { + const computedMinRows = Math.min(minRows, MAX_ROWS); + + return ( + onChange?.(event.target.value)} + disabled={disabled} + /> + ); +}; diff --git a/front/src/modules/ui/input/components/TextInput.tsx b/front/src/modules/ui/input/components/TextInput.tsx index f8d4490b0..f5d210b07 100644 --- a/front/src/modules/ui/input/components/TextInput.tsx +++ b/front/src/modules/ui/input/components/TextInput.tsx @@ -19,7 +19,7 @@ import { useCombinedRefs } from '~/hooks/useCombinedRefs'; import { InputHotkeyScope } from '../types/InputHotkeyScope'; -type TextInputComponentProps = Omit< +export type TextInputComponentProps = Omit< InputHTMLAttributes, 'onChange' > & { @@ -53,9 +53,10 @@ const StyledInputContainer = styled.div` `; const StyledInput = styled.input>` - background-color: ${({ theme }) => theme.background.tertiary}; - border: none; + background-color: ${({ theme }) => theme.background.transparent.lighter}; + border: 1px solid ${({ theme }) => theme.border.color.medium}; border-bottom-left-radius: ${({ theme }) => theme.border.radius.sm}; + border-right: none; border-top-left-radius: ${({ theme }) => theme.border.radius.sm}; color: ${({ theme }) => theme.font.color.primary}; display: flex; @@ -74,6 +75,10 @@ const StyledInput = styled.input>` font-family: ${({ theme }) => theme.font.family}; font-weight: ${({ theme }) => theme.font.weight.medium}; } + + &:disabled { + color: ${({ theme }) => theme.font.color.tertiary}; + } `; const StyledErrorHelper = styled.div` @@ -84,8 +89,10 @@ const StyledErrorHelper = styled.div` const StyledTrailingIconContainer = styled.div` align-items: center; - background-color: ${({ theme }) => theme.background.tertiary}; + background-color: ${({ theme }) => theme.background.transparent.lighter}; + border: 1px solid ${({ theme }) => theme.border.color.medium}; border-bottom-right-radius: ${({ theme }) => theme.border.radius.sm}; + border-left: none; border-top-right-radius: ${({ theme }) => theme.border.radius.sm}; display: flex; justify-content: center; diff --git a/front/src/modules/ui/input/components/__stories__/TextArea.stories.tsx b/front/src/modules/ui/input/components/__stories__/TextArea.stories.tsx new file mode 100644 index 000000000..13f5a0655 --- /dev/null +++ b/front/src/modules/ui/input/components/__stories__/TextArea.stories.tsx @@ -0,0 +1,40 @@ +import { useState } from 'react'; +import { Meta, StoryObj } from '@storybook/react'; + +import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; + +import { TextArea, TextAreaProps } from '../TextArea'; + +type RenderProps = TextAreaProps; + +const Render = (args: RenderProps) => { + const [value, setValue] = useState(args.value); + const handleChange = (text: string) => { + args.onChange?.(text); + setValue(text); + }; + + // eslint-disable-next-line react/jsx-props-no-spreading + return