@operato/input 8.0.0-beta.5 → 8.0.0

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +24 -148
  2. package/assets/images/icon-editor-gradient-direction.png +0 -0
  3. package/assets/images/icon-properties-label.png +0 -0
  4. package/assets/images/icon-properties-line-type.png +0 -0
  5. package/assets/images/icon-properties-table.png +0 -0
  6. package/dist/src/index.d.ts +0 -1
  7. package/dist/src/index.js +0 -1
  8. package/dist/src/index.js.map +1 -1
  9. package/dist/src/ox-input-color-stops.d.ts +1 -1
  10. package/dist/src/ox-input-color-stops.js +2 -2
  11. package/dist/src/ox-input-color-stops.js.map +1 -1
  12. package/dist/src/ox-input-direction.d.ts +0 -1
  13. package/dist/src/ox-input-direction.js +4 -37
  14. package/dist/src/ox-input-direction.js.map +1 -1
  15. package/dist/src/ox-input-signature.d.ts +2 -4
  16. package/dist/src/ox-input-signature.js +14 -34
  17. package/dist/src/ox-input-signature.js.map +1 -1
  18. package/dist/src/ox-zoomable-image.d.ts +17 -0
  19. package/dist/src/ox-zoomable-image.js +80 -0
  20. package/dist/src/ox-zoomable-image.js.map +1 -0
  21. package/dist/stories/ox-input-direction.stories.js +0 -11
  22. package/dist/stories/ox-input-direction.stories.js.map +1 -1
  23. package/dist/tsconfig.tsbuildinfo +1 -1
  24. package/package.json +15 -23
  25. package/dist/src/ox-input-switch.d.ts +0 -10
  26. package/dist/src/ox-input-switch.js +0 -125
  27. package/dist/src/ox-input-switch.js.map +0 -1
  28. package/dist/src/ox-select-floor.d.ts +0 -35
  29. package/dist/src/ox-select-floor.js +0 -238
  30. package/dist/src/ox-select-floor.js.map +0 -1
  31. package/dist/stories/image-for-select-floor.d.ts +0 -1
  32. package/dist/stories/image-for-select-floor.js +0 -2
  33. package/dist/stories/image-for-select-floor.js.map +0 -1
  34. package/dist/stories/ox-input-switch.stories.d.ts +0 -38
  35. package/dist/stories/ox-input-switch.stories.js +0 -68
  36. package/dist/stories/ox-input-switch.stories.js.map +0 -1
  37. package/dist/stories/ox-select-floor.stories.d.ts +0 -45
  38. package/dist/stories/ox-select-floor.stories.js +0 -166
  39. package/dist/stories/ox-select-floor.stories.js.map +0 -1
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@operato/input",
3
3
  "description": "Webcomponents for input following open-wc recommendations",
4
4
  "author": "heartyoh@hatiolab.com",
5
- "version": "8.0.0-beta.5",
5
+ "version": "8.0.0",
6
6
  "main": "dist/src/index.js",
7
7
  "module": "dist/src/index.js",
8
8
  "license": "MIT",
@@ -42,7 +42,6 @@
42
42
  "./ox-input-key-values.js": "./dist/src/ox-input-key-values.js",
43
43
  "./ox-select.js": "./dist/src/ox-select.js",
44
44
  "./ox-input-file.js": "./dist/src/ox-input-file.js",
45
- "./ox-input-switch.js": "./dist/src/ox-input-switch.js",
46
45
  "./ox-input-image.js": "./dist/src/ox-input-image.js",
47
46
  "./ox-input-options.js": "./dist/src/ox-input-options.js",
48
47
  "./ox-input-select-buttons.js": "./dist/src/ox-input-select-buttons.js",
@@ -59,7 +58,6 @@
59
58
  "./ox-input-textarea.js": "./dist/src/ox-input-textarea.js",
60
59
  "./ox-input-direction.js": "./dist/src/ox-input-direction.js",
61
60
  "./ox-input-signature.js": "./dist/src/ox-input-signature.js",
62
- "./ox-select-floor.js": "./dist/src/ox-select-floor.js",
63
61
  "./ox-input-table-column-config.js": "./dist/src/ox-input-table-column-config.js"
64
62
  },
65
63
  "typesVersions": {
@@ -133,9 +131,6 @@
133
131
  "./ox-input-file.js": [
134
132
  "./dist/src/ox-input-file.d.ts"
135
133
  ],
136
- "./ox-input-switch.js": [
137
- "./dist/src/ox-input-switch.d.ts"
138
- ],
139
134
  "./ox-input-image.js": [
140
135
  "./dist/src/ox-input-image.d.ts"
141
136
  ],
@@ -184,9 +179,6 @@
184
179
  "./ox-input-signature.js": [
185
180
  "./dist/src/ox-input-signature.d.ts"
186
181
  ],
187
- "./ox-select-floor.js": [
188
- "./dist/src/ox-select-floor.d.ts"
189
- ],
190
182
  "./ox-input-table-column-config.js": [
191
183
  "./dist/src/ox-input-table-column-config.d.ts"
192
184
  ]
@@ -218,11 +210,11 @@
218
210
  "@ctrl/tinycolor": "^4.1.0",
219
211
  "@lit/localize": "^0.12.1",
220
212
  "@material/web": "^2.0.0",
221
- "@operato/color-picker": "^8.0.0-beta.2",
222
- "@operato/i18n": "^8.0.0-beta.2",
223
- "@operato/popup": "^8.0.0-beta.5",
224
- "@operato/styles": "^8.0.0-beta.2",
225
- "@operato/utils": "^8.0.0-beta.2",
213
+ "@operato/color-picker": "^8.0.0",
214
+ "@operato/i18n": "^8.0.0",
215
+ "@operato/popup": "^8.0.0",
216
+ "@operato/styles": "^8.0.0",
217
+ "@operato/utils": "^8.0.0",
226
218
  "@polymer/paper-dropdown-menu": "^3.2.0",
227
219
  "@polymer/paper-item": "^3.0.1",
228
220
  "@thebespokepixel/es-tinycolor": "^3.1.0",
@@ -233,18 +225,18 @@
233
225
  "lodash-es": "^4.17.21"
234
226
  },
235
227
  "devDependencies": {
236
- "@custom-elements-manifest/analyzer": "^0.10.0",
228
+ "@custom-elements-manifest/analyzer": "^0.9.2",
237
229
  "@hatiolab/prettier-config": "^1.0.0",
238
230
  "@lit/localize-tools": "^0.7.2",
239
231
  "@open-wc/eslint-config": "^12.0.3",
240
- "@open-wc/testing": "^4.0.0",
241
- "@typescript-eslint/eslint-plugin": "^8.0.0",
242
- "@typescript-eslint/parser": "^8.0.0",
243
- "@web/dev-server": "^0.4.0",
232
+ "@open-wc/testing": "^3.1.6",
233
+ "@typescript-eslint/eslint-plugin": "^7.0.1",
234
+ "@typescript-eslint/parser": "^7.0.1",
235
+ "@web/dev-server": "^0.3.0",
244
236
  "@web/dev-server-storybook": "^2.0.1",
245
- "@web/test-runner": "^0.19.0",
246
- "concurrently": "^9.0.0",
247
- "eslint": "^9.0.0",
237
+ "@web/test-runner": "^0.18.0",
238
+ "concurrently": "^8.0.1",
239
+ "eslint": "^8.39.0",
248
240
  "eslint-config-prettier": "^9.1.0",
249
241
  "husky": "^9.0.11",
250
242
  "lint-staged": "^15.2.2",
@@ -266,5 +258,5 @@
266
258
  "prettier --write"
267
259
  ]
268
260
  },
269
- "gitHead": "7c70814f95cd4f22508b513575984ceca6eb1bff"
261
+ "gitHead": "180d521a2ca296829122361a45be86e8542ada43"
270
262
  }
@@ -1,10 +0,0 @@
1
- import { OxFormField } from './ox-form-field';
2
- export declare class OxInputSwitch extends OxFormField {
3
- static styles: import("lit").CSSResult;
4
- round: boolean;
5
- value: boolean;
6
- disabled: boolean;
7
- render(): import("lit-html").TemplateResult<1>;
8
- firstUpdated(): void;
9
- protected appendFormData({ formData }: FormDataEvent): void;
10
- }
@@ -1,125 +0,0 @@
1
- import { __decorate } from "tslib";
2
- import { css, html } from 'lit';
3
- import { customElement, property } from 'lit/decorators.js';
4
- import { OxFormField } from './ox-form-field';
5
- let OxInputSwitch = class OxInputSwitch extends OxFormField {
6
- constructor() {
7
- super(...arguments);
8
- this.round = false;
9
- this.value = false;
10
- this.disabled = false;
11
- }
12
- static { this.styles = css `
13
- :host {
14
- --ox-simple-switch-fullwidth: 2em;
15
- --ox-simple-switch-fullheight: 1em;
16
- --ox-simple-switch-thumbnail-size: 1em;
17
- }
18
-
19
- label {
20
- position: relative;
21
- display: inline-block;
22
- width: 100%;
23
- height: 100%;
24
- }
25
-
26
- label input {
27
- opacity: 0;
28
- width: 0;
29
- height: 0;
30
- }
31
-
32
- span {
33
- position: absolute;
34
- cursor: pointer;
35
- width: var(--ox-simple-switch-fullwidth);
36
- height: var(--ox-simple-switch-fullheight);
37
- top: calc(0 - var(--ox-simple-switch-thumbnail-size));
38
- left: 0;
39
- background-color: var(--ox-simple-switch-off-color, #ccc);
40
- -webkit-transition: 0.4s;
41
- transition: 0.4s;
42
- }
43
-
44
- span:before {
45
- position: absolute;
46
- content: '';
47
- height: calc(var(--ox-simple-switch-thumbnail-size) - 8px);
48
- width: calc(var(--ox-simple-switch-thumbnail-size) - 8px);
49
- left: 4px;
50
- top: 4px;
51
- background-color: var(--ox-simple-switch-thumbnail-color, white);
52
- -webkit-transition: 0.4s;
53
- transition: 0.4s;
54
- }
55
-
56
- input:checked + span {
57
- background-color: var(--ox-simple-switch-on-color, #2196f3);
58
- }
59
-
60
- input + span:before {
61
- -webkit-transform: translateY(
62
- calc((var(--ox-simple-switch-fullheight) - var(--ox-simple-switch-thumbnail-size)) / 2)
63
- );
64
- -ms-transform: translateY(
65
- calc((var(--ox-simple-switch-fullheight) - var(--ox-simple-switch-thumbnail-size)) / 2)
66
- );
67
- transform: translateY(calc((var(--ox-simple-switch-fullheight) - var(--ox-simple-switch-thumbnail-size)) / 2));
68
- }
69
-
70
- input:checked + span:before {
71
- -webkit-transform: translateX(calc(var(--ox-simple-switch-fullwidth) - var(--ox-simple-switch-thumbnail-size)))
72
- translateY(calc((var(--ox-simple-switch-fullheight) - var(--ox-simple-switch-thumbnail-size)) / 2));
73
- -ms-transform: translateX(calc(var(--ox-simple-switch-fullwidth) - var(--ox-simple-switch-thumbnail-size)))
74
- translateY(calc((var(--ox-simple-switch-fullheight) - var(--ox-simple-switch-thumbnail-size)) / 2));
75
- transform: translateX(calc(var(--ox-simple-switch-fullwidth) - var(--ox-simple-switch-thumbnail-size)))
76
- translateY(calc((var(--ox-simple-switch-fullheight) - var(--ox-simple-switch-thumbnail-size)) / 2));
77
- }
78
-
79
- /* Rounded sliders */
80
- span[round] {
81
- border-radius: calc(var(--ox-simple-switch-thumbnail-size) / 2);
82
- }
83
-
84
- span[round]:before {
85
- border-radius: calc((var(--ox-simple-switch-thumbnail-size) - 8px) / 2);
86
- }
87
- `; }
88
- render() {
89
- return html `
90
- <label>
91
- <input type="checkbox" .checked=${this.value} ?disabled=${this.disabled} />
92
- <span ?round=${this.round}></span>
93
- </label>
94
- `;
95
- }
96
- firstUpdated() {
97
- this.renderRoot.addEventListener('change', (e) => {
98
- e.preventDefault();
99
- e.stopPropagation();
100
- this.value = e.target?.checked;
101
- this.dispatchEvent(new CustomEvent('change', {
102
- bubbles: true,
103
- composed: true,
104
- detail: this.value
105
- }));
106
- });
107
- }
108
- appendFormData({ formData }) {
109
- this.name && formData.append(this.name, this.value ? 'true' : 'false');
110
- }
111
- };
112
- __decorate([
113
- property({ type: Boolean })
114
- ], OxInputSwitch.prototype, "round", void 0);
115
- __decorate([
116
- property({ type: Boolean })
117
- ], OxInputSwitch.prototype, "value", void 0);
118
- __decorate([
119
- property({ type: Boolean })
120
- ], OxInputSwitch.prototype, "disabled", void 0);
121
- OxInputSwitch = __decorate([
122
- customElement('ox-input-switch')
123
- ], OxInputSwitch);
124
- export { OxInputSwitch };
125
- //# sourceMappingURL=ox-input-switch.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ox-input-switch.js","sourceRoot":"","sources":["../../src/ox-input-switch.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC/B,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAGtC,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,WAAW;IAAvC;;QA8EwB,UAAK,GAAY,KAAK,CAAA;QACtB,UAAK,GAAY,KAAK,CAAA;QACtB,aAAQ,GAAY,KAAK,CAAA;IA8BxD,CAAC;aA7GQ,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2ElB,AA3EY,CA2EZ;IAMD,MAAM;QACJ,OAAO,IAAI,CAAA;;0CAE2B,IAAI,CAAC,KAAK,cAAc,IAAI,CAAC,QAAQ;uBACxD,IAAI,CAAC,KAAK;;KAE5B,CAAA;IACH,CAAC;IAED,YAAY;QACV,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,QAAQ,EAAE,CAAC,CAAQ,EAAE,EAAE;YACtD,CAAC,CAAC,cAAc,EAAE,CAAA;YAClB,CAAC,CAAC,eAAe,EAAE,CAAA;YAEnB,IAAI,CAAC,KAAK,GAAI,CAAC,CAAC,MAA2B,EAAE,OAAO,CAAA;YACpD,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,QAAQ,EAAE;gBACxB,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,IAAI,CAAC,KAAK;aACnB,CAAC,CACH,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAES,cAAc,CAAC,EAAE,QAAQ,EAAiB;QAClD,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;IACxE,CAAC;;AA/B4B;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;4CAAuB;AACtB;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;4CAAuB;AACtB;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;+CAA0B;AAhF3C,aAAa;IADzB,aAAa,CAAC,iBAAiB,CAAC;GACpB,aAAa,CA8GzB","sourcesContent":["import { css, html } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { OxFormField } from './ox-form-field'\n\n@customElement('ox-input-switch')\nexport class OxInputSwitch extends OxFormField {\n static styles = css`\n :host {\n --ox-simple-switch-fullwidth: 2em;\n --ox-simple-switch-fullheight: 1em;\n --ox-simple-switch-thumbnail-size: 1em;\n }\n\n label {\n position: relative;\n display: inline-block;\n width: 100%;\n height: 100%;\n }\n\n label input {\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n span {\n position: absolute;\n cursor: pointer;\n width: var(--ox-simple-switch-fullwidth);\n height: var(--ox-simple-switch-fullheight);\n top: calc(0 - var(--ox-simple-switch-thumbnail-size));\n left: 0;\n background-color: var(--ox-simple-switch-off-color, #ccc);\n -webkit-transition: 0.4s;\n transition: 0.4s;\n }\n\n span:before {\n position: absolute;\n content: '';\n height: calc(var(--ox-simple-switch-thumbnail-size) - 8px);\n width: calc(var(--ox-simple-switch-thumbnail-size) - 8px);\n left: 4px;\n top: 4px;\n background-color: var(--ox-simple-switch-thumbnail-color, white);\n -webkit-transition: 0.4s;\n transition: 0.4s;\n }\n\n input:checked + span {\n background-color: var(--ox-simple-switch-on-color, #2196f3);\n }\n\n input + span:before {\n -webkit-transform: translateY(\n calc((var(--ox-simple-switch-fullheight) - var(--ox-simple-switch-thumbnail-size)) / 2)\n );\n -ms-transform: translateY(\n calc((var(--ox-simple-switch-fullheight) - var(--ox-simple-switch-thumbnail-size)) / 2)\n );\n transform: translateY(calc((var(--ox-simple-switch-fullheight) - var(--ox-simple-switch-thumbnail-size)) / 2));\n }\n\n input:checked + span:before {\n -webkit-transform: translateX(calc(var(--ox-simple-switch-fullwidth) - var(--ox-simple-switch-thumbnail-size)))\n translateY(calc((var(--ox-simple-switch-fullheight) - var(--ox-simple-switch-thumbnail-size)) / 2));\n -ms-transform: translateX(calc(var(--ox-simple-switch-fullwidth) - var(--ox-simple-switch-thumbnail-size)))\n translateY(calc((var(--ox-simple-switch-fullheight) - var(--ox-simple-switch-thumbnail-size)) / 2));\n transform: translateX(calc(var(--ox-simple-switch-fullwidth) - var(--ox-simple-switch-thumbnail-size)))\n translateY(calc((var(--ox-simple-switch-fullheight) - var(--ox-simple-switch-thumbnail-size)) / 2));\n }\n\n /* Rounded sliders */\n span[round] {\n border-radius: calc(var(--ox-simple-switch-thumbnail-size) / 2);\n }\n\n span[round]:before {\n border-radius: calc((var(--ox-simple-switch-thumbnail-size) - 8px) / 2);\n }\n `\n\n @property({ type: Boolean }) round: boolean = false\n @property({ type: Boolean }) value: boolean = false\n @property({ type: Boolean }) disabled: boolean = false\n\n render() {\n return html`\n <label>\n <input type=\"checkbox\" .checked=${this.value} ?disabled=${this.disabled} />\n <span ?round=${this.round}></span>\n </label>\n `\n }\n\n firstUpdated() {\n this.renderRoot.addEventListener('change', (e: Event) => {\n e.preventDefault()\n e.stopPropagation()\n\n this.value = (e.target as HTMLInputElement)?.checked\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n composed: true,\n detail: this.value\n })\n )\n })\n }\n\n protected appendFormData({ formData }: FormDataEvent): void {\n this.name && formData.append(this.name, this.value ? 'true' : 'false')\n }\n}\n"]}
@@ -1,35 +0,0 @@
1
- import { PropertyValues } from 'lit';
2
- import { OxFormField } from './ox-form-field';
3
- type Card = {
4
- name: string;
5
- image: string;
6
- };
7
- export declare class OxSelectFloor extends OxFormField {
8
- static styles: import("lit").CSSResult[];
9
- cards: Card[];
10
- value?: string;
11
- bottomLimit: number;
12
- interval: number;
13
- private selectedIndex;
14
- private activeIndex;
15
- private carouselContainer;
16
- private isDragging;
17
- private lastMouseY;
18
- render(): import("lit-html").TemplateResult<1>;
19
- updated(changes: PropertyValues<this>): void;
20
- firstUpdated(): void;
21
- getClassForCard(index: number): "selected" | "compressed";
22
- isActive(index: number): boolean;
23
- handleWheel(event: WheelEvent): void;
24
- handlePointerDown(event: PointerEvent): void;
25
- handlePointerMove(event: PointerEvent): void;
26
- handlePointerUp(event: PointerEvent): void;
27
- handlePointerLeave(event: PointerEvent): void;
28
- private toggleActiveCard;
29
- private updateSelectedIndex;
30
- private scrollToSelectedCard;
31
- private selectCard;
32
- private notifySelection;
33
- private adjustCardHeight;
34
- }
35
- export {};
@@ -1,238 +0,0 @@
1
- import { __decorate } from "tslib";
2
- import { css, html } from 'lit';
3
- import { customElement, property, query, state } from 'lit/decorators.js';
4
- import { OxFormField } from './ox-form-field';
5
- let OxSelectFloor = class OxSelectFloor extends OxFormField {
6
- constructor() {
7
- super(...arguments);
8
- this.cards = [];
9
- this.bottomLimit = 70;
10
- this.interval = 0;
11
- this.selectedIndex = -1;
12
- this.activeIndex = null;
13
- this.isDragging = false;
14
- this.lastMouseY = 0;
15
- }
16
- static { this.styles = [
17
- css `
18
- :host {
19
- display: block;
20
- position: relative;
21
- overflow: hidden;
22
- height: 100%;
23
-
24
- --ox-select-floor-rotate-x: 60deg;
25
- --ox-select-floor-rotate-x-active: 40deg;
26
- --ox-select-floor-perspective: 1200px;
27
- }
28
-
29
- .carousel-container {
30
- position: relative;
31
- width: 100%;
32
- overflow: hidden;
33
- user-select: none;
34
- }
35
-
36
- .card {
37
- position: absolute;
38
- bottom: 0;
39
- width: 100%;
40
- background-color: white;
41
- transition:
42
- transform 0.3s ease,
43
- opacity 0.3s ease,
44
- box-shadow 0.3s ease,
45
- border 0.3s ease;
46
- transform-origin: bottom;
47
- transform: perspective(var(--ox-select-floor-perspective)) rotateX(var(--ox-select-floor-rotate-x));
48
- opacity: 0.5;
49
- border: 2px solid transparent;
50
- border-radius: 12px;
51
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
52
- }
53
-
54
- .card img {
55
- width: 100%;
56
- height: auto;
57
- display: block;
58
- pointer-events: none;
59
- border-radius: 12px;
60
- }
61
-
62
- .selected {
63
- opacity: 0.8;
64
- z-index: 1;
65
- border: 4px solid #3b82f6;
66
- box-shadow: 0 8px 16px rgba(59, 130, 246, 0.4);
67
- }
68
-
69
- .selected.active {
70
- opacity: 1;
71
- z-index: 2;
72
- transform: perspective(var(--ox-select-floor-perspective)) rotateX(var(--ox-select-floor-rotate-x-active));
73
- box-shadow: 0 12px 24px rgba(59, 130, 246, 0.4);
74
- }
75
-
76
- [template-container] {
77
- position: absolute;
78
- right: 10px;
79
- z-index: 1;
80
- }
81
- `
82
- ]; }
83
- render() {
84
- const length = this.cards.length;
85
- const cards = this.cards;
86
- const interval = this.interval;
87
- return html `
88
- <div
89
- class="carousel-container"
90
- @wheel=${interval ? () => { } : this.handleWheel}
91
- @pointerdown=${this.handlePointerDown}
92
- @pointermove=${this.handlePointerMove}
93
- @pointerup=${this.handlePointerUp}
94
- @pointerleave=${this.handlePointerLeave}
95
- style=${interval ? `height: ${interval * length + 200}px;` : 'height: 100%;'}
96
- >
97
- ${cards.map(({ image, name }, index) => {
98
- return html `
99
- <div
100
- class="card ${this.getClassForCard(index)} ${this.isActive(index) ? 'active' : ''}"
101
- style=${`bottom: ${interval ? interval * index + 'px' : (this.bottomLimit * index) / length + '%'};`}
102
- @click=${() => {
103
- this.selectCard(index);
104
- this.toggleActiveCard(index);
105
- }}
106
- >
107
- <img src="${image}" @load=${(e) => this.adjustCardHeight(e, index)} />
108
- </div>
109
- `;
110
- })}
111
- ${cards.map(({ image, name }, index) => {
112
- return html `
113
- <div
114
- style=${`bottom: ${interval ? interval * index + 'px' : (this.bottomLimit * index) / length + '%'};`}
115
- @click=${() => this.selectCard(index)}
116
- template-container
117
- >
118
- <slot name="template-${index}"></slot>
119
- </div>
120
- `;
121
- })}
122
- </div>
123
- `;
124
- }
125
- updated(changes) {
126
- if (changes.has('value')) {
127
- if (this.value) {
128
- this.selectedIndex = this.cards.findIndex(card => card.name == this.value);
129
- }
130
- else {
131
- this.selectedIndex = -1;
132
- }
133
- }
134
- }
135
- firstUpdated() {
136
- this.scrollToSelectedCard();
137
- }
138
- getClassForCard(index) {
139
- return index === this.selectedIndex ? 'selected' : 'compressed';
140
- }
141
- isActive(index) {
142
- return this.activeIndex === index;
143
- }
144
- handleWheel(event) {
145
- event.preventDefault();
146
- const delta = Math.sign(event.deltaY);
147
- this.updateSelectedIndex(this.selectedIndex + delta);
148
- }
149
- handlePointerDown(event) {
150
- event.preventDefault();
151
- this.isDragging = true;
152
- this.lastMouseY = event.clientY;
153
- }
154
- handlePointerMove(event) {
155
- if (!this.isDragging) {
156
- return;
157
- }
158
- event.preventDefault();
159
- const deltaY = event.clientY - this.lastMouseY;
160
- if (!this.lastMouseY) {
161
- this.lastMouseY = event.clientY;
162
- }
163
- if (Math.abs(deltaY) > 30) {
164
- this.lastMouseY = event.clientY;
165
- const direction = deltaY > 0 ? -1 : 1;
166
- this.updateSelectedIndex(this.selectedIndex + direction);
167
- }
168
- }
169
- handlePointerUp(event) {
170
- event.preventDefault();
171
- this.isDragging = false;
172
- }
173
- handlePointerLeave(event) {
174
- event.preventDefault();
175
- this.isDragging = false;
176
- }
177
- toggleActiveCard(index) {
178
- if (this.activeIndex === index) {
179
- this.activeIndex = null;
180
- }
181
- else {
182
- this.activeIndex = index;
183
- }
184
- }
185
- updateSelectedIndex(newIndex) {
186
- this.activeIndex = null;
187
- this.selectedIndex = Math.max(-1, Math.min(newIndex, this.cards.length - 1));
188
- this.scrollToSelectedCard();
189
- }
190
- scrollToSelectedCard() {
191
- const cardHeight = 320;
192
- const targetScrollTop = this.selectedIndex * cardHeight - (window.innerHeight / 2 - cardHeight / 2);
193
- this.carouselContainer.scrollTo({ top: targetScrollTop, behavior: 'smooth' });
194
- }
195
- selectCard(index) {
196
- this.selectedIndex = index;
197
- this.notifySelection();
198
- this.scrollToSelectedCard();
199
- }
200
- notifySelection() {
201
- this.value = this.selectedIndex !== -1 ? this.cards[this.selectedIndex]?.name : undefined;
202
- this.dispatchEvent(new CustomEvent('change', {
203
- detail: this.value
204
- }));
205
- }
206
- adjustCardHeight(e, index) {
207
- const imgElement = e.target;
208
- const aspectRatio = imgElement.naturalWidth / imgElement.naturalHeight;
209
- const newHeight = imgElement.offsetWidth / aspectRatio;
210
- imgElement.style.height = `${newHeight}px`;
211
- }
212
- };
213
- __decorate([
214
- property({ type: Array })
215
- ], OxSelectFloor.prototype, "cards", void 0);
216
- __decorate([
217
- property({ type: String })
218
- ], OxSelectFloor.prototype, "value", void 0);
219
- __decorate([
220
- property({ type: Number })
221
- ], OxSelectFloor.prototype, "bottomLimit", void 0);
222
- __decorate([
223
- property({ type: Number })
224
- ], OxSelectFloor.prototype, "interval", void 0);
225
- __decorate([
226
- state()
227
- ], OxSelectFloor.prototype, "selectedIndex", void 0);
228
- __decorate([
229
- state()
230
- ], OxSelectFloor.prototype, "activeIndex", void 0);
231
- __decorate([
232
- query('.carousel-container')
233
- ], OxSelectFloor.prototype, "carouselContainer", void 0);
234
- OxSelectFloor = __decorate([
235
- customElement('ox-select-floor')
236
- ], OxSelectFloor);
237
- export { OxSelectFloor };
238
- //# sourceMappingURL=ox-select-floor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ox-select-floor.js","sourceRoot":"","sources":["../../src/ox-select-floor.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, PropertyValues } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { OxFormField } from './ox-form-field'\n\ntype Card = {\n name: string\n image: string\n}\n\n@customElement('ox-select-floor')\nexport class OxSelectFloor extends OxFormField {\n static styles = [\n css`\n :host {\n display: block;\n position: relative;\n overflow: hidden;\n height: 100%;\n\n --ox-select-floor-rotate-x: 60deg;\n --ox-select-floor-rotate-x-active: 40deg;\n --ox-select-floor-perspective: 1200px;\n }\n\n .carousel-container {\n position: relative;\n width: 100%;\n overflow: hidden;\n user-select: none;\n }\n\n .card {\n position: absolute;\n bottom: 0;\n width: 100%;\n background-color: white;\n transition:\n transform 0.3s ease,\n opacity 0.3s ease,\n box-shadow 0.3s ease,\n border 0.3s ease;\n transform-origin: bottom;\n transform: perspective(var(--ox-select-floor-perspective)) rotateX(var(--ox-select-floor-rotate-x));\n opacity: 0.5;\n border: 2px solid transparent;\n border-radius: 12px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n }\n\n .card img {\n width: 100%;\n height: auto;\n display: block;\n pointer-events: none;\n border-radius: 12px;\n }\n\n .selected {\n opacity: 0.8;\n z-index: 1;\n border: 4px solid #3b82f6;\n box-shadow: 0 8px 16px rgba(59, 130, 246, 0.4);\n }\n\n .selected.active {\n opacity: 1;\n z-index: 2;\n transform: perspective(var(--ox-select-floor-perspective)) rotateX(var(--ox-select-floor-rotate-x-active));\n box-shadow: 0 12px 24px rgba(59, 130, 246, 0.4);\n }\n\n [template-container] {\n position: absolute;\n right: 10px;\n z-index: 1;\n }\n `\n ]\n\n @property({ type: Array }) cards: Card[] = []\n @property({ type: String }) value?: string\n @property({ type: Number }) bottomLimit = 70\n @property({ type: Number }) interval = 0\n\n @state() private selectedIndex = -1\n @state() private activeIndex: number | null = null\n @query('.carousel-container') private carouselContainer!: HTMLDivElement\n\n private isDragging = false\n private lastMouseY = 0\n\n render() {\n const length = this.cards.length\n const cards = this.cards\n const interval = this.interval\n\n return html`\n <div\n class=\"carousel-container\"\n @wheel=${interval ? () => {} : this.handleWheel}\n @pointerdown=${this.handlePointerDown}\n @pointermove=${this.handlePointerMove}\n @pointerup=${this.handlePointerUp}\n @pointerleave=${this.handlePointerLeave}\n style=${interval ? `height: ${interval * length + 200}px;` : 'height: 100%;'}\n >\n ${cards.map(({ image, name }, index) => {\n return html`\n <div\n class=\"card ${this.getClassForCard(index)} ${this.isActive(index) ? 'active' : ''}\"\n style=${`bottom: ${interval ? interval * index + 'px' : (this.bottomLimit * index) / length + '%'};`}\n @click=${() => {\n this.selectCard(index)\n this.toggleActiveCard(index)\n }}\n >\n <img src=\"${image}\" @load=${(e: Event) => this.adjustCardHeight(e, index)} />\n </div>\n `\n })}\n ${cards.map(({ image, name }, index) => {\n return html`\n <div\n style=${`bottom: ${interval ? interval * index + 'px' : (this.bottomLimit * index) / length + '%'};`}\n @click=${() => this.selectCard(index)}\n template-container\n >\n <slot name=\"template-${index}\"></slot>\n </div>\n `\n })}\n </div>\n `\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('value')) {\n if (this.value) {\n this.selectedIndex = this.cards.findIndex(card => card.name == this.value)\n } else {\n this.selectedIndex = -1\n }\n }\n }\n\n firstUpdated() {\n this.scrollToSelectedCard()\n }\n\n getClassForCard(index: number) {\n return index === this.selectedIndex ? 'selected' : 'compressed'\n }\n\n isActive(index: number): boolean {\n return this.activeIndex === index\n }\n\n handleWheel(event: WheelEvent) {\n event.preventDefault()\n const delta = Math.sign(event.deltaY)\n this.updateSelectedIndex(this.selectedIndex + delta)\n }\n\n handlePointerDown(event: PointerEvent) {\n event.preventDefault()\n\n this.isDragging = true\n this.lastMouseY = event.clientY\n }\n\n handlePointerMove(event: PointerEvent) {\n if (!this.isDragging) {\n return\n }\n\n event.preventDefault()\n\n const deltaY = event.clientY - this.lastMouseY\n\n if (!this.lastMouseY) {\n this.lastMouseY = event.clientY\n }\n\n if (Math.abs(deltaY) > 30) {\n this.lastMouseY = event.clientY\n const direction = deltaY > 0 ? -1 : 1\n this.updateSelectedIndex(this.selectedIndex + direction)\n }\n }\n\n handlePointerUp(event: PointerEvent) {\n event.preventDefault()\n this.isDragging = false\n }\n\n handlePointerLeave(event: PointerEvent) {\n event.preventDefault()\n\n this.isDragging = false\n }\n\n private toggleActiveCard(index: number) {\n if (this.activeIndex === index) {\n this.activeIndex = null\n } else {\n this.activeIndex = index\n }\n }\n\n private updateSelectedIndex(newIndex: number) {\n this.activeIndex = null\n\n this.selectedIndex = Math.max(-1, Math.min(newIndex, this.cards.length - 1))\n this.scrollToSelectedCard()\n }\n\n private scrollToSelectedCard() {\n const cardHeight = 320\n const targetScrollTop = this.selectedIndex * cardHeight - (window.innerHeight / 2 - cardHeight / 2)\n\n this.carouselContainer.scrollTo({ top: targetScrollTop, behavior: 'smooth' })\n }\n\n private selectCard(index: number) {\n this.selectedIndex = index\n this.notifySelection()\n this.scrollToSelectedCard()\n }\n\n private notifySelection() {\n this.value = this.selectedIndex !== -1 ? this.cards[this.selectedIndex]?.name : undefined\n\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: this.value\n })\n )\n }\n\n private adjustCardHeight(e: Event, index: number) {\n const imgElement = e.target as HTMLImageElement\n const aspectRatio = imgElement.naturalWidth / imgElement.naturalHeight\n const newHeight = imgElement.offsetWidth / aspectRatio\n imgElement.style.height = `${newHeight}px`\n }\n}\n"]}