@grackle-ai/web-components 0.107.2
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/.rush/temp/3ae72563f781afd72723475938136f113846603e.untar.log +10 -0
- package/.rush/temp/bc1d5bf9201ce71abeaeaddd096deb9b0805d703.untar.log +10 -0
- package/.rush/temp/operation/_phase_build/all.log +18 -0
- package/.rush/temp/operation/_phase_build/log-chunks.jsonl +18 -0
- package/.rush/temp/operation/_phase_build/state.json +3 -0
- package/.rush/temp/operation/_phase_test/all.log +121 -0
- package/.rush/temp/operation/_phase_test/log-chunks.jsonl +121 -0
- package/.rush/temp/operation/_phase_test/state.json +3 -0
- package/.rush/temp/shrinkwrap-deps.json +938 -0
- package/.storybook/main.ts +22 -0
- package/.storybook/preview.tsx +30 -0
- package/config/rig.json +4 -0
- package/config/rush-project.json +12 -0
- package/dist/index.css +1 -0
- package/dist/index.js +39221 -0
- package/eslint.config.cjs +5 -0
- package/package.json +83 -0
- package/rush-logs/web-components._phase_build.cache.log +4 -0
- package/rush-logs/web-components._phase_test.cache.log +4 -0
- package/src/components/chat/ChatInput.module.scss +81 -0
- package/src/components/chat/ChatInput.stories.tsx +91 -0
- package/src/components/chat/ChatInput.tsx +168 -0
- package/src/components/chat/index.ts +6 -0
- package/src/components/dag/DagView.module.scss +149 -0
- package/src/components/dag/DagView.stories.tsx +125 -0
- package/src/components/dag/DagView.tsx +109 -0
- package/src/components/dag/TaskNode.stories.tsx +133 -0
- package/src/components/dag/TaskNode.tsx +40 -0
- package/src/components/dag/useDagLayout.ts +139 -0
- package/src/components/display/Breadcrumbs.module.scss +71 -0
- package/src/components/display/Breadcrumbs.stories.tsx +80 -0
- package/src/components/display/Breadcrumbs.tsx +46 -0
- package/src/components/display/Button.module.scss +110 -0
- package/src/components/display/Button.stories.tsx +88 -0
- package/src/components/display/Button.tsx +40 -0
- package/src/components/display/ConfirmDialog.module.scss +67 -0
- package/src/components/display/ConfirmDialog.stories.tsx +81 -0
- package/src/components/display/ConfirmDialog.tsx +88 -0
- package/src/components/display/CopyButton.module.scss +41 -0
- package/src/components/display/CopyButton.stories.tsx +78 -0
- package/src/components/display/CopyButton.tsx +64 -0
- package/src/components/display/DemoBanner.module.scss +37 -0
- package/src/components/display/DemoBanner.stories.tsx +40 -0
- package/src/components/display/DemoBanner.tsx +23 -0
- package/src/components/display/EventHoverRow.module.scss +102 -0
- package/src/components/display/EventHoverRow.stories.tsx +99 -0
- package/src/components/display/EventHoverRow.tsx +154 -0
- package/src/components/display/EventRenderer.module.scss +272 -0
- package/src/components/display/EventRenderer.stories.tsx +186 -0
- package/src/components/display/EventRenderer.tsx +271 -0
- package/src/components/display/EventStream.module.scss +93 -0
- package/src/components/display/EventStream.stories.tsx +249 -0
- package/src/components/display/EventStream.tsx +369 -0
- package/src/components/display/FloatingActionBar.module.scss +107 -0
- package/src/components/display/FloatingActionBar.stories.tsx +122 -0
- package/src/components/display/FloatingActionBar.tsx +119 -0
- package/src/components/display/SessionAttemptSelector.module.scss +50 -0
- package/src/components/display/SessionAttemptSelector.stories.tsx +78 -0
- package/src/components/display/SessionAttemptSelector.tsx +49 -0
- package/src/components/display/SessionPicker.module.scss +200 -0
- package/src/components/display/SessionPicker.stories.tsx +169 -0
- package/src/components/display/SessionPicker.tsx +214 -0
- package/src/components/display/Skeleton.module.scss +58 -0
- package/src/components/display/Skeleton.stories.tsx +94 -0
- package/src/components/display/Skeleton.tsx +127 -0
- package/src/components/display/Spinner.module.scss +41 -0
- package/src/components/display/Spinner.stories.tsx +66 -0
- package/src/components/display/Spinner.tsx +32 -0
- package/src/components/display/SplashScreen.module.scss +20 -0
- package/src/components/display/SplashScreen.stories.tsx +26 -0
- package/src/components/display/SplashScreen.tsx +16 -0
- package/src/components/display/SplitButton.module.scss +166 -0
- package/src/components/display/SplitButton.stories.tsx +95 -0
- package/src/components/display/SplitButton.tsx +128 -0
- package/src/components/display/Tooltip.module.scss +84 -0
- package/src/components/display/Tooltip.stories.tsx +240 -0
- package/src/components/display/Tooltip.tsx +184 -0
- package/src/components/display/extractText.test.tsx +48 -0
- package/src/components/display/index.ts +20 -0
- package/src/components/editable/EditableCheckbox.stories.tsx +54 -0
- package/src/components/editable/EditableCheckbox.tsx +39 -0
- package/src/components/editable/EditableField.module.scss +135 -0
- package/src/components/editable/EditableSelect.tsx +164 -0
- package/src/components/editable/EditableTextArea.stories.tsx +50 -0
- package/src/components/editable/EditableTextArea.tsx +148 -0
- package/src/components/editable/EditableTextField.stories.tsx +62 -0
- package/src/components/editable/EditableTextField.tsx +153 -0
- package/src/components/editable/EnvironmentSelect.module.scss +17 -0
- package/src/components/editable/EnvironmentSelect.stories.tsx +61 -0
- package/src/components/editable/EnvironmentSelect.tsx +87 -0
- package/src/components/editable/index.ts +13 -0
- package/src/components/editable/useEditableField.test.tsx +233 -0
- package/src/components/editable/useEditableField.ts +173 -0
- package/src/components/index.ts +20 -0
- package/src/components/knowledge/KnowledgeDetailPanel.module.scss +162 -0
- package/src/components/knowledge/KnowledgeDetailPanel.stories.tsx +208 -0
- package/src/components/knowledge/KnowledgeDetailPanel.tsx +122 -0
- package/src/components/knowledge/KnowledgeGraph.module.scss +110 -0
- package/src/components/knowledge/KnowledgeGraph.stories.tsx +180 -0
- package/src/components/knowledge/KnowledgeGraph.tsx +455 -0
- package/src/components/knowledge/KnowledgeNav.module.scss +130 -0
- package/src/components/knowledge/KnowledgeNav.stories.tsx +108 -0
- package/src/components/knowledge/KnowledgeNav.tsx +138 -0
- package/src/components/knowledge/index.ts +3 -0
- package/src/components/layout/AppNav.module.scss +82 -0
- package/src/components/layout/AppNav.stories.tsx +115 -0
- package/src/components/layout/AppNav.tsx +133 -0
- package/src/components/layout/BottomStatusBar.module.scss +58 -0
- package/src/components/layout/BottomStatusBar.stories.tsx +35 -0
- package/src/components/layout/BottomStatusBar.tsx +206 -0
- package/src/components/layout/Sidebar.module.scss +60 -0
- package/src/components/layout/Sidebar.stories.tsx +46 -0
- package/src/components/layout/Sidebar.tsx +84 -0
- package/src/components/layout/StatusBar.module.scss +108 -0
- package/src/components/layout/StatusBar.stories.tsx +119 -0
- package/src/components/layout/StatusBar.tsx +70 -0
- package/src/components/layout/index.ts +9 -0
- package/src/components/lists/EnvironmentNav.module.scss +118 -0
- package/src/components/lists/EnvironmentNav.stories.tsx +121 -0
- package/src/components/lists/EnvironmentNav.tsx +133 -0
- package/src/components/lists/FindingsNav.module.scss +126 -0
- package/src/components/lists/FindingsNav.tsx +146 -0
- package/src/components/lists/TaskList.module.scss +206 -0
- package/src/components/lists/TaskList.stories.tsx +401 -0
- package/src/components/lists/TaskList.tsx +509 -0
- package/src/components/lists/index.ts +6 -0
- package/src/components/lists/listHelpers.tsx +130 -0
- package/src/components/notifications/Callout.module.scss +83 -0
- package/src/components/notifications/Callout.stories.tsx +81 -0
- package/src/components/notifications/Callout.tsx +64 -0
- package/src/components/notifications/Toast.module.scss +86 -0
- package/src/components/notifications/Toast.stories.tsx +71 -0
- package/src/components/notifications/Toast.tsx +51 -0
- package/src/components/notifications/ToastContainer.module.scss +23 -0
- package/src/components/notifications/ToastContainer.stories.tsx +66 -0
- package/src/components/notifications/ToastContainer.tsx +29 -0
- package/src/components/notifications/UpdateBanner.stories.tsx +77 -0
- package/src/components/notifications/UpdateBanner.test.tsx +64 -0
- package/src/components/notifications/UpdateBanner.tsx +44 -0
- package/src/components/notifications/index.ts +8 -0
- package/src/components/panels/AboutPanel.stories.tsx +70 -0
- package/src/components/panels/AboutPanel.tsx +66 -0
- package/src/components/panels/AppearancePanel.stories.tsx +45 -0
- package/src/components/panels/AppearancePanel.tsx +97 -0
- package/src/components/panels/CredentialProvidersPanel.stories.tsx +62 -0
- package/src/components/panels/CredentialProvidersPanel.tsx +111 -0
- package/src/components/panels/EnvironmentEditPanel.module.scss +170 -0
- package/src/components/panels/EnvironmentEditPanel.stories.tsx +206 -0
- package/src/components/panels/EnvironmentEditPanel.tsx +785 -0
- package/src/components/panels/FindingsPanel.module.scss +94 -0
- package/src/components/panels/FindingsPanel.stories.tsx +109 -0
- package/src/components/panels/FindingsPanel.tsx +76 -0
- package/src/components/panels/KeyboardShortcutsPanel.module.scss +65 -0
- package/src/components/panels/KeyboardShortcutsPanel.stories.tsx +40 -0
- package/src/components/panels/KeyboardShortcutsPanel.tsx +104 -0
- package/src/components/panels/PluginsPanel.tsx +77 -0
- package/src/components/panels/SettingsPanel.module.scss +336 -0
- package/src/components/panels/TaskActionButtons.module.scss +22 -0
- package/src/components/panels/TaskActionButtons.stories.tsx +125 -0
- package/src/components/panels/TaskActionButtons.tsx +87 -0
- package/src/components/panels/TaskEditPanel.module.scss +202 -0
- package/src/components/panels/TaskEditPanel.stories.tsx +75 -0
- package/src/components/panels/TaskEditPanel.tsx +328 -0
- package/src/components/panels/TaskOverviewPanel.module.scss +236 -0
- package/src/components/panels/TaskOverviewPanel.stories.tsx +219 -0
- package/src/components/panels/TaskOverviewPanel.tsx +270 -0
- package/src/components/panels/TokensPanel.stories.tsx +131 -0
- package/src/components/panels/TokensPanel.tsx +143 -0
- package/src/components/panels/WorkpadPanel.module.scss +39 -0
- package/src/components/panels/WorkpadPanel.stories.tsx +56 -0
- package/src/components/panels/WorkpadPanel.tsx +63 -0
- package/src/components/panels/index.ts +13 -0
- package/src/components/personas/McpToolSelector.module.scss +109 -0
- package/src/components/personas/McpToolSelector.stories.tsx +129 -0
- package/src/components/personas/McpToolSelector.tsx +180 -0
- package/src/components/personas/PersonaManager.module.scss +233 -0
- package/src/components/personas/PersonaManager.stories.tsx +139 -0
- package/src/components/personas/PersonaManager.tsx +122 -0
- package/src/components/schedules/ScheduleManager.module.scss +98 -0
- package/src/components/schedules/ScheduleManager.stories.tsx +78 -0
- package/src/components/schedules/ScheduleManager.tsx +160 -0
- package/src/components/settings/SettingsNav.module.scss +82 -0
- package/src/components/settings/SettingsNav.stories.tsx +83 -0
- package/src/components/settings/SettingsNav.tsx +104 -0
- package/src/components/streams/StreamDetailPanel.module.scss +206 -0
- package/src/components/streams/StreamDetailPanel.stories.tsx +132 -0
- package/src/components/streams/StreamDetailPanel.tsx +119 -0
- package/src/components/streams/StreamList.module.scss +92 -0
- package/src/components/streams/StreamList.stories.tsx +99 -0
- package/src/components/streams/StreamList.tsx +114 -0
- package/src/components/streams/index.ts +10 -0
- package/src/components/tools/AgentToolCard.module.scss +118 -0
- package/src/components/tools/AgentToolCard.stories.tsx +304 -0
- package/src/components/tools/AgentToolCard.tsx +247 -0
- package/src/components/tools/FileEditCard.stories.tsx +138 -0
- package/src/components/tools/FileEditCard.tsx +160 -0
- package/src/components/tools/FileReadCard.stories.tsx +120 -0
- package/src/components/tools/FileReadCard.tsx +106 -0
- package/src/components/tools/FindingCard.stories.tsx +124 -0
- package/src/components/tools/FindingCard.tsx +178 -0
- package/src/components/tools/GenericToolCard.stories.tsx +80 -0
- package/src/components/tools/GenericToolCard.tsx +111 -0
- package/src/components/tools/IpcCard.stories.tsx +129 -0
- package/src/components/tools/IpcCard.tsx +178 -0
- package/src/components/tools/KnowledgeCard.stories.tsx +112 -0
- package/src/components/tools/KnowledgeCard.tsx +165 -0
- package/src/components/tools/MetadataCard.stories.tsx +32 -0
- package/src/components/tools/MetadataCard.tsx +39 -0
- package/src/components/tools/SearchCard.stories.tsx +74 -0
- package/src/components/tools/SearchCard.tsx +86 -0
- package/src/components/tools/ShellCard.stories.tsx +112 -0
- package/src/components/tools/ShellCard.tsx +106 -0
- package/src/components/tools/TaskCard.stories.tsx +123 -0
- package/src/components/tools/TaskCard.tsx +203 -0
- package/src/components/tools/TodoCard.module.scss +131 -0
- package/src/components/tools/TodoCard.stories.tsx +202 -0
- package/src/components/tools/TodoCard.tsx +200 -0
- package/src/components/tools/ToolCard.stories.tsx +177 -0
- package/src/components/tools/ToolCard.tsx +60 -0
- package/src/components/tools/ToolCardProps.ts +20 -0
- package/src/components/tools/ToolSearchCard.stories.tsx +81 -0
- package/src/components/tools/ToolSearchCard.tsx +86 -0
- package/src/components/tools/WorkpadCard.stories.tsx +106 -0
- package/src/components/tools/WorkpadCard.tsx +125 -0
- package/src/components/tools/classifyTool.test.ts +44 -0
- package/src/components/tools/classifyTool.ts +134 -0
- package/src/components/tools/parseDiff.ts +95 -0
- package/src/components/tools/parseShellOutput.ts +28 -0
- package/src/components/tools/toolCardHelpers.test.ts +53 -0
- package/src/components/tools/toolCards.module.scss +234 -0
- package/src/components/workspace/WorkspaceBoard.module.scss +238 -0
- package/src/components/workspace/WorkspaceBoard.stories.tsx +240 -0
- package/src/components/workspace/WorkspaceBoard.tsx +232 -0
- package/src/components/workspace/WorkspaceFormFields.module.scss +79 -0
- package/src/components/workspace/WorkspaceFormFields.stories.tsx +133 -0
- package/src/components/workspace/WorkspaceFormFields.tsx +185 -0
- package/src/context/GrackleContext.ts +28 -0
- package/src/context/GrackleContextTypes.ts +64 -0
- package/src/context/SidebarContext.tsx +53 -0
- package/src/context/ThemeContext.tsx +21 -0
- package/src/context/ToastContext.tsx +56 -0
- package/src/hooks/types.ts +864 -0
- package/src/hooks/useEventSelection.test.ts +204 -0
- package/src/hooks/useEventSelection.ts +158 -0
- package/src/hooks/useSmartScroll.ts +151 -0
- package/src/hooks/useTheme.ts +228 -0
- package/src/index.ts +210 -0
- package/src/mocks/MockGrackleProvider.tsx +1397 -0
- package/src/mocks/mockData.ts +1966 -0
- package/src/mocks/mockKnowledgeData.ts +294 -0
- package/src/scss.d.ts +12 -0
- package/src/styles/global.scss +244 -0
- package/src/styles/mixins.scss +278 -0
- package/src/styles/prism-theme.scss +148 -0
- package/src/styles/theme.scss +1102 -0
- package/src/test-utils/storybook-decorators.tsx +50 -0
- package/src/test-utils/storybook-helpers.ts +262 -0
- package/src/themes.ts +142 -0
- package/src/utils/boardColumns.ts +141 -0
- package/src/utils/breadcrumbs.test.ts +285 -0
- package/src/utils/breadcrumbs.ts +222 -0
- package/src/utils/dashboard.test.ts +156 -0
- package/src/utils/dashboard.ts +195 -0
- package/src/utils/eventContent.test.ts +353 -0
- package/src/utils/eventContent.ts +209 -0
- package/src/utils/findingCategory.ts +33 -0
- package/src/utils/format.ts +27 -0
- package/src/utils/iconSize.ts +18 -0
- package/src/utils/navigation.ts +205 -0
- package/src/utils/route-config.test.ts +128 -0
- package/src/utils/scrollUtils.test.ts +65 -0
- package/src/utils/scrollUtils.ts +49 -0
- package/src/utils/sessionEvents.test.ts +302 -0
- package/src/utils/sessionEvents.ts +233 -0
- package/src/utils/taskStatus.tsx +137 -0
- package/src/utils/time.ts +92 -0
- package/tsconfig.json +8 -0
- package/vite.config.ts +20 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the GrackleContext value.
|
|
3
|
+
* Kept separate so both the real provider (in @grackle-ai/web) and
|
|
4
|
+
* MockGrackleProvider can use them without circular dependencies.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
UsageStats, UseKnowledgeResult,
|
|
11
|
+
UseEnvironmentsResult, UseSessionsResult, UseWorkspacesResult,
|
|
12
|
+
UseTasksResult, UseFindingsResult, UseTokensResult,
|
|
13
|
+
UseCredentialsResult, UseCodespacesResult, UsePersonasResult,
|
|
14
|
+
UsePluginsResult,
|
|
15
|
+
UseSchedulesResult,
|
|
16
|
+
UseStreamsResult,
|
|
17
|
+
ConnectionStatus,
|
|
18
|
+
} from "../hooks/types.js";
|
|
19
|
+
|
|
20
|
+
/** Return type for the useGrackleSocket hook (and the GrackleContext value). */
|
|
21
|
+
export interface UseGrackleSocketResult {
|
|
22
|
+
/** Current connection state of the event stream. */
|
|
23
|
+
connectionStatus: ConnectionStatus;
|
|
24
|
+
/** Environment state and actions. */
|
|
25
|
+
environments: Omit<UseEnvironmentsResult, "handleEvent" | "handleLegacyMessage">;
|
|
26
|
+
/** Session state and actions. */
|
|
27
|
+
sessions: Omit<UseSessionsResult, "handleMessage" | "handleSessionEvent" | "handleLegacyMessage" | "loadSessions">;
|
|
28
|
+
/** Workspace state and actions. */
|
|
29
|
+
workspaces: Omit<UseWorkspacesResult, "handleEvent" | "onDisconnect">;
|
|
30
|
+
/** Task state and actions. */
|
|
31
|
+
tasks: Omit<UseTasksResult, "handleEvent" | "onDisconnect" | "handleLegacyMessage">;
|
|
32
|
+
/** Finding state and actions. */
|
|
33
|
+
findings: Omit<UseFindingsResult, "handleEvent">;
|
|
34
|
+
/** Token state and actions. */
|
|
35
|
+
tokens: Omit<UseTokensResult, "handleEvent">;
|
|
36
|
+
/** Credential provider state and actions. */
|
|
37
|
+
credentials: Omit<UseCredentialsResult, "handleEvent" | "loadCredentials">;
|
|
38
|
+
/** GitHub Codespace state and actions. */
|
|
39
|
+
codespaces: UseCodespacesResult;
|
|
40
|
+
/** Persona state and actions. */
|
|
41
|
+
personas: Omit<UsePersonasResult, "handleEvent" | "loadPersonas">;
|
|
42
|
+
/** Schedule state and actions. */
|
|
43
|
+
schedules: Omit<UseSchedulesResult, "handleEvent" | "loadSchedules">;
|
|
44
|
+
/** IPC stream state and actions. */
|
|
45
|
+
streams: Omit<UseStreamsResult, "handleEvent">;
|
|
46
|
+
/** Knowledge graph state and actions. */
|
|
47
|
+
knowledge: Omit<UseKnowledgeResult, "handleEvent">;
|
|
48
|
+
/** Plugin state and actions. */
|
|
49
|
+
plugins: Omit<UsePluginsResult, "domainHook">;
|
|
50
|
+
/** App-level default persona ID setting. */
|
|
51
|
+
appDefaultPersonaId: string;
|
|
52
|
+
/** Update the app-level default persona ID. */
|
|
53
|
+
setAppDefaultPersonaId: (personaId: string) => Promise<void>;
|
|
54
|
+
/** Whether the user has completed onboarding. */
|
|
55
|
+
onboardingCompleted: boolean | undefined;
|
|
56
|
+
/** Mark onboarding as completed. */
|
|
57
|
+
completeOnboarding: () => Promise<void>;
|
|
58
|
+
/** Cached usage statistics keyed by "scope:id". */
|
|
59
|
+
usageCache: Record<string, UsageStats>;
|
|
60
|
+
/** Load usage statistics for a given scope and ID. */
|
|
61
|
+
loadUsage: (scope: string, id: string) => Promise<void>;
|
|
62
|
+
/** Refresh environments, sessions, workspaces, and tokens from the server. */
|
|
63
|
+
refresh: () => void;
|
|
64
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React, { createContext, useCallback, useContext, useState, type JSX, type ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/** Setter function for updating sidebar content. */
|
|
4
|
+
type SidebarSetter = (content: ReactNode | undefined) => void;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Context that holds the current sidebar content node.
|
|
8
|
+
* Consumed by the Sidebar component to render slot content.
|
|
9
|
+
*/
|
|
10
|
+
const SidebarContentContext: React.Context<ReactNode | undefined> = createContext<ReactNode | undefined>(undefined);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Context that holds a stable setter for updating sidebar content.
|
|
14
|
+
* Consumed by layout route wrappers to declare their sidebar content.
|
|
15
|
+
*/
|
|
16
|
+
const SidebarSetterContext: React.Context<SidebarSetter | undefined> = createContext<SidebarSetter | undefined>(undefined);
|
|
17
|
+
|
|
18
|
+
/** Props for the SidebarProvider component. */
|
|
19
|
+
interface SidebarProviderProps {
|
|
20
|
+
/** Child components. */
|
|
21
|
+
children: ReactNode;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Provides sidebar slot state to the component tree. */
|
|
25
|
+
export function SidebarProvider({ children }: SidebarProviderProps): JSX.Element {
|
|
26
|
+
const [content, setContent] = useState<ReactNode | undefined>(undefined);
|
|
27
|
+
|
|
28
|
+
const stableSetContent: SidebarSetter = useCallback((node: ReactNode | undefined) => {
|
|
29
|
+
setContent(node);
|
|
30
|
+
}, []);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<SidebarSetterContext.Provider value={stableSetContent}>
|
|
34
|
+
<SidebarContentContext.Provider value={content}>
|
|
35
|
+
{children}
|
|
36
|
+
</SidebarContentContext.Provider>
|
|
37
|
+
</SidebarSetterContext.Provider>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Read the current sidebar content. Returns `undefined` when no content is set. */
|
|
42
|
+
export function useSidebarContent(): ReactNode | undefined {
|
|
43
|
+
return useContext(SidebarContentContext);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Get the sidebar content setter. Must be called within a SidebarProvider. */
|
|
47
|
+
export function useSidebarSetter(): SidebarSetter {
|
|
48
|
+
const setter = useContext(SidebarSetterContext);
|
|
49
|
+
if (setter === undefined) {
|
|
50
|
+
throw new Error("useSidebarSetter must be used within a SidebarProvider");
|
|
51
|
+
}
|
|
52
|
+
return setter;
|
|
53
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React, { createContext, useContext, type ReactNode, type JSX } from "react";
|
|
2
|
+
import { useTheme, type UseThemeResult } from "../hooks/useTheme.js";
|
|
3
|
+
|
|
4
|
+
const ThemeContext: React.Context<UseThemeResult | undefined> = createContext<UseThemeResult | undefined>(undefined);
|
|
5
|
+
|
|
6
|
+
/** Provides theme state to the component tree. */
|
|
7
|
+
export function ThemeProvider({ children }: { children: ReactNode }): JSX.Element {
|
|
8
|
+
const themeState = useTheme();
|
|
9
|
+
return (
|
|
10
|
+
<ThemeContext.Provider value={themeState}>{children}</ThemeContext.Provider>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Consumes the theme context; must be called within a ThemeProvider. */
|
|
15
|
+
export function useThemeContext(): UseThemeResult {
|
|
16
|
+
const ctx = useContext(ThemeContext);
|
|
17
|
+
if (!ctx) {
|
|
18
|
+
throw new Error("useThemeContext must be used within ThemeProvider");
|
|
19
|
+
}
|
|
20
|
+
return ctx;
|
|
21
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React, { createContext, useContext, useState, useRef, useCallback, type ReactNode, type JSX } from "react";
|
|
2
|
+
|
|
3
|
+
/** Visual style variant for a toast notification. */
|
|
4
|
+
export type ToastVariant = "success" | "error" | "warning" | "info";
|
|
5
|
+
|
|
6
|
+
/** A single toast notification item. */
|
|
7
|
+
export interface ToastItem {
|
|
8
|
+
id: string;
|
|
9
|
+
message: string;
|
|
10
|
+
variant: ToastVariant;
|
|
11
|
+
/** Auto-dismiss delay in milliseconds. */
|
|
12
|
+
duration: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface ToastContextValue {
|
|
16
|
+
toasts: ToastItem[];
|
|
17
|
+
/** Display a new toast notification. */
|
|
18
|
+
showToast: (message: string, variant?: ToastVariant, duration?: number) => void;
|
|
19
|
+
/** Programmatically remove a toast by id. */
|
|
20
|
+
dismissToast: (id: string) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const ToastContext: React.Context<ToastContextValue | undefined> = createContext<ToastContextValue | undefined>(undefined);
|
|
24
|
+
|
|
25
|
+
const DEFAULT_DURATION_MS: number = 4_000;
|
|
26
|
+
|
|
27
|
+
/** Provides toast notification state to the component tree. Mount <ToastContainer> as a sibling to receive rendered output. */
|
|
28
|
+
export function ToastProvider({ children }: { children: ReactNode }): JSX.Element {
|
|
29
|
+
const [toasts, setToasts] = useState<ToastItem[]>([]);
|
|
30
|
+
const toastCounterRef = useRef<number>(0);
|
|
31
|
+
|
|
32
|
+
const dismissToast = useCallback((id: string) => {
|
|
33
|
+
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
34
|
+
}, []);
|
|
35
|
+
|
|
36
|
+
const showToast = useCallback(
|
|
37
|
+
(message: string, variant: ToastVariant = "info", duration: number = DEFAULT_DURATION_MS) => {
|
|
38
|
+
const id = `toast-${++toastCounterRef.current}`;
|
|
39
|
+
setToasts((prev) => [...prev, { id, message, variant, duration }]);
|
|
40
|
+
},
|
|
41
|
+
[],
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<ToastContext.Provider value={{ toasts, showToast, dismissToast }}>
|
|
46
|
+
{children}
|
|
47
|
+
</ToastContext.Provider>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Consumes the toast context; must be called within a ToastProvider. */
|
|
52
|
+
export function useToast(): ToastContextValue {
|
|
53
|
+
const ctx = useContext(ToastContext);
|
|
54
|
+
if (!ctx) throw new Error("useToast must be used within ToastProvider");
|
|
55
|
+
return ctx;
|
|
56
|
+
}
|