@likable-hair/svelte 3.0.68 → 3.0.70
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 +34 -8
- 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,33 @@ 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, fixedParent, validStickyParent } = getParentInstanceFromViewport(activator?.parentElement);
|
|
23
|
+
console.log(validStickyParent);
|
|
24
|
+
if (!!fixedParent) {
|
|
25
|
+
_top = _top - fixedParentTop;
|
|
26
|
+
_left = _left - fixedParentLeft;
|
|
27
|
+
} else if (!validStickyParent) {
|
|
28
|
+
_top = _top + window.scrollY;
|
|
29
|
+
_left = _left + window.scrollX;
|
|
30
|
+
}
|
|
23
31
|
} else if (anchor == "bottom-center") {
|
|
24
32
|
let { left: activatorLeft, top: activatorTop } = params.activator.getBoundingClientRect();
|
|
25
33
|
let activatorHeight = params.activator.offsetHeight;
|
|
26
34
|
let activatorWidth = params.activator.offsetWidth;
|
|
27
35
|
let menuWidth = params.menuElement.offsetWidth;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
_top = activatorTop + activatorHeight + _activatorGap;
|
|
37
|
+
_left = activatorLeft;
|
|
38
|
+
let { top: fixedParentTop, left: fixedParentLeft, fixedParent, validStickyParent } = getParentInstanceFromViewport(activator?.parentElement);
|
|
39
|
+
console.log(validStickyParent);
|
|
40
|
+
if (!!fixedParent) {
|
|
41
|
+
_top = _top - fixedParentTop;
|
|
42
|
+
_left = _left - fixedParentLeft;
|
|
43
|
+
} else if (!validStickyParent) {
|
|
44
|
+
_top = _top + window.scrollY;
|
|
45
|
+
_left = _left + window.scrollX;
|
|
46
|
+
}
|
|
31
47
|
if (menuWidth > activatorWidth) {
|
|
32
48
|
_left = _left - (menuWidth - activatorWidth) / 2;
|
|
33
49
|
} else {
|
|
@@ -149,7 +165,7 @@ $:
|
|
|
149
165
|
function getPositionedAncestor(elem) {
|
|
150
166
|
if (!elem)
|
|
151
167
|
return null;
|
|
152
|
-
if (["fixed", "absolute"].includes(getComputedStyle(elem).position))
|
|
168
|
+
if (["fixed", "absolute", "sticky"].includes(getComputedStyle(elem).position))
|
|
153
169
|
return elem;
|
|
154
170
|
return getPositionedAncestor(elem.parentElement);
|
|
155
171
|
}
|
|
@@ -159,6 +175,9 @@ function handleCloseControllerClick() {
|
|
|
159
175
|
function getParentInstanceFromViewport(activatorParent) {
|
|
160
176
|
let top = 0;
|
|
161
177
|
let left = 0;
|
|
178
|
+
let fixedParent = void 0;
|
|
179
|
+
let stickyParent = !!activatorParent && getComputedStyle(activatorParent).position === "sticky" ? activatorParent : void 0;
|
|
180
|
+
let isStickyValid = false;
|
|
162
181
|
while (!!activatorParent && activatorParent.nodeName.toLowerCase() !== "html" && activatorParent.nodeName.toLowerCase() !== "body") {
|
|
163
182
|
const currentParent = activatorParent.parentElement;
|
|
164
183
|
if (!currentParent)
|
|
@@ -170,10 +189,17 @@ function getParentInstanceFromViewport(activatorParent) {
|
|
|
170
189
|
const boundingClientRect = activatorParent.getBoundingClientRect();
|
|
171
190
|
top = top + boundingClientRect.top;
|
|
172
191
|
left = left + boundingClientRect.left;
|
|
192
|
+
fixedParent = activatorParent;
|
|
193
|
+
}
|
|
194
|
+
if (position === "sticky") {
|
|
195
|
+
stickyParent = activatorParent;
|
|
196
|
+
}
|
|
197
|
+
if (position === "relative" && !!stickyParent) {
|
|
198
|
+
isStickyValid = true;
|
|
173
199
|
}
|
|
174
200
|
activatorParent = activatorParent.parentElement;
|
|
175
201
|
}
|
|
176
|
-
return { top, left };
|
|
202
|
+
return { top, left, fixedParent, validStickyParent: isStickyValid ? stickyParent : void 0 };
|
|
177
203
|
}
|
|
178
204
|
function handleWindowScrollOrResize() {
|
|
179
205
|
if (open && !!menuElement && !!activator)
|
|
@@ -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)
|