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}' },
+ });
},
};