-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
QueryList itemRenderer prop & renderItem method #1877
Conversation
…ates to itemRenderer prop makes for much simpler item rendering!
fix the testsPreview: documentation |
Merge branch 'master' of github.com:palantir/blueprint into gg/querylist-modifiersPreview: documentation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
overall API breaks lgtm
) : ( | ||
undefined | ||
); | ||
|
||
return ( | ||
<FilmMultiSelect | ||
{...Films} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is pretty confusing / too clever. please refactor to export something like multiSelectProps
from the "./films" module
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
then you also wouldn't have awkward looking code like type Film = Films.Film;
@@ -108,4 +113,27 @@ export const TOP_100_FILMS = [ | |||
{ title: "Monty Python and the Holy Grail", year: 1975 }, | |||
].map((m, index) => ({ ...m, rank: index + 1 })); | |||
|
|||
export type Film = typeof TOP_100_FILMS[0]; | |||
export type Film = typeof items[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would rather just make this an interface so its usage is more obvious in the other files.
interface IFilm {
...
}
|
||
// TODO: not happy with this name | ||
/** Whether this item matches the predicate. A typical renderer could hide `false` values. */ | ||
filtered: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about matchesFilter: boolean
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure, but matchesPredicate
would be more accurate (itemPredicate
etc), and now we're getting verbose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure, yeah, makes sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like item
totally separate from props in general
* An object describing how to render a particular item. | ||
* An `itemRenderer` receives the item as its first argument, and this object as its second argument. | ||
*/ | ||
export interface IItemRendererProps { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the benefit of splitting the props/modifier? Why is it no longer generic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it was only generic for the item: T
field -- everything else has well-defined types.
also item
is the only user-supplied field; the others are derived from other props and state. so now the derived fields are in a separate place and can be reused across renders, rather than being forced to create a new object just to change item
.
|
||
// TODO: not happy with this name | ||
/** Whether this item matches the predicate. A typical renderer could hide `false` values. */ | ||
filtered: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specifically having a "filtered" prop is a little confusing; why is filtering special vs any other thing that users might want to do
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filtering is one of QueryList
's existential features: itemPredicate
/ itemListPredicate
.
this API sets us up to support arbitrary user-defined modifiers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming comments
/** Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top */ | ||
export const TOP_100_FILMS = [ | ||
export const items = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: why not UPPER_CASE?
item, | ||
}), | ||
); | ||
private renderItems({ items, renderItem }: IQueryListRendererProps<T>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure where IQueryListRendererProps
is defined, but i think this should be itemRenderer
/** Whether this item is disabled and should ignore interactions. */ | ||
disabled: boolean; | ||
|
||
// TODO: not happy with this name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename or not. remove comment.
* `QueryList` will retrieve modifiers for the item and delegate to `itemRenderer` prop for the actual rendering. | ||
* The second parameter `index` is optional here; if provided, it will be passed through `itemRenderer` props. | ||
*/ | ||
renderItem: (item: T, index?: number) => JSX.Element; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
itemRenderer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nope, this is a method given to you, not a prop you define.
@@ -107,6 +108,13 @@ export interface IQueryListRendererProps<T> extends IProps { | |||
*/ | |||
handleKeyUp: React.KeyboardEventHandler<HTMLElement>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this be onKeyUp
for the prop? handle[Event]
is for method names, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a method passed to the renderer. hard to tell without context above.
modifiers.filtered => modifiers.matchesPredicatePreview: documentation | landing | table |
@adidahiya this should be ready to go as well! |
@@ -11,18 +11,16 @@ import * as React from "react"; | |||
import * as sinon from "sinon"; | |||
|
|||
// this is an awkward import across the monorepo, but we'd rather not introduce a cyclical dependency or create another package |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in a future PR, we should move this to packages/select/src/__fixtures__/
. then you'd do the import from "@blueprintjs/select/src/__fixtures__/films"
btw we'd want to .npmignore
__tests__
and __fixtures__
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool yes i like that
Please read the new docs in
select-component.md
(including diffs in example code)!Looking for feedback on these changes. I think this is mostly an improvement but I need validation. 😬
API breaks ahead and no new features (yet) but this refactor greatly reduces duplication and enables desirable improvements like
disabled
support (through modifiers).Notable Changes
🤞 - denotes future / wishlist / proposals; cool stuff this feature enables down the road.
new
ItemRenderer<T>
type uses two arguments so theProps
bag doesn't need to be generic. also allows fornull
return values. (eventually, 🤞 props bag can be stored in state and intelligently diffed, rather than reconstructed in every render.)QueryList
IItemModifiers
for data about how to render. this sets us up fordisabled
support [Labs] MultiSelect needs a disabled prop #1834, and maybe even 🤞 user-defined modifiers a la react-day-picker or Popper.js!move
itemRenderer
prop definition toQueryList
itself (because every component redefined it exactly).add
renderItem
method inIQueryListRendererProps
that retrieves modifiers and delegates toitemRenderer
prop. makes for much simpler item rendering!refactor examples to share a common renderer and predicate implementation, and rename the data file to
films
.