@estiva-app/ui 0.73.0 → 0.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CommandPalette.d.ts +3 -1
- package/dist/CommandPalette.d.ts.map +1 -1
- package/dist/ComposerTriggers.d.ts +7 -0
- package/dist/ComposerTriggers.d.ts.map +1 -1
- package/dist/Menu.d.ts +8 -2
- package/dist/Menu.d.ts.map +1 -1
- package/dist/SuggestionMenu.d.ts +2 -0
- package/dist/SuggestionMenu.d.ts.map +1 -1
- package/dist/editor.js +7 -1
- package/dist/editor.js.map +2 -2
- package/dist/index.js +10 -4
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
- package/registry.json +7 -1
- package/src/CommandPalette.test.tsx +6 -0
- package/src/CommandPalette.tsx +4 -1
- package/src/ComposerTriggers.test.tsx +21 -0
- package/src/ComposerTriggers.tsx +14 -1
- package/src/Menu.tsx +19 -5
- package/src/SuggestionMenu.tsx +4 -1
package/package.json
CHANGED
package/registry.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"kind": "package",
|
|
5
5
|
"repo": "estiva-ui",
|
|
6
6
|
"package": "@estiva-app/ui",
|
|
7
|
-
"packageVersion": "0.
|
|
7
|
+
"packageVersion": "0.74.0",
|
|
8
8
|
"exports": 178,
|
|
9
9
|
"typeExports": 164,
|
|
10
10
|
"files": null
|
|
@@ -4395,6 +4395,12 @@
|
|
|
4395
4395
|
"required": false,
|
|
4396
4396
|
"note": "A second line under the label — a role, an address — 12px, secondary, truncating."
|
|
4397
4397
|
},
|
|
4398
|
+
{
|
|
4399
|
+
"name": "aside",
|
|
4400
|
+
"takes": "text",
|
|
4401
|
+
"required": false,
|
|
4402
|
+
"note": "After the label, on its line — 12px, muted, never cut: where a file sits (an issue's ref and project) when its second line is its summary (SUM-7)."
|
|
4403
|
+
},
|
|
4398
4404
|
{
|
|
4399
4405
|
"name": "leading",
|
|
4400
4406
|
"takes": "anything",
|
|
@@ -94,6 +94,12 @@ describe('CommandPaletteSearch — rows', () => {
|
|
|
94
94
|
expect(groups.map((g) => g.firstElementChild?.textContent)).toEqual(['First', 'Second'])
|
|
95
95
|
})
|
|
96
96
|
|
|
97
|
+
it('draws a row’s aside after its label, on the label’s line, above the second line (SUM-7)', () => {
|
|
98
|
+
render(<Search groups={[{ label: 'Recent', rows: [row('Ship launch', { aside: 'SHI-12 · Ship 1', description: 'What we show on Friday' })] }]} />)
|
|
99
|
+
const option = screen.getByRole('option')
|
|
100
|
+
expect(within(option).getByText('What we show on Friday').previousElementSibling?.textContent).toBe('Ship launchSHI-12 · Ship 1')
|
|
101
|
+
})
|
|
102
|
+
|
|
97
103
|
it('puts 2px between its rows and under each heading, as a menu does', () => {
|
|
98
104
|
render(<Search groups={[{ label: 'Group', rows: [row('One'), row('Two')] }]} />)
|
|
99
105
|
const [first] = screen.getAllByRole('option')
|
package/src/CommandPalette.tsx
CHANGED
|
@@ -196,8 +196,10 @@ export interface CommandPaletteRow {
|
|
|
196
196
|
/** Unique in the level. The footer follows the lit row by it. */
|
|
197
197
|
id: string
|
|
198
198
|
label: string
|
|
199
|
-
/** The second line — where it is, who said it, when. */
|
|
199
|
+
/** The second line — where it is, who said it, when; a file's summary. */
|
|
200
200
|
description?: string
|
|
201
|
+
/** After the label, muted: where a file sits (an issue's ref and project) when its second line is its summary. */
|
|
202
|
+
aside?: string
|
|
201
203
|
/** A 16px icon, drawn on the row's 32px tile. */
|
|
202
204
|
icon?: ReactNode
|
|
203
205
|
/** Instead of `icon`: something with a look of its own — a face, a status mark — in the same 32px space, with no tile. */
|
|
@@ -414,6 +416,7 @@ export function CommandPaletteSearch({ query, onQueryChange, placeholder, groups
|
|
|
414
416
|
size="tall"
|
|
415
417
|
label={row.label}
|
|
416
418
|
description={row.description}
|
|
419
|
+
aside={row.aside}
|
|
417
420
|
leading={<RowLeading row={row} />}
|
|
418
421
|
submenu={!!row.onGoIn}
|
|
419
422
|
hint={row.onGoIn ? <Kbd>Tab</Kbd> : <EnterHint />}
|
|
@@ -176,6 +176,27 @@ describe('[', () => {
|
|
|
176
176
|
expect(icons).toEqual(['kind-a', 'own', 'list'])
|
|
177
177
|
})
|
|
178
178
|
|
|
179
|
+
it('draws a summary as the second line, with where the thing sits beside the label; without one, the row is as before (SUM-7)', async () => {
|
|
180
|
+
const rows = [
|
|
181
|
+
{ id: 's', label: 'Ship launch', snippet: '', uri: 'nostr:s', description: 'SHI-12 · Ship 1', summary: 'What we show on Friday' },
|
|
182
|
+
{ id: 'n', label: 'Old plan', snippet: '', uri: 'nostr:n', description: 'SHI-3 · Ship 1' },
|
|
183
|
+
]
|
|
184
|
+
function Summarised() {
|
|
185
|
+
const made = useEditor({
|
|
186
|
+
extensions: [StarterKit, Chip, ReferenceTrigger.configure({ items: () => rows, nodeName: 'messageMention', ariaLabel: 'Things', sectionLabel: 'Things' })],
|
|
187
|
+
})
|
|
188
|
+
editor = made
|
|
189
|
+
return <EditorContent editor={made} />
|
|
190
|
+
}
|
|
191
|
+
render(<Summarised />)
|
|
192
|
+
await type('[')
|
|
193
|
+
const [withSummary, without] = within(screen.getByRole('listbox')).getAllByRole('option')
|
|
194
|
+
// The line above a row's second line, as a person reads it.
|
|
195
|
+
const lineAbove = (row: HTMLElement, second: string) => within(row).getByText(second).previousElementSibling?.textContent
|
|
196
|
+
expect(lineAbove(withSummary, 'What we show on Friday')).toBe('Ship launchSHI-12 · Ship 1')
|
|
197
|
+
expect(lineAbove(without, 'SHI-3 · Ship 1')).toBe('Old plan')
|
|
198
|
+
})
|
|
199
|
+
|
|
179
200
|
it('draws the app’s sections in order, skips an empty one, and redraws the open list when told', async () => {
|
|
180
201
|
const listeners = new Set<() => void>()
|
|
181
202
|
let late: CaptionedItem[] = []
|
package/src/ComposerTriggers.tsx
CHANGED
|
@@ -232,6 +232,13 @@ export interface CaptionedItem {
|
|
|
232
232
|
search?: string
|
|
233
233
|
/** The row's second line, e.g. where the thing sits. The chip does not wear it. */
|
|
234
234
|
description?: string
|
|
235
|
+
/**
|
|
236
|
+
* What the thing is about, in a line of plain text — a file's summary. When
|
|
237
|
+
* set, it is the row's second line and `description` moves up after the
|
|
238
|
+
* label, muted; absent, the row is as before. The chip does not wear it, and
|
|
239
|
+
* the query is not matched against it.
|
|
240
|
+
*/
|
|
241
|
+
summary?: string
|
|
235
242
|
/**
|
|
236
243
|
* This row's own 16px icon, in place of the list's `icon`: what the thing is,
|
|
237
244
|
* when the list holds several kinds — a topic, a project, a message
|
|
@@ -363,7 +370,13 @@ export function referenceMenu({ ariaLabel, sectionLabel, icon, iconFor }: Refere
|
|
|
363
370
|
return groups
|
|
364
371
|
},
|
|
365
372
|
itemKey: (item) => `reference-${item.id}`,
|
|
366
|
-
row: (item) => ({
|
|
373
|
+
row: (item) => ({
|
|
374
|
+
leading: item.icon ?? iconFor?.(item.uri) ?? icon,
|
|
375
|
+
label: captionOf(item.label, item.snippet),
|
|
376
|
+
// A summary is the second line, and where the thing sits moves up beside the label (SUM-7's story).
|
|
377
|
+
...(item.summary ? { description: item.summary, aside: item.description } : { description: item.description }),
|
|
378
|
+
hint: <EnterHint />,
|
|
379
|
+
}),
|
|
367
380
|
}
|
|
368
381
|
}
|
|
369
382
|
|
package/src/Menu.tsx
CHANGED
|
@@ -350,6 +350,12 @@ export interface MenuItemProps extends Omit<ComponentPropsWithRef<'button'>, 'ch
|
|
|
350
350
|
size?: 'default' | 'tall'
|
|
351
351
|
/** A second line under the label — a role, an address — 12px, secondary, truncating. */
|
|
352
352
|
description?: string
|
|
353
|
+
/**
|
|
354
|
+
* After the label, on its line — 12px, muted, never cut: where a file sits
|
|
355
|
+
* (an issue's ref and project) when its second line is its summary (SUM-7).
|
|
356
|
+
* The label truncates before it does.
|
|
357
|
+
*/
|
|
358
|
+
aside?: string
|
|
353
359
|
/** Before the label: a 16px icon (stroke 1.5, secondary), or an Avatar, for rows led by a face. */
|
|
354
360
|
leading?: ReactNode
|
|
355
361
|
/** At the right edge: a hint, a value — anything. Wins over `shortcut` and `submenu`. */
|
|
@@ -425,7 +431,7 @@ export function menuItemClassName({ size, selected, className }: { size: 'defaul
|
|
|
425
431
|
/** Everything inside the row — written once, for the same reason. Shared
|
|
426
432
|
* inside the package like `menuItemClassName`: `CommandPalette` draws it
|
|
427
433
|
* inside Base UI's `Autocomplete.Item`. Not exported from the index. */
|
|
428
|
-
export function MenuItemBody({ label, children, size = 'default', description, leading, trailing, hint, shortcut, submenu, destructive, selected }: Pick<MenuItemProps, 'label' | 'children' | 'size' | 'description' | 'leading' | 'trailing' | 'hint' | 'shortcut' | 'submenu' | 'destructive' | 'selected'>) {
|
|
434
|
+
export function MenuItemBody({ label, children, size = 'default', description, aside, leading, trailing, hint, shortcut, submenu, destructive, selected }: Pick<MenuItemProps, 'label' | 'children' | 'size' | 'description' | 'aside' | 'leading' | 'trailing' | 'hint' | 'shortcut' | 'submenu' | 'destructive' | 'selected'>) {
|
|
429
435
|
const edge =
|
|
430
436
|
trailing ??
|
|
431
437
|
(shortcut ? (
|
|
@@ -441,9 +447,16 @@ export function MenuItemBody({ label, children, size = 'default', description, l
|
|
|
441
447
|
colour. Ship's copy said `text-sm`, which was never the ramp. */}
|
|
442
448
|
{children ?? (
|
|
443
449
|
<span className={cn('flex min-w-0 flex-1 flex-col', size === 'tall' && 'gap-[2px]')}>
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
450
|
+
{aside ? (
|
|
451
|
+
<span className="flex min-w-0 items-baseline gap-2">
|
|
452
|
+
<span className={cn('truncate text-body-2', destructive ? 'text-error-default' : 'text-text-primary')}>{label}</span>
|
|
453
|
+
<span className="shrink-0 text-caption text-text-muted">{aside}</span>
|
|
454
|
+
</span>
|
|
455
|
+
) : (
|
|
456
|
+
<span className={cn('truncate text-body-2', destructive ? 'text-error-default' : 'text-text-primary')}>
|
|
457
|
+
{label}
|
|
458
|
+
</span>
|
|
459
|
+
)}
|
|
447
460
|
{description && <span className="truncate text-caption text-text-secondary">{description}</span>}
|
|
448
461
|
</span>
|
|
449
462
|
)}
|
|
@@ -469,12 +482,13 @@ export function MenuItemBody({ label, children, size = 'default', description, l
|
|
|
469
482
|
)
|
|
470
483
|
}
|
|
471
484
|
|
|
472
|
-
export function MenuItem({ label, children, size = 'default', description, leading, trailing, hint, shortcut, submenu, destructive, selected, className, ...props }: MenuItemProps) {
|
|
485
|
+
export function MenuItem({ label, children, size = 'default', description, aside, leading, trailing, hint, shortcut, submenu, destructive, selected, className, ...props }: MenuItemProps) {
|
|
473
486
|
const body = (
|
|
474
487
|
<MenuItemBody
|
|
475
488
|
label={label}
|
|
476
489
|
size={size}
|
|
477
490
|
description={description}
|
|
491
|
+
aside={aside}
|
|
478
492
|
leading={leading}
|
|
479
493
|
trailing={trailing}
|
|
480
494
|
hint={hint}
|
package/src/SuggestionMenu.tsx
CHANGED
|
@@ -34,6 +34,8 @@ import { Popover } from './Popover'
|
|
|
34
34
|
export interface SuggestionMenuRow {
|
|
35
35
|
label: string
|
|
36
36
|
description?: string
|
|
37
|
+
/** After the label, muted — `MenuItem`'s. */
|
|
38
|
+
aside?: string
|
|
37
39
|
leading?: ReactNode
|
|
38
40
|
/** What you would type — drawn as keys at the right, e.g. `#` for a heading. */
|
|
39
41
|
shortcut?: string
|
|
@@ -158,7 +160,7 @@ export function SuggestionMenu<T>({ rect, editorElement, ariaLabel, width, maxHe
|
|
|
158
160
|
const drawRow = (item: T) => {
|
|
159
161
|
const index = items.indexOf(item)
|
|
160
162
|
const selected = index === highlight
|
|
161
|
-
const { label, description, leading, shortcut, hint, size } = row(item)
|
|
163
|
+
const { label, description, aside, leading, shortcut, hint, size } = row(item)
|
|
162
164
|
return (
|
|
163
165
|
// A row of a list the editor drives from its caret: focus stays in the text, so the row is no Tab stop.
|
|
164
166
|
<MenuItem
|
|
@@ -171,6 +173,7 @@ export function SuggestionMenu<T>({ rect, editorElement, ariaLabel, width, maxHe
|
|
|
171
173
|
size={size}
|
|
172
174
|
label={label}
|
|
173
175
|
description={description}
|
|
176
|
+
aside={aside}
|
|
174
177
|
leading={leading}
|
|
175
178
|
shortcut={shortcut}
|
|
176
179
|
hint={hint}
|