@likable-hair/svelte 3.0.68 → 3.0.69
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/dist/components/composed/forms/YearPicketTextfield.svelte +228 -0
- package/dist/components/composed/forms/YearPicketTextfield.svelte.d.ts +58 -0
- package/dist/components/simple/common/Menu.svelte +30 -10
- package/dist/components/simple/dates/DatePicker.svelte +1 -1
- package/dist/components/simple/dates/YearSelector.css +1 -0
- package/dist/components/simple/dates/YearSelector.svelte +6 -0
- package/dist/components/simple/lists/SelectableVerticalList.svelte +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
<script>import IMask, { InputMask } from "imask";
|
|
2
|
+
import SimpleTextField from "../../simple/forms/SimpleTextField.svelte";
|
|
3
|
+
import DatePicker from "../../simple/dates/DatePicker.svelte";
|
|
4
|
+
import Menu from "../../simple/common/Menu.svelte";
|
|
5
|
+
import Icon from "../../simple/media/Icon.svelte";
|
|
6
|
+
import { onMount } from "svelte";
|
|
7
|
+
import { DateTime } from "luxon";
|
|
8
|
+
import { createEventDispatcher } from "svelte";
|
|
9
|
+
import MediaQuery from "../../simple/common/MediaQuery.svelte";
|
|
10
|
+
import Dialog from "../../simple/dialogs/Dialog.svelte";
|
|
11
|
+
let clazz = {};
|
|
12
|
+
export { clazz as class };
|
|
13
|
+
let dispatch = createEventDispatcher();
|
|
14
|
+
export let menuOpened = false, openingId = "date-picker-text-field", pattern = "dd/MM/yyyy", selectedMonth = void 0, selectedYear = void 0, visibleMonth = void 0, visibleYear = void 0, selectedDate = void 0, placeholder = void 0, mobileDialog = true, maxYearInRange = 2100, minYearInRange = 1970;
|
|
15
|
+
let activator, refreshPosition = false, menuElement, inputElement, mask = {
|
|
16
|
+
value: void 0
|
|
17
|
+
}, maskFactoryArgs = {
|
|
18
|
+
mask: Date,
|
|
19
|
+
pattern,
|
|
20
|
+
format: function(date) {
|
|
21
|
+
return DateTime.fromJSDate(date).toFormat(pattern);
|
|
22
|
+
},
|
|
23
|
+
parse: function(str) {
|
|
24
|
+
return DateTime.fromFormat(str, pattern).toJSDate();
|
|
25
|
+
},
|
|
26
|
+
blocks: {
|
|
27
|
+
yyyy: {
|
|
28
|
+
mask: IMask.MaskedRange,
|
|
29
|
+
from: minYearInRange,
|
|
30
|
+
to: maxYearInRange
|
|
31
|
+
},
|
|
32
|
+
MM: {
|
|
33
|
+
mask: IMask.MaskedRange,
|
|
34
|
+
from: 1,
|
|
35
|
+
to: 12
|
|
36
|
+
},
|
|
37
|
+
dd: {
|
|
38
|
+
mask: IMask.MaskedRange,
|
|
39
|
+
from: 1,
|
|
40
|
+
to: 31
|
|
41
|
+
},
|
|
42
|
+
HH: {
|
|
43
|
+
mask: IMask.MaskedRange,
|
|
44
|
+
from: 0,
|
|
45
|
+
to: 23
|
|
46
|
+
},
|
|
47
|
+
mm: {
|
|
48
|
+
mask: IMask.MaskedRange,
|
|
49
|
+
from: 0,
|
|
50
|
+
to: 59
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
function handleTextFieldFocus(mobile) {
|
|
55
|
+
if (!mobile || !mobileDialog) {
|
|
56
|
+
menuOpened = true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
onMount(() => {
|
|
60
|
+
mask = IMask(
|
|
61
|
+
inputElement,
|
|
62
|
+
maskFactoryArgs
|
|
63
|
+
);
|
|
64
|
+
if (!!selectedDate) {
|
|
65
|
+
mask.value = DateTime.fromJSDate(selectedDate).toFormat(pattern);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
function handleInputChange(event) {
|
|
69
|
+
setTimeout(() => {
|
|
70
|
+
const typedValue = mask.value;
|
|
71
|
+
if (typedValue !== void 0 && typedValue !== null) {
|
|
72
|
+
const dayOfMonthIndex = pattern.indexOf("dd");
|
|
73
|
+
const dayOfMonth = typedValue.substring(dayOfMonthIndex, dayOfMonthIndex + 2);
|
|
74
|
+
const monthIndex = pattern.indexOf("MM");
|
|
75
|
+
const oneBasedMonth = typedValue.substring(monthIndex, monthIndex + 2);
|
|
76
|
+
if (oneBasedMonth.length == 2) {
|
|
77
|
+
selectedMonth = Number(oneBasedMonth) - 1;
|
|
78
|
+
visibleMonth = selectedMonth;
|
|
79
|
+
}
|
|
80
|
+
const yearIndex = pattern.indexOf("yyyy");
|
|
81
|
+
const year = typedValue.substring(yearIndex, yearIndex + 4);
|
|
82
|
+
if (year.length == 4) {
|
|
83
|
+
selectedYear = Number(year);
|
|
84
|
+
visibleYear = selectedYear;
|
|
85
|
+
}
|
|
86
|
+
if (typedValue.length == pattern.length) {
|
|
87
|
+
selectedDate = DateTime.fromObject({
|
|
88
|
+
day: Number(dayOfMonth),
|
|
89
|
+
month: Number(oneBasedMonth),
|
|
90
|
+
year: Number(year)
|
|
91
|
+
}).toJSDate();
|
|
92
|
+
} else {
|
|
93
|
+
selectedDate = void 0;
|
|
94
|
+
}
|
|
95
|
+
dispatch("input", {
|
|
96
|
+
datetime: selectedDate
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}, 30);
|
|
100
|
+
}
|
|
101
|
+
function handleDateSelect(ev) {
|
|
102
|
+
if (!!selectedDate) {
|
|
103
|
+
mask.value = DateTime.fromJSDate(selectedDate).toFormat(pattern);
|
|
104
|
+
}
|
|
105
|
+
dispatch("day-click", {
|
|
106
|
+
dateStat: ev.detail.dateStat
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function handleYearSelect() {
|
|
110
|
+
mask.value = "";
|
|
111
|
+
}
|
|
112
|
+
function handleMonthSelect() {
|
|
113
|
+
mask.value = "";
|
|
114
|
+
}
|
|
115
|
+
$:
|
|
116
|
+
if (!!selectedDate) {
|
|
117
|
+
setTimeout(() => {
|
|
118
|
+
if (!!selectedDate) {
|
|
119
|
+
mask.value = DateTime.fromJSDate(selectedDate).toFormat(pattern);
|
|
120
|
+
}
|
|
121
|
+
}, 30);
|
|
122
|
+
}
|
|
123
|
+
</script>
|
|
124
|
+
|
|
125
|
+
<MediaQuery let:mAndDown>
|
|
126
|
+
<div
|
|
127
|
+
bind:this={activator}
|
|
128
|
+
class="year-picker-activator {clazz.activator || ''}"
|
|
129
|
+
>
|
|
130
|
+
<slot
|
|
131
|
+
name="activator"
|
|
132
|
+
{mask}
|
|
133
|
+
{handleTextFieldFocus}
|
|
134
|
+
{handleInputChange}
|
|
135
|
+
{inputElement}
|
|
136
|
+
{placeholder}
|
|
137
|
+
>
|
|
138
|
+
<SimpleTextField
|
|
139
|
+
bind:value={mask.value}
|
|
140
|
+
on:focus={() => handleTextFieldFocus(mAndDown)}
|
|
141
|
+
on:keydown={handleInputChange}
|
|
142
|
+
bind:input={inputElement}
|
|
143
|
+
bind:placeholder
|
|
144
|
+
class={clazz.textfield}
|
|
145
|
+
>
|
|
146
|
+
<svelte:fragment slot="prepend-inner" let:prependInnerIcon let:iconSize>
|
|
147
|
+
<slot name="prepend-inner" {prependInnerIcon} {iconSize}>
|
|
148
|
+
<Icon
|
|
149
|
+
name="mdi-calendar"
|
|
150
|
+
click
|
|
151
|
+
on:click={() => menuOpened = !menuOpened}
|
|
152
|
+
></Icon>
|
|
153
|
+
</slot>
|
|
154
|
+
</svelte:fragment>
|
|
155
|
+
<svelte:fragment slot="append-inner" let:appendInnerIcon let:iconSize>
|
|
156
|
+
<slot name="append-inner" {appendInnerIcon} {iconSize}>
|
|
157
|
+
</slot>
|
|
158
|
+
</svelte:fragment>
|
|
159
|
+
<svelte:fragment slot="prepend" let:prependIcon let:iconSize>
|
|
160
|
+
<slot name="append-inner" {prependIcon} {iconSize}>
|
|
161
|
+
</slot>
|
|
162
|
+
</svelte:fragment>
|
|
163
|
+
<svelte:fragment slot="append" let:appendIcon let:iconSize>
|
|
164
|
+
<slot name="append-inner" {appendIcon} {iconSize}>
|
|
165
|
+
</slot>
|
|
166
|
+
</svelte:fragment>
|
|
167
|
+
</SimpleTextField>
|
|
168
|
+
</slot>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
{#if mAndDown && mobileDialog}
|
|
172
|
+
<Dialog
|
|
173
|
+
bind:open={menuOpened}
|
|
174
|
+
>
|
|
175
|
+
<div
|
|
176
|
+
style:background-color="rgb(var(--global-color-background-100))"
|
|
177
|
+
style:width="300px"
|
|
178
|
+
style:border-radius="10px"
|
|
179
|
+
>
|
|
180
|
+
<DatePicker
|
|
181
|
+
bind:selectedDate={selectedDate}
|
|
182
|
+
bind:selectedMonth={selectedMonth}
|
|
183
|
+
bind:selectedYear={selectedYear}
|
|
184
|
+
bind:visibleMonth
|
|
185
|
+
bind:visibleYear
|
|
186
|
+
on:day-click={handleDateSelect}
|
|
187
|
+
on:year-click={handleYearSelect}
|
|
188
|
+
on:month-click={handleMonthSelect}
|
|
189
|
+
></DatePicker>
|
|
190
|
+
</div>
|
|
191
|
+
</Dialog>
|
|
192
|
+
{:else}
|
|
193
|
+
<Menu
|
|
194
|
+
{activator}
|
|
195
|
+
_width={"300px"}
|
|
196
|
+
_boxShadow={"rgb(var(--global-color-background-300), .5) 0px 2px 4px"}
|
|
197
|
+
_borderRadius={"5px"}
|
|
198
|
+
bind:open={menuOpened}
|
|
199
|
+
anchor="bottom-center"
|
|
200
|
+
closeOnClickOutside
|
|
201
|
+
bind:refreshPosition
|
|
202
|
+
bind:menuElement
|
|
203
|
+
bind:openingId={openingId}
|
|
204
|
+
>
|
|
205
|
+
<div
|
|
206
|
+
style:background-color="rgb(var(--global-color-background-100))"
|
|
207
|
+
>
|
|
208
|
+
<DatePicker
|
|
209
|
+
bind:selectedDate={selectedDate}
|
|
210
|
+
bind:selectedMonth={selectedMonth}
|
|
211
|
+
bind:selectedYear={selectedYear}
|
|
212
|
+
bind:visibleMonth
|
|
213
|
+
bind:visibleYear
|
|
214
|
+
on:day-click={handleDateSelect}
|
|
215
|
+
on:year-click={handleYearSelect}
|
|
216
|
+
on:month-click={handleMonthSelect}
|
|
217
|
+
></DatePicker>
|
|
218
|
+
</div>
|
|
219
|
+
</Menu>
|
|
220
|
+
{/if}
|
|
221
|
+
</MediaQuery>
|
|
222
|
+
|
|
223
|
+
<style>
|
|
224
|
+
.year-picker-activator {
|
|
225
|
+
width: fit-content;
|
|
226
|
+
}
|
|
227
|
+
</style>
|
|
228
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import SimpleTextField from "../../simple/forms/SimpleTextField.svelte";
|
|
3
|
+
import { type ComponentProps } from 'svelte';
|
|
4
|
+
declare const __propDef: {
|
|
5
|
+
props: {
|
|
6
|
+
class?: {
|
|
7
|
+
activator?: string | undefined;
|
|
8
|
+
textfield?: ComponentProps<SimpleTextField>['class'];
|
|
9
|
+
} | undefined;
|
|
10
|
+
menuOpened?: boolean | undefined;
|
|
11
|
+
openingId?: string | undefined;
|
|
12
|
+
pattern?: string | undefined;
|
|
13
|
+
selectedMonth?: number | undefined;
|
|
14
|
+
selectedYear?: number | undefined;
|
|
15
|
+
visibleMonth?: number | undefined;
|
|
16
|
+
visibleYear?: number | undefined;
|
|
17
|
+
selectedDate?: Date | undefined;
|
|
18
|
+
placeholder?: string | undefined;
|
|
19
|
+
mobileDialog?: boolean | undefined;
|
|
20
|
+
maxYearInRange?: number | undefined;
|
|
21
|
+
minYearInRange?: number | undefined;
|
|
22
|
+
};
|
|
23
|
+
events: {
|
|
24
|
+
'year-click': CustomEvent<{
|
|
25
|
+
year: number;
|
|
26
|
+
}>;
|
|
27
|
+
input: CustomEvent<{
|
|
28
|
+
datetime: Date | undefined;
|
|
29
|
+
}>;
|
|
30
|
+
} & {
|
|
31
|
+
[evt: string]: CustomEvent<any>;
|
|
32
|
+
};
|
|
33
|
+
slots: {
|
|
34
|
+
activator: {
|
|
35
|
+
mask: {
|
|
36
|
+
value: string | undefined;
|
|
37
|
+
};
|
|
38
|
+
handleTextFieldFocus: (mobile: boolean) => void;
|
|
39
|
+
handleInputChange: (event: any) => void;
|
|
40
|
+
inputElement: HTMLElement;
|
|
41
|
+
placeholder: string | undefined;
|
|
42
|
+
};
|
|
43
|
+
'prepend-inner': {
|
|
44
|
+
prependInnerIcon: string | undefined;
|
|
45
|
+
iconSize: string;
|
|
46
|
+
};
|
|
47
|
+
'append-inner': {
|
|
48
|
+
appendIcon: string | undefined;
|
|
49
|
+
iconSize: string;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
export type YearPicketTextfieldProps = typeof __propDef.props;
|
|
54
|
+
export type YearPicketTextfieldEvents = typeof __propDef.events;
|
|
55
|
+
export type YearPicketTextfieldSlots = typeof __propDef.slots;
|
|
56
|
+
export default class YearPicketTextfield extends SvelteComponentTyped<YearPicketTextfieldProps, YearPicketTextfieldEvents, YearPicketTextfieldSlots> {
|
|
57
|
+
}
|
|
58
|
+
export {};
|
|
@@ -17,17 +17,31 @@ function calculateMenuPosition(params) {
|
|
|
17
17
|
if (anchor == "bottom") {
|
|
18
18
|
let { left: activatorLeft, top: activatorTop } = params.activator.getBoundingClientRect();
|
|
19
19
|
let activatorHeight = params.activator.offsetHeight;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
_top = activatorTop + activatorHeight + _activatorGap;
|
|
21
|
+
_left = activatorLeft;
|
|
22
|
+
let { top: fixedParentTop, left: fixedParentLeft, element } = getParentInstanceFromViewport(activator?.parentElement);
|
|
23
|
+
if (!!element) {
|
|
24
|
+
_top = _top - fixedParentTop;
|
|
25
|
+
_left = _left - fixedParentLeft;
|
|
26
|
+
} else {
|
|
27
|
+
_top = _top + window.scrollY;
|
|
28
|
+
_left = _left + window.scrollX;
|
|
29
|
+
}
|
|
23
30
|
} else if (anchor == "bottom-center") {
|
|
24
31
|
let { left: activatorLeft, top: activatorTop } = params.activator.getBoundingClientRect();
|
|
25
32
|
let activatorHeight = params.activator.offsetHeight;
|
|
26
33
|
let activatorWidth = params.activator.offsetWidth;
|
|
27
34
|
let menuWidth = params.menuElement.offsetWidth;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
35
|
+
_top = activatorTop + activatorHeight + _activatorGap;
|
|
36
|
+
_left = activatorLeft;
|
|
37
|
+
let { top: fixedParentTop, left: fixedParentLeft, element } = getParentInstanceFromViewport(activator?.parentElement);
|
|
38
|
+
if (!!element) {
|
|
39
|
+
_top = _top - fixedParentTop;
|
|
40
|
+
_left = _left - fixedParentLeft;
|
|
41
|
+
} else {
|
|
42
|
+
_top = _top + window.scrollY;
|
|
43
|
+
_left = _left + window.scrollX;
|
|
44
|
+
}
|
|
31
45
|
if (menuWidth > activatorWidth) {
|
|
32
46
|
_left = _left - (menuWidth - activatorWidth) / 2;
|
|
33
47
|
} else {
|
|
@@ -149,7 +163,7 @@ $:
|
|
|
149
163
|
function getPositionedAncestor(elem) {
|
|
150
164
|
if (!elem)
|
|
151
165
|
return null;
|
|
152
|
-
if (["fixed", "absolute"].includes(getComputedStyle(elem).position))
|
|
166
|
+
if (["fixed", "absolute", "sticky"].includes(getComputedStyle(elem).position))
|
|
153
167
|
return elem;
|
|
154
168
|
return getPositionedAncestor(elem.parentElement);
|
|
155
169
|
}
|
|
@@ -159,6 +173,7 @@ function handleCloseControllerClick() {
|
|
|
159
173
|
function getParentInstanceFromViewport(activatorParent) {
|
|
160
174
|
let top = 0;
|
|
161
175
|
let left = 0;
|
|
176
|
+
let fixedParentElement = void 0;
|
|
162
177
|
while (!!activatorParent && activatorParent.nodeName.toLowerCase() !== "html" && activatorParent.nodeName.toLowerCase() !== "body") {
|
|
163
178
|
const currentParent = activatorParent.parentElement;
|
|
164
179
|
if (!currentParent)
|
|
@@ -170,14 +185,19 @@ function getParentInstanceFromViewport(activatorParent) {
|
|
|
170
185
|
const boundingClientRect = activatorParent.getBoundingClientRect();
|
|
171
186
|
top = top + boundingClientRect.top;
|
|
172
187
|
left = left + boundingClientRect.left;
|
|
188
|
+
fixedParentElement = activatorParent;
|
|
173
189
|
}
|
|
174
190
|
activatorParent = activatorParent.parentElement;
|
|
175
191
|
}
|
|
176
|
-
return { top, left };
|
|
192
|
+
return { top, left, element: fixedParentElement };
|
|
177
193
|
}
|
|
178
194
|
function handleWindowScrollOrResize() {
|
|
179
|
-
if (open && !!menuElement && !!activator)
|
|
195
|
+
if (open && !!menuElement && !!activator) {
|
|
196
|
+
let elem = getPositionedAncestor(menuElement.parentElement);
|
|
197
|
+
if (!!elem && getComputedStyle(elem).position == "sticky")
|
|
198
|
+
return;
|
|
180
199
|
calculateMenuPosition({ menuElement, activator });
|
|
200
|
+
}
|
|
181
201
|
}
|
|
182
202
|
function handleMenuClick(e, zIndex2) {
|
|
183
203
|
let otherMenus = document.querySelectorAll(`[data-menu]`);
|
|
@@ -215,7 +235,7 @@ function handleMenuClick(e, zIndex2) {
|
|
|
215
235
|
data-menu
|
|
216
236
|
data-uid={currentUid}
|
|
217
237
|
style:z-index={zIndex}
|
|
218
|
-
style:position=
|
|
238
|
+
style:position={!!positionedAncestor && getComputedStyle(positionedAncestor).position == 'sticky' ? 'sticky' : 'absolute'}
|
|
219
239
|
style:top={_top + "px"}
|
|
220
240
|
style:box-shadow={_boxShadow}
|
|
221
241
|
style:border-radius={_borderRadius}
|
|
@@ -139,7 +139,7 @@ function handleMonthChange() {
|
|
|
139
139
|
/>
|
|
140
140
|
{:else if view == "year"}
|
|
141
141
|
<YearSelector
|
|
142
|
-
--year-selector-height="calc(var(--date-picker-height, var(--date-picker-default-height))
|
|
142
|
+
--year-selector-height="calc(var(--date-picker-height, var(--date-picker-default-height)) - calc(var(--date-picker-height, var(--date-picker-default-height)) / 4))"
|
|
143
143
|
bind:selectedYear={visibleYear}
|
|
144
144
|
{selectableYears}
|
|
145
145
|
on:click={handleYearChange}
|
|
@@ -29,6 +29,8 @@ import Button from "../buttons/Button.svelte";
|
|
|
29
29
|
<div bind:this={targetButtons[year]} style:width="100%">
|
|
30
30
|
<Button
|
|
31
31
|
--button-background-color={year == selectedYear ? "rgb(var(--global-color-primary-500))" : "trasparent"}
|
|
32
|
+
--button-active-background-color={year == selectedYear ? "rgb(var(--global-color-primary-500))" : "trasparent"}
|
|
33
|
+
--button-focus-background-color={year == selectedYear ? "rgb(var(--global-color-primary-500))" : "trasparent"}
|
|
32
34
|
--button-hover-background-color={year == selectedYear ? "var(--button-background-color)" : "rgb(var(--global-color-primary-500), .2)"}
|
|
33
35
|
--button-color={year == selectedYear ? "rgb(var(--global-color-grey-50))" : undefined}
|
|
34
36
|
--button-font-weight="500"
|
|
@@ -59,6 +61,10 @@ import Button from "../buttons/Button.svelte";
|
|
|
59
61
|
--year-selector-height,
|
|
60
62
|
var(--year-selector-default-height)
|
|
61
63
|
);
|
|
64
|
+
max-height: var(
|
|
65
|
+
--year-selector-max-height,
|
|
66
|
+
var(--year-selector-default-max-height)
|
|
67
|
+
);
|
|
62
68
|
width: var(
|
|
63
69
|
--year-selector-width,
|
|
64
70
|
var(--year-selector-default-width)
|