minerva-design 1.0.0 → 1.0.2
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.
- package/CHANGELOG.md +12 -0
- package/custom-elements.json +663 -0
- package/dist/angular/fesm2022/minerva-angular.mjs +1163 -34
- package/dist/angular/fesm2022/minerva-angular.mjs.map +1 -1
- package/dist/angular/types/minerva-angular.d.ts +237 -1
- package/dist/core/calendar-date.d.cts +5 -0
- package/dist/core/calendar-date.d.ts +5 -0
- package/dist/core/contracts.cjs +1 -1
- package/dist/core/contracts.cjs.map +1 -1
- package/dist/core/contracts.js +1 -1
- package/dist/core/contracts.js.map +1 -1
- package/dist/core/index.cjs +6 -6
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +671 -630
- package/dist/core/index.js.map +1 -1
- package/dist/core/styling-hooks/components/date-picker.d.cts +45 -0
- package/dist/core/styling-hooks/components/date-picker.d.ts +45 -0
- package/dist/core/styling-hooks/manifest.d.cts +44 -0
- package/dist/core/styling-hooks/manifest.d.ts +44 -0
- package/dist/core/styling-hooks.cjs +1 -1
- package/dist/core/styling-hooks.cjs.map +1 -1
- package/dist/core/styling-hooks.js +62 -0
- package/dist/core/styling-hooks.js.map +1 -1
- package/dist/native/components/Calendar/Calendar.cjs +1 -1
- package/dist/native/components/Calendar/Calendar.cjs.map +1 -1
- package/dist/native/components/Calendar/Calendar.d.cts +2 -0
- package/dist/native/components/Calendar/Calendar.d.ts +2 -0
- package/dist/native/components/Calendar/Calendar.js +115 -112
- package/dist/native/components/Calendar/Calendar.js.map +1 -1
- package/dist/native/components/Checkbox/Checkbox.cjs +1 -1
- package/dist/native/components/Checkbox/Checkbox.cjs.map +1 -1
- package/dist/native/components/Checkbox/Checkbox.js +8 -8
- package/dist/native/components/Checkbox/CheckboxGroup.cjs +1 -1
- package/dist/native/components/Checkbox/CheckboxGroup.cjs.map +1 -1
- package/dist/native/components/Checkbox/CheckboxGroup.js +6 -6
- package/dist/native/components/DatePicker/DatePicker.cjs +2 -0
- package/dist/native/components/DatePicker/DatePicker.cjs.map +1 -0
- package/dist/native/components/DatePicker/DatePicker.d.cts +40 -0
- package/dist/native/components/DatePicker/DatePicker.d.ts +40 -0
- package/dist/native/components/DatePicker/DatePicker.js +110 -0
- package/dist/native/components/DatePicker/DatePicker.js.map +1 -0
- package/dist/native/components/DatePicker/index.cjs +1 -0
- package/dist/native/components/DatePicker/index.d.cts +2 -0
- package/dist/native/components/DatePicker/index.d.ts +2 -0
- package/dist/native/components/DatePicker/index.js +2 -0
- package/dist/native/components/Radio/RadioGroup.cjs +1 -1
- package/dist/native/components/Radio/RadioGroup.cjs.map +1 -1
- package/dist/native/components/Radio/RadioGroup.js +9 -9
- package/dist/native/components/Switch/Switch.cjs +1 -1
- package/dist/native/components/Switch/Switch.cjs.map +1 -1
- package/dist/native/components/Switch/Switch.js +23 -23
- package/dist/native/components/Switch/Switch.js.map +1 -1
- package/dist/native/index.cjs +1 -1
- package/dist/native/index.d.cts +1 -0
- package/dist/native/index.d.ts +1 -0
- package/dist/native/index.js +70 -68
- package/dist/native/source/components/Calendar/Calendar.tsx +14 -6
- package/dist/native/source/components/DatePicker/DatePicker.tsx +201 -0
- package/dist/native/source/components/DatePicker/index.ts +2 -0
- package/dist/native/source/index.ts +1 -0
- package/dist/native/source/manifest.ts +6 -0
- package/dist/react/components/DatePicker/DatePicker.cjs +2 -0
- package/dist/react/components/DatePicker/DatePicker.cjs.map +1 -0
- package/dist/react/components/DatePicker/DatePicker.d.cts +13 -0
- package/dist/react/components/DatePicker/DatePicker.d.ts +13 -0
- package/dist/react/components/DatePicker/DatePicker.js +315 -0
- package/dist/react/components/DatePicker/DatePicker.js.map +1 -0
- package/dist/react/components/DatePicker/datePicker.module.scss.cjs +2 -0
- package/dist/react/components/DatePicker/datePicker.module.scss.cjs.map +1 -0
- package/dist/react/components/DatePicker/datePicker.module.scss.js +23 -0
- package/dist/react/components/DatePicker/datePicker.module.scss.js.map +1 -0
- package/dist/react/components/DatePicker/index.cjs +1 -0
- package/dist/react/components/DatePicker/index.d.cts +5 -0
- package/dist/react/components/DatePicker/index.d.ts +5 -0
- package/dist/react/components/DatePicker/index.js +3 -0
- package/dist/react/components/DatePicker/types.d.cts +97 -0
- package/dist/react/components/DatePicker/types.d.ts +97 -0
- package/dist/react/components/Tooltip/Tooltip.cjs +1 -1
- package/dist/react/components/Tooltip/Tooltip.cjs.map +1 -1
- package/dist/react/components/Tooltip/Tooltip.js +5 -5
- package/dist/react/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/react/components/index.cjs +1 -1
- package/dist/react/components/index.d.cts +1 -0
- package/dist/react/components/index.d.ts +1 -0
- package/dist/react/components/index.js +3 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.js +7 -6
- package/dist/react/style.css +1 -0
- package/dist/react/styles/date-picker.css +7 -0
- package/dist/taro/date-picker.d.ts +20 -0
- package/dist/taro/index.d.ts +1 -0
- package/dist/taro/index.js +1155 -990
- package/dist/uni/DatePicker.vue +225 -0
- package/dist/uni/DatePicker.vue.d.ts +36 -0
- package/dist/uni/MonthCalendar.vue +2 -0
- package/dist/uni/MonthCalendar.vue.d.ts +2 -0
- package/dist/uni/index.d.ts +1 -0
- package/dist/uni/index.js +1 -0
- package/dist/uni/manifest.d.ts +7 -0
- package/dist/uni/manifest.js +8 -0
- package/dist/vue/components/DatePicker/DatePicker.vue.d.ts +36 -0
- package/dist/vue/components/DatePicker/DatePicker.vue.js +7 -0
- package/dist/vue/components/DatePicker/DatePicker.vue.js.map +1 -0
- package/dist/vue/components/DatePicker/DatePicker.vue_vue_type_script_setup_true_lang.js +380 -0
- package/dist/vue/components/DatePicker/DatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/vue/components/DatePicker/index.d.ts +2 -0
- package/dist/vue/components/DatePicker/index.js +2 -0
- package/dist/vue/components/DatePicker/types.d.ts +26 -0
- package/dist/vue/components/MonthCalendar/MonthCalendar.vue.d.ts +1 -1
- package/dist/vue/global.d.ts +108 -0
- package/dist/vue/groups/forms-pickers.d.ts +1 -0
- package/dist/vue/groups/forms-pickers.js +5 -2
- package/dist/vue/groups/forms-pickers.js.map +1 -1
- package/dist/vue/index.js +95 -94
- package/dist/weapp/controls.js +259 -76
- package/dist/weapp/date-picker/index.js +1 -0
- package/dist/weapp/date-picker/index.json +1 -0
- package/dist/weapp/date-picker/index.wxml +1 -0
- package/dist/weapp/date-picker/index.wxss +1 -0
- package/dist/weapp/types.d.ts +19 -0
- package/dist/web-components/cdn/minerva.js +461 -335
- package/dist/web-components/cdn/minerva.js.map +1 -1
- package/dist/web-components/components/date-picker/date-picker.d.ts +110 -0
- package/dist/web-components/components/date-picker/date-picker.js +378 -0
- package/dist/web-components/components/date-picker/date-picker.js.map +1 -0
- package/dist/web-components/elements/date-picker.d.ts +1 -0
- package/dist/web-components/elements/date-picker.js +8 -0
- package/dist/web-components/elements/date-picker.js.map +1 -0
- package/dist/web-components/html-custom-data.json +85 -0
- package/dist/web-components/index.d.ts +1 -0
- package/dist/web-components/index.js +8 -6
- package/dist/web-components/styles/DatePicker/datePicker.css.js +6 -0
- package/dist/web-components/styles/DatePicker/datePicker.css.js.map +1 -0
- package/dist/web-components/types/react.d.ts +12 -0
- package/dist/web-components/types/solid.d.ts +9 -0
- package/dist/web-components/types/svelte.d.ts +9 -0
- package/dist/web-components/types/vue.d.ts +10 -0
- package/package.json +9 -1
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref, watch, provide, getCurrentInstance } from "vue";
|
|
3
|
+
import { dayKey, monthStart, parseDayKey } from "../core/index.js";
|
|
4
|
+
import Input from "./Input.vue";
|
|
5
|
+
import MonthCalendar from "./MonthCalendar.vue";
|
|
6
|
+
import PopoverContent from "./PopoverContent.vue";
|
|
7
|
+
import type { MiniPopoverContext } from "./popover-context.js";
|
|
8
|
+
import { inheritForm } from "./form-context.js";
|
|
9
|
+
import { useI18n } from "./i18n.js";
|
|
10
|
+
import { useNativeId } from "./native-id.js";
|
|
11
|
+
const raw = withDefaults(
|
|
12
|
+
defineProps<{
|
|
13
|
+
value?: string | null;
|
|
14
|
+
modelValue?: string | null;
|
|
15
|
+
defaultValue?: string;
|
|
16
|
+
minDate?: string;
|
|
17
|
+
maxDate?: string;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
readOnly?: boolean;
|
|
20
|
+
required?: boolean;
|
|
21
|
+
invalid?: boolean;
|
|
22
|
+
clearable?: boolean;
|
|
23
|
+
placeholder?: string;
|
|
24
|
+
label?: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
id?: string;
|
|
27
|
+
ariaLabel?: string;
|
|
28
|
+
ariaLabelledby?: string;
|
|
29
|
+
ariaDescribedby?: string;
|
|
30
|
+
locale?: string;
|
|
31
|
+
size?: "small" | "medium" | "large";
|
|
32
|
+
}>(),
|
|
33
|
+
{ clearable: true, name: "date-picker", size: "medium" },
|
|
34
|
+
);
|
|
35
|
+
const props = inheritForm(raw),
|
|
36
|
+
{ t } = useI18n();
|
|
37
|
+
const emit = defineEmits<{
|
|
38
|
+
change: [value: string];
|
|
39
|
+
"update:modelValue": [value: string];
|
|
40
|
+
openChange: [open: boolean];
|
|
41
|
+
}>();
|
|
42
|
+
const local = ref(props.defaultValue ?? ""),
|
|
43
|
+
draft = ref<string | null>(null),
|
|
44
|
+
open = ref(false);
|
|
45
|
+
const current = computed(() =>
|
|
46
|
+
props.modelValue !== undefined
|
|
47
|
+
? (props.modelValue ?? "")
|
|
48
|
+
: props.value !== undefined
|
|
49
|
+
? (props.value ?? "")
|
|
50
|
+
: local.value,
|
|
51
|
+
);
|
|
52
|
+
const month = ref(monthStart(parseDayKey(current.value) ?? new Date()));
|
|
53
|
+
const blocked = computed(() => props.disabled || props.readOnly);
|
|
54
|
+
const field = ref<any>(),
|
|
55
|
+
fieldId = `mn-date-${useNativeId()}`;
|
|
56
|
+
const instance = getCurrentInstance();
|
|
57
|
+
let touching = false;
|
|
58
|
+
function setOpen(next: boolean) {
|
|
59
|
+
if ((next && blocked.value) || next === open.value) return;
|
|
60
|
+
open.value = next;
|
|
61
|
+
emit("openChange", next);
|
|
62
|
+
if (next) month.value = monthStart(parseDayKey(current.value) ?? new Date());
|
|
63
|
+
}
|
|
64
|
+
watch(blocked, (value) => {
|
|
65
|
+
if (value) setOpen(false);
|
|
66
|
+
});
|
|
67
|
+
watch(
|
|
68
|
+
() => [props.value, props.modelValue],
|
|
69
|
+
() => {
|
|
70
|
+
draft.value = null;
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
const allowed = (key: string) =>
|
|
74
|
+
(!props.minDate || key >= props.minDate) &&
|
|
75
|
+
(!props.maxDate || key <= props.maxDate);
|
|
76
|
+
function commit(next: string) {
|
|
77
|
+
if (blocked.value) return;
|
|
78
|
+
if (props.value === undefined && props.modelValue === undefined)
|
|
79
|
+
local.value = next;
|
|
80
|
+
emit("change", next);
|
|
81
|
+
emit("update:modelValue", next);
|
|
82
|
+
}
|
|
83
|
+
function input(text: string) {
|
|
84
|
+
if (blocked.value) return;
|
|
85
|
+
draft.value = text;
|
|
86
|
+
if (!text) commit("");
|
|
87
|
+
else {
|
|
88
|
+
const parsed = parseDayKey(text, true);
|
|
89
|
+
if (parsed && allowed(dayKey(parsed))) {
|
|
90
|
+
commit(dayKey(parsed));
|
|
91
|
+
month.value = monthStart(parsed);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function blur() {
|
|
96
|
+
if (touching) {
|
|
97
|
+
touching = false;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (blocked.value || draft.value === null) return;
|
|
101
|
+
const parsed = parseDayKey(draft.value.trim(), false);
|
|
102
|
+
if (!draft.value.trim()) {
|
|
103
|
+
if (current.value) commit("");
|
|
104
|
+
} else if (parsed) {
|
|
105
|
+
const key = dayKey(parsed);
|
|
106
|
+
if (allowed(key) && key !== current.value) {
|
|
107
|
+
commit(key);
|
|
108
|
+
month.value = monthStart(parsed);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
draft.value = null;
|
|
112
|
+
}
|
|
113
|
+
function choose(key: string) {
|
|
114
|
+
touching = false;
|
|
115
|
+
if (blocked.value || !allowed(key)) return;
|
|
116
|
+
draft.value = null;
|
|
117
|
+
commit(key);
|
|
118
|
+
setOpen(false);
|
|
119
|
+
}
|
|
120
|
+
function clear() {
|
|
121
|
+
touching = false;
|
|
122
|
+
draft.value = null;
|
|
123
|
+
commit("");
|
|
124
|
+
}
|
|
125
|
+
provide<MiniPopoverContext>("minerva:popover", {
|
|
126
|
+
open: computed(() => open.value && !blocked.value),
|
|
127
|
+
disabled: blocked,
|
|
128
|
+
placement: computed(() => "bottom"),
|
|
129
|
+
modal: computed(() => false),
|
|
130
|
+
setOpen,
|
|
131
|
+
trigger: field,
|
|
132
|
+
anchor: ref(),
|
|
133
|
+
anchorId: ref(""),
|
|
134
|
+
triggerId: fieldId,
|
|
135
|
+
measureTrigger: (callback) => {
|
|
136
|
+
uni
|
|
137
|
+
.createSelectorQuery?.()
|
|
138
|
+
.in(instance?.proxy)
|
|
139
|
+
.select(`#${fieldId}`)
|
|
140
|
+
.boundingClientRect((rect: any) => {
|
|
141
|
+
if (rect) callback(rect);
|
|
142
|
+
})
|
|
143
|
+
.exec();
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
</script>
|
|
147
|
+
<template>
|
|
148
|
+
<view
|
|
149
|
+
:id="fieldId"
|
|
150
|
+
class="mn-uni-date-picker"
|
|
151
|
+
:data-state="open ? 'open' : 'closed'"
|
|
152
|
+
>
|
|
153
|
+
<text v-if="label">{{ label }}</text>
|
|
154
|
+
<Input
|
|
155
|
+
ref="field"
|
|
156
|
+
:id="props.id"
|
|
157
|
+
:value="draft ?? current"
|
|
158
|
+
:name="name"
|
|
159
|
+
:size="size"
|
|
160
|
+
:placeholder="placeholder ?? t('datePicker.placeholder')"
|
|
161
|
+
:aria-label="label ?? props.ariaLabel ?? t('datePicker.label')"
|
|
162
|
+
:aria-labelledby="props.ariaLabelledby"
|
|
163
|
+
:aria-describedby="props.ariaDescribedby"
|
|
164
|
+
:disabled="props.disabled"
|
|
165
|
+
:read-only="props.readOnly"
|
|
166
|
+
:required="props.required"
|
|
167
|
+
:invalid="props.invalid"
|
|
168
|
+
@change="input"
|
|
169
|
+
@blur="blur"
|
|
170
|
+
@confirm="
|
|
171
|
+
blur();
|
|
172
|
+
setOpen(false);
|
|
173
|
+
"
|
|
174
|
+
@click="setOpen(!open)"
|
|
175
|
+
@keydown="
|
|
176
|
+
if ($event.key === 'Escape') setOpen(false);
|
|
177
|
+
else if ($event.key === 'ArrowDown') setOpen(true);
|
|
178
|
+
"
|
|
179
|
+
>
|
|
180
|
+
<template #suffix
|
|
181
|
+
><button
|
|
182
|
+
v-if="clearable && current && !blocked"
|
|
183
|
+
class="mn-close"
|
|
184
|
+
:aria-label="t('datePicker.clear')"
|
|
185
|
+
@touchstart="touching = true"
|
|
186
|
+
@touchcancel="touching = false"
|
|
187
|
+
@mousedown.prevent
|
|
188
|
+
@tap.stop="clear"
|
|
189
|
+
>
|
|
190
|
+
×
|
|
191
|
+
</button></template
|
|
192
|
+
>
|
|
193
|
+
</Input>
|
|
194
|
+
<PopoverContent
|
|
195
|
+
align="start"
|
|
196
|
+
:aria-label="label ?? props.ariaLabel ?? t('datePicker.label')"
|
|
197
|
+
@open-auto-focus="$event.preventDefault()"
|
|
198
|
+
>
|
|
199
|
+
<view
|
|
200
|
+
@touchstart="touching = true"
|
|
201
|
+
@touchcancel="touching = false"
|
|
202
|
+
@mousedown.prevent
|
|
203
|
+
>
|
|
204
|
+
<MonthCalendar
|
|
205
|
+
:month="month"
|
|
206
|
+
:value="current"
|
|
207
|
+
:min="minDate"
|
|
208
|
+
:max="maxDate"
|
|
209
|
+
:locale="locale"
|
|
210
|
+
:size="size"
|
|
211
|
+
:show-selected-day-events="false"
|
|
212
|
+
@month-change="month = $event"
|
|
213
|
+
@select="choose"
|
|
214
|
+
/>
|
|
215
|
+
<button
|
|
216
|
+
class="mn-button mn-variant-ghost"
|
|
217
|
+
:disabled="!allowed(dayKey(new Date()))"
|
|
218
|
+
@tap="choose(dayKey(new Date()))"
|
|
219
|
+
>
|
|
220
|
+
{{ t("datePicker.today") }}
|
|
221
|
+
</button>
|
|
222
|
+
</view>
|
|
223
|
+
</PopoverContent>
|
|
224
|
+
</view>
|
|
225
|
+
</template>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
value?: string | null;
|
|
3
|
+
modelValue?: string | null;
|
|
4
|
+
defaultValue?: string;
|
|
5
|
+
minDate?: string;
|
|
6
|
+
maxDate?: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
readOnly?: boolean;
|
|
9
|
+
required?: boolean;
|
|
10
|
+
invalid?: boolean;
|
|
11
|
+
clearable?: boolean;
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
label?: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
id?: string;
|
|
16
|
+
ariaLabel?: string;
|
|
17
|
+
ariaLabelledby?: string;
|
|
18
|
+
ariaDescribedby?: string;
|
|
19
|
+
locale?: string;
|
|
20
|
+
size?: "small" | "medium" | "large";
|
|
21
|
+
};
|
|
22
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
23
|
+
change: (value: string) => any;
|
|
24
|
+
"update:modelValue": (value: string) => any;
|
|
25
|
+
openChange: (open: boolean) => any;
|
|
26
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
27
|
+
onChange?: ((value: string) => any) | undefined;
|
|
28
|
+
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
29
|
+
onOpenChange?: ((open: boolean) => any) | undefined;
|
|
30
|
+
}>, {
|
|
31
|
+
size: "small" | "medium" | "large";
|
|
32
|
+
name: string;
|
|
33
|
+
clearable: boolean;
|
|
34
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
35
|
+
declare const _default: typeof __VLS_export;
|
|
36
|
+
export default _default;
|
|
@@ -49,6 +49,7 @@ const props = withDefaults(
|
|
|
49
49
|
);
|
|
50
50
|
const emit = defineEmits<{
|
|
51
51
|
change: [day: string];
|
|
52
|
+
select: [day: string];
|
|
52
53
|
"update:modelValue": [day: string];
|
|
53
54
|
monthChange: [date: Date];
|
|
54
55
|
"update:month": [date: Date];
|
|
@@ -157,6 +158,7 @@ function goTo(date: Date) {
|
|
|
157
158
|
function choose(date: Date) {
|
|
158
159
|
const day = dayKey(date);
|
|
159
160
|
if (blocked(day)) return;
|
|
161
|
+
emit("select", day);
|
|
160
162
|
const changed = day !== selected.value;
|
|
161
163
|
if (props.value === undefined && props.modelValue === undefined)
|
|
162
164
|
localValue.value = day;
|
|
@@ -43,12 +43,14 @@ type __VLS_Slots = {} & {
|
|
|
43
43
|
event?: (props: typeof __VLS_6) => any;
|
|
44
44
|
};
|
|
45
45
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
46
|
+
select: (day: string) => any;
|
|
46
47
|
change: (day: string) => any;
|
|
47
48
|
"update:modelValue": (day: string) => any;
|
|
48
49
|
monthChange: (date: Date) => any;
|
|
49
50
|
"update:month": (date: Date) => any;
|
|
50
51
|
eventClick: (event: CalendarEvent) => any;
|
|
51
52
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
53
|
+
onSelect?: ((day: string) => any) | undefined;
|
|
52
54
|
onChange?: ((day: string) => any) | undefined;
|
|
53
55
|
"onUpdate:modelValue"?: ((day: string) => any) | undefined;
|
|
54
56
|
onMonthChange?: ((date: Date) => any) | undefined;
|
package/dist/uni/index.d.ts
CHANGED
|
@@ -123,3 +123,4 @@ export { default as ToastProvider } from "./ToastProvider.vue.js";
|
|
|
123
123
|
export { default as TooltipProvider } from "./TooltipProvider.vue.js";
|
|
124
124
|
export { confirm, toast } from "./feedback-store.js";
|
|
125
125
|
export { useConfirm, useToast } from "./feedback-context.js";
|
|
126
|
+
export { default as DatePicker } from "./DatePicker.vue.js";
|
package/dist/uni/index.js
CHANGED
|
@@ -123,3 +123,4 @@ export { default as ToastProvider } from "./ToastProvider.vue";
|
|
|
123
123
|
export { default as TooltipProvider } from "./TooltipProvider.vue";
|
|
124
124
|
export { confirm, toast } from "./feedback-store.js";
|
|
125
125
|
export { useConfirm, useToast } from "./feedback-context.js";
|
|
126
|
+
export { default as DatePicker } from "./DatePicker.vue";
|
package/dist/uni/manifest.d.ts
CHANGED
|
@@ -97,6 +97,13 @@ export declare const uniComponentManifest: readonly [{
|
|
|
97
97
|
readonly tests: readonly ["src/parity.test.ts: native host mount", "src/advanced-fields.test.ts: actual advanced field interactions and owner rejection"];
|
|
98
98
|
readonly status: "partial";
|
|
99
99
|
readonly deviceE2E: false;
|
|
100
|
+
}, {
|
|
101
|
+
readonly name: "DatePicker";
|
|
102
|
+
readonly scope: "YYYY-MM-DD controlled strings/null/empty, defaultValue, strict typing and lenient blur normalization, valid-date and minDate/maxDate checks, clearing, field locks, label and open/change events. Popup MonthCalendar with month navigation; update:modelValue supports v-model.";
|
|
103
|
+
readonly limitations: readonly ["Native focus and popup placement need device validation."];
|
|
104
|
+
readonly tests: readonly ["src/date-picker.test.ts", "spike/browser/date-picker.spec.ts"];
|
|
105
|
+
readonly status: "partial";
|
|
106
|
+
readonly deviceE2E: false;
|
|
100
107
|
}, {
|
|
101
108
|
readonly name: "TimePicker";
|
|
102
109
|
readonly scope: "Typed HH:mm or HH:mm:ss, hour/minute/second steps, normalized constraints, locale labels, clear, keyboard time columns, original string change and open-change notifications; measured collision-aware popup.";
|
package/dist/uni/manifest.js
CHANGED
|
@@ -170,6 +170,14 @@ export const uniComponentManifest = [
|
|
|
170
170
|
status: "partial",
|
|
171
171
|
deviceE2E: false,
|
|
172
172
|
},
|
|
173
|
+
{
|
|
174
|
+
name: "DatePicker",
|
|
175
|
+
scope: "YYYY-MM-DD controlled strings/null/empty, defaultValue, strict typing and lenient blur normalization, valid-date and minDate/maxDate checks, clearing, field locks, label and open/change events. Popup MonthCalendar with month navigation; update:modelValue supports v-model.",
|
|
176
|
+
limitations: ["Native focus and popup placement need device validation."],
|
|
177
|
+
tests: ["src/date-picker.test.ts", "spike/browser/date-picker.spec.ts"],
|
|
178
|
+
status: "partial",
|
|
179
|
+
deviceE2E: false,
|
|
180
|
+
},
|
|
173
181
|
{
|
|
174
182
|
name: "TimePicker",
|
|
175
183
|
scope: "Typed HH:mm or HH:mm:ss, hour/minute/second steps, normalized constraints, locale labels, clear, keyboard time columns, original string change and open-change notifications; measured collision-aware popup.",
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { DatePickerProps } from './types.js';
|
|
2
|
+
declare const __VLS_export: import('vue').DefineComponent<DatePickerProps, {
|
|
3
|
+
/** The native `<input>` (the React `ref`) */
|
|
4
|
+
input: import('vue').ShallowRef<HTMLInputElement | null, HTMLInputElement | null>;
|
|
5
|
+
focus: () => void | undefined;
|
|
6
|
+
blur: () => void | undefined;
|
|
7
|
+
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
8
|
+
change: (value: string) => any;
|
|
9
|
+
"update:modelValue": (value: string) => any;
|
|
10
|
+
openChange: (open: boolean) => any;
|
|
11
|
+
}, string, import('vue').PublicProps, Readonly<DatePickerProps> & Readonly<{
|
|
12
|
+
onChange?: ((value: string) => any) | undefined;
|
|
13
|
+
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
14
|
+
onOpenChange?: ((open: boolean) => any) | undefined;
|
|
15
|
+
}>, {
|
|
16
|
+
name: string;
|
|
17
|
+
required: boolean;
|
|
18
|
+
placeholder: string;
|
|
19
|
+
label: string;
|
|
20
|
+
defaultValue: string;
|
|
21
|
+
id: string;
|
|
22
|
+
disabled: boolean;
|
|
23
|
+
invalid: boolean;
|
|
24
|
+
readOnly: boolean;
|
|
25
|
+
clearable: boolean;
|
|
26
|
+
size: "small" | "medium" | "large";
|
|
27
|
+
modelValue: string | null;
|
|
28
|
+
ariaLabel: string;
|
|
29
|
+
ariaLabelledby: string;
|
|
30
|
+
ariaDescribedby: string;
|
|
31
|
+
minDate: string;
|
|
32
|
+
maxDate: string;
|
|
33
|
+
locale: string;
|
|
34
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
35
|
+
declare const _default: typeof __VLS_export;
|
|
36
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DatePicker.vue.js","names":["_sfc_main","DatePicker_vue_vue_type_script_setup_true_lang_default","DatePicker_default"],"sources":["../../../../../vue/src/components/DatePicker/DatePicker.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/** A date input with an accessible popup calendar; values use YYYY-MM-DD. */\nimport {\n computed,\n nextTick,\n onMounted,\n provide,\n ref,\n shallowRef,\n unref,\n useId,\n} from \"vue\";\nimport {\n addDays,\n dayKey,\n localDate,\n monthStart,\n parseDayKey,\n sameMonth,\n} from \"@minerva/core\";\nimport styles from \"@react-styles/components/DatePicker/datePicker.module.scss\";\nimport iconButtonStyles from \"@react-styles/components/IconButton/iconButton.module.scss\";\nimport { hooks } from \"../../internal/hooks\";\nimport {\n IconCalendar,\n IconChevronLeft,\n IconChevronRight,\n IconX,\n} from \"../../internal/icons\";\nimport { useControllable } from \"../../internal/controllable\";\nimport FloatingPanel from \"../../internal/FloatingPanel.vue\";\nimport { useLayerParent } from \"../../internal/scope\";\nimport {\n FORM_CONTROL_KEY,\n useFormControlContext,\n useFormControlProps,\n} from \"../../internal/form-control\";\nimport { useI18n } from \"../../config/useI18n\";\nimport { Input } from \"../Input\";\nimport { logicalArrowKey } from \"../../internal/direction\";\nimport { adjacentTabbable, tabLeavesPanel } from \"../TimePicker/tabbing\";\nimport type { DatePickerEmits, DatePickerProps } from \"./types\";\n\ndefineOptions({ name: \"DatePicker\", inheritAttrs: false });\n\nconst props = withDefaults(defineProps<DatePickerProps>(), {\n modelValue: undefined,\n defaultValue: undefined,\n placeholder: undefined,\n label: undefined,\n ariaLabel: undefined,\n ariaLabelledby: undefined,\n ariaDescribedby: undefined,\n id: undefined,\n required: undefined,\n readOnly: undefined,\n invalid: undefined,\n name: \"date-picker\",\n disabled: undefined,\n clearable: true,\n size: \"medium\",\n minDate: undefined,\n maxDate: undefined,\n locale: undefined,\n});\nconst emit = defineEmits<DatePickerEmits>();\n\nconst { t, language } = useI18n();\nconst fc = useFormControlContext();\n// The field state is resolved here (explicit props win over the\n// FormControl), so the inner Input must not merge it again.\nprovide(FORM_CONTROL_KEY, null as never);\nconst fieldProps = useFormControlProps(() => ({\n id: props.id,\n \"aria-describedby\": props.ariaDescribedby,\n}));\n\nconst disabled = computed(() => props.disabled ?? fc?.disabled.value ?? false);\nconst readOnly = computed(() => props.readOnly ?? fc?.readOnly.value ?? false);\nconst required = computed(() => props.required ?? fc?.required.value ?? false);\nconst invalid = computed(() => props.invalid ?? fc?.invalid.value ?? false);\nconst accessibleName = computed(\n () => props.label ?? props.ariaLabel ?? t(\"datePicker.label\"),\n);\n// A FormLabel names the input unless `label` / `aria-label` is given; the\n// aria-label stays as fallback (aria-labelledby wins when its target\n// exists, and is ignored when it does not).\nconst labelledBy = computed(\n () =>\n props.ariaLabelledby ??\n (fc && !props.label && !props.ariaLabel ? fc.labelId.value : undefined),\n);\n\nconst current = useControllable<string | null>(props, \"modelValue\", {\n defaultProp: \"defaultValue\",\n fallback: \"\",\n name: \"DatePicker\",\n});\nconst open = ref(false);\nconst setOpen = (next: boolean) => {\n if (next === open.value) return;\n open.value = next;\n emit(\"openChange\", next);\n};\nconst panelOpen = computed(\n () => open.value && !disabled.value && !readOnly.value,\n);\n\n// Text being typed; `null` = show the formatted value\nconst draft = ref<string | null>(null);\nconst field = ref<HTMLDivElement | null>(null);\nconst input = shallowRef<HTMLInputElement | null>(null);\nconst floating = ref<InstanceType<typeof FloatingPanel> | null>(null);\n// Tab moves on within the enclosing layer (e.g. a Modal), else the page.\nconst tabContainer = useLayerParent();\n\nonMounted(() => {\n input.value = field.value?.querySelector(\"input\") ?? null;\n});\n\nconst headingId = useId();\nconst month = ref(monthStart(parseDayKey(current.value ?? \"\") ?? new Date()));\nconst focusedKey = ref(\"\");\nconst weekdays = [\"mon\", \"tue\", \"wed\", \"thu\", \"fri\", \"sat\", \"sun\"] as const;\nconst todayKey = dayKey(new Date());\nconst heading = computed(() =>\n new Intl.DateTimeFormat(props.locale ?? language.value, {\n year: \"numeric\",\n month: \"long\",\n }).format(month.value),\n);\nconst days = computed(() => {\n const first = monthStart(month.value);\n const start = addDays(first, -((first.getDay() + 6) % 7));\n return Array.from({ length: 42 }, (_, i) => addDays(start, i));\n});\nconst weeks = computed(() =>\n Array.from({ length: 6 }, (_, i) => days.value.slice(i * 7, i * 7 + 7)),\n);\nconst isDayDisabled = (key: string) =>\n !!(\n (props.minDate && key < props.minDate) ||\n (props.maxDate && key > props.maxDate)\n );\nconst activeKey = computed(() => {\n const keys = days.value.map(dayKey);\n return [\n focusedKey.value,\n current.value,\n todayKey,\n dayKey(month.value),\n ...keys,\n ].find((key) => key && keys.includes(key) && !isDayDisabled(key));\n});\nfunction commit(next: string) {\n current.value = next;\n emit(\"change\", next);\n}\nfunction syncMonth() {\n const date = parseDayKey(current.value ?? \"\");\n if (date) month.value = monthStart(date);\n}\nfunction handleInputChange(value: string | number) {\n if (disabled.value || readOnly.value) return;\n const text = String(value);\n draft.value = text;\n if (text === \"\") {\n commit(\"\");\n return;\n }\n const date = parseDayKey(text, true);\n if (date && !isDayDisabled(dayKey(date))) {\n commit(dayKey(date));\n month.value = monthStart(date);\n }\n}\nfunction handleInputBlur() {\n if (draft.value === null) return;\n const text = draft.value.trim();\n if (!disabled.value && !readOnly.value) {\n if (!text) {\n if (current.value) commit(\"\");\n } else {\n const date = parseDayKey(text, false);\n if (\n date &&\n !isDayDisabled(dayKey(date)) &&\n dayKey(date) !== current.value\n ) {\n commit(dayKey(date));\n month.value = monthStart(date);\n }\n }\n }\n draft.value = null;\n}\nfunction handleClear() {\n if (disabled.value || readOnly.value) return;\n draft.value = null;\n commit(\"\");\n input.value?.focus();\n}\nfunction selectDate(date: Date) {\n if (disabled.value || readOnly.value || isDayDisabled(dayKey(date))) return;\n draft.value = null;\n commit(dayKey(date));\n month.value = monthStart(date);\n setOpen(false);\n input.value?.focus();\n}\nfunction toggle() {\n if (disabled.value || readOnly.value) return;\n if (!open.value) syncMonth();\n setOpen(!open.value);\n}\nasync function focusDay(key?: string) {\n await nextTick();\n const panel = unref(floating.value?.element);\n (key\n ? panel?.querySelector<HTMLElement>(`[data-date=\"${key}\"]`)\n : panel?.querySelector<HTMLElement>('[role=\"gridcell\"][tabindex=\"0\"]')\n )?.focus();\n}\nfunction handleDayKeyDown(event: KeyboardEvent, date: Date) {\n if (disabled.value || readOnly.value) return;\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n if (!event.repeat) selectDate(date);\n return;\n }\n let target: Date;\n const weekday = (date.getDay() + 6) % 7;\n switch (logicalArrowKey(event.key, event.currentTarget as HTMLElement)) {\n case \"ArrowLeft\":\n target = addDays(date, -1);\n break;\n case \"ArrowRight\":\n target = addDays(date, 1);\n break;\n case \"ArrowUp\":\n target = addDays(date, -7);\n break;\n case \"ArrowDown\":\n target = addDays(date, 7);\n break;\n case \"Home\":\n target = addDays(date, -weekday);\n break;\n case \"End\":\n target = addDays(date, 6 - weekday);\n break;\n case \"PageUp\":\n case \"PageDown\": {\n const next = monthStart(\n date,\n (event.key === \"PageUp\" ? -1 : 1) * (event.shiftKey ? 12 : 1),\n );\n target = localDate(\n next.getFullYear(),\n next.getMonth(),\n Math.min(date.getDate(), addDays(monthStart(next, 1), -1).getDate()),\n );\n break;\n }\n default:\n return;\n }\n event.preventDefault();\n focusedKey.value = dayKey(target);\n if (!sameMonth(target, month.value)) month.value = monthStart(target);\n void focusDay(dayKey(target));\n}\n\n// Clicking the input toggles the panel. The handler only reacts to clicks\n// on the inner <input>, which has its own keyboard support (ArrowDown opens\n// the panel; Escape closes it), so the wrapper is not a control.\nfunction handleRootClick(event: MouseEvent) {\n if (input.value && event.target === input.value) toggle();\n}\n\nfunction handleInputKeyDown(event: KeyboardEvent) {\n if (event.key !== \"ArrowDown\" || disabled.value || readOnly.value) return;\n event.preventDefault();\n if (!open.value) {\n syncMonth();\n focusedKey.value = current.value ?? \"\";\n setOpen(true);\n }\n void focusDay();\n}\n\n// The portalled panel sits after the input in the Tab order: Tab past its\n// last control continues after the input (its clear button, then the rest of\n// the page); Shift+Tab before its first control returns to the input.\nfunction handlePanelKeyDown(event: KeyboardEvent) {\n const panel = event.currentTarget as HTMLElement;\n const el = input.value;\n if (\n !el ||\n event.key !== \"Tab\" ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey ||\n !tabLeavesPanel(panel, event.target as Element, event.shiftKey)\n )\n return;\n event.preventDefault();\n const next = event.shiftKey\n ? el\n : (adjacentTabbable(\n el,\n tabContainer?.value ?? el.ownerDocument.body,\n false,\n ) ?? el);\n next.focus();\n setOpen(false);\n}\n\nconst displayValue = computed(() => draft.value ?? current.value ?? \"\");\nconst showClear = computed(\n () =>\n props.clearable && !!current.value && !disabled.value && !readOnly.value,\n);\n\ndefineExpose({\n /** The native `<input>` (the React `ref`) */\n input,\n focus: () => input.value?.focus(),\n blur: () => input.value?.blur(),\n});\n</script>\n\n<template>\n <div\n ref=\"field\"\n :class=\"styles.datePicker\"\n v-bind=\"{\n ...$attrs,\n ...hooks('date-picker', 'root', {\n state: panelOpen ? 'open' : 'closed',\n disabled,\n readonly: readOnly,\n invalid,\n size,\n }),\n }\"\n @click=\"handleRootClick\"\n >\n <Input\n :model-value=\"displayValue\"\n :placeholder=\"placeholder ?? t('datePicker.placeholder')\"\n :id=\"fieldProps.id\"\n :aria-label=\"accessibleName\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"fieldProps['aria-describedby']\"\n :aria-invalid=\"invalid || undefined\"\n :aria-readonly=\"readOnly || undefined\"\n :required=\"required\"\n :read-only=\"readOnly\"\n :name=\"name\"\n :disabled=\"disabled\"\n :size=\"size\"\n @update:model-value=\"handleInputChange\"\n @blur=\"handleInputBlur\"\n @keydown=\"handleInputKeyDown\"\n >\n <template #suffix>\n <button\n v-if=\"showClear\"\n type=\"button\"\n :class=\"[\n iconButtonStyles.iconButton,\n iconButtonStyles.neutral,\n iconButtonStyles['variant-ghost'],\n iconButtonStyles.small,\n iconButtonStyles.circle,\n styles.clearButton,\n ]\"\n tabindex=\"0\"\n :aria-label=\"t('datePicker.clear')\"\n v-bind=\"\n hooks('icon-button', 'root', {\n state: 'inactive',\n disabled: false,\n loading: false,\n size: 'small',\n variant: 'ghost',\n color: 'neutral',\n shape: 'circle',\n })\n \"\n @click=\"handleClear\"\n >\n <span\n :class=\"iconButtonStyles.glyph\"\n aria-hidden=\"true\"\n v-bind=\"hooks('icon-button', 'icon')\"\n >\n <IconX />\n </span>\n </button>\n <span\n v-else\n :class=\"styles.calendarIcon\"\n aria-hidden=\"true\"\n v-bind=\"hooks('date-picker', 'icon')\"\n >\n <IconCalendar />\n </span>\n </template>\n </Input>\n <FloatingPanel\n ref=\"floating\"\n :open=\"panelOpen\"\n :anchor=\"input\"\n placement=\"bottom-start\"\n :branches=\"() => [field]\"\n :return-focus-on-escape=\"() => input\"\n focusable\n role=\"dialog\"\n tabindex=\"-1\"\n :aria-label=\"accessibleName\"\n :aria-labelledby=\"labelledBy\"\n :class=\"styles.popup\"\n v-bind=\"hooks('date-picker', 'content', { state: 'open' })\"\n @dismiss=\"setOpen(false)\"\n @keydown=\"handlePanelKeyDown\"\n >\n <div :class=\"styles.panel\">\n <div :class=\"styles.header\">\n <h2 :id=\"headingId\" :class=\"styles.heading\" aria-live=\"polite\">\n {{ heading }}\n </h2>\n <div :class=\"styles.navGroup\">\n <button\n type=\"button\"\n :class=\"styles.navButton\"\n :aria-label=\"t('monthCalendar.previousMonth')\"\n @click=\"month = monthStart(month, -1)\"\n >\n <IconChevronLeft aria-hidden=\"true\" focusable=\"false\" />\n </button>\n <button\n type=\"button\"\n :class=\"styles.navButton\"\n :aria-label=\"t('monthCalendar.nextMonth')\"\n @click=\"month = monthStart(month, 1)\"\n >\n <IconChevronRight aria-hidden=\"true\" focusable=\"false\" />\n </button>\n </div>\n </div>\n <div role=\"grid\" :aria-labelledby=\"headingId\" :class=\"styles.grid\">\n <div role=\"row\" :class=\"styles.week\">\n <div\n v-for=\"day in weekdays\"\n :key=\"day\"\n role=\"columnheader\"\n :class=\"styles.weekday\"\n >\n {{ t(`monthCalendar.weekdays.${day}`) }}\n </div>\n </div>\n <div\n v-for=\"(week, index) in weeks\"\n :key=\"index\"\n role=\"row\"\n :class=\"styles.week\"\n >\n <div\n v-for=\"date in week\"\n :key=\"dayKey(date)\"\n role=\"gridcell\"\n :class=\"styles.day\"\n :data-date=\"dayKey(date)\"\n :data-outside=\"!sameMonth(date, month) ? '' : undefined\"\n :aria-label=\"dayKey(date)\"\n :aria-selected=\"current === dayKey(date)\"\n :aria-current=\"dayKey(date) === todayKey ? 'date' : undefined\"\n :aria-disabled=\"isDayDisabled(dayKey(date)) || undefined\"\n :tabindex=\"dayKey(date) === activeKey ? 0 : -1\"\n @focus=\"focusedKey = dayKey(date)\"\n @click=\"selectDate(date)\"\n @keydown=\"handleDayKeyDown($event, date)\"\n >\n {{ date.getDate() }}\n </div>\n </div>\n </div>\n <div :class=\"styles.footer\">\n <button\n type=\"button\"\n :class=\"styles.footerButton\"\n :disabled=\"isDayDisabled(todayKey)\"\n @click=\"selectDate(new Date())\"\n >\n {{ t(\"datePicker.today\") }}\n </button>\n <button\n v-if=\"clearable && current\"\n type=\"button\"\n :class=\"styles.footerButton\"\n @click=\"\n handleClear();\n setOpen(false);\n \"\n >\n {{ t(\"datePicker.clear\") }}\n </button>\n </div>\n </div>\n </FloatingPanel>\n </div>\n</template>\n"],"mappings":""}
|