@fgv/ts-app-shell 5.1.0-1

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 (180) hide show
  1. package/README.md +26 -0
  2. package/dist/index.browser.js +3 -0
  3. package/dist/index.js +43 -0
  4. package/dist/packlets/ai-assist/index.js +6 -0
  5. package/dist/packlets/ai-assist/useAiAssist.js +219 -0
  6. package/dist/packlets/cascade/CascadeContainer.js +83 -0
  7. package/dist/packlets/cascade/ComparisonView.js +48 -0
  8. package/dist/packlets/cascade/EntityTabLayout.js +104 -0
  9. package/dist/packlets/cascade/MobileCascadeStack.js +63 -0
  10. package/dist/packlets/cascade/index.js +37 -0
  11. package/dist/packlets/cascade/model.js +30 -0
  12. package/dist/packlets/cascade/useCascadeOps.js +206 -0
  13. package/dist/packlets/cascade/useCascadeTransitions.js +58 -0
  14. package/dist/packlets/detail/DetailHelpers.js +103 -0
  15. package/dist/packlets/detail/index.js +6 -0
  16. package/dist/packlets/drop-zone/JsonDropZone.js +112 -0
  17. package/dist/packlets/drop-zone/index.js +6 -0
  18. package/dist/packlets/editing/EditFieldHelpers.js +130 -0
  19. package/dist/packlets/editing/MultiActionButton.js +73 -0
  20. package/dist/packlets/editing/NumericInput.js +119 -0
  21. package/dist/packlets/editing/TypeaheadInput.js +207 -0
  22. package/dist/packlets/editing/index.js +10 -0
  23. package/dist/packlets/editing/useTypeaheadMatch.js +102 -0
  24. package/dist/packlets/keyboard/index.js +7 -0
  25. package/dist/packlets/keyboard/registry.js +133 -0
  26. package/dist/packlets/keyboard/useKeyboardShortcuts.js +117 -0
  27. package/dist/packlets/messages/MessagesContext.js +76 -0
  28. package/dist/packlets/messages/MessagesLogger.js +103 -0
  29. package/dist/packlets/messages/StatusBar.js +154 -0
  30. package/dist/packlets/messages/Toast.js +68 -0
  31. package/dist/packlets/messages/index.js +11 -0
  32. package/dist/packlets/messages/model.js +56 -0
  33. package/dist/packlets/messages/useLogReporter.js +66 -0
  34. package/dist/packlets/modal/ConfirmDialog.js +78 -0
  35. package/dist/packlets/modal/Modal.js +55 -0
  36. package/dist/packlets/modal/index.js +7 -0
  37. package/dist/packlets/print/PrintEnclosure.js +60 -0
  38. package/dist/packlets/print/index.js +7 -0
  39. package/dist/packlets/print/openPrintWindow.js +112 -0
  40. package/dist/packlets/responsive/ResponsiveProvider.js +56 -0
  41. package/dist/packlets/responsive/index.js +7 -0
  42. package/dist/packlets/responsive/useResponsiveLayout.js +118 -0
  43. package/dist/packlets/selectors/EntityRow.js +276 -0
  44. package/dist/packlets/selectors/PreferredSelector.js +251 -0
  45. package/dist/packlets/selectors/index.js +24 -0
  46. package/dist/packlets/sidebar/CollectionSection.js +107 -0
  47. package/dist/packlets/sidebar/EntityList.js +164 -0
  48. package/dist/packlets/sidebar/FilterBar.js +42 -0
  49. package/dist/packlets/sidebar/FilterRow.js +182 -0
  50. package/dist/packlets/sidebar/GroupedEntityList.js +183 -0
  51. package/dist/packlets/sidebar/SearchBar.js +34 -0
  52. package/dist/packlets/sidebar/SidebarLayout.js +62 -0
  53. package/dist/packlets/sidebar/index.js +12 -0
  54. package/dist/packlets/theme/ThemeProvider.js +141 -0
  55. package/dist/packlets/theme/index.js +6 -0
  56. package/dist/packlets/top-bar/ModeSelector.js +46 -0
  57. package/dist/packlets/top-bar/TabBar.js +37 -0
  58. package/dist/packlets/top-bar/index.js +7 -0
  59. package/dist/packlets/url-sync/index.js +6 -0
  60. package/dist/packlets/url-sync/useUrlSync.js +157 -0
  61. package/eslint.config.js +22 -0
  62. package/lib/index.browser.d.ts +2 -0
  63. package/lib/index.browser.js +19 -0
  64. package/lib/index.d.ts +28 -0
  65. package/lib/index.js +59 -0
  66. package/lib/packlets/ai-assist/index.d.ts +6 -0
  67. package/lib/packlets/ai-assist/index.js +11 -0
  68. package/lib/packlets/ai-assist/useAiAssist.d.ts +77 -0
  69. package/lib/packlets/ai-assist/useAiAssist.js +223 -0
  70. package/lib/packlets/cascade/CascadeContainer.d.ts +44 -0
  71. package/lib/packlets/cascade/CascadeContainer.js +119 -0
  72. package/lib/packlets/cascade/ComparisonView.d.ts +35 -0
  73. package/lib/packlets/cascade/ComparisonView.js +54 -0
  74. package/lib/packlets/cascade/EntityTabLayout.d.ts +47 -0
  75. package/lib/packlets/cascade/EntityTabLayout.js +110 -0
  76. package/lib/packlets/cascade/MobileCascadeStack.d.ts +20 -0
  77. package/lib/packlets/cascade/MobileCascadeStack.js +99 -0
  78. package/lib/packlets/cascade/index.d.ts +12 -0
  79. package/lib/packlets/cascade/index.js +48 -0
  80. package/lib/packlets/cascade/model.d.ts +57 -0
  81. package/lib/packlets/cascade/model.js +33 -0
  82. package/lib/packlets/cascade/useCascadeOps.d.ts +111 -0
  83. package/lib/packlets/cascade/useCascadeOps.js +209 -0
  84. package/lib/packlets/cascade/useCascadeTransitions.d.ts +19 -0
  85. package/lib/packlets/cascade/useCascadeTransitions.js +62 -0
  86. package/lib/packlets/detail/DetailHelpers.d.ts +83 -0
  87. package/lib/packlets/detail/DetailHelpers.js +113 -0
  88. package/lib/packlets/detail/index.d.ts +6 -0
  89. package/lib/packlets/detail/index.js +14 -0
  90. package/lib/packlets/drop-zone/JsonDropZone.d.ts +40 -0
  91. package/lib/packlets/drop-zone/JsonDropZone.js +149 -0
  92. package/lib/packlets/drop-zone/index.d.ts +6 -0
  93. package/lib/packlets/drop-zone/index.js +10 -0
  94. package/lib/packlets/editing/EditFieldHelpers.d.ts +171 -0
  95. package/lib/packlets/editing/EditFieldHelpers.js +144 -0
  96. package/lib/packlets/editing/MultiActionButton.d.ts +45 -0
  97. package/lib/packlets/editing/MultiActionButton.js +109 -0
  98. package/lib/packlets/editing/NumericInput.d.ts +47 -0
  99. package/lib/packlets/editing/NumericInput.js +155 -0
  100. package/lib/packlets/editing/TypeaheadInput.d.ts +46 -0
  101. package/lib/packlets/editing/TypeaheadInput.js +243 -0
  102. package/lib/packlets/editing/index.d.ts +10 -0
  103. package/lib/packlets/editing/index.js +26 -0
  104. package/lib/packlets/editing/useTypeaheadMatch.d.ts +42 -0
  105. package/lib/packlets/editing/useTypeaheadMatch.js +105 -0
  106. package/lib/packlets/keyboard/index.d.ts +7 -0
  107. package/lib/packlets/keyboard/index.js +15 -0
  108. package/lib/packlets/keyboard/registry.d.ts +92 -0
  109. package/lib/packlets/keyboard/registry.js +138 -0
  110. package/lib/packlets/keyboard/useKeyboardShortcuts.d.ts +50 -0
  111. package/lib/packlets/keyboard/useKeyboardShortcuts.js +155 -0
  112. package/lib/packlets/messages/MessagesContext.d.ts +40 -0
  113. package/lib/packlets/messages/MessagesContext.js +113 -0
  114. package/lib/packlets/messages/MessagesLogger.d.ts +50 -0
  115. package/lib/packlets/messages/MessagesLogger.js +107 -0
  116. package/lib/packlets/messages/StatusBar.d.ts +22 -0
  117. package/lib/packlets/messages/StatusBar.js +190 -0
  118. package/lib/packlets/messages/Toast.d.ts +31 -0
  119. package/lib/packlets/messages/Toast.js +105 -0
  120. package/lib/packlets/messages/index.d.ts +11 -0
  121. package/lib/packlets/messages/index.js +24 -0
  122. package/lib/packlets/messages/model.d.ts +59 -0
  123. package/lib/packlets/messages/model.js +61 -0
  124. package/lib/packlets/messages/useLogReporter.d.ts +22 -0
  125. package/lib/packlets/messages/useLogReporter.js +69 -0
  126. package/lib/packlets/modal/ConfirmDialog.d.ts +39 -0
  127. package/lib/packlets/modal/ConfirmDialog.js +114 -0
  128. package/lib/packlets/modal/Modal.d.ts +22 -0
  129. package/lib/packlets/modal/Modal.js +91 -0
  130. package/lib/packlets/modal/index.d.ts +7 -0
  131. package/lib/packlets/modal/index.js +12 -0
  132. package/lib/packlets/print/PrintEnclosure.d.ts +33 -0
  133. package/lib/packlets/print/PrintEnclosure.js +96 -0
  134. package/lib/packlets/print/index.d.ts +7 -0
  135. package/lib/packlets/print/index.js +12 -0
  136. package/lib/packlets/print/openPrintWindow.d.ts +35 -0
  137. package/lib/packlets/print/openPrintWindow.js +118 -0
  138. package/lib/packlets/responsive/ResponsiveProvider.d.ts +35 -0
  139. package/lib/packlets/responsive/ResponsiveProvider.js +93 -0
  140. package/lib/packlets/responsive/index.d.ts +7 -0
  141. package/lib/packlets/responsive/index.js +13 -0
  142. package/lib/packlets/responsive/useResponsiveLayout.d.ts +48 -0
  143. package/lib/packlets/responsive/useResponsiveLayout.js +121 -0
  144. package/lib/packlets/selectors/EntityRow.d.ts +45 -0
  145. package/lib/packlets/selectors/EntityRow.js +315 -0
  146. package/lib/packlets/selectors/PreferredSelector.d.ts +50 -0
  147. package/lib/packlets/selectors/PreferredSelector.js +287 -0
  148. package/lib/packlets/selectors/index.d.ts +5 -0
  149. package/lib/packlets/selectors/index.js +29 -0
  150. package/lib/packlets/sidebar/CollectionSection.d.ts +82 -0
  151. package/lib/packlets/sidebar/CollectionSection.js +143 -0
  152. package/lib/packlets/sidebar/EntityList.d.ts +105 -0
  153. package/lib/packlets/sidebar/EntityList.js +200 -0
  154. package/lib/packlets/sidebar/FilterBar.d.ts +26 -0
  155. package/lib/packlets/sidebar/FilterBar.js +48 -0
  156. package/lib/packlets/sidebar/FilterRow.d.ts +42 -0
  157. package/lib/packlets/sidebar/FilterRow.js +218 -0
  158. package/lib/packlets/sidebar/GroupedEntityList.d.ts +59 -0
  159. package/lib/packlets/sidebar/GroupedEntityList.js +219 -0
  160. package/lib/packlets/sidebar/SearchBar.d.ts +19 -0
  161. package/lib/packlets/sidebar/SearchBar.js +40 -0
  162. package/lib/packlets/sidebar/SidebarLayout.d.ts +28 -0
  163. package/lib/packlets/sidebar/SidebarLayout.js +98 -0
  164. package/lib/packlets/sidebar/index.d.ts +12 -0
  165. package/lib/packlets/sidebar/index.js +22 -0
  166. package/lib/packlets/theme/ThemeProvider.d.ts +68 -0
  167. package/lib/packlets/theme/ThemeProvider.js +178 -0
  168. package/lib/packlets/theme/index.d.ts +6 -0
  169. package/lib/packlets/theme/index.js +11 -0
  170. package/lib/packlets/top-bar/ModeSelector.d.ts +38 -0
  171. package/lib/packlets/top-bar/ModeSelector.js +52 -0
  172. package/lib/packlets/top-bar/TabBar.d.ts +31 -0
  173. package/lib/packlets/top-bar/TabBar.js +43 -0
  174. package/lib/packlets/top-bar/index.d.ts +7 -0
  175. package/lib/packlets/top-bar/index.js +12 -0
  176. package/lib/packlets/url-sync/index.d.ts +6 -0
  177. package/lib/packlets/url-sync/index.js +12 -0
  178. package/lib/packlets/url-sync/useUrlSync.d.ts +75 -0
  179. package/lib/packlets/url-sync/useUrlSync.js +162 -0
  180. package/package.json +82 -0
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Opens a popup window for print-optimized content rendering.
3
+ * @packageDocumentation
4
+ */
5
+ import React from 'react';
6
+ /**
7
+ * Options for {@link openPrintWindow}.
8
+ * @public
9
+ */
10
+ export interface IPrintWindowOptions {
11
+ /** Title for the popup window. */
12
+ readonly title: string;
13
+ /** Width of the popup window in pixels (default 900). */
14
+ readonly width?: number;
15
+ /** Height of the popup window in pixels (default 700). */
16
+ readonly height?: number;
17
+ /** Extra toolbar controls to render in the print enclosure header. */
18
+ readonly toolbarExtras?: React.ReactNode;
19
+ }
20
+ /**
21
+ * Opens a popup window and renders the given React content inside a
22
+ * {@link PrintEnclosure} with Print and Close toolbar buttons.
23
+ *
24
+ * @remarks
25
+ * Must be called synchronously from a user click handler to avoid
26
+ * popup blockers. If the popup is blocked, returns `null`.
27
+ *
28
+ * Styles are cloned from the parent document so that Tailwind and other
29
+ * CSS frameworks work in the popup. An independent React root is created
30
+ * in the popup (not a portal) so the popup is fully self-contained.
31
+ *
32
+ * @public
33
+ */
34
+ export declare function openPrintWindow(content: React.ReactElement, options: IPrintWindowOptions): Window | null;
35
+ //# sourceMappingURL=openPrintWindow.d.ts.map
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Erik Fortune
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ * of this software and associated documentation files (the "Software"), to deal
7
+ * in the Software without restriction, including without limitation the rights
8
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ * copies of the Software, and to permit persons to whom the Software is
10
+ * furnished to do so, subject to the following conditions:
11
+ *
12
+ * The above copyright notice and this permission notice shall be included in all
13
+ * copies or substantial portions of the Software.
14
+ *
15
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ * SOFTWARE.
22
+ */
23
+ var __importDefault = (this && this.__importDefault) || function (mod) {
24
+ return (mod && mod.__esModule) ? mod : { "default": mod };
25
+ };
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.openPrintWindow = openPrintWindow;
28
+ /**
29
+ * Opens a popup window for print-optimized content rendering.
30
+ * @packageDocumentation
31
+ */
32
+ const react_1 = __importDefault(require("react"));
33
+ const client_1 = require("react-dom/client");
34
+ const PrintEnclosure_1 = require("./PrintEnclosure");
35
+ /**
36
+ * Clones all stylesheet-related elements from the source document head
37
+ * into the target document head so that styles are available in the popup.
38
+ */
39
+ function cloneStyles(source, target) {
40
+ const styles = Array.from(source.querySelectorAll('style'));
41
+ for (const style of styles) {
42
+ target.head.appendChild(style.cloneNode(true));
43
+ }
44
+ const links = Array.from(source.querySelectorAll('link[rel="stylesheet"]'));
45
+ for (const link of links) {
46
+ target.head.appendChild(link.cloneNode(true));
47
+ }
48
+ }
49
+ /**
50
+ * Opens a popup window and renders the given React content inside a
51
+ * {@link PrintEnclosure} with Print and Close toolbar buttons.
52
+ *
53
+ * @remarks
54
+ * Must be called synchronously from a user click handler to avoid
55
+ * popup blockers. If the popup is blocked, returns `null`.
56
+ *
57
+ * Styles are cloned from the parent document so that Tailwind and other
58
+ * CSS frameworks work in the popup. An independent React root is created
59
+ * in the popup (not a portal) so the popup is fully self-contained.
60
+ *
61
+ * @public
62
+ */
63
+ function openPrintWindow(content, options) {
64
+ const { title, width = 900, height = 700, toolbarExtras } = options;
65
+ const popup = window.open('', '', `width=${width},height=${height}`);
66
+ if (!popup) {
67
+ return null;
68
+ }
69
+ popup.document.write(`<!DOCTYPE html>
70
+ <html>
71
+ <head>
72
+ <meta charset="utf-8" />
73
+ <title>${title.replace(/</g, '&lt;')}</title>
74
+ <style>
75
+ @media screen {
76
+ body {
77
+ background: #f9fafb;
78
+ padding: 2rem;
79
+ margin: 0;
80
+ }
81
+ }
82
+ @media print {
83
+ body {
84
+ margin: 0;
85
+ padding: 0;
86
+ background: white;
87
+ }
88
+ .print-toolbar {
89
+ display: none !important;
90
+ }
91
+ .break-before-page {
92
+ break-before: page;
93
+ }
94
+ .break-inside-avoid {
95
+ break-inside: avoid;
96
+ }
97
+ }
98
+ </style>
99
+ </head>
100
+ <body>
101
+ <div id="print-root"></div>
102
+ </body>
103
+ </html>`);
104
+ popup.document.close();
105
+ cloneStyles(document, popup.document);
106
+ const container = popup.document.getElementById('print-root');
107
+ if (!container) {
108
+ popup.close();
109
+ return null;
110
+ }
111
+ const root = (0, client_1.createRoot)(container);
112
+ root.render(react_1.default.createElement(PrintEnclosure_1.PrintEnclosure, { title: title, toolbarExtras: toolbarExtras, popupWindow: popup }, content));
113
+ popup.addEventListener('beforeunload', () => {
114
+ root.unmount();
115
+ });
116
+ return popup;
117
+ }
118
+ //# sourceMappingURL=openPrintWindow.js.map
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import { type IResponsiveLayout, type LayoutMode } from './useResponsiveLayout';
3
+ /**
4
+ * Props for {@link ResponsiveProvider}.
5
+ * @public
6
+ */
7
+ export interface IResponsiveProviderProps {
8
+ /** Optional layout mode override (for testing or storybook). */
9
+ readonly forceLayoutMode?: LayoutMode;
10
+ /** Children */
11
+ readonly children: React.ReactNode;
12
+ }
13
+ /**
14
+ * Provides responsive layout information to the component tree via context.
15
+ *
16
+ * Wrap your app (or a subtree) with this provider. Descendants use
17
+ * {@link useResponsive} to read the current layout mode, device type, etc.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * <ResponsiveProvider>
22
+ * <App />
23
+ * </ResponsiveProvider>
24
+ * ```
25
+ * @public
26
+ */
27
+ export declare function ResponsiveProvider({ forceLayoutMode, children }: IResponsiveProviderProps): React.JSX.Element;
28
+ /**
29
+ * Access the current responsive layout information.
30
+ *
31
+ * Must be called within a {@link ResponsiveProvider}.
32
+ * @public
33
+ */
34
+ export declare function useResponsive(): IResponsiveLayout;
35
+ //# sourceMappingURL=ResponsiveProvider.d.ts.map
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Erik Fortune
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ * of this software and associated documentation files (the "Software"), to deal
7
+ * in the Software without restriction, including without limitation the rights
8
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ * copies of the Software, and to permit persons to whom the Software is
10
+ * furnished to do so, subject to the following conditions:
11
+ *
12
+ * The above copyright notice and this permission notice shall be included in all
13
+ * copies or substantial portions of the Software.
14
+ *
15
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ * SOFTWARE.
22
+ */
23
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ var desc = Object.getOwnPropertyDescriptor(m, k);
26
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
27
+ desc = { enumerable: true, get: function() { return m[k]; } };
28
+ }
29
+ Object.defineProperty(o, k2, desc);
30
+ }) : (function(o, m, k, k2) {
31
+ if (k2 === undefined) k2 = k;
32
+ o[k2] = m[k];
33
+ }));
34
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
35
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
36
+ }) : function(o, v) {
37
+ o["default"] = v;
38
+ });
39
+ var __importStar = (this && this.__importStar) || (function () {
40
+ var ownKeys = function(o) {
41
+ ownKeys = Object.getOwnPropertyNames || function (o) {
42
+ var ar = [];
43
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
44
+ return ar;
45
+ };
46
+ return ownKeys(o);
47
+ };
48
+ return function (mod) {
49
+ if (mod && mod.__esModule) return mod;
50
+ var result = {};
51
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
52
+ __setModuleDefault(result, mod);
53
+ return result;
54
+ };
55
+ })();
56
+ Object.defineProperty(exports, "__esModule", { value: true });
57
+ exports.ResponsiveProvider = ResponsiveProvider;
58
+ exports.useResponsive = useResponsive;
59
+ const react_1 = __importStar(require("react"));
60
+ const useResponsiveLayout_1 = require("./useResponsiveLayout");
61
+ const ResponsiveContext = (0, react_1.createContext)(undefined);
62
+ /**
63
+ * Provides responsive layout information to the component tree via context.
64
+ *
65
+ * Wrap your app (or a subtree) with this provider. Descendants use
66
+ * {@link useResponsive} to read the current layout mode, device type, etc.
67
+ *
68
+ * @example
69
+ * ```tsx
70
+ * <ResponsiveProvider>
71
+ * <App />
72
+ * </ResponsiveProvider>
73
+ * ```
74
+ * @public
75
+ */
76
+ function ResponsiveProvider({ forceLayoutMode, children }) {
77
+ const layout = (0, useResponsiveLayout_1.useResponsiveLayout)(forceLayoutMode);
78
+ return react_1.default.createElement(ResponsiveContext.Provider, { value: layout }, children);
79
+ }
80
+ /**
81
+ * Access the current responsive layout information.
82
+ *
83
+ * Must be called within a {@link ResponsiveProvider}.
84
+ * @public
85
+ */
86
+ function useResponsive() {
87
+ const context = (0, react_1.useContext)(ResponsiveContext);
88
+ if (!context) {
89
+ throw new Error('useResponsive must be used within a ResponsiveProvider');
90
+ }
91
+ return context;
92
+ }
93
+ //# sourceMappingURL=ResponsiveProvider.js.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Responsive layout detection and context provider.
3
+ * @packageDocumentation
4
+ */
5
+ export { useResponsiveLayout, type DeviceType, type ScreenOrientation, type LayoutMode, type IResponsiveLayout } from './useResponsiveLayout';
6
+ export { ResponsiveProvider, useResponsive, type IResponsiveProviderProps } from './ResponsiveProvider';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /**
3
+ * Responsive layout detection and context provider.
4
+ * @packageDocumentation
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.useResponsive = exports.ResponsiveProvider = exports.useResponsiveLayout = void 0;
8
+ var useResponsiveLayout_1 = require("./useResponsiveLayout");
9
+ Object.defineProperty(exports, "useResponsiveLayout", { enumerable: true, get: function () { return useResponsiveLayout_1.useResponsiveLayout; } });
10
+ var ResponsiveProvider_1 = require("./ResponsiveProvider");
11
+ Object.defineProperty(exports, "ResponsiveProvider", { enumerable: true, get: function () { return ResponsiveProvider_1.ResponsiveProvider; } });
12
+ Object.defineProperty(exports, "useResponsive", { enumerable: true, get: function () { return ResponsiveProvider_1.useResponsive; } });
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Device type detection result.
3
+ * @public
4
+ */
5
+ export type DeviceType = 'mobile' | 'tablet' | 'desktop';
6
+ /**
7
+ * Screen orientation.
8
+ * @public
9
+ */
10
+ export type ScreenOrientation = 'portrait' | 'landscape';
11
+ /**
12
+ * Layout mode that drives structural rendering decisions.
13
+ * - `full`: Desktop — sidebar visible, cascade columns side-by-side.
14
+ * - `compact`: Tablet — sidebar as drawer, cascade still horizontal.
15
+ * - `mobile`: Phone — sidebar as drawer, cascade becomes a view stack.
16
+ * @public
17
+ */
18
+ export type LayoutMode = 'full' | 'compact' | 'mobile';
19
+ /**
20
+ * Responsive layout information exposed by the hook and context.
21
+ * @public
22
+ */
23
+ export interface IResponsiveLayout {
24
+ /** Device type based on screen size and touch capability */
25
+ readonly deviceType: DeviceType;
26
+ /** Current screen orientation */
27
+ readonly orientation: ScreenOrientation;
28
+ /** Structural layout mode driving component tree decisions */
29
+ readonly layoutMode: LayoutMode;
30
+ /** Viewport width in pixels */
31
+ readonly screenWidth: number;
32
+ /** Viewport height in pixels */
33
+ readonly screenHeight: number;
34
+ /** Whether the device supports touch input */
35
+ readonly isTouchDevice: boolean;
36
+ }
37
+ /**
38
+ * Hook that tracks responsive layout information for the current viewport.
39
+ *
40
+ * Listens to `resize` and `orientationchange` events and recomputes layout
41
+ * on every change. Use the `layoutMode` field to drive structural rendering
42
+ * decisions (e.g., sidebar as drawer vs. fixed panel).
43
+ *
44
+ * @param forceLayoutMode - Optional override for testing or storybook use.
45
+ * @public
46
+ */
47
+ export declare function useResponsiveLayout(forceLayoutMode?: LayoutMode): IResponsiveLayout;
48
+ //# sourceMappingURL=useResponsiveLayout.d.ts.map
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Erik Fortune
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ * of this software and associated documentation files (the "Software"), to deal
7
+ * in the Software without restriction, including without limitation the rights
8
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ * copies of the Software, and to permit persons to whom the Software is
10
+ * furnished to do so, subject to the following conditions:
11
+ *
12
+ * The above copyright notice and this permission notice shall be included in all
13
+ * copies or substantial portions of the Software.
14
+ *
15
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ * SOFTWARE.
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.useResponsiveLayout = useResponsiveLayout;
25
+ const react_1 = require("react");
26
+ /**
27
+ * Breakpoints for responsive design (in CSS pixels).
28
+ */
29
+ const BREAKPOINTS = {
30
+ /** At or below this width, use mobile layout */
31
+ mobile: 640,
32
+ /** At or below this width, use compact layout */
33
+ compact: 1024
34
+ };
35
+ /**
36
+ * Detect if the device supports touch input.
37
+ */
38
+ function detectTouchSupport() {
39
+ var _a;
40
+ return ('ontouchstart' in window ||
41
+ navigator.maxTouchPoints > 0 ||
42
+ ((_a = navigator.msMaxTouchPoints) !== null && _a !== void 0 ? _a : 0) > 0);
43
+ }
44
+ /**
45
+ * Determine device type from viewport dimensions and touch capability.
46
+ */
47
+ function determineDeviceType(width, isTouch) {
48
+ if (width <= BREAKPOINTS.mobile) {
49
+ return 'mobile';
50
+ }
51
+ if (width <= BREAKPOINTS.compact && isTouch) {
52
+ return 'tablet';
53
+ }
54
+ return 'desktop';
55
+ }
56
+ /**
57
+ * Determine the structural layout mode from viewport width.
58
+ */
59
+ function determineLayoutMode(width) {
60
+ if (width <= BREAKPOINTS.mobile) {
61
+ return 'mobile';
62
+ }
63
+ if (width <= BREAKPOINTS.compact) {
64
+ return 'compact';
65
+ }
66
+ return 'full';
67
+ }
68
+ /**
69
+ * Compute the full layout info from current viewport state.
70
+ */
71
+ function computeLayout(forceLayoutMode) {
72
+ const width = window.innerWidth;
73
+ const height = window.innerHeight;
74
+ const isTouchDevice = detectTouchSupport();
75
+ const orientation = width > height ? 'landscape' : 'portrait';
76
+ const deviceType = determineDeviceType(width, isTouchDevice);
77
+ const layoutMode = forceLayoutMode !== null && forceLayoutMode !== void 0 ? forceLayoutMode : determineLayoutMode(width);
78
+ return {
79
+ deviceType,
80
+ orientation,
81
+ layoutMode,
82
+ screenWidth: width,
83
+ screenHeight: height,
84
+ isTouchDevice
85
+ };
86
+ }
87
+ /**
88
+ * Hook that tracks responsive layout information for the current viewport.
89
+ *
90
+ * Listens to `resize` and `orientationchange` events and recomputes layout
91
+ * on every change. Use the `layoutMode` field to drive structural rendering
92
+ * decisions (e.g., sidebar as drawer vs. fixed panel).
93
+ *
94
+ * @param forceLayoutMode - Optional override for testing or storybook use.
95
+ * @public
96
+ */
97
+ function useResponsiveLayout(forceLayoutMode) {
98
+ const [layout, setLayout] = (0, react_1.useState)(() => computeLayout(forceLayoutMode));
99
+ (0, react_1.useEffect)(() => {
100
+ if (forceLayoutMode) {
101
+ return;
102
+ }
103
+ function updateLayout() {
104
+ setLayout(computeLayout());
105
+ }
106
+ window.addEventListener('resize', updateLayout);
107
+ const onOrientationChange = () => {
108
+ // Small delay to let the browser update viewport dimensions
109
+ setTimeout(updateLayout, 100);
110
+ };
111
+ window.addEventListener('orientationchange', onOrientationChange);
112
+ // Sync on mount in case viewport changed between SSR and hydration
113
+ updateLayout();
114
+ return () => {
115
+ window.removeEventListener('resize', updateLayout);
116
+ window.removeEventListener('orientationchange', onOrientationChange);
117
+ };
118
+ }, [forceLayoutMode]);
119
+ return layout;
120
+ }
121
+ //# sourceMappingURL=useResponsiveLayout.js.map
@@ -0,0 +1,45 @@
1
+ /**
2
+ * EntityRow — clickable text row with optional discrete swap-icon for alternates.
3
+ *
4
+ * Renders a uniform row regardless of whether alternates exist:
5
+ * - Left slot: swap icon (when alternates exist) or empty spacer
6
+ * - Name text: clickable for drill-down
7
+ * - Optional right-side content (amount, sublabel, etc.)
8
+ * - Drill-down chevron ›
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ import React from 'react';
13
+ import type { ISelectableItem } from './PreferredSelector';
14
+ /**
15
+ * Props for the EntityRow component.
16
+ * @public
17
+ */
18
+ export interface IEntityRowProps<TId extends string = string> {
19
+ /** All options (preferred + alternates). If length === 1, no swap icon is shown. */
20
+ readonly items: ReadonlyArray<ISelectableItem<TId>>;
21
+ /** ID of the preferred/default item (shows ★ marker) */
22
+ readonly preferredId?: TId;
23
+ /** Controlled selected ID (overrides internal state). Use with onSelect. */
24
+ readonly selectedId?: TId;
25
+ /** Callback when the displayed item changes via the swap picker */
26
+ readonly onSelect?: (id: TId) => void;
27
+ /** Callback when the row is clicked (drill-down navigation) */
28
+ readonly onClick?: (id: TId) => void;
29
+ /** Callback to compare items. When provided, popover shows compare buttons. */
30
+ readonly onCompare?: (ids: ReadonlyArray<TId>) => void;
31
+ /** Optional right-side content rendered before the › chevron */
32
+ readonly rightContent?: React.ReactNode;
33
+ /** Optional section label displayed above the row */
34
+ readonly label?: string;
35
+ }
36
+ /**
37
+ * A clickable text row with an optional discrete swap-icon popover for
38
+ * switching between alternates. Clicking the row itself always triggers
39
+ * drill-down navigation. The swap icon opens a small picker to change
40
+ * which alternate is displayed.
41
+ *
42
+ * @public
43
+ */
44
+ export declare function EntityRow<TId extends string = string>(props: IEntityRowProps<TId>): React.ReactElement;
45
+ //# sourceMappingURL=EntityRow.d.ts.map