Skip to content

Commit

Permalink
feat: add dropdown
Browse files Browse the repository at this point in the history
  • Loading branch information
philippfromme committed Jan 10, 2025
1 parent 2b167d9 commit cafc7ce
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 18 deletions.
36 changes: 36 additions & 0 deletions src/assets/properties-panel.css
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,42 @@
font-family: inherit;
}

.bio-properties-panel-textfield-dropdown-wrapper {
position: relative;
}

.bio-properties-panel-textfield-dropdown {
display: none;
position: absolute;
top: 100%;
left: 0;
width: 100%;
z-index: 100;
background-color: var(--color-grey-225-10-95);
border: 1px solid var(--color-grey-225-10-75);
}

.bio-properties-panel-textfield-dropdown-open {
display: block;
}

.bio-properties-panel-textfield-dropdown-options {
list-style: none;
padding: 0;
margin: 0;
}

.bio-properties-panel-textfield-dropdown-option {
padding: 2px 6px;
}

.bio-properties-panel-textfield-dropdown-option:focus,
.bio-properties-panel-textfield-dropdown-option:hover,
.bio-properties-panel-textfield-dropdown-option-selected {
background-color: var(--color-blue-205-100-50);
color: var(--color-white);
}

.bio-properties-panel-input[type=number],
select.bio-properties-panel-input,
textarea.bio-properties-panel-input,
Expand Down
131 changes: 113 additions & 18 deletions src/components/entries/TextField.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import {

import classnames from 'classnames';

import { isFunction } from 'min-dash';
import { isFunction, set } from 'min-dash';

Check failure on line 12 in src/components/entries/TextField.js

View workflow job for this annotation

GitHub Actions / Build (macos-latest, 20)

'set' is defined but never used. Allowed unused vars must match /^_/u

Check failure on line 12 in src/components/entries/TextField.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, 20)

'set' is defined but never used. Allowed unused vars must match /^_/u

Check failure on line 12 in src/components/entries/TextField.js

View workflow job for this annotation

GitHub Actions / Build (windows-latest, 20)

'set' is defined but never used. Allowed unused vars must match /^_/u

import {
useError,
useShowEntryEvent
} from '../../hooks';
import classNames from 'classnames';

function Textfield(props) {

Expand All @@ -24,14 +25,32 @@ function Textfield(props) {
id,
label,
onInput,
onFocus,
onBlur,
onFocus: _onFocus,
onBlur: _onBlur,
placeholder,
value = '',
tooltip
tooltip,
dropdown = {
options: [
{
value: 'foo'
},
{
value: 'bar'
},
{
value: 'baz'
}
],
text: 'Foo bar!'
}
} = props;

const [ localValue, setLocalValue ] = useState(value || '');
const [ dropdownOptions, setDropdownOptions ] = useState([]);
const [ dropdownOpen, setDropdownOpen ] = useState(false);
const [ dropdownOptionSelected, setDropdownOptionSelected ] = useState(0);
const [ isFocused, setIsFocused ] = useState(false);

const ref = useShowEntryEvent(id);

Expand All @@ -44,6 +63,31 @@ function Textfield(props) {
setLocalValue(e.target.value);
};

const onFocus = e => {
setIsFocused(true);
isFunction(_onFocus) && _onFocus(e);
};

const onBlur = e => {
setIsFocused(false);
isFunction(_onBlur) && _onBlur(e);
};

const onKeydown = e => {
if (isFocused && e.key === 'Escape') {
setDropdownOpen(false);
} else if (isFocused && e.key === 'ArrowUp') {
e.preventDefault();
setDropdownOptionSelected(Math.max(0, dropdownOptionSelected - 1));
} else if (isFocused && e.key === 'ArrowDown') {
e.preventDefault();
setDropdownOptionSelected(Math.min(dropdownOptions.length - 1, dropdownOptionSelected + 1));
} else if (isFocused && e.key === 'Enter') {
handleInput({ target: { value: dropdownOptions[dropdownOptionSelected].value } });
setDropdownOpen(false);
}
};

useEffect(() => {
if (value === localValue) {
return;
Expand All @@ -52,27 +96,78 @@ function Textfield(props) {
setLocalValue(value);
}, [ value ]);

useEffect(() => {
if (!dropdown) {
return;
}

setDropdownOptions(dropdown.options.filter(option => option.value.startsWith(localValue)));
}, [ localValue ]);

useEffect(() => {
setDropdownOpen(dropdownOptions.length > 0 && isFocused);
setDropdownOptionSelected(Math.max(Math.min(dropdownOptions.length - 1, dropdownOptionSelected), 0));
}, [ dropdownOptions, isFocused ]);

useEffect(() => {
if (!dropdownOpen) {
setDropdownOptionSelected(0);
}
}, [ dropdownOpen ]);

console.log('selected', dropdownOptionSelected);

return (
<div class="bio-properties-panel-textfield">
<label for={ prefixId(id) } class="bio-properties-panel-label">
<Tooltip value={ tooltip } forId={ id } element={ props.element }>
{ label }
</Tooltip>
</label>
<input
ref={ ref }
id={ prefixId(id) }
type="text"
name={ id }
spellCheck="false"
autoComplete="off"
disabled={ disabled }
class="bio-properties-panel-input"
onInput={ handleInput }
onFocus={ onFocus }
onBlur={ onBlur }
placeholder={ placeholder }
value={ localValue } />
<div class="bio-properties-panel-textfield-dropdown-wrapper">
<input
ref={ ref }
id={ prefixId(id) }
type="text"
name={ id }
spellCheck="false"
autoComplete="off"
disabled={ disabled }
class="bio-properties-panel-input"
onInput={ handleInput }
onKeyDown={ onKeydown }
onFocus={ onFocus }
onBlur={ onBlur }
placeholder={ placeholder }
value={ localValue } />
{
dropdownOpen && <div class={
classNames('bio-properties-panel-textfield-dropdown', {
'bio-properties-panel-textfield-dropdown-open': true
})
}>
{
dropdownOptions.length && <ul class="bio-properties-panel-textfield-dropdown-options">
{
dropdownOptions.map((option, index) => {
return <li
class={
classNames('bio-properties-panel-textfield-dropdown-option', {
'bio-properties-panel-textfield-dropdown-option-selected': dropdownOptionSelected === index
})
}
key={ index }
onClick={ () => handleInput({ target: { value: option.value } }) }
>
{ option.value }
</li>;
})
}
</ul>
}
</div>
}
</div>
</div>
);
}
Expand Down

0 comments on commit cafc7ce

Please sign in to comment.