-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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
feat(cdk-experimental/ui-patterns): listbox ui pattern #30495
Conversation
afdc290
to
3e8455d
Compare
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.
First batch of comments, I'm still going
src/cdk-experimental/ui-patterns/behaviors/event-manager/event-manager.ts
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/event-manager/event-manager.ts
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/event-manager/event-manager.ts
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/event-manager/event-manager.ts
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/event-manager/event-manager.ts
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/event-manager/event-manager.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/event-manager/event-manager.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/event-manager/event-manager.ts
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/event-manager/keyboard-event-manager.ts
Outdated
Show resolved
Hide resolved
* An event manager that is specialized for handling mouse events. By default this manager stops | ||
* propagation and prevents default on all events it handles. |
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'm not sure that pointer events should always preventDefault and stopPropogation the way that keyboard events do. What's your thinking here?
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.
There was no thinking on this, I wasn't really sure what the default behaviors should be. This is just what I put in the prototype.
Thinking about it more right now, I would suggest:
keyboard:
- preventDefualt (yes)
- stopPropagation (yes? - motivation for this is things like stacks of dialog, menu, etc where escape should probably close the top one, not all of them)
mouse:
- preventDefault (no - e.g. this is probably not desired for mousedown where preventDefault would cancel focusing of the element)
- stopPropagation (maybe? not really sure about this one)
Anyways that's just my thought for the default defaults. People could always create a manager with different defaults new KeydownEventManager({preventDefault: false})
or register a handler with a different setting than the manager's default manager.on('x', () => {...}, {preventDefault: false})
src/cdk-experimental/ui-patterns/behaviors/event-manager/mouse-event-manager.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/event-manager/keyboard-event-manager.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/event-manager/keyboard-event-manager.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/event-manager/event-manager.ts
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/event-manager/mouse-event-manager.ts
Outdated
Show resolved
Hide resolved
'cdk-experimental/popover-edit', | ||
'cdk-experimental/scrolling', | ||
'cdk-experimental/selection', | ||
'cdk-experimental/table-scroll-container', | ||
'cdk-experimental/ui-patterns', |
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.
Why don't we call this patterns
? The ui-
seems a bit redundant.
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.
@jelbourn Do you recall the reason for keeping the ui-
prefix?
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 the ui-
, patterns
by itself makes me think of like GoF design patterns or something
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.
Yeah, the thinking was that just "patterns" by itself was too 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.
Isn't everything we do related to building UI though? It seems a bit redundant to have it in the name. Then again, if we don't intend to make this public it might not matter 🤷♂️
label = input<string>(); | ||
|
||
/** The text used by the typeahead search. */ | ||
searchTerm = computed(() => this.label() ?? this.element().textContent); |
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.
Should we make the label required so we don't have to hit the DOM every time the computed
runs?
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.
IMO the devex is worth the performance cost in this case. If I understand correctly, this computed will only rerun if the label is set/unset or if the element changes (which I would assume is rare)
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 think that initially it runs so the runtime can figure out the dependencies and afterwards it only runs on changes. That being said, it might be a bit misleading because it's not going to update if the textContent
changes. I expect it might come up, given that we had to account for it in mat-option
: https://github.com/angular/components/blob/main/src/material/core/option/option.ts#L267
My thinking was that it's easier to introduce it later than having consumers depend on it and us having to change it later.
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.
That's a good point, I hadn't considered the text content changing. I still lean against making the label required because I think it's too much boilerplate. Would it be ok to leave this for a follow-up PR so that we can discuss when we review the public API design doc?
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.
Another option can be to only derive the label from the input and if there isn't one, we just don't do typeahead.
src/cdk-experimental/ui-patterns/behaviors/event-manager/event-manager.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/event-manager/event-manager.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/event-manager/event-manager.ts
Outdated
Show resolved
Hide resolved
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.
LGTM for dev-infra; leaving naming to others
9d6a824
to
89cb225
Compare
src/cdk-experimental/ui-patterns/behaviors/list-focus/list-focus.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/list-focus/list-focus.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/list-navigation/list-navigation.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/list-navigation/list-navigation.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/list-selection/list-selection.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/list-selection/list-selection.ts
Outdated
Show resolved
Hide resolved
multiselectable: Signal<boolean>; | ||
|
||
/** The ids of the current selected items. */ | ||
selectedIds: WritableSignal<string[]>; |
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 necessarily for this PR, but one thing we should discuss in a bit more detail is how we're managing selected IDs, since I worry that the array isn't the best data structure vs. a Set
, but we don't have a pattern established yet for a Set
that plays well with signals
src/cdk-experimental/ui-patterns/behaviors/list-typeahead/list-typeahead.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/list-typeahead/list-typeahead.ts
Outdated
Show resolved
Hide resolved
src/components-examples/cdk-experimental/listbox/cdk-listbox/cdk-listbox-example.css
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/list-focus/list-focus.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/list-navigation/list-navigation.ts
Outdated
Show resolved
Hide resolved
src/cdk-experimental/ui-patterns/behaviors/list-navigation/list-navigation.ts
Show resolved
Hide resolved
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.
LGTM aside from a last few minor comments
private readonly _generatedId = inject(_IdGenerator).getId('cdk-option-'); | ||
|
||
/** A unique identifier for the option. */ | ||
protected id = computed(() => this._generatedId); |
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 can be a TODO / cleanup for a next PR, but these generally shouldn't be computed
for things that won't change.
I think the reason that you're doing this is because the e.g. OptionInputs
expects a signal. However, you don't really want those to be a Signal<T>
, but instead a () => T
(which would also make the types work for Wiz) . You could optionally introduce a convenience type for this that's something like
export type Reactive<T> = () => T;
We probably want to do this before build too many more ___Input
types
No description provided.