@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.
- package/README.md +26 -0
- package/dist/index.browser.js +3 -0
- package/dist/index.js +43 -0
- package/dist/packlets/ai-assist/index.js +6 -0
- package/dist/packlets/ai-assist/useAiAssist.js +219 -0
- package/dist/packlets/cascade/CascadeContainer.js +83 -0
- package/dist/packlets/cascade/ComparisonView.js +48 -0
- package/dist/packlets/cascade/EntityTabLayout.js +104 -0
- package/dist/packlets/cascade/MobileCascadeStack.js +63 -0
- package/dist/packlets/cascade/index.js +37 -0
- package/dist/packlets/cascade/model.js +30 -0
- package/dist/packlets/cascade/useCascadeOps.js +206 -0
- package/dist/packlets/cascade/useCascadeTransitions.js +58 -0
- package/dist/packlets/detail/DetailHelpers.js +103 -0
- package/dist/packlets/detail/index.js +6 -0
- package/dist/packlets/drop-zone/JsonDropZone.js +112 -0
- package/dist/packlets/drop-zone/index.js +6 -0
- package/dist/packlets/editing/EditFieldHelpers.js +130 -0
- package/dist/packlets/editing/MultiActionButton.js +73 -0
- package/dist/packlets/editing/NumericInput.js +119 -0
- package/dist/packlets/editing/TypeaheadInput.js +207 -0
- package/dist/packlets/editing/index.js +10 -0
- package/dist/packlets/editing/useTypeaheadMatch.js +102 -0
- package/dist/packlets/keyboard/index.js +7 -0
- package/dist/packlets/keyboard/registry.js +133 -0
- package/dist/packlets/keyboard/useKeyboardShortcuts.js +117 -0
- package/dist/packlets/messages/MessagesContext.js +76 -0
- package/dist/packlets/messages/MessagesLogger.js +103 -0
- package/dist/packlets/messages/StatusBar.js +154 -0
- package/dist/packlets/messages/Toast.js +68 -0
- package/dist/packlets/messages/index.js +11 -0
- package/dist/packlets/messages/model.js +56 -0
- package/dist/packlets/messages/useLogReporter.js +66 -0
- package/dist/packlets/modal/ConfirmDialog.js +78 -0
- package/dist/packlets/modal/Modal.js +55 -0
- package/dist/packlets/modal/index.js +7 -0
- package/dist/packlets/print/PrintEnclosure.js +60 -0
- package/dist/packlets/print/index.js +7 -0
- package/dist/packlets/print/openPrintWindow.js +112 -0
- package/dist/packlets/responsive/ResponsiveProvider.js +56 -0
- package/dist/packlets/responsive/index.js +7 -0
- package/dist/packlets/responsive/useResponsiveLayout.js +118 -0
- package/dist/packlets/selectors/EntityRow.js +276 -0
- package/dist/packlets/selectors/PreferredSelector.js +251 -0
- package/dist/packlets/selectors/index.js +24 -0
- package/dist/packlets/sidebar/CollectionSection.js +107 -0
- package/dist/packlets/sidebar/EntityList.js +164 -0
- package/dist/packlets/sidebar/FilterBar.js +42 -0
- package/dist/packlets/sidebar/FilterRow.js +182 -0
- package/dist/packlets/sidebar/GroupedEntityList.js +183 -0
- package/dist/packlets/sidebar/SearchBar.js +34 -0
- package/dist/packlets/sidebar/SidebarLayout.js +62 -0
- package/dist/packlets/sidebar/index.js +12 -0
- package/dist/packlets/theme/ThemeProvider.js +141 -0
- package/dist/packlets/theme/index.js +6 -0
- package/dist/packlets/top-bar/ModeSelector.js +46 -0
- package/dist/packlets/top-bar/TabBar.js +37 -0
- package/dist/packlets/top-bar/index.js +7 -0
- package/dist/packlets/url-sync/index.js +6 -0
- package/dist/packlets/url-sync/useUrlSync.js +157 -0
- package/eslint.config.js +22 -0
- package/lib/index.browser.d.ts +2 -0
- package/lib/index.browser.js +19 -0
- package/lib/index.d.ts +28 -0
- package/lib/index.js +59 -0
- package/lib/packlets/ai-assist/index.d.ts +6 -0
- package/lib/packlets/ai-assist/index.js +11 -0
- package/lib/packlets/ai-assist/useAiAssist.d.ts +77 -0
- package/lib/packlets/ai-assist/useAiAssist.js +223 -0
- package/lib/packlets/cascade/CascadeContainer.d.ts +44 -0
- package/lib/packlets/cascade/CascadeContainer.js +119 -0
- package/lib/packlets/cascade/ComparisonView.d.ts +35 -0
- package/lib/packlets/cascade/ComparisonView.js +54 -0
- package/lib/packlets/cascade/EntityTabLayout.d.ts +47 -0
- package/lib/packlets/cascade/EntityTabLayout.js +110 -0
- package/lib/packlets/cascade/MobileCascadeStack.d.ts +20 -0
- package/lib/packlets/cascade/MobileCascadeStack.js +99 -0
- package/lib/packlets/cascade/index.d.ts +12 -0
- package/lib/packlets/cascade/index.js +48 -0
- package/lib/packlets/cascade/model.d.ts +57 -0
- package/lib/packlets/cascade/model.js +33 -0
- package/lib/packlets/cascade/useCascadeOps.d.ts +111 -0
- package/lib/packlets/cascade/useCascadeOps.js +209 -0
- package/lib/packlets/cascade/useCascadeTransitions.d.ts +19 -0
- package/lib/packlets/cascade/useCascadeTransitions.js +62 -0
- package/lib/packlets/detail/DetailHelpers.d.ts +83 -0
- package/lib/packlets/detail/DetailHelpers.js +113 -0
- package/lib/packlets/detail/index.d.ts +6 -0
- package/lib/packlets/detail/index.js +14 -0
- package/lib/packlets/drop-zone/JsonDropZone.d.ts +40 -0
- package/lib/packlets/drop-zone/JsonDropZone.js +149 -0
- package/lib/packlets/drop-zone/index.d.ts +6 -0
- package/lib/packlets/drop-zone/index.js +10 -0
- package/lib/packlets/editing/EditFieldHelpers.d.ts +171 -0
- package/lib/packlets/editing/EditFieldHelpers.js +144 -0
- package/lib/packlets/editing/MultiActionButton.d.ts +45 -0
- package/lib/packlets/editing/MultiActionButton.js +109 -0
- package/lib/packlets/editing/NumericInput.d.ts +47 -0
- package/lib/packlets/editing/NumericInput.js +155 -0
- package/lib/packlets/editing/TypeaheadInput.d.ts +46 -0
- package/lib/packlets/editing/TypeaheadInput.js +243 -0
- package/lib/packlets/editing/index.d.ts +10 -0
- package/lib/packlets/editing/index.js +26 -0
- package/lib/packlets/editing/useTypeaheadMatch.d.ts +42 -0
- package/lib/packlets/editing/useTypeaheadMatch.js +105 -0
- package/lib/packlets/keyboard/index.d.ts +7 -0
- package/lib/packlets/keyboard/index.js +15 -0
- package/lib/packlets/keyboard/registry.d.ts +92 -0
- package/lib/packlets/keyboard/registry.js +138 -0
- package/lib/packlets/keyboard/useKeyboardShortcuts.d.ts +50 -0
- package/lib/packlets/keyboard/useKeyboardShortcuts.js +155 -0
- package/lib/packlets/messages/MessagesContext.d.ts +40 -0
- package/lib/packlets/messages/MessagesContext.js +113 -0
- package/lib/packlets/messages/MessagesLogger.d.ts +50 -0
- package/lib/packlets/messages/MessagesLogger.js +107 -0
- package/lib/packlets/messages/StatusBar.d.ts +22 -0
- package/lib/packlets/messages/StatusBar.js +190 -0
- package/lib/packlets/messages/Toast.d.ts +31 -0
- package/lib/packlets/messages/Toast.js +105 -0
- package/lib/packlets/messages/index.d.ts +11 -0
- package/lib/packlets/messages/index.js +24 -0
- package/lib/packlets/messages/model.d.ts +59 -0
- package/lib/packlets/messages/model.js +61 -0
- package/lib/packlets/messages/useLogReporter.d.ts +22 -0
- package/lib/packlets/messages/useLogReporter.js +69 -0
- package/lib/packlets/modal/ConfirmDialog.d.ts +39 -0
- package/lib/packlets/modal/ConfirmDialog.js +114 -0
- package/lib/packlets/modal/Modal.d.ts +22 -0
- package/lib/packlets/modal/Modal.js +91 -0
- package/lib/packlets/modal/index.d.ts +7 -0
- package/lib/packlets/modal/index.js +12 -0
- package/lib/packlets/print/PrintEnclosure.d.ts +33 -0
- package/lib/packlets/print/PrintEnclosure.js +96 -0
- package/lib/packlets/print/index.d.ts +7 -0
- package/lib/packlets/print/index.js +12 -0
- package/lib/packlets/print/openPrintWindow.d.ts +35 -0
- package/lib/packlets/print/openPrintWindow.js +118 -0
- package/lib/packlets/responsive/ResponsiveProvider.d.ts +35 -0
- package/lib/packlets/responsive/ResponsiveProvider.js +93 -0
- package/lib/packlets/responsive/index.d.ts +7 -0
- package/lib/packlets/responsive/index.js +13 -0
- package/lib/packlets/responsive/useResponsiveLayout.d.ts +48 -0
- package/lib/packlets/responsive/useResponsiveLayout.js +121 -0
- package/lib/packlets/selectors/EntityRow.d.ts +45 -0
- package/lib/packlets/selectors/EntityRow.js +315 -0
- package/lib/packlets/selectors/PreferredSelector.d.ts +50 -0
- package/lib/packlets/selectors/PreferredSelector.js +287 -0
- package/lib/packlets/selectors/index.d.ts +5 -0
- package/lib/packlets/selectors/index.js +29 -0
- package/lib/packlets/sidebar/CollectionSection.d.ts +82 -0
- package/lib/packlets/sidebar/CollectionSection.js +143 -0
- package/lib/packlets/sidebar/EntityList.d.ts +105 -0
- package/lib/packlets/sidebar/EntityList.js +200 -0
- package/lib/packlets/sidebar/FilterBar.d.ts +26 -0
- package/lib/packlets/sidebar/FilterBar.js +48 -0
- package/lib/packlets/sidebar/FilterRow.d.ts +42 -0
- package/lib/packlets/sidebar/FilterRow.js +218 -0
- package/lib/packlets/sidebar/GroupedEntityList.d.ts +59 -0
- package/lib/packlets/sidebar/GroupedEntityList.js +219 -0
- package/lib/packlets/sidebar/SearchBar.d.ts +19 -0
- package/lib/packlets/sidebar/SearchBar.js +40 -0
- package/lib/packlets/sidebar/SidebarLayout.d.ts +28 -0
- package/lib/packlets/sidebar/SidebarLayout.js +98 -0
- package/lib/packlets/sidebar/index.d.ts +12 -0
- package/lib/packlets/sidebar/index.js +22 -0
- package/lib/packlets/theme/ThemeProvider.d.ts +68 -0
- package/lib/packlets/theme/ThemeProvider.js +178 -0
- package/lib/packlets/theme/index.d.ts +6 -0
- package/lib/packlets/theme/index.js +11 -0
- package/lib/packlets/top-bar/ModeSelector.d.ts +38 -0
- package/lib/packlets/top-bar/ModeSelector.js +52 -0
- package/lib/packlets/top-bar/TabBar.d.ts +31 -0
- package/lib/packlets/top-bar/TabBar.js +43 -0
- package/lib/packlets/top-bar/index.d.ts +7 -0
- package/lib/packlets/top-bar/index.js +12 -0
- package/lib/packlets/url-sync/index.d.ts +6 -0
- package/lib/packlets/url-sync/index.js +12 -0
- package/lib/packlets/url-sync/useUrlSync.d.ts +75 -0
- package/lib/packlets/url-sync/useUrlSync.js +162 -0
- package/package.json +82 -0
|
@@ -0,0 +1,98 @@
|
|
|
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.SidebarLayout = SidebarLayout;
|
|
58
|
+
const react_1 = __importStar(require("react"));
|
|
59
|
+
const responsive_1 = require("../responsive");
|
|
60
|
+
/**
|
|
61
|
+
* Layout component that renders a persistent left sidebar alongside a main content area.
|
|
62
|
+
*
|
|
63
|
+
* On `full` layout mode, the sidebar is a fixed-width panel.
|
|
64
|
+
* On `compact` and `mobile` layout modes, the sidebar becomes a slide-out drawer
|
|
65
|
+
* controlled by {@link ISidebarLayoutProps.isSidebarOpen | isSidebarOpen} and
|
|
66
|
+
* {@link ISidebarLayoutProps.onSidebarClose | onSidebarClose}.
|
|
67
|
+
* @public
|
|
68
|
+
*/
|
|
69
|
+
function SidebarLayout(props) {
|
|
70
|
+
const { sidebar, children, sidebarWidth = '280px', isSidebarOpen = false, onSidebarClose } = props;
|
|
71
|
+
const { layoutMode } = (0, responsive_1.useResponsive)();
|
|
72
|
+
const isDrawer = layoutMode !== 'full';
|
|
73
|
+
// Close drawer on Escape key
|
|
74
|
+
(0, react_1.useEffect)(() => {
|
|
75
|
+
if (!isDrawer || !isSidebarOpen) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const handleKeyDown = (e) => {
|
|
79
|
+
if (e.key === 'Escape') {
|
|
80
|
+
onSidebarClose === null || onSidebarClose === void 0 ? void 0 : onSidebarClose();
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
84
|
+
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
85
|
+
}, [isDrawer, isSidebarOpen, onSidebarClose]);
|
|
86
|
+
// Full mode: static sidebar
|
|
87
|
+
if (!isDrawer) {
|
|
88
|
+
return (react_1.default.createElement("div", { className: "flex flex-1 overflow-hidden" },
|
|
89
|
+
react_1.default.createElement("aside", { className: "flex flex-col border-r border-border bg-surface overflow-y-auto shrink-0", style: { width: sidebarWidth } }, sidebar),
|
|
90
|
+
react_1.default.createElement("div", { className: "flex flex-col flex-1 overflow-hidden" }, children)));
|
|
91
|
+
}
|
|
92
|
+
// Compact/mobile: drawer overlay
|
|
93
|
+
return (react_1.default.createElement("div", { className: "flex flex-col flex-1 overflow-hidden relative" },
|
|
94
|
+
react_1.default.createElement("div", { className: "flex flex-col flex-1 overflow-hidden" }, children),
|
|
95
|
+
isSidebarOpen && (react_1.default.createElement("div", { className: "fixed inset-0 bg-backdrop z-40 transition-opacity", onClick: onSidebarClose, "aria-hidden": "true" })),
|
|
96
|
+
react_1.default.createElement("aside", { className: `fixed inset-y-0 left-0 z-50 flex flex-col bg-surface border-r border-border overflow-y-auto shadow-lg transition-transform duration-200 ease-in-out ${isSidebarOpen ? 'translate-x-0' : '-translate-x-full'}`, style: { width: sidebarWidth } }, sidebar)));
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=SidebarLayout.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sidebar packlet - layout, search, filter rows, and entity list.
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
export { SidebarLayout, type ISidebarLayoutProps } from './SidebarLayout';
|
|
6
|
+
export { SearchBar, type ISearchBarProps } from './SearchBar';
|
|
7
|
+
export { FilterRow, type IFilterRowProps, type IFilterOption } from './FilterRow';
|
|
8
|
+
export { FilterBar, type IFilterBarProps } from './FilterBar';
|
|
9
|
+
export { EntityList, type IEntityListProps, type IEntityDescriptor, type IEntityStatus, type IEmptyStateConfig, type IEmptyStateAction } from './EntityList';
|
|
10
|
+
export { GroupedEntityList, type IGroupedEntityListProps, type IEntityGroupDescriptor } from './GroupedEntityList';
|
|
11
|
+
export { CollectionSection, type ICollectionSectionProps, type ICollectionRowItem } from './CollectionSection';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Sidebar packlet - layout, search, filter rows, and entity list.
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.CollectionSection = exports.GroupedEntityList = exports.EntityList = exports.FilterBar = exports.FilterRow = exports.SearchBar = exports.SidebarLayout = void 0;
|
|
8
|
+
var SidebarLayout_1 = require("./SidebarLayout");
|
|
9
|
+
Object.defineProperty(exports, "SidebarLayout", { enumerable: true, get: function () { return SidebarLayout_1.SidebarLayout; } });
|
|
10
|
+
var SearchBar_1 = require("./SearchBar");
|
|
11
|
+
Object.defineProperty(exports, "SearchBar", { enumerable: true, get: function () { return SearchBar_1.SearchBar; } });
|
|
12
|
+
var FilterRow_1 = require("./FilterRow");
|
|
13
|
+
Object.defineProperty(exports, "FilterRow", { enumerable: true, get: function () { return FilterRow_1.FilterRow; } });
|
|
14
|
+
var FilterBar_1 = require("./FilterBar");
|
|
15
|
+
Object.defineProperty(exports, "FilterBar", { enumerable: true, get: function () { return FilterBar_1.FilterBar; } });
|
|
16
|
+
var EntityList_1 = require("./EntityList");
|
|
17
|
+
Object.defineProperty(exports, "EntityList", { enumerable: true, get: function () { return EntityList_1.EntityList; } });
|
|
18
|
+
var GroupedEntityList_1 = require("./GroupedEntityList");
|
|
19
|
+
Object.defineProperty(exports, "GroupedEntityList", { enumerable: true, get: function () { return GroupedEntityList_1.GroupedEntityList; } });
|
|
20
|
+
var CollectionSection_1 = require("./CollectionSection");
|
|
21
|
+
Object.defineProperty(exports, "CollectionSection", { enumerable: true, get: function () { return CollectionSection_1.CollectionSection; } });
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* A theme identifier string. Built-in values are 'light', 'dark', and 'system'.
|
|
4
|
+
* Custom themes use arbitrary strings that map to CSS classes (e.g., 'ocean' maps to '.theme-ocean').
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export type ThemeId = string;
|
|
8
|
+
/**
|
|
9
|
+
* Describes an available theme for display in selectors.
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export interface IThemeOption {
|
|
13
|
+
/** Theme identifier used in settings and CSS class mapping */
|
|
14
|
+
readonly id: ThemeId;
|
|
15
|
+
/** Human-readable label for display */
|
|
16
|
+
readonly label: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Value exposed by ThemeContext.
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
export interface IThemeContext {
|
|
23
|
+
/** The currently active theme ID */
|
|
24
|
+
readonly theme: ThemeId;
|
|
25
|
+
/** Whether the resolved (effective) appearance is dark */
|
|
26
|
+
readonly isDark: boolean;
|
|
27
|
+
/** Set the active theme */
|
|
28
|
+
readonly setTheme: (theme: ThemeId) => void;
|
|
29
|
+
/** All available theme options */
|
|
30
|
+
readonly availableThemes: ReadonlyArray<IThemeOption>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Props for {@link ThemeProvider}.
|
|
34
|
+
* @public
|
|
35
|
+
*/
|
|
36
|
+
export interface IThemeProviderProps {
|
|
37
|
+
/** Initial theme ID (typically from persisted settings). Defaults to 'light'. */
|
|
38
|
+
readonly initialTheme?: ThemeId;
|
|
39
|
+
/** Additional custom themes beyond the built-in light/dark/system. */
|
|
40
|
+
readonly customThemes?: ReadonlyArray<IThemeOption>;
|
|
41
|
+
/** Called when the user changes the theme. Use this to persist the choice. */
|
|
42
|
+
readonly onThemeChange?: (theme: ThemeId) => void;
|
|
43
|
+
/** Children */
|
|
44
|
+
readonly children: React.ReactNode;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Provides theme context to the application and manages the CSS class on `<html>`.
|
|
48
|
+
*
|
|
49
|
+
* Wrap your app (or a subtree) with this provider. Components use {@link useTheme}
|
|
50
|
+
* to read or change the active theme.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```tsx
|
|
54
|
+
* <ThemeProvider initialTheme={settings.appearance?.theme} onThemeChange={saveTheme}>
|
|
55
|
+
* <App />
|
|
56
|
+
* </ThemeProvider>
|
|
57
|
+
* ```
|
|
58
|
+
* @public
|
|
59
|
+
*/
|
|
60
|
+
export declare function ThemeProvider({ initialTheme, customThemes, onThemeChange, children }: IThemeProviderProps): React.JSX.Element;
|
|
61
|
+
/**
|
|
62
|
+
* Access the current theme and theme-switching controls.
|
|
63
|
+
*
|
|
64
|
+
* Must be called within a {@link ThemeProvider}.
|
|
65
|
+
* @public
|
|
66
|
+
*/
|
|
67
|
+
export declare function useTheme(): IThemeContext;
|
|
68
|
+
//# sourceMappingURL=ThemeProvider.d.ts.map
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) 2026 Erik Fortune
|
|
3
|
+
//
|
|
4
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
// in the Software without restriction, including without limitation the rights
|
|
7
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
// furnished to do so, subject to the following conditions:
|
|
10
|
+
//
|
|
11
|
+
// The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
// copies or substantial portions of the Software.
|
|
13
|
+
//
|
|
14
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
// SOFTWARE.
|
|
21
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
24
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
25
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
26
|
+
}
|
|
27
|
+
Object.defineProperty(o, k2, desc);
|
|
28
|
+
}) : (function(o, m, k, k2) {
|
|
29
|
+
if (k2 === undefined) k2 = k;
|
|
30
|
+
o[k2] = m[k];
|
|
31
|
+
}));
|
|
32
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
33
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
34
|
+
}) : function(o, v) {
|
|
35
|
+
o["default"] = v;
|
|
36
|
+
});
|
|
37
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
38
|
+
var ownKeys = function(o) {
|
|
39
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
40
|
+
var ar = [];
|
|
41
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
42
|
+
return ar;
|
|
43
|
+
};
|
|
44
|
+
return ownKeys(o);
|
|
45
|
+
};
|
|
46
|
+
return function (mod) {
|
|
47
|
+
if (mod && mod.__esModule) return mod;
|
|
48
|
+
var result = {};
|
|
49
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
50
|
+
__setModuleDefault(result, mod);
|
|
51
|
+
return result;
|
|
52
|
+
};
|
|
53
|
+
})();
|
|
54
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
|
+
exports.ThemeProvider = ThemeProvider;
|
|
56
|
+
exports.useTheme = useTheme;
|
|
57
|
+
const react_1 = __importStar(require("react"));
|
|
58
|
+
/**
|
|
59
|
+
* Default built-in themes.
|
|
60
|
+
*/
|
|
61
|
+
const BUILT_IN_THEMES = [
|
|
62
|
+
{ id: 'light', label: 'Light' },
|
|
63
|
+
{ id: 'dark', label: 'Dark' },
|
|
64
|
+
{ id: 'system', label: 'System' }
|
|
65
|
+
];
|
|
66
|
+
const ThemeContext = (0, react_1.createContext)(undefined);
|
|
67
|
+
/**
|
|
68
|
+
* Maps a theme ID to the CSS class applied to the document element.
|
|
69
|
+
* - 'light': no class (uses :root defaults)
|
|
70
|
+
* - 'dark': 'dark' class
|
|
71
|
+
* - 'system': 'system-theme' class (uses prefers-color-scheme media query)
|
|
72
|
+
* - custom: 'theme-\{id\}' class
|
|
73
|
+
*/
|
|
74
|
+
function themeIdToCssClass(id) {
|
|
75
|
+
switch (id) {
|
|
76
|
+
case 'light':
|
|
77
|
+
return undefined;
|
|
78
|
+
case 'dark':
|
|
79
|
+
return 'dark';
|
|
80
|
+
case 'system':
|
|
81
|
+
return 'system-theme';
|
|
82
|
+
default:
|
|
83
|
+
return `theme-${id}`;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Determines whether the effective appearance is dark.
|
|
88
|
+
*/
|
|
89
|
+
function resolveIsDark(themeId) {
|
|
90
|
+
if (themeId === 'dark') {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
if (themeId === 'system' && typeof window !== 'undefined') {
|
|
94
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* All CSS classes that ThemeProvider may apply.
|
|
100
|
+
* Used to cleanly remove the previous theme before applying a new one.
|
|
101
|
+
*/
|
|
102
|
+
const MANAGED_CLASSES = ['dark', 'system-theme'];
|
|
103
|
+
/**
|
|
104
|
+
* Provides theme context to the application and manages the CSS class on `<html>`.
|
|
105
|
+
*
|
|
106
|
+
* Wrap your app (or a subtree) with this provider. Components use {@link useTheme}
|
|
107
|
+
* to read or change the active theme.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```tsx
|
|
111
|
+
* <ThemeProvider initialTheme={settings.appearance?.theme} onThemeChange={saveTheme}>
|
|
112
|
+
* <App />
|
|
113
|
+
* </ThemeProvider>
|
|
114
|
+
* ```
|
|
115
|
+
* @public
|
|
116
|
+
*/
|
|
117
|
+
function ThemeProvider({ initialTheme = 'light', customThemes, onThemeChange, children }) {
|
|
118
|
+
const [theme, setThemeState] = (0, react_1.useState)(initialTheme);
|
|
119
|
+
const [isDark, setIsDark] = (0, react_1.useState)(() => resolveIsDark(initialTheme));
|
|
120
|
+
const availableThemes = (0, react_1.useMemo)(() => {
|
|
121
|
+
if (!customThemes || customThemes.length === 0) {
|
|
122
|
+
return BUILT_IN_THEMES;
|
|
123
|
+
}
|
|
124
|
+
return [...BUILT_IN_THEMES, ...customThemes];
|
|
125
|
+
}, [customThemes]);
|
|
126
|
+
const setTheme = (0, react_1.useCallback)((newTheme) => {
|
|
127
|
+
setThemeState(newTheme);
|
|
128
|
+
onThemeChange === null || onThemeChange === void 0 ? void 0 : onThemeChange(newTheme);
|
|
129
|
+
}, [onThemeChange]);
|
|
130
|
+
// Apply CSS class to document element when theme changes
|
|
131
|
+
(0, react_1.useEffect)(() => {
|
|
132
|
+
const root = document.documentElement;
|
|
133
|
+
// Remove all managed theme classes
|
|
134
|
+
for (const cls of MANAGED_CLASSES) {
|
|
135
|
+
root.classList.remove(cls);
|
|
136
|
+
}
|
|
137
|
+
// Also remove any custom theme classes
|
|
138
|
+
for (const cls of Array.from(root.classList)) {
|
|
139
|
+
if (cls.startsWith('theme-')) {
|
|
140
|
+
root.classList.remove(cls);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Apply new theme class
|
|
144
|
+
const cssClass = themeIdToCssClass(theme);
|
|
145
|
+
if (cssClass) {
|
|
146
|
+
root.classList.add(cssClass);
|
|
147
|
+
}
|
|
148
|
+
setIsDark(resolveIsDark(theme));
|
|
149
|
+
}, [theme]);
|
|
150
|
+
// Listen for OS preference changes when using 'system' theme
|
|
151
|
+
(0, react_1.useEffect)(() => {
|
|
152
|
+
if (theme !== 'system') {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
156
|
+
const handler = (e) => {
|
|
157
|
+
setIsDark(e.matches);
|
|
158
|
+
};
|
|
159
|
+
mediaQuery.addEventListener('change', handler);
|
|
160
|
+
return () => mediaQuery.removeEventListener('change', handler);
|
|
161
|
+
}, [theme]);
|
|
162
|
+
const value = (0, react_1.useMemo)(() => ({ theme, isDark, setTheme, availableThemes }), [theme, isDark, setTheme, availableThemes]);
|
|
163
|
+
return react_1.default.createElement(ThemeContext.Provider, { value: value }, children);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Access the current theme and theme-switching controls.
|
|
167
|
+
*
|
|
168
|
+
* Must be called within a {@link ThemeProvider}.
|
|
169
|
+
* @public
|
|
170
|
+
*/
|
|
171
|
+
function useTheme() {
|
|
172
|
+
const context = (0, react_1.useContext)(ThemeContext);
|
|
173
|
+
if (!context) {
|
|
174
|
+
throw new Error('useTheme must be used within a ThemeProvider');
|
|
175
|
+
}
|
|
176
|
+
return context;
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=ThemeProvider.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Theme provider and hook for runtime theme switching.
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.useTheme = exports.ThemeProvider = void 0;
|
|
8
|
+
var ThemeProvider_1 = require("./ThemeProvider");
|
|
9
|
+
Object.defineProperty(exports, "ThemeProvider", { enumerable: true, get: function () { return ThemeProvider_1.ThemeProvider; } });
|
|
10
|
+
Object.defineProperty(exports, "useTheme", { enumerable: true, get: function () { return ThemeProvider_1.useTheme; } });
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for a single mode in the mode selector.
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export interface IModeConfig<TMode extends string> {
|
|
7
|
+
/** Mode identifier */
|
|
8
|
+
readonly id: TMode;
|
|
9
|
+
/** Display label */
|
|
10
|
+
readonly label: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Props for the ModeSelector component.
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
export interface IModeSelectorProps<TMode extends string> {
|
|
17
|
+
/** Available modes */
|
|
18
|
+
readonly modes: ReadonlyArray<IModeConfig<TMode>>;
|
|
19
|
+
/** Currently active mode */
|
|
20
|
+
readonly activeMode: TMode;
|
|
21
|
+
/** Callback when a mode is selected */
|
|
22
|
+
readonly onModeChange: (mode: TMode) => void;
|
|
23
|
+
/** Optional right-side content (e.g., settings gear icon) */
|
|
24
|
+
readonly rightContent?: React.ReactNode;
|
|
25
|
+
/** Application title */
|
|
26
|
+
readonly title: string;
|
|
27
|
+
/** Optional callback to toggle sidebar drawer (shows hamburger icon when provided). */
|
|
28
|
+
readonly onMenuToggle?: () => void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Top-level mode selector bar.
|
|
32
|
+
* Renders the application title, mode toggle buttons, and optional right-side content.
|
|
33
|
+
* When {@link IModeSelectorProps.onMenuToggle | onMenuToggle} is provided, a hamburger
|
|
34
|
+
* menu button is shown at the left edge (for compact/mobile layouts).
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
export declare function ModeSelector<TMode extends string>(props: IModeSelectorProps<TMode>): React.ReactElement;
|
|
38
|
+
//# sourceMappingURL=ModeSelector.d.ts.map
|
|
@@ -0,0 +1,52 @@
|
|
|
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.ModeSelector = ModeSelector;
|
|
28
|
+
const react_1 = __importDefault(require("react"));
|
|
29
|
+
const responsive_1 = require("../responsive");
|
|
30
|
+
/**
|
|
31
|
+
* Top-level mode selector bar.
|
|
32
|
+
* Renders the application title, mode toggle buttons, and optional right-side content.
|
|
33
|
+
* When {@link IModeSelectorProps.onMenuToggle | onMenuToggle} is provided, a hamburger
|
|
34
|
+
* menu button is shown at the left edge (for compact/mobile layouts).
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
function ModeSelector(props) {
|
|
38
|
+
const { modes, activeMode, onModeChange, rightContent, title, onMenuToggle } = props;
|
|
39
|
+
const { layoutMode } = (0, responsive_1.useResponsive)();
|
|
40
|
+
const isMobile = layoutMode === 'mobile';
|
|
41
|
+
return (react_1.default.createElement("div", { className: "flex items-center justify-between px-4 py-2 bg-brand-primary text-white" },
|
|
42
|
+
react_1.default.createElement("div", { className: `flex items-center ${isMobile ? 'gap-2' : 'gap-6'}` },
|
|
43
|
+
onMenuToggle && (react_1.default.createElement("button", { onClick: onMenuToggle, className: "p-1.5 -ml-1.5 rounded-md text-white/70 hover:text-white hover:bg-white/10 transition-colors", "aria-label": "Open menu" },
|
|
44
|
+
react_1.default.createElement("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor" },
|
|
45
|
+
react_1.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" })))),
|
|
46
|
+
!isMobile && react_1.default.createElement("h1", { className: "text-lg font-semibold whitespace-nowrap" }, title),
|
|
47
|
+
react_1.default.createElement("div", { className: "flex gap-1" }, modes.map((mode) => (react_1.default.createElement("button", { key: mode.id, onClick: () => onModeChange(mode.id), className: `rounded-md font-medium transition-colors ${isMobile ? 'px-2 py-1 text-xs' : 'px-4 py-1.5 text-sm'} ${activeMode === mode.id
|
|
48
|
+
? 'bg-white/20 text-white'
|
|
49
|
+
: 'text-white/70 hover:text-white hover:bg-white/10'}`, "aria-current": activeMode === mode.id ? 'true' : undefined }, mode.label))))),
|
|
50
|
+
rightContent && react_1.default.createElement("div", { className: "flex items-center gap-2" }, rightContent)));
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=ModeSelector.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for a single tab.
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export interface ITabConfig<TTab extends string> {
|
|
7
|
+
/** Tab identifier */
|
|
8
|
+
readonly id: TTab;
|
|
9
|
+
/** Display label */
|
|
10
|
+
readonly label: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Props for the TabBar component.
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
export interface ITabBarProps<TTab extends string> {
|
|
17
|
+
/** Available tabs */
|
|
18
|
+
readonly tabs: ReadonlyArray<ITabConfig<TTab>>;
|
|
19
|
+
/** Currently active tab */
|
|
20
|
+
readonly activeTab: TTab;
|
|
21
|
+
/** Callback when a tab is selected */
|
|
22
|
+
readonly onTabChange: (tab: TTab) => void;
|
|
23
|
+
/** Optional content pinned to the far right of the tab bar */
|
|
24
|
+
readonly rightContent?: React.ReactNode;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Second-level tab bar for switching views within a mode.
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
export declare function TabBar<TTab extends string>(props: ITabBarProps<TTab>): React.ReactElement;
|
|
31
|
+
//# sourceMappingURL=TabBar.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
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.TabBar = TabBar;
|
|
28
|
+
const react_1 = __importDefault(require("react"));
|
|
29
|
+
/**
|
|
30
|
+
* Second-level tab bar for switching views within a mode.
|
|
31
|
+
* @public
|
|
32
|
+
*/
|
|
33
|
+
function TabBar(props) {
|
|
34
|
+
const { tabs, activeTab, onTabChange, rightContent } = props;
|
|
35
|
+
return (react_1.default.createElement("div", { className: "flex items-center gap-1 px-4 py-1 bg-brand-secondary text-white border-t border-white/10 overflow-x-auto" },
|
|
36
|
+
tabs.map((tab) => (react_1.default.createElement("button", { key: tab.id, onClick: () => onTabChange(tab.id), className: `px-3 py-1.5 rounded-md text-sm font-medium transition-colors shrink-0 ${activeTab === tab.id
|
|
37
|
+
? 'bg-white/20 text-white'
|
|
38
|
+
: 'text-white/60 hover:text-white hover:bg-white/10'}`, "aria-current": activeTab === tab.id ? 'page' : undefined }, tab.label))),
|
|
39
|
+
rightContent !== undefined && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
40
|
+
react_1.default.createElement("div", { className: "flex-1" }),
|
|
41
|
+
rightContent))));
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=TabBar.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top bar components: mode selector and tab bar.
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
export { ModeSelector, type IModeConfig, type IModeSelectorProps } from './ModeSelector';
|
|
6
|
+
export { TabBar, type ITabConfig, type ITabBarProps } from './TabBar';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Top bar components: mode selector and tab bar.
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.TabBar = exports.ModeSelector = void 0;
|
|
8
|
+
var ModeSelector_1 = require("./ModeSelector");
|
|
9
|
+
Object.defineProperty(exports, "ModeSelector", { enumerable: true, get: function () { return ModeSelector_1.ModeSelector; } });
|
|
10
|
+
var TabBar_1 = require("./TabBar");
|
|
11
|
+
Object.defineProperty(exports, "TabBar", { enumerable: true, get: function () { return TabBar_1.TabBar; } });
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL sync packlet - bidirectional URL hash synchronization for mode/tab navigation.
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
export { type IUrlSyncConfig, type IUrlSyncCallbacks, type IUrlSyncState, type IParsedHash, encodeUrlHash, parseUrlHash, useUrlSync } from './useUrlSync';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* URL sync packlet - bidirectional URL hash synchronization for mode/tab navigation.
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.useUrlSync = exports.parseUrlHash = exports.encodeUrlHash = void 0;
|
|
8
|
+
var useUrlSync_1 = require("./useUrlSync");
|
|
9
|
+
Object.defineProperty(exports, "encodeUrlHash", { enumerable: true, get: function () { return useUrlSync_1.encodeUrlHash; } });
|
|
10
|
+
Object.defineProperty(exports, "parseUrlHash", { enumerable: true, get: function () { return useUrlSync_1.parseUrlHash; } });
|
|
11
|
+
Object.defineProperty(exports, "useUrlSync", { enumerable: true, get: function () { return useUrlSync_1.useUrlSync; } });
|
|
12
|
+
//# sourceMappingURL=index.js.map
|