-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: Add subdialog support to Menu and Autocomplete #7561
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
Changes from all commits
db04fec
2f7cb82
c3fece1
34ab703
e63c5fd
5e3fb0b
30e6762
c4fc772
19f9eaa
222807e
b3f3ecd
931c28e
fdc40c5
a1bd7f5
cc954c2
016bb1a
2e581cf
f27a766
5cb78be
a2c87ed
43ab42f
7f4a779
19251e1
7af516b
61d812a
9922dd7
fec56ff
d1e9eef
eab66a8
0d2f41d
5a32a08
04a1782
dbee21e
0198298
14e7403
b81d9dd
9b81a2c
ca935d7
237b30e
426681e
0dc6d84
4b3bc0c
6d5cec9
e66a8e2
5b49889
f6b7272
0b75f85
a5573cd
65b105e
77148f5
1e394d2
e03daa4
30c517c
46c90a0
057f60c
506312f
7862d51
1eaa17c
3fae6be
43b3595
3929cef
7fd803a
08b8c1a
dc2dbb4
6d3d377
7be3d10
3dee094
8f6724f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
diff --git a/dist/cjs/document/prepareDocument.js b/dist/cjs/document/prepareDocument.js | ||
index 39a24b8f2ccdc52739d130480ab18975073616cb..0c3f5199401c15b90230c25a02de364eeef3e297 100644 | ||
--- a/dist/cjs/document/prepareDocument.js | ||
+++ b/dist/cjs/document/prepareDocument.js | ||
@@ -30,7 +30,7 @@ function prepareDocument(document) { | ||
const initialValue = UI.getInitialValue(el); | ||
if (initialValue !== undefined) { | ||
if (el.value !== initialValue) { | ||
- dispatchEvent.dispatchDOMEvent(el, 'change'); | ||
+ el.dispatchEvent(new Event('change')); | ||
} | ||
UI.clearInitialValue(el); | ||
} | ||
diff --git a/dist/cjs/utils/focus/getActiveElement.js b/dist/cjs/utils/focus/getActiveElement.js | ||
index d25f3a8ef67e856e43614559f73012899c0b53d7..4ed9ee45565ed438ee9284d8d3043c0bd50463eb 100644 | ||
--- a/dist/cjs/utils/focus/getActiveElement.js | ||
+++ b/dist/cjs/utils/focus/getActiveElement.js | ||
@@ -6,6 +6,8 @@ function getActiveElement(document) { | ||
const activeElement = document.activeElement; | ||
if (activeElement === null || activeElement === undefined ? undefined : activeElement.shadowRoot) { | ||
return getActiveElement(activeElement.shadowRoot); | ||
+ } else if (activeElement && activeElement.tagName === 'IFRAME') { | ||
+ return getActiveElement(activeElement.contentWindow.document); | ||
} else { | ||
// Browser does not yield disabled elements as document.activeElement - jsdom does | ||
if (isDisabled.isDisabled(activeElement)) { |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -126,7 +126,7 @@ | |
"@testing-library/dom": "^10.1.0", | ||
"@testing-library/jest-dom": "^5.16.5", | ||
"@testing-library/react": "^15.0.7", | ||
"@testing-library/user-event": "^14.6.1", | ||
"@testing-library/user-event": "patch:@testing-library/user-event@npm%3A14.6.1#~/.yarn/patches/@testing-library-user-event-npm-14.6.1-5da7e1d4e2.patch", | ||
"@types/react": "npm:[email protected]", | ||
"@types/react-dom": "npm:[email protected]", | ||
"@types/storybook__react": "^4.0.2", | ||
|
@@ -234,7 +234,8 @@ | |
"@types/react-dom": "npm:[email protected]", | ||
"recast": "0.23.6", | ||
"ast-types": "0.16.1", | ||
"svgo": "^3" | ||
"svgo": "^3", | ||
"@testing-library/user-event@npm:^14.4.0": "patch:@testing-library/user-event@npm%3A14.6.1#~/.yarn/patches/@testing-library-user-event-npm-14.6.1-5da7e1d4e2.patch" | ||
}, | ||
"@parcel/transformer-css": { | ||
"cssModules": { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -228,7 +228,7 @@ export class BaseCollection<T> implements ICollection<Node<T>> { | |
let clonedSection: Mutable<CollectionNode<T>> = (node as CollectionNode<T>).clone(); | ||
let lastChildInSection: Mutable<CollectionNode<T>> | null = null; | ||
for (let child of this.getChildren(node.key)) { | ||
if (filterFn(child.textValue) || child.type === 'header') { | ||
if (shouldKeepNode(child, filterFn, this, newCollection)) { | ||
let clonedChild: Mutable<CollectionNode<T>> = (child as CollectionNode<T>).clone(); | ||
// eslint-disable-next-line max-depth | ||
if (lastChildInSection == null) { | ||
|
@@ -288,22 +288,25 @@ export class BaseCollection<T> implements ICollection<Node<T>> { | |
lastNode = clonedSeparator; | ||
newCollection.addNode(clonedSeparator); | ||
} | ||
} else if (filterFn(node.textValue)) { | ||
} else { | ||
// At this point, the node is either a subdialogtrigger node or a standard row/item | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. weirdly specific comment about subdialogtriggers, can we generalize a little more of what is going on? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah this whole method has had a TODO comment above it for a while. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can refactor this to move a lot of this logic into Menu/ListBox, but I want to do that separately and not block this PR any further. |
||
let clonedNode: Mutable<CollectionNode<T>> = (node as CollectionNode<T>).clone(); | ||
if (newCollection.firstKey == null) { | ||
newCollection.firstKey = clonedNode.key; | ||
} | ||
if (shouldKeepNode(clonedNode, filterFn, this, newCollection)) { | ||
if (newCollection.firstKey == null) { | ||
newCollection.firstKey = clonedNode.key; | ||
} | ||
|
||
if (lastNode != null && (lastNode.type !== 'section' && lastNode.type !== 'separator') && lastNode.parentKey === clonedNode.parentKey) { | ||
lastNode.nextKey = clonedNode.key; | ||
clonedNode.prevKey = lastNode.key; | ||
} else { | ||
clonedNode.prevKey = null; | ||
} | ||
if (lastNode != null && (lastNode.type !== 'section' && lastNode.type !== 'separator') && lastNode.parentKey === clonedNode.parentKey) { | ||
lastNode.nextKey = clonedNode.key; | ||
clonedNode.prevKey = lastNode.key; | ||
} else { | ||
clonedNode.prevKey = null; | ||
} | ||
|
||
clonedNode.nextKey = null; | ||
newCollection.addNode(clonedNode); | ||
lastNode = clonedNode; | ||
clonedNode.nextKey = null; | ||
newCollection.addNode(clonedNode); | ||
lastNode = clonedNode; | ||
} | ||
} | ||
} | ||
|
||
|
@@ -322,3 +325,22 @@ export class BaseCollection<T> implements ICollection<Node<T>> { | |
return newCollection; | ||
} | ||
} | ||
|
||
function shouldKeepNode<T>(node: Node<T>, filterFn: (nodeValue: string) => boolean, oldCollection: BaseCollection<T>, newCollection: BaseCollection<T>): boolean { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't really follow what this function is for, can we get some comments There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Definitely can do when we settle on the form of the collection node filtering. For now, this function basically checks if a given node in the collection should be retained based on its text value versus the filterFn that the user has provided (aka typical case is that the filterFn should return true if the current autocomplete string is a part of the node's text value). There is extra logic in here specifically for the subdialogtrigger/submenutrigger case where we need to look up the first child of those nodes (aka the wrapped menu item) to extract the text value associated with the trigger. Said child also then needs to be added to the newCollection (aka the filtered collection), otherwise we'd only be adding the wrapper node |
||
if (node.type === 'subdialogtrigger' || node.type === 'submenutrigger') { | ||
// Subdialog wrapper should only have one child, if it passes the filter add it to the new collection since we don't need to | ||
// do any extra handling for its first/next key | ||
let triggerChild = [...oldCollection.getChildren(node.key)][0]; | ||
if (triggerChild && filterFn(triggerChild.textValue)) { | ||
let clonedChild: Mutable<CollectionNode<T>> = (triggerChild as CollectionNode<T>).clone(); | ||
newCollection.addNode(clonedChild); | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} else if (node.type === 'header') { | ||
return true; | ||
} else { | ||
return filterFn(node.textValue); | ||
} | ||
} |
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.
fyi i opened a pr against userEvent to add this patch