diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index fb8e23266..cdcc44251 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '16' + node-version: '20' - name: Install dependencies working-directory: ./ run: npm ci diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 05706372c..2ada3c475 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -31,8 +31,7 @@ jobs: with: languages: ${{ matrix.language }} queries: +security-and-quality - paths-ignore: - - '**/*.test-d.ts(x?)' + paths-ignore: "**/*.test-d.ts(x?)" - name: Autobuild uses: github/codeql-action/autobuild@v2 diff --git a/.github/workflows/shipjs-manual-prepare.yml b/.github/workflows/shipjs-manual-prepare.yml index 3a889ebbe..54fe920db 100644 --- a/.github/workflows/shipjs-manual-prepare.yml +++ b/.github/workflows/shipjs-manual-prepare.yml @@ -15,7 +15,7 @@ jobs: ref: main - uses: actions/setup-node@v2 with: - node-version: '16' + node-version: '20' - run: npm ci - run: | git config --global user.email "github-actions[bot]@users.noreply.github.com" diff --git a/.github/workflows/shipjs-trigger.yml b/.github/workflows/shipjs-trigger.yml index 18535ec28..65e926e84 100644 --- a/.github/workflows/shipjs-trigger.yml +++ b/.github/workflows/shipjs-trigger.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/setup-node@v2 with: registry-url: "https://registry.npmjs.org" - node-version: '16' + node-version: '20' - run: npm ci - run: | git config --global user.email "github-actions[bot]@users.noreply.github.com" diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..2edeafb09 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +20 \ No newline at end of file diff --git a/README.md b/README.md index 2c52ad9f1..3fffd6ca3 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ We use [JSDoc type annotations](https://www.typescriptlang.org/docs/handbook/int href="https://cdn.jsdelivr.net/npm/@uploadcare/file-uploader@1/web/uc-file-uploader-regular.min.css" /> - + ``` 3. Configure Uploadcare File Uploader and add your personal public key to the project. Discover the instructions in the [following section](#configuration). @@ -109,7 +109,7 @@ UC.defineComponents(UC); href="https://cdn.jsdelivr.net/npm/@uploadcare/file-uploader@1/web/uc-file-uploader-regular.min.css" /> - + ``` 4. Configure Uploadcare File Uploader and add your personal public key to the project. Discover the instructions in the [following section](#configuration). @@ -123,10 +123,10 @@ All configurations in Uploadcare File Uploader are managed from `uc-config` bloc 3. Add a `uc-config` block to your markup and replace `YOUR_PUBLIC_KEY` with your own public key: ```html - + ``` -4. Make sure that your config block uses the same `ctx-name` attribute value as your solution block. +4. Make sure that your config block uses the same `ctx` attribute value as your solution block. Discover more about Uploadcare File Uploader configuration in [our documentation](https://uploadcare.com/docs/file-uploader/configuration/?ref=github-readme). diff --git a/abstract/ActivityBlock.js b/abstract/ActivityBlock.js index 2dbbbc1bc..c74fa7c45 100644 --- a/abstract/ActivityBlock.js +++ b/abstract/ActivityBlock.js @@ -54,6 +54,8 @@ export class ActivityBlock extends Block { this.setAttribute('activity', this.activityType); } this.sub('*currentActivity', (/** @type {String} */ val) => { + if (this.activityType === 'url') { + } if (this.activityType !== val && this[ACTIVE_PROP]) { this._deactivate(); } else if (this.activityType === val && !this[ACTIVE_PROP]) { diff --git a/abstract/Block.js b/abstract/Block.js index a69fa1df3..e861f92e1 100644 --- a/abstract/Block.js +++ b/abstract/Block.js @@ -1,23 +1,27 @@ // @ts-check -import { BaseComponent, Data } from '@symbiotejs/symbiote'; +import { DICT, PubSub, Symbiote } from '@symbiotejs/symbiote'; +// @ts-ignore - something wrong with the tsd +import { slotProcessor } from '@symbiotejs/symbiote/core/slotProcessor.js'; import { initialConfig } from '../blocks/Config/initialConfig.js'; import { EventEmitter } from '../blocks/UploadCtxProvider/EventEmitter.js'; import { WindowHeightTracker } from '../utils/WindowHeightTracker.js'; -import { extractFilename, extractCdnUrlModifiers, extractUuid } from '../utils/cdn-utils.js'; +import { extractCdnUrlModifiers, extractFilename, extractUuid } from '../utils/cdn-utils.js'; import { getLocaleDirection } from '../utils/getLocaleDirection.js'; import { getPluralForm } from '../utils/getPluralForm.js'; import { applyTemplateData, getPluralObjects } from '../utils/template-utils.js'; import { waitForAttribute } from '../utils/waitForAttribute.js'; import { blockCtx } from './CTX.js'; import { LocaleManager, localeStateKey } from './LocaleManager.js'; +import { A11y } from './a11y.js'; import { l10nProcessor } from './l10nProcessor.js'; import { sharedConfigKey } from './sharedConfigKey.js'; -import { A11y } from './a11y.js'; +import { bindCompatibilityFallbackProcessor } from './bindCompatibilityFallbackProcessor.js'; const TAG_PREFIX = 'uc-'; +const CTX_NAME_FALLBACK_ATTR = 'ctx-name'; // @ts-ignore TODO: fix this -export class Block extends BaseComponent { +export class Block extends Symbiote { /** @type {string | null} */ static StateConsumerScope = null; @@ -78,8 +82,12 @@ export class Block extends BaseComponent { super(); /** @type {Map void }>>} */ this.l10nProcessorSubs = new Map(); - // @ts-ignore TODO: fix this + // @ts-expect-error TODO: fix this this.addTemplateProcessor(l10nProcessor); + this.addTemplateProcessor(slotProcessor); + + // Prepend tpl processors with bind compatibility fallback processor + this.tplProcessors = new Set([bindCompatibilityFallbackProcessor, ...this.tplProcessors]); } /** @@ -135,17 +143,29 @@ export class Block extends BaseComponent { this.processInnerHtml = true; } if (this.requireCtxName) { - waitForAttribute({ - element: this, - attribute: 'ctx-name', - onSuccess: () => { - // async wait for ctx-name attribute to be set, needed for Angular because it sets attributes after mount + Promise.race([ + waitForAttribute({ + element: this, + attribute: DICT.CTX_NAME_ATTR, + }), + waitForAttribute({ + element: this, + attribute: CTX_NAME_FALLBACK_ATTR, + }), + ]).then((result) => { + if (result.success) { + if (result.attribute === CTX_NAME_FALLBACK_ATTR) { + const ctxName = result.value; + this.style.setProperty(DICT.CSS_CTX_PROP, `'${ctxName}'`); + } + // async wait for ctx attribute to be set, needed for Angular because it sets attributes after mount // TODO: should be moved to the symbiote core super.connectedCallback(); - }, - onTimeout: () => { - console.error('Attribute `ctx-name` is required and it is not set.'); - }, + } else { + console.error( + `Attribute "${DICT.CTX_NAME_ATTR}" or "${CTX_NAME_FALLBACK_ATTR}" is required and it is not set.`, + ); + } }); } else { super.connectedCallback(); @@ -217,7 +237,7 @@ export class Block extends BaseComponent { // Destroy local context // TODO: this should be done inside symbiote - Data.deleteCtx(this); + PubSub.deleteCtx(this.localCtx.uid); if (blocksRegistry?.size === 0) { setTimeout(() => { @@ -233,7 +253,7 @@ export class Block extends BaseComponent { * @protected */ destroyCtxCallback() { - Data.deleteCtx(this.ctxName); + PubSub.deleteCtx(this.ctxName); this.localeManager?.destroy(); } @@ -327,6 +347,7 @@ export class Block extends BaseComponent { const resolver = args[0]; consoleArgs = resolver(); } + console.log(`[${this.ctxName}]`, ...consoleArgs); } @@ -341,5 +362,3 @@ export class Block extends BaseComponent { } } } - -export { BaseComponent }; diff --git a/abstract/CTX.js b/abstract/CTX.js index 4462de40b..188f9e99a 100644 --- a/abstract/CTX.js +++ b/abstract/CTX.js @@ -25,7 +25,7 @@ export const uploaderBlockCtx = (fnCtx) => ({ '*uploadList': [], '*focusedEntry': null, '*uploadQueue': new Queue(1), - /** @type {ReturnType[]} */ + /** @type {import('../types').OutputErrorCollection[]} */ '*collectionErrors': [], /** @type {import('../types').OutputCollectionState | null} */ '*collectionState': null, diff --git a/abstract/TypedCollection.js b/abstract/TypedCollection.js index a5a871529..f6daa75ba 100644 --- a/abstract/TypedCollection.js +++ b/abstract/TypedCollection.js @@ -1,4 +1,4 @@ -import { Data, UID } from '@symbiotejs/symbiote'; +import { PubSub, UID } from '@symbiotejs/symbiote'; import { TypedData } from './TypedData.js'; export class TypedCollection { @@ -22,9 +22,9 @@ export class TypedCollection { this.__ctxId = options.ctxName || UID.generate(); /** * @private - * @type {Data} + * @type {PubSub} */ - this.__data = Data.registerCtx({}, this.__ctxId); + this.__data = PubSub.registerCtx({}, this.__ctxId); /** * @private * @type {string[]} @@ -232,7 +232,7 @@ export class TypedCollection { } destroy() { - Data.deleteCtx(this.__ctxId); + PubSub.deleteCtx(this.__ctxId); this.__propertyObservers = null; this.__collectionObservers = null; for (let id in this.__subsMap) { diff --git a/abstract/TypedData.js b/abstract/TypedData.js index af7f1039f..ac4a75bda 100644 --- a/abstract/TypedData.js +++ b/abstract/TypedData.js @@ -1,4 +1,4 @@ -import { Data, UID } from '@symbiotejs/symbiote'; +import { PubSub, UID } from '@symbiotejs/symbiote'; const MSG_NAME = '[Typed State] Wrong property name: '; const MSG_TYPE = '[Typed State] Wrong property type: '; @@ -20,9 +20,9 @@ export class TypedData { }, {}); /** * @private - * @type {Data} + * @type {PubSub} */ - this.__data = Data.registerCtx(this.__schema, this.__ctxId); + this.__data = PubSub.registerCtx(this.__schema, this.__ctxId); } /** @returns {String} */ @@ -72,6 +72,6 @@ export class TypedData { } remove() { - Data.deleteCtx(this.__ctxId); + PubSub.deleteCtx(this.__ctxId); } } diff --git a/abstract/UploaderBlock.js b/abstract/UploaderBlock.js index efc04d298..589ef0c08 100644 --- a/abstract/UploaderBlock.js +++ b/abstract/UploaderBlock.js @@ -1,7 +1,7 @@ // @ts-check import { ActivityBlock } from './ActivityBlock.js'; -import { Data } from '@symbiotejs/symbiote'; +import { PubSub } from '@symbiotejs/symbiote'; import { uploadFileGroup } from '@uploadcare/upload-client'; import { calculateMaxCenteredCropFrame } from '../blocks/CloudImageEditor/src/crop-utils.js'; import { parseCropPreset } from '../blocks/CloudImageEditor/src/lib/parseCropPreset.js'; @@ -234,7 +234,7 @@ export class UploaderBlock extends ActivityBlock { if (changeMap.uploadProgress) { for (const entryId of changeMap.uploadProgress) { - const { isUploading, silent } = Data.getCtx(entryId).store; + const { isUploading, silent } = PubSub.getCtx(entryId).store; if (isUploading && !silent) { this.emit(EventType.FILE_UPLOAD_PROGRESS, this.api.getOutputItem(entryId)); } @@ -244,7 +244,7 @@ export class UploaderBlock extends ActivityBlock { } if (changeMap.isUploading) { for (const entryId of changeMap.isUploading) { - const { isUploading, silent } = Data.getCtx(entryId).store; + const { isUploading, silent } = PubSub.getCtx(entryId).store; if (isUploading && !silent) { this.emit(EventType.FILE_UPLOAD_START, this.api.getOutputItem(entryId)); } @@ -252,7 +252,7 @@ export class UploaderBlock extends ActivityBlock { } if (changeMap.fileInfo) { for (const entryId of changeMap.fileInfo) { - const { fileInfo, silent } = Data.getCtx(entryId).store; + const { fileInfo, silent } = PubSub.getCtx(entryId).store; if (fileInfo && !silent) { this.emit(EventType.FILE_UPLOAD_SUCCESS, this.api.getOutputItem(entryId)); } @@ -263,7 +263,7 @@ export class UploaderBlock extends ActivityBlock { } if (changeMap.errors) { for (const entryId of changeMap.errors) { - const { errors } = Data.getCtx(entryId).store; + const { errors } = PubSub.getCtx(entryId).store; if (errors.length > 0) { this.emit(EventType.FILE_UPLOAD_FAILED, this.api.getOutputItem(entryId)); this.emit( diff --git a/abstract/UploaderPublicApi.js b/abstract/UploaderPublicApi.js index daef7e8a9..599f64fc1 100644 --- a/abstract/UploaderPublicApi.js +++ b/abstract/UploaderPublicApi.js @@ -1,14 +1,14 @@ // @ts-check import { ActivityBlock } from './ActivityBlock.js'; -import { Data } from '@symbiotejs/symbiote'; +import { PubSub } from '@symbiotejs/symbiote'; import { EventType } from '../blocks/UploadCtxProvider/EventEmitter.js'; import { UploadSource } from '../blocks/utils/UploadSource.js'; import { serializeCsv } from '../blocks/utils/comma-separated.js'; import { IMAGE_ACCEPT_LIST, fileIsImage, mergeFileTypes } from '../utils/fileTypes.js'; import { parseCdnUrl } from '../utils/parseCdnUrl.js'; -import { buildOutputCollectionState } from './buildOutputCollectionState.js'; import { stringToArray } from '../utils/stringToArray.js'; +import { buildOutputCollectionState } from './buildOutputCollectionState.js'; export class UploaderPublicApi { /** @@ -176,7 +176,7 @@ export class UploaderPublicApi { * @returns {import('../types/exported.js').OutputFileEntry} */ getOutputItem = (entryId) => { - const uploadEntryData = /** @type {import('./uploadEntrySchema.js').UploadEntry} */ (Data.getCtx(entryId).store); + const uploadEntryData = /** @type {import('./uploadEntrySchema.js').UploadEntry} */ (PubSub.getCtx(entryId).store); /** @type {import('@uploadcare/upload-client').UploadcareFile?} */ const fileInfo = uploadEntryData.fileInfo; diff --git a/abstract/bindCompatibilityFallbackProcessor.js b/abstract/bindCompatibilityFallbackProcessor.js new file mode 100644 index 000000000..c1b5a5e99 --- /dev/null +++ b/abstract/bindCompatibilityFallbackProcessor.js @@ -0,0 +1,16 @@ +// @ts-check + +import { DICT } from '@symbiotejs/symbiote'; + +const FALLBACK_BIND_ATTR = 'set'; + +/** @param {DocumentFragment | import('@symbiotejs/symbiote').Symbiote} fr */ +export function bindCompatibilityFallbackProcessor(fr) { + [...fr.querySelectorAll(`[${FALLBACK_BIND_ATTR}]`)].forEach((el) => { + const setAttrValue = el.getAttribute(FALLBACK_BIND_ATTR); + if (setAttrValue) { + el.removeAttribute(FALLBACK_BIND_ATTR); + el.setAttribute(DICT.BIND_ATTR, setAttrValue); + } + }); +} diff --git a/abstract/defineComponents.js b/abstract/defineComponents.js index e8a09af9c..98b13bc42 100644 --- a/abstract/defineComponents.js +++ b/abstract/defineComponents.js @@ -1,6 +1,11 @@ +const EXCLUDE_COMPONENTS = ['Symbiote', 'BaseComponent', 'UploaderBlock', 'ActivityBlock', 'Block', 'SolutionBlock']; + /** @param {Object} blockExports */ export function defineComponents(blockExports) { for (let blockName in blockExports) { + if (EXCLUDE_COMPONENTS.includes(blockName)) { + continue; + } let tagName = [...blockName].reduce((name, char) => { if (char.toUpperCase() === char) { char = '-' + char.toLowerCase(); diff --git a/abstract/l10nProcessor.js b/abstract/l10nProcessor.js index 43076a19f..3d31b5670 100644 --- a/abstract/l10nProcessor.js +++ b/abstract/l10nProcessor.js @@ -48,11 +48,11 @@ export function l10nProcessor(fr, fnCtx) { // We don't need the leading * in the key because we use the key as a local context key relative to the global state const nodeStateKey = localeStateKey(mappedKey).replace('*', ''); // If the key is not present in the node context, add it - if (!fnCtx.nodeCtx.has(nodeStateKey)) { - fnCtx.nodeCtx.add(nodeStateKey, mappedKey); + if (!fnCtx.sharedCtx.has(nodeStateKey)) { + fnCtx.sharedCtx.add(nodeStateKey, mappedKey); } // Subscribe on the global l10n key change - const sub = fnCtx.nodeCtx.sub(nodeStateKey, () => { + const sub = fnCtx.sharedCtx.sub(nodeStateKey, () => { el[/** @type {'textContent'} */ (elProp)] = fnCtx.l10n(mappedKey); }); keySubs?.add(sub); diff --git a/abstract/uploadEntrySchema.js b/abstract/uploadEntrySchema.js index 797384472..cace666ca 100644 --- a/abstract/uploadEntrySchema.js +++ b/abstract/uploadEntrySchema.js @@ -109,7 +109,7 @@ export const uploadEntrySchema = Object.freeze({ }, source: { type: String, - value: false, + value: null, nullable: true, }, fullPath: { diff --git a/blocks/CameraSource/CameraSource.js b/blocks/CameraSource/CameraSource.js index c3e8b025d..bc08248fa 100644 --- a/blocks/CameraSource/CameraSource.js +++ b/blocks/CameraSource/CameraSource.js @@ -1,8 +1,9 @@ -import { UploaderBlock } from '../../abstract/UploaderBlock.js'; +import { html } from '@symbiotejs/symbiote'; import { ActivityBlock } from '../../abstract/ActivityBlock.js'; +import { UploaderBlock } from '../../abstract/UploaderBlock.js'; +import { UploadSource } from '../utils/UploadSource.js'; import { canUsePermissionsApi } from '../utils/abilities.js'; import { debounce } from '../utils/debounce.js'; -import { UploadSource } from '../utils/UploadSource.js'; export class CameraSource extends UploaderBlock { couldBeCtxOwner = true; @@ -213,21 +214,21 @@ export class CameraSource extends UploaderBlock { } } -CameraSource.template = /* HTML */ ` +CameraSource.template = html` - -
+
- @@ -235,18 +236,18 @@ CameraSource.template = /* HTML */ ` -
+
-
diff --git a/blocks/CloudImageEditor/src/CropFrame.js b/blocks/CloudImageEditor/src/CropFrame.js index 334afd647..074aeab1a 100644 --- a/blocks/CloudImageEditor/src/CropFrame.js +++ b/blocks/CloudImageEditor/src/CropFrame.js @@ -1,4 +1,5 @@ // @ts-check +import { html } from '@symbiotejs/symbiote'; import { Block } from '../../../abstract/Block.js'; import { clamp, @@ -508,4 +509,4 @@ export class CropFrame extends Block { } } -CropFrame.template = /* HTML */ ` `; +CropFrame.template = html``; diff --git a/blocks/CloudImageEditor/src/EditorButtonControl.js b/blocks/CloudImageEditor/src/EditorButtonControl.js index 0a29bbcdf..329f4880e 100644 --- a/blocks/CloudImageEditor/src/EditorButtonControl.js +++ b/blocks/CloudImageEditor/src/EditorButtonControl.js @@ -1,3 +1,4 @@ +import { html } from '@symbiotejs/symbiote'; import { classNames } from './lib/classNames.js'; import { Block } from '../../../abstract/Block.js'; @@ -36,9 +37,9 @@ export class EditorButtonControl extends Block { } } -EditorButtonControl.template = /* HTML */ ` +EditorButtonControl.template = html` `; diff --git a/blocks/CloudImageEditor/src/EditorCropButtonControl.js b/blocks/CloudImageEditor/src/EditorCropButtonControl.js index 22767ae95..e0d5b0acf 100644 --- a/blocks/CloudImageEditor/src/EditorCropButtonControl.js +++ b/blocks/CloudImageEditor/src/EditorCropButtonControl.js @@ -30,7 +30,7 @@ export class EditorCropButtonControl extends EditorButtonControl { this.$['icon'] = operation; }); - this.$['on.click'] = (e) => { + this.$['on.click'] = () => { let prev = this.$['*cropperEl'].getValue(this._operation); let next = nextValue(this._operation, prev); this.$['*cropperEl'].setValue(this._operation, next); diff --git a/blocks/CloudImageEditor/src/EditorFilterControl.js b/blocks/CloudImageEditor/src/EditorFilterControl.js index 61369bf31..3b089c065 100644 --- a/blocks/CloudImageEditor/src/EditorFilterControl.js +++ b/blocks/CloudImageEditor/src/EditorFilterControl.js @@ -1,9 +1,10 @@ // @ts-check +import { html } from '@symbiotejs/symbiote'; import { createCdnUrl, createCdnUrlModifiers } from '../../../utils/cdn-utils.js'; import { EditorButtonControl } from './EditorButtonControl.js'; import { FAKE_ORIGINAL_FILTER } from './EditorSlider.js'; -import { COMMON_OPERATIONS, transformationsToOperations } from './lib/transformationUtils.js'; import { preloadImage } from './lib/preloadImage.js'; +import { COMMON_OPERATIONS, transformationsToOperations } from './lib/transformationUtils.js'; export class EditorFilterControl extends EditorButtonControl { constructor() { @@ -15,7 +16,6 @@ export class EditorFilterControl extends EditorButtonControl { title: '', icon: '', isOriginal: false, - iconSize: '20', 'on.click': null, }; } @@ -119,10 +119,6 @@ export class EditorFilterControl extends EditorButtonControl { this.$.active = currentFilter && currentFilter === this._filter; }); - this.sub('isOriginal', (isOriginal) => { - this.$.iconSize = isOriginal ? 40 : 20; - }); - this.sub('active', (active) => { if (this.$.isOriginal) { return; @@ -157,9 +153,9 @@ export class EditorFilterControl extends EditorButtonControl { } } -EditorFilterControl.template = /* HTML */ ` +EditorFilterControl.template = html` `; diff --git a/blocks/CloudImageEditor/src/EditorImageCropper.js b/blocks/CloudImageEditor/src/EditorImageCropper.js index adde39382..a03868c96 100644 --- a/blocks/CloudImageEditor/src/EditorImageCropper.js +++ b/blocks/CloudImageEditor/src/EditorImageCropper.js @@ -1,5 +1,5 @@ // @ts-check - +import { html } from '@symbiotejs/symbiote'; import { Block } from '../../../abstract/Block.js'; import { debounce } from '../../utils/debounce.js'; import { throttle } from '../../utils/throttle.js'; @@ -545,7 +545,7 @@ export class EditorImageCropper extends Block { } } -EditorImageCropper.template = /* HTML */ ` +EditorImageCropper.template = html` `; diff --git a/blocks/CloudImageEditor/src/EditorOperationControl.js b/blocks/CloudImageEditor/src/EditorOperationControl.js index 91df9b282..2a2c5420f 100644 --- a/blocks/CloudImageEditor/src/EditorOperationControl.js +++ b/blocks/CloudImageEditor/src/EditorOperationControl.js @@ -11,7 +11,7 @@ export class EditorOperationControl extends EditorButtonControl { initCallback() { super.initCallback(); - this.$['on.click'] = (e) => { + this.$['on.click'] = () => { this.$['*sliderEl'].setOperation(this._operation); this.$['*showSlider'] = true; this.$['*currentOperation'] = this._operation; diff --git a/blocks/CloudImageEditor/src/EditorScroller.js b/blocks/CloudImageEditor/src/EditorScroller.js index ccdb9f6c2..105dd2b4b 100644 --- a/blocks/CloudImageEditor/src/EditorScroller.js +++ b/blocks/CloudImageEditor/src/EditorScroller.js @@ -1,3 +1,4 @@ +import { html } from '@symbiotejs/symbiote'; import { Block } from '../../../abstract/Block.js'; const X_THRESHOLD = 1; @@ -30,4 +31,4 @@ export class EditorScroller extends Block { } } -EditorScroller.template = /* HTML */ ` `; +EditorScroller.template = html` `; diff --git a/blocks/CloudImageEditor/src/EditorSlider.js b/blocks/CloudImageEditor/src/EditorSlider.js index 9282d81ee..628828a3b 100644 --- a/blocks/CloudImageEditor/src/EditorSlider.js +++ b/blocks/CloudImageEditor/src/EditorSlider.js @@ -1,4 +1,5 @@ import { Block } from '../../../abstract/Block.js'; +import { html } from '@symbiotejs/symbiote'; import { COLOR_OPERATIONS_CONFIG } from './toolbar-constants.js'; const ControlType = { @@ -110,9 +111,9 @@ export class EditorSlider extends Block { } } -EditorSlider.template = /* HTML */ ` +EditorSlider.template = html` `; diff --git a/blocks/CloudImageEditor/src/EditorToolbar.js b/blocks/CloudImageEditor/src/EditorToolbar.js index e8a21fed4..e68996a6a 100644 --- a/blocks/CloudImageEditor/src/EditorToolbar.js +++ b/blocks/CloudImageEditor/src/EditorToolbar.js @@ -1,4 +1,5 @@ // @ts-check +import { html } from '@symbiotejs/symbiote'; import { debounce } from '../../utils/debounce.js'; import { Block } from '../../../abstract/Block.js'; import { EditorCropButtonControl } from './EditorCropButtonControl.js'; @@ -21,14 +22,14 @@ function renderTabToggle(id) { return /* HTML */ ` @@ -37,11 +38,11 @@ function renderTabToggle(id) { /** @param {String} id */ function renderTabContent(id) { - return /* HTML */ ` + return html`
@@ -334,7 +335,7 @@ export class EditorToolbar extends Block { this.sub('*editorTransformations', (editorTransformations) => { let appliedFilter = editorTransformations?.filter?.name; if (this.$['*currentFilter'] !== appliedFilter) { - this.$['*currentFilter'] = appliedFilter; + this.$['*currentFilter'] = appliedFilter ?? null; } }); @@ -399,8 +400,8 @@ export class EditorToolbar extends Block { } } -EditorToolbar.template = /* HTML */ ` - +EditorToolbar.template = html` +
{{*operationTooltip}}
@@ -410,31 +411,31 @@ EditorToolbar.template = /* HTML */ `
${ALL_TABS.map(renderTabContent).join('')}
${ALL_TABS.map(renderTabToggle).join('')}
- - + +
- - + +
diff --git a/blocks/CloudImageEditor/src/css/common.css b/blocks/CloudImageEditor/src/css/common.css index de989c04d..3b3f9e8d5 100644 --- a/blocks/CloudImageEditor/src/css/common.css +++ b/blocks/CloudImageEditor/src/css/common.css @@ -375,7 +375,7 @@ uc-editor-operation-control > button { height: var(--size-icon); } -uc-editor-filter-control > uc-icon.uc-original-icon > svg { +uc-editor-filter-control uc-icon.uc-original-icon > svg { width: 100%; height: 100%; } @@ -448,7 +448,7 @@ uc-editor-filter-control > button .uc-preview { transition: var(--transition-duration-3); } -uc-editor-filter-control > .uc-original-icon { +uc-editor-filter-control .uc-original-icon { color: var(--color-effect); opacity: 0.3; } diff --git a/blocks/CloudImageEditor/src/elements/button/BtnUi.js b/blocks/CloudImageEditor/src/elements/button/BtnUi.js index 2951c9672..a0183765b 100644 --- a/blocks/CloudImageEditor/src/elements/button/BtnUi.js +++ b/blocks/CloudImageEditor/src/elements/button/BtnUi.js @@ -1,3 +1,4 @@ +import { html } from '@symbiotejs/symbiote'; import { Block } from '../../../../../abstract/Block.js'; import { classNames } from '../../lib/classNames.js'; @@ -52,7 +53,7 @@ export class BtnUi extends Block { } }); - this.sub('text', (txt) => { + this.sub('text', () => { this._iconSingle = false; }); @@ -79,12 +80,11 @@ export class BtnUi extends Block { } } } - BtnUi.bindAttributes({ text: 'text', icon: 'icon', reverse: 'reverse', theme: 'theme' }); -BtnUi.template = /* HTML */ ` - `; diff --git a/blocks/CloudImageEditor/src/elements/line-loader/LineLoaderUi.js b/blocks/CloudImageEditor/src/elements/line-loader/LineLoaderUi.js index 6cb45e6d4..c4ecd0594 100644 --- a/blocks/CloudImageEditor/src/elements/line-loader/LineLoaderUi.js +++ b/blocks/CloudImageEditor/src/elements/line-loader/LineLoaderUi.js @@ -1,3 +1,4 @@ +import { html } from '@symbiotejs/symbiote'; import { Block } from '../../../../../abstract/Block.js'; export class LineLoaderUi extends Block { @@ -45,7 +46,7 @@ export class LineLoaderUi extends Block { } } -LineLoaderUi.template = /* HTML */ ` +LineLoaderUi.template = html`
diff --git a/blocks/CloudImageEditor/src/elements/presence-toggle/PresenceToggle.js b/blocks/CloudImageEditor/src/elements/presence-toggle/PresenceToggle.js index b53453378..ddfa6d482 100644 --- a/blocks/CloudImageEditor/src/elements/presence-toggle/PresenceToggle.js +++ b/blocks/CloudImageEditor/src/elements/presence-toggle/PresenceToggle.js @@ -1,5 +1,6 @@ -import { applyClassNames } from '../../lib/classNames.js'; +import { html } from '@symbiotejs/symbiote'; import { Block } from '../../../../../abstract/Block.js'; +import { applyClassNames } from '../../lib/classNames.js'; /** * @typedef {Object} Style @@ -68,4 +69,4 @@ export class PresenceToggle extends Block { }, 0); } } -PresenceToggle.template = /* HTML */ ` `; +PresenceToggle.template = html` `; diff --git a/blocks/CloudImageEditor/src/elements/slider/SliderUi.js b/blocks/CloudImageEditor/src/elements/slider/SliderUi.js index 88feacd66..be104d797 100644 --- a/blocks/CloudImageEditor/src/elements/slider/SliderUi.js +++ b/blocks/CloudImageEditor/src/elements/slider/SliderUi.js @@ -1,3 +1,4 @@ +import { html } from '@symbiotejs/symbiote'; import { Block } from '../../../../../abstract/Block.js'; export class SliderUi extends Block { @@ -166,13 +167,13 @@ export class SliderUi extends Block { this._observer?.disconnect(); } } -SliderUi.template = /* HTML */ ` +SliderUi.template = html`
`; diff --git a/blocks/CloudImageEditor/src/lib/FocusVisible.js b/blocks/CloudImageEditor/src/lib/FocusVisible.js deleted file mode 100644 index 4badd96a9..000000000 --- a/blocks/CloudImageEditor/src/lib/FocusVisible.js +++ /dev/null @@ -1,33 +0,0 @@ -import { applyFocusVisiblePolyfill } from './applyFocusVisiblePolyfill.js'; - -export class FocusVisible { - /** - * @param {boolean} focusVisible - * @param {HTMLElement} element - */ - static handleFocusVisible(focusVisible, element) { - if (focusVisible) { - let customOutline = element.style.getPropertyValue('--focus-visible-outline'); - element.style.outline = customOutline || '2px solid var(--color-focus-ring)'; - } else { - element.style.outline = 'none'; - } - } - - /** @param {ShadowRoot | Document} scope */ - static register(scope) { - FocusVisible._destructors.set(scope, applyFocusVisiblePolyfill(scope, FocusVisible.handleFocusVisible)); - } - - /** @param {Document | ShadowRoot} scope */ - static unregister(scope) { - if (!FocusVisible._destructors.has(scope)) { - return; - } - let removeFocusVisiblePolyfill = FocusVisible._destructors.get(scope); - removeFocusVisiblePolyfill(); - FocusVisible._destructors.delete(scope); - } -} - -FocusVisible._destructors = new WeakMap(); diff --git a/blocks/CloudImageEditor/src/lib/applyFocusVisiblePolyfill.js b/blocks/CloudImageEditor/src/lib/applyFocusVisiblePolyfill.js deleted file mode 100644 index e6754ebac..000000000 --- a/blocks/CloudImageEditor/src/lib/applyFocusVisiblePolyfill.js +++ /dev/null @@ -1,256 +0,0 @@ -/** - * Helper function for legacy browsers and iframes which sometimes focus on elements like document, body, and - * non-interactive SVG. - * - * @param {EventTarget} el - */ -function isValidFocusTarget(el) { - if ( - el && - el !== document && - /** @type {Element} */ (el).nodeName !== 'HTML' && - /** @type {Element} */ (el).nodeName !== 'BODY' && - 'classList' in el && - 'contains' in /** @type {Element} */ (el).classList - ) { - return true; - } - return false; -} - -/** - * Computes whether the given element should automatically trigger the `focus-visible` class being added, i.e., whether - * it should always match `:focus-visible` when focused. - * - * @param {EventTarget} el - * @returns {boolean} - */ -function focusTriggersKeyboardModality(el) { - let { tagName } = /** @type {Element} */ (el); - - if (tagName === 'INPUT' && !(/** @type {HTMLInputElement} */ (el).readOnly)) { - return true; - } - - if (tagName === 'TEXTAREA' && !(/** @type {HTMLTextAreaElement} */ (el).readOnly)) { - return true; - } - - if (/** @type {HTMLElement} */ (el).isContentEditable) { - return true; - } - - return false; -} - -let hadKeyboardEvent = true; -let hadFocusVisibleRecently = false; - -/** - * Applies the :focus-visible polyfill at the given scope. A scope, in this case, is either the top-level Document or a - * Shadow Root. - * - * @param {Document | ShadowRoot} scope - * @param {(focusVisible: boolean, el: EventTarget) => void} [callback] - * @see https://github.com/WICG/focus-visible - */ -export function applyFocusVisiblePolyfill(scope, callback) { - let hadFocusVisibleRecentlyTimeout = null; - - /** - * Add the `focus-visible` class to the given element if the author did not add it. - * - * @param {EventTarget} el - */ - function addFocusVisibleClass(el) { - /** @type {Element} */ (el).setAttribute('focus-visible', ''); - callback(true, el); - } - - /** - * Remove the `focus-visible` class from the given element if the author did not originally add it. - * - * @param {EventTarget} el - */ - function removeFocusVisibleClass(el) { - if (!(/** @type {Element} */ (el).hasAttribute('focus-visible'))) { - return; - } - /** @type {Element} */ (el).removeAttribute('focus-visible'); - callback(false, el); - } - - /** - * If the most recent user interaction was via the keyboard, and the keypress did not include a meta, alt/option, or - * control key, then the keyboard's modality. Otherwise, the modality is not the keyboard.Apply `focus-visible` to any - * current active element and keep track of our keyboard modality state with `hadKeyboardEvent`. - * - * @param {KeyboardEvent} e - */ - function onKeyDown(e) { - if (e.metaKey || e.altKey || e.ctrlKey) { - return; - } - - if (isValidFocusTarget(scope.activeElement)) { - addFocusVisibleClass(scope.activeElement); - } - - hadKeyboardEvent = true; - } - - /** - * If at any point a user clicks with a pointing device, ensure that we change the modality away from the keyboard. - * This avoids the situation where a user presses a key on an already focused element, and then clicks on a different - * element focusing it with a pointing device while we still think we're in keyboard modality. - * - * @param {Event} e - */ - function onPointerDown(e) { - hadKeyboardEvent = false; - } - - /** - * On `focus`, add the `focus-visible` class to the target if: - the target received focus as a result of keyboard - * navigation or - the event target is an element that will likely require interaction via the keyboard (e.g., a text - * box). - * - * @param {Event} e - */ - function onFocus(e) { - // Prevent IE from focusing the document or HTML element. - if (!isValidFocusTarget(e.target)) { - return; - } - - if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) { - addFocusVisibleClass(e.target); - } - } - - /** - * On `blur`, remove the `focus-visible` class from the target. - * - * @param {Event} e - */ - function onBlur(e) { - if (!isValidFocusTarget(e.target)) { - return; - } - - if (/** @type {Element} */ (e.target).hasAttribute('focus-visible')) { - // To detect a tab/window switch, we look for a blur event followed - // rapidly by a visibility change. - // If we don't see a visibility change within 100ms, it's probably a - // regular focus change. - hadFocusVisibleRecently = true; - window.clearTimeout(hadFocusVisibleRecentlyTimeout); - hadFocusVisibleRecentlyTimeout = window.setTimeout(() => { - hadFocusVisibleRecently = false; - }, 100); - removeFocusVisibleClass(e.target); - } - } - - /** - * Add a group of listeners to detect usage of any pointing devices. These listeners will be added when the polyfill - * first loads and anytime the window is blurred so that they are active when the window regains focus. - */ - function addInitialPointerMoveListeners() { - /* eslint-disable no-use-before-define */ - document.addEventListener('mousemove', onInitialPointerMove); - document.addEventListener('mousedown', onInitialPointerMove); - document.addEventListener('mouseup', onInitialPointerMove); - document.addEventListener('pointermove', onInitialPointerMove); - document.addEventListener('pointerdown', onInitialPointerMove); - document.addEventListener('pointerup', onInitialPointerMove); - document.addEventListener('touchmove', onInitialPointerMove); - document.addEventListener('touchstart', onInitialPointerMove); - document.addEventListener('touchend', onInitialPointerMove); - /* eslint-enable no-use-before-define */ - } - - function removeInitialPointerMoveListeners() { - /* eslint-disable no-use-before-define */ - document.removeEventListener('mousemove', onInitialPointerMove); - document.removeEventListener('mousedown', onInitialPointerMove); - document.removeEventListener('mouseup', onInitialPointerMove); - document.removeEventListener('pointermove', onInitialPointerMove); - document.removeEventListener('pointerdown', onInitialPointerMove); - document.removeEventListener('pointerup', onInitialPointerMove); - document.removeEventListener('touchmove', onInitialPointerMove); - document.removeEventListener('touchstart', onInitialPointerMove); - document.removeEventListener('touchend', onInitialPointerMove); - /* eslint-enable no-use-before-define */ - } - - /** - * If the user changes tabs, keep track of whether or not the previously focused element had .focus-visible. - * - * @param {Event} e - */ - function onVisibilityChange(e) { - if (document.visibilityState === 'hidden') { - // If the tab becomes active again, the browser will handle calling focus - // on the element (Safari actually calls it twice). - // If this tab change caused a blur on an element with focus-visible, - // re-apply the class when the user switches back to the tab. - if (hadFocusVisibleRecently) { - hadKeyboardEvent = true; - } - addInitialPointerMoveListeners(); - } - } - - /** - * When the polyfill first loads, assume the user is in keyboard modality. If any event is received from a pointing - * device (e.g., mouse, pointer, touch), turn off keyboard modality. This accounts for situations where focus enters - * the page from the URL bar. - * - * @param {Event} e - */ - function onInitialPointerMove(e) { - // Work around a Safari quirk that fires a mousemove on whenever the - // window blurs, even if you're tabbing out of the page. ¯\_(ツ)_/¯ - if ( - /** @type {Element} */ (e.target).nodeName && - /** @type {Element} */ (e.target).nodeName.toLowerCase() === 'html' - ) { - return; - } - - hadKeyboardEvent = false; - removeInitialPointerMoveListeners(); - } - - // We are interested in changes at the global scope only for some kinds of states. - // For example, global pointer input, global key presses, and global - // visibility change should affect the state at every scope: - document.addEventListener('keydown', onKeyDown, true); - document.addEventListener('mousedown', onPointerDown, true); - document.addEventListener('pointerdown', onPointerDown, true); - document.addEventListener('touchstart', onPointerDown, true); - document.addEventListener('visibilitychange', onVisibilityChange, true); - - addInitialPointerMoveListeners(); - - // We specifically care about state changes in the local scope for focus and blur. - // This is because focus/blur events that originate from within a - // shadow root are not re-dispatched from the host element if it was already - // the active element in its own scope: - scope.addEventListener('focus', onFocus, true); - scope.addEventListener('blur', onBlur, true); - - return () => { - removeInitialPointerMoveListeners(); - - document.removeEventListener('keydown', onKeyDown, true); - document.removeEventListener('mousedown', onPointerDown, true); - document.removeEventListener('pointerdown', onPointerDown, true); - document.removeEventListener('touchstart', onPointerDown, true); - document.removeEventListener('visibilitychange', onVisibilityChange, true); - - scope.removeEventListener('focus', onFocus, true); - scope.removeEventListener('blur', onBlur, true); - }; -} diff --git a/blocks/CloudImageEditor/src/template.js b/blocks/CloudImageEditor/src/template.js index 61c2365db..7d4c531de 100644 --- a/blocks/CloudImageEditor/src/template.js +++ b/blocks/CloudImageEditor/src/template.js @@ -1,10 +1,11 @@ +import { html } from '@symbiotejs/symbiote'; import { TRANSPARENT_PIXEL_SRC } from '../../../utils/transparentPixelSrc.js'; import svgIconsSprite from './svg-sprite.js'; -export const TEMPLATE = /* HTML */ ` +export const TEMPLATE = html` ${svgIconsSprite}
- +
@@ -12,7 +13,7 @@ export const TEMPLATE = /* HTML */ `
Network error
@@ -27,7 +28,7 @@ export const TEMPLATE = /* HTML */ `
{{msg}}
- +
diff --git a/blocks/CloudImageEditorActivity/CloudImageEditorActivity.js b/blocks/CloudImageEditorActivity/CloudImageEditorActivity.js index 000e17552..60fb39d5a 100644 --- a/blocks/CloudImageEditorActivity/CloudImageEditorActivity.js +++ b/blocks/CloudImageEditorActivity/CloudImageEditorActivity.js @@ -1,4 +1,5 @@ // @ts-check +import { DICT } from '@symbiotejs/symbiote'; import { ActivityBlock } from '../../abstract/ActivityBlock.js'; import { UploaderBlock } from '../../abstract/UploaderBlock.js'; import { CloudImageEditorBlock } from '../CloudImageEditor/index.js'; @@ -73,7 +74,7 @@ export class CloudImageEditorActivity extends UploaderBlock { const cropPreset = this.cfg.cropPreset; const tabs = this.cfg.cloudImageEditorTabs; - instance.setAttribute('ctx-name', this.ctxName); + instance.setAttribute(DICT.CTX_NAME_ATTR, this.ctxName); instance.setAttribute('cdn-url', cdnUrl); if (cropPreset) { diff --git a/blocks/Copyright/Copyright.js b/blocks/Copyright/Copyright.js index 30db0a2de..8f7282a13 100644 --- a/blocks/Copyright/Copyright.js +++ b/blocks/Copyright/Copyright.js @@ -1,3 +1,4 @@ +import { html } from '@symbiotejs/symbiote'; import { Block } from '../../abstract/Block.js'; export class Copyright extends Block { @@ -13,7 +14,7 @@ export class Copyright extends Block { ); } - static template = /* HTML */ ` + static template = html` -
-
+
+
diff --git a/blocks/ExternalSource/ExternalSource.js b/blocks/ExternalSource/ExternalSource.js index 42903641c..b21056835 100644 --- a/blocks/ExternalSource/ExternalSource.js +++ b/blocks/ExternalSource/ExternalSource.js @@ -1,6 +1,6 @@ // @ts-check -import { create } from '@symbiotejs/symbiote'; +import { create, html } from '@symbiotejs/symbiote'; import { ActivityBlock } from '../../abstract/ActivityBlock.js'; import { UploaderBlock } from '../../abstract/UploaderBlock.js'; import { stringToArray } from '../../utils/stringToArray.js'; @@ -87,7 +87,7 @@ export class ExternalSource extends UploaderBlock { this.mountIframe(); }, }); - this.sub('*currentActivityParams', (val) => { + this.sub('*currentActivityParams', () => { if (!this.isActivityActive) { return; } @@ -238,29 +238,29 @@ export class ExternalSource extends UploaderBlock { } } -ExternalSource.template = /* HTML */ ` +ExternalSource.template = html` -
- + {{activityCaption}}
-
- +
-
{{counter}}
+
{{counter}}
diff --git a/blocks/ExternalSource/buildStyles.js b/blocks/ExternalSource/buildStyles.js index 388d349f4..82e047fd4 100644 --- a/blocks/ExternalSource/buildStyles.js +++ b/blocks/ExternalSource/buildStyles.js @@ -7,9 +7,9 @@ const styleToCss = (style) => { const css = Object.keys(style).reduce((acc, selector) => { const propertiesObj = style[selector]; - const propertiesStr = Object.keys(propertiesObj).reduce((acc, prop) => { + const propertiesStr = Object.keys(propertiesObj).reduce((innerAcc, prop) => { const value = propertiesObj[prop]; - return acc + `${prop}: ${value};`; + return innerAcc + `${prop}: ${value};`; }, ''); return acc + `${selector}{${propertiesStr}}`; }, ''); diff --git a/blocks/FileItem/FileItem.js b/blocks/FileItem/FileItem.js index 2c24568c1..e5400cb22 100644 --- a/blocks/FileItem/FileItem.js +++ b/blocks/FileItem/FileItem.js @@ -1,4 +1,5 @@ // @ts-check +import { html } from '@symbiotejs/symbiote'; import { CancelError, uploadFile } from '@uploadcare/upload-client'; import { shrinkFile } from '@uploadcare/image-shrink'; import { ActivityBlock } from '../../abstract/ActivityBlock.js'; @@ -293,7 +294,7 @@ export class FileItem extends UploaderBlock { isFinished: state === FileItemState.FINISHED, progressVisible: state === FileItemState.UPLOADING, isEditable: this.cfg.useCloudImageEditor && this._entry?.getValue('isImage') && this._entry?.getValue('cdnUrl'), - errorText: this._entry.getValue('errors')?.[0]?.message, + errorText: this._entry.getValue('errors')?.[0]?.message ?? '', }); } @@ -422,23 +423,23 @@ export class FileItem extends UploaderBlock { } } -FileItem.template = /* HTML */ ` -
-
+FileItem.template = html` +
+
- +
- {{itemName}} - {{errorText}} + {{itemName}} + {{errorText}}
@@ -446,15 +447,15 @@ FileItem.template = /* HTML */ ` type="button" l10n="@title:file-item-remove-button" class="uc-remove-btn uc-mini-btn" - set="onclick: onRemove;" + bind="onclick: onRemove;" > -
- +
`; FileItem.activeInstances = new Set(); diff --git a/blocks/Icon/Icon.js b/blocks/Icon/Icon.js index 7ed291182..6e8442b9b 100644 --- a/blocks/Icon/Icon.js +++ b/blocks/Icon/Icon.js @@ -1,4 +1,5 @@ // @ts-check +import { html } from '@symbiotejs/symbiote'; import { Block } from '../../abstract/Block.js'; export class Icon extends Block { @@ -9,7 +10,6 @@ export class Icon extends Block { ...this.init$, name: '', href: '', - title: '', }; } @@ -31,14 +31,12 @@ export class Icon extends Block { } } -Icon.template = /* HTML */ ` +Icon.template = html` - {{title}} - + `; Icon.bindAttributes({ name: 'name', - title: 'title', }); diff --git a/blocks/Img/ImgBase.js b/blocks/Img/ImgBase.js index a095e0662..e13b8165f 100644 --- a/blocks/Img/ImgBase.js +++ b/blocks/Img/ImgBase.js @@ -103,8 +103,8 @@ export class ImgBase extends ImgConfig { createCdnUrl( // createOriginalUrl(this.$$('cdn-cname'), this.$$('uuid')), - cdnModifiers - ) + cdnModifiers, + ), ); } @@ -114,8 +114,8 @@ export class ImgBase extends ImgConfig { createCdnUrl( // createOriginalUrl(this.$$('cdn-cname'), this.$$('uuid')), - cdnModifiers - ) + cdnModifiers, + ), ); } @@ -126,8 +126,8 @@ export class ImgBase extends ImgConfig { // this.$$('proxy-cname'), cdnModifiers, - this._fmtAbs(this.$$('src')) - ) + this._fmtAbs(this.$$('src')), + ), ); } @@ -138,8 +138,8 @@ export class ImgBase extends ImgConfig { // `https://${this.$$('pubkey')}.ucr.io/`, cdnModifiers, - this._fmtAbs(this.$$('src')) - ) + this._fmtAbs(this.$$('src')), + ), ); } } @@ -157,7 +157,7 @@ export class ImgBase extends ImgConfig { return applyTemplateData( this.$$('secure-delivery-proxy'), { previewUrl: url }, - { transform: (value) => window.encodeURIComponent(value) } + { transform: (value) => window.encodeURIComponent(value) }, ); } diff --git a/blocks/Img/ImgConfig.js b/blocks/Img/ImgConfig.js index a80b6e71e..e7cf204be 100644 --- a/blocks/Img/ImgConfig.js +++ b/blocks/Img/ImgConfig.js @@ -1,4 +1,4 @@ -import { BaseComponent, Data } from '@symbiotejs/symbiote'; +import { Symbiote, PubSub } from '@symbiotejs/symbiote'; import { PROPS_MAP } from './props-map.js'; import { CSS_PREF } from './configurations.js'; import { PACKAGE_NAME, PACKAGE_VERSION } from '../../env.js'; @@ -8,7 +8,7 @@ for (let prop in PROPS_MAP) { CSS_PROPS[CSS_PREF + prop] = PROPS_MAP[prop]?.default || ''; } -export class ImgConfig extends BaseComponent { +export class ImgConfig extends Symbiote { cssInit$ = CSS_PROPS; /** @@ -87,7 +87,7 @@ export class ImgConfig extends BaseComponent { }); this._isnObserver = null; } - Data.deleteCtx(this); + PubSub.deleteCtx(this); } static get observedAttributes() { diff --git a/blocks/Img/utils/parseObjectToString.js b/blocks/Img/utils/parseObjectToString.js index 5e0582e0b..a7b6c6ea3 100644 --- a/blocks/Img/utils/parseObjectToString.js +++ b/blocks/Img/utils/parseObjectToString.js @@ -1,6 +1,6 @@ export const parseObjectToString = (params) => Object.entries(params) - .filter(([key, value]) => value !== undefined && value !== '') + .filter(([, value]) => value !== undefined && value !== '') .map(([key, value]) => { if (key === 'cdn-operations') { return value; diff --git a/blocks/Modal/Modal.js b/blocks/Modal/Modal.js index 39540d4ba..072243770 100644 --- a/blocks/Modal/Modal.js +++ b/blocks/Modal/Modal.js @@ -1,4 +1,5 @@ // @ts-check +import { html } from '@symbiotejs/symbiote'; import { Block } from '../../abstract/Block.js'; export class Modal extends Block { @@ -109,7 +110,7 @@ export class Modal extends Block { } } -Modal.template = /* HTML */ ` +Modal.template = html` diff --git a/blocks/ProgressBar/ProgressBar.js b/blocks/ProgressBar/ProgressBar.js index a8e0f8688..75db233ea 100644 --- a/blocks/ProgressBar/ProgressBar.js +++ b/blocks/ProgressBar/ProgressBar.js @@ -1,3 +1,4 @@ +import { html } from '@symbiotejs/symbiote'; import { Block } from '../../abstract/Block.js'; export class ProgressBar extends Block { @@ -35,4 +36,4 @@ export class ProgressBar extends Block { } } -ProgressBar.template = /* HTML */ `
`; +ProgressBar.template = html`
`; diff --git a/blocks/ProgressBarCommon/ProgressBarCommon.js b/blocks/ProgressBarCommon/ProgressBarCommon.js index bf3f2d5fa..bcd489b33 100644 --- a/blocks/ProgressBarCommon/ProgressBarCommon.js +++ b/blocks/ProgressBarCommon/ProgressBarCommon.js @@ -1,3 +1,4 @@ +import { html } from '@symbiotejs/symbiote'; import { UploaderBlock } from '../../abstract/UploaderBlock.js'; export class ProgressBarCommon extends UploaderBlock { @@ -41,4 +42,4 @@ export class ProgressBarCommon extends UploaderBlock { } } -ProgressBarCommon.template = /* HTML */ ` `; +ProgressBarCommon.template = html` `; diff --git a/blocks/Range/Range.js b/blocks/Range/Range.js deleted file mode 100644 index 5b51b33a1..000000000 --- a/blocks/Range/Range.js +++ /dev/null @@ -1,44 +0,0 @@ -import { BaseComponent } from '@symbiotejs/symbiote'; - -export class Range extends BaseComponent { - init$ = { - cssLeft: '50%', - barActive: false, - value: 50, - onChange: (e) => { - e.preventDefault(); - e.stopPropagation(); - this.$.value = parseFloat(this._range.value); - this.dispatchEvent(new Event('change')); - }, - }; - - initCallback() { - super.initCallback(); - /** @type {HTMLInputElement} */ - this._range = this.ref.range; - [...this.attributes].forEach((attr) => { - let exclude = ['style', 'ref']; - if (!exclude.includes(attr.name)) { - this.ref.range.setAttribute(attr.name, attr.value); - } - }); - this.sub('value', (val) => { - let pcnt = (val / 100) * 100; - this.$.cssLeft = `${pcnt}%`; - }); - this.defineAccessor('value', (val) => { - this.$.value = val; - }); - } -} - -Range.template = /* HTML */ ` -
-
-
-
-
- - -`; diff --git a/blocks/Range/range.css b/blocks/Range/range.css deleted file mode 100644 index f095a6d2c..000000000 --- a/blocks/Range/range.css +++ /dev/null @@ -1,65 +0,0 @@ -uc-range { - position: relative; - display: inline-flex; - align-items: center; - justify-content: center; - height: var(--uc-button-size); -} - -uc-range datalist { - display: none; -} - -uc-range input { - width: 100%; - height: 100%; - opacity: 0; -} - -uc-range .uc-track-wrapper { - position: absolute; - right: 10px; - left: 10px; - display: flex; - align-items: center; - justify-content: center; - height: 2px; - user-select: none; - pointer-events: none; -} - -uc-range .uc-track { - position: absolute; - right: 0; - left: 0; - display: flex; - align-items: center; - justify-content: center; - height: 2px; - background-color: currentColor; - border-radius: 2px; - opacity: 0.5; -} - -uc-range .uc-slider { - position: absolute; - width: 16px; - height: 16px; - background-color: currentColor; - border-radius: 100%; - transform: translateX(-50%); -} - -uc-range .uc-bar { - position: absolute; - left: 0; - height: 100%; - background-color: currentColor; - border-radius: 2px; -} - -uc-range .uc-caption { - position: absolute; - display: inline-flex; - justify-content: center; -} diff --git a/blocks/Select/Select.js b/blocks/Select/Select.js index ad3c149a6..3b49240f5 100644 --- a/blocks/Select/Select.js +++ b/blocks/Select/Select.js @@ -1,3 +1,4 @@ +import { html } from '@symbiotejs/symbiote'; import { Block } from '../../abstract/Block.js'; export class Select extends Block { @@ -21,15 +22,19 @@ export class Select extends Block { initCallback() { super.initCallback(); - this.sub('options', (/** @type {{ text: String; value: String }[]} */ options) => { - this.$.currentText = options?.[0]?.text || ''; - let html = ''; - options?.forEach((opt) => { - html += /* HTML */ ``; - }); - this.$.selectHtml = html; - }); + this.defineAccessor( + 'options', + /** @param {{ text: String; value: String }[]} options */ + (options) => { + this.$.currentText = options?.[0]?.text || ''; + let htmlCode = ''; + options?.forEach((opt) => { + htmlCode += html``; + }); + this.$.selectHtml = htmlCode; + }, + ); } } -Select.template = /* HTML */ ` `; +Select.template = html` `; diff --git a/blocks/SimpleBtn/SimpleBtn.js b/blocks/SimpleBtn/SimpleBtn.js index 9381a38ee..21b8a1100 100644 --- a/blocks/SimpleBtn/SimpleBtn.js +++ b/blocks/SimpleBtn/SimpleBtn.js @@ -1,4 +1,5 @@ // @ts-check +import { html } from '@symbiotejs/symbiote'; import { UploaderBlock } from '../../abstract/UploaderBlock.js'; import { asBoolean } from '../Config/normalizeConfigValue.js'; @@ -37,9 +38,9 @@ export class SimpleBtn extends UploaderBlock { } } -SimpleBtn.template = /* HTML */ ` - - `; diff --git a/blocks/SourceList/SourceList.js b/blocks/SourceList/SourceList.js index 7e9e45577..85c13f4bf 100644 --- a/blocks/SourceList/SourceList.js +++ b/blocks/SourceList/SourceList.js @@ -1,19 +1,20 @@ import { Block } from '../../abstract/Block.js'; import { stringToArray } from '../../utils/stringToArray.js'; +import { html } from '@symbiotejs/symbiote'; export class SourceList extends Block { initCallback() { super.initCallback(); this.subConfigValue('sourceList', (/** @type {String} */ val) => { let list = stringToArray(val); - let html = ''; + let htmlContent = ''; list.forEach((srcName) => { - html += /* HTML */ ``; + htmlContent += html``; }); if (this.cfg.sourceListWrap) { - this.innerHTML = html; + this.innerHTML = htmlContent; } else { - this.outerHTML = html; + this.outerHTML = htmlContent; } }); } diff --git a/blocks/StartFrom/StartFrom.js b/blocks/StartFrom/StartFrom.js index fa9900a77..72c2d13ef 100644 --- a/blocks/StartFrom/StartFrom.js +++ b/blocks/StartFrom/StartFrom.js @@ -1,3 +1,4 @@ +import { html } from '@symbiotejs/symbiote'; import { ActivityBlock } from '../../abstract/ActivityBlock.js'; export class StartFrom extends ActivityBlock { @@ -11,4 +12,4 @@ export class StartFrom extends ActivityBlock { } } -StartFrom.template = /* HTML */ `
`; +StartFrom.template = html`
`; diff --git a/blocks/UploadList/UploadList.js b/blocks/UploadList/UploadList.js index 7d4e07039..611a016e8 100644 --- a/blocks/UploadList/UploadList.js +++ b/blocks/UploadList/UploadList.js @@ -1,4 +1,5 @@ // @ts-check +import { html } from '@symbiotejs/symbiote'; import { ActivityBlock } from '../../abstract/ActivityBlock.js'; import { UploaderBlock } from '../../abstract/UploaderBlock.js'; import { EventType } from '../UploadCtxProvider/EventEmitter.js'; @@ -14,8 +15,6 @@ import { throttle } from '../utils/throttle.js'; */ export class UploadList extends UploaderBlock { - // Context owner should have access to CSS l10n - // TODO: We need to move away l10n from CSS couldBeCtxOwner = true; historyTracked = true; activityType = ActivityBlock.activities.UPLOAD_LIST; @@ -199,42 +198,42 @@ export class UploadList extends UploaderBlock { } } -UploadList.template = /* HTML */ ` +UploadList.template = html` {{headerText}} - -
+
-
+
-
+
- +
diff --git a/blocks/UrlSource/UrlSource.js b/blocks/UrlSource/UrlSource.js index 80b7d6fa9..23a7c03ad 100644 --- a/blocks/UrlSource/UrlSource.js +++ b/blocks/UrlSource/UrlSource.js @@ -1,5 +1,6 @@ -import { UploaderBlock } from '../../abstract/UploaderBlock.js'; +import { html } from '@symbiotejs/symbiote'; import { ActivityBlock } from '../../abstract/ActivityBlock.js'; +import { UploaderBlock } from '../../abstract/UploaderBlock.js'; import { UploadSource } from '../utils/UploadSource.js'; export class UrlSource extends UploaderBlock { @@ -36,25 +37,25 @@ export class UrlSource extends UploaderBlock { } } -UrlSource.template = /* HTML */ ` +UrlSource.template = html` -
-
- +
diff --git a/blocks/themes/uc-basic/index.css b/blocks/themes/uc-basic/index.css index a6c16b8ec..2bd27d9d8 100644 --- a/blocks/themes/uc-basic/index.css +++ b/blocks/themes/uc-basic/index.css @@ -9,7 +9,6 @@ /* UI COMPONENTS: */ @import url('../../Icon/icon.css'); -@import url('../../Range/range.css'); /* BLOCKS: */ @import url('../../Config/config.css'); diff --git a/blocks/themes/uc-basic/svg-sprite.js b/blocks/themes/uc-basic/svg-sprite.js index f67fa0a4e..2bc3acc1a 100644 --- a/blocks/themes/uc-basic/svg-sprite.js +++ b/blocks/themes/uc-basic/svg-sprite.js @@ -1 +1 @@ -export default ""; +export default ""; diff --git a/demo/cloud-image-editor.html b/demo/cloud-image-editor.html index ec7d13c16..7ad6ff8b3 100644 --- a/demo/cloud-image-editor.html +++ b/demo/cloud-image-editor.html @@ -11,7 +11,8 @@ - - + +
- +

diff --git a/demo/icons.html b/demo/icons.html index 361959cb3..6c64e9477 100644 --- a/demo/icons.html +++ b/demo/icons.html @@ -32,8 +32,8 @@ - - + + diff --git a/demo/locales.html b/demo/locales.html index e903842a7..0ab5a0939 100644 --- a/demo/locales.html +++ b/demo/locales.html @@ -132,7 +132,7 @@ const setMode = (mode) => { document.querySelector('#container').innerHTML = ` `; @@ -163,7 +163,7 @@ setMode('regular'); - +
diff --git a/demo/preview-proxy/secure-delivery-proxy-url-resolver.html b/demo/preview-proxy/secure-delivery-proxy-url-resolver.html index 974b6b5b6..d15475f37 100644 --- a/demo/preview-proxy/secure-delivery-proxy-url-resolver.html +++ b/demo/preview-proxy/secure-delivery-proxy-url-resolver.html @@ -30,6 +30,6 @@ - - - + + + diff --git a/demo/preview-proxy/secure-delivery-proxy-url-template.html b/demo/preview-proxy/secure-delivery-proxy-url-template.html index 735e50d9d..eba48eaeb 100644 --- a/demo/preview-proxy/secure-delivery-proxy-url-template.html +++ b/demo/preview-proxy/secure-delivery-proxy-url-template.html @@ -25,10 +25,10 @@ - + - + diff --git a/demo/raw-inline.html b/demo/raw-inline.html index b78bd6872..51b64a156 100644 --- a/demo/raw-inline.html +++ b/demo/raw-inline.html @@ -18,7 +18,8 @@ - - \ No newline at end of file + + \ No newline at end of file diff --git a/demo/raw-regular.html b/demo/raw-regular.html index 5214a6241..edc16de85 100644 --- a/demo/raw-regular.html +++ b/demo/raw-regular.html @@ -18,14 +18,14 @@ - - - - + + + diff --git a/demo/validators.html b/demo/validators.html index 9a8a47c01..6ceb6463e 100644 --- a/demo/validators.html +++ b/demo/validators.html @@ -35,9 +35,9 @@ - - - + + +