@14ch/svelte-ui 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +359 -0
- package/dist/assets/styles/README.md +144 -0
- package/dist/assets/styles/core.scss +61 -0
- package/dist/assets/styles/import.scss +11 -0
- package/dist/assets/styles/optional/fonts.scss +23 -0
- package/dist/assets/styles/optional/reset.scss +230 -0
- package/dist/assets/styles/variables.scss +805 -0
- package/dist/components/Button.svelte +574 -0
- package/dist/components/Button.svelte.d.ts +56 -0
- package/dist/components/COMPONENT_DESIGN_GUIDELINES.md +127 -0
- package/dist/components/Checkbox.svelte +523 -0
- package/dist/components/Checkbox.svelte.d.ts +42 -0
- package/dist/components/CheckboxGroup.svelte +82 -0
- package/dist/components/CheckboxGroup.svelte.d.ts +13 -0
- package/dist/components/ColorPicker.svelte +496 -0
- package/dist/components/ColorPicker.svelte.d.ts +45 -0
- package/dist/components/Combobox.svelte +576 -0
- package/dist/components/Combobox.svelte.d.ts +52 -0
- package/dist/components/ConfirmDialog.svelte +116 -0
- package/dist/components/ConfirmDialog.svelte.d.ts +20 -0
- package/dist/components/Datepicker.svelte +578 -0
- package/dist/components/Datepicker.svelte.d.ts +72 -0
- package/dist/components/DatepickerCalendar.svelte +925 -0
- package/dist/components/DatepickerCalendar.svelte.d.ts +31 -0
- package/dist/components/Dialog.svelte +245 -0
- package/dist/components/Dialog.svelte.d.ts +38 -0
- package/dist/components/Drawer.svelte +383 -0
- package/dist/components/Drawer.svelte.d.ts +39 -0
- package/dist/components/Fab.svelte +486 -0
- package/dist/components/Fab.svelte.d.ts +51 -0
- package/dist/components/FileUploader.svelte +456 -0
- package/dist/components/FileUploader.svelte.d.ts +36 -0
- package/dist/components/Icon.svelte +167 -0
- package/dist/components/Icon.svelte.d.ts +21 -0
- package/dist/components/IconButton.svelte +557 -0
- package/dist/components/IconButton.svelte.d.ts +60 -0
- package/dist/components/ImageUploader.svelte +516 -0
- package/dist/components/ImageUploader.svelte.d.ts +37 -0
- package/dist/components/ImageUploaderPreview.svelte +157 -0
- package/dist/components/ImageUploaderPreview.svelte.d.ts +13 -0
- package/dist/components/Input.svelte +885 -0
- package/dist/components/Input.svelte.d.ts +75 -0
- package/dist/components/LoadingSpinner.svelte +116 -0
- package/dist/components/LoadingSpinner.svelte.d.ts +10 -0
- package/dist/components/Modal.svelte +313 -0
- package/dist/components/Modal.svelte.d.ts +34 -0
- package/dist/components/Pagination.svelte +276 -0
- package/dist/components/Pagination.svelte.d.ts +14 -0
- package/dist/components/Popup.svelte +676 -0
- package/dist/components/Popup.svelte.d.ts +40 -0
- package/dist/components/PopupMenu.svelte +421 -0
- package/dist/components/PopupMenu.svelte.d.ts +24 -0
- package/dist/components/PopupMenuButton.svelte +365 -0
- package/dist/components/PopupMenuButton.svelte.d.ts +42 -0
- package/dist/components/Radio.svelte +548 -0
- package/dist/components/Radio.svelte.d.ts +42 -0
- package/dist/components/RadioGroup.svelte +74 -0
- package/dist/components/RadioGroup.svelte.d.ts +14 -0
- package/dist/components/Select.svelte +479 -0
- package/dist/components/Select.svelte.d.ts +47 -0
- package/dist/components/Slider.svelte +473 -0
- package/dist/components/Slider.svelte.d.ts +46 -0
- package/dist/components/Snackbar.svelte +124 -0
- package/dist/components/Snackbar.svelte.d.ts +9 -0
- package/dist/components/SnackbarItem.svelte +423 -0
- package/dist/components/SnackbarItem.svelte.d.ts +21 -0
- package/dist/components/Switch.svelte +454 -0
- package/dist/components/Switch.svelte.d.ts +40 -0
- package/dist/components/Tab.svelte +193 -0
- package/dist/components/Tab.svelte.d.ts +14 -0
- package/dist/components/TabItem.svelte +140 -0
- package/dist/components/TabItem.svelte.d.ts +17 -0
- package/dist/components/Textarea.svelte +702 -0
- package/dist/components/Textarea.svelte.d.ts +64 -0
- package/dist/components/skeleton/Skeleton.svelte +235 -0
- package/dist/components/skeleton/Skeleton.svelte.d.ts +13 -0
- package/dist/components/skeleton/SkeletonAvatar.svelte +97 -0
- package/dist/components/skeleton/SkeletonAvatar.svelte.d.ts +8 -0
- package/dist/components/skeleton/SkeletonBox.svelte +105 -0
- package/dist/components/skeleton/SkeletonBox.svelte.d.ts +12 -0
- package/dist/components/skeleton/SkeletonButton.svelte +71 -0
- package/dist/components/skeleton/SkeletonButton.svelte.d.ts +8 -0
- package/dist/components/skeleton/SkeletonHeading.svelte +49 -0
- package/dist/components/skeleton/SkeletonHeading.svelte.d.ts +8 -0
- package/dist/components/skeleton/SkeletonMedia.svelte +115 -0
- package/dist/components/skeleton/SkeletonMedia.svelte.d.ts +9 -0
- package/dist/components/skeleton/SkeletonText.svelte +75 -0
- package/dist/components/skeleton/SkeletonText.svelte.d.ts +8 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +43 -0
- package/dist/types/icon.d.ts +4 -0
- package/dist/types/icon.js +2 -0
- package/dist/types/menuItem.d.ts +8 -0
- package/dist/types/menuItem.js +1 -0
- package/dist/types/options.d.ts +6 -0
- package/dist/types/options.js +4 -0
- package/dist/types/skeleton.d.ts +77 -0
- package/dist/types/skeleton.js +19 -0
- package/dist/utils/accessibility.d.ts +48 -0
- package/dist/utils/accessibility.js +87 -0
- package/dist/utils/formatText.d.ts +4 -0
- package/dist/utils/formatText.js +44 -0
- package/dist/utils/mobile.d.ts +9 -0
- package/dist/utils/mobile.js +47 -0
- package/dist/utils/snackbar.svelte.d.ts +51 -0
- package/dist/utils/snackbar.svelte.js +107 -0
- package/dist/utils/style.d.ts +17 -0
- package/dist/utils/style.js +22 -0
- package/package.json +102 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<!-- ConfirmDialog.svelte -->
|
|
2
|
+
|
|
3
|
+
<script lang="ts">
|
|
4
|
+
import Dialog from './Dialog.svelte';
|
|
5
|
+
import Button from './Button.svelte';
|
|
6
|
+
import { convertToHtml } from '../utils/formatText';
|
|
7
|
+
import type { SvelteComponent } from 'svelte';
|
|
8
|
+
|
|
9
|
+
// =========================================================================
|
|
10
|
+
// Props, States & Constants
|
|
11
|
+
// =========================================================================
|
|
12
|
+
let {
|
|
13
|
+
// 基本プロパティ
|
|
14
|
+
title = 'Confirm',
|
|
15
|
+
description = 'Are you sure?',
|
|
16
|
+
confirmLabel = 'Confirm',
|
|
17
|
+
cancelLabel = 'Cancel',
|
|
18
|
+
|
|
19
|
+
// HTML属性
|
|
20
|
+
id,
|
|
21
|
+
|
|
22
|
+
// スタイル/レイアウト
|
|
23
|
+
variant = 'info',
|
|
24
|
+
width = 400,
|
|
25
|
+
|
|
26
|
+
// 状態/動作
|
|
27
|
+
isOpen = $bindable(false),
|
|
28
|
+
closeIfClickOutside = true,
|
|
29
|
+
|
|
30
|
+
// イベントハンドラー
|
|
31
|
+
onConfirm = () => {}, // No params for type inference
|
|
32
|
+
onCancel = () => {} // No params for type inference
|
|
33
|
+
}: {
|
|
34
|
+
// 基本プロパティ
|
|
35
|
+
title?: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
confirmLabel?: string;
|
|
38
|
+
cancelLabel?: string;
|
|
39
|
+
|
|
40
|
+
// HTML属性
|
|
41
|
+
id?: string;
|
|
42
|
+
|
|
43
|
+
// スタイル/レイアウト
|
|
44
|
+
variant?: 'info' | 'warning' | 'danger';
|
|
45
|
+
width?: string | number;
|
|
46
|
+
|
|
47
|
+
// 状態/動作
|
|
48
|
+
isOpen?: boolean;
|
|
49
|
+
closeIfClickOutside?: boolean;
|
|
50
|
+
|
|
51
|
+
// イベントハンドラー
|
|
52
|
+
onConfirm?: () => void;
|
|
53
|
+
onCancel?: () => void;
|
|
54
|
+
} = $props();
|
|
55
|
+
|
|
56
|
+
let dialogRef: SvelteComponent | undefined = $state();
|
|
57
|
+
|
|
58
|
+
// =========================================================================
|
|
59
|
+
// Methods
|
|
60
|
+
// =========================================================================
|
|
61
|
+
const handleConfirm = (): void => {
|
|
62
|
+
onConfirm();
|
|
63
|
+
close();
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const handleCancel = (): void => {
|
|
67
|
+
onCancel();
|
|
68
|
+
close();
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const open = (): void => {
|
|
72
|
+
isOpen = true;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const close = (): void => {
|
|
76
|
+
isOpen = false;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const toggle = (): void => {
|
|
80
|
+
isOpen = !isOpen;
|
|
81
|
+
};
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<Dialog
|
|
85
|
+
bind:this={dialogRef}
|
|
86
|
+
bind:isOpen
|
|
87
|
+
{title}
|
|
88
|
+
{width}
|
|
89
|
+
{closeIfClickOutside}
|
|
90
|
+
id={id ? `${id}-dialog` : undefined}
|
|
91
|
+
>
|
|
92
|
+
<div class="confirm-dialog-message">
|
|
93
|
+
{@html convertToHtml(description)}
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
{#snippet footer()}
|
|
97
|
+
<Button variant="ghost" color="var(--svelte-ui-text-color)" onclick={handleCancel}>
|
|
98
|
+
{cancelLabel}
|
|
99
|
+
</Button>
|
|
100
|
+
<Button
|
|
101
|
+
variant="filled"
|
|
102
|
+
color={variant === 'danger'
|
|
103
|
+
? 'var(--svelte-ui-danger-color)'
|
|
104
|
+
: variant === 'warning'
|
|
105
|
+
? 'var(--svelte-ui-warning-color)'
|
|
106
|
+
: undefined}
|
|
107
|
+
onclick={handleConfirm}
|
|
108
|
+
>
|
|
109
|
+
{confirmLabel}
|
|
110
|
+
</Button>
|
|
111
|
+
{/snippet}
|
|
112
|
+
</Dialog>
|
|
113
|
+
|
|
114
|
+
<style>.confirm-dialog-message {
|
|
115
|
+
padding: 16px 0;
|
|
116
|
+
}</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
title?: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
confirmLabel?: string;
|
|
5
|
+
cancelLabel?: string;
|
|
6
|
+
id?: string;
|
|
7
|
+
variant?: 'info' | 'warning' | 'danger';
|
|
8
|
+
width?: string | number;
|
|
9
|
+
isOpen?: boolean;
|
|
10
|
+
closeIfClickOutside?: boolean;
|
|
11
|
+
onConfirm?: () => void;
|
|
12
|
+
onCancel?: () => void;
|
|
13
|
+
};
|
|
14
|
+
declare const ConfirmDialog: import("svelte").Component<$$ComponentProps, {
|
|
15
|
+
open: () => void;
|
|
16
|
+
close: () => void;
|
|
17
|
+
toggle: () => void;
|
|
18
|
+
}, "isOpen">;
|
|
19
|
+
type ConfirmDialog = ReturnType<typeof ConfirmDialog>;
|
|
20
|
+
export default ConfirmDialog;
|
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
<!-- Datepicker.svelte -->
|
|
2
|
+
|
|
3
|
+
<script lang="ts">
|
|
4
|
+
import { type SvelteComponent } from 'svelte';
|
|
5
|
+
import dayjs from 'dayjs';
|
|
6
|
+
import localeData from 'dayjs/plugin/localeData';
|
|
7
|
+
import 'dayjs/locale/ja';
|
|
8
|
+
import 'dayjs/locale/en';
|
|
9
|
+
import 'dayjs/locale/fr';
|
|
10
|
+
import 'dayjs/locale/de';
|
|
11
|
+
import 'dayjs/locale/es';
|
|
12
|
+
import 'dayjs/locale/zh-cn';
|
|
13
|
+
import Input from './Input.svelte';
|
|
14
|
+
import Popup from './Popup.svelte';
|
|
15
|
+
import DatepickerCalendar from './DatepickerCalendar.svelte';
|
|
16
|
+
import { announceToScreenReader } from '../utils/accessibility';
|
|
17
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
18
|
+
import type { IconVariant, IconWeight, IconGrade, IconOpticalSize } from '../types/icon';
|
|
19
|
+
|
|
20
|
+
dayjs.extend(localeData);
|
|
21
|
+
|
|
22
|
+
// =========================================================================
|
|
23
|
+
// Props, States & Constants
|
|
24
|
+
// =========================================================================
|
|
25
|
+
|
|
26
|
+
let {
|
|
27
|
+
// 基本プロパティ
|
|
28
|
+
value = $bindable(),
|
|
29
|
+
format,
|
|
30
|
+
nullString = '',
|
|
31
|
+
locale = 'en',
|
|
32
|
+
rangeSeparator = ' - ',
|
|
33
|
+
|
|
34
|
+
// HTML属性系
|
|
35
|
+
id = `datepicker-${Math.random().toString(36).substring(2, 15)}`,
|
|
36
|
+
inputAttributes,
|
|
37
|
+
|
|
38
|
+
// スタイル/レイアウト
|
|
39
|
+
variant = 'default',
|
|
40
|
+
focusStyle = 'outline',
|
|
41
|
+
fullWidth = false,
|
|
42
|
+
rounded = false,
|
|
43
|
+
|
|
44
|
+
// アイコン関連
|
|
45
|
+
hasIcon = false,
|
|
46
|
+
iconFilled = false,
|
|
47
|
+
iconWeight = 300,
|
|
48
|
+
iconGrade = 0,
|
|
49
|
+
iconOpticalSize = 24,
|
|
50
|
+
iconVariant = 'outlined',
|
|
51
|
+
|
|
52
|
+
// 状態/動作
|
|
53
|
+
disabled = false,
|
|
54
|
+
mode = 'single',
|
|
55
|
+
allowDirectInput = false,
|
|
56
|
+
openIfClicked = true,
|
|
57
|
+
minDate,
|
|
58
|
+
maxDate,
|
|
59
|
+
|
|
60
|
+
// 入力イベント
|
|
61
|
+
onchange = () => {}, // No params for type inference
|
|
62
|
+
oninput = () => {}, // No params for type inference
|
|
63
|
+
|
|
64
|
+
// フォーカスイベント
|
|
65
|
+
onfocus = () => {}, // No params for type inference
|
|
66
|
+
onblur = () => {}, // No params for type inference
|
|
67
|
+
|
|
68
|
+
// キーボードイベント
|
|
69
|
+
onkeydown = () => {}, // No params for type inference
|
|
70
|
+
onkeyup = () => {}, // No params for type inference
|
|
71
|
+
|
|
72
|
+
// マウスイベント
|
|
73
|
+
onclick = () => {}, // No params for type inference
|
|
74
|
+
onmousedown = () => {}, // No params for type inference
|
|
75
|
+
onmouseup = () => {}, // No params for type inference
|
|
76
|
+
onmouseenter = () => {}, // No params for type inference
|
|
77
|
+
onmouseleave = () => {}, // No params for type inference
|
|
78
|
+
onmouseover = () => {}, // No params for type inference
|
|
79
|
+
onmouseout = () => {}, // No params for type inference
|
|
80
|
+
oncontextmenu = () => {}, // No params for type inference
|
|
81
|
+
onauxclick = () => {}, // No params for type inference
|
|
82
|
+
|
|
83
|
+
// タッチイベント
|
|
84
|
+
ontouchstart = () => {}, // No params for type inference
|
|
85
|
+
ontouchend = () => {}, // No params for type inference
|
|
86
|
+
ontouchmove = () => {}, // No params for type inference
|
|
87
|
+
ontouchcancel = () => {}, // No params for type inference
|
|
88
|
+
|
|
89
|
+
// ポインターイベント
|
|
90
|
+
onpointerdown = () => {}, // No params for type inference
|
|
91
|
+
onpointerup = () => {}, // No params for type inference
|
|
92
|
+
onpointerenter = () => {}, // No params for type inference
|
|
93
|
+
onpointerleave = () => {}, // No params for type inference
|
|
94
|
+
onpointermove = () => {}, // No params for type inference
|
|
95
|
+
onpointercancel = () => {}, // No params for type inference
|
|
96
|
+
|
|
97
|
+
// その他
|
|
98
|
+
...restProps
|
|
99
|
+
}: {
|
|
100
|
+
// 基本プロパティ
|
|
101
|
+
value: Date | { start: Date; end: Date } | undefined;
|
|
102
|
+
format?: string;
|
|
103
|
+
nullString?: string;
|
|
104
|
+
locale?: 'en' | 'ja' | 'fr' | 'de' | 'es' | 'zh-cn';
|
|
105
|
+
rangeSeparator?: string;
|
|
106
|
+
|
|
107
|
+
// HTML属性系
|
|
108
|
+
id?: string;
|
|
109
|
+
inputAttributes?: HTMLInputAttributes | undefined;
|
|
110
|
+
|
|
111
|
+
// スタイル/レイアウト
|
|
112
|
+
variant?: 'default' | 'inline';
|
|
113
|
+
focusStyle?: 'background' | 'outline' | 'none';
|
|
114
|
+
fullWidth?: boolean;
|
|
115
|
+
rounded?: boolean;
|
|
116
|
+
|
|
117
|
+
// アイコン関連
|
|
118
|
+
hasIcon?: boolean;
|
|
119
|
+
iconFilled?: boolean;
|
|
120
|
+
iconWeight?: IconWeight;
|
|
121
|
+
iconGrade?: IconGrade;
|
|
122
|
+
iconOpticalSize?: IconOpticalSize;
|
|
123
|
+
iconVariant?: IconVariant;
|
|
124
|
+
|
|
125
|
+
// 状態/動作
|
|
126
|
+
disabled?: boolean;
|
|
127
|
+
mode?: 'single' | 'range';
|
|
128
|
+
allowDirectInput?: boolean;
|
|
129
|
+
openIfClicked?: boolean;
|
|
130
|
+
minDate?: Date;
|
|
131
|
+
maxDate?: Date;
|
|
132
|
+
|
|
133
|
+
// 入力イベント
|
|
134
|
+
onchange?: (value: Date | { start: Date; end: Date } | undefined) => void;
|
|
135
|
+
oninput?: (value: string) => void;
|
|
136
|
+
|
|
137
|
+
// フォーカスイベント
|
|
138
|
+
onfocus?: Function; // No params for type inference
|
|
139
|
+
onblur?: Function; // No params for type inference
|
|
140
|
+
onkeydown?: Function; // No params for type inference
|
|
141
|
+
onkeyup?: Function; // No params for type inference
|
|
142
|
+
onclick?: Function; // No params for type inference
|
|
143
|
+
onmousedown?: Function; // No params for type inference
|
|
144
|
+
onmouseup?: Function; // No params for type inference
|
|
145
|
+
onmouseenter?: Function; // No params for type inference
|
|
146
|
+
onmouseleave?: Function; // No params for type inference
|
|
147
|
+
onmouseover?: Function; // No params for type inference
|
|
148
|
+
onmouseout?: Function; // No params for type inference
|
|
149
|
+
oncontextmenu?: Function; // No params for type inference
|
|
150
|
+
onauxclick?: Function; // No params for type inference
|
|
151
|
+
ontouchstart?: Function; // No params for type inference
|
|
152
|
+
ontouchend?: Function; // No params for type inference
|
|
153
|
+
ontouchmove?: Function; // No params for type inference
|
|
154
|
+
ontouchcancel?: Function; // No params for type inference
|
|
155
|
+
onpointerdown?: Function; // No params for type inference
|
|
156
|
+
onpointerup?: Function; // No params for type inference
|
|
157
|
+
onpointerenter?: Function; // No params for type inference
|
|
158
|
+
onpointerleave?: Function; // No params for type inference
|
|
159
|
+
onpointermove?: Function; // No params for type inference
|
|
160
|
+
onpointercancel?: Function; // No params for type inference
|
|
161
|
+
|
|
162
|
+
// その他
|
|
163
|
+
[key: string]: any;
|
|
164
|
+
} = $props();
|
|
165
|
+
|
|
166
|
+
// =========================================================================
|
|
167
|
+
// Props, States & Constants
|
|
168
|
+
// =========================================================================
|
|
169
|
+
let inputRef: any = $state();
|
|
170
|
+
let containerElement: HTMLDivElement | undefined = $state();
|
|
171
|
+
let popupRef: SvelteComponent | undefined = $state();
|
|
172
|
+
let datapickerCalendarRef: SvelteComponent | undefined = $state();
|
|
173
|
+
let openedViaKeyboard: boolean = $state(false);
|
|
174
|
+
let displayValue = $state('');
|
|
175
|
+
|
|
176
|
+
const calendarId = `${id}-calendar`;
|
|
177
|
+
|
|
178
|
+
// =========================================================================
|
|
179
|
+
|
|
180
|
+
const localeConfig = {
|
|
181
|
+
en: {
|
|
182
|
+
defaultFormat: 'MM/DD/YYYY (ddd)',
|
|
183
|
+
rangeFormat: 'MM/DD/YYYY',
|
|
184
|
+
selectDateLabel: 'Select a date. Current value:',
|
|
185
|
+
notSelected: 'Not selected',
|
|
186
|
+
directInputPlaceholder: 'Enter date'
|
|
187
|
+
},
|
|
188
|
+
ja: {
|
|
189
|
+
defaultFormat: 'YYYY/M/D(ddd)',
|
|
190
|
+
rangeFormat: 'YYYY/M/D',
|
|
191
|
+
selectDateLabel: '日付を選択してください。現在の値:',
|
|
192
|
+
notSelected: '未選択',
|
|
193
|
+
directInputPlaceholder: '日付を入力してください'
|
|
194
|
+
},
|
|
195
|
+
fr: {
|
|
196
|
+
defaultFormat: 'DD/MM/YYYY (ddd)',
|
|
197
|
+
rangeFormat: 'DD/MM/YYYY',
|
|
198
|
+
selectDateLabel: 'Sélectionnez une date. Valeur actuelle :',
|
|
199
|
+
notSelected: 'Non sélectionné',
|
|
200
|
+
directInputPlaceholder: 'Saisir la date'
|
|
201
|
+
},
|
|
202
|
+
de: {
|
|
203
|
+
defaultFormat: 'DD.MM.YYYY (ddd)',
|
|
204
|
+
rangeFormat: 'DD.MM.YYYY',
|
|
205
|
+
selectDateLabel: 'Wählen Sie ein Datum. Aktueller Wert:',
|
|
206
|
+
notSelected: 'Nicht ausgewählt',
|
|
207
|
+
directInputPlaceholder: 'Datum eingeben'
|
|
208
|
+
},
|
|
209
|
+
es: {
|
|
210
|
+
defaultFormat: 'DD/MM/YYYY (ddd)',
|
|
211
|
+
rangeFormat: 'DD/MM/YYYY',
|
|
212
|
+
selectDateLabel: 'Seleccione una fecha. Valor actual:',
|
|
213
|
+
notSelected: 'No seleccionado',
|
|
214
|
+
directInputPlaceholder: 'Introducir fecha'
|
|
215
|
+
},
|
|
216
|
+
'zh-cn': {
|
|
217
|
+
defaultFormat: 'YYYY/M/D(ddd)',
|
|
218
|
+
rangeFormat: 'YYYY/M/D',
|
|
219
|
+
selectDateLabel: '请选择日期。当前值:',
|
|
220
|
+
notSelected: '未选择',
|
|
221
|
+
directInputPlaceholder: '请输入日期'
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// =========================================================================
|
|
226
|
+
// Effects
|
|
227
|
+
// =========================================================================
|
|
228
|
+
$effect(() => {
|
|
229
|
+
dayjs.locale(locale);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
$effect(() => {
|
|
233
|
+
const formatWithLocale = (date: Date) => dayjs(date).locale(locale).format(finalFormat);
|
|
234
|
+
|
|
235
|
+
if (mode === 'range' && value && 'start' in value && 'end' in value) {
|
|
236
|
+
displayValue = `${formatWithLocale(value.start)}${rangeSeparator}${formatWithLocale(value.end)}`;
|
|
237
|
+
} else if (mode === 'single' && value && value instanceof Date) {
|
|
238
|
+
displayValue = formatWithLocale(value);
|
|
239
|
+
} else {
|
|
240
|
+
displayValue = '';
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// =========================================================================
|
|
245
|
+
// Methods
|
|
246
|
+
// =========================================================================
|
|
247
|
+
const handleChange = () => {
|
|
248
|
+
// スクリーンリーダーアナウンス
|
|
249
|
+
if (value) {
|
|
250
|
+
if (mode === 'range' && typeof value === 'object' && 'start' in value && 'end' in value) {
|
|
251
|
+
const startDate = dayjs(value.start).format(finalFormat);
|
|
252
|
+
const endDate = dayjs(value.end).format(finalFormat);
|
|
253
|
+
announceToScreenReader(`Date range selected: ${startDate} to ${endDate}`);
|
|
254
|
+
} else if (value instanceof Date) {
|
|
255
|
+
const formattedDate = dayjs(value).format(finalFormat);
|
|
256
|
+
announceToScreenReader(`Date selected: ${formattedDate}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
onchange(value);
|
|
261
|
+
|
|
262
|
+
// 単一日付選択時、または範囲選択時の終了日選択時にポップアップを閉じる
|
|
263
|
+
if (
|
|
264
|
+
mode === 'single' ||
|
|
265
|
+
(mode === 'range' &&
|
|
266
|
+
value &&
|
|
267
|
+
typeof value === 'object' &&
|
|
268
|
+
'start' in value &&
|
|
269
|
+
'end' in value &&
|
|
270
|
+
value.end)
|
|
271
|
+
) {
|
|
272
|
+
popupRef?.close();
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const handleClick = (event: MouseEvent) => {
|
|
277
|
+
if (disabled) return;
|
|
278
|
+
if (openIfClicked) {
|
|
279
|
+
openedViaKeyboard = false;
|
|
280
|
+
open();
|
|
281
|
+
}
|
|
282
|
+
onclick?.(event);
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
286
|
+
if (disabled) return;
|
|
287
|
+
onkeydown(event);
|
|
288
|
+
|
|
289
|
+
switch (event.key) {
|
|
290
|
+
case 'Enter':
|
|
291
|
+
case ' ':
|
|
292
|
+
// 直接入力が許可されている場合はEnterキーで入力を確定
|
|
293
|
+
if (allowDirectInput && event.key === 'Enter') {
|
|
294
|
+
return; // Inputコンポーネントの処理に任せる
|
|
295
|
+
}
|
|
296
|
+
event?.preventDefault?.();
|
|
297
|
+
openedViaKeyboard = true;
|
|
298
|
+
open();
|
|
299
|
+
break;
|
|
300
|
+
case 'ArrowDown':
|
|
301
|
+
// ポップアップが既に開いている場合は何もしない(DatepickerCalendarのキーボード処理に任せる)
|
|
302
|
+
if (popupRef?.getIsOpen && popupRef.getIsOpen()) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
event.preventDefault();
|
|
306
|
+
openedViaKeyboard = true;
|
|
307
|
+
open();
|
|
308
|
+
break;
|
|
309
|
+
case 'Escape':
|
|
310
|
+
event.preventDefault();
|
|
311
|
+
close();
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const handleKeyup = (event: KeyboardEvent) => {
|
|
317
|
+
if (disabled) return;
|
|
318
|
+
onkeyup(event);
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const handleInput = (event: Event) => {
|
|
322
|
+
if (disabled) return;
|
|
323
|
+
const target = event.target as HTMLInputElement;
|
|
324
|
+
oninput?.(target.value);
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
// マウスイベント
|
|
328
|
+
const handleMouseDown = (event: MouseEvent) => {
|
|
329
|
+
if (disabled) return;
|
|
330
|
+
onmousedown?.(event);
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
const handleMouseUp = (event: MouseEvent) => {
|
|
334
|
+
if (disabled) return;
|
|
335
|
+
onmouseup?.(event);
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
const handleMouseEnter = (event: MouseEvent) => {
|
|
339
|
+
if (disabled) return;
|
|
340
|
+
onmouseenter?.(event);
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
const handleMouseLeave = (event: MouseEvent) => {
|
|
344
|
+
if (disabled) return;
|
|
345
|
+
onmouseleave?.(event);
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
const handleMouseOver = (event: MouseEvent) => {
|
|
349
|
+
if (disabled) return;
|
|
350
|
+
onmouseover?.(event);
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
const handleMouseOut = (event: MouseEvent) => {
|
|
354
|
+
if (disabled) return;
|
|
355
|
+
onmouseout?.(event);
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const handleContextMenu = (event: MouseEvent) => {
|
|
359
|
+
if (disabled) return;
|
|
360
|
+
oncontextmenu?.(event);
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
const handleAuxClick = (event: MouseEvent) => {
|
|
364
|
+
if (disabled) return;
|
|
365
|
+
onauxclick?.(event);
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
// タッチイベント
|
|
369
|
+
const handleTouchStart = (event: TouchEvent) => {
|
|
370
|
+
if (disabled) return;
|
|
371
|
+
ontouchstart?.(event);
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
const handleTouchEnd = (event: TouchEvent) => {
|
|
375
|
+
if (disabled) return;
|
|
376
|
+
ontouchend?.(event);
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const handleTouchMove = (event: TouchEvent) => {
|
|
380
|
+
if (disabled) return;
|
|
381
|
+
ontouchmove?.(event);
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
const handleTouchCancel = (event: TouchEvent) => {
|
|
385
|
+
if (disabled) return;
|
|
386
|
+
ontouchcancel?.(event);
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
// ポインターイベント
|
|
390
|
+
const handlePointerDown = (event: PointerEvent) => {
|
|
391
|
+
if (disabled) return;
|
|
392
|
+
onpointerdown?.(event);
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
const handlePointerUp = (event: PointerEvent) => {
|
|
396
|
+
if (disabled) return;
|
|
397
|
+
onpointerup?.(event);
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
const handlePointerEnter = (event: PointerEvent) => {
|
|
401
|
+
if (disabled) return;
|
|
402
|
+
onpointerenter?.(event);
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
const handlePointerLeave = (event: PointerEvent) => {
|
|
406
|
+
if (disabled) return;
|
|
407
|
+
onpointerleave?.(event);
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
const handlePointerMove = (event: PointerEvent) => {
|
|
411
|
+
if (disabled) return;
|
|
412
|
+
onpointermove?.(event);
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
const handlePointerCancel = (event: PointerEvent) => {
|
|
416
|
+
if (disabled) return;
|
|
417
|
+
onpointercancel?.(event);
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
const handlePopupOpen = () => {
|
|
421
|
+
// DatepickerCalendarのイベントハンドラーを有効にする
|
|
422
|
+
datapickerCalendarRef?.handlePopupOpen();
|
|
423
|
+
// キーボードで開いた場合は、最初のキーボード操作時にフォーカス表示が有効になる
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
const handlePopupClose = () => {
|
|
427
|
+
// DatepickerCalendarのイベントハンドラーを無効にする
|
|
428
|
+
datapickerCalendarRef?.handlePopupClose();
|
|
429
|
+
// 状態をリセット
|
|
430
|
+
openedViaKeyboard = false;
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
const handleFocus = (event: FocusEvent) => {
|
|
434
|
+
if (disabled) return;
|
|
435
|
+
// キーボードでのフォーカス時のみPopupを開く
|
|
436
|
+
// クリック時は handleClick で処理
|
|
437
|
+
onfocus(event);
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
const handleBlur = (event: FocusEvent) => {
|
|
441
|
+
if (disabled) return;
|
|
442
|
+
// Popupの外側クリック機能に依存するため、ここでは自動クローズしない
|
|
443
|
+
// フォーカスイベントのみをハンドルする
|
|
444
|
+
onblur(event);
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
const handleInputChange = (inputValue: string | number | undefined) => {
|
|
448
|
+
if (disabled) return;
|
|
449
|
+
if (!allowDirectInput) return;
|
|
450
|
+
|
|
451
|
+
const inputStr = String(inputValue || '');
|
|
452
|
+
if (!inputStr) {
|
|
453
|
+
value = undefined;
|
|
454
|
+
onchange(value);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// 日付の解析を試行
|
|
459
|
+
const parsedDate = dayjs(inputStr, finalFormat, locale, true);
|
|
460
|
+
if (parsedDate.isValid()) {
|
|
461
|
+
value = parsedDate.toDate();
|
|
462
|
+
onchange(value);
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
export const open = () => {
|
|
467
|
+
datapickerCalendarRef?.reset();
|
|
468
|
+
popupRef?.open();
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
export const close = () => {
|
|
472
|
+
popupRef?.close();
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
export const toggle = () => {
|
|
476
|
+
datapickerCalendarRef?.reset();
|
|
477
|
+
popupRef?.toggle();
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
// =========================================================================
|
|
481
|
+
// $derived
|
|
482
|
+
// =========================================================================
|
|
483
|
+
|
|
484
|
+
const currentLocaleConfig = $derived(localeConfig[locale]);
|
|
485
|
+
const finalFormat = $derived(
|
|
486
|
+
format ||
|
|
487
|
+
(mode === 'range' ? currentLocaleConfig.rangeFormat : currentLocaleConfig.defaultFormat)
|
|
488
|
+
);
|
|
489
|
+
const placeholderText = $derived(
|
|
490
|
+
allowDirectInput
|
|
491
|
+
? nullString || currentLocaleConfig.directInputPlaceholder
|
|
492
|
+
: nullString || currentLocaleConfig.notSelected
|
|
493
|
+
);
|
|
494
|
+
</script>
|
|
495
|
+
|
|
496
|
+
<div
|
|
497
|
+
bind:this={containerElement}
|
|
498
|
+
class="datepicker"
|
|
499
|
+
class:datepicker--full-width={fullWidth}
|
|
500
|
+
data-testid="datepicker"
|
|
501
|
+
>
|
|
502
|
+
<Input
|
|
503
|
+
bind:this={inputRef}
|
|
504
|
+
value={displayValue}
|
|
505
|
+
{variant}
|
|
506
|
+
{focusStyle}
|
|
507
|
+
{fullWidth}
|
|
508
|
+
{rounded}
|
|
509
|
+
{disabled}
|
|
510
|
+
readonly={!allowDirectInput}
|
|
511
|
+
placeholder={placeholderText}
|
|
512
|
+
rightIcon={hasIcon ? (mode === 'range' ? 'date_range' : 'calendar_today') : undefined}
|
|
513
|
+
{iconFilled}
|
|
514
|
+
{iconWeight}
|
|
515
|
+
{iconGrade}
|
|
516
|
+
{iconOpticalSize}
|
|
517
|
+
{iconVariant}
|
|
518
|
+
onRightIconClick={handleClick}
|
|
519
|
+
onclick={handleClick}
|
|
520
|
+
onfocus={handleFocus}
|
|
521
|
+
onblur={handleBlur}
|
|
522
|
+
onchange={handleInputChange}
|
|
523
|
+
oninput={handleInput}
|
|
524
|
+
onkeydown={handleKeyDown}
|
|
525
|
+
onkeyup={handleKeyup}
|
|
526
|
+
onmousedown={handleMouseDown}
|
|
527
|
+
onmouseup={handleMouseUp}
|
|
528
|
+
onmouseenter={handleMouseEnter}
|
|
529
|
+
onmouseleave={handleMouseLeave}
|
|
530
|
+
onmouseover={handleMouseOver}
|
|
531
|
+
onmouseout={handleMouseOut}
|
|
532
|
+
oncontextmenu={handleContextMenu}
|
|
533
|
+
onauxclick={handleAuxClick}
|
|
534
|
+
ontouchstart={handleTouchStart}
|
|
535
|
+
ontouchend={handleTouchEnd}
|
|
536
|
+
ontouchmove={handleTouchMove}
|
|
537
|
+
ontouchcancel={handleTouchCancel}
|
|
538
|
+
onpointerdown={handlePointerDown}
|
|
539
|
+
onpointerup={handlePointerUp}
|
|
540
|
+
onpointerenter={handlePointerEnter}
|
|
541
|
+
onpointerleave={handlePointerLeave}
|
|
542
|
+
onpointermove={handlePointerMove}
|
|
543
|
+
onpointercancel={handlePointerCancel}
|
|
544
|
+
{id}
|
|
545
|
+
{inputAttributes}
|
|
546
|
+
{...restProps}
|
|
547
|
+
/>
|
|
548
|
+
</div>
|
|
549
|
+
<Popup
|
|
550
|
+
bind:this={popupRef}
|
|
551
|
+
anchorElement={containerElement}
|
|
552
|
+
position="bottom"
|
|
553
|
+
margin={4}
|
|
554
|
+
onOpen={handlePopupOpen}
|
|
555
|
+
onClose={handlePopupClose}
|
|
556
|
+
id={id ? `${id}-popup` : undefined}
|
|
557
|
+
>
|
|
558
|
+
<DatepickerCalendar
|
|
559
|
+
bind:this={datapickerCalendarRef}
|
|
560
|
+
bind:value
|
|
561
|
+
{mode}
|
|
562
|
+
onchange={handleChange}
|
|
563
|
+
{minDate}
|
|
564
|
+
{maxDate}
|
|
565
|
+
{locale}
|
|
566
|
+
id={calendarId}
|
|
567
|
+
/>
|
|
568
|
+
</Popup>
|
|
569
|
+
|
|
570
|
+
<style>.datepicker {
|
|
571
|
+
position: relative;
|
|
572
|
+
display: inline-block;
|
|
573
|
+
width: auto;
|
|
574
|
+
}
|
|
575
|
+
.datepicker.datepicker--full-width {
|
|
576
|
+
display: block;
|
|
577
|
+
width: 100%;
|
|
578
|
+
}</style>
|