@theroutingcompany/components 0.0.143 → 0.0.144-alpha.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theroutingcompany/components",
3
- "version": "0.0.143",
3
+ "version": "0.0.144-alpha.0",
4
4
  "description": "The Routing Company Components",
5
5
  "main": "./dist/trc-components.umd.js",
6
6
  "module": "./dist/trc-components.es.js",
@@ -43,7 +43,11 @@
43
43
  "build": "npm run clean && npm run build:components && npm run build:types",
44
44
  "test": "vitest --run",
45
45
  "test:ui": "vitest --ui",
46
- "test:coverage": "vitest --coverage"
46
+ "test:coverage": "vitest --coverage",
47
+ "cypress:open": "cypress open",
48
+ "cypress:run": "cypress run --component",
49
+ "test:component": "cypress run --component",
50
+ "test:component:open": "cypress open --component"
47
51
  },
48
52
  "sideEffects": false,
49
53
  "license": "UNLICENSED",
@@ -135,10 +139,6 @@
135
139
  "@rollup/plugin-node-resolve": "^15.0.2",
136
140
  "@rollup/plugin-typescript": "^11.1.0",
137
141
  "@storybook/addon-a11y": "^7.0.3",
138
- "@testing-library/jest-dom": "^6.1.5",
139
- "@testing-library/react": "^14.1.2",
140
- "@testing-library/user-event": "^14.5.1",
141
- "@types/jest": "^29.5.11",
142
142
  "@storybook/addon-actions": "^7.0.3",
143
143
  "@storybook/addon-essentials": "^7.0.3",
144
144
  "@storybook/addon-interactions": "^7.0.3",
@@ -146,8 +146,12 @@
146
146
  "@storybook/react": "^7.0.3",
147
147
  "@storybook/react-vite": "^7.0.3",
148
148
  "@storybook/testing-library": "^0.1.0",
149
+ "@testing-library/jest-dom": "^6.1.5",
150
+ "@testing-library/react": "^14.1.2",
151
+ "@testing-library/user-event": "^14.5.1",
149
152
  "@types/eslint": "^8.37.0",
150
153
  "@types/google.maps": "^3.55.11",
154
+ "@types/jest": "^29.5.11",
151
155
  "@types/prettier": "^2.7.2",
152
156
  "@types/react": "^18.0.34",
153
157
  "@types/react-dom": "^18.0.11",
@@ -156,7 +160,9 @@
156
160
  "@typescript-eslint/eslint-plugin": "^5.58.0",
157
161
  "@typescript-eslint/parser": "^5.58.0",
158
162
  "@vitejs/plugin-react": "^3.1.0",
163
+ "@vitest/ui": "^1.1.0",
159
164
  "chromatic": "^6.17.3",
165
+ "cypress": "^13.17.0",
160
166
  "eslint": "^8.38.0",
161
167
  "eslint-config-prettier": "^8.8.0",
162
168
  "eslint-plugin-jsx-a11y": "^6.7.1",
@@ -164,12 +170,14 @@
164
170
  "eslint-plugin-react-hooks": "^4.6.0",
165
171
  "eslint-plugin-simple-import-sort": "^10.0.0",
166
172
  "eslint-plugin-storybook": "^0.6.11",
173
+ "jsdom": "^23.0.1",
167
174
  "postcss-styled-syntax": "^0.3.3",
168
175
  "prettier": "^2.8.7",
169
176
  "react": "^18.2.0",
170
177
  "react-dom": "^18.2.0",
171
178
  "react-is": "^18.2.0",
172
179
  "rimraf": "^5.0.0",
180
+ "start-server-and-test": "^2.1.3",
173
181
  "storybook": "^7.0.3",
174
182
  "styled-components": "^5.3.11",
175
183
  "stylelint": "^15.2.0",
@@ -179,8 +187,6 @@
179
187
  "typescript": "^5.0.4",
180
188
  "vite": "^4.2.1",
181
189
  "vite-tsconfig-paths": "^4.1.0",
182
- "vitest": "^1.1.0",
183
- "@vitest/ui": "^1.1.0",
184
- "jsdom": "^23.0.1"
190
+ "vitest": "^1.1.0"
185
191
  }
186
192
  }
@@ -0,0 +1,30 @@
1
+ import { ReactNode } from 'react';
2
+ interface ActionMenuProps {
3
+ children: ReactNode;
4
+ closeOnOutsideClick?: boolean;
5
+ triggerMoveBehavior?: 'follow' | 'close';
6
+ size?: 'small' | 'medium';
7
+ align?: 'left' | 'right';
8
+ autoAdjustAlign?: boolean;
9
+ }
10
+ export declare const ActionMenu: import("react").ForwardRefExoticComponent<ActionMenuProps & import("react").RefAttributes<HTMLDivElement>>;
11
+ interface ActionMenuTriggerProps {
12
+ children: ReactNode;
13
+ 'aria-label'?: string;
14
+ }
15
+ export declare const ActionMenuTrigger: import("react").ForwardRefExoticComponent<ActionMenuTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
16
+ interface ActionMenuContentProps {
17
+ children: ReactNode;
18
+ }
19
+ export declare const ActionMenuContent: import("react").ForwardRefExoticComponent<ActionMenuContentProps & import("react").RefAttributes<HTMLDivElement>>;
20
+ interface ActionMenuItemProps {
21
+ children: ReactNode;
22
+ onClick?: () => void;
23
+ disabled?: boolean;
24
+ icon?: ReactNode;
25
+ title?: string;
26
+ 'aria-label'?: string;
27
+ hidden?: boolean;
28
+ }
29
+ export declare const ActionMenuItem: import("react").ForwardRefExoticComponent<ActionMenuItemProps & import("react").RefAttributes<HTMLButtonElement>>;
30
+ export {};
@@ -0,0 +1 @@
1
+ export { ActionMenu, ActionMenuContent, ActionMenuItem, ActionMenuTrigger, } from './ActionMenu';
@@ -20,6 +20,33 @@ export type DrawerProps = {
20
20
  width?: string;
21
21
  maxWidth?: string;
22
22
  dialogTitle?: string;
23
+ instanceId?: string;
24
+ stackGroupId?: string;
25
+ stackPosition?: number;
26
+ isFocused?: boolean;
27
+ onBringToFront?: () => void;
28
+ zIndexBase?: number;
29
+ onFocusNext?: () => void;
30
+ onFocusPrevious?: () => void;
31
+ enableKeyboardShortcuts?: boolean;
32
+ resizable?: boolean;
33
+ size?: {
34
+ width: number;
35
+ height: number;
36
+ };
37
+ onSizeChange?: (nextSize: {
38
+ width: number;
39
+ height: number;
40
+ }) => void;
41
+ movable?: boolean;
42
+ moveOffset?: {
43
+ x: number;
44
+ y: number;
45
+ };
46
+ onMoveOffsetChange?: (nextOffset: {
47
+ x: number;
48
+ y: number;
49
+ }) => void;
23
50
  };
24
51
  declare const Drawer: ForwardRefExoticComponent<DrawerProps> & {
25
52
  Close: typeof Close;
@@ -38,16 +65,12 @@ export type UseDrawerState = {
38
65
  toggleDrawer: () => void;
39
66
  openDrawer: () => void;
40
67
  closeDrawer: () => void;
41
- getActivatorProps: (additionalProps?: {
42
- [k: string]: unknown;
43
- }) => {
68
+ getActivatorProps: (additionalProps?: Record<string, unknown>) => {
44
69
  'aria-controls': UseDrawerProps['id'];
45
70
  onClick: () => void;
46
71
  [key: string]: unknown;
47
72
  };
48
- getDrawerProps: (props?: {
49
- [k: string]: unknown;
50
- }) => {
73
+ getDrawerProps: (props?: Record<string, unknown>) => {
51
74
  id: UseDrawerProps['id'];
52
75
  onClose: () => void;
53
76
  open: boolean;
@@ -2,6 +2,10 @@ import React from 'react';
2
2
  type DrawerContextProps = {
3
3
  onClose: () => void;
4
4
  loading?: boolean;
5
+ instanceId?: string;
6
+ stackPosition?: number;
7
+ isFocused?: boolean;
8
+ onBringToFront?: () => void;
5
9
  };
6
10
  export declare const DrawerContext: React.Context<DrawerContextProps>;
7
11
  export {};
@@ -1,2 +1,5 @@
1
1
  export { default as Drawer } from './Drawer';
2
2
  export * from './Drawer';
3
+ export * from './useMultiDrawer';
4
+ export * from './useDrawerFocusControl';
5
+ export * from './useDrawerStack';
@@ -3,6 +3,7 @@ interface ContainerProps extends BoxProps {
3
3
  $state?: string;
4
4
  $viewportPosition?: string;
5
5
  name?: string;
6
+ $isFocused?: boolean;
6
7
  }
7
8
  export declare const Container: import("styled-components").StyledComponent<import("../..").ForwardRefComponent<"div", BoxProps>, any, ContainerProps, never>;
8
9
  export {};
@@ -0,0 +1,60 @@
1
+ /// <reference types="react" />
2
+ export type FocusControlOptions = {
3
+ /**
4
+ * Callback for cycling to next drawer (Cmd/Ctrl + Tab)
5
+ */
6
+ onFocusNext?: () => void;
7
+ /**
8
+ * Callback for cycling to previous drawer (Cmd/Ctrl + Shift + Tab)
9
+ */
10
+ onFocusPrevious?: () => void;
11
+ /**
12
+ * Callback for closing focused drawer (Escape)
13
+ */
14
+ onCloseFocused?: () => void;
15
+ /**
16
+ * Whether this drawer is currently focused
17
+ */
18
+ isFocused: boolean;
19
+ /**
20
+ * Whether this drawer is open
21
+ */
22
+ isOpen: boolean;
23
+ /**
24
+ * Whether to enable keyboard shortcuts
25
+ * @default true
26
+ */
27
+ enableKeyboardShortcuts?: boolean;
28
+ /**
29
+ * Optional label for debug logging.
30
+ */
31
+ debugLabel?: string;
32
+ };
33
+ /**
34
+ * Hook for managing focus control in multi-drawer scenarios
35
+ *
36
+ * Handles:
37
+ * - Keyboard shortcuts (Cmd+Tab, Escape)
38
+ * - Focus trap within drawer
39
+ * - Focus restoration on close
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * const drawerRef = useDrawerFocusControl({
44
+ * isFocused: true,
45
+ * isOpen: true,
46
+ * onFocusNext: focusNextDrawer,
47
+ * onFocusPrevious: focusPreviousDrawer,
48
+ * onCloseFocused: closeDrawer,
49
+ * });
50
+ *
51
+ * <div ref={drawerRef}>
52
+ * {/ * drawer content * /}
53
+ * </div>
54
+ * ```
55
+ */
56
+ export declare function useDrawerFocusControl({ onFocusNext, onFocusPrevious, onCloseFocused, isFocused, isOpen, enableKeyboardShortcuts, debugLabel, }: FocusControlOptions): {
57
+ drawerRef: import("react").RefObject<HTMLDivElement>;
58
+ handleTabKey: (event: React.KeyboardEvent<HTMLDivElement>) => void;
59
+ getFocusableElements: () => HTMLElement[];
60
+ };
@@ -0,0 +1,5 @@
1
+ export declare function useDrawerStackItem(id: string, isOpen: boolean, groupId?: string): {
2
+ stackPosition: number;
3
+ isFocused: boolean;
4
+ bringToFront: () => void;
5
+ };
@@ -0,0 +1,99 @@
1
+ export type DrawerInstance = {
2
+ id: string;
3
+ isOpen: boolean;
4
+ stackPosition: number;
5
+ size: {
6
+ width: number;
7
+ height: number;
8
+ };
9
+ moveOffset: {
10
+ x: number;
11
+ y: number;
12
+ };
13
+ data?: Record<string, unknown>;
14
+ };
15
+ export type UseMultiDrawerProps = {
16
+ /**
17
+ * Maximum number of drawers that can be open simultaneously
18
+ * @default undefined (no limit)
19
+ */
20
+ maxDrawers?: number;
21
+ /**
22
+ * Base ID for drawer instances
23
+ * @default 'multi-drawer'
24
+ */
25
+ baseId?: string;
26
+ /**
27
+ * Callback when drawers change
28
+ */
29
+ onChange?: (instances: DrawerInstance[]) => void;
30
+ };
31
+ export type UseMultiDrawerState = {
32
+ /** Array of all drawer instances */
33
+ instances: DrawerInstance[];
34
+ /** ID of the currently focused drawer */
35
+ focusedInstanceId: string | null;
36
+ /** Open a new drawer instance */
37
+ openDrawer: (data?: Record<string, unknown>) => string;
38
+ /** Close a specific drawer instance */
39
+ closeDrawer: (instanceId: string) => void;
40
+ /** Close all drawers */
41
+ closeAllDrawers: () => void;
42
+ /** Bring a drawer to the front (focus it) */
43
+ bringToFront: (instanceId: string) => void;
44
+ /** Focus the next drawer in the stack */
45
+ focusNextDrawer: () => void;
46
+ /** Focus the previous drawer in the stack */
47
+ focusPreviousDrawer: () => void;
48
+ /** Check if a drawer instance is open */
49
+ isDrawerOpen: (instanceId: string) => boolean;
50
+ /** Check if a drawer instance is focused */
51
+ isDrawerFocused: (instanceId: string) => boolean;
52
+ /** Get drawer props for a specific instance */
53
+ getDrawerProps: (instanceId: string, additionalProps?: Record<string, unknown>) => {
54
+ id: string;
55
+ instanceId: string;
56
+ open: boolean;
57
+ onClose: () => void;
58
+ stackPosition: number;
59
+ isFocused: boolean;
60
+ onBringToFront: () => void;
61
+ [key: string]: unknown;
62
+ };
63
+ };
64
+ /**
65
+ * Hook for managing multiple drawer instances
66
+ *
67
+ * This hook allows multiple drawers to be open simultaneously, with proper
68
+ * stack management, focus control, and keyboard navigation.
69
+ *
70
+ * @example
71
+ * ```tsx
72
+ * const {
73
+ * instances,
74
+ * focusedInstanceId,
75
+ * openDrawer,
76
+ * closeDrawer,
77
+ * getDrawerProps
78
+ * } = useMultiDrawer({ baseId: 'trip-drawer' });
79
+ *
80
+ * // Open a new drawer with Cmd/Ctrl + Click
81
+ * const handleClick = (event: React.MouseEvent, tripId: string) => {
82
+ * if (event.metaKey || event.ctrlKey) {
83
+ * openDrawer({ tripId });
84
+ * } else {
85
+ * // Close existing and open new (single drawer mode)
86
+ * closeAllDrawers();
87
+ * openDrawer({ tripId });
88
+ * }
89
+ * };
90
+ *
91
+ * // Render drawers
92
+ * {instances.map(instance => (
93
+ * <Drawer key={instance.id} {...getDrawerProps(instance.id)}>
94
+ * <TripContent tripId={instance.data?.tripId} />
95
+ * </Drawer>
96
+ * ))}
97
+ * ```
98
+ */
99
+ export declare function useMultiDrawer({ maxDrawers, baseId, onChange, }?: UseMultiDrawerProps): UseMultiDrawerState;
@@ -1,5 +1,6 @@
1
1
  export * from './AccessibleIcon/AccessibleIcon';
2
2
  export * from './Accordion';
3
+ export * from './ActionMenu';
3
4
  export * from './AlertDialog/AlertDialog';
4
5
  export * from './Badge/Badge';
5
6
  export * from './Banner/Banner';