From 4ee2cb4468ef52ceb246a2f8d8771ce525ab2eb1 Mon Sep 17 00:00:00 2001 From: Foxhoundn Date: Tue, 5 Dec 2023 13:50:10 +0000 Subject: [PATCH] Improve tree styling, fix compact buttons, fix textarea templates --- .storybook/preview.tsx | 2 + __tests__/tree.test.tsx | 16 ---- package.json | 2 +- src/components/Button/index.tsx | 17 ++-- src/components/Dropdown/list.tsx | 11 ++- src/components/Icon/index.tsx | 13 ++- src/components/Paragraph/index.tsx | 4 +- src/components/Textarea/index.tsx | 3 + src/components/Tree/index.tsx | 82 ++++++++++++------- src/constants/colors.ts | 2 +- src/stories/Button/Button.stories.tsx | 7 ++ .../TextArea/TextAreaTests.stories.tsx | 9 +- 12 files changed, 105 insertions(+), 63 deletions(-) diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 00c04778..9640680b 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -1,5 +1,7 @@ import { ReqoreContent, ReqoreLayoutContent, ReqoreUIProvider } from '../src'; + export const parameters = { + actions: { argTypesRegex: '^on[A-Z].*' }, layout: 'fullscreen', options: { panelPosition: 'right', diff --git a/__tests__/tree.test.tsx b/__tests__/tree.test.tsx index e6e7ab11..53743549 100644 --- a/__tests__/tree.test.tsx +++ b/__tests__/tree.test.tsx @@ -36,22 +36,6 @@ test(' items can be expanded and collapsed', () => { expect(document.querySelectorAll('.reqore-tree-label').length).toBe(0); }); -test('Shows types for properly', () => { - render( - - - - - - - - ); - - fireEvent.click(document.querySelector('.reqore-tree-show-types')); - - expect(document.querySelectorAll('.reqore-tree-type').length).toBe(7); -}); - test('Renders with clickable items', () => { const fn = jest.fn(); diff --git a/package.json b/package.json index 58e61210..03970c16 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@qoretechnologies/reqore", - "version": "0.38.3", + "version": "0.38.4", "description": "ReQore is a highly theme-able and modular UI library for React", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index bbbf9b7c..459feadb 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -283,9 +283,10 @@ export interface IReqoreButtonBadgeProps extends IWithReqoreSize { content?: TReqoreBadge | TReqoreBadge[]; wrap?: boolean; wrapGroup?: boolean; + compact?: boolean; } -export const ButtonBadge = memo(({ wrapGroup, ...props }: IReqoreButtonBadgeProps) => { +export const ButtonBadge = memo(({ wrapGroup, compact, ...props }: IReqoreButtonBadgeProps) => { const renderTag = useCallback( ({ size, color, theme, content, key }: IReqoreButtonBadgeProps & { key: number }) => ( @@ -363,6 +364,7 @@ const ReqoreButton = memo( leftIconProps, rightIconProps, label, + compact, as, ...rest }: IReqoreButtonProps, @@ -418,6 +420,7 @@ const ReqoreButton = memo( wrap={wrap} description={description} className={`${className || ''} reqore-control reqore-button`} + compact={compact} > {hasLeftIcon ? ( @@ -426,6 +429,7 @@ const ReqoreButton = memo( icon={icon} size={size} color={leftIconColor || iconColor} + compact={compact} {...leftIconProps} style={ textAlign !== 'left' || iconsAlign === 'center' @@ -440,7 +444,7 @@ const ReqoreButton = memo( } /> {_children || hasRightIcon ? ( - + ) : null} ) : _children ? ( @@ -471,7 +475,7 @@ const ReqoreButton = memo( )} {(badge || badge === 0) && !wrap ? ( - + ) : null} {!hasRightIcon ? ( _children ? ( @@ -482,11 +486,14 @@ const ReqoreButton = memo( ) : null ) : ( <> - {_children || badge ? : null} + {_children || badge ? ( + + ) : null} { if (item.divider) { - return false; + return true; } const text: string | undefined = item.label || item.value || item.children; @@ -153,7 +153,8 @@ const ReqoreDropdownList = memo( {_onBackClick && ( @@ -163,7 +164,10 @@ const ReqoreDropdownList = memo( value={onFilterChange ? filter : query} icon='SearchLine' onChange={handleQueryChange} - placeholder={filterPlaceholder || `Search ${size(_items)} items...`} + placeholder={ + filterPlaceholder || + `Search ${size(_items.filter((item) => !item.divider))} items...` + } onClearClick={() => (onFilterChange ? onFilterChange('') : setQuery(''))} {...inputProps} /> @@ -195,6 +199,7 @@ const ReqoreDropdownList = memo( diff --git a/src/components/Icon/index.tsx b/src/components/Icon/index.tsx index c9336039..30e006e4 100644 --- a/src/components/Icon/index.tsx +++ b/src/components/Icon/index.tsx @@ -29,6 +29,8 @@ export interface IReqoreIconProps rounded?: boolean; rotation?: number; animation?: 'spin' | 'heartbeat'; + interactive?: boolean; + compact?: boolean; } const SpinKeyframes = keyframes` @@ -51,18 +53,23 @@ export const StyledIconWrapper = styled(StyledEffect)<{ margin: 'right' | 'left' border-radius: ${({ rounded }) => (rounded ? '50%' : undefined)}; rotate: ${({ rotation }) => (rotation ? `${rotation}deg` : undefined)}; + cursor: ${({ interactive }) => (interactive ? 'pointer' : undefined)}; - ${({ margin, size }) => + ${({ margin, size, compact }) => margin && css` margin-left: ${margin === 'left' || margin === 'both' ? isStringSize(size) - ? `${PADDING_FROM_SIZE[size]}px` + ? `${PADDING_FROM_SIZE[size] / (compact ? 2 : 1)}px` + : compact + ? '3px' : '10px' : undefined}; margin-right: ${margin === 'right' || margin === 'both' ? isStringSize(size) - ? `${PADDING_FROM_SIZE[size]}px` + ? `${PADDING_FROM_SIZE[size] / (compact ? 2 : 1)}px` + : compact + ? '3px' : '10px' : undefined}; `} diff --git a/src/components/Paragraph/index.tsx b/src/components/Paragraph/index.tsx index ff1f57ef..afa65776 100644 --- a/src/components/Paragraph/index.tsx +++ b/src/components/Paragraph/index.tsx @@ -17,7 +17,8 @@ export interface IReqoreParagraphProps export const StyledParagraph = styled(StyledTextEffect)` padding: 0; margin: 0; - color: ${({ theme, intent }) => (intent ? theme.intents[intent] : 'inherit')}; + color: ${({ theme, intent }) => + intent ? theme.intents[intent] : theme.text?.color || 'inherit'}; font-size: ${({ _size }) => (isStringSize(_size) ? `${TEXT_FROM_SIZE[_size]}px` : _size)}; `; @@ -29,6 +30,7 @@ export const ReqoreP = memo( ( )}`; setValue(value); + // Trigger the onChange event + onChange?.({ target: { value } } as any); }, [inputRef, _value] ); @@ -232,6 +234,7 @@ const ReqoreInput = forwardRef( component={StyledTextareaWrapper} className={`${className || ''} reqore-control-wrapper`} width={width} + filterable height={height} fluid={fluid} fixed={fixed} diff --git a/src/components/Tree/index.tsx b/src/components/Tree/index.tsx index 4db0e398..f71934e8 100644 --- a/src/components/Tree/index.tsx +++ b/src/components/Tree/index.tsx @@ -1,17 +1,16 @@ import { cloneDeep, size as lodashSize } from 'lodash'; import { useMemo, useState } from 'react'; import styled from 'styled-components'; -import { ReqoreMessage, ReqorePanel, useReqoreProperty } from '../..'; +import { ReqoreHorizontalSpacer, ReqoreIcon, ReqoreP, ReqorePanel, useReqoreProperty } from '../..'; import { GAP_FROM_SIZE, TSizes } from '../../constants/sizes'; import { IReqoreTheme } from '../../constants/theme'; -import { getTypeFromValue } from '../../helpers/utils'; +import { getOneLessSize, getTypeFromValue } from '../../helpers/utils'; import { IWithReqoreSize } from '../../types/global'; -import ReqoreButton from '../Button'; +import ReqoreButton, { IReqoreButtonProps } from '../Button'; import ReqoreControlGroup from '../ControlGroup'; import { ReqoreExportModal } from '../ExportModal'; import { IReqorePanelAction, IReqorePanelProps } from '../Panel'; import { getExportActions, getZoomActions, sizeToZoom, zoomToSize } from '../Table/helpers'; -import ReqoreTag from '../Tag'; export interface IReqoreTreeProps extends IReqorePanelProps, IWithReqoreSize { data: Record | Array; @@ -33,8 +32,10 @@ export interface ITreeStyle { size?: TSizes; } -export const StyledTreeLabel = styled(ReqoreMessage)` +export const StyledTreeLabel = styled(ReqoreP)` flex-shrink: 1; + + cursor: ${({ onClick }) => (onClick ? 'pointer' : 'default')}; `; export const StyledTreeWrapper = styled.div` @@ -107,49 +108,68 @@ export const ReqoreTree = ({ isExpandable = false; } + const badges: IReqoreButtonProps['badge'] = [`{...} ${lodashSize(data[key])} items`]; + + if (_showTypes) { + badges.push({ + icon: 'CodeBoxFill', + label: dataType, + }); + } + return ( {isObject ? ( + {level !== 1 && } handleItemClick(stateKey, isExpandable)} - flat + flat={false} + badge={badges} > {displayKey} - {_showTypes ? : null} ) : ( - - { - navigator.clipboard.writeText(JSON.stringify(data[key])); - addNotification({ - content: 'Successfuly copied to clipboard', - id: Date.now().toString(), - type: 'success', - duration: 3000, - }); - }, - }, - ] - : undefined - } - /> - {_showTypes ? : null} + + {level !== 1 && } + + {displayKey}: + + {withLabelCopy && ( + { + try { + navigator.clipboard.writeText(JSON.stringify(data[key])); + addNotification({ + content: 'Successfuly copied to clipboard', + id: Date.now().toString(), + type: 'success', + duration: 3000, + }); + } catch (e) { + console.error(e); + } + }} + /> + )} onItemClick(data[key], [...path, key])} + onClick={() => onItemClick?.(data[key], [...path, key])} className='reqore-tree-label' + size={zoomToSize[zoom]} > {JSON.stringify(data[key])} diff --git a/src/constants/colors.ts b/src/constants/colors.ts index b0f9765c..201b13ce 100644 --- a/src/constants/colors.ts +++ b/src/constants/colors.ts @@ -4,7 +4,7 @@ export const Colors: Record = { DARK: '#000000', DARK_THEME: '#333333', LIGHT: '#ffffff', - BLUE: '#0E5A8A', + BLUE: '#0776CB', GREEN: '#0A6640', YELLOW: '#d1a036', ORANGE: '#A66321', diff --git a/src/stories/Button/Button.stories.tsx b/src/stories/Button/Button.stories.tsx index 68739f3e..e1d52a05 100644 --- a/src/stories/Button/Button.stories.tsx +++ b/src/stories/Button/Button.stories.tsx @@ -53,6 +53,13 @@ const Template: StoryFn = (buttonProps) => { + Read only diff --git a/src/stories/TextArea/TextAreaTests.stories.tsx b/src/stories/TextArea/TextAreaTests.stories.tsx index 6b389e9a..26fd7746 100644 --- a/src/stories/TextArea/TextAreaTests.stories.tsx +++ b/src/stories/TextArea/TextAreaTests.stories.tsx @@ -1,4 +1,4 @@ -import { expect } from '@storybook/jest'; +import { expect, jest } from '@storybook/jest'; import { StoryObj } from '@storybook/react'; import { fireEvent, waitFor, within } from '@storybook/testing-library'; import { IReqoreTextareaProps } from '../../components/Textarea'; @@ -16,6 +16,7 @@ const meta = { scaleWithContent: true, fluid: undefined, placeholder: 'Placeholder', + onChange: jest.fn(), }, argTypes: { ...MinimalArg(), @@ -77,12 +78,13 @@ export const ItemCanBeSelected: Story = { label: 'New event in Google Calendar', icon: 'Calendar2Fill', description: 'When a new event is created in Google Calendar', + items: [], }, ], }, }, - play: async ({ canvasElement }) => { + play: async ({ canvasElement, args }) => { const canvas = within(canvasElement); await sleep(200); @@ -99,5 +101,8 @@ export const ItemCanBeSelected: Story = { await fireEvent.click(canvas.getAllByText('Author')[0]); await expect(canvas.getAllByText('$state:{1.field.author}')[0]).toBeTruthy(); + await expect(args.onChange).toHaveBeenCalledWith({ + target: { value: '$state:{1.field.author}' }, + }); }, };