termcast 1.3.32 → 1.3.34
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/dist/action-utils.d.ts.map +1 -1
- package/dist/action-utils.js +8 -0
- package/dist/action-utils.js.map +1 -1
- package/dist/apis/cache.d.ts +1 -2
- package/dist/apis/cache.d.ts.map +1 -1
- package/dist/apis/cache.js +138 -54
- package/dist/apis/cache.js.map +1 -1
- package/dist/apis/clipboard.d.ts.map +1 -1
- package/dist/apis/clipboard.js +4 -0
- package/dist/apis/clipboard.js.map +1 -1
- package/dist/apis/oauth.d.ts.map +1 -1
- package/dist/apis/oauth.js +31 -4
- package/dist/apis/oauth.js.map +1 -1
- package/dist/build.d.ts +0 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +30 -51
- package/dist/build.js.map +1 -1
- package/dist/cli.js +31 -14
- package/dist/cli.js.map +1 -1
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +5 -1
- package/dist/compile.js.map +1 -1
- package/dist/components/actions.d.ts +14 -0
- package/dist/components/actions.d.ts.map +1 -1
- package/dist/components/actions.js +151 -59
- package/dist/components/actions.js.map +1 -1
- package/dist/components/alert.d.ts.map +1 -1
- package/dist/components/alert.js +6 -5
- package/dist/components/alert.js.map +1 -1
- package/dist/components/animation-tick.d.ts +1 -1
- package/dist/components/animation-tick.js +1 -1
- package/dist/components/animation-tick.js.map +1 -1
- package/dist/components/detail.d.ts +5 -31
- package/dist/components/detail.d.ts.map +1 -1
- package/dist/components/detail.js +36 -52
- package/dist/components/detail.js.map +1 -1
- package/dist/components/dropdown.d.ts +1 -1
- package/dist/components/dropdown.d.ts.map +1 -1
- package/dist/components/dropdown.js +50 -22
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/footer.d.ts.map +1 -1
- package/dist/components/footer.js +19 -18
- package/dist/components/footer.js.map +1 -1
- package/dist/components/form/checkbox.d.ts.map +1 -1
- package/dist/components/form/checkbox.js +12 -11
- package/dist/components/form/checkbox.js.map +1 -1
- package/dist/components/form/date-picker.d.ts.map +1 -1
- package/dist/components/form/date-picker.js +7 -22
- package/dist/components/form/date-picker.js.map +1 -1
- package/dist/components/form/description.d.ts +1 -1
- package/dist/components/form/description.d.ts.map +1 -1
- package/dist/components/form/description.js +6 -5
- package/dist/components/form/description.js.map +1 -1
- package/dist/components/form/dropdown.d.ts.map +1 -1
- package/dist/components/form/dropdown.js +53 -50
- package/dist/components/form/dropdown.js.map +1 -1
- package/dist/components/form/file-autocomplete.d.ts.map +1 -1
- package/dist/components/form/file-autocomplete.js +5 -4
- package/dist/components/form/file-autocomplete.js.map +1 -1
- package/dist/components/form/file-picker.d.ts.map +1 -1
- package/dist/components/form/file-picker.js +23 -22
- package/dist/components/form/file-picker.js.map +1 -1
- package/dist/components/form/form-end.d.ts.map +1 -1
- package/dist/components/form/form-end.js +6 -4
- package/dist/components/form/form-end.js.map +1 -1
- package/dist/components/form/form-field-wrapper.d.ts +15 -0
- package/dist/components/form/form-field-wrapper.d.ts.map +1 -0
- package/dist/components/form/form-field-wrapper.js +29 -0
- package/dist/components/form/form-field-wrapper.js.map +1 -0
- package/dist/components/form/index.d.ts.map +1 -1
- package/dist/components/form/index.js +31 -30
- package/dist/components/form/index.js.map +1 -1
- package/dist/components/form/password-field.d.ts.map +1 -1
- package/dist/components/form/password-field.js +7 -6
- package/dist/components/form/password-field.js.map +1 -1
- package/dist/components/form/separator.d.ts.map +1 -1
- package/dist/components/form/separator.js +3 -2
- package/dist/components/form/separator.js.map +1 -1
- package/dist/components/form/tagpicker.d.ts.map +1 -1
- package/dist/components/form/tagpicker.js +2 -1
- package/dist/components/form/tagpicker.js.map +1 -1
- package/dist/components/form/text-area.d.ts.map +1 -1
- package/dist/components/form/text-area.js +7 -6
- package/dist/components/form/text-area.js.map +1 -1
- package/dist/components/form/text-field.d.ts.map +1 -1
- package/dist/components/form/text-field.js +7 -6
- package/dist/components/form/text-field.js.map +1 -1
- package/dist/components/form/use-form-navigation.d.ts.map +1 -1
- package/dist/components/form/use-form-navigation.js +4 -4
- package/dist/components/form/use-form-navigation.js.map +1 -1
- package/dist/components/form/with-left-border.d.ts +15 -0
- package/dist/components/form/with-left-border.d.ts.map +1 -1
- package/dist/components/form/with-left-border.js +21 -9
- package/dist/components/form/with-left-border.js.map +1 -1
- package/dist/components/icon.d.ts +14 -0
- package/dist/components/icon.d.ts.map +1 -1
- package/dist/components/icon.js +60 -0
- package/dist/components/icon.js.map +1 -1
- package/dist/components/image.d.ts +47 -2
- package/dist/components/image.d.ts.map +1 -1
- package/dist/components/image.js +46 -7
- package/dist/components/image.js.map +1 -1
- package/dist/components/list.d.ts +5 -0
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +188 -132
- package/dist/components/list.js.map +1 -1
- package/dist/components/loading-bar.d.ts.map +1 -1
- package/dist/components/loading-bar.js +4 -3
- package/dist/components/loading-bar.js.map +1 -1
- package/dist/components/metadata.d.ts +70 -0
- package/dist/components/metadata.d.ts.map +1 -0
- package/dist/components/metadata.js +82 -0
- package/dist/components/metadata.js.map +1 -0
- package/dist/components/theme-picker.d.ts.map +1 -1
- package/dist/components/theme-picker.js +3 -2
- package/dist/components/theme-picker.js.map +1 -1
- package/dist/descendants-v2.d.ts +60 -0
- package/dist/descendants-v2.d.ts.map +1 -0
- package/dist/descendants-v2.js +144 -0
- package/dist/descendants-v2.js.map +1 -0
- package/dist/examples/actions-context.d.ts +2 -0
- package/dist/examples/actions-context.d.ts.map +1 -0
- package/dist/examples/actions-context.js +33 -0
- package/dist/examples/actions-context.js.map +1 -0
- package/dist/examples/form-basic.d.ts.map +1 -1
- package/dist/examples/form-basic.js +1 -1
- package/dist/examples/form-basic.js.map +1 -1
- package/dist/examples/form-dropdown.js +1 -1
- package/dist/examples/form-dropdown.js.map +1 -1
- package/dist/examples/internal/custom-action-renderables.d.ts +70 -0
- package/dist/examples/internal/custom-action-renderables.d.ts.map +1 -0
- package/dist/examples/internal/custom-action-renderables.js +163 -0
- package/dist/examples/internal/custom-action-renderables.js.map +1 -0
- package/dist/examples/internal/custom-dropdown.d.ts +99 -0
- package/dist/examples/internal/custom-dropdown.d.ts.map +1 -0
- package/dist/examples/internal/custom-dropdown.js +270 -0
- package/dist/examples/internal/custom-dropdown.js.map +1 -0
- package/dist/examples/internal/custom-renderable-form.d.ts +43 -0
- package/dist/examples/internal/custom-renderable-form.d.ts.map +1 -0
- package/dist/examples/internal/custom-renderable-form.js +284 -0
- package/dist/examples/internal/custom-renderable-form.js.map +1 -0
- package/dist/examples/internal/custom-renderable-list-default-search.d.ts +2 -0
- package/dist/examples/internal/custom-renderable-list-default-search.d.ts.map +1 -0
- package/dist/examples/internal/custom-renderable-list-default-search.js +16 -0
- package/dist/examples/internal/custom-renderable-list-default-search.js.map +1 -0
- package/dist/examples/internal/custom-renderable-list-v2-default-search.d.ts +2 -0
- package/dist/examples/internal/custom-renderable-list-v2-default-search.d.ts.map +1 -0
- package/dist/examples/internal/custom-renderable-list-v2-default-search.js +24 -0
- package/dist/examples/internal/custom-renderable-list-v2-default-search.js.map +1 -0
- package/dist/examples/internal/custom-renderable-list-v2.d.ts +189 -0
- package/dist/examples/internal/custom-renderable-list-v2.d.ts.map +1 -0
- package/dist/examples/internal/custom-renderable-list-v2.js +708 -0
- package/dist/examples/internal/custom-renderable-list-v2.js.map +1 -0
- package/dist/examples/internal/custom-renderable-list.d.ts +72 -0
- package/dist/examples/internal/custom-renderable-list.d.ts.map +1 -0
- package/dist/examples/internal/custom-renderable-list.js +544 -0
- package/dist/examples/internal/custom-renderable-list.js.map +1 -0
- package/dist/examples/internal/rhf-custom-ref.js +5 -4
- package/dist/examples/internal/rhf-custom-ref.js.map +1 -1
- package/dist/examples/internal/scrollbox-with-descendants.js +4 -2
- package/dist/examples/internal/scrollbox-with-descendants.js.map +1 -1
- package/dist/examples/list-controlled-search.d.ts +2 -0
- package/dist/examples/list-controlled-search.d.ts.map +1 -0
- package/dist/examples/list-controlled-search.js +12 -0
- package/dist/examples/list-controlled-search.js.map +1 -0
- package/dist/examples/list-detail-metadata.js +1 -1
- package/dist/examples/list-detail-metadata.js.map +1 -1
- package/dist/examples/simple-image-mask.d.ts +8 -0
- package/dist/examples/simple-image-mask.d.ts.map +1 -0
- package/dist/examples/simple-image-mask.js +12 -0
- package/dist/examples/simple-image-mask.js.map +1 -0
- package/dist/examples/toast-variations.js +1 -1
- package/dist/examples/toast-variations.js.map +1 -1
- package/dist/extensions/dev.d.ts.map +1 -1
- package/dist/extensions/dev.js +3 -2
- package/dist/extensions/dev.js.map +1 -1
- package/dist/extensions/react-refresh-init.d.ts.map +1 -1
- package/dist/extensions/react-refresh-init.js +4 -3
- package/dist/extensions/react-refresh-init.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/date-picker-widget.d.ts.map +1 -1
- package/dist/internal/date-picker-widget.js +2 -1
- package/dist/internal/date-picker-widget.js.map +1 -1
- package/dist/internal/dialog.d.ts +6 -0
- package/dist/internal/dialog.d.ts.map +1 -1
- package/dist/internal/dialog.js +59 -18
- package/dist/internal/dialog.js.map +1 -1
- package/dist/internal/navigation.d.ts.map +1 -1
- package/dist/internal/navigation.js +8 -1
- package/dist/internal/navigation.js.map +1 -1
- package/dist/internal/offscreen.d.ts +3 -0
- package/dist/internal/offscreen.d.ts.map +1 -1
- package/dist/internal/offscreen.js +5 -0
- package/dist/internal/offscreen.js.map +1 -1
- package/dist/internal/providers.d.ts.map +1 -1
- package/dist/internal/providers.js +20 -3
- package/dist/internal/providers.js.map +1 -1
- package/dist/internal/scrollbox.d.ts.map +1 -1
- package/dist/internal/scrollbox.js +3 -2
- package/dist/internal/scrollbox.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +4 -0
- package/dist/logger.js.map +1 -1
- package/dist/preload.js +5 -17
- package/dist/preload.js.map +1 -1
- package/dist/state.d.ts +4 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +4 -0
- package/dist/state.js.map +1 -1
- package/dist/test-border-overlay.d.ts +2 -0
- package/dist/test-border-overlay.d.ts.map +1 -0
- package/dist/test-border-overlay.js +7 -0
- package/dist/test-border-overlay.js.map +1 -0
- package/dist/test-layout-2.d.ts +2 -0
- package/dist/test-layout-2.d.ts.map +1 -0
- package/dist/test-layout-2.js +5 -0
- package/dist/test-layout-2.js.map +1 -0
- package/dist/test-layout.d.ts +2 -0
- package/dist/test-layout.d.ts.map +1 -0
- package/dist/test-layout.js +7 -0
- package/dist/test-layout.js.map +1 -0
- package/dist/theme.d.ts +1 -2
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +5 -9
- package/dist/theme.js.map +1 -1
- package/dist/utils/run-command.d.ts +1 -1
- package/dist/utils/run-command.d.ts.map +1 -1
- package/dist/utils/run-command.js +27 -7
- package/dist/utils/run-command.js.map +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +44 -23
- package/dist/utils.js.map +1 -1
- package/dist/watcher.d.ts.map +1 -1
- package/dist/watcher.js +24 -4
- package/dist/watcher.js.map +1 -1
- package/package.json +14 -12
- package/src/action-utils.tsx +10 -0
- package/src/apis/cache.test.ts +35 -3
- package/src/apis/cache.tsx +184 -59
- package/src/apis/clipboard.tsx +5 -0
- package/src/apis/oauth.tsx +33 -4
- package/src/build.tsx +35 -58
- package/src/cli.tsx +156 -134
- package/src/compile.tsx +6 -3
- package/src/compile.vitest.tsx +33 -15
- package/src/components/actions.tsx +230 -99
- package/src/components/alert.tsx +11 -10
- package/src/components/animation-tick.tsx +1 -1
- package/src/components/detail.tsx +56 -151
- package/src/components/dropdown.tsx +70 -36
- package/src/components/footer.tsx +58 -33
- package/src/components/form/checkbox.tsx +30 -32
- package/src/components/form/date-picker.tsx +27 -47
- package/src/components/form/description.tsx +19 -18
- package/src/components/form/dropdown.tsx +95 -103
- package/src/components/form/file-autocomplete.tsx +9 -8
- package/src/components/form/file-picker.tsx +46 -46
- package/src/components/form/form-end.tsx +6 -4
- package/src/components/form/index.tsx +38 -48
- package/src/components/form/password-field.tsx +25 -27
- package/src/components/form/separator.tsx +3 -2
- package/src/components/form/tagpicker.tsx +2 -1
- package/src/components/form/text-area.tsx +25 -30
- package/src/components/form/text-field.tsx +25 -27
- package/src/components/form/use-form-navigation.tsx +4 -5
- package/src/components/form/with-left-border.tsx +48 -10
- package/src/components/icon.tsx +69 -0
- package/src/components/image.tsx +60 -7
- package/src/components/list.tsx +270 -202
- package/src/components/loading-bar.tsx +4 -3
- package/src/components/metadata.tsx +217 -0
- package/src/components/theme-picker.tsx +3 -2
- package/src/examples/actions-context.tsx +63 -0
- package/src/examples/actions-context.vitest.tsx +110 -0
- package/src/examples/actions-dialog-layout.vitest.tsx +2 -1
- package/src/examples/file-autocomplete.vitest.tsx +15 -15
- package/src/examples/form-basic.tsx +12 -0
- package/src/examples/form-basic.vitest.tsx +74 -74
- package/src/examples/form-dropdown.tsx +8 -0
- package/src/examples/form-dropdown.vitest.tsx +364 -421
- package/src/examples/form-tagpicker.vitest.tsx +56 -54
- package/src/examples/github.vitest.tsx +252 -0
- package/src/examples/internal/rhf-custom-ref.tsx +16 -15
- package/src/examples/internal/scrollbox-with-descendants.tsx +4 -2
- package/src/examples/internal/simple-dialog.tsx +1 -1
- package/src/examples/internal/simple-scrollbox.vitest.tsx +14 -9
- package/src/examples/list-controlled-search.tsx +28 -0
- package/src/examples/list-controlled-search.vitest.tsx +49 -0
- package/src/examples/list-detail-metadata.tsx +8 -5
- package/src/examples/list-detail-metadata.vitest.tsx +22 -22
- package/src/examples/list-dropdown-default.vitest.tsx +12 -12
- package/src/examples/list-scrollbox.vitest.tsx +52 -38
- package/src/examples/list-with-detail.vitest.tsx +45 -41
- package/src/examples/list-with-dropdown.vitest.tsx +5 -5
- package/src/examples/list-with-sections.vitest.tsx +65 -12
- package/src/examples/list-with-toast.vitest.tsx +4 -4
- package/src/examples/simple-file-picker.vitest.tsx +12 -12
- package/src/examples/simple-grid.vitest.tsx +53 -53
- package/src/examples/simple-image-mask.tsx +58 -0
- package/src/examples/simple-navigation.vitest.tsx +19 -19
- package/src/examples/store.vitest.tsx +1 -1
- package/src/examples/swift-extension.vitest.tsx +4 -2
- package/src/examples/synonyms.vitest.tsx +31 -9
- package/src/examples/toast-action.vitest.tsx +8 -8
- package/src/examples/toast-variations.tsx +1 -1
- package/src/examples/toast-variations.vitest.tsx +69 -134
- package/src/extensions/dev.tsx +3 -2
- package/src/extensions/dev.vitest.tsx +65 -28
- package/src/extensions/react-refresh-init.tsx +4 -3
- package/src/index.tsx +3 -1
- package/src/internal/date-picker-widget.tsx +2 -1
- package/src/internal/dialog.tsx +100 -28
- package/src/internal/navigation.tsx +8 -1
- package/src/internal/offscreen.tsx +10 -0
- package/src/internal/providers.tsx +34 -8
- package/src/internal/scrollbox.tsx +4 -2
- package/src/logger.tsx +4 -0
- package/src/preload.tsx +5 -17
- package/src/state.tsx +12 -0
- package/src/theme.tsx +6 -9
- package/src/utils/run-command.tsx +32 -8
- package/src/utils.tsx +58 -23
- package/src/watcher.tsx +26 -6
|
@@ -6,8 +6,8 @@ import React, {
|
|
|
6
6
|
useMemo,
|
|
7
7
|
useLayoutEffect,
|
|
8
8
|
} from 'react'
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { createPortal, useRenderer } from '@opentui/react'
|
|
10
|
+
import { useTheme } from 'termcast/src/theme'
|
|
11
11
|
import {
|
|
12
12
|
copyToClipboard,
|
|
13
13
|
openInBrowser,
|
|
@@ -22,15 +22,15 @@ import { Dropdown } from 'termcast/src/components/dropdown'
|
|
|
22
22
|
import { ExtensionPreferences } from 'termcast/src/components/extension-preferences'
|
|
23
23
|
import { ThemePicker } from 'termcast/src/components/theme-picker'
|
|
24
24
|
import { useStore } from 'termcast/src/state'
|
|
25
|
-
import {
|
|
26
|
-
import { useIsOffscreen } from 'termcast/src/internal/offscreen'
|
|
25
|
+
import { InFocus } from 'termcast/src/internal/focus-context'
|
|
26
|
+
import { Onscreen, useIsOffscreen } from 'termcast/src/internal/offscreen'
|
|
27
27
|
import { CommonProps } from 'termcast/src/utils'
|
|
28
28
|
import type {
|
|
29
|
-
KeyboardShortcut,
|
|
30
29
|
KeyboardKeyEquivalent,
|
|
31
30
|
KeyboardKeyModifier,
|
|
32
31
|
} from 'termcast/src/keyboard'
|
|
33
32
|
import { showToast, Toast } from 'termcast/src/apis/toast'
|
|
33
|
+
import { Clipboard } from 'termcast/src/apis/clipboard'
|
|
34
34
|
import { createDescendants } from 'termcast/src/descendants'
|
|
35
35
|
import { useFormSubmit } from 'termcast/src/components/form/index'
|
|
36
36
|
import { logger } from '../logger'
|
|
@@ -155,10 +155,13 @@ interface PickDateProps extends Omit<ActionProps, 'onAction'> {
|
|
|
155
155
|
onPick?: (date: Date | null) => void
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
// Create descendants for Actions -
|
|
158
|
+
// Create descendants for Actions - includes all data needed for display
|
|
159
159
|
interface ActionDescendant {
|
|
160
160
|
title: string
|
|
161
|
+
icon?: string | null
|
|
161
162
|
shortcut?: { modifiers?: KeyboardKeyModifier[]; key: KeyboardKeyEquivalent } | null
|
|
163
|
+
style?: ActionStyle
|
|
164
|
+
sectionTitle?: string
|
|
162
165
|
execute: () => void
|
|
163
166
|
}
|
|
164
167
|
|
|
@@ -168,7 +171,7 @@ const {
|
|
|
168
171
|
useDescendant: useActionDescendant,
|
|
169
172
|
} = createDescendants<ActionDescendant>()
|
|
170
173
|
|
|
171
|
-
// Context for ActionPanel
|
|
174
|
+
// Context for ActionPanel - provides section info to child actions
|
|
172
175
|
interface ActionPanelContextValue {
|
|
173
176
|
currentSection?: string
|
|
174
177
|
}
|
|
@@ -176,10 +179,16 @@ interface ActionPanelContextValue {
|
|
|
176
179
|
const ActionPanelContext = createContext<ActionPanelContextValue>({})
|
|
177
180
|
|
|
178
181
|
const Action: ActionType = (props) => {
|
|
179
|
-
|
|
182
|
+
const theme = useTheme()
|
|
183
|
+
const { currentSection } = useContext(ActionPanelContext)
|
|
184
|
+
|
|
185
|
+
// Register as descendant with execute function - captures all data including section
|
|
180
186
|
useActionDescendant({
|
|
181
|
-
title: props.title,
|
|
187
|
+
title: props.title || 'View',
|
|
188
|
+
icon: props.icon,
|
|
182
189
|
shortcut: props.shortcut,
|
|
190
|
+
style: props.style,
|
|
191
|
+
sectionTitle: currentSection,
|
|
183
192
|
execute: () => props.onAction?.(),
|
|
184
193
|
})
|
|
185
194
|
|
|
@@ -192,7 +201,7 @@ const Action: ActionType = (props) => {
|
|
|
192
201
|
value={props.title}
|
|
193
202
|
icon={props.icon}
|
|
194
203
|
label={formatShortcut(props.shortcut)}
|
|
195
|
-
color={isDestructive ?
|
|
204
|
+
color={isDestructive ? theme.error : undefined}
|
|
196
205
|
/>
|
|
197
206
|
)
|
|
198
207
|
}
|
|
@@ -200,17 +209,20 @@ const Action: ActionType = (props) => {
|
|
|
200
209
|
Action.Style = ActionStyle
|
|
201
210
|
|
|
202
211
|
Action.Push = (props) => {
|
|
203
|
-
const
|
|
212
|
+
const { push } = useNavigation()
|
|
213
|
+
const { currentSection } = useContext(ActionPanelContext)
|
|
204
214
|
|
|
205
215
|
// Register as descendant with execute function
|
|
206
216
|
useActionDescendant({
|
|
207
|
-
title: props.title,
|
|
217
|
+
title: props.title || 'Navigate',
|
|
218
|
+
icon: props.icon,
|
|
208
219
|
shortcut: props.shortcut,
|
|
220
|
+
sectionTitle: currentSection,
|
|
209
221
|
execute: () => {
|
|
210
222
|
props.onPush?.()
|
|
211
|
-
// Push the target to
|
|
223
|
+
// Push the target to navigation stack
|
|
212
224
|
if (props.target) {
|
|
213
|
-
|
|
225
|
+
push(props.target)
|
|
214
226
|
}
|
|
215
227
|
},
|
|
216
228
|
})
|
|
@@ -227,10 +239,14 @@ Action.Push = (props) => {
|
|
|
227
239
|
}
|
|
228
240
|
|
|
229
241
|
Action.CopyToClipboard = (props) => {
|
|
242
|
+
const { currentSection } = useContext(ActionPanelContext)
|
|
243
|
+
|
|
230
244
|
// Register as descendant with execute function
|
|
231
245
|
useActionDescendant({
|
|
232
|
-
title: props.title,
|
|
246
|
+
title: props.title || 'Copy to clipboard',
|
|
247
|
+
icon: props.icon,
|
|
233
248
|
shortcut: props.shortcut,
|
|
249
|
+
sectionTitle: currentSection,
|
|
234
250
|
execute: () => {
|
|
235
251
|
copyToClipboard(props.content, props.concealed)
|
|
236
252
|
props.onCopy?.(props.content)
|
|
@@ -260,10 +276,14 @@ Action.CopyToClipboard = (props) => {
|
|
|
260
276
|
}
|
|
261
277
|
|
|
262
278
|
Action.OpenInBrowser = (props) => {
|
|
279
|
+
const { currentSection } = useContext(ActionPanelContext)
|
|
280
|
+
|
|
263
281
|
// Register as descendant with execute function
|
|
264
282
|
useActionDescendant({
|
|
265
|
-
title: props.title,
|
|
283
|
+
title: props.title || 'Open in Browser',
|
|
284
|
+
icon: props.icon,
|
|
266
285
|
shortcut: props.shortcut,
|
|
286
|
+
sectionTitle: currentSection,
|
|
267
287
|
execute: () => {
|
|
268
288
|
openInBrowser(props.url)
|
|
269
289
|
props.onOpen?.(props.url)
|
|
@@ -278,8 +298,7 @@ Action.OpenInBrowser = (props) => {
|
|
|
278
298
|
// Render as Dropdown.Item (handles offscreen check internally)
|
|
279
299
|
return (
|
|
280
300
|
<Dropdown.Item
|
|
281
|
-
title={props.title}
|
|
282
|
-
value={props.title}
|
|
301
|
+
title={props.title || 'Open in Browser'}
|
|
283
302
|
icon={props.icon}
|
|
284
303
|
label={formatShortcut(props.shortcut)}
|
|
285
304
|
/>
|
|
@@ -287,10 +306,14 @@ Action.OpenInBrowser = (props) => {
|
|
|
287
306
|
}
|
|
288
307
|
|
|
289
308
|
Action.Open = (props) => {
|
|
309
|
+
const { currentSection } = useContext(ActionPanelContext)
|
|
310
|
+
|
|
290
311
|
// Register as descendant with execute function
|
|
291
312
|
useActionDescendant({
|
|
292
|
-
title: props.title,
|
|
313
|
+
title: props.title || 'Open',
|
|
314
|
+
icon: props.icon,
|
|
293
315
|
shortcut: props.shortcut,
|
|
316
|
+
sectionTitle: currentSection,
|
|
294
317
|
execute: () => {
|
|
295
318
|
openFile(props.target, props.application)
|
|
296
319
|
props.onOpen?.(props.target)
|
|
@@ -315,10 +338,14 @@ Action.Open = (props) => {
|
|
|
315
338
|
}
|
|
316
339
|
|
|
317
340
|
Action.Paste = (props) => {
|
|
341
|
+
const { currentSection } = useContext(ActionPanelContext)
|
|
342
|
+
|
|
318
343
|
// Register as descendant with execute function
|
|
319
344
|
useActionDescendant({
|
|
320
|
-
title: props.title,
|
|
345
|
+
title: props.title || 'Paste',
|
|
346
|
+
icon: props.icon,
|
|
321
347
|
shortcut: props.shortcut,
|
|
348
|
+
sectionTitle: currentSection,
|
|
322
349
|
execute: () => {
|
|
323
350
|
pasteContent(props.content)
|
|
324
351
|
props.onPaste?.(props.content)
|
|
@@ -345,10 +372,14 @@ Action.Paste = (props) => {
|
|
|
345
372
|
}
|
|
346
373
|
|
|
347
374
|
Action.ShowInFinder = (props) => {
|
|
375
|
+
const { currentSection } = useContext(ActionPanelContext)
|
|
376
|
+
|
|
348
377
|
// Register as descendant with execute function
|
|
349
378
|
useActionDescendant({
|
|
350
379
|
title: props.title || 'Show in Finder',
|
|
380
|
+
icon: props.icon,
|
|
351
381
|
shortcut: props.shortcut,
|
|
382
|
+
sectionTitle: currentSection,
|
|
352
383
|
execute: () => {
|
|
353
384
|
showInFinder(props.path)
|
|
354
385
|
props.onShow?.(props.path)
|
|
@@ -372,10 +403,14 @@ Action.ShowInFinder = (props) => {
|
|
|
372
403
|
}
|
|
373
404
|
|
|
374
405
|
Action.OpenWith = (props) => {
|
|
406
|
+
const { currentSection } = useContext(ActionPanelContext)
|
|
407
|
+
|
|
375
408
|
// Register as descendant with execute function
|
|
376
409
|
useActionDescendant({
|
|
377
410
|
title: props.title || `Open with ${props.application}`,
|
|
411
|
+
icon: props.icon,
|
|
378
412
|
shortcut: props.shortcut,
|
|
413
|
+
sectionTitle: currentSection,
|
|
379
414
|
execute: () => {
|
|
380
415
|
openFile(props.path, props.application)
|
|
381
416
|
props.onOpen?.(props.path)
|
|
@@ -400,11 +435,15 @@ Action.OpenWith = (props) => {
|
|
|
400
435
|
|
|
401
436
|
Action.Trash = (props) => {
|
|
402
437
|
const paths = Array.isArray(props.paths) ? props.paths : [props.paths]
|
|
438
|
+
const { currentSection } = useContext(ActionPanelContext)
|
|
403
439
|
|
|
404
440
|
// Register as descendant with execute function
|
|
405
441
|
useActionDescendant({
|
|
406
442
|
title: props.title || 'Move to Trash',
|
|
443
|
+
icon: props.icon,
|
|
407
444
|
shortcut: props.shortcut,
|
|
445
|
+
style: ActionStyle.Destructive,
|
|
446
|
+
sectionTitle: currentSection,
|
|
408
447
|
execute: async () => {
|
|
409
448
|
for (const path of paths) {
|
|
410
449
|
await moveToTrash(path)
|
|
@@ -431,6 +470,7 @@ Action.Trash = (props) => {
|
|
|
431
470
|
|
|
432
471
|
Action.SubmitForm = (props) => {
|
|
433
472
|
const dialog = useDialog()
|
|
473
|
+
const { currentSection } = useContext(ActionPanelContext)
|
|
434
474
|
|
|
435
475
|
// Get form context - will be null if not in a form
|
|
436
476
|
const formContext = useFormSubmit()
|
|
@@ -438,7 +478,9 @@ Action.SubmitForm = (props) => {
|
|
|
438
478
|
// Register as descendant with execute function
|
|
439
479
|
useActionDescendant({
|
|
440
480
|
title: props.title || 'Submit',
|
|
481
|
+
icon: props.icon,
|
|
441
482
|
shortcut: props.shortcut || { modifiers: ['cmd'], key: 'return' },
|
|
483
|
+
sectionTitle: currentSection,
|
|
442
484
|
execute: () => {
|
|
443
485
|
if (formContext) {
|
|
444
486
|
// Also call the onSubmit if provided
|
|
@@ -467,10 +509,14 @@ Action.SubmitForm = (props) => {
|
|
|
467
509
|
}
|
|
468
510
|
|
|
469
511
|
Action.CreateSnippet = (props) => {
|
|
512
|
+
const { currentSection } = useContext(ActionPanelContext)
|
|
513
|
+
|
|
470
514
|
// Register as descendant with execute function
|
|
471
515
|
useActionDescendant({
|
|
472
516
|
title: props.title || 'Create Snippet',
|
|
517
|
+
icon: props.icon,
|
|
473
518
|
shortcut: props.shortcut,
|
|
519
|
+
sectionTitle: currentSection,
|
|
474
520
|
execute: () => {
|
|
475
521
|
// TODO: Navigate to Create Snippet command when extension system is implemented
|
|
476
522
|
logger.log(
|
|
@@ -497,10 +543,14 @@ Action.CreateSnippet = (props) => {
|
|
|
497
543
|
}
|
|
498
544
|
|
|
499
545
|
Action.CreateQuicklink = (props) => {
|
|
546
|
+
const { currentSection } = useContext(ActionPanelContext)
|
|
547
|
+
|
|
500
548
|
// Register as descendant with execute function
|
|
501
549
|
useActionDescendant({
|
|
502
550
|
title: props.title || 'Create Quicklink',
|
|
551
|
+
icon: props.icon,
|
|
503
552
|
shortcut: props.shortcut,
|
|
553
|
+
sectionTitle: currentSection,
|
|
504
554
|
execute: () => {
|
|
505
555
|
// TODO: Navigate to Create Quicklink command when extension system is implemented
|
|
506
556
|
logger.log(
|
|
@@ -527,10 +577,14 @@ Action.CreateQuicklink = (props) => {
|
|
|
527
577
|
}
|
|
528
578
|
|
|
529
579
|
Action.ToggleQuickLook = (props) => {
|
|
580
|
+
const { currentSection } = useContext(ActionPanelContext)
|
|
581
|
+
|
|
530
582
|
// Register as descendant with execute function
|
|
531
583
|
useActionDescendant({
|
|
532
584
|
title: props.title || 'Quick Look',
|
|
585
|
+
icon: props.icon,
|
|
533
586
|
shortcut: props.shortcut || { key: 'space' },
|
|
587
|
+
sectionTitle: currentSection,
|
|
534
588
|
execute: async () => {
|
|
535
589
|
if (!props.path) {
|
|
536
590
|
props.onToggle?.()
|
|
@@ -569,10 +623,14 @@ Action.ToggleQuickLook = (props) => {
|
|
|
569
623
|
}
|
|
570
624
|
|
|
571
625
|
Action.PickDate = (props) => {
|
|
626
|
+
const { currentSection } = useContext(ActionPanelContext)
|
|
627
|
+
|
|
572
628
|
// Register as descendant with execute function
|
|
573
629
|
useActionDescendant({
|
|
574
630
|
title: props.title || 'Pick Date',
|
|
631
|
+
icon: props.icon,
|
|
575
632
|
shortcut: props.shortcut,
|
|
633
|
+
sectionTitle: currentSection,
|
|
576
634
|
execute: () => {
|
|
577
635
|
// TODO: Show date picker dialog when implemented
|
|
578
636
|
logger.log(`Picking ${props.type || 'date'}`)
|
|
@@ -643,13 +701,32 @@ function formatShortcut(
|
|
|
643
701
|
.join('')
|
|
644
702
|
}
|
|
645
703
|
|
|
704
|
+
/**
|
|
705
|
+
* ActionPanel uses React portals to render its dialog content in the overlay
|
|
706
|
+
* area while staying in the original React tree. This preserves all React
|
|
707
|
+
* context (FormSubmitContext, NavigationContext, etc.) because portals inherit
|
|
708
|
+
* context from the source tree, not the portal target.
|
|
709
|
+
*
|
|
710
|
+
* Flow:
|
|
711
|
+
* 1. ActionPanel is rendered offscreen via <Offscreen> in List/Detail/Form
|
|
712
|
+
* 2. Action children register as descendants (title, icon, shortcut, execute)
|
|
713
|
+
* 3. A useLayoutEffect captures the first action title for footer display
|
|
714
|
+
* 4. When showActionsDialog is true, ActionPanel renders a Dropdown via
|
|
715
|
+
* createPortal into the overlay target (provided by DialogOverlay)
|
|
716
|
+
* 5. The Dropdown and all callbacks have fresh context from the original tree
|
|
717
|
+
*/
|
|
646
718
|
const ActionPanel: ActionPanelType = (props) => {
|
|
647
719
|
const { children, title } = props
|
|
648
720
|
const dialog = useDialog()
|
|
649
721
|
const { push } = useNavigation()
|
|
650
|
-
const inFocus = useIsInFocus()
|
|
651
|
-
const isOffscreen = useIsOffscreen()
|
|
652
722
|
const descendantsContext = useActionDescendants()
|
|
723
|
+
const renderer = useRenderer()
|
|
724
|
+
const isOffscreen = useIsOffscreen()
|
|
725
|
+
|
|
726
|
+
const showActionsDialog = useStore((state) => state.showActionsDialog)
|
|
727
|
+
const portalTarget = useStore((state) => state.actionsPortalTarget)
|
|
728
|
+
// Subscribe so a re-render + layout effect fires when Enter sets this flag
|
|
729
|
+
const shouldAutoExecute = useStore((state) => state.shouldAutoExecuteFirstAction)
|
|
653
730
|
|
|
654
731
|
// Get extension and command info for configure actions
|
|
655
732
|
const extensionPackageJson = useStore((state) => state.extensionPackageJson)
|
|
@@ -668,96 +745,150 @@ const ActionPanel: ActionPanelType = (props) => {
|
|
|
668
745
|
[],
|
|
669
746
|
)
|
|
670
747
|
|
|
671
|
-
//
|
|
672
|
-
//
|
|
748
|
+
// Capture first action title for footer display, and handle auto-execute.
|
|
749
|
+
// Runs after every render so descendant props are always fresh.
|
|
673
750
|
useLayoutEffect(() => {
|
|
674
751
|
const allActions = Object.values(descendantsContext.map.current)
|
|
675
752
|
.filter((item: any) => item.index !== -1)
|
|
676
|
-
.
|
|
753
|
+
.sort((a: any, b: any) => a.index - b.index)
|
|
677
754
|
|
|
678
|
-
|
|
679
|
-
if (
|
|
680
|
-
useStore.setState({ firstActionTitle
|
|
681
|
-
return
|
|
755
|
+
const firstActionTitle = allActions[0]?.props?.title ?? ''
|
|
756
|
+
if (useStore.getState().firstActionTitle !== firstActionTitle) {
|
|
757
|
+
useStore.setState({ firstActionTitle })
|
|
682
758
|
}
|
|
683
759
|
|
|
684
|
-
|
|
685
|
-
|
|
760
|
+
// Auto-execute first action when Enter was pressed (shouldAutoExecuteFirstAction flag)
|
|
761
|
+
if (shouldAutoExecute) {
|
|
762
|
+
useStore.setState({ shouldAutoExecuteFirstAction: false, showActionsDialog: false })
|
|
763
|
+
const firstAction = allActions[0]?.props as ActionDescendant | undefined
|
|
764
|
+
if (firstAction) {
|
|
765
|
+
logger.log(`Auto-executing first action: ${firstAction.title}`)
|
|
766
|
+
firstAction.execute()
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
})
|
|
686
770
|
|
|
687
|
-
|
|
771
|
+
// Keep offscreen registration lightweight for fast initial command startup.
|
|
772
|
+
// We only need descendants for footer title + auto-execute; rendering the full
|
|
773
|
+
// Dropdown tree offscreen adds avoidable mount work before first paint.
|
|
774
|
+
const offscreenRegistrationTree = (
|
|
775
|
+
<ActionDescendantsProvider value={descendantsContext}>
|
|
776
|
+
<ActionPanelContext.Provider value={contextValue}>
|
|
777
|
+
{children}
|
|
778
|
+
</ActionPanelContext.Provider>
|
|
779
|
+
</ActionDescendantsProvider>
|
|
780
|
+
)
|
|
688
781
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
782
|
+
// Always render the full Dropdown tree when actions are visible so Action
|
|
783
|
+
// children stay mounted and descendants are always registered.
|
|
784
|
+
// descendants are always registered. The Dropdown handles offscreen mode
|
|
785
|
+
// internally (returns null for visual output when isOffscreen is true).
|
|
786
|
+
// When showActionsDialog is true, we portal into the DialogOverlay's content
|
|
787
|
+
// target so the dialog shell and z-order are managed in one place.
|
|
788
|
+
const dropdownTree = (
|
|
789
|
+
<Dropdown
|
|
790
|
+
tooltip={title || 'Actions'}
|
|
791
|
+
placeholder='Search actions...'
|
|
792
|
+
filtering
|
|
793
|
+
onChange={(value) => {
|
|
794
|
+
logger.log(`actions dropdown onChange`, value)
|
|
795
|
+
// Find and execute the selected action from live descendants
|
|
796
|
+
const allActions = Object.values(descendantsContext.map.current)
|
|
797
|
+
.filter((item: any) => item.index !== -1)
|
|
798
|
+
.map((item: any) => item.props as ActionDescendant)
|
|
799
|
+
|
|
800
|
+
const action = allActions.find((a) => a.title === value)
|
|
801
|
+
if (action) {
|
|
802
|
+
useStore.setState({ showActionsDialog: false, dialogStack: [] })
|
|
803
|
+
action.execute()
|
|
804
|
+
}
|
|
805
|
+
}}
|
|
806
|
+
>
|
|
807
|
+
{children}
|
|
808
|
+
<ActionPanel.Section title="Settings">
|
|
809
|
+
{hasExtensionPrefs && (
|
|
810
|
+
<Action
|
|
811
|
+
title={`Configure ${extensionPackageJson!.title}...`}
|
|
812
|
+
shortcut={{ modifiers: ['cmd', 'shift'], key: ',' }}
|
|
813
|
+
onAction={() => {
|
|
814
|
+
useStore.setState({ showActionsDialog: false })
|
|
815
|
+
push(
|
|
816
|
+
<ExtensionPreferences
|
|
817
|
+
extensionName={extensionPackageJson!.name}
|
|
818
|
+
/>,
|
|
819
|
+
)
|
|
820
|
+
}}
|
|
821
|
+
/>
|
|
822
|
+
)}
|
|
823
|
+
{hasCommandPrefs && (
|
|
824
|
+
<Action
|
|
825
|
+
title="Configure Command..."
|
|
826
|
+
onAction={() => {
|
|
827
|
+
useStore.setState({ showActionsDialog: false })
|
|
828
|
+
push(
|
|
829
|
+
<ExtensionPreferences
|
|
830
|
+
extensionName={extensionPackageJson!.name}
|
|
831
|
+
commandName={currentCommandName!}
|
|
832
|
+
/>,
|
|
833
|
+
)
|
|
834
|
+
}}
|
|
835
|
+
/>
|
|
836
|
+
)}
|
|
837
|
+
<Action
|
|
838
|
+
title="Change Theme..."
|
|
839
|
+
onAction={() => {
|
|
840
|
+
useStore.setState({ showActionsDialog: false })
|
|
841
|
+
dialog.push({ element: <ThemePicker /> })
|
|
842
|
+
}}
|
|
843
|
+
/>
|
|
844
|
+
<Action
|
|
845
|
+
title="See Console Logs"
|
|
846
|
+
onAction={() => {
|
|
847
|
+
useStore.setState({ showActionsDialog: false })
|
|
848
|
+
if (renderer) {
|
|
849
|
+
renderer.console.onCopySelection = (text: any) => {
|
|
850
|
+
Clipboard.copy(text)
|
|
851
|
+
}
|
|
852
|
+
renderer.toggleDebugOverlay()
|
|
853
|
+
renderer.console.toggle()
|
|
854
|
+
}
|
|
855
|
+
}}
|
|
856
|
+
/>
|
|
857
|
+
</ActionPanel.Section>
|
|
858
|
+
</Dropdown>
|
|
859
|
+
)
|
|
695
860
|
|
|
696
|
-
//
|
|
697
|
-
|
|
698
|
-
|
|
861
|
+
// When dialog is active and portal target exists, render the Dropdown in
|
|
862
|
+
// a portal. The portal inherits React context from the source tree, which
|
|
863
|
+
// preserves FormSubmitContext, custom contexts, etc.
|
|
864
|
+
// Onscreen resets the OffscreenContext (since we're portaled from an offscreen
|
|
865
|
+
// tree into a visible overlay), so the Dropdown renders its items normally.
|
|
866
|
+
if (showActionsDialog && portalTarget) {
|
|
867
|
+
return createPortal(
|
|
868
|
+
<Onscreen>
|
|
869
|
+
<InFocus inFocus={true}>
|
|
870
|
+
<ActionDescendantsProvider value={descendantsContext}>
|
|
871
|
+
<ActionPanelContext.Provider value={contextValue}>
|
|
872
|
+
{dropdownTree}
|
|
873
|
+
</ActionPanelContext.Provider>
|
|
874
|
+
</ActionDescendantsProvider>
|
|
875
|
+
</InFocus>
|
|
876
|
+
</Onscreen>,
|
|
877
|
+
portalTarget,
|
|
878
|
+
null,
|
|
879
|
+
)
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
if (isOffscreen) {
|
|
883
|
+
return offscreenRegistrationTree
|
|
884
|
+
}
|
|
699
885
|
|
|
700
|
-
//
|
|
886
|
+
// When not showing dialog, render the tree inline (offscreen) so descendants
|
|
887
|
+
// register and first action title is captured for the footer.
|
|
701
888
|
return (
|
|
702
889
|
<ActionDescendantsProvider value={descendantsContext}>
|
|
703
890
|
<ActionPanelContext.Provider value={contextValue}>
|
|
704
|
-
|
|
705
|
-
tooltip={title || 'Actions'}
|
|
706
|
-
placeholder='Search actions...'
|
|
707
|
-
filtering
|
|
708
|
-
onChange={(value) => {
|
|
709
|
-
logger.log(`actions dropdown onChange`, value)
|
|
710
|
-
// Find and execute the selected action
|
|
711
|
-
const allActions = Object.values(descendantsContext.map.current)
|
|
712
|
-
.filter((item: any) => item.index !== -1)
|
|
713
|
-
.map((item: any) => item.props as ActionDescendant)
|
|
714
|
-
|
|
715
|
-
const action = allActions.find((a) => a.title === value)
|
|
716
|
-
if (action) {
|
|
717
|
-
dialog.clear()
|
|
718
|
-
action.execute()
|
|
719
|
-
}
|
|
720
|
-
}}
|
|
721
|
-
>
|
|
722
|
-
{children}
|
|
723
|
-
<ActionPanel.Section title="Settings">
|
|
724
|
-
{hasExtensionPrefs && (
|
|
725
|
-
<Action
|
|
726
|
-
title={`Configure ${extensionPackageJson!.title}...`}
|
|
727
|
-
shortcut={{ modifiers: ['cmd', 'shift'], key: ',' }}
|
|
728
|
-
onAction={() => {
|
|
729
|
-
dialog.clear()
|
|
730
|
-
push(
|
|
731
|
-
<ExtensionPreferences
|
|
732
|
-
extensionName={extensionPackageJson!.name}
|
|
733
|
-
/>,
|
|
734
|
-
)
|
|
735
|
-
}}
|
|
736
|
-
/>
|
|
737
|
-
)}
|
|
738
|
-
{hasCommandPrefs && (
|
|
739
|
-
<Action
|
|
740
|
-
title="Configure Command..."
|
|
741
|
-
onAction={() => {
|
|
742
|
-
dialog.clear()
|
|
743
|
-
push(
|
|
744
|
-
<ExtensionPreferences
|
|
745
|
-
extensionName={extensionPackageJson!.name}
|
|
746
|
-
commandName={currentCommandName!}
|
|
747
|
-
/>,
|
|
748
|
-
)
|
|
749
|
-
}}
|
|
750
|
-
/>
|
|
751
|
-
)}
|
|
752
|
-
<Action
|
|
753
|
-
title="Change Theme..."
|
|
754
|
-
onAction={() => {
|
|
755
|
-
dialog.clear()
|
|
756
|
-
dialog.push({ element: <ThemePicker /> })
|
|
757
|
-
}}
|
|
758
|
-
/>
|
|
759
|
-
</ActionPanel.Section>
|
|
760
|
-
</Dropdown>
|
|
891
|
+
{dropdownTree}
|
|
761
892
|
</ActionPanelContext.Provider>
|
|
762
893
|
</ActionDescendantsProvider>
|
|
763
894
|
)
|
package/src/components/alert.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
2
|
import { useKeyboard } from '@opentui/react'
|
|
3
|
-
import {
|
|
3
|
+
import { useTheme } from 'termcast/src/theme'
|
|
4
4
|
import { TextAttributes } from '@opentui/core'
|
|
5
5
|
import { LocalStorage } from 'termcast/src/apis/localstorage'
|
|
6
6
|
import { useStore } from 'termcast/src/state'
|
|
@@ -44,6 +44,7 @@ function AlertComponent({
|
|
|
44
44
|
onConfirm,
|
|
45
45
|
onDismiss,
|
|
46
46
|
}: AlertComponentProps): any {
|
|
47
|
+
const theme = useTheme()
|
|
47
48
|
const [rememberChoice, setRememberChoice] = useState(false)
|
|
48
49
|
const inFocus = useIsInFocus()
|
|
49
50
|
|
|
@@ -73,18 +74,18 @@ function AlertComponent({
|
|
|
73
74
|
const getPrimaryColor = () => {
|
|
74
75
|
switch (primaryStyle) {
|
|
75
76
|
case Alert.ActionStyle.Destructive:
|
|
76
|
-
return
|
|
77
|
+
return theme.error
|
|
77
78
|
case Alert.ActionStyle.Default:
|
|
78
79
|
default:
|
|
79
|
-
return
|
|
80
|
+
return theme.primary
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
return (
|
|
84
85
|
<box
|
|
85
86
|
border
|
|
86
|
-
borderColor={
|
|
87
|
-
backgroundColor={
|
|
87
|
+
borderColor={theme.border}
|
|
88
|
+
backgroundColor={theme.backgroundPanel}
|
|
88
89
|
paddingTop={2}
|
|
89
90
|
paddingBottom={2}
|
|
90
91
|
paddingLeft={3}
|
|
@@ -94,17 +95,17 @@ function AlertComponent({
|
|
|
94
95
|
<box flexDirection='column' alignItems='center'>
|
|
95
96
|
{options.icon && (
|
|
96
97
|
<box marginBottom={1}>
|
|
97
|
-
<text fg={
|
|
98
|
+
<text fg={theme.accent}>⚠️</text>
|
|
98
99
|
</box>
|
|
99
100
|
)}
|
|
100
101
|
|
|
101
|
-
<text fg={
|
|
102
|
+
<text fg={theme.text} attributes={TextAttributes.BOLD}>
|
|
102
103
|
{options.title}
|
|
103
104
|
</text>
|
|
104
105
|
|
|
105
106
|
{options.message && (
|
|
106
107
|
<box marginTop={1} marginBottom={1}>
|
|
107
|
-
<text fg={
|
|
108
|
+
<text fg={theme.textMuted}>{options.message}</text>
|
|
108
109
|
</box>
|
|
109
110
|
)}
|
|
110
111
|
|
|
@@ -114,7 +115,7 @@ function AlertComponent({
|
|
|
114
115
|
marginBottom={1}
|
|
115
116
|
onMouseDown={() => setRememberChoice(!rememberChoice)}
|
|
116
117
|
>
|
|
117
|
-
<text fg={
|
|
118
|
+
<text fg={theme.textMuted} selectable={false}>
|
|
118
119
|
{rememberChoice ? '[x]' : '[ ]'} Do not show this message again
|
|
119
120
|
(Space to toggle)
|
|
120
121
|
</text>
|
|
@@ -149,7 +150,7 @@ function AlertComponent({
|
|
|
149
150
|
onDismiss()
|
|
150
151
|
}}
|
|
151
152
|
>
|
|
152
|
-
<text fg={
|
|
153
|
+
<text fg={theme.textMuted} selectable={false}>
|
|
153
154
|
[{options.dismissAction?.title || 'Cancel'} (ESC)]
|
|
154
155
|
</text>
|
|
155
156
|
</box>
|
|
@@ -80,6 +80,6 @@ export function useAnimationTick(divisor: number = 1): number {
|
|
|
80
80
|
// Waves share the same speed so they animate in sync
|
|
81
81
|
export const TICK_DIVISORS = {
|
|
82
82
|
LOADING_BAR: 2, // 40ms - wave animation
|
|
83
|
-
LOADING_TEXT:
|
|
83
|
+
LOADING_TEXT: 1, // 20ms - faster wave animation for text
|
|
84
84
|
SPINNER: 10, // 200ms - pulses every 5 wave steps
|
|
85
85
|
} as const
|