@launchpad-ui/dropdown 0.2.7 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,43 +1,13 @@
1
- import type { Button } from '@launchpad-ui/button';
2
- import type { PopoverPlacement } from '@launchpad-ui/popover';
3
- import { Component } from 'react';
1
+ /// <reference types="react" />
2
+ import type { PopoverProps } from '@launchpad-ui/popover';
4
3
  declare type DropdownState = {
5
4
  isOpen?: boolean;
6
- } & Record<string | number, unknown>;
7
- declare type DropdownProps<T extends string | object | number> = {
8
- isOpen?: boolean;
9
- placement?: PopoverPlacement;
5
+ };
6
+ declare type DropdownProps<T extends string | object | number> = PopoverProps & {
10
7
  onSelect?: (item: T, stateChanges: DropdownState) => void;
11
- onStateChange?: (state: Record<string | number, unknown>) => void;
12
- disabled?: boolean;
13
- targetClassName?: string;
14
- children: React.ReactNode;
15
- onInteraction?: (nextIsOpen: boolean) => void;
16
- popoverClassName?: string;
17
- enforceFocus?: boolean;
18
- [key: string]: unknown;
8
+ onStateChange?: (state: DropdownState) => void;
19
9
  };
20
- declare class Dropdown<T extends string | object | number> extends Component<DropdownProps<T>, DropdownState> {
21
- triggerElement: HTMLElement | null | typeof Button;
22
- refHandlers: {
23
- trigger: (node: HTMLElement | null | typeof Button) => void;
24
- };
25
- state: {
26
- isOpen: boolean;
27
- };
28
- componentDidUpdate(prevProps: DropdownProps<T>, prevState: DropdownState): void;
29
- render(): JSX.Element;
30
- renderTrigger(): import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
31
- renderContent(): import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
32
- handleSelect: (item: T) => void;
33
- handlePopoverInteraction: (nextIsOpen: boolean) => void;
34
- parseChildren(): {
35
- target: import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
36
- content: import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
37
- };
38
- updateState(state: DropdownState, selectedItem?: T): void;
39
- isControlledProp(key: string): boolean;
40
- }
10
+ declare const Dropdown: <T extends string | number | object>(props: DropdownProps<T>) => JSX.Element;
41
11
  export { Dropdown };
42
12
  export type { DropdownProps };
43
13
  //# sourceMappingURL=Dropdown.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Dropdown.d.ts","sourceRoot":"","sources":["../src/Dropdown.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAI9D,OAAO,EAA0B,SAAS,EAAE,MAAM,OAAO,CAAC;AAE1D,aAAK,aAAa,GAAG;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC;AAErC,aAAK,aAAa,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,MAAM,IAAI;IACvD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,YAAY,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1D,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,cAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,MAAM,CAAE,SAAQ,SAAS,CAClE,aAAa,CAAC,CAAC,CAAC,EAChB,aAAa,CACd;IACC,cAAc,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,MAAM,CAAQ;IAC1D,WAAW;wBACO,WAAW,GAAG,IAAI,GAAG,aAAa;MAGlD;IAEF,KAAK;;MAEH;IAEF,kBAAkB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,aAAa;IAwBxE,MAAM;IA+BN,aAAa;IASb,aAAa;IAMb,YAAY,SAAU,CAAC,UAErB;IAEF,wBAAwB,eAAgB,OAAO,UAE7C;IAEF,aAAa;;;;IAQb,WAAW,CAAC,KAAK,EAAE,aAAa,EAAE,YAAY,CAAC,EAAE,CAAC;IA6BlD,gBAAgB,CAAC,GAAG,EAAE,MAAM;CAG7B;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC;AACpB,YAAY,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"Dropdown.d.ts","sourceRoot":"","sources":["../src/Dropdown.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAM1D,aAAK,aAAa,GAAG;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,aAAK,aAAa,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,MAAM,IAAI,YAAY,GAAG;IACtE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,YAAY,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1D,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,QAAA,MAAM,QAAQ,8EAoGb,CAAC;AAEF,OAAO,EAAE,QAAQ,EAAE,CAAC;AACpB,YAAY,EAAE,aAAa,EAAE,CAAC"}
package/dist/index.es.js CHANGED
@@ -4,33 +4,33 @@ import * as React from "react";
4
4
  // src/Dropdown.tsx
5
5
  import { Popover } from "@launchpad-ui/popover";
6
6
  import cx from "clsx";
7
- import { Children, cloneElement, Component } from "react";
8
- var Dropdown = class extends Component {
9
- constructor() {
10
- super(...arguments);
11
- this.triggerElement = null;
12
- this.refHandlers = {
13
- trigger: (node) => {
14
- this.triggerElement = node;
15
- }
16
- };
17
- this.state = {
18
- isOpen: this.isControlledProp("isOpen") ? this.props.isOpen : false
19
- };
20
- this.handleSelect = (item) => {
21
- this.updateState({ isOpen: false }, item);
22
- };
23
- this.handlePopoverInteraction = (nextIsOpen) => {
24
- this.updateState({ isOpen: nextIsOpen });
25
- };
26
- }
27
- componentDidUpdate(prevProps, prevState) {
28
- if (this.props.isOpen !== prevProps.isOpen) {
29
- this.setState({ isOpen: this.props.isOpen });
7
+ import { Children, cloneElement, useEffect, useRef, useState } from "react";
8
+ import { jsxs } from "react/jsx-runtime";
9
+ var Dropdown = (props) => {
10
+ const {
11
+ placement,
12
+ disabled,
13
+ targetClassName,
14
+ popoverClassName,
15
+ isOpen: isOpenProp,
16
+ onInteraction,
17
+ onSelect,
18
+ onStateChange,
19
+ children,
20
+ ...rest
21
+ } = props;
22
+ const triggerRef = useRef(null);
23
+ const [isOpen, setIsOpen] = useState(isOpenProp ?? false);
24
+ const [hasOpened, setHasOpened] = useState(isOpen);
25
+ useEffect(() => {
26
+ if (isOpenProp !== void 0) {
27
+ setIsOpen(isOpenProp);
30
28
  }
31
- if (prevState.isOpen !== this.state.isOpen && this.state.isOpen === false) {
29
+ }, [isOpenProp]);
30
+ useEffect(() => {
31
+ if (hasOpened && isOpen === false) {
32
32
  setTimeout(() => {
33
- const current = this.triggerElement;
33
+ const current = triggerRef.current;
34
34
  if (!current) {
35
35
  return;
36
36
  }
@@ -38,91 +38,77 @@ var Dropdown = class extends Component {
38
38
  !hasModal && current.focus?.();
39
39
  });
40
40
  }
41
- }
42
- render() {
43
- const {
44
- placement,
45
- disabled,
46
- targetClassName,
47
- popoverClassName,
48
- isOpen: isOpenProp,
49
- onInteraction,
50
- ...rest
51
- } = this.props;
52
- const { isOpen } = this.state;
53
- const popoverTargetClasses = cx("Dropdown-target", targetClassName);
54
- const popoverClasses = cx("Dropdown", popoverClassName);
55
- return /* @__PURE__ */ React.createElement(Popover, {
56
- isOpen,
57
- placement,
58
- onInteraction: onInteraction || this.handlePopoverInteraction,
59
- restrictHeight: false,
60
- disabled,
61
- targetClassName: popoverTargetClasses,
62
- popoverClassName: popoverClasses,
63
- ...rest
64
- }, this.renderTrigger(), this.renderContent());
65
- }
66
- renderTrigger() {
67
- return cloneElement(this.parseChildren().target, {
41
+ }, [isOpen, hasOpened]);
42
+ useEffect(() => {
43
+ setHasOpened(isOpen);
44
+ onStateChange?.({ isOpen });
45
+ }, [isOpen]);
46
+ const renderTrigger = () => {
47
+ return cloneElement(parseChildren().target, {
68
48
  "aria-haspopup": true,
69
- "aria-expanded": this.state.isOpen ? true : false,
70
- ref: this.refHandlers.trigger,
71
- isopen: this.state.isOpen?.toString()
49
+ "aria-expanded": isOpen ? true : false,
50
+ ref: triggerRef,
51
+ isopen: isOpen?.toString()
72
52
  });
73
- }
74
- renderContent() {
75
- return cloneElement(this.parseChildren().content, {
76
- onSelect: this.handleSelect
53
+ };
54
+ const renderContent = () => {
55
+ return cloneElement(parseChildren().content, {
56
+ onSelect: handleSelect
77
57
  });
78
- }
79
- parseChildren() {
80
- const [targetChild, contentChild] = Children.toArray(this.props.children);
58
+ };
59
+ const handleSelect = (item) => {
60
+ setIsOpen(false);
61
+ onSelect?.(item, { isOpen: false });
62
+ };
63
+ const handlePopoverInteraction = (nextIsOpen) => {
64
+ setIsOpen(nextIsOpen);
65
+ };
66
+ const parseChildren = () => {
67
+ const [targetChild, contentChild] = Children.toArray(children);
81
68
  return {
82
69
  target: targetChild,
83
70
  content: contentChild
84
71
  };
85
- }
86
- updateState(state, selectedItem) {
87
- const nextState = {};
88
- const stateChanges = {};
89
- this.setState((currentState) => {
90
- Object.keys(state).forEach((key) => {
91
- if (currentState[key] !== state[key]) {
92
- stateChanges[key] = state[key];
93
- }
94
- if (!this.isControlledProp(key)) {
95
- nextState[key] = state[key];
96
- }
97
- });
98
- return nextState;
99
- }, () => {
100
- if (selectedItem !== void 0 && selectedItem !== null) {
101
- this.props.onSelect?.(selectedItem, stateChanges);
102
- }
103
- if (Object.keys(stateChanges).length) {
104
- this.props.onStateChange?.(stateChanges);
105
- }
106
- });
107
- }
108
- isControlledProp(key) {
109
- return this.props[key] !== void 0;
110
- }
72
+ };
73
+ const popoverTargetClasses = cx("Dropdown-target", targetClassName);
74
+ const popoverClasses = cx("Dropdown", popoverClassName);
75
+ return /* @__PURE__ */ jsxs(Popover, {
76
+ isOpen,
77
+ placement,
78
+ onInteraction: onInteraction || handlePopoverInteraction,
79
+ restrictHeight: false,
80
+ disabled,
81
+ targetClassName: popoverTargetClasses,
82
+ popoverClassName: popoverClasses,
83
+ ...rest,
84
+ children: [
85
+ renderTrigger(),
86
+ renderContent()
87
+ ]
88
+ });
111
89
  };
112
90
 
113
91
  // src/DropdownButton.tsx
114
92
  import { Button } from "@launchpad-ui/button";
115
93
  import { ExpandMore, IconSize } from "@launchpad-ui/icons";
116
94
  import { forwardRef } from "react";
117
- var DropdownButton = forwardRef((props, ref) => {
118
- const { children, hideCaret, ...rest } = props;
119
- return /* @__PURE__ */ React.createElement(Button, {
120
- ...rest,
121
- ref
122
- }, children, " ", !hideCaret && /* @__PURE__ */ React.createElement(ExpandMore, {
123
- size: IconSize.SMALL
124
- }));
125
- });
95
+ import { jsx, jsxs as jsxs2 } from "react/jsx-runtime";
96
+ var DropdownButton = forwardRef(
97
+ (props, ref) => {
98
+ const { children, hideCaret, ...rest } = props;
99
+ return /* @__PURE__ */ jsxs2(Button, {
100
+ ...rest,
101
+ ref,
102
+ children: [
103
+ children,
104
+ " ",
105
+ !hideCaret && /* @__PURE__ */ jsx(ExpandMore, {
106
+ size: IconSize.SMALL
107
+ })
108
+ ]
109
+ });
110
+ }
111
+ );
126
112
  DropdownButton.displayName = "DropdownButton";
127
113
  export {
128
114
  Dropdown,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../scripts/react-shim.js", "../src/Dropdown.tsx", "../src/DropdownButton.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable functional/no-class */\nimport type { Button } from '@launchpad-ui/button';\nimport type { PopoverPlacement } from '@launchpad-ui/popover';\n\nimport { Popover } from '@launchpad-ui/popover';\nimport cx from 'clsx';\nimport { Children, cloneElement, Component } from 'react';\n\ntype DropdownState = {\n isOpen?: boolean;\n} & Record<string | number, unknown>;\n\ntype DropdownProps<T extends string | object | number> = {\n isOpen?: boolean;\n placement?: PopoverPlacement;\n onSelect?: (item: T, stateChanges: DropdownState) => void;\n onStateChange?: (state: Record<string | number, unknown>) => void;\n disabled?: boolean;\n targetClassName?: string;\n children: React.ReactNode;\n onInteraction?: (nextIsOpen: boolean) => void;\n popoverClassName?: string;\n enforceFocus?: boolean;\n [key: string]: unknown;\n};\n\nclass Dropdown<T extends string | object | number> extends Component<\n DropdownProps<T>,\n DropdownState\n> {\n triggerElement: HTMLElement | null | typeof Button = null;\n refHandlers = {\n trigger: (node: HTMLElement | null | typeof Button) => {\n this.triggerElement = node;\n },\n };\n\n state = {\n isOpen: this.isControlledProp('isOpen') ? (this.props.isOpen as boolean) : false,\n };\n\n componentDidUpdate(prevProps: DropdownProps<T>, prevState: DropdownState) {\n if (this.props.isOpen !== prevProps.isOpen) {\n this.setState({ isOpen: this.props.isOpen });\n }\n\n // Focus the button upon closing for convenient tabbing\n if (prevState.isOpen !== this.state.isOpen && this.state.isOpen === false) {\n setTimeout(() => {\n const current = this.triggerElement as HTMLElement;\n if (!current) {\n return;\n }\n\n // If a dropdown menu item triggers a modal, we do not want to focus the trigger. Instead\n // we let the modal components control their own focus.\n // Note that this is not ideal since closing the modal will not cause the dropdown trigger\n // to regain focus.\n const hasModal = current.closest?.('.has-modal');\n\n !hasModal && current.focus?.();\n });\n }\n }\n\n render() {\n const {\n placement,\n disabled,\n targetClassName,\n popoverClassName,\n isOpen: isOpenProp,\n onInteraction,\n ...rest\n } = this.props;\n const { isOpen } = this.state;\n const popoverTargetClasses = cx('Dropdown-target', targetClassName);\n const popoverClasses = cx('Dropdown', popoverClassName);\n\n return (\n <Popover\n isOpen={isOpen}\n placement={placement}\n onInteraction={onInteraction || this.handlePopoverInteraction}\n restrictHeight={false}\n disabled={disabled}\n targetClassName={popoverTargetClasses}\n popoverClassName={popoverClasses}\n {...rest}\n >\n {this.renderTrigger()}\n {this.renderContent()}\n </Popover>\n );\n }\n\n renderTrigger() {\n return cloneElement(this.parseChildren().target, {\n 'aria-haspopup': true,\n 'aria-expanded': this.state.isOpen ? true : false,\n ref: this.refHandlers.trigger,\n isopen: this.state.isOpen?.toString(),\n });\n }\n\n renderContent() {\n return cloneElement(this.parseChildren().content, {\n onSelect: this.handleSelect,\n });\n }\n\n handleSelect = (item: T) => {\n this.updateState({ isOpen: false }, item);\n };\n\n handlePopoverInteraction = (nextIsOpen: boolean) => {\n this.updateState({ isOpen: nextIsOpen });\n };\n\n parseChildren() {\n const [targetChild, contentChild] = Children.toArray(this.props.children);\n return {\n target: targetChild as React.ReactElement,\n content: contentChild as React.ReactElement,\n };\n }\n\n updateState(state: DropdownState, selectedItem?: T) {\n const nextState: DropdownState = {};\n const stateChanges: DropdownState = {};\n this.setState(\n (currentState) => {\n Object.keys(state).forEach((key) => {\n if (currentState[key] !== state[key]) {\n stateChanges[key] = state[key];\n }\n\n if (!this.isControlledProp(key)) {\n nextState[key] = state[key];\n }\n });\n\n return nextState;\n },\n () => {\n if (selectedItem !== undefined && selectedItem !== null) {\n this.props.onSelect?.(selectedItem, stateChanges);\n }\n\n if (Object.keys(stateChanges).length) {\n this.props.onStateChange?.(stateChanges);\n }\n }\n );\n }\n\n isControlledProp(key: string) {\n return this.props[key] !== undefined;\n }\n}\n\nexport { Dropdown };\nexport type { DropdownProps };\n", "import type { ButtonKind, ButtonSize } from '@launchpad-ui/button';\n\nimport { Button } from '@launchpad-ui/button';\nimport { ExpandMore, IconSize } from '@launchpad-ui/icons';\nimport { forwardRef } from 'react';\n\ntype DropdownButtonProps = {\n hideCaret?: boolean;\n kind?: ButtonKind;\n size?: ButtonSize;\n className?: string;\n disabled?: boolean;\n children?: React.ReactNode;\n onClick?(v: React.MouseEvent): void;\n testId?: string;\n};\n\nconst DropdownButton = forwardRef<React.ElementRef<typeof Button>, DropdownButtonProps>(\n (props, ref) => {\n const { children, hideCaret, ...rest } = props;\n\n return (\n <Button {...rest} ref={ref}>\n {children} {!hideCaret && <ExpandMore size={IconSize.SMALL} />}\n </Button>\n );\n }\n);\n\nDropdownButton.displayName = 'DropdownButton';\n\nexport { DropdownButton };\nexport type { DropdownButtonProps };\n"],
5
- "mappings": ";AAAA;;;ACIA;AACA;AACA;AAoBA,IAAM,WAAN,cAA2D,UAGzD;AAAA,EAHF;AAAA;AAIE,0BAAqD;AACrD,uBAAc;AAAA,MACZ,SAAS,CAAC,SAA6C;AACrD,aAAK,iBAAiB;AAAA,MACxB;AAAA,IACF;AAEA,iBAAQ;AAAA,MACN,QAAQ,KAAK,iBAAiB,QAAQ,IAAK,KAAK,MAAM,SAAqB;AAAA,IAC7E;AAwEA,wBAAe,CAAC,SAAY;AAC1B,WAAK,YAAY,EAAE,QAAQ,MAAM,GAAG,IAAI;AAAA,IAC1C;AAEA,oCAA2B,CAAC,eAAwB;AAClD,WAAK,YAAY,EAAE,QAAQ,WAAW,CAAC;AAAA,IACzC;AAAA;AAAA,EA5EA,mBAAmB,WAA6B,WAA0B;AACxE,QAAI,KAAK,MAAM,WAAW,UAAU,QAAQ;AAC1C,WAAK,SAAS,EAAE,QAAQ,KAAK,MAAM,OAAO,CAAC;AAAA,IAC7C;AAGA,QAAI,UAAU,WAAW,KAAK,MAAM,UAAU,KAAK,MAAM,WAAW,OAAO;AACzE,iBAAW,MAAM;AACf,cAAM,UAAU,KAAK;AACrB,YAAI,CAAC,SAAS;AACZ;AAAA,QACF;AAMA,cAAM,WAAW,QAAQ,UAAU,YAAY;AAE/C,SAAC,YAAY,QAAQ,QAAQ;AAAA,MAC/B,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,SAAS;AACP,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,SACG;AAAA,QACD,KAAK;AACT,UAAM,EAAE,WAAW,KAAK;AACxB,UAAM,uBAAuB,GAAG,mBAAmB,eAAe;AAClE,UAAM,iBAAiB,GAAG,YAAY,gBAAgB;AAEtD,WACE,oCAAC;AAAA,MACC;AAAA,MACA;AAAA,MACA,eAAe,iBAAiB,KAAK;AAAA,MACrC,gBAAgB;AAAA,MAChB;AAAA,MACA,iBAAiB;AAAA,MACjB,kBAAkB;AAAA,MACjB,GAAG;AAAA,OAEH,KAAK,cAAc,GACnB,KAAK,cAAc,CACtB;AAAA,EAEJ;AAAA,EAEA,gBAAgB;AACd,WAAO,aAAa,KAAK,cAAc,EAAE,QAAQ;AAAA,MAC/C,iBAAiB;AAAA,MACjB,iBAAiB,KAAK,MAAM,SAAS,OAAO;AAAA,MAC5C,KAAK,KAAK,YAAY;AAAA,MACtB,QAAQ,KAAK,MAAM,QAAQ,SAAS;AAAA,IACtC,CAAC;AAAA,EACH;AAAA,EAEA,gBAAgB;AACd,WAAO,aAAa,KAAK,cAAc,EAAE,SAAS;AAAA,MAChD,UAAU,KAAK;AAAA,IACjB,CAAC;AAAA,EACH;AAAA,EAUA,gBAAgB;AACd,UAAM,CAAC,aAAa,gBAAgB,SAAS,QAAQ,KAAK,MAAM,QAAQ;AACxE,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEA,YAAY,OAAsB,cAAkB;AAClD,UAAM,YAA2B,CAAC;AAClC,UAAM,eAA8B,CAAC;AACrC,SAAK,SACH,CAAC,iBAAiB;AAChB,aAAO,KAAK,KAAK,EAAE,QAAQ,CAAC,QAAQ;AAClC,YAAI,aAAa,SAAS,MAAM,MAAM;AACpC,uBAAa,OAAO,MAAM;AAAA,QAC5B;AAEA,YAAI,CAAC,KAAK,iBAAiB,GAAG,GAAG;AAC/B,oBAAU,OAAO,MAAM;AAAA,QACzB;AAAA,MACF,CAAC;AAED,aAAO;AAAA,IACT,GACA,MAAM;AACJ,UAAI,iBAAiB,UAAa,iBAAiB,MAAM;AACvD,aAAK,MAAM,WAAW,cAAc,YAAY;AAAA,MAClD;AAEA,UAAI,OAAO,KAAK,YAAY,EAAE,QAAQ;AACpC,aAAK,MAAM,gBAAgB,YAAY;AAAA,MACzC;AAAA,IACF,CACF;AAAA,EACF;AAAA,EAEA,iBAAiB,KAAa;AAC5B,WAAO,KAAK,MAAM,SAAS;AAAA,EAC7B;AACF;;;AC7JA;AACA;AACA;AAaA,IAAM,iBAAiB,WACrB,CAAC,OAAO,QAAQ;AACd,QAAM,EAAE,UAAU,cAAc,SAAS;AAEzC,SACE,oCAAC;AAAA,IAAQ,GAAG;AAAA,IAAM;AAAA,KACf,UAAS,KAAE,CAAC,aAAa,oCAAC;AAAA,IAAW,MAAM,SAAS;AAAA,GAAO,CAC9D;AAEJ,CACF;AAEA,eAAe,cAAc;",
6
- "names": []
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import type { PopoverProps } from '@launchpad-ui/popover';\n\nimport { Popover } from '@launchpad-ui/popover';\nimport cx from 'clsx';\nimport { Children, cloneElement, useEffect, useRef, useState } from 'react';\n\ntype DropdownState = {\n isOpen?: boolean;\n};\n\ntype DropdownProps<T extends string | object | number> = PopoverProps & {\n onSelect?: (item: T, stateChanges: DropdownState) => void;\n onStateChange?: (state: DropdownState) => void;\n};\n\nconst Dropdown = <T extends string | object | number>(props: DropdownProps<T>) => {\n const {\n placement,\n disabled,\n targetClassName,\n popoverClassName,\n isOpen: isOpenProp,\n onInteraction,\n onSelect,\n onStateChange,\n children,\n ...rest\n } = props;\n\n const triggerRef = useRef<HTMLElement>(null);\n const [isOpen, setIsOpen] = useState(isOpenProp ?? false);\n const [hasOpened, setHasOpened] = useState(isOpen);\n\n useEffect(() => {\n if (isOpenProp !== undefined) {\n setIsOpen(isOpenProp);\n }\n }, [isOpenProp]);\n\n useEffect(() => {\n // Focus the button upon closing for convenient tabbing\n if (hasOpened && isOpen === false) {\n setTimeout(() => {\n const current = triggerRef.current;\n if (!current) {\n return;\n }\n\n // If a dropdown menu item triggers a modal, we do not want to focus the trigger. Instead\n // we let the modal components control their own focus.\n // Note that this is not ideal since closing the modal will not cause the dropdown trigger\n // to regain focus.\n const hasModal = current.closest?.('.has-modal');\n\n !hasModal && current.focus?.();\n });\n }\n }, [isOpen, hasOpened]);\n\n useEffect(() => {\n setHasOpened(isOpen);\n onStateChange?.({ isOpen });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen]);\n\n const renderTrigger = () => {\n return cloneElement(parseChildren().target, {\n 'aria-haspopup': true,\n 'aria-expanded': isOpen ? true : false,\n ref: triggerRef,\n isopen: isOpen?.toString(),\n });\n };\n\n const renderContent = () => {\n return cloneElement(parseChildren().content, {\n onSelect: handleSelect,\n });\n };\n\n const handleSelect = (item: T) => {\n setIsOpen(false);\n onSelect?.(item, { isOpen: false });\n };\n\n const handlePopoverInteraction = (nextIsOpen: boolean) => {\n setIsOpen(nextIsOpen);\n };\n\n const parseChildren = () => {\n const [targetChild, contentChild] = Children.toArray(children);\n return {\n target: targetChild as React.ReactElement,\n content: contentChild as React.ReactElement,\n };\n };\n\n const popoverTargetClasses = cx('Dropdown-target', targetClassName);\n const popoverClasses = cx('Dropdown', popoverClassName);\n\n return (\n <Popover\n isOpen={isOpen}\n placement={placement}\n onInteraction={onInteraction || handlePopoverInteraction}\n restrictHeight={false}\n disabled={disabled}\n targetClassName={popoverTargetClasses}\n popoverClassName={popoverClasses}\n {...rest}\n >\n {renderTrigger()}\n {renderContent()}\n </Popover>\n );\n};\n\nexport { Dropdown };\nexport type { DropdownProps };\n", "import type { ButtonKind, ButtonSize } from '@launchpad-ui/button';\n\nimport { Button } from '@launchpad-ui/button';\nimport { ExpandMore, IconSize } from '@launchpad-ui/icons';\nimport { forwardRef } from 'react';\n\ntype DropdownButtonProps = {\n hideCaret?: boolean;\n kind?: ButtonKind;\n size?: ButtonSize;\n className?: string;\n disabled?: boolean;\n children?: React.ReactNode;\n onClick?(v: React.MouseEvent): void;\n testId?: string;\n};\n\nconst DropdownButton = forwardRef<React.ElementRef<typeof Button>, DropdownButtonProps>(\n (props, ref) => {\n const { children, hideCaret, ...rest } = props;\n\n return (\n <Button {...rest} ref={ref}>\n {children} {!hideCaret && <ExpandMore size={IconSize.SMALL} />}\n </Button>\n );\n }\n);\n\nDropdownButton.displayName = 'DropdownButton';\n\nexport { DropdownButton };\nexport type { DropdownButtonProps };\n"],
5
+ "mappings": ";AAAA,YAAY,WAAW;;;ACEvB,SAAS,eAAe;AACxB,OAAO,QAAQ;AACf,SAAS,UAAU,cAAc,WAAW,QAAQ,gBAAgB;AAiGhE;AAtFJ,IAAM,WAAW,CAAqC,UAA4B;AAChF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,OACG;AAAA,EACL,IAAI;AAEJ,QAAM,aAAa,OAAoB,IAAI;AAC3C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,cAAc,KAAK;AACxD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,MAAM;AAEjD,YAAU,MAAM;AACd,QAAI,eAAe,QAAW;AAC5B,gBAAU,UAAU;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,UAAU,CAAC;AAEf,YAAU,MAAM;AAEd,QAAI,aAAa,WAAW,OAAO;AACjC,iBAAW,MAAM;AACf,cAAM,UAAU,WAAW;AAC3B,YAAI,CAAC,SAAS;AACZ;AAAA,QACF;AAMA,cAAM,WAAW,QAAQ,UAAU,YAAY;AAE/C,SAAC,YAAY,QAAQ,QAAQ;AAAA,MAC/B,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,CAAC;AAEtB,YAAU,MAAM;AACd,iBAAa,MAAM;AACnB,oBAAgB,EAAE,OAAO,CAAC;AAAA,EAE5B,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,gBAAgB,MAAM;AAC1B,WAAO,aAAa,cAAc,EAAE,QAAQ;AAAA,MAC1C,iBAAiB;AAAA,MACjB,iBAAiB,SAAS,OAAO;AAAA,MACjC,KAAK;AAAA,MACL,QAAQ,QAAQ,SAAS;AAAA,IAC3B,CAAC;AAAA,EACH;AAEA,QAAM,gBAAgB,MAAM;AAC1B,WAAO,aAAa,cAAc,EAAE,SAAS;AAAA,MAC3C,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,QAAM,eAAe,CAAC,SAAY;AAChC,cAAU,KAAK;AACf,eAAW,MAAM,EAAE,QAAQ,MAAM,CAAC;AAAA,EACpC;AAEA,QAAM,2BAA2B,CAAC,eAAwB;AACxD,cAAU,UAAU;AAAA,EACtB;AAEA,QAAM,gBAAgB,MAAM;AAC1B,UAAM,CAAC,aAAa,YAAY,IAAI,SAAS,QAAQ,QAAQ;AAC7D,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,uBAAuB,GAAG,mBAAmB,eAAe;AAClE,QAAM,iBAAiB,GAAG,YAAY,gBAAgB;AAEtD,SACE,qBAAC;AAAA,IACC;AAAA,IACA;AAAA,IACA,eAAe,iBAAiB;AAAA,IAChC,gBAAgB;AAAA,IAChB;AAAA,IACA,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IACjB,GAAG;AAAA,IAEH;AAAA,oBAAc;AAAA,MACd,cAAc;AAAA;AAAA,GACjB;AAEJ;;;ACjHA,SAAS,cAAc;AACvB,SAAS,YAAY,gBAAgB;AACrC,SAAS,kBAAkB;AAkBrB,SAC4B,KAD5B,QAAAA,aAAA;AALN,IAAM,iBAAiB;AAAA,EACrB,CAAC,OAAO,QAAQ;AACd,UAAM,EAAE,UAAU,cAAc,KAAK,IAAI;AAEzC,WACE,gBAAAA,MAAC;AAAA,MAAQ,GAAG;AAAA,MAAM;AAAA,MACf;AAAA;AAAA,QAAS;AAAA,QAAE,CAAC,aAAa,oBAAC;AAAA,UAAW,MAAM,SAAS;AAAA,SAAO;AAAA;AAAA,KAC9D;AAAA,EAEJ;AACF;AAEA,eAAe,cAAc;",
6
+ "names": ["jsxs"]
7
7
  }
package/dist/index.js CHANGED
@@ -17,7 +17,10 @@ var __copyProps = (to, from, except, desc) => {
17
17
  }
18
18
  return to;
19
19
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
21
24
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
25
 
23
26
  // src/index.ts
@@ -35,32 +38,32 @@ var React = __toESM(require("react"));
35
38
  var import_popover = require("@launchpad-ui/popover");
36
39
  var import_clsx = __toESM(require("clsx"));
37
40
  var import_react = require("react");
38
- var Dropdown = class extends import_react.Component {
39
- constructor() {
40
- super(...arguments);
41
- this.triggerElement = null;
42
- this.refHandlers = {
43
- trigger: (node) => {
44
- this.triggerElement = node;
45
- }
46
- };
47
- this.state = {
48
- isOpen: this.isControlledProp("isOpen") ? this.props.isOpen : false
49
- };
50
- this.handleSelect = (item) => {
51
- this.updateState({ isOpen: false }, item);
52
- };
53
- this.handlePopoverInteraction = (nextIsOpen) => {
54
- this.updateState({ isOpen: nextIsOpen });
55
- };
56
- }
57
- componentDidUpdate(prevProps, prevState) {
58
- if (this.props.isOpen !== prevProps.isOpen) {
59
- this.setState({ isOpen: this.props.isOpen });
41
+ var import_jsx_runtime = require("react/jsx-runtime");
42
+ var Dropdown = (props) => {
43
+ const {
44
+ placement,
45
+ disabled,
46
+ targetClassName,
47
+ popoverClassName,
48
+ isOpen: isOpenProp,
49
+ onInteraction,
50
+ onSelect,
51
+ onStateChange,
52
+ children,
53
+ ...rest
54
+ } = props;
55
+ const triggerRef = (0, import_react.useRef)(null);
56
+ const [isOpen, setIsOpen] = (0, import_react.useState)(isOpenProp ?? false);
57
+ const [hasOpened, setHasOpened] = (0, import_react.useState)(isOpen);
58
+ (0, import_react.useEffect)(() => {
59
+ if (isOpenProp !== void 0) {
60
+ setIsOpen(isOpenProp);
60
61
  }
61
- if (prevState.isOpen !== this.state.isOpen && this.state.isOpen === false) {
62
+ }, [isOpenProp]);
63
+ (0, import_react.useEffect)(() => {
64
+ if (hasOpened && isOpen === false) {
62
65
  setTimeout(() => {
63
- const current = this.triggerElement;
66
+ const current = triggerRef.current;
64
67
  if (!current) {
65
68
  return;
66
69
  }
@@ -68,91 +71,77 @@ var Dropdown = class extends import_react.Component {
68
71
  !hasModal && current.focus?.();
69
72
  });
70
73
  }
71
- }
72
- render() {
73
- const {
74
- placement,
75
- disabled,
76
- targetClassName,
77
- popoverClassName,
78
- isOpen: isOpenProp,
79
- onInteraction,
80
- ...rest
81
- } = this.props;
82
- const { isOpen } = this.state;
83
- const popoverTargetClasses = (0, import_clsx.default)("Dropdown-target", targetClassName);
84
- const popoverClasses = (0, import_clsx.default)("Dropdown", popoverClassName);
85
- return /* @__PURE__ */ React.createElement(import_popover.Popover, {
86
- isOpen,
87
- placement,
88
- onInteraction: onInteraction || this.handlePopoverInteraction,
89
- restrictHeight: false,
90
- disabled,
91
- targetClassName: popoverTargetClasses,
92
- popoverClassName: popoverClasses,
93
- ...rest
94
- }, this.renderTrigger(), this.renderContent());
95
- }
96
- renderTrigger() {
97
- return (0, import_react.cloneElement)(this.parseChildren().target, {
74
+ }, [isOpen, hasOpened]);
75
+ (0, import_react.useEffect)(() => {
76
+ setHasOpened(isOpen);
77
+ onStateChange?.({ isOpen });
78
+ }, [isOpen]);
79
+ const renderTrigger = () => {
80
+ return (0, import_react.cloneElement)(parseChildren().target, {
98
81
  "aria-haspopup": true,
99
- "aria-expanded": this.state.isOpen ? true : false,
100
- ref: this.refHandlers.trigger,
101
- isopen: this.state.isOpen?.toString()
82
+ "aria-expanded": isOpen ? true : false,
83
+ ref: triggerRef,
84
+ isopen: isOpen?.toString()
102
85
  });
103
- }
104
- renderContent() {
105
- return (0, import_react.cloneElement)(this.parseChildren().content, {
106
- onSelect: this.handleSelect
86
+ };
87
+ const renderContent = () => {
88
+ return (0, import_react.cloneElement)(parseChildren().content, {
89
+ onSelect: handleSelect
107
90
  });
108
- }
109
- parseChildren() {
110
- const [targetChild, contentChild] = import_react.Children.toArray(this.props.children);
91
+ };
92
+ const handleSelect = (item) => {
93
+ setIsOpen(false);
94
+ onSelect?.(item, { isOpen: false });
95
+ };
96
+ const handlePopoverInteraction = (nextIsOpen) => {
97
+ setIsOpen(nextIsOpen);
98
+ };
99
+ const parseChildren = () => {
100
+ const [targetChild, contentChild] = import_react.Children.toArray(children);
111
101
  return {
112
102
  target: targetChild,
113
103
  content: contentChild
114
104
  };
115
- }
116
- updateState(state, selectedItem) {
117
- const nextState = {};
118
- const stateChanges = {};
119
- this.setState((currentState) => {
120
- Object.keys(state).forEach((key) => {
121
- if (currentState[key] !== state[key]) {
122
- stateChanges[key] = state[key];
123
- }
124
- if (!this.isControlledProp(key)) {
125
- nextState[key] = state[key];
126
- }
127
- });
128
- return nextState;
129
- }, () => {
130
- if (selectedItem !== void 0 && selectedItem !== null) {
131
- this.props.onSelect?.(selectedItem, stateChanges);
132
- }
133
- if (Object.keys(stateChanges).length) {
134
- this.props.onStateChange?.(stateChanges);
135
- }
136
- });
137
- }
138
- isControlledProp(key) {
139
- return this.props[key] !== void 0;
140
- }
105
+ };
106
+ const popoverTargetClasses = (0, import_clsx.default)("Dropdown-target", targetClassName);
107
+ const popoverClasses = (0, import_clsx.default)("Dropdown", popoverClassName);
108
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_popover.Popover, {
109
+ isOpen,
110
+ placement,
111
+ onInteraction: onInteraction || handlePopoverInteraction,
112
+ restrictHeight: false,
113
+ disabled,
114
+ targetClassName: popoverTargetClasses,
115
+ popoverClassName: popoverClasses,
116
+ ...rest,
117
+ children: [
118
+ renderTrigger(),
119
+ renderContent()
120
+ ]
121
+ });
141
122
  };
142
123
 
143
124
  // src/DropdownButton.tsx
144
125
  var import_button = require("@launchpad-ui/button");
145
126
  var import_icons = require("@launchpad-ui/icons");
146
127
  var import_react2 = require("react");
147
- var DropdownButton = (0, import_react2.forwardRef)((props, ref) => {
148
- const { children, hideCaret, ...rest } = props;
149
- return /* @__PURE__ */ React.createElement(import_button.Button, {
150
- ...rest,
151
- ref
152
- }, children, " ", !hideCaret && /* @__PURE__ */ React.createElement(import_icons.ExpandMore, {
153
- size: import_icons.IconSize.SMALL
154
- }));
155
- });
128
+ var import_jsx_runtime = require("react/jsx-runtime");
129
+ var DropdownButton = (0, import_react2.forwardRef)(
130
+ (props, ref) => {
131
+ const { children, hideCaret, ...rest } = props;
132
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_button.Button, {
133
+ ...rest,
134
+ ref,
135
+ children: [
136
+ children,
137
+ " ",
138
+ !hideCaret && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.ExpandMore, {
139
+ size: import_icons.IconSize.SMALL
140
+ })
141
+ ]
142
+ });
143
+ }
144
+ );
156
145
  DropdownButton.displayName = "DropdownButton";
157
146
  // Annotate the CommonJS export names for ESM import in node:
158
147
  0 && (module.exports = {
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts", "../../../scripts/react-shim.js", "../src/Dropdown.tsx", "../src/DropdownButton.tsx"],
4
- "sourcesContent": ["export type { DropdownProps } from './Dropdown';\nexport type { DropdownButtonProps } from './DropdownButton';\nexport { Dropdown } from './Dropdown';\nexport { DropdownButton } from './DropdownButton';\n", "import * as React from 'react';\nexport { React };\n", "/* eslint-disable functional/no-class */\nimport type { Button } from '@launchpad-ui/button';\nimport type { PopoverPlacement } from '@launchpad-ui/popover';\n\nimport { Popover } from '@launchpad-ui/popover';\nimport cx from 'clsx';\nimport { Children, cloneElement, Component } from 'react';\n\ntype DropdownState = {\n isOpen?: boolean;\n} & Record<string | number, unknown>;\n\ntype DropdownProps<T extends string | object | number> = {\n isOpen?: boolean;\n placement?: PopoverPlacement;\n onSelect?: (item: T, stateChanges: DropdownState) => void;\n onStateChange?: (state: Record<string | number, unknown>) => void;\n disabled?: boolean;\n targetClassName?: string;\n children: React.ReactNode;\n onInteraction?: (nextIsOpen: boolean) => void;\n popoverClassName?: string;\n enforceFocus?: boolean;\n [key: string]: unknown;\n};\n\nclass Dropdown<T extends string | object | number> extends Component<\n DropdownProps<T>,\n DropdownState\n> {\n triggerElement: HTMLElement | null | typeof Button = null;\n refHandlers = {\n trigger: (node: HTMLElement | null | typeof Button) => {\n this.triggerElement = node;\n },\n };\n\n state = {\n isOpen: this.isControlledProp('isOpen') ? (this.props.isOpen as boolean) : false,\n };\n\n componentDidUpdate(prevProps: DropdownProps<T>, prevState: DropdownState) {\n if (this.props.isOpen !== prevProps.isOpen) {\n this.setState({ isOpen: this.props.isOpen });\n }\n\n // Focus the button upon closing for convenient tabbing\n if (prevState.isOpen !== this.state.isOpen && this.state.isOpen === false) {\n setTimeout(() => {\n const current = this.triggerElement as HTMLElement;\n if (!current) {\n return;\n }\n\n // If a dropdown menu item triggers a modal, we do not want to focus the trigger. Instead\n // we let the modal components control their own focus.\n // Note that this is not ideal since closing the modal will not cause the dropdown trigger\n // to regain focus.\n const hasModal = current.closest?.('.has-modal');\n\n !hasModal && current.focus?.();\n });\n }\n }\n\n render() {\n const {\n placement,\n disabled,\n targetClassName,\n popoverClassName,\n isOpen: isOpenProp,\n onInteraction,\n ...rest\n } = this.props;\n const { isOpen } = this.state;\n const popoverTargetClasses = cx('Dropdown-target', targetClassName);\n const popoverClasses = cx('Dropdown', popoverClassName);\n\n return (\n <Popover\n isOpen={isOpen}\n placement={placement}\n onInteraction={onInteraction || this.handlePopoverInteraction}\n restrictHeight={false}\n disabled={disabled}\n targetClassName={popoverTargetClasses}\n popoverClassName={popoverClasses}\n {...rest}\n >\n {this.renderTrigger()}\n {this.renderContent()}\n </Popover>\n );\n }\n\n renderTrigger() {\n return cloneElement(this.parseChildren().target, {\n 'aria-haspopup': true,\n 'aria-expanded': this.state.isOpen ? true : false,\n ref: this.refHandlers.trigger,\n isopen: this.state.isOpen?.toString(),\n });\n }\n\n renderContent() {\n return cloneElement(this.parseChildren().content, {\n onSelect: this.handleSelect,\n });\n }\n\n handleSelect = (item: T) => {\n this.updateState({ isOpen: false }, item);\n };\n\n handlePopoverInteraction = (nextIsOpen: boolean) => {\n this.updateState({ isOpen: nextIsOpen });\n };\n\n parseChildren() {\n const [targetChild, contentChild] = Children.toArray(this.props.children);\n return {\n target: targetChild as React.ReactElement,\n content: contentChild as React.ReactElement,\n };\n }\n\n updateState(state: DropdownState, selectedItem?: T) {\n const nextState: DropdownState = {};\n const stateChanges: DropdownState = {};\n this.setState(\n (currentState) => {\n Object.keys(state).forEach((key) => {\n if (currentState[key] !== state[key]) {\n stateChanges[key] = state[key];\n }\n\n if (!this.isControlledProp(key)) {\n nextState[key] = state[key];\n }\n });\n\n return nextState;\n },\n () => {\n if (selectedItem !== undefined && selectedItem !== null) {\n this.props.onSelect?.(selectedItem, stateChanges);\n }\n\n if (Object.keys(stateChanges).length) {\n this.props.onStateChange?.(stateChanges);\n }\n }\n );\n }\n\n isControlledProp(key: string) {\n return this.props[key] !== undefined;\n }\n}\n\nexport { Dropdown };\nexport type { DropdownProps };\n", "import type { ButtonKind, ButtonSize } from '@launchpad-ui/button';\n\nimport { Button } from '@launchpad-ui/button';\nimport { ExpandMore, IconSize } from '@launchpad-ui/icons';\nimport { forwardRef } from 'react';\n\ntype DropdownButtonProps = {\n hideCaret?: boolean;\n kind?: ButtonKind;\n size?: ButtonSize;\n className?: string;\n disabled?: boolean;\n children?: React.ReactNode;\n onClick?(v: React.MouseEvent): void;\n testId?: string;\n};\n\nconst DropdownButton = forwardRef<React.ElementRef<typeof Button>, DropdownButtonProps>(\n (props, ref) => {\n const { children, hideCaret, ...rest } = props;\n\n return (\n <Button {...rest} ref={ref}>\n {children} {!hideCaret && <ExpandMore size={IconSize.SMALL} />}\n </Button>\n );\n }\n);\n\nDropdownButton.displayName = 'DropdownButton';\n\nexport { DropdownButton };\nexport type { DropdownButtonProps };\n"],
5
- "mappings": "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",
6
- "names": []
4
+ "sourcesContent": ["export type { DropdownProps } from './Dropdown';\nexport type { DropdownButtonProps } from './DropdownButton';\nexport { Dropdown } from './Dropdown';\nexport { DropdownButton } from './DropdownButton';\n", "import * as React from 'react';\nexport { React };\n", "import type { PopoverProps } from '@launchpad-ui/popover';\n\nimport { Popover } from '@launchpad-ui/popover';\nimport cx from 'clsx';\nimport { Children, cloneElement, useEffect, useRef, useState } from 'react';\n\ntype DropdownState = {\n isOpen?: boolean;\n};\n\ntype DropdownProps<T extends string | object | number> = PopoverProps & {\n onSelect?: (item: T, stateChanges: DropdownState) => void;\n onStateChange?: (state: DropdownState) => void;\n};\n\nconst Dropdown = <T extends string | object | number>(props: DropdownProps<T>) => {\n const {\n placement,\n disabled,\n targetClassName,\n popoverClassName,\n isOpen: isOpenProp,\n onInteraction,\n onSelect,\n onStateChange,\n children,\n ...rest\n } = props;\n\n const triggerRef = useRef<HTMLElement>(null);\n const [isOpen, setIsOpen] = useState(isOpenProp ?? false);\n const [hasOpened, setHasOpened] = useState(isOpen);\n\n useEffect(() => {\n if (isOpenProp !== undefined) {\n setIsOpen(isOpenProp);\n }\n }, [isOpenProp]);\n\n useEffect(() => {\n // Focus the button upon closing for convenient tabbing\n if (hasOpened && isOpen === false) {\n setTimeout(() => {\n const current = triggerRef.current;\n if (!current) {\n return;\n }\n\n // If a dropdown menu item triggers a modal, we do not want to focus the trigger. Instead\n // we let the modal components control their own focus.\n // Note that this is not ideal since closing the modal will not cause the dropdown trigger\n // to regain focus.\n const hasModal = current.closest?.('.has-modal');\n\n !hasModal && current.focus?.();\n });\n }\n }, [isOpen, hasOpened]);\n\n useEffect(() => {\n setHasOpened(isOpen);\n onStateChange?.({ isOpen });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen]);\n\n const renderTrigger = () => {\n return cloneElement(parseChildren().target, {\n 'aria-haspopup': true,\n 'aria-expanded': isOpen ? true : false,\n ref: triggerRef,\n isopen: isOpen?.toString(),\n });\n };\n\n const renderContent = () => {\n return cloneElement(parseChildren().content, {\n onSelect: handleSelect,\n });\n };\n\n const handleSelect = (item: T) => {\n setIsOpen(false);\n onSelect?.(item, { isOpen: false });\n };\n\n const handlePopoverInteraction = (nextIsOpen: boolean) => {\n setIsOpen(nextIsOpen);\n };\n\n const parseChildren = () => {\n const [targetChild, contentChild] = Children.toArray(children);\n return {\n target: targetChild as React.ReactElement,\n content: contentChild as React.ReactElement,\n };\n };\n\n const popoverTargetClasses = cx('Dropdown-target', targetClassName);\n const popoverClasses = cx('Dropdown', popoverClassName);\n\n return (\n <Popover\n isOpen={isOpen}\n placement={placement}\n onInteraction={onInteraction || handlePopoverInteraction}\n restrictHeight={false}\n disabled={disabled}\n targetClassName={popoverTargetClasses}\n popoverClassName={popoverClasses}\n {...rest}\n >\n {renderTrigger()}\n {renderContent()}\n </Popover>\n );\n};\n\nexport { Dropdown };\nexport type { DropdownProps };\n", "import type { ButtonKind, ButtonSize } from '@launchpad-ui/button';\n\nimport { Button } from '@launchpad-ui/button';\nimport { ExpandMore, IconSize } from '@launchpad-ui/icons';\nimport { forwardRef } from 'react';\n\ntype DropdownButtonProps = {\n hideCaret?: boolean;\n kind?: ButtonKind;\n size?: ButtonSize;\n className?: string;\n disabled?: boolean;\n children?: React.ReactNode;\n onClick?(v: React.MouseEvent): void;\n testId?: string;\n};\n\nconst DropdownButton = forwardRef<React.ElementRef<typeof Button>, DropdownButtonProps>(\n (props, ref) => {\n const { children, hideCaret, ...rest } = props;\n\n return (\n <Button {...rest} ref={ref}>\n {children} {!hideCaret && <ExpandMore size={IconSize.SMALL} />}\n </Button>\n );\n }\n);\n\nDropdownButton.displayName = 'DropdownButton';\n\nexport { DropdownButton };\nexport type { DropdownButtonProps };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,YAAuB;;;ACEvB,qBAAwB;AACxB,kBAAe;AACf,mBAAoE;AAiGhE;AAtFJ,IAAM,WAAW,CAAqC,UAA4B;AAChF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,OACG;AAAA,EACL,IAAI;AAEJ,QAAM,iBAAa,qBAAoB,IAAI;AAC3C,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,cAAc,KAAK;AACxD,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,MAAM;AAEjD,8BAAU,MAAM;AACd,QAAI,eAAe,QAAW;AAC5B,gBAAU,UAAU;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,UAAU,CAAC;AAEf,8BAAU,MAAM;AAEd,QAAI,aAAa,WAAW,OAAO;AACjC,iBAAW,MAAM;AACf,cAAM,UAAU,WAAW;AAC3B,YAAI,CAAC,SAAS;AACZ;AAAA,QACF;AAMA,cAAM,WAAW,QAAQ,UAAU,YAAY;AAE/C,SAAC,YAAY,QAAQ,QAAQ;AAAA,MAC/B,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,CAAC;AAEtB,8BAAU,MAAM;AACd,iBAAa,MAAM;AACnB,oBAAgB,EAAE,OAAO,CAAC;AAAA,EAE5B,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,gBAAgB,MAAM;AAC1B,eAAO,2BAAa,cAAc,EAAE,QAAQ;AAAA,MAC1C,iBAAiB;AAAA,MACjB,iBAAiB,SAAS,OAAO;AAAA,MACjC,KAAK;AAAA,MACL,QAAQ,QAAQ,SAAS;AAAA,IAC3B,CAAC;AAAA,EACH;AAEA,QAAM,gBAAgB,MAAM;AAC1B,eAAO,2BAAa,cAAc,EAAE,SAAS;AAAA,MAC3C,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,QAAM,eAAe,CAAC,SAAY;AAChC,cAAU,KAAK;AACf,eAAW,MAAM,EAAE,QAAQ,MAAM,CAAC;AAAA,EACpC;AAEA,QAAM,2BAA2B,CAAC,eAAwB;AACxD,cAAU,UAAU;AAAA,EACtB;AAEA,QAAM,gBAAgB,MAAM;AAC1B,UAAM,CAAC,aAAa,YAAY,IAAI,sBAAS,QAAQ,QAAQ;AAC7D,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,2BAAuB,YAAAA,SAAG,mBAAmB,eAAe;AAClE,QAAM,qBAAiB,YAAAA,SAAG,YAAY,gBAAgB;AAEtD,SACE,6CAAC;AAAA,IACC;AAAA,IACA;AAAA,IACA,eAAe,iBAAiB;AAAA,IAChC,gBAAgB;AAAA,IAChB;AAAA,IACA,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IACjB,GAAG;AAAA,IAEH;AAAA,oBAAc;AAAA,MACd,cAAc;AAAA;AAAA,GACjB;AAEJ;;;ACjHA,oBAAuB;AACvB,mBAAqC;AACrC,IAAAC,gBAA2B;AAkBrB;AALN,IAAM,qBAAiB;AAAA,EACrB,CAAC,OAAO,QAAQ;AACd,UAAM,EAAE,UAAU,cAAc,KAAK,IAAI;AAEzC,WACE,6CAAC;AAAA,MAAQ,GAAG;AAAA,MAAM;AAAA,MACf;AAAA;AAAA,QAAS;AAAA,QAAE,CAAC,aAAa,4CAAC;AAAA,UAAW,MAAM,sBAAS;AAAA,SAAO;AAAA;AAAA,KAC9D;AAAA,EAEJ;AACF;AAEA,eAAe,cAAc;",
6
+ "names": ["cx", "import_react"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@launchpad-ui/dropdown",
3
- "version": "0.2.7",
3
+ "version": "0.3.0",
4
4
  "status": "beta",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -25,15 +25,15 @@
25
25
  },
26
26
  "source": "src/index.ts",
27
27
  "dependencies": {
28
- "@launchpad-ui/button": "~0.3.1",
29
- "@launchpad-ui/icons": "~0.2.3",
30
- "@launchpad-ui/popover": "~0.5.5",
28
+ "@launchpad-ui/button": "~0.4.0",
29
+ "@launchpad-ui/icons": "~0.3.0",
30
+ "@launchpad-ui/popover": "~0.6.0",
31
31
  "@launchpad-ui/tokens": "~0.1.5",
32
32
  "clsx": "^1.2.0"
33
33
  },
34
34
  "peerDependencies": {
35
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
36
- "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
35
+ "react": "^18.0.0",
36
+ "react-dom": "^18.0.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "react": "^18.2.0",