Skip to content

Commit 3381040

Browse files
jcfrancobenelan
authored andcommitted
feat(dropdown): add offsetDistance and offsetSkidding properties (#11614)
**Related Issue:** #7224 ## Summary Adds offset properties for dropdown menu placement.
1 parent f151cc4 commit 3381040

File tree

4 files changed

+81
-33
lines changed

4 files changed

+81
-33
lines changed

packages/calcite-components/src/components/dropdown/dropdown.e2e.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ describe("calcite-dropdown", () => {
3939

4040
describe("defaults", () => {
4141
defaults("calcite-dropdown", [
42+
{
43+
propertyName: "offsetDistance",
44+
defaultValue: 0,
45+
},
46+
{
47+
propertyName: "offsetSkidding",
48+
defaultValue: 0,
49+
},
4250
{
4351
propertyName: "scale",
4452
defaultValue: "m",
@@ -52,6 +60,14 @@ describe("calcite-dropdown", () => {
5260

5361
describe("reflects", () => {
5462
reflects("calcite-dropdown", [
63+
{
64+
propertyName: "offsetDistance",
65+
value: 10,
66+
},
67+
{
68+
propertyName: "offsetSkidding",
69+
value: 10,
70+
},
5571
{
5672
propertyName: "scale",
5773
value: "m",

packages/calcite-components/src/components/dropdown/dropdown.stories.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,3 +524,19 @@ export const openInAllScales = (): string => html`
524524
</calcite-dropdown>
525525
</div>
526526
`;
527+
528+
export const offsetPlacement = (): string => html`
529+
<calcite-dropdown offset-skidding="10" offset-distance="10" open placement="leading">
530+
<calcite-button icon-start="rectangle-plus" slot="trigger"></calcite-button>
531+
<calcite-dropdown-group group-title="Add to new...">
532+
<calcite-dropdown-item icon-start="nodes-link" selected>Link Chart</calcite-dropdown-item>
533+
<calcite-dropdown-item icon-start="map">Map</calcite-dropdown-item>
534+
</calcite-dropdown-group>
535+
<calcite-dropdown-group group-title="Add to existing...">
536+
<calcite-dropdown-item icon-start="nodes-link" selected>My Link Chart 1</calcite-dropdown-item>
537+
<calcite-dropdown-item icon-start="nodes-link" selected>My Link Chart 2</calcite-dropdown-item>
538+
<calcite-dropdown-item icon-start="map">My Map 1</calcite-dropdown-item>
539+
<calcite-dropdown-item icon-start="map">My Map 2</calcite-dropdown-item>
540+
</calcite-dropdown-group>
541+
</calcite-dropdown>
542+
`;

packages/calcite-components/src/components/dropdown/dropdown.tsx

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,16 @@ export class Dropdown
118118
*/
119119
@property({ reflect: true }) maxItems = 0;
120120

121+
/**
122+
* Offset the position of the component away from the `referenceElement`.
123+
*
124+
* @default 0
125+
*/
126+
@property({ type: Number, reflect: true }) offsetDistance = 0;
127+
128+
/** Offset the position of the component along the `referenceElement`. */
129+
@property({ reflect: true }) offsetSkidding = 0;
130+
121131
/** When `true`, displays and positions the component. */
122132
@property({ reflect: true }) open = false;
123133

@@ -171,13 +181,23 @@ export class Dropdown
171181
*/
172182
@method()
173183
async reposition(delayed = false): Promise<void> {
174-
const { floatingEl, referenceEl, placement, overlayPositioning, filteredFlipPlacements } = this;
184+
const {
185+
filteredFlipPlacements,
186+
floatingEl,
187+
offsetDistance,
188+
offsetSkidding,
189+
overlayPositioning,
190+
placement,
191+
referenceEl,
192+
} = this;
175193

176194
return reposition(
177195
this,
178196
{
179197
floatingEl,
180198
referenceEl,
199+
offsetDistance,
200+
offsetSkidding,
181201
overlayPositioning,
182202
placement,
183203
flipPlacements: filteredFlipPlacements,
@@ -257,9 +277,11 @@ export class Dropdown
257277
}
258278

259279
if (
260-
(changes.has("overlayPositioning") &&
261-
(this.hasUpdated || this.overlayPositioning !== "absolute")) ||
262-
(changes.has("placement") && (this.hasUpdated || this.placement !== defaultMenuPlacement))
280+
this.hasUpdated &&
281+
((changes.has("offsetDistance") && this.offsetDistance !== 0) ||
282+
(changes.has("offsetSkidding") && this.offsetSkidding !== 0) ||
283+
(changes.has("overlayPositioning") && this.overlayPositioning !== "absolute") ||
284+
(changes.has("placement") && this.placement !== defaultMenuPlacement))
263285
) {
264286
this.reposition(true);
265287
}

packages/calcite-components/src/utils/floating-ui.ts

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -337,46 +337,40 @@ function getMiddleware({
337337
arrowEl?: SVGSVGElement;
338338
type: UIType;
339339
}): Middleware[] {
340-
const defaultMiddleware = [shift(), hide()];
340+
const middleware = [shift(), hide()];
341341

342342
if (type === "menu") {
343-
return [
344-
...defaultMiddleware,
343+
middleware.push(
345344
flip({
346345
fallbackPlacements: flipPlacements || ["top-start", "top", "top-end", "bottom-start", "bottom", "bottom-end"],
347346
}),
348-
];
347+
);
349348
}
350349

351-
if (type === "popover" || type === "tooltip") {
352-
const middleware: Middleware[] = [
353-
...defaultMiddleware,
354-
offset({
355-
mainAxis: typeof offsetDistance === "number" ? offsetDistance : 0,
356-
crossAxis: typeof offsetSkidding === "number" ? offsetSkidding : 0,
357-
}),
358-
];
359-
360-
if (placement === "auto" || placement === "auto-start" || placement === "auto-end") {
361-
middleware.push(
362-
autoPlacement({ alignment: placement === "auto-start" ? "start" : placement === "auto-end" ? "end" : null }),
363-
);
364-
} else if (!flipDisabled) {
365-
middleware.push(flip(flipPlacements ? { fallbackPlacements: flipPlacements } : {}));
366-
}
350+
middleware.push(
351+
offset({
352+
mainAxis: typeof offsetDistance === "number" ? offsetDistance : 0,
353+
crossAxis: typeof offsetSkidding === "number" ? offsetSkidding : 0,
354+
}),
355+
);
367356

368-
if (arrowEl) {
369-
middleware.push(
370-
arrow({
371-
element: arrowEl,
372-
}),
373-
);
374-
}
357+
if (placement === "auto" || placement === "auto-start" || placement === "auto-end") {
358+
middleware.push(
359+
autoPlacement({ alignment: placement === "auto-start" ? "start" : placement === "auto-end" ? "end" : null }),
360+
);
361+
} else if (!flipDisabled) {
362+
middleware.push(flip(flipPlacements ? { fallbackPlacements: flipPlacements } : {}));
363+
}
375364

376-
return middleware;
365+
if (arrowEl) {
366+
middleware.push(
367+
arrow({
368+
element: arrowEl,
369+
}),
370+
);
377371
}
378372

379-
return [];
373+
return middleware;
380374
}
381375

382376
export function filterValidFlipPlacements(placements: string[], el: HTMLElement): EffectivePlacement[] {

0 commit comments

Comments
 (0)