nuxt-hs-ui 2.12.6 → 4.0.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 (131) hide show
  1. package/README.md +202 -14
  2. package/dist/module.d.mts +3 -4
  3. package/dist/module.json +9 -6
  4. package/dist/module.mjs +109 -99
  5. package/dist/runtime/assets/flatpickr-dark.css +1 -1
  6. package/dist/runtime/assets/main.css +1 -0
  7. package/dist/runtime/assets/tabulator-custom.css +1 -1
  8. package/dist/runtime/components/form/_select/hidden-item-toggle.vue +28 -0
  9. package/dist/runtime/components/form/_select/hidden-item-toggle.vue.d.ts +10 -0
  10. package/dist/runtime/components/form/_select/item-container.vue +63 -0
  11. package/dist/runtime/components/form/_select/item-container.vue.d.ts +19 -0
  12. package/dist/runtime/components/form/_select/item-label.vue +31 -0
  13. package/dist/runtime/components/form/_select/item-label.vue.d.ts +13 -0
  14. package/dist/runtime/components/form/_select/item-row.vue +62 -0
  15. package/dist/runtime/components/form/_select/item-row.vue.d.ts +34 -0
  16. package/dist/runtime/components/form/btn-line-loading.vue +62 -81
  17. package/dist/runtime/components/form/btn-line-loading.vue.d.ts +14 -0
  18. package/dist/runtime/components/form/btn.vue +411 -494
  19. package/dist/runtime/components/form/btn.vue.d.ts +0 -0
  20. package/dist/runtime/components/form/check-box.vue +200 -315
  21. package/dist/runtime/components/form/check-box.vue.d.ts +71 -0
  22. package/dist/runtime/components/form/check-list.vue +234 -364
  23. package/dist/runtime/components/form/check-list.vue.d.ts +99 -0
  24. package/dist/runtime/components/form/combo-box.vue +340 -0
  25. package/dist/runtime/components/form/combo-box.vue.d.ts +69 -0
  26. package/dist/runtime/components/form/datepicker.vue +717 -883
  27. package/dist/runtime/components/form/datepicker.vue.d.ts +122 -0
  28. package/dist/runtime/components/form/input-frame.vue +174 -258
  29. package/dist/runtime/components/form/input-frame.vue.d.ts +88 -0
  30. package/dist/runtime/components/form/radio.vue +451 -614
  31. package/dist/runtime/components/form/radio.vue.d.ts +62 -0
  32. package/dist/runtime/components/form/select-img-icon.vue +38 -53
  33. package/dist/runtime/components/form/select-img-icon.vue.d.ts +15 -0
  34. package/dist/runtime/components/form/select.vue +733 -579
  35. package/dist/runtime/components/form/select.vue.d.ts +63 -0
  36. package/dist/runtime/components/form/text-box.vue +266 -365
  37. package/dist/runtime/components/form/text-box.vue.d.ts +105 -0
  38. package/dist/runtime/components/form/textarea.vue +338 -421
  39. package/dist/runtime/components/form/textarea.vue.d.ts +98 -0
  40. package/dist/runtime/components/form/value-box.vue +512 -641
  41. package/dist/runtime/components/form/value-box.vue.d.ts +128 -0
  42. package/dist/runtime/components/interactive/alert.vue +49 -113
  43. package/dist/runtime/components/interactive/alert.vue.d.ts +30 -0
  44. package/dist/runtime/components/interactive/block-loading.vue +91 -119
  45. package/dist/runtime/components/interactive/block-loading.vue.d.ts +22 -0
  46. package/dist/runtime/components/interactive/dialog.vue +252 -407
  47. package/dist/runtime/components/interactive/dialog.vue.d.ts +3 -0
  48. package/dist/runtime/components/interactive/modal-bg.vue +72 -82
  49. package/dist/runtime/components/interactive/modal-bg.vue.d.ts +11 -0
  50. package/dist/runtime/components/interactive/modal.vue +121 -169
  51. package/dist/runtime/components/interactive/modal.vue.d.ts +38 -0
  52. package/dist/runtime/components/interactive/toast.vue +164 -206
  53. package/dist/runtime/components/interactive/toast.vue.d.ts +3 -0
  54. package/dist/runtime/components/interactive/window-loader.vue +61 -84
  55. package/dist/runtime/components/interactive/window-loader.vue.d.ts +3 -0
  56. package/dist/runtime/components/layout/accordion-down.vue +72 -0
  57. package/dist/runtime/components/layout/accordion-down.vue.d.ts +26 -0
  58. package/dist/runtime/components/layout/accordion.vue +47 -78
  59. package/dist/runtime/components/layout/accordion.vue.d.ts +22 -0
  60. package/dist/runtime/components/layout/aspect-box.vue +29 -58
  61. package/dist/runtime/components/layout/aspect-box.vue.d.ts +29 -0
  62. package/dist/runtime/components/layout/card-item.vue +148 -193
  63. package/dist/runtime/components/layout/card-item.vue.d.ts +0 -0
  64. package/dist/runtime/components/layout/card.vue +27 -42
  65. package/dist/runtime/components/layout/card.vue.d.ts +23 -0
  66. package/dist/runtime/components/layout/container.vue +25 -40
  67. package/dist/runtime/components/layout/container.vue.d.ts +35 -0
  68. package/dist/runtime/components/layout/divider-h.vue +30 -50
  69. package/dist/runtime/components/layout/divider-h.vue.d.ts +18 -0
  70. package/dist/runtime/components/misc/breadcrumb.vue +47 -95
  71. package/dist/runtime/components/misc/breadcrumb.vue.d.ts +22 -0
  72. package/dist/runtime/components/misc/tabulator.vue +122 -190
  73. package/dist/runtime/components/misc/tabulator.vue.d.ts +28 -0
  74. package/dist/runtime/components/misc/view-name-display.vue +53 -68
  75. package/dist/runtime/components/misc/view-name-display.vue.d.ts +14 -0
  76. package/dist/runtime/components/test.vue +13 -0
  77. package/dist/runtime/components/test.vue.d.ts +3 -0
  78. package/dist/runtime/composables/test.d.ts +8 -0
  79. package/dist/runtime/composables/test.js +12 -0
  80. package/dist/runtime/composables/use-hs-dialog.d.ts +3 -20
  81. package/dist/runtime/composables/use-hs-dialog.js +3 -9
  82. package/dist/runtime/composables/use-hs-is-mobile.d.ts +8 -2
  83. package/dist/runtime/composables/use-hs-is-mobile.js +43 -26
  84. package/dist/runtime/composables/use-hs-misc.d.ts +8 -38
  85. package/dist/runtime/composables/use-hs-misc.js +9 -61
  86. package/dist/runtime/composables/use-hs-modal.js +1 -3
  87. package/dist/runtime/composables/use-hs-multi-lang.d.ts +23 -40
  88. package/dist/runtime/composables/use-hs-multi-lang.js +30 -74
  89. package/dist/runtime/composables/use-hs-scroll-lock.d.ts +1 -1
  90. package/dist/runtime/composables/use-hs-scroll-lock.js +2 -1
  91. package/dist/runtime/composables/use-hs-toast.d.ts +2 -2
  92. package/dist/runtime/composables/use-hs-toast.js +12 -4
  93. package/dist/runtime/composables/use-pinia.d.ts +1 -0
  94. package/dist/runtime/composables/use-pinia.js +2 -0
  95. package/dist/runtime/plugin.d.ts +2 -0
  96. package/dist/runtime/plugin.js +4 -0
  97. package/dist/runtime/server/tsconfig.json +3 -3
  98. package/dist/runtime/types/dialog.d.ts +11 -20
  99. package/dist/runtime/types/dialog.js +2 -1
  100. package/dist/runtime/types/flatpickr/default.js +2 -23
  101. package/dist/runtime/types/flatpickr/ja.js +3 -37
  102. package/dist/runtime/types/toast.d.ts +1 -1
  103. package/dist/runtime/utils/dayjs.d.ts +8 -6
  104. package/dist/runtime/utils/dayjs.js +12 -5
  105. package/dist/runtime/utils/modal.d.ts +9 -28
  106. package/dist/runtime/utils/modal.js +7 -36
  107. package/dist/runtime/utils/multi-lang-object.d.ts +2 -2
  108. package/dist/runtime/utils/multi-lang-object.js +1 -5
  109. package/dist/runtime/utils/multi-lang.js +12 -22
  110. package/dist/runtime/utils/object.js +1 -1
  111. package/dist/runtime/utils/select-item.d.ts +3 -1
  112. package/dist/runtime/utils/stop-watch.js +6 -4
  113. package/dist/runtime/utils/string.js +4 -4
  114. package/dist/runtime/utils/tabulator.d.ts +1 -42
  115. package/dist/runtime/utils/tabulator.js +2 -99
  116. package/dist/runtime/utils/theme.d.ts +20 -20
  117. package/dist/runtime/utils/theme.js +180 -30
  118. package/dist/runtime/utils/tv.d.ts +1 -101
  119. package/dist/runtime/utils/tv.js +0 -22
  120. package/dist/types.d.mts +3 -1
  121. package/package.json +61 -119
  122. package/dist/module.cjs +0 -5
  123. package/dist/module.d.ts +0 -16
  124. package/dist/runtime/assets/vue-select.css +0 -1
  125. package/dist/runtime/components/misc/view-name-display-target.vue +0 -39
  126. package/dist/runtime/plugin/v-select.d.ts +0 -2
  127. package/dist/runtime/plugin/v-select.js +0 -5
  128. package/dist/runtime/style.css +0 -22
  129. package/dist/runtime/tailwind.css +0 -78
  130. package/dist/runtime/types/app.config.d.ts +0 -5
  131. package/dist/types.d.ts +0 -1
@@ -1,880 +1,684 @@
1
- <script setup lang="ts">
2
- /* ----------------------------------------------------------------------------
3
- // src\runtime\components\form\datepicker.vue
4
- // ----------------------------------------------------------------------------
5
- // Datepicker
6
- // DatepickerDatepicker
7
- ----------------------------------------------------------------------------- */
8
-
9
- // [ node-modules ]
10
- import dayjs from "dayjs/esm/index";
11
- // flatpickr cdn 経由で使用する
12
- import flatpickr from "flatpickr";
13
- // import monthSelectPlugin from "flatpickr/dist/plugins/monthSelect";
14
- // [ vueuse ]
15
- import { useMounted } from "@vueuse/core";
16
- // [ NUXT ]
17
- import {
18
- reactive,
19
- ref,
20
- watch,
21
- computed,
22
- useId,
23
- onMounted,
24
- nextTick,
25
- onUnmounted,
26
- // useHead,
27
- } from "#imports";
28
- // [ utils ]
29
- import { Sleep } from "../../utils/com";
30
- import type { ClassType } from "../../utils/class-style";
31
- import { GetTimeShiftValue, Dayjs, DayjsInit } from "../../utils/dayjs";
32
- import type { MultiLang } from "../../utils/multi-lang";
33
- // [ utils ]
34
-
35
- import { ja } from "../../types/flatpickr/ja";
36
- import { en } from "../../types/flatpickr/default";
37
- // [ composables ]
38
- import { useHsMisc } from "../../composables/use-hs-misc";
39
- import { useHsFocus } from "../../composables/use-hs-focus";
40
- import { useHsToast } from "../../composables/use-hs-toast";
41
- import { useHsMultiLang } from "../../composables/use-hs-multi-lang";
42
- // [ Components ]
43
- import InputFrame from "./input-frame.vue";
44
-
45
- // useHead({
46
- // script: [
47
- // //
48
- // // https://npmcdn.com/flatpickr@4.6.13/dist/plugins/monthSelect/index.js
49
- // //{ src: `https://npmcdn.com/flatpickr/dist/flatpickr.min.js` },
50
- // { src: `https://npmcdn.com/flatpickr/dist/plugins/monthSelect` },
51
- // { src: `https://npmcdn.com/flatpickr/dist/l10n/ja.js` },
52
- // { src: `https://npmcdn.com/flatpickr/dist/l10n/default.js` },
53
- // ],
54
- // });
55
-
56
- // ----------------------------------------------------------------------------
57
- // [ nac-stroe ]
58
- DayjsInit();
59
- const hsFocus = useHsFocus();
60
- const Toast = useHsToast();
61
- const multiLang = useHsMultiLang();
62
- const hsMisc = useHsMisc();
63
- const tx = multiLang.tx;
64
- // ----------------------------------------------------------------------------
65
- // [ vueuse ]
66
- const isMounted = useMounted();
67
- // ----------------------------------------------------------------------------
68
- // flatpickr
69
- // const MonthSelectPlugin: any = monthSelectPlugin;
70
- const timeDateFormat = "YYYY-MM-DD HH:mm:ss.SSS";
71
- const timeOutputDateFormat = "HH:mm:ss.SSS";
72
- const timeShowDateFormat = "HH:mm";
73
- // ----------------------------------------------------------------------------
74
- // [ Props ]
75
- type Props = {
76
- // ----------------------------------------------------------------------------
77
- // Input 種類別
78
- textAlign?: "left" | "center" | "right";
79
- mode?: "all" | "date" | "time";
80
- // mode?: "all" | "date" | "time" | "month";
81
- /** mode=time の場合、[HH:mm:ss.SSS] に固定 */
82
- dataFormat?: string;
83
- /** mode=time の場合、[HH:mm] に固定 */
84
- showFormat?: string;
85
- minDate?: string | null;
86
- maxDate?: string | null;
87
- hideDeleteBtn?: boolean;
88
- hideTodayBtn?: boolean;
89
- disableMobile?: boolean;
90
- hasShift?: boolean;
91
- // ----------------------------------------------------------------------------
92
- data: string | null;
93
- diff?: string | null | undefined;
94
- tabindex?: string | undefined;
95
- // ----------------------------------------------------------------------------
96
- class?: ClassType;
97
- classHeader?: ClassType;
98
- classInput?: ClassType;
99
- // ----------------------------------------------------------------------------
100
- // 状態
101
- focusColor?: string;
102
- changeColor?: string;
103
- error?: boolean;
104
- errorColor?: string;
105
- disabled?: boolean;
106
- disabledColor?: string;
107
- readonly?: boolean;
108
- headerless?: boolean;
109
- // ----------------------------------------------------------------------------
110
- // 表示
111
- label?: MultiLang;
112
- // 表示-副情報
113
- require?: boolean;
114
- requireText?: MultiLang;
115
- warn?: string;
116
- warnTimeOut?: number;
117
- // ----------------------------------------------------------------------------
118
- // 設定
119
- size?: "s" | "m" | "l";
120
- // ----------------------------------------------------------------------------
121
- uiText?: {
122
- error: {
123
- inputRangeTitle: MultiLang;
124
- inputRangeMessage: MultiLang;
125
- };
126
- };
127
- };
128
-
129
- const props = withDefaults(defineProps<Props>(), {
130
- // ----------------------------------------------------------------------------
131
- // Input 種類別
132
- textAlign: "left",
133
- mode: "date",
134
- dataFormat: "",
135
- showFormat: "",
136
- minDate: null,
137
- maxDate: null,
138
- hideDeleteBtn: false,
139
- disableMobile: false,
140
- hasShift: true,
141
- // ----------------------------------------------------------------------------
142
- diff: undefined,
143
- tabindex: undefined,
144
- // ----------------------------------------------------------------------------
145
- class: "",
146
- classHeader: "",
147
- classInput: "",
148
- // ----------------------------------------------------------------------------
149
- // 状態
150
- // focus: false,
151
- focusColor: "shadow-[inset_0px_0px_1px_2px_#0d8ee4]",
152
- // change: false,
153
- changeColor: "shadow-[inset_0px_0px_1px_2px_#fd9831be]",
154
- error: false,
155
- errorColor: "shadow-[inset_0px_0px_1px_2px_#d80000dc]",
156
- disabled: false,
157
- disabledColor: "",
158
- readonly: false,
159
- headerless: false,
160
- // ----------------------------------------------------------------------------
161
- // 表示
162
- label: "",
163
- // 表示-副情報
164
- require: false,
165
- requireText: () => ({ ja: "必須", en: "Required" }),
166
- warn: "",
167
- warnTimeOut: 3000,
168
- // ----------------------------------------------------------------------------
169
- // 設定
170
- size: "m",
171
- // ----------------------------------------------------------------------------
172
- uiText: () => {
173
- return {
174
- error: {
175
- inputRangeTitle: { ja: "入力値の警告", en: "Input Value Warning" },
176
- inputRangeMessage: {
177
- ja: "入力範囲外です",
178
- en: "Input is out of range",
179
- },
180
- },
181
- };
182
- },
183
- });
184
- // [ emit ]
185
- type Emits = {
186
- ref: [element: HTMLElement];
187
- focus: [elm: HTMLElement];
188
- blur: [elm: HTMLElement];
189
- // ----------------------------
190
- "update:data": [value: string | null];
191
- "value-change": [after: string | null, before: string | null];
192
- // ----------------------------
193
- "reset-piceker-func": [func: any];
194
- // ----------------------------
195
- };
196
- const emit = defineEmits<Emits>();
197
- // ----------------------------------------------------------------------------
198
- const slots = defineSlots<{
199
- default(props: { msg: string }): any;
200
- overlay?(): any;
201
- "right-icons"?(): any;
202
- "left-icons"?(): any;
203
- }>();
204
- // ----------------------------------------------------------------------------
205
- // ----------------------------------------------------------------------------
206
- // [ getCurrentInstance ]
207
- const uid = useId();
208
-
209
- // ----------------------------------------------------------------------------
210
- // [ reactive ]
211
-
212
- interface State {
213
- picker: any;
214
- // FormControl値
215
- date: Date | null;
216
- // text: string;
217
- option: any;
218
- }
219
- const state = reactive<State>({
220
- // text: '',
221
- picker: null,
222
- date: null,
223
- option: {
224
- dateFormat: "Z",
225
- locale: ja,
226
- time_24hr: true,
227
- minDate: undefined,
228
- maxDate: undefined,
229
- plugins: [],
230
- disableMobile: true,
231
- },
232
- });
233
-
234
- onMounted(() => {
235
- state.option.maxDate =
236
- dayjs(props.maxDate).isValid() === true
237
- ? dayjs(props.maxDate).toISOString()
238
- : undefined;
239
- state.option.minDate =
240
- dayjs(props.minDate).isValid() === true
241
- ? dayjs(props.minDate).toISOString()
242
- : undefined;
243
- });
244
- const shiftM = GetTimeShiftValue(Dayjs());
245
- const getShiftDayjs = (date: any) => {
246
- if (props.hasShift && shiftM !== 0) {
247
- return dayjs(date).subtract(shiftM, "minute");
248
- }
249
- return dayjs(date);
250
- };
251
-
252
- const inputBoxClass = computed(() => {
253
- if (props.textAlign === "left") {
254
- return "display-left";
255
- } else if (props.textAlign === "center") {
256
- return "display-center";
257
- } else {
258
- return "display-right";
259
- }
260
- });
261
- const displayText = computed(() => {
262
- const lang = multiLang.state.lang;
263
- dayjs.locale(lang);
264
- if (props.data === null) {
265
- return "";
266
- } else if (props.mode === "time") {
267
- return getShiftDayjs(dayjs().format("YYYY-MM-DD ") + props.data).format(
268
- timeShowDateFormat
269
- );
270
- } else {
271
- return getShiftDayjs(props.data).format(props.showFormat);
272
- }
273
- });
274
-
275
- // ----------------------------------------------------------------------------
276
- watch(
277
- () =>
278
- computed(() => {
279
- return [props.minDate, props.maxDate, multiLang.state.lang];
280
- }).value,
281
- async () => {
282
- // console.log('computed', props.minDate, props.maxDate, isMounted.value);
283
- if (!isMounted.value) return;
284
- await Sleep(1);
285
- resetPicekr();
286
- }
287
- );
288
-
289
- const checkDate = (date: any) => {
290
- // console.log(props.minDate);
291
- const d = getShiftDayjs(date);
292
- if (props.minDate !== "" && d.isBefore(props.minDate)) {
293
- // console.log('最小日付を下回っています', props.data, props.minDate);
294
- return false;
295
- } else if (props.maxDate !== "" && d.isAfter(props.maxDate)) {
296
- // console.log('最大日付を下回っています', props.data, props.maxDate);
297
- return false;
298
- }
299
- return true;
300
- };
301
-
302
- const keyDown = (event: any) => {
303
- const before = props.data;
304
- // console.log('keyDown', state.picker);
305
- if (event.key === "Enter") {
306
- datePickerToday();
307
- return;
308
- }
309
- if (event.key === "Backspace") {
310
- iconEventDelete();
311
- return;
312
- }
313
- let move = 0;
314
- if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
315
- move--;
316
- }
317
- if (event.key === "ArrowRight" || event.key === "ArrowDown") {
318
- move++;
319
- }
320
- if (event.key === "ArrowUp" || event.key === "ArrowDown") {
321
- // Flatpickerにフォーカスを奪われるキーイベントはフォーカスを取り戻す予約
322
- setTimeout(() => {
323
- // console.log('フォーカス戻す');
324
- if (inputElement.value != null) {
325
- inputElement.value.focus();
326
- }
327
- }, 150);
328
- }
329
- if (move !== 0) {
330
- let m =
331
- props.data == null ? getShiftDayjs(dayjs()) : getShiftDayjs(props.data);
332
- if (move < 0) {
333
- m = m.subtract(1, "d");
334
- } else {
335
- m = m.add(1, "d");
336
- }
337
- if (props.data !== "") {
338
- if (checkDate(m) === false) {
339
- // console.log('行き過ぎ');
340
- return false;
341
- }
342
- } else if (move < 0) {
343
- m = getShiftDayjs(props.maxDate).subtract(1, "d");
344
- } else {
345
- m = getShiftDayjs(props.minDate).add(1, "d");
346
- }
347
- emit("update:data", m.format(props.dataFormat));
348
- nextTick(() => {
349
- emit("value-change", m.format(props.dataFormat), before);
350
- });
351
- return false;
352
- }
353
- };
354
-
355
- // ----------------------------------------------------------------------------
356
- // [ flatpicker関連 ]
357
- const initFlatPickerOption = () => {
358
- if (props.mode === "all" || props.mode === "time") {
359
- state.option.enableTime = true;
360
- if (props.mode === "time") {
361
- state.option.noCalendar = true;
362
- }
363
- }
364
- if (props.disableMobile) {
365
- state.option.disableMobile = true;
366
- }
367
- // if (props.mode === "month") {
368
- // state.option.disableMobile = true;
369
- // state.option.plugins = [
370
- // new MonthSelectPlugin({
371
- // shorthand: true, // デフォルトはfalse
372
- // dateFormat: "m.y", // デフォルトは"F Y"
373
- // altFormat: "F Y", // デフォルトは"F Y"
374
- // theme: "dark", // デフォルトは"light"
375
- // }),
376
- // ];
377
- // }
378
- };
379
-
380
- const onOpen = () => {
381
- focusState.isOpenFlatpickr = true;
382
- };
383
-
384
- const onClose = () => {
385
- focusState.isOpenFlatpickr = false;
386
- focusState.isClosingFlatpickr = true;
387
- setTimeout(() => {
388
- focusState.isClosingFlatpickr = false;
389
- }, 200);
390
- };
391
-
392
- const onChange = (selectedDates: any) => {
393
- let value = null;
394
- if (selectedDates.length === 0) {
395
- value = null;
396
- } else {
397
- const d = selectedDates[0];
398
- if (d == null) {
399
- value = null;
400
- } else {
401
- value = d;
402
- }
403
- }
404
- updateValue(value);
405
- };
406
-
407
- const generateFlatPickerOption = () => {
408
- // console.log('generatePicker', elmInput.value);
409
- if (inputElement.value != null) {
410
- dayjs.locale(multiLang.state.lang);
411
- switch (multiLang.state.lang) {
412
- case "jp":
413
- case "ja":
414
- state.option.locale = ja;
415
- break;
416
- default:
417
- state.option.locale = en;
418
- break;
419
- }
420
- // state.option.position = 'above';
421
- // state.option.static = true;
422
- state.picker = flatpickr(inputElement.value, state.option);
423
- state.picker.config.onChange.push(onChange);
424
- state.picker.config.onOpen.push(onOpen);
425
- state.picker.config.onClose.push(onClose);
426
- setValue();
427
- // MonthSelectPlugin();
428
- }
429
- };
430
- const flag = ref(false);
431
-
432
- const resetPicekr = () => {
433
- if (flag.value) return;
434
- try {
435
- flag.value = true;
436
- state.picker.destroy();
437
- state.picker = false;
438
- focusState.isOpenFlatpickr = false;
439
- dayjs.locale(multiLang.state.lang);
440
- if (props.minDate !== null) {
441
- state.option.minDate =
442
- dayjs(props.minDate).isValid() === true
443
- ? dayjs(props.minDate).toISOString()
444
- : undefined;
445
- } else {
446
- state.option.minDate = null;
447
- }
448
- if (props.maxDate !== null) {
449
- state.option.maxDate =
450
- dayjs(props.maxDate).isValid() === true
451
- ? dayjs(props.maxDate).toISOString()
452
- : undefined;
453
- } else {
454
- state.option.maxDate = null;
455
- }
456
- generateFlatPickerOption();
457
- } catch (error) {
458
- console.error("resetPicekr()", error);
459
- } finally {
460
- flag.value = false;
461
- }
462
- };
463
- emit("reset-piceker-func", resetPicekr);
464
- watch(
465
- () => props.data,
466
- () => {
467
- setValue();
468
- }
469
- );
470
-
471
- const setValue = () => {
472
- // console.log('setValue');
473
- try {
474
- if (props.data == null) {
475
- state.picker.setDate(null);
476
- state.date = null;
477
- return;
478
- }
479
- const date =
480
- props.mode === "time"
481
- ? dayjs().format("YYYY-MM-DD ") + props.data
482
- : props.data;
483
- const d = getShiftDayjs(date);
484
- // console.log('setValue', date);
485
- if (d.isValid() === true) {
486
- if (checkDate(props.data) === true) {
487
- state.date = d.toDate();
488
- state.picker.setDate(state.date);
489
- return;
490
- }
491
- }
492
- throw new Error("変換失敗");
493
- } catch (err) {
494
- console.error(err);
495
- state.picker.setDate(null);
496
- state.date = null;
497
- updateValue(null);
498
- }
499
- };
500
-
501
- // アイコン系イベント
502
- const datePickerToggle = () => {
503
- if (props.readonly === true) return;
504
- if (props.disabled === true) return;
505
- if (state.picker === null) return;
506
- if (focusState.isClosingFlatpickr) return;
507
- hsFocus.state.id = uid;
508
- state.picker.open();
509
- };
510
-
511
- const datePickerToday = () => {
512
- if (props.readonly === true) return;
513
- if (props.disabled === true) return;
514
- if (state.date !== null) return;
515
- const inputValue = dayjs();
516
- // if (props.mode === "month") {
517
- // inputValue = inputValue.startOf("month");
518
- // }
519
- const d = getShiftDayjs(inputValue);
520
- if (checkDate(d.format("YYYY-MM-DD")) === false) {
521
- Toast.Warning(
522
- props.uiText.error.inputRangeMessage,
523
- props.uiText.error.inputRangeTitle,
524
- props.warnTimeOut
525
- );
526
- return;
527
- }
528
- if (props.mode === "time") {
529
- updateValue(inputValue.format(timeDateFormat));
530
- } else {
531
- updateValue(inputValue.format(props.dataFormat));
532
- }
533
- };
534
-
535
- const updateValue = async (text: string | null) => {
536
- // console.log('updateValue', text);
537
- const before = props.data;
538
- if (text === null || text.length === 0) {
539
- emit("update:data", null);
540
- await nextTick();
541
- emit("value-change", null, before);
542
- return;
543
- }
544
- if (props.mode === "all") {
545
- emit("update:data", dayjs(text).format(props.dataFormat));
546
- nextTick(() => {
547
- emit("value-change", dayjs(text).format(props.dataFormat), before);
548
- });
549
- } else if (props.mode === "time") {
550
- emit("update:data", dayjs(text).format(timeOutputDateFormat));
551
- nextTick(() => {
552
- emit("value-change", dayjs(text).format(timeOutputDateFormat), before);
553
- });
554
- } else {
555
- // 時間情報を削除する
556
- emit(
557
- "update:data",
558
- dayjs(dayjs(text).format("YYYY-MM-DD")).format(props.dataFormat)
559
- );
560
- nextTick(() => {
561
- emit(
562
- "value-change",
563
- dayjs(dayjs(text).format("YYYY-MM-DD")).format(props.dataFormat),
564
- before
565
- );
566
- });
567
- }
568
- };
569
-
570
- const iconEventDelete = () => {
571
- const before = props.data;
572
- if (props.readonly === true) return;
573
- if (props.disabled === true) return;
574
- if (state.date != null) {
575
- emit("update:data", null);
576
- nextTick(() => {
577
- emit("value-change", null, before);
578
- });
579
- }
580
- };
581
-
582
- // [ ref ]
583
- const inputElement = ref();
584
- onMounted(() => {
585
- emit("ref", inputElement.value as HTMLInputElement);
586
- });
587
-
588
- const setRef = (elm: any) => {
589
- inputElement.value = elm;
590
- emit("ref", elm);
591
- };
592
-
593
- // [ focus, blur ]
594
-
595
- interface FocusState {
596
- isOpenFlatpickr: boolean;
597
- isClosingFlatpickr: boolean;
598
- manualInput: boolean;
599
- openBtn: boolean;
600
- }
601
-
602
- const focusState = reactive<FocusState>({
603
- isOpenFlatpickr: false,
604
- isClosingFlatpickr: false,
605
- manualInput: false,
606
- openBtn: false,
607
- });
608
-
609
- /**
610
- * コントロールのFocus判定
611
- */
612
- const computedActivate = computed(() => {
613
- if (props.disabled === true) return false;
614
- if (props.readonly === true) return false;
615
- if (hsFocus.state.id !== uid) return false;
616
- if (focusState.isOpenFlatpickr) return true;
617
- if (focusState.manualInput) return true;
618
- if (focusState.openBtn) return true;
619
- return false;
620
- });
621
-
622
- /**
623
- * focus, blur イベント
624
- */
625
- watch(computedActivate, (value) => {
626
- if (value === true) {
627
- // クリックでの遷移の場合に
628
- // 一つ前のコントロールのblurイベントよりも早くfocusが発生しないようにする対策で10ミリ秒処理をずらす
629
- setTimeout(() => {
630
- emit("focus", inputElement.value);
631
- }, 10);
632
- } else {
633
- emit("blur", inputElement.value);
634
- }
635
- });
636
-
637
- onMounted(async () => {
638
- await Sleep(1);
639
- // setTimeout(() => {
640
- initFlatPickerOption();
641
- generateFlatPickerOption();
642
- // }, 1);
643
- });
644
- onUnmounted(async () => {
645
- await Sleep(1);
646
- if (state.picker != null) {
647
- state.picker.destroy();
648
- state.picker = null;
649
- }
650
- });
651
- const tabindex = computed(() => {
652
- if (props.disabled === true) return -1;
653
- return props.tabindex;
654
- });
655
-
656
- // 更新の有無判定
657
- const isChangeData = computed(() => {
658
- if (props.diff === undefined) return false;
659
- if (props.diff === null && props.data === "") return false;
660
- if (props.diff === "" && props.data === null) return false;
661
- if (props.diff !== props.data) return true;
662
- return false;
663
- });
664
-
665
- const openBtn = ref<HTMLElement | null>();
666
- const manualElm = ref<HTMLInputElement | null>();
667
- const manualData = ref("");
668
- const manualInput = ref(false);
669
- const manualInputClick = () => {
670
- if (props.readonly) return;
671
- if (props.disabled) return;
672
- if (hsMisc.state.isMobile) {
673
- datePickerToggle();
674
- return;
675
- }
676
- manualInput.value = true;
677
- manualElm.value?.focus();
678
- };
679
- const manualInputfocus = () => {
680
- if (props.readonly) return;
681
- if (props.disabled) return;
682
- manualData.value = displayText.value;
683
- focusState.openBtn = false;
684
- setTimeout(() => {
685
- manualElm.value?.select();
686
- hsFocus.state.id = uid;
687
- focusState.manualInput = true;
688
- }, 1);
689
- };
690
- const manualInputBlur = () => {
691
- if (props.readonly) return;
692
- if (props.disabled) return;
693
- try {
694
- const data = manualData.value
695
- .replace(/\//g, "-")
696
- .replace(/-(\d)-/g, "-0$1-")
697
- .replace(/-(\d)$/g, "-0$1");
698
- const dataFormat = props.showFormat.replace(/\//g, "-");
699
- const dt = dayjs(data, dataFormat);
700
- // console.log('manualInputBlur', { data, dataFormat, dt });
701
- if (dt.isValid() === false) {
702
- updateValue(null);
703
- return;
704
- }
705
- updateValue(dt.format(props.dataFormat));
706
- // console.log('manualInputBlur', data);
707
- } catch (err) {
708
- console.error("manualInputBlur", err);
709
- } finally {
710
- manualData.value = "";
711
- manualInput.value = false;
712
- focusState.manualInput = false;
713
- }
714
- };
715
-
716
- const openBtnClick = () => {
717
- if (props.readonly) return;
718
- if (props.disabled) return;
719
- if (!hsMisc.state.isMobile) {
720
- inputElement.value?.focus();
721
- return;
722
- }
723
- hsFocus.state.id = uid;
724
- datePickerToggle();
725
- };
726
-
727
- const openBtnFocus = () => {
728
- if (props.readonly) return;
729
- if (props.disabled) return;
730
- hsFocus.state.id = uid;
731
- focusState.openBtn = true;
732
- };
733
- const computedIsFocusOpenBtn = computed(() => {
734
- if (props.disabled === true) return false;
735
- if (props.readonly === true) return false;
736
- if (hsFocus.state.id !== uid) return false;
737
- if (focusState.isOpenFlatpickr) return true;
738
- if (focusState.openBtn) return true;
739
- return false;
740
- });
741
-
742
- // ---------------------------------------------------------------------------------
743
- </script>
744
-
745
- <template>
746
- <InputFrame
747
- :class="props.class"
748
- :class-header="props.classHeader"
749
- :class-input="[props.classInput]"
750
- :focus="computedActivate"
751
- :focus-color="props.focusColor"
752
- :change="isChangeData"
753
- :change-color="props.changeColor"
754
- :error="props.error"
755
- :error-color="props.errorColor"
756
- :disabled="props.disabled"
757
- :disabled-color="props.disabledColor"
758
- :readonly="props.readonly"
759
- :label="props.label"
760
- :require="props.require"
761
- :require-text="tx(props.requireText).value"
762
- :warn="props.warn"
763
- :warn-time-out="props.warnTimeOut"
764
- :size="props.size"
765
- :headerless="props.headerless"
766
- >
767
- <template v-if="slots.overlay" #overlay>
768
- <slot name="overlay"></slot>
769
- </template>
770
- <template v-if="!props.readonly" #left-icons>
771
- <slot name="left-icons" :disabled="disabled" />
772
- <button
773
- ref="openBtn"
774
- data-sep="right"
775
- data-icon="calendar"
776
- :tabindex="tabindex"
777
- :disabled="disabled"
778
- :class="
779
- !disabled
780
- ? 'cursor-pointer hover:bg-accent1/[0.1] active:bg-accent1/[0.2]'
781
- : ''
782
- "
783
- @click.stop.prevent="openBtnClick()"
784
- @focus="openBtnFocus"
785
- @blur="focusState.openBtn = false"
786
- >
787
- <div
788
- class="tw-absolute tw-inset-[2px] tw-border-main2 tw-border tw-pointer-events-none tw-transition-all tw-rounded-sm"
789
- :class="computedIsFocusOpenBtn ? 'tw-opacity-100' : 'tw-opacity-0'"
790
- ></div>
791
- <i
792
- :class="
793
- props.mode === 'time'
794
- ? 'fa-regular fa-clock'
795
- : 'fa-solid fa-calendar-days'
796
- "
797
- ></i>
798
- <!-- <div
799
- class="absolute inset-[2px] border-main2 border pointer-events-none transition-all rounded-sm"
800
- :class="computedIsFocusOpenBtn ? 'opacity-100' : 'opacity-0'"
801
- ></div> -->
802
- </button>
803
- </template>
804
- <div
805
- class="nac-c-input-p"
806
- :class="[
807
- { disabled: props.disabled, readonly: props.readonly },
808
- inputBoxClass,
809
- ]"
810
- @click="manualInputClick"
811
- @dblclick="datePickerToggle()"
812
- >
813
- <!---->
814
- <!-- -->
815
- <input
816
- :ref="(e) => setRef(e)"
817
- type="text"
818
- class="flatpickr-body"
819
- :disabled="props.disabled"
820
- tabindex="-1"
821
- @keydown="keyDown"
822
- />
823
- <input
824
- ref="manualElm"
825
- v-model="manualData"
826
- type="text"
827
- class="absolute inset-0"
828
- :class="[
829
- manualInput
830
- ? 'pointer-events-auto opacity-100'
831
- : 'pointer-events-none opacity-0',
832
- inputBoxClass,
833
- ]"
834
- :tabindex="-1"
835
- @blur="manualInputBlur()"
836
- @focus="manualInputfocus()"
837
- />
838
- <span
839
- :class="
840
- !manualInput
841
- ? 'pointer-events-auto opacity-100'
842
- : 'pointer-events-none opacity-0'
843
- "
844
- >{{ displayText }}</span
845
- >
846
- <span
847
- v-if="props.data === null && !props.hideTodayBtn && !props.readonly"
848
- class="today"
849
- :class="
850
- !manualInput
851
- ? 'pointer-events-auto opacity-100'
852
- : 'pointer-events-none opacity-0'
853
- "
854
- @click.stop="datePickerToday()"
855
- >
856
- <!-- {{ props.mode === "month" ? "Now" : "Today" }} -->
857
- Today
858
- </span>
859
- </div>
860
- <template #right-icons>
861
- <template v-if="!props.hideDeleteBtn && !props.readonly">
862
- <div
863
- :class="
864
- !disabled
865
- ? 'text-error cursor-pointer hover:bg-error/[0.1] active:bg-error/[0.2]'
866
- : ''
867
- "
868
- @click="iconEventDelete()"
869
- >
870
- <i class="fa-solid fa-delete-left"></i>
871
- </div>
872
- </template>
873
- <slot name="right-icons" :disabled="disabled" />
874
- </template>
875
- </InputFrame>
876
- </template>
877
-
1
+ <script setup>
2
+ import { fromDate, toCalendarDate, getLocalTimeZone } from "@internationalized/date";
3
+ import { reactive, ref, watch, computed, useId, onMounted, nextTick, shallowRef } from "#imports";
4
+ import { GetTimeShiftValue, Dayjs, DayjsInit, dayjs } from "../../utils/dayjs";
5
+ import { Theme, GetColorCode } from "../../utils/theme";
6
+ import { IntNullable } from "../../utils/number";
7
+ import { useHsFocus } from "../../composables/use-hs-focus";
8
+ import { useHsToast } from "../../composables/use-hs-toast";
9
+ import { useHsMultiLang } from "../../composables/use-hs-multi-lang";
10
+ import { useHsPinia } from "../../composables/use-pinia";
11
+ import { useHsIsMobile } from "../../composables/use-hs-is-mobile";
12
+ import { useHsMisc } from "../../composables/use-hs-misc";
13
+ import InputFrame from "./input-frame.vue";
14
+ DayjsInit();
15
+ const hsFocus = useHsFocus(useHsPinia());
16
+ const Toast = useHsToast(useHsPinia());
17
+ const multiLang = useHsMultiLang(useHsPinia());
18
+ const tx = multiLang.tx;
19
+ const hsIsMobile = useHsIsMobile(useHsPinia());
20
+ const hsMisc = useHsMisc(useHsPinia());
21
+ onMounted(() => {
22
+ hsIsMobile.init();
23
+ });
24
+ const timeOutputDateFormat = "HH:mm:ss.SSS";
25
+ const timeShowDateFormat = "HH:mm";
26
+ const timeDateFormat = "YYYY-MM-DD HH:mm:ss.SSS";
27
+ const props = defineProps({
28
+ theme: { type: null, required: false, default: Theme.accent1 },
29
+ textAlign: { type: String, required: false, default: "left" },
30
+ mode: { type: String, required: false, default: "date" },
31
+ dataFormat: { type: String, required: false, default: "" },
32
+ showFormat: { type: String, required: false, default: "" },
33
+ minDate: { type: [String, null], required: false, default: null },
34
+ maxDate: { type: [String, null], required: false, default: null },
35
+ hideDeleteBtn: { type: Boolean, required: false, default: false },
36
+ hideTodayBtn: { type: Boolean, required: false },
37
+ disableMobile: { type: Boolean, required: false, default: false },
38
+ hasShift: { type: Boolean, required: false, default: true },
39
+ locale: { type: null, required: false, default: void 0 },
40
+ portal: { type: [String, Boolean], required: false, skipCheck: true, default: true },
41
+ data: { type: [String, null], required: true },
42
+ diff: { type: null, required: false, default: void 0 },
43
+ tabindex: { type: null, required: false, default: void 0 },
44
+ class: { type: [String, Object, Array], required: false, default: "" },
45
+ classHeader: { type: [String, Object, Array], required: false, default: "" },
46
+ classInput: { type: [String, Object, Array], required: false, default: "" },
47
+ focusColor: { type: String, required: false, default: "shadow-[inset_0px_0px_1px_2px_#0d8ee4]" },
48
+ changeColor: { type: String, required: false, default: "shadow-[inset_0px_0px_1px_2px_#fd9831be]" },
49
+ error: { type: Boolean, required: false, default: false },
50
+ errorColor: { type: String, required: false, default: "shadow-[inset_0px_0px_1px_2px_#d80000dc]" },
51
+ disabled: { type: Boolean, required: false, default: false },
52
+ disabledColor: { type: String, required: false, default: "" },
53
+ readonly: { type: Boolean, required: false, default: false },
54
+ headerless: { type: Boolean, required: false, default: false },
55
+ label: { type: [String, Object], required: false, default: "" },
56
+ require: { type: Boolean, required: false, default: false },
57
+ requireText: { type: [String, Object], required: false, default: () => ({ ja: "\u5FC5\u9808", en: "Required" }) },
58
+ warn: { type: String, required: false, default: "" },
59
+ warnTimeOut: { type: Number, required: false, default: 3e3 },
60
+ size: { type: String, required: false, default: "m" },
61
+ uiText: { type: Object, required: false, default: () => {
62
+ return {
63
+ error: {
64
+ inputRangeTitle: { ja: "\u5165\u529B\u5024\u306E\u8B66\u544A", en: "Input Value Warning" },
65
+ inputRangeMessage: {
66
+ ja: "\u5165\u529B\u7BC4\u56F2\u5916\u3067\u3059",
67
+ en: "Input is out of range"
68
+ }
69
+ }
70
+ };
71
+ } }
72
+ });
73
+ const emit = defineEmits(["ref", "focus", "blur", "update:data", "value-change", "reset-piceker-func"]);
74
+ const themeColor = computed(() => {
75
+ return GetColorCode(props.theme);
76
+ });
77
+ const themeWeekColor = computed(() => {
78
+ return GetColorCode(Theme.main1);
79
+ });
80
+ const themeErrorColor = computed(() => {
81
+ return GetColorCode(Theme.error);
82
+ });
83
+ const slots = defineSlots();
84
+ const uid = useId();
85
+ const shiftM = GetTimeShiftValue(Dayjs());
86
+ const getShiftDayjs = (date) => {
87
+ if (props.hasShift && shiftM !== 0) {
88
+ return dayjs().subtract(shiftM, "minute");
89
+ }
90
+ return dayjs(date);
91
+ };
92
+ const dataDasyjs = computed(() => {
93
+ const lang = multiLang.lang;
94
+ dayjs.locale(lang);
95
+ if (props.data === null) {
96
+ return null;
97
+ } else if (props.mode === "time") {
98
+ return getShiftDayjs(dayjs().format("YYYY-MM-DD ") + props.data);
99
+ } else {
100
+ return getShiftDayjs(props.data);
101
+ }
102
+ });
103
+ const minDayjs = computed(() => {
104
+ if (props.minDate === null) {
105
+ return null;
106
+ } else if (props.mode === "time") {
107
+ return getShiftDayjs(dayjs().format("YYYY-MM-DD ") + props.minDate);
108
+ } else {
109
+ return getShiftDayjs(props.minDate);
110
+ }
111
+ });
112
+ const maxDayjs = computed(() => {
113
+ if (props.maxDate === null) {
114
+ return null;
115
+ } else if (props.mode === "time") {
116
+ return getShiftDayjs(dayjs().format("YYYY-MM-DD ") + props.maxDate);
117
+ } else {
118
+ return getShiftDayjs(props.maxDate);
119
+ }
120
+ });
121
+ const diffDasyjs = computed(() => {
122
+ const lang = multiLang.lang;
123
+ dayjs.locale(lang);
124
+ if (!props.diff) {
125
+ return null;
126
+ } else if (props.mode === "time") {
127
+ return getShiftDayjs(dayjs().format("YYYY-MM-DD ") + props.diff);
128
+ } else {
129
+ return getShiftDayjs(props.diff);
130
+ }
131
+ });
132
+ const displayText = computed(() => {
133
+ if (dataDasyjs.value === null) {
134
+ return "";
135
+ } else if (props.mode === "time") {
136
+ return dataDasyjs.value.format(timeShowDateFormat);
137
+ } else {
138
+ return dataDasyjs.value.format(props.showFormat);
139
+ }
140
+ });
141
+ const displayDiffText = computed(() => {
142
+ if (diffDasyjs.value === null) {
143
+ return "";
144
+ } else if (props.mode === "time") {
145
+ return diffDasyjs.value.format(timeShowDateFormat);
146
+ } else {
147
+ return diffDasyjs.value.format(props.showFormat);
148
+ }
149
+ });
150
+ const checkDate = (date) => {
151
+ const d = getShiftDayjs(date);
152
+ if (props.minDate !== "" && d.isBefore(props.minDate)) {
153
+ return false;
154
+ } else if (props.maxDate !== "" && d.isAfter(props.maxDate)) {
155
+ return false;
156
+ }
157
+ return true;
158
+ };
159
+ const updateValue = async (text) => {
160
+ const before = props.data;
161
+ if (text === null || text.length === 0) {
162
+ emit("update:data", null);
163
+ await nextTick();
164
+ emit("value-change", null, before);
165
+ return;
166
+ }
167
+ if (props.mode === "all" || props.mode === "date") {
168
+ const d = getShiftDayjs(dayjs(text));
169
+ if (checkDate(d.format("YYYY-MM-DD")) === false) {
170
+ Toast.Warning(props.uiText.error.inputRangeMessage, props.uiText.error.inputRangeTitle, props.warnTimeOut);
171
+ return;
172
+ }
173
+ }
174
+ if (props.mode === "all") {
175
+ emit("update:data", dayjs(text).format(props.dataFormat));
176
+ nextTick(() => {
177
+ emit("value-change", dayjs(text).format(props.dataFormat), before);
178
+ });
179
+ } else if (props.mode === "time") {
180
+ emit("update:data", dayjs(text).format(timeOutputDateFormat));
181
+ nextTick(() => {
182
+ emit("value-change", dayjs(text).format(timeOutputDateFormat), before);
183
+ });
184
+ } else {
185
+ emit("update:data", dayjs(dayjs(text).format("YYYY-MM-DD")).format(props.dataFormat));
186
+ nextTick(() => {
187
+ emit("value-change", dayjs(dayjs(text).format("YYYY-MM-DD")).format(props.dataFormat), before);
188
+ });
189
+ }
190
+ };
191
+ const datePickerToday = () => {
192
+ if (props.readonly === true) return;
193
+ if (props.disabled === true) return;
194
+ const inputValue = dayjs();
195
+ const d = getShiftDayjs(inputValue);
196
+ if (checkDate(d.format("YYYY-MM-DD")) === false) {
197
+ Toast.Warning(props.uiText.error.inputRangeMessage, props.uiText.error.inputRangeTitle, props.warnTimeOut);
198
+ return;
199
+ }
200
+ updateValue(inputValue.format(""));
201
+ };
202
+ const inputBoxClass = computed(() => {
203
+ if (props.textAlign === "left") {
204
+ return "display-left";
205
+ } else if (props.textAlign === "center") {
206
+ return "display-center";
207
+ } else {
208
+ return "display-right";
209
+ }
210
+ });
211
+ const iconEventDelete = () => {
212
+ const before = props.data;
213
+ if (props.readonly === true) return;
214
+ if (props.disabled === true) return;
215
+ emit("update:data", null);
216
+ nextTick(() => {
217
+ emit("value-change", null, before);
218
+ });
219
+ };
220
+ const inputElement = ref();
221
+ defineExpose({ el: inputElement });
222
+ onMounted(() => {
223
+ emit("ref", inputElement.value);
224
+ });
225
+ const tabindex = computed(() => {
226
+ if (props.disabled === true) return -1;
227
+ return props.tabindex;
228
+ });
229
+ const isChangeData = computed(() => {
230
+ if (props.diff === void 0) return false;
231
+ if (props.diff === null && props.data === "") return false;
232
+ if (props.diff === "" && props.data === null) return false;
233
+ if (props.diff !== props.data) return true;
234
+ return false;
235
+ });
236
+ const open = ref(false);
237
+ const openBtn = shallowRef(null);
238
+ const calendarValue = shallowRef(null);
239
+ const displayLocale = computed(() => {
240
+ if (props.locale) return props.locale;
241
+ return multiLang.lang === "ja" ? "ja-JP" : "en-US";
242
+ });
243
+ const calendarMinValue = computed(() => {
244
+ if (!minDayjs.value) return null;
245
+ return toCalendarDate(fromDate(minDayjs.value.toDate(), getLocalTimeZone()));
246
+ });
247
+ const calendarMaxValue = computed(() => {
248
+ if (!maxDayjs.value) return null;
249
+ return toCalendarDate(fromDate(maxDayjs.value.toDate(), getLocalTimeZone()));
250
+ });
251
+ const HH = shallowRef(null);
252
+ const MM = shallowRef(null);
253
+ const pad2 = (n) => String(n).padStart(2, "0");
254
+ const listHH = Array.from({ length: 24 }).fill(null).map((_, index) => {
255
+ return { id: index, label: pad2(index) };
256
+ });
257
+ const listMM = Array.from({ length: 60 }).fill(null).map((_, index) => {
258
+ return { id: index, label: pad2(index) };
259
+ });
260
+ const toggleModal = () => {
261
+ if (props.readonly) return;
262
+ if (props.disabled) return;
263
+ const openState = !open.value;
264
+ if (!openState) {
265
+ open.value = false;
266
+ return;
267
+ }
268
+ if (hsFocus.state.id !== uid) {
269
+ hsFocus.state.id = uid;
270
+ }
271
+ if (dataDasyjs.value === null) {
272
+ calendarValue.value = null;
273
+ HH.value = null;
274
+ MM.value = null;
275
+ open.value = true;
276
+ return;
277
+ }
278
+ if (props.mode !== "time") {
279
+ const calDate = toCalendarDate(fromDate(dataDasyjs.value.toDate(), getLocalTimeZone()));
280
+ calendarValue.value = calDate;
281
+ } else {
282
+ calendarValue.value = null;
283
+ }
284
+ if (props.mode === "all" || props.mode === "time") {
285
+ HH.value = dataDasyjs.value.hour();
286
+ MM.value = dataDasyjs.value.minute();
287
+ } else {
288
+ HH.value = null;
289
+ MM.value = null;
290
+ }
291
+ open.value = true;
292
+ };
293
+ function toJSDate(v, tz) {
294
+ return "timeZone" in v || "offset" in v ? v.toDate() : v.toDate(tz);
295
+ }
296
+ const changeCalender = (date) => {
297
+ const TZ = getLocalTimeZone();
298
+ const t = date ? Dayjs(toJSDate(date, TZ)).tz(TZ) : null;
299
+ if (!t) {
300
+ calendarValue.value = null;
301
+ HH.value = null;
302
+ MM.value = null;
303
+ updateValue(null);
304
+ return;
305
+ }
306
+ if (!HH.value) HH.value = 0;
307
+ if (!MM.value) MM.value = 0;
308
+ if (props.mode === "all" || props.mode === "time") {
309
+ updateValue(t.format("YYYY-MM-DD") + ` ${pad2(HH.value || 0)}:${pad2(MM.value || 0)}`);
310
+ } else {
311
+ updateValue(t.format(""));
312
+ }
313
+ calendarValue.value = date;
314
+ };
315
+ const hhValueChange = (_value) => {
316
+ const value = IntNullable(_value);
317
+ if (value && value >= 0 && value <= 23) {
318
+ HH.value = value;
319
+ if (!MM.value) MM.value = 0;
320
+ if (!calendarValue.value) {
321
+ calendarValue.value = toCalendarDate(fromDate(/* @__PURE__ */ new Date(), getLocalTimeZone()));
322
+ }
323
+ } else {
324
+ HH.value = null;
325
+ MM.value = null;
326
+ calendarValue.value = null;
327
+ }
328
+ changeCalender(calendarValue.value);
329
+ };
330
+ const mmValueChange = (_value) => {
331
+ const value = IntNullable(_value);
332
+ if (value && value >= 0 && value <= 59) {
333
+ HH.value = value;
334
+ if (!HH.value) HH.value = 0;
335
+ if (!calendarValue.value) {
336
+ calendarValue.value = toCalendarDate(fromDate(/* @__PURE__ */ new Date(), getLocalTimeZone()));
337
+ }
338
+ } else {
339
+ HH.value = null;
340
+ MM.value = null;
341
+ calendarValue.value = null;
342
+ }
343
+ changeCalender(calendarValue.value);
344
+ };
345
+ const focusState = reactive({
346
+ isOpenFlatpickr: false,
347
+ isClosingFlatpickr: false,
348
+ manualInput: false,
349
+ openBtn: false
350
+ });
351
+ const computedActivate = computed(() => {
352
+ if (props.disabled === true) return false;
353
+ if (props.readonly === true) return false;
354
+ if (hsFocus.state.id !== uid) return false;
355
+ if (open.value === true) return true;
356
+ if (focusState.isOpenFlatpickr) return true;
357
+ if (focusState.manualInput) return true;
358
+ if (focusState.openBtn) return true;
359
+ return false;
360
+ });
361
+ watch(
362
+ () => hsFocus.state.id,
363
+ () => {
364
+ open.value = false;
365
+ }
366
+ );
367
+ watch(computedActivate, (value) => {
368
+ if (value === true) {
369
+ setTimeout(() => {
370
+ emit("focus", inputElement.value);
371
+ }, 10);
372
+ } else {
373
+ emit("blur", inputElement.value);
374
+ }
375
+ });
376
+ const openBtnFocus = () => {
377
+ if (props.readonly) return;
378
+ if (props.disabled) return;
379
+ if (hsFocus.state.id !== uid) {
380
+ hsFocus.state.id = uid;
381
+ }
382
+ focusState.openBtn = true;
383
+ };
384
+ const manualElm = ref(null);
385
+ const manualData = ref("");
386
+ const manualInput = ref(false);
387
+ const manualInputClick = () => {
388
+ if (props.readonly) return;
389
+ if (props.disabled) return;
390
+ if (hsIsMobile.isMobile) {
391
+ toggleModal();
392
+ return;
393
+ }
394
+ manualInput.value = true;
395
+ manualElm.value?.focus();
396
+ };
397
+ const manualInputfocus = () => {
398
+ if (props.readonly) return;
399
+ if (props.disabled) return;
400
+ manualData.value = displayText.value;
401
+ focusState.openBtn = false;
402
+ setTimeout(() => {
403
+ manualElm.value?.select();
404
+ if (hsFocus.state.id !== uid) {
405
+ hsFocus.state.id = uid;
406
+ }
407
+ focusState.manualInput = true;
408
+ }, 1);
409
+ };
410
+ const manualInputBlur = () => {
411
+ if (props.readonly) return;
412
+ if (props.disabled) return;
413
+ const TZ = getLocalTimeZone();
414
+ try {
415
+ if (props.mode === "all" || props.mode === "date") {
416
+ const d = dayjs(manualData.value, props.showFormat, true);
417
+ if (!d.isValid()) {
418
+ updateValue(null);
419
+ return;
420
+ }
421
+ updateValue(d.tz(TZ).format(props.dataFormat));
422
+ } else if (props.mode === "time") {
423
+ const inputValue = manualData.value.replace(/[-:]/g, "").replace(/(\d{2})(\d{2})/, "$1:$2");
424
+ const nowDt = dayjs().format("YYYY-MM-DD");
425
+ const d = dayjs(nowDt + " " + inputValue, timeDateFormat, true);
426
+ if (!d.isValid()) {
427
+ updateValue(null);
428
+ return;
429
+ }
430
+ updateValue(d.tz(TZ).format(timeDateFormat));
431
+ }
432
+ } catch (err) {
433
+ console.error("manualInputBlur", err);
434
+ } finally {
435
+ manualData.value = "";
436
+ manualInput.value = false;
437
+ focusState.manualInput = false;
438
+ }
439
+ };
440
+ const computedIsFocusOpenBtn = computed(() => {
441
+ if (props.disabled === true) return false;
442
+ if (props.readonly === true) return false;
443
+ if (hsFocus.state.id !== uid) return false;
444
+ if (focusState.isOpenFlatpickr) return true;
445
+ if (focusState.openBtn) return true;
446
+ return false;
447
+ });
448
+ const KEEP_OPEN_SELECTOR = "[data-keep-popover-open]";
449
+ const content = {
450
+ align: "start",
451
+ sideOffset: 8,
452
+ onPointerDownOutside: (e) => {
453
+ const t = e.target;
454
+ if (t.closest(KEEP_OPEN_SELECTOR)) {
455
+ e.preventDefault();
456
+ }
457
+ },
458
+ onFocusOutside: (e) => {
459
+ const t = e.target;
460
+ if (t.closest(KEEP_OPEN_SELECTOR)) e.preventDefault();
461
+ }
462
+ };
463
+ const posTarget = shallowRef(null);
464
+ </script>
465
+
466
+ <template>
467
+ <InputFrame
468
+ v-bind="$attrs"
469
+ :class="['HsDatePicker', props.class]"
470
+ :class-header="props.classHeader"
471
+ :class-input="[props.classInput]"
472
+ :focus="computedActivate"
473
+ :focus-color="props.focusColor"
474
+ :change="isChangeData"
475
+ :change-color="props.changeColor"
476
+ :error="props.error"
477
+ :error-color="props.errorColor"
478
+ :disabled="props.disabled"
479
+ :disabled-color="props.disabledColor"
480
+ :readonly="props.readonly"
481
+ :label="props.label"
482
+ :require="props.require"
483
+ :require-text="tx(props.requireText).value"
484
+ :warn="props.warn"
485
+ :warn-time-out="props.warnTimeOut"
486
+ :size="props.size"
487
+ :headerless="props.headerless"
488
+ @ref="(e) => posTarget = e"
489
+ >
490
+ <template #overlay="{ focus, change }">
491
+ <div
492
+ v-if="props.diff !== void 0 && change"
493
+ class="absolute inset-0 bg-red/30 transition-opacity flex items-center p-1 bg-dark/20"
494
+ :class="!focus && hsMisc.capsLockState ? 'opacity-100' : 'opacity-0 pointer-events-none select-none'"
495
+ >
496
+ <div class="flex">
497
+ <Btn
498
+ variant="outlined"
499
+ theme="error"
500
+ tabindex="-1"
501
+ size="xs"
502
+ class="bg-white flex-none"
503
+ @click="updateValue(props.diff)"
504
+ >
505
+ <i class="fa-solid fa-rotate-right"></i>
506
+ </Btn>
507
+ <div v-if="props.diff" class="px-1 truncate bg-white mx-1 flex items-center">{{ displayDiffText }}</div>
508
+ </div>
509
+ </div>
510
+ <template v-if="slots.overlay">
511
+ <slot name="overlay" :focus="focus" :change="change"></slot>
512
+ </template>
513
+ </template>
514
+ <template v-if="!props.readonly || slots['left-icons']" #left-icons>
515
+ <slot name="left-icons" :disabled="disabled" />
516
+ <!-- <UButton label="" color="neutral" variant="subtle" /> -->
517
+
518
+ <button
519
+ v-if="!props.readonly"
520
+ ref="openBtn"
521
+ data-sep="right"
522
+ data-icon="calendar"
523
+ :tabindex="tabindex"
524
+ :disabled="disabled"
525
+ class="open-btn"
526
+ :class="!disabled ? 'cursor-pointer hover:bg-accent1/10 active:bg-accent1/20' : ''"
527
+ data-keep-popover-open
528
+ @focus="openBtnFocus"
529
+ @blur="focusState.openBtn = false"
530
+ @click.stop="toggleModal"
531
+ >
532
+ <div
533
+ class="absolute inset-1 border-main2 border pointer-events-none transition-all rounded-sm"
534
+ :class="computedIsFocusOpenBtn ? 'opacity-100' : 'opacity-0'"
535
+ ></div>
536
+ <i :class="props.mode === 'time' ? 'fa-regular fa-clock' : 'fa-solid fa-calendar-days'"></i>
537
+ </button>
538
+ </template>
539
+ <template #right-icons>
540
+ <template v-if="!props.hideDeleteBtn && !props.readonly">
541
+ <button
542
+ :class="!disabled ? 'text-error cursor-pointer hover:bg-error/10 active:bg-error/20' : ''"
543
+ tabindex="-1"
544
+ @click.stop="iconEventDelete()"
545
+ >
546
+ <i class="fa-solid fa-delete-left"></i>
547
+ </button>
548
+ </template>
549
+ <slot name="right-icons" :disabled="disabled" />
550
+ </template>
551
+ <template v-if="slots['label-prepend']" #label-prepend>
552
+ <slot name="label-prepend" />
553
+ </template>
554
+ <template v-if="slots['label-append']" #label-append>
555
+ <slot name="label-append" />
556
+ </template>
557
+ <template v-if="slots['header-right']" #header-right>
558
+ <slot name="header-right" />
559
+ </template>
560
+
561
+ <div
562
+ class="nac-c-input-p relative min-h-5"
563
+ :class="[{ disabled: props.disabled, readonly: props.readonly }, inputBoxClass]"
564
+ @click.stop="manualInputClick"
565
+ >
566
+ <input
567
+ ref="manualElm"
568
+ v-model="manualData"
569
+ type="text"
570
+ class="absolute inset-0"
571
+ :class="[manualInput ? 'pointer-events-auto opacity-100' : 'pointer-events-none opacity-0', inputBoxClass]"
572
+ :tabindex="-1"
573
+ :name="'HsDatePicker-manual-input-' + uid"
574
+ @blur="manualInputBlur()"
575
+ @focus="manualInputfocus()"
576
+ />
577
+ <span :class="!manualInput ? 'pointer-events-auto opacity-100' : 'pointer-events-none opacity-0'">
578
+ {{ displayText }}
579
+ </span>
580
+ <span
581
+ v-if="props.data === null && !props.hideTodayBtn && !props.readonly"
582
+ class="today"
583
+ :class="!manualInput ? 'pointer-events-auto opacity-100' : 'pointer-events-none opacity-0'"
584
+ @click.stop="datePickerToday()"
585
+ >
586
+ {{ props.mode === "time" ? "Now" : "Today" }}
587
+ </span>
588
+ </div>
589
+ </InputFrame>
590
+ <ClientOnly>
591
+ <UPopover
592
+ v-model:open="open"
593
+ arrow
594
+ :reference="openBtn || void 0"
595
+ :portal="props.portal"
596
+ :open-delay="10"
597
+ :same-width="false"
598
+ strategy="absolute"
599
+ :content="content"
600
+ >
601
+ <template #content>
602
+ <div
603
+ class="calender-modal min-w-50"
604
+ :style="{
605
+ '--selected-color': themeColor,
606
+ '--error-color': themeErrorColor,
607
+ '--ui-primary': themeColor,
608
+ '--ui-secondary': themeWeekColor
609
+ }"
610
+ >
611
+ <UCalendar
612
+ v-if="props.mode !== 'time'"
613
+ :model-value="calendarValue"
614
+ class="p-2"
615
+ :locale="displayLocale"
616
+ :min-value="calendarMinValue || void 0"
617
+ :max-value="calendarMaxValue || void 0"
618
+ color="secondary"
619
+ :ui="{}"
620
+ @update:model-value="(v) => changeCalender(v)"
621
+ />
622
+ <div v-if="props.mode === 'all' || props.mode === 'time'" class="grid grid-cols-2 gap-1 p-1">
623
+ <template v-if="hsIsMobile.isMobile">
624
+ <USelect
625
+ :model-value="HH || void 0"
626
+ :items="listHH"
627
+ class=""
628
+ value-key="id"
629
+ placeholder="HH"
630
+ :search-input="{
631
+ placeholder: 'HH',
632
+ type: 'number'
633
+ }"
634
+ @update:model-value="(v) => hhValueChange(v)"
635
+ />
636
+ <USelect
637
+ :model-value="MM || void 0"
638
+ :items="listMM"
639
+ class=""
640
+ value-key="id"
641
+ placeholder="mm"
642
+ :search-input="{
643
+ placeholder: 'mm',
644
+ type: 'number'
645
+ }"
646
+ @update:model-value="(v) => mmValueChange(v)"
647
+ />
648
+ </template>
649
+ <template v-else>
650
+ <USelectMenu
651
+ :model-value="HH || void 0"
652
+ :items="listHH"
653
+ class=""
654
+ value-key="id"
655
+ placeholder="HH"
656
+ :search-input="{
657
+ placeholder: 'HH',
658
+ type: 'number'
659
+ }"
660
+ @update:model-value="(v) => hhValueChange(v)"
661
+ />
662
+ <USelectMenu
663
+ :model-value="MM || void 0"
664
+ :items="listMM"
665
+ class=""
666
+ value-key="id"
667
+ placeholder="mm"
668
+ :search-input="{
669
+ placeholder: 'mm',
670
+ type: 'number'
671
+ }"
672
+ @update:model-value="(v) => mmValueChange(v)"
673
+ />
674
+ </template>
675
+ </div>
676
+ </div>
677
+ </template>
678
+ </UPopover>
679
+ </ClientOnly>
680
+ </template>
681
+
878
682
  <style scoped>
879
683
  .nac-c-input-p {
880
684
  width: 100%;
@@ -905,11 +709,6 @@ const computedIsFocusOpenBtn = computed(() => {
905
709
  pointer-events: none;
906
710
  }
907
711
 
908
- :deep(.flatpickr-mobile) {
909
- position: absolute;
910
- opacity: 0;
911
- }
912
-
913
712
  .nac-c-input-p {
914
713
  display: flex;
915
714
  align-items: center;
@@ -930,4 +729,39 @@ const computedIsFocusOpenBtn = computed(() => {
930
729
  .disabled .nac-c-input-p .today {
931
730
  display: none;
932
731
  }
933
- </style>
732
+
733
+ .calender-modal:deep(*) [data-reka-calendar-cell-trigger] {
734
+ cursor: pointer;
735
+ }
736
+ .calender-modal:deep(*) [data-reka-calendar-cell-trigger][data-today]:not([data-selected]) {
737
+ color: var(--selected-color) !important;
738
+ }
739
+ .calender-modal:deep(*) [data-reka-calendar-cell-trigger][data-disabled] {
740
+ background-color: #afafaf !important;
741
+ color: white !important;
742
+ }
743
+ .calender-modal:deep(*) [data-selected] {
744
+ background: var(--selected-color) !important;
745
+ color: white !important;
746
+ }
747
+ @media (hover: hover) {
748
+ .calender-modal:deep(*) [data-reka-calendar-cell-trigger]:hover:not([data-selected]):not([data-disabled]) {
749
+ background-color: color-mix(in oklab, var(--selected-color) 20%, transparent);
750
+ }
751
+ }
752
+ @media (hover: hover) {
753
+ .calender-modal:deep(*) [data-reka-calendar-cell-trigger]:hover:not([data-selected])[data-disabled] {
754
+ background-color: color-mix(in oklab, var(--error-color) 50%, transparent);
755
+ }
756
+ }
757
+ </style>
758
+
759
+ <style>
760
+ [data-reka-popper-content-wrapper] > [data-dismissable-layer] {
761
+ filter: drop-shadow(0px 0px 3px rgba(0, 0, 0, 0.58));
762
+ }
763
+
764
+ [data-reka-popper-content-wrapper] > [data-dismissable-layer] > span > svg {
765
+ fill: white;
766
+ }
767
+ </style>