@peektravel/app-utilities 0.5.4 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -71,6 +71,25 @@ declare abstract class OdyElement extends HTMLElement {
71
71
  * to call on every attribute change without losing the original children.
72
72
  */
73
73
  protected mount(chrome: string): void;
74
+ /**
75
+ * Move slotted content out of a portaled chrome node (dialog/panel/bubble)
76
+ * back into the captured slot fragment, so it survives `disconnectedCallback`
77
+ * tearing that node down and is re-slotted by the re-render on reconnect.
78
+ * Portal components call this before `removePortal(...)`; without it, moving
79
+ * the element in the DOM would permanently lose the consumer's content.
80
+ */
81
+ protected reclaimPortaledSlot(node: ParentNode | null | undefined): void;
82
+ appendChild<T extends Node>(node: T): T;
83
+ insertBefore<T extends Node>(node: T, child: Node | null): T;
84
+ removeChild<T extends Node>(child: T): T;
85
+ replaceChild<T extends Node>(node: Node, child: T): T;
86
+ /**
87
+ * Append an element the component owns (chrome / portaled nodes) as a direct
88
+ * host child, bypassing the slot-forwarding {@link appendChild} override.
89
+ * Portal-based components use this to re-home a portaled node before a
90
+ * re-render rebuilds the chrome.
91
+ */
92
+ protected adopt(node: Node): void;
74
93
  /** Read a string attribute with a fallback. */
75
94
  protected attr(name: string, fallback?: string): string;
76
95
  /** Whether a boolean attribute is present and not explicitly `"false"`. */
@@ -92,6 +111,13 @@ declare function escapeHtml(value: string): string;
92
111
  /**
93
112
  * Join class-name fragments, dropping falsy entries. Keeps component templates
94
113
  * readable when classes are conditional.
114
+ *
115
+ * The result is HTML-escaped because it is always interpolated into a
116
+ * `class="…"` attribute (or assigned to `el.className`). Many components build
117
+ * a class fragment from a raw, unvalidated attribute (`ody-tag--${attr('color')}`,
118
+ * `--size-${attr('size')}`, …); without escaping, a value containing a `"` would
119
+ * break out of the attribute and inject markup (DOM XSS). Legitimate class tokens
120
+ * contain none of the escaped characters, so this is a no-op for real class names.
95
121
  */
96
122
  declare function classes(...parts: Array<string | false | null | undefined>): string;
97
123
  /**
@@ -433,6 +459,8 @@ interface OdyToggleOption {
433
459
  * Attributes:
434
460
  * - `options` — JSON array of {@link OdyToggleOption} (e.g.
435
461
  * `options='[{"value":"day","label":"Day"},{"value":"week","label":"Week"}]'`).
462
+ * Also settable as a JS **property** (`el.options = [...]`) — accepts an array
463
+ * or a JSON string, so a framework binding (`options={items}`) works directly.
436
464
  * - `selected` — the currently-selected option value.
437
465
  * - `size` — `base` | `small` (default `base`).
438
466
  * - `disabled` — disables the whole group.
@@ -440,6 +468,9 @@ interface OdyToggleOption {
440
468
  declare class OdyToggleButton extends OdyElement {
441
469
  #private;
442
470
  static observedAttributes: string[];
471
+ /** Options: the JS property wins, else the JSON `options` attribute. */
472
+ get options(): OdyToggleOption[];
473
+ set options(next: OdyToggleOption[] | string);
443
474
  connectedCallback(): void;
444
475
  disconnectedCallback(): void;
445
476
  protected render(): void;
@@ -760,6 +791,13 @@ declare class OdyMoneyInput extends OdyElement {
760
791
  set value(next: string);
761
792
  /** Decimal precision for the configured currency. */
762
793
  get precision(): number;
794
+ /**
795
+ * Reflect a `value` change into the live control in place instead of a full
796
+ * re-render, so a framework-controlled `value` binding never drops focus or
797
+ * caret while the user is typing. Other observed attributes change the chrome
798
+ * and still re-render via the base implementation.
799
+ */
800
+ attributeChangedCallback(name?: string, oldValue?: string | null, newValue?: string | null): void;
763
801
  protected render(): void;
764
802
  }
765
803
 
@@ -783,6 +821,13 @@ declare class OdyPercentageInput extends OdyElement {
783
821
  /** Current percentage value. */
784
822
  get value(): string;
785
823
  set value(next: string);
824
+ /**
825
+ * Reflect a `value` change into the live control in place instead of a full
826
+ * re-render, so a framework-controlled `value` binding never drops focus or
827
+ * caret while the user is typing. Other observed attributes change the chrome
828
+ * and still re-render via the base implementation.
829
+ */
830
+ attributeChangedCallback(name?: string, oldValue?: string | null, newValue?: string | null): void;
786
831
  protected render(): void;
787
832
  }
788
833
 
@@ -810,6 +855,12 @@ declare class OdyCheckbox extends OdyElement {
810
855
  /** Convenience alias for {@link checked}. */
811
856
  get value(): boolean;
812
857
  set value(next: boolean);
858
+ /**
859
+ * Reflect `checked` / `indeterminate` in place instead of a full re-render, so
860
+ * selecting the box (mouse or keyboard) never rebuilds the native `<input>`
861
+ * and drops focus. Other observed attributes still re-render via the base.
862
+ */
863
+ attributeChangedCallback(name?: string, oldValue?: string | null, newValue?: string | null): void;
813
864
  protected render(): void;
814
865
  }
815
866
 
@@ -838,8 +889,15 @@ declare class OdyRadioButtonGroup extends OdyElement {
838
889
  /** The selected option value. */
839
890
  get value(): string;
840
891
  set value(next: string);
841
- /** Parsed `options`; malformed JSON yields an empty list. */
892
+ /** Options: the JS property wins, else the JSON `options` attribute. */
842
893
  get options(): OdyRadioOption[];
894
+ set options(next: OdyRadioOption[] | string);
895
+ /**
896
+ * Reflect a `value` change by re-checking the matching radio in place instead
897
+ * of rebuilding the fieldset — a full re-render would replace the focused
898
+ * radio and break keyboard (arrow-key) navigation between options.
899
+ */
900
+ attributeChangedCallback(name?: string, oldValue?: string | null, newValue?: string | null): void;
843
901
  protected render(): void;
844
902
  }
845
903
 
@@ -859,10 +917,12 @@ interface OdyCheckboxOption {
859
917
  *
860
918
  * Attributes:
861
919
  * - `options` — JSON array, e.g. `options='[{"label":"A","value":"a"}]'`. Also
862
- * a settable JS property ({@link options}): `el.options = [...]` mirrors
863
- * `<ody-dropdown-*>` and writes the JSON attribute.
864
- * - `value` — comma-separated selected values (also a JS array property,
865
- * {@link value}).
920
+ * a settable JS property ({@link options}): `el.options = [...]` (array or JSON
921
+ * string) mirrors `<ody-dropdown-*>`; the property is the source of truth and
922
+ * is not reflected back onto the attribute.
923
+ * - `value` — selected values (also a JS array property, {@link value}). The
924
+ * reflected attribute is a JSON array (values with commas round-trip); a
925
+ * legacy comma-separated attribute is still accepted when read.
866
926
  * - `select-all-label` — when present, renders the parent select-all row.
867
927
  * - `size` — `base` | `small` (default `small`).
868
928
  * - `disabled` — boolean flag applied to every checkbox.
@@ -872,18 +932,27 @@ interface OdyCheckboxOption {
872
932
  declare class OdyCheckboxGroup extends OdyElement {
873
933
  #private;
874
934
  static observedAttributes: string[];
875
- /** The selected option values. */
935
+ /**
936
+ * The selected option values. The reflected `value` attribute is serialized
937
+ * as a JSON array so values containing commas round-trip; a legacy
938
+ * comma-separated attribute is still read for backwards compatibility.
939
+ */
876
940
  get value(): string[];
877
941
  set value(next: string[]);
878
- /** Parsed `options`; malformed JSON yields an empty list. */
942
+ /** Options: the JS property wins, else the JSON `options` attribute. */
879
943
  get options(): OdyCheckboxOption[];
880
944
  /**
881
- * Accepts an array of `{ label, value }` and stores it as the JSON `options`
882
- * attribute. Mirrors `<ody-dropdown-*>` so `el.options = [...]` works across
883
- * the data-driven elements. `options` is observed, so this triggers a
884
- * re-render via `attributeChangedCallback`.
945
+ * Accepts an array of `{ label, value }` (or a JSON string) and stores it as
946
+ * the source of truth. Mirrors `<ody-dropdown-*>` so `el.options = [...]`
947
+ * works, without reflecting a large JSON blob onto the DOM attribute.
885
948
  */
886
- set options(next: OdyCheckboxOption[]);
949
+ set options(next: OdyCheckboxOption[] | string);
950
+ /**
951
+ * Reflect a `value` change by updating each checkbox (and the select-all
952
+ * parent) in place, so toggling an option keeps focus instead of rebuilding
953
+ * the group. Other observed attributes still re-render via the base.
954
+ */
955
+ attributeChangedCallback(name?: string, oldValue?: string | null, newValue?: string | null): void;
887
956
  protected render(): void;
888
957
  }
889
958
 
@@ -967,6 +1036,7 @@ declare class OdyCopyButton extends OdyElement {
967
1036
  #private;
968
1037
  static observedAttributes: string[];
969
1038
  protected render(): void;
1039
+ disconnectedCallback(): void;
970
1040
  }
971
1041
 
972
1042
  /**
@@ -1173,11 +1243,13 @@ interface OdyToastOptions {
1173
1243
  * {@link toast} lazily creates and portals one for you.
1174
1244
  */
1175
1245
  declare class OdyToastHost extends OdyElement {
1246
+ #private;
1176
1247
  protected render(): void;
1177
1248
  /** Render and stack a toast, returning a handle to dismiss it early. */
1178
1249
  push(message: string, options?: OdyToastOptions): {
1179
1250
  dismiss: () => void;
1180
1251
  };
1252
+ disconnectedCallback(): void;
1181
1253
  }
1182
1254
  /**
1183
1255
  * Show a toast notification, lazily creating an {@link OdyToastHost} portaled to
@@ -1241,6 +1313,7 @@ declare abstract class OdySelectBase extends OdyElement {
1241
1313
  protected abstract triggerContent(): string;
1242
1314
  /** ARIA `aria-multiselectable` value for the listbox (`'true'`/`'false'`). */
1243
1315
  protected abstract get multiselectable(): boolean;
1316
+ connectedCallback(): void;
1244
1317
  protected render(): void;
1245
1318
  /** Open the panel and start listening for outside clicks. */
1246
1319
  protected openPanel(): void;
@@ -1353,7 +1426,8 @@ type OdyDateFormatter = (date: Date) => string;
1353
1426
  * - `range` — boolean; enables start/end range selection.
1354
1427
  * - `first-day-of-week` — `0`–`6` (0 = Sunday, default `0`).
1355
1428
  * - `placeholder` — trigger text shown when no value is selected.
1356
- * - `presets` — JSON `[{ "label", "value" }]` shortcut buttons.
1429
+ * - `presets` — JSON `[{ "label", "value" }]` shortcut buttons. Also settable
1430
+ * as a JS **property** (`el.presets = [...]`) — accepts an array or JSON string.
1357
1431
  * - `display-format` — how the selected date is shown to the user:
1358
1432
  * `short` | `medium` (default) | `long` | `full`. The displayed text is
1359
1433
  * localized via `Intl.DateTimeFormat` for the element's `lang`; the `value`
@@ -1371,10 +1445,15 @@ type OdyDateFormatter = (date: Date) => string;
1371
1445
  declare class OdyDatePicker extends OdyElement {
1372
1446
  #private;
1373
1447
  static observedAttributes: string[];
1448
+ /** Preset list: the JS property wins, else the JSON `presets` attribute. */
1449
+ get presets(): OdyDatePreset[];
1450
+ set presets(next: OdyDatePreset[] | string);
1374
1451
  /** Disable arbitrary days; not an attribute (functions can't serialize). */
1375
- isDateDisallowed?: OdyDateDisallowed;
1452
+ get isDateDisallowed(): OdyDateDisallowed | undefined;
1453
+ set isDateDisallowed(fn: OdyDateDisallowed | undefined);
1376
1454
  /** Custom trigger-label formatter; wins over `display-format`/`Intl`. */
1377
- formatDate?: OdyDateFormatter;
1455
+ get formatDate(): OdyDateFormatter | undefined;
1456
+ set formatDate(fn: OdyDateFormatter | undefined);
1378
1457
  /** Whether the popover is currently shown. */
1379
1458
  get isOpen(): boolean;
1380
1459
  /** Show the popover and focus the roving day. */
@@ -71,6 +71,25 @@ declare abstract class OdyElement extends HTMLElement {
71
71
  * to call on every attribute change without losing the original children.
72
72
  */
73
73
  protected mount(chrome: string): void;
74
+ /**
75
+ * Move slotted content out of a portaled chrome node (dialog/panel/bubble)
76
+ * back into the captured slot fragment, so it survives `disconnectedCallback`
77
+ * tearing that node down and is re-slotted by the re-render on reconnect.
78
+ * Portal components call this before `removePortal(...)`; without it, moving
79
+ * the element in the DOM would permanently lose the consumer's content.
80
+ */
81
+ protected reclaimPortaledSlot(node: ParentNode | null | undefined): void;
82
+ appendChild<T extends Node>(node: T): T;
83
+ insertBefore<T extends Node>(node: T, child: Node | null): T;
84
+ removeChild<T extends Node>(child: T): T;
85
+ replaceChild<T extends Node>(node: Node, child: T): T;
86
+ /**
87
+ * Append an element the component owns (chrome / portaled nodes) as a direct
88
+ * host child, bypassing the slot-forwarding {@link appendChild} override.
89
+ * Portal-based components use this to re-home a portaled node before a
90
+ * re-render rebuilds the chrome.
91
+ */
92
+ protected adopt(node: Node): void;
74
93
  /** Read a string attribute with a fallback. */
75
94
  protected attr(name: string, fallback?: string): string;
76
95
  /** Whether a boolean attribute is present and not explicitly `"false"`. */
@@ -92,6 +111,13 @@ declare function escapeHtml(value: string): string;
92
111
  /**
93
112
  * Join class-name fragments, dropping falsy entries. Keeps component templates
94
113
  * readable when classes are conditional.
114
+ *
115
+ * The result is HTML-escaped because it is always interpolated into a
116
+ * `class="…"` attribute (or assigned to `el.className`). Many components build
117
+ * a class fragment from a raw, unvalidated attribute (`ody-tag--${attr('color')}`,
118
+ * `--size-${attr('size')}`, …); without escaping, a value containing a `"` would
119
+ * break out of the attribute and inject markup (DOM XSS). Legitimate class tokens
120
+ * contain none of the escaped characters, so this is a no-op for real class names.
95
121
  */
96
122
  declare function classes(...parts: Array<string | false | null | undefined>): string;
97
123
  /**
@@ -433,6 +459,8 @@ interface OdyToggleOption {
433
459
  * Attributes:
434
460
  * - `options` — JSON array of {@link OdyToggleOption} (e.g.
435
461
  * `options='[{"value":"day","label":"Day"},{"value":"week","label":"Week"}]'`).
462
+ * Also settable as a JS **property** (`el.options = [...]`) — accepts an array
463
+ * or a JSON string, so a framework binding (`options={items}`) works directly.
436
464
  * - `selected` — the currently-selected option value.
437
465
  * - `size` — `base` | `small` (default `base`).
438
466
  * - `disabled` — disables the whole group.
@@ -440,6 +468,9 @@ interface OdyToggleOption {
440
468
  declare class OdyToggleButton extends OdyElement {
441
469
  #private;
442
470
  static observedAttributes: string[];
471
+ /** Options: the JS property wins, else the JSON `options` attribute. */
472
+ get options(): OdyToggleOption[];
473
+ set options(next: OdyToggleOption[] | string);
443
474
  connectedCallback(): void;
444
475
  disconnectedCallback(): void;
445
476
  protected render(): void;
@@ -760,6 +791,13 @@ declare class OdyMoneyInput extends OdyElement {
760
791
  set value(next: string);
761
792
  /** Decimal precision for the configured currency. */
762
793
  get precision(): number;
794
+ /**
795
+ * Reflect a `value` change into the live control in place instead of a full
796
+ * re-render, so a framework-controlled `value` binding never drops focus or
797
+ * caret while the user is typing. Other observed attributes change the chrome
798
+ * and still re-render via the base implementation.
799
+ */
800
+ attributeChangedCallback(name?: string, oldValue?: string | null, newValue?: string | null): void;
763
801
  protected render(): void;
764
802
  }
765
803
 
@@ -783,6 +821,13 @@ declare class OdyPercentageInput extends OdyElement {
783
821
  /** Current percentage value. */
784
822
  get value(): string;
785
823
  set value(next: string);
824
+ /**
825
+ * Reflect a `value` change into the live control in place instead of a full
826
+ * re-render, so a framework-controlled `value` binding never drops focus or
827
+ * caret while the user is typing. Other observed attributes change the chrome
828
+ * and still re-render via the base implementation.
829
+ */
830
+ attributeChangedCallback(name?: string, oldValue?: string | null, newValue?: string | null): void;
786
831
  protected render(): void;
787
832
  }
788
833
 
@@ -810,6 +855,12 @@ declare class OdyCheckbox extends OdyElement {
810
855
  /** Convenience alias for {@link checked}. */
811
856
  get value(): boolean;
812
857
  set value(next: boolean);
858
+ /**
859
+ * Reflect `checked` / `indeterminate` in place instead of a full re-render, so
860
+ * selecting the box (mouse or keyboard) never rebuilds the native `<input>`
861
+ * and drops focus. Other observed attributes still re-render via the base.
862
+ */
863
+ attributeChangedCallback(name?: string, oldValue?: string | null, newValue?: string | null): void;
813
864
  protected render(): void;
814
865
  }
815
866
 
@@ -838,8 +889,15 @@ declare class OdyRadioButtonGroup extends OdyElement {
838
889
  /** The selected option value. */
839
890
  get value(): string;
840
891
  set value(next: string);
841
- /** Parsed `options`; malformed JSON yields an empty list. */
892
+ /** Options: the JS property wins, else the JSON `options` attribute. */
842
893
  get options(): OdyRadioOption[];
894
+ set options(next: OdyRadioOption[] | string);
895
+ /**
896
+ * Reflect a `value` change by re-checking the matching radio in place instead
897
+ * of rebuilding the fieldset — a full re-render would replace the focused
898
+ * radio and break keyboard (arrow-key) navigation between options.
899
+ */
900
+ attributeChangedCallback(name?: string, oldValue?: string | null, newValue?: string | null): void;
843
901
  protected render(): void;
844
902
  }
845
903
 
@@ -859,10 +917,12 @@ interface OdyCheckboxOption {
859
917
  *
860
918
  * Attributes:
861
919
  * - `options` — JSON array, e.g. `options='[{"label":"A","value":"a"}]'`. Also
862
- * a settable JS property ({@link options}): `el.options = [...]` mirrors
863
- * `<ody-dropdown-*>` and writes the JSON attribute.
864
- * - `value` — comma-separated selected values (also a JS array property,
865
- * {@link value}).
920
+ * a settable JS property ({@link options}): `el.options = [...]` (array or JSON
921
+ * string) mirrors `<ody-dropdown-*>`; the property is the source of truth and
922
+ * is not reflected back onto the attribute.
923
+ * - `value` — selected values (also a JS array property, {@link value}). The
924
+ * reflected attribute is a JSON array (values with commas round-trip); a
925
+ * legacy comma-separated attribute is still accepted when read.
866
926
  * - `select-all-label` — when present, renders the parent select-all row.
867
927
  * - `size` — `base` | `small` (default `small`).
868
928
  * - `disabled` — boolean flag applied to every checkbox.
@@ -872,18 +932,27 @@ interface OdyCheckboxOption {
872
932
  declare class OdyCheckboxGroup extends OdyElement {
873
933
  #private;
874
934
  static observedAttributes: string[];
875
- /** The selected option values. */
935
+ /**
936
+ * The selected option values. The reflected `value` attribute is serialized
937
+ * as a JSON array so values containing commas round-trip; a legacy
938
+ * comma-separated attribute is still read for backwards compatibility.
939
+ */
876
940
  get value(): string[];
877
941
  set value(next: string[]);
878
- /** Parsed `options`; malformed JSON yields an empty list. */
942
+ /** Options: the JS property wins, else the JSON `options` attribute. */
879
943
  get options(): OdyCheckboxOption[];
880
944
  /**
881
- * Accepts an array of `{ label, value }` and stores it as the JSON `options`
882
- * attribute. Mirrors `<ody-dropdown-*>` so `el.options = [...]` works across
883
- * the data-driven elements. `options` is observed, so this triggers a
884
- * re-render via `attributeChangedCallback`.
945
+ * Accepts an array of `{ label, value }` (or a JSON string) and stores it as
946
+ * the source of truth. Mirrors `<ody-dropdown-*>` so `el.options = [...]`
947
+ * works, without reflecting a large JSON blob onto the DOM attribute.
885
948
  */
886
- set options(next: OdyCheckboxOption[]);
949
+ set options(next: OdyCheckboxOption[] | string);
950
+ /**
951
+ * Reflect a `value` change by updating each checkbox (and the select-all
952
+ * parent) in place, so toggling an option keeps focus instead of rebuilding
953
+ * the group. Other observed attributes still re-render via the base.
954
+ */
955
+ attributeChangedCallback(name?: string, oldValue?: string | null, newValue?: string | null): void;
887
956
  protected render(): void;
888
957
  }
889
958
 
@@ -967,6 +1036,7 @@ declare class OdyCopyButton extends OdyElement {
967
1036
  #private;
968
1037
  static observedAttributes: string[];
969
1038
  protected render(): void;
1039
+ disconnectedCallback(): void;
970
1040
  }
971
1041
 
972
1042
  /**
@@ -1173,11 +1243,13 @@ interface OdyToastOptions {
1173
1243
  * {@link toast} lazily creates and portals one for you.
1174
1244
  */
1175
1245
  declare class OdyToastHost extends OdyElement {
1246
+ #private;
1176
1247
  protected render(): void;
1177
1248
  /** Render and stack a toast, returning a handle to dismiss it early. */
1178
1249
  push(message: string, options?: OdyToastOptions): {
1179
1250
  dismiss: () => void;
1180
1251
  };
1252
+ disconnectedCallback(): void;
1181
1253
  }
1182
1254
  /**
1183
1255
  * Show a toast notification, lazily creating an {@link OdyToastHost} portaled to
@@ -1241,6 +1313,7 @@ declare abstract class OdySelectBase extends OdyElement {
1241
1313
  protected abstract triggerContent(): string;
1242
1314
  /** ARIA `aria-multiselectable` value for the listbox (`'true'`/`'false'`). */
1243
1315
  protected abstract get multiselectable(): boolean;
1316
+ connectedCallback(): void;
1244
1317
  protected render(): void;
1245
1318
  /** Open the panel and start listening for outside clicks. */
1246
1319
  protected openPanel(): void;
@@ -1353,7 +1426,8 @@ type OdyDateFormatter = (date: Date) => string;
1353
1426
  * - `range` — boolean; enables start/end range selection.
1354
1427
  * - `first-day-of-week` — `0`–`6` (0 = Sunday, default `0`).
1355
1428
  * - `placeholder` — trigger text shown when no value is selected.
1356
- * - `presets` — JSON `[{ "label", "value" }]` shortcut buttons.
1429
+ * - `presets` — JSON `[{ "label", "value" }]` shortcut buttons. Also settable
1430
+ * as a JS **property** (`el.presets = [...]`) — accepts an array or JSON string.
1357
1431
  * - `display-format` — how the selected date is shown to the user:
1358
1432
  * `short` | `medium` (default) | `long` | `full`. The displayed text is
1359
1433
  * localized via `Intl.DateTimeFormat` for the element's `lang`; the `value`
@@ -1371,10 +1445,15 @@ type OdyDateFormatter = (date: Date) => string;
1371
1445
  declare class OdyDatePicker extends OdyElement {
1372
1446
  #private;
1373
1447
  static observedAttributes: string[];
1448
+ /** Preset list: the JS property wins, else the JSON `presets` attribute. */
1449
+ get presets(): OdyDatePreset[];
1450
+ set presets(next: OdyDatePreset[] | string);
1374
1451
  /** Disable arbitrary days; not an attribute (functions can't serialize). */
1375
- isDateDisallowed?: OdyDateDisallowed;
1452
+ get isDateDisallowed(): OdyDateDisallowed | undefined;
1453
+ set isDateDisallowed(fn: OdyDateDisallowed | undefined);
1376
1454
  /** Custom trigger-label formatter; wins over `display-format`/`Intl`. */
1377
- formatDate?: OdyDateFormatter;
1455
+ get formatDate(): OdyDateFormatter | undefined;
1456
+ set formatDate(fn: OdyDateFormatter | undefined);
1378
1457
  /** Whether the popover is currently shown. */
1379
1458
  get isOpen(): boolean;
1380
1459
  /** Show the popover and focus the roving day. */