Skip to content

Commit

Permalink
Merge pull request #461 from uploadcare/feature/configuration-block
Browse files Browse the repository at this point in the history
feature: implement `lr-config` block
  • Loading branch information
nd0ut authored Jul 24, 2023
2 parents 81d674c + 592e90b commit d23166f
Show file tree
Hide file tree
Showing 91 changed files with 1,595 additions and 582 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ web
# this line will be removed on pages deploy at `.github/workflows/pages.yml`
# __REMOVE_BELOW_LINE__
**/*.html

index.ssr.js
Empty file added .npmignore
Empty file.
6 changes: 6 additions & 0 deletions abstract/ActivityBlock.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @ts-check
import { Modal } from '../blocks/Modal/Modal.js';
import { debounce } from '../blocks/utils/debounce.js';
import { Block } from './Block.js';
Expand All @@ -14,6 +15,7 @@ export class ActivityBlock extends Block {

/** @private */
_deactivate() {
// @ts-ignore TODO: fix this
let actDesc = ActivityBlock._activityRegistry[this.activityKey];
this[ACTIVE_PROP] = false;
this.removeAttribute(ACTIVE_ATTR);
Expand All @@ -23,6 +25,7 @@ export class ActivityBlock extends Block {

/** @private */
_activate() {
// @ts-ignore TODO: fix this
let actDesc = ActivityBlock._activityRegistry[this.activityKey];
this.$['*historyBack'] = this.historyBack.bind(this);
/** @private */
Expand Down Expand Up @@ -77,6 +80,7 @@ export class ActivityBlock extends Block {

/** @private */
_isActivityRegistered() {
// @ts-ignore TODO: fix this
return this.activityType && !!ActivityBlock._activityRegistry[this.activityKey];
}

Expand All @@ -103,6 +107,7 @@ export class ActivityBlock extends Block {
if (!ActivityBlock._activityRegistry) {
ActivityBlock._activityRegistry = Object.create(null);
}
// @ts-ignore TODO: fix this
ActivityBlock._activityRegistry[this.activityKey] = {
activateCallback: onActivate,
deactivateCallback: onDeactivate,
Expand All @@ -113,6 +118,7 @@ export class ActivityBlock extends Block {
if (this.isActivityActive) {
this._deactivate();
}
// @ts-ignore TODO: fix this
ActivityBlock._activityRegistry[this.activityKey] = undefined;
}

Expand Down
79 changes: 74 additions & 5 deletions abstract/Block.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
// @ts-check
import { BaseComponent } from '@symbiotejs/symbiote';
import { createWindowHeightTracker, getIsWindowHeightTracked } from '../utils/createWindowHeightTracker.js';
import { applyTemplateData, getPluralObjects } from '../utils/template-utils.js';
import { blockCtx } from './CTX.js';
import { l10nProcessor } from './l10nProcessor.js';
import { sharedConfigKey } from './sharedConfigKey.js';
import { toKebabCase } from '../utils/toKebabCase.js';
import { warnOnce } from '../utils/warnOnce.js';
import { getPluralForm } from '../utils/getPluralForm.js';

const TAG_PREFIX = 'lr-';

// @ts-ignore TODO: fix this
export class Block extends BaseComponent {
/** @type {string | null} */
static StateConsumerScope = null;
static className = '';
allowCustomTemplate = true;

init$ = blockCtx();
Expand Down Expand Up @@ -41,14 +48,16 @@ export class Block extends BaseComponent {
*/
pluralize(key, count) {
const locale = this.l10n('locale-name') || 'en-US';
const pluralForm = new Intl.PluralRules(locale).select(count);
const pluralForm = getPluralForm(locale, count);
return this.l10n(`${key}__${pluralForm}`);
}

constructor() {
super();
/** @type {String} */
// @ts-ignore TODO: fix this
this.activityType = null;
// @ts-ignore TODO: fix this
this.addTemplateProcessor(l10nProcessor);
// TODO: inspect template on lr-* elements
// this.addTemplateProcessor((fr) => {
Expand Down Expand Up @@ -80,7 +89,8 @@ export class Block extends BaseComponent {
* @param {(block: Block) => boolean} callback
* @returns {Boolean}
*/
findBlockInCtx(callback) {
hasBlockInCtx(callback) {
// @ts-ignore TODO: fix this
/** @type {Set} */
let blocksRegistry = this.$['*blocksRegistry'];
for (let block of blocksRegistry) {
Expand All @@ -97,25 +107,31 @@ export class Block extends BaseComponent {
* @param {any} newVal
*/
setForCtxTarget(consumerScope, prop, newVal) {
if (this.findBlockInCtx((b) => /** @type {typeof Block} */ (b.constructor).StateConsumerScope === consumerScope)) {
if (this.hasBlockInCtx((b) => /** @type {typeof Block} */ (b.constructor).StateConsumerScope === consumerScope)) {
this.$[prop] = newVal;
}
}

/** @param {String} activityType */
setActivity(activityType) {
if (this.findBlockInCtx((b) => b.activityType === activityType)) {
if (this.hasBlockInCtx((b) => b.activityType === activityType)) {
this.$['*currentActivity'] = activityType;
return;
}
console.warn(`Activity type "${activityType}" not found in the context`);
}

connectedCallback() {
const className = /** @type {typeof Block} */ (this.constructor).className;
if (className) {
this.classList.toggle(`${TAG_PREFIX}${className}`, true);
}

if (!getIsWindowHeightTracked()) {
this._destroyInnerHeightTracker = createWindowHeightTracker();
}
if (this.hasAttribute('retpl')) {
// @ts-ignore TODO: fix this
this.constructor['template'] = null;
this.processInnerHtml = true;
}
Expand Down Expand Up @@ -164,7 +180,7 @@ export class Block extends BaseComponent {
* @returns {String}
*/
proxyUrl(url) {
let previewProxy = this.getCssData('--cfg-secure-delivery-proxy', true);
let previewProxy = this.cfg.secureDeliveryProxy;
if (!previewProxy) {
return url;
}
Expand All @@ -175,6 +191,59 @@ export class Block extends BaseComponent {
);
}

/**
* @param {String} prop
* @protected
*/
parseCfgProp(prop) {
return {
ctx: this.nodeCtx,
name: prop.replace('*', ''),
};
}

/** @returns {import('../types').ConfigType} } */
get cfg() {
if (!this.__cfgProxy) {
let o = Object.create(null);
/** @private */
this.__cfgProxy = new Proxy(o, {
/**
* @param {never} obj
* @param {keyof import('../types').ConfigType} key
*/
get: (obj, key) => {
const sharedKey = sharedConfigKey(key);
const parsed = this.parseCfgProp(sharedKey);
if (parsed.ctx.has(parsed.name)) {
return parsed.ctx.read(parsed.name);
} else {
warnOnce(
'Using CSS variables for configuration is deprecated. Please use `lr-config` instead. See migration guide: https://uploadcare.com/docs/file-uploader/migration-to-0.25.0/'
);
return this.getCssData(`--cfg-${toKebabCase(key)}`);
}
},
});
}
return this.__cfgProxy;
}

/**
* @template {keyof import('../types').ConfigType} T
* @param {T} key
* @param {(value: import('../types').ConfigType[T]) => void} callback
*/
subConfigValue(key, callback) {
const parsed = this.parseCfgProp(sharedConfigKey(key));
if (parsed.ctx.has(parsed.name)) {
this.sub(sharedConfigKey(key), callback);
} else {
this.bindCssData(`--cfg-${toKebabCase(key)}`);
this.sub(`--cfg-${toKebabCase(key)}`, callback);
}
}

updateCtxCssData = () => {
/** @type {Set<Block>} */
let blocks = this.$['*blocksRegistry'];
Expand Down
3 changes: 3 additions & 0 deletions abstract/CTX.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// @ts-check
import { Queue } from '@uploadcare/upload-client';

export const blockCtx = () => ({
/** @type {Set<import('./Block').Block>} */
'*blocksRegistry': new Set(),
});

/** @param {import('./Block').Block} fnCtx */
export const activityBlockCtx = (fnCtx) => ({
...blockCtx(),
'*currentActivity': '',
Expand All @@ -19,6 +21,7 @@ export const activityBlockCtx = (fnCtx) => ({
},
});

/** @param {import('./Block').Block} fnCtx */
export const uploaderBlockCtx = (fnCtx) => ({
...activityBlockCtx(fnCtx),
'*commonProgress': 0,
Expand Down
18 changes: 16 additions & 2 deletions abstract/TypedCollection.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,27 @@ export class TypedCollection {
}
/** @private */
this.__notifyTimeout = window.setTimeout(() => {
let added = this.__added;
let removed = this.__removed;
let added = new Set(this.__added);
let removed = new Set(this.__removed);
this.__added.clear();
this.__removed.clear();
this.__handler?.([...this.__items], added, removed);
});
}

/** @param {(list: string[], added: Set<any>, removed: Set<any>) => void} handler */
setHandler(handler) {
this.__handler = handler;
}

getHandler() {
return this.__handler;
}

removeHandler() {
this.__handler = null;
}

/**
* @param {Object<string, any>} init
* @returns {any}
Expand Down Expand Up @@ -206,6 +219,7 @@ export class TypedCollection {
destroy() {
Data.deleteCtx(this.__data);
this.__observers = null;
this.__handler = null;
for (let id in this.__subsMap) {
this.__subsMap[id].forEach((sub) => {
sub.remove();
Expand Down
Loading

0 comments on commit d23166f

Please sign in to comment.