diff --git a/src/uix/eidos/components/date-picker/date-picker-cancel.svelte b/src/uix/eidos/components/date-picker/date-picker-cancel.svelte
deleted file mode 100644
index 8d0853bab..000000000
--- a/src/uix/eidos/components/date-picker/date-picker-cancel.svelte
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
diff --git a/src/uix/eidos/components/date-picker/date-picker-clear.svelte b/src/uix/eidos/components/date-picker/date-picker-clear.svelte
deleted file mode 100644
index 88c29dd26..000000000
--- a/src/uix/eidos/components/date-picker/date-picker-clear.svelte
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
diff --git a/src/uix/eidos/components/date-picker/date-picker-close.svelte b/src/uix/eidos/components/date-picker/date-picker-close.svelte
deleted file mode 100644
index bd6345769..000000000
--- a/src/uix/eidos/components/date-picker/date-picker-close.svelte
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
diff --git a/src/uix/eidos/components/date-picker/date-picker-footer.svelte b/src/uix/eidos/components/date-picker/date-picker-footer.svelte
deleted file mode 100644
index 5116662ab..000000000
--- a/src/uix/eidos/components/date-picker/date-picker-footer.svelte
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
- {@render children?.()}
-
diff --git a/src/uix/eidos/components/date-picker/date-picker.css b/src/uix/eidos/components/date-picker/date-picker.css
index 6c0785c98..0773594f6 100644
--- a/src/uix/eidos/components/date-picker/date-picker.css
+++ b/src/uix/eidos/components/date-picker/date-picker.css
@@ -185,63 +185,6 @@
border-color: transparent;
}
-/* ── Footer (Clear / Cancel / Close action row) ──────────────────────────── */
-
-[data-date-picker-footer] {
- display: flex;
- align-items: center;
- gap: var(--space-2);
- padding-block-start: var(--space-3);
- margin-block-start: var(--space-3);
- border-block-start: var(--border-width) solid var(--color-border-subtle);
-}
-
-[data-date-picker-clear],
-[data-date-picker-cancel] {
- margin-inline-end: auto;
-}
-
-[data-date-picker-clear],
-[data-date-picker-cancel],
-[data-date-picker-close] {
- inline-size: max-content;
- min-block-size: var(--control-height-sm);
- padding-inline: var(--space-3);
- border-radius: var(--radius-md);
- border: var(--border-width) solid transparent;
- background: transparent;
- color: var(--color-content-primary);
- font: inherit;
- font-size: var(--font-size-sm);
- line-height: var(--leading-ui);
- cursor: pointer;
- transition:
- background var(--duration-fast) var(--ease-default),
- border-color var(--duration-fast) var(--ease-default),
- color var(--duration-fast) var(--ease-default);
-}
-
-[data-date-picker-clear]:hover,
-[data-date-picker-cancel]:hover {
- background: var(--color-surface-overlay);
-}
-
-[data-date-picker-close] {
- border-color: var(--color-primary-border);
- background: var(--color-primary-solid);
- color: var(--color-content-on-solid);
-}
-
-[data-date-picker-close]:hover {
- background: var(--color-primary-solid-hover);
-}
-
-[data-date-picker-clear]:focus-visible,
-[data-date-picker-cancel]:focus-visible,
-[data-date-picker-close]:focus-visible {
- outline: var(--focus-ring-width) solid var(--color-primary-border);
- outline-offset: var(--focus-ring-offset);
-}
/* ── Year-view + Month-view (kind='year' / 'month') ──────────────────────── */
@@ -333,11 +276,6 @@
[data-date-picker-trigger] {
transition: none;
}
- [data-date-picker-clear],
- [data-date-picker-cancel],
- [data-date-picker-close] {
- transition: none;
- }
[data-date-picker-year-view-cell],
[data-date-picker-month-view-cell] {
transition: none;
diff --git a/src/uix/eidos/components/date-picker/index.ts b/src/uix/eidos/components/date-picker/index.ts
index 4a55489e1..d047cbd30 100644
--- a/src/uix/eidos/components/date-picker/index.ts
+++ b/src/uix/eidos/components/date-picker/index.ts
@@ -2,10 +2,14 @@ import DatePickerComponent from './date-picker.svelte';
import Trigger from './date-picker-trigger.svelte';
import Content from './date-picker-content.svelte';
import Calendar from './date-picker-calendar.svelte';
-import Footer from './date-picker-footer.svelte';
-import Clear from './date-picker-clear.svelte';
-import Cancel from './date-picker-cancel.svelte';
-import Close from './date-picker-close.svelte';
+// PickerShell parts — shared by every composite picker. Re-exported
+// under the DatePicker namespace so `` keeps working. The shell parts read `commit/cancel/clear`
+// off the picker via `pickerShellContext`.
+import Footer from '../picker-shell/picker-shell-footer.svelte';
+import Clear from '../picker-shell/picker-shell-clear.svelte';
+import Cancel from '../picker-shell/picker-shell-cancel.svelte';
+import Close from '../picker-shell/picker-shell-close.svelte';
import YearView from './date-picker-year-view.svelte';
import MonthView from './date-picker-month-view.svelte';
import Label from '../date-field/date-field-label.svelte';
diff --git a/src/uix/eidos/components/date-picker/types.ts b/src/uix/eidos/components/date-picker/types.ts
index 144b2d8dc..8f7fe3fe8 100644
--- a/src/uix/eidos/components/date-picker/types.ts
+++ b/src/uix/eidos/components/date-picker/types.ts
@@ -2,7 +2,6 @@ import type {
ArrowProps as SomaDatePickerArrowProps,
CalendarProps as SomaDatePickerCalendarProps,
CalendarSnippetProps as DatePickerCalendarSnippetProps,
- CloseProps as SomaDatePickerCloseProps,
InputProps as SomaDatePickerInputProps,
InputSnippetProps as DatePickerInputSnippetProps,
LabelProps as SomaDatePickerLabelProps,
@@ -10,6 +9,12 @@ import type {
SegmentProps as SomaDatePickerSegmentProps,
TriggerProps as SomaDatePickerTriggerProps
} from '$soma/components/date-picker';
+import type {
+ FooterProps as PickerShellFooterProps,
+ ClearProps as PickerShellClearProps,
+ CancelProps as PickerShellCancelProps,
+ CloseProps as PickerShellCloseProps
+} from '../picker-shell';
import type {
PopoverAnchorProps,
PopoverContentProps,
@@ -78,7 +83,12 @@ export type DatePickerHiddenInputProps = Record;
export type DatePickerAnchorProps = PopoverAnchorProps;
export type DatePickerOverlayProps = PopoverOverlayProps;
export type DatePickerArrowProps = SomaDatePickerArrowProps;
-export type DatePickerCloseProps = SomaDatePickerCloseProps;
+
+// PickerShell action-row props.
+export type DatePickerFooterProps = PickerShellFooterProps;
+export type DatePickerClearProps = PickerShellClearProps;
+export type DatePickerCancelProps = PickerShellCancelProps;
+export type DatePickerCloseProps = PickerShellCloseProps;
export type DatePickerHeaderProps = EidosCalendarHeaderProps;
export type DatePickerHeadingProps = EidosCalendarHeadingProps;
diff --git a/src/uix/eidos/components/date-range-picker/date-range-picker-cancel.svelte b/src/uix/eidos/components/date-range-picker/date-range-picker-cancel.svelte
deleted file mode 100644
index 854c828c6..000000000
--- a/src/uix/eidos/components/date-range-picker/date-range-picker-cancel.svelte
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
diff --git a/src/uix/eidos/components/date-range-picker/date-range-picker-clear.svelte b/src/uix/eidos/components/date-range-picker/date-range-picker-clear.svelte
deleted file mode 100644
index f44831922..000000000
--- a/src/uix/eidos/components/date-range-picker/date-range-picker-clear.svelte
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
diff --git a/src/uix/eidos/components/date-range-picker/date-range-picker-close.svelte b/src/uix/eidos/components/date-range-picker/date-range-picker-close.svelte
deleted file mode 100644
index e2ccfc744..000000000
--- a/src/uix/eidos/components/date-range-picker/date-range-picker-close.svelte
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
diff --git a/src/uix/eidos/components/date-range-picker/date-range-picker-footer.svelte b/src/uix/eidos/components/date-range-picker/date-range-picker-footer.svelte
deleted file mode 100644
index f99585302..000000000
--- a/src/uix/eidos/components/date-range-picker/date-range-picker-footer.svelte
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
- {@render children?.()}
-
diff --git a/src/uix/eidos/components/date-range-picker/date-range-picker.css b/src/uix/eidos/components/date-range-picker/date-range-picker.css
index e02cfa4f2..7e07ce22d 100644
--- a/src/uix/eidos/components/date-range-picker/date-range-picker.css
+++ b/src/uix/eidos/components/date-range-picker/date-range-picker.css
@@ -933,63 +933,6 @@
outline-offset: var(--focus-ring-offset);
}
-/* ── Footer (Clear / Cancel / Close action row) ──────────────────────────── */
-
-[data-date-range-picker-footer] {
- display: flex;
- align-items: center;
- gap: var(--space-2);
- padding-block-start: var(--space-3);
- margin-block-start: var(--space-3);
- border-block-start: var(--border-width) solid var(--color-border-subtle);
-}
-
-[data-date-range-picker-clear],
-[data-date-range-picker-cancel] {
- margin-inline-end: auto;
-}
-
-[data-date-range-picker-clear],
-[data-date-range-picker-cancel],
-[data-date-range-picker-close] {
- inline-size: max-content;
- min-block-size: var(--control-height-sm);
- padding-inline: var(--space-3);
- border-radius: var(--radius-md);
- border: var(--border-width) solid transparent;
- background: transparent;
- color: var(--color-content-primary);
- font: inherit;
- font-size: var(--font-size-sm);
- line-height: var(--leading-ui);
- cursor: pointer;
- transition:
- background var(--duration-fast) var(--ease-default),
- border-color var(--duration-fast) var(--ease-default),
- color var(--duration-fast) var(--ease-default);
-}
-
-[data-date-range-picker-clear]:hover,
-[data-date-range-picker-cancel]:hover {
- background: var(--color-surface-overlay);
-}
-
-[data-date-range-picker-close] {
- border-color: var(--color-primary-border);
- background: var(--color-primary-solid);
- color: var(--color-content-on-solid);
-}
-
-[data-date-range-picker-close]:hover {
- background: var(--color-primary-solid-hover);
-}
-
-[data-date-range-picker-clear]:focus-visible,
-[data-date-range-picker-cancel]:focus-visible,
-[data-date-range-picker-close]:focus-visible {
- outline: var(--focus-ring-width) solid var(--color-primary-border);
- outline-offset: var(--focus-ring-offset);
-}
@media (prefers-reduced-motion: reduce) {
[data-date-range-picker-trigger],
@@ -999,10 +942,7 @@
[data-range-calendar-next-button],
[data-range-calendar-month-select],
[data-range-calendar-year-select],
- [data-range-calendar-day],
- [data-date-range-picker-clear],
- [data-date-range-picker-cancel],
- [data-date-range-picker-close] {
+ [data-range-calendar-day] {
transition: none;
}
}
diff --git a/src/uix/eidos/components/date-range-picker/index.ts b/src/uix/eidos/components/date-range-picker/index.ts
index d1447437e..b21631fdb 100644
--- a/src/uix/eidos/components/date-range-picker/index.ts
+++ b/src/uix/eidos/components/date-range-picker/index.ts
@@ -8,12 +8,13 @@ import Segment from './date-range-picker-segment.svelte';
import Anchor from '../popover/popover-anchor.svelte';
import Overlay from '../popover/popover-overlay.svelte';
import Arrow from '../popover/popover-arrow.svelte';
-import Close from './date-range-picker-close.svelte';
-import Footer from './date-range-picker-footer.svelte';
+// PickerShell parts — shared by every composite picker.
+import Footer from '../picker-shell/picker-shell-footer.svelte';
+import Clear from '../picker-shell/picker-shell-clear.svelte';
+import Cancel from '../picker-shell/picker-shell-cancel.svelte';
+import Close from '../picker-shell/picker-shell-close.svelte';
import YearView from './date-range-picker-year-view.svelte';
import MonthView from './date-range-picker-month-view.svelte';
-import Clear from './date-range-picker-clear.svelte';
-import Cancel from './date-range-picker-cancel.svelte';
import Header from './date-range-picker-header.svelte';
import Heading from './date-range-picker-heading.svelte';
import PrevButton from './date-range-picker-prev-button.svelte';
diff --git a/src/uix/eidos/components/date-range-picker/types.ts b/src/uix/eidos/components/date-range-picker/types.ts
index 3a5eb0462..2b2702145 100644
--- a/src/uix/eidos/components/date-range-picker/types.ts
+++ b/src/uix/eidos/components/date-range-picker/types.ts
@@ -2,7 +2,6 @@ import type {
ArrowProps as SomaDateRangePickerArrowProps,
CalendarProps as SomaDateRangePickerCalendarProps,
CalendarSnippetProps as SomaDateRangePickerCalendarSnippetProps,
- CloseProps as SomaDateRangePickerCloseProps,
GridBodyProps as SomaDateRangePickerGridBodyProps,
GridHeadProps as SomaDateRangePickerGridHeadProps,
GridProps as SomaDateRangePickerGridProps,
@@ -76,7 +75,14 @@ export type DateRangePickerSegmentProps = SomaDateRangePickerSegmentProps;
export type DateRangePickerAnchorProps = PopoverAnchorProps;
export type DateRangePickerOverlayProps = PopoverOverlayProps;
export type DateRangePickerArrowProps = SomaDateRangePickerArrowProps;
-export type DateRangePickerCloseProps = SomaDateRangePickerCloseProps;
+
+// PickerShell action-row props — Footer/Clear/Cancel/Close are shared.
+export type {
+ FooterProps as DateRangePickerFooterProps,
+ ClearProps as DateRangePickerClearProps,
+ CancelProps as DateRangePickerCancelProps,
+ CloseProps as DateRangePickerCloseProps
+} from '../picker-shell';
export type DateRangePickerHeaderProps = SomaDateRangePickerHeaderProps;
export type DateRangePickerHeadingProps = SomaDateRangePickerHeadingProps;
diff --git a/src/uix/eidos/components/time-picker/index.ts b/src/uix/eidos/components/time-picker/index.ts
index b5a1f117f..d94c22e44 100644
--- a/src/uix/eidos/components/time-picker/index.ts
+++ b/src/uix/eidos/components/time-picker/index.ts
@@ -2,10 +2,11 @@ import TimePickerComponent from './time-picker.svelte'
import Trigger from './time-picker-trigger.svelte'
import Content from './time-picker-content.svelte'
import Clock from './time-picker-clock.svelte'
-import Footer from './time-picker-footer.svelte'
-import Clear from './time-picker-clear.svelte'
-import Cancel from './time-picker-cancel.svelte'
-import Close from './time-picker-close.svelte'
+// PickerShell parts — shared by every composite picker.
+import Footer from '../picker-shell/picker-shell-footer.svelte'
+import Clear from '../picker-shell/picker-shell-clear.svelte'
+import Cancel from '../picker-shell/picker-shell-cancel.svelte'
+import Close from '../picker-shell/picker-shell-close.svelte'
import HourSlider from './time-picker-hour-slider.svelte'
import MinuteSlider from './time-picker-minute-slider.svelte'
import SecondSlider from './time-picker-second-slider.svelte'
diff --git a/src/uix/eidos/components/time-picker/time-picker-cancel.svelte b/src/uix/eidos/components/time-picker/time-picker-cancel.svelte
deleted file mode 100644
index 6fcd4a20c..000000000
--- a/src/uix/eidos/components/time-picker/time-picker-cancel.svelte
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
diff --git a/src/uix/eidos/components/time-picker/time-picker-clear.svelte b/src/uix/eidos/components/time-picker/time-picker-clear.svelte
deleted file mode 100644
index 19d021c08..000000000
--- a/src/uix/eidos/components/time-picker/time-picker-clear.svelte
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
diff --git a/src/uix/eidos/components/time-picker/time-picker-close.svelte b/src/uix/eidos/components/time-picker/time-picker-close.svelte
deleted file mode 100644
index b50431f19..000000000
--- a/src/uix/eidos/components/time-picker/time-picker-close.svelte
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
diff --git a/src/uix/eidos/components/time-picker/time-picker-footer.svelte b/src/uix/eidos/components/time-picker/time-picker-footer.svelte
deleted file mode 100644
index 13ef5e13e..000000000
--- a/src/uix/eidos/components/time-picker/time-picker-footer.svelte
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
- {@render children?.()}
-
diff --git a/src/uix/eidos/components/time-picker/time-picker.css b/src/uix/eidos/components/time-picker/time-picker.css
index 4d3212edd..650341a60 100644
--- a/src/uix/eidos/components/time-picker/time-picker.css
+++ b/src/uix/eidos/components/time-picker/time-picker.css
@@ -246,69 +246,9 @@
background: var(--_time-field-accent-border);
}
-/* ── Footer (Clear / Cancel / Close action row) ──────────────────────────── */
-
-[data-time-picker-footer] {
- display: flex;
- align-items: center;
- gap: var(--space-2);
- padding-block-start: var(--space-3);
- margin-block-start: var(--space-3);
- border-block-start: var(--border-width) solid var(--color-border-subtle);
-}
-
-[data-time-picker-clear],
-[data-time-picker-cancel] {
- margin-inline-end: auto;
-}
-
-[data-time-picker-clear],
-[data-time-picker-cancel],
-[data-time-picker-close] {
- inline-size: max-content;
- min-block-size: var(--control-height-sm);
- padding-inline: var(--space-3);
- border-radius: var(--radius-md);
- border: var(--border-width) solid transparent;
- background: transparent;
- color: var(--color-content-primary);
- font: inherit;
- font-size: var(--font-size-sm);
- line-height: var(--leading-ui);
- cursor: pointer;
- transition:
- background var(--duration-fast) var(--ease-default),
- border-color var(--duration-fast) var(--ease-default),
- color var(--duration-fast) var(--ease-default);
-}
-
-[data-time-picker-clear]:hover,
-[data-time-picker-cancel]:hover {
- background: var(--color-surface-overlay);
-}
-
-[data-time-picker-close] {
- border-color: var(--color-primary-border);
- background: var(--color-primary-solid);
- color: var(--color-content-on-solid);
-}
-
-[data-time-picker-close]:hover {
- background: var(--color-primary-solid-hover);
-}
-
-[data-time-picker-clear]:focus-visible,
-[data-time-picker-cancel]:focus-visible,
-[data-time-picker-close]:focus-visible {
- outline: var(--focus-ring-width) solid var(--color-primary-border);
- outline-offset: var(--focus-ring-offset);
-}
@media (prefers-reduced-motion: reduce) {
- [data-time-picker-trigger],
- [data-time-picker-clear],
- [data-time-picker-cancel],
- [data-time-picker-close] {
+ [data-time-picker-trigger] {
transition: none;
}
}
diff --git a/src/uix/eidos/components/time-picker/types.ts b/src/uix/eidos/components/time-picker/types.ts
index a6cb97660..a98d0c145 100644
--- a/src/uix/eidos/components/time-picker/types.ts
+++ b/src/uix/eidos/components/time-picker/types.ts
@@ -20,7 +20,6 @@ import type {
} from '../popover/types'
import type { ColorRole, ControlVariant, ResponsiveProp, Size } from '$uix/eidos/lib/types'
import type { Snippet } from 'svelte'
-import type { HTMLButtonAttributes } from 'svelte/elements'
export type TimePickerSize = Extract
export type TimePickerVariant = ControlVariant
@@ -60,24 +59,13 @@ export type TimePickerClockProps = {
children?: Snippet
}
-export type TimePickerFooterProps = {
- id?: string
- class?: string
- style?: string
- children?: Snippet
-}
-
-export type TimePickerClearProps = HTMLButtonAttributes & {
- children?: Snippet
-}
-
-export type TimePickerCancelProps = HTMLButtonAttributes & {
- children?: Snippet
-}
-
-export type TimePickerCloseProps = HTMLButtonAttributes & {
- children?: Snippet
-}
+// PickerShell action-row props — Footer/Clear/Cancel/Close are shared.
+export type {
+ FooterProps as TimePickerFooterProps,
+ ClearProps as TimePickerClearProps,
+ CancelProps as TimePickerCancelProps,
+ CloseProps as TimePickerCloseProps
+} from '../picker-shell'
export type TimePickerLabelProps = SomaTimePickerLabelProps
export type TimePickerInputProps = SomaTimePickerInputProps
diff --git a/src/uix/morfo/components/date-picker.ts b/src/uix/morfo/components/date-picker.ts
index 461c86da6..5a53c1555 100644
--- a/src/uix/morfo/components/date-picker.ts
+++ b/src/uix/morfo/components/date-picker.ts
@@ -231,78 +231,11 @@ export const datePickerMorfo = {
{ key: 'Tab', action: 'focus-next' },
{ key: 'Shift+Tab', action: 'focus-prev' }
]
- },
- {
- // Optional footer rendered inside the Calendar. Visibility is owned
- // by the consumer (`clearButton`/`cancelButton`/`closeButton` props
- // on the root). In `mode='modal'` the Close affordance is forced on.
- name: 'Footer',
- kebab: 'footer',
- archetype: 'footer',
- kind: 'public',
- defaultElement: 'div',
- optional: true,
- data: [{ attr: 'data-mode', values: ['inline', 'modal'], severity: 'optional' }],
- aria: []
- },
- {
- // Clear action — resets value to undefined, keeps the popover open.
- name: 'Clear',
- kebab: 'clear',
- archetype: 'trigger',
- kind: 'public',
- defaultElement: 'button',
- role: 'button',
- optional: true,
- data: [{ attr: 'data-action', value: v.literal('clear') }],
- aria: [
- { attr: 'type', value: v.literal('button') },
- {
- attr: 'aria-label',
- value: v.translationRef('#?components.date-picker.clear|Clear date'),
- severity: 'recommended'
- }
- ]
- },
- {
- // Cancel action — reverts to the value snapshot taken on open, closes.
- name: 'Cancel',
- kebab: 'cancel',
- archetype: 'trigger',
- kind: 'public',
- defaultElement: 'button',
- role: 'button',
- optional: true,
- data: [{ attr: 'data-action', value: v.literal('cancel') }],
- aria: [
- { attr: 'type', value: v.literal('button') },
- {
- attr: 'aria-label',
- value: v.translationRef('#?components.date-picker.cancel|Cancel'),
- severity: 'recommended'
- }
- ]
- },
- {
- // Close / Save action — commits current value and closes. In modal
- // mode this is the only affordance to exit (outside-click + Escape
- // are intentionally blocked).
- name: 'Close',
- kebab: 'close',
- archetype: 'trigger',
- kind: 'public',
- defaultElement: 'button',
- role: 'button',
- optional: true,
- data: [{ attr: 'data-action', value: v.literal('close') }],
- aria: [
- { attr: 'type', value: v.literal('button') },
- {
- attr: 'aria-label',
- value: v.translationRef('#?components.date-picker.close|Close'),
- severity: 'recommended'
- }
- ]
}
+ // Footer / Clear / Cancel / Close — declared by the shared
+ // `picker-shell` (Eidos ``).
+ // Their data-attrs are `[data-picker-footer/clear/cancel/close]`
+ // (no per-picker prefix). The audit / runtime won't find them in
+ // this morfo because they're chrome shared across pickers.
]
} as const satisfies Morfo;
diff --git a/src/uix/morfo/components/date-range-picker.ts b/src/uix/morfo/components/date-range-picker.ts
index cb802db9b..5de58498d 100644
--- a/src/uix/morfo/components/date-range-picker.ts
+++ b/src/uix/morfo/components/date-range-picker.ts
@@ -237,78 +237,9 @@ export const dateRangePickerMorfo = {
{ key: 'Tab', action: 'focus-next' },
{ key: 'Shift+Tab', action: 'focus-prev' }
]
- },
- {
- // Optional footer rendered inside the Calendar. Visibility is owned
- // by the consumer (`clearButton`/`cancelButton`/`closeButton` props
- // on the root). In `mode='modal'` the Close affordance is forced on.
- name: 'Footer',
- kebab: 'footer',
- archetype: 'footer',
- kind: 'public',
- defaultElement: 'div',
- optional: true,
- data: [{ attr: 'data-mode', values: ['inline', 'modal'], severity: 'optional' }],
- aria: []
- },
- {
- // Clear action — resets value to an empty range, keeps the popover open.
- name: 'Clear',
- kebab: 'clear',
- archetype: 'trigger',
- kind: 'public',
- defaultElement: 'button',
- role: 'button',
- optional: true,
- data: [{ attr: 'data-action', value: v.literal('clear') }],
- aria: [
- { attr: 'type', value: v.literal('button') },
- {
- attr: 'aria-label',
- value: v.translationRef('#?components.date-range-picker.clear|Clear range'),
- severity: 'recommended'
- }
- ]
- },
- {
- // Cancel action — reverts to the value snapshot taken on open, closes.
- name: 'Cancel',
- kebab: 'cancel',
- archetype: 'trigger',
- kind: 'public',
- defaultElement: 'button',
- role: 'button',
- optional: true,
- data: [{ attr: 'data-action', value: v.literal('cancel') }],
- aria: [
- { attr: 'type', value: v.literal('button') },
- {
- attr: 'aria-label',
- value: v.translationRef('#?components.date-range-picker.cancel|Cancel'),
- severity: 'recommended'
- }
- ]
- },
- {
- // Close / Save action — commits current value and closes. In modal
- // mode this is the only affordance to exit (outside-click + Escape
- // are intentionally blocked).
- name: 'Close',
- kebab: 'close',
- archetype: 'trigger',
- kind: 'public',
- defaultElement: 'button',
- role: 'button',
- optional: true,
- data: [{ attr: 'data-action', value: v.literal('close') }],
- aria: [
- { attr: 'type', value: v.literal('button') },
- {
- attr: 'aria-label',
- value: v.translationRef('#?components.date-range-picker.close|Close'),
- severity: 'recommended'
- }
- ]
}
+ // Footer / Clear / Cancel / Close — chrome shared via picker-shell;
+ // not declared here. Eidos `` re-exports the `` parts.
]
} as const satisfies Morfo;
diff --git a/src/uix/morfo/components/time-picker.ts b/src/uix/morfo/components/time-picker.ts
index 60d424c46..dfe307f1c 100644
--- a/src/uix/morfo/components/time-picker.ts
+++ b/src/uix/morfo/components/time-picker.ts
@@ -308,70 +308,9 @@ export const timePickerMorfo = {
optional: true,
data: [{ attr: 'data-checked', severity: 'optional' }],
aria: []
- },
- {
- name: 'Footer',
- kebab: 'footer',
- archetype: 'footer',
- kind: 'public',
- defaultElement: 'div',
- optional: true,
- data: [{ attr: 'data-mode', values: ['inline', 'modal'], severity: 'optional' }],
- aria: []
- },
- {
- name: 'Clear',
- kebab: 'clear',
- archetype: 'trigger',
- kind: 'public',
- defaultElement: 'button',
- role: 'button',
- optional: true,
- data: [{ attr: 'data-action', value: v.literal('clear') }],
- aria: [
- { attr: 'type', value: v.literal('button') },
- {
- attr: 'aria-label',
- value: v.translationRef('#?components.time-picker.clear|Clear time'),
- severity: 'recommended'
- }
- ]
- },
- {
- name: 'Cancel',
- kebab: 'cancel',
- archetype: 'trigger',
- kind: 'public',
- defaultElement: 'button',
- role: 'button',
- optional: true,
- data: [{ attr: 'data-action', value: v.literal('cancel') }],
- aria: [
- { attr: 'type', value: v.literal('button') },
- {
- attr: 'aria-label',
- value: v.translationRef('#?components.time-picker.cancel|Cancel'),
- severity: 'recommended'
- }
- ]
- },
- {
- name: 'Close',
- kebab: 'close',
- archetype: 'trigger',
- kind: 'public',
- defaultElement: 'button',
- role: 'button',
- optional: true,
- data: [{ attr: 'data-action', value: v.literal('close') }],
- aria: [
- { attr: 'type', value: v.literal('button') },
- {
- attr: 'aria-label',
- value: v.translationRef('#?components.time-picker.close|Close'),
- severity: 'recommended'
- }
- ]
}
+ // Footer / Clear / Cancel / Close — chrome shared via picker-shell;
+ // not declared here. Eidos ``
+ // re-exports the `` parts.
]
} as const satisfies Morfo;
diff --git a/src/uix/soma/components/date-picker/date-picker-provider.svelte.ts b/src/uix/soma/components/date-picker/date-picker-provider.svelte.ts
index 500af79d7..d5dcea3ed 100644
--- a/src/uix/soma/components/date-picker/date-picker-provider.svelte.ts
+++ b/src/uix/soma/components/date-picker/date-picker-provider.svelte.ts
@@ -7,6 +7,10 @@ import { type ActiveProps, type StateProps } from '$libs/reactive';
import type { OnChangeFn, Direction } from '../../types';
import { Soma } from '../../core/soma.svelte';
import { isBefore } from '$libs/days';
+import {
+ pickerShellContext,
+ type PickerShellHandle
+} from '../picker-shell';
import type {
DateValue,
DateMatcher,
@@ -160,8 +164,19 @@ export class DatePickerProvider {
}
}
);
+
+ // Expose our commit/cancel/clear/mode handle to descendant Eidos
+ // PickerShell parts (``, ``, etc.).
+ pickerShellContext.set(this.pickerShellHandle);
}
+ readonly pickerShellHandle: PickerShellHandle = {
+ getMode: () => this.opts.mode.current,
+ commit: () => this.commit(),
+ cancel: () => this.cancel(),
+ clear: () => this.clear()
+ };
+
readonly validationStatus = $derived.by(() => {
const value = this.opts.value.current;
if (!value) return false as const;
diff --git a/src/uix/soma/components/date-range-picker/date-range-picker-provider.svelte.ts b/src/uix/soma/components/date-range-picker/date-range-picker-provider.svelte.ts
index b7869165d..c178e4871 100644
--- a/src/uix/soma/components/date-range-picker/date-range-picker-provider.svelte.ts
+++ b/src/uix/soma/components/date-range-picker/date-range-picker-provider.svelte.ts
@@ -7,6 +7,10 @@ import { type ActiveProps, type StateProps } from '$libs/reactive';
import type { OnChangeFn, Direction } from '../../types';
import { Soma } from '../../core/soma.svelte';
import { getLocalTimeZone, isBefore } from '$libs/days';
+import {
+ pickerShellContext,
+ type PickerShellHandle
+} from '../picker-shell';
/**
* Picker interaction mode. `inline` (default) auto-closes the popover when
@@ -150,8 +154,19 @@ export class DateRangePickerProvider {
}
}
);
+
+ // Expose our commit/cancel/clear/mode handle to descendant Eidos
+ // PickerShell parts (``, etc.).
+ pickerShellContext.set(this.pickerShellHandle);
}
+ readonly pickerShellHandle: PickerShellHandle = {
+ getMode: () => this.opts.mode.current,
+ commit: () => this.commit(),
+ cancel: () => this.cancel(),
+ clear: () => this.clear()
+ };
+
readonly validationStatus = $derived.by(() => {
const value = this.opts.value.current;
const start = value.start;
diff --git a/src/uix/soma/components/time-picker/time-picker-provider.svelte.ts b/src/uix/soma/components/time-picker/time-picker-provider.svelte.ts
index c4e150e2a..23f8f1132 100644
--- a/src/uix/soma/components/time-picker/time-picker-provider.svelte.ts
+++ b/src/uix/soma/components/time-picker/time-picker-provider.svelte.ts
@@ -17,6 +17,10 @@ import type {
import { timePickerMorfo } from '../../../morfo/components/time-picker';
import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte';
+import {
+ pickerShellContext,
+ type PickerShellHandle
+} from '../picker-shell';
const attrs = createAttrs(timePickerMorfo);
@@ -109,8 +113,19 @@ export class TimePickerProvider {
}
}
);
+
+ // Expose our commit/cancel/clear/mode handle to descendant Eidos
+ // PickerShell parts (``, ``, etc.).
+ pickerShellContext.set(this.pickerShellHandle);
}
+ readonly pickerShellHandle: PickerShellHandle = {
+ getMode: () => this.opts.mode.current,
+ commit: () => this.commit(),
+ cancel: () => this.cancel(),
+ clear: () => this.clear()
+ };
+
/** Resolved hour cycle — same rule as TimeField: explicit → service → locale. */
readonly resolvedHourCycle: HourCycle = $derived.by(() => {
const explicit = this.opts.hourCycle.current;