@stellar-expert/ui-framework 1.19.0 → 1.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/filter/filter-view.js +16 -7
- package/index.d.ts +1 -1
- package/interaction/dialog.js +10 -4
- package/interaction/dialog.scss +13 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1048,9 +1048,9 @@ import {FilterView, parseFiltersFromQuery} from '@stellar-expert/ui-framework'
|
|
|
1048
1048
|
onChange={filters => setActiveFilters(filters)}/>
|
|
1049
1049
|
```
|
|
1050
1050
|
|
|
1051
|
-
#### `parseFiltersFromQuery()`
|
|
1051
|
+
#### `parseFiltersFromQuery(fields)`
|
|
1052
1052
|
|
|
1053
|
-
Parses and validates filter parameters from the current URL query string against
|
|
1053
|
+
Parses and validates filter parameters from the current URL query string against passed field definitions. Returns an object with matched filter key-value pairs.
|
|
1054
1054
|
|
|
1055
1055
|
---
|
|
1056
1056
|
|
package/filter/filter-view.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, {useCallback, useEffect, useState} from 'react'
|
|
2
|
-
import {parseQuery} from '@stellar-expert/navigation'
|
|
2
|
+
import {navigation, parseQuery} from '@stellar-expert/navigation'
|
|
3
3
|
import deepmerge from 'deepmerge'
|
|
4
4
|
import {Dropdown} from '../controls/dropdown'
|
|
5
5
|
import {resolveFilterEditor} from './filter-editors'
|
|
@@ -10,10 +10,16 @@ let fieldDescriptionMapping = {}
|
|
|
10
10
|
function FilterCondition({field, value, setValue, removeFilter, edit}) {
|
|
11
11
|
const updateValue = useCallback(function (value) {
|
|
12
12
|
setValue(field, value)
|
|
13
|
+
//reset cursor when apply filter
|
|
14
|
+
navigation.updateQuery({cursor: undefined})
|
|
13
15
|
}, [field, setValue])
|
|
14
16
|
|
|
15
17
|
const removeValue = useCallback(function () {
|
|
16
18
|
removeFilter(field, value)
|
|
19
|
+
//reset cursor when remove applied filter
|
|
20
|
+
if (!!value) {
|
|
21
|
+
navigation.updateQuery({cursor: undefined})
|
|
22
|
+
}
|
|
17
23
|
}, [field, value, removeFilter])
|
|
18
24
|
|
|
19
25
|
const childProps = {value, edit}
|
|
@@ -27,19 +33,22 @@ function FilterCondition({field, value, setValue, removeFilter, edit}) {
|
|
|
27
33
|
return <span className="filter-condition condensed" title={edit ? '' : filter.description}>
|
|
28
34
|
<span className={'icon-' + filter.icon}/>
|
|
29
35
|
{title} {React.createElement(editor, childProps)}
|
|
30
|
-
{removeFilter ?
|
|
36
|
+
{removeFilter ?
|
|
37
|
+
<a href="#" className="icon-delete-circle" onClick={removeValue} title="Remove filter"/> :
|
|
38
|
+
!!setValue ? <>  </> : <> </>}
|
|
31
39
|
</span>
|
|
32
40
|
}
|
|
33
41
|
/**
|
|
34
42
|
* Parses and validates filter parameters from the current URL query string
|
|
43
|
+
* @param {object} [fields] - Custom filter field definitions
|
|
35
44
|
* @return {object}
|
|
36
45
|
*/
|
|
37
|
-
export function parseFiltersFromQuery() {
|
|
46
|
+
export function parseFiltersFromQuery(fields = fieldDescriptionMapping) {
|
|
38
47
|
const params = parseQuery()
|
|
39
48
|
const filters = {}
|
|
40
49
|
let isEmpty = true
|
|
41
50
|
for (const [key, value] of Object.entries(params)) {
|
|
42
|
-
const filterDescriptor =
|
|
51
|
+
const filterDescriptor = fields[key]
|
|
43
52
|
if (!filterDescriptor)
|
|
44
53
|
continue //skip unrelated query parameters
|
|
45
54
|
filters[key] = value
|
|
@@ -124,10 +133,10 @@ export function FilterView({presetFilter, fields = {}, onChange}) {
|
|
|
124
133
|
}, [onChange])
|
|
125
134
|
|
|
126
135
|
useEffect(() => {
|
|
127
|
-
const queryParams = parseFiltersFromQuery()
|
|
136
|
+
const queryParams = parseFiltersFromQuery(fields)
|
|
128
137
|
setFilters(queryParams)
|
|
129
138
|
updateExternalFilters(queryParams)
|
|
130
|
-
}, [])
|
|
139
|
+
}, [fields])
|
|
131
140
|
|
|
132
141
|
|
|
133
142
|
const replaceFilter = useCallback((field, value) => setTimeout(() => setFilters(prev => {
|
|
@@ -202,7 +211,7 @@ export function FilterView({presetFilter, fields = {}, onChange}) {
|
|
|
202
211
|
<div className="mobile-only micro-space"/>
|
|
203
212
|
<span className="icon-filter"/> Filters 
|
|
204
213
|
<FiltersGroup filters={presetFilter}/>
|
|
205
|
-
<FiltersGroup filters={readyFilters} replaceFilter={replaceFilter} removeFilter={removeFilter}/>
|
|
214
|
+
<FiltersGroup filters={readyFilters} replaceFilter={replaceFilter} removeFilter={!editorMode ? removeFilter : null}/>
|
|
206
215
|
{!editorMode ?
|
|
207
216
|
<Dropdown title={title} options={availableFields} onChange={addFilter}/> :
|
|
208
217
|
<div className="micro-space">
|
package/index.d.ts
CHANGED
|
@@ -1207,7 +1207,7 @@ export interface FilterViewProps {
|
|
|
1207
1207
|
export function FilterView(props: FilterViewProps): React.ReactElement;
|
|
1208
1208
|
|
|
1209
1209
|
/** Parse and validate filter parameters from the current URL query string */
|
|
1210
|
-
export function parseFiltersFromQuery(): Record<string, any>;
|
|
1210
|
+
export function parseFiltersFromQuery(fields: FilterFieldDescriptor): Record<string, any>;
|
|
1211
1211
|
|
|
1212
1212
|
// ============================================================================
|
|
1213
1213
|
// Stellar Utilities
|
package/interaction/dialog.js
CHANGED
|
@@ -1,28 +1,34 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
+
import {createPortal} from 'react-dom'
|
|
2
3
|
import PropTypes from 'prop-types'
|
|
4
|
+
import cn from 'classnames'
|
|
3
5
|
import './dialog.scss'
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Modal dialog
|
|
7
9
|
* @param {boolean} dialogOpen - Whether a dialog is shown
|
|
10
|
+
* @param {boolean} [big] - Increases dialog max-width to 42em
|
|
11
|
+
* @param {string} [className] - Extra CSS classes for the dialog container
|
|
8
12
|
* @param {*} children - Dialog content
|
|
9
13
|
* @return {JSX.Element|null}
|
|
10
14
|
* @constructor
|
|
11
15
|
*/
|
|
12
|
-
export const Dialog = React.memo(function Dialog({dialogOpen, children}) {
|
|
16
|
+
export const Dialog = React.memo(function Dialog({dialogOpen, big, className, children}) {
|
|
13
17
|
if (!dialogOpen)
|
|
14
18
|
return null
|
|
15
|
-
return <div className="dialog">
|
|
19
|
+
return createPortal(<div className="dialog">
|
|
16
20
|
<div className="dialog-backdrop"/>
|
|
17
21
|
<div className="dialog-content container">
|
|
18
|
-
<div className=
|
|
22
|
+
<div className={cn('container', {big}, className)}>
|
|
19
23
|
{children}
|
|
20
24
|
</div>
|
|
21
25
|
</div>
|
|
22
|
-
</div
|
|
26
|
+
</div>, document.body)
|
|
23
27
|
})
|
|
24
28
|
|
|
25
29
|
Dialog.propTypes = {
|
|
26
30
|
dialogOpen: PropTypes.bool,
|
|
31
|
+
big: PropTypes.bool,
|
|
32
|
+
className: PropTypes.string,
|
|
27
33
|
children: PropTypes.any
|
|
28
34
|
}
|
package/interaction/dialog.scss
CHANGED
|
@@ -20,16 +20,28 @@
|
|
|
20
20
|
> .dialog-content {
|
|
21
21
|
display: flex;
|
|
22
22
|
flex-direction: column;
|
|
23
|
-
|
|
23
|
+
align-items: center;
|
|
24
|
+
overflow-y: auto;
|
|
24
25
|
height: 100%;
|
|
25
26
|
|
|
27
|
+
&::before,
|
|
28
|
+
&::after {
|
|
29
|
+
content: '';
|
|
30
|
+
flex: 1 0 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
> .container {
|
|
34
|
+
margin: $space-standard 0;
|
|
27
35
|
background: var(--color-bg);
|
|
28
36
|
border: 1px solid var(--color-contrast-border);
|
|
29
37
|
border-radius: $border-radius-input;
|
|
30
38
|
box-shadow: 0 2px 4px 0 var(--color-modal-bg);
|
|
31
39
|
padding: $space-micro $space-standard $space-standard;
|
|
32
40
|
max-width: 32em;
|
|
41
|
+
|
|
42
|
+
&.big {
|
|
43
|
+
max-width: 42em;
|
|
44
|
+
}
|
|
33
45
|
}
|
|
34
46
|
}
|
|
35
47
|
}
|