Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(FilterBar): remove reference copying of filter/input elements #6214

Merged
merged 28 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b2be620
wip
Lukas742 Jul 19, 2024
a35ccd9
Merge branch 'main' into feat/fb-fully-control
Lukas742 Aug 9, 2024
1842834
Merge branch 'main' into feat/fb-fully-control
Lukas742 Aug 9, 2024
61186e8
Merge branch 'main' into feat/fb-fully-control
Lukas742 Aug 12, 2024
bce4adb
wip
Lukas742 Aug 14, 2024
abf428e
fix reordering
Lukas742 Aug 16, 2024
c85b9d8
events, cleanup, lint, search filter
Lukas742 Aug 16, 2024
30ca319
Update TestComp.tsx
Lukas742 Aug 16, 2024
0beb0c8
update `onFiltersDialogClose`
Lukas742 Aug 16, 2024
da5da40
Update index.tsx
Lukas742 Aug 16, 2024
4c1ca44
fix and improve "With Logic" story
Lukas742 Aug 16, 2024
3fbbc54
cleanup, reorder story, save event fix
Lukas742 Aug 19, 2024
a207d23
add React portal, fix dynamic page story
Lukas742 Aug 19, 2024
46a0e8c
add `onReorder` event
Lukas742 Aug 19, 2024
c05ca51
cleanup stories
Lukas742 Aug 19, 2024
367a0aa
fix tests, `onReorder` optional, cleanup
Lukas742 Aug 19, 2024
e82f59e
Merge branch 'main' into feat/fb-fully-control
Lukas742 Aug 19, 2024
6b61358
cleanup, fix dialog filter length with values, docs
Lukas742 Aug 20, 2024
239592f
add data-attr for identifying origin of input events
Lukas742 Aug 20, 2024
f7f5344
remove breaking change todos
Lukas742 Aug 20, 2024
1883d0e
FilterGroupItem: MigrationGuide
Lukas742 Aug 20, 2024
264e7ff
Migration Guide, remove `portalContainer` (again)
Lukas742 Aug 20, 2024
9fbcda4
Revert Portals.mdx
Lukas742 Aug 20, 2024
57dbd44
replace wcr Toolbar with ui5wc Toolbar
Lukas742 Aug 20, 2024
39b9c1d
cleanup
Lukas742 Aug 20, 2024
c4e2f50
fix `hideToolbar`, fix tests
Lukas742 Aug 20, 2024
424b821
Update FilterBar.cy.tsx
Lukas742 Aug 21, 2024
1081ba1
Update FilterBar.cy.tsx
Lukas742 Aug 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .storybook/components/FilterBarExample.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.filterBarDemo {
padding: 1rem;
border: var(--sapElement_BorderWidth) solid var(--sapNeutralBorderColor);
border-radius: var(--sapElement_BorderCornerRadius);
}

.filterBarDemo [ui5-dialog] {
max-height: 80vh;
}
234 changes: 234 additions & 0 deletions .storybook/components/FilterBarExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
import TitleLevel from '@ui5/webcomponents/dist/types/TitleLevel.js';
import { useReducer, useRef, useState } from 'react';
import {
DatePicker,
FilterBar,
FilterBarPropTypes,
FilterGroupItem,
FlexBox,
FlexBoxDirection,
Input,
Label,
MultiComboBox,
MultiComboBoxItem,
Option,
Select,
StepInput,
Text,
ThemeProvider,
Title
} from '@ui5/webcomponents-react';
import classes from './FilterBarExample.module.css';

const initialState = {
age: 37,
countries: {},
currency: 'USD',
date: '',
search: ''
};

function reducer(state, action) {
switch (action.type) {
case 'SET_AGE':
return { ...state, age: action.payload };
case 'SET_COUNTRIES':
return { ...state, countries: action.payload };
case 'SET_CURRENCY':
return { ...state, currency: action.payload };
case 'SET_DATE':
return { ...state, date: action.payload };
case 'SET_SEARCH':
return { ...state, search: action.payload };
case 'SET_STATE':
return { ...state, ...action.payload };
case 'DIALOG_RESTORE':
return action.payload;
default:
return state;
}
}

export function FilterBarExample() {
const [filterState, dispatch] = useReducer(reducer, initialState);
const { age, countries, currency, date, search } = filterState;
const dialogStateRef = useRef({});
const [visibleChildrenByKey, setVisibleChildrenByKey] = useState<Record<string, boolean>>({
'0': true,
'1': true,
'2': true
});
const [orderedFilterKeys, setOrderedFilterKeys] = useState(['0', '1', '2', '3']);

const handleSearch = (e) => {
dispatch({ type: 'SET_SEARCH', payload: e.target.value });
};
const handleAgeChange = (e) => {
const { value } = e.target;
if (e.currentTarget.parentElement.dataset.inFiltersDialog) {
dialogStateRef.current.age = value;
} else {
dispatch({ type: 'SET_AGE', payload: value });
}
};

const handleCountriesChange = (e) => {
const newCountries = e.detail.items.reduce((acc, cur) => {
return { ...acc, [cur.getAttribute('text').toLowerCase()]: true };
}, {});
if (e.currentTarget.parentElement.dataset.inFiltersDialog) {
dialogStateRef.current.countries = newCountries;
} else {
dispatch({ type: 'SET_COUNTRIES', payload: newCountries });
}
};

const handleCurrencyChange = (e) => {
const currency = e.detail.selectedOption.textContent;
if (e.currentTarget.parentElement.dataset.inFiltersDialog) {
dialogStateRef.current.currency = currency;
} else {
dispatch({ type: 'SET_CURRENCY', payload: currency });
}
};

const handleDateChange = (e) => {
const { value } = e.target;
if (e.currentTarget.parentElement.dataset.inFiltersDialog) {
dialogStateRef.current.date = value;
} else if (e.detail.valid) {
dispatch({ type: 'SET_DATE', payload: value });
}
};

const handleFiltersDialogSave: FilterBarPropTypes['onFiltersDialogSave'] = (e) => {
setOrderedFilterKeys(e.detail.reorderedFilterKeys);
setVisibleChildrenByKey(
e.detail.selectedFilterKeys.reduce((acc, cur) => {
acc[cur] = true;
return acc;
}, {})
);
dispatch({ type: 'SET_STATE', payload: dialogStateRef.current });
};

return (
<ThemeProvider>
<div className={classes.filterBarDemo}>
<Text>
The FilterBar applies filter changes inside the FilterBar immediately and inside the dialog only after 'OK'
has been pressed.
</Text>
<FilterBar
header={
<Title level={TitleLevel.H2} size={TitleLevel.H4}>
Apply changes after dialog save
</Title>
}
enableReordering
onFiltersDialogSave={handleFiltersDialogSave}
search={<Input onInput={handleSearch} />}
>
{orderedFilterKeys.map((filterKey) => {
const isHidden = !visibleChildrenByKey[filterKey];
switch (filterKey) {
case '0':
return (
<FilterGroupItem key={0} filterKey="0" label="Age" required>
<StepInput value={age} onChange={handleAgeChange} required />
</FilterGroupItem>
);
case '1':
return (
<FilterGroupItem
key={1}
filterKey="1"
label="Countries"
active={Object.keys(countries).length > 0}
hiddenInFilterBar={isHidden}
>
<MultiComboBox onSelectionChange={handleCountriesChange}>
<MultiComboBoxItem text="Argentina" selected={countries.argentina} />
<MultiComboBoxItem text="Bulgaria" selected={countries.bulgaria} />
<MultiComboBoxItem text="Finland" selected={countries.finland} />
<MultiComboBoxItem text="Germany" selected={countries.germany} />
<MultiComboBoxItem text="Ireland" selected={countries.ireland} />
<MultiComboBoxItem text="Ukraine" selected={countries.ukraine} />
<MultiComboBoxItem text="USA" selected={countries.usa} />
</MultiComboBox>
</FilterGroupItem>
);
case '2':
return (
<FilterGroupItem
key={2}
filterKey="2"
label="Currency"
active={!!currency}
hiddenInFilterBar={isHidden}
>
<Select onChange={handleCurrencyChange}>
<Option additionalText="€" selected={currency === 'EUR'}>
EUR
</Option>
<Option additionalText="$" selected={currency === 'USD'}>
USD
</Option>
<Option additionalText="£" selected={currency === 'GBP'}>
GBP
</Option>
<Option additionalText="₺" selected={currency === 'TRY'}>
TRY
</Option>
<Option additionalText="¥" selected={currency === 'JPY'}>
JPY
</Option>
</Select>
</FilterGroupItem>
);
case '3':
return (
<FilterGroupItem key={3} filterKey="3" label="Date" active={!!date} hiddenInFilterBar={isHidden}>
<DatePicker value={date} onChange={handleDateChange} style={{ minWidth: 'auto' }} />
</FilterGroupItem>
);
default:
return null;
}
})}
</FilterBar>
<FlexBox direction={FlexBoxDirection.Column}>
<FlexBox>
<Label showColon>Search</Label>
<Text>{search}</Text>
</FlexBox>
<FlexBox>
<Label showColon>Age</Label>
<Text>{age}</Text>
</FlexBox>
<FlexBox>
<Label showColon>Countries</Label>
<Text>{JSON.stringify(countries)}</Text>
</FlexBox>
<FlexBox>
<Label showColon>Currency</Label>
<Text>{currency}</Text>
</FlexBox>
<FlexBox>
<Label showColon>Date</Label>
<Text>{date}</Text>
</FlexBox>
<hr style={{ width: '100%' }} />
<FlexBox>
<Label showColon>Visible Filters</Label>
<Text>{Object.keys(visibleChildrenByKey).join(', ')}</Text>
</FlexBox>
<FlexBox>
<Label showColon>Filters Order</Label>
<Text>{orderedFilterKeys.join(', ')}</Text>
</FlexBox>
</FlexBox>
</div>
</ThemeProvider>
);
}
19 changes: 10 additions & 9 deletions .storybook/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
export * from './ArgTypesWithNote';
export * from './ControlsWithNote';
export * from './DocsHeader';
export * from './Footer';
export * from './ProductsTable';
export * from './ProjectTemplate';
export * from './TableOfContent';
export * from './LabelWithWrapping';
export * from './CommandsAndQueries';
export * from './ArgTypesWithNote.js';
export * from './ControlsWithNote.js';
export * from './DocsHeader.js';
export * from './Footer.js';
export * from './ProductsTable.js';
export * from './ProjectTemplate.js';
export * from './TableOfContent.js';
export * from './LabelWithWrapping.js';
export * from './CommandsAndQueries.js';
export * from './FilterBarExample.js';
Loading
Loading