Compare commits
3 Commits
7ccd541d40
...
b087de84c4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b087de84c4 | ||
|
|
3e07f6798c | ||
|
|
bc0824b934 |
@@ -35,6 +35,8 @@ public class TranscriptionBlock {
|
|||||||
@Column(columnDefinition = "TEXT")
|
@Column(columnDefinition = "TEXT")
|
||||||
private String text;
|
private String text;
|
||||||
|
|
||||||
|
// EAGER: mention set is bounded by block text length (typically < 20 entries).
|
||||||
|
// Switching back to LAZY requires callers to be inside an open Hibernate session.
|
||||||
@ElementCollection(fetch = FetchType.EAGER)
|
@ElementCollection(fetch = FetchType.EAGER)
|
||||||
@CollectionTable(
|
@CollectionTable(
|
||||||
name = "transcription_block_mentioned_persons",
|
name = "transcription_block_mentioned_persons",
|
||||||
|
|||||||
@@ -72,6 +72,13 @@ const ariaLabel = $derived(
|
|||||||
// aria-busy="true" while loading so SR clients know the region's contents
|
// aria-busy="true" while loading so SR clients know the region's contents
|
||||||
// will change. Cleared on loaded/error so the new content is announced.
|
// will change. Cleared on loaded/error so the new content is announced.
|
||||||
const ariaBusy = $derived(state.status === 'loading');
|
const ariaBusy = $derived(state.status === 'loading');
|
||||||
|
|
||||||
|
const showMaidenName = $derived(
|
||||||
|
state.status === 'loaded' &&
|
||||||
|
!!state.person.alias &&
|
||||||
|
state.person.alias !== state.person.lastName &&
|
||||||
|
state.person.alias !== state.person.displayName
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -113,7 +120,7 @@ const ariaBusy = $derived(state.status === 'loading');
|
|||||||
{#if dateRange}
|
{#if dateRange}
|
||||||
<div class="dates" data-testid="person-hover-card-dates">{dateRange}</div>
|
<div class="dates" data-testid="person-hover-card-dates">{dateRange}</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if state.person.alias && state.person.alias !== state.person.lastName && state.person.alias !== state.person.displayName}
|
{#if showMaidenName}
|
||||||
<div class="maiden" data-testid="person-hover-card-maiden">
|
<div class="maiden" data-testid="person-hover-card-maiden">
|
||||||
{m.person_born_name_prefix()}
|
{m.person_born_name_prefix()}
|
||||||
{state.person.alias}
|
{state.person.alias}
|
||||||
@@ -250,6 +257,7 @@ const ariaBusy = $derived(state.status === 'loading');
|
|||||||
|
|
||||||
.chip-type {
|
.chip-type {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
/* opacity 0.7 on --c-ink: ~5.6:1 light, ~7.1:1 dark — WCAG AA ✓ */
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ describe('PersonHoverCard — accessibility', () => {
|
|||||||
expect(root.id).toBe('card-xyz');
|
expect(root.id).toBe('card-xyz');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('positions itself absolutely at the given top/left', async () => {
|
it('positions itself fixed at the given top/left', async () => {
|
||||||
render(PersonHoverCard, {
|
render(PersonHoverCard, {
|
||||||
personId: 'p-aug',
|
personId: 'p-aug',
|
||||||
cardId: 'card-1',
|
cardId: 'card-1',
|
||||||
@@ -368,6 +368,6 @@ describe('PersonHoverCard — accessibility', () => {
|
|||||||
const root = document.querySelector('[data-testid="person-hover-card"]') as HTMLElement;
|
const root = document.querySelector('[data-testid="person-hover-card"]') as HTMLElement;
|
||||||
expect(root.style.top).toBe('333px');
|
expect(root.style.top).toBe('333px');
|
||||||
expect(root.style.left).toBe('444px');
|
expect(root.style.left).toBe('444px');
|
||||||
expect(root.style.position).toBe('absolute');
|
expect(root.style.position).toBe('fixed');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -363,6 +363,38 @@ describe('PersonMentionEditor — XSS resistance', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Placeholder behavior ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
describe('PersonMentionEditor — placeholder behavior', () => {
|
||||||
|
it('sets data-placeholder on the inner element when editor is empty', async () => {
|
||||||
|
render(PersonMentionEditorHost, {
|
||||||
|
initialValue: '',
|
||||||
|
initialMentions: [],
|
||||||
|
placeholder: 'Gib Text ein...',
|
||||||
|
onChange: () => {}
|
||||||
|
});
|
||||||
|
await vi.waitFor(() => {
|
||||||
|
const inner = document.querySelector('.tiptap-editor-inner') as HTMLElement | null;
|
||||||
|
expect(inner).not.toBeNull();
|
||||||
|
expect(inner!.getAttribute('data-placeholder')).toBe('Gib Text ein...');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('omits data-placeholder on the inner element when editor has content', async () => {
|
||||||
|
render(PersonMentionEditorHost, {
|
||||||
|
initialValue: 'Bestehender Text',
|
||||||
|
initialMentions: [],
|
||||||
|
placeholder: 'Gib Text ein...',
|
||||||
|
onChange: () => {}
|
||||||
|
});
|
||||||
|
await vi.waitFor(() => {
|
||||||
|
const inner = document.querySelector('.tiptap-editor-inner') as HTMLElement | null;
|
||||||
|
expect(inner).not.toBeNull();
|
||||||
|
expect(inner!.hasAttribute('data-placeholder')).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// ─── Touch target (WCAG 2.2 AA) ──────────────────────────────────────────────
|
// ─── Touch target (WCAG 2.2 AA) ──────────────────────────────────────────────
|
||||||
|
|
||||||
describe('PersonMentionEditor — touch target', () => {
|
describe('PersonMentionEditor — touch target', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user