Skip to content

Commit fe9c597

Browse files
committed
Merge origin/main into feat/a11y-nuxt-rework
Resolve the messages-plugin refactor (main split App.vue/MessagesView.vue into MessageList/MessageDetail/MessageFilterBar + useMessageFilters and removed src/types.ts): re-apply the message->dock navigation onto the new components — canActivate probe + onActivate in App.vue, threaded through MessagesView to the new MessageDetail, which renders the action buttons. Types now come from @devframes/hub/types. Regenerate the tsnapi API snapshots against the merged build.
2 parents 462cb1c + 24aedc0 commit fe9c597

65 files changed

Lines changed: 3021 additions & 1901 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

alias.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ export const alias = {
101101
'@devframes/plugin-messages/client': p('messages/src/client/index.ts'),
102102
'@devframes/plugin-messages/node': p('messages/src/node/index.ts'),
103103
'@devframes/plugin-messages/constants': p('messages/src/constants.ts'),
104-
'@devframes/plugin-messages/types': p('messages/src/types.ts'),
105104
'@devframes/plugin-messages/rpc': p('messages/src/rpc/index.ts'),
106105
'@devframes/plugin-messages/cli': p('messages/src/cli.ts'),
107106
'@devframes/plugin-messages/vite': p('messages/src/vite.ts'),

docs/guide/when-clauses.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,24 @@ ctx.docks.register({
4040

4141
`when: 'false'` hides an entry unconditionally.
4242

43+
### Render-only visibility on dock entries
44+
45+
A dock entry also takes `visibility`, a second expression in the same syntax that hides only the entry's own dock-bar button, leaving the entry registered and reachable — `docks.activate()`/`switchEntry()` by id, RPC lookups, and anything else that walks the raw entry list keep working. `when` remains the general relevance switch for the entry as a whole; reach for `visibility` only when an entry must stay in the model without a button of its own.
46+
47+
The canonical case is a shared-frame anchor (`subTabs`): the anchor iframe must stay registered to keep driving the postMessage nav loop, but only its synthesized member tabs should render as dock-bar buttons.
48+
49+
```ts
50+
ctx.docks.register({
51+
id: 'my-devtool:anchor',
52+
title: 'My Devtool',
53+
type: 'iframe',
54+
icon: 'ph:squares-four-duotone',
55+
url: '/__my-devtool/',
56+
subTabs: { protocol: 'postmessage' },
57+
visibility: 'false', // hide the anchor's own button; its tabs still render
58+
})
59+
```
60+
4361
## Expression syntax
4462

4563
### Operators

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"type": "module",
44
"version": "0.7.12",
55
"private": true,
6-
"packageManager": "pnpm@11.15.1",
6+
"packageManager": "pnpm@11.16.0",
77
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
88
"license": "MIT",
99
"funding": "https://github.com/sponsors/antfu",

packages/devframe/src/types/devframe.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,13 @@ export interface DevframeDockDefaults {
219219
* clauses). Set to `'false'` to hide the entry unconditionally.
220220
*/
221221
when?: string
222+
/**
223+
* Render-only visibility expression, same syntax as {@link when}. Hides the
224+
* entry's own dock-bar button when it evaluates to `false` while leaving it
225+
* registered and reachable (activation, RPC lookups, etc.) — unlike `when`,
226+
* which is the general relevance switch for the entry as a whole.
227+
*/
228+
visibility?: string
222229
/** Badge text rendered on the dock icon (e.g. an unread count). */
223230
badge?: string
224231
/** Id of the dock group this entry collapses under, if any. */

packages/hub/src/client/__tests__/host.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,24 @@ describe('createDevframeClientHost', () => {
9999
host.dispose()
100100
})
101101

102+
it('keeps a `visibility: false` entry in the raw model, activatable by id', async () => {
103+
const { rpc, states } = createStubRpc()
104+
const host = await createDevframeClientHost({ rpc })
105+
states.get('devframe:docks')!.push([
106+
iframeEntry('anchor', { subTabs: { protocol: 'postmessage' }, visibility: 'false' }),
107+
iframeEntry('visible'),
108+
])
109+
110+
// `visibility` is a render-only hint for the UI layer — the hub itself
111+
// never filters `entries`/`getStateById`/`switchEntry` by it, so the
112+
// anchor stays fully reachable.
113+
expect(host.context.docks.entries.map(e => e.id)).toEqual(['anchor', 'visible'])
114+
expect(host.context.docks.getStateById('anchor')).toBeDefined()
115+
expect(await host.context.docks.switchEntry('anchor')).toBe(true)
116+
expect(host.context.docks.selected?.id).toBe('anchor')
117+
host.dispose()
118+
})
119+
102120
it('groups entries by category — grouped members bucket under their group, orphans by their own', async () => {
103121
const { rpc, states } = createStubRpc()
104122
const host = await createDevframeClientHost({ rpc })

packages/hub/src/define.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ export function defineCommand<const W extends string = ''>(
1616
export function defineDockEntry<
1717
const T extends DevframeDockUserEntry,
1818
const W extends string = '',
19+
const V extends string = '',
1920
>(
20-
entry: Omit<T, 'when'> & { when?: WhenExpression<WhenContext, W> },
21+
entry: Omit<T, 'when' | 'visibility'> & {
22+
when?: WhenExpression<WhenContext, W>
23+
visibility?: WhenExpression<WhenContext, V>
24+
},
2125
): T {
2226
return entry as unknown as T
2327
}

packages/hub/src/node/__tests__/mount-devframe.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,19 @@ describe('mountDevframe', () => {
7171
})
7272
})
7373

74+
it('applies the definition-level dock `visibility` default to the synthesized entry, independent of `when`', async () => {
75+
const ctx = createContext()
76+
await mountDevframe(ctx, makeDevframe({
77+
dock: { when: 'clientType == embedded', visibility: 'false' },
78+
}))
79+
80+
expect(ctx.docks.views.get('demo')).toMatchObject({
81+
id: 'demo',
82+
when: 'clientType == embedded',
83+
visibility: 'false',
84+
})
85+
})
86+
7487
it('lets per-mount dock overrides win over the definition dock defaults', async () => {
7588
const ctx = createContext()
7689
await mountDevframe(

packages/hub/src/node/mount-devframe.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ export interface MountDevframeOptions {
1313
/**
1414
* Per-mount overrides for the auto-synthesized iframe dock entry. Use
1515
* this to customize the entry's `category`, override the icon, hide it
16-
* via `when`, etc. Takes precedence over the definition's own
17-
* {@link DevframeDefinition.dock} defaults. Cannot change `id`, `type`,
18-
* or `url` — those are derived from the devframe definition.
16+
* via `when` (or only its dock-bar button via `visibility`), etc. Takes
17+
* precedence over the definition's own {@link DevframeDefinition.dock}
18+
* defaults. Cannot change `id`, `type`, or `url` — those are derived from
19+
* the devframe definition.
1920
*/
2021
dock?: Partial<Omit<DevframeViewIframe, 'id' | 'type' | 'url'>>
2122
}

packages/hub/src/types/docks.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,28 @@ export interface DevframeDockEntryBase {
108108
* @see {@link import('devframe/utils/when').evaluateWhen}
109109
*/
110110
when?: string
111+
/**
112+
* Render-only conditional visibility expression, same syntax as {@link when}.
113+
* When it evaluates to `false`, a viewer omits the entry from the rendered
114+
* dock bar / list, but the entry stays registered and fully reachable —
115+
* `docks.activate()`/`switchEntry()` by id, RPC lookups, and anything else
116+
* that walks the raw entry list (e.g. the {@link DevframeViewIframe.subTabs}
117+
* frame-nav adapter) keep working exactly as if it were visible.
118+
*
119+
* Use this instead of {@link when} when an entry must remain part of the
120+
* model without a dock-bar button of its own — the canonical case is a
121+
* shared-frame {@link DevframeViewIframe.subTabs anchor}: set
122+
* `visibility: 'false'` on the anchor so only its synthesized member tabs
123+
* render, while the anchor itself keeps driving the postMessage nav loop.
124+
* `when`, by contrast, is the general relevance switch for the entry as a
125+
* whole; reach for `visibility` only for this render-only carve-out.
126+
*
127+
* Set to `'false'` to unconditionally hide the entry's own dock-bar button.
128+
*
129+
* @example 'false'
130+
* @see {@link import('devframe/utils/when').evaluateWhen}
131+
*/
132+
visibility?: string
111133
/**
112134
* Badge text to display on the dock icon (e.g., unread count)
113135
*/
@@ -182,6 +204,10 @@ export interface DevframeViewIframe extends DevframeDockEntryBase {
182204
* (grouped/soft-navigated via this anchor's {@link frameId}), and drives the
183205
* live navigation loop. Absent a shim, the anchor simply renders as a single
184206
* plain iframe dock.
207+
*
208+
* Set {@link DevframeDockEntryBase.visibility} to `'false'` on the anchor to
209+
* hide its own dock-bar button once tabs are discovered, surfacing only the
210+
* synthesized member docks while the anchor keeps driving the nav loop.
185211
*/
186212
subTabs?: FrameSubTabsConfig
187213
/**

plugins/data-inspector/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,20 +59,20 @@
5959
"dependencies": {
6060
"cac": "catalog:deps",
6161
"get-port-please": "catalog:deps",
62-
"jora": "catalog:",
62+
"jora": "catalog:deps",
6363
"nostics": "catalog:deps"
6464
},
6565
"devDependencies": {
6666
"@antfu/design": "catalog:frontend",
67-
"@discoveryjs/discovery": "catalog:",
67+
"@discoveryjs/discovery": "catalog:frontend",
6868
"@iconify-json/ph": "catalog:frontend",
69-
"@types/codemirror": "catalog:",
69+
"@types/codemirror": "catalog:types",
7070
"@vitejs/plugin-vue": "catalog:build",
7171
"devframe": "workspace:*",
7272
"dompurify": "catalog:frontend",
7373
"floating-vue": "catalog:frontend",
7474
"reka-ui": "catalog:frontend",
75-
"splitpanes": "catalog:",
75+
"splitpanes": "catalog:frontend",
7676
"tsdown": "catalog:build",
7777
"unocss": "catalog:frontend",
7878
"vite": "catalog:build",

0 commit comments

Comments
 (0)