Skip to content

Commit 7e9cd14

Browse files
serpentbladeclaude
andcommitted
fix(47-05): rename marks loop var mark->tick (Svelte #mark slot shadow) + regen leaves
A loop var named 'mark' shadows the '#mark' slot snippet on Svelte: the emitted {#each ... as mark} rebinds 'mark', so {@render mark()} renders the loop-item object (non-function) -> Svelte-only mount throw -> SliderMarksDemo[svelte] empty. Same bug class as embla's slide->item. Renamed the loop var to 'tick' in Slider.rozie (slot NAME stays 'mark' = public API) and regenerated all 6 leaves. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent b70ae13 commit 7e9cd14

7 files changed

Lines changed: 29 additions & 20 deletions

File tree

packages/ui/slider/packages/angular/src/Slider.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,14 @@ function __rozieAttr(v: unknown): string | null {
5959
6060
@if (normalizedMarks().length > 0) {
6161
<div class="rozie-slider-marks" aria-hidden="true">
62-
@for (mark of normalizedMarks(); track mark.value) {
63-
<div class="rozie-slider-mark" [style]="{ left: pct(mark.value) + '%' }">
62+
63+
@for (tick of normalizedMarks(); track tick.value) {
64+
<div class="rozie-slider-mark" [style]="{ left: pct(tick.value) + '%' }">
6465
@if ((markTpl ?? templates()?.['mark'])) {
65-
<ng-container *ngTemplateOutlet="(markTpl ?? templates()?.['mark']); context: { $implicit: { value: mark.value, label: mark.label, position: pct(mark.value) }, value: mark.value, label: mark.label, position: pct(mark.value) }" />
66+
<ng-container *ngTemplateOutlet="(markTpl ?? templates()?.['mark']); context: { $implicit: { value: tick.value, label: tick.label, position: pct(tick.value) }, value: tick.value, label: tick.label, position: pct(tick.value) }" />
6667
} @else {
6768
68-
<span class="rozie-slider-mark-label">{{ rozieDisplay(mark.label) }}</span>
69+
<span class="rozie-slider-mark-label">{{ rozieDisplay(tick.label) }}</span>
6970
7071
}
7172
</div>

packages/ui/slider/packages/lit/src/Slider.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,10 @@ export default class Slider extends SignalWatcher(LitElement) {
259259
260260
261261
${this.normalizedMarks().length > 0 ? html`<div class="rozie-slider-marks" aria-hidden="true" data-rozie-s-4e6f0be6>
262-
${repeat<any>(this.normalizedMarks(), (mark, _idx) => mark.value, (mark, _idx) => html`<div class="rozie-slider-mark" key=${rozieAttr(mark.value)} style=${styleMap({ left: this.pct(mark.value) + '%' })} data-rozie-s-4e6f0be6>
263-
${this.mark !== undefined ? this.mark({value: mark.value, label: mark.label, position: this.pct(mark.value)}) : html`<slot name="mark" data-rozie-params=${(() => { try { return JSON.stringify({value: mark.value, label: mark.label, position: this.pct(mark.value)}); } catch { return '{}'; } })()}>
264-
<span class="rozie-slider-mark-label" data-rozie-s-4e6f0be6>${rozieDisplay(mark.label)}</span>
262+
263+
${repeat<any>(this.normalizedMarks(), (tick, _idx) => tick.value, (tick, _idx) => html`<div class="rozie-slider-mark" key=${rozieAttr(tick.value)} style=${styleMap({ left: this.pct(tick.value) + '%' })} data-rozie-s-4e6f0be6>
264+
${this.mark !== undefined ? this.mark({value: tick.value, label: tick.label, position: this.pct(tick.value)}) : html`<slot name="mark" data-rozie-params=${(() => { try { return JSON.stringify({value: tick.value, label: tick.label, position: this.pct(tick.value)}); } catch { return '{}'; } })()}>
265+
<span class="rozie-slider-mark-label" data-rozie-s-4e6f0be6>${rozieDisplay(tick.label)}</span>
265266
</slot>`}
266267
</div>`)}
267268
</div>` : nothing}${this.showValue && !this.range ? html`<div class="rozie-slider-bubbles" aria-hidden="true" data-rozie-s-4e6f0be6>

packages/ui/slider/packages/react/src/Slider.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,9 @@ const Slider = forwardRef<SliderHandle, SliderProps>(function Slider(_props: Sli
208208

209209

210210
{(normalizedMarks().length > 0) && <div className={"rozie-slider-marks"} aria-hidden="true" data-rozie-s-4e6f0be6="">
211-
{normalizedMarks().map((mark) => <div key={mark.value} className={"rozie-slider-mark"} style={{ left: pct(mark.value) + '%' }} data-rozie-s-4e6f0be6="">
212-
{(props.renderMark ?? props.slots?.['mark']) ? ((props.renderMark ?? props.slots?.['mark']) as Function)({ value: mark.value, label: mark.label, position: pct(mark.value) }) : <span className={"rozie-slider-mark-label"} data-rozie-s-4e6f0be6="">{rozieDisplay(mark.label)}</span>}
211+
212+
{normalizedMarks().map((tick) => <div key={tick.value} className={"rozie-slider-mark"} style={{ left: pct(tick.value) + '%' }} data-rozie-s-4e6f0be6="">
213+
{(props.renderMark ?? props.slots?.['mark']) ? ((props.renderMark ?? props.slots?.['mark']) as Function)({ value: tick.value, label: tick.label, position: pct(tick.value) }) : <span className={"rozie-slider-mark-label"} data-rozie-s-4e6f0be6="">{rozieDisplay(tick.label)}</span>}
213214
</div>)}
214215
</div>}{(props.showValue && !props.range) && <div className={"rozie-slider-bubbles"} aria-hidden="true" data-rozie-s-4e6f0be6="">
215216
<div className={"rozie-slider-bubble"} style={{ left: 'var(--rozie-slider-fill-end)' }} data-rozie-s-4e6f0be6="">

packages/ui/slider/packages/solid/src/Slider.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,8 +399,9 @@ export default function Slider(_props: SliderProps): JSX.Element {
399399

400400

401401
{<Show when={normalizedMarks().length > 0}><div class={"rozie-slider-marks"} aria-hidden="true" data-rozie-s-4e6f0be6="">
402-
<For each={normalizedMarks()}>{(mark) => <div class={"rozie-slider-mark"} style={{ left: pct(mark.value) + '%' }} data-rozie-s-4e6f0be6="">
403-
{(_props.markSlot ?? _props.slots?.['mark'])?.({ value: mark.value, label: mark.label, position: pct(mark.value) }) ?? <span class={"rozie-slider-mark-label"} data-rozie-s-4e6f0be6="">{rozieDisplay(mark.label)}</span>}
402+
403+
<For each={normalizedMarks()}>{(tick) => <div class={"rozie-slider-mark"} style={{ left: pct(tick.value) + '%' }} data-rozie-s-4e6f0be6="">
404+
{(_props.markSlot ?? _props.slots?.['mark'])?.({ value: tick.value, label: tick.label, position: pct(tick.value) }) ?? <span class={"rozie-slider-mark-label"} data-rozie-s-4e6f0be6="">{rozieDisplay(tick.label)}</span>}
404405
</div>}</For>
405406
</div></Show>}{<Show when={local.showValue && !local.range}><div class={"rozie-slider-bubbles"} aria-hidden="true" data-rozie-s-4e6f0be6="">
406407
<div class={"rozie-slider-bubble"} style={{ left: 'var(--rozie-slider-fill-end)' }} data-rozie-s-4e6f0be6="">

packages/ui/slider/packages/svelte/src/Slider.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ const fillStyle = $derived.by(() => {
264264
});
265265
</script>
266266

267-
<div style={fillStyle} {...__rozieAttrs} class={["rozie-slider", { 'rozie-slider--vertical': orientation === 'vertical', 'rozie-slider--horizontal': orientation !== 'vertical', 'rozie-slider--range': range, 'rozie-slider--disabled': disabled }, (__rozieAttrs)?.class]} use:applyListeners={__rozieAttrs} data-rozie-s-4e6f0be6><div class="rozie-slider-track" aria-hidden="true" data-rozie-s-4e6f0be6><div class="rozie-slider-fill" data-rozie-s-4e6f0be6></div></div>{#if normalizedMarks().length > 0}<div class="rozie-slider-marks" aria-hidden="true" data-rozie-s-4e6f0be6>{#each normalizedMarks() as mark (mark.value)}<div class="rozie-slider-mark" style:left={pct(mark.value) + '%'} data-rozie-s-4e6f0be6>{#if mark}{@render mark({ value: mark.value, label: mark.label, position: pct(mark.value) })}{:else}<span class="rozie-slider-mark-label" data-rozie-s-4e6f0be6>{rozieDisplay(mark.label)}</span>{/if}</div>{/each}</div>{/if}{#if showValue && !range}<div class="rozie-slider-bubbles" aria-hidden="true" data-rozie-s-4e6f0be6><div class="rozie-slider-bubble" style:left={'var(--rozie-slider-fill-end)'} data-rozie-s-4e6f0be6>{#if bubble}{@render bubble({ value: singleValue() })}{:else}<span class="rozie-slider-bubble-text" data-rozie-s-4e6f0be6>{rozieDisplay(display(singleValue()))}</span>{/if}</div></div>{/if}{#if showValue && range}<div class="rozie-slider-bubbles" aria-hidden="true" data-rozie-s-4e6f0be6><div class="rozie-slider-bubble" style:left={'var(--rozie-slider-fill-start)'} data-rozie-s-4e6f0be6>{#if bubble}{@render bubble({ value: rangePair()[0] })}{:else}<span class="rozie-slider-bubble-text" data-rozie-s-4e6f0be6>{rozieDisplay(display(rangePair()[0]))}</span>{/if}</div><div class="rozie-slider-bubble" style:left={'var(--rozie-slider-fill-end)'} data-rozie-s-4e6f0be6>{#if bubble}{@render bubble({ value: rangePair()[1] })}{:else}<span class="rozie-slider-bubble-text" data-rozie-s-4e6f0be6>{rozieDisplay(display(rangePair()[1]))}</span>{/if}</div></div>{/if}{#if !range}<input bind:this={inputEl} class="rozie-slider-input" type="range" min={min} max={max} step={step} value={singleValue()} disabled={!!disabled} aria-label={ariaLabel} aria-orientation={rozieAttr(orientation === 'vertical' ? 'vertical' : 'horizontal')} aria-valuetext={rozieAttr(formatValue !== null ? display(singleValue()) : null)} oninput={($event) => { onInputSingle($event); }} onkeydown={($event) => { onKeyDownSingle($event); }} data-rozie-s-4e6f0be6 />{/if}{#if range}<input bind:this={inputEl} class="rozie-slider-input rozie-slider-input--lo" type="range" min={min} max={max} step={step} value={rangePair()[0]} disabled={!!disabled} aria-label={ariaLabel} aria-orientation={rozieAttr(orientation === 'vertical' ? 'vertical' : 'horizontal')} aria-valuetext={rozieAttr(formatValue !== null ? display(rangePair()[0]) : null)} oninput={($event) => { onInputLo($event); }} onkeydown={($event) => { onKeyDownRange('lo', $event); }} data-rozie-s-4e6f0be6 />{/if}{#if range}<input class="rozie-slider-input rozie-slider-input--hi" type="range" min={min} max={max} step={step} value={rangePair()[1]} disabled={!!disabled} aria-label={ariaLabel} aria-orientation={rozieAttr(orientation === 'vertical' ? 'vertical' : 'horizontal')} aria-valuetext={rozieAttr(formatValue !== null ? display(rangePair()[1]) : null)} oninput={($event) => { onInputHi($event); }} onkeydown={($event) => { onKeyDownRange('hi', $event); }} data-rozie-s-4e6f0be6 />{/if}</div>
267+
<div style={fillStyle} {...__rozieAttrs} class={["rozie-slider", { 'rozie-slider--vertical': orientation === 'vertical', 'rozie-slider--horizontal': orientation !== 'vertical', 'rozie-slider--range': range, 'rozie-slider--disabled': disabled }, (__rozieAttrs)?.class]} use:applyListeners={__rozieAttrs} data-rozie-s-4e6f0be6><div class="rozie-slider-track" aria-hidden="true" data-rozie-s-4e6f0be6><div class="rozie-slider-fill" data-rozie-s-4e6f0be6></div></div>{#if normalizedMarks().length > 0}<div class="rozie-slider-marks" aria-hidden="true" data-rozie-s-4e6f0be6>{#each normalizedMarks() as tick (tick.value)}<div class="rozie-slider-mark" style:left={pct(tick.value) + '%'} data-rozie-s-4e6f0be6>{#if mark}{@render mark({ value: tick.value, label: tick.label, position: pct(tick.value) })}{:else}<span class="rozie-slider-mark-label" data-rozie-s-4e6f0be6>{rozieDisplay(tick.label)}</span>{/if}</div>{/each}</div>{/if}{#if showValue && !range}<div class="rozie-slider-bubbles" aria-hidden="true" data-rozie-s-4e6f0be6><div class="rozie-slider-bubble" style:left={'var(--rozie-slider-fill-end)'} data-rozie-s-4e6f0be6>{#if bubble}{@render bubble({ value: singleValue() })}{:else}<span class="rozie-slider-bubble-text" data-rozie-s-4e6f0be6>{rozieDisplay(display(singleValue()))}</span>{/if}</div></div>{/if}{#if showValue && range}<div class="rozie-slider-bubbles" aria-hidden="true" data-rozie-s-4e6f0be6><div class="rozie-slider-bubble" style:left={'var(--rozie-slider-fill-start)'} data-rozie-s-4e6f0be6>{#if bubble}{@render bubble({ value: rangePair()[0] })}{:else}<span class="rozie-slider-bubble-text" data-rozie-s-4e6f0be6>{rozieDisplay(display(rangePair()[0]))}</span>{/if}</div><div class="rozie-slider-bubble" style:left={'var(--rozie-slider-fill-end)'} data-rozie-s-4e6f0be6>{#if bubble}{@render bubble({ value: rangePair()[1] })}{:else}<span class="rozie-slider-bubble-text" data-rozie-s-4e6f0be6>{rozieDisplay(display(rangePair()[1]))}</span>{/if}</div></div>{/if}{#if !range}<input bind:this={inputEl} class="rozie-slider-input" type="range" min={min} max={max} step={step} value={singleValue()} disabled={!!disabled} aria-label={ariaLabel} aria-orientation={rozieAttr(orientation === 'vertical' ? 'vertical' : 'horizontal')} aria-valuetext={rozieAttr(formatValue !== null ? display(singleValue()) : null)} oninput={($event) => { onInputSingle($event); }} onkeydown={($event) => { onKeyDownSingle($event); }} data-rozie-s-4e6f0be6 />{/if}{#if range}<input bind:this={inputEl} class="rozie-slider-input rozie-slider-input--lo" type="range" min={min} max={max} step={step} value={rangePair()[0]} disabled={!!disabled} aria-label={ariaLabel} aria-orientation={rozieAttr(orientation === 'vertical' ? 'vertical' : 'horizontal')} aria-valuetext={rozieAttr(formatValue !== null ? display(rangePair()[0]) : null)} oninput={($event) => { onInputLo($event); }} onkeydown={($event) => { onKeyDownRange('lo', $event); }} data-rozie-s-4e6f0be6 />{/if}{#if range}<input class="rozie-slider-input rozie-slider-input--hi" type="range" min={min} max={max} step={step} value={rangePair()[1]} disabled={!!disabled} aria-label={ariaLabel} aria-orientation={rozieAttr(orientation === 'vertical' ? 'vertical' : 'horizontal')} aria-valuetext={rozieAttr(formatValue !== null ? display(rangePair()[1]) : null)} oninput={($event) => { onInputHi($event); }} onkeydown={($event) => { onKeyDownRange('hi', $event); }} data-rozie-s-4e6f0be6 />{/if}</div>
268268

269269
<style>
270270
:global {

packages/ui/slider/packages/vue/src/Slider.vue

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88

99

1010
<div v-if="normalizedMarks().length > 0" class="rozie-slider-marks" aria-hidden="true">
11-
<div v-for="mark in normalizedMarks()" :key="mark.value" class="rozie-slider-mark" :style="{ left: pct(mark.value) + '%' }">
12-
<slot name="mark" :value="mark.value" :label="mark.label" :position="pct(mark.value)">
13-
<span class="rozie-slider-mark-label">{{ mark.label }}</span>
11+
12+
<div v-for="tick in normalizedMarks()" :key="tick.value" class="rozie-slider-mark" :style="{ left: pct(tick.value) + '%' }">
13+
<slot name="mark" :value="tick.value" :label="tick.label" :position="pct(tick.value)">
14+
<span class="rozie-slider-mark-label">{{ tick.label }}</span>
1415
</slot>
1516
</div>
1617
</div><div v-if="props.showValue && !props.range" class="rozie-slider-bubbles" aria-hidden="true">

packages/ui/slider/src/Slider.rozie

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -301,14 +301,18 @@ $expose({ focus, increment, decrement })
301301
scoped slot ({ value, label, position }) overrides the default label.
302302
Mirrors the listbox #option scoped-slot shape. -->
303303
<div r-if="normalizedMarks().length > 0" class="rozie-slider-marks" aria-hidden="true">
304+
<!-- Loop var is `tick`, NOT `mark`: a loop var named `mark` shadows the
305+
`#mark` slot snippet on Svelte (`{#each … as mark}` collides with the
306+
`mark` snippet binding → `{@render mark()}` renders a non-function →
307+
Svelte-only mount throw). Same class of bug as embla's slide→item. -->
304308
<div
305-
r-for="mark in normalizedMarks()"
306-
:key="mark.value"
309+
r-for="tick in normalizedMarks()"
310+
:key="tick.value"
307311
class="rozie-slider-mark"
308-
:style="{ left: pct(mark.value) + '%' }"
312+
:style="{ left: pct(tick.value) + '%' }"
309313
>
310-
<slot name="mark" :value="mark.value" :label="mark.label" :position="pct(mark.value)">
311-
<span class="rozie-slider-mark-label">{{ mark.label }}</span>
314+
<slot name="mark" :value="tick.value" :label="tick.label" :position="pct(tick.value)">
315+
<span class="rozie-slider-mark-label">{{ tick.label }}</span>
312316
</slot>
313317
</div>
314318
</div>

0 commit comments

Comments
 (0)