mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
feat: new shortcuts hook with registrations (#44954)
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? - Brand new hook APIs for registering shortcuts using tanstack hotkeys - Support for command menu injection when shortcut is added <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Centralized keyboard shortcuts system with per‑shortcut registration and per‑user enable/disable preferences stored locally * Added a "Copy results as Markdown" shortcut (Mod+Shift+M) * Shortcuts can be surfaced in the Command Menu with a visual shortcut badge for discoverability * **Documentation** * Legacy keyboard shortcut hooks marked as deprecated and documentation updated to point to the new shortcut API <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
1 parent
8ef6181ef7
commit
3ed436de74
11 files changed
+341
-6
No files matched your search
@@ -7,6 +7,10 @@ function includes(array: string[], element: string) {
|
||||
/**
|
||||
* Hook for listening on key events.
|
||||
*
|
||||
* @deprecated Use `useShortcut` from `state/shortcuts/useShortcut` instead.
|
||||
* The new hook reads from a central registry, respects user preferences, and
|
||||
* can surface shortcuts in the Cmd+P command menu.
|
||||
*
|
||||
* @param {Object|Map} keyMap Key names mapped to event handlers. If a key name exists, its
|
||||
* default behavior will be suppressed.
|
||||
* @param {Array} whitelistNodes If target element is in the whitelist nodes array, will not
|
||||
|
||||
@@ -7,4 +7,5 @@ export const COMMAND_MENU_SECTIONS = {
|
||||
SQL: 'SQL Editor',
|
||||
DATABASE: 'Database',
|
||||
INTEGRATIONS: 'Integrations',
|
||||
SHORTCUTS: 'Shortcuts',
|
||||
} as const
|
||||
@@ -1,14 +1,24 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useLatest } from 'react-use'
|
||||
|
||||
// [Joshen] Refactor: Remove dependencies, and just make this into a single definition
|
||||
/**
|
||||
* @deprecated Use `useShortcut` from `state/shortcuts/useShortcut` instead.
|
||||
* It reads from a central shortcut registry (`SHORTCUT_DEFINITIONS`) and
|
||||
* integrates with the user's enable/disable preferences + the Cmd+P command menu.
|
||||
*
|
||||
* Migration:
|
||||
* 1. Add an entry to `state/shortcuts/registry.ts` with a unique ID, label, and sequence.
|
||||
* 2. Replace `useHotKey(cb, 'k', { shift: true })` with
|
||||
* `useShortcut(SHORTCUT_IDS.YOUR_ID, cb)`.
|
||||
*/
|
||||
function useHotKey(
|
||||
callback: (e: KeyboardEvent) => void,
|
||||
key: string,
|
||||
options?: { enabled?: boolean; shift?: boolean }
|
||||
): void
|
||||
/**
|
||||
* @deprecated The `dependencies` parameter is deprecated. Use the overload without dependencies instead.
|
||||
* @deprecated Use `useShortcut` from `state/shortcuts/useShortcut` instead.
|
||||
* The `dependencies` parameter is also deprecated in this legacy hook.
|
||||
*/
|
||||
function useHotKey(
|
||||
callback: (e: KeyboardEvent) => void,
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
"@supabase/shared-types": "0.1.88",
|
||||
"@supabase/sql-to-rest": "^0.1.6",
|
||||
"@supabase/supabase-js": "catalog:",
|
||||
"@tanstack/react-hotkeys": "^0.9.1",
|
||||
"@tanstack/react-query": "^5.0.0",
|
||||
"@tanstack/react-query-devtools": "^5.0.0",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import { ShortcutDefinition } from './types'
|
||||
|
||||
/**
|
||||
* The canonical list of shortcut IDs. Add new shortcuts here first, then
|
||||
* register them in `SHORTCUT_DEFINITIONS` below.
|
||||
*
|
||||
* ID convention: `"<surface>.<action>"` in kebab-case, e.g. `"results.copy-markdown"`.
|
||||
* The `<surface>` groups related shortcuts (sql-editor, table-editor, results, etc).
|
||||
*/
|
||||
export const SHORTCUT_IDS = {
|
||||
RESULTS_COPY_MARKDOWN: 'results.copy-markdown',
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Union of all valid shortcut IDs. Use this as the `id` parameter type on any
|
||||
* hook or util that takes a shortcut reference.
|
||||
*/
|
||||
export type ShortcutId = (typeof SHORTCUT_IDS)[keyof typeof SHORTCUT_IDS]
|
||||
|
||||
/**
|
||||
* The shortcut registry — every shortcut the app knows about, keyed by
|
||||
* `ShortcutId`. The `Record` type ensures this map stays exhaustive: adding a
|
||||
* new entry to `SHORTCUT_IDS` without a matching definition here is a type error.
|
||||
*
|
||||
* See `ShortcutDefinition` for the shape of each entry.
|
||||
*
|
||||
* @example
|
||||
* // Add a new shortcut:
|
||||
* // 1. Add to SHORTCUT_IDS:
|
||||
* // SQL_EDITOR_RUN: 'sql-editor.run'
|
||||
* // 2. Add to SHORTCUT_DEFINITIONS:
|
||||
* // [SHORTCUT_IDS.SQL_EDITOR_RUN]: {
|
||||
* // id: SHORTCUT_IDS.SQL_EDITOR_RUN,
|
||||
* // label: 'Run query',
|
||||
* // sequence: ['Mod+Enter'],
|
||||
* // }
|
||||
* // 3. Use in a component:
|
||||
* // useShortcut(SHORTCUT_IDS.SQL_EDITOR_RUN, runQuery)
|
||||
*/
|
||||
export const SHORTCUT_DEFINITIONS: Record<ShortcutId, ShortcutDefinition> = {
|
||||
[SHORTCUT_IDS.RESULTS_COPY_MARKDOWN]: {
|
||||
id: SHORTCUT_IDS.RESULTS_COPY_MARKDOWN,
|
||||
label: 'Copy results as Markdown',
|
||||
sequence: ['Mod+Shift+M'],
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import type { ShortcutId } from './registry'
|
||||
import { DisabledShortcuts } from './types'
|
||||
import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage'
|
||||
|
||||
const STORAGE_KEY = LOCAL_STORAGE_KEYS.SHORTCUT_STORAGE_KEY
|
||||
|
||||
const DEFAULT_DISABLED: DisabledShortcuts = {}
|
||||
|
||||
export function useShortcutPreferences() {
|
||||
const [disabled, setDisabled] = useLocalStorageQuery<DisabledShortcuts>(
|
||||
STORAGE_KEY,
|
||||
DEFAULT_DISABLED
|
||||
)
|
||||
|
||||
const setShortcutEnabled = useCallback(
|
||||
(id: ShortcutId, enabled: boolean) => {
|
||||
setDisabled((prev) => {
|
||||
if (enabled) {
|
||||
const { [id]: _removed, ...rest } = prev
|
||||
return rest
|
||||
}
|
||||
return { ...prev, [id]: true }
|
||||
})
|
||||
},
|
||||
[setDisabled]
|
||||
)
|
||||
|
||||
const resetShortcut = useCallback(
|
||||
(id: ShortcutId) => {
|
||||
setDisabled((prev) => {
|
||||
const { [id]: _removed, ...rest } = prev
|
||||
return rest
|
||||
})
|
||||
},
|
||||
[setDisabled]
|
||||
)
|
||||
|
||||
const resetAllShortcuts = useCallback(() => {
|
||||
setDisabled(DEFAULT_DISABLED)
|
||||
}, [setDisabled])
|
||||
|
||||
return {
|
||||
disabled,
|
||||
setShortcutEnabled,
|
||||
resetShortcut,
|
||||
resetAllShortcuts,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import { HotkeySequence } from '@tanstack/react-hotkeys'
|
||||
|
||||
export type DisabledShortcuts = Record<string, boolean>
|
||||
|
||||
/**
|
||||
* Runtime options for a shortcut. Used in two places:
|
||||
*
|
||||
* 1. On a `ShortcutDefinition` in the registry — acts as the default options
|
||||
* whenever the shortcut is mounted via `useShortcut`.
|
||||
* 2. As the third argument to `useShortcut(id, callback, options)` — lets the
|
||||
* call site override the registry defaults for a specific mount.
|
||||
*
|
||||
* Caller options take priority over registry defaults, which take priority over
|
||||
* the hard-coded fallbacks listed on each field below.
|
||||
*/
|
||||
export interface ShortcutOptions {
|
||||
/**
|
||||
* Whether the shortcut is live. Defaults to `true`.
|
||||
*
|
||||
* Conjunctive with the user's global enable/disable preference: if the user
|
||||
* has disabled a shortcut in Account → Preferences, passing `enabled: true`
|
||||
* here will NOT re-enable it. Use this to gate the shortcut on local
|
||||
* conditions (e.g. `enabled: hasUnsavedChanges`).
|
||||
*/
|
||||
enabled?: boolean
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds between consecutive keys in a multi-step
|
||||
* sequence. Defaults to `undefined`, which falls through to TanStack's
|
||||
* library default (1000ms).
|
||||
*
|
||||
* Only meaningful for multi-step sequences like `['G', 'G']`. Single-step
|
||||
* shortcuts ignore this.
|
||||
*/
|
||||
timeout?: number
|
||||
|
||||
/**
|
||||
* When `true`, the shortcut also appears as an entry in the Cmd+P command
|
||||
* menu (under the "Shortcuts" section) for as long as the hook is mounted.
|
||||
* The entry's label comes from `ShortcutDefinition.label` and the keybind
|
||||
* is rendered from `ShortcutDefinition.sequence`.
|
||||
*
|
||||
* Defaults to `false` — opt-in per call site so Cmd+P doesn't fill up with
|
||||
* context-specific shortcuts that only make sense in certain views.
|
||||
*/
|
||||
registerInCommandMenu?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* A single entry in the shortcut registry. Every shortcut the app uses must
|
||||
* have a matching definition in `SHORTCUT_DEFINITIONS`.
|
||||
*
|
||||
* The registry is the single source of truth for:
|
||||
* - the keybind (`sequence`) — used by the hotkey listener AND the Cmd+P badge
|
||||
* - the human-readable `label` — shown in Cmd+P and in the preferences UI
|
||||
* - per-shortcut default `options` — overridable per call site
|
||||
*/
|
||||
export interface ShortcutDefinition {
|
||||
/** Stable unique identifier. Must match the key used in `SHORTCUT_IDS`. */
|
||||
id: string
|
||||
|
||||
/** Human-readable label shown in the command menu and preferences UI. */
|
||||
label: string
|
||||
|
||||
/**
|
||||
* Keybind as a TanStack Hotkeys sequence — an array of one or more hotkey
|
||||
* strings. Single-step: `['Mod+Shift+M']`. Multi-step (chord): `['G', 'G']`.
|
||||
*
|
||||
* Use `Mod` for the platform modifier (⌘ on macOS, Ctrl elsewhere). Supports
|
||||
* `Shift`, `Alt`, `Ctrl` (literal), named keys (`Enter`, `Escape`, arrows),
|
||||
* and single character keys.
|
||||
*/
|
||||
sequence: HotkeySequence
|
||||
|
||||
/**
|
||||
* Default runtime options applied when the shortcut is mounted. Each field
|
||||
* is overridable by the caller of `useShortcut`.
|
||||
*/
|
||||
options?: ShortcutOptions
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import type { ShortcutId } from './registry'
|
||||
import { useShortcutPreferences } from './state'
|
||||
|
||||
/**
|
||||
* Reactive check for whether a shortcut is currently enabled for the user.
|
||||
*
|
||||
* Subscribes the calling component to the shortcut preferences query so it
|
||||
* re-renders when the user toggles this shortcut in Account → Preferences.
|
||||
*
|
||||
* For one-off, non-reactive checks outside render (event handlers, module-level
|
||||
* code), use the plain `isShortcutEnabled(id)` function from `./state` instead.
|
||||
*
|
||||
* @example
|
||||
* const isEnabled = useIsShortcutEnabled(SHORTCUT_IDS.AI_ASSISTANT_TOGGLE)
|
||||
* return <Tooltip>{isEnabled && <KeyboardShortcut keys={['Meta', 'I']} />}</Tooltip>
|
||||
*/
|
||||
export function useIsShortcutEnabled(id: ShortcutId): boolean {
|
||||
const { disabled } = useShortcutPreferences()
|
||||
return !disabled[id]
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import { useHotkeySequence } from '@tanstack/react-hotkeys'
|
||||
import { Fragment, useCallback } from 'react'
|
||||
import { KeyboardShortcut } from 'ui'
|
||||
import { useRegisterCommands } from 'ui-patterns/CommandMenu'
|
||||
|
||||
import { SHORTCUT_DEFINITIONS, type ShortcutId } from './registry'
|
||||
import type { ShortcutOptions } from './types'
|
||||
import { useIsShortcutEnabled } from './useIsShortcutEnabled'
|
||||
import { COMMAND_MENU_SECTIONS } from '@/components/interfaces/App/CommandMenu/CommandMenu.utils'
|
||||
import useLatest from '@/hooks/misc/useLatest'
|
||||
|
||||
const hotkeyToKeys = (hotkey: string): string[] =>
|
||||
hotkey.split('+').map((part) => (part === 'Mod' ? 'Meta' : part))
|
||||
|
||||
/**
|
||||
* Subscribe to a registered keyboard shortcut.
|
||||
*
|
||||
* Looks up the shortcut's `sequence` and `label` from `SHORTCUT_DEFINITIONS`,
|
||||
* wires up a global hotkey listener via `@tanstack/react-hotkeys`, and
|
||||
* (optionally) registers the shortcut as an entry in the Cmd+P command menu
|
||||
* under the "Shortcuts" section for as long as the hook is mounted.
|
||||
*
|
||||
* Option resolution priority (highest first):
|
||||
* 1. `options` passed to this hook
|
||||
* 2. `def.options` from the registry entry
|
||||
* 3. Hard-coded fallbacks (`enabled: true`, `timeout: undefined`, `registerInCommandMenu: false`)
|
||||
*
|
||||
* `enabled` is ANDed with the user's global enable/disable preference — if the
|
||||
* user has disabled the shortcut in Preferences, it won't fire even if the
|
||||
* caller or registry say `enabled: true`.
|
||||
*
|
||||
* @param id The registered shortcut to bind to. See `SHORTCUT_IDS`.
|
||||
* @param callback Runs when the sequence matches. Always calls the latest
|
||||
* reference — no stale closure issues.
|
||||
* @param options Per-mount overrides. See `ShortcutOptions`.
|
||||
*
|
||||
* @example
|
||||
* useShortcut(SHORTCUT_IDS.RESULTS_COPY_MARKDOWN, handleCopy)
|
||||
*
|
||||
* @example
|
||||
* // Surface in Cmd+P while this component is mounted:
|
||||
* useShortcut(SHORTCUT_IDS.SQL_EDITOR_RUN, runQuery, {
|
||||
* registerInCommandMenu: true,
|
||||
* })
|
||||
*
|
||||
* @example
|
||||
* // Gate on local state — disables hotkey AND hides Cmd+P entry when false:
|
||||
* useShortcut(SHORTCUT_IDS.SAVE, handleSave, {
|
||||
* enabled: hasUnsavedChanges,
|
||||
* registerInCommandMenu: true,
|
||||
* })
|
||||
*/
|
||||
export function useShortcut(id: ShortcutId, callback: () => void, options?: ShortcutOptions) {
|
||||
const def = SHORTCUT_DEFINITIONS[id]
|
||||
|
||||
// Handle override for the shortcut
|
||||
const globallyEnabled = useIsShortcutEnabled(id)
|
||||
const callerEnabled = options?.enabled ?? def.options?.enabled ?? true
|
||||
const enabled = globallyEnabled && callerEnabled
|
||||
const timeout = options?.timeout ?? def.options?.timeout ?? undefined
|
||||
|
||||
useHotkeySequence(def.sequence, callback, { enabled, timeout })
|
||||
|
||||
// Handle overrides for command menu
|
||||
const enabledInCommandMenu = enabled && (options?.registerInCommandMenu ?? false)
|
||||
const depsInCommandMenu = [enabled, def.label]
|
||||
const callbackRef = useLatest(callback)
|
||||
const stableAction = useCallback(() => callbackRef.current(), [callbackRef])
|
||||
|
||||
useRegisterCommands(
|
||||
COMMAND_MENU_SECTIONS.SHORTCUTS,
|
||||
[
|
||||
{
|
||||
id,
|
||||
name: def.label,
|
||||
action: stableAction,
|
||||
badge: () => (
|
||||
<div className="flex items-center gap-1">
|
||||
{def.sequence.map((step, i) => (
|
||||
<Fragment key={i}>
|
||||
{i > 0 && <span className="text-foreground-lighter text-[11px]">then</span>}
|
||||
<KeyboardShortcut keys={hotkeyToKeys(step)} />
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
],
|
||||
{
|
||||
enabled: enabledInCommandMenu,
|
||||
deps: depsInCommandMenu,
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -80,6 +80,9 @@ export const LOCAL_STORAGE_KEYS = {
|
||||
// api keys view switcher for new and legacy api keys
|
||||
API_KEYS_VIEW: (ref: string) => `supabase-api-keys-view-${ref}`,
|
||||
|
||||
// Shortcut preferences
|
||||
SHORTCUT_STORAGE_KEY: 'supabase-shortcut-preferences',
|
||||
|
||||
LAST_VISITED_ORGANIZATION: 'last-visited-organization',
|
||||
|
||||
// user impersonation selector previous searches
|
||||
|
||||
Generated
+29
-4
@@ -933,7 +933,7 @@ importers:
|
||||
version: 1.1.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@sentry/nextjs':
|
||||
specifier: 'catalog:'
|
||||
version: 10.27.0(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@16.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)(supports-color@8.1.1)(webpack@5.105.4(esbuild@0.25.2))
|
||||
version: 10.27.0(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@16.2.3(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)(supports-color@8.1.1)(webpack@5.105.4(esbuild@0.25.2))
|
||||
'@std/path':
|
||||
specifier: npm:@jsr/std__path@^1.0.8
|
||||
version: '@jsr/std__path@1.0.8'
|
||||
@@ -967,6 +967,9 @@ importers:
|
||||
'@supabase/supabase-js':
|
||||
specifier: 'catalog:'
|
||||
version: 2.103.2
|
||||
'@tanstack/react-hotkeys':
|
||||
specifier: ^0.9.1
|
||||
version: 0.9.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@tanstack/react-query':
|
||||
specifier: ^5.0.0
|
||||
version: 5.83.0(react@18.3.1)
|
||||
@@ -1086,7 +1089,7 @@ importers:
|
||||
version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
nuqs:
|
||||
specifier: 2.7.1
|
||||
version: 2.7.1(@tanstack/react-router@1.168.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@16.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react-router@7.13.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
version: 2.7.1(@tanstack/react-router@1.168.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@16.2.3(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react-router@7.13.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
openai:
|
||||
specifier: ^4.104.0
|
||||
version: 4.104.0(encoding@0.1.13)(ws@8.19.0)(zod@3.25.76)
|
||||
@@ -8945,12 +8948,23 @@ packages:
|
||||
resolution: {integrity: sha512-NaOGLRrddszbQj9upGat6HG/4TKvXLvu+osAIgfxPYA+eIvYKv8GKDJOrY2D3/U9MRnKfMWD7bU4jeD4xmqyIg==}
|
||||
engines: {node: '>=20.19'}
|
||||
|
||||
'@tanstack/hotkeys@0.7.1':
|
||||
resolution: {integrity: sha512-YHVO1z6wnvUCu7bg870Kv5k2D+FIuIOSIcbN0dAmTTsJ3mLMDLwcTVx0qVaq+SZp1B514JJTqGVstvUp85yIpQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@tanstack/query-core@5.83.0':
|
||||
resolution: {integrity: sha512-0M8dA+amXUkyz5cVUm/B+zSk3xkQAcuXuz5/Q/LveT4ots2rBpPTZOzd7yJa2Utsf8D2Upl5KyjhHRY+9lB/XA==}
|
||||
|
||||
'@tanstack/query-devtools@5.90.1':
|
||||
resolution: {integrity: sha512-GtINOPjPUH0OegJExZ70UahT9ykmAhmtNVcmtdnOZbxLwT7R5OmRztR5Ahe3/Cu7LArEmR6/588tAycuaWb1xQ==}
|
||||
|
||||
'@tanstack/react-hotkeys@0.9.1':
|
||||
resolution: {integrity: sha512-/qdQUUVkYAHAWRGdFXqFgWpW/S+a6OzkvxWNWKLLDHQODJlO6EPBPa073CglaafBfzig58RK07T09ET+NnZhpg==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
react: '>=16.8'
|
||||
react-dom: '>=16.8'
|
||||
|
||||
'@tanstack/react-query-devtools@5.90.2':
|
||||
resolution: {integrity: sha512-vAXJzZuBXtCQtrY3F/yUNJCV4obT/A/n81kb3+YqLbro5Z2+phdAbceO+deU3ywPw8B42oyJlp4FhO0SoivDFQ==}
|
||||
peerDependencies:
|
||||
@@ -25761,7 +25775,7 @@ snapshots:
|
||||
- supports-color
|
||||
- webpack
|
||||
|
||||
'@sentry/nextjs@10.27.0(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@16.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)(supports-color@8.1.1)(webpack@5.105.4(esbuild@0.25.2))':
|
||||
'@sentry/nextjs@10.27.0(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@16.2.3(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)(supports-color@8.1.1)(webpack@5.105.4(esbuild@0.25.2))':
|
||||
dependencies:
|
||||
'@opentelemetry/api': 1.9.0
|
||||
'@opentelemetry/semantic-conventions': 1.38.0
|
||||
@@ -26519,10 +26533,21 @@ snapshots:
|
||||
|
||||
'@tanstack/history@1.161.6': {}
|
||||
|
||||
'@tanstack/hotkeys@0.7.1':
|
||||
dependencies:
|
||||
'@tanstack/store': 0.9.3
|
||||
|
||||
'@tanstack/query-core@5.83.0': {}
|
||||
|
||||
'@tanstack/query-devtools@5.90.1': {}
|
||||
|
||||
'@tanstack/react-hotkeys@0.9.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@tanstack/hotkeys': 0.7.1
|
||||
'@tanstack/react-store': 0.9.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
'@tanstack/react-query-devtools@5.90.2(@tanstack/react-query@5.83.0(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@tanstack/query-devtools': 5.90.1
|
||||
@@ -34199,7 +34224,7 @@ snapshots:
|
||||
mitt: 3.0.1
|
||||
next: 15.5.15(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4)
|
||||
|
||||
nuqs@2.7.1(@tanstack/react-router@1.168.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@16.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react-router@7.13.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1):
|
||||
nuqs@2.7.1(@tanstack/react-router@1.168.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(next@16.2.3(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react-router@7.13.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@standard-schema/spec': 1.0.0
|
||||
react: 18.3.1
|
||||
|
||||
Reference in new issue
Block a user