fix(words): close 12 type-drift errors from F2/F3/COLOR sprints

After the toggle-group structural migration `npm run check` still had
12 pre-existing errors. All from the active Words sprint (post-2026-05
F2/F3/COLOR work), not introduced by this session. Closes them to
restore green check:

- soma words.svelte: thread `onUploadImage` through the Provider opts
  (was required-undefined in WordsOpts but missing from the create()
  call).
- eidos words-toolbar-family-menu.svelte + words.svelte: add
  'insert-image' label to COMMAND_LABELS (the Record<WordsToolbarButton
  CommandName, string> required full coverage).
- eidos words.svelte: hoist the `leafItem` snippet out of <SomaWords.
  Provider> to template root level. Snippets defined INSIDE a component
  element are passed as named props in Svelte 5; this one was meant as
  a local helper. Also kills the "Expression too complex" error at the
  Provider tag — the leafItem prop was bloating the union.
- eidos words-drawer.svelte: extract 5 inline button-config arrays to
  typed `as const satisfies readonly { id: WordsCommandName; ... }[]`
  constants (FORMAT_MARKS, TEXT_ALIGN_ACTIONS, CELL_TONE_ACTIONS,
  CELL_VERTICAL_ACTIONS, CELL_TEXT_ALIGN_ACTIONS). The inline literals
  were inferring `id: string`, breaking `runCommand` and
  `activeMarks.includes`.

Result: npm run check 16 → 0 errors. Tests 658/658 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
active-uix
dev 4 months ago
parent d2f184da44
commit c250f7d790

@ -39,7 +39,9 @@
DrawerSnippetProps,
DrawerProps,
ProviderSnippetProps,
WordsDrawerMode
WordsDrawerMode,
WordsCommandName,
WordsMark
} from '$soma/components/words';
import { SvelteMap } from 'svelte/reactivity';
@ -159,6 +161,45 @@
const found = marks.find((m) => m.startsWith(`${prefix}:`));
return found ? found.slice(prefix.length + 1) : '';
}
// Typed catalogs for drawer action buttons. `as const` narrows
// `id` to its literal type so it satisfies the canonical unions
// (WordsMark for inline marks; WordsCommandName for runCommand).
// Without this, an inline array literal infers `id: string` and
// runCommand / activeMarks.includes reject the call.
const FORMAT_MARKS = [
{ id: 'bold', label: 'B', title: 'Bold' },
{ id: 'italic', label: 'I', title: 'Italic' },
{ id: 'underline', label: 'U', title: 'Underline' },
{ id: 'strike', label: 'S', title: 'Strikethrough' },
{ id: 'code', label: '<>', title: 'Inline code' }
] as const satisfies readonly { id: WordsMark & WordsCommandName; label: string; title: string }[];
const TEXT_ALIGN_ACTIONS = [
{ id: 'align-left', label: '⫷', title: 'Left' },
{ id: 'align-center', label: '☰', title: 'Center' },
{ id: 'align-right', label: '⫸', title: 'Right' },
{ id: 'align-justify', label: '☷', title: 'Justify' }
] as const satisfies readonly { id: WordsCommandName; label: string; title: string }[];
const CELL_TONE_ACTIONS = [
{ id: 'table-cell-tone-default', label: 'Plain' },
{ id: 'table-cell-tone-muted', label: 'Muted' },
{ id: 'table-cell-tone-accent', label: 'Accent' }
] as const satisfies readonly { id: WordsCommandName; label: string }[];
const CELL_VERTICAL_ACTIONS = [
{ id: 'table-cell-vertical-top', label: '⬆ Top' },
{ id: 'table-cell-vertical-middle', label: '◆ Mid' },
{ id: 'table-cell-vertical-bottom', label: '⬇ Bot' }
] as const satisfies readonly { id: WordsCommandName; label: string }[];
const CELL_TEXT_ALIGN_ACTIONS = [
{ id: 'align-left', label: '⫷' },
{ id: 'align-center', label: '☰' },
{ id: 'align-right', label: '⫸' },
{ id: 'align-justify', label: '☷' }
] as const satisfies readonly { id: WordsCommandName; label: string }[];
</script>
<Words.Drawer bind:open {defaultOpen} {disabled} {...rest} data-side={side}>
@ -356,13 +397,7 @@
{#snippet formatPanel(s: ProviderSnippetProps)}
<div data-words-drawer-actions>
{#each [
{ id: 'bold', label: 'B', title: 'Bold' },
{ id: 'italic', label: 'I', title: 'Italic' },
{ id: 'underline', label: 'U', title: 'Underline' },
{ id: 'strike', label: 'S', title: 'Strikethrough' },
{ id: 'code', label: '<>', title: 'Inline code' }
] as mark (mark.id)}
{#each FORMAT_MARKS as mark (mark.id)}
<button
type="button"
data-words-drawer-action
@ -486,12 +521,7 @@
{#snippet blockPanel(s: ProviderSnippetProps)}
<div data-words-drawer-section-subtitle>Text align</div>
<div data-words-drawer-actions>
{#each [
{ id: 'align-left', label: '⫷', title: 'Left' },
{ id: 'align-center', label: '☰', title: 'Center' },
{ id: 'align-right', label: '⫸', title: 'Right' },
{ id: 'align-justify', label: '☷', title: 'Justify' }
] as a (a.id)}
{#each TEXT_ALIGN_ACTIONS as a (a.id)}
<button
type="button"
data-words-drawer-action
@ -509,11 +539,7 @@
{#snippet cellPanel(s: ProviderSnippetProps)}
<div data-words-drawer-section-subtitle>Tone</div>
<div data-words-drawer-actions>
{#each [
{ id: 'table-cell-tone-default', label: 'Plain' },
{ id: 'table-cell-tone-muted', label: 'Muted' },
{ id: 'table-cell-tone-accent', label: 'Accent' }
] as t (t.id)}
{#each CELL_TONE_ACTIONS as t (t.id)}
<button
type="button"
data-words-drawer-action
@ -524,11 +550,7 @@
</div>
<div data-words-drawer-section-subtitle>Vertical</div>
<div data-words-drawer-actions>
{#each [
{ id: 'table-cell-vertical-top', label: '⬆ Top' },
{ id: 'table-cell-vertical-middle', label: '◆ Mid' },
{ id: 'table-cell-vertical-bottom', label: '⬇ Bot' }
] as v (v.id)}
{#each CELL_VERTICAL_ACTIONS as v (v.id)}
<button
type="button"
data-words-drawer-action
@ -539,12 +561,7 @@
</div>
<div data-words-drawer-section-subtitle>Text align</div>
<div data-words-drawer-actions>
{#each [
{ id: 'align-left', label: '⫷' },
{ id: 'align-center', label: '☰' },
{ id: 'align-right', label: '⫸' },
{ id: 'align-justify', label: '☷' }
] as a (a.id)}
{#each CELL_TEXT_ALIGN_ACTIONS as a (a.id)}
<button
type="button"
data-words-drawer-action

@ -70,6 +70,7 @@
heading: 'Heading',
quote: 'Quote',
'code-block': 'Code block',
'insert-image': 'Insert image',
'insert-table': 'Insert table',
'insert-table-row': 'Add row',
'insert-table-column': 'Add column',

@ -87,6 +87,7 @@
heading: 'Heading',
quote: 'Quote',
'code-block': 'Code block',
'insert-image': 'Insert image',
'insert-table': 'Insert table',
'insert-table-row': 'Add row',
'insert-table-column': 'Add column',
@ -258,14 +259,12 @@
}
</script>
<SomaWords.Provider
{...rest}
bind:value
bind:selection
data-size={resolvedSize}
data-variant={variant}
data-color={color}
>
<!--
`leafItem` is a LOCAL helper snippet, not a prop passed to
SomaWords.Provider. Defining it at template root level keeps it
out of the Provider's prop space (Svelte 5 routes snippets defined
INSIDE a component element to its named props).
-->
{#snippet leafItem(item: WordsToolbarLeafItemConfig, snippetProps: any)}
{#if isLinkEditorConfig(item)}
<LinkEditor />
@ -299,6 +298,14 @@
{/if}
{/snippet}
<SomaWords.Provider
{...rest}
bind:value
bind:selection
data-size={resolvedSize}
data-variant={variant}
data-color={color}
>
{#snippet children(snippetProps)}
{#if visibleToolbarGroups.length}
<Toolbar aria-label="Formatting toolbar">

@ -26,6 +26,7 @@
onValueChange,
onSelectionChange,
onValueCommit,
onUploadImage,
children,
child,
...restProps
@ -56,7 +57,8 @@
ariaLabel: readableActive(() => ariaLabel),
onValueChange: readableActive(() => onValueChange),
onSelectionChange: readableActive(() => onSelectionChange),
onValueCommit: readableActive(() => onValueCommit)
onValueCommit: readableActive(() => onValueCommit),
onUploadImage: readableActive(() => onUploadImage)
});
const mergedProps = $derived(mergeProps(restProps, state.props));

Loading…
Cancel
Save

Powered by TurnKey Linux.