-
Notifications
You must be signed in to change notification settings - Fork 92
feat(list): Add support for dragging items. #7109
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 48 commits
59f1968
ceea051
0478bb0
84cd376
49ce1f8
ae85ebc
5bcd803
2eae6be
befbfea
bf8ecad
84502ef
88a9258
9a7b80d
5ef19b2
de11b60
ccc748e
8ab64fe
0cacf88
a2acfdb
ccf0a9a
628c09f
a553935
9b6dd24
f010af2
24e20e9
1c922ba
d0eae6a
19e9eff
d06d16f
980a144
9b6c5eb
e4943b0
69c3138
bbf9a68
d20bea8
99e5e12
f97ceea
3580920
f1f94c7
202b9e7
ca77444
83fb4c0
98acf7d
b7eb538
4b4329a
e174a94
162cd5e
f820923
f826ce0
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 |
|---|---|---|
| @@ -1,3 +1,7 @@ | ||
| { | ||
| "dragHandle": "Drag handle" | ||
| "dragHandle": "Drag handle", | ||
| "dragHandleActive": "Reordering {itemLabel}, current position {position} of {total}.", | ||
| "dragHandleChange": "{itemLabel}, new position {position} of {total}. Press space to confirm.", | ||
| "dragHandleCommit": "{itemLabel}, current position {position} of {total}.", | ||
| "dragHandleIdle": "{itemLabel}, press space and use arrow keys to reorder content. Current position {position} of {total}." | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,7 @@ | ||
| { | ||
| "dragHandle": "Drag handle" | ||
| "dragHandle": "Drag handle", | ||
| "dragHandleActive": "Reordering {itemLabel}, current position {position} of {total}.", | ||
| "dragHandleChange": "{itemLabel}, new position {position} of {total}. Press space to confirm.", | ||
| "dragHandleCommit": "{itemLabel}, current position {position} of {total}.", | ||
| "dragHandleIdle": "{itemLabel}, press space and use arrow keys to reorder content. Current position {position} of {total}." | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,7 @@ | ||
| export interface HandleNudge { | ||
| direction: "up" | "down"; | ||
| } | ||
|
|
||
| export interface HandleChange { | ||
| message: string; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ import { | |
| EventEmitter, | ||
| h, | ||
| Host, | ||
| Listen, | ||
| Method, | ||
| Prop, | ||
| State, | ||
|
|
@@ -106,6 +107,13 @@ export class ListItem | |
| this.emitCalciteInternalListItemChange(); | ||
| } | ||
|
|
||
| /** | ||
| * When `true`, the component displays a draggable button. | ||
| * | ||
| * @internal | ||
| */ | ||
| @Prop() dragHandle = false; | ||
|
|
||
| /** | ||
| * The label text of the component. Displays above the description text. | ||
| */ | ||
|
|
@@ -226,6 +234,13 @@ export class ListItem | |
| */ | ||
| @Event({ cancelable: false }) calciteInternalListItemChange: EventEmitter<void>; | ||
|
|
||
| @Listen("calciteInternalListItemGroupDefaultSlotChange") | ||
| @Listen("calciteInternalListDefaultSlotChange") | ||
| handleCalciteInternalListDefaultSlotChanges(event: CustomEvent): void { | ||
| event.stopPropagation(); | ||
| this.handleOpenableChange(this.defaultSlotEl); | ||
| } | ||
|
|
||
| // -------------------------------------------------------------------------- | ||
| // | ||
| // Private Properties | ||
|
|
@@ -269,6 +284,14 @@ export class ListItem | |
|
|
||
| actionsEndEl: HTMLTableCellElement; | ||
|
|
||
| defaultSlotEl: HTMLSlotElement; | ||
|
|
||
| // -------------------------------------------------------------------------- | ||
| // | ||
| // Lifecycle | ||
| // | ||
| // -------------------------------------------------------------------------- | ||
|
|
||
| connectedCallback(): void { | ||
| connectInteractive(this); | ||
| connectLocalized(this); | ||
|
|
@@ -354,6 +377,14 @@ export class ListItem | |
| ); | ||
| } | ||
|
|
||
| renderDragHandle(): VNode { | ||
| return this.dragHandle ? ( | ||
| <td class={CSS.dragContainer} key="drag-handle-container"> | ||
| <calcite-handle label={this.label} setPosition={this.setPosition} setSize={this.setSize} /> | ||
| </td> | ||
| ) : null; | ||
| } | ||
|
|
||
| renderOpen(): VNode { | ||
| const { el, open, openable, parentListEl } = this; | ||
| const dir = getElementDir(el); | ||
|
|
@@ -533,6 +564,7 @@ export class ListItem | |
| // eslint-disable-next-line react/jsx-sort-props | ||
| ref={(el) => (this.containerEl = el)} | ||
| > | ||
| {this.renderDragHandle()} | ||
| {this.renderSelected()} | ||
| {this.renderOpen()} | ||
| {this.renderActionsStart()} | ||
|
|
@@ -545,7 +577,10 @@ export class ListItem | |
| [CSS.nestedContainerHidden]: openable && !open, | ||
| }} | ||
| > | ||
| <slot onSlotchange={this.handleDefaultSlotChange} /> | ||
| <slot | ||
| onSlotchange={this.handleDefaultSlotChange} | ||
| ref={(el: HTMLSlotElement) => (this.defaultSlotEl = el)} | ||
|
Contributor
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. Does this arrow function need to be called each render?
Member
Author
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 its only called once when the ref is established
Contributor
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've just seen patterns where we declare a private method on the class for assigning the ref so that the function doesn't have to get recalled on every render, so that stood out to me. |
||
| /> | ||
| </div> | ||
| </Host> | ||
| ); | ||
|
|
@@ -602,9 +637,13 @@ export class ListItem | |
| } | ||
| } | ||
|
|
||
| handleDefaultSlotChange = (event: Event): void => { | ||
| handleOpenableChange(slotEl: HTMLSlotElement): void { | ||
| if (!slotEl) { | ||
| return; | ||
| } | ||
|
|
||
| const { parentListEl } = this; | ||
| const listItemChildren = getListItemChildren(event); | ||
| const listItemChildren = getListItemChildren(slotEl); | ||
| updateListItemChildren(listItemChildren); | ||
| const openable = !!listItemChildren.length; | ||
|
|
||
|
|
@@ -617,6 +656,10 @@ export class ListItem | |
| if (!openable) { | ||
| this.open = false; | ||
| } | ||
| } | ||
|
|
||
| handleDefaultSlotChange = (event: Event): void => { | ||
| this.handleOpenableChange(event.target as HTMLSlotElement); | ||
| }; | ||
|
|
||
| toggleOpen = (): void => { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.