1 |
|
2 |
|
3 |
|
4 | import { proxyCustomElement, HTMLElement, createEvent, h, Host } from '@stencil/core/internal/client';
|
5 | import { b as getIonMode } from './ionic-global.js';
|
6 | import { j as clamp } from './helpers.js';
|
7 | import { b as hapticSelectionChanged, h as hapticSelectionEnd, a as hapticSelectionStart } from './haptic.js';
|
8 |
|
9 | const pickerColumnIosCss = ".picker-col{display:-ms-flexbox;display:flex;position:relative;-ms-flex:1;flex:1;-ms-flex-pack:center;justify-content:center;height:100%;-webkit-box-sizing:content-box;box-sizing:content-box;contain:content}.picker-opts{position:relative;-ms-flex:1;flex:1;max-width:100%}.picker-opt{left:0;top:0;display:block;position:absolute;width:100%;border:0;text-align:center;text-overflow:ellipsis;white-space:nowrap;contain:strict;overflow:hidden;will-change:transform}[dir=rtl] .picker-opt,:host-context([dir=rtl]) .picker-opt{left:unset;right:unset;right:0}.picker-opt.picker-opt-disabled{pointer-events:none}.picker-opt-disabled{opacity:0}.picker-opts-left{-ms-flex-pack:start;justify-content:flex-start}.picker-opts-right{-ms-flex-pack:end;justify-content:flex-end}.picker-opt:active,.picker-opt:focus{outline:none}.picker-prefix{position:relative;-ms-flex:1;flex:1;text-align:end;white-space:nowrap}.picker-suffix{position:relative;-ms-flex:1;flex:1;text-align:start;white-space:nowrap}.picker-col{padding-left:4px;padding-right:4px;padding-top:0;padding-bottom:0;-webkit-transform-style:preserve-3d;transform-style:preserve-3d}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.picker-col{padding-left:unset;padding-right:unset;-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px}}.picker-prefix,.picker-suffix,.picker-opts{top:77px;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;color:inherit;font-size:20px;line-height:42px;pointer-events:none}.picker-opt{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-transform-origin:center center;transform-origin:center center;height:46px;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out;background:transparent;color:inherit;font-size:20px;line-height:42px;-webkit-backface-visibility:hidden;backface-visibility:hidden;pointer-events:auto}[dir=rtl] .picker-opt,:host-context([dir=rtl]) .picker-opt{-webkit-transform-origin:calc(100% - center) center;transform-origin:calc(100% - center) center}";
|
10 |
|
11 | const pickerColumnMdCss = ".picker-col{display:-ms-flexbox;display:flex;position:relative;-ms-flex:1;flex:1;-ms-flex-pack:center;justify-content:center;height:100%;-webkit-box-sizing:content-box;box-sizing:content-box;contain:content}.picker-opts{position:relative;-ms-flex:1;flex:1;max-width:100%}.picker-opt{left:0;top:0;display:block;position:absolute;width:100%;border:0;text-align:center;text-overflow:ellipsis;white-space:nowrap;contain:strict;overflow:hidden;will-change:transform}[dir=rtl] .picker-opt,:host-context([dir=rtl]) .picker-opt{left:unset;right:unset;right:0}.picker-opt.picker-opt-disabled{pointer-events:none}.picker-opt-disabled{opacity:0}.picker-opts-left{-ms-flex-pack:start;justify-content:flex-start}.picker-opts-right{-ms-flex-pack:end;justify-content:flex-end}.picker-opt:active,.picker-opt:focus{outline:none}.picker-prefix{position:relative;-ms-flex:1;flex:1;text-align:end;white-space:nowrap}.picker-suffix{position:relative;-ms-flex:1;flex:1;text-align:start;white-space:nowrap}.picker-col{padding-left:8px;padding-right:8px;padding-top:0;padding-bottom:0;-webkit-transform-style:preserve-3d;transform-style:preserve-3d}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.picker-col{padding-left:unset;padding-right:unset;-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px}}.picker-prefix,.picker-suffix,.picker-opts{top:77px;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;color:inherit;font-size:22px;line-height:42px;pointer-events:none}.picker-opt{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;height:43px;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out;background:transparent;color:inherit;font-size:22px;line-height:42px;-webkit-backface-visibility:hidden;backface-visibility:hidden;pointer-events:auto}.picker-prefix,.picker-suffix,.picker-opt.picker-opt-selected{color:var(--ion-color-primary, #3880ff)}";
|
12 |
|
13 | const PickerColumnCmp = proxyCustomElement(class extends HTMLElement {
|
14 | constructor() {
|
15 | super();
|
16 | this.__registerHost();
|
17 | this.ionPickerColChange = createEvent(this, "ionPickerColChange", 7);
|
18 | this.optHeight = 0;
|
19 | this.rotateFactor = 0;
|
20 | this.scaleFactor = 1;
|
21 | this.velocity = 0;
|
22 | this.y = 0;
|
23 | this.noAnimate = true;
|
24 | }
|
25 | colChanged() {
|
26 | this.refresh();
|
27 | }
|
28 | async connectedCallback() {
|
29 | let pickerRotateFactor = 0;
|
30 | let pickerScaleFactor = 0.81;
|
31 | const mode = getIonMode(this);
|
32 | if (mode === 'ios') {
|
33 | pickerRotateFactor = -0.46;
|
34 | pickerScaleFactor = 1;
|
35 | }
|
36 | this.rotateFactor = pickerRotateFactor;
|
37 | this.scaleFactor = pickerScaleFactor;
|
38 | this.gesture = (await import('./index2.js')).createGesture({
|
39 | el: this.el,
|
40 | gestureName: 'picker-swipe',
|
41 | gesturePriority: 100,
|
42 | threshold: 0,
|
43 | passive: false,
|
44 | onStart: ev => this.onStart(ev),
|
45 | onMove: ev => this.onMove(ev),
|
46 | onEnd: ev => this.onEnd(ev),
|
47 | });
|
48 | this.gesture.enable();
|
49 | this.tmrId = setTimeout(() => {
|
50 | this.noAnimate = false;
|
51 | this.refresh(true);
|
52 | }, 250);
|
53 | }
|
54 | componentDidLoad() {
|
55 | const colEl = this.optsEl;
|
56 | if (colEl) {
|
57 |
|
58 |
|
59 | this.optHeight = (colEl.firstElementChild ? colEl.firstElementChild.clientHeight : 0);
|
60 | }
|
61 | this.refresh();
|
62 | }
|
63 | disconnectedCallback() {
|
64 | cancelAnimationFrame(this.rafId);
|
65 | clearTimeout(this.tmrId);
|
66 | if (this.gesture) {
|
67 | this.gesture.destroy();
|
68 | this.gesture = undefined;
|
69 | }
|
70 | }
|
71 | emitColChange() {
|
72 | this.ionPickerColChange.emit(this.col);
|
73 | }
|
74 | setSelected(selectedIndex, duration) {
|
75 |
|
76 |
|
77 | const y = (selectedIndex > -1) ? -(selectedIndex * this.optHeight) : 0;
|
78 | this.velocity = 0;
|
79 |
|
80 | cancelAnimationFrame(this.rafId);
|
81 | this.update(y, duration, true);
|
82 | this.emitColChange();
|
83 | }
|
84 | update(y, duration, saveY) {
|
85 | if (!this.optsEl) {
|
86 | return;
|
87 | }
|
88 |
|
89 | let translateY = 0;
|
90 | let translateZ = 0;
|
91 | const { col, rotateFactor } = this;
|
92 | const selectedIndex = col.selectedIndex = this.indexForY(-y);
|
93 | const durationStr = (duration === 0) ? '' : duration + 'ms';
|
94 | const scaleStr = `scale(${this.scaleFactor})`;
|
95 | const children = this.optsEl.children;
|
96 | for (let i = 0; i < children.length; i++) {
|
97 | const button = children[i];
|
98 | const opt = col.options[i];
|
99 | const optOffset = (i * this.optHeight) + y;
|
100 | let transform = '';
|
101 | if (rotateFactor !== 0) {
|
102 | const rotateX = optOffset * rotateFactor;
|
103 | if (Math.abs(rotateX) <= 90) {
|
104 | translateY = 0;
|
105 | translateZ = 90;
|
106 | transform = `rotateX(${rotateX}deg) `;
|
107 | }
|
108 | else {
|
109 | translateY = -9999;
|
110 | }
|
111 | }
|
112 | else {
|
113 | translateZ = 0;
|
114 | translateY = optOffset;
|
115 | }
|
116 | const selected = selectedIndex === i;
|
117 | transform += `translate3d(0px,${translateY}px,${translateZ}px) `;
|
118 | if (this.scaleFactor !== 1 && !selected) {
|
119 | transform += scaleStr;
|
120 | }
|
121 |
|
122 | if (this.noAnimate) {
|
123 | opt.duration = 0;
|
124 | button.style.transitionDuration = '';
|
125 | }
|
126 | else if (duration !== opt.duration) {
|
127 | opt.duration = duration;
|
128 | button.style.transitionDuration = durationStr;
|
129 | }
|
130 |
|
131 | if (transform !== opt.transform) {
|
132 | opt.transform = transform;
|
133 | button.style.transform = transform;
|
134 | }
|
135 |
|
136 | if (selected !== opt.selected) {
|
137 | opt.selected = selected;
|
138 | if (selected) {
|
139 | button.classList.add(PICKER_OPT_SELECTED);
|
140 | }
|
141 | else {
|
142 | button.classList.remove(PICKER_OPT_SELECTED);
|
143 | }
|
144 | }
|
145 | }
|
146 | this.col.prevSelected = selectedIndex;
|
147 | if (saveY) {
|
148 | this.y = y;
|
149 | }
|
150 | if (this.lastIndex !== selectedIndex) {
|
151 |
|
152 | hapticSelectionChanged();
|
153 | this.lastIndex = selectedIndex;
|
154 | }
|
155 | }
|
156 | decelerate() {
|
157 | if (this.velocity !== 0) {
|
158 |
|
159 | this.velocity *= DECELERATION_FRICTION;
|
160 |
|
161 | this.velocity = (this.velocity > 0)
|
162 | ? Math.max(this.velocity, 1)
|
163 | : Math.min(this.velocity, -1);
|
164 | let y = this.y + this.velocity;
|
165 | if (y > this.minY) {
|
166 |
|
167 | y = this.minY;
|
168 | this.velocity = 0;
|
169 | }
|
170 | else if (y < this.maxY) {
|
171 |
|
172 | y = this.maxY;
|
173 | this.velocity = 0;
|
174 | }
|
175 | this.update(y, 0, true);
|
176 | const notLockedIn = (Math.round(y) % this.optHeight !== 0) || (Math.abs(this.velocity) > 1);
|
177 | if (notLockedIn) {
|
178 |
|
179 | this.rafId = requestAnimationFrame(() => this.decelerate());
|
180 | }
|
181 | else {
|
182 | this.velocity = 0;
|
183 | this.emitColChange();
|
184 | hapticSelectionEnd();
|
185 | }
|
186 | }
|
187 | else if (this.y % this.optHeight !== 0) {
|
188 |
|
189 | const currentPos = Math.abs(this.y % this.optHeight);
|
190 |
|
191 | this.velocity = (currentPos > (this.optHeight / 2) ? 1 : -1);
|
192 | this.decelerate();
|
193 | }
|
194 | }
|
195 | indexForY(y) {
|
196 | return Math.min(Math.max(Math.abs(Math.round(y / this.optHeight)), 0), this.col.options.length - 1);
|
197 | }
|
198 |
|
199 | onStart(detail) {
|
200 |
|
201 |
|
202 |
|
203 | if (detail.event.cancelable) {
|
204 | detail.event.preventDefault();
|
205 | }
|
206 | detail.event.stopPropagation();
|
207 | hapticSelectionStart();
|
208 |
|
209 | cancelAnimationFrame(this.rafId);
|
210 | const options = this.col.options;
|
211 | let minY = (options.length - 1);
|
212 | let maxY = 0;
|
213 | for (let i = 0; i < options.length; i++) {
|
214 | if (!options[i].disabled) {
|
215 | minY = Math.min(minY, i);
|
216 | maxY = Math.max(maxY, i);
|
217 | }
|
218 | }
|
219 | this.minY = -(minY * this.optHeight);
|
220 | this.maxY = -(maxY * this.optHeight);
|
221 | }
|
222 | onMove(detail) {
|
223 | if (detail.event.cancelable) {
|
224 | detail.event.preventDefault();
|
225 | }
|
226 | detail.event.stopPropagation();
|
227 |
|
228 | let y = this.y + detail.deltaY;
|
229 | if (y > this.minY) {
|
230 |
|
231 | y = Math.pow(y, 0.8);
|
232 | this.bounceFrom = y;
|
233 | }
|
234 | else if (y < this.maxY) {
|
235 |
|
236 | y += Math.pow(this.maxY - y, 0.9);
|
237 | this.bounceFrom = y;
|
238 | }
|
239 | else {
|
240 | this.bounceFrom = 0;
|
241 | }
|
242 | this.update(y, 0, false);
|
243 | }
|
244 | onEnd(detail) {
|
245 | if (this.bounceFrom > 0) {
|
246 |
|
247 | this.update(this.minY, 100, true);
|
248 | this.emitColChange();
|
249 | return;
|
250 | }
|
251 | else if (this.bounceFrom < 0) {
|
252 |
|
253 | this.update(this.maxY, 100, true);
|
254 | this.emitColChange();
|
255 | return;
|
256 | }
|
257 | this.velocity = clamp(-MAX_PICKER_SPEED, detail.velocityY * 23, MAX_PICKER_SPEED);
|
258 | if (this.velocity === 0 && detail.deltaY === 0) {
|
259 | const opt = detail.event.target.closest('.picker-opt');
|
260 | if (opt && opt.hasAttribute('opt-index')) {
|
261 | this.setSelected(parseInt(opt.getAttribute('opt-index'), 10), TRANSITION_DURATION);
|
262 | }
|
263 | }
|
264 | else {
|
265 | this.y += detail.deltaY;
|
266 | if (Math.abs(detail.velocityY) < 0.05) {
|
267 | const isScrollingUp = detail.deltaY > 0;
|
268 | const optHeightFraction = (Math.abs(this.y) % this.optHeight) / this.optHeight;
|
269 | if (isScrollingUp && optHeightFraction > 0.5) {
|
270 | this.velocity = Math.abs(this.velocity) * -1;
|
271 | }
|
272 | else if (!isScrollingUp && optHeightFraction <= 0.5) {
|
273 | this.velocity = Math.abs(this.velocity);
|
274 | }
|
275 | }
|
276 | this.decelerate();
|
277 | }
|
278 | }
|
279 | refresh(forceRefresh) {
|
280 | let min = this.col.options.length - 1;
|
281 | let max = 0;
|
282 | const options = this.col.options;
|
283 | for (let i = 0; i < options.length; i++) {
|
284 | if (!options[i].disabled) {
|
285 | min = Math.min(min, i);
|
286 | max = Math.max(max, i);
|
287 | }
|
288 | }
|
289 | |
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 |
|
296 | if (this.velocity !== 0) {
|
297 | return;
|
298 | }
|
299 | const selectedIndex = clamp(min, this.col.selectedIndex || 0, max);
|
300 | if (this.col.prevSelected !== selectedIndex || forceRefresh) {
|
301 | const y = (selectedIndex * this.optHeight) * -1;
|
302 | this.velocity = 0;
|
303 | this.update(y, TRANSITION_DURATION, true);
|
304 | }
|
305 | }
|
306 | render() {
|
307 | const col = this.col;
|
308 | const Button = 'button';
|
309 | const mode = getIonMode(this);
|
310 | return (h(Host, { class: {
|
311 | [mode]: true,
|
312 | 'picker-col': true,
|
313 | 'picker-opts-left': this.col.align === 'left',
|
314 | 'picker-opts-right': this.col.align === 'right'
|
315 | }, style: {
|
316 | 'max-width': this.col.columnWidth
|
317 | } }, col.prefix && (h("div", { class: "picker-prefix", style: { width: col.prefixWidth } }, col.prefix)), h("div", { class: "picker-opts", style: { maxWidth: col.optionsWidth }, ref: el => this.optsEl = el }, col.options.map((o, index) => h(Button, { type: "button", class: { 'picker-opt': true, 'picker-opt-disabled': !!o.disabled }, "opt-index": index }, o.text))), col.suffix && (h("div", { class: "picker-suffix", style: { width: col.suffixWidth } }, col.suffix))));
|
318 | }
|
319 | get el() { return this; }
|
320 | static get watchers() { return {
|
321 | "col": ["colChanged"]
|
322 | }; }
|
323 | static get style() { return {
|
324 | ios: pickerColumnIosCss,
|
325 | md: pickerColumnMdCss
|
326 | }; }
|
327 | }, [32, "ion-picker-column", {
|
328 | "col": [16]
|
329 | }]);
|
330 | const PICKER_OPT_SELECTED = 'picker-opt-selected';
|
331 | const DECELERATION_FRICTION = 0.97;
|
332 | const MAX_PICKER_SPEED = 90;
|
333 | const TRANSITION_DURATION = 150;
|
334 | function defineCustomElement() {
|
335 | if (typeof customElements === "undefined") {
|
336 | return;
|
337 | }
|
338 | const components = ["ion-picker-column"];
|
339 | components.forEach(tagName => { switch (tagName) {
|
340 | case "ion-picker-column":
|
341 | if (!customElements.get(tagName)) {
|
342 | customElements.define(tagName, PickerColumnCmp);
|
343 | }
|
344 | break;
|
345 | } });
|
346 | }
|
347 |
|
348 | export { PickerColumnCmp as P, defineCustomElement as d };
|