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 663a13f72..d0c92f814 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/Block.js b/abstract/Block.js index 61918f5ce..e44cbc5a3 100644 --- a/abstract/Block.js +++ b/abstract/Block.js @@ -1,23 +1,23 @@ // @ts-check -import { BaseComponent, Data } from '@symbiotejs/symbiote'; +import { DICT, PubSub, Symbiote, slotProcessor } from '../symbiote.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'; const TAG_PREFIX = 'uc-'; // @ts-ignore TODO: fix this -export class Block extends BaseComponent { +export class Block extends Symbiote { /** @type {string | null} */ static StateConsumerScope = null; @@ -78,8 +78,9 @@ 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); } /** @@ -137,15 +138,15 @@ export class Block extends BaseComponent { 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 + attribute: DICT.CTX_NAME_ATTR, + }).then((result) => { + if (result.success) { + // 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}" is required and it is not set.`); + } }); } else { super.connectedCallback(); @@ -219,7 +220,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(() => { @@ -235,7 +236,7 @@ export class Block extends BaseComponent { * @protected */ destroyCtxCallback() { - Data.deleteCtx(this.ctxName); + PubSub.deleteCtx(this.ctxName); this.localeManager?.destroy(); } @@ -329,6 +330,7 @@ export class Block extends BaseComponent { const resolver = args[0]; consoleArgs = resolver(); } + console.log(`[${this.ctxName}]`, ...consoleArgs); } @@ -343,5 +345,3 @@ export class Block extends BaseComponent { } } } - -export { BaseComponent }; diff --git a/abstract/CTX.js b/abstract/CTX.js index 840dbed31..8deb0a6ae 100644 --- a/abstract/CTX.js +++ b/abstract/CTX.js @@ -24,7 +24,7 @@ export const uploaderBlockCtx = (fnCtx) => ({ '*commonProgress': 0, '*uploadList': [], '*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..ba5630bf3 100644 --- a/abstract/TypedCollection.js +++ b/abstract/TypedCollection.js @@ -1,4 +1,4 @@ -import { Data, UID } from '@symbiotejs/symbiote'; +import { PubSub, UID } from '../symbiote.js'; 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..85a874310 100644 --- a/abstract/TypedData.js +++ b/abstract/TypedData.js @@ -1,4 +1,4 @@ -import { Data, UID } from '@symbiotejs/symbiote'; +import { PubSub, UID } from '../symbiote.js'; 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 93d4d40f4..eaa2dab81 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 '../symbiote.js'; 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 8de0c7d55..2730683c6 100644 --- a/abstract/UploaderPublicApi.js +++ b/abstract/UploaderPublicApi.js @@ -1,14 +1,14 @@ // @ts-check import { ActivityBlock } from './ActivityBlock.js'; -import { applyStyles, Data } from '@symbiotejs/symbiote'; +import { applyStyles, 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 { /** @@ -202,7 +202,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/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..5a09be1bc 100644 --- a/blocks/CameraSource/CameraSource.js +++ b/blocks/CameraSource/CameraSource.js @@ -1,8 +1,9 @@ -import { UploaderBlock } from '../../abstract/UploaderBlock.js'; +import { html } from '../../symbiote.js'; 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,7 +214,7 @@ export class CameraSource extends UploaderBlock { } } -CameraSource.template = /* HTML */ ` +CameraSource.template = html` 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 @@ - - - + + +