Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .sync/log/7eab4bcb78f17b9eed365d617aa3ef3874c21bac.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Port: perf(types): import cross-component types from source, not the barrel (#6646)

**Upstream:** `7eab4bcb78f17b9eed365d617aa3ef3874c21bac` (nuxt/ui)
**Decision:** port

## Upstream change
A perf refactor: stop importing cross-component types from the `../types`
**barrel** (`src/runtime/types/index.ts`, which `export *`s every component +
every `types/*` submodule). One barrel import eagerly pulls the whole library
into a consumer's type graph. Instead, import each type directly from its
**source** — the owning component `.vue` (e.g. `ButtonProps` from
`./Button.vue`) or a specific `../types/*` module (e.g. `Messages` from
`../types/locale`). Adds an eslint `no-restricted-imports` guard so the barrel
can't creep back in, with `useComponentProps.ts` exempted (it legitimately
needs the whole barrel via `import type * as ComponentTypes`).

## b24ui port — adapted, not 1:1
b24ui's `types/index.ts` barrel has the **same** shape (re-exports every
`components/*.vue` + `types/{content,editor,form,input,icons,locale,prose,color-mode,utils}`),
so the same refactor applies — but the per-type → source mapping had to be
resolved against **b24ui's own** exports because the component/type set
diverges from upstream:

- b24ui has **no `Icon.vue`**: upstream maps `IconProps` → `./Icon.vue`; b24ui
components use `IconComponent`, which resolves to `../types/icons`.
- b24ui has its own component set (no `AuthForm`/`BlogPost`/…, plus extras like
`Advice`, `Countdown`, the `Sidebar*`/`Navbar*` families).
- b24ui maintains a **curated, smaller locale set** (§2) — 20 locale files
touched here vs upstream's 62. Existing locales are edited normally
(`Messages` import retargeted to `../types/locale`); no new locales added.

Rather than copy upstream's per-file import lines, I built a name→source index
from b24ui's barrel sources and rewrote every consumer's
`import type { … } from '<../types barrel>'` into per-source grouped imports
with the correct relative specifier for the consumer's depth. Verified: **0**
unresolved type names, **0** ambiguous names (no type exported by >1 source).

### Scope
- **119** consumer files rewritten (`src/runtime/{components,composables,utils,
dictionary,locale,vue/...}`), `+`eslint.config.mjs. `120` files total,
+284/−120 lines (single barrel lines split into per-source lines).
- Only remaining barrel import: `composables/useComponentProps.ts`
(`import type * as ComponentTypes from '../types'`) — intentional, and the
eslint rule turns `no-restricted-imports` **off** for that file, mirroring
upstream.
- eslint rule appended via the existing `.append(...)` chain (b24ui uses the
`bitrix24-ui/` plugin namespace, not upstream's `nuxt-ui/`). Rule `files`
globs and restricted paths (`../types`, `../../types`) mirror upstream.
b24ui's only depth-3 barrel importers live under `src/runtime/vue/…` (not
`components/**`/`composables/**`), so — exactly as upstream — they are
rewritten but not eslint-guarded.

## Tests
Types-only change, no runtime/markup change → no snapshot churn. Full suite
unchanged (225 files, 5143 passed / 6 skipped).

## Verify (CI=true)
`dev:prepare` · `lint` (new rule active, green) · `typecheck` (all 119 rewrites
resolve) · `test` · `build` — all green.
10 changes: 8 additions & 2 deletions .sync/nuxt-ui.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"upstream": "nuxt/ui",
"branch": "v4",
"sync_enabled": false,
"cursor": "88baabcf42b115b7da1a65e5f71092a37b5c9bf3",
"cursor": "7eab4bcb78f17b9eed365d617aa3ef3874c21bac",
"_cursor_note": "cursor = last upstream commit ported into b24ui (oldest-first, manual cadence). sync_enabled stays false until Phase 2 (porter workflow #67 + CLAUDE_CODE_OAUTH_TOKEN) is wired and trusted. `processed` is maintained per port from now on (backfilled #68-#72 on 2026-06-09).",
"stats": {
"queue_depth": 0,
Expand Down Expand Up @@ -773,10 +773,16 @@
"summary": "fix(ContentNavigation): key items by identity to prevent leading icon flash (#6640) — NO-OP: upstream keys the navigation v-for by `${index}-${link.path}` in src/runtime/components/content/ContentNavigation.vue (+spec). b24ui has no ContentNavigation component (git ls-files grep contentnavigation => none). Nothing to port. Bookkeeping only"
},
"88baabcf42b115b7da1a65e5f71092a37b5c9bf3": {
"pr": 225,
"b24ui_sha": "007602bf",
"decision": "port",
"summary": "fix(Separator): forward fall-through attributes to root (#6641) — Separator.vue: add defineOptions({ inheritAttrs: false }) + change root <Separator> binding v-bind=rootProps -> v-bind={...rootProps, ...$attrs} so fall-through attrs land on the actual root. Direct 1:1 (b24ui matched pre-change; useForwardProps rootProps + reka <Separator> root unchanged; no ui/icon/color renames). +attr-forwarding spec mirroring #218 (d3b5f1d3) (targets [data-slot=root] since Separator is multi-root). 2 snapshots updated (Separator + -vue): the existing 'with color success' renderEach case passes `color` which is NOT a SeparatorProps member = a fall-through attr; pre-fix multi-root dropped it, post-fix $attrs forwards it to root -> snapshot now carries color=air-primary-success (the fix demonstrating itself)"
},
"7eab4bcb78f17b9eed365d617aa3ef3874c21bac": {
"pr": null,
"b24ui_sha": "pending-merge",
"decision": "port",
"summary": "fix(Separator): forward fall-through attributes to root (#6641) — Separator.vue: add defineOptions({ inheritAttrs: false }) + change root <Separator> binding v-bind=rootProps -> v-bind={...rootProps, ...$attrs} so fall-through attrs land on the actual root. Direct 1:1 (b24ui matched pre-change; useForwardProps rootProps + reka <Separator> root unchanged; no ui/icon/color renames). +attr-forwarding spec mirroring #218 (d3b5f1d3) (targets [data-slot=root] since Separator is multi-root). 2 snapshots updated (Separator + -vue): the existing 'with color success' renderEach case passes `color` which is NOT a SeparatorProps member = a fall-through attr; pre-fix multi-root dropped it, post-fix $attrs forwards it to root -> snapshot now carries color=air-primary-success (the fix demonstrating itself)"
"summary": "perf(types): import cross-component types from source, not the barrel (#6646) — replace `import type {...} from '../types'` barrel imports with per-source imports (owning component .vue, e.g. ButtonProps from ./Button.vue; or specific ../types/* module, e.g. Messages from ../types/locale) across 119 consumer files in src/runtime/{components,composables,utils,dictionary,locale,vue/...}; +eslint no-restricted-imports guard on ../types & ../../types for components/**/*.vue + composables/**/*.ts, with useComponentProps.ts exempted (keeps `import type * as ComponentTypes from '../types'`). Adapted, not 1:1: resolved each type->source against b24ui's OWN exports (IconComponent->../types/icons since b24ui has no Icon.vue; own component set; curated 20 locale files vs upstream 62 per §2). 0 unresolved / 0 ambiguous names. Rule appended via existing .append chain (bitrix24-ui/ namespace). Types-only, no snapshot churn. 120 files, +284/-120"
}
}
}
15 changes: 15 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,19 @@ export default createConfigForNuxt({
rules: {
'bitrix24-ui/no-bare-prop-refs': 'error'
}
}).append({
files: ['src/runtime/components/**/*.vue', 'src/runtime/composables/**/*.ts'],
rules: {
'no-restricted-imports': ['error', {
paths: [
{ name: '../types', message: 'Import cross-component types from their source file (e.g. \'./Button.vue\') or a specific \'../types/*\' module, not the \'../types\' barrel: it re-exports every component, so one import eagerly loads the whole library into a consumer\'s type graph.' },
{ name: '../../types', message: 'Import cross-component types from their source file (e.g. \'./Button.vue\') or a specific \'../../types/*\' module, not the \'../../types\' barrel: it re-exports every component, so one import eagerly loads the whole library into a consumer\'s type graph.' }
]
}]
}
}, {
files: ['src/runtime/composables/useComponentProps.ts'],
rules: {
'no-restricted-imports': 'off'
}
})
2 changes: 1 addition & 1 deletion src/runtime/components/Accordion.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { AccordionRootProps, AccordionRootEmits } from 'reka-ui'
import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/accordion'
import type { IconComponent } from '../types'
import type { IconComponent } from '../types/icons'
import type { DynamicSlots, GetItemKeys } from '../types/utils'
import type { ComponentConfig } from '../types/tv'

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/components/Advice.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/advice'
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
import type { AvatarProps } from '../types'
import type { AvatarProps } from './Avatar.vue'
import type { ComponentConfig } from '../types/tv'

type Advice = ComponentConfig<typeof theme, AppConfig, 'advice'>
Expand Down
5 changes: 4 additions & 1 deletion src/runtime/components/Alert.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/alert'
import type { AvatarProps, ButtonProps, IconComponent, LinkPropsKeys } from '../types'
import type { IconComponent } from '../types/icons'
import type { AvatarProps } from './Avatar.vue'
import type { ButtonProps } from './Button.vue'
import type { LinkPropsKeys } from './Link.vue'
import type { ComponentConfig } from '../types/tv'

type Alert = ComponentConfig<typeof theme, AppConfig, 'alert'>
Expand Down
3 changes: 2 additions & 1 deletion src/runtime/components/App.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<script lang="ts">
import type { ConfigProviderProps, TooltipProviderProps } from 'reka-ui'
import type { VNode } from 'vue'
import type { ToasterProps, Locale, Messages } from '../types'
import type { Locale, Messages } from '../types/locale'
import type { ToasterProps } from './Toaster.vue'

export interface AppProps<T extends Messages = Messages> extends Omit<ConfigProviderProps, 'useId' | 'locale' | 'teleportTo'> {
tooltip?: TooltipProviderProps
Expand Down
3 changes: 2 additions & 1 deletion src/runtime/components/Avatar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/avatar'
import type { IconComponent, ChipProps } from '../types'
import type { IconComponent } from '../types/icons'
import type { ChipProps } from './Chip.vue'
import type { ImgHTMLAttributes } from '../types/html'
import type { ComponentConfig } from '../types/tv'

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/components/Badge.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/badge'
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
import type { AvatarProps } from '../types'
import type { AvatarProps } from './Avatar.vue'
import type { ComponentConfig } from '../types/tv'

type Badge = ComponentConfig<typeof theme, AppConfig, 'badge'>
Expand Down
4 changes: 3 additions & 1 deletion src/runtime/components/Banner.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/banner'
import type { ButtonProps, IconComponent, LinkProps, LinkPropsKeys } from '../types'
import type { IconComponent } from '../types/icons'
import type { ButtonProps } from './Button.vue'
import type { LinkProps, LinkPropsKeys } from './Link.vue'
import type { ComponentConfig } from '../types/tv'

type Banner = ComponentConfig<typeof theme, AppConfig, 'banner'>
Expand Down
4 changes: 3 additions & 1 deletion src/runtime/components/Breadcrumb.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/breadcrumb'
import type { AvatarProps, IconComponent, LinkProps } from '../types'
import type { IconComponent } from '../types/icons'
import type { AvatarProps } from './Avatar.vue'
import type { LinkProps } from './Link.vue'
import type { DynamicSlots, GetItemKeys } from '../types/utils'
import type { ComponentConfig } from '../types/tv'

Expand Down
3 changes: 2 additions & 1 deletion src/runtime/components/Button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import type { Ref, VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/button'
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
import type { LinkProps, AvatarProps } from '../types'
import type { AvatarProps } from './Avatar.vue'
import type { LinkProps } from './Link.vue'
import type { ComponentConfig } from '../types/tv'

type Button = ComponentConfig<typeof theme, AppConfig, 'button'>
Expand Down
4 changes: 3 additions & 1 deletion src/runtime/components/Calendar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import type { VNode } from 'vue'
import type { DateValue } from '@internationalized/date'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/calendar'
import type { IconComponent, ButtonProps, LinkPropsKeys } from '../types'
import type { IconComponent } from '../types/icons'
import type { ButtonProps } from './Button.vue'
import type { LinkPropsKeys } from './Link.vue'
import type { ComponentConfig } from '../types/tv'

type Calendar = ComponentConfig<typeof theme, AppConfig, 'calendar'>
Expand Down
4 changes: 3 additions & 1 deletion src/runtime/components/ChatMessage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import type { UIDataTypes, UIMessage, UITools, FileUIPart, TextUIPart } from 'ai'
import theme from '#build/b24ui/chat-message'
import type { AvatarProps, ButtonProps, IconComponent } from '../types'
import type { IconComponent } from '../types/icons'
import type { AvatarProps } from './Avatar.vue'
import type { ButtonProps } from './Button.vue'
import type { ComponentConfig } from '../types/tv'

type ChatMessage = ComponentConfig<typeof theme, AppConfig, 'chatMessage'>
Expand Down
5 changes: 4 additions & 1 deletion src/runtime/components/ChatMessages.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import type { ComponentPublicInstance, VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import type { UIDataTypes, UIMessage, UITools, ChatStatus } from 'ai'
import theme from '#build/b24ui/chat-messages'
import type { ButtonProps, ChatMessageProps, ChatMessageSlots, IconComponent, LinkPropsKeys } from '../types'
import type { IconComponent } from '../types/icons'
import type { ButtonProps } from './Button.vue'
import type { ChatMessageProps, ChatMessageSlots } from './ChatMessage.vue'
import type { LinkPropsKeys } from './Link.vue'
import type { ComponentConfig } from '../types/tv'

type ChatMessages = ComponentConfig<typeof theme, AppConfig, 'chatMessages'>
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/components/ChatPrompt.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/chat-prompt'
import type { TextareaProps, TextareaSlots } from '../types'
import type { TextareaProps, TextareaSlots } from './Textarea.vue'
import type { ComponentConfig } from '../types/tv'

type ChatPrompt = ComponentConfig<typeof theme, AppConfig, 'chatPrompt'>
Expand Down
4 changes: 3 additions & 1 deletion src/runtime/components/ChatPromptSubmit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
import type { ChatStatus } from 'ai'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/chat-prompt-submit'
import type { ButtonProps, ButtonSlots, IconComponent, LinkPropsKeys } from '../types'
import type { IconComponent } from '../types/icons'
import type { ButtonProps, ButtonSlots } from './Button.vue'
import type { LinkPropsKeys } from './Link.vue'
import type { ComponentConfig } from '../types/tv'

type ChatPromptSubmit = ComponentConfig<typeof theme, AppConfig, 'chatPromptSubmit'>
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/components/ChatReasoning.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { CollapsibleRootProps } from 'reka-ui'
import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/chat-reasoning'
import type { IconComponent } from '../types'
import type { IconComponent } from '../types/icons'
import type { ChatShimmerProps } from './ChatShimmer.vue'
import type { ComponentConfig } from '../types/tv'

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/components/ChatTool.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { CollapsibleRootProps } from 'reka-ui'
import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/chat-tool'
import type { IconComponent } from '../types'
import type { IconComponent } from '../types/icons'
import type { ChatShimmerProps } from './ChatShimmer.vue'
import type { ComponentConfig } from '../types/tv'

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/components/CheckboxGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { CheckboxGroupRootProps, CheckboxGroupRootEmits } from 'reka-ui'
import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/checkbox-group'
import type { CheckboxProps } from '../types'
import type { CheckboxProps } from './Checkbox.vue'
import type { AcceptableValue, GetItemKeys, GetModelValue, GetModelValueEmits } from '../types/utils'
import type { ComponentConfig } from '../types/tv'

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/components/Chip.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/chip'
import type { IconComponent } from '../types'
import type { IconComponent } from '../types/icons'
import type { ComponentConfig } from '../types/tv'

type Chip = ComponentConfig<typeof theme, AppConfig, 'chip'>
Expand Down
8 changes: 7 additions & 1 deletion src/runtime/components/CommandPalette.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ import type { AppConfig } from '@nuxt/schema'
import type { UseFuseOptions } from '@vueuse/integrations/useFuse'
import theme from '#build/b24ui/command-palette'
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
import type { AvatarProps, ButtonProps, ChipProps, KbdProps, InputProps, LinkProps, IconComponent, LinkPropsKeys } from '../types'
import type { IconComponent } from '../types/icons'
import type { AvatarProps } from './Avatar.vue'
import type { ButtonProps } from './Button.vue'
import type { ChipProps } from './Chip.vue'
import type { InputProps } from './Input.vue'
import type { KbdProps } from './Kbd.vue'
import type { LinkProps, LinkPropsKeys } from './Link.vue'
import type { GetItemKeys } from '../types/utils'
import type { ComponentConfig } from '../types/tv'

Expand Down
5 changes: 4 additions & 1 deletion src/runtime/components/ContextMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import type { ContextMenuRootProps, ContextMenuRootEmits, ContextMenuContentProp
import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/context-menu'
import type { AvatarProps, IconComponent, KbdProps, LinkProps } from '../types'
import type { IconComponent } from '../types/icons'
import type { AvatarProps } from './Avatar.vue'
import type { KbdProps } from './Kbd.vue'
import type { LinkProps } from './Link.vue'
import type { ArrayOrNested, DynamicSlots, GetItemKeys, MergeTypes, NestedItem, EmitsToProps } from '../types/utils'
import type { ComponentConfig } from '../types/tv'

Expand Down
5 changes: 4 additions & 1 deletion src/runtime/components/ContextMenuContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
import type { ContextMenuContentProps as RekaContextMenuContentProps, ContextMenuContentEmits as RekaContextMenuContentEmits } from 'reka-ui'
import type { AppConfig } from '@nuxt/schema'
import type theme from '#build/b24ui/context-menu'
import type { AvatarProps, ContextMenuItem, ContextMenuSlots, IconComponent, KbdProps } from '../types'
import type { IconComponent } from '../types/icons'
import type { AvatarProps } from './Avatar.vue'
import type { ContextMenuItem, ContextMenuSlots } from './ContextMenu.vue'
import type { KbdProps } from './Kbd.vue'
import type { ArrayOrNested, GetItemKeys } from '../types/utils'
import type { ComponentConfig } from '../types/tv'

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/components/Countdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/countdown'
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
import type { AvatarProps } from '../types'
import type { AvatarProps } from './Avatar.vue'
import type { ComponentConfig } from '../types/tv'

type Countdown = ComponentConfig<typeof theme, AppConfig, 'countdown'>
Expand Down
4 changes: 3 additions & 1 deletion src/runtime/components/DashboardNavbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import type { VNode } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/b24ui/dashboard-navbar'
import type { DashboardContext } from '../utils/dashboard'
import type { ButtonProps, IconComponent, LinkPropsKeys } from '../types'
import type { IconComponent } from '../types/icons'
import type { ButtonProps } from './Button.vue'
import type { LinkPropsKeys } from './Link.vue'
import type { ComponentConfig } from '../types/tv'

type DashboardNavbar = ComponentConfig<typeof theme, AppConfig, 'dashboardNavbar'>
Expand Down
Loading