@operato/grist-editor 8.0.0-alpha.9 → 8.0.0-beta.1

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 +187 -0
  2. package/dist/src/ox-grist-renderer-hashtags.js +0 -1
  3. package/dist/src/ox-grist-renderer-hashtags.js.map +1 -1
  4. package/dist/tsconfig.tsbuildinfo +1 -1
  5. package/package.json +17 -17
  6. package/.storybook/main.js +0 -3
  7. package/.storybook/preview.js +0 -52
  8. package/.storybook/server.mjs +0 -8
  9. package/src/index.ts +0 -40
  10. package/src/ox-grist-editor-crontab.ts +0 -63
  11. package/src/ox-grist-editor-duration.ts +0 -63
  12. package/src/ox-grist-editor-hashtags.ts +0 -68
  13. package/src/ox-grist-editor-i18n-label.ts +0 -101
  14. package/src/ox-grist-editor-parameters.ts +0 -100
  15. package/src/ox-grist-editor-partition-keys.ts +0 -88
  16. package/src/ox-grist-editor-quantifier.ts +0 -13
  17. package/src/ox-grist-editor-signature.ts +0 -13
  18. package/src/ox-grist-editor-value-map.ts +0 -97
  19. package/src/ox-grist-editor-value-ranges.ts +0 -96
  20. package/src/ox-grist-renderer-crontab.ts +0 -18
  21. package/src/ox-grist-renderer-duration.ts +0 -31
  22. package/src/ox-grist-renderer-hashtags.ts +0 -14
  23. package/src/ox-grist-renderer-i18n-label.ts +0 -12
  24. package/src/ox-grist-renderer-partition-keys.ts +0 -29
  25. package/src/ox-grist-renderer-quantifier.ts +0 -9
  26. package/src/ox-grist-renderer-signature.ts +0 -9
  27. package/src/ox-parameters-builder.ts +0 -134
  28. package/src/ox-popup-crontab-input.ts +0 -75
  29. package/src/ox-popup-duration-input.ts +0 -65
  30. package/src/ox-popup-hashtags-input.ts +0 -66
  31. package/src/ox-popup-i18n-label-input.ts +0 -98
  32. package/src/ox-popup-parameters-builder.ts +0 -112
  33. package/src/ox-popup-partition-keys-input.ts +0 -97
  34. package/src/ox-popup-value-map-input.ts +0 -105
  35. package/src/ox-popup-value-ranges-input.ts +0 -104
  36. package/stories/ox-grist-editor-crontab.stories.ts +0 -451
  37. package/tsconfig.json +0 -24
  38. package/web-dev-server.config.mjs +0 -28
  39. package/web-test-runner.config.mjs +0 -29
@@ -1,97 +0,0 @@
1
- /**
2
- * @license Copyright © HatioLab Inc. All rights reserved.
3
- */
4
-
5
- import './ox-popup-value-map-input.js'
6
-
7
- import { html } from 'lit'
8
- import { customElement } from 'lit/decorators.js'
9
-
10
- import { cloneDeep } from 'lodash-es'
11
-
12
- import { OxGristEditor } from '@operato/data-grist'
13
- import { i18next } from '@operato/i18n'
14
- import { openPopup, PopupHandle } from '@operato/popup'
15
-
16
- @customElement('ox-grist-editor-value-map')
17
- export class OxGristEditorValueMap extends OxGristEditor {
18
- private popup?: PopupHandle
19
-
20
- get options() {
21
- return this.column.record?.options || {}
22
- }
23
-
24
- get editorTemplate() {
25
- const value = typeof this.value === 'object' ? JSON.stringify(this.value) : this.value
26
- return html`<div tabindex="0">${value || ''}</div>`
27
- }
28
-
29
- _onclick(e: Event): void {
30
- e.stopPropagation()
31
- this.openSelector()
32
- }
33
-
34
- _onkeydown(e: KeyboardEvent): void {
35
- const key = e.key
36
- if (key == 'Enter') {
37
- e.stopPropagation()
38
- this.openSelector()
39
- }
40
- }
41
-
42
- async openSelector() {
43
- if (this.popup) {
44
- delete this.popup
45
- }
46
-
47
- const { name, help, valuetype = 'string', defaultValue, objectified = false } = this.options || {}
48
-
49
- const confirmCallback = (newval: any) => {
50
- this.dispatchEvent(
51
- new CustomEvent('field-change', {
52
- bubbles: true,
53
- composed: true,
54
- detail: {
55
- before: this.value,
56
- after: !objectified ? JSON.stringify(newval) : newval,
57
- record: this.record,
58
- column: this.column,
59
- row: this.row
60
- }
61
- })
62
- )
63
- }
64
-
65
- try {
66
- var value: any =
67
- !objectified && typeof this.value === 'string' ? JSON.parse(this.value) : cloneDeep(this.value || {})
68
- } catch (e) {
69
- var value: any = {}
70
- }
71
-
72
- /*
73
- 주의 : 이 팝업 템플릿은 layout 모듈에 의해서 render 되므로,
74
- layout의 구성에 변화가 발생하면, 다시 render된다.
75
- 이 팝업이 떠 있는 상태에서, 또 다른 팝업이 뜨는 경우도 layout 구성의 변화를 야기한다. (overlay의 갯수의 증가)
76
- 이 경우 value, options, confirmCallback 등 클로져를 사용한 것들이 초기 바인딩된 값으로 다시 바인딩되게 되는데,
77
- 만약, 템플릿 내부에서 이들 속성의 레퍼런스가 변화했다면, 원래 상태로 되돌아가는 현상이 발생하게 된다.
78
- 따라서, 가급적 이들 속성의 레퍼런스를 변화시키지 않는 것이 좋다.
79
- */
80
- var template = html`
81
- <ox-popup-value-map-input
82
- .value=${value}
83
- .valuetype=${valuetype}
84
- .defaultValue=${defaultValue}
85
- .confirmCallback=${confirmCallback}
86
- >
87
- </ox-popup-value-map-input>
88
- `
89
-
90
- this.popup = openPopup(template, {
91
- backdrop: true,
92
- size: 'large',
93
- title: `${name?.toUpperCase() || i18next.t('title.value-map')} `,
94
- help
95
- })
96
- }
97
- }
@@ -1,96 +0,0 @@
1
- /**
2
- * @license Copyright © HatioLab Inc. All rights reserved.
3
- */
4
-
5
- import './ox-popup-value-ranges-input.js'
6
-
7
- import { html } from 'lit'
8
- import { customElement } from 'lit/decorators.js'
9
- import { cloneDeep } from 'lodash-es'
10
-
11
- import { OxGristEditor } from '@operato/data-grist'
12
- import { i18next } from '@operato/i18n'
13
- import { openPopup, PopupHandle } from '@operato/popup'
14
-
15
- @customElement('ox-grist-editor-value-ranges')
16
- export class OxGristEditorValueRanges extends OxGristEditor {
17
- private popup?: PopupHandle
18
-
19
- get options() {
20
- return this.column.record?.options || {}
21
- }
22
-
23
- get editorTemplate() {
24
- const value = typeof this.value === 'object' ? JSON.stringify(this.value) : this.value
25
- return html`<div tabindex="0">${value || ''}</div>`
26
- }
27
-
28
- _onclick(e: Event): void {
29
- e.stopPropagation()
30
- this.openSelector()
31
- }
32
-
33
- _onkeydown(e: KeyboardEvent): void {
34
- const key = e.key
35
- if (key == 'Enter') {
36
- e.stopPropagation()
37
- this.openSelector()
38
- }
39
- }
40
-
41
- async openSelector() {
42
- if (this.popup) {
43
- delete this.popup
44
- }
45
-
46
- const { name, help, valuetype = 'string', defaultValue, objectified = false } = this.options || {}
47
-
48
- const confirmCallback = (newval: any) => {
49
- this.dispatchEvent(
50
- new CustomEvent('field-change', {
51
- bubbles: true,
52
- composed: true,
53
- detail: {
54
- before: this.value,
55
- after: !objectified ? JSON.stringify(newval) : newval,
56
- record: this.record,
57
- column: this.column,
58
- row: this.row
59
- }
60
- })
61
- )
62
- }
63
-
64
- try {
65
- var value: any =
66
- !objectified && typeof this.value === 'string' ? JSON.parse(this.value) : cloneDeep(this.value || {})
67
- } catch (e) {
68
- var value: any = {}
69
- }
70
-
71
- /*
72
- 주의 : 이 팝업 템플릿은 layout 모듈에 의해서 render 되므로,
73
- layout의 구성에 변화가 발생하면, 다시 render된다.
74
- 이 팝업이 떠 있는 상태에서, 또 다른 팝업이 뜨는 경우도 layout 구성의 변화를 야기한다. (overlay의 갯수의 증가)
75
- 이 경우 value, options, confirmCallback 등 클로져를 사용한 것들이 초기 바인딩된 값으로 다시 바인딩되게 되는데,
76
- 만약, 템플릿 내부에서 이들 속성의 레퍼런스가 변화했다면, 원래 상태로 되돌아가는 현상이 발생하게 된다.
77
- 따라서, 가급적 이들 속성의 레퍼런스를 변화시키지 않는 것이 좋다.
78
- */
79
- var template = html`
80
- <ox-popup-value-ranges-input
81
- .value=${value}
82
- .valuetype=${valuetype}
83
- .defaultValue=${defaultValue}
84
- .confirmCallback=${confirmCallback}
85
- >
86
- </ox-popup-value-ranges-input>
87
- `
88
-
89
- this.popup = openPopup(template, {
90
- backdrop: true,
91
- size: 'large',
92
- title: `${name?.toUpperCase() || i18next.t('title.value-ranges')} `,
93
- help
94
- })
95
- }
96
- }
@@ -1,18 +0,0 @@
1
- import cronstrue from 'cronstrue/i18n'
2
- import i18next from 'i18next'
3
- import { html } from 'lit'
4
-
5
- import { FieldRenderer } from '@operato/data-grist'
6
-
7
- export const OxGristRendererCrontab: FieldRenderer = (value, column, record, rowIndex, field) => {
8
- let text = ''
9
-
10
- try {
11
- const language = (i18next.language || 'en').substring(0, 2)
12
- text = !value ? '' : cronstrue.toString(value, { locale: language || 'en' })
13
- } catch (e) {
14
- console.error(e)
15
- }
16
-
17
- return html`<span data-reactive-tooltip>${text}</span>`
18
- }
@@ -1,31 +0,0 @@
1
- import i18next from 'i18next'
2
- import { html } from 'lit'
3
-
4
- import { FieldRenderer } from '@operato/data-grist'
5
-
6
- export const OxGristRendererDuration: FieldRenderer = (value, column, record, rowIndex, field) => {
7
- var text = ''
8
-
9
- try {
10
- var secs = Number(value) || 0
11
- var positive = secs >= 0
12
-
13
- secs = Math.abs(secs)
14
- const days = Math.floor(secs / (3600 * 24))
15
- secs -= days * 24 * 3600
16
- const hours = Math.floor(secs / 3600)
17
- secs -= hours * 3600
18
- const minutes = Math.floor(secs / 60)
19
- const seconds = secs - minutes * 60
20
-
21
- text = `${positive ? '' : '- '}${days ? `${days}${i18next.t('label.days')} ` : ''}${
22
- hours ? `${hours}${i18next.t('label.hours')} ` : ''
23
- }${minutes ? `${minutes}${i18next.t('label.minutes')} ` : ''}${
24
- seconds ? `${seconds}${i18next.t('label.seconds')}` : ''
25
- }`.trim()
26
- } catch (e) {
27
- console.error(e)
28
- }
29
-
30
- return html`<span data-reactive-tooltip>${text}</span>`
31
- }
@@ -1,14 +0,0 @@
1
- import { html } from 'lit'
2
-
3
- import { FieldRenderer } from '@operato/data-grist'
4
-
5
- export const OxGristRendererHashtags: FieldRenderer = (value, column, record, rowIndex, field) => {
6
- if (!(value instanceof Array)) {
7
- console.error('value is not a instance of string array')
8
- return html`<span>&nbsp;</span>`
9
- }
10
-
11
- return html`<span>
12
- ${value && value.length > 0 ? (value as string[]).map(x => `#${x}`).join(' ') : '\u00A0' /* &nbsp; */}
13
- </span>`
14
- }
@@ -1,12 +0,0 @@
1
- import { html } from 'lit'
2
-
3
- import { FieldRenderer } from '@operato/data-grist'
4
- import i18next from 'i18next'
5
-
6
- export const OxGristRendererI18nLabel: FieldRenderer = (value, column, record, rowIndex, field) => {
7
- const language = i18next.language || 'en-US'
8
- const labels = value || {}
9
- const label = labels[language] || labels[language.substring(0, 2)] || labels['en'] || ''
10
-
11
- return html`<span>${label}</span>`
12
- }
@@ -1,29 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
- import { html } from 'lit'
3
- import { FieldRenderer } from '@operato/data-grist'
4
-
5
- function onmouseover(e: MouseEvent, value: any[]) {
6
- const element = e.target as HTMLPreElement
7
- const tooltip = value.map(key => key.name).join(',')
8
- element.setAttribute('data-tooltip', tooltip)
9
-
10
- const rect = element.getBoundingClientRect()
11
- element.style.setProperty('--tooltip-top', `${rect.top + rect.height}px`)
12
- element.style.setProperty('--tooltip-left', `${rect.left}px`)
13
- }
14
-
15
- function onmouseout(e: MouseEvent) {
16
- const element = e.target as HTMLPreElement
17
- element.removeAttribute('data-tooltip')
18
- }
19
-
20
- export const OxGristRendererPartitionKeys: FieldRenderer = (value, column, record, rowIndex, field) => {
21
- return value && value instanceof Array && value.length > 0
22
- ? html`<md-icon
23
- style="--md-icon-size:1.3em"
24
- @mouseover=${(e: MouseEvent) => onmouseover(e, value)}
25
- @mouseout=${onmouseout}
26
- >key</md-icon
27
- >`
28
- : html``
29
- }
@@ -1,9 +0,0 @@
1
- import { html } from 'lit'
2
-
3
- import { FieldRenderer } from '@operato/data-grist'
4
-
5
- export const OxGristRendererQuantifier: FieldRenderer = (value, column, record, rowIndex, field) => {
6
- const [min = 1, max = 1] = value || []
7
-
8
- return html`<span>${min}, ${max}</span>`
9
- }
@@ -1,9 +0,0 @@
1
- import { html } from 'lit'
2
-
3
- import { FieldRenderer } from '@operato/data-grist'
4
-
5
- export const OxGristRendererSignature: FieldRenderer = (value, column, record, rowIndex, field) => {
6
- return html`<div
7
- style="flex: 1; align-self: stretch; min-height: var(--signature-min-height, 80px); border: 1px solid var(--md-sys-color-outline); background-image: url(${value}); background-size: contain; background-repeat: no-repeat; background-position: center;"
8
- ></div>`
9
- }
@@ -1,134 +0,0 @@
1
- /**
2
- * @license Copyright © HatioLab Inc. All rights reserved.
3
- */
4
-
5
- import { html, LitElement, PropertyValues } from 'lit'
6
- import { customElement, property } from 'lit/decorators.js'
7
-
8
- import { OxPropertyEditor, PropertySpec, CSSStyles } from '@operato/property-editor'
9
-
10
- /**
11
- 모든 에디터들은 change 이벤트를 지원해야 한다. 또한, 모든 에디터들은 value속성에 값을 가져야 한다.
12
-
13
- Example:
14
-
15
- <ox-parameters-builder value="{{value}}">
16
- <label>Center X</label>
17
- <input type="number" .value="${value.cx}">
18
- <label>Width</label>
19
- <input type="number" .value="${value.width}">
20
- </ox-parameters-builder>
21
- */
22
-
23
- const DEFAULT_VALUE = {
24
- legend: '',
25
- number: 0,
26
- angle: 0,
27
- string: '',
28
- text: '',
29
- textarea: '',
30
- checkbox: false,
31
- select: '',
32
- color: '#000000',
33
- 'solidcolor-stops': null,
34
- 'gradientcolor-stops': null,
35
- 'gltf-selector': '',
36
- 'image-selector': '',
37
- multiplecolor: null,
38
- editortable: null,
39
- imageselector: '',
40
- options: null,
41
- date: null
42
- } as any
43
-
44
- @customElement('ox-parameters-builder')
45
- export class OxParametersBuilder extends LitElement {
46
- @property({ type: Object }) value: any
47
- @property({ type: Array }) props?: PropertySpec[]
48
- @property({ type: Object }) host: any
49
- @property({ type: Object }) context: any
50
-
51
- render() {
52
- return html`<slot></slot>`
53
- }
54
-
55
- firstUpdated() {
56
- this.addEventListener('change', this._onValueChanged.bind(this))
57
- }
58
-
59
- updated(changes: PropertyValues<this>) {
60
- changes.has('props') && this._onPropsChanged(this.props)
61
- changes.has('value') && this._setValues()
62
- }
63
-
64
- _onPropsChanged(props: PropertySpec[] | undefined) {
65
- this.textContent = ''
66
- ;(props || []).forEach(prop => {
67
- let elementType = OxPropertyEditor.getEditor(prop.type)
68
- if (!elementType) {
69
- console.warn('Property Editor not defined', prop.type)
70
- return
71
- }
72
- let element = document.createElement(elementType) as OxPropertyEditor
73
-
74
- element.label = prop.label
75
- element.type = prop.type
76
- element.placeholder = prop.placeholder
77
- element.host = this.host
78
- element.context = this.context
79
- element.setAttribute('name', prop.name)
80
-
81
- if (prop.observe) {
82
- element.observe = prop.observe
83
- }
84
- element.property = prop.property
85
- element.editor = prop.editor
86
- element.setAttribute('property-editor', '')
87
-
88
- if (prop.styles) {
89
- Object.keys(prop.styles).forEach((key: string) => {
90
- element.style[key as keyof CSSStyles] = prop.styles![key as keyof CSSStyles]
91
- })
92
- }
93
-
94
- this.appendChild(element)
95
- })
96
- }
97
-
98
- _setValues() {
99
- var value = this.value || {}
100
- Array.from(this.querySelectorAll('[name]')).forEach(propertyEditor => {
101
- const editor = propertyEditor as OxPropertyEditor
102
- let name = editor.getAttribute('name')
103
- editor.value = value[name!] === undefined ? DEFAULT_VALUE[editor.type] : value[name!]
104
- })
105
- }
106
-
107
- _getValues() {
108
- var value = {} as any
109
- Array.from(this.querySelectorAll('[name]')).forEach(propertyEditor => {
110
- const editor = propertyEditor as OxPropertyEditor
111
- let name = editor.getAttribute('name')
112
- value[name!] = editor.value === undefined ? DEFAULT_VALUE[editor.type] : editor.value
113
- })
114
-
115
- return value
116
- }
117
-
118
- _onValueChanged(e: Event) {
119
- e.stopPropagation()
120
- var prop = e.target as HTMLElement
121
-
122
- if (!prop || !prop.hasAttribute('property-editor')) {
123
- return
124
- }
125
-
126
- this.dispatchEvent(
127
- new CustomEvent('property-change', {
128
- bubbles: true,
129
- composed: true,
130
- detail: this._getValues()
131
- })
132
- )
133
- }
134
- }
@@ -1,75 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
- import '@operato/input/ox-input-crontab.js'
3
-
4
- import { css, html, LitElement } from 'lit'
5
- import { customElement, property } from 'lit/decorators.js'
6
-
7
- import { i18next } from '@operato/i18n'
8
- import { closePopup } from '@operato/popup'
9
- import { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'
10
-
11
- @customElement('ox-popup-crontab-input')
12
- export class OxPopupCrontabInput extends LitElement {
13
- static styles = [
14
- CommonHeaderStyles,
15
- ScrollbarStyles,
16
- css`
17
- :host {
18
- display: flex;
19
- flex-direction: column;
20
-
21
- background-color: var(--md-sys-color-surface);
22
-
23
- width: var(--overlay-center-normal-width, 50%);
24
- height: var(--overlay-center-normal-height, 50%);
25
- }
26
-
27
- ox-input-crontab {
28
- flex: 1;
29
- overflow-y: auto;
30
- }
31
-
32
- span {
33
- flex: 1;
34
-
35
- display: flex;
36
- align-items: center;
37
- justify-content: center;
38
-
39
- color: var(--md-sys-color-on-primary-container);
40
- }
41
- `
42
- ]
43
-
44
- @property({ type: Object }) value: any
45
- @property({ type: Object }) confirmCallback!: (newval: any) => void
46
-
47
- render() {
48
- return html`
49
- <ox-input-crontab .value=${this.value} @change=${this.onChange.bind(this)}> </ox-input-crontab>
50
-
51
- <div class="footer">
52
- <div filler></div>
53
- <button @click=${this.onCancel.bind(this)} danger>
54
- <md-icon>cancel</md-icon>${i18next.t('button.cancel')}
55
- </button>
56
- <button @click=${this.onConfirm.bind(this)} done><md-icon>done</md-icon>${i18next.t('button.confirm')}</button>
57
- </div>
58
- `
59
- }
60
-
61
- private onChange(e: CustomEvent) {
62
- e.stopPropagation()
63
-
64
- this.value = e.detail
65
- }
66
-
67
- private onCancel(e: Event) {
68
- closePopup(this)
69
- }
70
-
71
- private onConfirm(e: Event) {
72
- this.confirmCallback && this.confirmCallback(this.value)
73
- closePopup(this)
74
- }
75
- }
@@ -1,65 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
- import '@operato/input/ox-input-duration.js'
3
-
4
- import { css, html, LitElement } from 'lit'
5
- import { customElement, property } from 'lit/decorators.js'
6
-
7
- import { i18next } from '@operato/i18n'
8
- import { closePopup } from '@operato/popup'
9
- import { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'
10
-
11
- @customElement('ox-popup-duration-input')
12
- export class OxPopupDurationInput extends LitElement {
13
- static styles = [
14
- CommonHeaderStyles,
15
- ScrollbarStyles,
16
- css`
17
- :host {
18
- display: flex;
19
- flex-direction: column;
20
-
21
- background-color: var(--md-sys-color-surface);
22
-
23
- width: var(--overlay-center-normal-width, 50%);
24
- height: var(--overlay-center-normal-height, 50%);
25
- }
26
-
27
- ox-input-duration {
28
- flex: 1;
29
- overflow-y: auto;
30
- }
31
- `
32
- ]
33
-
34
- @property({ type: Object }) value: any
35
- @property({ type: Object }) confirmCallback!: (newval: any) => void
36
-
37
- render() {
38
- return html`
39
- <ox-input-duration .value=${this.value} @change=${this.onChange.bind(this)}> </ox-input-duration>
40
-
41
- <div class="footer">
42
- <div filler></div>
43
- <button @click=${this.onCancel.bind(this)} danger>
44
- <md-icon>cancel</md-icon>${i18next.t('button.cancel')}
45
- </button>
46
- <button @click=${this.onConfirm.bind(this)} done><md-icon>done</md-icon>${i18next.t('button.confirm')}</button>
47
- </div>
48
- `
49
- }
50
-
51
- private onChange(e: CustomEvent) {
52
- e.stopPropagation()
53
-
54
- this.value = e.detail
55
- }
56
-
57
- private onCancel(e: Event) {
58
- closePopup(this)
59
- }
60
-
61
- private onConfirm(e: Event) {
62
- this.confirmCallback && this.confirmCallback(this.value)
63
- closePopup(this)
64
- }
65
- }
@@ -1,66 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
- import '@operato/input/ox-input-hashtags.js'
3
-
4
- import { css, html, LitElement } from 'lit'
5
- import { customElement, property } from 'lit/decorators.js'
6
-
7
- import { i18next } from '@operato/i18n'
8
- import { closePopup } from '@operato/popup'
9
- import { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'
10
-
11
- @customElement('ox-popup-hashtags-input')
12
- export class OxPopupHashtagsInput extends LitElement {
13
- static styles = [
14
- CommonHeaderStyles,
15
- ScrollbarStyles,
16
- css`
17
- :host {
18
- display: flex;
19
- flex-direction: column;
20
-
21
- background-color: var(--md-sys-color-surface);
22
-
23
- width: var(--overlay-center-normal-width, 50%);
24
- height: var(--overlay-center-normal-height, 50%);
25
- }
26
-
27
- ox-input-hashtags {
28
- flex: 1;
29
- overflow-y: auto;
30
- padding: var(--spacing-medium, 8px);
31
- }
32
- `
33
- ]
34
-
35
- @property({ type: Array }) value: string[] = []
36
- @property({ type: Object }) confirmCallback!: (newval: any) => void
37
-
38
- render() {
39
- return html`
40
- <ox-input-hashtags .value=${this.value} @change=${this.onChange.bind(this)}> </ox-input-hashtags>
41
-
42
- <div class="footer">
43
- <div filler></div>
44
- <button @click=${this.onCancel.bind(this)} danger>
45
- <md-icon>cancel</md-icon>${i18next.t('button.cancel')}
46
- </button>
47
- <button @click=${this.onConfirm.bind(this)} done><md-icon>done</md-icon>${i18next.t('button.confirm')}</button>
48
- </div>
49
- `
50
- }
51
-
52
- private onChange(e: CustomEvent) {
53
- e.stopPropagation()
54
-
55
- this.value = (e.target as any).value
56
- }
57
-
58
- private onCancel(e: Event) {
59
- closePopup(this)
60
- }
61
-
62
- private onConfirm(e: Event) {
63
- this.confirmCallback && this.confirmCallback(this.value)
64
- closePopup(this)
65
- }
66
- }