@aceshooting/lyra-ui 0.1.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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +98 -0
  3. package/dist/components/combobox/combobox.d.ts +90 -0
  4. package/dist/components/combobox/combobox.js +398 -0
  5. package/dist/components/combobox/combobox.styles.d.ts +1 -0
  6. package/dist/components/combobox/combobox.styles.js +148 -0
  7. package/dist/components/combobox/option.d.ts +32 -0
  8. package/dist/components/combobox/option.js +62 -0
  9. package/dist/components/date-picker/calendar-core.d.ts +20 -0
  10. package/dist/components/date-picker/calendar-core.js +71 -0
  11. package/dist/components/date-picker/date-input.d.ts +57 -0
  12. package/dist/components/date-picker/date-input.js +233 -0
  13. package/dist/components/date-picker/date-input.styles.d.ts +1 -0
  14. package/dist/components/date-picker/date-input.styles.js +67 -0
  15. package/dist/components/date-picker/date-picker.d.ts +64 -0
  16. package/dist/components/date-picker/date-picker.js +310 -0
  17. package/dist/components/date-picker/date-picker.styles.d.ts +1 -0
  18. package/dist/components/date-picker/date-picker.styles.js +101 -0
  19. package/dist/components/flag/flag.d.ts +35 -0
  20. package/dist/components/flag/flag.js +91 -0
  21. package/dist/components/flag/flag.styles.d.ts +1 -0
  22. package/dist/components/flag/flag.styles.js +27 -0
  23. package/dist/components/flag/language-map.d.ts +11 -0
  24. package/dist/components/flag/language-map.js +62 -0
  25. package/dist/components/sparkline/sparkline.d.ts +30 -0
  26. package/dist/components/sparkline/sparkline.js +74 -0
  27. package/dist/components/sparkline/sparkline.styles.d.ts +1 -0
  28. package/dist/components/sparkline/sparkline.styles.js +31 -0
  29. package/dist/components/toast/toast-item.d.ts +49 -0
  30. package/dist/components/toast/toast-item.js +123 -0
  31. package/dist/components/toast/toast-item.styles.d.ts +1 -0
  32. package/dist/components/toast/toast-item.styles.js +81 -0
  33. package/dist/components/toast/toast.d.ts +32 -0
  34. package/dist/components/toast/toast.js +48 -0
  35. package/dist/components/toast/toast.styles.d.ts +1 -0
  36. package/dist/components/toast/toast.styles.js +52 -0
  37. package/dist/components/toast/toaster.d.ts +26 -0
  38. package/dist/components/toast/toaster.js +41 -0
  39. package/dist/internal/a11y.d.ts +4 -0
  40. package/dist/internal/a11y.js +18 -0
  41. package/dist/internal/form-associated.d.ts +26 -0
  42. package/dist/internal/form-associated.js +56 -0
  43. package/dist/internal/lyra-element.d.ts +11 -0
  44. package/dist/internal/lyra-element.js +21 -0
  45. package/dist/internal/positioner.d.ts +10 -0
  46. package/dist/internal/positioner.js +21 -0
  47. package/dist/internal/prefix.d.ts +4 -0
  48. package/dist/internal/prefix.js +8 -0
  49. package/dist/internal/tokens.styles.d.ts +1 -0
  50. package/dist/internal/tokens.styles.js +35 -0
  51. package/dist/lyra.d.ts +26 -0
  52. package/dist/lyra.js +23 -0
  53. package/package.json +64 -0
@@ -0,0 +1,148 @@
1
+ import { css } from 'lit';
2
+ export const styles = css `
3
+ :host {
4
+ display: block;
5
+ }
6
+ [part='form-control-label'] {
7
+ display: block;
8
+ margin-block-end: var(--lyra-space-xs);
9
+ font-size: 0.875rem;
10
+ font-weight: 600;
11
+ }
12
+ [part='form-control-label']:empty {
13
+ display: none;
14
+ }
15
+
16
+ [part='combobox'] {
17
+ display: flex;
18
+ flex-wrap: wrap;
19
+ align-items: center;
20
+ gap: var(--lyra-space-xs);
21
+ inline-size: 100%;
22
+ min-block-size: 2.5rem;
23
+ padding: var(--lyra-space-xs) var(--lyra-space-s);
24
+ border: 1px solid var(--lyra-color-border);
25
+ border-radius: var(--lyra-radius);
26
+ background: var(--lyra-color-surface);
27
+ cursor: text;
28
+ }
29
+ [part='combobox']:focus-within {
30
+ border-color: var(--lyra-color-brand);
31
+ outline: 2px solid transparent;
32
+ }
33
+ :host([disabled]) [part='combobox'] {
34
+ opacity: 0.5;
35
+ cursor: not-allowed;
36
+ }
37
+
38
+ [part='tag'] {
39
+ display: inline-flex;
40
+ align-items: center;
41
+ gap: var(--lyra-space-xs);
42
+ padding: 0.1rem 0.4rem;
43
+ font-size: 0.8125rem;
44
+ background: var(--lyra-color-brand-quiet);
45
+ color: var(--lyra-color-text);
46
+ border-radius: var(--lyra-radius);
47
+ }
48
+ [part='tag__remove-button'] {
49
+ border: none;
50
+ background: none;
51
+ cursor: pointer;
52
+ color: inherit;
53
+ padding: 0;
54
+ line-height: 1;
55
+ font-size: 1rem;
56
+ }
57
+
58
+ [part='combobox-input'] {
59
+ flex: 1 1 6ch;
60
+ min-inline-size: 4ch;
61
+ border: none;
62
+ outline: none;
63
+ background: transparent;
64
+ color: inherit;
65
+ font: inherit;
66
+ }
67
+
68
+ [part='clear-button'],
69
+ [part='expand-icon'] {
70
+ flex: 0 0 auto;
71
+ border: none;
72
+ background: none;
73
+ cursor: pointer;
74
+ color: var(--lyra-color-text-quiet);
75
+ padding: 0 var(--lyra-space-xs);
76
+ line-height: 1;
77
+ }
78
+
79
+ [part='listbox'] {
80
+ display: none;
81
+ position: fixed;
82
+ z-index: 900;
83
+ box-sizing: border-box;
84
+ max-block-size: 18rem;
85
+ overflow-y: auto;
86
+ inline-size: max-content;
87
+ min-inline-size: 12rem;
88
+ max-inline-size: min(92vw, 28rem);
89
+ padding: var(--lyra-space-xs);
90
+ background: var(--lyra-color-surface);
91
+ border: 1px solid var(--lyra-color-border);
92
+ border-radius: var(--lyra-radius);
93
+ box-shadow: var(--lyra-shadow);
94
+ }
95
+ :host([open]) [part='listbox'] {
96
+ display: block;
97
+ }
98
+
99
+ [part='option'] {
100
+ display: flex;
101
+ flex-direction: column;
102
+ align-items: start;
103
+ inline-size: 100%;
104
+ padding: var(--lyra-space-xs) var(--lyra-space-s);
105
+ border: 1px solid transparent;
106
+ border-radius: var(--lyra-radius);
107
+ background: none;
108
+ color: inherit;
109
+ font: inherit;
110
+ text-align: start;
111
+ cursor: pointer;
112
+ }
113
+ [part='option']:hover,
114
+ [part='option'][data-active] {
115
+ background: var(--lyra-color-brand-quiet);
116
+ }
117
+ [part='option'][aria-selected='true'] {
118
+ border-color: var(--lyra-color-brand);
119
+ color: var(--lyra-color-brand);
120
+ font-weight: 600;
121
+ }
122
+ [part='option'][aria-disabled='true'] {
123
+ opacity: 0.4;
124
+ cursor: not-allowed;
125
+ }
126
+
127
+ .group-label {
128
+ padding: var(--lyra-space-xs) var(--lyra-space-s) 0;
129
+ font-size: 0.6875rem;
130
+ font-weight: 700;
131
+ text-transform: uppercase;
132
+ letter-spacing: 0.04em;
133
+ color: var(--lyra-color-text-quiet);
134
+ }
135
+ .empty {
136
+ padding: var(--lyra-space-m);
137
+ color: var(--lyra-color-text-quiet);
138
+ font-size: 0.875rem;
139
+ }
140
+ [part='hint'] {
141
+ margin-block-start: var(--lyra-space-xs);
142
+ font-size: 0.8125rem;
143
+ color: var(--lyra-color-text-quiet);
144
+ }
145
+ [part='hint']:empty {
146
+ display: none;
147
+ }
148
+ `;
@@ -0,0 +1,32 @@
1
+ import { type TemplateResult } from 'lit';
2
+ import { LyraElement } from '../../internal/lyra-element.js';
3
+ /**
4
+ * `<lyra-option>` — a selectable option for `<lyra-combobox>`.
5
+ * Mirrors `<wa-option>`. Acts as the data source; the combobox renders the
6
+ * interactive rows in its own shadow root and filters/caps them.
7
+ *
8
+ * The label is the element's text content (or an explicit `label` attribute).
9
+ *
10
+ * @customElement lyra-option
11
+ */
12
+ export declare class LyraOption extends LyraElement {
13
+ static styles: import("lit").CSSResult;
14
+ /** The selection key submitted with the form. */
15
+ value: string;
16
+ /** Disable selecting this option. */
17
+ disabled: boolean;
18
+ /** Whether this option is currently selected (reflected by the combobox). */
19
+ selected: boolean;
20
+ /** Optional section header this option belongs under. */
21
+ group: string;
22
+ /** Extra text the filter should match beyond the label. */
23
+ searchText: string;
24
+ /** Resolved label: explicit `label` attribute wins, else trimmed text content. */
25
+ get label(): string;
26
+ render(): TemplateResult;
27
+ }
28
+ declare global {
29
+ interface HTMLElementTagNameMap {
30
+ 'lyra-option': LyraOption;
31
+ }
32
+ }
@@ -0,0 +1,62 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { html, css } from 'lit';
8
+ import { property } from 'lit/decorators.js';
9
+ import { LyraElement } from '../../internal/lyra-element.js';
10
+ import { defineElement } from '../../internal/prefix.js';
11
+ /**
12
+ * `<lyra-option>` — a selectable option for `<lyra-combobox>`.
13
+ * Mirrors `<wa-option>`. Acts as the data source; the combobox renders the
14
+ * interactive rows in its own shadow root and filters/caps them.
15
+ *
16
+ * The label is the element's text content (or an explicit `label` attribute).
17
+ *
18
+ * @customElement lyra-option
19
+ */
20
+ export class LyraOption extends LyraElement {
21
+ constructor() {
22
+ super(...arguments);
23
+ /** The selection key submitted with the form. */
24
+ this.value = '';
25
+ /** Disable selecting this option. */
26
+ this.disabled = false;
27
+ /** Whether this option is currently selected (reflected by the combobox). */
28
+ this.selected = false;
29
+ /** Optional section header this option belongs under. */
30
+ this.group = '';
31
+ /** Extra text the filter should match beyond the label. */
32
+ this.searchText = '';
33
+ }
34
+ static { this.styles = css `
35
+ :host {
36
+ display: none;
37
+ }
38
+ `; }
39
+ /** Resolved label: explicit `label` attribute wins, else trimmed text content. */
40
+ get label() {
41
+ return (this.getAttribute('label') ?? this.textContent ?? '').trim();
42
+ }
43
+ render() {
44
+ return html `<slot></slot>`;
45
+ }
46
+ }
47
+ __decorate([
48
+ property()
49
+ ], LyraOption.prototype, "value", void 0);
50
+ __decorate([
51
+ property({ type: Boolean })
52
+ ], LyraOption.prototype, "disabled", void 0);
53
+ __decorate([
54
+ property({ type: Boolean, reflect: true })
55
+ ], LyraOption.prototype, "selected", void 0);
56
+ __decorate([
57
+ property()
58
+ ], LyraOption.prototype, "group", void 0);
59
+ __decorate([
60
+ property({ attribute: 'search-text' })
61
+ ], LyraOption.prototype, "searchText", void 0);
62
+ defineElement('option', LyraOption);
@@ -0,0 +1,20 @@
1
+ export type WeekdayFormat = 'narrow' | 'short' | 'long';
2
+ /** Parse `YYYY-MM-DD` into a local Date, or null if invalid. */
3
+ export declare function parseISO(s: string): Date | null;
4
+ /** Format a Date as local `YYYY-MM-DD`. */
5
+ export declare function formatISO(d: Date): string;
6
+ export declare function isSameDay(a: Date, b: Date): boolean;
7
+ /** First day of the month `n` months from `d`. */
8
+ export declare function addMonths(d: Date, n: number): Date;
9
+ export declare function clampDate(d: Date, min: Date | null, max: Date | null): Date;
10
+ /**
11
+ * A 6×7 grid of Dates covering the given month, week-aligned to `firstDayOfWeek`
12
+ * (0=Sunday … 6=Saturday). Includes leading/trailing days from adjacent months.
13
+ */
14
+ export declare function monthMatrix(year: number, month: number, firstDayOfWeek?: number): Date[][];
15
+ /** Localized weekday header labels, ordered from `firstDayOfWeek`. */
16
+ export declare function weekdayLabels(firstDayOfWeek?: number, format?: WeekdayFormat, locale?: string): string[];
17
+ /** Localized "Month YYYY" title. */
18
+ export declare function monthTitle(year: number, month: number, locale?: string): string;
19
+ /** Resolve a `first-day-of-week` attribute (name or 'auto') to a 0–6 index. */
20
+ export declare function resolveFirstDayOfWeek(value: string): number;
@@ -0,0 +1,71 @@
1
+ /** Parse `YYYY-MM-DD` into a local Date, or null if invalid. */
2
+ export function parseISO(s) {
3
+ if (!s)
4
+ return null;
5
+ const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s.trim());
6
+ if (!m)
7
+ return null;
8
+ const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
9
+ return isNaN(d.getTime()) ? null : d;
10
+ }
11
+ /** Format a Date as local `YYYY-MM-DD`. */
12
+ export function formatISO(d) {
13
+ const mm = String(d.getMonth() + 1).padStart(2, '0');
14
+ const dd = String(d.getDate()).padStart(2, '0');
15
+ return `${d.getFullYear()}-${mm}-${dd}`;
16
+ }
17
+ export function isSameDay(a, b) {
18
+ return (a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate());
19
+ }
20
+ /** First day of the month `n` months from `d`. */
21
+ export function addMonths(d, n) {
22
+ return new Date(d.getFullYear(), d.getMonth() + n, 1);
23
+ }
24
+ export function clampDate(d, min, max) {
25
+ if (min && d < min)
26
+ return min;
27
+ if (max && d > max)
28
+ return max;
29
+ return d;
30
+ }
31
+ /**
32
+ * A 6×7 grid of Dates covering the given month, week-aligned to `firstDayOfWeek`
33
+ * (0=Sunday … 6=Saturday). Includes leading/trailing days from adjacent months.
34
+ */
35
+ export function monthMatrix(year, month, firstDayOfWeek = 0) {
36
+ const first = new Date(year, month, 1);
37
+ const offset = (first.getDay() - firstDayOfWeek + 7) % 7;
38
+ const cursor = new Date(year, month, 1 - offset);
39
+ const weeks = [];
40
+ for (let w = 0; w < 6; w++) {
41
+ const row = [];
42
+ for (let d = 0; d < 7; d++) {
43
+ row.push(new Date(cursor));
44
+ cursor.setDate(cursor.getDate() + 1);
45
+ }
46
+ weeks.push(row);
47
+ }
48
+ return weeks;
49
+ }
50
+ /** Localized weekday header labels, ordered from `firstDayOfWeek`. */
51
+ export function weekdayLabels(firstDayOfWeek = 0, format = 'short', locale) {
52
+ const fmt = new Intl.DateTimeFormat(locale || undefined, { weekday: format });
53
+ const labels = [];
54
+ // 2021-08-01 is a Sunday, so index i maps cleanly to a weekday.
55
+ for (let i = 0; i < 7; i++) {
56
+ const day = (firstDayOfWeek + i) % 7;
57
+ labels.push(fmt.format(new Date(2021, 7, 1 + day)));
58
+ }
59
+ return labels;
60
+ }
61
+ /** Localized "Month YYYY" title. */
62
+ export function monthTitle(year, month, locale) {
63
+ return new Intl.DateTimeFormat(locale || undefined, { month: 'long', year: 'numeric' }).format(new Date(year, month, 1));
64
+ }
65
+ const FDOW = { sun: 0, mon: 1, tue: 2, wed: 3, thu: 4, fri: 5, sat: 6 };
66
+ /** Resolve a `first-day-of-week` attribute (name or 'auto') to a 0–6 index. */
67
+ export function resolveFirstDayOfWeek(value) {
68
+ if (!value || value === 'auto')
69
+ return 0;
70
+ return FDOW[value.toLowerCase()] ?? 0;
71
+ }
@@ -0,0 +1,57 @@
1
+ import { type TemplateResult, type PropertyValues } from 'lit';
2
+ import { LyraElement } from '../../internal/lyra-element.js';
3
+ import { type WeekdayFormat } from './calendar-core.js';
4
+ import './date-picker.js';
5
+ declare const LyraDateInput_base: typeof LyraElement & (new (...args: any[]) => import("../../internal/form-associated.js").FormAssociatedInterface);
6
+ /**
7
+ * `<lyra-date-input>` — a date field with an attached calendar popover.
8
+ * Mirrors the core `<wa-date-input>` API under `lyra-`. Value is ISO 8601
9
+ * (`YYYY-MM-DD`, or `YYYY-MM-DD/YYYY-MM-DD` in range mode). Form-associated.
10
+ *
11
+ * v1 uses a single text field (locale-segmented spinbuttons are a future
12
+ * enhancement); typing accepts ISO or a locale-parseable date.
13
+ *
14
+ * @customElement lyra-date-input
15
+ * @event input - Fired on edits.
16
+ * @event change - Fired on committed date transitions.
17
+ * @event lyra-show / lyra-hide - Calendar popover lifecycle.
18
+ * @event lyra-clear - The clear button was used.
19
+ * @csspart form-control, form-control-label, input-wrapper, input, clear-button, expand-button, popup, date-picker, hint
20
+ */
21
+ export declare class LyraDateInput extends LyraDateInput_base {
22
+ static styles: import("lit").CSSResultGroup[];
23
+ mode: 'single' | 'range';
24
+ min: string;
25
+ max: string;
26
+ readonly: boolean;
27
+ open: boolean;
28
+ withClear: boolean;
29
+ label: string;
30
+ hint: string;
31
+ placeholder: string;
32
+ locale: string;
33
+ months: 1 | 2;
34
+ firstDayOfWeek: string;
35
+ weekdayFormat: WeekdayFormat;
36
+ private cleanupFn?;
37
+ private get displayText();
38
+ /** Open the calendar popover. */
39
+ show(): void;
40
+ /** Close the calendar popover. */
41
+ hide(): void;
42
+ private onDocPointer;
43
+ /** Clear the value. */
44
+ clear(): void;
45
+ disconnectedCallback(): void;
46
+ protected updated(changed: PropertyValues): void;
47
+ private onInputChange;
48
+ private onInputKey;
49
+ private onPickerChange;
50
+ render(): TemplateResult;
51
+ }
52
+ declare global {
53
+ interface HTMLElementTagNameMap {
54
+ 'lyra-date-input': LyraDateInput;
55
+ }
56
+ }
57
+ export {};
@@ -0,0 +1,233 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { html } from 'lit';
8
+ import { property, state } from 'lit/decorators.js';
9
+ import { LyraElement } from '../../internal/lyra-element.js';
10
+ import { FormAssociated } from '../../internal/form-associated.js';
11
+ import { defineElement } from '../../internal/prefix.js';
12
+ import { place } from '../../internal/positioner.js';
13
+ import { parseISO, formatISO } from './calendar-core.js';
14
+ import { styles } from './date-input.styles.js';
15
+ import { LyraDatePicker } from './date-picker.js';
16
+ import './date-picker.js';
17
+ /**
18
+ * `<lyra-date-input>` — a date field with an attached calendar popover.
19
+ * Mirrors the core `<wa-date-input>` API under `lyra-`. Value is ISO 8601
20
+ * (`YYYY-MM-DD`, or `YYYY-MM-DD/YYYY-MM-DD` in range mode). Form-associated.
21
+ *
22
+ * v1 uses a single text field (locale-segmented spinbuttons are a future
23
+ * enhancement); typing accepts ISO or a locale-parseable date.
24
+ *
25
+ * @customElement lyra-date-input
26
+ * @event input - Fired on edits.
27
+ * @event change - Fired on committed date transitions.
28
+ * @event lyra-show / lyra-hide - Calendar popover lifecycle.
29
+ * @event lyra-clear - The clear button was used.
30
+ * @csspart form-control, form-control-label, input-wrapper, input, clear-button, expand-button, popup, date-picker, hint
31
+ */
32
+ export class LyraDateInput extends FormAssociated(LyraElement) {
33
+ constructor() {
34
+ super(...arguments);
35
+ this.mode = 'single';
36
+ this.min = '';
37
+ this.max = '';
38
+ this.readonly = false;
39
+ this.open = false;
40
+ this.withClear = false;
41
+ this.label = '';
42
+ this.hint = '';
43
+ this.placeholder = '';
44
+ this.locale = '';
45
+ this.months = 1;
46
+ this.firstDayOfWeek = 'auto';
47
+ this.weekdayFormat = 'short';
48
+ this.onDocPointer = (e) => {
49
+ if (!e.composedPath().includes(this))
50
+ this.hide();
51
+ };
52
+ this.onInputChange = (e) => {
53
+ const raw = e.target.value.trim();
54
+ if (!raw) {
55
+ this.value = '';
56
+ this.emit('input');
57
+ this.emit('change');
58
+ return;
59
+ }
60
+ const parsed = parseISO(raw) ?? (isNaN(Date.parse(raw)) ? null : new Date(Date.parse(raw)));
61
+ if (parsed) {
62
+ this.value = formatISO(parsed);
63
+ this.emit('input');
64
+ this.emit('change');
65
+ }
66
+ };
67
+ this.onInputKey = (e) => {
68
+ if (e.altKey && e.key === 'ArrowDown') {
69
+ e.preventDefault();
70
+ this.show();
71
+ }
72
+ };
73
+ this.onPickerChange = (e) => {
74
+ e.stopPropagation();
75
+ const picker = e.target;
76
+ this.value = picker.value;
77
+ this.emit('input');
78
+ this.emit('change');
79
+ if (this.mode === 'single')
80
+ this.hide();
81
+ };
82
+ }
83
+ static { this.styles = [LyraElement.styles, styles]; }
84
+ get displayText() {
85
+ const parts = this.value.split('/');
86
+ const from = parseISO(parts[0] ?? '');
87
+ const to = parseISO(parts[1] ?? '');
88
+ if (!from)
89
+ return '';
90
+ const fmt = (d) => d.toLocaleDateString(this.locale || undefined);
91
+ return this.mode === 'range' && to ? `${fmt(from)} – ${fmt(to)}` : fmt(from);
92
+ }
93
+ /** Open the calendar popover. */
94
+ show() {
95
+ if (this.open || this.disabled || this.readonly)
96
+ return;
97
+ this.open = true;
98
+ this.emit('lyra-show');
99
+ document.addEventListener('pointerdown', this.onDocPointer);
100
+ }
101
+ /** Close the calendar popover. */
102
+ hide() {
103
+ if (!this.open)
104
+ return;
105
+ this.open = false;
106
+ this.emit('lyra-hide');
107
+ document.removeEventListener('pointerdown', this.onDocPointer);
108
+ }
109
+ /** Clear the value. */
110
+ clear() {
111
+ this.value = '';
112
+ this.emit('input');
113
+ this.emit('change');
114
+ this.emit('lyra-clear');
115
+ }
116
+ disconnectedCallback() {
117
+ super.disconnectedCallback();
118
+ this.cleanupFn?.();
119
+ document.removeEventListener('pointerdown', this.onDocPointer);
120
+ }
121
+ updated(changed) {
122
+ if (changed.has('open')) {
123
+ this.cleanupFn?.();
124
+ this.cleanupFn = undefined;
125
+ if (this.open) {
126
+ const anchor = this.renderRoot.querySelector('[part="input-wrapper"]');
127
+ const popup = this.renderRoot.querySelector('[part="popup"]');
128
+ if (anchor && popup)
129
+ this.cleanupFn = place(anchor, popup);
130
+ }
131
+ }
132
+ }
133
+ render() {
134
+ const hasValue = this.value.length > 0;
135
+ return html `
136
+ <div part="form-control">
137
+ <label part="form-control-label">${this.label}<slot name="label"></slot></label>
138
+ <div part="input-wrapper">
139
+ <input
140
+ part="input"
141
+ type="text"
142
+ aria-label=${this.label || this.placeholder || 'Date'}
143
+ .value=${this.displayText}
144
+ placeholder=${this.placeholder}
145
+ ?disabled=${this.disabled}
146
+ ?readonly=${this.readonly}
147
+ @change=${this.onInputChange}
148
+ @keydown=${this.onInputKey}
149
+ />
150
+ ${this.withClear && hasValue
151
+ ? html `<button
152
+ part="clear-button"
153
+ type="button"
154
+ aria-label="Clear"
155
+ @click=${() => this.clear()}
156
+ >
157
+ &times;
158
+ </button>`
159
+ : ''}
160
+ <button
161
+ part="expand-button"
162
+ type="button"
163
+ aria-label="Open calendar"
164
+ aria-haspopup="dialog"
165
+ aria-expanded=${this.open ? 'true' : 'false'}
166
+ ?disabled=${this.disabled || this.readonly}
167
+ @click=${() => (this.open ? this.hide() : this.show())}
168
+ >
169
+ <span part="expand-icon" aria-hidden="true">📅</span>
170
+ </button>
171
+ </div>
172
+ <div part="popup" role="dialog" aria-label="Choose date">
173
+ <lyra-date-picker
174
+ part="date-picker"
175
+ .value=${this.value}
176
+ .mode=${this.mode}
177
+ .min=${this.min}
178
+ .max=${this.max}
179
+ .months=${this.months}
180
+ .locale=${this.locale}
181
+ first-day-of-week=${this.firstDayOfWeek}
182
+ weekday-format=${this.weekdayFormat}
183
+ @change=${this.onPickerChange}
184
+ ></lyra-date-picker>
185
+ </div>
186
+ <div part="hint">${this.hint}<slot name="hint"></slot></div>
187
+ </div>
188
+ `;
189
+ }
190
+ }
191
+ __decorate([
192
+ property()
193
+ ], LyraDateInput.prototype, "mode", void 0);
194
+ __decorate([
195
+ property()
196
+ ], LyraDateInput.prototype, "min", void 0);
197
+ __decorate([
198
+ property()
199
+ ], LyraDateInput.prototype, "max", void 0);
200
+ __decorate([
201
+ property({ type: Boolean, reflect: true })
202
+ ], LyraDateInput.prototype, "readonly", void 0);
203
+ __decorate([
204
+ property({ type: Boolean, reflect: true })
205
+ ], LyraDateInput.prototype, "open", void 0);
206
+ __decorate([
207
+ property({ type: Boolean, attribute: 'with-clear' })
208
+ ], LyraDateInput.prototype, "withClear", void 0);
209
+ __decorate([
210
+ property()
211
+ ], LyraDateInput.prototype, "label", void 0);
212
+ __decorate([
213
+ property()
214
+ ], LyraDateInput.prototype, "hint", void 0);
215
+ __decorate([
216
+ property()
217
+ ], LyraDateInput.prototype, "placeholder", void 0);
218
+ __decorate([
219
+ property()
220
+ ], LyraDateInput.prototype, "locale", void 0);
221
+ __decorate([
222
+ property({ type: Number })
223
+ ], LyraDateInput.prototype, "months", void 0);
224
+ __decorate([
225
+ property({ attribute: 'first-day-of-week' })
226
+ ], LyraDateInput.prototype, "firstDayOfWeek", void 0);
227
+ __decorate([
228
+ property({ attribute: 'weekday-format' })
229
+ ], LyraDateInput.prototype, "weekdayFormat", void 0);
230
+ __decorate([
231
+ state()
232
+ ], LyraDateInput.prototype, "cleanupFn", void 0);
233
+ defineElement('date-input', LyraDateInput);
@@ -0,0 +1 @@
1
+ export declare const styles: import("lit").CSSResult;
@@ -0,0 +1,67 @@
1
+ import { css } from 'lit';
2
+ export const styles = css `
3
+ :host {
4
+ display: block;
5
+ }
6
+ [part='form-control-label'] {
7
+ display: block;
8
+ margin-block-end: var(--lyra-space-xs);
9
+ font-size: 0.875rem;
10
+ font-weight: 600;
11
+ }
12
+ [part='form-control-label']:empty {
13
+ display: none;
14
+ }
15
+ [part='input-wrapper'] {
16
+ display: flex;
17
+ align-items: center;
18
+ gap: var(--lyra-space-xs);
19
+ inline-size: 100%;
20
+ padding: var(--lyra-space-xs) var(--lyra-space-s);
21
+ border: 1px solid var(--lyra-color-border);
22
+ border-radius: var(--lyra-radius);
23
+ background: var(--lyra-color-surface);
24
+ }
25
+ [part='input-wrapper']:focus-within {
26
+ border-color: var(--lyra-color-brand);
27
+ }
28
+ :host([disabled]) [part='input-wrapper'] {
29
+ opacity: 0.5;
30
+ }
31
+ [part='input'] {
32
+ flex: 1 1 auto;
33
+ min-inline-size: 0;
34
+ border: none;
35
+ outline: none;
36
+ background: transparent;
37
+ color: inherit;
38
+ font: inherit;
39
+ }
40
+ [part='clear-button'],
41
+ [part='expand-button'] {
42
+ flex: 0 0 auto;
43
+ border: none;
44
+ background: none;
45
+ cursor: pointer;
46
+ color: var(--lyra-color-text-quiet);
47
+ padding: 0 var(--lyra-space-xs);
48
+ line-height: 1;
49
+ font-size: 1rem;
50
+ }
51
+ [part='popup'] {
52
+ display: none;
53
+ position: fixed;
54
+ z-index: 900;
55
+ }
56
+ :host([open]) [part='popup'] {
57
+ display: block;
58
+ }
59
+ [part='hint'] {
60
+ margin-block-start: var(--lyra-space-xs);
61
+ font-size: 0.8125rem;
62
+ color: var(--lyra-color-text-quiet);
63
+ }
64
+ [part='hint']:empty {
65
+ display: none;
66
+ }
67
+ `;