@nulogy/components 16.0.4 → 16.2.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.
@@ -3,13 +3,13 @@ import type { AnimationProps } from "framer-motion";
3
3
  import type { HeightProps, LayoutProps, MaxHeightProps, MaxWidthProps, SpaceProps, WidthProps } from "styled-system";
4
4
  declare const Overlay: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<Omit<Omit<Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
5
5
  ref?: import("react").Ref<HTMLDivElement>;
6
- }, "as" | keyof import("@reach/dialog").DialogOverlayProps> & import("@reach/dialog").DialogOverlayProps & {
6
+ }, "as" | keyof import("@reach/dialog").DialogInnerProps> & import("@reach/dialog").DialogInnerProps & {
7
7
  as?: "div";
8
8
  } & import("framer-motion").MotionProps, "ref"> & import("react").RefAttributes<HTMLElement | SVGElement>, "ref"> & {
9
9
  ref?: import("react").Ref<HTMLElement | SVGElement>;
10
10
  }, never>> & string & Omit<import("framer-motion").CustomDomComponent<Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
11
11
  ref?: import("react").Ref<HTMLDivElement>;
12
- }, "as" | keyof import("@reach/dialog").DialogOverlayProps> & import("@reach/dialog").DialogOverlayProps & {
12
+ }, "as" | keyof import("@reach/dialog").DialogInnerProps> & import("@reach/dialog").DialogInnerProps & {
13
13
  as?: "div";
14
14
  }>, keyof import("react").Component<any, {}, any>>;
15
15
  interface SheetProps extends DialogContentProps, AnimationProps, WidthProps, MaxWidthProps, HeightProps, MaxHeightProps, SpaceProps, LayoutProps {
@@ -2,7 +2,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from "react";
3
3
  import { styled } from "styled-components";
4
4
  import { space, variant } from "styled-system";
5
- import { Manager, Reference, Popper } from "react-popper-2";
6
5
  import { transparentize } from "polished";
7
6
  import icons from "@nulogy/icons";
8
7
  import { Icon } from "../Icon";
@@ -20,7 +19,7 @@ const IconWrapper = styled.span(({ theme, size }) => ({
20
19
  }));
21
20
  const HoverText = styled.div(({ theme }) => ({
22
21
  whiteSpace: "nowrap",
23
- ontSize: theme.fontSizes.small,
22
+ fontSize: theme.fontSizes.small,
24
23
  lineHeight: theme.lineHeights.smallTextCompressed,
25
24
  color: theme.colors.whiteGrey,
26
25
  backgroundColor: transparentize(0.15, theme.colors.blackBlue),
@@ -28,6 +27,11 @@ const HoverText = styled.div(({ theme }) => ({
28
27
  marginTop: theme.space.half,
29
28
  padding: `${theme.space.half} ${theme.space.x1}`,
30
29
  pointerEvents: "none",
30
+ position: "absolute",
31
+ top: "100%",
32
+ left: "50%",
33
+ transform: "translateX(-50%)",
34
+ zIndex: 1,
31
35
  }));
32
36
  const WrapperButton = styled.button(({ disabled, hoverBackgroundColor, theme }) => ({
33
37
  background: "transparent",
@@ -90,16 +94,7 @@ const WrapperButton = styled.button(({ disabled, hoverBackgroundColor, theme })
90
94
  }), space);
91
95
  const IconicButton = React.forwardRef(({ children, color = "darkBlue", hoverBackgroundColor = "lightBlue", icon, labelHidden, className, iconSize = "x3", fontSize, tooltip, variant, ...props }, forwardedRef) => {
92
96
  const componentVariant = useComponentVariant(variant);
93
- return (_jsxs(WrapperButton, { ref: forwardedRef, "aria-label": props["aria-label"] ? props["aria-label"] : typeof children === "string" ? children : undefined, className: className, hoverBackgroundColor: hoverBackgroundColor, variant: componentVariant, ...props, children: [_jsxs(Manager, { children: [_jsx(Reference, { children: ({ ref }) => (_jsx(IconWrapper, { ref: ref, size: iconSize, children: _jsx(Icon, { size: iconSize, icon: icon, color: color }) })) }), _jsx(Popper, { placement: "bottom", modifiers: [
94
- {
95
- name: "preventOverflow",
96
- enabled: true,
97
- options: {
98
- padding: 8,
99
- rootBoundary: "viewport",
100
- },
101
- },
102
- ], children: ({ ref, style }) => labelHidden || tooltip ? (_jsx(HoverText, { ref: ref, style: style, children: tooltip ? tooltip : children })) : null })] }), children &&
97
+ return (_jsxs(WrapperButton, { ref: forwardedRef, "aria-label": props["aria-label"] ? props["aria-label"] : typeof children === "string" ? children : undefined, className: className, hoverBackgroundColor: hoverBackgroundColor, variant: componentVariant, ...props, children: [_jsx(IconWrapper, { size: iconSize, children: _jsx(Icon, { size: iconSize, icon: icon, color: color }) }), (labelHidden || tooltip) && _jsx(HoverText, { children: tooltip ?? children }), children &&
103
98
  !labelHidden &&
104
99
  (typeof children === "string" || typeof children === "number" ? (_jsx(Text, { fontSize: fontSize, mr: "half", ml: "half", color: color, children: children })) : (children))] }));
105
100
  });
@@ -13,7 +13,7 @@ export default _default;
13
13
  type Story = StoryObj<typeof Sidebar>;
14
14
  export declare const _Sidebar: () => import("react/jsx-runtime").JSX.Element;
15
15
  export declare const WithoutOverlay: () => import("react/jsx-runtime").JSX.Element;
16
- export declare const OpenByDefault: () => import("react/jsx-runtime").JSX.Element;
16
+ export declare const OpenByDefault: Story;
17
17
  export declare const WithCustomOffset: Story;
18
18
  export declare const DontCloseOnOutsideClick: () => import("react/jsx-runtime").JSX.Element;
19
19
  export declare const WithoutCloseButton: () => import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useState, useRef } from "react";
3
+ import { expect, userEvent, waitFor, within } from "storybook/test";
3
4
  import { ApplicationFrame, Breadcrumbs, Link, Page, Sidebar, Select, PrimaryButton, Box, Textarea, Heading3, Navigation, } from "..";
4
5
  import { useUrlProps } from "../utils/testing/useUrlProps";
5
6
  export default {
@@ -33,16 +34,28 @@ export const WithoutOverlay = () => {
33
34
  };
34
35
  return (_jsx(ApplicationFrame, { navBar: _jsx(Navigation, {}), overflowX: "hidden", children: _jsxs(Page, { breadcrumbs: _jsxs(Breadcrumbs, { children: [_jsx(Link, { href: "/", children: "Home" }), _jsx(Link, { href: "/", children: "Materials" })] }), title: "Materials Overview", children: [_jsxs(Box, { minWidth: "300px", children: [_jsx(PrimaryButton, { onClick: toggleSidebar, ref: triggerRef, id: "openSidebarTrigger", children: "Open Sidebar" }), _jsxs(Box, { height: "3000px", width: "100%", bg: "lightBlue", mt: "x3", p: "x2", children: ["Space for more content", _jsx("input", {})] })] }), _jsx(ExampleSidebar, { isOpen: isOpen, onClose: closeSidebar, triggerRef: triggerRef, "aria-controls": "openSidebarTrigger", overlay: false })] }) }));
35
36
  };
36
- export const OpenByDefault = () => {
37
- const [isOpen, setIsOpen] = useState(true);
38
- const triggerRef = useRef(null);
39
- const toggleSidebar = () => {
40
- setIsOpen(!isOpen);
41
- };
42
- const closeSidebar = () => {
43
- setIsOpen(false);
44
- };
45
- return (_jsx(ApplicationFrame, { navBar: _jsx(Navigation, {}), overflowX: "hidden", children: _jsxs(Page, { breadcrumbs: _jsxs(Breadcrumbs, { children: [_jsx(Link, { href: "/", children: "Home" }), _jsx(Link, { href: "/", children: "Materials" })] }), title: "Materials Overview", children: [_jsxs(Box, { minWidth: "300px", children: [_jsx(PrimaryButton, { onClick: toggleSidebar, ref: triggerRef, id: "openSidebarTrigger", children: "Open Sidebar" }), _jsx(Box, { height: "3000px", width: "100%", bg: "lightBlue", mt: "x3", p: "x2", children: "Space for more content" })] }), _jsx(ExampleSidebar, { isOpen: isOpen, onClose: closeSidebar, triggerRef: triggerRef, "aria-controls": "openSidebarTrigger" })] }) }));
37
+ export const OpenByDefault = {
38
+ play: async ({ canvasElement, step }) => {
39
+ await step("overlay is visible when sidebar is open", async () => {
40
+ await expect(canvasElement.querySelector("[data-testid='sidebar-overlay']")).toBeTruthy();
41
+ });
42
+ await step("close button dismisses the sidebar", async () => {
43
+ const canvas = within(canvasElement);
44
+ await userEvent.click(canvas.getByLabelText("Close"));
45
+ await waitFor(() => expect(canvasElement.querySelector("[data-testid='sidebar-overlay']")).toBeNull());
46
+ });
47
+ },
48
+ render: () => {
49
+ const [isOpen, setIsOpen] = useState(true);
50
+ const triggerRef = useRef(null);
51
+ const toggleSidebar = () => {
52
+ setIsOpen(!isOpen);
53
+ };
54
+ const closeSidebar = () => {
55
+ setIsOpen(false);
56
+ };
57
+ return (_jsx(ApplicationFrame, { navBar: _jsx(Navigation, {}), overflowX: "hidden", children: _jsxs(Page, { breadcrumbs: _jsxs(Breadcrumbs, { children: [_jsx(Link, { href: "/", children: "Home" }), _jsx(Link, { href: "/", children: "Materials" })] }), title: "Materials Overview", children: [_jsxs(Box, { minWidth: "300px", children: [_jsx(PrimaryButton, { onClick: toggleSidebar, ref: triggerRef, id: "openSidebarTrigger", children: "Open Sidebar" }), _jsx(Box, { height: "3000px", width: "100%", bg: "lightBlue", mt: "x3", p: "x2", children: "Space for more content" })] }), _jsx(ExampleSidebar, { isOpen: isOpen, onClose: closeSidebar, triggerRef: triggerRef, "aria-controls": "openSidebarTrigger" })] }) }));
58
+ },
46
59
  };
47
60
  const WithCustomOffsetComponent = (args) => {
48
61
  const [isOpen, setIsOpen] = useState(true);
@@ -1,27 +1,31 @@
1
1
  import React from "react";
2
- type ModalProps = {
2
+ interface ModalProps {
3
3
  children?: React.ReactNode;
4
4
  isOpen?: boolean;
5
5
  title?: string;
6
6
  ariaLabel?: string;
7
- onRequestClose?: (...args: any[]) => any;
7
+ onRequestClose?: () => void;
8
8
  closeAriaLabel?: string;
9
- onAfterOpen?: (...args: any[]) => any;
9
+ onAfterOpen?: () => void;
10
10
  shouldFocusAfterRender?: boolean;
11
11
  shouldReturnFocusAfterClose?: boolean;
12
12
  ariaDescribedBy?: string;
13
13
  maxWidth?: string;
14
+ /** @deprecated No-op. Radix handles portal class automatically. */
14
15
  portalClassName?: string;
16
+ /** @deprecated No-op. Use className for the modal content element. */
15
17
  overlayClassName?: string;
16
18
  className?: string;
17
19
  id?: string;
20
+ /** @deprecated No-op. Radix handles aria-modal automatically. */
18
21
  appElement?: JSX.Element;
22
+ /** @deprecated No-op. Radix handles aria hiding automatically. */
19
23
  ariaHideApp?: boolean;
20
24
  footerContent?: React.ReactNode;
21
- parentSelector?: (...args: any) => HTMLElement;
22
- };
23
- declare function Modal({ isOpen, shouldFocusAfterRender, shouldReturnFocusAfterClose, maxWidth, ariaHideApp, children, title, onRequestClose, onAfterOpen, ariaLabel, ariaDescribedBy, portalClassName, overlayClassName, className, id, appElement, footerContent, closeAriaLabel, parentSelector, }: ModalProps): import("react/jsx-runtime").JSX.Element;
25
+ parentSelector?: () => HTMLElement;
26
+ }
27
+ declare function Modal({ isOpen, shouldFocusAfterRender, shouldReturnFocusAfterClose, maxWidth, children, title, onRequestClose, onAfterOpen, ariaLabel, ariaDescribedBy, className, id, footerContent, closeAriaLabel, parentSelector, portalClassName: _portalClassName, overlayClassName: _overlayClassName, appElement: _appElement, ariaHideApp: _ariaHideApp, }: ModalProps): import("react/jsx-runtime").JSX.Element;
24
28
  declare namespace Modal {
25
- var setAppElement: any;
29
+ var setAppElement: (_appElement?: string | HTMLElement) => void;
26
30
  }
27
31
  export default Modal;
@@ -1,7 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useContext } from "react";
3
- import { styled, ThemeContext, useTheme } from "styled-components";
4
- import ReactModal from "react-modal";
2
+ import { styled, useTheme } from "styled-components";
3
+ import * as Dialog from "@radix-ui/react-dialog";
5
4
  import { transparentize } from "polished";
6
5
  import { Heading2 } from "../Type";
7
6
  import { useScrollLock } from "../utils/useScrollLock";
@@ -9,67 +8,70 @@ import ModalContent from "./ModalContent";
9
8
  import ModalFooter from "./ModalFooter";
10
9
  import ModalHeader from "./ModalHeader";
11
10
  import ModalCloseButton from "./ModalCloseButton";
12
- const overlayStyle = (theme) => ({
11
+ const StyledDialogOverlay = styled(Dialog.Overlay)(({ theme }) => ({
13
12
  position: "fixed",
14
- top: 0,
15
- left: 0,
16
- right: 0,
17
- bottom: 0,
18
- display: "flex",
19
- justifyContent: "center",
20
- alignItems: "center",
13
+ inset: 0,
21
14
  backgroundColor: transparentize(0.5, theme.colors.blackBlue),
22
15
  zIndex: theme.zIndices.overlay,
23
- });
24
- const StyledReactModal = styled(ReactModal)(({ maxWidth }) => ({
25
- maxWidth,
26
- }), ({ theme }) => ({
16
+ }));
17
+ const StyledDialogContent = styled(Dialog.Content)(({ theme, $maxWidth }) => ({
27
18
  "&:focus": {
28
19
  outline: "none",
29
20
  },
30
21
  display: "flex",
31
22
  flexDirection: "column",
32
- position: "relative",
33
- top: 0,
34
- left: 0,
35
- right: 0,
36
- bottom: 0,
23
+ position: "fixed",
24
+ top: "50%",
25
+ left: "50%",
26
+ transform: "translate(-50%, -50%)",
37
27
  backgroundColor: theme.colors.white,
38
28
  borderRadius: theme.radii.medium,
39
29
  boxShadow: theme.shadows.large,
40
- border: undefined,
41
- width: "100%",
42
- height: "auto",
30
+ width: `calc(100% - ${theme.space.x4})`,
31
+ maxWidth: $maxWidth,
43
32
  maxHeight: `calc(100vh - ${theme.space.x8})`,
44
- margin: `0px ${theme.space.x2}`,
33
+ height: "auto",
34
+ overflow: "hidden",
45
35
  padding: 0,
36
+ zIndex: theme.zIndices.overlay,
46
37
  [`@media only screen and (max-width: ${theme.breakpoints.small})`]: {
47
- width: "100%",
48
38
  maxWidth: "100%",
39
+ width: "100%",
49
40
  },
50
41
  "*": {
51
42
  boxSizing: "border-box",
52
43
  },
53
44
  color: theme.colors.black,
45
+ fontFamily: theme.fonts.base,
54
46
  fontSize: theme.fontSizes.base,
55
47
  lineHeight: theme.lineHeights.base,
56
48
  WebkitFontSmoothing: "antialiased",
57
49
  MozOsxFontSmoothing: "grayscale",
58
50
  }));
59
- function Modal({ isOpen = true, shouldFocusAfterRender = true, shouldReturnFocusAfterClose = true, maxWidth = "624px", ariaHideApp = true, children, title, onRequestClose, onAfterOpen, ariaLabel, ariaDescribedBy, portalClassName, overlayClassName, className, id, appElement, footerContent, closeAriaLabel, parentSelector, }) {
51
+ function Modal({ isOpen = true, shouldFocusAfterRender = true, shouldReturnFocusAfterClose = true, maxWidth = "624px", children, title, onRequestClose, onAfterOpen, ariaLabel, ariaDescribedBy, className, id, footerContent, closeAriaLabel, parentSelector,
52
+ // accepted but unused (no-ops):
53
+ portalClassName: _portalClassName, overlayClassName: _overlayClassName, appElement: _appElement, ariaHideApp: _ariaHideApp, }) {
60
54
  const modalHasHeader = Boolean(onRequestClose || title);
61
- const themeContext = useContext(ThemeContext);
62
- return (_jsx(StyledReactModal, { maxWidth: maxWidth, contentLabel: ariaLabel, onRequestClose: onRequestClose, onAfterOpen: onAfterOpen, shouldFocusAfterRender: shouldFocusAfterRender, shouldReturnFocusAfterClose: shouldReturnFocusAfterClose, isOpen: isOpen, portalClassName: portalClassName, overlayClassName: overlayClassName, className: className, id: id, aria: {
63
- labelledby: title ? "modal-title" : undefined,
64
- describedby: ariaDescribedBy,
65
- }, shouldCloseOnOverlayClick: true, shouldCloseOnEsc: true, style: {
66
- overlay: overlayStyle(themeContext),
67
- }, appElement: appElement, ariaHideApp: ariaHideApp, parentSelector: parentSelector, children: _jsx(ModalWrapper, { closeAriaLabel: closeAriaLabel, modalHasHeader: modalHasHeader, title: title, onRequestClose: onRequestClose, footerContent: footerContent, children: children }) }));
55
+ return (_jsx(Dialog.Root, { open: isOpen, onOpenChange: (open) => {
56
+ if (open)
57
+ onAfterOpen?.();
58
+ else
59
+ onRequestClose?.();
60
+ }, children: _jsxs(Dialog.Portal, { container: parentSelector?.(), children: [_jsx(StyledDialogOverlay, {}), _jsx(StyledDialogContent, { "$maxWidth": maxWidth, "aria-label": !title ? ariaLabel : undefined, "aria-labelledby": title ? "modal-title" : undefined, "aria-describedby": ariaDescribedBy, className: className, id: id, onOpenAutoFocus: (e) => {
61
+ if (!shouldFocusAfterRender)
62
+ e.preventDefault();
63
+ }, onCloseAutoFocus: (e) => {
64
+ if (!shouldReturnFocusAfterClose)
65
+ e.preventDefault();
66
+ }, children: _jsx(ModalWrapper, { closeAriaLabel: closeAriaLabel, modalHasHeader: modalHasHeader, title: title, onRequestClose: onRequestClose, footerContent: footerContent, children: children }) })] }) }));
68
67
  }
69
68
  function ModalWrapper({ modalHasHeader, title, onRequestClose, closeAriaLabel, children, footerContent, }) {
70
69
  const theme = useTheme();
71
70
  useScrollLock();
72
71
  return (_jsxs(_Fragment, { children: [modalHasHeader && (_jsxs(ModalHeader, { hasCloseButton: Boolean(onRequestClose), children: [title ? (_jsx(Heading2, { id: "modal-title", mb: "none", children: title })) : (_jsx("div", { style: { height: theme.space.x4 } })), onRequestClose && _jsx(ModalCloseButton, { onClick: onRequestClose, "aria-label": closeAriaLabel })] })), _jsx(ModalContent, { hasFooter: !!footerContent, children: children }), footerContent && _jsx(ModalFooter, { children: footerContent })] }));
73
72
  }
74
- Modal.setAppElement = ReactModal.setAppElement;
73
+ Modal.setAppElement = (_appElement) => {
74
+ console.warn("[NDS] Modal.setAppElement() is deprecated and has no effect. " +
75
+ "The Modal component now uses @radix-ui/react-dialog, which handles aria-modal automatically.");
76
+ };
75
77
  export default Modal;
@@ -10,7 +10,6 @@ declare const _default: {
10
10
  export default _default;
11
11
  type Story = StoryObj<typeof NDSModal>;
12
12
  export declare const Default: Story;
13
- export declare const WithCloseButton: Story;
14
13
  export declare const WithScrollingContent: Story;
15
14
  export declare const WithScrollingContentWithoutFooterContent: Story;
16
15
  export declare const WithNoTitle: Story;
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { expect, userEvent, within } from "storybook/test";
2
3
  import { useState } from "react";
3
4
  import { Modal as NDSModal, Button, QuietButton, PrimaryButton, ButtonGroup, Form, Input, Select, Text, DatePicker, } from "../index";
4
5
  if (process.env.NODE_ENV !== "test")
@@ -28,15 +29,6 @@ export const Default = {
28
29
  onRequestClose: () => { },
29
30
  },
30
31
  };
31
- export const WithCloseButton = {
32
- args: {
33
- children: "Content Content Content",
34
- title: "Modal Title",
35
- footerContent: ModalButtons,
36
- onRequestClose: () => { },
37
- },
38
- name: "with close button",
39
- };
40
32
  export const WithScrollingContent = {
41
33
  args: {
42
34
  title: "Modal Title",
@@ -108,6 +100,15 @@ export const WithParentSelector = {
108
100
  export const ExampleControlledModal = {
109
101
  render: () => _jsx(ModalExample, {}),
110
102
  name: "example controlled modal",
103
+ play: async ({ canvasElement }) => {
104
+ const canvas = within(canvasElement);
105
+ const body = within(document.body);
106
+ await userEvent.click(canvas.getByRole("button", { name: "Open Modal" }));
107
+ const dialog = await body.findByRole("dialog");
108
+ expect(dialog).toBeVisible();
109
+ await userEvent.keyboard("{Escape}");
110
+ expect(body.queryByRole("dialog")).not.toBeInTheDocument();
111
+ },
111
112
  };
112
113
  const ModalExample = () => {
113
114
  const [isOpen, setIsOpen] = useState(false);
@@ -10,6 +10,7 @@ export declare const WithData: Story;
10
10
  export declare const WithNoData: Story;
11
11
  export declare const WithStickyHeader: Story;
12
12
  export declare const WithLotsOfRowsAndColumns: Story;
13
+ export declare const WithLoading: Story;
13
14
  export declare const WithCustomColumnWidths: () => import("react/jsx-runtime").JSX.Element;
14
15
  export declare const WithACustomCellComponent: () => import("react/jsx-runtime").JSX.Element;
15
16
  export declare const WithCellAlignment: () => import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { action } from "storybook/actions";
3
+ import { expect, within } from "storybook/test";
3
4
  import { Box, DropdownButton, DropdownMenu, Button, Text, Flex } from "../..";
4
5
  import { getMockRows, mockColumns } from "../Table.mock-utils";
5
6
  import { Table } from "..";
@@ -300,6 +301,20 @@ export const WithLotsOfRowsAndColumns = {
300
301
  },
301
302
  },
302
303
  };
304
+ export const WithLoading = {
305
+ args: {
306
+ columns,
307
+ rows: rowData,
308
+ loading: true,
309
+ },
310
+ name: "with loading state",
311
+ play: async ({ canvasElement }) => {
312
+ const canvas = within(canvasElement);
313
+ await expect(canvas.getByText("Loading...")).toBeInTheDocument();
314
+ const rows = canvasElement.querySelectorAll("tbody tr");
315
+ await expect(rows).toHaveLength(1);
316
+ },
317
+ };
303
318
  export const WithCustomColumnWidths = () => _jsx(Table, { columns: columnsWithWidths, rows: rowDataWithWidths });
304
319
  export const WithACustomCellComponent = () => (_jsx(Table, { columns: getColumnsWithCellRenderer(dropdownCellRenderer), rows: rowData }));
305
320
  export const WithCellAlignment = () => _jsx(Table, { columns: columnsWithAlignment, rows: rowData });
@@ -242,6 +242,19 @@ export const WithEverything = {
242
242
  },
243
243
  };
244
244
  export const WithOnHoverActions = {
245
+ play: async ({ canvasElement, step }) => {
246
+ const canvas = within(canvasElement);
247
+ await step("reveals row actions when mouse enters a row", async () => {
248
+ const rows = canvas.getAllByTestId("table-row");
249
+ await userEvent.hover(rows[0]);
250
+ await waitFor(() => expect(within(rows[0]).getByRole("button")).toBeInTheDocument());
251
+ });
252
+ await step("hides row actions when mouse leaves the row", async () => {
253
+ const rows = canvas.getAllByTestId("table-row");
254
+ await userEvent.unhover(rows[0]);
255
+ await waitFor(() => expect(within(rows[0]).queryByRole("button")).not.toBeInTheDocument());
256
+ });
257
+ },
245
258
  render: (args) => {
246
259
  const rowDataWithHovers = [
247
260
  {
@@ -11,13 +11,13 @@ declare const StyledBackLink: import("styled-components/dist/types").IStyledComp
11
11
  declare const StyledPageTitle: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, never>> & string;
12
12
  declare const Overlay: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<Omit<Omit<Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
13
13
  ref?: import("react").Ref<HTMLDivElement>;
14
- }, "as" | keyof import("@reach/dialog").DialogOverlayProps> & import("@reach/dialog").DialogOverlayProps & {
14
+ }, "as" | keyof import("@reach/dialog").DialogInnerProps> & import("@reach/dialog").DialogInnerProps & {
15
15
  as?: "div";
16
16
  } & import("framer-motion").MotionProps, "ref"> & import("react").RefAttributes<HTMLElement | SVGElement>, "ref"> & {
17
17
  ref?: import("react").Ref<HTMLElement | SVGElement>;
18
18
  }, never>> & string & Omit<import("framer-motion").CustomDomComponent<Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
19
19
  ref?: import("react").Ref<HTMLDivElement>;
20
- }, "as" | keyof import("@reach/dialog").DialogOverlayProps> & import("@reach/dialog").DialogOverlayProps & {
20
+ }, "as" | keyof import("@reach/dialog").DialogInnerProps> & import("@reach/dialog").DialogInnerProps & {
21
21
  as?: "div";
22
22
  }>, keyof import("react").Component<any, {}, any>>;
23
23
  declare const TileLink: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, never>> & string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nulogy/components",
3
- "version": "16.0.4",
3
+ "version": "16.2.0",
4
4
  "type": "module",
5
5
  "description": "Component library for the Nulogy Design System - http://nulogy.design",
6
6
  "private": false,
@@ -16,7 +16,7 @@
16
16
  "build:verify": "node scripts/verify-build.js",
17
17
  "build:watch": "vite build --watch",
18
18
  "build:storybook": "storybook build --stats-json",
19
- "warn:prepush": "echo \"Make sure you also run all the other CI steps before pushing by running 'pnpm ci'\"",
19
+ "warn:prepush": "echo \"Make sure you also run all the other CI steps before pushing by running 'pnpm check'\"",
20
20
  "check": "pnpm warn:prepush && pnpm check:types && pnpm check:lint && pnpm check:format",
21
21
  "check:types": "tsc",
22
22
  "check:lint": "eslint '**/*.{js,ts,jsx,tsx}'",
@@ -70,7 +70,7 @@
70
70
  "devDependencies": {
71
71
  "@apollo/client": "^4.1.6",
72
72
  "@eslint/js": "^9.0.0",
73
- "@nulogy/icons": "^4.37.2",
73
+ "@nulogy/icons": "^4.39.0",
74
74
  "@semantic-release/changelog": "^6.0.2",
75
75
  "@semantic-release/commit-analyzer": "^9.0.2",
76
76
  "@semantic-release/git": "^10.0.1",
@@ -84,7 +84,7 @@
84
84
  "@testing-library/react": "^16.0.0",
85
85
  "@types/css-mediaquery": "^0.1.4",
86
86
  "@types/deep-equal": "^1.0.4",
87
- "@types/node": "^24.10.4",
87
+ "@types/node": "^25.3.5",
88
88
  "@types/react": "^18.0.0",
89
89
  "@types/react-dom": "^18.0.0",
90
90
  "@typescript-eslint/eslint-plugin": "^8.49.0",
@@ -125,9 +125,10 @@
125
125
  "dependencies": {
126
126
  "@emotion/is-prop-valid": "^1.3.1",
127
127
  "@nulogy/tokens": "^6.1.1",
128
+ "@radix-ui/react-dialog": "^1.1.0",
128
129
  "@radix-ui/react-navigation-menu": "^1.1.4",
129
- "@radix-ui/react-tooltip": "1.0.7",
130
- "@reach/dialog": "0.17.0",
130
+ "@radix-ui/react-tooltip": "1.2.8",
131
+ "@reach/dialog": "0.18.0",
131
132
  "@styled-system/prop-types": "^5.1.4",
132
133
  "@styled-system/theme-get": "^5.1.2",
133
134
  "@types/react-window": "^1.8.8",
@@ -144,7 +145,6 @@
144
145
  "react-i18next": "^12.3.1",
145
146
  "react-modal": "^3.14.4",
146
147
  "react-popper": "1.3.11",
147
- "react-popper-2": "npm:react-popper@2.2.4",
148
148
  "react-resize-detector": "^9.1.0",
149
149
  "react-select": "^5.9.0",
150
150
  "react-window": "^1.8.11",