reshaped 3.8.0-canary.5 → 3.8.0-canary.7

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/bundle.css +1 -1
  3. package/dist/bundle.js +11 -11
  4. package/dist/components/Autocomplete/Autocomplete.js +2 -2
  5. package/dist/components/Autocomplete/Autocomplete.types.d.ts +1 -1
  6. package/dist/components/DropdownMenu/DropdownMenu.js +4 -4
  7. package/dist/components/DropdownMenu/DropdownMenu.types.d.ts +2 -2
  8. package/dist/components/Flyout/Flyout.module.css +1 -1
  9. package/dist/components/Flyout/Flyout.types.d.ts +7 -7
  10. package/dist/components/Flyout/FlyoutContent.js +1 -1
  11. package/dist/components/Flyout/FlyoutControlled.js +4 -2
  12. package/dist/components/Flyout/tests/Flyout.stories.d.ts +8 -0
  13. package/dist/components/Flyout/tests/Flyout.stories.js +81 -33
  14. package/dist/components/Flyout/useFlyout.d.ts +1 -7
  15. package/dist/components/Flyout/useFlyout.js +5 -1
  16. package/dist/components/Flyout/utilities/calculatePosition.d.ts +3 -2
  17. package/dist/components/Flyout/utilities/calculatePosition.js +47 -22
  18. package/dist/components/Flyout/utilities/flyout.js +4 -2
  19. package/dist/components/Flyout/utilities/getPositionFallbacks.js +3 -3
  20. package/dist/components/Flyout/utilities/isFullyVisible.d.ts +0 -2
  21. package/dist/components/Flyout/utilities/isFullyVisible.js +5 -7
  22. package/dist/components/Hidden/Hidden.js +2 -1
  23. package/dist/components/Icon/Icon.js +2 -2
  24. package/dist/components/Icon/Icon.types.d.ts +1 -1
  25. package/dist/components/Icon/tests/Icon.stories.js +6 -1
  26. package/dist/components/MenuItem/MenuItem.module.css +1 -1
  27. package/dist/components/Popover/Popover.js +2 -2
  28. package/dist/components/Popover/Popover.module.css +1 -1
  29. package/dist/components/Popover/Popover.types.d.ts +3 -1
  30. package/dist/components/Reshaped/Reshaped.css +1 -1
  31. package/dist/components/Resizable/Resizable.js +4 -3
  32. package/dist/components/Select/Select.d.ts +8 -1
  33. package/dist/components/Select/Select.js +22 -48
  34. package/dist/components/Select/Select.module.css +1 -1
  35. package/dist/components/Select/Select.types.d.ts +56 -38
  36. package/dist/components/Select/SelectCustom.d.ts +3 -0
  37. package/dist/components/Select/SelectCustom.js +11 -0
  38. package/dist/components/Select/SelectCustomControlled.d.ts +4 -0
  39. package/dist/components/Select/SelectCustomControlled.js +88 -0
  40. package/dist/components/Select/SelectCustomUncontrolled.d.ts +4 -0
  41. package/dist/components/Select/SelectCustomUncontrolled.js +15 -0
  42. package/dist/components/Select/SelectEndContent.d.ts +3 -0
  43. package/dist/components/Select/SelectEndContent.js +12 -0
  44. package/dist/components/Select/SelectNative.d.ts +4 -0
  45. package/dist/components/Select/SelectNative.js +29 -0
  46. package/dist/components/Select/SelectOption.d.ts +4 -0
  47. package/dist/components/Select/SelectOption.js +15 -0
  48. package/dist/components/Select/SelectOptionGroup.d.ts +4 -0
  49. package/dist/components/Select/SelectOptionGroup.js +11 -0
  50. package/dist/components/Select/SelectRoot.d.ts +4 -0
  51. package/dist/components/Select/SelectRoot.js +21 -0
  52. package/dist/components/Select/SelectStartContent.d.ts +3 -0
  53. package/dist/components/Select/SelectStartContent.js +20 -0
  54. package/dist/components/Select/SelectTrigger.d.ts +4 -0
  55. package/dist/components/Select/SelectTrigger.js +16 -0
  56. package/dist/components/Select/tests/Select.stories.d.ts +35 -10
  57. package/dist/components/Select/tests/Select.stories.js +447 -175
  58. package/dist/components/Stepper/Stepper.js +2 -2
  59. package/dist/components/Stepper/Stepper.types.d.ts +2 -0
  60. package/dist/components/Stepper/tests/Stepper.stories.d.ts +1 -0
  61. package/dist/components/Stepper/tests/Stepper.stories.js +23 -0
  62. package/dist/components/Table/Table.js +6 -3
  63. package/dist/components/Timeline/Timeline.js +3 -2
  64. package/dist/components/Timeline/tests/Timeline.stories.js +0 -3
  65. package/dist/components/View/View.js +6 -4
  66. package/dist/utilities/props.d.ts +3 -0
  67. package/dist/utilities/props.js +19 -0
  68. package/package.json +1 -1
  69. package/dist/components/Select/tests/Select.test.stories.d.ts +0 -27
  70. package/dist/components/Select/tests/Select.test.stories.js +0 -132
@@ -11,7 +11,7 @@ import useElementId from "../../hooks/useElementId.js";
11
11
  import useIsomorphicLayoutEffect from "../../hooks/useIsomorphicLayoutEffect.js";
12
12
  const AutocompleteContext = React.createContext({});
13
13
  const Autocomplete = (props) => {
14
- const { children, onChange, onInput, onItemSelect, name, containerRef, instanceRef, onBackspace, onEnter, active, onOpen, onClose, ...textFieldProps } = props;
14
+ const { children, onChange, onInput, onItemSelect, name, containerRef, instanceRef, onBackspace, onEnter, active, onOpen, onClose, fallbackAdjustLayout, fallbackMinWidth, fallbackMinHeight, ...textFieldProps } = props;
15
15
  const [highlightedId, setHighlightedId] = React.useState();
16
16
  const onBackspaceRef = useHandlerRef(onBackspace);
17
17
  const contentRef = React.useRef(null);
@@ -120,7 +120,7 @@ const Autocomplete = (props) => {
120
120
  highlightedId,
121
121
  setHighlightedId,
122
122
  }), [highlightedId, handleItemClick]);
123
- return (_jsx(AutocompleteContext.Provider, { value: contextValue, children: _jsxs(DropdownMenu, { position: "bottom", width: "trigger", triggerType: "focus", trapFocusMode: false, active: isDropdownActive, onClose: handleClose, onOpen: handleOpen, containerRef: containerRef, disableHideAnimation: true, instanceRef: instanceRef, children: [_jsx(DropdownMenu.Trigger, { children: ({ ref, ...attributes }) => (_jsx(TextField, { ...textFieldProps, name: name, onChange: handleChange, focused: isDropdownActive, attributes: {
123
+ return (_jsx(AutocompleteContext.Provider, { value: contextValue, children: _jsxs(DropdownMenu, { position: "bottom", width: "trigger", triggerType: "focus", trapFocusMode: false, active: isDropdownActive, onClose: handleClose, onOpen: handleOpen, containerRef: containerRef, fallbackAdjustLayout: fallbackAdjustLayout, fallbackMinWidth: fallbackMinWidth, fallbackMinHeight: fallbackMinHeight, disableHideAnimation: true, instanceRef: instanceRef, children: [_jsx(DropdownMenu.Trigger, { children: ({ ref, ...attributes }) => (_jsx(TextField, { ...textFieldProps, name: name, onChange: handleChange, focused: isDropdownActive, attributes: {
124
124
  ...textFieldProps.attributes,
125
125
  // Ignoring the type check since TS can't infer the correct html element type
126
126
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -7,7 +7,7 @@ type SelectArgs = {
7
7
  /** Additional data that will be passed to the onItemSelect callback */
8
8
  data?: unknown;
9
9
  };
10
- export type Props = TextFieldProps & Pick<DropdownMenuProps, "containerRef" | "instanceRef" | "active" | "onOpen" | "onClose"> & {
10
+ export type Props = TextFieldProps & Pick<DropdownMenuProps, "containerRef" | "instanceRef" | "active" | "onOpen" | "onClose" | "fallbackAdjustLayout" | "fallbackMinWidth" | "fallbackMinHeight"> & {
11
11
  /** Callback for when value changes from user input */
12
12
  onInput?: TextFieldProps["onChange"];
13
13
  /** Callback for when an item is selected in the dropdown */
@@ -14,8 +14,8 @@ import s from "./DropdownMenu.module.css";
14
14
  const DropdownMenuSubContext = React.createContext(null);
15
15
  const DropdownMenuSubTriggerContext = React.createContext(false);
16
16
  const DropdownMenu = (props) => {
17
- const { children, position = "bottom-start", triggerType = "click", trapFocusMode = "action-menu", ...popoverProps } = props;
18
- return (_jsx(Popover, { ...popoverProps, position: position, padding: 0, trapFocusMode: trapFocusMode, triggerType: triggerType, children: children }));
17
+ const { children, position = "bottom-start", triggerType = "click", trapFocusMode = "action-menu", borderRadius = "small", ...popoverProps } = props;
18
+ return (_jsx(Popover, { ...popoverProps, position: position, padding: 0, trapFocusMode: trapFocusMode, triggerType: triggerType, borderRadius: borderRadius, disableHideAnimation: true, children: children }));
19
19
  };
20
20
  const DropdownMenuContent = (props) => {
21
21
  const { children, attributes, className } = props;
@@ -62,9 +62,9 @@ const DropdownMenuItem = (props) => {
62
62
  return (_jsx(MenuItem, { ...props, roundedCorners: true, className: [s.item, props.className], attributes: { role: "menuitem", ...props.attributes }, onClick: handleClick }));
63
63
  };
64
64
  const DropdownMenuSubMenu = (props) => {
65
- const { children } = props;
65
+ const { children, position = "end-top", contentGap = 0.5, ...dropdownMenuProps } = props;
66
66
  const dropdownMenuRef = React.useRef(null);
67
- return (_jsx(DropdownMenuSubContext.Provider, { value: dropdownMenuRef, children: _jsx(DropdownMenu, { triggerType: "hover", position: "end-top", contentGap: 0.5, instanceRef: dropdownMenuRef, children: children }) }));
67
+ return (_jsx(DropdownMenuSubContext.Provider, { value: dropdownMenuRef, children: _jsx(DropdownMenu, { ...dropdownMenuProps, triggerType: "hover", position: position, contentGap: contentGap, instanceRef: dropdownMenuRef, children: children }) }));
68
68
  };
69
69
  const DropdownMenuSubTriggerItem = (props) => {
70
70
  const { children, attributes, ...menuItemProps } = props;
@@ -3,7 +3,7 @@ import type { PopoverProps, PopoverInstance } from "../Popover";
3
3
  import type { MenuItemProps } from "../MenuItem";
4
4
  import type { FlyoutContentProps } from "../Flyout";
5
5
  export type Instance = PopoverInstance;
6
- export type Props = Pick<PopoverProps, "children" | "position" | "forcePosition" | "fallbackPositions" | "fallbackAdjustLayout" | "triggerType" | "contentGap" | "contentShift" | "onOpen" | "onClose" | "active" | "defaultActive" | "width" | "disableHideAnimation" | "disableCloseOnOutsideClick" | "instanceRef" | "containerRef" | "originCoordinates"> & {
6
+ export type Props = Pick<PopoverProps, "children" | "position" | "forcePosition" | "fallbackPositions" | "fallbackAdjustLayout" | "fallbackMinWidth" | "fallbackMinHeight" | "triggerType" | "contentGap" | "contentShift" | "onOpen" | "onClose" | "active" | "defaultActive" | "width" | "disableHideAnimation" | "disableCloseOnOutsideClick" | "instanceRef" | "containerRef" | "originCoordinates" | "borderRadius" | "elevation" | "initialFocusRef"> & {
7
7
  /** Change component trap focus keyboard behavior and shortcuts */
8
8
  trapFocusMode?: Extract<PopoverProps["trapFocusMode"], "action-menu" | "selection-menu"> | false;
9
9
  };
@@ -16,5 +16,5 @@ export type SectionProps = {
16
16
  export type SubMenuProps = {
17
17
  /** Node for inserting children */
18
18
  children: React.ReactNode;
19
- };
19
+ } & Pick<PopoverProps, "position" | "forcePosition" | "fallbackPositions" | "fallbackAdjustLayout" | "fallbackMinWidth" | "fallbackMinHeight" | "contentGap" | "contentShift" | "width" | "containerRef">;
20
20
  export type SubTriggerProps = Omit<MenuItemProps, "endSlot" | "roundedCorners">;
@@ -1 +1 @@
1
- .content{--rs-flyout-gap:0;--rs-flyout-origin-x:50%;--rs-flyout-origin-y:50%;isolation:isolate;pointer-events:none;position:absolute}.content.--hover{pointer-events:all}.content.--hover-disabled,.content.--hover-disabled .inner{pointer-events:none}.inner{opacity:0;outline:none;pointer-events:all;transform:scale(.9) translateY(0);transform-origin:var(--rs-flyout-origin-x) var(--rs-flyout-origin-y);transition:1ms var(--rs-easing-accelerate)}[data-rs-keyboard] .inner:focus{box-shadow:var(--rs-focus-shadow)}.content.--width-trigger .inner{transform:scale(1) translateY(var(--rs-unit-x2))}.content.--position-top,.content.--position-top-end,.content.--position-top-start{--rs-flyout-origin-y:100%;padding-bottom:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-bottom,.content.--position-bottom-end,.content.--position-bottom-start{--rs-flyout-origin-y:0%;padding-top:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-bottom-start,.content.--position-top-start{--rs-flyout-origin-x:0%}.content.--position-bottom-end,.content.--position-top-end{--rs-flyout-origin-x:100%}.content.--position-start,.content.--position-start-bottom,.content.--position-start-top{--rs-flyout-origin-x:100%;padding-right:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-end,.content.--position-end-bottom,.content.--position-end-top{--rs-flyout-origin-x:0%;padding-left:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-end-top,.content.--position-start-top{--rs-flyout-origin-y:0%}.content.--position-end-bottom,.content.--position-start-bottom{--rs-flyout-origin-y:100%}.content.--visible .inner{opacity:1;transform:scale(1) translateY(0)}.content.--animated .inner{transition-duration:var(--rs-duration-rapid);transition-property:opacity,transform}.content.--animated.--visible .inner{transition-duration:var(--rs-duration-fast);transition-timing-function:var(--rs-easing-decelerate)}
1
+ .content{--rs-flyout-gap:0;--rs-flyout-origin-x:50%;--rs-flyout-origin-y:50%;isolation:isolate;pointer-events:none;position:absolute}.content.--hover{pointer-events:all}.content.--hover-disabled,.content.--hover-disabled .inner{pointer-events:none}.inner{backface-visibility:hidden;height:100%;max-height:100%;max-width:100%;opacity:0;outline:none;overflow:auto;pointer-events:all;transform:scale(.92) translateY(0);transform-origin:var(--rs-flyout-origin-x) var(--rs-flyout-origin-y);transition:1ms var(--rs-easing-accelerate)}[data-rs-keyboard] .inner:focus{box-shadow:var(--rs-focus-shadow)}.content.--width-trigger .inner{transform:scale(1) translateY(var(--rs-unit-x2))}.content.--position-top,.content.--position-top-end,.content.--position-top-start{--rs-flyout-origin-y:100%;padding-bottom:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-bottom,.content.--position-bottom-end,.content.--position-bottom-start{--rs-flyout-origin-y:0%;padding-top:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-bottom-start,.content.--position-top-start{--rs-flyout-origin-x:0%}.content.--position-bottom-end,.content.--position-top-end{--rs-flyout-origin-x:100%}.content.--position-start,.content.--position-start-bottom,.content.--position-start-top{--rs-flyout-origin-x:100%;padding-right:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-end,.content.--position-end-bottom,.content.--position-end-top{--rs-flyout-origin-x:0%;padding-left:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-end-top,.content.--position-start-top{--rs-flyout-origin-y:0%}.content.--position-end-bottom,.content.--position-start-bottom{--rs-flyout-origin-y:100%}.content.--visible .inner{opacity:1;transform:scale(1) translateY(0)}.content.--animated .inner{transition-duration:var(--rs-duration-rapid);transition-property:opacity,transform}.content.--animated.--visible .inner{transition-duration:var(--rs-duration-fast);transition-timing-function:var(--rs-easing-decelerate)}
@@ -15,17 +15,13 @@ export type CloseReason = "escape-key" | "outside-click"
15
15
  | "item-selection" | "close-button";
16
16
  export type Position = `${YSide}` | `${YSide}-${XSide}` | `${XSide}` | `${XSide}-${YSide}`;
17
17
  export type Width = "trigger" | string;
18
- export type Options = {
19
- width?: Width;
18
+ export type Options = Pick<BaseProps, "width" | "fallbackAdjustLayout" | "fallbackMinWidth" | "fallbackMinHeight" | "contentGap" | "contentShift"> & {
20
19
  position: Position;
20
+ fallbackPositions?: Position[];
21
21
  container?: HTMLElement | null;
22
22
  rtl: boolean;
23
- fallbackPositions?: Position[];
24
- fallbackAdjustLayout?: boolean;
25
23
  lastUsedPosition: Position;
26
24
  onPositionChoose: (position: Position) => void;
27
- contentGap?: number;
28
- contentShift?: number;
29
25
  };
30
26
  export type Styles = React.CSSProperties;
31
27
  export type State = {
@@ -102,6 +98,10 @@ type BaseProps = {
102
98
  fallbackPositions?: Position[] | false;
103
99
  /** Adjust the content size and shift its position to fit into the container when none of the fallback positions work */
104
100
  fallbackAdjustLayout?: boolean;
101
+ /** Minimum width for the content when fallbackAdjustLayout is true */
102
+ fallbackMinWidth?: string;
103
+ /** Minimum height for the content when fallbackAdjustLayout is true */
104
+ fallbackMinHeight?: string;
105
105
  /** Change component trap focus keyboard behavior and shortcuts */
106
106
  trapFocusMode?: TrapMode | false;
107
107
  /** Disable the flyout content interactivity */
@@ -187,7 +187,7 @@ export type ContextProps = {
187
187
  handleContentMouseDown: () => void;
188
188
  handleContentMouseUp: () => void;
189
189
  isSubmenu: boolean;
190
- } & Pick<Props, "triggerType" | "contentClassName" | "contentAttributes" | "trapFocusMode" | "contentGap" | "contentShift" | "containerRef" | "disableContentHover" | "autoFocus">;
190
+ } & Pick<Props, "triggerType" | "contentClassName" | "contentAttributes" | "contentGap" | "trapFocusMode" | "containerRef" | "disableContentHover" | "autoFocus">;
191
191
  export type TriggerContextProps = {
192
192
  elRef?: ContextProps["triggerElRef"];
193
193
  };
@@ -11,7 +11,7 @@ import { useFlyoutContext, ContentProvider } from "./Flyout.context.js";
11
11
  import s from "./Flyout.module.css";
12
12
  const FlyoutContent = (props) => {
13
13
  const { children, className, attributes } = props;
14
- const { flyout, id, flyoutElRef, triggerElRef, handleClose, handleTransitionEnd, handleTransitionStart, triggerType, handleMouseEnter, handleMouseLeave, handleContentMouseDown, handleContentMouseUp, contentGap, contentClassName, contentAttributes, trapFocusMode, disableContentHover, autoFocus, width, containerRef: passedContainerRef, isSubmenu, } = useFlyoutContext();
14
+ const { flyout, id, flyoutElRef, triggerElRef, handleClose, handleTransitionEnd, handleTransitionStart, triggerType, handleMouseEnter, handleMouseLeave, handleContentMouseDown, handleContentMouseUp, contentClassName, contentAttributes, contentGap, trapFocusMode, disableContentHover, autoFocus, width, containerRef: passedContainerRef, isSubmenu, } = useFlyoutContext();
15
15
  const { styles, status, position } = flyout;
16
16
  const [mounted, setMounted] = React.useState(false);
17
17
  const closestFixedContainer = React.useMemo(() => {
@@ -15,7 +15,7 @@ import cooldown from "./utilities/cooldown.js";
15
15
  import { Provider, useFlyoutTriggerContext, useFlyoutContext, useFlyoutContentContext, } from "./Flyout.context.js";
16
16
  import useHandlerRef from "../../hooks/useHandlerRef.js";
17
17
  const FlyoutControlled = (props) => {
18
- const { triggerType = "click", groupTimeouts, onOpen, onClose, children, disabled, forcePosition, fallbackAdjustLayout, trapFocusMode = "dialog", width, disableHideAnimation, disableContentHover, disableCloseOnOutsideClick, autoFocus = true, originCoordinates, contentGap = 2, contentShift, contentClassName, contentAttributes, position: passedPosition, active: passedActive, id: passedId, instanceRef, containerRef, initialFocusRef, } = props;
18
+ const { triggerType = "click", groupTimeouts, onOpen, onClose, children, disabled, forcePosition, fallbackAdjustLayout, fallbackMinWidth, fallbackMinHeight, trapFocusMode = "dialog", width, disableHideAnimation, disableContentHover, disableCloseOnOutsideClick, autoFocus = true, originCoordinates, contentGap = 2, contentShift, contentClassName, contentAttributes, position: passedPosition, active: passedActive, id: passedId, instanceRef, containerRef, initialFocusRef, } = props;
19
19
  const fallbackPositions = props.fallbackPositions === false || forcePosition ? [] : props.fallbackPositions;
20
20
  const onOpenRef = useHandlerRef(onOpen);
21
21
  const onCloseRef = useHandlerRef(onClose);
@@ -63,6 +63,8 @@ const FlyoutControlled = (props) => {
63
63
  container: containerRef?.current,
64
64
  fallbackPositions,
65
65
  fallbackAdjustLayout,
66
+ fallbackMinWidth,
67
+ fallbackMinHeight,
66
68
  contentGap,
67
69
  contentShift,
68
70
  });
@@ -322,9 +324,9 @@ const FlyoutControlled = (props) => {
322
324
  handleContentMouseUp,
323
325
  triggerType,
324
326
  trapFocusMode,
325
- contentGap,
326
327
  contentClassName,
327
328
  contentAttributes,
329
+ contentGap,
328
330
  containerRef,
329
331
  disableContentHover,
330
332
  autoFocus,
@@ -33,6 +33,14 @@ export declare const fallbackAdjustLayout: {
33
33
  name: string;
34
34
  render: () => React.JSX.Element;
35
35
  };
36
+ export declare const fallbackAdjustLayoutShift: {
37
+ name: string;
38
+ render: () => React.JSX.Element;
39
+ };
40
+ export declare const fallbackAdjustLayoutSize: {
41
+ name: string;
42
+ render: () => React.JSX.Element;
43
+ };
36
44
  export declare const originCoordinates: {
37
45
  name: string;
38
46
  render: () => React.JSX.Element;
@@ -17,7 +17,7 @@ const Content = (props) => (<div style={{
17
17
  background: "var(--rs-color-background-elevation-overlay)",
18
18
  padding: "var(--rs-unit-x4)",
19
19
  height: props.height === false ? undefined : props.height || 150,
20
- minWidth: props.width === false ? undefined : props.width || 160,
20
+ width: props.width === false ? undefined : props.width || 160,
21
21
  borderRadius: "var(--rs-radius-medium)",
22
22
  border: "1px solid var(--rs-color-border-neutral-faded)",
23
23
  boxSizing: "border-box",
@@ -30,10 +30,18 @@ const Demo = (props) => {
30
30
  <Flyout.Trigger>
31
31
  {(attributes) => <Button attributes={attributes}>{text || position}</Button>}
32
32
  </Flyout.Trigger>
33
- <Flyout.Content>
34
- <Content height={contentHeight} width={contentWidth}>
35
- {children}
36
- </Content>
33
+ <Flyout.Content attributes={{
34
+ style: {
35
+ background: "var(--rs-color-background-elevation-overlay)",
36
+ padding: "var(--rs-unit-x4)",
37
+ height: contentHeight === false ? undefined : contentHeight || 150,
38
+ width: contentWidth === false ? undefined : contentWidth || 160,
39
+ borderRadius: "var(--rs-radius-medium)",
40
+ border: "1px solid var(--rs-color-border-neutral-faded)",
41
+ boxSizing: "border-box",
42
+ },
43
+ }}>
44
+ {children || "Content"}
37
45
  </Flyout.Content>
38
46
  </Flyout>);
39
47
  };
@@ -222,42 +230,58 @@ export const positionFallbacks = {
222
230
  </Example>);
223
231
  },
224
232
  };
225
- const FallbackAdjustLayoutControls = ({ containerRef, }) => (<>
226
- {/* Left side */}
227
- <View position="absolute" insetStart={4} insetTop={10} gap={2}>
228
- <Demo contentHeight="200px" position="end" fallbackPositions={false} fallbackAdjustLayout containerRef={containerRef}/>
229
- <Demo contentHeight="200px" position="end-bottom" fallbackPositions={false} fallbackAdjustLayout containerRef={containerRef}/>
230
- </View>
233
+ const FallbackAdjustLayoutControls = ({ containerRef, large, }) => {
234
+ const contentHeight = large ? "2000px" : "200px";
235
+ const contentWidth = large ? "2000px" : "300px";
236
+ return (<>
237
+ {/* Left side */}
238
+ <View position="absolute" insetStart={4} insetTop={10} gap={2}>
239
+ <Demo contentHeight={contentHeight} position="end" fallbackAdjustLayout fallbackPositions={false} containerRef={containerRef}/>
240
+ <Demo contentHeight={contentHeight} position="end-bottom" fallbackPositions={false} fallbackAdjustLayout containerRef={containerRef}/>
241
+ </View>
231
242
 
232
- <View position="absolute" insetStart={4} insetTop={80} gap={2}>
233
- <Demo position="bottom-end" fallbackPositions={false} fallbackAdjustLayout contentWidth={300} containerRef={containerRef}/>
234
- <Demo position="bottom" fallbackPositions={false} fallbackAdjustLayout contentWidth={300} containerRef={containerRef}/>
235
- </View>
243
+ <View position="absolute" insetStart={4} insetTop={80} gap={2}>
244
+ <Demo position="top" fallbackPositions={false} fallbackAdjustLayout contentWidth={contentWidth} containerRef={containerRef}/>
245
+ <Demo position="top-end" fallbackPositions={false} fallbackAdjustLayout contentWidth={contentWidth} containerRef={containerRef}/>
246
+ <Demo position="bottom-end" fallbackPositions={false} fallbackAdjustLayout contentWidth={contentWidth} containerRef={containerRef}/>
247
+ <Demo position="bottom" fallbackPositions={false} fallbackAdjustLayout contentWidth={contentWidth} containerRef={containerRef}/>
248
+ </View>
236
249
 
237
- <View position="absolute" insetBottom={4} insetStart={4} gap={2}>
238
- <Demo contentHeight="200px" position="end-top" fallbackPositions={false} fallbackAdjustLayout containerRef={containerRef}/>
239
- <Demo contentHeight="200px" position="end" fallbackPositions={false} fallbackAdjustLayout containerRef={containerRef}/>
240
- </View>
250
+ <View position="absolute" insetBottom={4} insetStart={4} gap={2}>
251
+ <Demo contentHeight={contentHeight} position="end-top" fallbackPositions={false} fallbackAdjustLayout containerRef={containerRef}/>
252
+ <Demo contentHeight={contentHeight} position="end" fallbackPositions={false} fallbackAdjustLayout containerRef={containerRef}/>
253
+ </View>
241
254
 
242
- {/* Right side */}
255
+ {/* Right side */}
243
256
 
244
- <View position="absolute" insetTop={10} insetEnd={4} gap={2}>
245
- <Demo contentHeight="200px" position="start" fallbackPositions={false} fallbackAdjustLayout/>
246
- <Demo contentHeight="200px" position="start-bottom" fallbackPositions={false} fallbackAdjustLayout containerRef={containerRef}/>
247
- </View>
257
+ <View position="absolute" insetTop={10} insetEnd={4} gap={2}>
258
+ <Demo contentHeight={contentHeight} position="start" fallbackPositions={false} fallbackAdjustLayout containerRef={containerRef}/>
259
+ <Demo contentHeight={contentHeight} position="start-bottom" fallbackPositions={false} fallbackAdjustLayout containerRef={containerRef}/>
260
+ </View>
248
261
 
249
- <View position="absolute" insetEnd={4} insetTop={80} gap={2}>
250
- <Demo position="top-start" fallbackPositions={false} fallbackAdjustLayout contentWidth={300} containerRef={containerRef}/>
251
- <Demo position="top" fallbackPositions={false} fallbackAdjustLayout contentWidth={300} containerRef={containerRef}/>
252
- </View>
262
+ <View position="absolute" insetEnd={4} insetTop={80} gap={2}>
263
+ <Demo position="top-start" fallbackPositions={false} fallbackAdjustLayout contentWidth={contentWidth} containerRef={containerRef}/>
264
+ <Demo position="top" fallbackPositions={false} fallbackAdjustLayout contentWidth={contentWidth} containerRef={containerRef}/>
265
+ <Demo position="bottom-start" fallbackPositions={false} fallbackAdjustLayout contentWidth={contentWidth} containerRef={containerRef}/>
266
+ <Demo position="bottom" fallbackPositions={false} fallbackAdjustLayout contentWidth={contentWidth} containerRef={containerRef}/>
267
+ </View>
253
268
 
254
- <View position="absolute" insetBottom={4} insetEnd={4} gap={2}>
255
- <Demo contentHeight="200px" position="start-top" fallbackPositions={false} fallbackAdjustLayout containerRef={containerRef}/>
256
- <Demo contentHeight="200px" position="start" fallbackPositions={false} fallbackAdjustLayout containerRef={containerRef}/>
257
- </View>
258
- </>);
269
+ <View position="absolute" insetBottom={4} insetEnd={4} gap={2}>
270
+ <Demo contentHeight={contentHeight} position="start-top" fallbackPositions={false} fallbackAdjustLayout containerRef={containerRef}/>
271
+ <Demo contentHeight={contentHeight} position="start" fallbackPositions={false} fallbackAdjustLayout containerRef={containerRef}/>
272
+ </View>
273
+ </>);
274
+ };
259
275
  export const fallbackAdjustLayout = {
260
276
  name: "fallbackAdjustLayout",
277
+ render: () => {
278
+ return (<Demo contentHeight={false} position="bottom-start" width="200px" fallbackAdjustLayout defaultActive>
279
+ <div style={{ height: "600px" }}>Content</div>
280
+ </Demo>);
281
+ },
282
+ };
283
+ export const fallbackAdjustLayoutShift = {
284
+ name: "fallbackAdjustLayout, shift",
261
285
  render: () => {
262
286
  const containerRef = React.useRef(null);
263
287
  return (<View gap={10}>
@@ -280,6 +304,30 @@ export const fallbackAdjustLayout = {
280
304
  </View>);
281
305
  },
282
306
  };
307
+ export const fallbackAdjustLayoutSize = {
308
+ name: "fallbackAdjustLayout, size",
309
+ render: () => {
310
+ const containerRef = React.useRef(null);
311
+ return (<View gap={10}>
312
+ <View height="95vh" width="100%" align="center" justify="center">
313
+ <View backgroundColor="neutral-faded" borderRadius="medium" height="1000px" width="600px" padding={4} paddingBlock={15} overflow="auto">
314
+ <FallbackAdjustLayoutControls large/>
315
+ <View height="150%" width="150%" attributes={{ style: { pointerEvents: "none" } }}/>
316
+ </View>
317
+ </View>
318
+
319
+ <View height="95vh" width="100%" align="center" justify="center">
320
+ <View backgroundColor="neutral-faded" borderRadius="medium" height="1000px" width="600px" attributes={{ ref: containerRef }} padding={4} paddingBlock={15} overflow="auto">
321
+ <FallbackAdjustLayoutControls containerRef={containerRef} large/>
322
+ <View height="150%" width="150%" attributes={{ style: { pointerEvents: "none" } }}/>
323
+ </View>
324
+ </View>
325
+
326
+ <FallbackAdjustLayoutControls large/>
327
+ <div style={{ height: "100vh", width: "250%" }}/>
328
+ </View>);
329
+ },
330
+ };
283
331
  export const originCoordinates = {
284
332
  name: "originCoordinates",
285
333
  render: () => {
@@ -1,14 +1,8 @@
1
1
  import React from "react";
2
2
  import type * as G from "../../types/global";
3
3
  import type * as T from "./Flyout.types";
4
- type UseFlyout = (args: {
5
- width?: T.Width;
6
- position?: T.Position;
7
- defaultActive?: boolean;
4
+ type UseFlyout = (args: Pick<T.Props, "width" | "position" | "defaultActive" | "fallbackAdjustLayout" | "fallbackMinWidth" | "fallbackMinHeight" | "contentGap" | "contentShift"> & {
8
5
  fallbackPositions?: T.Position[];
9
- fallbackAdjustLayout?: boolean;
10
- contentGap?: number;
11
- contentShift?: number;
12
6
  container?: HTMLElement | null;
13
7
  triggerElRef: React.RefObject<HTMLElement | null>;
14
8
  flyoutElRef: React.RefObject<HTMLElement | null>;
@@ -38,7 +38,7 @@ const flyoutReducer = (state, action) => {
38
38
  };
39
39
  const useFlyout = (args) => {
40
40
  const { triggerElRef, flyoutElRef, triggerBounds, contentGap, contentShift, ...options } = args;
41
- const { position: defaultPosition = "bottom", fallbackPositions, width, container, fallbackAdjustLayout, } = options;
41
+ const { position: defaultPosition = "bottom", fallbackPositions, fallbackAdjustLayout, fallbackMinWidth, fallbackMinHeight, width, container, } = options;
42
42
  const lastUsedPositionRef = React.useRef(defaultPosition);
43
43
  // Memo the array internally to avoid new arrays triggering useCallback
44
44
  const cachedFallbackPositions = React.useMemo(() => fallbackPositions,
@@ -77,6 +77,8 @@ const useFlyout = (args) => {
77
77
  position: changePositon ? defaultPosition : lastUsedPositionRef.current,
78
78
  fallbackPositions: changePositon ? cachedFallbackPositions : [],
79
79
  fallbackAdjustLayout,
80
+ fallbackMinWidth,
81
+ fallbackMinHeight,
80
82
  lastUsedPosition: lastUsedPositionRef.current,
81
83
  onPositionChoose: handlePosition,
82
84
  rtl: isRTL,
@@ -103,6 +105,8 @@ const useFlyout = (args) => {
103
105
  contentGap,
104
106
  contentShift,
105
107
  handlePosition,
108
+ fallbackMinWidth,
109
+ fallbackMinHeight,
106
110
  ]);
107
111
  React.useEffect(() => {
108
112
  if (state.status === "rendered")
@@ -10,15 +10,16 @@ declare const calculatePosition: (args: {
10
10
  };
11
11
  passedContainer?: HTMLElement | null;
12
12
  containerBounds: DOMRect;
13
- } & Pick<T.Options, "position" | "rtl" | "width" | "contentGap" | "contentShift" | "fallbackAdjustLayout">) => {
13
+ } & Pick<T.Options, "position" | "rtl" | "width" | "contentGap" | "contentShift" | "fallbackAdjustLayout" | "fallbackMinWidth" | "fallbackMinHeight">) => {
14
14
  position: T.Position;
15
15
  styles: {
16
- width: string | number | undefined;
17
16
  left: number | undefined;
18
17
  right: number | undefined;
19
18
  top: number | undefined;
20
19
  bottom: number | undefined;
21
20
  transform: string;
21
+ height: number | undefined;
22
+ width: string | number | undefined;
22
23
  };
23
24
  boundaries: {
24
25
  left: number;
@@ -4,12 +4,14 @@ const SCREEN_OFFSET = 8;
4
4
  * Calculate styles for the current position
5
5
  */
6
6
  const calculatePosition = (args) => {
7
- const { triggerBounds, flyoutBounds, containerBounds, position: passedPosition, rtl, width, contentGap = 0, contentShift = 0, passedContainer, fallbackAdjustLayout, } = args;
8
- const isFullWidth = width === "full" || width === "100%";
7
+ const { triggerBounds, flyoutBounds, containerBounds, position: passedPosition, rtl, width: passedWidth, contentGap = 0, contentShift = 0, passedContainer, fallbackAdjustLayout, fallbackMinWidth, fallbackMinHeight, } = args;
8
+ const isFullWidth = passedWidth === "full" || passedWidth === "100%";
9
9
  let left = 0;
10
10
  let top = 0;
11
11
  let bottom = null;
12
12
  let right = null;
13
+ let height = undefined;
14
+ let width = undefined;
13
15
  let position = passedPosition;
14
16
  if (rtl)
15
17
  position = getRTLPosition(position);
@@ -96,57 +98,80 @@ const calculatePosition = (args) => {
96
98
  break;
97
99
  }
98
100
  if (fallbackAdjustLayout) {
99
- const topOverflowSize = -top + scrollY + SCREEN_OFFSET;
100
- const bottomOverflowSize = top + flyoutHeight + SCREEN_OFFSET - scrollY - renderContainerHeight;
101
- const leftOverflowSize = -left + scrollX + SCREEN_OFFSET;
102
- const rightOverflowSize = left + flyoutWidth + SCREEN_OFFSET - scrollX - renderContainerWidth;
101
+ const getOverflow = () => {
102
+ return {
103
+ top: -top + scrollY + SCREEN_OFFSET,
104
+ bottom: top + flyoutHeight + SCREEN_OFFSET - scrollY - renderContainerHeight,
105
+ left: -left + scrollX + SCREEN_OFFSET,
106
+ right: left + flyoutWidth + SCREEN_OFFSET - scrollX - renderContainerWidth,
107
+ };
108
+ };
109
+ const overflow = getOverflow();
103
110
  if (isHorizontalPosition) {
104
- if (topOverflowSize > 0) {
111
+ if (overflow.top > 0) {
105
112
  top = SCREEN_OFFSET + scrollY;
106
113
  if (bottom !== null)
107
- bottom = bottom - topOverflowSize;
114
+ bottom = bottom - overflow.top;
108
115
  }
109
- else if (bottomOverflowSize > 0) {
110
- console.log({ bottomOverflowSize, renderContainerHeight });
111
- top = top - bottomOverflowSize;
116
+ else if (overflow.bottom > 0) {
117
+ top = top - overflow.bottom;
112
118
  }
113
119
  }
114
120
  else {
115
- if (leftOverflowSize > 0) {
121
+ if (overflow.left > 0) {
116
122
  left = SCREEN_OFFSET + scrollX;
117
123
  if (right !== null)
118
- right = right - leftOverflowSize;
124
+ right = right - overflow.left;
119
125
  }
120
- else if (rightOverflowSize > 0) {
121
- left = left - rightOverflowSize;
126
+ else if (overflow.right > 0) {
127
+ left = left - overflow.right;
122
128
  }
123
129
  }
130
+ const updatedOverflow = getOverflow();
131
+ if (updatedOverflow.top > 0) {
132
+ height = Math.max(fallbackMinHeight ? parseInt(fallbackMinHeight) : 0, flyoutHeight - updatedOverflow.top);
133
+ top = top + (flyoutHeight - height);
134
+ }
135
+ else if (updatedOverflow.bottom > 0) {
136
+ height = Math.max(fallbackMinHeight ? parseInt(fallbackMinHeight) : 0, flyoutHeight - updatedOverflow.bottom);
137
+ if (bottom !== null)
138
+ bottom = bottom + (flyoutHeight - height);
139
+ }
140
+ if (updatedOverflow.left > 0) {
141
+ width = Math.max(fallbackMinWidth ? parseInt(fallbackMinWidth) : 0, flyoutWidth - updatedOverflow.left);
142
+ left = left + (flyoutWidth - width);
143
+ }
144
+ else if (updatedOverflow.right > 0) {
145
+ width = Math.max(fallbackMinWidth ? parseInt(fallbackMinWidth) : 0, flyoutWidth - updatedOverflow.right);
146
+ if (right !== null)
147
+ right = right + (flyoutWidth - width);
148
+ }
124
149
  }
125
- let widthStyle;
126
150
  if (isFullWidth) {
127
151
  left = SCREEN_OFFSET;
128
- widthStyle = window.innerWidth - SCREEN_OFFSET * 2;
152
+ width = window.innerWidth - SCREEN_OFFSET * 2;
129
153
  }
130
- else if (width === "trigger") {
131
- widthStyle = triggerBounds.width;
154
+ else if (passedWidth === "trigger") {
155
+ width = triggerBounds.width;
132
156
  }
133
157
  const translateX = right !== null ? -right : left;
134
158
  const translateY = bottom !== null ? -bottom : top;
135
159
  return {
136
160
  position,
137
161
  styles: {
138
- width: widthStyle ?? width,
139
162
  left: right === null ? 0 : undefined,
140
163
  right: right === null ? undefined : 0,
141
164
  top: bottom === null ? 0 : undefined,
142
165
  bottom: bottom === null ? undefined : 0,
143
166
  transform: `translate(${translateX}px, ${translateY}px)`,
167
+ height,
168
+ width: width ?? passedWidth,
144
169
  },
145
170
  boundaries: {
146
171
  left,
147
172
  top,
148
- height: Math.ceil(flyoutHeight),
149
- width: widthStyle ?? Math.ceil(flyoutWidth),
173
+ height: height ?? Math.ceil(flyoutHeight),
174
+ width: width ?? Math.ceil(flyoutWidth),
150
175
  },
151
176
  };
152
177
  };
@@ -7,7 +7,7 @@ import { resetStyles } from "../Flyout.constants.js";
7
7
  * Set position of the target element to fit on the screen
8
8
  */
9
9
  const flyout = (args) => {
10
- const { triggerEl, flyoutEl, triggerBounds: passedTriggerBounds, contentShift = 0, contentGap = 0, position, fallbackPositions, fallbackAdjustLayout, width, container: passedContainer, lastUsedPosition, onPositionChoose, rtl, } = args;
10
+ const { triggerEl, flyoutEl, triggerBounds: passedTriggerBounds, contentShift = 0, contentGap = 0, position, fallbackPositions, fallbackAdjustLayout, fallbackMinWidth, fallbackMinHeight, width, container: passedContainer, lastUsedPosition, onPositionChoose, rtl, } = args;
11
11
  const targetClone = flyoutEl.cloneNode(true);
12
12
  const baseUnit = getComputedStyle(flyoutEl).getPropertyValue("--rs-unit-x1");
13
13
  const unitModifier = baseUnit ? parseInt(baseUnit) : 4;
@@ -55,6 +55,8 @@ const flyout = (args) => {
55
55
  passedContainer: passedContainer ||
56
56
  (closestFixedContainer !== document.body ? closestFixedContainer : undefined),
57
57
  fallbackAdjustLayout,
58
+ fallbackMinWidth,
59
+ fallbackMinHeight,
58
60
  });
59
61
  };
60
62
  const testVisibility = (calculated) => {
@@ -62,7 +64,6 @@ const flyout = (args) => {
62
64
  flyoutBounds: calculated.boundaries,
63
65
  visualContainerBounds,
64
66
  renderContainerBounds,
65
- container,
66
67
  });
67
68
  };
68
69
  let calculated = null;
@@ -70,6 +71,7 @@ const flyout = (args) => {
70
71
  testOrder.some((currentPosition) => {
71
72
  const tested = applyPosition(currentPosition);
72
73
  const visible = testVisibility(tested);
74
+ console.log(currentPosition, tested, visible ? "yes" : "no");
73
75
  if (visible)
74
76
  calculated = tested;
75
77
  return visible;
@@ -14,7 +14,7 @@ const fallbackOrder = {
14
14
  };
15
15
  // Get an order of positions to try to fit flyout on the screen based on its starting position
16
16
  const getPositionFallbacks = (position, availableFallbacks) => {
17
- const result = [position];
17
+ const result = new Set([position]);
18
18
  const chunks = position.split("-");
19
19
  const [firstChunk] = chunks;
20
20
  const passedPositionOrder = positions[firstChunk];
@@ -31,9 +31,9 @@ const getPositionFallbacks = (position, availableFallbacks) => {
31
31
  const position = fallbackOrder[index];
32
32
  if (availableFallbacks?.indexOf(position) === -1)
33
33
  return;
34
- result.push(position);
34
+ result.add(position);
35
35
  });
36
36
  });
37
- return result;
37
+ return Array.from(result);
38
38
  };
39
39
  export default getPositionFallbacks;
@@ -8,7 +8,5 @@ declare const isFullyVisible: (args: {
8
8
  visualContainerBounds: DOMRect;
9
9
  /** Bounds of the container where flyout content is rendered */
10
10
  renderContainerBounds: DOMRect;
11
- /** Container where the flyout content is rendered */
12
- container: HTMLElement;
13
11
  }) => boolean;
14
12
  export default isFullyVisible;
@@ -2,20 +2,18 @@
2
2
  * Check if element visually fits within its render container
3
3
  */
4
4
  const isFullyVisible = (args) => {
5
- const { flyoutBounds, visualContainerBounds, renderContainerBounds, container } = args;
6
- const scrollX = container === document.body ? window.scrollX : container.scrollLeft;
7
- const scrollY = container === document.body ? window.scrollY : container.scrollTop;
8
- if (renderContainerBounds.left + flyoutBounds.left - scrollX < visualContainerBounds.left) {
5
+ const { flyoutBounds, visualContainerBounds, renderContainerBounds } = args;
6
+ if (renderContainerBounds.left + flyoutBounds.left < visualContainerBounds.left) {
9
7
  return false;
10
8
  }
11
- if (renderContainerBounds.top + flyoutBounds.top - scrollY < visualContainerBounds.top) {
9
+ if (renderContainerBounds.top + flyoutBounds.top < visualContainerBounds.top) {
12
10
  return false;
13
11
  }
14
- if (renderContainerBounds.left + flyoutBounds.left + flyoutBounds.width - scrollX >
12
+ if (renderContainerBounds.left + flyoutBounds.left + flyoutBounds.width >
15
13
  visualContainerBounds.right) {
16
14
  return false;
17
15
  }
18
- if (renderContainerBounds.top + flyoutBounds.top + flyoutBounds.height - scrollY >
16
+ if (renderContainerBounds.top + flyoutBounds.top + flyoutBounds.height >
19
17
  visualContainerBounds.bottom) {
20
18
  return false;
21
19
  }
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { classNames, responsiveClassNames } from "../../utilities/props.js";
2
+ import { classNames, responsiveClassNames, setComponentChildId } from "../../utilities/props.js";
3
3
  import s from "./Hidden.module.css";
4
4
  const Hidden = (props) => {
5
5
  const { as: TagName = "div", children, visibility, hide } = props;
@@ -7,4 +7,5 @@ const Hidden = (props) => {
7
7
  return _jsx(TagName, { className: rootClassNames, children: children });
8
8
  };
9
9
  Hidden.displayName = "Hidden";
10
+ setComponentChildId(Hidden, "Hidden");
10
11
  export default Hidden;