Skip to content

Commit

Permalink
Simple search added in select component & version updated
Browse files Browse the repository at this point in the history
  • Loading branch information
neilveil committed Oct 14, 2023
1 parent d918004 commit 97f7069
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 128 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "mumpui",
"description": "A light-weight flexible & elegant design system for developers.",
"version": "1.2.1",
"version": "1.3.0",
"main": "dist/index.js",
"author": "neilveil",
"repository": "neilveil/mumpui",
Expand Down
20 changes: 16 additions & 4 deletions src/lib/components/select/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type props = Omit<React.InputHTMLAttributes<HTMLDivElement>, 'onChange' | 'value
value?: option
onChange?: (value?: option) => void
onSearch?: (search: string) => void
simpleSearch?: boolean
placeholder?: any
clearable?: boolean
disabled?: boolean
Expand All @@ -27,6 +28,7 @@ export default function Main({
options = [],
onChange,
onSearch,
simpleSearch,
placeholder,
clearable = false,
disabled = false,
Expand All @@ -36,6 +38,7 @@ export default function Main({
...props
}: props) {
const [optionsVisible, setOptionsVisible] = useState(false)
const [_search, _setSearch] = useState('')

className = 'mumpui mp-select ' + (disabled ? 'mp-disabled ' : '') + (className || '')

Expand All @@ -56,10 +59,18 @@ export default function Main({
if (onSearch) onSearch('')
if (onChange) onChange(selected)
setOptionsVisible(false)
_setSearch('')
}

const _onSearch = (search: string = '') => {
if (onSearch) onSearch(search)
if (simpleSearch) _setSearch(search)
}

if (value) options = options.filter(x => value.key !== x.key)

if (_search) options = search(_search, options)

return (
<div
{...props}
Expand All @@ -70,26 +81,27 @@ export default function Main({
>
<div className='mp-select-single'>{value ? valueHOC(value) : placeholder}</div>

{optionsVisible && !!(options.length || onSearch) && (
{optionsVisible && !!(options.length || onSearch || simpleSearch) && (
<div className='mp-input-expanded-area'>
{!!(onSearch || clearable) && (
{!!(onSearch || simpleSearch || clearable) && (
<div
className='mp-select-area'
onClick={e => {
e.preventDefault()
e.stopPropagation()
}}
>
{onSearch ? (
{onSearch || simpleSearch ? (
<input
placeholder='Search..'
onChange={e => onSearch && onSearch(e.target.value)}
onChange={e => _onSearch(e.target.value)}
onKeyUp={e => {
if (e.key === 'Enter') {
if (options.length) _onSelect(options[0])
}
}}
className='mp-select-search'
onBlur={() => _setSearch('')}
autoFocus
/>
) : (
Expand Down
21 changes: 17 additions & 4 deletions src/lib/components/select/multi.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React, { useEffect, useRef, useState } from 'react'
import { type option } from '.'
import search from './search'

type multiple = Omit<React.InputHTMLAttributes<HTMLDivElement>, 'onChange' | 'value'> & {
options?: option[]
value?: option[]
onChange?: (value: option[]) => void
onSearch?: (search: string) => void
simpleSearch?: boolean
placeholder?: any
clearable?: boolean
disabled?: boolean
Expand All @@ -18,6 +20,7 @@ export default function Main({
options = [],
onChange,
onSearch,
simpleSearch,
placeholder,
clearable = false,
disabled = false,
Expand All @@ -26,6 +29,7 @@ export default function Main({
...props
}: multiple) {
const [optionsVisible, setOptionsVisible] = useState(false)
const [_search, _setSearch] = useState('')

className = 'mumpui mp-select ' + (disabled ? 'mp-disabled ' : '') + (className || '')

Expand All @@ -45,6 +49,7 @@ export default function Main({
const _onChange = (selected: option) => {
if (onSearch) onSearch('')
if (onChange) onChange(value.concat(selected))
_setSearch('')

const inputEl = ref.current.querySelector('input')
if (inputEl) {
Expand All @@ -53,6 +58,11 @@ export default function Main({
}
}

const _onSearch = (search: string = '') => {
if (onSearch) onSearch(search)
if (simpleSearch) _setSearch(search)
}

const selectedKey = value.map(x => x.key)

const valueEl = value.map((x, i) => (
Expand All @@ -71,6 +81,8 @@ export default function Main({

options = options.filter(x => !selectedKey.includes(x.key))

if (_search) options = search(_search, options)

return (
<div
{...props}
Expand All @@ -81,25 +93,26 @@ export default function Main({
>
<div className='mp-select-multi'>{value.length ? valueEl : placeholder}</div>

{optionsVisible && !!(options.length || onSearch) && (
{optionsVisible && !!(options.length || onSearch || simpleSearch) && (
<div className='mp-input-expanded-area'>
{!!(onSearch || clearable) && (
{!!(onSearch || simpleSearch || clearable) && (
<div
className='mp-select-area'
onClick={e => {
e.preventDefault()
e.stopPropagation()
}}
>
{onSearch ? (
{onSearch || simpleSearch ? (
<input
placeholder='Search..'
onChange={e => onSearch && onSearch(e.target.value)}
onChange={e => _onSearch(e.target.value)}
onKeyUp={e => {
if (e.key === 'Enter') {
if (options.length) _onChange(options[0])
}
}}
onBlur={() => _setSearch('')}
className='mp-select-search'
autoFocus
/>
Expand Down
77 changes: 46 additions & 31 deletions src/pages/docs/multiSelect/index.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,58 @@
import { Docs } from 'components'
import { Field, Select } from 'lib'
import { Field, Fields, Select } from 'lib'
import { useState } from 'react'
import * as snippets from './snippets'
import data from 'data'

export default function Main() {
const [options, setOptions] = useState(data.countries)
const [value, setValue] = useState<typeof data.countries>([data.countries[0]])

return (
<Docs name='multiSelect'>
<Docs.Showcase code={snippets.s1}>
<Field label='Multi-Select' style={{ maxWidth: '15rem' }}>
<Select.Multi options={data.countries} value={value} onChange={value => setValue(value)} />
</Field>
</Docs.Showcase>
<Fields autoCol>
<Field label='Multi-Select'>
<Select.Multi
value={value}
onChange={value => setValue(value)}
options={data.countries}
placeholder='Select..'
/>
</Field>

<Field label='Multi-Select with search'>
<Select.Multi
value={value}
onChange={value => setValue(value)}
options={data.countries}
simpleSearch
placeholder='Select..'
/>
</Field>
</Fields>

<Fields autoCol>
<Field label='Multi-Select with clear'>
<Select.Multi
value={value}
onChange={value => setValue(value)}
options={data.countries}
clearable
placeholder='Select..'
/>
</Field>

<Docs.Showcase title='Multi-Select component with search or clear only' code={snippets.s2}>
<Field label='Multi-Select with search & clear' style={{ maxWidth: '15rem' }}>
<Select.Multi
value={value}
onChange={value => setValue(value)}
options={options}
onSearch={search => setOptions(Select.search(search, data.countries))}
clearable
placeholder='Select..'
/>
</Field>
<Field label='Multi-Select with search & clear'>
<Select.Multi
value={value}
onChange={value => setValue(value)}
options={data.countries}
simpleSearch
clearable
placeholder='Select..'
/>
</Field>
</Fields>
</Docs.Showcase>

<Docs.Props
Expand All @@ -38,27 +64,16 @@ export default function Main() {
{ name: 'value', type: 'array', usage: 'Array of selected option objects containing key & label' },
{ name: 'onChange', type: 'function', usage: '' },
{ name: 'placeholder', type: 'string' },
{ name: 'onSearch', type: 'function', usage: 'Shows search box only if search function is passed' },
{ name: 'simpleSearch', type: 'function', usage: 'Show search box in dropdown' },
{ name: 'onSearch', type: 'function', usage: 'For advanced search implementation' },
{ name: 'clearable', type: 'boolean', usage: '' },
{ name: 'disabled', type: 'boolean', usage: '' }
]}
/>

{/* All the changes belows also need to be done in select docs */}

<Docs.Props
title='Select.search'
type='function'
fields={[
{ name: 'search', type: 'string', usage: 'Searched text' },
{ name: 'options', type: 'array', usage: 'Select input field options' },
{ name: 'caseSensitive', type: 'boolean', defaultValue: 'false' }
]}
/>

<Docs.Info>
A basic text based <code>Search</code> method is provied with <code>Select</code> component. For calling API or
any other functionality, search method need to be implemented.
any other functionality, search method need to be implemented with <code>onSearch</code>.
</Docs.Info>
</Docs>
)
Expand Down
73 changes: 43 additions & 30 deletions src/pages/docs/multiSelect/snippets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,49 @@ const [value, setValue] = useState([${JSON.stringify(data.countries[0])}])
..
<Field label='Multi-Select' style={{ maxWidth: '15rem' }}>
<Select.Multi
options={countries}
value={value}
onChange={value => setValue(value)}
/>
</Field>
..
const countries = ${JSON.stringify(data.countries, null, 2)}
`

export const s2 = `
const [options, setOptions] = useState(countries)
const [value, setValue] = useState([${JSON.stringify(data.countries[0])}])
..
<Field label='Multi-Select with search & clear' style={{ maxWidth: '15rem' }}>
<Select.Multi
value={value}
onChange={value => setValue(value)}
options={options}
onSearch={search => setOptions(Select.search(search, countries))}
clearable
placeholder='Select..'
/>
</Field>
<Fields autoCol>
<Field label='Multi-Select'>
<Select.Multi
value={value}
onChange={value => setValue(value)}
options={countries}
placeholder='Select..'
/>
</Field>
<Field label='Multi-Select with search'>
<Select.Multi
value={value}
onChange={value => setValue(value)}
options={countries}
simpleSearch
placeholder='Select..'
/>
</Field>
</Fields>
<Fields autoCol>
<Field label='Multi-Select with clear'>
<Select.Multi
value={value}
onChange={value => setValue(value)}
options={countries}
clearable
placeholder='Select..'
/>
</Field>
<Field label='Multi-Select with search & clear'>
<Select.Multi
value={value}
onChange={value => setValue(value)}
options={countries}
simpleSearch
clearable
placeholder='Select..'
/>
</Field>
</Fields>
..
Expand Down
Loading

0 comments on commit 97f7069

Please sign in to comment.