@operato/input 8.0.0-alpha.2 → 8.0.0-alpha.21
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/CHANGELOG.md +56 -0
- package/dist/src/ox-input-file.js +3 -2
- package/dist/src/ox-input-file.js.map +1 -1
- package/dist/src/ox-input-signature.d.ts +4 -5
- package/dist/src/ox-input-signature.js +31 -20
- package/dist/src/ox-input-signature.js.map +1 -1
- package/dist/src/ox-select-floor.d.ts +39 -0
- package/dist/src/ox-select-floor.js +251 -0
- package/dist/src/ox-select-floor.js.map +1 -0
- package/dist/stories/image-for-select-floor.d.ts +1 -0
- package/dist/stories/image-for-select-floor.js +2 -0
- package/dist/stories/image-for-select-floor.js.map +1 -0
- package/dist/stories/{ox-input-/bsignature.stories.js → ox-input-signature.stories.js} +1 -1
- package/dist/stories/ox-input-signature.stories.js.map +1 -0
- package/dist/stories/ox-select-floor.stories.d.ts +41 -0
- package/dist/stories/ox-select-floor.stories.js +163 -0
- package/dist/stories/ox-select-floor.stories.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -4
- package/src/ox-input-file.ts +3 -2
- package/src/ox-input-signature.ts +30 -21
- package/src/ox-select-floor.ts +264 -0
- package/stories/image-for-select-floor.ts +2 -0
- package/stories/ox-select-floor.stories.ts +192 -0
- package/assets/images/icon-editor-gradient-direction.png +0 -0
- package/assets/images/icon-properties-label.png +0 -0
- package/assets/images/icon-properties-line-type.png +0 -0
- package/assets/images/icon-properties-table.png +0 -0
- package/dist/stories/ox-input-/bsignature.stories.js.map +0 -1
- /package/dist/stories/{ox-input-/bsignature.stories.d.ts" → ox-input-signature.stories.d.ts} +0 -0
- /package/stories/{ox-input-/bsignature.stories.ts" → ox-input-signature.stories.ts} +0 -0
package/CHANGELOG.md
CHANGED
@@ -3,6 +3,62 @@
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
5
5
|
|
6
|
+
## [8.0.0-alpha.21](https://github.com/hatiolab/operato/compare/v8.0.0-alpha.20...v8.0.0-alpha.21) (2024-10-05)
|
7
|
+
|
8
|
+
|
9
|
+
### :bug: Bug Fix
|
10
|
+
|
11
|
+
* support touch gesture for ox-select-floor ([217b1b6](https://github.com/hatiolab/operato/commit/217b1b6bf6415a893a9bb08524b546ec7a8fdca4))
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
## [8.0.0-alpha.20](https://github.com/hatiolab/operato/compare/v8.0.0-alpha.19...v8.0.0-alpha.20) (2024-10-04)
|
16
|
+
|
17
|
+
|
18
|
+
### :rocket: New Features
|
19
|
+
|
20
|
+
* ox-select-floor input component ([ad71891](https://github.com/hatiolab/operato/commit/ad718914cd44d16abc62109bfd17594dce43b349))
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
## [8.0.0-alpha.19](https://github.com/hatiolab/operato/compare/v8.0.0-alpha.18...v8.0.0-alpha.19) (2024-10-04)
|
25
|
+
|
26
|
+
|
27
|
+
### :rocket: New Features
|
28
|
+
|
29
|
+
* ox-select-floor input component ([3d5c53e](https://github.com/hatiolab/operato/commit/3d5c53e8ecac718b3713fc244c36739c977f5dcf))
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
## [8.0.0-alpha.10](https://github.com/hatiolab/operato/compare/v8.0.0-alpha.9...v8.0.0-alpha.10) (2024-09-18)
|
34
|
+
|
35
|
+
|
36
|
+
### :bug: Bug Fix
|
37
|
+
|
38
|
+
* remove unused files ([7c84a82](https://github.com/hatiolab/operato/commit/7c84a82e62897f0844423f6e2cb27d8f4ef0942f))
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
## [8.0.0-alpha.4](https://github.com/hatiolab/operato/compare/v8.0.0-alpha.3...v8.0.0-alpha.4) (2024-09-07)
|
43
|
+
|
44
|
+
|
45
|
+
### :bug: Bug Fix
|
46
|
+
|
47
|
+
* dataset components & styles ([be44acd](https://github.com/hatiolab/operato/commit/be44acde8f25980e5b27afc481a2c149f8c23dbd))
|
48
|
+
* style for ox-data-sample-view ([8facbab](https://github.com/hatiolab/operato/commit/8facbaba683accc6e4cf2375902a0b25cde31c49))
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
## [8.0.0-alpha.3](https://github.com/hatiolab/operato/compare/v8.0.0-alpha.2...v8.0.0-alpha.3) (2024-09-06)
|
53
|
+
|
54
|
+
|
55
|
+
### :bug: Bug Fix
|
56
|
+
|
57
|
+
* add ox-grist-editor/renderer-signature for dataset signature item ([b5dda5e](https://github.com/hatiolab/operato/commit/b5dda5ebe0afc8c9a3af73d9475bba160893155a))
|
58
|
+
* style for ox-data-sample-view ([f2a1266](https://github.com/hatiolab/operato/commit/f2a1266d9355b78a389e998129e16b8fba5ab480))
|
59
|
+
|
60
|
+
|
61
|
+
|
6
62
|
## [8.0.0-alpha.2](https://github.com/hatiolab/operato/compare/v8.0.0-alpha.1...v8.0.0-alpha.2) (2024-09-05)
|
7
63
|
|
8
64
|
|
@@ -81,12 +81,13 @@ let OxInputFile = class OxInputFile extends OxFormField {
|
|
81
81
|
border-bottom: var(--file-uploader-li-border-bottom);
|
82
82
|
font-size: var(--md-sys-typescale-label-large-size, 0.875rem);
|
83
83
|
color: var(--md-sys-color-on-primary-container);
|
84
|
+
display: flex;
|
85
|
+
align-items: center;
|
84
86
|
}
|
85
87
|
li md-icon {
|
86
|
-
float: right;
|
87
88
|
cursor: pointer;
|
88
|
-
margin: var(--file-uploader-li-icon-margin);
|
89
89
|
font-size: var(--icon-size-small);
|
90
|
+
margin-left: auto;
|
90
91
|
}
|
91
92
|
li md-icon:hover,
|
92
93
|
li md-icon:active {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"ox-input-file.js","sourceRoot":"","sources":["../../src/ox-input-file.ts"],"names":[],"mappings":"AAAA;;GAEG;;AAEH,OAAO,4BAA4B,CAAA;AAEnC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAkB,MAAM,KAAK,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGzC,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,WAAW;IAArC;;
|
1
|
+
{"version":3,"file":"ox-input-file.js","sourceRoot":"","sources":["../../src/ox-input-file.ts"],"names":[],"mappings":"AAAA;;GAEG;;AAEH,OAAO,4BAA4B,CAAA;AAEnC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAkB,MAAM,KAAK,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGzC,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,WAAW;IAArC;;QAmFuB,SAAI,GAAY,QAAQ,CAAA;QAExB,gBAAW,GAAY,kBAAkB,CAAA;QAErE,iBAAY,GAAY,KAAK,CAAA;QAE7B,mBAAc,GAAY,KAAK,CAAA;IAwGjC,CAAC;aAhMQ,WAAM,GAAG;QACd,eAAe;QACf,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2EF;KACF,AA9EY,CA8EZ;IAcD,MAAM;QACJ,IAAI,KAAK,GAAW,IAAI,CAAC,KAAK,IAAI,EAAE,CAAA;QAEpC,OAAO,IAAI,CAAA;iBACE,IAAI,CAAC,IAAI,IAAI,QAAQ;;cAExB,IAAI,CAAC,WAAW,IAAI,kBAAkB;;;;;iBAKnC,IAAI,CAAC,MAAM;oBACR,IAAI,CAAC,QAAQ;;;kBAGf,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;oBAClC,IAAI,CAAC,QAAQ;;;gCAGD,IAAI,CAAC,KAAK,IAAI,cAAc;;QAEpD,CAAC,IAAI,CAAC,YAAY,IAAI,KAAK,EAAE,MAAM;YACnC,CAAC,CAAC,IAAI,CAAA;cACA,KAAK,CAAC,GAAG,CACT,IAAI,CAAC,EAAE,CAAC,IAAI,CAAA;;sBAEJ,IAAI,CAAC,IAAI;;6BAEF,CAAC,CAAQ,EAAE,EAAE;gBACpB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAClB,OAAM;gBACR,CAAC;gBACD,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;gBACpC,IAAI,CAAC,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,CAAA;gBACvB,IAAI,CAAC,aAAa,EAAE,CAAA;YACtB,CAAC;;;;eAIN,CACF;gBACG;YACR,CAAC,CAAC,IAAI,CAAA,EAAE;KACX,CAAA;IACH,CAAC;IAED,OAAO,CAAC,OAA6B;QACnC,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;YAC3D,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC;IAED,YAAY;QACV,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAExB,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,CAAC,CAAQ,EAAE,EAAE;YAC9C,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,OAAM;YACR,CAAC;YAED,MAAM,MAAM,GAAI,CAAiB,CAAC,MAAM,CAAA;YACxC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;YAElE,IAAI,CAAC,aAAa,EAAE,CAAA;QACtB,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,SAAS,CAAC,KAAK,GAAG,EAAE,CAAA;QACzB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAA;QAEf,IAAI,CAAC,aAAa,EAAE,CAAA;IACtB,CAAC;IAED,cAAc,CAAC,CAAQ;QACrB,MAAM,SAAS,GAAG,CAAC,CAAC,aAAiC,CAAA;QACrD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAA;QAE9B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,cAAc;YAC9B,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAiB,CAAC,CAAC;YACxD,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAiB,CAAC,CAAC,CAAA;QAEhD,SAAS,CAAC,KAAK,GAAG,IAAI,CAAA;QAEtB,IAAI,CAAC,aAAa,EAAE,CAAA;IACtB,CAAC;IAED,aAAa;QACX,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,QAAQ,EAAE;YACxB,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,IAAI,CAAC,KAAK;SACnB,CAAC,CACH,CAAA;IACH,CAAC;;AA/G4B;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;6CAAmB;AACnB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;2CAAgB;AACf;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;yCAAyB;AACxB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;0CAAe;AACd;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gDAA0C;AAErE;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;iDAC1C;AAE7B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC;mDAC1C;AAET;IAArB,KAAK,CAAC,aAAa,CAAC;8CAA6B;AA3FvC,WAAW;IADvB,aAAa,CAAC,eAAe,CAAC;GAClB,WAAW,CAiMvB","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@material/web/icon/icon.js'\n\nimport { css, html, PropertyValues } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport { ScrollbarStyles } from '@operato/styles'\nimport { FileDropHelper } from '@operato/utils'\n\nimport { OxFormField } from './ox-form-field.js'\n\n@customElement('ox-input-file')\nexport class OxInputFile extends OxFormField {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n border-radius: var(--md-sys-shape-corner-small);\n align-items: center;\n justify-content: center;\n padding: var(--padding-default, 9px);\n min-height: 100px;\n text-transform: capitalize;\n\n border: 1px dashed var(--md-sys-color-outline-variant);\n background-color: var(--md-sys-color-surface);\n font-size: var(--md-sys-typescale-label-large-size, 0.875rem);\n }\n :host > span {\n color: var(--md-sys-color-primary);\n font-weight: var(--md-sys-typescale-label-medium-weight, var(--md-ref-typeface-weight-medium, 500));\n }\n\n :host > md-icon {\n color: var(--md-sys-color-primary);\n --md-icon-size: var(--file-uploader-icon-size, 36px);\n }\n\n :host(.candrop) {\n background-color: var(--md-sys-color-primary-fixed);\n border: 1px dashed var(--md-sys-color-primary-fixed-dim);\n }\n\n #input-file {\n display: none;\n }\n\n label {\n position: relative;\n width: auto;\n border: none;\n text-transform: capitalize;\n\n padding: var(--file-uploader-label-padding);\n border-radius: var(--file-uploader-label-border-radius);\n font-size: var(--md-sys-typescale-label-large-size, 0.875rem);\n color: var(--md-sys-color-on-surface-variant);\n }\n\n ul {\n max-width: 500px;\n width: 100%;\n list-style: none;\n margin: 5px 0 0 0;\n padding: 0;\n max-height: 46px;\n overflow: auto;\n background-color: var(--md-sys-color-on-primary);\n }\n li {\n text-align: left;\n\n padding: 3px 5px 2px 5px;\n border-bottom: var(--file-uploader-li-border-bottom);\n font-size: var(--md-sys-typescale-label-large-size, 0.875rem);\n color: var(--md-sys-color-on-primary-container);\n display: flex;\n align-items: center;\n }\n li md-icon {\n cursor: pointer;\n font-size: var(--icon-size-small);\n margin-left: auto;\n }\n li md-icon:hover,\n li md-icon:active {\n color: var(--md-sys-color-error);\n }\n `\n ]\n\n @property({ type: Boolean }) multiple?: boolean\n @property({ type: String }) accept?: string\n @property({ type: String }) icon?: string = 'upload'\n @property({ type: String }) label?: string\n @property({ type: String }) description?: string = 'drop files here!'\n @property({ type: Boolean, reflect: true, attribute: 'hide-filelist' })\n hideFileList: boolean = false\n @property({ type: Boolean, reflect: true, attribute: 'attach-filelist' })\n attachFileList: boolean = false\n\n @query('#input-file') fileInput!: HTMLInputElement\n\n render() {\n var files: File[] = this.value || []\n\n return html`\n <md-icon>${this.icon || 'upload'}</md-icon>\n\n <span>${this.description || 'drop files here!'}</span>\n\n <input\n id=\"input-file\"\n type=\"file\"\n accept=${this.accept}\n ?multiple=${this.multiple}\n hidden\n capture=\"environment\"\n @change=${(e: Event) => this._onChangeValue(e)}\n ?disabled=${this.disabled}\n />\n\n <label for=\"input-file\">${this.label || 'select files'}</label>\n\n ${!this.hideFileList && files?.length\n ? html` <ul>\n ${files.map(\n file => html`\n <li>\n - ${file.name}\n <md-icon\n @click=${(e: Event) => {\n if (this.disabled) {\n return\n }\n files.splice(files.indexOf(file), 1)\n this.value = [...files]\n this._notifyChange()\n }}\n >delete_outline</md-icon\n >\n </li>\n `\n )}\n </ul>`\n : html``}\n `\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('value') && !(this.value instanceof Array)) {\n this.value = !this.value ? [] : [this.value]\n }\n }\n\n firstUpdated() {\n FileDropHelper.set(this)\n\n this.addEventListener('file-drop', (e: Event) => {\n if (this.disabled) {\n return\n }\n\n const detail = (e as CustomEvent).detail\n this.value = this.multiple ? detail : detail[0] ? [detail[0]] : []\n\n this._notifyChange()\n })\n }\n\n get files() {\n return this.value\n }\n\n reset() {\n this.fileInput.value = ''\n this.value = []\n\n this._notifyChange()\n }\n\n _onChangeValue(e: Event) {\n const fileInput = e.currentTarget as HTMLInputElement\n const files = this.value || []\n\n this.value = this.attachFileList\n ? [...files, ...Array.from(fileInput.files as FileList)]\n : [...Array.from(fileInput.files as FileList)]\n\n fileInput.files = null\n\n this._notifyChange()\n }\n\n _notifyChange() {\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n composed: true,\n detail: this.value\n })\n )\n }\n}\n"]}
|
@@ -2,13 +2,12 @@ import '@material/web/icon/icon.js';
|
|
2
2
|
import { OxFormField } from './ox-form-field.js';
|
3
3
|
export declare class OxInputSignature extends OxFormField {
|
4
4
|
static styles: import("lit").CSSResult[];
|
5
|
-
isDrawing: boolean;
|
6
5
|
value: string | null;
|
7
|
-
private ctx;
|
8
|
-
private canvas;
|
9
|
-
private dialog;
|
10
6
|
private previewDiv;
|
11
|
-
private
|
7
|
+
private dialog;
|
8
|
+
private canvas;
|
9
|
+
private ctx;
|
10
|
+
private isDrawing;
|
12
11
|
render(): import("lit-html").TemplateResult<1>;
|
13
12
|
firstUpdated(): void;
|
14
13
|
openDialog(): void;
|
@@ -1,38 +1,30 @@
|
|
1
1
|
import { __decorate } from "tslib";
|
2
2
|
import '@material/web/icon/icon.js';
|
3
3
|
import { css, html } from 'lit';
|
4
|
-
import { customElement, property } from 'lit/decorators.js';
|
4
|
+
import { customElement, property, query } from 'lit/decorators.js';
|
5
5
|
import { OxFormField } from './ox-form-field.js';
|
6
6
|
let OxInputSignature = class OxInputSignature extends OxFormField {
|
7
7
|
constructor() {
|
8
8
|
super(...arguments);
|
9
|
-
this.isDrawing = false;
|
10
9
|
this.value = null;
|
10
|
+
this.isDrawing = false;
|
11
11
|
}
|
12
12
|
static { this.styles = [
|
13
13
|
css `
|
14
14
|
:host {
|
15
|
-
position: relative;
|
16
|
-
box-sizing: border-box;
|
17
|
-
|
18
15
|
display: flex;
|
19
16
|
flex-direction: column;
|
20
|
-
|
21
|
-
|
22
|
-
padding: var(--padding-default, 9px);
|
23
|
-
min-height: 100px;
|
24
|
-
text-transform: capitalize;
|
17
|
+
min-height: var(--signature-min-height, 80px);
|
18
|
+
min-width: var(--signature-min-width, 120px);
|
25
19
|
|
26
|
-
|
27
|
-
background-color: var(--md-sys-color-background);
|
28
|
-
font: var(--file-uploader-font) !important;
|
29
|
-
color: var(--file-uploader-color);
|
20
|
+
background-color: var(--signature-background-color, white);
|
30
21
|
|
31
22
|
overflow: hidden;
|
32
23
|
}
|
33
24
|
|
34
25
|
.signature-preview {
|
35
26
|
flex: 1;
|
27
|
+
align-self: stretch;
|
36
28
|
|
37
29
|
border: 1px solid var(--md-sys-color-outline);
|
38
30
|
background-size: contain;
|
@@ -48,6 +40,13 @@ let OxInputSignature = class OxInputSignature extends OxFormField {
|
|
48
40
|
|
49
41
|
.controls {
|
50
42
|
margin-top: 10px;
|
43
|
+
display: flex;
|
44
|
+
flex-direction: row;
|
45
|
+
gap: var(--spacing-medium);
|
46
|
+
}
|
47
|
+
|
48
|
+
.filler {
|
49
|
+
flex: 1;
|
51
50
|
}
|
52
51
|
`
|
53
52
|
]; }
|
@@ -69,6 +68,7 @@ let OxInputSignature = class OxInputSignature extends OxFormField {
|
|
69
68
|
></canvas>
|
70
69
|
<div class="controls">
|
71
70
|
<button @click="${this.clearCanvas}">Clear</button>
|
71
|
+
<div class="filler"></div>
|
72
72
|
<button @click="${this.saveSignature}">Save</button>
|
73
73
|
<button @click="${this.closeDialog}">Close</button>
|
74
74
|
</div>
|
@@ -76,9 +76,6 @@ let OxInputSignature = class OxInputSignature extends OxFormField {
|
|
76
76
|
`;
|
77
77
|
}
|
78
78
|
firstUpdated() {
|
79
|
-
this.previewDiv = this.shadowRoot.querySelector('.signature-preview');
|
80
|
-
this.dialog = this.shadowRoot.querySelector('dialog');
|
81
|
-
this.canvas = this.dialog.querySelector('canvas');
|
82
79
|
this.ctx = this.canvas.getContext('2d');
|
83
80
|
this.ctx.strokeStyle = '#000';
|
84
81
|
this.ctx.lineWidth = 2;
|
@@ -91,6 +88,14 @@ let OxInputSignature = class OxInputSignature extends OxFormField {
|
|
91
88
|
if (this.disabled)
|
92
89
|
return;
|
93
90
|
this.dialog.showModal();
|
91
|
+
// 다이아로그가 열릴 때 현재 value를 캔버스에 그리기
|
92
|
+
if (this.value) {
|
93
|
+
const img = new Image();
|
94
|
+
img.onload = () => {
|
95
|
+
this.ctx.drawImage(img, 0, 0, this.canvas.width, this.canvas.height);
|
96
|
+
};
|
97
|
+
img.src = this.value;
|
98
|
+
}
|
94
99
|
}
|
95
100
|
closeDialog() {
|
96
101
|
this.dialog.close();
|
@@ -145,12 +150,18 @@ let OxInputSignature = class OxInputSignature extends OxFormField {
|
|
145
150
|
}));
|
146
151
|
}
|
147
152
|
};
|
148
|
-
__decorate([
|
149
|
-
property({ type: Boolean })
|
150
|
-
], OxInputSignature.prototype, "isDrawing", void 0);
|
151
153
|
__decorate([
|
152
154
|
property({ type: String })
|
153
155
|
], OxInputSignature.prototype, "value", void 0);
|
156
|
+
__decorate([
|
157
|
+
query('.signature-preview')
|
158
|
+
], OxInputSignature.prototype, "previewDiv", void 0);
|
159
|
+
__decorate([
|
160
|
+
query('dialog')
|
161
|
+
], OxInputSignature.prototype, "dialog", void 0);
|
162
|
+
__decorate([
|
163
|
+
query('canvas')
|
164
|
+
], OxInputSignature.prototype, "canvas", void 0);
|
154
165
|
OxInputSignature = __decorate([
|
155
166
|
customElement('ox-input-signature')
|
156
167
|
], OxInputSignature);
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"ox-input-signature.js","sourceRoot":"","sources":["../../src/ox-input-signature.ts"],"names":[],"mappings":";AAAA,OAAO,4BAA4B,CAAA;AAEnC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAW,MAAM,KAAK,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;
|
1
|
+
{"version":3,"file":"ox-input-signature.js","sourceRoot":"","sources":["../../src/ox-input-signature.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, nothing } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { OxFormField } from './ox-form-field.js'\n\n@customElement('ox-input-signature')\nexport class OxInputSignature extends OxFormField {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n min-height: var(--signature-min-height, 80px);\n min-width: var(--signature-min-width, 120px);\n\n background-color: var(--signature-background-color, white);\n\n overflow: hidden;\n }\n\n .signature-preview {\n flex: 1;\n align-self: stretch;\n\n border: 1px solid var(--md-sys-color-outline);\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n }\n\n dialog canvas {\n width: 100%;\n height: 100%;\n border: 1px solid var(--md-sys-color-outline);\n }\n\n .controls {\n margin-top: 10px;\n display: flex;\n flex-direction: row;\n gap: var(--spacing-medium);\n }\n\n .filler {\n flex: 1;\n }\n `\n ]\n\n @property({ type: String }) value: string | null = null\n\n @query('.signature-preview')\n private previewDiv!: HTMLDivElement\n @query('dialog')\n private dialog!: HTMLDialogElement\n @query('canvas')\n private canvas!: HTMLCanvasElement\n\n private ctx!: CanvasRenderingContext2D\n private isDrawing = false\n\n render() {\n return html`\n <div class=\"signature-preview\" @click=${this.openDialog}></div>\n\n <dialog>\n <canvas\n width=\"800\"\n height=\"400\"\n @mousedown=${this.startDrawing}\n @mouseup=${this.stopDrawing}\n @mousemove=${this.draw}\n @mouseleave=${this.stopDrawing}\n @touchstart=${this.startDrawing}\n @touchend=${this.stopDrawing}\n @touchmove=${this.draw}\n ></canvas>\n <div class=\"controls\">\n <button @click=\"${this.clearCanvas}\">Clear</button>\n <div class=\"filler\"></div>\n <button @click=\"${this.saveSignature}\">Save</button>\n <button @click=\"${this.closeDialog}\">Close</button>\n </div>\n </dialog>\n `\n }\n\n firstUpdated() {\n this.ctx = this.canvas.getContext('2d')!\n this.ctx.strokeStyle = '#000'\n this.ctx.lineWidth = 2\n\n // 처음 로딩 시 서명 데이터를 미리보기 div에 표시\n if (this.value) {\n this.loadSignature(this.value)\n }\n }\n\n openDialog() {\n if (this.disabled) return\n this.dialog.showModal()\n\n // 다이아로그가 열릴 때 현재 value를 캔버스에 그리기\n if (this.value) {\n const img = new Image()\n img.onload = () => {\n this.ctx.drawImage(img, 0, 0, this.canvas.width, this.canvas.height)\n }\n img.src = this.value\n }\n }\n\n closeDialog() {\n this.dialog.close()\n }\n\n startDrawing(event: MouseEvent | TouchEvent) {\n if (this.disabled) {\n return\n }\n\n this.isDrawing = true\n this.ctx.beginPath()\n const position = this.getEventPosition(event)\n this.ctx.moveTo(position.x, position.y)\n }\n\n stopDrawing() {\n this.isDrawing = false\n }\n\n draw(event: MouseEvent | TouchEvent) {\n if (!this.isDrawing) return\n const position = this.getEventPosition(event)\n this.ctx.lineTo(position.x, position.y)\n this.ctx.stroke()\n }\n\n clearCanvas() {\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)\n }\n\n saveSignature() {\n this.value = this.canvas.toDataURL()\n this._notifyChange()\n this.previewDiv.style.backgroundImage = `url(${this.value})`\n this.closeDialog()\n }\n\n loadSignature(dataUrl: string) {\n this.previewDiv.style.backgroundImage = `url(${dataUrl})`\n }\n\n getEventPosition(event: MouseEvent | TouchEvent) {\n const rect = this.canvas.getBoundingClientRect()\n\n // 캔버스의 실제 크기와 CSS 크기 간의 비율을 계산\n const scaleX = this.canvas.width / rect.width\n const scaleY = this.canvas.height / rect.height\n\n // 실제 좌표 계산\n const isTouchEvent = event instanceof TouchEvent\n const x = (isTouchEvent ? event.touches[0].clientX - rect.left : (event as MouseEvent).clientX - rect.left) * scaleX\n const y = (isTouchEvent ? event.touches[0].clientY - rect.top : (event as MouseEvent).clientY - rect.top) * scaleY\n\n return { x, y }\n }\n\n _notifyChange() {\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n composed: true,\n detail: this.value\n })\n )\n }\n}\n"]}
|
@@ -0,0 +1,39 @@
|
|
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
|
+
private selectedIndex;
|
13
|
+
private activeIndex;
|
14
|
+
private carouselContainer;
|
15
|
+
private isDragging;
|
16
|
+
private lastTouchY;
|
17
|
+
private lastMouseY;
|
18
|
+
private startY;
|
19
|
+
render(): import("lit-html").TemplateResult<1>;
|
20
|
+
updated(changes: PropertyValues<this>): void;
|
21
|
+
firstUpdated(): void;
|
22
|
+
getClassForCard(index: number): "selected" | "compressed";
|
23
|
+
isActive(index: number): boolean;
|
24
|
+
handleWheel(event: WheelEvent): void;
|
25
|
+
handleTouchStart(event: TouchEvent): void;
|
26
|
+
handleTouchMove(event: TouchEvent): void;
|
27
|
+
handleTouchEnd(): void;
|
28
|
+
handleMouseDown(event: MouseEvent): void;
|
29
|
+
handleMouseMove(event: MouseEvent): void;
|
30
|
+
handleMouseUp(): void;
|
31
|
+
handleMouseLeave(): void;
|
32
|
+
private toggleActiveCard;
|
33
|
+
private updateSelectedIndex;
|
34
|
+
private scrollToSelectedCard;
|
35
|
+
private selectCard;
|
36
|
+
private notifySelection;
|
37
|
+
private adjustCardHeight;
|
38
|
+
}
|
39
|
+
export {};
|
@@ -0,0 +1,251 @@
|
|
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.selectedIndex = -1;
|
11
|
+
this.activeIndex = null;
|
12
|
+
this.isDragging = false;
|
13
|
+
this.lastTouchY = 0;
|
14
|
+
this.lastMouseY = 0;
|
15
|
+
this.startY = 0;
|
16
|
+
}
|
17
|
+
static { this.styles = [
|
18
|
+
css `
|
19
|
+
:host {
|
20
|
+
display: block;
|
21
|
+
position: relative;
|
22
|
+
overflow: hidden;
|
23
|
+
height: 100%;
|
24
|
+
|
25
|
+
--ox-select-floor-rotate-x: 60deg;
|
26
|
+
--ox-select-floor-rotate-x-active: 40deg;
|
27
|
+
--ox-select-floor-perspective: 1200px;
|
28
|
+
}
|
29
|
+
|
30
|
+
.carousel-container {
|
31
|
+
position: relative;
|
32
|
+
height: 100%;
|
33
|
+
width: 100%;
|
34
|
+
overflow: hidden;
|
35
|
+
user-select: none;
|
36
|
+
}
|
37
|
+
|
38
|
+
.card {
|
39
|
+
position: absolute;
|
40
|
+
bottom: 0;
|
41
|
+
width: 100%;
|
42
|
+
background-color: white;
|
43
|
+
transition:
|
44
|
+
transform 0.3s ease,
|
45
|
+
opacity 0.3s ease,
|
46
|
+
box-shadow 0.3s ease,
|
47
|
+
border 0.3s ease;
|
48
|
+
transform-origin: bottom;
|
49
|
+
transform: perspective(var(--ox-select-floor-perspective)) rotateX(var(--ox-select-floor-rotate-x));
|
50
|
+
opacity: 0.5;
|
51
|
+
border: 2px solid transparent;
|
52
|
+
border-radius: 12px;
|
53
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
54
|
+
}
|
55
|
+
|
56
|
+
.card img {
|
57
|
+
width: 100%;
|
58
|
+
height: auto;
|
59
|
+
display: block;
|
60
|
+
pointer-events: none;
|
61
|
+
border-radius: 12px;
|
62
|
+
}
|
63
|
+
|
64
|
+
.selected {
|
65
|
+
opacity: 0.8;
|
66
|
+
z-index: 1;
|
67
|
+
border: 4px solid #3b82f6;
|
68
|
+
box-shadow: 0 8px 16px rgba(59, 130, 246, 0.4);
|
69
|
+
}
|
70
|
+
|
71
|
+
.selected.active {
|
72
|
+
opacity: 1;
|
73
|
+
z-index: 2;
|
74
|
+
transform: perspective(var(--ox-select-floor-perspective)) rotateX(var(--ox-select-floor-rotate-x-active));
|
75
|
+
box-shadow: 0 12px 24px rgba(59, 130, 246, 0.4);
|
76
|
+
}
|
77
|
+
|
78
|
+
[template-container] {
|
79
|
+
position: absolute;
|
80
|
+
right: 10px;
|
81
|
+
z-index: 1;
|
82
|
+
}
|
83
|
+
`
|
84
|
+
]; }
|
85
|
+
render() {
|
86
|
+
const length = this.cards.length;
|
87
|
+
const cards = this.cards;
|
88
|
+
return html `
|
89
|
+
<div
|
90
|
+
class="carousel-container"
|
91
|
+
@wheel=${this.handleWheel}
|
92
|
+
@mousedown=${this.handleMouseDown}
|
93
|
+
@mousemove=${this.handleMouseMove}
|
94
|
+
@mouseup=${this.handleMouseUp}
|
95
|
+
@mouseleave=${this.handleMouseLeave}
|
96
|
+
@touchstart=${this.handleTouchStart}
|
97
|
+
@touchmove=${this.handleTouchMove}
|
98
|
+
@touchend=${this.handleTouchEnd}
|
99
|
+
>
|
100
|
+
${cards.map(({ image, name }, index) => {
|
101
|
+
return html `
|
102
|
+
<div
|
103
|
+
class="card ${this.getClassForCard(index)} ${this.isActive(index) ? 'active' : ''}"
|
104
|
+
style="bottom: ${(this.bottomLimit * index) / length}%;"
|
105
|
+
@click=${() => this.selectCard(index)}
|
106
|
+
@tap=${() => this.toggleActiveCard(index)}
|
107
|
+
>
|
108
|
+
<img src="${image}" @load=${(e) => this.adjustCardHeight(e, index)} />
|
109
|
+
</div>
|
110
|
+
`;
|
111
|
+
})}
|
112
|
+
${cards.map(({ image, name }, index) => {
|
113
|
+
return html `
|
114
|
+
<div
|
115
|
+
style="bottom: ${(this.bottomLimit * index) / length}%;"
|
116
|
+
@click=${() => this.selectCard(index)}
|
117
|
+
template-container
|
118
|
+
>
|
119
|
+
<slot name="template-${index}"></slot>
|
120
|
+
</div>
|
121
|
+
`;
|
122
|
+
})}
|
123
|
+
</div>
|
124
|
+
`;
|
125
|
+
}
|
126
|
+
updated(changes) {
|
127
|
+
if (changes.has('value')) {
|
128
|
+
if (this.value) {
|
129
|
+
this.selectedIndex = this.cards.findIndex(card => card.name == this.value);
|
130
|
+
}
|
131
|
+
else {
|
132
|
+
this.selectedIndex = -1;
|
133
|
+
}
|
134
|
+
}
|
135
|
+
}
|
136
|
+
firstUpdated() {
|
137
|
+
this.scrollToSelectedCard();
|
138
|
+
}
|
139
|
+
getClassForCard(index) {
|
140
|
+
return index === this.selectedIndex ? 'selected' : 'compressed';
|
141
|
+
}
|
142
|
+
isActive(index) {
|
143
|
+
return this.activeIndex === index;
|
144
|
+
}
|
145
|
+
handleWheel(event) {
|
146
|
+
event.preventDefault();
|
147
|
+
const delta = Math.sign(event.deltaY);
|
148
|
+
this.updateSelectedIndex(this.selectedIndex + delta);
|
149
|
+
}
|
150
|
+
handleTouchStart(event) {
|
151
|
+
this.lastTouchY = event.touches[0].clientY;
|
152
|
+
this.startY = this.lastTouchY;
|
153
|
+
}
|
154
|
+
handleTouchMove(event) {
|
155
|
+
const touch = event.touches[0];
|
156
|
+
const deltaY = touch.clientY - this.lastMouseY;
|
157
|
+
if (!this.lastMouseY) {
|
158
|
+
this.lastMouseY = touch.clientY;
|
159
|
+
}
|
160
|
+
if (Math.abs(deltaY) > 30) {
|
161
|
+
this.lastMouseY = touch.clientY;
|
162
|
+
const direction = deltaY > 0 ? -1 : 1;
|
163
|
+
this.updateSelectedIndex(this.selectedIndex + direction);
|
164
|
+
}
|
165
|
+
}
|
166
|
+
handleTouchEnd() {
|
167
|
+
this.isDragging = false;
|
168
|
+
}
|
169
|
+
handleMouseDown(event) {
|
170
|
+
this.isDragging = true;
|
171
|
+
this.lastMouseY = event.clientY;
|
172
|
+
}
|
173
|
+
handleMouseMove(event) {
|
174
|
+
if (!this.isDragging) {
|
175
|
+
return;
|
176
|
+
}
|
177
|
+
const deltaY = event.clientY - this.lastMouseY;
|
178
|
+
if (!this.lastMouseY) {
|
179
|
+
this.lastMouseY = event.clientY;
|
180
|
+
}
|
181
|
+
if (Math.abs(deltaY) > 30) {
|
182
|
+
this.lastMouseY = event.clientY;
|
183
|
+
const direction = deltaY > 0 ? -1 : 1;
|
184
|
+
this.updateSelectedIndex(this.selectedIndex + direction);
|
185
|
+
}
|
186
|
+
}
|
187
|
+
handleMouseUp() {
|
188
|
+
this.isDragging = false;
|
189
|
+
}
|
190
|
+
handleMouseLeave() {
|
191
|
+
this.isDragging = false;
|
192
|
+
}
|
193
|
+
toggleActiveCard(index) {
|
194
|
+
if (this.activeIndex === index) {
|
195
|
+
this.activeIndex = null;
|
196
|
+
}
|
197
|
+
else {
|
198
|
+
this.activeIndex = index;
|
199
|
+
}
|
200
|
+
}
|
201
|
+
updateSelectedIndex(newIndex) {
|
202
|
+
this.activeIndex = null;
|
203
|
+
this.selectedIndex = Math.max(-1, Math.min(newIndex, this.cards.length - 1));
|
204
|
+
this.scrollToSelectedCard();
|
205
|
+
}
|
206
|
+
scrollToSelectedCard() {
|
207
|
+
const cardHeight = 320;
|
208
|
+
const targetScrollTop = this.selectedIndex * cardHeight - (window.innerHeight / 2 - cardHeight / 2);
|
209
|
+
this.carouselContainer.scrollTo({ top: targetScrollTop, behavior: 'smooth' });
|
210
|
+
}
|
211
|
+
selectCard(index) {
|
212
|
+
this.selectedIndex = index;
|
213
|
+
this.notifySelection();
|
214
|
+
this.scrollToSelectedCard();
|
215
|
+
}
|
216
|
+
notifySelection() {
|
217
|
+
this.value = this.selectedIndex !== -1 ? this.cards[this.selectedIndex]?.name : undefined;
|
218
|
+
this.dispatchEvent(new CustomEvent('change', {
|
219
|
+
detail: this.value
|
220
|
+
}));
|
221
|
+
}
|
222
|
+
adjustCardHeight(e, index) {
|
223
|
+
const imgElement = e.target;
|
224
|
+
const aspectRatio = imgElement.naturalWidth / imgElement.naturalHeight;
|
225
|
+
const newHeight = imgElement.offsetWidth / aspectRatio;
|
226
|
+
imgElement.style.height = `${newHeight}px`;
|
227
|
+
}
|
228
|
+
};
|
229
|
+
__decorate([
|
230
|
+
property({ type: Array })
|
231
|
+
], OxSelectFloor.prototype, "cards", void 0);
|
232
|
+
__decorate([
|
233
|
+
property({ type: String })
|
234
|
+
], OxSelectFloor.prototype, "value", void 0);
|
235
|
+
__decorate([
|
236
|
+
property({ type: Number })
|
237
|
+
], OxSelectFloor.prototype, "bottomLimit", void 0);
|
238
|
+
__decorate([
|
239
|
+
state()
|
240
|
+
], OxSelectFloor.prototype, "selectedIndex", void 0);
|
241
|
+
__decorate([
|
242
|
+
state()
|
243
|
+
], OxSelectFloor.prototype, "activeIndex", void 0);
|
244
|
+
__decorate([
|
245
|
+
query('.carousel-container')
|
246
|
+
], OxSelectFloor.prototype, "carouselContainer", void 0);
|
247
|
+
OxSelectFloor = __decorate([
|
248
|
+
customElement('ox-select-floor')
|
249
|
+
], OxSelectFloor);
|
250
|
+
export { OxSelectFloor };
|
251
|
+
//# sourceMappingURL=ox-select-floor.js.map
|
@@ -0,0 +1 @@
|
|
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 height: 100%;\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\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 lastTouchY = 0\n private lastMouseY = 0\n private startY = 0\n\n render() {\n const length = this.cards.length\n const cards = this.cards\n\n return html`\n <div\n class=\"carousel-container\"\n @wheel=${this.handleWheel}\n @mousedown=${this.handleMouseDown}\n @mousemove=${this.handleMouseMove}\n @mouseup=${this.handleMouseUp}\n @mouseleave=${this.handleMouseLeave}\n @touchstart=${this.handleTouchStart}\n @touchmove=${this.handleTouchMove}\n @touchend=${this.handleTouchEnd}\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: ${(this.bottomLimit * index) / length}%;\"\n @click=${() => this.selectCard(index)}\n @tap=${() => this.toggleActiveCard(index)}\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: ${(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 handleTouchStart(event: TouchEvent) {\n this.lastTouchY = event.touches[0].clientY\n this.startY = this.lastTouchY\n }\n\n handleTouchMove(event: TouchEvent) {\n const touch = event.touches[0]\n const deltaY = touch.clientY - this.lastMouseY\n\n if (!this.lastMouseY) {\n this.lastMouseY = touch.clientY\n }\n\n if (Math.abs(deltaY) > 30) {\n this.lastMouseY = touch.clientY\n const direction = deltaY > 0 ? -1 : 1\n this.updateSelectedIndex(this.selectedIndex + direction)\n }\n }\n\n handleTouchEnd() {\n this.isDragging = false\n }\n\n handleMouseDown(event: MouseEvent) {\n this.isDragging = true\n this.lastMouseY = event.clientY\n }\n\n handleMouseMove(event: MouseEvent) {\n if (!this.isDragging) {\n return\n }\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 handleMouseUp() {\n this.isDragging = false\n }\n\n handleMouseLeave() {\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"]}
|