@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.
@@ -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
- let { top: fixedParentTop, left: fixedParentLeft } = getParentInstanceFromViewport(activator?.parentElement);
21
- _top = activatorTop + window.scrollY + activatorHeight + _activatorGap - fixedParentTop;
22
- _left = activatorLeft + window.scrollX - fixedParentLeft;
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
- let { top: fixedParentTop, left: fixedParentLeft } = getParentInstanceFromViewport(activator?.parentElement);
29
- _top = activatorTop + window.scrollY + activatorHeight + _activatorGap - fixedParentTop;
30
- _left = activatorLeft + window.scrollX - fixedParentLeft;
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="absolute"
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)) / 8 * 6)"
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}
@@ -1,4 +1,5 @@
1
1
  :root {
2
+ --year-selector-default-max-height: 500px;
2
3
  --year-selector-default-height: 100%;
3
4
  --year-selector-default-width: 100%;
4
5
  }
@@ -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)
@@ -192,6 +192,7 @@ function handleIconClick(index, element) {
192
192
  }
193
193
 
194
194
  .element {
195
+ position: relative;
195
196
  padding: var(
196
197
  --selectable-vertical-list-element-padding,
197
198
  var(--selectable-vertical-list-default-element-padding)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@likable-hair/svelte",
3
3
  "description": "A Svelte component for likablehair",
4
- "version": "3.0.68",
4
+ "version": "3.0.69",
5
5
  "scripts": {
6
6
  "host": "vite --host",
7
7
  "dev": "vite dev",