@@ -13,7 +13,11 @@ import { useListContext } from '../controller/list/useListContext';
1313
1414export default { title : 'ra-core/form/FilterLiveForm' } ;
1515
16- const TextInput = ( { defaultValue = '' , ...props } : InputProps ) => {
16+ const TextInput = ( {
17+ defaultValue = '' ,
18+ style,
19+ ...props
20+ } : InputProps & { style ?: React . CSSProperties } ) => {
1721 const { field, fieldState } = useInput ( { defaultValue, ...props } ) ;
1822 const { error } = fieldState ;
1923
@@ -24,12 +28,13 @@ const TextInput = ({ defaultValue = '', ...props }: InputProps) => {
2428 display : 'flex' ,
2529 flexDirection : 'column' ,
2630 gap : '5px' ,
31+ ...style ,
2732 } }
2833 >
29- < label htmlFor = { field . name } id = { `id-${ field . name } ` } >
34+ < label htmlFor = { `id-${ field . name } ` } >
3035 { props . label || field . name }
3136 </ label >
32- < input { ...field } aria-labelledby = { `id-${ field . name } ` } />
37+ < input { ...field } id = { `id-${ field . name } ` } />
3338 { error && (
3439 < div style = { { color : 'red' } } >
3540 { /* @ts -ignore */ }
@@ -143,6 +148,31 @@ export const MultipleFilterLiveForm = () => {
143148 ) ;
144149} ;
145150
151+ export const MultipleFilterLiveFormOverlapping = ( ) => {
152+ const listContext = useList ( {
153+ data : [
154+ { id : 1 , title : 'Hello' , has_newsletter : true } ,
155+ { id : 2 , title : 'World' , has_newsletter : false } ,
156+ ] ,
157+ filter : {
158+ category : 'deals' ,
159+ } ,
160+ } ) ;
161+ return (
162+ < ListContextProvider value = { listContext } >
163+ < FilterLiveForm >
164+ < TextInput source = "title" />
165+ < TextInput source = "body" />
166+ </ FilterLiveForm >
167+ < FilterLiveForm >
168+ < TextInput source = "author" />
169+ < TextInput source = "body" />
170+ </ FilterLiveForm >
171+ < FilterValue />
172+ </ ListContextProvider >
173+ ) ;
174+ } ;
175+
146176export const PerInputValidation = ( ) => {
147177 const listContext = useList ( {
148178 data : [
@@ -206,3 +236,109 @@ const FilterValue = () => {
206236 </ div >
207237 ) ;
208238} ;
239+
240+ const ExternalList = ( ) => {
241+ const [ body , setBody ] = React . useState < string | undefined > ( undefined ) ;
242+ const { filterValues, setFilters, data } = useListContext ( ) ;
243+ React . useEffect ( ( ) => {
244+ setBody ( filterValues . body ) ;
245+ } , [ filterValues ] ) ;
246+ const onChange = ( event : React . ChangeEvent < HTMLInputElement > ) => {
247+ setBody ( event . target . value ) ;
248+ } ;
249+ const onApplyFilter = ( ) => {
250+ setFilters ( { ...filterValues , body } ) ;
251+ } ;
252+ return (
253+ < div
254+ style = { {
255+ padding : '1em' ,
256+ border : '2px solid gray' ,
257+ } }
258+ >
259+ < p > External list</ p >
260+ < div
261+ style = { {
262+ display : 'flex' ,
263+ flexDirection : 'row' ,
264+ gap : '5px' ,
265+ } }
266+ >
267+ < label htmlFor = "id_body" > body</ label >
268+ < input
269+ id = "id_body"
270+ type = "text"
271+ value = { body || '' }
272+ onChange = { onChange }
273+ />
274+ < button type = "button" onClick = { onApplyFilter } >
275+ Apply filter
276+ </ button >
277+ </ div >
278+ { data . length ? (
279+ < ul >
280+ { data . map ( item => (
281+ < li key = { item . id } >
282+ { item . id } - { item . title } - { item . body }
283+ </ li >
284+ ) ) }
285+ </ ul >
286+ ) : (
287+ < p > No data</ p >
288+ ) }
289+ </ div >
290+ ) ;
291+ } ;
292+
293+ const ClearFiltersButton = ( ) => {
294+ const { setFilters } = useListContext ( ) ;
295+ return (
296+ < div style = { { margin : '1em' } } >
297+ < button
298+ type = "button"
299+ onClick = { ( ) => {
300+ setFilters ( { } ) ;
301+ } }
302+ >
303+ Clear filters
304+ </ button >
305+ </ div >
306+ ) ;
307+ } ;
308+
309+ export const WithExternalChanges = ( ) => {
310+ const [ mounted , setMounted ] = React . useState ( true ) ;
311+ const onToggle = ( ) => {
312+ setMounted ( mounted => ! mounted ) ;
313+ } ;
314+ const listContext = useList ( {
315+ data : [
316+ { id : 1 , title : 'hello' , body : 'foo' } ,
317+ { id : 2 , title : 'world' , body : 'bar' } ,
318+ ] ,
319+ } ) ;
320+ return (
321+ < div >
322+ < input
323+ id = "id_mounted"
324+ type = "checkbox"
325+ onChange = { onToggle }
326+ checked = { mounted }
327+ />
328+ < label htmlFor = "id_mounted" > Mount/unmount</ label >
329+ { mounted && (
330+ < ListContextProvider value = { listContext } >
331+ < FilterLiveForm >
332+ < TextInput
333+ source = "title"
334+ style = { { flexDirection : 'row' } }
335+ />
336+ < ClearFiltersButton />
337+ </ FilterLiveForm >
338+ < ExternalList />
339+ < FilterValue />
340+ </ ListContextProvider >
341+ ) }
342+ </ div >
343+ ) ;
344+ } ;
0 commit comments