picker demos: footer composition switches + popover closed by default

Two follow-ups from user feedback:

(1) User: 'en los demos no existen para definir las propiedades y
visibilidad del pie y los botones' — after the previous refactor that
moved visibility from props to composition, the demos lost their UI
switches and there was no way to toggle the parts on/off.

Restored toggles but with the correct semantics: the switches now
decide whether each part is INCLUDED in the markup, not whether the
part renders internally. Composition first, demo UX second.

- Both demos: new state vars showFooter / showClear / showCancel /
  showClose (default all true).
- New `{#snippet pickerFooter()}` snippet that renders
  <Footer><Clear/><Cancel/><Close/></Footer> with {#if show*}
  guards on each child. Rendered once via {@render pickerFooter()}
  at the end of every calendar branch (Calendar / MonthView /
  YearView for single; the rangeCalendar for range).
- New 'footer' control row with 4 switches per demo, labelled with
  the structural intent ('compose parts inside <Footer>').

(2) User: 'el popover del calendar aparece, eso es un error' — the
previous commit defaulted open=true on both demos so the new Footer
was visible at first paint. That conflicted with the natural flow
(user expects to click the trigger to open). Reverted to open=false
by default.

Also removed the auto-reopen $effect that re-opened the popover
whenever `kind` changed. The chip click can close the popover via
outside-click in inline mode; the user re-opens deliberately. No more
magic.

Verification: 0 type errors, 67/67 component:audit PASS.

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

@ -47,7 +47,7 @@
let value = $state<DateValue | undefined>(delivery);
let valueInput = $state(toDateInput(delivery));
let placeholder = $state<DateValue>(delivery);
let open = $state(true);
let open = $state(false);
let minInput = $state(toDateInput(defaultMin));
let maxInput = $state(toDateInput(defaultMax));
let required = $state(true);
@ -56,6 +56,16 @@
let closeOnDateSelect = $state(false);
let mode = $state<'inline' | 'modal'>('inline');
let kind = $state<'date' | 'month' | 'year'>('date');
// Footer composition demo toggles. Visibility is purely structural:
// the switches decide whether each part is INCLUDED in the markup,
// not whether the part itself decides to render. Omit the part →
// nothing renders. Include it → it always renders.
let showFooter = $state(true);
let showClear = $state(true);
let showCancel = $state(true);
let showClose = $state(true);
let disableDaysOutsideMonth = $state(true);
let fixedWeeks = $state(false);
let pagedNavigation = $state(false);
@ -216,14 +226,6 @@
valueInput = value ? toDateInput(value) : '';
});
// Re-open the popover whenever the kind changes — clicking the kind
// chip is outside the popover and closes it in inline mode. The demo
// wants the new view (Calendar / MonthView / YearView) visible
// immediately so the change is observable.
$effect(() => {
void kind;
open = true;
});
$effect(() => {
const el = stageRef;
@ -467,18 +469,8 @@
<DatePicker.Content align="end" sideOffset={10} collisionPadding={12}>
{#if kind === 'year'}
<DatePicker.YearView />
<DatePicker.Footer>
<DatePicker.Clear />
<DatePicker.Cancel />
<DatePicker.Close />
</DatePicker.Footer>
{:else if kind === 'month'}
<DatePicker.MonthView />
<DatePicker.Footer>
<DatePicker.Clear />
<DatePicker.Cancel />
<DatePicker.Close />
</DatePicker.Footer>
{:else}
<DatePicker.Calendar>
{#snippet children(args: DatePickerCalendarSnippetProps)}
@ -486,6 +478,7 @@
{/snippet}
</DatePicker.Calendar>
{/if}
{@render pickerFooter()}
</DatePicker.Content>
</DatePicker.Portal>
</DatePicker>
@ -653,6 +646,31 @@
{/each}
</span>
</label>
<label data-uix-control>
<span data-uix-control-label
>footer <span data-uix-control-hint>compose parts inside &lt;Footer&gt;</span></span
>
<span data-uix-switch
><input type="checkbox" bind:checked={showFooter} /><span data-uix-switch-label
>Footer</span
></span
>
<span data-uix-switch
><input type="checkbox" bind:checked={showClear} /><span data-uix-switch-label
>Clear</span
></span
>
<span data-uix-switch
><input type="checkbox" bind:checked={showCancel} /><span data-uix-switch-label
>Cancel</span
></span
>
<span data-uix-switch
><input type="checkbox" bind:checked={showClose} /><span data-uix-switch-label
>Close</span
></span
>
</label>
<label data-uix-control>
<span data-uix-control-label>calendar behavior</span>
<span data-uix-switch><input type="checkbox" bind:checked={closeOnDateSelect} /><span data-uix-switch-label>close on select</span></span>
@ -1009,6 +1027,16 @@
{/if}
</div>
{#snippet pickerFooter()}
{#if showFooter && (showClear || showCancel || showClose)}
<DatePicker.Footer>
{#if showClear}<DatePicker.Clear />{/if}
{#if showCancel}<DatePicker.Cancel />{/if}
{#if showClose}<DatePicker.Close />{/if}
</DatePicker.Footer>
{/if}
{/snippet}
{#snippet calendarBody({ months, weekdays, validationMessage }: DatePickerCalendarSnippetProps)}
<DatePicker.Header>
<DatePicker.PrevButton aria-label="Previous month">&lt;</DatePicker.PrevButton>

@ -47,10 +47,8 @@
let stageRef = $state<HTMLElement | null>(null);
let value = $state<DateRange | undefined>({ start: sprintStart, end: sprintEnd });
let placeholder = $state<DateValue>(sprintStart);
// Popover starts open in the demo so the new Footer + segment-lock
// affordances are visible on first load. Consumers can close it via
// the Cancel/Close buttons or by clicking outside (in inline mode).
let open = $state(true);
// Popover starts closed. Consumers click the trigger icon to open.
let open = $state(false);
let startInput = $state(toDateInput(sprintStart));
let endInput = $state(toDateInput(sprintEnd));
let minInput = $state(toDateInput(defaultMin));
@ -61,6 +59,14 @@
let closeOnRangeSelect = $state(false);
let mode = $state<'inline' | 'modal'>('inline');
let kind = $state<'date' | 'month' | 'year'>('date');
// Footer composition demo toggles. Visibility = whether the part is
// INCLUDED in the markup (the parts themselves render unconditionally).
let showFooter = $state(true);
let showClear = $state(true);
let showCancel = $state(true);
let showClose = $state(true);
let disableDaysOutsideMonth = $state(true);
let fixedWeeks = $state(true);
let pagedNavigation = $state(false);
@ -714,6 +720,31 @@
{/each}
</span>
</label>
<label data-uix-control>
<span data-uix-control-label
>footer <span data-uix-control-hint>compose parts inside &lt;Footer&gt;</span></span
>
<span data-uix-switch
><input type="checkbox" bind:checked={showFooter} /><span data-uix-switch-label
>Footer</span
></span
>
<span data-uix-switch
><input type="checkbox" bind:checked={showClear} /><span data-uix-switch-label
>Clear</span
></span
>
<span data-uix-switch
><input type="checkbox" bind:checked={showCancel} /><span data-uix-switch-label
>Cancel</span
></span
>
<span data-uix-switch
><input type="checkbox" bind:checked={showClose} /><span data-uix-switch-label
>Close</span
></span
>
</label>
<label data-uix-control>
<span data-uix-control-label>states</span>
<span data-uix-switch><input type="checkbox" bind:checked={required} /><span data-uix-switch-label>required</span></span>
@ -1051,11 +1082,17 @@
</div>
{/each}
</div>
<DateRangePicker.Footer>
<DateRangePicker.Clear />
<DateRangePicker.Cancel />
<DateRangePicker.Close />
</DateRangePicker.Footer>
{@render pickerFooter()}
{/snippet}
{#snippet pickerFooter()}
{#if showFooter && (showClear || showCancel || showClose)}
<DateRangePicker.Footer>
{#if showClear}<DateRangePicker.Clear />{/if}
{#if showCancel}<DateRangePicker.Cancel />{/if}
{#if showClose}<DateRangePicker.Close />{/if}
</DateRangePicker.Footer>
{/if}
{/snippet}
<style>

Loading…
Cancel
Save

Powered by TurnKey Linux.