termcast 1.3.21 → 1.3.25
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/ai.d.ts +104 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +135 -0
- package/dist/ai.js.map +1 -0
- package/dist/apis/browser-extension.d.ts +18 -0
- package/dist/apis/browser-extension.d.ts.map +1 -0
- package/dist/apis/browser-extension.js +14 -0
- package/dist/apis/browser-extension.js.map +1 -0
- package/dist/apis/localstorage.d.ts.map +1 -1
- package/dist/apis/localstorage.js +4 -7
- package/dist/apis/localstorage.js.map +1 -1
- package/dist/apis/oauth.d.ts.map +1 -1
- package/dist/apis/oauth.js +5 -1
- package/dist/apis/oauth.js.map +1 -1
- package/dist/apis/preferences.d.ts.map +1 -1
- package/dist/apis/preferences.js +38 -19
- package/dist/apis/preferences.js.map +1 -1
- package/dist/apis/toast.d.ts +5 -0
- package/dist/apis/toast.d.ts.map +1 -1
- package/dist/apis/toast.js +7 -43
- package/dist/apis/toast.js.map +1 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +3 -1
- package/dist/build.js.map +1 -1
- package/dist/cache.d.ts +32 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +205 -0
- package/dist/cache.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +87 -41
- package/dist/cli.js.map +1 -1
- package/dist/clipboard.d.ts +36 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +154 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/compile.d.ts +2 -1
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +31 -12
- package/dist/compile.js.map +1 -1
- package/dist/components/actions.d.ts.map +1 -1
- package/dist/components/actions.js +56 -30
- package/dist/components/actions.js.map +1 -1
- package/dist/components/detail.d.ts.map +1 -1
- package/dist/components/detail.js +4 -0
- package/dist/components/detail.js.map +1 -1
- package/dist/components/dropdown.d.ts.map +1 -1
- package/dist/components/dropdown.js +38 -15
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/extension-preferences.d.ts.map +1 -1
- package/dist/components/extension-preferences.js +40 -13
- package/dist/components/extension-preferences.js.map +1 -1
- package/dist/components/form/checkbox.d.ts.map +1 -1
- package/dist/components/form/checkbox.js +5 -3
- 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 +5 -3
- package/dist/components/form/date-picker.js.map +1 -1
- package/dist/components/form/description.d.ts.map +1 -1
- package/dist/components/form/description.js +2 -2
- 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 +84 -80
- package/dist/components/form/dropdown.js.map +1 -1
- package/dist/components/form/file-autocomplete.d.ts +3 -6
- package/dist/components/form/file-autocomplete.d.ts.map +1 -1
- package/dist/components/form/file-autocomplete.js +61 -66
- 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 +33 -30
- 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 +21 -1
- package/dist/components/form/form-end.js.map +1 -1
- package/dist/components/form/form-type-only.d.ts +174 -0
- package/dist/components/form/form-type-only.d.ts.map +1 -0
- package/dist/components/form/form-type-only.js +2 -0
- package/dist/components/form/form-type-only.js.map +1 -0
- package/dist/components/form/index.d.ts +3 -1
- package/dist/components/form/index.d.ts.map +1 -1
- package/dist/components/form/index.js +104 -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 +5 -3
- package/dist/components/form/password-field.js.map +1 -1
- package/dist/components/form/text-area.d.ts.map +1 -1
- package/dist/components/form/text-area.js +5 -3
- 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 +6 -4
- package/dist/components/form/text-field.js.map +1 -1
- package/dist/components/form/types.d.ts +5 -0
- package/dist/components/form/types.d.ts.map +1 -1
- package/dist/components/form/use-form-handling.d.ts +4 -0
- package/dist/components/form/use-form-handling.d.ts.map +1 -0
- package/dist/components/form/use-form-handling.js +37 -0
- package/dist/components/form/use-form-handling.js.map +1 -0
- package/dist/components/form/with-left-border.d.ts +2 -1
- package/dist/components/form/with-left-border.d.ts.map +1 -1
- package/dist/components/form/with-left-border.js +27 -3
- package/dist/components/form/with-left-border.js.map +1 -1
- package/dist/components/icon.d.ts +1 -0
- package/dist/components/icon.d.ts.map +1 -1
- package/dist/components/icon.js +24 -8
- package/dist/components/icon.js.map +1 -1
- package/dist/components/list.d.ts +2 -2
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +155 -70
- package/dist/components/list.js.map +1 -1
- package/dist/components/loading-bar.d.ts.map +1 -1
- package/dist/components/loading-bar.js +2 -2
- package/dist/components/loading-bar.js.map +1 -1
- package/dist/components/loading-text.d.ts +8 -0
- package/dist/components/loading-text.d.ts.map +1 -0
- package/dist/components/loading-text.js +58 -0
- package/dist/components/loading-text.js.map +1 -0
- package/dist/descendants.js +1 -1
- package/dist/descendants.js.map +1 -1
- package/dist/dev-ui.d.ts +7 -0
- package/dist/dev-ui.d.ts.map +1 -0
- package/dist/dev-ui.js +118 -0
- package/dist/dev-ui.js.map +1 -0
- package/dist/environment.d.ts +63 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +189 -0
- package/dist/environment.js.map +1 -0
- package/dist/examples/datepicker.d.ts +2 -0
- package/dist/examples/datepicker.d.ts.map +1 -0
- package/dist/examples/datepicker.js +344 -0
- package/dist/examples/datepicker.js.map +1 -0
- package/dist/examples/file-autocomplete.vitest.d.ts +2 -0
- package/dist/examples/file-autocomplete.vitest.d.ts.map +1 -0
- package/dist/examples/file-autocomplete.vitest.js +223 -0
- package/dist/examples/file-autocomplete.vitest.js.map +1 -0
- package/dist/examples/form-basic-arrow-keys.vitest.d.ts +2 -0
- package/dist/examples/form-basic-arrow-keys.vitest.d.ts.map +1 -0
- package/dist/examples/form-basic-arrow-keys.vitest.js +46 -0
- package/dist/examples/form-basic-arrow-keys.vitest.js.map +1 -0
- package/dist/examples/form-basic.vitest.d.ts +2 -0
- package/dist/examples/form-basic.vitest.d.ts.map +1 -0
- package/dist/examples/form-basic.vitest.js +630 -0
- package/dist/examples/form-basic.vitest.js.map +1 -0
- package/dist/examples/form-dropdown-with-sections.d.ts +2 -0
- package/dist/examples/form-dropdown-with-sections.d.ts.map +1 -0
- package/dist/examples/form-dropdown-with-sections.js +13 -0
- package/dist/examples/form-dropdown-with-sections.js.map +1 -0
- package/dist/examples/form-dropdown-with-sections.vitest.d.ts +2 -0
- package/dist/examples/form-dropdown-with-sections.vitest.d.ts.map +1 -0
- package/dist/examples/form-dropdown-with-sections.vitest.js +75 -0
- package/dist/examples/form-dropdown-with-sections.vitest.js.map +1 -0
- package/dist/examples/form-dropdown.vitest.d.ts +2 -0
- package/dist/examples/form-dropdown.vitest.d.ts.map +1 -0
- package/dist/examples/form-dropdown.vitest.js +854 -0
- package/dist/examples/form-dropdown.vitest.js.map +1 -0
- package/dist/examples/form-multiselect-dropdown.d.ts +2 -0
- package/dist/examples/form-multiselect-dropdown.d.ts.map +1 -0
- package/dist/examples/form-multiselect-dropdown.js +13 -0
- package/dist/examples/form-multiselect-dropdown.js.map +1 -0
- package/dist/examples/form-scroll.d.ts.map +1 -1
- package/dist/examples/form-scroll.js +7 -1
- package/dist/examples/form-scroll.js.map +1 -1
- package/dist/examples/form-scroll.vitest.d.ts +2 -0
- package/dist/examples/form-scroll.vitest.d.ts.map +1 -0
- package/dist/examples/form-scroll.vitest.js +211 -0
- package/dist/examples/form-scroll.vitest.js.map +1 -0
- package/dist/examples/form-tagpicker.vitest.d.ts +2 -0
- package/dist/examples/form-tagpicker.vitest.d.ts.map +1 -0
- package/dist/examples/form-tagpicker.vitest.js +736 -0
- package/dist/examples/form-tagpicker.vitest.js.map +1 -0
- package/dist/examples/internal/descendants-filtering.js +1 -1
- package/dist/examples/internal/descendants-filtering.js.map +1 -1
- package/dist/examples/internal/descendants.js +1 -1
- package/dist/examples/internal/descendants.js.map +1 -1
- package/dist/examples/internal/nested-boxes.d.ts +2 -0
- package/dist/examples/internal/nested-boxes.d.ts.map +1 -0
- package/dist/examples/internal/nested-boxes.js +7 -0
- package/dist/examples/internal/nested-boxes.js.map +1 -0
- package/dist/examples/internal/rhf-custom-ref.js +2 -2
- package/dist/examples/internal/rhf-custom-ref.js.map +1 -1
- package/dist/examples/internal/scrollbox-demo.js +3 -22
- package/dist/examples/internal/scrollbox-demo.js.map +1 -1
- package/dist/examples/internal/scrollbox-descendants.d.ts +2 -0
- package/dist/examples/internal/scrollbox-descendants.d.ts.map +1 -0
- package/dist/examples/internal/scrollbox-descendants.js +83 -0
- package/dist/examples/internal/scrollbox-descendants.js.map +1 -0
- package/dist/examples/internal/scrollbox-with-descendants.js +4 -8
- package/dist/examples/internal/scrollbox-with-descendants.js.map +1 -1
- package/dist/examples/internal/simple-scrollbox.vitest.d.ts +2 -0
- package/dist/examples/internal/simple-scrollbox.vitest.d.ts.map +1 -0
- package/dist/examples/internal/simple-scrollbox.vitest.js +96 -0
- package/dist/examples/internal/simple-scrollbox.vitest.js.map +1 -0
- package/dist/examples/internal/unicode-square-repro.d.ts +2 -0
- package/dist/examples/internal/unicode-square-repro.d.ts.map +1 -0
- package/dist/examples/internal/unicode-square-repro.js +7 -0
- package/dist/examples/internal/unicode-square-repro.js.map +1 -0
- package/dist/examples/list-detail-metadata.d.ts +2 -0
- package/dist/examples/list-detail-metadata.d.ts.map +1 -0
- package/dist/examples/list-detail-metadata.js +8 -0
- package/dist/examples/list-detail-metadata.js.map +1 -0
- package/dist/examples/list-dropdown-default.vitest.d.ts +2 -0
- package/dist/examples/list-dropdown-default.vitest.d.ts.map +1 -0
- package/dist/examples/list-dropdown-default.vitest.js +234 -0
- package/dist/examples/list-dropdown-default.vitest.js.map +1 -0
- package/dist/examples/list-fetch-data.vitest.d.ts +2 -0
- package/dist/examples/list-fetch-data.vitest.d.ts.map +1 -0
- package/dist/examples/list-fetch-data.vitest.js +111 -0
- package/dist/examples/list-fetch-data.vitest.js.map +1 -0
- package/dist/examples/list-filter-navigation.d.ts +2 -0
- package/dist/examples/list-filter-navigation.d.ts.map +1 -0
- package/dist/examples/list-filter-navigation.js +8 -0
- package/dist/examples/list-filter-navigation.js.map +1 -0
- package/dist/examples/list-scrollbox.vitest.d.ts +2 -0
- package/dist/examples/list-scrollbox.vitest.d.ts.map +1 -0
- package/dist/examples/list-scrollbox.vitest.js +93 -0
- package/dist/examples/list-scrollbox.vitest.js.map +1 -0
- package/dist/examples/list-with-detail-long.d.ts +2 -0
- package/dist/examples/list-with-detail-long.d.ts.map +1 -0
- package/dist/examples/list-with-detail-long.js +53 -0
- package/dist/examples/list-with-detail-long.js.map +1 -0
- package/dist/examples/list-with-detail.vitest.d.ts +2 -0
- package/dist/examples/list-with-detail.vitest.d.ts.map +1 -0
- package/dist/examples/list-with-detail.vitest.js +434 -0
- package/dist/examples/list-with-detail.vitest.js.map +1 -0
- package/dist/examples/list-with-dropdown.vitest.d.ts +2 -0
- package/dist/examples/list-with-dropdown.vitest.d.ts.map +1 -0
- package/dist/examples/list-with-dropdown.vitest.js +337 -0
- package/dist/examples/list-with-dropdown.vitest.js.map +1 -0
- package/dist/examples/list-with-sections.js +5 -1
- package/dist/examples/list-with-sections.js.map +1 -1
- package/dist/examples/list-with-sections.vitest.d.ts +2 -0
- package/dist/examples/list-with-sections.vitest.d.ts.map +1 -0
- package/dist/examples/list-with-sections.vitest.js +601 -0
- package/dist/examples/list-with-sections.vitest.js.map +1 -0
- package/dist/examples/scrollbox-vertical-centering.d.ts +6 -0
- package/dist/examples/scrollbox-vertical-centering.d.ts.map +1 -0
- package/dist/examples/scrollbox-vertical-centering.js +17 -0
- package/dist/examples/scrollbox-vertical-centering.js.map +1 -0
- package/dist/examples/simple-file-picker.vitest.d.ts +2 -0
- package/dist/examples/simple-file-picker.vitest.d.ts.map +1 -0
- package/dist/examples/simple-file-picker.vitest.js +678 -0
- package/dist/examples/simple-file-picker.vitest.js.map +1 -0
- package/dist/examples/simple-grid.vitest.d.ts +2 -0
- package/dist/examples/simple-grid.vitest.d.ts.map +1 -0
- package/dist/examples/simple-grid.vitest.js +521 -0
- package/dist/examples/simple-grid.vitest.js.map +1 -0
- package/dist/examples/simple-navigation.js +10 -4
- package/dist/examples/simple-navigation.js.map +1 -1
- package/dist/examples/simple-navigation.vitest.d.ts +2 -0
- package/dist/examples/simple-navigation.vitest.d.ts.map +1 -0
- package/dist/examples/simple-navigation.vitest.js +718 -0
- package/dist/examples/simple-navigation.vitest.js.map +1 -0
- package/dist/examples/store.vitest.d.ts +2 -0
- package/dist/examples/store.vitest.d.ts.map +1 -0
- package/dist/examples/store.vitest.js +69 -0
- package/dist/examples/store.vitest.js.map +1 -0
- package/dist/examples/toast-variations.d.ts +2 -0
- package/dist/examples/toast-variations.d.ts.map +1 -0
- package/dist/examples/toast-variations.js +122 -0
- package/dist/examples/toast-variations.js.map +1 -0
- package/dist/extensions/dev.d.ts +4 -2
- package/dist/extensions/dev.d.ts.map +1 -1
- package/dist/extensions/dev.js +61 -10
- package/dist/extensions/dev.js.map +1 -1
- package/dist/extensions/dev.vitest.d.ts +2 -0
- package/dist/extensions/dev.vitest.d.ts.map +1 -0
- package/dist/extensions/dev.vitest.js +197 -0
- package/dist/extensions/dev.vitest.js.map +1 -0
- package/dist/extensions/home.d.ts.map +1 -1
- package/dist/extensions/home.js +3 -0
- package/dist/extensions/home.js.map +1 -1
- package/dist/home-command.d.ts +8 -0
- package/dist/home-command.d.ts.map +1 -0
- package/dist/home-command.js +181 -0
- package/dist/home-command.js.map +1 -0
- package/dist/hover-repro.d.ts +2 -0
- package/dist/hover-repro.d.ts.map +1 -0
- package/dist/hover-repro.js +20 -0
- package/dist/hover-repro.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/dialog.d.ts +1 -0
- package/dist/internal/dialog.d.ts.map +1 -1
- package/dist/internal/dialog.js +27 -18
- package/dist/internal/dialog.js.map +1 -1
- package/dist/internal/navigation.d.ts +9 -1
- package/dist/internal/navigation.d.ts.map +1 -1
- package/dist/internal/navigation.js +5 -5
- package/dist/internal/navigation.js.map +1 -1
- package/dist/internal/offscreen.d.ts +6 -0
- package/dist/internal/offscreen.d.ts.map +1 -0
- package/dist/internal/offscreen.js +10 -0
- package/dist/internal/offscreen.js.map +1 -0
- package/dist/internal/providers.d.ts.map +1 -1
- package/dist/internal/providers.js +2 -2
- package/dist/internal/providers.js.map +1 -1
- package/dist/internal/scrollbox.d.ts +1 -10
- package/dist/internal/scrollbox.d.ts.map +1 -1
- package/dist/internal/scrollbox.js +2 -1
- package/dist/internal/scrollbox.js.map +1 -1
- package/dist/localstorage.d.ts +13 -0
- package/dist/localstorage.d.ts.map +1 -0
- package/dist/localstorage.js +190 -0
- package/dist/localstorage.js.map +1 -0
- package/dist/oauth.d.ts +142 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +551 -0
- package/dist/oauth.js.map +1 -0
- package/dist/preferences.d.ts +23 -0
- package/dist/preferences.d.ts.map +1 -0
- package/dist/preferences.js +105 -0
- package/dist/preferences.js.map +1 -0
- package/dist/release.d.ts +1 -1
- package/dist/release.d.ts.map +1 -1
- package/dist/release.js +29 -33
- package/dist/release.js.map +1 -1
- package/dist/state.d.ts +2 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +3 -0
- package/dist/state.js.map +1 -1
- package/dist/store.d.ts +21 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +84 -0
- package/dist/store.js.map +1 -0
- package/dist/swift-loader.d.ts +3 -0
- package/dist/swift-loader.d.ts.map +1 -0
- package/dist/swift-loader.js +193 -0
- package/dist/swift-loader.js.map +1 -0
- package/dist/swift-runtime.d.ts +2 -0
- package/dist/swift-runtime.d.ts.map +1 -0
- package/dist/swift-runtime.js +27 -0
- package/dist/swift-runtime.js.map +1 -0
- package/dist/toast.d.ts +44 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +221 -0
- package/dist/toast.js.map +1 -0
- package/dist/utils/file-system.d.ts +9 -0
- package/dist/utils/file-system.d.ts.map +1 -1
- package/dist/utils/file-system.js +49 -0
- package/dist/utils/file-system.js.map +1 -1
- package/dist/utils/run-command.d.ts +26 -1
- package/dist/utils/run-command.d.ts.map +1 -1
- package/dist/utils/run-command.js +53 -4
- package/dist/utils/run-command.js.map +1 -1
- package/dist/window.d.ts +12 -0
- package/dist/window.d.ts.map +1 -0
- package/dist/window.js +48 -0
- package/dist/window.js.map +1 -0
- package/package.json +12 -12
- package/src/apis/browser-extension.tsx +29 -0
- package/src/apis/localstorage.test.ts +14 -6
- package/src/apis/localstorage.tsx +8 -5
- package/src/apis/oauth.tsx +5 -1
- package/src/apis/preferences.tsx +48 -22
- package/src/apis/toast.tsx +37 -62
- package/src/build.test.tsx +52 -0
- package/src/build.tsx +3 -1
- package/src/cli.tsx +99 -48
- package/src/compile.tsx +32 -11
- package/src/components/actions.tsx +94 -32
- package/src/components/detail.tsx +4 -0
- package/src/components/dropdown.tsx +47 -14
- package/src/components/extension-preferences.tsx +44 -16
- package/src/components/form/checkbox.tsx +12 -6
- package/src/components/form/date-picker.tsx +12 -6
- package/src/components/form/description.tsx +7 -2
- package/src/components/form/dropdown.tsx +131 -119
- package/src/components/form/file-autocomplete.tsx +90 -108
- package/src/components/form/file-picker.tsx +54 -43
- package/src/components/form/form-end.tsx +23 -2
- package/src/components/form/index.tsx +168 -41
- package/src/components/form/password-field.tsx +12 -6
- package/src/components/form/text-area.tsx +13 -6
- package/src/components/form/text-field.tsx +13 -6
- package/src/components/form/types.tsx +6 -0
- package/src/components/form/with-left-border.tsx +41 -8
- package/src/components/icon.tsx +27 -8
- package/src/components/list.tsx +243 -101
- package/src/components/loading-bar.tsx +3 -2
- package/src/components/loading-text.tsx +79 -0
- package/src/descendants.tsx +1 -0
- package/src/examples/file-autocomplete.vitest.tsx +130 -125
- package/src/examples/form-basic.vitest.tsx +376 -176
- package/src/examples/form-dropdown.vitest.tsx +126 -126
- package/src/examples/form-scroll.tsx +2 -0
- package/src/examples/form-scroll.vitest.tsx +58 -58
- package/src/examples/form-tagpicker.vitest.tsx +99 -99
- package/src/examples/internal/descendants-filtering.tsx +1 -0
- package/src/examples/internal/descendants.tsx +1 -0
- package/src/examples/internal/rhf-custom-ref.tsx +2 -0
- package/src/examples/internal/scrollbox-demo.tsx +3 -27
- package/src/examples/internal/scrollbox-with-descendants.tsx +4 -7
- package/src/examples/internal/simple-scrollbox.vitest.tsx +7 -5
- package/src/examples/list-detail-metadata.tsx +49 -0
- package/src/examples/list-detail-metadata.vitest.tsx +88 -0
- package/src/examples/list-dropdown-default.vitest.tsx +51 -51
- package/src/examples/list-fetch-data.vitest.tsx +4 -4
- package/src/examples/list-scrollbox.vitest.tsx +73 -14
- package/src/examples/list-with-detail-long.tsx +70 -0
- package/src/examples/list-with-detail.vitest.tsx +191 -85
- package/src/examples/list-with-dropdown.vitest.tsx +53 -53
- package/src/examples/list-with-sections.tsx +1 -0
- package/src/examples/list-with-sections.vitest.tsx +221 -97
- package/src/examples/list-with-toast.vitest.tsx +16 -16
- package/src/examples/simple-file-picker.vitest.tsx +63 -469
- package/src/examples/simple-grid.vitest.tsx +238 -233
- package/src/examples/simple-navigation.tsx +15 -7
- package/src/examples/simple-navigation.vitest.tsx +130 -219
- package/src/examples/store.vitest.tsx +1 -1
- package/src/examples/swift-extension.vitest.tsx +148 -0
- package/src/examples/synonyms.vitest.tsx +159 -0
- package/src/examples/toast-variations.tsx +150 -0
- package/src/examples/toast-variations.vitest.tsx +370 -0
- package/src/extensions/dev.tsx +74 -7
- package/src/extensions/dev.vitest.tsx +102 -34
- package/src/extensions/home.tsx +6 -0
- package/src/index.tsx +3 -0
- package/src/internal/dialog.tsx +43 -30
- package/src/internal/navigation.tsx +3 -1
- package/src/internal/offscreen.tsx +15 -0
- package/src/internal/providers.tsx +4 -2
- package/src/internal/scrollbox.tsx +4 -8
- package/src/keyboard.test.tsx +69 -0
- package/src/release.tsx +32 -38
- package/src/state.tsx +7 -0
- package/src/swift-loader.tsx +239 -0
- package/src/swift-runtime.tsx +36 -0
- package/src/utils/file-system.ts +61 -0
- package/src/utils/run-command.tsx +82 -6
package/src/components/list.tsx
CHANGED
|
@@ -18,9 +18,11 @@ import React, {
|
|
|
18
18
|
} from 'react'
|
|
19
19
|
import { LoadingBar } from 'termcast/src/components/loading-bar'
|
|
20
20
|
import { createDescendants } from 'termcast/src/descendants'
|
|
21
|
+
import { useStore } from 'termcast/src/state'
|
|
21
22
|
import { useDialog } from 'termcast/src/internal/dialog'
|
|
22
23
|
import { useIsInFocus } from 'termcast/src/internal/focus-context'
|
|
23
24
|
import { useNavigationPending } from 'termcast/src/internal/navigation'
|
|
25
|
+
import { Offscreen } from 'termcast/src/internal/offscreen'
|
|
24
26
|
import { ScrollBox } from 'termcast/src/internal/scrollbox'
|
|
25
27
|
|
|
26
28
|
import { Color, resolveColor } from 'termcast/src/colors'
|
|
@@ -67,9 +69,34 @@ interface ActionsInterface {
|
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
function ListFooter(): any {
|
|
72
|
+
const firstActionTitle = useStore((s) => s.firstActionTitle)
|
|
73
|
+
const hasToast = useStore((s) => s.toast !== null)
|
|
74
|
+
|
|
75
|
+
const content = hasToast ? null : (
|
|
76
|
+
<>
|
|
77
|
+
{firstActionTitle && (
|
|
78
|
+
<>
|
|
79
|
+
<text fg={Theme.text} attributes={TextAttributes.BOLD}>
|
|
80
|
+
↵
|
|
81
|
+
</text>
|
|
82
|
+
<text fg={Theme.textMuted}> {firstActionTitle.toLowerCase()}</text>
|
|
83
|
+
</>
|
|
84
|
+
)}
|
|
85
|
+
<text fg={Theme.text} attributes={TextAttributes.BOLD}>
|
|
86
|
+
{' '}↑↓
|
|
87
|
+
</text>
|
|
88
|
+
<text fg={Theme.textMuted}> navigate</text>
|
|
89
|
+
<text fg={Theme.text} attributes={TextAttributes.BOLD}>
|
|
90
|
+
{' '}^k
|
|
91
|
+
</text>
|
|
92
|
+
<text fg={Theme.textMuted}> actions</text>
|
|
93
|
+
</>
|
|
94
|
+
)
|
|
95
|
+
|
|
70
96
|
return (
|
|
71
97
|
<box
|
|
72
98
|
border={false}
|
|
99
|
+
height={1}
|
|
73
100
|
style={{
|
|
74
101
|
paddingLeft: 1,
|
|
75
102
|
flexShrink: 0,
|
|
@@ -79,18 +106,7 @@ function ListFooter(): any {
|
|
|
79
106
|
flexDirection: 'row',
|
|
80
107
|
}}
|
|
81
108
|
>
|
|
82
|
-
|
|
83
|
-
↵
|
|
84
|
-
</text>
|
|
85
|
-
<text fg={Theme.textMuted}> select</text>
|
|
86
|
-
<text fg={Theme.text} attributes={TextAttributes.BOLD}>
|
|
87
|
-
{' '}↑↓
|
|
88
|
-
</text>
|
|
89
|
-
<text fg={Theme.textMuted}> navigate</text>
|
|
90
|
-
<text fg={Theme.text} attributes={TextAttributes.BOLD}>
|
|
91
|
-
{' '}^k
|
|
92
|
-
</text>
|
|
93
|
-
<text fg={Theme.textMuted}> actions</text>
|
|
109
|
+
{content}
|
|
94
110
|
</box>
|
|
95
111
|
)
|
|
96
112
|
}
|
|
@@ -175,13 +191,13 @@ export interface ItemProps extends ActionsInterface, CommonProps {
|
|
|
175
191
|
tooltip: string
|
|
176
192
|
}
|
|
177
193
|
accessories?: ItemAccessory[]
|
|
178
|
-
detail?:
|
|
194
|
+
detail?: ReactNode
|
|
179
195
|
}
|
|
180
196
|
|
|
181
197
|
export interface DetailProps extends CommonProps {
|
|
182
198
|
isLoading?: boolean
|
|
183
199
|
markdown?: string
|
|
184
|
-
metadata?:
|
|
200
|
+
metadata?: ReactNode
|
|
185
201
|
}
|
|
186
202
|
|
|
187
203
|
export interface MetadataProps extends CommonProps {
|
|
@@ -380,7 +396,14 @@ function ListDropdownDialog(props: ListDropdownDialogProps): any {
|
|
|
380
396
|
// Wrapper function that updates search text
|
|
381
397
|
const setSearchText = (value: string) => {
|
|
382
398
|
setSearchTextRaw(value)
|
|
383
|
-
|
|
399
|
+
// TODO: use flushSync when available to force descendants to update visibility
|
|
400
|
+
const items = Object.values(descendantsContext.map.current)
|
|
401
|
+
.filter((item) => item.index !== -1 && item.props?.visible !== false)
|
|
402
|
+
.sort((a, b) => a.index - b.index)
|
|
403
|
+
|
|
404
|
+
if (items.length > 0 && items[0]) {
|
|
405
|
+
setSelectedIndex(items[0].index)
|
|
406
|
+
}
|
|
384
407
|
}
|
|
385
408
|
|
|
386
409
|
|
|
@@ -456,6 +479,7 @@ function ListDropdownDialog(props: ListDropdownDialogProps): any {
|
|
|
456
479
|
<textarea
|
|
457
480
|
ref={inputRef}
|
|
458
481
|
height={1}
|
|
482
|
+
wrapMode='none'
|
|
459
483
|
keyBindings={[
|
|
460
484
|
{ name: 'return', action: 'submit' },
|
|
461
485
|
{ name: 'linefeed', action: 'submit' },
|
|
@@ -499,30 +523,45 @@ function ListDropdownDialog(props: ListDropdownDialogProps): any {
|
|
|
499
523
|
)}
|
|
500
524
|
</box>
|
|
501
525
|
|
|
502
|
-
<
|
|
503
|
-
border={false}
|
|
504
|
-
style={{
|
|
505
|
-
paddingRight: 2,
|
|
506
|
-
paddingLeft: 3,
|
|
507
|
-
paddingBottom: 1,
|
|
508
|
-
paddingTop: 1,
|
|
509
|
-
flexDirection: 'row',
|
|
510
|
-
}}
|
|
511
|
-
>
|
|
512
|
-
<text fg={Theme.text} attributes={TextAttributes.BOLD}>
|
|
513
|
-
↵
|
|
514
|
-
</text>
|
|
515
|
-
<text fg={Theme.textMuted}> select</text>
|
|
516
|
-
<text fg={Theme.text} attributes={TextAttributes.BOLD}>
|
|
517
|
-
{' '}↑↓
|
|
518
|
-
</text>
|
|
519
|
-
<text fg={Theme.textMuted}> navigate</text>
|
|
520
|
-
</box>
|
|
526
|
+
<DropdownFooter />
|
|
521
527
|
</box>
|
|
522
528
|
</DropdownDescendantsProvider>
|
|
523
529
|
)
|
|
524
530
|
}
|
|
525
531
|
|
|
532
|
+
function DropdownFooter(): any {
|
|
533
|
+
const hasToast = useStore((s) => s.toast !== null)
|
|
534
|
+
|
|
535
|
+
const content = hasToast ? null : (
|
|
536
|
+
<>
|
|
537
|
+
<text fg={Theme.text} attributes={TextAttributes.BOLD}>
|
|
538
|
+
↵
|
|
539
|
+
</text>
|
|
540
|
+
<text fg={Theme.textMuted}> select</text>
|
|
541
|
+
<text fg={Theme.text} attributes={TextAttributes.BOLD}>
|
|
542
|
+
{' '}↑↓
|
|
543
|
+
</text>
|
|
544
|
+
<text fg={Theme.textMuted}> navigate</text>
|
|
545
|
+
</>
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
return (
|
|
549
|
+
<box
|
|
550
|
+
border={false}
|
|
551
|
+
height={1}
|
|
552
|
+
style={{
|
|
553
|
+
paddingRight: 2,
|
|
554
|
+
paddingLeft: 3,
|
|
555
|
+
paddingBottom: 1,
|
|
556
|
+
paddingTop: 1,
|
|
557
|
+
flexDirection: 'row',
|
|
558
|
+
}}
|
|
559
|
+
>
|
|
560
|
+
{content}
|
|
561
|
+
</box>
|
|
562
|
+
)
|
|
563
|
+
}
|
|
564
|
+
|
|
526
565
|
// Render a single list item row
|
|
527
566
|
function ListItemRow(props: {
|
|
528
567
|
title: string
|
|
@@ -670,7 +709,7 @@ export const List: ListType = (props) => {
|
|
|
670
709
|
const {
|
|
671
710
|
children,
|
|
672
711
|
onSelectionChange,
|
|
673
|
-
filtering
|
|
712
|
+
filtering,
|
|
674
713
|
searchText: controlledSearchText,
|
|
675
714
|
onSearchTextChange,
|
|
676
715
|
searchBarPlaceholder = 'Search...',
|
|
@@ -686,6 +725,7 @@ export const List: ListType = (props) => {
|
|
|
686
725
|
const [selectedIndex, setSelectedIndex] = useState(0)
|
|
687
726
|
const [isDropdownOpen, setIsDropdownOpen] = useState(false)
|
|
688
727
|
const [currentDetail, setCurrentDetail] = useState<ReactNode>(null)
|
|
728
|
+
const [currentItemActions, setCurrentItemActions] = useState<ReactNode>(null)
|
|
689
729
|
const inputRef = useRef<TextareaRenderable>(null)
|
|
690
730
|
const scrollBoxRef = useRef<ScrollBoxRenderable>(null)
|
|
691
731
|
const descendantsContext = useListDescendants()
|
|
@@ -700,23 +740,35 @@ export const List: ListType = (props) => {
|
|
|
700
740
|
useLayoutEffect(() => {
|
|
701
741
|
if (controlledSearchText === undefined) return
|
|
702
742
|
const textarea = inputRef.current
|
|
703
|
-
if (textarea
|
|
704
|
-
|
|
705
|
-
|
|
743
|
+
if (!textarea) return
|
|
744
|
+
|
|
745
|
+
// Skip if textarea already has the correct value
|
|
746
|
+
if (textarea.plainText === controlledSearchText) return
|
|
747
|
+
|
|
748
|
+
// Save cursor position, set text, then restore cursor (clamped to valid range)
|
|
749
|
+
const cursorOffset = textarea.cursorOffset
|
|
750
|
+
textarea.setText(controlledSearchText)
|
|
751
|
+
textarea.cursorOffset = Math.min(cursorOffset, controlledSearchText.length)
|
|
706
752
|
}, [controlledSearchText])
|
|
707
753
|
|
|
708
|
-
//
|
|
709
|
-
//
|
|
710
|
-
//
|
|
711
|
-
//
|
|
712
|
-
//
|
|
713
|
-
//
|
|
714
|
-
//
|
|
754
|
+
// Filtering logic (matches Raycast behavior):
|
|
755
|
+
//
|
|
756
|
+
// | filtering prop | onSearchTextChange | Result |
|
|
757
|
+
// |----------------|-------------------|-----------------|
|
|
758
|
+
// | undefined | undefined | true (default) |
|
|
759
|
+
// | undefined | provided | false |
|
|
760
|
+
// | true | undefined | true |
|
|
761
|
+
// | true | provided | true |
|
|
762
|
+
// | false | undefined | false |
|
|
763
|
+
// | false | provided | false |
|
|
764
|
+
//
|
|
765
|
+
// Summary: filtering defaults to true, but is implicitly disabled when
|
|
766
|
+
// onSearchTextChange is provided (user manages filtering). Set filtering={true}
|
|
767
|
+
// explicitly to use built-in filtering alongside onSearchTextChange.
|
|
715
768
|
const isFilteringEnabled = (() => {
|
|
716
769
|
if (filtering === false) return false
|
|
717
770
|
if (filtering === true) return true
|
|
718
|
-
|
|
719
|
-
return !onSearchTextChange // defaults to true unless onSearchTextChange is provided
|
|
771
|
+
return !onSearchTextChange
|
|
720
772
|
})()
|
|
721
773
|
|
|
722
774
|
const openDropdown = () => {
|
|
@@ -726,8 +778,15 @@ export const List: ListType = (props) => {
|
|
|
726
778
|
// Wrapper function that updates search text
|
|
727
779
|
const setInternalSearchText = (value: string) => {
|
|
728
780
|
setInternalSearchTextRaw(value)
|
|
729
|
-
//
|
|
730
|
-
|
|
781
|
+
// TODO: use flushSync when available to force descendants to update visibility
|
|
782
|
+
// before querying. For now, we compute visibility inline with the new search value.
|
|
783
|
+
const items = Object.values(descendantsContext.map.current)
|
|
784
|
+
.filter((item) => item.index !== -1 && item.props?.visible !== false)
|
|
785
|
+
.sort((a, b) => a.index - b.index)
|
|
786
|
+
|
|
787
|
+
if (items.length > 0 && items[0]) {
|
|
788
|
+
setSelectedIndex(items[0].index)
|
|
789
|
+
}
|
|
731
790
|
}
|
|
732
791
|
|
|
733
792
|
const listContextValue = useMemo<ListContextValue>(
|
|
@@ -758,27 +817,37 @@ export const List: ListType = (props) => {
|
|
|
758
817
|
if (selectedItemId !== undefined) {
|
|
759
818
|
const items = Object.values(descendantsContext.map.current)
|
|
760
819
|
.filter((item) => item.index !== -1)
|
|
761
|
-
.sort((a, b) => a.index - b.index)
|
|
762
820
|
|
|
763
|
-
const
|
|
764
|
-
if (
|
|
765
|
-
setSelectedIndex(index)
|
|
821
|
+
const foundItem = items.find((item) => item.props?.id === selectedItemId)
|
|
822
|
+
if (foundItem) {
|
|
823
|
+
setSelectedIndex(foundItem.index)
|
|
766
824
|
}
|
|
767
825
|
}
|
|
768
826
|
}, [selectedItemId])
|
|
769
827
|
|
|
770
|
-
// Call onSelectionChange when selection changes
|
|
828
|
+
// Call onSelectionChange when selection changes and track current item's actions
|
|
771
829
|
useEffect(() => {
|
|
772
|
-
if (!onSelectionChange) return
|
|
773
|
-
|
|
774
830
|
const items = Object.values(descendantsContext.map.current)
|
|
775
831
|
.filter((item) => item.index !== -1)
|
|
776
832
|
.sort((a, b) => a.index - b.index)
|
|
777
833
|
|
|
778
834
|
const currentItem = items.find((item) => item.index === selectedIndex)
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
835
|
+
|
|
836
|
+
// Track current item's actions for footer display
|
|
837
|
+
const actions = currentItem?.props?.actions ?? props.actions ?? null
|
|
838
|
+
setCurrentItemActions(actions)
|
|
839
|
+
|
|
840
|
+
// Clear first action title when there are no actions
|
|
841
|
+
if (!actions) {
|
|
842
|
+
useStore.setState({ firstActionTitle: '' })
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Call onSelectionChange callback if provided
|
|
846
|
+
if (onSelectionChange) {
|
|
847
|
+
const selectedId = currentItem?.props?.id ?? null
|
|
848
|
+
onSelectionChange(selectedId)
|
|
849
|
+
}
|
|
850
|
+
}, [selectedIndex, props.actions])
|
|
782
851
|
|
|
783
852
|
const scrollToItem = (item: { props?: ListItemDescendant }) => {
|
|
784
853
|
const scrollBox = scrollBoxRef.current
|
|
@@ -787,29 +856,24 @@ export const List: ListType = (props) => {
|
|
|
787
856
|
|
|
788
857
|
const contentY = scrollBox.content?.y || 0
|
|
789
858
|
const viewportHeight = scrollBox.viewport?.height || 10
|
|
790
|
-
const currentScrollTop = scrollBox.scrollTop || 0
|
|
791
859
|
|
|
860
|
+
// Calculate item position relative to content
|
|
792
861
|
const itemTop = elementRef.y - contentY
|
|
793
|
-
const itemBottom = itemTop + elementRef.height
|
|
794
|
-
|
|
795
|
-
const visibleTop = currentScrollTop
|
|
796
|
-
const visibleBottom = currentScrollTop + viewportHeight
|
|
797
862
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
scrollBox.scrollTo(itemBottom - viewportHeight)
|
|
802
|
-
}
|
|
863
|
+
// Scroll so the top of the item is centered in the viewport
|
|
864
|
+
const targetScrollTop = itemTop - viewportHeight / 2
|
|
865
|
+
scrollBox.scrollTo(Math.max(0, targetScrollTop))
|
|
803
866
|
}
|
|
804
867
|
|
|
805
868
|
const move = (direction: -1 | 1) => {
|
|
869
|
+
// Get all visible items
|
|
806
870
|
const items = Object.values(descendantsContext.map.current)
|
|
807
871
|
.filter((item) => item.index !== -1 && item.props?.visible !== false)
|
|
808
872
|
.sort((a, b) => a.index - b.index)
|
|
809
873
|
|
|
810
874
|
if (items.length === 0) return
|
|
811
875
|
|
|
812
|
-
|
|
876
|
+
// Find currently selected item's position in visible items
|
|
813
877
|
let currentVisibleIndex = items.findIndex(
|
|
814
878
|
(item) => item.index === selectedIndex,
|
|
815
879
|
)
|
|
@@ -817,19 +881,19 @@ export const List: ListType = (props) => {
|
|
|
817
881
|
// If current selection is not visible, select first visible item
|
|
818
882
|
if (items[0]) {
|
|
819
883
|
setSelectedIndex(items[0].index)
|
|
820
|
-
scrollToItem(items[0])
|
|
821
884
|
}
|
|
822
885
|
return
|
|
823
886
|
}
|
|
824
887
|
|
|
888
|
+
// Calculate next visible index
|
|
825
889
|
let nextVisibleIndex = currentVisibleIndex + direction
|
|
826
890
|
if (nextVisibleIndex < 0) nextVisibleIndex = items.length - 1
|
|
827
891
|
if (nextVisibleIndex >= items.length) nextVisibleIndex = 0
|
|
828
892
|
|
|
829
893
|
const nextItem = items[nextVisibleIndex]
|
|
830
894
|
if (nextItem) {
|
|
831
|
-
setSelectedIndex(nextItem.index)
|
|
832
895
|
scrollToItem(nextItem)
|
|
896
|
+
setSelectedIndex(nextItem.index)
|
|
833
897
|
}
|
|
834
898
|
}
|
|
835
899
|
|
|
@@ -845,14 +909,14 @@ export const List: ListType = (props) => {
|
|
|
845
909
|
return
|
|
846
910
|
}
|
|
847
911
|
|
|
848
|
-
//
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
const currentItem = items.find((item) => item.index === selectedIndex)
|
|
912
|
+
// Get current item by selectedIndex (which is a descendant index)
|
|
913
|
+
const items = Object.values(descendantsContext.map.current)
|
|
914
|
+
.filter((item) => item.index !== -1)
|
|
915
|
+
.sort((a, b) => a.index - b.index)
|
|
916
|
+
const currentItem = items.find((item) => item.index === selectedIndex)
|
|
855
917
|
|
|
918
|
+
// Handle Ctrl+K to show actions (always show sheet)
|
|
919
|
+
if (evt.name === 'k' && evt.ctrl) {
|
|
856
920
|
// Show current item's actions if available
|
|
857
921
|
if (currentItem?.props?.actions) {
|
|
858
922
|
dialog.push(currentItem.props.actions, 'bottom-right')
|
|
@@ -866,15 +930,12 @@ export const List: ListType = (props) => {
|
|
|
866
930
|
|
|
867
931
|
if (evt.name === 'up') move(-1)
|
|
868
932
|
if (evt.name === 'down') move(1)
|
|
933
|
+
// Handle Enter to execute first action directly
|
|
869
934
|
if (evt.name === 'return') {
|
|
870
|
-
const items = Object.values(descendantsContext.map.current)
|
|
871
|
-
.filter((item) => item.index !== -1)
|
|
872
|
-
.sort((a, b) => a.index - b.index)
|
|
873
|
-
|
|
874
|
-
const currentItem = items.find((item) => item.index === selectedIndex)
|
|
875
935
|
if (!currentItem?.props) return
|
|
876
936
|
|
|
877
937
|
if (currentItem.props.actions) {
|
|
938
|
+
useStore.setState({ shouldAutoExecuteFirstAction: true })
|
|
878
939
|
dialog.push(currentItem.props.actions, 'bottom-right')
|
|
879
940
|
}
|
|
880
941
|
}
|
|
@@ -904,7 +965,10 @@ export const List: ListType = (props) => {
|
|
|
904
965
|
border={false}
|
|
905
966
|
style={{
|
|
906
967
|
paddingBottom: 0,
|
|
907
|
-
|
|
968
|
+
flexShrink: 0,
|
|
969
|
+
paddingLeft: 1,
|
|
970
|
+
paddingRight: 1,
|
|
971
|
+
overflow: 'hidden',
|
|
908
972
|
}}
|
|
909
973
|
>
|
|
910
974
|
<LoadingBar
|
|
@@ -938,6 +1002,7 @@ export const List: ListType = (props) => {
|
|
|
938
1002
|
<textarea
|
|
939
1003
|
ref={inputRef}
|
|
940
1004
|
height={1}
|
|
1005
|
+
wrapMode='none'
|
|
941
1006
|
keyBindings={[
|
|
942
1007
|
{ name: 'return', action: 'submit' },
|
|
943
1008
|
{ name: 'linefeed', action: 'submit' },
|
|
@@ -985,6 +1050,11 @@ export const List: ListType = (props) => {
|
|
|
985
1050
|
|
|
986
1051
|
{/* Footer with keyboard shortcuts or toast */}
|
|
987
1052
|
<ListFooter />
|
|
1053
|
+
|
|
1054
|
+
{/* Render current item's actions offscreen to collect first action title */}
|
|
1055
|
+
{currentItemActions && (
|
|
1056
|
+
<Offscreen>{currentItemActions}</Offscreen>
|
|
1057
|
+
)}
|
|
988
1058
|
</box>
|
|
989
1059
|
|
|
990
1060
|
{/* Detail panel on the right */}
|
|
@@ -1076,7 +1146,7 @@ const ListItem: ListItemType = (props) => {
|
|
|
1076
1146
|
elementRef: elementRef.current,
|
|
1077
1147
|
})
|
|
1078
1148
|
|
|
1079
|
-
//
|
|
1149
|
+
// Check if this item is selected
|
|
1080
1150
|
const selectedIndex = listContext?.selectedIndex ?? 0
|
|
1081
1151
|
const isActive = index === selectedIndex
|
|
1082
1152
|
|
|
@@ -1156,7 +1226,7 @@ const ListItemDetail: ListItemDetailType = (props) => {
|
|
|
1156
1226
|
)}
|
|
1157
1227
|
|
|
1158
1228
|
<ScrollBox
|
|
1159
|
-
focused={
|
|
1229
|
+
focused={false}
|
|
1160
1230
|
flexGrow={1}
|
|
1161
1231
|
flexShrink={1}
|
|
1162
1232
|
style={{
|
|
@@ -1200,8 +1270,8 @@ const ListItemDetailMetadata = (props: MetadataProps) => {
|
|
|
1200
1270
|
|
|
1201
1271
|
const ListItemDetailMetadataLabel = (props: { title: string; text?: string; icon?: Image.ImageLike }) => {
|
|
1202
1272
|
return (
|
|
1203
|
-
<box style={{ flexDirection: '
|
|
1204
|
-
<text fg={Theme.textMuted}
|
|
1273
|
+
<box style={{ flexDirection: 'column', paddingBottom: 0.5 }}>
|
|
1274
|
+
<text fg={Theme.textMuted}>{props.title}:</text>
|
|
1205
1275
|
{props.text && <text fg={Theme.text}>{props.text}</text>}
|
|
1206
1276
|
</box>
|
|
1207
1277
|
)
|
|
@@ -1217,8 +1287,8 @@ const ListItemDetailMetadataSeparator = () => {
|
|
|
1217
1287
|
|
|
1218
1288
|
const ListItemDetailMetadataLink = (props: { title: string; target: string; text: string }) => {
|
|
1219
1289
|
return (
|
|
1220
|
-
<box style={{ flexDirection: '
|
|
1221
|
-
<text fg={Theme.textMuted}
|
|
1290
|
+
<box style={{ flexDirection: 'column', paddingBottom: 0.5 }}>
|
|
1291
|
+
<text fg={Theme.textMuted}>{props.title}:</text>
|
|
1222
1292
|
<text fg={Theme.link}>{props.text}</text>
|
|
1223
1293
|
</box>
|
|
1224
1294
|
)
|
|
@@ -1568,13 +1638,21 @@ const ListSection = (props: SectionProps) => {
|
|
|
1568
1638
|
[parentContext, props.title, searchText],
|
|
1569
1639
|
)
|
|
1570
1640
|
|
|
1571
|
-
|
|
1572
|
-
|
|
1641
|
+
const isSearching = searchText.trim().length > 0
|
|
1642
|
+
|
|
1643
|
+
const children = (
|
|
1644
|
+
<ListSectionContext.Provider value={sectionContextValue}>
|
|
1645
|
+
{props.children}
|
|
1646
|
+
</ListSectionContext.Provider>
|
|
1647
|
+
)
|
|
1648
|
+
|
|
1649
|
+
if (isSearching) {
|
|
1650
|
+
return children
|
|
1651
|
+
}
|
|
1573
1652
|
|
|
1574
1653
|
return (
|
|
1575
1654
|
<box style={{ marginBottom: 1 }}>
|
|
1576
|
-
{
|
|
1577
|
-
{showTitle && (
|
|
1655
|
+
{props.title && (
|
|
1578
1656
|
<box
|
|
1579
1657
|
border={false}
|
|
1580
1658
|
style={{
|
|
@@ -1586,18 +1664,82 @@ const ListSection = (props: SectionProps) => {
|
|
|
1586
1664
|
</text>
|
|
1587
1665
|
</box>
|
|
1588
1666
|
)}
|
|
1589
|
-
{
|
|
1590
|
-
<ListSectionContext.Provider value={sectionContextValue}>
|
|
1591
|
-
{props.children}
|
|
1592
|
-
</ListSectionContext.Provider>
|
|
1667
|
+
{children}
|
|
1593
1668
|
</box>
|
|
1594
1669
|
)
|
|
1595
1670
|
}
|
|
1596
1671
|
|
|
1597
1672
|
List.Section = ListSection
|
|
1598
1673
|
List.Dropdown = ListDropdown
|
|
1599
|
-
List.EmptyView = (props) => {
|
|
1600
|
-
|
|
1674
|
+
List.EmptyView = (props: EmptyViewProps) => {
|
|
1675
|
+
const dialog = useDialog()
|
|
1676
|
+
const inFocus = useIsInFocus()
|
|
1677
|
+
|
|
1678
|
+
// Handle keyboard for actions
|
|
1679
|
+
useKeyboard((evt) => {
|
|
1680
|
+
if (!inFocus) return
|
|
1681
|
+
|
|
1682
|
+
// Handle Ctrl+K to show actions
|
|
1683
|
+
if (evt.name === 'k' && evt.ctrl && props.actions) {
|
|
1684
|
+
dialog.push(props.actions, 'bottom-right')
|
|
1685
|
+
return
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
// Handle Enter to execute first action
|
|
1689
|
+
if (evt.name === 'return' && props.actions) {
|
|
1690
|
+
useStore.setState({ shouldAutoExecuteFirstAction: true })
|
|
1691
|
+
dialog.push(props.actions, 'bottom-right')
|
|
1692
|
+
}
|
|
1693
|
+
})
|
|
1694
|
+
|
|
1695
|
+
// Get icon string from ImageLike
|
|
1696
|
+
const getIconString = (icon: Image.ImageLike): string | null => {
|
|
1697
|
+
if (typeof icon === 'string') {
|
|
1698
|
+
return getIconEmoji(icon)
|
|
1699
|
+
}
|
|
1700
|
+
if (icon && typeof icon === 'object' && 'source' in icon) {
|
|
1701
|
+
// For { source: string } or { source: { light, dark } } objects
|
|
1702
|
+
const source = icon.source
|
|
1703
|
+
if (typeof source === 'string') {
|
|
1704
|
+
return getIconEmoji(source)
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
return null
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
const iconEmoji = props.icon ? getIconString(props.icon) : null
|
|
1711
|
+
|
|
1712
|
+
return (
|
|
1713
|
+
<box
|
|
1714
|
+
style={{
|
|
1715
|
+
flexDirection: 'column',
|
|
1716
|
+
alignItems: 'center',
|
|
1717
|
+
justifyContent: 'center',
|
|
1718
|
+
flexGrow: 1,
|
|
1719
|
+
paddingTop: 2,
|
|
1720
|
+
paddingBottom: 2,
|
|
1721
|
+
paddingLeft: 2,
|
|
1722
|
+
paddingRight: 2,
|
|
1723
|
+
gap: 1,
|
|
1724
|
+
}}
|
|
1725
|
+
>
|
|
1726
|
+
{iconEmoji && (
|
|
1727
|
+
<text fg={Theme.textMuted} style={{ marginBottom: 1 }}>
|
|
1728
|
+
{iconEmoji}
|
|
1729
|
+
</text>
|
|
1730
|
+
)}
|
|
1731
|
+
{props.title && (
|
|
1732
|
+
<text fg={Theme.text} attributes={TextAttributes.BOLD}>
|
|
1733
|
+
{props.title?.replace(/\bRaycast\b/g, 'Termcast').replace(/\braycast\b/g, 'termcast') || ''}
|
|
1734
|
+
</text>
|
|
1735
|
+
)}
|
|
1736
|
+
{props.description && (
|
|
1737
|
+
<text fg={Theme.textMuted} wrapMode='word'>
|
|
1738
|
+
{props.description?.replace(/\bRaycast\b/g, 'Termcast').replace(/\braycast\b/g, 'termcast') || ''}
|
|
1739
|
+
</text>
|
|
1740
|
+
)}
|
|
1741
|
+
</box>
|
|
1742
|
+
)
|
|
1601
1743
|
}
|
|
1602
1744
|
|
|
1603
1745
|
export default List
|
|
@@ -127,10 +127,11 @@ export function LoadingBar(props: LoadingBarProps): any {
|
|
|
127
127
|
style={{
|
|
128
128
|
flexDirection: 'row',
|
|
129
129
|
flexGrow: 1,
|
|
130
|
-
paddingLeft: 1,
|
|
131
|
-
paddingRight: 1,
|
|
130
|
+
// paddingLeft: 1,
|
|
131
|
+
// paddingRight: 1,
|
|
132
132
|
}}
|
|
133
133
|
>
|
|
134
|
+
|
|
134
135
|
{characters.map((char, index) => (
|
|
135
136
|
<text key={index} fg={getCharacterColor(index)} flexShrink={0}>
|
|
136
137
|
{char}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import React, { useState, useEffect, useRef } from 'react'
|
|
2
|
+
import { colord } from 'colord'
|
|
3
|
+
|
|
4
|
+
interface LoadingTextProps {
|
|
5
|
+
children: string
|
|
6
|
+
isLoading?: boolean
|
|
7
|
+
color: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Generate wave colors based on base color
|
|
12
|
+
* Creates a gradient from base color to a lighter version and back
|
|
13
|
+
* Uses a shorter wave (12 chars) compared to LoadingBar
|
|
14
|
+
*/
|
|
15
|
+
function generateWaveColors(baseColor: string): string[] {
|
|
16
|
+
const base = colord(baseColor)
|
|
17
|
+
// Shorter wave for text - lighten factors from 0 to 0.5 and back
|
|
18
|
+
const steps = [0, 10, 20, 30, 40, 50, 40, 30, 20, 10, 0, 0]
|
|
19
|
+
return steps.map((percent) => base.lighten(percent / 100).toHex())
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function LoadingText(props: LoadingTextProps): any {
|
|
23
|
+
const { children, isLoading = false, color = '#FFC000' } = props
|
|
24
|
+
const [position, setPosition] = useState(0)
|
|
25
|
+
const intervalRef = useRef<NodeJS.Timeout | null>(null)
|
|
26
|
+
|
|
27
|
+
const characters = children.split('')
|
|
28
|
+
const waveColors = generateWaveColors(color)
|
|
29
|
+
const waveWidth = waveColors.length
|
|
30
|
+
// Add padding at the end to create a delay before the next loop
|
|
31
|
+
const endPadding = 10
|
|
32
|
+
const totalLength = characters.length + waveWidth + endPadding
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (isLoading) {
|
|
36
|
+
intervalRef.current = setInterval(() => {
|
|
37
|
+
setPosition((prev) => (prev + 1) % totalLength)
|
|
38
|
+
}, 30)
|
|
39
|
+
} else {
|
|
40
|
+
if (intervalRef.current) {
|
|
41
|
+
clearInterval(intervalRef.current)
|
|
42
|
+
intervalRef.current = null
|
|
43
|
+
}
|
|
44
|
+
setPosition(0)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return () => {
|
|
48
|
+
if (intervalRef.current) {
|
|
49
|
+
clearInterval(intervalRef.current)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}, [isLoading, totalLength])
|
|
53
|
+
|
|
54
|
+
const getCharacterColor = (index: number): string => {
|
|
55
|
+
if (!isLoading) {
|
|
56
|
+
return color
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const distance = position - index
|
|
60
|
+
|
|
61
|
+
// If character is within the wave (behind the current position)
|
|
62
|
+
if (distance >= 0 && distance < waveWidth) {
|
|
63
|
+
return waveColors[distance]
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Default to base color for characters outside the wave
|
|
67
|
+
return color
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<box flexDirection="row">
|
|
72
|
+
{characters.map((char, index) => (
|
|
73
|
+
<text key={index} fg={getCharacterColor(index)} flexShrink={0}>
|
|
74
|
+
{char}
|
|
75
|
+
</text>
|
|
76
|
+
))}
|
|
77
|
+
</box>
|
|
78
|
+
)
|
|
79
|
+
}
|