From 48d23cd74429fbd3672f09b7830f981e0d0d42cd Mon Sep 17 00:00:00 2001 From: Joel Date: Tue, 21 Apr 2026 15:57:16 +0800 Subject: [PATCH 1/6] feat: support slash variable filtering in prompt editor (#35460) --- .../prompt-editor/__tests__/hooks.spec.tsx | 10 +-- .../components/base/prompt-editor/hooks.ts | 7 +- .../__tests__/index.spec.tsx | 78 +++++++++++++++++++ .../plugins/component-picker-block/index.tsx | 21 +++-- .../var-reference-vars.helpers.spec.ts | 23 ++++++ .../__tests__/var-reference-vars.spec.tsx | 28 +++++++ .../variable/var-reference-vars.helpers.ts | 50 +++++++++++- .../variable/var-reference-vars.tsx | 13 ++-- 8 files changed, 210 insertions(+), 20 deletions(-) diff --git a/web/app/components/base/prompt-editor/__tests__/hooks.spec.tsx b/web/app/components/base/prompt-editor/__tests__/hooks.spec.tsx index 9917918628..13c0c05803 100644 --- a/web/app/components/base/prompt-editor/__tests__/hooks.spec.tsx +++ b/web/app/components/base/prompt-editor/__tests__/hooks.spec.tsx @@ -423,11 +423,11 @@ describe('prompt-editor/hooks', () => { maxLength: 5, })) - const match = result.current('prefix @..', {} as LexicalEditor) + const match = result.current('prefix @ab', {} as LexicalEditor) expect(match).toEqual({ leadOffset: 7, - matchingString: '..', - replaceableString: '@..', + matchingString: 'ab', + replaceableString: '@ab', }) }) @@ -437,7 +437,7 @@ describe('prompt-editor/hooks', () => { maxLength: 5, })) - expect(result.current('prefix @.', {} as LexicalEditor)).toBeNull() + expect(result.current('prefix @a', {} as LexicalEditor)).toBeNull() }) it('should return null when matching text exceeds maxLength', () => { @@ -445,7 +445,7 @@ describe('prompt-editor/hooks', () => { minLength: 1, maxLength: 2, })) - expect(result.current('prefix @...', {} as LexicalEditor)).toBeNull() + expect(result.current('prefix @abc', {} as LexicalEditor)).toBeNull() }) it('should return null when text has no trigger character', () => { diff --git a/web/app/components/base/prompt-editor/hooks.ts b/web/app/components/base/prompt-editor/hooks.ts index dd6c6295a6..70869d6a17 100644 --- a/web/app/components/base/prompt-editor/hooks.ts +++ b/web/app/components/base/prompt-editor/hooks.ts @@ -154,17 +154,18 @@ type TriggerFn = ( text: string, editor: LexicalEditor, ) => MenuTextMatch | null -const PUNCTUATION = '\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%\'"~=<>_:;' +const escapeForCharacterClass = (value: string) => value.replace(/[[\]\\^-]/g, '\\$&') export function useBasicTypeaheadTriggerMatch( trigger: string, { minLength = 1, maxLength = 75 }: { minLength?: number, maxLength?: number }, ): TriggerFn { return useCallback( (text: string) => { - const validChars = `[${PUNCTUATION}\\s]` + const escapedTrigger = escapeForCharacterClass(trigger) + const validChars = `[^${escapedTrigger}\\n\\r]` const TypeaheadTriggerRegex = new RegExp( '(.*)(' - + `[${trigger}]` + + `[${escapedTrigger}]` + `((?:${validChars}){0,${maxLength}})` + ')$', ) diff --git a/web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/index.spec.tsx index 6cc38ad78f..3c734700a7 100644 --- a/web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/index.spec.tsx @@ -521,6 +521,84 @@ describe('ComponentPicker (component-picker-block/index.tsx)', () => { await waitFor(() => expect(readEditorText(editor)).not.toContain('{')) }) + it('filters workflow variables from slash input and matches child paths', async () => { + const captures: Captures = { editor: null, eventEmitter: null } + const user = userEvent.setup() + + const workflowVariableBlock = makeWorkflowVariableBlock({}, [ + makeWorkflowVarNode('node-1', 'Node 1', [ + makeWorkflowNodeVar('payload', VarType.object, [makeWorkflowNodeVar('child_name', VarType.string)]), + makeWorkflowNodeVar('other_value', VarType.string), + ]), + ]) + + render(( + + )) + + const editor = await waitForEditor(captures) + const dispatchSpy = vi.spyOn(editor, 'dispatchCommand') + + await setEditorText(editor, '/child', true) + await flushNextTick() + + expect(screen.queryByPlaceholderText('workflow.common.searchVar')).not.toBeInTheDocument() + expect(await screen.findByText('payload')).toBeInTheDocument() + expect(screen.queryByText('other_value')).not.toBeInTheDocument() + + const label = document.querySelector('[title="payload"]') + expect(label).not.toBeNull() + const row = (label as HTMLElement).parentElement?.parentElement + expect(row).not.toBeNull() + + await user.hover(row as HTMLElement) + const childField = await screen.findByText('child_name') + fireEvent.mouseDown(childField) + await user.unhover(row as HTMLElement) + + expect(dispatchSpy).toHaveBeenCalledWith(INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND, ['node-1', 'payload', 'child_name']) + await waitFor(() => expect(readEditorText(editor)).not.toContain('/child')) + }) + + it('filters workflow variables on the first character after slash and does not highlight context by default', async () => { + const captures: Captures = { editor: null, eventEmitter: null } + + const workflowVariableBlock = makeWorkflowVariableBlock({}, [ + makeWorkflowVarNode('node-1', 'Node 1', [ + makeWorkflowNodeVar('child_value', VarType.string), + makeWorkflowNodeVar('other_value', VarType.string), + ]), + ]) + + render(( + + )) + + const editor = await waitForEditor(captures) + await setEditorText(editor, '/c', true) + await flushNextTick() + + expect(await screen.findByText('child_value')).toBeInTheDocument() + expect(screen.queryByText('other_value')).not.toBeInTheDocument() + + const contextTitle = screen.getByText('common.promptEditor.context.item.title') + expect(contextTitle.closest('[tabindex="-1"]')).not.toHaveClass('bg-state-base-hover!') + + await waitFor(() => { + expect(readEditorText(editor)).toContain('/c') + }) + }) + it('skips removing the trigger when selection is null (needRemove is null) and still dispatches', async () => { const captures: Captures = { editor: null, eventEmitter: null } diff --git a/web/app/components/base/prompt-editor/plugins/component-picker-block/index.tsx b/web/app/components/base/prompt-editor/plugins/component-picker-block/index.tsx index 5903060911..5e983ed09a 100644 --- a/web/app/components/base/prompt-editor/plugins/component-picker-block/index.tsx +++ b/web/app/components/base/prompt-editor/plugins/component-picker-block/index.tsx @@ -1,5 +1,5 @@ import type { MenuRenderFn } from '@lexical/react/LexicalTypeaheadMenuPlugin' -import type { TextNode } from 'lexical' +import type { LexicalEditor, TextNode } from 'lexical' import type { ContextBlockType, CurrentBlockType, @@ -89,10 +89,16 @@ const ComponentPicker = ({ ], }) const [editor] = useLexicalComposerContext() - const checkForTriggerMatch = useBasicTypeaheadTriggerMatch(triggerString, { + const triggerMatchRef = useRef(null) + const baseCheckForTriggerMatch = useBasicTypeaheadTriggerMatch(triggerString, { minLength: 0, - maxLength: 0, + maxLength: 75, }) + const checkForTriggerMatch = useCallback((text: string, editor: LexicalEditor) => { + const match = baseCheckForTriggerMatch(text, editor) + triggerMatchRef.current = match?.matchingString ?? null + return match + }, [baseCheckForTriggerMatch]) const [queryString, setQueryString] = useState(null) const [blurHidden, setBlurHidden] = useState(false) @@ -155,6 +161,7 @@ const ComponentPicker = ({ currentBlock, errorMessageBlock, lastRunBlock, + queryString || undefined, ) const onSelectOption = useCallback( @@ -207,6 +214,8 @@ const ComponentPicker = ({ anchorElementRef, { options, selectedIndex, selectOptionAndCleanUp, setHighlightedIndex }, ) => { + const effectiveQueryString = triggerMatchRef.current ?? queryString + if (blurHidden) return null if (!(anchorElementRef.current && (allFlattenOptions.length || workflowVariableBlock?.show))) @@ -237,6 +246,8 @@ const ComponentPicker = ({ workflowVariableBlock?.show && (
{ @@ -270,8 +281,8 @@ const ComponentPicker = ({ ) } {option.renderMenuOption({ - queryString, - isSelected: selectedIndex === index, + queryString: effectiveQueryString, + isSelected: workflowVariableBlock?.show ? false : selectedIndex === index, onSelect: () => { selectOptionAndCleanUp(option) }, diff --git a/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-vars.helpers.spec.ts b/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-vars.helpers.spec.ts index 773ecacc39..13b7879bad 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-vars.helpers.spec.ts +++ b/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-vars.helpers.spec.ts @@ -81,4 +81,27 @@ describe('var-reference-vars helpers', () => { expect(vars[0]!.title).toBe('Node B') expect(vars[0]!.vars).toEqual([expect.objectContaining({ variable: 'another_value' })]) }) + + it('should keep parent vars when search text matches a child variable', () => { + const vars = filterReferenceVars([ + { + title: 'Node A', + nodeId: 'node-a', + vars: [{ + variable: 'payload', + type: VarType.object, + children: [{ variable: 'child_name', type: VarType.string }], + }], + }, + { + title: 'Node B', + nodeId: 'node-b', + vars: [{ variable: 'other_value', type: VarType.string }], + }, + ] as NodeOutPutVar[], 'child') + + expect(vars).toHaveLength(1) + expect(vars[0]!.title).toBe('Node A') + expect(vars[0]!.vars).toEqual([expect.objectContaining({ variable: 'payload' })]) + }) }) diff --git a/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-vars.spec.tsx b/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-vars.spec.tsx index 93c857223a..372fcb3508 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-vars.spec.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-vars.spec.tsx @@ -199,6 +199,34 @@ describe('VarReferenceVars', () => { })) }) + it('should filter by externally controlled search text and match child variables', () => { + render( + , + ) + + expect(screen.queryByPlaceholderText('workflow.common.searchVar')).not.toBeInTheDocument() + expect(screen.getByText('payload')).toBeInTheDocument() + expect(screen.queryByText('other_value')).not.toBeInTheDocument() + }) + it('should ignore file vars when file support is disabled and forward blur-sm events', () => { const onChange = vi.fn() const onBlur = vi.fn() diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.helpers.ts b/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.helpers.ts index d36dc807a8..a9941bf72c 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.helpers.ts +++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.helpers.ts @@ -1,3 +1,4 @@ +import type { Field, StructuredOutput } from '@/app/components/workflow/nodes/llm/types' import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types' import { VAR_SHOW_NAME_MAP } from '@/app/components/workflow/constants' import { checkKeys } from '@/utils/var' @@ -76,6 +77,51 @@ const getVisibleChildren = (vars: Var[]) => { return vars.filter(variable => checkKeys([variable.variable], false).isValid || isSpecialVar(variable.variable.split('.')[0]!)) } +const includesSearchText = (value: string | undefined, searchTextLower: string) => { + if (!value) + return false + + return value.toLowerCase().includes(searchTextLower) +} + +const isStructuredOutputChildren = (children: Var['children']): children is StructuredOutput => { + return !!children && !Array.isArray(children) && 'schema' in children +} + +const matchesStructuredField = (fieldName: string, field: Field, searchTextLower: string): boolean => { + if (includesSearchText(fieldName, searchTextLower)) + return true + + if (field.properties) + return Object.entries(field.properties).some(([childName, childField]) => matchesStructuredField(childName, childField, searchTextLower)) + + if (field.items) + return matchesStructuredField(field.items.type, field.items, searchTextLower) + + return false +} + +const matchesVariableSearch = (variable: Var, searchTextLower: string): boolean => { + if ( + includesSearchText(variable.variable, searchTextLower) + || includesSearchText(variable.des, searchTextLower) + || includesSearchText(variable.schemaType, searchTextLower) + ) { + return true + } + + if (!variable.children) + return false + + if (Array.isArray(variable.children)) + return getVisibleChildren(variable.children).some(child => matchesVariableSearch(child, searchTextLower)) + + if (isStructuredOutputChildren(variable.children)) + return Object.entries(variable.children.schema.properties).some(([fieldName, field]) => matchesStructuredField(fieldName, field, searchTextLower)) + + return false +} + export const filterReferenceVars = (vars: NodeOutPutVar[], searchText: string) => { const searchTextLower = searchText.toLowerCase() @@ -85,7 +131,7 @@ export const filterReferenceVars = (vars: NodeOutPutVar[], searchText: string) = .filter((node) => { if (!searchText) return true - return node.vars.some(variable => variable.variable.toLowerCase().includes(searchTextLower)) + return node.vars.some(variable => matchesVariableSearch(variable, searchTextLower)) || node.title.toLowerCase().includes(searchTextLower) }) .map((node) => { @@ -94,7 +140,7 @@ export const filterReferenceVars = (vars: NodeOutPutVar[], searchText: string) = return { ...node, - vars: node.vars.filter(variable => variable.variable.toLowerCase().includes(searchTextLower)), + vars: node.vars.filter(variable => matchesVariableSearch(variable, searchTextLower)), } }) } diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx index 5c67723d78..648e795dcc 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx @@ -241,6 +241,7 @@ const Item: FC = ({ type Props = { hideSearch?: boolean + searchText?: string searchBoxClassName?: string vars: NodeOutPutVar[] isSupportFileVar?: boolean @@ -258,6 +259,7 @@ type Props = { } const VarReferenceVars: FC = ({ hideSearch, + searchText, searchBoxClassName, vars, isSupportFileVar, @@ -274,7 +276,8 @@ const VarReferenceVars: FC = ({ preferSchemaType, }) => { const { t } = useTranslation() - const [searchText, setSearchText] = useState('') + const [internalSearchValue, setInternalSearchValue] = useState('') + const searchValue = searchText ?? internalSearchValue const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Escape') { @@ -283,7 +286,7 @@ const VarReferenceVars: FC = ({ } } - const filteredVars = useMemo(() => filterReferenceVars(vars, searchText), [vars, searchText]) + const filteredVars = useMemo(() => filterReferenceVars(vars, searchValue), [vars, searchValue]) return ( <> @@ -295,11 +298,11 @@ const VarReferenceVars: FC = ({ className="var-search-input" showLeftIcon showClearIcon - value={searchText} + value={searchValue} placeholder={t('common.searchVar', { ns: 'workflow' }) || ''} - onChange={e => setSearchText(e.target.value)} + onChange={e => setInternalSearchValue(e.target.value)} onKeyDown={handleKeyDown} - onClear={() => setSearchText('')} + onClear={() => setInternalSearchValue('')} onBlur={onBlur} autoFocus={autoFocus} /> From 73f9a9e7d622931cf87a7a131669621b2fe867fe Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Tue, 21 Apr 2026 16:18:31 +0800 Subject: [PATCH 2/6] chore(deps): bump base ui to 1.4.1 (#35459) --- pnpm-lock.yaml | 26 +++++++++++++++----------- pnpm-workspace.yaml | 2 +- web/eslint.config.mjs | 8 ++++---- web/eslint.constants.mjs | 17 ++++++++++++++++- 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0c276fae9e..0725b3bb7d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,8 +16,8 @@ catalogs: specifier: 8.2.0 version: 8.2.0 '@base-ui/react': - specifier: 1.4.0 - version: 1.4.0 + specifier: 1.4.1 + version: 1.4.1 '@chromatic-com/storybook': specifier: 5.1.2 version: 5.1.2 @@ -643,7 +643,7 @@ importers: devDependencies: '@base-ui/react': specifier: 'catalog:' - version: 1.4.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 1.4.1(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@chromatic-com/storybook': specifier: 'catalog:' version: 5.1.2(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) @@ -790,7 +790,7 @@ importers: version: 1.27.7(@amplitude/rrweb@2.0.0-alpha.37) '@base-ui/react': specifier: 'catalog:' - version: 1.4.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 1.4.1(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@emoji-mart/data': specifier: 'catalog:' version: 1.2.1 @@ -1539,8 +1539,8 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@base-ui/react@1.4.0': - resolution: {integrity: sha512-QcqdVbr/+ba2/RAKJIV1PV6S02Q5+r6a4Eym8ndBw+ZbBILkkmQAyRxXCg/pArrHnkrGeU8goe26aw0h6eE8pg==} + '@base-ui/react@1.4.1': + resolution: {integrity: sha512-Ab5/LIhcmL8BQcsBUYiOfkSDRdLpvgUBzMK30cu684JPcLclYlztharvCZyNNgzJtbAiREzI9q0pI5erHCMgCw==} engines: {node: '>=14.0.0'} peerDependencies: '@date-fns/tz': ^1.2.0 @@ -1549,11 +1549,15 @@ packages: react: ^17 || ^18 || ^19 react-dom: ^17 || ^18 || ^19 peerDependenciesMeta: + '@date-fns/tz': + optional: true '@types/react': optional: true + date-fns: + optional: true - '@base-ui/utils@0.2.7': - resolution: {integrity: sha512-nXYKhiL/0JafyJE8PfcflipGftOftlIwKd72rU15iZ1M5yqgg5J9P8NHU71GReDuXco5MJA/eVQqUT5WRqX9sA==} + '@base-ui/utils@0.2.8': + resolution: {integrity: sha512-jvOi+c+ftGlGotNcKnzPVg2IhCaDTB6/6R3JeqdjdXktuAJi3wKH9T7+svuaKh1mmfVU11UWzUZVH74JDfi/wQ==} peerDependencies: '@types/react': ^17 || ^18 || ^19 react: ^17 || ^18 || ^19 @@ -8622,10 +8626,10 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@base-ui/react@1.4.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + '@base-ui/react@1.4.1(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@base-ui/utils': 0.2.7(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@base-ui/utils': 0.2.8(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@floating-ui/react-dom': 2.1.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@floating-ui/utils': 0.2.11 react: 19.2.5 @@ -8634,7 +8638,7 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - '@base-ui/utils@0.2.7(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + '@base-ui/utils@0.2.8(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 '@floating-ui/utils': 0.2.11 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f02d05b233..5afca57719 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -50,7 +50,7 @@ catalog: '@amplitude/analytics-browser': 2.39.0 '@amplitude/plugin-session-replay-browser': 1.27.7 '@antfu/eslint-config': 8.2.0 - '@base-ui/react': 1.4.0 + '@base-ui/react': 1.4.1 '@chromatic-com/storybook': 5.1.2 '@cucumber/cucumber': 12.8.0 '@egoist/tailwindcss-icons': 1.9.2 diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs index 62cc63536f..2a043ac73d 100644 --- a/web/eslint.config.mjs +++ b/web/eslint.config.mjs @@ -13,9 +13,9 @@ import storybook from 'eslint-plugin-storybook' import { HYOBAN_PREFER_TAILWIND_ICONS_OPTIONS, NEXT_PLATFORM_RESTRICTED_IMPORT_PATHS, - NEXT_PLATFORM_RESTRICTED_IMPORT_PATTERNS, OVERLAY_MIGRATION_LEGACY_BASE_FILES, OVERLAY_RESTRICTED_IMPORT_PATTERNS, + WEB_RESTRICTED_IMPORT_PATTERNS, } from './eslint.constants.mjs' import dify from './plugins/eslint/index.js' @@ -161,13 +161,13 @@ export default antfu( }, }, { - name: 'dify/no-direct-next-imports', + name: 'dify/restricted-imports', files: [GLOB_TS, GLOB_TSX], ignores: ['next/**'], rules: { 'no-restricted-imports': ['error', { paths: NEXT_PLATFORM_RESTRICTED_IMPORT_PATHS, - patterns: NEXT_PLATFORM_RESTRICTED_IMPORT_PATTERNS, + patterns: WEB_RESTRICTED_IMPORT_PATTERNS, }], }, }, @@ -183,7 +183,7 @@ export default antfu( 'no-restricted-imports': ['error', { paths: NEXT_PLATFORM_RESTRICTED_IMPORT_PATHS, patterns: [ - ...NEXT_PLATFORM_RESTRICTED_IMPORT_PATTERNS, + ...WEB_RESTRICTED_IMPORT_PATTERNS, ...OVERLAY_RESTRICTED_IMPORT_PATTERNS, ], }], diff --git a/web/eslint.constants.mjs b/web/eslint.constants.mjs index 1c09cbcb23..1039a300ec 100644 --- a/web/eslint.constants.mjs +++ b/web/eslint.constants.mjs @@ -5,7 +5,7 @@ export const NEXT_PLATFORM_RESTRICTED_IMPORT_PATHS = [ }, ] -export const NEXT_PLATFORM_RESTRICTED_IMPORT_PATTERNS = [ +const NEXT_PLATFORM_RESTRICTED_IMPORT_PATTERNS = [ { group: ['next/image'], message: 'Do not import next/image. Use native img tags instead.', @@ -20,6 +20,21 @@ export const NEXT_PLATFORM_RESTRICTED_IMPORT_PATTERNS = [ }, ] +const BASE_UI_RESTRICTED_IMPORT_PATTERNS = [ + { + group: [ + '@base-ui/react', + '@base-ui/react/*', + ], + message: 'Do not import Base UI directly in web. Use @langgenius/dify-ui/* primitives instead.', + }, +] + +export const WEB_RESTRICTED_IMPORT_PATTERNS = [ + ...NEXT_PLATFORM_RESTRICTED_IMPORT_PATTERNS, + ...BASE_UI_RESTRICTED_IMPORT_PATTERNS, +] + export const OVERLAY_RESTRICTED_IMPORT_PATTERNS = [ { group: [ From 5e5113e08e52f21e32a9b82fde6c88fd3831864d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2026 17:59:59 +0900 Subject: [PATCH 3/6] chore(deps-dev): bump the dev group in /api with 6 updates (#35402) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- api/pyproject.toml | 12 +++---- api/uv.lock | 80 +++++++++++++++++++++++----------------------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/api/pyproject.toml b/api/pyproject.toml index b13c744f0a..fbd5d394ad 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -114,10 +114,10 @@ override-dependencies = [ dev = [ "coverage>=7.13.4", "dotenv-linter>=0.7.0", - "faker>=20.1.0", + "faker>=40.15.0", "lxml-stubs>=0.5.1", - "basedpyright>=1.39.0", - "ruff>=0.15.10", + "basedpyright>=1.39.3", + "ruff>=0.15.11", "pytest>=9.0.3", "pytest-benchmark>=5.2.3", "pytest-cov>=7.1.0", @@ -157,14 +157,14 @@ dev = [ "types-tensorflow>=2.18.0.20260408", "types-tqdm>=4.67.3.20260408", "types-ujson>=5.10.0", - "boto3-stubs>=1.42.88", + "boto3-stubs>=1.42.92", "types-jmespath>=1.1.0.20260408", - "hypothesis>=6.151.12", + "hypothesis>=6.152.1", "types_pyOpenSSL>=24.1.0", "types_cffi>=2.0.0.20260408", "types_setuptools>=82.0.0.20260408", "pandas-stubs>=3.0.0", - "scipy-stubs>=1.15.3.0", + "scipy-stubs>=1.17.1.4", "types-python-http-client>=3.3.7.20260408", "import-linter>=2.3", "types-redis>=4.6.0.20241004", diff --git a/api/uv.lock b/api/uv.lock index 40d196a160..bab24a87d2 100644 --- a/api/uv.lock +++ b/api/uv.lock @@ -469,14 +469,14 @@ wheels = [ [[package]] name = "basedpyright" -version = "1.39.0" +version = "1.39.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nodejs-wheel-binaries" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ac/f4/4a77cc1ffb3dab7391642cde30163961d8ee973e9e6b6740c7d15aa3d3ba/basedpyright-1.39.0.tar.gz", hash = "sha256:6666f51c378c7ac45877c4c1c7041ee0b5b83d755ebc82f898f47b6fafe0cc4f", size = 25357403, upload-time = "2026-04-01T12:27:41.92Z" } +sdist = { url = "https://files.pythonhosted.org/packages/04/19/5a5b9b9197973da732638957be3a65cf514d2f5a4964eeedbf33b6c65bbd/basedpyright-1.39.3.tar.gz", hash = "sha256:2f794e6b5f4260fb89f614ca6cd23c6f305373bb6b50c4ed7794ff2ae647fb14", size = 25503187, upload-time = "2026-04-20T22:14:47.424Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/97/47/08145d1bcc3083ed20059bdecbde404bd767f91b91e2764ec01cffec9f4b/basedpyright-1.39.0-py3-none-any.whl", hash = "sha256:91b8ad50bc85ee4a985b928f9368c35c99eee5a56c44e99b2442fa12ecc3d670", size = 12353868, upload-time = "2026-04-01T12:27:38.495Z" }, + { url = "https://files.pythonhosted.org/packages/54/5c/f950c1239ad26f3bb453e665428a2cf1893995de725a5eb0b64a2520b366/basedpyright-1.39.3-py3-none-any.whl", hash = "sha256:aba760dc83307727554f936d6b4381caa14482f30dbc2173167710e217c1f7ab", size = 12419181, upload-time = "2026-04-20T22:14:51.975Z" }, ] [[package]] @@ -618,15 +618,15 @@ wheels = [ [[package]] name = "boto3-stubs" -version = "1.42.88" +version = "1.42.92" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore-stubs" }, { name = "types-s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/c7/d4dfbb4757cd72fd350ba666902ec3ac19e04d6be639e96cdad4543d4726/boto3_stubs-1.42.88.tar.gz", hash = "sha256:85215fb4938a94d1cf83cd8632f46ae7728b5ec88187d83468f393bbe64236d6", size = 102495, upload-time = "2026-04-10T19:55:57.526Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/b4/7f472d64a89f6aa6b8e8eeadc876667b7e4edfb526c6118efe2b2c98ba17/boto3_stubs-1.42.92.tar.gz", hash = "sha256:4bc934069c5e8c7b3cdd2442569dae14e8272fe207d445bd38aa578b8463638f", size = 102696, upload-time = "2026-04-20T19:55:19.858Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/6f/3befd72080aedbb4ad26b353a6e364645668664930ce49668fd0bab8f2b5/boto3_stubs-1.42.88-py3-none-any.whl", hash = "sha256:9e74350715ca8ccd63fc250f8eca9fa3161b3d1704339554344d72e4e21c5ed1", size = 70603, upload-time = "2026-04-10T19:55:49.921Z" }, + { url = "https://files.pythonhosted.org/packages/6c/ce/2fe2c6456f8dc0b8bb8d80e05e154c7975ec058991bedf54f3aeed634b79/boto3_stubs-1.42.92-py3-none-any.whl", hash = "sha256:b3994e60f0133b2dd3d9a88ceaeef48fa6367d9a9429426e919575768a1ad9c6", size = 70666, upload-time = "2026-04-20T19:55:16.398Z" }, ] [package.optional-dependencies] @@ -1616,13 +1616,13 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "basedpyright", specifier = ">=1.39.0" }, - { name = "boto3-stubs", specifier = ">=1.42.88" }, + { name = "basedpyright", specifier = ">=1.39.3" }, + { name = "boto3-stubs", specifier = ">=1.42.92" }, { name = "celery-types", specifier = ">=0.23.0" }, { name = "coverage", specifier = ">=7.13.4" }, { name = "dotenv-linter", specifier = ">=0.7.0" }, - { name = "faker", specifier = ">=20.1.0" }, - { name = "hypothesis", specifier = ">=6.151.12" }, + { name = "faker", specifier = ">=40.15.0" }, + { name = "hypothesis", specifier = ">=6.152.1" }, { name = "import-linter", specifier = ">=2.3" }, { name = "lxml-stubs", specifier = ">=0.5.1" }, { name = "mypy", specifier = ">=1.20.1" }, @@ -1635,8 +1635,8 @@ dev = [ { name = "pytest-mock", specifier = ">=3.15.1" }, { name = "pytest-timeout", specifier = ">=2.4.0" }, { name = "pytest-xdist", specifier = ">=3.8.0" }, - { name = "ruff", specifier = ">=0.15.10" }, - { name = "scipy-stubs", specifier = ">=1.15.3.0" }, + { name = "ruff", specifier = ">=0.15.11" }, + { name = "scipy-stubs", specifier = ">=1.17.1.4" }, { name = "testcontainers", specifier = ">=4.14.2" }, { name = "types-aiofiles", specifier = ">=25.1.0" }, { name = "types-beautifulsoup4", specifier = ">=4.12.0" }, @@ -2351,14 +2351,14 @@ wheels = [ [[package]] name = "faker" -version = "40.13.0" +version = "40.15.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tzdata", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/89/95/4822ffe94723553789aef783104f4f18fc20d7c4c68e1bbd633e11d09758/faker-40.13.0.tar.gz", hash = "sha256:a0751c84c3abac17327d7bb4c98e8afe70ebf7821e01dd7d0b15cd8856415525", size = 1962043, upload-time = "2026-04-06T16:44:55.68Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7f/13/6741787bd91c4109c7bed047d68273965cd52ce8a5f773c471b949334b6d/faker-40.15.0.tar.gz", hash = "sha256:20f3a6ec8c266b74d4c554e34118b21c3c2056c0b4a519d15c8decb3a4e6e795", size = 1967447, upload-time = "2026-04-17T20:05:27.555Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/da/8a/708103325edff16a0b0e004de0d37db8ba216a32713948c64d71f6d4a4c2/faker-40.13.0-py3-none-any.whl", hash = "sha256:c1298fd0d819b3688fb5fd358c4ba8f56c7c8c740b411fd3dbd8e30bf2c05019", size = 1994597, upload-time = "2026-04-06T16:44:53.698Z" }, + { url = "https://files.pythonhosted.org/packages/a7/a7/a600f8f30d4505e89166de51dd121bd540ab8e560e8cf0901de00a81de8c/faker-40.15.0-py3-none-any.whl", hash = "sha256:71ab3c3370da9d2205ab74ffb0fd51273063ad562b3a3bb69d0026a20923e318", size = 2004447, upload-time = "2026-04-17T20:05:25.437Z" }, ] [[package]] @@ -3317,14 +3317,14 @@ wheels = [ [[package]] name = "hypothesis" -version = "6.151.12" +version = "6.152.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sortedcontainers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ce/ab/67ca321d1ab96fd3828b12142f1c258e2d4a668a025d06cd50ab3409787f/hypothesis-6.151.12.tar.gz", hash = "sha256:be485f503979af4c3dfa19e3fc2b967d0458e7f8c4e28128d7e215e0a55102e0", size = 463900, upload-time = "2026-04-08T19:40:06.205Z" } +sdist = { url = "https://files.pythonhosted.org/packages/64/b1/c32bcddb9aab9e3abc700f1f56faf14e7655c64a16ca47701a57362276ea/hypothesis-6.152.1.tar.gz", hash = "sha256:4f4ed934eee295dd84ee97592477d23e8dc03e9f12ae0ee30a4e7c9ef3fca3b0", size = 465029, upload-time = "2026-04-14T22:29:24.062Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/5a/6cecf134b631050a1f8605096adbe812483b60790d951470989d39b56860/hypothesis-6.151.12-py3-none-any.whl", hash = "sha256:37d4f3a768365c30571b11dfd7a6857a12173d933010b2c4ab65619f1b5952c5", size = 529656, upload-time = "2026-04-08T19:40:03.126Z" }, + { url = "https://files.pythonhosted.org/packages/5d/83/860fb3075e00b0fc19a22a2301bc3c96f00437558c3911bdd0a3573a4a53/hypothesis-6.152.1-py3-none-any.whl", hash = "sha256:40a3619d9e0cb97b018857c7986f75cf5de2e5ec0fa8a0b172d00747758f749e", size = 530752, upload-time = "2026-04-14T22:29:20.893Z" }, ] [[package]] @@ -5887,27 +5887,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.10" +version = "0.15.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/d9/aa3f7d59a10ef6b14fe3431706f854dbf03c5976be614a9796d36326810c/ruff-0.15.10.tar.gz", hash = "sha256:d1f86e67ebfdef88e00faefa1552b5e510e1d35f3be7d423dc7e84e63788c94e", size = 4631728, upload-time = "2026-04-09T14:06:09.884Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/8d/192f3d7103816158dfd5ea50d098ef2aec19194e6cbccd4b3485bdb2eb2d/ruff-0.15.11.tar.gz", hash = "sha256:f092b21708bf0e7437ce9ada249dfe688ff9a0954fc94abab05dcea7dcd29c33", size = 4637264, upload-time = "2026-04-16T18:46:26.58Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/00/a1c2fdc9939b2c03691edbda290afcd297f1f389196172826b03d6b6a595/ruff-0.15.10-py3-none-linux_armv6l.whl", hash = "sha256:0744e31482f8f7d0d10a11fcbf897af272fefdfcb10f5af907b18c2813ff4d5f", size = 10563362, upload-time = "2026-04-09T14:06:21.189Z" }, - { url = "https://files.pythonhosted.org/packages/5c/15/006990029aea0bebe9d33c73c3e28c80c391ebdba408d1b08496f00d422d/ruff-0.15.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b1e7c16ea0ff5a53b7c2df52d947e685973049be1cdfe2b59a9c43601897b22e", size = 10951122, upload-time = "2026-04-09T14:06:02.236Z" }, - { url = "https://files.pythonhosted.org/packages/f2/c0/4ac978fe874d0618c7da647862afe697b281c2806f13ce904ad652fa87e4/ruff-0.15.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:93cc06a19e5155b4441dd72808fdf84290d84ad8a39ca3b0f994363ade4cebb1", size = 10314005, upload-time = "2026-04-09T14:06:00.026Z" }, - { url = "https://files.pythonhosted.org/packages/da/73/c209138a5c98c0d321266372fc4e33ad43d506d7e5dd817dd89b60a8548f/ruff-0.15.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83e1dd04312997c99ea6965df66a14fb4f03ba978564574ffc68b0d61fd3989e", size = 10643450, upload-time = "2026-04-09T14:05:42.137Z" }, - { url = "https://files.pythonhosted.org/packages/ec/76/0deec355d8ec10709653635b1f90856735302cb8e149acfdf6f82a5feb70/ruff-0.15.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8154d43684e4333360fedd11aaa40b1b08a4e37d8ffa9d95fee6fa5b37b6fab1", size = 10379597, upload-time = "2026-04-09T14:05:49.984Z" }, - { url = "https://files.pythonhosted.org/packages/dc/be/86bba8fc8798c081e28a4b3bb6d143ccad3fd5f6f024f02002b8f08a9fa3/ruff-0.15.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ab88715f3a6deb6bde6c227f3a123410bec7b855c3ae331b4c006189e895cef", size = 11146645, upload-time = "2026-04-09T14:06:12.246Z" }, - { url = "https://files.pythonhosted.org/packages/a8/89/140025e65911b281c57be1d385ba1d932c2366ca88ae6663685aed8d4881/ruff-0.15.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a768ff5969b4f44c349d48edf4ab4f91eddb27fd9d77799598e130fb628aa158", size = 12030289, upload-time = "2026-04-09T14:06:04.776Z" }, - { url = "https://files.pythonhosted.org/packages/88/de/ddacca9545a5e01332567db01d44bd8cf725f2db3b3d61a80550b48308ea/ruff-0.15.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ee3ef42dab7078bda5ff6a1bcba8539e9857deb447132ad5566a038674540d0", size = 11496266, upload-time = "2026-04-09T14:05:55.485Z" }, - { url = "https://files.pythonhosted.org/packages/bc/bb/7ddb00a83760ff4a83c4e2fc231fd63937cc7317c10c82f583302e0f6586/ruff-0.15.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51cb8cc943e891ba99989dd92d61e29b1d231e14811db9be6440ecf25d5c1609", size = 11256418, upload-time = "2026-04-09T14:05:57.69Z" }, - { url = "https://files.pythonhosted.org/packages/dc/8d/55de0d35aacf6cd50b6ee91ee0f291672080021896543776f4170fc5c454/ruff-0.15.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e59c9bdc056a320fb9ea1700a8d591718b8faf78af065484e801258d3a76bc3f", size = 11288416, upload-time = "2026-04-09T14:05:44.695Z" }, - { url = "https://files.pythonhosted.org/packages/68/cf/9438b1a27426ec46a80e0a718093c7f958ef72f43eb3111862949ead3cc1/ruff-0.15.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:136c00ca2f47b0018b073f28cb5c1506642a830ea941a60354b0e8bc8076b151", size = 10621053, upload-time = "2026-04-09T14:05:52.782Z" }, - { url = "https://files.pythonhosted.org/packages/4c/50/e29be6e2c135e9cd4cb15fbade49d6a2717e009dff3766dd080fcb82e251/ruff-0.15.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8b80a2f3c9c8a950d6237f2ca12b206bccff626139be9fa005f14feb881a1ae8", size = 10378302, upload-time = "2026-04-09T14:06:14.361Z" }, - { url = "https://files.pythonhosted.org/packages/18/2f/e0b36a6f99c51bb89f3a30239bc7bf97e87a37ae80aa2d6542d6e5150364/ruff-0.15.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e3e53c588164dc025b671c9df2462429d60357ea91af7e92e9d56c565a9f1b07", size = 10850074, upload-time = "2026-04-09T14:06:16.581Z" }, - { url = "https://files.pythonhosted.org/packages/11/08/874da392558ce087a0f9b709dc6ec0d60cbc694c1c772dab8d5f31efe8cb/ruff-0.15.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b0c52744cf9f143a393e284125d2576140b68264a93c6716464e129a3e9adb48", size = 11358051, upload-time = "2026-04-09T14:06:18.948Z" }, - { url = "https://files.pythonhosted.org/packages/e4/46/602938f030adfa043e67112b73821024dc79f3ab4df5474c25fa4c1d2d14/ruff-0.15.10-py3-none-win32.whl", hash = "sha256:d4272e87e801e9a27a2e8df7b21011c909d9ddd82f4f3281d269b6ba19789ca5", size = 10588964, upload-time = "2026-04-09T14:06:07.14Z" }, - { url = "https://files.pythonhosted.org/packages/25/b6/261225b875d7a13b33a6d02508c39c28450b2041bb01d0f7f1a83d569512/ruff-0.15.10-py3-none-win_amd64.whl", hash = "sha256:28cb32d53203242d403d819fd6983152489b12e4a3ae44993543d6fe62ab42ed", size = 11745044, upload-time = "2026-04-09T14:05:39.473Z" }, - { url = "https://files.pythonhosted.org/packages/58/ed/dea90a65b7d9e69888890fb14c90d7f51bf0c1e82ad800aeb0160e4bacfd/ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188", size = 11035607, upload-time = "2026-04-09T14:05:47.593Z" }, + { url = "https://files.pythonhosted.org/packages/02/1e/6aca3427f751295ab011828e15e9bf452200ac74484f1db4be0197b8170b/ruff-0.15.11-py3-none-linux_armv6l.whl", hash = "sha256:e927cfff503135c558eb581a0c9792264aae9507904eb27809cdcff2f2c847b7", size = 10607943, upload-time = "2026-04-16T18:46:05.967Z" }, + { url = "https://files.pythonhosted.org/packages/e7/26/1341c262e74f36d4e84f3d6f4df0ac68cd53331a66bfc5080daa17c84c0b/ruff-0.15.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7a1b5b2938d8f890b76084d4fa843604d787a912541eae85fd7e233398bbb73e", size = 10988592, upload-time = "2026-04-16T18:46:00.742Z" }, + { url = "https://files.pythonhosted.org/packages/03/71/850b1d6ffa9564fbb6740429bad53df1094082fe515c8c1e74b6d8d05f18/ruff-0.15.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d4176f3d194afbdaee6e41b9ccb1a2c287dba8700047df474abfbe773825d1cb", size = 10338501, upload-time = "2026-04-16T18:46:03.723Z" }, + { url = "https://files.pythonhosted.org/packages/f2/11/cc1284d3e298c45a817a6aadb6c3e1d70b45c9b36d8d9cce3387b495a03a/ruff-0.15.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b17c886fb88203ced3afe7f14e8d5ae96e9d2f4ccc0ee66aa19f2c2675a27e4", size = 10670693, upload-time = "2026-04-16T18:46:41.941Z" }, + { url = "https://files.pythonhosted.org/packages/ce/9e/f8288b034ab72b371513c13f9a41d9ba3effac54e24bfb467b007daee2ca/ruff-0.15.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:49fafa220220afe7758a487b048de4c8f9f767f37dfefad46b9dd06759d003eb", size = 10416177, upload-time = "2026-04-16T18:46:21.717Z" }, + { url = "https://files.pythonhosted.org/packages/85/71/504d79abfd3d92532ba6bbe3d1c19fada03e494332a59e37c7c2dabae427/ruff-0.15.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2ab8427e74a00d93b8bda1307b1e60970d40f304af38bccb218e056c220120d", size = 11221886, upload-time = "2026-04-16T18:46:15.086Z" }, + { url = "https://files.pythonhosted.org/packages/43/5a/947e6ab7a5ad603d65b474be15a4cbc6d29832db5d762cd142e4e3a74164/ruff-0.15.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:195072c0c8e1fc8f940652073df082e37a5d9cb43b4ab1e4d0566ab8977a13b7", size = 12075183, upload-time = "2026-04-16T18:46:07.944Z" }, + { url = "https://files.pythonhosted.org/packages/9f/a1/0b7bb6268775fdd3a0818aee8efd8f5b4e231d24dd4d528ced2534023182/ruff-0.15.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a3a0996d486af3920dec930a2e7daed4847dfc12649b537a9335585ada163e9e", size = 11516575, upload-time = "2026-04-16T18:46:31.687Z" }, + { url = "https://files.pythonhosted.org/packages/30/c3/bb5168fc4d233cc06e95f482770d0f3c87945a0cd9f614b90ea8dc2f2833/ruff-0.15.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bef2cb556d509259f1fe440bb9cd33c756222cf0a7afe90d15edf0866702431", size = 11306537, upload-time = "2026-04-16T18:46:36.988Z" }, + { url = "https://files.pythonhosted.org/packages/e4/92/4cfae6441f3967317946f3b788136eecf093729b94d6561f963ed810c82e/ruff-0.15.11-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:030d921a836d7d4a12cf6e8d984a88b66094ccb0e0f17ddd55067c331191bf19", size = 11296813, upload-time = "2026-04-16T18:46:24.182Z" }, + { url = "https://files.pythonhosted.org/packages/43/26/972784c5dde8313acde8ac71ba8ac65475b85db4a2352a76c9934361f9bc/ruff-0.15.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0e783b599b4577788dbbb66b9addcef87e9a8832f4ce0c19e34bf55543a2f890", size = 10633136, upload-time = "2026-04-16T18:46:39.802Z" }, + { url = "https://files.pythonhosted.org/packages/5b/53/3985a4f185020c2f367f2e08a103032e12564829742a1b417980ce1514a0/ruff-0.15.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ae90592246625ba4a34349d68ec28d4400d75182b71baa196ddb9f82db025ef5", size = 10424701, upload-time = "2026-04-16T18:46:10.381Z" }, + { url = "https://files.pythonhosted.org/packages/d3/57/bf0dfb32241b56c83bb663a826133da4bf17f682ba8c096973065f6e6a68/ruff-0.15.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1f111d62e3c983ed20e0ca2e800f8d77433a5b1161947df99a5c2a3fb60514f0", size = 10873887, upload-time = "2026-04-16T18:46:29.157Z" }, + { url = "https://files.pythonhosted.org/packages/02/05/e48076b2a57dc33ee8c7a957296f97c744ca891a8ffb4ffb1aaa3b3f517d/ruff-0.15.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:06f483d6646f59eaffba9ae30956370d3a886625f511a3108994000480621d1c", size = 11404316, upload-time = "2026-04-16T18:46:19.462Z" }, + { url = "https://files.pythonhosted.org/packages/88/27/0195d15fe7a897cbcba0904792c4b7c9fdd958456c3a17d2ea6093716a9a/ruff-0.15.11-py3-none-win32.whl", hash = "sha256:476a2aa56b7da0b73a3ee80b6b2f0e19cce544245479adde7baa65466664d5f3", size = 10655535, upload-time = "2026-04-16T18:46:12.47Z" }, + { url = "https://files.pythonhosted.org/packages/3a/5e/c927b325bd4c1d3620211a4b96f47864633199feed60fa936025ab27e090/ruff-0.15.11-py3-none-win_amd64.whl", hash = "sha256:8b6756d88d7e234fb0c98c91511aae3cd519d5e3ed271cae31b20f39cb2a12a3", size = 11779692, upload-time = "2026-04-16T18:46:17.268Z" }, + { url = "https://files.pythonhosted.org/packages/63/b6/aeadee5443e49baa2facd51131159fd6301cc4ccfc1541e4df7b021c37dd/ruff-0.15.11-py3-none-win_arm64.whl", hash = "sha256:063fed18cc1bbe0ee7393957284a6fe8b588c6a406a285af3ee3f46da2391ee4", size = 11032614, upload-time = "2026-04-16T18:46:34.487Z" }, ] [[package]] @@ -5946,14 +5946,14 @@ wheels = [ [[package]] name = "scipy-stubs" -version = "1.17.1.3" +version = "1.17.1.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "optype", extra = ["numpy"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a7/59/59c6cc3f9970154b9ed6b1aff42a0185cdd60cef54adc0404b9e77972221/scipy_stubs-1.17.1.3.tar.gz", hash = "sha256:5eb87a8d23d726706259b012ebe76a4a96a9ae9e141fc59bf55fc8eac2ed9e0f", size = 392185, upload-time = "2026-03-22T22:11:58.34Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/75/d944a11fca64aa84fbb4bfcf613b758319c6103cb30a304a0e9727009d62/scipy_stubs-1.17.1.4.tar.gz", hash = "sha256:cae00c5207aa62ceb4bcadea202d9fbbf002e958f9e4de981720436b8d5c1802", size = 396980, upload-time = "2026-04-13T11:46:54.528Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/d4/94304532c0a75a55526119043dd44a9bd1541a21e14483cbb54261c527d2/scipy_stubs-1.17.1.3-py3-none-any.whl", hash = "sha256:7b91d3f05aa47da06fbca14eb6c5bb4c28994e9245fd250cc847e375bab31297", size = 597933, upload-time = "2026-03-22T22:11:56.525Z" }, + { url = "https://files.pythonhosted.org/packages/92/f8/334aa5a7a482ea89cb14d92f6a4d9ffa1e193e733144d4d14c7ffcb33583/scipy_stubs-1.17.1.4-py3-none-any.whl", hash = "sha256:e6e5c390fb864745bc3d5f591de81f5cb4f84403857d4f660acb5b6339956f5b", size = 604752, upload-time = "2026-04-13T11:46:53.135Z" }, ] [[package]] From 0fec9af6a6ab587fef032b041ddfd880539c3d7d Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Tue, 21 Apr 2026 17:11:11 +0800 Subject: [PATCH 4/6] chore(deps): bump vite-plus to 0.1.19 (#35462) --- pnpm-lock.yaml | 384 +++++++++++++++--------------- pnpm-workspace.yaml | 10 +- sdks/nodejs-client/vite.config.ts | 1 + 3 files changed, 198 insertions(+), 197 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0725b3bb7d..d573664e3a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -532,8 +532,8 @@ catalogs: specifier: 12.0.0-beta.1 version: 12.0.0-beta.1 vite-plus: - specifier: 0.1.18 - version: 0.1.18 + specifier: 0.1.19 + version: 0.1.19 vitest-browser-react: specifier: 2.2.0 version: 2.2.0 @@ -574,8 +574,8 @@ overrides: svgo@>=3.0.0 <3.3.3: 3.3.3 tar@<=7.5.10: 7.5.11 undici@>=7.0.0 <7.24.0: 7.24.0 - vite: npm:@voidzero-dev/vite-plus-core@0.1.18 - vitest: npm:@voidzero-dev/vite-plus-test@0.1.18 + vite: npm:@voidzero-dev/vite-plus-core@0.1.19 + vitest: npm:@voidzero-dev/vite-plus-test@0.1.19 yaml@>=2.0.0 <2.8.3: 2.8.3 yauzl@<3.2.1: 3.2.1 @@ -585,7 +585,7 @@ importers: devDependencies: '@antfu/eslint-config': specifier: 'catalog:' - version: 8.2.0(@eslint-react/eslint-plugin@3.0.0(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@next/eslint-plugin-next@16.2.3)(@types/node@25.6.0)(@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2))(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(eslint-plugin-react-refresh@0.5.2(eslint@10.2.0(jiti@2.6.1)))(eslint@10.2.0(jiti@2.6.1))(happy-dom@20.9.0)(jiti@2.6.1)(oxlint@1.60.0(oxlint-tsgolint@0.20.0))(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + version: 8.2.0(@eslint-react/eslint-plugin@3.0.0(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@next/eslint-plugin-next@16.2.3)(@types/node@25.6.0)(@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2))(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(eslint-plugin-react-refresh@0.5.2(eslint@10.2.0(jiti@2.6.1)))(eslint@10.2.0(jiti@2.6.1))(happy-dom@20.9.0)(jiti@2.6.1)(oxlint@1.60.0(oxlint-tsgolint@0.21.1))(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) eslint: specifier: 'catalog:' version: 10.2.0(jiti@2.6.1) @@ -599,11 +599,11 @@ importers: specifier: 'catalog:' version: 1.3.1(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) vite: - specifier: npm:@voidzero-dev/vite-plus-core@0.1.18 - version: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + specifier: npm:@voidzero-dev/vite-plus-core@0.1.19 + version: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' vite-plus: specifier: 'catalog:' - version: 0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + version: 0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) e2e: devDependencies: @@ -626,11 +626,11 @@ importers: specifier: 'catalog:' version: 6.0.2 vite: - specifier: npm:@voidzero-dev/vite-plus-core@0.1.18 - version: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + specifier: npm:@voidzero-dev/vite-plus-core@0.1.19 + version: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' vite-plus: specifier: 'catalog:' - version: 0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + version: 0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) packages/dify-ui: dependencies: @@ -658,7 +658,7 @@ importers: version: 1.2.10 '@storybook/addon-docs': specifier: 'catalog:' - version: 10.3.5(@types/react@19.2.14)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) + version: 10.3.5(@types/react@19.2.14)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) '@storybook/addon-links': specifier: 'catalog:' version: 10.3.5(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) @@ -667,10 +667,10 @@ importers: version: 10.3.5(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) '@storybook/react-vite': specifier: 'catalog:' - version: 10.3.5(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2) + version: 10.3.5(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.2.2(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) + version: 4.2.2(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) '@types/react': specifier: 'catalog:' version: 19.2.14 @@ -679,10 +679,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: 'catalog:' - version: 6.0.1(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) + version: 6.0.1(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) '@vitest/coverage-v8': specifier: 'catalog:' - version: 4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + version: 4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) class-variance-authority: specifier: 'catalog:' version: 0.7.1 @@ -705,14 +705,14 @@ importers: specifier: 'catalog:' version: 6.0.2 vite: - specifier: npm:@voidzero-dev/vite-plus-core@0.1.18 - version: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + specifier: npm:@voidzero-dev/vite-plus-core@0.1.19 + version: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' vite-plus: specifier: 'catalog:' - version: 0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + version: 0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) vitest-browser-react: specifier: 'catalog:' - version: 2.2.0(@types/node@25.6.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + version: 2.2.0(@types/node@25.6.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) packages/iconify-collections: devDependencies: @@ -736,11 +736,11 @@ importers: specifier: 'catalog:' version: 25.6.0 vite: - specifier: npm:@voidzero-dev/vite-plus-core@0.1.18 - version: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + specifier: npm:@voidzero-dev/vite-plus-core@0.1.19 + version: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' vite-plus: specifier: 'catalog:' - version: 0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + version: 0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) packages/tsconfig: {} @@ -763,7 +763,7 @@ importers: version: 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) '@vitest/coverage-v8': specifier: 'catalog:' - version: 4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + version: 4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) eslint: specifier: 'catalog:' version: 10.2.0(jiti@2.6.1) @@ -771,14 +771,14 @@ importers: specifier: 'catalog:' version: 6.0.2 vite: - specifier: npm:@voidzero-dev/vite-plus-core@0.1.18 - version: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + specifier: npm:@voidzero-dev/vite-plus-core@0.1.19 + version: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' vite-plus: specifier: 'catalog:' - version: 0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + version: 0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) vitest: - specifier: npm:@voidzero-dev/vite-plus-test@0.1.18 - version: '@voidzero-dev/vite-plus-test@0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + specifier: npm:@voidzero-dev/vite-plus-test@0.1.19 + version: '@voidzero-dev/vite-plus-test@0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' web: dependencies: @@ -1091,7 +1091,7 @@ importers: devDependencies: '@antfu/eslint-config': specifier: 'catalog:' - version: 8.2.0(@eslint-react/eslint-plugin@3.0.0(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@next/eslint-plugin-next@16.2.3)(@types/node@25.6.0)(@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2))(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(eslint-plugin-react-refresh@0.5.2(eslint@10.2.0(jiti@2.6.1)))(eslint@10.2.0(jiti@2.6.1))(happy-dom@20.9.0)(jiti@2.6.1)(oxlint@1.60.0(oxlint-tsgolint@0.20.0))(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + version: 8.2.0(@eslint-react/eslint-plugin@3.0.0(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@next/eslint-plugin-next@16.2.3)(@types/node@25.6.0)(@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2))(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(eslint-plugin-react-refresh@0.5.2(eslint@10.2.0(jiti@2.6.1)))(eslint@10.2.0(jiti@2.6.1))(happy-dom@20.9.0)(jiti@2.6.1)(oxlint@1.60.0(oxlint-tsgolint@0.21.1))(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) '@chromatic-com/storybook': specifier: 'catalog:' version: 5.1.2(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) @@ -1139,7 +1139,7 @@ importers: version: 4.2.0 '@storybook/addon-docs': specifier: 'catalog:' - version: 10.3.5(@types/react@19.2.14)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) + version: 10.3.5(@types/react@19.2.14)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) '@storybook/addon-links': specifier: 'catalog:' version: 10.3.5(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) @@ -1151,7 +1151,7 @@ importers: version: 10.3.5(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) '@storybook/nextjs-vite': specifier: 'catalog:' - version: 10.3.5(@babel/core@7.29.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(next@16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2) + version: 10.3.5(@babel/core@7.29.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(next@16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2) '@storybook/react': specifier: 'catalog:' version: 10.3.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2) @@ -1160,7 +1160,7 @@ importers: version: 4.2.2 '@tailwindcss/vite': specifier: 'catalog:' - version: 4.2.2(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) + version: 4.2.2(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) '@tanstack/eslint-plugin-query': specifier: 'catalog:' version: 5.99.0(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) @@ -1226,13 +1226,13 @@ importers: version: 7.0.0-dev.20260413.1 '@vitejs/plugin-react': specifier: 'catalog:' - version: 6.0.1(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) + version: 6.0.1(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) '@vitejs/plugin-rsc': specifier: 'catalog:' - version: 0.5.24(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(react-dom@19.2.5(react@19.2.5))(react-server-dom-webpack@19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5) + version: 0.5.24(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(react-dom@19.2.5(react@19.2.5))(react-server-dom-webpack@19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5) '@vitest/coverage-v8': specifier: 'catalog:' - version: 4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + version: 4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) agentation: specifier: 'catalog:' version: 3.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -1247,7 +1247,7 @@ importers: version: 0.6.1(eslint@10.2.0(jiti@2.6.1)) eslint-plugin-better-tailwindcss: specifier: 'catalog:' - version: 4.4.1(eslint@10.2.0(jiti@2.6.1))(oxlint@1.60.0(oxlint-tsgolint@0.20.0))(tailwindcss@4.2.2)(typescript@6.0.2) + version: 4.4.1(eslint@10.2.0(jiti@2.6.1))(oxlint@1.60.0(oxlint-tsgolint@0.21.1))(tailwindcss@4.2.2)(typescript@6.0.2) eslint-plugin-hyoban: specifier: 'catalog:' version: 0.14.1(eslint@10.2.0(jiti@2.6.1)) @@ -1298,22 +1298,22 @@ importers: version: 3.19.3 vinext: specifier: 'catalog:' - version: 0.0.41(@mdx-js/rollup@3.1.1)(@vitejs/plugin-react@6.0.1(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)))(@vitejs/plugin-rsc@0.5.24(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(react-dom@19.2.5(react@19.2.5))(react-server-dom-webpack@19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(next@16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react-server-dom-webpack@19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(typescript@6.0.2) + version: 0.0.41(@mdx-js/rollup@3.1.1)(@vitejs/plugin-react@6.0.1(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)))(@vitejs/plugin-rsc@0.5.24(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(react-dom@19.2.5(react@19.2.5))(react-server-dom-webpack@19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(next@16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react-server-dom-webpack@19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(typescript@6.0.2) vite: - specifier: npm:@voidzero-dev/vite-plus-core@0.1.18 - version: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + specifier: npm:@voidzero-dev/vite-plus-core@0.1.19 + version: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' vite-plugin-inspect: specifier: 'catalog:' - version: 12.0.0-beta.1(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2)(ws@8.20.0) + version: 12.0.0-beta.1(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2)(ws@8.20.0) vite-plus: specifier: 'catalog:' - version: 0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + version: 0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) vitest: - specifier: npm:@voidzero-dev/vite-plus-test@0.1.18 - version: '@voidzero-dev/vite-plus-test@0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + specifier: npm:@voidzero-dev/vite-plus-test@0.1.19 + version: '@voidzero-dev/vite-plus-test@0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' vitest-canvas-mock: specifier: 'catalog:' - version: 1.1.4(@voidzero-dev/vite-plus-test@0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) + version: 1.1.4(@voidzero-dev/vite-plus-test@0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) packages: @@ -2665,15 +2665,15 @@ packages: cpu: [x64] os: [win32] - '@oxc-project/runtime@0.124.0': - resolution: {integrity: sha512-sSg6n37J3w3mM4odFvRqzQENf6+qxKnvStr/gU0FgRRg1VE/4MqryLd9PJmE0a7K5xlDfbrctBtSagaFH6ij9Q==} + '@oxc-project/runtime@0.126.0': + resolution: {integrity: sha512-oksjxfqDNmIYMGlIgLzYgnz5YjZax27RtQezsPpKEGo9AC5LOaIGHsivCCeaAWdCtPnRyjZXM/7svreCC8kZVQ==} engines: {node: ^20.19.0 || >=22.12.0} '@oxc-project/types@0.121.0': resolution: {integrity: sha512-CGtOARQb9tyv7ECgdAlFxi0Fv7lmzvmlm2rpD/RdijOO9rfk/JvB1CjT8EnoD+tjna/IYgKKw3IV7objRb+aYw==} - '@oxc-project/types@0.124.0': - resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==} + '@oxc-project/types@0.126.0': + resolution: {integrity: sha512-oGfVtjAgwQVVpfBrbtk4e1XDyWHRFta6BS3GWVzrF8xYBT2VGQAk39yJS/wFSMrZqoiCU4oghT3Ch0HaHGIHcQ==} '@oxc-resolver/binding-android-arm-eabi@11.19.1': resolution: {integrity: sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg==} @@ -2905,33 +2905,33 @@ packages: cpu: [x64] os: [win32] - '@oxlint-tsgolint/darwin-arm64@0.20.0': - resolution: {integrity: sha512-KKQcIHZHMxqpHUA1VXIbOG6chNCFkUWbQy6M+AFVtPKkA/3xAeJkJ3njoV66bfzwPHRcWQO+kcj5XqtbkjakoA==} + '@oxlint-tsgolint/darwin-arm64@0.21.1': + resolution: {integrity: sha512-7TLjyWe4wG9saJc992VWmaHq2hwKfOEEVTjheReXJXaDhavMZI4X9a6nKhbEng4IVkYtzjD2jw16vw2WFXLYLw==} cpu: [arm64] os: [darwin] - '@oxlint-tsgolint/darwin-x64@0.20.0': - resolution: {integrity: sha512-7HeVMuclGfG+NLZi2ybY0T4fMI7/XxO/208rJk+zEIloKkVnlh11Wd241JMGwgNFXn+MLJbOqOfojDb2Dt4L1g==} + '@oxlint-tsgolint/darwin-x64@0.21.1': + resolution: {integrity: sha512-7wf9Wf75nTzA7zpL9myhFe2RKvfuqGUOADNvUooCjEWvh7hmPz3lSEqTMh5Z/VQhzsG04mM9ACyghxhRzq7zFw==} cpu: [x64] os: [darwin] - '@oxlint-tsgolint/linux-arm64@0.20.0': - resolution: {integrity: sha512-zxhUwz+WSxE6oWlZLK2z2ps9yC6ebmgoYmjAl0Oa48+GqkZ56NVgo+wb8DURNv6xrggzHStQxqQxe3mK51HZag==} + '@oxlint-tsgolint/linux-arm64@0.21.1': + resolution: {integrity: sha512-IPuQN/Vd0Rjklg/cCGBbQyUuRBp2f6LQXpZYwk5ivOR6V/+CgiYsv8pn/PVY7gjeyoNvPQrXB7xMjHUO2YZbdw==} cpu: [arm64] os: [linux] - '@oxlint-tsgolint/linux-x64@0.20.0': - resolution: {integrity: sha512-/1l6FnahC9im8PK+Ekkx/V3yetO/PzZnJegE2FXcv/iXEhbeVxP/ouiTYcUQu9shT1FWJCSNti1VJHH+21Y1dg==} + '@oxlint-tsgolint/linux-x64@0.21.1': + resolution: {integrity: sha512-d1niGuTbh2qiv7dR7tqkbOcM5cIR63of0lMBFdEQavL1KrJV8zuRdwdi68K7MNGdgoR+J5A9ajpGGvsHwp1bPg==} cpu: [x64] os: [linux] - '@oxlint-tsgolint/win32-arm64@0.20.0': - resolution: {integrity: sha512-oPZ5Yz8sVdo7P/5q+i3IKeix31eFZ55JAPa1+RGPoe9PoaYVsdMvR6Jvib6YtrqoJnFPlg3fjEjlEPL8VBKYJA==} + '@oxlint-tsgolint/win32-arm64@0.21.1': + resolution: {integrity: sha512-ICu9y2JLnFPvFqstnWPPNqBM8LK8BWw2OTeaR0UgEMm4hOSbrZAKv1/hwZYyiLqnCNjBL87AGSQIgTHCYlsipw==} cpu: [arm64] os: [win32] - '@oxlint-tsgolint/win32-x64@0.20.0': - resolution: {integrity: sha512-4stx8RHj3SP9vQyRF/yZbz5igtPvYMEUR8CUoha4BVNZihi39DpCR8qkU7lpjB5Ga1DRMo2pHaA4bdTOMaY4mw==} + '@oxlint-tsgolint/win32-x64@0.21.1': + resolution: {integrity: sha512-cTEFCFjCj6iXfrSHcvajSPNqhEA4TxSzU3gFxbdGSAUTNXGToU99IbdhWAPSbhcucoym0XE4Zl7E41NiSkNTug==} cpu: [x64] os: [win32] @@ -4336,13 +4336,13 @@ packages: '@vitest/utils@4.1.4': resolution: {integrity: sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==} - '@voidzero-dev/vite-plus-core@0.1.18': - resolution: {integrity: sha512-3PmXOL26yHzlw8ET9SwXCmglGzUYq2fOTYf2t0mxvVIs7ua3bnf6tOnmR+6YX5k1Ez26B0ooYzx+znc8k+CAMw==} + '@voidzero-dev/vite-plus-core@0.1.19': + resolution: {integrity: sha512-BTmz50juSDolIN4Vtu5iVaPONV1XSrMB5V+9IoBhhxdogfvp7PBhaHuAcPjTN2RTVowhLZXoo8mn+aHjq//bkw==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: '@arethetypeswrong/core': ^0.18.1 - '@tsdown/css': 0.21.8 - '@tsdown/exe': 0.21.8 + '@tsdown/css': 0.21.9 + '@tsdown/exe': 0.21.9 '@types/node': ^20.19.0 || >=22.12.0 '@vitejs/devtools': ^0.1.0 esbuild: 0.27.2 @@ -4396,48 +4396,48 @@ packages: yaml: optional: true - '@voidzero-dev/vite-plus-darwin-arm64@0.1.18': - resolution: {integrity: sha512-bw2pWWE8RZRELWjXcdxdmRaOaYjmGmsxEm23TxvGxQXFb7k9l51W8tpjxariPGLxrEl+Cw5u601IL5LASaPJ5w==} + '@voidzero-dev/vite-plus-darwin-arm64@0.1.19': + resolution: {integrity: sha512-6MY/RiaRXKJ6wD/ftZnf+ohEqU68zHp3bVWetIw9dakcPL7TXoiIkDoechmZXCh+5eqxehvap4eh2eNEvWSM1Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@voidzero-dev/vite-plus-darwin-x64@0.1.18': - resolution: {integrity: sha512-8TFj6yJNsumoH+yFc+6zf3g2UuzvrPHq2FAAVORffaVZ29PWnDSsXjegaIBmoAtGO5Xb4lcilQx7NoF9hONrZg==} + '@voidzero-dev/vite-plus-darwin-x64@0.1.19': + resolution: {integrity: sha512-jV6ygWCarMFW5DRqRyFkB2jpRDiAlLYzyQu0HZfYNoxfdNyO7isfuR5X6gV+ji7J3Kp0RZOiGrQUCjxTPqZg5w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@voidzero-dev/vite-plus-linux-arm64-gnu@0.1.18': - resolution: {integrity: sha512-xHRqncKanOZ0zNnZSufL4Yx/gWrIFkCjU6jFzCukBOOCrcemq3SrALPHrNf+Nw1RLwNptGUZn2Vx/IjRLzUQDw==} + '@voidzero-dev/vite-plus-linux-arm64-gnu@0.1.19': + resolution: {integrity: sha512-jIWMgAok77aDuTK2kCQXn4Zp7pnUM56BvKhHCvnAmsF4yrs1KLQfH6YOdQMnVbNjQDneQgqdwHVDnkOfJRokYw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@voidzero-dev/vite-plus-linux-arm64-musl@0.1.18': - resolution: {integrity: sha512-CA6XxZbkT8lYwWzS2yAj6exr7nHl3R8Sz+ZdOhYCU4yR2qvzGatdVgFr7oPnrkHLF426cHJ172rmNNj8NKie/w==} + '@voidzero-dev/vite-plus-linux-arm64-musl@0.1.19': + resolution: {integrity: sha512-fUuXUqCl3zMbS5QpMJzewVjrpbtzlwuzYQSh5q59CMq65uCXT07amJzmuAFReDEMrwEAmjGgbamJ1ctLAYCxrA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@voidzero-dev/vite-plus-linux-x64-gnu@0.1.18': - resolution: {integrity: sha512-xBO3MtLGVASPjH/GDRxexfLCT0othVpiFMdEQ83Y+woVNbrrzcdQTGFUuFG4cAiMhtmjytyFwPBtZ76BWsDO3w==} + '@voidzero-dev/vite-plus-linux-x64-gnu@0.1.19': + resolution: {integrity: sha512-xFVGMo1Yo5p9gABpOSSGgu5LhhMQs6qVXU7xL+NAGnaVViAYujNuOhCpBk2yK4Cy98KiNOjwnR5jG0TnRd22xg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@voidzero-dev/vite-plus-linux-x64-musl@0.1.18': - resolution: {integrity: sha512-ADNis6SMarY7i8+b2ynUJ1PiqCHqnVwY7EQ+fSGug5zZ+W/cZq14+VWPxOvGR9LJk+iol8XuqsHy4BaV2+gjzw==} + '@voidzero-dev/vite-plus-linux-x64-musl@0.1.19': + resolution: {integrity: sha512-iEDxL85v/C01yF2EJKknkjDhKbgY10NL9/sZ4HxezWykePK6QpYY5ClWGL7gIi+YFp8rtAdRPKlrf0mTlYMvxw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@voidzero-dev/vite-plus-test@0.1.18': - resolution: {integrity: sha512-dovC2kJgiwMI8ay0i+3NvQGCDWPj8HQB2ONP/HbdJ5/XQVPq13+BihnCq8/ztz6uGhiDD8Nu4OZ3RgB14uvTfA==} + '@voidzero-dev/vite-plus-test@0.1.19': + resolution: {integrity: sha512-KK0lfqyiEOEykp3hrcHT49f1j3M3t15ZKCuO+e9KbDRambU7tdz70xoHCKkRXcFgnds9gqi09PSLVy1k8XN+Hg==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: '@edge-runtime/vm': '*' @@ -4467,14 +4467,14 @@ packages: jsdom: optional: true - '@voidzero-dev/vite-plus-win32-arm64-msvc@0.1.18': - resolution: {integrity: sha512-EcDETMHG8xgjIlMizIu/wf0UtRZLGz+lHFvYFZVCkz4vLLz93a06vZ+3Oi9xY2Kc8aOHsCf8Gj5/dox/03cscw==} + '@voidzero-dev/vite-plus-win32-arm64-msvc@0.1.19': + resolution: {integrity: sha512-2GGeGr2mtXLjV9O8CXEEZkV6O8q8rMBhq8fj5fyaSuBe5FQ1OxGYYMDqNBxvbg+hSUw0ThKK6qmirj5fF2e/iw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@voidzero-dev/vite-plus-win32-x64-msvc@0.1.18': - resolution: {integrity: sha512-jBgL4ZjSJJu3FDcrqj4muzbr0WKlU6Ym1ilHQnq8R+2TRvE0AtvAMMuphICDslZGi6EK3fwJ+r2Lv7GU1AipQA==} + '@voidzero-dev/vite-plus-win32-x64-msvc@0.1.19': + resolution: {integrity: sha512-//xUNHQnd+p4Xd4rlObAvum3DW1ugbWZ+kfaqD7biHQ9HQwHF28WSpJ3+d31vLUHj4o3DXYSA67g1Bq2d4tVgg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -6797,8 +6797,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - oxlint-tsgolint@0.20.0: - resolution: {integrity: sha512-/Uc9TQyN1l8w9QNvXtVHYtz+SzDJHKpb5X0UnHodl0BVzijUPk0LPlDOHAvogd1UI+iy9ZSF6gQxEqfzUxCULQ==} + oxlint-tsgolint@0.21.1: + resolution: {integrity: sha512-O2hxiT14C2HJkwzBU6CQBFPoagSd/IcV+Tt3e3UUaXFwbW4BO5DSDPSSboc3UM5MIDY+MLyepvtQwBQafNxWdw==} hasBin: true oxlint@1.60.0: @@ -8039,8 +8039,8 @@ packages: storybook: ^0.0.0-0 || ^9.0.0 || ^10.0.0 || ^10.0.0-0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 || ^10.4.0-0 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - vite-plus@0.1.18: - resolution: {integrity: sha512-RiWUoOmQiJMtd4Dfm6WD0v0Selqh/nQzmaGVIrkfnr+2s5UxGVZy7n2TCO5ZnR7w9noMIgtUAQN8GtKhwHEiOQ==} + vite-plus@0.1.19: + resolution: {integrity: sha512-QWuTqkO/a8Q7I3hHnYdvwlJa7mcc6hgh99/8CHoRb27pgo+z1ux+NGYYCZPJHKVtatAtVRaQQvy4cEQBHyB87A==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -8437,17 +8437,17 @@ snapshots: idb: 8.0.0 tslib: 2.8.1 - '@antfu/eslint-config@8.2.0(@eslint-react/eslint-plugin@3.0.0(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@next/eslint-plugin-next@16.2.3)(@types/node@25.6.0)(@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2))(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(eslint-plugin-react-refresh@0.5.2(eslint@10.2.0(jiti@2.6.1)))(eslint@10.2.0(jiti@2.6.1))(happy-dom@20.9.0)(jiti@2.6.1)(oxlint@1.60.0(oxlint-tsgolint@0.20.0))(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)': + '@antfu/eslint-config@8.2.0(@eslint-react/eslint-plugin@3.0.0(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@next/eslint-plugin-next@16.2.3)(@types/node@25.6.0)(@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2))(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(eslint-plugin-react-refresh@0.5.2(eslint@10.2.0(jiti@2.6.1)))(eslint@10.2.0(jiti@2.6.1))(happy-dom@20.9.0)(jiti@2.6.1)(oxlint@1.60.0(oxlint-tsgolint@0.21.1))(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)': dependencies: '@antfu/install-pkg': 1.1.0 '@clack/prompts': 1.2.0 - '@e18e/eslint-plugin': 0.3.0(eslint@10.2.0(jiti@2.6.1))(oxlint@1.60.0(oxlint-tsgolint@0.20.0)) + '@e18e/eslint-plugin': 0.3.0(eslint@10.2.0(jiti@2.6.1))(oxlint@1.60.0(oxlint-tsgolint@0.21.1)) '@eslint-community/eslint-plugin-eslint-comments': 4.7.1(eslint@10.2.0(jiti@2.6.1)) '@eslint/markdown': 8.0.1 '@stylistic/eslint-plugin': 5.10.0(eslint@10.2.0(jiti@2.6.1)) '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) '@typescript-eslint/parser': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) - '@vitest/eslint-plugin': 1.6.15(@types/node@25.6.0)(@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(eslint@10.2.0(jiti@2.6.1))(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + '@vitest/eslint-plugin': 1.6.15(@types/node@25.6.0)(@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(eslint@10.2.0(jiti@2.6.1))(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) ansis: 4.2.0 cac: 7.0.0 eslint: 10.2.0(jiti@2.6.1) @@ -8857,12 +8857,12 @@ snapshots: '@cucumber/tag-expressions@9.1.0': {} - '@e18e/eslint-plugin@0.3.0(eslint@10.2.0(jiti@2.6.1))(oxlint@1.60.0(oxlint-tsgolint@0.20.0))': + '@e18e/eslint-plugin@0.3.0(eslint@10.2.0(jiti@2.6.1))(oxlint@1.60.0(oxlint-tsgolint@0.21.1))': dependencies: eslint-plugin-depend: 1.5.0(eslint@10.2.0(jiti@2.6.1)) optionalDependencies: eslint: 10.2.0(jiti@2.6.1) - oxlint: 1.60.0(oxlint-tsgolint@0.20.0) + oxlint: 1.60.0(oxlint-tsgolint@0.21.1) '@egoist/tailwindcss-icons@1.9.2(tailwindcss@4.2.2)': dependencies: @@ -9390,11 +9390,11 @@ snapshots: dependencies: minipass: 7.1.3 - '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2)': + '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2)': dependencies: glob: 13.0.6 react-docgen-typescript: 2.4.0(typescript@6.0.2) - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' optionalDependencies: typescript: 6.0.2 @@ -9831,11 +9831,11 @@ snapshots: '@oxc-parser/binding-win32-x64-msvc@0.121.0': optional: true - '@oxc-project/runtime@0.124.0': {} + '@oxc-project/runtime@0.126.0': {} '@oxc-project/types@0.121.0': {} - '@oxc-project/types@0.124.0': {} + '@oxc-project/types@0.126.0': {} '@oxc-resolver/binding-android-arm-eabi@11.19.1': optional: true @@ -9959,22 +9959,22 @@ snapshots: '@oxfmt/binding-win32-x64-msvc@0.45.0': optional: true - '@oxlint-tsgolint/darwin-arm64@0.20.0': + '@oxlint-tsgolint/darwin-arm64@0.21.1': optional: true - '@oxlint-tsgolint/darwin-x64@0.20.0': + '@oxlint-tsgolint/darwin-x64@0.21.1': optional: true - '@oxlint-tsgolint/linux-arm64@0.20.0': + '@oxlint-tsgolint/linux-arm64@0.21.1': optional: true - '@oxlint-tsgolint/linux-x64@0.20.0': + '@oxlint-tsgolint/linux-x64@0.21.1': optional: true - '@oxlint-tsgolint/win32-arm64@0.20.0': + '@oxlint-tsgolint/win32-arm64@0.21.1': optional: true - '@oxlint-tsgolint/win32-x64@0.20.0': + '@oxlint-tsgolint/win32-x64@0.21.1': optional: true '@oxlint/binding-android-arm-eabi@1.60.0': @@ -10474,10 +10474,10 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@storybook/addon-docs@10.3.5(@types/react@19.2.14)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))': + '@storybook/addon-docs@10.3.5(@types/react@19.2.14)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))': dependencies: '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.5) - '@storybook/csf-plugin': 10.3.5(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) + '@storybook/csf-plugin': 10.3.5(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) '@storybook/icons': 2.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@storybook/react-dom-shim': 10.3.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) react: 19.2.5 @@ -10507,24 +10507,24 @@ snapshots: storybook: 10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) ts-dedent: 2.2.0 - '@storybook/builder-vite@10.3.5(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))': + '@storybook/builder-vite@10.3.5(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))': dependencies: - '@storybook/csf-plugin': 10.3.5(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) + '@storybook/csf-plugin': 10.3.5(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) storybook: 10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) ts-dedent: 2.2.0 - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' transitivePeerDependencies: - esbuild - rollup - webpack - '@storybook/csf-plugin@10.3.5(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))': + '@storybook/csf-plugin@10.3.5(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))': dependencies: storybook: 10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) unplugin: 2.3.11 optionalDependencies: esbuild: 0.27.2 - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' '@storybook/global@5.0.0': {} @@ -10533,18 +10533,18 @@ snapshots: react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - '@storybook/nextjs-vite@10.3.5(@babel/core@7.29.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(next@16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2)': + '@storybook/nextjs-vite@10.3.5(@babel/core@7.29.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(next@16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2)': dependencies: - '@storybook/builder-vite': 10.3.5(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) + '@storybook/builder-vite': 10.3.5(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) '@storybook/react': 10.3.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2) - '@storybook/react-vite': 10.3.5(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2) + '@storybook/react-vite': 10.3.5(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2) next: 16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: 19.2.5 react-dom: 19.2.5(react@19.2.5) storybook: 10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.5) - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' - vite-plugin-storybook-nextjs: 3.2.4(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(next@16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2) + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite-plugin-storybook-nextjs: 3.2.4(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(next@16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2) optionalDependencies: typescript: 6.0.2 transitivePeerDependencies: @@ -10561,11 +10561,11 @@ snapshots: react-dom: 19.2.5(react@19.2.5) storybook: 10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@storybook/react-vite@10.3.5(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2)': + '@storybook/react-vite@10.3.5(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2)': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2) '@rollup/pluginutils': 5.3.0 - '@storybook/builder-vite': 10.3.5(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) + '@storybook/builder-vite': 10.3.5(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) '@storybook/react': 10.3.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2) empathic: 2.0.0 magic-string: 0.30.21 @@ -10575,7 +10575,7 @@ snapshots: resolve: 1.22.11 storybook: 10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) tsconfig-paths: 4.2.0 - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' transitivePeerDependencies: - esbuild - rollup @@ -10714,12 +10714,12 @@ snapshots: postcss-selector-parser: 6.0.10 tailwindcss: 4.2.2 - '@tailwindcss/vite@4.2.2(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))': + '@tailwindcss/vite@4.2.2(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))': dependencies: '@tailwindcss/node': 4.2.2 '@tailwindcss/oxide': 4.2.2 tailwindcss: 4.2.2 - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' '@tanstack/devtools-client@0.0.6': dependencies: @@ -11337,12 +11337,12 @@ snapshots: '@resvg/resvg-wasm': 2.4.0 satori: 0.16.0 - '@vitejs/devtools-kit@0.1.11(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2)(ws@8.20.0)': + '@vitejs/devtools-kit@0.1.11(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2)(ws@8.20.0)': dependencies: '@vitejs/devtools-rpc': 0.1.11(typescript@6.0.2)(ws@8.20.0) birpc: 4.0.0 ohash: 2.0.11 - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' transitivePeerDependencies: - typescript - ws @@ -11359,12 +11359,12 @@ snapshots: transitivePeerDependencies: - typescript - '@vitejs/plugin-react@6.0.1(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))': + '@vitejs/plugin-react@6.0.1(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.7 - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' - '@vitejs/plugin-rsc@0.5.24(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(react-dom@19.2.5(react@19.2.5))(react-server-dom-webpack@19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)': + '@vitejs/plugin-rsc@0.5.24(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(react-dom@19.2.5(react@19.2.5))(react-server-dom-webpack@19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)': dependencies: '@rolldown/pluginutils': 1.0.0-rc.15 es-module-lexer: 2.0.0 @@ -11375,12 +11375,12 @@ snapshots: srvx: 0.11.15 strip-literal: 3.1.0 turbo-stream: 3.2.0 - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' - vitefu: 1.1.3(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vitefu: 1.1.3(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) optionalDependencies: react-server-dom-webpack: 19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)': + '@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.1.4 @@ -11392,7 +11392,7 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.1.0 - vitest: '@voidzero-dev/vite-plus-test@0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vitest: '@voidzero-dev/vite-plus-test@0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' transitivePeerDependencies: - '@arethetypeswrong/core' - '@edge-runtime/vm' @@ -11422,12 +11422,12 @@ snapshots: - vite - yaml - '@vitest/eslint-plugin@1.6.15(@types/node@25.6.0)(@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(eslint@10.2.0(jiti@2.6.1))(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)': + '@vitest/eslint-plugin@1.6.15(@types/node@25.6.0)(@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(eslint@10.2.0(jiti@2.6.1))(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)': dependencies: '@typescript-eslint/scope-manager': 8.58.2 '@typescript-eslint/utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) eslint: 10.2.0(jiti@2.6.1) - vitest: '@voidzero-dev/vite-plus-test@0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vitest: '@voidzero-dev/vite-plus-test@0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' optionalDependencies: '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) typescript: 6.0.2 @@ -11493,10 +11493,10 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)': + '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)': dependencies: - '@oxc-project/runtime': 0.124.0 - '@oxc-project/types': 0.124.0 + '@oxc-project/runtime': 0.126.0 + '@oxc-project/types': 0.126.0 lightningcss: 1.32.0 postcss: 8.5.9 optionalDependencies: @@ -11508,29 +11508,29 @@ snapshots: typescript: 6.0.2 yaml: 2.8.3 - '@voidzero-dev/vite-plus-darwin-arm64@0.1.18': + '@voidzero-dev/vite-plus-darwin-arm64@0.1.19': optional: true - '@voidzero-dev/vite-plus-darwin-x64@0.1.18': + '@voidzero-dev/vite-plus-darwin-x64@0.1.19': optional: true - '@voidzero-dev/vite-plus-linux-arm64-gnu@0.1.18': + '@voidzero-dev/vite-plus-linux-arm64-gnu@0.1.19': optional: true - '@voidzero-dev/vite-plus-linux-arm64-musl@0.1.18': + '@voidzero-dev/vite-plus-linux-arm64-musl@0.1.19': optional: true - '@voidzero-dev/vite-plus-linux-x64-gnu@0.1.18': + '@voidzero-dev/vite-plus-linux-x64-gnu@0.1.19': optional: true - '@voidzero-dev/vite-plus-linux-x64-musl@0.1.18': + '@voidzero-dev/vite-plus-linux-x64-musl@0.1.19': optional: true - '@voidzero-dev/vite-plus-test@0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)': + '@voidzero-dev/vite-plus-test@0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@voidzero-dev/vite-plus-core': 0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + '@voidzero-dev/vite-plus-core': 0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) es-module-lexer: 1.7.0 obug: 2.1.1 pixelmatch: 7.1.0 @@ -11540,11 +11540,11 @@ snapshots: tinybench: 2.9.0 tinyexec: 1.0.4 tinyglobby: 0.2.16 - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' ws: 8.20.0 optionalDependencies: '@types/node': 25.6.0 - '@vitest/coverage-v8': 4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + '@vitest/coverage-v8': 4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) happy-dom: 20.9.0 transitivePeerDependencies: - '@arethetypeswrong/core' @@ -11567,10 +11567,10 @@ snapshots: - utf-8-validate - yaml - '@voidzero-dev/vite-plus-win32-arm64-msvc@0.1.18': + '@voidzero-dev/vite-plus-win32-arm64-msvc@0.1.19': optional: true - '@voidzero-dev/vite-plus-win32-x64-msvc@0.1.18': + '@voidzero-dev/vite-plus-win32-x64-msvc@0.1.19': optional: true '@volar/language-core@2.4.28': @@ -12467,7 +12467,7 @@ snapshots: dependencies: eslint: 10.2.0(jiti@2.6.1) - eslint-plugin-better-tailwindcss@4.4.1(eslint@10.2.0(jiti@2.6.1))(oxlint@1.60.0(oxlint-tsgolint@0.20.0))(tailwindcss@4.2.2)(typescript@6.0.2): + eslint-plugin-better-tailwindcss@4.4.1(eslint@10.2.0(jiti@2.6.1))(oxlint@1.60.0(oxlint-tsgolint@0.21.1))(tailwindcss@4.2.2)(typescript@6.0.2): dependencies: '@eslint/css-tree': 4.0.1 '@valibot/to-json-schema': 1.6.0(valibot@1.3.1(typescript@6.0.2)) @@ -12480,7 +12480,7 @@ snapshots: valibot: 1.3.1(typescript@6.0.2) optionalDependencies: eslint: 10.2.0(jiti@2.6.1) - oxlint: 1.60.0(oxlint-tsgolint@0.20.0) + oxlint: 1.60.0(oxlint-tsgolint@0.21.1) transitivePeerDependencies: - '@eslint/css' - typescript @@ -14492,16 +14492,16 @@ snapshots: '@oxfmt/binding-win32-ia32-msvc': 0.45.0 '@oxfmt/binding-win32-x64-msvc': 0.45.0 - oxlint-tsgolint@0.20.0: + oxlint-tsgolint@0.21.1: optionalDependencies: - '@oxlint-tsgolint/darwin-arm64': 0.20.0 - '@oxlint-tsgolint/darwin-x64': 0.20.0 - '@oxlint-tsgolint/linux-arm64': 0.20.0 - '@oxlint-tsgolint/linux-x64': 0.20.0 - '@oxlint-tsgolint/win32-arm64': 0.20.0 - '@oxlint-tsgolint/win32-x64': 0.20.0 + '@oxlint-tsgolint/darwin-arm64': 0.21.1 + '@oxlint-tsgolint/darwin-x64': 0.21.1 + '@oxlint-tsgolint/linux-arm64': 0.21.1 + '@oxlint-tsgolint/linux-x64': 0.21.1 + '@oxlint-tsgolint/win32-arm64': 0.21.1 + '@oxlint-tsgolint/win32-x64': 0.21.1 - oxlint@1.60.0(oxlint-tsgolint@0.20.0): + oxlint@1.60.0(oxlint-tsgolint@0.21.1): optionalDependencies: '@oxlint/binding-android-arm-eabi': 1.60.0 '@oxlint/binding-android-arm64': 1.60.0 @@ -14522,7 +14522,7 @@ snapshots: '@oxlint/binding-win32-arm64-msvc': 1.60.0 '@oxlint/binding-win32-ia32-msvc': 1.60.0 '@oxlint/binding-win32-x64-msvc': 1.60.0 - oxlint-tsgolint: 0.20.0 + oxlint-tsgolint: 0.21.1 p-limit@3.1.0: dependencies: @@ -15826,20 +15826,20 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vinext@0.0.41(@mdx-js/rollup@3.1.1)(@vitejs/plugin-react@6.0.1(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)))(@vitejs/plugin-rsc@0.5.24(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(react-dom@19.2.5(react@19.2.5))(react-server-dom-webpack@19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(next@16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react-server-dom-webpack@19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(typescript@6.0.2): + vinext@0.0.41(@mdx-js/rollup@3.1.1)(@vitejs/plugin-react@6.0.1(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)))(@vitejs/plugin-rsc@0.5.24(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(react-dom@19.2.5(react@19.2.5))(react-server-dom-webpack@19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(next@16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react-server-dom-webpack@19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(typescript@6.0.2): dependencies: '@unpic/react': 1.0.2(next@16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@vercel/og': 0.8.6 - '@vitejs/plugin-react': 6.0.1(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) + '@vitejs/plugin-react': 6.0.1(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)) magic-string: 0.30.21 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' vite-plugin-commonjs: 0.10.4 - vite-tsconfig-paths: 6.1.1(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2) + vite-tsconfig-paths: 6.1.1(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2) optionalDependencies: '@mdx-js/rollup': 3.1.1 - '@vitejs/plugin-rsc': 0.5.24(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(react-dom@19.2.5(react@19.2.5))(react-server-dom-webpack@19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5) + '@vitejs/plugin-rsc': 0.5.24(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(react-dom@19.2.5(react@19.2.5))(react-server-dom-webpack@19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5) react-server-dom-webpack: 19.2.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5) transitivePeerDependencies: - next @@ -15859,9 +15859,9 @@ snapshots: fast-glob: 3.3.3 magic-string: 0.30.21 - vite-plugin-inspect@12.0.0-beta.1(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2)(ws@8.20.0): + vite-plugin-inspect@12.0.0-beta.1(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2)(ws@8.20.0): dependencies: - '@vitejs/devtools-kit': 0.1.11(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2)(ws@8.20.0) + '@vitejs/devtools-kit': 0.1.11(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2)(ws@8.20.0) ansis: 4.2.0 error-stack-parser-es: 1.0.5 obug: 2.1.1 @@ -15870,12 +15870,12 @@ snapshots: perfect-debounce: 2.1.0 sirv: 3.0.2 unplugin-utils: 0.3.1 - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' transitivePeerDependencies: - typescript - ws - vite-plugin-storybook-nextjs@3.2.4(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(next@16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2): + vite-plugin-storybook-nextjs@3.2.4(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(next@16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(storybook@10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@6.0.2): dependencies: '@next/env': 16.0.0 image-size: 2.0.2 @@ -15884,29 +15884,29 @@ snapshots: next: 16.2.3(@babel/core@7.29.0)(@playwright/test@1.59.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) storybook: 10.3.5(@testing-library/dom@10.4.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) ts-dedent: 2.2.0 - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' - vite-tsconfig-paths: 5.1.4(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2) + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite-tsconfig-paths: 5.1.4(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2) transitivePeerDependencies: - supports-color - typescript - vite-plus@0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3): + vite-plus@0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3): dependencies: - '@oxc-project/types': 0.124.0 - '@voidzero-dev/vite-plus-core': 0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) - '@voidzero-dev/vite-plus-test': 0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + '@oxc-project/types': 0.126.0 + '@voidzero-dev/vite-plus-core': 0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) + '@voidzero-dev/vite-plus-test': 0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3) oxfmt: 0.45.0 - oxlint: 1.60.0(oxlint-tsgolint@0.20.0) - oxlint-tsgolint: 0.20.0 + oxlint: 1.60.0(oxlint-tsgolint@0.21.1) + oxlint-tsgolint: 0.21.1 optionalDependencies: - '@voidzero-dev/vite-plus-darwin-arm64': 0.1.18 - '@voidzero-dev/vite-plus-darwin-x64': 0.1.18 - '@voidzero-dev/vite-plus-linux-arm64-gnu': 0.1.18 - '@voidzero-dev/vite-plus-linux-arm64-musl': 0.1.18 - '@voidzero-dev/vite-plus-linux-x64-gnu': 0.1.18 - '@voidzero-dev/vite-plus-linux-x64-musl': 0.1.18 - '@voidzero-dev/vite-plus-win32-arm64-msvc': 0.1.18 - '@voidzero-dev/vite-plus-win32-x64-msvc': 0.1.18 + '@voidzero-dev/vite-plus-darwin-arm64': 0.1.19 + '@voidzero-dev/vite-plus-darwin-x64': 0.1.19 + '@voidzero-dev/vite-plus-linux-arm64-gnu': 0.1.19 + '@voidzero-dev/vite-plus-linux-arm64-musl': 0.1.19 + '@voidzero-dev/vite-plus-linux-x64-gnu': 0.1.19 + '@voidzero-dev/vite-plus-linux-x64-musl': 0.1.19 + '@voidzero-dev/vite-plus-win32-arm64-msvc': 0.1.19 + '@voidzero-dev/vite-plus-win32-x64-msvc': 0.1.19 transitivePeerDependencies: - '@arethetypeswrong/core' - '@edge-runtime/vm' @@ -15937,36 +15937,36 @@ snapshots: - vite - yaml - vite-tsconfig-paths@5.1.4(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2): + vite-tsconfig-paths@5.1.4(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2): dependencies: debug: 4.4.3(supports-color@8.1.1) globrex: 0.1.2 tsconfck: 3.1.6(typescript@6.0.2) optionalDependencies: - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' transitivePeerDependencies: - supports-color - typescript - vite-tsconfig-paths@6.1.1(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2): + vite-tsconfig-paths@6.1.1(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(typescript@6.0.2): dependencies: debug: 4.4.3(supports-color@8.1.1) globrex: 0.1.2 tsconfck: 3.1.6(typescript@6.0.2) - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' transitivePeerDependencies: - supports-color - typescript - vitefu@1.1.3(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)): + vitefu@1.1.3(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)): optionalDependencies: - vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' - vitest-browser-react@2.2.0(@types/node@25.6.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3): + vitest-browser-react@2.2.0(@types/node@25.6.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3): dependencies: react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - vitest: '@voidzero-dev/vite-plus-test@0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vitest: '@voidzero-dev/vite-plus-test@0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) @@ -16000,11 +16000,11 @@ snapshots: - vite - yaml - vitest-canvas-mock@1.1.4(@voidzero-dev/vite-plus-test@0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)): + vitest-canvas-mock@1.1.4(@voidzero-dev/vite-plus-test@0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)): dependencies: cssfontparser: 1.2.1 moo-color: 1.0.3 - vitest: '@voidzero-dev/vite-plus-test@0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' + vitest: '@voidzero-dev/vite-plus-test@0.1.19(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)' void-elements@3.1.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5afca57719..7a81789267 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -42,8 +42,8 @@ overrides: svgo@>=3.0.0 <3.3.3: 3.3.3 tar@<=7.5.10: 7.5.11 undici@>=7.0.0 <7.24.0: 7.24.0 - vite: npm:@voidzero-dev/vite-plus-core@0.1.18 - vitest: npm:@voidzero-dev/vite-plus-test@0.1.18 + vite: npm:@voidzero-dev/vite-plus-core@0.1.19 + vitest: npm:@voidzero-dev/vite-plus-test@0.1.19 yaml@>=2.0.0 <2.8.3: 2.8.3 yauzl@<3.2.1: 3.2.1 catalog: @@ -222,10 +222,10 @@ catalog: use-context-selector: 2.0.0 uuid: 13.0.0 vinext: 0.0.41 - vite: npm:@voidzero-dev/vite-plus-core@0.1.18 + vite: npm:@voidzero-dev/vite-plus-core@0.1.19 vite-plugin-inspect: 12.0.0-beta.1 - vite-plus: 0.1.18 - vitest: npm:@voidzero-dev/vite-plus-test@0.1.18 + vite-plus: 0.1.19 + vitest: npm:@voidzero-dev/vite-plus-test@0.1.19 vitest-browser-react: 2.2.0 vitest-canvas-mock: 1.1.4 zod: 4.3.6 diff --git a/sdks/nodejs-client/vite.config.ts b/sdks/nodejs-client/vite.config.ts index 8d89508682..68ced551a3 100644 --- a/sdks/nodejs-client/vite.config.ts +++ b/sdks/nodejs-client/vite.config.ts @@ -4,6 +4,7 @@ export default defineConfig({ pack: { entry: ["src/index.ts"], format: ["esm"], + platform: "node", dts: true, clean: true, sourcemap: true, From 44a91e344cee4885124a0464db402f18efadf44d Mon Sep 17 00:00:00 2001 From: zyssyz123 <916125788@qq.com> Date: Tue, 21 Apr 2026 17:28:44 +0800 Subject: [PATCH 5/6] fix(plugin): persist tenant plugin auto-upgrade strategy changes (#35464) --- api/services/plugin/plugin_auto_upgrade_service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/services/plugin/plugin_auto_upgrade_service.py b/api/services/plugin/plugin_auto_upgrade_service.py index 9bb0ab6ae2..b96b8140ac 100644 --- a/api/services/plugin/plugin_auto_upgrade_service.py +++ b/api/services/plugin/plugin_auto_upgrade_service.py @@ -23,7 +23,7 @@ class PluginAutoUpgradeService: exclude_plugins: list[str], include_plugins: list[str], ) -> bool: - with session_factory.create_session() as session: + with session_factory.create_session() as session, session.begin(): exist_strategy = session.scalar( select(TenantPluginAutoUpgradeStrategy) .where(TenantPluginAutoUpgradeStrategy.tenant_id == tenant_id) @@ -50,7 +50,7 @@ class PluginAutoUpgradeService: @staticmethod def exclude_plugin(tenant_id: str, plugin_id: str) -> bool: - with session_factory.create_session() as session: + with session_factory.create_session() as session, session.begin(): exist_strategy = session.scalar( select(TenantPluginAutoUpgradeStrategy) .where(TenantPluginAutoUpgradeStrategy.tenant_id == tenant_id) From d65a6b481066cb0abd46a4d376795060e555fc06 Mon Sep 17 00:00:00 2001 From: Coding On Star <447357187@qq.com> Date: Tue, 21 Apr 2026 18:09:22 +0800 Subject: [PATCH 6/6] refactor: migrate from PortalToFollowElem to Popover component across various components (#35454) Co-authored-by: CodingOnStar Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- eslint-suppressions.json | 115 ----- .../context-var/__tests__/index.spec.tsx | 84 +++- .../context-var/__tests__/var-picker.spec.tsx | 42 +- .../dataset-config/context-var/var-picker.tsx | 91 ++-- .../member-selector.tsx | 77 +-- .../__tests__/selector-entry.spec.tsx | 55 ++- .../subscription-list/selector-entry.tsx | 53 +-- .../plugin-tasks/__tests__/index.spec.tsx | 25 +- .../plugin-page/plugin-tasks/index.tsx | 1 + .../__tests__/index.spec.tsx | 64 ++- .../__tests__/tool-picker.spec.tsx | 75 +-- .../auto-update-setting/tool-picker.tsx | 128 ++--- .../tools/labels/__tests__/selector.spec.tsx | 59 +++ web/app/components/tools/labels/selector.tsx | 63 +-- .../workflow/__tests__/custom-edge.spec.tsx | 4 + .../__tests__/tool-picker.spec.tsx | 4 +- .../workflow/block-selector/tool-picker.tsx | 72 +-- web/app/components/workflow/custom-edge.tsx | 8 +- .../agent-strategy-selector.spec.tsx | 446 ++++++++++++++++++ .../components/agent-strategy-selector.tsx | 164 ++++--- .../var-reference-picker.trigger.spec.tsx | 146 +++--- .../variable/var-reference-picker.trigger.tsx | 85 ++-- .../variable/var-reference-picker.tsx | 58 ++- .../variable/var-reference-vars.tsx | 128 ++--- .../workflow/nodes/code/dependency-picker.tsx | 41 +- .../__tests__/member-selector.spec.tsx | 53 +++ .../delivery-method/recipient/email-input.tsx | 61 ++- .../recipient/member-selector.tsx | 59 ++- .../if-else/components/condition-add.tsx | 60 +-- .../condition-list/condition-var-selector.tsx | 49 +- .../components/metadata/add-condition.tsx | 89 ++-- .../condition-common-variable-selector.tsx | 86 ++-- .../condition-variable-selector.tsx | 57 +-- .../nodes/loop/components/condition-add.tsx | 60 +-- .../condition-list/condition-var-selector.tsx | 49 +- .../__tests__/search-input.spec.tsx | 159 +++++++ web/app/education-apply/search-input.tsx | 102 ++-- 37 files changed, 1900 insertions(+), 1072 deletions(-) create mode 100644 web/app/components/workflow/nodes/_base/components/__tests__/agent-strategy-selector.spec.tsx create mode 100644 web/app/education-apply/__tests__/search-input.spec.tsx diff --git a/eslint-suppressions.json b/eslint-suppressions.json index d969e0bf83..0e0970f90d 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -488,11 +488,6 @@ "count": 1 } }, - "web/app/components/app/configuration/dataset-config/context-var/var-picker.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/app/configuration/dataset-config/index.tsx": { "ts/no-explicit-any": { "count": 1 @@ -3060,14 +3055,6 @@ "count": 3 } }, - "web/app/components/header/account-setting/members-page/transfer-ownership-modal/member-selector.tsx": { - "no-restricted-imports": { - "count": 1 - }, - "ts/no-explicit-any": { - "count": 2 - } - }, "web/app/components/header/account-setting/model-provider-page/declarations.ts": { "erasable-syntax-only/enums": { "count": 11 @@ -3554,11 +3541,6 @@ "count": 2 } }, - "web/app/components/plugins/plugin-detail-panel/subscription-list/selector-entry.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/plugins/plugin-detail-panel/subscription-list/selector-view.tsx": { "no-restricted-imports": { "count": 1 @@ -3672,11 +3654,6 @@ "count": 1 } }, - "web/app/components/plugins/reference-setting-modal/auto-update-setting/tool-picker.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/plugins/reference-setting-modal/auto-update-setting/types.ts": { "erasable-syntax-only/enums": { "count": 2 @@ -3933,11 +3910,6 @@ "count": 1 } }, - "web/app/components/tools/labels/selector.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/tools/mcp/create-card.tsx": { "ts/no-explicit-any": { "count": 1 @@ -4123,11 +4095,6 @@ "count": 1 } }, - "web/app/components/workflow/block-selector/tool-picker.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/workflow/block-selector/tool/tool-list-flat-view/list.tsx": { "ts/no-explicit-any": { "count": 1 @@ -4313,14 +4280,6 @@ "count": 2 } }, - "web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx": { - "no-restricted-imports": { - "count": 3 - }, - "ts/no-explicit-any": { - "count": 4 - } - }, "web/app/components/workflow/nodes/_base/components/agent-strategy.tsx": { "ts/no-empty-object-type": { "count": 1 @@ -4547,22 +4506,6 @@ "count": 1 } }, - "web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx": { - "no-restricted-imports": { - "count": 1 - }, - "react/set-state-in-effect": { - "count": 1 - }, - "ts/no-explicit-any": { - "count": 3 - } - }, - "web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/workflow/nodes/_base/components/variable/var-type-picker.tsx": { "no-restricted-imports": { "count": 1 @@ -4742,11 +4685,6 @@ "count": 1 } }, - "web/app/components/workflow/nodes/code/dependency-picker.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/workflow/nodes/code/types.ts": { "erasable-syntax-only/enums": { "count": 1 @@ -4897,16 +4835,6 @@ "count": 1 } }, - "web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/email-input.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, - "web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/member-selector.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/workflow/nodes/human-input/components/delivery-method/test-email-sender.tsx": { "no-restricted-imports": { "count": 1 @@ -4957,11 +4885,6 @@ "count": 2 } }, - "web/app/components/workflow/nodes/if-else/components/condition-add.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/workflow/nodes/if-else/components/condition-list/condition-input.tsx": { "ts/no-explicit-any": { "count": 1 @@ -4977,11 +4900,6 @@ "count": 1 } }, - "web/app/components/workflow/nodes/if-else/components/condition-list/condition-var-selector.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/workflow/nodes/if-else/components/condition-number-input.tsx": { "no-restricted-imports": { "count": 1 @@ -5085,16 +5003,6 @@ "count": 1 } }, - "web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/add-condition.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, - "web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-common-variable-selector.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-item.tsx": { "ts/no-explicit-any": { "count": 1 @@ -5110,11 +5018,6 @@ "count": 1 } }, - "web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-variable-selector.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/metadata-filter/index.tsx": { "no-restricted-imports": { "count": 1 @@ -5294,11 +5197,6 @@ "count": 1 } }, - "web/app/components/workflow/nodes/loop/components/condition-add.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/workflow/nodes/loop/components/condition-list/condition-input.tsx": { "ts/no-explicit-any": { "count": 1 @@ -5314,11 +5212,6 @@ "count": 1 } }, - "web/app/components/workflow/nodes/loop/components/condition-list/condition-var-selector.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/workflow/nodes/loop/components/condition-number-input.tsx": { "no-restricted-imports": { "count": 1 @@ -6095,14 +5988,6 @@ "count": 5 } }, - "web/app/education-apply/search-input.tsx": { - "no-restricted-imports": { - "count": 1 - }, - "ts/no-explicit-any": { - "count": 1 - } - }, "web/app/education-apply/verify-state-modal.tsx": { "react/set-state-in-effect": { "count": 1 diff --git a/web/app/components/app/configuration/dataset-config/context-var/__tests__/index.spec.tsx b/web/app/components/app/configuration/dataset-config/context-var/__tests__/index.spec.tsx index 6726ba0583..91fe47d83d 100644 --- a/web/app/components/app/configuration/dataset-config/context-var/__tests__/index.spec.tsx +++ b/web/app/components/app/configuration/dataset-config/context-var/__tests__/index.spec.tsx @@ -10,6 +10,72 @@ vi.mock('@/next/navigation', () => ({ usePathname: () => '/test', })) +vi.mock('@langgenius/dify-ui/popover', async () => { + const React = await import('react') + const PopoverContext = React.createContext({ + open: false, + setOpen: (_open: boolean) => {}, + }) + + const Popover = ({ + children, + open: controlledOpen, + onOpenChange, + }: { + children: React.ReactNode + open?: boolean + onOpenChange?: (open: boolean) => void + }) => { + const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false) + const isControlled = controlledOpen !== undefined + const open = isControlled ? !!controlledOpen : uncontrolledOpen + const setOpen = (nextOpen: boolean) => { + if (!isControlled) + setUncontrolledOpen(nextOpen) + onOpenChange?.(nextOpen) + } + + return ( + + {children} + + ) + } + + const PopoverTrigger = ({ render }: { render: React.ReactNode }) => { + const { open, setOpen } = React.useContext(PopoverContext) + return ( +
setOpen(!open)} + > + {render} +
+ ) + } + + const PopoverContent = ({ + children, + ...props + }: React.HTMLAttributes & { children?: React.ReactNode }) => { + const { open } = React.useContext(PopoverContext) + if (!open) + return null + + return ( +
+ {children} +
+ ) + } + + return { + Popover, + PopoverTrigger, + PopoverContent, + } +}) + type PortalToFollowElemProps = { children: React.ReactNode open?: boolean @@ -209,20 +275,17 @@ describe('ContextVar', () => { // Act render() - const triggers = screen.getAllByTestId('portal-trigger') - const varPickerTrigger = triggers[triggers.length - 1] + const varPickerTrigger = screen.getByTestId('popover-trigger') await user.click(varPickerTrigger!) - expect(screen.getByTestId('portal-content'))!.toBeInTheDocument() + expect(screen.getByTestId('popover-content'))!.toBeInTheDocument() // Select a different option - const options = screen.getAllByText('var2') - expect(options.length).toBeGreaterThan(0) - await user.click(options[0]!) + await user.click(screen.getByText('var2')) // Assert expect(onChange).toHaveBeenCalledWith('var2') - expect(screen.queryByTestId('portal-content')).not.toBeInTheDocument() + expect(screen.queryByTestId('popover-content')).not.toBeInTheDocument() }) it('should toggle dropdown when clicking the trigger button', async () => { @@ -233,16 +296,15 @@ describe('ContextVar', () => { // Act render() - const triggers = screen.getAllByTestId('portal-trigger') - const varPickerTrigger = triggers[triggers.length - 1] + const varPickerTrigger = screen.getByTestId('popover-trigger') // Open dropdown await user.click(varPickerTrigger!) - expect(screen.getByTestId('portal-content'))!.toBeInTheDocument() + expect(screen.getByTestId('popover-content'))!.toBeInTheDocument() // Close dropdown await user.click(varPickerTrigger!) - expect(screen.queryByTestId('portal-content')).not.toBeInTheDocument() + expect(screen.queryByTestId('popover-content')).not.toBeInTheDocument() }) }) diff --git a/web/app/components/app/configuration/dataset-config/context-var/__tests__/var-picker.spec.tsx b/web/app/components/app/configuration/dataset-config/context-var/__tests__/var-picker.spec.tsx index 1d81a31091..7890343720 100644 --- a/web/app/components/app/configuration/dataset-config/context-var/__tests__/var-picker.spec.tsx +++ b/web/app/components/app/configuration/dataset-config/context-var/__tests__/var-picker.spec.tsx @@ -18,18 +18,21 @@ type PortalToFollowElemProps = { type PortalToFollowElemTriggerProps = React.HTMLAttributes & { children?: React.ReactNode, asChild?: boolean } type PortalToFollowElemContentProps = React.HTMLAttributes & { children?: React.ReactNode } -vi.mock('@/app/components/base/portal-to-follow-elem', () => { - const PortalContext = React.createContext({ open: false }) +vi.mock('@langgenius/dify-ui/popover', () => { + const PortalContext = React.createContext({ + open: false, + onOpenChange: undefined as ((open: boolean) => void) | undefined, + }) - const PortalToFollowElem = ({ children, open }: PortalToFollowElemProps) => { + const Popover = ({ children, open, onOpenChange }: PortalToFollowElemProps) => { return ( - +
{children}
) } - const PortalToFollowElemContent = ({ children, ...props }: PortalToFollowElemContentProps) => { + const PopoverContent = ({ children, ...props }: PortalToFollowElemContentProps) => { const { open } = React.useContext(PortalContext) if (!open) return null @@ -40,24 +43,41 @@ vi.mock('@/app/components/base/portal-to-follow-elem', () => { ) } - const PortalToFollowElemTrigger = ({ children, asChild, ...props }: PortalToFollowElemTriggerProps) => { + const PopoverTrigger = ({ children, asChild, render, ...props }: PortalToFollowElemTriggerProps & { render?: React.ReactNode }) => { + const { open, onOpenChange } = React.useContext(PortalContext) + const content = render ?? children + const handleClick = (e: React.MouseEvent) => { + props.onClick?.(e) + if (!props.onClick) + onOpenChange?.(!open) + } + + if (React.isValidElement(content)) { + return React.cloneElement(content, { + ...props, + 'onClick': handleClick, + 'data-testid': 'portal-trigger', + } as React.HTMLAttributes) + } + if (asChild && React.isValidElement(children)) { return React.cloneElement(children, { ...props, + 'onClick': handleClick, 'data-testid': 'portal-trigger', } as React.HTMLAttributes) } return ( -
- {children} +
+ {content}
) } return { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, + Popover, + PopoverContent, + PopoverTrigger, } }) diff --git a/web/app/components/app/configuration/dataset-config/context-var/var-picker.tsx b/web/app/components/app/configuration/dataset-config/context-var/var-picker.tsx index d29b2e34df..9bac1c7a41 100644 --- a/web/app/components/app/configuration/dataset-config/context-var/var-picker.tsx +++ b/web/app/components/app/configuration/dataset-config/context-var/var-picker.tsx @@ -3,15 +3,15 @@ import type { FC } from 'react' import type { IInputTypeIconProps } from '@/app/components/app/configuration/config-var/input-type-icon' import { ChevronDownIcon } from '@heroicons/react/24/outline' import { cn } from '@langgenius/dify-ui/cn' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import * as React from 'react' import { useState } from 'react' import { useTranslation } from 'react-i18next' import IconTypeIcon from '@/app/components/app/configuration/config-var/input-type-icon' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' type Option = { name: string, value: string, type: string } export type Props = { @@ -33,6 +33,7 @@ const VarItem: FC<{ item: Option }> = ({ item }) => (
) + const VarPicker: FC = ({ triggerClassName, className, @@ -45,47 +46,51 @@ const VarPicker: FC = ({ const [open, setOpen] = useState(false) const currItem = options.find(item => item.value === value) const notSetVar = !currItem + return ( - - setOpen(v => !v)}> -
-
- {value - ? ( - - ) - : ( -
- {notSelectedVarTip || t('feature.dataSet.queryVariable.choosePlaceholder', { ns: 'appDebug' })} -
- )} + + +
+
+ {currItem + ? ( + + ) + : ( +
+ {notSelectedVarTip || t('feature.dataSet.queryVariable.choosePlaceholder', { ns: 'appDebug' })} +
+ )} +
+ +
- -
-
- + )} + /> + {options.length > 0 ? (
- {options.map(({ name, value, type }, index) => ( + {options.map(({ name, value, type }) => (
{ onChange(value) @@ -103,9 +108,9 @@ const VarPicker: FC = ({
{t('feature.dataSet.queryVariable.noVarTip', { ns: 'appDebug' })}
)} - - - + + ) } + export default React.memo(VarPicker) diff --git a/web/app/components/header/account-setting/members-page/transfer-ownership-modal/member-selector.tsx b/web/app/components/header/account-setting/members-page/transfer-ownership-modal/member-selector.tsx index 5875b4fb6a..4dc41a307b 100644 --- a/web/app/components/header/account-setting/members-page/transfer-ownership-modal/member-selector.tsx +++ b/web/app/components/header/account-setting/members-page/transfer-ownership-modal/member-selector.tsx @@ -2,16 +2,20 @@ import type { FC } from 'react' import { Avatar } from '@langgenius/dify-ui/avatar' import { cn } from '@langgenius/dify-ui/cn' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import * as React from 'react' import { useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import Input from '@/app/components/base/input' -import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem' import { useMembers } from '@/service/use-common' type Props = { - value?: any - onSelect: (value: any) => void + value?: string + onSelect: (value: string) => void exclude?: string[] } @@ -27,12 +31,9 @@ const MemberSelector: FC = ({ const { data } = useMembers() const currentValue = useMemo(() => { - if (!data?.accounts) + if (!data?.accounts || !value) return null - const accounts = data.accounts || [] - if (!value) - return null - return accounts.find(account => account.id === value) + return data.accounts.find(account => account.id === value) ?? null }, [data, value]) const filteredList = useMemo(() => { @@ -47,37 +48,36 @@ const MemberSelector: FC = ({ return name.toLowerCase().includes(searchValue.toLowerCase()) || email.toLowerCase().includes(searchValue.toLowerCase()) }).filter(account => !exclude.includes(account.id)) - }, [data, searchValue, exclude]) + }, [data, exclude, searchValue]) return ( - - setOpen(v => !v)} + + + {!currentValue && ( +
{t('members.transferModal.transferPlaceholder', { ns: 'common' })}
+ )} + {currentValue && ( + <> + +
{currentValue.name}
+
{currentValue.email}
+ + )} +
+
+ )} + /> + -
- {!currentValue && ( -
{t('members.transferModal.transferPlaceholder', { ns: 'common' })}
- )} - {currentValue && ( - <> - -
{currentValue.name}
-
{currentValue.email}
- - )} -
-
- -
= ({ ))}
-
- + + ) } + export default MemberSelector diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/__tests__/selector-entry.spec.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/__tests__/selector-entry.spec.tsx index 37d828591f..1eb02fb15a 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/__tests__/selector-entry.spec.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/__tests__/selector-entry.spec.tsx @@ -4,6 +4,59 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { TriggerCredentialTypeEnum } from '@/app/components/workflow/block-selector/types' import { SubscriptionSelectorEntry } from '../selector-entry' +vi.mock('@langgenius/dify-ui/popover', async () => { + const React = await import('react') + const PopoverContext = React.createContext({ + open: false, + setOpen: (_open: boolean) => {}, + }) + + const Popover = ({ + children, + open: controlledOpen, + onOpenChange, + }: { + children: React.ReactNode + open?: boolean + onOpenChange?: (open: boolean) => void + }) => { + const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false) + const isControlled = controlledOpen !== undefined + const open = isControlled ? !!controlledOpen : uncontrolledOpen + const setOpen = (nextOpen: boolean) => { + if (!isControlled) + setUncontrolledOpen(nextOpen) + onOpenChange?.(nextOpen) + } + + return ( + + {children} + + ) + } + + const PopoverTrigger = ({ render }: { render: React.ReactNode }) => { + const { open, setOpen } = React.useContext(PopoverContext) + return ( +
setOpen(!open)}> + {render} +
+ ) + } + + const PopoverContent = ({ children }: { children: React.ReactNode }) => { + const { open } = React.useContext(PopoverContext) + return open ?
{children}
: null + } + + return { + Popover, + PopoverTrigger, + PopoverContent, + } +}) + let mockSubscriptions: TriggerSubscription[] = [] const mockRefetch = vi.fn() @@ -92,6 +145,6 @@ describe('SubscriptionSelectorEntry', () => { fireEvent.click(screen.getByRole('button', { name: 'Subscription One' })) expect(onSelect).toHaveBeenCalledWith(expect.objectContaining({ id: 'sub-1', name: 'Subscription One' }), expect.any(Function)) - expect(screen.queryByText('Subscription One')).not.toBeInTheDocument() + expect(screen.queryByTestId('popover-content')).not.toBeInTheDocument() }) }) diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/selector-entry.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/selector-entry.tsx index 5f755ff634..21f1d4898b 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/selector-entry.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/selector-entry.tsx @@ -1,28 +1,26 @@ 'use client' import type { SimpleSubscription } from './types' import { cn } from '@langgenius/dify-ui/cn' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import { RiArrowDownSLine, RiWebhookLine } from '@remixicon/react' import { useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' import { SubscriptionList } from '@/app/components/plugins/plugin-detail-panel/subscription-list' import { SubscriptionListMode } from './types' import { useSubscriptionList } from './use-subscription-list' type SubscriptionTriggerButtonProps = { selectedId?: string - onClick?: () => void isOpen?: boolean className?: string } const SubscriptionTriggerButton: React.FC = ({ selectedId, - onClick, isOpen = false, className, }) => { @@ -44,7 +42,7 @@ const SubscriptionTriggerButton: React.FC = ({ } if (subscriptions && subscriptions.length > 0) { - const selectedSubscription = subscriptions?.find(sub => sub.id === selectedId) + const selectedSubscription = subscriptions.find(sub => sub.id === selectedId) if (!selectedSubscription) { return { @@ -67,13 +65,13 @@ const SubscriptionTriggerButton: React.FC = ({ return (
+ )} + /> +
- -
+ + ) } diff --git a/web/app/components/plugins/plugin-page/plugin-tasks/__tests__/index.spec.tsx b/web/app/components/plugins/plugin-page/plugin-tasks/__tests__/index.spec.tsx index c87673b750..12fc796531 100644 --- a/web/app/components/plugins/plugin-page/plugin-tasks/__tests__/index.spec.tsx +++ b/web/app/components/plugins/plugin-page/plugin-tasks/__tests__/index.spec.tsx @@ -61,6 +61,9 @@ const setupMocks = (plugins: PluginStatus[] = []) => { return { mockMutateAsync, mockHandleRefetch } } +const getTaskMenuTrigger = () => + document.getElementById('plugin-task-trigger')!.closest('[role="button"]') as HTMLElement + describe('usePluginTaskStatus Hook', () => { beforeEach(() => { vi.clearAllMocks() @@ -637,7 +640,7 @@ describe('PluginTasks Component', () => { render() // Click to open - fireEvent.click(document.getElementById('plugin-task-trigger')!) + fireEvent.click(getTaskMenuTrigger()) // The popover content should be visible (PluginTaskList) // The popover content should be visible (PluginTaskList) @@ -666,7 +669,7 @@ describe('PluginTasks Component', () => { render() // Open popover - fireEvent.click(document.getElementById('plugin-task-trigger')!) + fireEvent.click(getTaskMenuTrigger()) // Wait for popover content to render await waitFor(() => { @@ -692,7 +695,7 @@ describe('PluginTasks Component', () => { render() - fireEvent.click(document.getElementById('plugin-task-trigger')!) + fireEvent.click(getTaskMenuTrigger()) await waitFor(() => { expect(document.querySelector('.w-\\[360px\\]')).toBeInTheDocument() @@ -713,16 +716,14 @@ describe('PluginTasks Component', () => { render() // Open popover - fireEvent.click(document.getElementById('plugin-task-trigger')!) + fireEvent.click(getTaskMenuTrigger()) await waitFor(() => { expect(document.querySelector('.w-\\[360px\\]'))!.toBeInTheDocument() }) // Find and click the clear all button in error section - const clearButtons = screen.getAllByRole('button') - if (clearButtons.length > 0) - fireEvent.click(clearButtons[0]!) + fireEvent.click(screen.getByRole('button', { name: /task\.clearAll/i })) await waitFor(() => { expect(mockMutateAsync).toHaveBeenCalled() @@ -741,7 +742,7 @@ describe('PluginTasks Component', () => { render() // Open popover - fireEvent.click(document.getElementById('plugin-task-trigger')!) + fireEvent.click(getTaskMenuTrigger()) await waitFor(() => { expect(document.querySelector('.w-\\[360px\\]'))!.toBeInTheDocument() @@ -813,7 +814,7 @@ describe('PluginTasks Component', () => { render() // Open popover - fireEvent.click(document.getElementById('plugin-task-trigger')!) + fireEvent.click(getTaskMenuTrigger()) expect(document.querySelector('.w-\\[360px\\]'))!.toBeInTheDocument() }) @@ -825,7 +826,7 @@ describe('PluginTasks Component', () => { ]) render() - fireEvent.click(document.getElementById('plugin-task-trigger')!) + fireEvent.click(getTaskMenuTrigger()) expect(document.querySelector('.w-\\[360px\\]')).toBeInTheDocument() }) @@ -837,7 +838,7 @@ describe('PluginTasks Component', () => { ]) render() - fireEvent.click(document.getElementById('plugin-task-trigger')!) + fireEvent.click(getTaskMenuTrigger()) expect(document.querySelector('.w-\\[360px\\]')).toBeInTheDocument() }) @@ -892,7 +893,7 @@ describe('PluginTasks Integration', () => { render() // Open popover - fireEvent.click(document.getElementById('plugin-task-trigger')!) + fireEvent.click(getTaskMenuTrigger()) // All sections should be visible const sections = document.querySelectorAll('.max-h-\\[300px\\]') diff --git a/web/app/components/plugins/plugin-page/plugin-tasks/index.tsx b/web/app/components/plugins/plugin-page/plugin-tasks/index.tsx index 7603cae33d..f3102c4909 100644 --- a/web/app/components/plugins/plugin-page/plugin-tasks/index.tsx +++ b/web/app/components/plugins/plugin-page/plugin-tasks/index.tsx @@ -97,6 +97,7 @@ const PluginTasks = () => { onOpenChange={setOpen} > } disabled={!canOpenMenu} > diff --git a/web/app/components/plugins/reference-setting-modal/auto-update-setting/__tests__/index.spec.tsx b/web/app/components/plugins/reference-setting-modal/auto-update-setting/__tests__/index.spec.tsx index 19ce12b328..ed3c457aaf 100644 --- a/web/app/components/plugins/reference-setting-modal/auto-update-setting/__tests__/index.spec.tsx +++ b/web/app/components/plugins/reference-setting-modal/auto-update-setting/__tests__/index.spec.tsx @@ -61,35 +61,78 @@ vi.mock('@/service/use-plugins', () => ({ }), })) -// Mock portal component for ToolPicker and StrategyPicker +// Mock popover component for ToolPicker and StrategyPicker let mockPortalOpen = false let forcePortalContentVisible = false // Allow tests to force content visibility -vi.mock('@/app/components/base/portal-to-follow-elem', () => ({ - PortalToFollowElem: ({ children, open, onOpenChange: _onOpenChange }: { +let mockPortalOnOpenChange: ((open: boolean) => void) | undefined +vi.mock('@langgenius/dify-ui/popover', () => ({ + Popover: ({ children, open = false, onOpenChange }: { children: React.ReactNode - open: boolean - onOpenChange: (open: boolean) => void + open?: boolean + onOpenChange?: (open: boolean) => void }) => { mockPortalOpen = open + mockPortalOnOpenChange = onOpenChange + return ( +
{children}
+ ) + }, + PopoverTrigger: ({ children, render, onClick, className }: { + children?: React.ReactNode + render?: React.ReactNode + onClick?: (e: React.MouseEvent) => void + className?: string + }) => ( +
{ + onClick?.(e) + if (!onClick) + mockPortalOnOpenChange?.(!mockPortalOpen) + }} + className={className} + > + {render ?? children} +
+ ), + PopoverContent: ({ children, className, popupClassName }: { + children: React.ReactNode + className?: string + popupClassName?: string + }) => { + if (!mockPortalOpen && !forcePortalContentVisible) + return null + return
{children}
+ }, +})) + +vi.mock('@/app/components/base/portal-to-follow-elem', () => ({ + PortalToFollowElem: ({ children, open = false, onOpenChange }: { + children: React.ReactNode + open?: boolean + onOpenChange?: (open: boolean) => void + }) => { + mockPortalOpen = open + mockPortalOnOpenChange = onOpenChange return
{children}
}, PortalToFollowElemTrigger: ({ children, onClick, className }: { - children: React.ReactNode - onClick: (e: React.MouseEvent) => void + children?: React.ReactNode + onClick?: (e: React.MouseEvent) => void className?: string }) => (
{children}
), - PortalToFollowElemContent: ({ children, className }: { + PortalToFollowElemContent: ({ children, className, popupClassName }: { children: React.ReactNode className?: string + popupClassName?: string }) => { - // Allow forcing content visibility for testing option selection if (!mockPortalOpen && !forcePortalContentVisible) return null - return
{children}
+ return
{children}
}, })) @@ -319,6 +362,7 @@ describe('auto-update-setting', () => { beforeEach(() => { vi.clearAllMocks() mockPortalOpen = false + mockPortalOnOpenChange = undefined forcePortalContentVisible = false mockPluginsData.plugins = [] }) diff --git a/web/app/components/plugins/reference-setting-modal/auto-update-setting/__tests__/tool-picker.spec.tsx b/web/app/components/plugins/reference-setting-modal/auto-update-setting/__tests__/tool-picker.spec.tsx index e89b1b3161..176598158c 100644 --- a/web/app/components/plugins/reference-setting-modal/auto-update-setting/__tests__/tool-picker.spec.tsx +++ b/web/app/components/plugins/reference-setting-modal/auto-update-setting/__tests__/tool-picker.spec.tsx @@ -4,8 +4,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { PluginSource } from '@/app/components/plugins/types' import ToolPicker from '../tool-picker' -let portalOpen = false - const mockInstalledPluginList = vi.hoisted(() => ({ data: { plugins: [] as PluginDetail[], @@ -21,33 +19,51 @@ vi.mock('@/app/components/base/loading', () => ({ default: () =>
loading
, })) -vi.mock('@/app/components/base/portal-to-follow-elem', async () => { - const _React = await import('react') +vi.mock('@langgenius/dify-ui/popover', async () => { + const React = await import('react') + const PopoverContext = React.createContext({ + open: false, + setOpen: (_open: boolean) => {}, + }) + + const Popover = ({ + children, + open, + onOpenChange, + }: { + children: React.ReactNode + open?: boolean + onOpenChange?: (open: boolean) => void + }) => ( + onOpenChange?.(nextOpen) }}> + {children} + + ) + + const PopoverTrigger = ({ render }: { render: React.ReactNode }) => { + const { open, setOpen } = React.useContext(PopoverContext) + return ( +
setOpen(!open)}> + {render} +
+ ) + } + + const PopoverContent = ({ + children, + className, + }: { + children: React.ReactNode + className?: string + }) => { + const { open } = React.useContext(PopoverContext) + return open ?
{children}
: null + } + return { - PortalToFollowElem: ({ - open, - children, - }: { - open: boolean - children: React.ReactNode - }) => { - portalOpen = open - return
{children}
- }, - PortalToFollowElemTrigger: ({ - children, - onClick, - }: { - children: React.ReactNode - onClick: () => void - }) => , - PortalToFollowElemContent: ({ - children, - className, - }: { - children: React.ReactNode - className?: string - }) => portalOpen ?
{children}
: null, + Popover, + PopoverTrigger, + PopoverContent, } }) @@ -118,7 +134,6 @@ const createPlugin = ( describe('ToolPicker', () => { beforeEach(() => { vi.clearAllMocks() - portalOpen = false mockInstalledPluginList.data = { plugins: [], } @@ -137,7 +152,7 @@ describe('ToolPicker', () => { />, ) - fireEvent.click(screen.getByTestId('trigger')) + fireEvent.click(screen.getByText('trigger')) expect(onShowChange).toHaveBeenCalledWith(true) }) diff --git a/web/app/components/plugins/reference-setting-modal/auto-update-setting/tool-picker.tsx b/web/app/components/plugins/reference-setting-modal/auto-update-setting/tool-picker.tsx index 975dd2217e..1c499104c2 100644 --- a/web/app/components/plugins/reference-setting-modal/auto-update-setting/tool-picker.tsx +++ b/web/app/components/plugins/reference-setting-modal/auto-update-setting/tool-picker.tsx @@ -2,15 +2,15 @@ import type { FC } from 'react' import type { ActivePluginType } from '../../marketplace/constants' import { cn } from '@langgenius/dify-ui/cn' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import * as React from 'react' -import { useCallback, useMemo, useState } from 'react' +import { useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import Loading from '@/app/components/base/loading' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' import SearchBox from '@/app/components/plugins/marketplace/search-box' import { useInstalledPluginList } from '@/service/use-plugins' import { PLUGIN_TYPE_SEARCH_MAP } from '../../marketplace/constants' @@ -24,7 +24,6 @@ type Props = { onChange: (value: string[]) => void isShow: boolean onShowChange: (isShow: boolean) => void - } const ToolPicker: FC = ({ @@ -35,43 +34,16 @@ const ToolPicker: FC = ({ onShowChange, }) => { const { t } = useTranslation() - const toggleShowPopup = useCallback(() => { - onShowChange(!isShow) - }, [onShowChange, isShow]) const tabs = [ - { - key: PLUGIN_TYPE_SEARCH_MAP.all, - name: t('category.all', { ns: 'plugin' }), - }, - { - key: PLUGIN_TYPE_SEARCH_MAP.model, - name: t('category.models', { ns: 'plugin' }), - }, - { - key: PLUGIN_TYPE_SEARCH_MAP.tool, - name: t('category.tools', { ns: 'plugin' }), - }, - { - key: PLUGIN_TYPE_SEARCH_MAP.agent, - name: t('category.agents', { ns: 'plugin' }), - }, - { - key: PLUGIN_TYPE_SEARCH_MAP.extension, - name: t('category.extensions', { ns: 'plugin' }), - }, - { - key: PLUGIN_TYPE_SEARCH_MAP.datasource, - name: t('category.datasources', { ns: 'plugin' }), - }, - { - key: PLUGIN_TYPE_SEARCH_MAP.trigger, - name: t('category.triggers', { ns: 'plugin' }), - }, - { - key: PLUGIN_TYPE_SEARCH_MAP.bundle, - name: t('category.bundles', { ns: 'plugin' }), - }, + { key: PLUGIN_TYPE_SEARCH_MAP.all, name: t('category.all', { ns: 'plugin' }) }, + { key: PLUGIN_TYPE_SEARCH_MAP.model, name: t('category.models', { ns: 'plugin' }) }, + { key: PLUGIN_TYPE_SEARCH_MAP.tool, name: t('category.tools', { ns: 'plugin' }) }, + { key: PLUGIN_TYPE_SEARCH_MAP.agent, name: t('category.agents', { ns: 'plugin' }) }, + { key: PLUGIN_TYPE_SEARCH_MAP.extension, name: t('category.extensions', { ns: 'plugin' }) }, + { key: PLUGIN_TYPE_SEARCH_MAP.datasource, name: t('category.datasources', { ns: 'plugin' }) }, + { key: PLUGIN_TYPE_SEARCH_MAP.trigger, name: t('category.triggers', { ns: 'plugin' }) }, + { key: PLUGIN_TYPE_SEARCH_MAP.bundle, name: t('category.bundles', { ns: 'plugin' }) }, ] const [pluginType, setPluginType] = useState(PLUGIN_TYPE_SEARCH_MAP.all) @@ -89,14 +61,13 @@ const ToolPicker: FC = ({ ) }) }, [data, pluginType, query, tags]) - const handleCheckChange = useCallback((pluginId: string) => { - return () => { - const newValue = value.includes(pluginId) - ? value.filter(id => id !== pluginId) - : [...value, pluginId] - onChange(newValue) - } - }, [onChange, value]) + + const handleCheckChange = (pluginId: string) => { + const newValue = value.includes(pluginId) + ? value.filter(id => id !== pluginId) + : [...value, pluginId] + onChange(newValue) + } const listContent = (
@@ -105,7 +76,7 @@ const ToolPicker: FC = ({ key={item.plugin_id} payload={item} isChecked={value.includes(item.plugin_id)} - onCheckChange={handleCheckChange(item.plugin_id)} + onCheckChange={() => handleCheckChange(item.plugin_id)} /> ))}
@@ -121,21 +92,18 @@ const ToolPicker: FC = ({ ) + const resolvedTrigger = React.isValidElement(trigger) ? trigger :
{trigger}
+ return ( - - + + - {trigger} - - -
+
= ({
- { - tabs.map(tab => ( -
setPluginType(tab.key)} - > - {tab.name} -
- )) - } + {tabs.map(tab => ( +
setPluginType(tab.key)} + > + {tab.name} +
+ ))}
{!isLoading && filteredList.length > 0 && listContent} {!isLoading && filteredList.length === 0 && noData} {isLoading && loadingContent}
- - + + ) } diff --git a/web/app/components/tools/labels/__tests__/selector.spec.tsx b/web/app/components/tools/labels/__tests__/selector.spec.tsx index b495d2d227..4ef4534759 100644 --- a/web/app/components/tools/labels/__tests__/selector.spec.tsx +++ b/web/app/components/tools/labels/__tests__/selector.spec.tsx @@ -2,6 +2,65 @@ import { act, fireEvent, render, screen } from '@testing-library/react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import LabelSelector from '../selector' +vi.mock('@langgenius/dify-ui/popover', async () => { + const React = await import('react') + const PopoverContext = React.createContext({ + open: false, + setOpen: (_open: boolean) => {}, + }) + + const Popover = ({ + children, + open: controlledOpen, + onOpenChange, + }: { + children: React.ReactNode + open?: boolean + onOpenChange?: (open: boolean) => void + }) => { + const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false) + const isControlled = controlledOpen !== undefined + const open = isControlled ? !!controlledOpen : uncontrolledOpen + const setOpen = (nextOpen: boolean) => { + if (!isControlled) + setUncontrolledOpen(nextOpen) + onOpenChange?.(nextOpen) + } + + return ( + + {children} + + ) + } + + const PopoverTrigger = ({ render }: { render: React.ReactNode }) => { + const { open, setOpen } = React.useContext(PopoverContext) + return ( +
setOpen(!open)}> + {render} +
+ ) + } + + const PopoverContent = ({ + children, + ...props + }: React.HTMLAttributes & { children?: React.ReactNode }) => { + const { open } = React.useContext(PopoverContext) + if (!open) + return null + + return
{children}
+ } + + return { + Popover, + PopoverTrigger, + PopoverContent, + } +}) + // Mock useTags hook with controlled test data const mockTags = [ { name: 'agent', label: 'Agent' }, diff --git a/web/app/components/tools/labels/selector.tsx b/web/app/components/tools/labels/selector.tsx index 830b4d7aaf..67539715a7 100644 --- a/web/app/components/tools/labels/selector.tsx +++ b/web/app/components/tools/labels/selector.tsx @@ -1,6 +1,11 @@ import type { FC } from 'react' import type { Label } from '@/app/components/tools/labels/constant' import { cn } from '@langgenius/dify-ui/cn' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import { RiArrowDownSLine } from '@remixicon/react' import { useDebounceFn } from 'ahooks' import { noop } from 'es-toolkit/function' @@ -9,17 +14,13 @@ import { useTranslation } from 'react-i18next' import Checkbox from '@/app/components/base/checkbox' import { Tag03 } from '@/app/components/base/icons/src/vender/line/financeAndECommerce' import Input from '@/app/components/base/input' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' import { useTags } from '@/app/components/plugins/hooks' type LabelSelectorProps = { value: string[] onChange: (v: string[]) => void } + const LabelSelector: FC = ({ value, onChange, @@ -34,6 +35,7 @@ const LabelSelector: FC = ({ const { run: handleSearch } = useDebounceFn(() => { setSearchKeywords(keywords) }, { wait: 500 }) + const handleKeywordsChange = (value: string) => { setKeywords(value) handleSearch() @@ -55,32 +57,31 @@ const LabelSelector: FC = ({ } return ( - +
- setOpen(v => !v)} - className="block" - > -
+
0 ? selectedLabels : ''} className={cn('grow truncate text-[13px] leading-[18px] text-text-secondary', !value.length && 'text-text-quaternary!')}> + {!value.length && t('createTool.toolInput.labelPlaceholder', { ns: 'tools' })} + {!!value.length && selectedLabels} +
+
+ +
+
)} - > -
0 ? selectedLabels : ''} className={cn('grow truncate text-[13px] leading-[18px] text-text-secondary', !value.length && 'text-text-quaternary!')}> - {!value.length && t('createTool.toolInput.labelPlaceholder', { ns: 'tools' })} - {!!value.length && selectedLabels} -
-
- -
-
- - + /> +
= ({ )}
-
+
-
+ ) } diff --git a/web/app/components/workflow/__tests__/custom-edge.spec.tsx b/web/app/components/workflow/__tests__/custom-edge.spec.tsx index f8ff9a1a0e..5c98402d9e 100644 --- a/web/app/components/workflow/__tests__/custom-edge.spec.tsx +++ b/web/app/components/workflow/__tests__/custom-edge.spec.tsx @@ -231,5 +231,9 @@ describe('CustomEdge', () => { expect(screen.getByTestId('base-edge')).toHaveAttribute('data-stroke', 'var(--color-workflow-link-line-normal)') expect(screen.getByTestId('block-selector')).toHaveAttribute('data-trigger-class', 'hover:scale-150 transition-all') + expect(screen.getByTestId('block-selector').parentElement).toHaveStyle({ + opacity: '0', + pointerEvents: 'none', + }) }) }) diff --git a/web/app/components/workflow/block-selector/__tests__/tool-picker.spec.tsx b/web/app/components/workflow/block-selector/__tests__/tool-picker.spec.tsx index 9c55d174fd..1ec4ed241f 100644 --- a/web/app/components/workflow/block-selector/__tests__/tool-picker.spec.tsx +++ b/web/app/components/workflow/block-selector/__tests__/tool-picker.spec.tsx @@ -455,12 +455,12 @@ describe('ToolPicker', () => { it('should create a custom collection from the add button and refresh custom tools', async () => { const user = userEvent.setup() - const { container } = renderToolPicker({ + renderToolPicker({ isShow: true, supportAddCustomTool: true, }) - const addCustomToolButton = Array.from(container.querySelectorAll('button')).find((button) => { + const addCustomToolButton = Array.from(document.querySelectorAll('button')).find((button) => { return button.className.includes('bg-components-button-primary-bg') }) diff --git a/web/app/components/workflow/block-selector/tool-picker.tsx b/web/app/components/workflow/block-selector/tool-picker.tsx index e7e948a54d..0ee25a9ce6 100644 --- a/web/app/components/workflow/block-selector/tool-picker.tsx +++ b/web/app/components/workflow/block-selector/tool-picker.tsx @@ -8,17 +8,17 @@ import type { ToolDefaultValue, ToolValue } from './types' import type { CustomCollectionBackend } from '@/app/components/tools/types' import type { BlockEnum, OnSelectBlock } from '@/app/components/workflow/types' import { cn } from '@langgenius/dify-ui/cn' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import { toast } from '@langgenius/dify-ui/toast' import { useSuspenseQuery } from '@tanstack/react-query' import { useBoolean } from 'ahooks' import * as React from 'react' -import { useMemo, useState } from 'react' +import { useCallback, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' import SearchBox from '@/app/components/plugins/marketplace/search-box' import EditCustomToolModal from '@/app/components/tools/edit-custom-collection-modal' import AllTools from '@/app/components/workflow/block-selector/all-tools' @@ -43,7 +43,7 @@ type Props = { disabled: boolean trigger: React.ReactNode placement?: Placement - offset?: OffsetOptions + offset?: OffsetOptions | number isShow: boolean onShowChange: (isShow: boolean) => void onSelect: (tool: ToolDefaultValue) => void @@ -120,12 +120,6 @@ const ToolPicker: FC = ({ const handleAddedCustomTool = invalidateCustomTools - const handleTriggerClick = () => { - if (disabled) - return - onShowChange(true) - } - const handleSelect = (_type: BlockEnum, tool?: ToolDefaultValue) => { onSelect(tool!) } @@ -139,6 +133,11 @@ const ToolPicker: FC = ({ setTrue: showEditCustomCollectionModal, }] = useBoolean(false) + const handleShowAddCustomCollectionModal = useCallback(() => { + onShowChange(false) + showEditCustomCollectionModal() + }, [onShowChange, showEditCustomCollectionModal]) + const doCreateCustomToolCollection = async (data: CustomCollectionBackend) => { await createCustomCollection(data) toast.success(t('api.actionSuccess', { ns: 'common' })) @@ -157,20 +156,35 @@ const ToolPicker: FC = ({ ) } - return ( - - - {trigger} - + const resolvedTrigger = React.isValidElement(trigger) ? trigger :
{trigger}
+ const resolvedOffset = typeof offset === 'object' && offset !== null + ? offset as { mainAxis?: number, crossAxis?: number, alignmentAxis?: number | null } + : undefined + const sideOffset = typeof offset === 'number' ? offset : resolvedOffset?.mainAxis ?? 0 + const alignOffset = typeof offset === 'number' ? 0 : resolvedOffset?.crossAxis ?? resolvedOffset?.alignmentAxis ?? 0 - + return ( + { + if (disabled && nextOpen) + return + onShowChange(nextOpen) + }} + > + { + if (disabled) + e.preventDefault() + }} + /> +
= ({ placeholder={t('searchTools', { ns: 'plugin' })!} supportAddCustomTool={supportAddCustomTool} onAddedCustomTool={handleAddedCustomTool} - onShowAddCustomCollectionModal={showEditCustomCollectionModal} + onShowAddCustomCollectionModal={handleShowAddCustomCollectionModal} inputClassName="grow" />
@@ -209,8 +223,8 @@ const ToolPicker: FC = ({ }} />
-
-
+ + ) } diff --git a/web/app/components/workflow/custom-edge.tsx b/web/app/components/workflow/custom-edge.tsx index af0fb19e6b..d8c3b59a4a 100644 --- a/web/app/components/workflow/custom-edge.tsx +++ b/web/app/components/workflow/custom-edge.tsx @@ -63,6 +63,7 @@ const CustomEdge = ({ _sourceRunningStatus, _targetRunningStatus, } = data + const isTriggerVisible = !!(data?._hovering || isTriggerHovered || open) const linearGradientId = useMemo(() => { if ( @@ -144,16 +145,15 @@ const CustomEdge = ({
setIsTriggerHovered(true)} onMouseLeave={() => setIsTriggerHovered(false)} diff --git a/web/app/components/workflow/nodes/_base/components/__tests__/agent-strategy-selector.spec.tsx b/web/app/components/workflow/nodes/_base/components/__tests__/agent-strategy-selector.spec.tsx new file mode 100644 index 0000000000..995d3c8a70 --- /dev/null +++ b/web/app/components/workflow/nodes/_base/components/__tests__/agent-strategy-selector.spec.tsx @@ -0,0 +1,446 @@ +import type { ReactNode } from 'react' +import type { StrategyPluginDetail } from '@/app/components/plugins/types' +import { render, screen, waitFor } from '@testing-library/react' +import userEvent from '@testing-library/user-event' +import { beforeEach, describe, expect, it, vi } from 'vitest' +import { PluginCategoryEnum } from '@/app/components/plugins/types' +import { AgentStrategySelector } from '../agent-strategy-selector' + +const mocks = vi.hoisted(() => ({ + useSuspenseQuery: vi.fn(), + useStrategyProviders: vi.fn(), + useMarketplacePlugins: vi.fn(), + useStrategyInfo: vi.fn(), + refetchStrategyInfo: vi.fn(), + queryPluginsWithDebounced: vi.fn(), +})) + +vi.mock('@tanstack/react-query', () => ({ + useSuspenseQuery: mocks.useSuspenseQuery, +})) + +vi.mock('@/service/system-features', () => ({ + systemFeaturesQueryOptions: () => ({}), +})) + +vi.mock('@/service/use-strategy', () => ({ + useStrategyProviders: mocks.useStrategyProviders, +})) + +vi.mock('@/app/components/plugins/marketplace/hooks', () => ({ + useMarketplacePlugins: mocks.useMarketplacePlugins, +})) + +vi.mock('@/app/components/workflow/nodes/agent/use-config', () => ({ + useStrategyInfo: mocks.useStrategyInfo, +})) + +vi.mock('@/app/components/plugins/install-plugin/base/use-get-icon', () => ({ + default: () => ({ + getIconUrl: (icon: string) => `https://example.com/${icon}`, + }), +})) + +vi.mock('@/app/components/base/search-input', () => ({ + default: ({ + value, + onChange, + placeholder, + }: { + value: string + onChange: (value: string) => void + placeholder?: string + className?: string + }) => ( + onChange(e.target.value)} + /> + ), +})) + +vi.mock('@/app/components/workflow/block-selector/view-type-select', () => ({ + default: ({ + onChange, + }: { + viewType: string + onChange: (value: string) => void + }) => ( + + ), + ViewType: { + flat: 'flat', + grid: 'grid', + }, +})) + +vi.mock('@/app/components/workflow/block-selector/tools', () => ({ + default: ({ + tools, + onSelect, + }: { + tools: Array<{ + id: string + name: string + meta?: unknown + tools: Array<{ + name: string + label: string | { en_US?: string } + output_schema?: Record + }> + }> + onSelect: (value: unknown, tool: { + tool_name: string + provider_name: string + tool_label: string + output_schema?: Record + provider_id: string + meta?: unknown + }) => void + }) => ( +
+ {tools.map(tool => ( +
+ {tool.name} + +
+ ))} +
+ ), +})) + +vi.mock('@/app/components/workflow/block-selector/market-place-plugin/list', () => ({ + default: ({ + list, + searchText, + }: { + list: Array<{ plugin_id: string }> + searchText: string + }) => ( +
+ {`${searchText}:${list.map(item => item.plugin_id).join(',')}`} +
+ ), +})) + +vi.mock('@/app/components/workflow/nodes/_base/components/install-plugin-button', () => ({ + InstallPluginButton: ({ + onClick, + }: { + onClick?: (event: { stopPropagation: () => void }) => void + uniqueIdentifier: string + size: string + }) => ( + + ), +})) + +vi.mock('@/app/components/workflow/nodes/_base/components/switch-plugin-version', () => ({ + SwitchPluginVersion: ({ + onChange, + }: { + onChange: () => void + uniqueIdentifier: string + tooltip: ReactNode + }) => ( + + ), +})) + +vi.mock('@/next/link', () => ({ + default: ({ + href, + children, + className, + }: { + href: string + children: ReactNode + className?: string + }) => {children}, +})) + +vi.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: (key: string) => key, + }), +})) + +vi.mock('@langgenius/dify-ui/popover', async () => { + const React = await import('react') + const PopoverContext = React.createContext({ + open: false, + setOpen: (_open: boolean) => {}, + }) + + const Popover = ({ + children, + open: controlledOpen, + onOpenChange, + }: { + children: React.ReactNode + open?: boolean + onOpenChange?: (open: boolean) => void + }) => { + const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false) + const isControlled = controlledOpen !== undefined + const open = isControlled ? !!controlledOpen : uncontrolledOpen + const setOpen = (nextOpen: boolean) => { + if (!isControlled) + setUncontrolledOpen(nextOpen) + onOpenChange?.(nextOpen) + } + + return ( + + {children} + + ) + } + + const PopoverTrigger = ({ render }: { render: React.ReactNode }) => { + const { open, setOpen } = React.useContext(PopoverContext) + return ( +
setOpen(!open)}> + {render} +
+ ) + } + + const PopoverContent = ({ children }: { children: React.ReactNode }) => { + const { open } = React.useContext(PopoverContext) + return open ?
{children}
: null + } + + return { + Popover, + PopoverTrigger, + PopoverContent, + } +}) + +vi.mock('@langgenius/dify-ui/tooltip', () => ({ + Tooltip: ({ children }: { children: ReactNode }) =>
{children}
, + TooltipTrigger: ({ render }: { render: ReactNode }) =>
{render}
, + TooltipContent: ({ children }: { children: ReactNode }) =>
{children}
, +})) + +const createStrategyDetail = ( + name: string, + strategyName: string, + strategyLabel: string, +): StrategyPluginDetail => ({ + plugin_unique_identifier: `provider/${name}`, + plugin_id: `plugin-${name}`, + declaration: { + identity: { + author: 'Dify', + name, + description: { en_US: `${name} description` }, + icon: `${name}.png`, + label: { en_US: `${name} label` }, + tags: [], + }, + strategies: [{ + identity: { + name: strategyName, + author: 'Dify', + label: { en_US: strategyLabel }, + }, + description: { en_US: `${strategyLabel} description` }, + parameters: [], + output_schema: { result: { type: 'string' } }, + }], + }, + meta: { version: '1.0.0' }, +} as unknown as StrategyPluginDetail) + +describe('AgentStrategySelector', () => { + const alphaDetail = createStrategyDetail('alpha', 'alpha-strategy', 'Alpha Strategy') + const betaDetail = createStrategyDetail('beta', 'beta-strategy', 'Beta Strategy') + + beforeEach(() => { + vi.clearAllMocks() + + mocks.useSuspenseQuery.mockReturnValue({ data: true }) + mocks.useStrategyProviders.mockReturnValue({ data: [alphaDetail, betaDetail] }) + mocks.useMarketplacePlugins.mockReturnValue({ + queryPluginsWithDebounced: mocks.queryPluginsWithDebounced, + plugins: [{ plugin_id: 'market-agent' }], + }) + mocks.useStrategyInfo.mockReturnValue({ + strategyStatus: undefined, + refetch: mocks.refetchStrategyInfo, + }) + }) + + it('filters strategies and queries marketplace when searching', async () => { + const user = userEvent.setup() + + render( + , + ) + + await user.click(screen.getByTestId('agent-strategy-trigger')) + + expect(screen.getByText('alpha')).toBeInTheDocument() + expect(screen.getByText('beta')).toBeInTheDocument() + expect(screen.getByTestId('plugin-list')).toHaveTextContent(':market-agent') + + await user.type( + screen.getByRole('textbox', { name: 'nodes.agent.strategy.searchPlaceholder' }), + 'alp', + ) + + await waitFor(() => { + expect(mocks.queryPluginsWithDebounced).toHaveBeenLastCalledWith({ + query: 'alp', + category: PluginCategoryEnum.agent, + }) + }) + + expect(screen.getByText('alpha')).toBeInTheDocument() + expect(screen.queryByText('beta')).not.toBeInTheDocument() + }) + + it('maps the selected tool and closes the popover', async () => { + const user = userEvent.setup() + const onChange = vi.fn() + + render( + , + ) + + await user.click(screen.getByTestId('agent-strategy-trigger')) + await user.click(screen.getByRole('button', { name: 'select-alpha' })) + + expect(onChange).toHaveBeenCalledWith({ + agent_strategy_name: 'alpha-strategy', + agent_strategy_provider_name: 'provider/alpha', + agent_strategy_label: 'Alpha Strategy', + agent_output_schema: { result: { type: 'string' } }, + plugin_unique_identifier: 'provider/alpha', + meta: { version: '1.0.0' }, + }) + expect(screen.queryByTestId('agent-strategy-popover')).not.toBeInTheDocument() + }) + + it('renders the plugin-not-installed warning for external strategies', () => { + mocks.useStrategyInfo.mockReturnValue({ + strategyStatus: { + plugin: { + source: 'external', + installed: false, + }, + isExistInPlugin: true, + }, + refetch: mocks.refetchStrategyInfo, + }) + + render( + , + ) + + expect(screen.getByText('nodes.agent.pluginNotInstalled')).toBeInTheDocument() + expect(screen.getByText('nodes.agent.pluginNotInstalledDesc')).toBeInTheDocument() + }) + + it('renders install and switch-version actions for marketplace strategies', async () => { + const user = userEvent.setup() + + mocks.useStrategyInfo.mockReturnValueOnce({ + strategyStatus: { + plugin: { + source: 'marketplace', + installed: false, + }, + isExistInPlugin: false, + }, + refetch: mocks.refetchStrategyInfo, + }) + + const { rerender } = render( + , + ) + + expect(screen.getByTestId('install-plugin-button')).toBeInTheDocument() + + mocks.useStrategyInfo.mockReturnValue({ + strategyStatus: { + plugin: { + source: 'marketplace', + installed: true, + }, + isExistInPlugin: false, + }, + refetch: mocks.refetchStrategyInfo, + }) + + rerender( + , + ) + + await user.click(screen.getByTestId('switch-plugin-version')) + + expect(mocks.refetchStrategyInfo).toHaveBeenCalled() + }) +}) diff --git a/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx b/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx index 8e7c1609d1..765c8ea76a 100644 --- a/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx +++ b/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx @@ -4,14 +4,21 @@ import type { Strategy } from './agent-strategy' import type { StrategyPluginDetail } from '@/app/components/plugins/types' import type { ListProps, ListRef } from '@/app/components/workflow/block-selector/market-place-plugin/list' import { cn } from '@langgenius/dify-ui/cn' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from '@langgenius/dify-ui/tooltip' import { RiArrowDownSLine, RiErrorWarningFill } from '@remixicon/react' import { useSuspenseQuery } from '@tanstack/react-query' import { memo, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem' import SearchInput from '@/app/components/base/search-input' -import Tooltip from '@/app/components/base/tooltip' -import { ToolTipContent } from '@/app/components/base/tooltip/content' import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon' import { useMarketplacePlugins } from '@/app/components/plugins/marketplace/hooks' import { PluginCategoryEnum } from '@/app/components/plugins/types' @@ -36,8 +43,11 @@ const NotFoundWarn = (props: { const { t } = useTranslation() return ( - +
} + /> +

{title} @@ -51,11 +61,7 @@ const NotFoundWarn = (props: {

- )} - > -
- -
+
) } @@ -66,18 +72,18 @@ function formatStrategy(input: StrategyPluginDetail[], getIcon: (i: string) => s id: item.plugin_unique_identifier, author: item.declaration.identity.author, name: item.declaration.identity.name, - description: item.declaration.identity.description as any, + description: item.declaration.identity.description as ToolWithProvider['description'], plugin_id: item.plugin_id, icon: getIcon(item.declaration.identity.icon), - label: item.declaration.identity.label as any, + label: item.declaration.identity.label as ToolWithProvider['label'], type: CollectionType.all, meta: item.meta, tools: item.declaration.strategies.map(strategy => ({ name: strategy.identity.name, author: strategy.identity.author, - label: strategy.identity.label as any, + label: strategy.identity.label as ToolWithProvider['tools'][number]['label'], description: strategy.description, - parameters: strategy.parameters as any, + parameters: strategy.parameters as unknown as ToolWithProvider['tools'][number]['parameters'], output_schema: strategy.output_schema, labels: [], })), @@ -151,76 +157,82 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) => category: PluginCategoryEnum.agent, }) } - }, [query]) + }, [enable_marketplace, fetchPlugins, query]) const pluginRef = useRef(null) return ( - - -
setOpen(o => !o)} - > - { } - {icon && ( -
- icon -
- )} -

- {value?.agent_strategy_label || t('nodes.agent.strategy.selectTip', { ns: 'workflow' })} -

-
- {showInstallButton && value && ( - e.stopPropagation()} - size="small" - uniqueIdentifier={value.plugin_unique_identifier} - /> + + + {icon && ( +
+ icon +
)} - {showPluginNotInstalledWarn - ? ( - - ) - : showUnsupportedStrategy +

+ {value?.agent_strategy_label || t('nodes.agent.strategy.selectTip', { ns: 'workflow' })} +

+
+ {showInstallButton && value && ( + e.stopPropagation()} + size="small" + uniqueIdentifier={value.plugin_unique_identifier} + /> + )} + {showPluginNotInstalledWarn ? ( ) - : } - {showSwitchVersion && ( - - {t('nodes.agent.strategyNotFoundDescAndSwitchVersion', { ns: 'workflow' })} - - )} - onChange={() => { - refetchStrategyInfo() - }} - /> - )} + : showUnsupportedStrategy + ? ( + + ) + : } + {showSwitchVersion && value && ( + +

+ {t('nodes.agent.unsupportedStrategy', { ns: 'workflow' })} +

+

+ {t('nodes.agent.strategyNotFoundDescAndSwitchVersion', { ns: 'workflow' })} +

+
+ )} + onChange={() => { + refetchStrategyInfo() + }} + /> + )} +
-
- - + )} + /> +
@@ -260,8 +272,8 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) => )}
-
-
+ + ) }) diff --git a/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-picker.trigger.spec.tsx b/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-picker.trigger.spec.tsx index c401377450..a01d2a0387 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-picker.trigger.spec.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-picker.trigger.spec.tsx @@ -1,4 +1,8 @@ import type { ComponentProps } from 'react' +import { + Popover, + PopoverContent, +} from '@langgenius/dify-ui/popover' import { fireEvent, render, screen } from '@testing-library/react' import { BlockEnum, VarType } from '@/app/components/workflow/types' import { VarType as VarKindType } from '../../../../tool/types' @@ -38,46 +42,53 @@ const createProps = ( ], varName: '', variableCategory: 'system', - WrapElem: 'div', - VarPickerWrap: 'div', ...overrides, }) +const renderWithPopover = ( + overrides: Partial> = {}, +) => { + const onOpenChange = vi.fn() + + render( + + + +
picker-content
+
+
, + ) + + return { onOpenChange } +} + describe('VarReferencePickerTrigger', () => { it('should show the placeholder state and open the picker for variable mode', () => { - const setOpen = vi.fn() - render( - , - ) + const { onOpenChange } = renderWithPopover({ + placeholder: 'Pick variable', + }) expect(screen.getByText('Pick variable'))!.toBeInTheDocument() fireEvent.click(screen.getByTestId('var-reference-picker-trigger')) - expect(setOpen).toHaveBeenCalledWith(true) + expect(onOpenChange).toHaveBeenCalledWith(true, expect.anything()) }) it('should render the selected variable state and clear it', () => { const handleClearVar = vi.fn() const handleVariableJump = vi.fn() - render( - , - ) + renderWithPopover({ + handleClearVar, + handleVariableJump, + hasValue: true, + outputVarNode: { title: 'Source Node', desc: '', type: BlockEnum.Code }, + outputVarNodeId: 'node-a', + type: VarType.string, + value: ['node-a', 'answer'], + varName: 'answer', + }) expect(screen.getByText('Source Node'))!.toBeInTheDocument() expect(screen.getByText('answer'))!.toBeInTheDocument() @@ -93,20 +104,16 @@ describe('VarReferencePickerTrigger', () => { const setControlFocus = vi.fn() const setOpen = vi.fn() - render( - , - ) + renderWithPopover({ + isConstant: true, + isSupportConstantValue: true, + schemaWithDynamicSelect: { + type: 'text-input', + } as never, + setOpen, + setControlFocus, + value: 'constant-value', + }) fireEvent.click(screen.getByTestId('var-reference-picker-trigger')) expect(setControlFocus).toHaveBeenCalledTimes(1) @@ -116,38 +123,27 @@ describe('VarReferencePickerTrigger', () => { }) it('should render add button trigger in table mode', () => { - render( - , - ) + renderWithPopover({ + hasValue: true, + isAddBtnTrigger: true, + isInTable: true, + value: ['node-a', 'answer'], + varName: 'answer', + }) - expect(document.querySelector('button'))!.toBeInTheDocument() + expect(screen.getByTestId('add-button'))!.toBeInTheDocument() }) it('should stay inert in readonly mode and show value type placeholder badge', () => { - const setOpen = vi.fn() - - render( - , - ) + const { onOpenChange } = renderWithPopover({ + placeholder: 'Readonly placeholder', + readonly: true, + typePlaceHolder: 'string', + valueTypePlaceHolder: 'text', + }) fireEvent.click(screen.getByTestId('var-reference-picker-trigger')) - expect(setOpen).not.toHaveBeenCalled() + expect(onOpenChange).not.toHaveBeenCalled() expect(screen.getByText('string'))!.toBeInTheDocument() expect(screen.getByText('text'))!.toBeInTheDocument() }) @@ -155,17 +151,13 @@ describe('VarReferencePickerTrigger', () => { it('should show loading placeholder and remove rows in table mode', () => { const onRemove = vi.fn() - render( - , - ) + renderWithPopover({ + hasValue: false, + isInTable: true, + isLoading: true, + onRemove, + placeholder: 'Loading variable', + }) expect(screen.getByText('Loading variable'))!.toBeInTheDocument() diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.trigger.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.trigger.tsx index 5a0362a07e..7f77f37987 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.trigger.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.trigger.tsx @@ -7,6 +7,7 @@ import type { Tool } from '@/app/components/tools/types' import type { TriggerWithProvider } from '@/app/components/workflow/block-selector/types' import type { Node, ToolWithProvider, ValueSelector, Var } from '@/app/components/workflow/types' import { cn } from '@langgenius/dify-ui/cn' +import { PopoverTrigger } from '@langgenius/dify-ui/popover' import { PreviewCard, PreviewCardContent, PreviewCardTrigger } from '@langgenius/dify-ui/preview-card' import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip' import { RiArrowDownSLine, RiCloseLine, RiErrorWarningFill, RiLoader4Line, RiMoreLine } from '@remixicon/react' @@ -68,8 +69,6 @@ type Props = { varKindTypes: Array<{ label: string, value: VarKindType }> varName: string variableCategory: string - WrapElem: React.ElementType - VarPickerWrap: React.ElementType } const VarReferencePickerTrigger: FC = ({ @@ -114,9 +113,14 @@ const VarReferencePickerTrigger: FC = ({ varKindTypes, varName, variableCategory, - VarPickerWrap, - WrapElem, }) => { + const handleTriggerReadonlyClick = (e: React.MouseEvent) => { + if (!readonly) + return + e.preventDefault() + e.stopPropagation() + } + const pill = (
{hasValue @@ -212,18 +216,36 @@ const VarReferencePickerTrigger: FC = ({ ) : pill - return ( - { - if (readonly) - return - if (!isConstant) - setOpen(!open) - else - setControlFocus(Date.now()) - }} + const variablePicker = ( +
+
+ {hoveredPill} +
+
+ ) + + const resolvedVariablePicker = isSupportConstantValue + ? ( + readonly + ? variablePicker + : ( + + ) + ) + : variablePicker + + const triggerContent = ( +
{ + if (!isConstant || readonly) + return + setControlFocus(Date.now()) + }} > <> {isAddBtnTrigger @@ -278,24 +300,7 @@ const VarReferencePickerTrigger: FC = ({ isLoading={isLoading} /> ) - : ( - { - if (readonly) - return - if (!isConstant) - setOpen(!open) - else - setControlFocus(Date.now()) - }} - className="h-full grow" - > -
- {hoveredPill} -
- -
- )} + : resolvedVariablePicker} {(hasValue && !readonly && !isInTable && !isJustShowValue) && (
= ({ )} - +
) + + if (!isSupportConstantValue) { + if (readonly) + return triggerContent + + return ( + + ) + } + + return triggerContent } export default VarReferencePickerTrigger diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx index 9b985c8a9e..7e99988ae8 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx @@ -6,6 +6,11 @@ import type { Tool } from '@/app/components/tools/types' import type { TriggerWithProvider } from '@/app/components/workflow/block-selector/types' import type { CommonNodeType, Node, NodeOutPutVar, ToolWithProvider, ValueSelector, Var } from '@/app/components/workflow/types' import { cn } from '@langgenius/dify-ui/cn' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import { noop } from 'es-toolkit/function' import { produce } from 'immer' import * as React from 'react' @@ -16,11 +21,6 @@ import { useReactFlow, useStoreApi, } from 'reactflow' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' import { useIsChatMode, @@ -141,10 +141,10 @@ const VarReferencePicker: FC = ({ }) const node = nodes.find(n => n.id === nodeId) - const isInIteration = !!(node?.data as any)?.isInIteration + const isInIteration = !!node?.data.isInIteration const iterationNode = isInIteration ? (nodes.find(n => n.id === node?.parentId) ?? null) : null - const isInLoop = !!(node?.data as any)?.isInLoop + const isInLoop = !!node?.data.isInLoop const loopNode = isInLoop ? (nodes.find(n => n.id === node?.parentId) ?? null) : null const triggerRef = useRef(null) @@ -210,13 +210,11 @@ const VarReferencePicker: FC = ({ }, [onChange]) const inputRef = useRef(null) - const [isFocus, setIsFocus] = useState(false) const [controlFocus, setControlFocus] = useState(0) + const isFocus = controlFocus > 0 useEffect(() => { - if (controlFocus && inputRef.current) { + if (controlFocus && inputRef.current) inputRef.current.focus() - setIsFocus(true) - } }, [controlFocus]) const handleVarReferenceChange = useCallback((value: ValueSelector, varInfo: Var) => { @@ -264,7 +262,7 @@ const VarReferencePicker: FC = ({ }, [availableNodes, reactflow, store]) const type = getCurrentVariableType({ - parentNode: (isInIteration ? iterationNode : loopNode) as any, + parentNode: isInIteration ? iterationNode : loopNode, valueSelector: value as ValueSelector, availableNodes, isChatMode, @@ -289,9 +287,6 @@ const VarReferencePicker: FC = ({ maxVarNameWidth, } = getWidthAllocations(triggerWidth, outputVarNode?.title || '', varName || '', type || '') - const WrapElem = isSupportConstantValue ? 'div' : PortalToFollowElemTrigger - const VarPickerWrap = !isSupportConstantValue ? 'div' : PortalToFollowElemTrigger - const hoverPopup = useMemo(() => { const tooltipType = getTooltipContent(hasValue, isShowAPart, isValidVar) if (tooltipType === 'full-path') { @@ -349,15 +344,23 @@ const VarReferencePicker: FC = ({ ) const triggerPlaceholder = placeholder ?? t('common.setVarValuePlaceholder', { ns: 'workflow' }) + const resolvedTrigger = React.isValidElement(trigger) ? trigger :
{trigger}
return (
- - {!!trigger && setOpen(!open)}>{trigger}} + {!!trigger && ( + { + if (readonly) + e.preventDefault() + }} + /> + )} {!trigger && ( = ({ varKindTypes={varKindTypes} varName={varName} variableCategory={variableCategory} - VarPickerWrap={VarPickerWrap} - WrapElem={WrapElem} /> )} - {!isConstant && ( = ({ preferSchemaType={preferSchemaType} /> )} - - + +
) } diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx index 648e795dcc..28ad104ed7 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx @@ -4,6 +4,11 @@ import type { StructuredOutput } from '../../../llm/types' import type { Field } from '@/app/components/workflow/nodes/llm/types' import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types' import { cn } from '@langgenius/dify-ui/cn' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import { useHover } from 'ahooks' import { noop } from 'es-toolkit/function' import * as React from 'react' @@ -13,11 +18,6 @@ import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows import { CodeAssistant, MagicEdit } from '@/app/components/base/icons/src/vender/line/general' import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' import Input from '@/app/components/base/input' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' import PickerStructurePanel from '@/app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/picker' import { VariableIconWithColor } from '@/app/components/workflow/nodes/_base/components/variable/variable-label' import { VarType } from '@/app/components/workflow/types' @@ -143,7 +143,7 @@ const Item: FC = ({ const open = (isObj || isStructureOutput) && isHovering useEffect(() => { onHovering?.(isHovering) - }, [isHovering]) + }, [isHovering, onHovering]) const handleChosen = (e: React.MouseEvent) => { e.stopPropagation() e.nativeEvent.stopImmediatePropagation() @@ -167,62 +167,70 @@ const Item: FC = ({ () => getVariableCategory({ isEnv, isChatVar, isLoopVar, isRagVariable }), [isEnv, isChatVar, isLoopVar, isRagVariable], ) + + const itemTrigger = ( +
{ + e.preventDefault() + e.stopPropagation() + e.nativeEvent.stopImmediatePropagation() + }} + > +
+ {!isFlat && ( + + )} + {isFlat && flatVarIcon} + + {!isEnv && !isChatVar && !isRagVariable && ( +
{varName}
+ )} + {isEnv && ( +
{itemData.variable.replace('env.', '')}
+ )} + {isChatVar && ( +
{itemData.variable.replace('conversation.', '')}
+ )} + {isRagVariable && ( +
{itemData.variable.split('.').slice(-1)[0]}
+ )} +
+
{(preferSchemaType && itemData.schemaType) ? itemData.schemaType : itemData.type}
+ { + (isObj || isStructureOutput) && ( + + ) + } +
+ ) + return ( - - -
{ - e.preventDefault() - e.stopPropagation() - e.nativeEvent.stopImmediatePropagation() - }} - > -
- {!isFlat && ( - - )} - {isFlat && flatVarIcon} - - {!isEnv && !isChatVar && !isRagVariable && ( -
{varName}
- )} - {isEnv && ( -
{itemData.variable.replace('env.', '')}
- )} - {isChatVar && ( -
{itemData.variable.replace('conversation.', '')}
- )} - {isRagVariable && ( -
{itemData.variable.split('.').slice(-1)[0]}
- )} -
-
{(preferSchemaType && itemData.schemaType) ? itemData.schemaType : itemData.type}
- { - (isObj || isStructureOutput) && ( - - ) - } -
-
- + {(isStructureOutput || isObj) && ( = ({ }} /> )} - -
+ + ) } diff --git a/web/app/components/workflow/nodes/code/dependency-picker.tsx b/web/app/components/workflow/nodes/code/dependency-picker.tsx index feed5234a7..dd9e97af6f 100644 --- a/web/app/components/workflow/nodes/code/dependency-picker.tsx +++ b/web/app/components/workflow/nodes/code/dependency-picker.tsx @@ -1,5 +1,10 @@ import type { FC } from 'react' import type { CodeDependency } from './types' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import { RiArrowDownSLine, } from '@remixicon/react' @@ -8,7 +13,6 @@ import * as React from 'react' import { useCallback, useState } from 'react' import { Check } from '@/app/components/base/icons/src/vender/line/general' import Input from '@/app/components/base/input' -import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem' type Props = { value: CodeDependency @@ -32,21 +36,22 @@ const DependencyPicker: FC = ({ }, [onChange]) return ( - - setOpen(!open)} className="grow cursor-pointer"> -
-
{value.name}
- -
-
- + +
+
{value.name}
+ +
+
+ )} + /> +
= ({ ))}
- - + + ) } diff --git a/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/__tests__/member-selector.spec.tsx b/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/__tests__/member-selector.spec.tsx index 823aa68047..e1d959bd86 100644 --- a/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/__tests__/member-selector.spec.tsx +++ b/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/__tests__/member-selector.spec.tsx @@ -2,6 +2,59 @@ import type { Member } from '@/models/common' import { fireEvent, render, screen } from '@testing-library/react' import MemberSelector from '../member-selector' +vi.mock('@langgenius/dify-ui/popover', async () => { + const React = await import('react') + const PopoverContext = React.createContext({ + open: false, + setOpen: (_open: boolean) => {}, + }) + + const Popover = ({ + children, + open: controlledOpen, + onOpenChange, + }: { + children: import('react').ReactNode + open?: boolean + onOpenChange?: (open: boolean) => void + }) => { + const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false) + const isControlled = controlledOpen !== undefined + const open = isControlled ? !!controlledOpen : uncontrolledOpen + const setOpen = (nextOpen: boolean) => { + if (!isControlled) + setUncontrolledOpen(nextOpen) + onOpenChange?.(nextOpen) + } + + return ( + + {children} + + ) + } + + const PopoverTrigger = ({ render }: { render: import('react').ReactNode }) => { + const { open, setOpen } = React.useContext(PopoverContext) + return ( +
setOpen(!open)}> + {render} +
+ ) + } + + const PopoverContent = ({ children }: { children: import('react').ReactNode }) => { + const { open } = React.useContext(PopoverContext) + return open ?
{children}
: null + } + + return { + Popover, + PopoverTrigger, + PopoverContent, + } +}) + const mockMemberList = vi.hoisted(() => vi.fn()) vi.mock('../member-list', () => ({ diff --git a/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/email-input.tsx b/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/email-input.tsx index 1f18ef076d..cb8de634a2 100644 --- a/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/email-input.tsx +++ b/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/email-input.tsx @@ -1,14 +1,13 @@ import type { Recipient as RecipientItem } from '../../../types' import type { Member } from '@/models/common' import { cn } from '@langgenius/dify-ui/cn' +import { + Popover, + PopoverContent, +} from '@langgenius/dify-ui/popover' import * as React from 'react' import { useCallback, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' import EmailItem from './email-item' import MemberList from './member-list' @@ -58,8 +57,7 @@ const EmailInput = ({ if (disabled) return setIsFocus(true) - const input = inputRef.current?.children[0] as HTMLInputElement - input?.focus() + inputRef.current?.focus() } const handleValueChange = (e: React.ChangeEvent) => { @@ -141,28 +139,29 @@ const EmailInput = ({ /> ))} {!disabled && ( - - - setIsFocus(true)} - onBlur={handleInputBlur} - value={searchKey} - onChange={handleValueChange} - onKeyDown={handleKeyDown} - /> - - + + setIsFocus(true)} + onBlur={handleInputBlur} + value={searchKey} + onChange={handleValueChange} + onKeyDown={handleKeyDown} + /> + - - + + )} diff --git a/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/member-selector.tsx b/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/member-selector.tsx index c2df6afb15..f091ec5a30 100644 --- a/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/member-selector.tsx +++ b/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/member-selector.tsx @@ -4,12 +4,16 @@ import type { Recipient } from '@/app/components/workflow/nodes/human-input/type import type { Member } from '@/models/common' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import { RiContactsBookLine, } from '@remixicon/react' -import { useState } from 'react' +import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' -import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem' import MemberList from './member-list' const i18nPrefix = 'nodes.humanInput' @@ -31,39 +35,42 @@ const MemberSelector: FC = ({ const [open, setOpen] = useState(false) const [searchValue, setSearchValue] = useState('') + const handleSelect = useCallback((memberId: string) => { + onSelect(memberId) + setOpen(false) + }, [onSelect]) + return ( - - setOpen(v => !v)} + + + +
{t(`${i18nPrefix}.deliveryMethod.emailConfigure.memberSelector.trigger`, { ns: 'workflow' })}
+ + )} + /> + - -
- - -
+ + ) } + export default MemberSelector diff --git a/web/app/components/workflow/nodes/if-else/components/condition-add.tsx b/web/app/components/workflow/nodes/if-else/components/condition-add.tsx index 85a45ac5c7..b8f5dab85b 100644 --- a/web/app/components/workflow/nodes/if-else/components/condition-add.tsx +++ b/web/app/components/workflow/nodes/if-else/components/condition-add.tsx @@ -5,17 +5,17 @@ import type { Var, } from '@/app/components/workflow/types' import { Button } from '@langgenius/dify-ui/button' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import { RiAddLine } from '@remixicon/react' import { useCallback, useState, } from 'react' import { useTranslation } from 'react-i18next' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars' type ConditionAddProps = { @@ -25,6 +25,7 @@ type ConditionAddProps = { onSelectVariable: HandleAddCondition disabled?: boolean } + const ConditionAdd = ({ className, caseId, @@ -38,29 +39,32 @@ const ConditionAdd = ({ const handleSelectVariable = useCallback((valueSelector: ValueSelector, varItem: Var) => { onSelectVariable(caseId, valueSelector, varItem) setOpen(false) - }, [caseId, onSelectVariable, setOpen]) + }, [caseId, onSelectVariable]) return ( - - setOpen(!open)}> - - - + + + + {t('nodes.ifElse.addCondition', { ns: 'workflow' })} + + )} + onClick={(e) => { + if (disabled) + e.preventDefault() + }} + /> +
-
-
+ + ) } diff --git a/web/app/components/workflow/nodes/if-else/components/condition-list/condition-var-selector.tsx b/web/app/components/workflow/nodes/if-else/components/condition-list/condition-var-selector.tsx index 2740471610..e94eca7b38 100644 --- a/web/app/components/workflow/nodes/if-else/components/condition-list/condition-var-selector.tsx +++ b/web/app/components/workflow/nodes/if-else/components/condition-list/condition-var-selector.tsx @@ -1,5 +1,9 @@ import type { Node, NodeOutPutVar, ValueSelector, Var, VarType } from '@/app/components/workflow/types' -import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import VariableTag from '@/app/components/workflow/nodes/_base/components/variable-tag' import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars' @@ -23,26 +27,25 @@ const ConditionVarSelector = ({ onChange, }: ConditionVarSelectorProps) => { return ( - - onOpenChange(!open)}> -
- -
-
- + + + + + )} + /> +
-
-
+ + ) } diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/add-condition.tsx b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/add-condition.tsx index ea7870431a..2787aafafd 100644 --- a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/add-condition.tsx +++ b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/add-condition.tsx @@ -2,8 +2,11 @@ import type { MetadataShape } from '@/app/components/workflow/nodes/knowledge-re import type { MetadataInDoc } from '@/models/datasets' import { Button } from '@langgenius/dify-ui/button' import { - RiAddLine, -} from '@remixicon/react' + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' +import { RiAddLine } from '@remixicon/react' import { useCallback, useMemo, @@ -11,11 +14,6 @@ import { } from 'react' import { useTranslation } from 'react-i18next' import Input from '@/app/components/base/input' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' import MetadataIcon from './metadata-icon' const AddCondition = ({ @@ -36,25 +34,24 @@ const AddCondition = ({ }, [handleAddCondition]) return ( - - setOpen(!open)}> - - - + + + + {t('nodes.knowledgeRetrieval.metadata.panel.add', { ns: 'workflow' })} + + )} + /> +
- { - filteredMetadataList?.map(metadata => ( -
-
- -
-
handleAddConditionWrapped(metadata)} - > - {metadata.name} -
-
{metadata.type}
+ {filteredMetadataList?.map(metadata => ( +
+
+
- )) - } +
handleAddConditionWrapped(metadata)} + > + {metadata.name} +
+
{metadata.type}
+
+ ))}
- - + + ) } diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-common-variable-selector.tsx b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-common-variable-selector.tsx index dd0858942d..d4aedbd8b9 100644 --- a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-common-variable-selector.tsx +++ b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-common-variable-selector.tsx @@ -1,12 +1,12 @@ import type { VarType } from '@/app/components/workflow/types' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' type ConditionCommonVariableSelectorProps = { variables?: { name: string, type: string, value: string }[] @@ -31,34 +31,17 @@ const ConditionCommonVariableSelector = ({ }, [onChange]) return ( - - { - if (!variables.length) - return - setOpen(!open) - }} - > -
- { - selected && ( + + + {selected && (
{selected.value}
- ) - } - { - !selected && ( + )} + {!selected && ( <>
@@ -68,27 +51,34 @@ const ConditionCommonVariableSelector = ({ {varType}
- ) - } -
-
- + )} +
+ )} + onClick={(e) => { + if (!variables.length) + e.preventDefault() + }} + /> +
- { - variables.map(v => ( -
handleChange(v.value)} - > - - {v.value} -
- )) - } + {variables.map(v => ( +
handleChange(v.value)} + > + + {v.value} +
+ ))}
-
-
+ + ) } diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-variable-selector.tsx b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-variable-selector.tsx index 15f5ec9377..7ef4ed7388 100644 --- a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-variable-selector.tsx +++ b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-variable-selector.tsx @@ -4,14 +4,14 @@ import type { ValueSelector, Var, } from '@/app/components/workflow/types' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' import VariableTag from '@/app/components/workflow/nodes/_base/components/variable-tag' import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars' import { VarType } from '@/app/components/workflow/types' @@ -34,35 +34,25 @@ const ConditionVariableSelector = ({ const { t } = useTranslation() const [open, setOpen] = useState(false) - const handleChange = useCallback((valueSelector: ValueSelector, varItem: Var) => { - onChange(valueSelector, varItem) + const handleChange = useCallback((nextValueSelector: ValueSelector, varItem: Var) => { + onChange(nextValueSelector, varItem) setOpen(false) }, [onChange]) return ( - - setOpen(!open)}> -
- { - !!valueSelector.length && ( + + + {!!valueSelector.length && ( - ) - } - { - !valueSelector.length && ( + )} + {!valueSelector.length && ( <>
@@ -72,11 +62,16 @@ const ConditionVariableSelector = ({ {varType}
- ) - } -
-
- + )} + + )} + /> +
-
-
+ + ) } diff --git a/web/app/components/workflow/nodes/loop/components/condition-add.tsx b/web/app/components/workflow/nodes/loop/components/condition-add.tsx index 36a09dd434..a28b066098 100644 --- a/web/app/components/workflow/nodes/loop/components/condition-add.tsx +++ b/web/app/components/workflow/nodes/loop/components/condition-add.tsx @@ -5,17 +5,17 @@ import type { Var, } from '@/app/components/workflow/types' import { Button } from '@langgenius/dify-ui/button' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import { RiAddLine } from '@remixicon/react' import { useCallback, useState, } from 'react' import { useTranslation } from 'react-i18next' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars' type ConditionAddProps = { @@ -24,6 +24,7 @@ type ConditionAddProps = { onSelectVariable: HandleAddCondition disabled?: boolean } + const ConditionAdd = ({ className, variables, @@ -36,29 +37,32 @@ const ConditionAdd = ({ const handleSelectVariable = useCallback((valueSelector: ValueSelector, varItem: Var) => { onSelectVariable(valueSelector, varItem) setOpen(false) - }, [onSelectVariable, setOpen]) + }, [onSelectVariable]) return ( - - setOpen(!open)}> - - - + + + + {t('nodes.ifElse.addCondition', { ns: 'workflow' })} + + )} + onClick={(e) => { + if (disabled) + e.preventDefault() + }} + /> +
-
-
+ + ) } diff --git a/web/app/components/workflow/nodes/loop/components/condition-list/condition-var-selector.tsx b/web/app/components/workflow/nodes/loop/components/condition-list/condition-var-selector.tsx index 7a7957ad71..496ed4087d 100644 --- a/web/app/components/workflow/nodes/loop/components/condition-list/condition-var-selector.tsx +++ b/web/app/components/workflow/nodes/loop/components/condition-list/condition-var-selector.tsx @@ -1,5 +1,9 @@ import type { Node, NodeOutPutVar, ValueSelector, Var, VarType } from '@/app/components/workflow/types' -import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import VariableTag from '@/app/components/workflow/nodes/_base/components/variable-tag' import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars' @@ -23,26 +27,25 @@ const ConditionVarSelector = ({ onChange, }: ConditionVarSelectorProps) => { return ( - - onOpenChange(!open)}> -
- -
-
- + + + + + )} + /> +
-
-
+ + ) } diff --git a/web/app/education-apply/__tests__/search-input.spec.tsx b/web/app/education-apply/__tests__/search-input.spec.tsx new file mode 100644 index 0000000000..bb3cd8cc84 --- /dev/null +++ b/web/app/education-apply/__tests__/search-input.spec.tsx @@ -0,0 +1,159 @@ +import type { ReactNode } from 'react' +import { fireEvent, render, screen } from '@testing-library/react' +import userEvent from '@testing-library/user-event' +import { useState } from 'react' +import { beforeEach, describe, expect, it, vi } from 'vitest' +import SearchInput from '../search-input' + +const educationMocks = vi.hoisted(() => ({ + schools: ['Alpha University', 'Beta College'], + setSchools: vi.fn(), + querySchoolsWithDebounced: vi.fn(), + handleUpdateSchools: vi.fn(), + hasNext: false, +})) + +vi.mock('../hooks', () => ({ + useEducation: () => educationMocks, +})) + +vi.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: (key: string) => key, + }), +})) + +vi.mock('@/app/components/base/input', () => ({ + default: ({ + value, + onChange, + placeholder, + className, + }: { + value?: string + onChange: (event: { target: { value: string } }) => void + placeholder?: string + className?: string + }) => ( + onChange({ target: { value: e.target.value } })} + /> + ), +})) + +vi.mock('@langgenius/dify-ui/popover', async () => { + const React = await import('react') + const PopoverContext = React.createContext({ + open: false, + setOpen: (_open: boolean) => {}, + }) + + const Popover = ({ + children, + open: controlledOpen, + onOpenChange, + }: { + children: ReactNode + open?: boolean + onOpenChange?: (open: boolean) => void + }) => { + const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false) + const isControlled = controlledOpen !== undefined + const open = isControlled ? !!controlledOpen : uncontrolledOpen + const setOpen = (nextOpen: boolean) => { + if (!isControlled) + setUncontrolledOpen(nextOpen) + onOpenChange?.(nextOpen) + } + + return ( + + {children} + + ) + } + + const PopoverTrigger = ({ render }: { render: ReactNode }) => <>{render} + + const PopoverContent = ({ children }: { children: ReactNode }) => { + const { open } = React.useContext(PopoverContext) + return open ?
{children}
: null + } + + return { + Popover, + PopoverTrigger, + PopoverContent, + } +}) + +const ControlledSearchInput = () => { + const [value, setValue] = useState('') + return +} + +describe('education-apply/search-input', () => { + beforeEach(() => { + vi.clearAllMocks() + educationMocks.schools = ['Alpha University', 'Beta College'] + educationMocks.hasNext = false + }) + + it('opens the popover, queries schools, and closes after selection', async () => { + const user = userEvent.setup() + + render() + + const input = screen.getByPlaceholderText('form.schoolName.placeholder') + await user.type(input, 'A') + + expect(educationMocks.setSchools).toHaveBeenCalledWith([]) + expect(educationMocks.querySchoolsWithDebounced).toHaveBeenLastCalledWith({ + keywords: 'A', + page: 0, + }) + + expect(screen.getByTestId('education-search-popover')).toBeInTheDocument() + expect(screen.getByText('Alpha University')).toBeInTheDocument() + + await user.click(screen.getByText('Beta College')) + + expect(screen.getByDisplayValue('Beta College')).toBeInTheDocument() + expect(screen.queryByTestId('education-search-popover')).not.toBeInTheDocument() + }) + + it('loads the next page when the dropdown is scrolled to the bottom', async () => { + const user = userEvent.setup() + educationMocks.hasNext = true + + render() + + await user.type(screen.getByPlaceholderText('form.schoolName.placeholder'), 'A') + + const scrollContainer = screen.getByText('Alpha University').parentElement as HTMLDivElement + Object.defineProperties(scrollContainer, { + scrollTop: { + value: 60, + configurable: true, + }, + scrollHeight: { + value: 100, + configurable: true, + }, + clientHeight: { + value: 40, + configurable: true, + }, + }) + + fireEvent.scroll(scrollContainer) + + expect(educationMocks.handleUpdateSchools).toHaveBeenCalledWith({ + keywords: 'A', + page: 1, + }) + }) +}) diff --git a/web/app/education-apply/search-input.tsx b/web/app/education-apply/search-input.tsx index 47eca921ee..4f930eb3eb 100644 --- a/web/app/education-apply/search-input.tsx +++ b/web/app/education-apply/search-input.tsx @@ -1,4 +1,9 @@ -import type { ChangeEventHandler } from 'react' +import type { ChangeEventHandler, UIEventHandler } from 'react' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@langgenius/dify-ui/popover' import { useCallback, useRef, @@ -6,17 +11,13 @@ import { } from 'react' import { useTranslation } from 'react-i18next' import Input from '@/app/components/base/input' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' import { useEducation } from './hooks' type SearchInputProps = { value?: string onChange: (value: string) => void } + const SearchInput = ({ value, onChange, @@ -48,7 +49,7 @@ const SearchInput = ({ keywords, page, }) - }, [querySchoolsWithDebounced, handleUpdateSchools]) + }, [handleUpdateSchools, querySchoolsWithDebounced]) const handleValueChange: ChangeEventHandler = useCallback((e) => { setOpen(true) @@ -58,10 +59,10 @@ const SearchInput = ({ valueRef.current = inputValue onChange(inputValue) handleSearch(true) - }, [onChange, handleSearch, setSchools]) + }, [handleSearch, onChange, setSchools]) - const handleScroll = useCallback((e: Event) => { - const target = e.target as HTMLDivElement + const handleScroll: UIEventHandler = useCallback((e) => { + const target = e.currentTarget const { scrollTop, scrollHeight, @@ -74,48 +75,45 @@ const SearchInput = ({ }, [handleSearch, hasNext]) return ( - - - - - - { - !!schools.length && value && ( -
- { - schools.map((school, index) => ( -
{ - onChange(school) - setOpen(false) - }} - > - {school} -
- )) - } -
- ) - } -
-
+ + + )} + /> + {!!schools.length && !!value && ( + +
+ {schools.map(school => ( +
{ + onChange(school) + setOpen(false) + }} + > + {school} +
+ ))} +
+
+ )} +
) }