Skip to content

Commit a5e2e98

Browse files
serpentbladeclaude
andcommitted
fix(quick-260622-let): coerce EditorSelect value binding to string for strict tsc
- [Rule 1 - Bug] strict bundled-leaf tsc rejected :value="$props.value" (typed unknown) against the native <select> value type on React+Solid (TS2322). The .rozie-native fix is a plain selectValue() function returning a String — uniform x6, not a $computed (which can't be aliased). - regenerated only the 6 EditorSelect leaves; DataTable/Column/other editors byte-identical; compile-check still 30/30 clean, r.css empty - found during Task 3 typecheck gate Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011JE6gykywo57CcqUJZTsB9
1 parent a8d7e26 commit a5e2e98

7 files changed

Lines changed: 47 additions & 7 deletions

File tree

packages/ui/data-table/packages/angular/src/EditorSelect.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function __rozieAttr(v: unknown): string | null {
2525
standalone: true,
2626
template: `
2727
28-
<select class="rdt-cell-editor" data-editing-cell="" [attr.aria-label]="columnId()" [value]="value()" (change)="onChange($event)" (keydown)="onKeydown($event)">
28+
<select class="rdt-cell-editor" data-editing-cell="" [attr.aria-label]="columnId()" [value]="selectValue()" (change)="onChange($event)" (keydown)="onKeydown($event)">
2929
@for (opt of options(); track opt.value) {
3030
<option [attr.value]="rozieAttr(opt.value)">{{ rozieDisplay(opt.label) }}</option>
3131
}
@@ -42,6 +42,7 @@ export class EditorSelect {
4242
cancel = input<((...args: unknown[]) => unknown) | null>(null);
4343
options = input<any[]>((() => [])());
4444

45+
selectValue = () => this.value() != null ? String(this.value()) : '';
4546
onChange = (e: any) => {
4647
const __commit = this.commit();
4748
__commit && __commit(e && e.target ? e.target.value : '');

packages/ui/data-table/packages/lit/src/EditorSelect.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,14 @@ export default class EditorSelect extends SignalWatcher(LitElement) {
3131

3232
render() {
3333
return html`
34-
<select class="rdt-cell-editor" data-editing-cell="" aria-label=${this.columnId} .value=${this.value} @change=${($event: Event) => { this.onChange($event); }} @keydown=${($event: Event) => { this.onKeydown($event); }} data-rozie-s-117f1a16>
34+
<select class="rdt-cell-editor" data-editing-cell="" aria-label=${this.columnId} .value=${this.selectValue()} @change=${($event: Event) => { this.onChange($event); }} @keydown=${($event: Event) => { this.onKeydown($event); }} data-rozie-s-117f1a16>
3535
${repeat<any>(this.options, (opt, _idx) => opt.value, (opt, _idx) => html`<option key=${rozieAttr(opt.value)} value=${rozieAttr(opt.value)} data-rozie-s-117f1a16>${rozieDisplay(opt.label)}</option>`)}
3636
</select>
3737
`;
3838
}
3939

40+
selectValue = () => this.value != null ? String(this.value) : '';
41+
4042
onChange = (e: any) => {
4143
this.commit && this.commit(e && e.target ? e.target.value : '');
4244
};

packages/ui/data-table/packages/react/src/EditorSelect.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ export default function EditorSelect(_props: EditorSelectProps): JSX.Element {
2424
options: _props.options ?? __defaultOptions,
2525
};
2626

27+
function selectValue() {
28+
return props.value != null ? String(props.value) : '';
29+
}
2730
const { commit: _rozieProp_commit } = props;
2831
const onChange = useCallback((e: any) => {
2932
_rozieProp_commit && _rozieProp_commit(e && e.target ? e.target.value : '');
@@ -38,7 +41,7 @@ export default function EditorSelect(_props: EditorSelectProps): JSX.Element {
3841

3942
return (
4043
<>
41-
<select className={"rdt-cell-editor"} data-editing-cell="" aria-label={props.columnId} value={props.value} onChange={($event) => { onChange($event); }} onKeyDown={($event) => { onKeydown($event); }} data-rozie-s-117f1a16="">
44+
<select className={"rdt-cell-editor"} data-editing-cell="" aria-label={props.columnId} value={selectValue()} onChange={($event) => { onChange($event); }} onKeyDown={($event) => { onKeydown($event); }} data-rozie-s-117f1a16="">
4245
{props.options.map((opt) => <option key={opt.value} value={rozieAttr(opt.value)} data-rozie-s-117f1a16="">{rozieDisplay(opt.label)}</option>)}
4346
</select>
4447
</>

packages/ui/data-table/packages/solid/src/EditorSelect.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ export default function EditorSelect(_props: EditorSelectProps): JSX.Element {
1616
const _merged = mergeProps({ columnId: '', column: null, row: null, value: null, commit: null, cancel: null, options: (() => [])() }, _props);
1717
const [local, attrs] = splitProps(_merged, ['columnId', 'column', 'row', 'value', 'commit', 'cancel', 'options']);
1818

19+
// The <select> value binding coerced to a string. $props.value is typed `unknown`
20+
// (opaque slot-scope), which the strict bundled-leaf tsc rejects against the
21+
// native select `value` type (string | number | string[]) on React/Solid — the
22+
// .rozie-native fix is a plain function returning a string (uniform ×6, NOT a
23+
// $computed which can't be aliased; the listbox value-vs-accessor lesson).
24+
function selectValue() {
25+
return local.value != null ? String(local.value) : '';
26+
}
27+
1928
// Immediate-commit-on-change: read the selected value the global-filter way and
2029
// commit it directly (no draft needed for a single-gesture select).
2130
function onChange(e: any) {
@@ -30,7 +39,7 @@ export default function EditorSelect(_props: EditorSelectProps): JSX.Element {
3039

3140
return (
3241
<>
33-
<select data-editing-cell="" aria-label={local.columnId} class={"rdt-cell-editor"} value={local.value} onChange={($event) => { onChange($event); }} onKeyDown={($event) => { onKeydown($event); }} data-rozie-s-117f1a16="">
42+
<select data-editing-cell="" aria-label={local.columnId} class={"rdt-cell-editor"} value={selectValue()} onChange={($event) => { onChange($event); }} onKeyDown={($event) => { onKeydown($event); }} data-rozie-s-117f1a16="">
3443
<For each={local.options}>{(opt) => <option value={rozieAttr(opt.value)} data-rozie-s-117f1a16="">{rozieDisplay(opt.label)}</option>}</For>
3544
</select>
3645
</>

packages/ui/data-table/packages/svelte/src/EditorSelect.svelte

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ let {
2323
options = __defaultOptions
2424
}: Props = $props();
2525
26+
// The <select> value binding coerced to a string. $props.value is typed `unknown`
27+
// (opaque slot-scope), which the strict bundled-leaf tsc rejects against the
28+
// native select `value` type (string | number | string[]) on React/Solid — the
29+
// .rozie-native fix is a plain function returning a string (uniform ×6, NOT a
30+
// $computed which can't be aliased; the listbox value-vs-accessor lesson).
31+
const selectValue = () => value != null ? String(value) : '';
32+
33+
// Immediate-commit-on-change: read the selected value the global-filter way and
34+
// commit it directly (no draft needed for a single-gesture select).
2635
// Immediate-commit-on-change: read the selected value the global-filter way and
2736
// commit it directly (no draft needed for a single-gesture select).
2837
const onChange = (e: any) => {
@@ -36,4 +45,4 @@ const onKeydown = (e: any) => {
3645
};
3746
</script>
3847

39-
<select class="rdt-cell-editor" data-editing-cell="" aria-label={columnId} value={rozieAttr(value)} onchange={($event) => { onChange($event); }} onkeydown={($event) => { onKeydown($event); }} data-rozie-s-117f1a16>{#each options as opt (opt.value)}<option value={rozieAttr(opt.value)} data-rozie-s-117f1a16>{rozieDisplay(opt.label)}</option>{/each}</select>
48+
<select class="rdt-cell-editor" data-editing-cell="" aria-label={columnId} value={rozieAttr(selectValue())} onchange={($event) => { onChange($event); }} onkeydown={($event) => { onKeydown($event); }} data-rozie-s-117f1a16>{#each options as opt (opt.value)}<option value={rozieAttr(opt.value)} data-rozie-s-117f1a16>{rozieDisplay(opt.label)}</option>{/each}</select>

packages/ui/data-table/packages/vue/src/EditorSelect.vue

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22

3-
<select class="rdt-cell-editor" data-editing-cell="" :aria-label="props.columnId" :value="props.value" @change="onChange($event)" @keydown="onKeydown($event)">
3+
<select class="rdt-cell-editor" data-editing-cell="" :aria-label="props.columnId" :value="selectValue()" @change="onChange($event)" @keydown="onKeydown($event)">
44
<option v-for="opt in props.options" :key="opt.value" :value="opt.value">{{ opt.label }}</option>
55
</select>
66

@@ -12,6 +12,15 @@ const props = withDefaults(
1212
{ columnId: '', column: null, row: null, value: null, commit: null, cancel: null, options: () => [] }
1313
);
1414
15+
// The <select> value binding coerced to a string. $props.value is typed `unknown`
16+
// (opaque slot-scope), which the strict bundled-leaf tsc rejects against the
17+
// native select `value` type (string | number | string[]) on React/Solid — the
18+
// .rozie-native fix is a plain function returning a string (uniform ×6, NOT a
19+
// $computed which can't be aliased; the listbox value-vs-accessor lesson).
20+
const selectValue = () => props.value != null ? String(props.value) : '';
21+
22+
// Immediate-commit-on-change: read the selected value the global-filter way and
23+
// commit it directly (no draft needed for a single-gesture select).
1524
// Immediate-commit-on-change: read the selected value the global-filter way and
1625
// commit it directly (no draft needed for a single-gesture select).
1726
const onChange = (e: any) => {

packages/ui/data-table/src/EditorSelect.rozie

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@
2828
</props>
2929

3030
<script lang="ts">
31+
// The <select> value binding coerced to a string. $props.value is typed `unknown`
32+
// (opaque slot-scope), which the strict bundled-leaf tsc rejects against the
33+
// native select `value` type (string | number | string[]) on React/Solid — the
34+
// .rozie-native fix is a plain function returning a string (uniform ×6, NOT a
35+
// $computed which can't be aliased; the listbox value-vs-accessor lesson).
36+
const selectValue = () => ($props.value != null ? String($props.value) : '')
37+
3138
// Immediate-commit-on-change: read the selected value the global-filter way and
3239
// commit it directly (no draft needed for a single-gesture select).
3340
const onChange = (e) => {
@@ -47,7 +54,7 @@ const onKeydown = (e) => {
4754
class="rdt-cell-editor"
4855
data-editing-cell
4956
:aria-label="$props.columnId"
50-
:value="$props.value"
57+
:value="selectValue()"
5158
@change="onChange($event)"
5259
@keydown="onKeydown($event)"
5360
>

0 commit comments

Comments
 (0)