From 156e35d59abef12e86715b626825785242ca5782 Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Wed, 8 Jan 2025 10:29:07 +0600 Subject: [PATCH 01/17] fix: Line chart not showing info in the tooltip --- src/components/line-chart/line-chart.tsx | 52 ++++++++++++------------ 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/src/components/line-chart/line-chart.tsx b/src/components/line-chart/line-chart.tsx index 9b714b59..d4a00524 100644 --- a/src/components/line-chart/line-chart.tsx +++ b/src/components/line-chart/line-chart.tsx @@ -87,8 +87,8 @@ const LineChart = ( { data, dataKeys = [], colors = [], - showXAxis = true, - showYAxis = true, + showXAxis = false, + showYAxis = false, showTooltip = true, tooltipIndicator = 'dot', // dot, line, dashed tooltipLabelKey, @@ -128,31 +128,29 @@ const LineChart = ( { { showCartesianGrid && } - { showXAxis && ( - - ) } - { showYAxis && ( - - ) } + + { showTooltip && ( Date: Wed, 8 Jan 2025 10:29:17 +0600 Subject: [PATCH 02/17] chore: Lint --- .github/workflows/code-reviewer.yml | 66 ++++++++++++++--------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/.github/workflows/code-reviewer.yml b/.github/workflows/code-reviewer.yml index c1681125..60c464d5 100644 --- a/.github/workflows/code-reviewer.yml +++ b/.github/workflows/code-reviewer.yml @@ -1,43 +1,43 @@ name: BSF Code Reviewer on: - pull_request: - types: [opened, synchronize, edited] + pull_request: + types: [opened, synchronize, edited] permissions: write-all jobs: - CHECK_SHORTCODE: - if: contains(github.event.pull_request.body, '[BSF-PR-SUMMARY]') - runs-on: ubuntu-latest - steps: - - name: Checkout Repository - uses: actions/checkout@v3 + CHECK_SHORTCODE: + if: contains(github.event.pull_request.body, '[BSF-PR-SUMMARY]') + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v3 - - name: WRITE PR SUMMARY - uses: brainstormforce/pull-request-reviewer@master - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - ACTION_CONTEXT: 'CHECK_SHORTCODE' - EXCLUDE_EXTENSIONS: "md, yml, lock" - INCLUDE_EXTENSIONS: "php, js, jsx, ts, tsx, css, scss, html, json" - EXCLUDE_PATHS: "node_modules/" + - name: WRITE PR SUMMARY + uses: brainstormforce/pull-request-reviewer@master + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + ACTION_CONTEXT: 'CHECK_SHORTCODE' + EXCLUDE_EXTENSIONS: 'md, yml, lock' + INCLUDE_EXTENSIONS: 'php, js, jsx, ts, tsx, css, scss, html, json' + EXCLUDE_PATHS: 'node_modules/' - CODE_REVIEW: - needs: CHECK_SHORTCODE - if: always() - runs-on: ubuntu-latest - steps: - - name: Checkout Repository - uses: actions/checkout@v3 + CODE_REVIEW: + needs: CHECK_SHORTCODE + if: always() + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v3 - - name: AI CODE REVIEW - uses: brainstormforce/pull-request-reviewer@master - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - ACTION_CONTEXT: "CODE_REVIEW" - EXCLUDE_EXTENSIONS: "md, yml, lock" - INCLUDE_EXTENSIONS: "php, js, jsx, ts, tsx, css, scss, html, json" - EXCLUDE_PATHS: "node_modules/" \ No newline at end of file + - name: AI CODE REVIEW + uses: brainstormforce/pull-request-reviewer@master + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + ACTION_CONTEXT: 'CODE_REVIEW' + EXCLUDE_EXTENSIONS: 'md, yml, lock' + INCLUDE_EXTENSIONS: 'php, js, jsx, ts, tsx, css, scss, html, json' + EXCLUDE_PATHS: 'node_modules/' From 6dd90c777ae4ab6181d7dcedc5506bbcdd7db4c8 Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Wed, 8 Jan 2025 10:49:33 +0600 Subject: [PATCH 03/17] Updated the cartesian grid style --- src/components/line-chart/line-chart.tsx | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/components/line-chart/line-chart.tsx b/src/components/line-chart/line-chart.tsx index d4a00524..3fdf2be4 100644 --- a/src/components/line-chart/line-chart.tsx +++ b/src/components/line-chart/line-chart.tsx @@ -81,6 +81,18 @@ interface LineChartProps { CategoricalChartProps, 'width' | 'height' | 'data' >; + /** + * The stroke dasharray for the Cartesian grid. + * @default '3 3' + * @see https://recharts.org/en-US/api/CartesianGrid + */ + strokeDasharray?: string; + + /** + * The color of the Cartesian grid lines. + * @default '#E5E7EB' + */ + gridColor?: string; } const LineChart = ( { @@ -103,6 +115,8 @@ const LineChart = ( { chartHeight = 200, withDots = false, lineChartWrapperProps, + strokeDasharray = '3 3', + gridColor = '#E5E7EB', }: LineChartProps ) => { const defaultColors = [ { stroke: '#2563EB' }, { stroke: '#38BDF8' } ]; @@ -127,7 +141,13 @@ const LineChart = ( { return ( - { showCartesianGrid && } + { showCartesianGrid && ( + + ) } Date: Wed, 8 Jan 2025 12:16:58 +0600 Subject: [PATCH 04/17] imprv: Select component search functionality --- src/components/select/select-types.ts | 9 +-- src/components/select/select.tsx | 103 +++++++++++++++----------- src/components/select/utils.ts | 22 ++++++ 3 files changed, 84 insertions(+), 50 deletions(-) create mode 100644 src/components/select/utils.ts diff --git a/src/components/select/select-types.ts b/src/components/select/select-types.ts index b3dc0da9..c3fdd009 100644 --- a/src/components/select/select-types.ts +++ b/src/components/select/select-types.ts @@ -67,6 +67,8 @@ export type SelectProps = { onChange: SelectOnChange; /** Defines the default value of the Select Component. */ defaultValue?: SelectOptionValue | SelectOptionValue[]; + /** Placeholder text for search box. */ + searchPlaceholder?: string; }; export interface SelectPortalProps { @@ -110,11 +112,7 @@ export interface SelectOptionGroupProps { export interface SelectOptionsProps { /** Expects the `Select.Option` or `Select.OptionGroup` children */ - children?: ReactNode; - /** Key used to identify searched value using the key. Default is 'id'. */ - searchBy?: string; - /** Placeholder text for search box. */ - searchPlaceholder?: string; + children: React.ReactNode; /** Additional class name for the Select Options wrapper. */ className?: string; } @@ -164,4 +162,5 @@ export type SelectContextValue = { searchKeyword: string; onChange: SelectOnChange; value?: SelectOptionValue | SelectOptionValue[]; + searchPlaceholder?: string; }; diff --git a/src/components/select/select.tsx b/src/components/select/select.tsx index 25ab0375..1e1efe61 100644 --- a/src/components/select/select.tsx +++ b/src/components/select/select.tsx @@ -51,6 +51,7 @@ import type { SelectSizes, SelectOptionGroupProps, } from './select-types'; +import { getTextContent } from './utils'; // Context to manage the state of the select component. const SelectContext = createContext( @@ -332,8 +333,6 @@ export function SelectOptionGroup( { export function SelectOptions( { children, - searchBy = 'name', // Used to identify searched value using the key. Default is 'id'. - searchPlaceholder = 'Search...', // Placeholder text for search box. className, // Additional class name for the dropdown. }: SelectOptionsProps ) { const { @@ -353,6 +352,7 @@ export function SelectOptions( { searchKeyword, listContentRef, by, + searchPlaceholder, } = useSelectContext(); const initialSelectedValueIndex = useMemo( () => { @@ -379,11 +379,17 @@ export function SelectOptions( { return indexValue; }, [ value, selected, children ] ); + // Initialize active and selected index. useLayoutEffect( () => { setActiveIndex( initialSelectedValueIndex ); setSelectedIndex( initialSelectedValueIndex ); }, [] ); + // Reset active index when search keyword changes. + useLayoutEffect( () => { + setActiveIndex( initialSelectedValueIndex ); + }, [ searchKeyword ] ); + // Render children based on the search keyword. const renderChildren = useMemo( () => { // Track actual visible groups after filtering @@ -402,14 +408,23 @@ export function SelectOptions( { if ( searchKeyword ) { const valueProp = groupChild.props.value; - if ( typeof valueProp === 'object' ) { - return valueProp[ searchBy ] + const exactValue = + typeof valueProp === 'object' + ? valueProp[ by ] + : valueProp; + const textContent = getTextContent( + groupChild.props.children + )?.toLowerCase(); + const searchTerm = searchKeyword.toLowerCase(); + + // For non-object values, search directly in the value and text content + return ( + exactValue + .toString() .toLowerCase() - .includes( searchKeyword.toLowerCase() ); - } - return valueProp - .toLowerCase() - .includes( searchKeyword.toLowerCase() ); + .includes( searchTerm ) || + textContent.includes( searchTerm ) + ); } return true; } ); @@ -458,19 +473,21 @@ export function SelectOptions( { // Handle regular options if ( searchKeyword ) { const valueProp = child.props.value; - if ( typeof valueProp === 'object' ) { - if ( - ! valueProp[ searchBy ] + const textContent = getTextContent( + child.props?.children + )?.toLowerCase(); + const searchTerm = searchKeyword.toLowerCase(); + + const valueMatch = + typeof valueProp === 'object' + ? valueProp[ by ]?.toLowerCase()?.includes( searchTerm ) + : valueProp + .toString() .toLowerCase() - .includes( searchKeyword.toLowerCase() ) - ) { - return null; - } - } else if ( - ! valueProp - .toLowerCase() - .includes( searchKeyword.toLowerCase() ) - ) { + .includes( searchTerm ); + const textMatch = textContent?.includes( searchTerm ); + + if ( ! valueMatch && ! textMatch ) { return null; } } @@ -508,32 +525,26 @@ export function SelectOptions( { return; } - if ( child.props.value ) { - if ( searchKeyword ) { - const valueProp = child.props.value; - if ( typeof valueProp === 'object' ) { - if ( - valueProp[ searchBy ] - .toLowerCase() - .indexOf( searchKeyword.toLowerCase() ) === -1 - ) { - return; - } - } else if ( - valueProp - .toLowerCase() - .indexOf( searchKeyword.toLowerCase() ) === -1 - ) { - return; - } + const textContent = getTextContent( + child.props?.children + )?.toLowerCase(); + const valueProp = child.props.value; + const exactValue = + typeof valueProp === 'object' ? valueProp[ by ] : valueProp; + if ( searchKeyword ) { + const searchTerm = searchKeyword.toLowerCase(); + const valueMatch = exactValue + .toString() + .toLowerCase() + .includes( searchTerm ); + const textMatch = textContent?.includes( searchTerm ); + + if ( ! valueMatch && ! textMatch ) { + return; } - - listContentRef.current.push( - typeof child.props.value === 'object' - ? child.props.value[ searchBy || by ] - : child.props.value - ); } + + listContentRef.current.push( textContent ); } ); }, [ searchKeyword ] ); @@ -748,6 +759,7 @@ const Select = ( { multiple = false, // If true, it will allow multiple selection. combobox = false, // If true, it will show a search box. disabled = false, // If true, it will disable the select component. + searchPlaceholder = 'Search...', // Placeholder text for search box. }: SelectProps ) => { const selectId = useMemo( () => id || `select-${ nanoid() }`, [ id ] ); const isControlled = useMemo( () => typeof value !== 'undefined', [ value ] ); @@ -934,6 +946,7 @@ const Select = ( { setSearchKeyword, disabled, isControlled, + searchPlaceholder, } } > { children } diff --git a/src/components/select/utils.ts b/src/components/select/utils.ts new file mode 100644 index 00000000..23a0896e --- /dev/null +++ b/src/components/select/utils.ts @@ -0,0 +1,22 @@ +import { type ReactNode } from 'react'; + +/** + * Get text content of a node + * @param {ReactNode} node - React node + * @return {string} text content of the node + */ +export const getTextContent = ( node: ReactNode ): string => { + if ( typeof node === 'string' ) { + return node; + } + + if ( typeof node === 'object' && 'textContent' in node! ) { + return node.textContent?.toString().toLowerCase() || ''; + } + + if ( typeof node === 'object' && 'children' in node! ) { + return getTextContent( node.children ); + } + + return ''; +}; From 052009102a910217106d54ddc3fede9d25cf3a54 Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Wed, 8 Jan 2025 13:32:48 +0600 Subject: [PATCH 05/17] Bumped version and updated the change log --- README.md | 4 ++-- changelog.txt | 4 ++++ package.json | 2 +- version.json | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9bed5786..6dc49af3 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Using Force UI as a dependency in package.json - ```json "dependencies": { - "@bsf/force-ui": "git+https://github.com/brainstormforce/force-ui#1.3.5" + "@bsf/force-ui": "git+https://github.com/brainstormforce/force-ui#1.3.6" } ``` @@ -28,7 +28,7 @@ npm install Or you can directly run the following command to install the package - ```bash -npm i -S @bsf/force-ui@git+https://github.com/brainstormforce/force-ui.git#1.3.5 +npm i -S @bsf/force-ui@git+https://github.com/brainstormforce/force-ui.git#1.3.6 ```
diff --git a/changelog.txt b/changelog.txt index 557363ee..521263e0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +Version 1.3.6 - 8th January, 2025 +- Improvement: Optimized the component item search logic and reorganized props for improved usability. +- Fixed: LineChart component Tooltip does not show the required information. + Version 1.3.5 - 6th January, 2025 - Improvement: Display a light blue color on hover when selecting a date range. diff --git a/package.json b/package.json index 480f2431..931a383a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bsf/force-ui", - "version": "1.3.5", + "version": "1.3.6", "description": "Library of components for the BSF project", "main": "./dist/force-ui.js", "module": "./dist/force-ui.js", diff --git a/version.json b/version.json index 7dd2216d..4797dc5a 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "force-ui": "1.3.5" + "force-ui": "1.3.6" } From 93a77de0cdde7488023ec0e6968edbd411e967ba Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Wed, 8 Jan 2025 13:35:50 +0600 Subject: [PATCH 06/17] Update select-atom.stories.tsx --- src/components/select/select-atom.stories.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/select/select-atom.stories.tsx b/src/components/select/select-atom.stories.tsx index de2ad67c..d3e357bc 100644 --- a/src/components/select/select-atom.stories.tsx +++ b/src/components/select/select-atom.stories.tsx @@ -236,13 +236,14 @@ export const SelectWithSearch: Story = ( { combobox={ combobox } disabled={ disabled } onChange={ ( value ) => value } + searchPlaceholder="Search..." > - + { options.map( ( option ) => ( { option.name } From 98cbd2afe9a43db6a62fd2a5a6a3b3ab73fd1fe3 Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Wed, 8 Jan 2025 13:37:50 +0600 Subject: [PATCH 07/17] Update changelog.txt --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index 521263e0..940c8289 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,6 @@ Version 1.3.6 - 8th January, 2025 - Improvement: Optimized the component item search logic and reorganized props for improved usability. +- Improvement: Added a vertical dashed line feature to the LineChart. - Fixed: LineChart component Tooltip does not show the required information. Version 1.3.5 - 6th January, 2025 From 8fbd7b98d85914d94243c680ab4f29442a7e6bc3 Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Wed, 8 Jan 2025 20:01:09 +0600 Subject: [PATCH 08/17] fix: badge label type --- src/components/badge/badge.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/badge/badge.tsx b/src/components/badge/badge.tsx index 1f070bff..23d626e3 100644 --- a/src/components/badge/badge.tsx +++ b/src/components/badge/badge.tsx @@ -6,7 +6,7 @@ export interface BadgeProps { /** * Defines the Label of the badge. */ - label?: string; + label?: ReactNode; /** * Defines the size of the badge. */ From 66be8df8813dccec9eaa7487d27bb80bdd67d3f8 Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Wed, 8 Jan 2025 20:43:41 +0600 Subject: [PATCH 09/17] Replaced displayBy prop with the render function for dev flexibility --- src/components/select/select-types.ts | 8 +- src/components/select/select.tsx | 108 ++++++++++++-------------- 2 files changed, 56 insertions(+), 60 deletions(-) diff --git a/src/components/select/select-types.ts b/src/components/select/select-types.ts index c3fdd009..768f3762 100644 --- a/src/components/select/select-types.ts +++ b/src/components/select/select-types.ts @@ -93,8 +93,12 @@ export interface SelectButtonProps extends AriaAttributes { placeholder?: string; /** Icon to show in the selected option badge (Multi-select mode only). By default it won't show unknown icon. */ optionIcon?: ReactNode | null; - /** Key to display selected item when the selected value is an object. Default value is `name`. */ - displayBy?: string; + /** + * Render function to display the selected option (Must use for multi-select mode). + * For multi-select mode, the selected option will be displayed as a badge but the render function will be used to display the selected options. + * For single-select mode, the render function will be used to display the selected option. + */ + render?: ( selected: SelectOptionValue ) => ReactNode | string; /** Label for the Select component. */ label?: string; /** Additional class name for the Select Button. */ diff --git a/src/components/select/select.tsx b/src/components/select/select.tsx index 1e1efe61..abebead1 100644 --- a/src/components/select/select.tsx +++ b/src/components/select/select.tsx @@ -11,6 +11,7 @@ import { useEffect, useLayoutEffect, Fragment, + type ReactNode, } from 'react'; import { cn } from '@/utilities/functions'; import { CheckIcon, ChevronDown, ChevronsUpDown, Search } from 'lucide-react'; @@ -64,7 +65,7 @@ export function SelectButton( { icon = null, // Icon to show in the select button. placeholder = 'Select an option', // Placeholder text. optionIcon = null, // Icon to show in the selected option. - displayBy = 'name', // Used to display the value. Default is 'name'. + render, label, // Label for the select component. className, ...props @@ -114,20 +115,6 @@ export function SelectButton( { return null; } - if ( typeof children === 'function' ) { - const childProps = { - value: selectedValue as SelectOptionValue, - ...( multiple - ? { - onClose: handleOnCloseItem( - selectedValue as SelectOptionValue - ), - } - : {} ), - }; - return children( childProps ); - } - if ( multiple ) { return ( selectedValue as SelectOptionValue[] ).map( ( valueItem: SelectOptionValue, index: number ) => ( @@ -139,8 +126,8 @@ export function SelectButton( { size={ badgeSize as SelectSizes } onMouseDown={ handleOnCloseItem( valueItem ) } label={ - typeof valueItem === 'object' - ? valueItem[ displayBy ]?.toString() + typeof render === 'function' + ? render( valueItem as SelectOptionValue ) : valueItem.toString() } closable={ true } @@ -150,12 +137,30 @@ export function SelectButton( { ); } - let renderValue = - typeof selectedValue === 'object' - ? ( selectedValue as Record )[ displayBy ] - : selectedValue; + let renderValue: ReactNode = typeof selectedValue === 'string' ? selectedValue : ''; + + if ( typeof render === 'function' ) { + renderValue = render( selectedValue as SelectOptionValue ); + } + + if ( typeof children === 'function' && typeof render !== 'function' ) { + const childProps = { + value: selectedValue as SelectOptionValue, + ...( multiple + ? { + onClose: handleOnCloseItem( + selectedValue as SelectOptionValue + ), + } + : {} ), + }; + renderValue = children( childProps ); + } - if ( isValidElement( children ) ) { + if ( + ( isValidElement( children ) || typeof children === 'string' ) && + typeof render !== 'function' + ) { renderValue = children; } @@ -244,7 +249,7 @@ export function SelectButton( { getValues() && 'flex flex-wrap' ) } > - { /* Show Selected item/items (Multiselector) */ } + { /* Show Selected item/items (Multi-selector) */ } { renderSelected() } { /* Placeholder */ } @@ -353,6 +358,7 @@ export function SelectOptions( { listContentRef, by, searchPlaceholder, + activeIndex, } = useSelectContext(); const initialSelectedValueIndex = useMemo( () => { @@ -365,7 +371,10 @@ export function SelectOptions( { if ( ! isValidElement( child ) ) { return false; } - if ( typeof child.props.value === 'object' ) { + if ( + typeof child.props.value === 'object' && + typeof currentValue === 'object' + ) { return ( child.props.value[ by ] === ( currentValue as Record )[ by ] @@ -377,18 +386,27 @@ export function SelectOptions( { } return indexValue; - }, [ value, selected, children ] ); + }, [ value, selected, children, searchKeyword ] ); // Initialize active and selected index. useLayoutEffect( () => { + if ( isOpen ) { + return; + } setActiveIndex( initialSelectedValueIndex ); setSelectedIndex( initialSelectedValueIndex ); - }, [] ); + }, [ initialSelectedValueIndex, isOpen ] ); // Reset active index when search keyword changes. useLayoutEffect( () => { - setActiveIndex( initialSelectedValueIndex ); - }, [ searchKeyword ] ); + if ( ! isOpen ) { + return; + } + if ( combobox && [ -1, null ].includes( activeIndex ) ) { + return; + } + setActiveIndex( -1 ); + }, [ searchKeyword, isOpen ] ); // Render children based on the search keyword. const renderChildren = useMemo( () => { @@ -407,24 +425,12 @@ export function SelectOptions( { } if ( searchKeyword ) { - const valueProp = groupChild.props.value; - const exactValue = - typeof valueProp === 'object' - ? valueProp[ by ] - : valueProp; const textContent = getTextContent( groupChild.props.children )?.toLowerCase(); const searchTerm = searchKeyword.toLowerCase(); - // For non-object values, search directly in the value and text content - return ( - exactValue - .toString() - .toLowerCase() - .includes( searchTerm ) || - textContent.includes( searchTerm ) - ); + return textContent.includes( searchTerm ); } return true; } ); @@ -472,22 +478,14 @@ export function SelectOptions( { // Handle regular options if ( searchKeyword ) { - const valueProp = child.props.value; const textContent = getTextContent( child.props?.children )?.toLowerCase(); const searchTerm = searchKeyword.toLowerCase(); - const valueMatch = - typeof valueProp === 'object' - ? valueProp[ by ]?.toLowerCase()?.includes( searchTerm ) - : valueProp - .toString() - .toLowerCase() - .includes( searchTerm ); const textMatch = textContent?.includes( searchTerm ); - if ( ! valueMatch && ! textMatch ) { + if ( ! textMatch ) { return null; } } @@ -528,18 +526,11 @@ export function SelectOptions( { const textContent = getTextContent( child.props?.children )?.toLowerCase(); - const valueProp = child.props.value; - const exactValue = - typeof valueProp === 'object' ? valueProp[ by ] : valueProp; if ( searchKeyword ) { const searchTerm = searchKeyword.toLowerCase(); - const valueMatch = exactValue - .toString() - .toLowerCase() - .includes( searchTerm ); const textMatch = textContent?.includes( searchTerm ); - if ( ! valueMatch && ! textMatch ) { + if ( ! textMatch ) { return; } } @@ -603,6 +594,7 @@ export function SelectOptions( { onChange={ ( event ) => setSearchKeyword( event.target.value ) } + value={ searchKeyword } autoComplete="off" /> From 8b7f8a41fa53a0cb1b42fd0903333959d3d28145 Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Wed, 8 Jan 2025 21:12:34 +0600 Subject: [PATCH 10/17] fix: Incorrect initial selection index --- src/components/select/select.tsx | 49 +++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/src/components/select/select.tsx b/src/components/select/select.tsx index abebead1..7226c2cb 100644 --- a/src/components/select/select.tsx +++ b/src/components/select/select.tsx @@ -366,27 +366,42 @@ export function SelectOptions( { let indexValue = -1; if ( currentValue ) { - indexValue = Children.toArray( children ).findIndex( - ( child: React.ReactNode ) => { - if ( ! isValidElement( child ) ) { - return false; - } - if ( - typeof child.props.value === 'object' && - typeof currentValue === 'object' - ) { - return ( - child.props.value[ by ] === - ( currentValue as Record )[ by ] - ); - } - return child.props.value === currentValue; + // Get all children as an array + let allChildren = Children.toArray( children ); + + // If it's an option group, flatten the children + if ( + allChildren.length > 0 && + isValidElement( allChildren[ 0 ] ) && + allChildren[ 0 ].type === SelectOptionGroup + ) { + allChildren = Children.toArray( children ) + .map( ( group ) => + isValidElement( group ) + ? Children.toArray( group.props.children ) + : [] + ) + .flat(); + } + + indexValue = allChildren.findIndex( ( child: React.ReactNode ) => { + if ( ! isValidElement( child ) ) { + return false; } - ); + + const childValue = child.props.value; + + if ( typeof childValue === 'object' && typeof currentValue === 'object' ) { + return childValue[ by ] === ( currentValue as Record )[ by ]; + } + + // For non-object values, do a direct comparison + return childValue === currentValue; + } ); } return indexValue; - }, [ value, selected, children, searchKeyword ] ); + }, [ value, selected, children, by ] ); // Initialize active and selected index. useLayoutEffect( () => { From 5aedae19da13cbf9a3d8be143a8ff14120d657d2 Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Wed, 8 Jan 2025 21:13:11 +0600 Subject: [PATCH 11/17] Updated the select component story stories --- src/components/select/select-atom.stories.tsx | 224 +++++++++++------- 1 file changed, 135 insertions(+), 89 deletions(-) diff --git a/src/components/select/select-atom.stories.tsx b/src/components/select/select-atom.stories.tsx index d3e357bc..83dd6f95 100644 --- a/src/components/select/select-atom.stories.tsx +++ b/src/components/select/select-atom.stories.tsx @@ -1,6 +1,8 @@ import type { Meta, StoryFn } from '@storybook/react'; import Select from './select'; import { expect, userEvent, within, screen } from '@storybook/test'; +import { SelectOptionValue } from './select-types'; +import { useState } from 'react'; const options = [ { id: '1', name: 'Red' }, @@ -64,34 +66,44 @@ export default meta; type Story = StoryFn; // Single Select Story -export const SingleSelect: Story = ( { size, multiple, combobox, disabled } ) => ( -
- -
-); +export const SingleSelect: Story = ( { size, multiple, combobox, disabled } ) => { + const [ selected, setSelected ] = useState( null ); + return ( +
+ +
+ ); +}; SingleSelect.args = { size: 'md', @@ -136,6 +148,9 @@ const SelectWithoutPortalTemplate: Story = ( { multiple ? 'Select multiple options' : 'Select an option' } label={ multiple ? 'Select Multiple Colors' : 'Select a Color' } + render={ ( selected ) => + ( selected as Record )?.name + } /> { options.map( ( option ) => ( @@ -157,33 +172,44 @@ SingleSelectWithoutPortal.args = { }; // Multi-select Story -export const MultiSelect: Story = ( { size, multiple, combobox, disabled } ) => ( -
- -
-); +export const MultiSelect: Story = ( { size, multiple, combobox, disabled } ) => { + const [ selected, setSelected ] = useState( [] ); + return ( +
+ +
+ ); +}; MultiSelect.args = { size: 'md', @@ -241,6 +267,9 @@ export const SelectWithSearch: Story = ( { + ( selected as Record )?.name + } /> @@ -301,41 +330,58 @@ const GroupedSelectTemplate: Story = ( { multiple, combobox, disabled, -} ) => ( -
- + setSelectedValue( value as SelectOptionValue ) } - label={ multiple ? 'Select Multiple Colors' : 'Select a Color' } - /> - - - { groupedOptions.map( ( group ) => ( - - { group.options.map( ( option ) => ( - - { option.name } - - ) ) } - - ) ) } - - - -
-); + value={ selectedValue as SelectOptionValue } + > + + ( selected as Record )?.name + } + /> + + + { groupedOptions.map( ( group ) => ( + + { group.options.map( ( option ) => ( + + { option.name } + + ) ) } + + ) ) } + + + + + ); +}; export const GroupedSelect = GroupedSelectTemplate.bind( {} ); GroupedSelect.args = { From f179288b242ce07f81380fb0d52724ef38437660 Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Wed, 8 Jan 2025 21:13:40 +0600 Subject: [PATCH 12/17] chore: Lint --- src/components/select/select.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/select/select.tsx b/src/components/select/select.tsx index 7226c2cb..87dec5d9 100644 --- a/src/components/select/select.tsx +++ b/src/components/select/select.tsx @@ -137,7 +137,8 @@ export function SelectButton( { ); } - let renderValue: ReactNode = typeof selectedValue === 'string' ? selectedValue : ''; + let renderValue: ReactNode = + typeof selectedValue === 'string' ? selectedValue : ''; if ( typeof render === 'function' ) { renderValue = render( selectedValue as SelectOptionValue ); @@ -391,8 +392,14 @@ export function SelectOptions( { const childValue = child.props.value; - if ( typeof childValue === 'object' && typeof currentValue === 'object' ) { - return childValue[ by ] === ( currentValue as Record )[ by ]; + if ( + typeof childValue === 'object' && + typeof currentValue === 'object' + ) { + return ( + childValue[ by ] === + ( currentValue as Record )[ by ] + ); } // For non-object values, do a direct comparison From 4e2b22930b3799473e6adcdaab0b278a75a109e8 Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Wed, 8 Jan 2025 21:15:10 +0600 Subject: [PATCH 13/17] Update changelog.txt --- changelog.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 940c8289..f735fbf6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,6 @@ Version 1.3.6 - 8th January, 2025 -- Improvement: Optimized the component item search logic and reorganized props for improved usability. +- Improvement: Optimized the Select component item search logic and reorganized props for improved usability. +- Improvement: Updated Select component props and logic for better useability. - Improvement: Added a vertical dashed line feature to the LineChart. - Fixed: LineChart component Tooltip does not show the required information. From de0a4fe4b154534740534f8ff0a9b9d3ed098937 Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Wed, 8 Jan 2025 21:15:25 +0600 Subject: [PATCH 14/17] Update changelog.txt --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index f735fbf6..c8a5db6c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,4 @@ -Version 1.3.6 - 8th January, 2025 +Version 1.3.6 - 9th January, 2025 - Improvement: Optimized the Select component item search logic and reorganized props for improved usability. - Improvement: Updated Select component props and logic for better useability. - Improvement: Added a vertical dashed line feature to the LineChart. From d3606fbda5df9ea132b97820dc6610a4a5dda078 Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Thu, 9 Jan 2025 09:51:56 +0600 Subject: [PATCH 15/17] Update changelog.txt --- changelog.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index c8a5db6c..0a067a28 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,5 @@ Version 1.3.6 - 9th January, 2025 - Improvement: Optimized the Select component item search logic and reorganized props for improved usability. -- Improvement: Updated Select component props and logic for better useability. - Improvement: Added a vertical dashed line feature to the LineChart. - Fixed: LineChart component Tooltip does not show the required information. From c35423b3c11bf0baa9651fad3ad37deb68b82646 Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Thu, 9 Jan 2025 10:59:42 +0600 Subject: [PATCH 16/17] Updated stories --- .../admin-settings-SureCart.stories.jsx | 22 ++- .../onboarding-smtp-connect.stories.jsx | 6 +- .../onboarding-profile.stories.jsx | 180 ++++++++++-------- 3 files changed, 117 insertions(+), 91 deletions(-) diff --git a/src/templates/admin-settings-SureCart/admin-settings-SureCart.stories.jsx b/src/templates/admin-settings-SureCart/admin-settings-SureCart.stories.jsx index 672b50db..5757fbbe 100644 --- a/src/templates/admin-settings-SureCart/admin-settings-SureCart.stories.jsx +++ b/src/templates/admin-settings-SureCart/admin-settings-SureCart.stories.jsx @@ -490,16 +490,16 @@ const Template = ( args ) => { onChange={ () => {} } placeholder="Select an option" size="md" + by="value" combobox > + selected.label + } /> - + { CURRENCY_OPTIONS.map( ( optionItem ) => ( { placeholder="Select an option" size="md" combobox - by="label" + by="value" > + selected.label + } /> { placeholder="Select an option" size="md" combobox - by="label" + by="value" > + selected.label + } /> { onChange={ () => {} } placeholder="Select an option" size="md" + by="id" > - + selected.name } + /> { onChange={ () => {} } placeholder="Select an option" size="md" + by="id" > - - - - Personal Website - - - Company Website - - - Client Website - - + selected.name } + /> + + + + Personal Website + + + Company Website + + + Client Website + + +
@@ -134,34 +140,40 @@ const Template = ( args ) => { onChange={ () => {} } placeholder="Select an option" size="md" + by="id" > - - - - Personal Website - - - Company Website - - - Client Website - - + selected.name } + /> + + + + Personal Website + + + Company Website + + + Client Website + + +
@@ -169,34 +181,40 @@ const Template = ( args ) => { onChange={ () => {} } placeholder="Select an option" size="md" + by="id" > - - - - Personal Contact - - - Company Contact - - - Client Contact - - + selected.name } + /> + + + + Personal Contact + + + Company Contact + + + Client Contact + + +
From 5ebccc2d49805447fee7997e94b0f8dea4025bd1 Mon Sep 17 00:00:00 2001 From: Jaied Al Sabid <87969327+jaieds@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:04:26 +0600 Subject: [PATCH 17/17] Updated select component stories --- src/components/select/select-atom.stories.tsx | 2 +- src/components/select/select.stories.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/select/select-atom.stories.tsx b/src/components/select/select-atom.stories.tsx index 83dd6f95..d3162e1f 100644 --- a/src/components/select/select-atom.stories.tsx +++ b/src/components/select/select-atom.stories.tsx @@ -47,9 +47,9 @@ const meta: Meta = { subcomponents: { 'Select.Button': Select.Button, 'Select.Portal': Select.Portal, + 'Select.OptionGroup': Select.OptionGroup, 'Select.Options': Select.Options, 'Select.Option': Select.Option, - 'Select.OptionGroup': Select.OptionGroup, } as Record>, parameters: { layout: 'centered', diff --git a/src/components/select/select.stories.tsx b/src/components/select/select.stories.tsx index de2aba34..f501658d 100644 --- a/src/components/select/select.stories.tsx +++ b/src/components/select/select.stories.tsx @@ -9,6 +9,7 @@ const meta: Meta = { subcomponents: { 'Select.Button': Select.Button, 'Select.Portal': Select.Portal, + 'Select.OptionGroup': Select.OptionGroup, 'Select.Options': Select.Options, 'Select.Option': Select.Option, } as Record>,