From 2e1263baa5710d6419f5b71d091a63cd72356498 Mon Sep 17 00:00:00 2001 From: Philippe Chevieux Date: Wed, 30 Oct 2024 17:03:42 +0100 Subject: [PATCH] feat(@leav/ui): adapt color to design system --- apps/data-studio/package.json | 2 +- apps/login/package.json | 2 +- apps/portal/package.json | 2 +- libs/ui/package.json | 2 +- .../EditRecordContent/antdUtils.tsx | 1 + .../StandardField/StandardFieldColor.test.tsx | 110 ----- .../DSColorPickerWrapper.test.tsx | 456 ++++++++++++++++++ .../DSColorPickerWrapper.tsx | 133 +++++ .../StandardFieldValue/StandardFieldValue.tsx | 5 +- .../StandardFieldValueDisplayHandler.tsx | 3 + .../ColorPickerBlock.tsx | 60 +++ .../StandardFieldValueRead.tsx | 46 +- yarn.lock | 16 +- 13 files changed, 710 insertions(+), 128 deletions(-) delete mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSColorPickerWrapper.test.tsx create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSColorPickerWrapper.tsx create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueRead/ColorPickerBlock.tsx diff --git a/apps/data-studio/package.json b/apps/data-studio/package.json index 836fce0cd..60deac33d 100644 --- a/apps/data-studio/package.json +++ b/apps/data-studio/package.json @@ -13,7 +13,7 @@ "antd": "5.15.3", "apollo-cache-inmemory": "1.6.6", "apollo-upload-client": "14.1.3", - "aristid-ds": "10.1.0-aa2d9f7", + "aristid-ds": "10.1.0-c112384", "dayjs": "1.11.10", "graphql": "15.0.0", "graphql-tag": "2.12.6", diff --git a/apps/login/package.json b/apps/login/package.json index 33a9d2726..3611a5da1 100644 --- a/apps/login/package.json +++ b/apps/login/package.json @@ -7,7 +7,7 @@ "@ant-design/icons": "5.2.6", "@leav/ui": "workspace:libs/ui", "antd": "5.15.3", - "aristid-ds": "10.1.0-aa2d9f7", + "aristid-ds": "10.1.0-c112384", "i18next": "22.5.0", "i18next-browser-languagedetector": "7.0.2", "i18next-http-backend": "2.1.1", diff --git a/apps/portal/package.json b/apps/portal/package.json index 8b3d7579d..c35c52265 100644 --- a/apps/portal/package.json +++ b/apps/portal/package.json @@ -8,7 +8,7 @@ "@leav/ui": "workspace:libs/ui", "@leav/utils": "workspace:libs/utils", "antd": "5.15.3", - "aristid-ds": "10.1.0-aa2d9f7", + "aristid-ds": "10.1.0-c112384", "cross-fetch": "3.1.5", "graphql-ws": "5.12.0", "i18next": "22.5.0", diff --git a/libs/ui/package.json b/libs/ui/package.json index a6692fa6b..04cb18df0 100644 --- a/libs/ui/package.json +++ b/libs/ui/package.json @@ -50,7 +50,7 @@ "@ant-design/icons": ">=5.2", "@apollo/client": ">=3.8.1", "antd": "5.15.3", - "aristid-ds": "10.1.0-aa2d9f7", + "aristid-ds": "10.1.0-c112384", "dayjs": "^1.11.10", "i18next": "22.5", "react": "18.2.0", diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/antdUtils.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/antdUtils.tsx index 352c2c4b9..858bd84ac 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/antdUtils.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/antdUtils.tsx @@ -66,6 +66,7 @@ export const getAntdFormInitialValues = (recordForm: IRecordForm) => } switch (attribute.format) { + case AttributeFormat.color: case AttributeFormat.text: case AttributeFormat.rich_text: case AttributeFormat.boolean: diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx deleted file mode 100644 index 0899b660a..000000000 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright LEAV Solutions 2017 -// This file is released under LGPL V3 -// License text available at https://www.gnu.org/licenses/lgpl-3.0.txt -import {render, screen, waitFor} from '_ui/_tests/testUtils'; -import userEvent from '@testing-library/user-event'; -import StandardField from './StandardField'; -import { - APICallStatus, - DeleteMultipleValuesFunc, - DeleteValueFunc, - ISubmitMultipleResult, - SubmitValueFunc -} from '../../_types'; -import {mockModifier} from '_ui/__mocks__/common/value'; -import {AttributeFormat, AttributeType, ValueDetailsValueFragment} from '_ui/_gqlTypes'; -import {IRecordPropertyAttribute} from '_ui/_queries/records/getRecordPropertiesQuery'; -import {mockFormElementInput} from '_ui/__mocks__/common/form'; -import {mockFormAttribute} from '_ui/__mocks__/common/attribute'; - -describe('StandardField, Color input', () => { - const mockRecordValuesCommon = { - created_at: 123456789, - modified_at: 123456789, - created_by: mockModifier, - modified_by: mockModifier, - id_value: null, - metadata: null, - version: null - }; - - const mockAttribute: IRecordPropertyAttribute = { - id: 'test_attribute', - label: {en: 'Test Attribute'}, - format: AttributeFormat.color, - type: AttributeType.simple, - system: false - }; - - const mockSubmitRes: ISubmitMultipleResult = { - status: APICallStatus.SUCCESS, - values: [ - { - id_value: null, - created_at: 1234567890, - created_by: { - ...mockModifier - }, - modified_at: 1234567890, - modified_by: { - ...mockModifier - }, - value: 'new value', - raw_value: 'new raw value', - version: null, - attribute: mockAttribute as ValueDetailsValueFragment['attribute'], - metadata: null - } - ] - }; - - const mockHandleSubmit: SubmitValueFunc = jest.fn().mockReturnValue(mockSubmitRes); - const mockHandleDelete: DeleteValueFunc = jest.fn().mockReturnValue({status: APICallStatus.SUCCESS}); - const mockHandleMultipleValues: DeleteMultipleValuesFunc = jest - .fn() - .mockReturnValue({status: APICallStatus.SUCCESS}); - - const baseProps = { - onValueSubmit: mockHandleSubmit, - onValueDelete: mockHandleDelete, - onDeleteMultipleValues: mockHandleMultipleValues - }; - - window.HTMLElement.prototype.scrollIntoView = jest.fn(); - test('Render color field', async () => { - const colorValue = 'FFFFFF'; - const newColorValue = '000000'; - const recordValuesDate = [ - { - ...mockRecordValuesCommon, - value: colorValue, - raw_value: colorValue - } - ]; - render( - - ); - // Open ColorPicker Element - const colorElem = screen.getByRole('textbox'); - await userEvent.click(colorElem); - - const colorPickerElem = screen.getByRole('textbox'); - expect(colorPickerElem).toBeInTheDocument(); - - // Update color value - colorPickerElem.focus(); - await userEvent.clear(colorPickerElem); - await userEvent.type(colorPickerElem, newColorValue); - await userEvent.click(screen.getByRole('button', {name: 'global.submit'})); - - expect(colorPickerElem).not.toBeInTheDocument(); - expect(mockHandleSubmit).toHaveBeenCalled(); - }); -}); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSColorPickerWrapper.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSColorPickerWrapper.test.tsx new file mode 100644 index 000000000..3cecfbd9c --- /dev/null +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSColorPickerWrapper.test.tsx @@ -0,0 +1,456 @@ +// Copyright LEAV Solutions 2017 +// This file is released under LGPL V3 +// License text available at https://www.gnu.org/licenses/lgpl-3.0.txt +import {fireEvent, render, screen, waitFor, within} from '_ui/_tests/testUtils'; +import {DSColorPickerWrapper} from './DSColorPickerWrapper'; +import {VersionFieldScope} from '../../../_types'; +import { + CalculatedFlags, + InheritedFlags, + IStandardFieldReducerState, + StandardFieldValueState +} from '../../../reducers/standardFieldReducer/standardFieldReducer'; +import {mockRecord} from '_ui/__mocks__/common/record'; +import {mockFormElementInput} from '_ui/__mocks__/common/form'; +import {mockFormAttribute} from '_ui/__mocks__/common/attribute'; +import userEvent from '@testing-library/user-event'; +import {AntForm} from 'aristid-ds'; +import {RecordFormAttributeFragment} from '_ui/_gqlTypes'; + +const en_label = 'label'; +const fr_label = 'libellé'; +const idValue = '123'; +const pinkColor = 'ff00ff'; +const blueColor = '0000ff'; +const mockValue = { + index: 0, + displayValue: pinkColor, + editingValue: pinkColor, + originRawValue: pinkColor, + idValue: null, + isEditing: false, + isErrorDisplayed: false, + value: { + id_value: null, + value: pinkColor, + raw_value: pinkColor, + modified_at: null, + created_at: null, + created_by: null, + modified_by: null + }, + version: null, + error: '', + state: StandardFieldValueState.PRISTINE +}; + +const getInitialState = ({ + required, + fallbackLang +}: { + required: boolean; + fallbackLang: boolean; +}): IStandardFieldReducerState => ({ + record: mockRecord, + formElement: { + ...mockFormElementInput, + settings: { + label: fallbackLang ? {en: en_label} : {fr: fr_label, en: en_label}, + required + } + }, + attribute: mockFormAttribute, + isReadOnly: false, + activeScope: VersionFieldScope.CURRENT, + values: { + [VersionFieldScope.CURRENT]: { + version: null, + values: {[idValue]: mockValue} + }, + [VersionFieldScope.INHERITED]: null + }, + metadataEdit: false, + inheritedValue: null, + isInheritedNotOverrideValue: false, + isInheritedOverrideValue: false, + isInheritedValue: false, + calculatedValue: null, + isCalculatedNotOverrideValue: false, + isCalculatedOverrideValue: false, + isCalculatedValue: false +}); + +const inheritedValues = [ + { + isInherited: null, + value: pinkColor, + raw_value: pinkColor + }, + { + isInherited: true, + value: blueColor, + raw_value: blueColor + } +]; + +const inheritedNotOverrideValue: InheritedFlags = { + isInheritedValue: true, + isInheritedOverrideValue: false, + isInheritedNotOverrideValue: true, + inheritedValue: {raw_value: inheritedValues[1].raw_value} +}; + +const inheritedOverrideValue: InheritedFlags = { + isInheritedValue: true, + isInheritedOverrideValue: true, + isInheritedNotOverrideValue: false, + inheritedValue: {raw_value: inheritedValues[1].raw_value} +}; + +const calculatedValues = [ + { + isCalculated: null, + value: pinkColor, + raw_value: pinkColor + }, + { + isCalculated: true, + value: blueColor, + raw_value: blueColor + } +]; + +const calculatedNotOverrideValue: CalculatedFlags = { + isCalculatedValue: true, + isCalculatedOverrideValue: false, + isCalculatedNotOverrideValue: true, + calculatedValue: {raw_value: calculatedValues[1].raw_value} +}; + +const calculatedOverrideValue: CalculatedFlags = { + isCalculatedValue: true, + isCalculatedOverrideValue: true, + isCalculatedNotOverrideValue: false, + calculatedValue: {raw_value: calculatedValues[1].raw_value} +}; + +describe('DSColorPickerWrapper', () => { + const mockHandleSubmit = jest.fn(); + const mockOnChange = jest.fn(); + const mockHandleBlur = jest.fn(); + + let user!: ReturnType; + + beforeEach(() => { + user = userEvent.setup({}); + mockOnChange.mockReset(); + mockHandleSubmit.mockReset(); + mockHandleBlur.mockReset(); + }); + + test('Should display colorPicker with fr label', async () => { + const state = getInitialState({required: false, fallbackLang: false}); + + render( + + + + + + ); + + expect(screen.getByText(fr_label)).toBeVisible(); + }); + + test('Should display colorPicker with fallback label', async () => { + const state = getInitialState({required: false, fallbackLang: true}); + + render( + + + + + + ); + + expect(screen.getByText(en_label)).toBeVisible(); + }); + + test('Should not submit if field has not changed', async () => { + const state = getInitialState({required: false, fallbackLang: true}); + render( + + + + + + ); + + const colorPicker = screen.getByLabelText(en_label); + await user.click(colorPicker); + await user.tab(); + + expect(mockOnChange).not.toHaveBeenCalled(); + expect(mockHandleSubmit).not.toHaveBeenCalled(); + }); + + describe('With required colorPicker and no inheritance', () => { + test('Should submit the value if field is not empty', async () => { + const state = getInitialState({required: false, fallbackLang: true}); + render( + + + + + + ); + + const colorPicker = screen.getByLabelText(en_label); + await user.click(colorPicker); + + const input = screen.getByRole('textbox'); + + await user.clear(input); + await user.type(input, pinkColor); + await user.click(document.body); + + expect(mockHandleSubmit).toHaveBeenCalledWith(pinkColor, state.attribute.id); + expect(mockOnChange).toHaveBeenCalled(); + }); + }); + + describe('With inheritance', () => { + test("Should display the inherited value by default and not save if we don't change it", async () => { + let state = getInitialState({required: false, fallbackLang: true}); + + state = { + ...state, + ...inheritedNotOverrideValue, + formElement: {...state.formElement, values: inheritedValues} + }; + + render( + + + + + + ); + + expect(screen.getByText('#' + inheritedValues[1].raw_value)).toBeVisible(); + + const colorPicker = screen.getByLabelText(en_label); + await user.click(colorPicker); + await user.click(document.body); + + expect(mockHandleSubmit).not.toHaveBeenCalled(); + expect(mockOnChange).not.toHaveBeenCalled(); + }); + + test('Should display the override value in the input and inherited value under it', async () => { + let state = getInitialState({required: false, fallbackLang: true}); + + state = { + ...state, + ...inheritedOverrideValue, + formElement: {...state.formElement, values: inheritedValues} + }; + + render( + + + + + + ); + + const inputText = screen.getByText('#' + inheritedValues[0].raw_value); + expect(inputText).toBeVisible(); + + const helperText = screen.getByText(new RegExp(inheritedValues[1].raw_value, 'i')); + expect(helperText).toBeInTheDocument(); + }); + + test("Should allow to clear input when it's override", async () => { + let state = getInitialState({required: false, fallbackLang: true}); + + state = { + ...state, + ...inheritedOverrideValue, + formElement: {...state.formElement, values: inheritedValues} + }; + + render( + + + + + + ); + + const colorPicker = screen.getByLabelText(en_label); + await user.click(colorPicker); + + const clearButton = screen.getByLabelText('clear'); + await user.click(clearButton); + + expect(mockHandleSubmit).toHaveBeenCalledWith('', state.attribute.id); + expect(screen.queryByText('#00000000')).toBeVisible(); + }); + }); + + describe('With calculation', () => { + test("Should display the calculated value by default and not save if we don't change it", async () => { + let state = getInitialState({required: false, fallbackLang: true}); + + state = { + ...state, + ...calculatedNotOverrideValue, + formElement: {...state.formElement, values: calculatedValues} + }; + + render( + + + + + + ); + + expect(screen.getByText('#' + calculatedValues[1].raw_value)).toBeVisible(); + + const colorPicker = screen.getByLabelText(en_label); + await user.click(colorPicker); + await user.click(document.body); + + expect(mockHandleSubmit).not.toHaveBeenCalled(); + expect(mockOnChange).not.toHaveBeenCalled(); + }); + + test('Should display the override value in the input and calculated value under it', async () => { + let state = getInitialState({required: false, fallbackLang: true}); + + state = { + ...state, + ...calculatedOverrideValue, + formElement: {...state.formElement, values: calculatedValues} + }; + + render( + + + + + + ); + + const inputText = screen.getByText('#' + calculatedValues[0].raw_value); + expect(inputText).toBeVisible(); + + const helperText = screen.getByText(new RegExp(calculatedValues[1].raw_value, 'i')); + expect(helperText).toBeInTheDocument(); + }); + + test("Should allow to clear input when it's override", async () => { + let state = getInitialState({required: false, fallbackLang: true}); + + state = { + ...state, + ...calculatedOverrideValue, + formElement: {...state.formElement, values: calculatedValues} + }; + + render( + + + + + + ); + + const colorPicker = screen.getByLabelText(en_label); + await user.click(colorPicker); + + const clearButton = screen.getByLabelText('clear'); + await user.click(clearButton); + + expect(mockHandleSubmit).toHaveBeenCalledWith('', state.attribute.id); + }); + }); +}); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSColorPickerWrapper.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSColorPickerWrapper.tsx new file mode 100644 index 000000000..c15397fa9 --- /dev/null +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSColorPickerWrapper.tsx @@ -0,0 +1,133 @@ +// Copyright LEAV Solutions 2017 +// This file is released under LGPL V3 +// License text available at https://www.gnu.org/licenses/lgpl-3.0.txt +import {KitColorPicker} from 'aristid-ds'; +import {FunctionComponent, useEffect, useRef, useState} from 'react'; +import { + IStandardFieldReducerState, + IStandardFieldValue +} from '../../../reducers/standardFieldReducer/standardFieldReducer'; +import {IProvidedByAntFormItem} from '_ui/components/RecordEdition/EditRecordContent/_types'; +import styled from 'styled-components'; +import {useSharedTranslation} from '_ui/hooks/useSharedTranslation'; +import {useLang} from '_ui/hooks'; +import {localizedTranslation} from '@leav/utils'; +import {RecordFormAttributeFragment} from '_ui/_gqlTypes'; +import {useValueDetailsButton} from '../../../shared/ValueDetailsBtn/useValueDetailsButton'; +import {KitColor, KitColorPickerProps, KitColorPickerRef} from 'aristid-ds/dist/Kit/DataEntry/ColorPicker/types'; + +interface IDSColorPickerWrapperProps extends IProvidedByAntFormItem { + state: IStandardFieldReducerState; + attribute: RecordFormAttributeFragment; + fieldValue: IStandardFieldValue; + handleSubmit: (value: string, id?: string) => void; + handleBlur: () => void; + shouldShowValueDetailsButton?: boolean; +} + +const KitColorPickerStyled = styled(KitColorPicker)<{$shouldHighlightColor: boolean}>` + .ant-color-picker-trigger-text { + color: ${({$shouldHighlightColor}) => + $shouldHighlightColor ? 'var(--general-colors-primary-400)' : 'var(--general-utilities-text-primary)'}; + + svg { + color: var(--general-utilities-text-primary); + } + } +`; + +export const DSColorPickerWrapper: FunctionComponent = ({ + value, + state, + attribute, + fieldValue, + onChange, + handleSubmit, + handleBlur, + shouldShowValueDetailsButton = false +}) => { + const {t} = useSharedTranslation(); + const {lang: availableLang} = useLang(); + const [hasChanged, setHasChanged] = useState(false); + const [currentColor, setCurrentColor] = useState(); + const [currentHex, setCurrentHex] = useState((value as string) ?? ''); + const colorPickerRef = useRef(null); + const {onValueDetailsButtonClick} = useValueDetailsButton({ + value: fieldValue?.value, + attribute + }); + + useEffect(() => { + if (fieldValue.isEditing) { + colorPickerRef.current.focus(); + } + }, [fieldValue.isEditing]); + + const _handleOnOpenChange = (open: boolean) => { + if (!open) { + if (!hasChanged) { + handleBlur(); + return; + } + + handleSubmit(currentColor.toHex(), state.attribute.id); + onChange(currentColor, currentHex); + } + }; + + const _handleOnChange = ( + color: Parameters[0], + hex: Parameters[1] + ) => { + setHasChanged(true); + setCurrentHex(hex); + setCurrentColor(color); + onChange(color, hex); + }; + + const _handleOnClear = () => { + setHasChanged(false); + + if (state.isInheritedValue) { + onChange(undefined, state.inheritedValue.raw_value); + } else if (state.isCalculatedValue) { + onChange(undefined, state.calculatedValue.raw_value); + } + + onChange(null, ''); + handleSubmit('', state.attribute.id); + }; + + const _getHelper = () => { + if (state.isInheritedOverrideValue) { + return t('record_edition.inherited_input_helper', {inheritedValue: state.inheritedValue.raw_value}); + } else if (state.isCalculatedOverrideValue) { + return t('record_edition.calculated_input_helper', {calculatedValue: state.calculatedValue.raw_value}); + } + return; + }; + + const label = localizedTranslation(state.formElement.settings.label, availableLang); + + return ( + + ); +}; diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx index 2cb462309..f47941c16 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx @@ -563,10 +563,11 @@ function StandardFieldValue({ AttributeFormat.encrypted, AttributeFormat.date, AttributeFormat.boolean, - AttributeFormat.rich_text + AttributeFormat.rich_text, + AttributeFormat.color ]; - const attributeFormatsWithoutDS = [AttributeFormat.color, AttributeFormat.extended]; + const attributeFormatsWithoutDS = [AttributeFormat.extended]; return ( <> diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueDisplayHandler.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueDisplayHandler.tsx index 7dc11171a..23fcb47a5 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueDisplayHandler.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueDisplayHandler.tsx @@ -21,6 +21,7 @@ import {useStandardFieldReducer} from '_ui/components/RecordEdition/EditRecordCo import {Form} from 'antd'; import {useTranslation} from 'react-i18next'; import {DSRichTextWrapper} from '../DSRichTextWrapper'; +import {DSColorPickerWrapper} from '../DSColorPickerWrapper'; interface IStandardFieldValueDisplayHandlerProps { state: IStandardFieldReducerState; @@ -92,6 +93,8 @@ export const StandardFieldValueDisplayHandler: FunctionComponent; break; + case AttributeFormat.color: + valueContent = ; } return ( diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueRead/ColorPickerBlock.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueRead/ColorPickerBlock.tsx new file mode 100644 index 000000000..d2df55ffb --- /dev/null +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueRead/ColorPickerBlock.tsx @@ -0,0 +1,60 @@ +import {FunctionComponent} from 'react'; +import styled from 'styled-components'; + +interface IColorPickerBlockProps { + isValueDefaultColor: boolean; + color: string; +} + +const ColorPickerColorBlock = styled.div` + height: 32px; + width: 32px; + border-radius: calc(var(--general-border-radius-xs) * 1px); + box-shadow: inset 0 0 1px 0 rgba(0, 0, 0, 0.25); + background-image: conic-gradient( + rgba(0, 0, 0, 0.06) 0 25%, + transparent 0 50%, + rgba(0, 0, 0, 0.06) 0 75%, + transparent 0 + ); + background-size: 50% 50%; +`; + +const ColorPickerColorBlockInner = styled.div<{$color: string}>` + width: 100%; + height: 100%; + border: 1px solid rgba(0, 0, 0, 0.06); + border-radius: calc(var(--general-border-radius-xs) * 1px); + background-color: ${({$color}) => $color}; +`; + +const ColorPickerClear = styled.div` + width: 24px; + height: 24px; + margin: calc(var(--general-spacing-xxs) * 1px) 0; + border-radius: calc(var(--general-border-radius-xs) * 1px); + border: 1px solid rgba(5, 5, 5, 0.06); + position: relative; + + &::after { + content: ''; + position: absolute; + inset-inline-end: 1px; + top: 0; + display: block; + width: 28px; + height: 2px; + transform-origin: right; + transform: rotate(-45deg); + background-color: var(--general-utilities-error-default); + } +`; + +export const ColorPickerBlock: FunctionComponent = ({isValueDefaultColor, color}) => + isValueDefaultColor ? ( + + ) : ( + + + + ); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueRead/StandardFieldValueRead.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueRead/StandardFieldValueRead.tsx index e5fa56aab..f84ce8276 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueRead/StandardFieldValueRead.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueRead/StandardFieldValueRead.tsx @@ -14,6 +14,7 @@ import {KitInputWrapper, KitTypography} from 'aristid-ds'; import {FunctionComponent, SyntheticEvent} from 'react'; import styled from 'styled-components'; import DOMPurify from 'dompurify'; +import {ColorPickerBlock} from './ColorPickerBlock'; interface IStandardFieldValueReadProps { fieldValue: IStandardFieldValue; @@ -24,18 +25,35 @@ interface IStandardFieldValueReadProps { const _isDateRangeValue = (value: any): value is {from: string; to: string} => !!value && typeof value === 'object' && 'from' in value && 'to' in value; -const KitInputWrapperStyled = styled(KitInputWrapper)<{$width: string}>` - > .kit-input-wrapper-content { +const KitInputWrapperStyled = styled(KitInputWrapper)<{$width: string; $isColorAttribute: boolean}>` + &.bordered > .kit-input-wrapper-content { width: ${({$width}) => $width}; + + ${({$isColorAttribute}) => $isColorAttribute && 'padding: 3px;'} } `; -const ValueWrapper = styled(KitTypography.Paragraph)<{$highlighted: boolean}>` +const ValueWrapper = styled(KitTypography.Paragraph)<{$highlighted: boolean; $isColorAttribute: boolean}>` min-height: calc(var(--general-typography-fontSize6) * var(--general-typography-lineHeight6) * 1px); - color: ${({$highlighted}) => ($highlighted ? 'var(--general-colors-primary-400)' : 'initial')}; + color: ${({$highlighted}) => + $highlighted ? 'var(--general-colors-primary-400)' : 'var(--general-utilities-text-primary)'}; font-size: calc(var(--general-typography-fontSize5) * 1px); + line-height: calc(var(--general-typography-fontSize5) * 1px); + display: flex; + flex-direction: row; + align-items: center; + + ${({$isColorAttribute}) => + $isColorAttribute && + `span { + margin-inline-start: 8px; + margin-inline-end: 5px; + } + `} `; +const defaultColorValue = '#00000000'; + export const StandardFieldValueRead: FunctionComponent = ({ fieldValue, onClick, @@ -64,6 +82,8 @@ export const StandardFieldValueRead: FunctionComponent + {isColorAttribute && ( + + )} diff --git a/yarn.lock b/yarn.lock index db2c42650..8dcafb6d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8107,7 +8107,7 @@ __metadata: "@ant-design/icons": ">=5.2" "@apollo/client": ">=3.8.1" antd: 5.15.3 - aristid-ds: 10.1.0-aa2d9f7 + aristid-ds: 10.1.0-c112384 dayjs: ^1.11.10 i18next: 22.5 react: 18.2.0 @@ -12415,9 +12415,9 @@ __metadata: languageName: node linkType: hard -"aristid-ds@npm:10.1.0-aa2d9f7": - version: 10.1.0-aa2d9f7 - resolution: "aristid-ds@npm:10.1.0-aa2d9f7" +"aristid-ds@npm:10.1.0-c112384": + version: 10.1.0-c112384 + resolution: "aristid-ds@npm:10.1.0-c112384" dependencies: "@dnd-kit/core": "npm:^6.1.0" "@dnd-kit/modifiers": "npm:^7.0.0" @@ -12473,7 +12473,7 @@ __metadata: react-uuid: ^2.0.0 remark-gfm: ^3.0.1 styled-components: ^6.0.7 - checksum: aecf4ffb06410c582eb3b5f4c155be80cbbd8890761b0ba1a315330496ead1829b0e624f27ecb49e8f1efbf8b81fd7207fcbc9d96bfda8034620b13106427ac1 + checksum: 1d4267ce2fdb840756fecbd803362ed2d49dba6ff2a356a8cf258cbb535ed0010145ba9b64246d0c93d5f8a93672932c18c032dd9f12f088325732d5a73eacff languageName: node linkType: hard @@ -15651,7 +15651,7 @@ __metadata: apollo: "npm:2.34.0" apollo-cache-inmemory: "npm:1.6.6" apollo-upload-client: "npm:14.1.3" - aristid-ds: "npm:10.1.0-aa2d9f7" + aristid-ds: "npm:10.1.0-c112384" commander: "npm:5.1.0" dayjs: "npm:1.11.10" graphql: "npm:15.0.0" @@ -24145,7 +24145,7 @@ __metadata: "@types/react-dom": "npm:18.2.6" "@vitejs/plugin-react": "npm:3.1.0" antd: "npm:5.15.3" - aristid-ds: "npm:10.1.0-aa2d9f7" + aristid-ds: "npm:10.1.0-c112384" i18next: "npm:22.5.0" i18next-browser-languagedetector: "npm:7.0.2" i18next-http-backend: "npm:2.1.1" @@ -26923,7 +26923,7 @@ __metadata: "@vitejs/plugin-react": "npm:3.1.0" antd: "npm:5.15.3" apollo: "npm:2.34.0" - aristid-ds: "npm:10.1.0-aa2d9f7" + aristid-ds: "npm:10.1.0-c112384" commander: "npm:10.0.0" cross-fetch: "npm:3.1.5" graphql-ws: "npm:5.12.0"