@lynx-js/genui 0.0.1-rc.0 → 0.0.1

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 (78) hide show
  1. package/a2ui/README.md +777 -100
  2. package/a2ui/dist/catalog/ChoicePicker/catalog.json +265 -0
  3. package/a2ui/dist/catalog/ChoicePicker/index.d.ts +56 -0
  4. package/a2ui/dist/catalog/ChoicePicker/index.js +66 -0
  5. package/a2ui/dist/catalog/ChoicePicker/index.js.map +1 -0
  6. package/a2ui/dist/catalog/ChoicePicker/utils.d.ts +13 -0
  7. package/a2ui/dist/catalog/ChoicePicker/utils.js +80 -0
  8. package/a2ui/dist/catalog/ChoicePicker/utils.js.map +1 -0
  9. package/a2ui/dist/catalog/Column/index.js +3 -7
  10. package/a2ui/dist/catalog/Column/index.js.map +1 -1
  11. package/a2ui/dist/catalog/DateTimeInput/catalog.json +165 -0
  12. package/a2ui/dist/catalog/DateTimeInput/index.d.ts +43 -0
  13. package/a2ui/dist/catalog/DateTimeInput/index.js +147 -0
  14. package/a2ui/dist/catalog/DateTimeInput/index.js.map +1 -0
  15. package/a2ui/dist/catalog/DateTimeInput/utils.d.ts +53 -0
  16. package/a2ui/dist/catalog/DateTimeInput/utils.js +248 -0
  17. package/a2ui/dist/catalog/DateTimeInput/utils.js.map +1 -0
  18. package/a2ui/dist/catalog/Icon/catalog.json +173 -2
  19. package/a2ui/dist/catalog/Icon/index.d.ts +2 -2
  20. package/a2ui/dist/catalog/Icon/index.js.map +1 -1
  21. package/a2ui/dist/catalog/Image/catalog.json +1 -17
  22. package/a2ui/dist/catalog/Image/index.d.ts +1 -3
  23. package/a2ui/dist/catalog/Image/index.js +3 -11
  24. package/a2ui/dist/catalog/Image/index.js.map +1 -1
  25. package/a2ui/dist/catalog/LineChart/index.js +3 -3
  26. package/a2ui/dist/catalog/LineChart/index.js.map +1 -1
  27. package/a2ui/dist/catalog/Modal/index.js +1 -1
  28. package/a2ui/dist/catalog/Modal/index.js.map +1 -1
  29. package/a2ui/dist/catalog/index.d.ts +4 -0
  30. package/a2ui/dist/catalog/index.js +2046 -3
  31. package/a2ui/dist/catalog/index.js.map +1 -1
  32. package/a2ui/dist/index.d.ts +1 -1
  33. package/a2ui/dist/index.js +1 -1
  34. package/a2ui/dist/index.js.map +1 -1
  35. package/a2ui/dist/react/A2UIRenderer.d.ts +1 -0
  36. package/a2ui/dist/react/A2UIRenderer.js +8 -6
  37. package/a2ui/dist/react/A2UIRenderer.js.map +1 -1
  38. package/a2ui/dist/react/useAction.js +2 -1
  39. package/a2ui/dist/react/useAction.js.map +1 -1
  40. package/a2ui/dist/react/useChecks.js +7 -2
  41. package/a2ui/dist/react/useChecks.js.map +1 -1
  42. package/a2ui/dist/react/useDataBinding.d.ts +1 -1
  43. package/a2ui/dist/react/useDataBinding.js +24 -48
  44. package/a2ui/dist/react/useDataBinding.js.map +1 -1
  45. package/a2ui/dist/store/MessageProcessor.js +7 -19
  46. package/a2ui/dist/store/MessageProcessor.js.map +1 -1
  47. package/a2ui/dist/store/SignalStore.d.ts +2 -0
  48. package/a2ui/dist/store/SignalStore.js +5 -0
  49. package/a2ui/dist/store/SignalStore.js.map +1 -1
  50. package/a2ui/dist/store/index.d.ts +3 -1
  51. package/a2ui/dist/store/index.js +3 -1
  52. package/a2ui/dist/store/index.js.map +1 -1
  53. package/a2ui/dist/store/resolveDynamic.d.ts +9 -0
  54. package/a2ui/dist/store/resolveDynamic.js +88 -0
  55. package/a2ui/dist/store/resolveDynamic.js.map +1 -0
  56. package/a2ui/dist/store/resolveFunctionCall.d.ts +2 -4
  57. package/a2ui/dist/store/resolveFunctionCall.js +24 -82
  58. package/a2ui/dist/store/resolveFunctionCall.js.map +1 -1
  59. package/a2ui/dist/store/signalResolution.d.ts +4 -0
  60. package/a2ui/dist/store/signalResolution.js +25 -0
  61. package/a2ui/dist/store/signalResolution.js.map +1 -0
  62. package/a2ui/dist/store/utils.d.ts +7 -0
  63. package/a2ui/dist/store/utils.js +24 -0
  64. package/a2ui/dist/store/utils.js.map +1 -0
  65. package/a2ui/dist/tsconfig.build.tsbuildinfo +1 -1
  66. package/a2ui/styles/catalog/ChoicePicker.css +157 -0
  67. package/a2ui/styles/catalog/DateTimeInput.css +375 -0
  68. package/a2ui/styles/catalog/Icon.css +1 -1
  69. package/a2ui/styles/catalog/Text.css +11 -11
  70. package/a2ui/styles/theme.css +2 -1
  71. package/a2ui-catalog-extractor/README.md +23 -15
  72. package/a2ui-catalog-extractor/bin/a2ui-catalog-extractor.js +0 -1
  73. package/a2ui-catalog-extractor/dist/tsconfig.build.tsbuildinfo +1 -1
  74. package/a2ui-prompt/README.md +1 -2
  75. package/a2ui-prompt/dist/index.js +65 -31
  76. package/cli/bin/cli.js +5 -2
  77. package/dist/tsconfig.build.tsbuildinfo +1 -1
  78. package/package.json +8 -1
@@ -0,0 +1,165 @@
1
+ {
2
+ "DateTimeInput": {
3
+ "properties": {
4
+ "value": {
5
+ "oneOf": [
6
+ {
7
+ "type": "string"
8
+ },
9
+ {
10
+ "type": "object",
11
+ "properties": {
12
+ "path": {
13
+ "type": "string"
14
+ }
15
+ },
16
+ "required": [
17
+ "path"
18
+ ],
19
+ "additionalProperties": false
20
+ }
21
+ ],
22
+ "description": "The current date/time value. Typically bound to a data path."
23
+ },
24
+ "label": {
25
+ "oneOf": [
26
+ {
27
+ "type": "string"
28
+ },
29
+ {
30
+ "type": "object",
31
+ "properties": {
32
+ "path": {
33
+ "type": "string"
34
+ }
35
+ },
36
+ "required": [
37
+ "path"
38
+ ],
39
+ "additionalProperties": false
40
+ },
41
+ {
42
+ "type": "object",
43
+ "properties": {
44
+ "call": {
45
+ "type": "string"
46
+ },
47
+ "args": {
48
+ "type": "object",
49
+ "additionalProperties": true
50
+ },
51
+ "returnType": {
52
+ "type": "string",
53
+ "enum": [
54
+ "string",
55
+ "number",
56
+ "boolean",
57
+ "object",
58
+ "array",
59
+ "any",
60
+ "void"
61
+ ]
62
+ }
63
+ },
64
+ "required": [
65
+ "call",
66
+ "args"
67
+ ],
68
+ "additionalProperties": false
69
+ }
70
+ ],
71
+ "description": "The text label for the input field."
72
+ },
73
+ "enableDate": {
74
+ "type": "boolean",
75
+ "description": "Whether to show the date picker."
76
+ },
77
+ "enableTime": {
78
+ "type": "boolean",
79
+ "description": "Whether to show the time picker."
80
+ },
81
+ "outputFormat": {
82
+ "type": "string",
83
+ "description": "Format string for the output value. Supports YYYY, MM, DD, HH, and mm."
84
+ },
85
+ "min": {
86
+ "type": "string",
87
+ "description": "Minimum allowed date/time value."
88
+ },
89
+ "max": {
90
+ "type": "string",
91
+ "description": "Maximum allowed date/time value."
92
+ },
93
+ "checks": {
94
+ "type": "array",
95
+ "items": {
96
+ "type": "object",
97
+ "properties": {
98
+ "condition": {
99
+ "oneOf": [
100
+ {
101
+ "type": "boolean"
102
+ },
103
+ {
104
+ "type": "object",
105
+ "properties": {
106
+ "path": {
107
+ "type": "string"
108
+ }
109
+ },
110
+ "required": [
111
+ "path"
112
+ ],
113
+ "additionalProperties": false
114
+ },
115
+ {
116
+ "type": "object",
117
+ "properties": {
118
+ "call": {
119
+ "type": "string"
120
+ },
121
+ "args": {
122
+ "type": "object",
123
+ "additionalProperties": true
124
+ },
125
+ "returnType": {
126
+ "type": "string",
127
+ "enum": [
128
+ "string",
129
+ "number",
130
+ "boolean",
131
+ "object",
132
+ "array",
133
+ "any",
134
+ "void"
135
+ ]
136
+ }
137
+ },
138
+ "required": [
139
+ "call",
140
+ "args"
141
+ ],
142
+ "additionalProperties": false
143
+ }
144
+ ],
145
+ "description": "The condition that indicates whether the check passes."
146
+ },
147
+ "message": {
148
+ "type": "string",
149
+ "description": "The error message to display if the check fails."
150
+ }
151
+ },
152
+ "required": [
153
+ "condition",
154
+ "message"
155
+ ],
156
+ "additionalProperties": false
157
+ },
158
+ "description": "A list of checks to perform."
159
+ }
160
+ },
161
+ "required": [
162
+ "value"
163
+ ]
164
+ }
165
+ }
@@ -0,0 +1,43 @@
1
+ import type { GenericComponentProps } from '../../store/types.js';
2
+ import '../../../styles/catalog/DateTimeInput.css';
3
+ /**
4
+ * @a2uiCatalog DateTimeInput
5
+ */
6
+ export interface DateTimeInputProps extends GenericComponentProps {
7
+ /** The current date/time value. Typically bound to a data path. */
8
+ value: string | {
9
+ path: string;
10
+ };
11
+ /** The text label for the input field. */
12
+ label?: string | {
13
+ path: string;
14
+ } | {
15
+ call: string;
16
+ args: Record<string, unknown>;
17
+ returnType?: 'string' | 'number' | 'boolean' | 'array' | 'object' | 'any' | 'void';
18
+ };
19
+ /** Whether to show the date picker. */
20
+ enableDate?: boolean;
21
+ /** Whether to show the time picker. */
22
+ enableTime?: boolean;
23
+ /** Format string for the output value. Supports YYYY, MM, DD, HH, and mm. */
24
+ outputFormat?: string;
25
+ /** Minimum allowed date/time value. */
26
+ min?: string;
27
+ /** Maximum allowed date/time value. */
28
+ max?: string;
29
+ /** A list of checks to perform. */
30
+ checks?: Array<{
31
+ /** The condition that indicates whether the check passes. */
32
+ condition: boolean | {
33
+ path: string;
34
+ } | {
35
+ call: string;
36
+ args: Record<string, unknown>;
37
+ returnType?: 'string' | 'number' | 'boolean' | 'array' | 'object' | 'any' | 'void';
38
+ };
39
+ /** The error message to display if the check fails. */
40
+ message: string;
41
+ }>;
42
+ }
43
+ export declare function DateTimeInput(props: DateTimeInputProps): import('@lynx-js/react').ReactNode;
@@ -0,0 +1,147 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@lynx-js/react/jsx-runtime";
2
+ // Copyright 2026 The Lynx Authors. All rights reserved.
3
+ // Licensed under the Apache License Version 2.0 that can be found in the
4
+ // LICENSE file in the root directory of this source tree.
5
+ import { DialogBackdrop, DialogContent, DialogRoot, DialogView, } from '@lynx-js/lynx-ui';
6
+ import { useEffect, useState } from '@lynx-js/react';
7
+ import { addMonths, buildDateTimeMonthPage, dateTimePartsToDate, formatDateTimeInputValue, getDateTimeDialogTitle, getDateTimeInputPlaceholder, getDefaultDateTimeParts, getWeekdayLabels, incrementDateTimePart, isDateTimeAfterMax, isDateTimeBeforeMin, normalizeDateTimeInputLabel, normalizeDateTimeInputMode, normalizeDateTimeInputValue, startOfMonth, withDate, } from './utils.js';
8
+ import { useChecks } from '../../react/useChecks.js';
9
+ import '../../../styles/catalog/DateTimeInput.css';
10
+ const MONTH_LABELS = [
11
+ 'January',
12
+ 'February',
13
+ 'March',
14
+ 'April',
15
+ 'May',
16
+ 'June',
17
+ 'July',
18
+ 'August',
19
+ 'September',
20
+ 'October',
21
+ 'November',
22
+ 'December',
23
+ ];
24
+ function formatMonthCaption(month) {
25
+ return `${MONTH_LABELS[month.getMonth()]} ${month.getFullYear()}`;
26
+ }
27
+ function joinClassNames(values) {
28
+ return values.filter(Boolean).join(' ');
29
+ }
30
+ function getPartsKey(parts) {
31
+ return parts
32
+ ? formatDateTimeInputValue(parts, 'YYYY-MM-DD HH:mm', { enableDate: true, enableTime: true })
33
+ : '';
34
+ }
35
+ export function DateTimeInput(props) {
36
+ const { dataContextPath, id, label, max, min, outputFormat, setValue, surface, } = props;
37
+ const mode = normalizeDateTimeInputMode(props.enableDate, props.enableTime);
38
+ const valueParts = normalizeDateTimeInputValue(props.value);
39
+ const minParts = normalizeDateTimeInputValue(min);
40
+ const maxParts = normalizeDateTimeInputValue(max);
41
+ const valueKey = getPartsKey(valueParts);
42
+ const initialParts = valueParts ?? getDefaultDateTimeParts();
43
+ const [open, setOpen] = useState(false);
44
+ const [draftParts, setDraftParts] = useState(initialParts);
45
+ const [visibleMonth, setVisibleMonth] = useState(startOfMonth(dateTimePartsToDate(initialParts)));
46
+ const checks = props.checks;
47
+ const { ok, firstFailureMessage } = useChecks({
48
+ checks,
49
+ componentId: id ?? '',
50
+ surface,
51
+ dataContextPath,
52
+ });
53
+ useEffect(() => {
54
+ if (open)
55
+ return undefined;
56
+ const nextParts = valueParts ?? getDefaultDateTimeParts();
57
+ setDraftParts(nextParts);
58
+ setVisibleMonth(startOfMonth(dateTimePartsToDate(nextParts)));
59
+ return undefined;
60
+ }, [open, valueKey]);
61
+ const minDate = minParts ? dateTimePartsToDate(minParts) : null;
62
+ const maxDate = maxParts ? dateTimePartsToDate(maxParts) : null;
63
+ const draftDate = dateTimePartsToDate(draftParts);
64
+ const monthPage = buildDateTimeMonthPage({
65
+ month: visibleMonth,
66
+ selectedDate: draftDate,
67
+ today: new Date(),
68
+ minDate,
69
+ maxDate,
70
+ });
71
+ const weekdayLabels = getWeekdayLabels();
72
+ const draftOutOfRange = isDateTimeBeforeMin(draftParts, minParts)
73
+ || isDateTimeAfterMax(draftParts, maxParts);
74
+ const currentOutOfRange = valueParts
75
+ ? isDateTimeBeforeMin(valueParts, minParts)
76
+ || isDateTimeAfterMax(valueParts, maxParts)
77
+ : false;
78
+ const invalid = !ok || currentOutOfRange;
79
+ const labelText = normalizeDateTimeInputLabel(label);
80
+ const displayValue = valueParts
81
+ ? formatDateTimeInputValue(valueParts, outputFormat, mode)
82
+ : getDateTimeInputPlaceholder(mode);
83
+ const handleOpen = () => {
84
+ const nextParts = valueParts ?? draftParts ?? getDefaultDateTimeParts();
85
+ setDraftParts(nextParts);
86
+ setVisibleMonth(startOfMonth(dateTimePartsToDate(nextParts)));
87
+ setOpen(true);
88
+ };
89
+ const handleCancel = () => {
90
+ setOpen(false);
91
+ };
92
+ const handleConfirm = () => {
93
+ if (draftOutOfRange)
94
+ return;
95
+ setValue?.('value', formatDateTimeInputValue(draftParts, outputFormat, mode));
96
+ setOpen(false);
97
+ };
98
+ const handlePreviousMonth = () => {
99
+ setVisibleMonth(addMonths(visibleMonth, -1));
100
+ };
101
+ const handleNextMonth = () => {
102
+ setVisibleMonth(addMonths(visibleMonth, 1));
103
+ };
104
+ const handleTimeStep = (part, delta) => {
105
+ setDraftParts((current) => incrementDateTimePart(current, part, delta));
106
+ };
107
+ const rootClassName = joinClassNames([
108
+ 'datetime-input',
109
+ invalid && 'datetime-input-invalid',
110
+ ]);
111
+ return (_jsxs("view", { className: rootClassName, children: [labelText
112
+ ? _jsx("text", { className: 'datetime-input-label', children: labelText })
113
+ : null, _jsxs("view", { className: joinClassNames([
114
+ 'datetime-input-control',
115
+ !valueParts && 'datetime-input-control-placeholder',
116
+ ]), bindtap: handleOpen, "event-through": false, children: [_jsx("text", { className: 'datetime-input-value', children: displayValue }), _jsx("text", { className: 'datetime-input-icon', children: "calendar_today" })] }), invalid && firstFailureMessage
117
+ ? _jsx("text", { className: 'datetime-input-error', children: firstFailureMessage })
118
+ : null, currentOutOfRange
119
+ ? _jsx("text", { className: 'datetime-input-error', children: "Date is out of range" })
120
+ : null, _jsx(DialogRoot, { show: open, onShowChange: (nextOpen) => {
121
+ setOpen(nextOpen);
122
+ }, children: _jsxs(DialogView, { className: 'datetime-dialog-view', overlayLevel: 4, children: [_jsx(DialogBackdrop, { className: 'datetime-dialog-backdrop', clickToClose: true, transition: true }), _jsxs(DialogContent, { className: 'datetime-dialog-content', transition: true, children: [_jsxs("view", { className: 'datetime-dialog-header', children: [_jsx("text", { className: 'datetime-dialog-title', children: getDateTimeDialogTitle(labelText, mode) }), _jsx("view", { className: 'datetime-dialog-close', bindtap: handleCancel, "event-through": false, children: _jsx("text", { className: 'datetime-dialog-close-icon', children: "close" }) })] }), mode.enableDate
123
+ ? (_jsxs("view", { className: 'datetime-calendar', children: [_jsxs("view", { className: 'datetime-calendar-header', children: [_jsx("view", { className: 'datetime-calendar-nav', bindtap: handlePreviousMonth, "event-through": false, children: _jsx("text", { className: 'datetime-calendar-nav-icon', children: "chevron_left" }) }), _jsx("text", { className: 'datetime-calendar-caption', children: formatMonthCaption(visibleMonth) }), _jsx("view", { className: 'datetime-calendar-nav', bindtap: handleNextMonth, "event-through": false, children: _jsx("text", { className: 'datetime-calendar-nav-icon', children: "chevron_right" }) })] }), _jsx("view", { className: 'datetime-weekdays', children: weekdayLabels.map((weekday, weekdayIndex) => (_jsx("view", { className: 'datetime-weekday', children: _jsx("text", { className: 'datetime-weekday-text', children: weekday }) }, weekdayIndex))) }), _jsx("view", { className: 'datetime-month', children: monthPage.days.map((day, dayIndex) => (_jsx("view", { className: joinClassNames([
124
+ 'datetime-day',
125
+ day.outside && 'datetime-day-outside',
126
+ day.selected && 'datetime-day-selected',
127
+ day.today && 'datetime-day-today',
128
+ day.disabled && 'datetime-day-disabled',
129
+ ]), bindtap: () => {
130
+ if (day.disabled)
131
+ return;
132
+ setDraftParts((current) => withDate(current, day.date));
133
+ if (day.outside) {
134
+ setVisibleMonth(startOfMonth(day.date));
135
+ }
136
+ }, "event-through": false, children: _jsx("text", { className: 'datetime-day-text', children: String(day.day) }) }, dayIndex))) })] }))
137
+ : null, mode.enableTime
138
+ ? (_jsxs("view", { className: 'datetime-time', children: [_jsx("text", { className: 'datetime-time-label', children: "Time" }), _jsxs("view", { className: 'datetime-time-fields', children: [_jsxs("view", { className: 'datetime-time-field', children: [_jsx("view", { className: 'datetime-time-stepper', bindtap: () => handleTimeStep('hour', 1), "event-through": false, children: _jsx("text", { className: 'datetime-time-stepper-icon', children: "expand_less" }) }), _jsx("text", { className: 'datetime-time-value', children: String(draftParts.hour).padStart(2, '0') }), _jsx("view", { className: 'datetime-time-stepper', bindtap: () => handleTimeStep('hour', -1), "event-through": false, children: _jsx("text", { className: 'datetime-time-stepper-icon', children: "expand_more" }) })] }), _jsx("text", { className: 'datetime-time-separator', children: ":" }), _jsxs("view", { className: 'datetime-time-field', children: [_jsx("view", { className: 'datetime-time-stepper', bindtap: () => handleTimeStep('minute', 1), "event-through": false, children: _jsx("text", { className: 'datetime-time-stepper-icon', children: "expand_less" }) }), _jsx("text", { className: 'datetime-time-value', children: String(draftParts.minute).padStart(2, '0') }), _jsx("view", { className: 'datetime-time-stepper', bindtap: () => handleTimeStep('minute', -1), "event-through": false, children: _jsx("text", { className: 'datetime-time-stepper-icon', children: "expand_more" }) })] })] })] }))
139
+ : null, draftOutOfRange
140
+ ? (_jsx("text", { className: 'datetime-dialog-error', children: "Date is out of range" }))
141
+ : null, _jsxs("view", { className: 'datetime-dialog-actions', children: [_jsx("view", { className: 'datetime-dialog-button datetime-dialog-button-secondary', bindtap: handleCancel, "event-through": false, children: _jsx("text", { className: 'datetime-dialog-button-text-secondary', children: "Cancel" }) }), _jsx("view", { className: joinClassNames([
142
+ 'datetime-dialog-button',
143
+ 'datetime-dialog-button-primary',
144
+ draftOutOfRange && 'datetime-dialog-button-disabled',
145
+ ]), bindtap: handleConfirm, "event-through": false, children: _jsx("text", { className: 'datetime-dialog-button-text-primary', children: "Done" }) })] })] })] }) })] }, id));
146
+ }
147
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/catalog/DateTimeInput/index.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ export interface DateTimeParts {
2
+ year: number;
3
+ month: number;
4
+ day: number;
5
+ hour: number;
6
+ minute: number;
7
+ }
8
+ export interface DateTimeInputMode {
9
+ enableDate: boolean;
10
+ enableTime: boolean;
11
+ }
12
+ export interface DateTimeDayInfo {
13
+ date: Date;
14
+ dateKey: string;
15
+ day: number;
16
+ outside: boolean;
17
+ selected: boolean;
18
+ today: boolean;
19
+ disabled: boolean;
20
+ }
21
+ export interface DateTimeMonthPage {
22
+ month: Date;
23
+ monthKey: string;
24
+ days: DateTimeDayInfo[];
25
+ }
26
+ export interface BuildDateTimeMonthPageOptions {
27
+ month: Date;
28
+ selectedDate: Date | null;
29
+ today: Date;
30
+ minDate: Date | null;
31
+ maxDate: Date | null;
32
+ weekStartsOn?: number;
33
+ }
34
+ export declare function normalizeDateTimeInputValue(value: unknown): DateTimeParts | null;
35
+ export declare function getDefaultDateTimeParts(now?: Date): DateTimeParts;
36
+ export declare function dateTimePartsToDate(parts: DateTimeParts): Date;
37
+ export declare function dateTimePartsToDateKey(parts: DateTimeParts): string;
38
+ export declare function formatDateKey(date: Date): string;
39
+ export declare function formatMonthKey(date: Date): string;
40
+ export declare function startOfMonth(date: Date): Date;
41
+ export declare function addMonths(date: Date, offset: number): Date;
42
+ export declare function getWeekdayLabels(weekStartsOn?: number, labels?: string[]): string[];
43
+ export declare function compareDateTimeParts(a: DateTimeParts, b: DateTimeParts): number;
44
+ export declare function isDateTimeBeforeMin(value: DateTimeParts, min: DateTimeParts | null): boolean;
45
+ export declare function isDateTimeAfterMax(value: DateTimeParts, max: DateTimeParts | null): boolean;
46
+ export declare function buildDateTimeMonthPage({ month, selectedDate, today, minDate, maxDate, weekStartsOn, }: BuildDateTimeMonthPageOptions): DateTimeMonthPage;
47
+ export declare function normalizeDateTimeInputMode(enableDate: unknown, enableTime: unknown): DateTimeInputMode;
48
+ export declare function normalizeDateTimeInputLabel(value: unknown): string;
49
+ export declare function formatDateTimeInputValue(parts: DateTimeParts, outputFormat: unknown, mode: DateTimeInputMode): string;
50
+ export declare function getDateTimeInputPlaceholder(mode: DateTimeInputMode): string;
51
+ export declare function getDateTimeDialogTitle(label: string, mode: DateTimeInputMode): string;
52
+ export declare function withDate(parts: DateTimeParts, date: Date): DateTimeParts;
53
+ export declare function incrementDateTimePart(parts: DateTimeParts, part: 'hour' | 'minute', delta: number): DateTimeParts;
@@ -0,0 +1,248 @@
1
+ // Copyright 2026 The Lynx Authors. All rights reserved.
2
+ // Licensed under the Apache License Version 2.0 that can be found in the
3
+ // LICENSE file in the root directory of this source tree.
4
+ const DAYS_PER_WEEK = 7;
5
+ const DATE_TIME_DAYS_PER_MONTH_PAGE = 42;
6
+ const DEFAULT_WEEKDAY_LABELS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
7
+ function pad2(value) {
8
+ return value < 10 ? `0${value}` : `${value}`;
9
+ }
10
+ function pad4(value) {
11
+ if (value < 10)
12
+ return `000${value}`;
13
+ if (value < 100)
14
+ return `00${value}`;
15
+ if (value < 1000)
16
+ return `0${value}`;
17
+ return `${value}`;
18
+ }
19
+ function createLocalDate(year, month, day = 1, hour = 0, minute = 0) {
20
+ return new Date(year, month, day, hour, minute, 0, 0);
21
+ }
22
+ function isValidDate(value) {
23
+ return !Number.isNaN(value.getTime());
24
+ }
25
+ function daysInMonth(year, month) {
26
+ return createLocalDate(year, month, 0).getDate();
27
+ }
28
+ function isValidDatePart(year, month, day) {
29
+ return month >= 1
30
+ && month <= 12
31
+ && day >= 1
32
+ && day <= daysInMonth(year, month);
33
+ }
34
+ function isValidTimePart(hour, minute) {
35
+ return hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59;
36
+ }
37
+ function partsFromDate(value) {
38
+ return {
39
+ year: value.getFullYear(),
40
+ month: value.getMonth() + 1,
41
+ day: value.getDate(),
42
+ hour: value.getHours(),
43
+ minute: value.getMinutes(),
44
+ };
45
+ }
46
+ function parseDateTimeString(value) {
47
+ const trimmed = value.trim();
48
+ if (!trimmed)
49
+ return null;
50
+ const dateTimeMatch = /^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}))?$/
51
+ .exec(trimmed);
52
+ if (dateTimeMatch) {
53
+ const [, year, month, day, hour = '0', minute = '0'] = dateTimeMatch;
54
+ const yearValue = Number(year);
55
+ const monthValue = Number(month);
56
+ const dayValue = Number(day);
57
+ const hourValue = Number(hour);
58
+ const minuteValue = Number(minute);
59
+ if (!isValidDatePart(yearValue, monthValue, dayValue)
60
+ || !isValidTimePart(hourValue, minuteValue)) {
61
+ return null;
62
+ }
63
+ const date = createLocalDate(yearValue, monthValue - 1, dayValue, hourValue, minuteValue);
64
+ return isValidDate(date) ? partsFromDate(date) : null;
65
+ }
66
+ const timeMatch = /^(\d{2}):(\d{2})$/.exec(trimmed);
67
+ if (timeMatch) {
68
+ const today = new Date();
69
+ const [, hour, minute] = timeMatch;
70
+ const hourValue = Number(hour);
71
+ const minuteValue = Number(minute);
72
+ if (!isValidTimePart(hourValue, minuteValue))
73
+ return null;
74
+ const date = createLocalDate(today.getFullYear(), today.getMonth(), today.getDate(), hourValue, minuteValue);
75
+ return isValidDate(date) ? partsFromDate(date) : null;
76
+ }
77
+ const date = new Date(trimmed);
78
+ return isValidDate(date) ? partsFromDate(date) : null;
79
+ }
80
+ export function normalizeDateTimeInputValue(value) {
81
+ if (value instanceof Date) {
82
+ return isValidDate(value) ? partsFromDate(value) : null;
83
+ }
84
+ if (typeof value === 'number') {
85
+ const date = new Date(value);
86
+ return isValidDate(date) ? partsFromDate(date) : null;
87
+ }
88
+ if (typeof value === 'string') {
89
+ return parseDateTimeString(value);
90
+ }
91
+ return null;
92
+ }
93
+ export function getDefaultDateTimeParts(now = new Date()) {
94
+ return {
95
+ year: now.getFullYear(),
96
+ month: now.getMonth() + 1,
97
+ day: now.getDate(),
98
+ hour: now.getHours(),
99
+ minute: now.getMinutes(),
100
+ };
101
+ }
102
+ export function dateTimePartsToDate(parts) {
103
+ return createLocalDate(parts.year, parts.month - 1, parts.day, parts.hour, parts.minute);
104
+ }
105
+ export function dateTimePartsToDateKey(parts) {
106
+ return `${pad4(parts.year)}-${pad2(parts.month)}-${pad2(parts.day)}`;
107
+ }
108
+ export function formatDateKey(date) {
109
+ return [
110
+ pad4(date.getFullYear()),
111
+ pad2(date.getMonth() + 1),
112
+ pad2(date.getDate()),
113
+ ].join('-');
114
+ }
115
+ export function formatMonthKey(date) {
116
+ return `${pad4(date.getFullYear())}-${pad2(date.getMonth() + 1)}`;
117
+ }
118
+ export function startOfMonth(date) {
119
+ return createLocalDate(date.getFullYear(), date.getMonth(), 1);
120
+ }
121
+ export function addMonths(date, offset) {
122
+ return createLocalDate(date.getFullYear(), date.getMonth() + offset, 1);
123
+ }
124
+ export function getWeekdayLabels(weekStartsOn = 0, labels = DEFAULT_WEEKDAY_LABELS) {
125
+ const start = Math.max(0, Math.min(6, Math.floor(weekStartsOn)));
126
+ return Array.from({ length: DAYS_PER_WEEK }, (_, index) => {
127
+ const weekdayIndex = (start + index) % DAYS_PER_WEEK;
128
+ return labels[weekdayIndex] ?? DEFAULT_WEEKDAY_LABELS[weekdayIndex];
129
+ });
130
+ }
131
+ function compareDateOnly(a, b) {
132
+ const left = a.getFullYear() * 10000
133
+ + (a.getMonth() + 1) * 100
134
+ + a.getDate();
135
+ const right = b.getFullYear() * 10000
136
+ + (b.getMonth() + 1) * 100
137
+ + b.getDate();
138
+ return left - right;
139
+ }
140
+ export function compareDateTimeParts(a, b) {
141
+ const left = a.year * 100000000
142
+ + a.month * 1000000
143
+ + a.day * 10000
144
+ + a.hour * 100
145
+ + a.minute;
146
+ const right = b.year * 100000000
147
+ + b.month * 1000000
148
+ + b.day * 10000
149
+ + b.hour * 100
150
+ + b.minute;
151
+ return left - right;
152
+ }
153
+ export function isDateTimeBeforeMin(value, min) {
154
+ return min !== null && compareDateTimeParts(value, min) < 0;
155
+ }
156
+ export function isDateTimeAfterMax(value, max) {
157
+ return max !== null && compareDateTimeParts(value, max) > 0;
158
+ }
159
+ export function buildDateTimeMonthPage({ month, selectedDate, today, minDate, maxDate, weekStartsOn = 0, }) {
160
+ const monthStart = startOfMonth(month);
161
+ const normalizedWeekStart = Math.max(0, Math.min(6, Math.floor(weekStartsOn)));
162
+ const firstWeekdayOffset = (monthStart.getDay() - normalizedWeekStart + DAYS_PER_WEEK)
163
+ % DAYS_PER_WEEK;
164
+ const gridStart = createLocalDate(monthStart.getFullYear(), monthStart.getMonth(), 1 - firstWeekdayOffset);
165
+ const selectedDateKey = selectedDate ? formatDateKey(selectedDate) : null;
166
+ const todayKey = formatDateKey(today);
167
+ const days = Array.from({ length: DATE_TIME_DAYS_PER_MONTH_PAGE }, (_, index) => {
168
+ const date = createLocalDate(gridStart.getFullYear(), gridStart.getMonth(), gridStart.getDate() + index);
169
+ const dateKey = formatDateKey(date);
170
+ const outside = date.getMonth() !== monthStart.getMonth();
171
+ const disabled = (minDate !== null && compareDateOnly(date, minDate) < 0)
172
+ || (maxDate !== null && compareDateOnly(date, maxDate) > 0);
173
+ return {
174
+ date,
175
+ dateKey,
176
+ day: date.getDate(),
177
+ outside,
178
+ selected: dateKey === selectedDateKey,
179
+ today: dateKey === todayKey,
180
+ disabled,
181
+ };
182
+ });
183
+ return {
184
+ month: monthStart,
185
+ monthKey: formatMonthKey(monthStart),
186
+ days,
187
+ };
188
+ }
189
+ export function normalizeDateTimeInputMode(enableDate, enableTime) {
190
+ const date = enableDate !== false;
191
+ const time = enableTime !== false;
192
+ if (!date && !time) {
193
+ return { enableDate: true, enableTime: false };
194
+ }
195
+ return { enableDate: date, enableTime: time };
196
+ }
197
+ export function normalizeDateTimeInputLabel(value) {
198
+ if (typeof value === 'string'
199
+ || typeof value === 'number'
200
+ || typeof value === 'boolean') {
201
+ return String(value);
202
+ }
203
+ return '';
204
+ }
205
+ function getDefaultOutputFormat(mode) {
206
+ if (!mode.enableDate && mode.enableTime)
207
+ return 'HH:mm';
208
+ return 'YYYY-MM-DD';
209
+ }
210
+ export function formatDateTimeInputValue(parts, outputFormat, mode) {
211
+ const format = typeof outputFormat === 'string' && outputFormat.trim()
212
+ ? outputFormat
213
+ : getDefaultOutputFormat(mode);
214
+ return format
215
+ .replaceAll('YYYY', pad4(parts.year))
216
+ .replaceAll('MM', pad2(parts.month))
217
+ .replaceAll('DD', pad2(parts.day))
218
+ .replaceAll('HH', pad2(parts.hour))
219
+ .replaceAll('mm', pad2(parts.minute));
220
+ }
221
+ export function getDateTimeInputPlaceholder(mode) {
222
+ if (mode.enableDate && mode.enableTime)
223
+ return 'Select date and time';
224
+ if (mode.enableTime)
225
+ return 'Select time';
226
+ return 'Select date';
227
+ }
228
+ export function getDateTimeDialogTitle(label, mode) {
229
+ return label || getDateTimeInputPlaceholder(mode);
230
+ }
231
+ export function withDate(parts, date) {
232
+ return {
233
+ ...parts,
234
+ year: date.getFullYear(),
235
+ month: date.getMonth() + 1,
236
+ day: date.getDate(),
237
+ };
238
+ }
239
+ export function incrementDateTimePart(parts, part, delta) {
240
+ const limit = part === 'hour' ? 24 : 60;
241
+ const current = parts[part];
242
+ const next = ((current + delta) % limit + limit) % limit;
243
+ return {
244
+ ...parts,
245
+ [part]: next,
246
+ };
247
+ }
248
+ //# sourceMappingURL=utils.js.map