From 436f39d1dfec41f961564770ab820204d36dfedf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 14:50:00 +0000 Subject: [PATCH 01/50] chore(deps): update actions/configure-pages action to v5 --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 2a337c115..ffc8fae42 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -28,7 +28,7 @@ jobs: node-version: 20 cache: yarn - name: Setup Pages - uses: actions/configure-pages@v4 + uses: actions/configure-pages@v5 - name: Install and build run: | yarn install From 95e59b8e9e95c8bf82ef72ebb3d9ab61202c1177 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 19:22:07 +0000 Subject: [PATCH 02/50] chore(deps): update codecov/codecov-action action to v4.3.0 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4424d5af0..26ab53a91 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: - name: Test run: yarn test - name: Codecov upload - uses: codecov/codecov-action@v4.0.1 + uses: codecov/codecov-action@v4.3.0 with: token: ${{ secrets.CODECOV_TOKEN }} build: From 1c12174a47c0744dcde2a8c353be6f24bef4d616 Mon Sep 17 00:00:00 2001 From: maxime Da Silva Date: Tue, 16 Apr 2024 16:36:54 +0200 Subject: [PATCH 03/50] feat(typescript): wip typescript --- packages/core/lib/Builder/index.ts | 263 ++++++++++ packages/core/lib/Components/index.d.ts | 25 - packages/core/lib/Components/index.ts | 249 ++++++++++ packages/core/lib/Emitter/index.js | 14 - packages/core/lib/Emitter/index.ts | 26 + packages/core/lib/Fields/index.d.ts | 22 - .../core/lib/Fields/{index.js => index.ts} | 37 +- packages/core/lib/Logger/index.d.ts | 7 - packages/core/lib/Logger/index.js | 18 - packages/core/lib/Logger/index.ts | 26 + packages/core/lib/Overrides/index.ts | 183 +++++++ .../core/lib/Settings/{index.js => index.ts} | 63 ++- packages/core/lib/Store/index.d.ts | 134 ----- .../core/lib/Store/{index.js => index.ts} | 169 ++++++- packages/core/lib/addons.d.ts | 35 -- packages/core/lib/{addons.js => addons.ts} | 463 +++++++++++------ packages/core/lib/index.d.ts | 17 - packages/core/lib/types.ts | 468 ++++++++++++++++++ tsconfig.json | 1 + 19 files changed, 1765 insertions(+), 455 deletions(-) create mode 100644 packages/core/lib/Builder/index.ts delete mode 100644 packages/core/lib/Components/index.d.ts create mode 100644 packages/core/lib/Components/index.ts delete mode 100644 packages/core/lib/Emitter/index.js create mode 100644 packages/core/lib/Emitter/index.ts delete mode 100644 packages/core/lib/Fields/index.d.ts rename packages/core/lib/Fields/{index.js => index.ts} (56%) delete mode 100644 packages/core/lib/Logger/index.d.ts delete mode 100644 packages/core/lib/Logger/index.js create mode 100644 packages/core/lib/Logger/index.ts create mode 100644 packages/core/lib/Overrides/index.ts rename packages/core/lib/Settings/{index.js => index.ts} (66%) delete mode 100644 packages/core/lib/Store/index.d.ts rename packages/core/lib/Store/{index.js => index.ts} (71%) delete mode 100644 packages/core/lib/addons.d.ts rename packages/core/lib/{addons.js => addons.ts} (56%) delete mode 100644 packages/core/lib/index.d.ts create mode 100644 packages/core/lib/types.ts diff --git a/packages/core/lib/Builder/index.ts b/packages/core/lib/Builder/index.ts new file mode 100644 index 000000000..ae8ea1336 --- /dev/null +++ b/packages/core/lib/Builder/index.ts @@ -0,0 +1,263 @@ +import { exists } from '@junipero/core'; +import { v4 as uuid } from 'uuid'; + +import Emitter from '../Emitter'; +import { BuilderOptions } from '../types'; +import Logger from '../Logger'; +import Components from '../Components'; +import Fields from '../Fields'; +import Overrides from '../Overrides'; +import Store from '../Store'; +import { Texts } from '../Texts'; +import Settings from '../Settings'; + +declare interface IBuilder { + //TODO do +} + +export default class Builder extends Emitter implements IBuilder { + logger = null; + options = null; + + #components = null; + #fields = null; + #overrides = null; + #texts = null; + #store = null; + #settings = null; + #addons = []; + + constructor ({ addons, content, options = {} }: {[_: string]: any} = {}) { // TODO fix it + super(); + + this.options = new BuilderOptions(options); + this.logger = new Logger({ builder: this }); + + this.#components = new Components({ builder: this }); + this.#fields = new Fields({ builder: this }); + this.#overrides = new Overrides({ builder: this }); + this.#store = new Store({ builder: this }); + this.#texts = new Texts({ builder: this }); + this.#settings = new Settings({ builder: this }); + + if (Array.isArray(addons)) { + this.#addons = addons; + addons.forEach(addon => { + this.logger.log('Initializing builder with addon:', addon); + this.addAddon(addon); + }); + } + + if (content) { + this.logger.log('Initializing builder with content:', content); + this.#store.set(content); + } + } + + subscribe (callback: Function) { + const subscriptions = [ + super.subscribe(callback), + this.#store.subscribe(this.emit.bind(this)), + this.#texts.subscribe(this.emit.bind(this)), + this.#components.subscribe(this.emit.bind(this)), + this.#fields.subscribe(this.emit.bind(this)), + this.#overrides.subscribe(this.emit.bind(this)), + this.#settings.subscribe(this.emit.bind(this)), + ]; + + return () => { + subscriptions.forEach(u => u()); + }; + } + + setAddons (addons) { + this.#addons?.forEach(addon => { + this.logger.log('Removing builder addon:', addon); + this.removeAddon(addon); + }); + + this.#addons = addons; + this.#addons?.forEach(addon => { + this.logger.log('Updating builder addon:', addon); + this.addAddon(addon); + }); + + this.emit('addons.update', addons); + } + + addAddon (addon) { + addon.fields?.forEach(field => { + this.#fields.add(field); + }); + + addon.components?.forEach(component => { + this.#components.add(component); + }); + + addon.texts?.forEach(sheet => { + this.#texts.addSheet(sheet); + }); + + addon.overrides?.forEach(override => { + this.#overrides.add(override); + }); + + addon.settings?.forEach(setting => { + this.#settings.add(setting); + }); + } + + removeAddon (addon) { + addon.settings?.forEach(setting => { + this.#settings.remove(setting.id); + }); + + addon.overrides?.forEach(override => { + this.#overrides.remove(override.id); + }); + + addon.texts?.forEach(sheet => { + this.#texts.removeSheet(sheet.id); + }); + + addon.components?.forEach(component => { + this.#components.remove(component.id); + }); + + addon.fields?.forEach(field => { + this.#fields.remove(field.type); + }); + } + + getAvailableComponents () { + const { groups, defaultGroup } = this.#components.all(); + + return [...groups, defaultGroup]; + } + + getComponent (type) { + return this.#components.getComponent(type); + } + + getComponentDisplayableSettings (element, { component }) { + return [ + ...this.#components + .getDisplayableSettings?.(element, { component }) || [], + ...this.#settings.getDisplayable?.(element) || [], + ]; + } + + getAvailableFields () { + return this.#fields.all(); + } + + getField (type) { + return this.#fields.get(type); + } + + getOverride (type, target, opts) { + return this.#overrides.get(type, target, opts); + } + + mergeOverrides (overrides) { + return this.#overrides.merge(overrides); + } + + getContent () { + return this.#store.get(); + } + + setContent (content, options) { + this.#store.set(content, options); + } + + createElement (type, options) { + return this.#store.createElement(type, options); + } + + addElement (element, options) { + return this.#store.addElement(element, options); + } + + addElements (elements, options) { + return this.#store.addElements(elements, options); + } + + getElement (id, options) { + return this.#store.getElement(id, options); + } + + removeElement (id, options) { + return this.#store.removeElement(id, options); + } + + setElement (id, updates, options) { + return this.#store.setElement(id, updates, options); + } + + moveElement (element, sibling, options) { + return this.#store.moveElement(element, sibling, options); + } + + duplicateElement (element, options) { + return this.#store.duplicateElement(element, options); + } + + getElementSettings (element, key, def) { + return this.#store.getElementSettings(element, key, def); + } + + setElementSettings (element, key, value) { + return this.#store.setElementSettings(element, key, value); + } + + undo () { + this.#store.undo(); + } + + redo () { + this.#store.redo(); + } + + canUndo () { + return this.#store.canUndo(); + } + + canRedo () { + return this.#store.canRedo(); + } + + resetHistory () { + this.#store.resetHistory(); + } + + generateId () { + const customId = this.options.generateId?.(); + + return exists(customId) && customId !== '' ? customId : uuid(); + } + + getTextSheet (id) { + return this.#texts.getSheet(id); + } + + getText (key, def) { + return this.#texts.get(key, def); + } + + setText (key, value) { + return this.#texts.set(key, value); + } + + getActiveTextSheet () { + return this.#texts.getActiveSheet(); + } + + setActiveTextSheet (id) { + return this.#texts.setActiveSheet(id); + } + + getAvailableSettings () { + return this.#settings.all(); + } +} diff --git a/packages/core/lib/Components/index.d.ts b/packages/core/lib/Components/index.d.ts deleted file mode 100644 index b2fe5f78e..000000000 --- a/packages/core/lib/Components/index.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Component, ComponentsGroup } from '../types'; -import { Builder } from '../Builder'; -import { Emitter } from '../Emitter'; - -export declare class Components extends Emitter { - static TYPE_COMPONENT: string; - static TYPE_GROUP: string; - static COMPONENTS_GROUP_CORE: string; - static COMPONENTS_GROUP_OTHER: string; - - constructor(options?: { builder: Builder }); - - hasGroup(id: string): boolean; - getGroup(id: string): ComponentsGroup; - - hasComponent(id: string, opts?: { groupId?: string }): boolean; - getComponent(id: string, opts?: { groupId?: string }): Component; - - append(component: object): void; - prepend(component: object): void; - add(component: object, opts?: { mode?: string }): void; - remove(id: string): void; - getAll(): object; - toJSON(): object; -} diff --git a/packages/core/lib/Components/index.ts b/packages/core/lib/Components/index.ts new file mode 100644 index 000000000..55a465d12 --- /dev/null +++ b/packages/core/lib/Components/index.ts @@ -0,0 +1,249 @@ +import { Component, ComponentObject, ComponentSettingsFieldObject, ComponentSettingsTabObject, ComponentsGroup, ComponentsGroupObject, FieldObject } from '../types'; +import Emitter from '../Emitter'; +import Builder from '../Builder'; + +declare abstract class IComponents { + static TYPE_COMPONENT: string; + static TYPE_GROUP: string; + static COMPONENTS_GROUP_CORE: string; + static COMPONENTS_GROUP_OTHER: string; + + constructor(options?: { builder: Builder }); + + hasGroup(id: string): boolean; + getGroup(id: string): ComponentsGroup; + + hasComponent(id: string, opts?: { groupId?: string }): boolean; + getComponent(id: string, opts?: { groupId?: string }): Component; + + append(component: object): void; + prepend(component: object): void; + add(component: object, opts?: { mode?: string }): void; + remove(id: string): void; + getAll(): object; + toJSON(): object; +} + +export default class Components extends Emitter implements IComponents { + static TYPE_COMPONENT = 'component'; + static TYPE_GROUP = 'group'; + + static COMPONENTS_GROUP_CORE = 'core'; + static COMPONENTS_GROUP_OTHER = 'other'; + + #builder = null; + #groups = null; + #defaultGroup = null; // Other tab + + constructor ({ builder }: { builder?: Builder} = {}) { + super(); + + this.#builder = builder; + this.#groups = []; + this.#defaultGroup = new ComponentsGroup({ + type: 'group', + id: Components.COMPONENTS_GROUP_OTHER, + name: t => t('core.components.other.title', 'Other'), + components: [], + }); + } + + hasGroup (id: string) { //TODO id is a string? + return this.#groups.some(ComponentsGroup.FIND_PREDICATE(id)); + } + + getGroup (id: string) { //TODO id is a string? + return this.#groups.find(ComponentsGroup.FIND_PREDICATE(id)); + } + + hasComponent ( + id: string, { groupId }: { groupId?: string } = {} + ) { //TODO groupId is a string ? id ? @ka + if (groupId) { + return this.getGroup(groupId)?.components + .some(Component.FIND_PREDICATE.bind(null, id)); + } + + for (const group of this.#groups) { + if (group.components.some(Component.FIND_PREDICATE(id))) { + return true; + } + } + + return this.#defaultGroup.components + .some(Component.FIND_PREDICATE.bind(null, id)); + } + + getComponent ( + id: string, + { groupId }: { groupId?: string } = {} + ) { //TODO groupId is a string ? id ? + if (groupId) { + return this.getGroup(groupId)?.components + ?.find(Component.FIND_PREDICATE(id)); + } + + for (const group of this.#groups) { + const component = group.components.find(Component.FIND_PREDICATE(id)); + + if (component) { + return component; + } + } + + return this.#defaultGroup.components.find(Component.FIND_PREDICATE(id)); + } + + append (component: ComponentObject) { + return this.add(component, { mode: 'append' }); + } + + prepend (component: ComponentObject) { + return this.add(component, { mode: 'prepend' }); + } + + add ( + component: ComponentObject | ComponentsGroupObject, + { mode = 'append' }: { mode?: string } = {}//TODO mode is a string ? + ) { + const mutateMethod = mode === 'append' ? 'push' : 'unshift'; + + // This component is a group, add a new group + if (component.type === Components.TYPE_GROUP) { + if (!this.hasGroup(component.id)) { + component = new ComponentsGroup(component); + (component as ComponentsGroupObject).components = + (component as ComponentsGroupObject).components || []; + + this.#groups[mutateMethod](component); + this.emit('groups.add', component); + } + + return; + } + + component = new Component(component); + + const group = component.group && this.hasGroup(component.group) + ? this.getGroup(component.group) + : this.#defaultGroup; + + const existing = this.getComponent(component.id, { groupId: group.id }); + + if (existing) { + this.#builder.logger.log( + 'Component already exists, updating definition.', + 'Old:', existing, + 'New:', component + ); + + const index = group.components.indexOf(existing); + group.components[index] = component; + this.emit('components.update', component, group); + } else { + group.components[mutateMethod](component); + this.emit('components.add', component, group); + } + } + + remove (id: string) { // TODO ID is a string ? + const groupIndex = this.#groups + .findIndex(ComponentsGroup.FIND_PREDICATE(id)); + + if (groupIndex !== -1) { + this.#builder.logger.log('Removing group:', this.#groups[groupIndex]); + const group = this.#groups[groupIndex]; + this.#groups.splice(groupIndex, 1); + this.emit('groups.remove', group); + + return; + } + + for (const group of this.#groups) { + const index = group.components + .findIndex(Component.FIND_PREDICATE(id)); + + if (index !== -1) { + this.#builder.logger + .log('Removing component:', group.components[index]); + const component = group.components[index]; + group.components.splice(index, 1); + this.emit('components.remove', component, group); + + return; + } + } + + const index = this.#defaultGroup.components + .findIndex(Component.FIND_PREDICATE(id)); + + if (index !== -1) { + this.#builder.logger.log( + 'Removing component:', this.#defaultGroup.components[index] + ); + const component = this.#defaultGroup.components[index]; + this.#defaultGroup.components.splice(index, 1); + this.emit('components.remove', component, this.#defaultGroup); + } + } + + getAll () { + return { + groups: this.#groups, + defaultGroup: this.#defaultGroup, + }; + } + + getDisplayableSettings ( + element, + { + fields, + component, + }: { + fields?: Array + component?: ComponentObject + } = {}) { + const displayable = []; + + if (!fields) { + component = component || this.getComponent(element.type); + + if (!component?.settings || !component?.settings.fields) { + return displayable; + } + + fields = component?.settings.fields; + } + + for (const setting of fields) { + if (Array.isArray(setting.fields)) { + displayable.push(...this.getDisplayableSettings(element, { + fields: setting.fields, + })); + } + + const settingFieldObject = setting as ComponentSettingsFieldObject; + + if ( + settingFieldObject.displayable === true + ) { + displayable.push(setting); + } else if (typeof settingFieldObject.displayable === 'function') { + if ( + settingFieldObject.displayable( + element, + { component, builder: this.#builder } + ) + ) { + displayable.push(setting); + } + } + } + + return displayable; + } + + toJSON () { + return this.getAll(); + } +} diff --git a/packages/core/lib/Emitter/index.js b/packages/core/lib/Emitter/index.js deleted file mode 100644 index 472e6909f..000000000 --- a/packages/core/lib/Emitter/index.js +++ /dev/null @@ -1,14 +0,0 @@ -export default class Emitter { - #subscribers = new Map(); - - subscribe (cb) { - const key = Symbol('store-subscriber'); - this.#subscribers.set(key, cb); - - return () => this.#subscribers.delete(key); - } - - emit (...args) { - this.#subscribers.forEach(c => c.bind(this)(...args)); - } -} diff --git a/packages/core/lib/Emitter/index.ts b/packages/core/lib/Emitter/index.ts new file mode 100644 index 000000000..22c4ffd71 --- /dev/null +++ b/packages/core/lib/Emitter/index.ts @@ -0,0 +1,26 @@ +export declare type EmitterCallback = (...args: any[]) => void; + +declare abstract class IEmitter { + constructor(); + + /** Subscribes to events and return an unsubscribe callback */ + subscribe(cb: EmitterCallback): EmitterCallback; + + /** Emits an event */ + emit(eventName: string, ...args: any[]): void; +} + +export default class Emitter implements IEmitter { + #subscribers: Map = new Map(); + + subscribe (cb: Function) { + const key = Symbol('store-subscriber'); + this.#subscribers.set(key, cb); + + return () => { this.#subscribers.delete(key); }; + } + + emit (...args: any[]) { + this.#subscribers.forEach(c => c.bind(this)(...args)); + } +} diff --git a/packages/core/lib/Fields/index.d.ts b/packages/core/lib/Fields/index.d.ts deleted file mode 100644 index c009f4bcc..000000000 --- a/packages/core/lib/Fields/index.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Field, FieldObject } from '../types'; -import { Builder } from '../Builder'; -import { Emitter } from '../Emitter'; - -export declare class Fields extends Emitter { - constructor(options?: { builder: Builder }); - - /** Checkes if a field exists */ - has(type: string): boolean; - - /** Get a field by its type */ - get(type: string): Field; - - /** Add a new field definition */ - add(field: FieldObject | Field): Field; - - /** Remove a field definition */ - remove(type: string): void; - - /** Get all fields */ - all(): Array; -} diff --git a/packages/core/lib/Fields/index.js b/packages/core/lib/Fields/index.ts similarity index 56% rename from packages/core/lib/Fields/index.js rename to packages/core/lib/Fields/index.ts index e6c867d02..92897e245 100644 --- a/packages/core/lib/Fields/index.js +++ b/packages/core/lib/Fields/index.ts @@ -1,25 +1,46 @@ -import { Field } from '../types'; +import { Field, FieldObject } from '../types'; import Emitter from '../Emitter'; +import Builder from '../Builder'; -export default class Fields extends Emitter { +export declare abstract class IFields { + constructor(options?: { builder: Builder }); + + /** Checkes if a field exists */ + has(type: string): boolean; + + /** Get a field by its type */ + get(type: string): Field; + + /** Add a new field definition */ + add(field: FieldObject | Field): Field; + + /** Remove a field definition */ + remove(type: string): void; + + /** Get all fields */ + all(): Array; +} + +export default class Fields extends Emitter implements IFields { #fields = []; #builder = null; - constructor ({ builder } = {}) { + field: object; + constructor ({ builder }: { builder?: Builder} = {}) { super(); this.#builder = builder; } - has (type) { + has (type: string) { return this.#fields.some(Field.FIND_PREDICATE(type)); } - get (type) { + get (type: string) { return this.#fields.find(Field.FIND_PREDICATE(type)); } - add (field) { + add (field: FieldObject | Field) { field = new Field(field); const existing = this.get(field.type); @@ -39,10 +60,10 @@ export default class Fields extends Emitter { this.emit('fields.add', this, field); } - return field; + return field as Field; } - remove (type) { + remove (type: string) { const index = this.#fields .findIndex(Field.FIND_PREDICATE(type)); diff --git a/packages/core/lib/Logger/index.d.ts b/packages/core/lib/Logger/index.d.ts deleted file mode 100644 index 23a171b2d..000000000 --- a/packages/core/lib/Logger/index.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Builder } from '../Builder'; - -export declare class Logger { - constructor(options?: { builder: Builder }); - log(...args: any[]): void; - warn(...args: any[]): void; -} diff --git a/packages/core/lib/Logger/index.js b/packages/core/lib/Logger/index.js deleted file mode 100644 index 37d122437..000000000 --- a/packages/core/lib/Logger/index.js +++ /dev/null @@ -1,18 +0,0 @@ -export default class Logger { - #builder = null; - - constructor ({ builder }) { - this.#builder = builder; - } - - log (...args) { - if (this.#builder.options.debug) { - // eslint-disable-next-line no-console - console.log('[oak]', ...args); - } - } - - warn (...args) { - console.warn('[oak]', ...args); - } -} diff --git a/packages/core/lib/Logger/index.ts b/packages/core/lib/Logger/index.ts new file mode 100644 index 000000000..0a7eaf4ec --- /dev/null +++ b/packages/core/lib/Logger/index.ts @@ -0,0 +1,26 @@ +import Builder from '../Builder'; + +declare abstract class ILogger { + constructor(options?: { builder: Builder }); + log(...args: any[]): void; + warn(...args: any[]): void; +} + +export default class Logger implements ILogger { + #builder = null; + + constructor ({ builder }: { builder?: Builder }) { + this.#builder = builder; + } + + log (...args: any[]) { + if (this.#builder.options.debug) { + // eslint-disable-next-line no-console + console.log('[oak]', ...args); + } + } + + warn (...args: any[]) { + console.warn('[oak]', ...args); + } +} diff --git a/packages/core/lib/Overrides/index.ts b/packages/core/lib/Overrides/index.ts new file mode 100644 index 000000000..ad9babb33 --- /dev/null +++ b/packages/core/lib/Overrides/index.ts @@ -0,0 +1,183 @@ +import { omit } from '@junipero/core'; + +import { ComponentOverride, ComponentOverrideObject, ComponentSettingsField, FieldOverride, FieldOverrideObject, SettingOverride } from '../types'; +import Emitter from '../Emitter'; +import Builder from '../Builder'; + +export declare class IOverrides { + constructor(options?: { builder: Builder }); + + /** Adds a new component or field override */ + add( + override: ComponentOverride | ComponentOverrideObject | FieldOverride | + FieldOverrideObject + ): ComponentOverride | FieldOverride; + + /** + * Retrieves an override for a component or a field. + * If the override type is 'component' and the output is set to 'field', + * the override will be returned as a field override object, potentially + * using a component setting field as base. + * + * Example: + * this.get('component', 'title', { + * output: 'field', + * setting: new ComponentSettingsField({ + * key: 'content', + * type: 'textarea', + * }), + * }) + * + * Will result in: + * { + * type: 'textarea', + * render: () => ..., + * } + * */ + get(type: 'component' | 'field' | 'setting', target: string, options?: { + output?: 'field', + setting?: ComponentSettingsField, + }): ComponentOverride | FieldOverrideObject; + + /** Removes an override by its id (if available) */ + remove (id: string): void; + + /** Merges overrides into a single non-typed object */ + merge(overrides: Array): object; + + /** Returns all available overrides */ + all(): Array; +} + +export default class Overrides extends Emitter implements IOverrides { + static FIND_PREDICATE = id => o => id ? o.id === id : null; + + #overrides = []; + #builder = null; + + constructor ({ builder }: { builder?: Builder } = {}) { + super(); + + this.#builder = builder; + } + + add ( + override: ComponentOverride | + ComponentOverrideObject | + FieldOverride | + FieldOverrideObject + ) { + const existing = this.#overrides + .find(Overrides.FIND_PREDICATE(override.id)); + + if (existing) { + this.#builder?.logger.log( + 'Override already exists, updating definition.', + 'Old:', existing, + 'New:', override + ); + + this.#overrides.splice(this.#overrides.indexOf(existing), 1, override); + this.emit('overrides.update', override); + + return override as ComponentOverride | FieldOverride; + } + + switch (override.type) { + case 'component': + override = new ComponentOverride(override); + this.#overrides.unshift(override); + break; + case 'field': + override = new FieldOverride(override); + this.#overrides.unshift(override); + break; + case 'setting': + override = new SettingOverride(override); + this.#overrides.unshift(override); + break; + } + + this.emit('overrides.add', this, override); + + return override as ComponentOverride | FieldOverride; + } + + get ( + overrideType: 'component' | 'field' | 'setting', + target: string, + { + output, + setting, + }: { + output?: 'field', + setting?: ComponentSettingsField + } = {} + ) { + const strategy = this.#builder?.options?.overrideStrategy; + const overrides = this.#overrides.filter(override => + override.type === overrideType && + (override.targets.includes('*') || override.targets.includes(target)) + ); + + switch (overrideType) { + case 'component': { + const override = strategy === 'merge' + ? this.merge(overrides) : overrides[0]; + + switch (output) { + case 'field': { + const newComponentField = override?.fields + ?.find(f => f.key === setting?.key); + + return Object.assign( + { type: newComponentField?.type || setting.type }, + this.#builder.getOverride('field', + newComponentField?.type || setting?.type), + omit(newComponentField || {}, ['type', 'key']) + ); + } + default: + return override; + } + } + case 'setting': + return overrides?.find(o => o.key === setting?.key); + default: + return strategy === 'merge' ? this.merge(overrides) : overrides[0]; + } + } + + remove (id: string) { + if (!id) { + return; + } + + const index = this.#overrides.findIndex(Overrides.FIND_PREDICATE(id)); + + if (index !== -1) { + this.#builder?.logger.log('Removing override:', this.#overrides[index]); + + const override = this.#overrides[index]; + this.#overrides.splice(index, 1); + this.emit('overrides.remove', this, override); + } + } + + merge (overrides: Array) { + return overrides.reduce((res, override) => { + Object.keys(override).forEach(key => { + if (override[key] === null || override[key] === undefined) { + delete override[key]; + } + }); + Object.assign(res, override); + + return res; + }, {}); + } + + all () { + return this.#overrides; + } +} diff --git a/packages/core/lib/Settings/index.js b/packages/core/lib/Settings/index.ts similarity index 66% rename from packages/core/lib/Settings/index.js rename to packages/core/lib/Settings/index.ts index 240c18136..153df5192 100644 --- a/packages/core/lib/Settings/index.js +++ b/packages/core/lib/Settings/index.ts @@ -1,7 +1,39 @@ -import { ComponentSettingsTab, ComponentSettingsField } from '../types'; +import { + ComponentSettingsTab, + ComponentSettingsField, + ComponentSettingsTabObject, + ComponentSettingsFieldObject, +} from '../types'; import Emitter from '../Emitter'; +import Builder from '../Builder'; -export default class Settings extends Emitter { +export declare class ISettings extends Emitter { + static TYPE_TAB: string; + static TYPE_SETTING: string; + + static SETTINGS_TAB_GENERAL: string; + static SETTINGS_TAB_STYLING: string; + static SETTINGS_TAB_RESPONSIVE: string; + + constructor(options?: { builder: Builder }); + + hasTab(id: string): boolean; + getTab(id: string): ComponentSettingsTab; + + hasSetting(id: string, opts?: { tabId?: string }): boolean; + getSetting(id: string, opts?: { tabId?: string }): ComponentSettingsField; + + add( + setting: ComponentSettingsTab | + ComponentSettingsTabObject | + ComponentSettingsField | + ComponentSettingsFieldObject + ): void; + remove(id: string): boolean; + + all(): Array; +} +export default class Settings extends Emitter implements ISettings { static TYPE_TAB = 'tab'; static TYPE_SETTING = 'setting'; @@ -12,27 +44,29 @@ export default class Settings extends Emitter { #builder = null; #tabs = null; - constructor ({ builder } = {}) { + constructor ({ builder }: { builder?: Builder } = {}) { super(); this.#builder = builder; this.#tabs = [new ComponentSettingsTab({ type: Settings.TYPE_TAB, id: Settings.SETTINGS_TAB_GENERAL, - title: t => t('core.settings.title', 'Settings'), + title: ( + t: (key: string, def: string) => string + ) => t('core.settings.title', 'Settings'), fields: [], })]; } - hasTab (id) { + hasTab (id: string) { return this.#tabs.some(ComponentSettingsTab.FIND_PREDICATE(id)); } - getTab (id) { + getTab (id: string) { return this.#tabs.find(ComponentSettingsTab.FIND_PREDICATE(id)); } - hasSetting (id, { tabId } = {}) { + hasSetting (id: string, { tabId }: { tabId?: string} = {}) { if (tabId) { return this.getTab(tabId)?.fields .some(ComponentSettingsField.FIND_PREDICATE(id)); @@ -47,7 +81,7 @@ export default class Settings extends Emitter { return false; } - getSetting (id, { tabId } = {}) { + getSetting (id: string, { tabId }: { tabId?: string} = {}) { if (tabId) { return this.getTab(tabId)?.fields .find(ComponentSettingsField.FIND_PREDICATE(id)); @@ -63,9 +97,12 @@ export default class Settings extends Emitter { } } - add (setting) { + add (setting: ComponentSettingsTab | + ComponentSettingsTabObject | + ComponentSettingsField | + ComponentSettingsFieldObject) { if ( - setting.type === Settings.TYPE_TAB && + (setting as ComponentSettingsFieldObject).type === Settings.TYPE_TAB && !this.hasTab(setting.id) ) { setting = new ComponentSettingsTab(setting); @@ -75,7 +112,9 @@ export default class Settings extends Emitter { return; } - setting = new ComponentSettingsField(setting); + setting = new ComponentSettingsField( + setting + ) as ComponentSettingsFieldObject | ComponentSettingsField; const tab = setting.tab && this.hasTab(setting.tab) ? this.getTab(setting.tab) @@ -84,7 +123,7 @@ export default class Settings extends Emitter { )); const existing = this - .getSetting(setting.id || setting.key, { tabId: tab.id }); + .getSetting((setting.id || setting.key) as string, { tabId: tab.id }); if (existing) { this.#builder?.logger.log( diff --git a/packages/core/lib/Store/index.d.ts b/packages/core/lib/Store/index.d.ts deleted file mode 100644 index 55fd3502c..000000000 --- a/packages/core/lib/Store/index.d.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { - Component, - ComponentOverride, - ComponentSettingsFieldKeyTuple, - ElementId, - ElementObject, -} from '../types'; -import { Builder } from '../Builder'; -import { Emitter } from '../Emitter'; - -export declare interface StoreSanitizeOptions { - component?: Component; - override?: ComponentOverride; - resetIds?: boolean; -} - -export declare interface StoreFindOptions { - parent?: Array; -} - -export declare type StoreFindDeepOptions = Partial; - -export declare class Store extends Emitter { - constructor(options?: { builder: Builder }); - - /** - * Check if an element id is valid. - * An Element ID is a string or a number, and cannot be empty. - */ - isIdValid(id: string | number): boolean; - - /** Check if two element ids are the same */ - isSameElement(elementId: ElementId, siblingId: ElementId): boolean; - - /** Get the content of the store */ - get(): Array; - - /** - * Set the content of the store. - * If the emit option is set to false, the store will not emit a change event. - */ - set(content: Array, options?: { emit?: boolean }): void; - - /** - * Sanitize an element object (adds missing properties, ids, etc.) - * If the resetIds option is set to true, the element id will be reset even - * if it already exists. - */ - sanitize( - element: ElementObject, - options?: StoreSanitizeOptions - ): ElementObject; - - /** Creates a new element object based on an existing component (or not) */ - createElement(type: string, options?: Partial<{ - baseElement?: ElementObject; - } & StoreSanitizeOptions>): ElementObject; - - /** Adds an element to the store */ - addElement(element: ElementObject, options?: Partial<{ - position?: 'before' | 'after'; - } & StoreFindOptions & StoreSanitizeOptions>): ElementObject; - - /** Adds multiple elements to the store */ - addElements(elements: Array, options?: Partial<{ - position?: 'before' | 'after'; - } & StoreFindOptions & StoreSanitizeOptions>): Array; - - /** Finds an element in the store */ - getElement(id: ElementId, options?: StoreFindDeepOptions): ElementObject; - - /** Removes an element from the the store */ - removeElement(id: ElementId, options?: StoreFindDeepOptions): boolean; - - /** Updates an element in the store with new props */ - setElement( - id: ElementId, - newContent: object, - options?: StoreFindDeepOptions - ): ElementObject; - - /** Moves an element next to a sibling (inside the same parent or not) */ - moveElement( - element: ElementObject, - sibling: ElementObject, - options?: Partial - ): ElementObject; - - /** Duplicate an element */ - duplicateElement( - element: ElementObject, - options?: StoreFindOptions - ): ElementObject; - - /** Recursively finds the nearest parent of an element */ - findNearestParent( - id: ElementId, - options?: StoreFindOptions - ): Array; - - /** Recursively checks if an element is inside a parent */ - contains(id: ElementId, options?: StoreFindOptions): boolean; - - /** Retrieves the setting value of an element */ - getElementSettings( - element: ElementObject, - key: string | Array | Array, - def?: any - ): any; - - /** Sets the setting value of an element */ - setElementSettings( - element: ElementObject, - key: string | Array | Array, - value: any - ): void; - - /** Commit changes into history */ - commit(): void; - - /** Undo the last change */ - undo(): void; - - /** Redo the last change */ - redo(): void; - - canUndo(): boolean; - canRedo(): boolean; - resetHistory(): void; -} diff --git a/packages/core/lib/Store/index.js b/packages/core/lib/Store/index.ts similarity index 71% rename from packages/core/lib/Store/index.js rename to packages/core/lib/Store/index.ts index d97ae3542..66f99d7a5 100644 --- a/packages/core/lib/Store/index.js +++ b/packages/core/lib/Store/index.ts @@ -1,6 +1,133 @@ import { exists, get, set, cloneDeep } from '@junipero/core'; import Emitter from '../Emitter'; +import { Component, ComponentObject, ComponentOverride, ComponentOverrideObject, ComponentSettingsFieldKeyTuple, ElementId, ElementObject } from '../types'; +import Builder from '../Builder'; + +export declare interface StoreSanitizeOptions { + component?: Component; + override?: ComponentOverride; + resetIds?: boolean; +} + +export declare interface StoreFindOptions { + parent?: Array; +} + +export declare type StoreFindDeepOptions = Partial; + +export declare class IStore { + constructor(options?: { builder: Builder }); + + /** + * Check if an element id is valid. + * An Element ID is a string or a number, and cannot be empty. + */ + isIdValid(id: string | number): boolean; + + /** Check if two element ids are the same */ + isSameElement(elementId: ElementId, siblingId: ElementId): boolean; + + /** Get the content of the store */ + get(): Array; + + /** + * Set the content of the store. + * If the emit option is set to false, the store will not emit a change event. + */ + set(content: Array, options?: { emit?: boolean }): void; + + /** + * Sanitize an element object (adds missing properties, ids, etc.) + * If the resetIds option is set to true, the element id will be reset even + * if it already exists. + */ + sanitize( + element: ElementObject, + options?: StoreSanitizeOptions + ): ElementObject; + + /** Creates a new element object based on an existing component (or not) */ + createElement(type: string, options?: Partial<{ + baseElement?: ElementObject; + } & StoreSanitizeOptions>): ElementObject; + + /** Adds an element to the store */ + addElement(element: ElementObject, options?: Partial<{ + position?: 'before' | 'after'; + } & StoreFindOptions & StoreSanitizeOptions>): ElementObject; + + /** Adds multiple elements to the store */ + addElements(elements: Array, options?: Partial<{ + position?: 'before' | 'after'; + } & StoreFindOptions & StoreSanitizeOptions>): Array; + + /** Finds an element in the store */ + getElement(id: ElementId, options?: StoreFindDeepOptions): ElementObject; + + /** Removes an element from the the store */ + removeElement(id: ElementId, options?: StoreFindDeepOptions): boolean; + + /** Updates an element in the store with new props */ + setElement( + id: ElementId, + newContent: object, + options?: StoreFindDeepOptions + ): ElementObject; + + /** Moves an element next to a sibling (inside the same parent or not) */ + moveElement( + element: ElementObject, + sibling: ElementObject, + options?: Partial + ): ElementObject; + + /** Duplicate an element */ + duplicateElement( + element: ElementObject, + options?: StoreFindOptions + ): ElementObject; + + /** Recursively finds the nearest parent of an element */ + findNearestParent( + id: ElementId, + options?: StoreFindOptions + ): Array; + + /** Recursively checks if an element is inside a parent */ + contains(id: ElementId, options?: StoreFindOptions): boolean; + + /** Retrieves the setting value of an element */ + getElementSettings( + element: ElementObject, + key: string | Array | Array, + def?: any + ): any; + + /** Sets the setting value of an element */ + setElementSettings( + element: ElementObject, + key: string | Array | Array, + value: any + ): void; + + /** Commit changes into history */ + commit(): void; + + /** Undo the last change */ + undo(): void; + + /** Redo the last change */ + redo(): void; + + canUndo(): boolean; + canRedo(): boolean; + resetHistory(): void; +} export default class Store extends Emitter { #content = []; @@ -39,6 +166,10 @@ export default class Store extends Emitter { component: c, override: o, ...opts + }: { + component?: ComponentObject, + override?: ComponentOverrideObject, + [_: string]: any } = {}) { if (!this.isIdValid(element.id) || opts.resetIds) { element.id = this.#builder.generateId(); @@ -82,6 +213,11 @@ export default class Store extends Emitter { override: o, baseElement, ...opts + }: { + component?: ComponentObject, + override?: ComponentOverrideObject, + baseElement?: ElementObject, + [_: string]: any } = {}) { const component = c || this.#builder.getComponent(type); const override = o || this.#builder.getOverride('component', component.id); @@ -114,6 +250,11 @@ export default class Store extends Emitter { position = 'after', component, ...opts + }: { + parent?: Array, + position?: 'before' | 'after', + component?: ComponentObject, + [_: string]: any } = {}) { this.#builder.logger.log('Adding element:', element, { parent, position }); @@ -193,7 +334,14 @@ export default class Store extends Emitter { } } - removeElement (id, { parent = this.#content, deep } = {}) { + removeElement ( + id: string, { + parent = this.#content, + deep, + }: { + parent?: Array, + deep?: boolean + } = {}) { if (!this.isIdValid(id)) { return; } @@ -229,10 +377,14 @@ export default class Store extends Emitter { return false; } - setElement (id, newContent, { + setElement (id: boolean, newContent: object, { element: e, parent = this.#content, deep, + }: { + element?: ElementObject, + parent?: Array, + deep?: boolean } = {}) { if (!this.isIdValid(id)) { return; @@ -256,7 +408,16 @@ export default class Store extends Emitter { return element; } - moveElement (element, sibling, { parent = this.#content, position } = {}) { + moveElement ( + element?: ElementObject, + sibling?: ElementObject, + { + parent = this.#content, + position, + }: { + parent?: Array, + position?: 'before' | 'after' + } = {}) { if ( this.isSameElement(element?.id, sibling?.id) || this.contains(sibling.id, { parent: element }) @@ -345,7 +506,7 @@ export default class Store extends Emitter { return null; } - contains (id, { parent = this.#content } = {}) { + contains (id, { parent = this.#content }: { parent?: ElementObject | Array } = {}) { // Force parent to be an array to be able to loop over it // ----- // In some cases (Store.moveElement for example), parent cannot be diff --git a/packages/core/lib/addons.d.ts b/packages/core/lib/addons.d.ts deleted file mode 100644 index 31301c59f..000000000 --- a/packages/core/lib/addons.d.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { - AddonObject, - ComponentObject, - ComponentSettingsTabObject, - ComponentsGroupObject, - FieldObject, -} from './types'; - -export function textField(...props: any[]): FieldObject; -export function textareaField(...props: any[]): FieldObject; -export function selectField(...props: any[]): FieldObject; -export function colorField(...props: any[]): FieldObject; -export function imageField(...props: any[]): FieldObject; -export function dateField(...props: any[]): FieldObject; -export function toggleField(...props: any[]): FieldObject; - -export function rowComponent(...props: any[]): ComponentObject; -export function colComponent(...props: any[]): ComponentObject; -export function emptySpaceComponent(...props: any[]): ComponentObject; -export function titleComponent(...props: any[]): ComponentObject; -export function textComponent(...props: any[]): ComponentObject; -export function imageComponent(...props: any[]): ComponentObject; -export function buttonComponent(...props: any[]): ComponentObject; -export function foldableComponent(...props: any[]): ComponentObject; - -export function stylingSettings(...props: any[]): ComponentSettingsTabObject; -export function responsiveSettings(...props: any[]): ComponentSettingsTabObject; - -export function baseFields(): Array; -export function baseComponents(): Array; -export function baseSettings(): Array; - -export function coreComponentsGroup(...props: any[]): ComponentsGroupObject; - -export function baseAddon(): AddonObject; diff --git a/packages/core/lib/addons.js b/packages/core/lib/addons.ts similarity index 56% rename from packages/core/lib/addons.js rename to packages/core/lib/addons.ts index 718b152c3..aec623c24 100644 --- a/packages/core/lib/addons.js +++ b/packages/core/lib/addons.ts @@ -1,50 +1,55 @@ -export const textField = (...props) => ({ +import { Component } from 'react'; + +import Builder from './Builder'; +import { ComponentObject, ComponentSettingsFieldObject, ElementObject, FieldObject, GetTextCallback, SettingOverrideObject } from './types'; + +export const textField = (...props: any): FieldObject => ({ type: 'text', deserialize: val => '' + val, render: () => null, ...props, }); -export const textareaField = (...props) => ({ +export const textareaField = (...props: any): FieldObject => ({ type: 'textarea', deserialize: val => '' + val, render: () => null, ...props, }); -export const selectField = (...props) => ({ +export const selectField = (...props: any): FieldObject => ({ type: 'select', render: () => null, ...props, }); -export const colorField = (...props) => ({ +export const colorField = (...props: any):FieldObject => ({ type: 'color', render: () => null, ...props, }); -export const imageField = (...props) => ({ +export const imageField = (...props: any): FieldObject => ({ type: 'image', render: () => null, ...props, }); -export const dateField = (...props) => ({ +export const dateField = (...props: any): FieldObject => ({ type: 'date', render: () => null, ...props, }); -export const toggleField = (...props) => ({ +export const toggleField = (...props: any): FieldObject => ({ type: 'toggle', render: () => null, ...props, }); -export const rowComponent = (...props) => ({ +export const rowComponent = (...props: any): ComponentObject => ({ id: 'row', - name: t => t('core.components.row.name', 'Row'), + name: (t: GetTextCallback) => t('core.components.row.name', 'Row'), type: 'component', render: () => null, icon: 'row', @@ -54,7 +59,9 @@ export const rowComponent = (...props) => ({ editable: true, options: [], settings: { - title: t => t('core.components.row.settings.title', 'Row options'), + title: ( + t: GetTextCallback + ) => t('core.components.row.settings.title', 'Row options'), floatingSettings: { placement: 'right-start', shift: { @@ -68,22 +75,28 @@ export const rowComponent = (...props) => ({ type: 'select', key: 'settings.flexDirection', default: 'row', - label: t => + label: (t: GetTextCallback) => t('core.components.row.settings.flexDirection.title', 'Direction'), options: [{ - title: t => t('core.components.row.settings.flexDirection.row', + title: ( + t: GetTextCallback + ) => t('core.components.row.settings.flexDirection.row', 'Row (left to right)'), value: 'row', }, { - title: t => t('core.components.row.settings.flexDirection.rowReverse', + title: ( + t: GetTextCallback + ) => t('core.components.row.settings.flexDirection.rowReverse', 'Reversed row (right to left)'), value: 'row-reverse', }, { - title: t => t('core.components.row.settings.flexDirection.column', + title: ( + t: GetTextCallback + ) => t('core.components.row.settings.flexDirection.column', 'Column (top to bottom)'), value: 'column', }, { - title: t => t( + title: (t: GetTextCallback) => t( 'core.components.row.settings.flexDirection.columnReverse', 'Reversed column (bottom to top)', ), @@ -93,28 +106,40 @@ export const rowComponent = (...props) => ({ type: 'select', key: 'settings.justifyContent', default: 'flex-start', - label: t => t('core.components.row.settings.justifyContent.title', + label: ( + t: GetTextCallback + ) => t('core.components.row.settings.justifyContent.title', 'Horizontal alignment'), options: [{ - title: t => t('core.components.row.settings.justifyContent.flexStart', + title: ( + t: GetTextCallback + ) => t('core.components.row.settings.justifyContent.flexStart', 'Left'), value: 'flex-start', }, { - title: t => t('core.components.row.settings.justifyContent.center', + title: ( + t: GetTextCallback + ) => t('core.components.row.settings.justifyContent.center', 'Center'), value: 'center', }, { - title: t => t('core.components.row.settings.justifyContent.flexEnd', + title: ( + t: GetTextCallback + ) => t('core.components.row.settings.justifyContent.flexEnd', 'Right'), value: 'flex-end', }, { - title: t => t( + title: ( + t: GetTextCallback + ) => t( 'core.components.row.settings.justifyContent.spaceBetween', 'Space between columns' ), value: 'space-between', }, { - title: t => t('core.components.row.settings.justifyContent.spaceAround', + title: ( + t: GetTextCallback + ) => t('core.components.row.settings.justifyContent.spaceAround', 'Space around columns'), value: 'space-around', }], @@ -122,22 +147,32 @@ export const rowComponent = (...props) => ({ type: 'select', key: 'settings.alignItems', default: 'flex-start', - label: t => t('core.components.row.settings.alignItems.title', + label: ( + t: GetTextCallback + ) => t('core.components.row.settings.alignItems.title', 'Vertical alignment'), options: [{ - title: t => t('core.components.row.settings.alignItems.flexStart', + title: ( + t: GetTextCallback + ) => t('core.components.row.settings.alignItems.flexStart', 'Top'), value: 'flex-start', }, { - title: t => t('core.components.row.settings.alignItems.center', + title: ( + t: GetTextCallback + ) => t('core.components.row.settings.alignItems.center', 'Center'), value: 'center', }, { - title: t => t('core.components.row.settings.alignItems.flexEnd', + title: ( + t: GetTextCallback + ) => t('core.components.row.settings.alignItems.flexEnd', 'Bottom'), value: 'flex-end', }, { - title: t => t('core.components.row.settings.alignItems.stretch', + title: ( + t: GetTextCallback + ) => t('core.components.row.settings.alignItems.stretch', 'Stretch'), value: 'stretch', }], @@ -145,21 +180,27 @@ export const rowComponent = (...props) => ({ type: 'select', key: 'settings.gutters', default: true, - label: t => t('core.components.row.settings.gutters.title', + label: ( + t: GetTextCallback + ) => t('core.components.row.settings.gutters.title', 'Column gap'), options: [{ - title: t => t('core.components.row.settings.gutters.enabled', + title: ( + t: GetTextCallback + ) => t('core.components.row.settings.gutters.enabled', 'Enabled'), value: true, }, { - title: t => t('core.components.row.settings.gutters.disabled', + title: ( + t: GetTextCallback + ) => t('core.components.row.settings.gutters.disabled', 'Disabled'), value: false, }], }], }, getContainers: element => [element.cols], - sanitize: (element, { builder } = {}) => { + sanitize: (element, { builder }: { builder?: Builder } = {}) => { const colComponent = builder.getComponent('col'); if (!colComponent) { @@ -198,17 +239,19 @@ const COL_SIZES = Array.from({ length: 12 }).map((_, i) => ({ })).reverse(); const COL_RESPONSIVE_SETTINGS = [{ - title: t => t('core.responsive.fluid', 'Flexible'), + title: (t: GetTextCallback) => t('core.responsive.fluid', 'Flexible'), value: 'fluid', }, { - title: t => t('core.responsive.auto', 'Adapted to content'), + title: ( + t: GetTextCallback + ) => t('core.responsive.auto', 'Adapted to content'), value: 'auto', }, ...COL_SIZES, { - title: t => t('core.responsive.hide', 'Hidden'), + title: (t: GetTextCallback) => t('core.responsive.hide', 'Hidden'), value: 'hide', }]; -export const colComponent = (...props) => ({ +export const colComponent = (...props): ComponentObject => ({ id: 'col', type: 'component', draggable: false, @@ -222,7 +265,9 @@ export const colComponent = (...props) => ({ editable: true, usable: false, settings: { - title: t => t('core.components.col.settings.title', 'Col options'), + title: ( + t: GetTextCallback + ) => t('core.components.col.settings.title', 'Col options'), floatingSettings: { placement: 'left-start', shift: { enabled: false }, @@ -232,14 +277,18 @@ export const colComponent = (...props) => ({ type: 'select', key: 'size', default: 'fluid', - label: t => t('core.components.col.settings.size.title', 'Column size'), + label: ( + t: GetTextCallback + ) => t('core.components.col.settings.size.title', 'Column size'), options: [ { - title: t => t('core.responsive.fluid', 'Flexible'), + title: (t: GetTextCallback) => t('core.responsive.fluid', 'Flexible'), value: 'fluid', }, { - title: t => t('core.responsive.auto', 'Adapted to content'), + title: ( + t: GetTextCallback + ) => t('core.responsive.auto', 'Adapted to content'), value: 'auto', }, ...COL_SIZES, @@ -248,35 +297,45 @@ export const colComponent = (...props) => ({ tab: 'responsive', key: 'responsive.xl', type: 'select', - label: t => t('core.responsive.xl', 'Extra-large screens'), + label: ( + t: GetTextCallback + ) => t('core.responsive.xl', 'Extra-large screens'), default: 'fluid', options: COL_RESPONSIVE_SETTINGS, }, { tab: 'responsive', key: 'responsive.lg', type: 'select', - label: t => t('core.responsive.lg', 'Large screens (desktop)'), + label: ( + t: GetTextCallback + ) => t('core.responsive.lg', 'Large screens (desktop)'), default: 'fluid', options: COL_RESPONSIVE_SETTINGS, }, { tab: 'responsive', key: 'responsive.md', type: 'select', - label: t => t('core.responsive.md', 'Medium screens (tablet)'), + label: ( + t: GetTextCallback + ) => t('core.responsive.md', 'Medium screens (tablet)'), default: 'fluid', options: COL_RESPONSIVE_SETTINGS, }, { tab: 'responsive', key: 'responsive.sm', type: 'select', - label: t => t('core.responsive.sm', 'Small screens (phones)'), + label: ( + t: GetTextCallback + ) => t('core.responsive.sm', 'Small screens (phones)'), default: 'fluid', options: COL_RESPONSIVE_SETTINGS, }, { tab: 'responsive', key: 'responsive.xs', type: 'select', - label: t => t('core.responsive.xs', 'Extra-small screens (old phones)'), + label: ( + t: GetTextCallback + ) => t('core.responsive.xs', 'Extra-small screens (old phones)'), default: 'fluid', options: COL_RESPONSIVE_SETTINGS, }], @@ -287,22 +346,26 @@ export const colComponent = (...props) => ({ ...props, }); -export const emptySpaceComponent = (...props) => ({ +export const emptySpaceComponent = (...props): ComponentObject => ({ id: 'empty-space', - name: t => t('core.components.emptySpace.name', 'Blank space'), + name: ( + t: GetTextCallback + ) => t('core.components.emptySpace.name', 'Blank space'), type: 'component', render: () => null, icon: 'blank_space', options: [], settings: { - title: t => + title: (t: GetTextCallback) => t('core.components.emptySpace.settings.title', 'Blank space options'), fields: [{ type: 'text', key: 'settings.height', default: '32px', displayable: true, - label: t => t('core.components.emptySpace.settings.height', 'Height'), + label: ( + t: GetTextCallback + ) => t('core.components.emptySpace.settings.height', 'Height'), }], }, editable: true, @@ -315,24 +378,30 @@ export const emptySpaceComponent = (...props) => ({ ...props, }); -export const titleComponent = (...props) => ({ +export const titleComponent = (...props): ComponentObject => ({ id: 'title', - name: t => t('core.components.title.name', 'Title'), + name: (t: GetTextCallback) => t('core.components.title.name', 'Title'), type: 'component', icon: 'title', editable: true, render: () => null, options: [], settings: { - title: t => t('core.components.title.settings.title', 'Title options'), + title: ( + t: GetTextCallback + ) => t('core.components.title.settings.title', 'Title options'), fields: [{ type: 'select', key: 'headingLevel', default: 'h1', displayable: true, - label: t => t('core.components.title.settings.type.title', 'Type'), + label: ( + t: GetTextCallback + ) => t('core.components.title.settings.type.title', 'Type'), options: Array.from({ length: 6 }).map((_, i) => ({ - title: t => t('core.components.type.value', 'Title') + + title: ( + t: GetTextCallback + ) => t('core.components.type.value', 'Title') + ` ${i + 1} (h${i + 1})`, value: `h${i + 1}`, })), @@ -340,7 +409,9 @@ export const titleComponent = (...props) => ({ type: 'textarea', key: 'content', default: '', - label: t => t('core.components.title.settings.content.title', 'Content'), + label: ( + t: GetTextCallback + ) => t('core.components.title.settings.content.title', 'Content'), }], }, construct: ({ builder } = {}) => ({ @@ -352,20 +423,24 @@ export const titleComponent = (...props) => ({ ...props, }); -export const textComponent = (...props) => ({ +export const textComponent = (...props): ComponentObject => ({ id: 'text', - name: t => t('core.components.text.name', 'Text'), + name: (t: GetTextCallback) => t('core.components.text.name', 'Text'), type: 'component', render: () => null, icon: 'multiline', options: [], settings: { - title: t => t('core.components.text.settings.title', 'Text options'), + title: ( + t: GetTextCallback + ) => t('core.components.text.settings.title', 'Text options'), fields: [{ type: 'textarea', key: 'content', default: '', - label: t => t('core.components.text.settings.content.title', 'Content'), + label: ( + t: GetTextCallback + ) => t('core.components.text.settings.content.title', 'Content'), }], }, editable: true, @@ -379,44 +454,48 @@ export const textComponent = (...props) => ({ ...props, }); -export const imageComponent = (...props) => ({ +export const imageComponent = (...props): ComponentObject => ({ id: 'image', - name: t => t('core.components.image.name', 'Image'), + name: (t: GetTextCallback) => t('core.components.image.name', 'Image'), type: 'component', render: () => null, icon: 'image', editable: true, options: [], settings: { - title: t => t('core.components.image.settings.title', 'Image options'), + title: ( + t: GetTextCallback + ) => t('core.components.image.settings.title', 'Image options'), fields: [{ type: 'image', key: ['url', 'name'], default: '', - label: t => t('core.components.image.settings.image.title', 'Image'), + label: ( + t: GetTextCallback + ) => t('core.components.image.settings.image.title', 'Image'), }, { type: 'select', key: 'settings.size', - label: t => t( + label: (t: GetTextCallback) => t( 'core.components.image.settings.image.size.title', 'Image size' ), default: 'auto', displayable: true, options: [{ - title: t => t( + title: (t: GetTextCallback) => t( 'core.components.image.settings.image.size.auto', 'Adapted to content' ), value: 'auto', }, { - title: t => t( + title: (t: GetTextCallback) => t( 'core.components.image.settings.image.size.full', 'Real size' ), value: 'full', }, { - title: t => t( + title: (t: GetTextCallback) => t( 'core.components.image.settings.image.size.custom', 'Custom' ), @@ -426,13 +505,13 @@ export const imageComponent = (...props) => ({ type: 'text', key: 'settings.width', displayable: true, - condition: element => + condition: (element: ElementObject) => element?.settings?.size === 'custom', - label: t => t( + label: (t: GetTextCallback) => t( 'core.components.image.settings.image.size.width', 'Image width' ), - placeholder: t => t( + placeholder: (t: GetTextCallback) => t( 'core.components.image.settings.image.size.width', 'Image width' ), @@ -440,13 +519,13 @@ export const imageComponent = (...props) => ({ type: 'text', key: 'settings.height', displayable: true, - condition: element => + condition: (element: ElementObject) => element?.settings?.size === 'custom', - label: t => t( + label: (t: GetTextCallback) => t( 'core.components.image.settings.image.size.height', 'Image height' ), - placeholder: t => t( + placeholder: (t: GetTextCallback) => t( 'core.components.image.settings.image.size.height', 'Image height' ), @@ -454,25 +533,25 @@ export const imageComponent = (...props) => ({ type: 'select', key: 'settings.textAlign', displayable: true, - label: t => t( + label: (t: GetTextCallback) => t( 'core.components.image.settings.image.align.title', 'Image alignment' ), default: 'left', options: [{ - title: t => t( + title: (t: GetTextCallback) => t( 'core.components.image.settings.image.align.left', 'Left' ), value: 'left', }, { - title: t => t( + title: (t: GetTextCallback) => t( 'core.components.image.settings.image.align.center', 'Center' ), value: 'center', }, { - title: t => t( + title: (t: GetTextCallback) => t( 'core.components.image.settings.image.align.right', 'Right' ), @@ -488,34 +567,40 @@ export const imageComponent = (...props) => ({ ...props, }); -export const buttonComponent = (...props) => ({ +export const buttonComponent = (...props): ComponentObject => ({ id: 'button', - name: t => t('core.components.button.name', 'Button'), + name: (t: GetTextCallback) => t('core.components.button.name', 'Button'), type: 'component', render: () => null, icon: 'button', options: [], settings: { - title: t => t('core.components.button.settings.title', 'Button options'), + title: ( + t: GetTextCallback + ) => t('core.components.button.settings.title', 'Button options'), fields: [{ type: 'textarea', key: 'content', default: '', - label: t => t('core.components.button.settings.content.title', 'Content'), + label: ( + t: GetTextCallback + ) => t('core.components.button.settings.content.title', 'Content'), }, { type: 'select', key: 'action', default: 'link', displayable: true, - label: t => t('core.components.button.settings.action.title', 'Action'), + label: ( + t: GetTextCallback + ) => t('core.components.button.settings.action.title', 'Action'), options: [{ - title: t => t( + title: (t: GetTextCallback) => t( 'core.components.button.settings.action.openLink', 'Open a link' ), value: 'link', }, { - title: t => t( + title: (t: GetTextCallback) => t( 'core.components.button.settings.action.fireEvent', 'Trigger an event' ), @@ -526,31 +611,37 @@ export const buttonComponent = (...props) => ({ key: 'url', default: '', displayable: true, - label: t => t('core.components.button.settings.url.title', 'URL link'), - condition: element => element.action === 'link', + label: ( + t: GetTextCallback + ) => t('core.components.button.settings.url.title', 'URL link'), + condition: (element: ElementObject) => element.action === 'link', }, { type: 'text', key: 'event', default: '', displayable: true, - label: t => t( + label: (t: GetTextCallback) => t( 'core.components.button.settings.event.title', 'Javascript event name' ), - condition: element => element.action === 'event', + condition: (element: ElementObject) => element.action === 'event', }, { type: 'select', key: 'settings.buttonType', default: 'button', - label: t => t( + label: (t: GetTextCallback) => t( 'core.components.button.settings.type.title', 'HTML element type' ), options: [{ - title: t => t('core.components.button.settings.type.button', 'Button'), + title: ( + t: GetTextCallback + ) => t('core.components.button.settings.type.button', 'Button'), value: 'button', }, { - title: t => t('core.components.button.settings.type.links', 'Link'), + title: ( + t: GetTextCallback + ) => t('core.components.button.settings.type.links', 'Link'), value: 'link', }], }], @@ -568,9 +659,9 @@ export const buttonComponent = (...props) => ({ ...props, }); -export const foldableComponent = (...props) => ({ +export const foldableComponent = (...props): ComponentObject => ({ id: 'foldable', - name: t => t('core.components.foldable.name', 'Foldable'), + name: (t: GetTextCallback) => t('core.components.foldable.name', 'Foldable'), type: 'component', render: () => null, icon: 'foldable', @@ -581,7 +672,7 @@ export const foldableComponent = (...props) => ({ getContainers: element => [element.content, element.seeMore, element.seeLess], settings: { - title: t => t( + title: (t: GetTextCallback) => t( 'core.components.foldable.settings.title', 'Foldable options'), floatingSettings: { placement: 'right-start', @@ -594,18 +685,18 @@ export const foldableComponent = (...props) => ({ key: 'settings.seeMorePosition', default: 'after', displayable: true, - label: t => t( + label: (t: GetTextCallback) => t( 'core.components.foldable.settings.seeMorePosition.title', 'See more placement' ), options: [{ - title: t => t( + title: (t: GetTextCallback) => t( 'core.components.foldable.settings.seeMorePosition.before', 'Before' ), value: 'before', }, { - title: t => t( + title: (t: GetTextCallback) => t( 'core.components.foldable.settings.seeMorePosition.after', 'After' ), @@ -625,51 +716,71 @@ export const foldableComponent = (...props) => ({ ...props, }); -export const stylingSettings = (...props) => ({ +export const stylingSettings = (props?: any): ComponentSettingsFieldObject => ({ id: 'styling', type: 'tab', - title: t => t('core.styling.title', 'Styling'), + title: (t: GetTextCallback) => t('core.styling.title', 'Styling'), ...props, fields: [...(props?.fields || []), { - label: t => t('core.styling.paddings.title', 'Inside spacing'), + label: ( + t: GetTextCallback + ) => t('core.styling.paddings.title', 'Inside spacing'), fields: [{ type: 'text', key: 'styles.paddingTop', - placeholder: t => t('core.styling.paddings.top', 'Top'), + placeholder: ( + t: GetTextCallback + ) => t('core.styling.paddings.top', 'Top'), }, { type: 'text', key: 'styles.paddingRight', - placeholder: t => t('core.styling.paddings.right', 'Right'), + placeholder: ( + t: GetTextCallback + ) => t('core.styling.paddings.right', 'Right'), }, { type: 'text', key: 'styles.paddingBottom', - placeholder: t => t('core.styling.paddings.bottom', 'Bottom'), + placeholder: ( + t: GetTextCallback + ) => t('core.styling.paddings.bottom', 'Bottom'), }, { type: 'text', key: 'styles.paddingLeft', - placeholder: t => t('core.styling.paddings.left', 'Left'), + placeholder: ( + t: GetTextCallback + ) => t('core.styling.paddings.left', 'Left'), }], }, { - label: t => t('core.styling.margins.title', 'Outside spacing'), + label: ( + t: GetTextCallback + ) => t('core.styling.margins.title', 'Outside spacing'), fields: [{ type: 'text', key: 'styles.marginTop', - placeholder: t => t('core.styling.margins.top', 'Top'), + placeholder: (t: GetTextCallback) => t('core.styling.margins.top', 'Top'), }, { type: 'text', key: 'styles.marginRight', - placeholder: t => t('core.styling.margins.right', 'Right'), + placeholder: ( + t: GetTextCallback + ) => t('core.styling.margins.right', 'Right'), }, { type: 'text', key: 'styles.marginBottom', - placeholder: t => t('core.styling.margins.bottom', 'Bottom'), + placeholder: ( + t: GetTextCallback + ) => t('core.styling.margins.bottom', 'Bottom'), }, { type: 'text', key: 'styles.marginLeft', - placeholder: t => t('core.styling.margins.left', 'Left'), + placeholder: ( + t: GetTextCallback + ) => t('core.styling.margins.left', 'Left'), }], }, { - label: t => t('core.styling.background.image.title', 'Background image'), + label: ( + t: GetTextCallback + ) => t('core.styling.background.image.title', 'Background image'), fields: [{ key: 'styles.backgroundImage', type: 'image', @@ -677,111 +788,133 @@ export const stylingSettings = (...props) => ({ iconOnly: true, }, }, { - label: t => t('core.styling.background.size.title', 'Size'), + label: ( + t: GetTextCallback + ) => t('core.styling.background.size.title', 'Size'), key: 'styles.backgroundSize', type: 'select', default: 'default', - placeholder: t => + placeholder: (t: GetTextCallback) => t('core.styling.background.size.title', 'Background size'), options: [{ - title: t => t('core.styling.background.size.default', 'Default'), + title: ( + t: GetTextCallback + ) => t('core.styling.background.size.default', 'Default'), value: 'default', }, { - title: t => t('core.styling.background.size.cover', 'Fill'), + title: ( + t: GetTextCallback + ) => t('core.styling.background.size.cover', 'Fill'), value: 'cover', }, { - title: t => t('core.styling.background.size.contain', 'Fit'), + title: ( + t: GetTextCallback + ) => t('core.styling.background.size.contain', 'Fit'), value: 'contain', }], }, { - label: t => t('core.styling.background.position.title', 'Position'), + label: ( + t: GetTextCallback + ) => t('core.styling.background.position.title', 'Position'), key: 'styles.backgroundPosition', type: 'select', default: 'center', - placeholder: t => + placeholder: (t: GetTextCallback) => t('core.styling.background.position.title', 'Background position'), options: [{ - title: t => t('core.styling.background.position.center', 'Centered'), + title: ( + t: GetTextCallback + ) => t('core.styling.background.position.center', 'Centered'), value: 'center', }, { - title: t => t('core.styling.background.position.top', 'Top'), + title: ( + t: GetTextCallback + ) => t('core.styling.background.position.top', 'Top'), value: 'top', }, { - title: t => t('core.styling.background.position.right', 'Right'), + title: ( + t: GetTextCallback + ) => t('core.styling.background.position.right', 'Right'), value: 'right', }, { - title: t => t('core.styling.background.position.bottom', 'Bottom'), + title: ( + t: GetTextCallback + ) => t('core.styling.background.position.bottom', 'Bottom'), value: 'bottom', }, { - title: t => t('core.styling.background.position.left', 'Left'), + title: ( + t: GetTextCallback + ) => t('core.styling.background.position.left', 'Left'), value: 'left', }, { - title: t => + title: (t: GetTextCallback) => t('core.styling.background.position.centerTop', 'Center top'), value: 'center top', }, { - title: t => + title: (t: GetTextCallback) => t('core.styling.background.position.centerBottom', 'Center bottom'), value: 'center bottom', }, { - title: t => + title: (t: GetTextCallback) => t('core.styling.background.position.leftCenter', 'Center left'), value: 'left center', }, { - title: t => + title: (t: GetTextCallback) => t('core.styling.background.position.leftTop', 'Top left'), value: 'left top', }, { - title: t => + title: (t: GetTextCallback) => t('core.styling.background.position.leftBottom', 'Bottom left'), value: 'left bottom', }, { - title: t => + title: (t: GetTextCallback) => t('core.styling.background.position.rightCenter', 'Center right'), value: 'right center', }, { - title: t => + title: (t: GetTextCallback) => t('core.styling.background.position.rightTop', 'Top right'), value: 'right top', }, { - title: t => + title: (t: GetTextCallback) => t('core.styling.background.position.rightBottom', 'Bottom right'), value: 'right bottom', }], }, { - label: t => t('core.styling.background.repeat.title', 'Repeat'), + label: ( + t: GetTextCallback + ) => t('core.styling.background.repeat.title', 'Repeat'), key: 'styles.backgroundRepeat', type: 'select', default: 'no-repeat', - placeholder: t => + placeholder: (t: GetTextCallback) => t('core.styling.background.repeat.title', 'Background repeat'), options: [{ - title: t => + title: (t: GetTextCallback) => t('core.styling.background.repeat.noRepeat', 'No repeat'), value: 'no-repeat', }, { - title: t => + title: (t: GetTextCallback) => t('core.styling.background.repeat.repeatX', 'Repeat horizontally'), value: 'repeat-x', }, { - title: t => + title: (t: GetTextCallback) => t('core.styling.background.repeat.repeatY', 'Repeat vertically'), value: 'repeat-y', }, { - title: t => t('core.styling.background.repeat.both', + title: (t: GetTextCallback) => t('core.styling.background.repeat.both', 'Repeat horizontally & vertically'), value: 'repeat', }, ], }], }, { - label: t => + label: (t: GetTextCallback) => t('core.styling.background.color.title', 'Background color'), placeholder: '#FFF', type: 'color', key: 'styles.backgroundColor', }, { - label: t => + label: (t: GetTextCallback) => t('core.styling.className.title', 'Additional CSS class'), type: 'text', placeholder: 'my-button', @@ -789,80 +922,90 @@ export const stylingSettings = (...props) => ({ }], }); -export const responsiveSettings = (...props) => ({ +export const responsiveSettings = (props?: any): SettingOverrideObject => ({ id: 'responsive', type: 'tab', - title: t => t('core.responsive.title', 'Responsive'), + title: (t: GetTextCallback) => t('core.responsive.title', 'Responsive'), ...props, fields: [...(props?.fields || []), { key: 'responsive.xl', type: 'select', - label: t => t('core.responsive.xl', 'Extra-large screens'), + label: ( + t: GetTextCallback + ) => t('core.responsive.xl', 'Extra-large screens'), default: 'show', options: [{ - title: t => t('core.responsive.show', 'Visible'), + title: (t: GetTextCallback) => t('core.responsive.show', 'Visible'), value: 'show', }, { - title: t => t('core.responsive.hide', 'Hidden'), + title: (t: GetTextCallback) => t('core.responsive.hide', 'Hidden'), value: 'hide', }], - condition: (_, { component } = {}) => + condition: (_, { component }: { component?: ComponentObject} = {}) => component.settings?.defaults?.responsive !== false, }, { key: 'responsive.lg', type: 'select', - label: t => t('core.responsive.lg', 'Large screens (desktop)'), + label: ( + t: GetTextCallback + ) => t('core.responsive.lg', 'Large screens (desktop)'), default: 'show', options: [{ - title: t => t('core.responsive.show', 'Visible'), + title: (t: GetTextCallback) => t('core.responsive.show', 'Visible'), value: 'show', }, { - title: t => t('core.responsive.hide', 'Hidden'), + title: (t: GetTextCallback) => t('core.responsive.hide', 'Hidden'), value: 'hide', }], - condition: (_, { component } = {}) => + condition: (_, { component }: { component?: ComponentObject} = {}) => component.settings?.defaults?.responsive !== false, }, { key: 'responsive.md', type: 'select', - label: t => t('core.responsive.md', 'Medium screens (tablet)'), + label: ( + t: GetTextCallback + ) => t('core.responsive.md', 'Medium screens (tablet)'), default: 'show', options: [{ - title: t => t('core.responsive.show', 'Visible'), + title: (t: GetTextCallback) => t('core.responsive.show', 'Visible'), value: 'show', }, { - title: t => t('core.responsive.hide', 'Hidden'), + title: (t: GetTextCallback) => t('core.responsive.hide', 'Hidden'), value: 'hide', }], - condition: (_, { component } = {}) => + condition: (_, { component }: { component?: ComponentObject} = {}) => component.settings?.defaults?.responsive !== false, }, { key: 'responsive.sm', type: 'select', - label: t => t('core.responsive.sm', 'Small screens (phones)'), + label: ( + t: GetTextCallback + ) => t('core.responsive.sm', 'Small screens (phones)'), default: 'show', options: [{ - title: t => t('core.responsive.show', 'Visible'), + title: (t: GetTextCallback) => t('core.responsive.show', 'Visible'), value: 'show', }, { - title: t => t('core.responsive.hide', 'Hidden'), + title: (t: GetTextCallback) => t('core.responsive.hide', 'Hidden'), value: 'hide', }], - condition: (_, { component } = {}) => + condition: (_, { component }: { component?: ComponentObject} = {}) => component.settings?.defaults?.responsive !== false, }, { key: 'responsive.xs', type: 'select', - label: t => t('core.responsive.xs', 'Extra-small screens (old phones)'), + label: ( + t: GetTextCallback + ) => t('core.responsive.xs', 'Extra-small screens (old phones)'), default: 'show', options: [{ - title: t => t('core.responsive.show', 'Visible'), + title: (t: GetTextCallback) => t('core.responsive.show', 'Visible'), value: 'show', }, { - title: t => t('core.responsive.hide', 'Hidden'), + title: (t: GetTextCallback) => t('core.responsive.hide', 'Hidden'), value: 'hide', }], - condition: (_, { component } = {}) => + condition: (_, { component }: { component?: ComponentObject} = {}) => component.settings?.defaults?.responsive !== false, }], }); @@ -896,7 +1039,9 @@ export const baseSettings = () => [ export const coreComponentsGroup = (...props) => ({ id: 'core', type: 'group', - name: t => t('core.components.core.title', 'Core components'), + name: ( + t: GetTextCallback + ) => t('core.components.core.title', 'Core components'), components: baseComponents(), ...props, }); diff --git a/packages/core/lib/index.d.ts b/packages/core/lib/index.d.ts deleted file mode 100644 index caef49878..000000000 --- a/packages/core/lib/index.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -export { Builder } from './Builder'; -export { Components } from './Components'; -export { Emitter } from './Emitter'; -export { Fields } from './Fields'; -export { Logger } from './Logger'; -export { Overrides } from './Overrides'; -export { - Store, - StoreSanitizeOptions, - StoreFindOptions, - StoreFindDeepOptions, -} from './Store'; -export { Texts } from './Texts'; -export { Settings } from './Settings'; - -export * from './addons'; -export * from './types'; diff --git a/packages/core/lib/types.ts b/packages/core/lib/types.ts new file mode 100644 index 000000000..6903a94ae --- /dev/null +++ b/packages/core/lib/types.ts @@ -0,0 +1,468 @@ +import Builder from './Builder'; + +export class BuilderOptions { + debug: boolean; + generateId: () => string | number; + historyLimit: number; + overrideStrategy: 'last' | 'merge'; + + constructor (props) { + this.debug = props.debug || false; + this.generateId = props.generateId; + this.historyLimit = props.historyLimit || 20; + this.overrideStrategy = props.overrideStrategy || 'last'; + } +} + +export class Component { + static FIND_PREDICATE = id => c => c.id === id; + type: string; + id: string; + group: string; + render: () => any; + sanitize: any; + construct: Function; + duplicate: Function; + icon: any; + getContainers: Function; + name: string; + hasCustomInnerContent: boolean; + draggable: boolean; + droppable: boolean; + usable: boolean; + editable: boolean; + disallow: any; + options: any; + settings: any; + + constructor (props: any) { + if (!props.id) { + throw new Error('Component must have an id'); + } + + this.type = 'component'; + this.id = props.id; + this.group = props.group; + this.render = props.render; + this.sanitize = props.sanitize; + this.construct = props.construct; + this.duplicate = props.duplicate; + this.icon = props.icon; + this.getContainers = props.getContainers; + this.name = props.name || ''; + this.hasCustomInnerContent = props.hasCustomInnerContent ?? false; + this.draggable = props.draggable ?? true; + this.droppable = props.droppable ?? true; + this.usable = props.usable ?? true; + this.editable = props.editable ?? true; + this.disallow = props.disallow || []; + this.options = (props.options || []).map(o => new ComponentOption(o)); + this.settings = new ComponentSettingsForm(props.settings || {}); + } +} + +export class ComponentsGroup { + static FIND_PREDICATE = id => g => g.id === id; + type: string; + id: string; + name: string; + usable: boolean; + components: Component[]; + constructor (props) { + if (!props.id) { + throw new Error('Component Group must have an id'); + } + + this.type = 'group'; + this.id = props.id; + this.name = props.name; + this.usable = props.usable ?? true; + this.components = (props.components || []).map(c => + c instanceof Component ? c : new Component(c) + ); + } +} + +export class Field { + type: string; + render: Function; + props: object; + static FIND_PREDICATE = type => f => f.type === type; + + constructor (props) { + if (!props.type) { + throw new Error('Field must have a type'); + } + + this.type = props.type; + this.render = props.render; + this.props = props.props || {}; + } +} + +export class ComponentOverride { + type: string; + id: string; + targets: Array; + fields: Array; + render: Function; + sanitize?: Function; + construct: Function; + duplicate: Function; + + constructor (props) { + this.type = 'component'; + this.id = props.id; + this.targets = props.targets || []; + this.fields = props.fields || []; + this.render = props.render; + this.sanitize = props.sanitize; + this.construct = props.construct; + this.duplicate = props.duplicate; + } +} + +export class FieldOverride { + type: string; + id: string; + targets: Array; + render: Function; + props: object; + + constructor (props) { + this.type = 'field'; + this.id = props.id; + this.targets = props.targets || []; + this.render = props.render; + this.props = props.props || {}; + } +} + +export class SettingOverride { + type: string; + key: string; + targets: Array; + id: string; + placeholder: string; + default: any; + options: Array; + label: string; + description: string; + displayable: boolean; + valueType: string; + condition: Function; + priority: number; + fields: Array; + props: object; + + constructor (props) { + this.type = 'setting'; + this.key = props.key; + this.targets = props.targets || []; + this.id = props.id; + this.placeholder = props.placeholder; + this.default = props.default; + this.options = props.options; + this.label = props.label; + this.description = props.description; + this.displayable = props.displayable; + this.valueType = props.valueType; + this.condition = props.condition; + this.priority = props.priority || 0; + this.fields = (props.fields || []).map(f => new ComponentSettingsField(f)); + this.props = props.props; + } +} + +export class ComponentOption { + icon: any; + render: Function; + + constructor (props) { + this.icon = props.icon; + this.render = props.render; + } +} + +export class ComponentSettingsForm { + title: string; + floatingSettings: any; + defaults: object; + fields: Array; + + constructor (props) { + this.title = props.title; + this.floatingSettings = props.floatingSettings; + this.defaults = props.defaults || {}; + this.fields = (props.fields || []).map(t => + t.type === 'tab' + ? t instanceof ComponentSettingsTab ? t : new ComponentSettingsTab(t) + : t instanceof ComponentSettingsField + ? t : new ComponentSettingsField(t) + ); + } +} + +export class ComponentSettingsTab { + static FIND_PREDICATE = id => t => t.id === id; + type: string; + id: string; + title: string; + priority: number; + condition: Function; + fields: Array; + + constructor (props) { + if (!props.id) { + throw new Error('ComponentSettingsTab must have an id'); + } + + this.type = 'tab'; + this.id = props.id; + this.priority = props.priority || 0; + this.title = props.title; + this.condition = props.condition; + this.fields = (props.fields || []).map(f => + f instanceof ComponentSettingsField ? f : new ComponentSettingsField(f)); + } +} + +export class ComponentSettingsField { + static FIND_PREDICATE = id => f => f.id === id || f.key === id; + type: string; + tab: string; + key: string; + id: string; + placeholder: string; + default: any; + options: Array; + label: string; + info: string; + description: string; + displayable: boolean; + valueType: string; + condition: Function; + priority: number; + fields: Array; + props: object; + + constructor (props) { + if (!props.fields && !props.type) { + throw new Error('ComponentSettingsField must have a type (or be ' + + 'a group of fields)'); + } + + this.type = props.type; + this.tab = props.tab; + this.key = props.key; + this.id = props.id; + this.placeholder = props.placeholder; + this.default = props.default; + this.options = props.options; + this.label = props.label; + this.info = props.info; + this.description = props.description; + this.displayable = props.displayable; + this.valueType = props.valueType; + this.condition = props.condition; + this.priority = props.priority || 0; + this.fields = (props.fields || []).map(f => new ComponentSettingsField(f)); + this.props = props.props; + } +} + +export class TextsSheet { + static FIND_PREDICATE = id => s => s.id === id; + id: string; + texts: object; + constructor (props) { + if (!props.id) { + throw new Error('TextsSheet must have an id'); + } + + this.id = props.id; + this.texts = props.texts || {}; + } +} + +export declare interface GetTextCallback { + (key: string | GetTextCallback, def?: any): any; +} + +export declare type ElementId = string | number; + +export declare interface ElementObject { + id?: ElementId; + type: string; + [_: string]: any +} + +export declare interface ComponentOptionObject { + icon: any; + render?(): any; +} + +export declare interface ComponentSettingsFieldKeyTuple { + from: string; + to: string; + default: any; +} + +export declare interface FieldObject { + type: string; + props?: object; + render?(props: any): any; +} + +export declare interface ComponentOverrideObject { + id?: string; + type?: string; + targets?: string[]; + fields?: ComponentSettingsFieldObject[]; + construct?(opts?: { builder?: Builder }): ElementObject; + render?(props?: any): any; + sanitize?(): any; + duplicate?(elmt?: ElementObject): ElementObject; +} + +export declare interface FieldOverrideObject { + id: string; + type: string; + targets: string[]; + props: Record; + render?(): any; +} + +export declare interface SettingOverrideObject { + type: string; + targets?: string[]; + key?: string | string[] | ComponentSettingsFieldKeyTuple[]; + id?: string; + label?: string | GetTextCallback; + title?: string | GetTextCallback; + info?: string | GetTextCallback; + description?: string | GetTextCallback; + placeholder?: string | GetTextCallback; + default?: any; + displayable?: boolean; + valueType?: string; + priority?: number; + fields?: (ComponentSettingsField | ComponentSettingsFieldObject)[]; + props?: Record; + condition?(element: Element | ElementObject, opts?: { + component: Component | ComponentObject; + builder: Builder; + }): boolean; +} + +export declare interface ComponentSettingsFieldOptionObject { + value?: any; + title?: string | GetTextCallback; + imageTransformation?: { + width: number; + height: number; + }; +} + +export declare interface ComponentSettingsFieldObject { + priority?: number; + type: string; + key?: string | string[]; + tab?: string; + id?: string; + label?: string | GetTextCallback; + info?: string | GetTextCallback; + description?: string | GetTextCallback; + title?: string | GetTextCallback; + placeholder?: string | GetTextCallback; + default?: any; + options?: ComponentSettingsFieldOptionObject[] | Record[]; + displayable?: boolean; + valueType?: string; + fields?: ComponentSettingsFieldObject[]; + props?: Record; + condition?(element: Element | ElementObject, opts?: { + component: Component | ComponentObject; + builder: Builder; + }): boolean; +} + +export declare interface ComponentSettingsTabObject { + id: string; + priority?: number; + title?: string | GetTextCallback; + fields?: (ComponentSettingsField | ComponentSettingsFieldObject)[]; + condition?(element: Element | ElementObject, opts?: { + component: Component | ComponentObject; + builder: Builder; + }): boolean; +} + +export declare class ComponentSettingsFormObject { + title?: string | GetTextCallback; + floatingSettings?: Record; + defaults?: any; + fields?: ( + ComponentSettingsTab | + ComponentSettingsTabObject | + ComponentSettingsField | + ComponentSettingsFieldObject + )[]; +} + +export declare interface ComponentObject { + type?: string; + id?: string; + group?: string; + icon?: any; + name?: string | GetTextCallback; + hasCustomInnerContent?: boolean; + draggable?: boolean; + droppable?: boolean; + usable?: boolean; + editable?: boolean; + options?: (ComponentOption | ComponentOptionObject)[]; + settings?: ComponentSettingsForm | ComponentSettingsFormObject; + disallow?: string[]; + render?(props?: any): any; + sanitize?(): any; + construct?(opts?: { builder?: Builder }): ElementObject; + duplicate?(elmt?: ElementObject): ElementObject; + getContainers?(element: ElementObject): ElementObject[]; +} + +export declare interface ComponentsGroupObject { + type: string; + id: string; + name: string; + usable: boolean; + components: (Component | ComponentObject)[]; +} + +export declare interface TextsSheetObject { + id: string; + texts: Record; +} + +export declare interface ComponentTabOject { + id: string; + title: string | GetTextCallback; + components: (Component | ComponentObject)[]; +} +export declare interface AddonObject { + components?: (Component | ComponentObject | ComponentTabOject)[]; + fields?: (Field | FieldObject)[]; + texts?: (TextsSheet | TextsSheetObject)[]; + overrides?: ( + ComponentOverride | + ComponentOverrideObject | + FieldOverride | + FieldOverrideObject + )[]; + settings?: ( + ComponentSettingsTab | + ComponentSettingsTabObject | + ComponentSettingsField | + ComponentSettingsFieldObject + )[]; +} diff --git a/tsconfig.json b/tsconfig.json index 0f421acbc..de8de596a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "target": "ES2015", "paths": { "@oakjs/core": [ "./packages/core/lib" From 88dec47fce29d8e3768305b39c5fc9cdb1e67ffa Mon Sep 17 00:00:00 2001 From: maxime Da Silva Date: Wed, 17 Apr 2024 16:10:39 +0200 Subject: [PATCH 04/50] feat(typescript): wip typescript --- package.json | 2 + packages/core/lib/Builder/index.d.ts | 117 ------ packages/core/lib/Builder/index.js | 256 ------------- packages/core/lib/Builder/index.ts | 7 +- packages/core/lib/Components/index.js | 202 ----------- packages/core/lib/Components/index.ts | 6 +- packages/core/lib/Emitter/index.d.ts | 11 - packages/core/lib/Overrides/index.d.ts | 55 --- packages/core/lib/Overrides/index.js | 122 ------- packages/core/lib/Texts/index.d.ts | 31 -- .../core/lib/Texts/{index.js => index.ts} | 35 +- packages/core/lib/{index.js => index.ts} | 0 packages/core/lib/types.d.ts | 337 ------------------ packages/core/lib/types.js | 192 ---------- packages/core/lib/types.ts | 15 +- packages/core/package.json | 3 + packages/core/rollup.config.mjs | 138 ++++--- packages/core/tsconfig.json | 8 + .../{HistoryButtons.js => HistoryButtons.tsx} | 17 +- packages/react/lib/Builder/index.d.ts | 62 ---- .../react/lib/Builder/{index.js => index.tsx} | 69 +++- .../lib/Catalogue/{index.js => index.tsx} | 28 +- packages/react/lib/Container/index.d.ts | 17 - .../lib/Container/{index.js => index.tsx} | 29 +- .../{index.js => index.tsx} | 17 +- packages/react/lib/Text/index.d.ts | 2 +- packages/react/lib/contexts.d.ts | 20 -- packages/react/lib/contexts.js | 3 - packages/react/lib/contexts.ts | 29 ++ packages/react/lib/hooks.d.ts | 3 + tsconfig.json | 6 +- yarn.lock | 238 ++++++++++++- 32 files changed, 551 insertions(+), 1526 deletions(-) delete mode 100644 packages/core/lib/Builder/index.d.ts delete mode 100644 packages/core/lib/Builder/index.js delete mode 100644 packages/core/lib/Components/index.js delete mode 100644 packages/core/lib/Emitter/index.d.ts delete mode 100644 packages/core/lib/Overrides/index.d.ts delete mode 100644 packages/core/lib/Overrides/index.js delete mode 100644 packages/core/lib/Texts/index.d.ts rename packages/core/lib/Texts/{index.js => index.ts} (70%) rename packages/core/lib/{index.js => index.ts} (100%) delete mode 100644 packages/core/lib/types.d.ts delete mode 100644 packages/core/lib/types.js create mode 100644 packages/core/tsconfig.json rename packages/react/lib/Builder/{HistoryButtons.js => HistoryButtons.tsx} (67%) delete mode 100644 packages/react/lib/Builder/index.d.ts rename packages/react/lib/Builder/{index.js => index.tsx} (60%) rename packages/react/lib/Catalogue/{index.js => index.tsx} (87%) delete mode 100644 packages/react/lib/Container/index.d.ts rename packages/react/lib/Container/{index.js => index.tsx} (75%) rename packages/react/lib/DisplayableSettings/{index.js => index.tsx} (73%) delete mode 100644 packages/react/lib/contexts.d.ts delete mode 100644 packages/react/lib/contexts.js create mode 100644 packages/react/lib/contexts.ts diff --git a/package.json b/package.json index 9d72c5075..a16219aa2 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,9 @@ "@rollup/plugin-babel": "6.0.4", "@rollup/plugin-commonjs": "25.0.7", "@rollup/plugin-node-resolve": "15.2.3", + "@rollup/plugin-swc": "0.3.0", "@rollup/plugin-terser": "0.4.4", + "@rollup/plugin-typescript": "11.1.6", "@storybook/addon-actions": "7.6.17", "@storybook/react": "7.6.17", "@storybook/react-webpack5": "7.6.17", diff --git a/packages/core/lib/Builder/index.d.ts b/packages/core/lib/Builder/index.d.ts deleted file mode 100644 index 1b1c53646..000000000 --- a/packages/core/lib/Builder/index.d.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { - AddonObject, - ElementObject, - BuilderOptions, - Component, - ComponentObject, - ComponentsGroup, - ComponentOverride, - Field, - FieldObject, - FieldOverride, - TextsSheet, - TextsSheetObject, - ComponentSettingsField, - SettingOverride, - ComponentOverrideObject, - ElementId, - ComponentSettingsFieldKeyTuple, - GetTextCallback, - ComponentSettingsTab, -} from '../types'; -import { Logger } from '../Logger'; -import { Emitter, EmitterCallback } from '../Emitter'; - -export declare class Builder extends Emitter { - constructor(opts?: { - addons?: AddonObject[]; - content?: ElementObject[]; - options?: BuilderOptions; - }); - - options: BuilderOptions; - logger: Logger; - - subscribe(cb: EmitterCallback): (() => void); - setAddons(addons: AddonObject[]): void; - addAddon(addon: AddonObject): void; - removeAddon(addon: AddonObject): void; - getAvailableComponents(): ComponentsGroup[]; - getComponent(type: string): Component; - getComponentDisplayableSettings( - element: ElementObject, - opts?: { - component?: Component | ComponentObject; - fields?: (Field | FieldObject)[]; - }, - ): ComponentSettingsField[]; - getAvailableFields(): Array; - getField(type: string): Field; - getOverride( - type: string, - target: string, - opts?: { - output?: 'field'; - setting?: ComponentSettingsField; - }, - ): ComponentOverride | FieldOverride; - mergeOverrides( - overrides: (ComponentOverride | FieldOverride | SettingOverride)[] - ): void; - getContent(): ElementObject[]; - setContent(content: ElementObject[], opts?: { emit?: boolean }): void; - createElement(type: string, opts: { - component?: Component | ComponentObject; - override?: ComponentOverride | ComponentOverrideObject; - baseElement?: ElementObject; - resetIds?: boolean; - }): object; - addElement(element: ElementObject, opts?: { - component?: Component | ComponentObject; - parent?: ElementObject[]; - position?: 'before' | 'after'; - }): Element; - addElements(elements: ElementObject[], options?: { - parent?: ElementObject[]; - position?: 'before' | 'after'; - }): ElementObject[]; - getElement(id: ElementId): ElementObject; - removeElement(id: ElementId, opts?: { - deep?: boolean; - }): boolean; - setElement(id: ElementId, updates: ElementObject, opts?: { - deep?: boolean; - }): ElementObject; - moveElement( - element: ElementObject, - sibling: ElementObject, - opts?: { - deep?: boolean; - position?: 'before' | 'after'; - parent: ElementObject; - } - ): ElementObject; - duplicateElement( - element: ElementObject, - opts?: { - deep?: boolean; - } - ): ElementObject; - getElementSettings( - element: ElementObject, - key: string | string[] | ComponentSettingsFieldKeyTuple[], - def?: any - ): any; - canUndo(): boolean; - canRedo(): boolean; - undo(): void; - redo(): void; - resetHistory(): void; - generateId(): string; - getTextSheet(id: string): TextsSheet; - getText(key: string | GetTextCallback, def?: any): any; - setText(key: string, value: any): void; - getActiveTextSheet(): TextsSheet; - setActiveTextSheet(id: string): void; - getAvailableSettings(): (ComponentSettingsTab | ComponentSettingsField)[]; -} diff --git a/packages/core/lib/Builder/index.js b/packages/core/lib/Builder/index.js deleted file mode 100644 index 88d570071..000000000 --- a/packages/core/lib/Builder/index.js +++ /dev/null @@ -1,256 +0,0 @@ -import { exists } from '@junipero/core'; -import { v4 as uuid } from 'uuid'; - -import { BuilderOptions } from '../types'; -import Components from '../Components'; -import Emitter from '../Emitter'; -import Fields from '../Fields'; -import Overrides from '../Overrides'; -import Store from '../Store'; -import Texts from '../Texts'; -import Logger from '../Logger'; -import Settings from '../Settings'; - -export default class Builder extends Emitter { - #components = null; - #fields = null; - #overrides = null; - #texts = null; - #store = null; - #settings = null; - #addons = []; - - constructor ({ addons, content, options = {} } = {}) { - super(); - - this.options = new BuilderOptions(options); - this.logger = new Logger({ builder: this }); - - this.#components = new Components({ builder: this }); - this.#fields = new Fields({ builder: this }); - this.#overrides = new Overrides({ builder: this }); - this.#store = new Store({ builder: this }); - this.#texts = new Texts({ builder: this }); - this.#settings = new Settings({ builder: this }); - - if (Array.isArray(addons)) { - this.#addons = addons; - addons.forEach(addon => { - this.logger.log('Initializing builder with addon:', addon); - this.addAddon(addon); - }); - } - - if (content) { - this.logger.log('Initializing builder with content:', content); - this.#store.set(content); - } - } - - subscribe (callback) { - const subscriptions = [ - super.subscribe(callback), - this.#store.subscribe(this.emit.bind(this)), - this.#texts.subscribe(this.emit.bind(this)), - this.#components.subscribe(this.emit.bind(this)), - this.#fields.subscribe(this.emit.bind(this)), - this.#overrides.subscribe(this.emit.bind(this)), - this.#settings.subscribe(this.emit.bind(this)), - ]; - - return () => { - subscriptions.forEach(u => u()); - }; - } - - setAddons (addons) { - this.#addons?.forEach(addon => { - this.logger.log('Removing builder addon:', addon); - this.removeAddon(addon); - }); - - this.#addons = addons; - this.#addons?.forEach(addon => { - this.logger.log('Updating builder addon:', addon); - this.addAddon(addon); - }); - - this.emit('addons.update', addons); - } - - addAddon (addon) { - addon.fields?.forEach(field => { - this.#fields.add(field); - }); - - addon.components?.forEach(component => { - this.#components.add(component); - }); - - addon.texts?.forEach(sheet => { - this.#texts.addSheet(sheet); - }); - - addon.overrides?.forEach(override => { - this.#overrides.add(override); - }); - - addon.settings?.forEach(setting => { - this.#settings.add(setting); - }); - } - - removeAddon (addon) { - addon.settings?.forEach(setting => { - this.#settings.remove(setting.id); - }); - - addon.overrides?.forEach(override => { - this.#overrides.remove(override.id); - }); - - addon.texts?.forEach(sheet => { - this.#texts.removeSheet(sheet.id); - }); - - addon.components?.forEach(component => { - this.#components.remove(component.id); - }); - - addon.fields?.forEach(field => { - this.#fields.remove(field.type); - }); - } - - getAvailableComponents () { - const { groups, defaultGroup } = this.#components.all(); - - return [...groups, defaultGroup]; - } - - getComponent (type) { - return this.#components.getComponent(type); - } - - getComponentDisplayableSettings (element, { component }) { - return [ - ...this.#components - .getDisplayableSettings?.(element, { component }) || [], - ...this.#settings.getDisplayable?.(element) || [], - ]; - } - - getAvailableFields () { - return this.#fields.all(); - } - - getField (type) { - return this.#fields.get(type); - } - - getOverride (type, target, opts) { - return this.#overrides.get(type, target, opts); - } - - mergeOverrides (overrides) { - return this.#overrides.merge(overrides); - } - - getContent () { - return this.#store.get(); - } - - setContent (content, options) { - this.#store.set(content, options); - } - - createElement (type, options) { - return this.#store.createElement(type, options); - } - - addElement (element, options) { - return this.#store.addElement(element, options); - } - - addElements (elements, options) { - return this.#store.addElements(elements, options); - } - - getElement (id, options) { - return this.#store.getElement(id, options); - } - - removeElement (id, options) { - return this.#store.removeElement(id, options); - } - - setElement (id, updates, options) { - return this.#store.setElement(id, updates, options); - } - - moveElement (element, sibling, options) { - return this.#store.moveElement(element, sibling, options); - } - - duplicateElement (element, options) { - return this.#store.duplicateElement(element, options); - } - - getElementSettings (element, key, def) { - return this.#store.getElementSettings(element, key, def); - } - - setElementSettings (element, key, value) { - return this.#store.setElementSettings(element, key, value); - } - - undo () { - this.#store.undo(); - } - - redo () { - this.#store.redo(); - } - - canUndo () { - return this.#store.canUndo(); - } - - canRedo () { - return this.#store.canRedo(); - } - - resetHistory () { - this.#store.resetHistory(); - } - - generateId () { - const customId = this.options.generateId?.(); - - return exists(customId) && customId !== '' ? customId : uuid(); - } - - getTextSheet (id) { - return this.#texts.getSheet(id); - } - - getText (key, def) { - return this.#texts.get(key, def); - } - - setText (key, value) { - return this.#texts.set(key, value); - } - - getActiveTextSheet () { - return this.#texts.getActiveSheet(); - } - - setActiveTextSheet (id) { - return this.#texts.setActiveSheet(id); - } - - getAvailableSettings () { - return this.#settings.all(); - } -} diff --git a/packages/core/lib/Builder/index.ts b/packages/core/lib/Builder/index.ts index ae8ea1336..abb99bf2e 100644 --- a/packages/core/lib/Builder/index.ts +++ b/packages/core/lib/Builder/index.ts @@ -8,7 +8,7 @@ import Components from '../Components'; import Fields from '../Fields'; import Overrides from '../Overrides'; import Store from '../Store'; -import { Texts } from '../Texts'; +import Texts from '../Texts'; import Settings from '../Settings'; declare interface IBuilder { @@ -27,7 +27,10 @@ export default class Builder extends Emitter implements IBuilder { #settings = null; #addons = []; - constructor ({ addons, content, options = {} }: {[_: string]: any} = {}) { // TODO fix it + constructor ( + { addons, content, options = {} }: + {[_: string]: any} = {} + ) { // TODO fix it super(); this.options = new BuilderOptions(options); diff --git a/packages/core/lib/Components/index.js b/packages/core/lib/Components/index.js deleted file mode 100644 index 82458b425..000000000 --- a/packages/core/lib/Components/index.js +++ /dev/null @@ -1,202 +0,0 @@ -import { Component, ComponentsGroup } from '../types'; -import Emitter from '../Emitter'; - -export default class Components extends Emitter { - static TYPE_COMPONENT = 'component'; - static TYPE_GROUP = 'group'; - - static COMPONENTS_GROUP_CORE = 'core'; - static COMPONENTS_GROUP_OTHER = 'other'; - - #builder = null; - #groups = null; - #defaultGroup = null; // Other tab - - constructor ({ builder } = {}) { - super(); - - this.#builder = builder; - this.#groups = []; - this.#defaultGroup = new ComponentsGroup({ - type: 'group', - id: Components.COMPONENTS_GROUP_OTHER, - name: t => t('core.components.other.title', 'Other'), - components: [], - }); - } - - hasGroup (id) { - return this.#groups.some(ComponentsGroup.FIND_PREDICATE(id)); - } - - getGroup (id) { - return this.#groups.find(ComponentsGroup.FIND_PREDICATE(id)); - } - - hasComponent (id, { groupId } = {}) { - if (groupId) { - return this.getGroup(groupId)?.components - .some(Component.FIND_PREDICATE.bind(null, id)); - } - - for (const group of this.#groups) { - if (group.components.some(Component.FIND_PREDICATE(id))) { - return true; - } - } - - return this.#defaultGroup.components - .some(Component.FIND_PREDICATE.bind(null, id)); - } - - getComponent (id, { groupId } = {}) { - if (groupId) { - return this.getGroup(groupId)?.components - ?.find(Component.FIND_PREDICATE(id)); - } - - for (const group of this.#groups) { - const component = group.components.find(Component.FIND_PREDICATE(id)); - - if (component) { - return component; - } - } - - return this.#defaultGroup.components.find(Component.FIND_PREDICATE(id)); - } - - append (component) { - return this.add(component, { mode: 'append' }); - } - - prepend (component) { - return this.add(component, { mode: 'prepend' }); - } - - add (component, { mode = 'append' } = {}) { - const mutateMethod = mode === 'append' ? 'push' : 'unshift'; - - // This component is a group, add a new group - if (component.type === Components.TYPE_GROUP) { - if (!this.hasGroup(component.id)) { - component = new ComponentsGroup(component); - component.components = component.components || []; - - this.#groups[mutateMethod](component); - this.emit('groups.add', component); - } - - return; - } - - component = new Component(component); - - const group = component.group && this.hasGroup(component.group) - ? this.getGroup(component.group) - : this.#defaultGroup; - - const existing = this.getComponent(component.id, { groupId: group.id }); - - if (existing) { - this.#builder.logger.log( - 'Component already exists, updating definition.', - 'Old:', existing, - 'New:', component - ); - - const index = group.components.indexOf(existing); - group.components[index] = component; - this.emit('components.update', component, group); - } else { - group.components[mutateMethod](component); - this.emit('components.add', component, group); - } - } - - remove (id) { - const groupIndex = this.#groups - .findIndex(ComponentsGroup.FIND_PREDICATE(id)); - - if (groupIndex !== -1) { - this.#builder.logger.log('Removing group:', this.#groups[groupIndex]); - const group = this.#groups[groupIndex]; - this.#groups.splice(groupIndex, 1); - this.emit('groups.remove', group); - - return; - } - - for (const group of this.#groups) { - const index = group.components - .findIndex(Component.FIND_PREDICATE(id)); - - if (index !== -1) { - this.#builder.logger - .log('Removing component:', group.components[index]); - const component = group.components[index]; - group.components.splice(index, 1); - this.emit('components.remove', component, group); - - return; - } - } - - const index = this.#defaultGroup.components - .findIndex(Component.FIND_PREDICATE(id)); - - if (index !== -1) { - this.#builder.logger.log( - 'Removing component:', this.#defaultGroup.components[index] - ); - const component = this.#defaultGroup.components[index]; - this.#defaultGroup.components.splice(index, 1); - this.emit('components.remove', component, this.#defaultGroup); - } - } - - all () { - return { - groups: this.#groups, - defaultGroup: this.#defaultGroup, - }; - } - - getDisplayableSettings (element, { fields, component } = {}) { - const displayable = []; - - if (!fields) { - component = component || this.getComponent(element.type); - - if (!component?.settings || !component?.settings.fields) { - return displayable; - } - - fields = component?.settings.fields; - } - - for (const setting of fields) { - if (Array.isArray(setting.fields)) { - displayable.push(...this.getDisplayableSettings(element, { - fields: setting.fields, - })); - } - - if ( - setting.displayable === true || - ( - typeof setting.displayable === 'function' && - setting.displayable({ element, builder: this.#builder }) - ) - ) { - displayable.push(setting); - } - } - - return displayable; - } - - toJSON () { - return this.all(); - } -} diff --git a/packages/core/lib/Components/index.ts b/packages/core/lib/Components/index.ts index 55a465d12..ae1a53549 100644 --- a/packages/core/lib/Components/index.ts +++ b/packages/core/lib/Components/index.ts @@ -103,7 +103,7 @@ export default class Components extends Emitter implements IComponents { } add ( - component: ComponentObject | ComponentsGroupObject, + component: Component | ComponentsGroup | ComponentObject | ComponentsGroupObject, { mode = 'append' }: { mode?: string } = {}//TODO mode is a string ? ) { const mutateMethod = mode === 'append' ? 'push' : 'unshift'; @@ -212,13 +212,13 @@ export default class Components extends Emitter implements IComponents { return displayable; } - fields = component?.settings.fields; + fields = component?.settings.fields as any; //TODO fix it; } for (const setting of fields) { if (Array.isArray(setting.fields)) { displayable.push(...this.getDisplayableSettings(element, { - fields: setting.fields, + fields: setting.fields as any, //TODO fix it; })); } diff --git a/packages/core/lib/Emitter/index.d.ts b/packages/core/lib/Emitter/index.d.ts deleted file mode 100644 index ea792175f..000000000 --- a/packages/core/lib/Emitter/index.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -export declare type EmitterCallback = (...args: any[]) => void; - -export declare class Emitter { - constructor(); - - /** Subscribes to events and return an unsubscribe callback */ - subscribe(cb: EmitterCallback): EmitterCallback; - - /** Emits an event */ - emit(eventName: string, ...args: any[]): void; -} diff --git a/packages/core/lib/Overrides/index.d.ts b/packages/core/lib/Overrides/index.d.ts deleted file mode 100644 index e9627fcfb..000000000 --- a/packages/core/lib/Overrides/index.d.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { - ComponentOverride, - ComponentOverrideObject, - ComponentSettingsField, - Field, - FieldOverride, - FieldOverrideObject, -} from '../types'; -import { Emitter } from '../Emitter'; -import { Builder } from '../Builder'; - -export declare class Overrides extends Emitter { - constructor(options?: { builder: Builder }); - - /** Adds a new component or field override */ - add( - override: ComponentOverride | ComponentOverrideObject | FieldOverride | - FieldOverrideObject - ): ComponentOverride | FieldOverride; - - /** - * Retrieves an override for a component or a field. - * If the override type is 'component' and the output is set to 'field', - * the override will be returned as a field override object, potentially - * using a component setting field as base. - * - * Example: - * this.get('component', 'title', { - * output: 'field', - * setting: new ComponentSettingsField({ - * key: 'content', - * type: 'textarea', - * }), - * }) - * - * Will result in: - * { - * type: 'textarea', - * render: () => ..., - * } - * */ - get(type: 'component' | 'field', target: string, options?: { - output?: 'field', - setting?: ComponentSettingsField, - }): ComponentOverride | FieldOverrideObject; - - /** Removes an override by its id (if available) */ - remove (id: string): void; - - /** Merges overrides into a single non-typed object */ - merge(overrides: Array): object; - - /** Returns all available overrides */ - all(): Array; -} diff --git a/packages/core/lib/Overrides/index.js b/packages/core/lib/Overrides/index.js deleted file mode 100644 index 5362b7c6a..000000000 --- a/packages/core/lib/Overrides/index.js +++ /dev/null @@ -1,122 +0,0 @@ -import { omit } from '@junipero/core'; - -import { ComponentOverride, FieldOverride, SettingOverride } from '../types'; -import Emitter from '../Emitter'; - -export default class Overrides extends Emitter { - static FIND_PREDICATE = id => o => id ? o.id === id : null; - - #overrides = []; - #builder = null; - - constructor ({ builder } = {}) { - super(); - - this.#builder = builder; - } - - add (override) { - const existing = this.#overrides - .find(Overrides.FIND_PREDICATE(override.id)); - - if (existing) { - this.#builder?.logger.log( - 'Override already exists, updating definition.', - 'Old:', existing, - 'New:', override - ); - - this.#overrides.splice(this.#overrides.indexOf(existing), 1, override); - this.emit('overrides.update', override); - - return override; - } - - switch (override.type) { - case 'component': - override = new ComponentOverride(override); - this.#overrides.unshift(override); - break; - case 'field': - override = new FieldOverride(override); - this.#overrides.unshift(override); - break; - case 'setting': - override = new SettingOverride(override); - this.#overrides.unshift(override); - break; - } - - this.emit('overrides.add', this, override); - - return override; - } - - get (overrideType, target, { output, setting } = {}) { - const strategy = this.#builder?.options?.overrideStrategy; - const overrides = this.#overrides.filter(override => - override.type === overrideType && - (override.targets.includes('*') || override.targets.includes(target)) - ); - - switch (overrideType) { - case 'component': { - const override = strategy === 'merge' - ? this.merge(overrides) : overrides[0]; - - switch (output) { - case 'field': { - const newComponentField = override?.fields - ?.find(f => f.key === setting?.key); - - return Object.assign( - { type: newComponentField?.type || setting.type }, - this.#builder.getOverride('field', - newComponentField?.type || setting?.type), - omit(newComponentField || {}, ['type', 'key']) - ); - } - default: - return override; - } - } - case 'setting': - return overrides?.find(o => o.key === setting?.key); - default: - return strategy === 'merge' ? this.merge(overrides) : overrides[0]; - } - } - - remove (id) { - if (!id) { - return; - } - - const index = this.#overrides.findIndex(Overrides.FIND_PREDICATE(id)); - - if (index !== -1) { - this.#builder?.logger.log('Removing override:', this.#overrides[index]); - - const override = this.#overrides[index]; - this.#overrides.splice(index, 1); - this.emit('overrides.remove', this, override); - } - } - - merge (overrides) { - return overrides.reduce((res, override) => { - Object.keys(override).forEach(key => { - if (override[key] === null || override[key] === undefined) { - delete override[key]; - } - }); - Object.assign(res, override); - - return res; - }, {}); - } - - all () { - return this.#overrides; - } -} diff --git a/packages/core/lib/Texts/index.d.ts b/packages/core/lib/Texts/index.d.ts deleted file mode 100644 index 82f867f57..000000000 --- a/packages/core/lib/Texts/index.d.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { TextsSheet, TextsSheetObject, GetTextCallback } from '../types'; -import { Builder } from '../Builder'; -import { Emitter } from '../Emitter'; - -export declare class Texts extends Emitter { - constructor(options?: { builder: Builder }); - - /** Retrieves a text sheet using its id */ - getSheet(id: string): TextsSheet; - - /** Adds a new texts sheet */ - addSheet(sheet: TextsSheetObject | TextsSheet): TextsSheet; - - /** Updates an existing text sheet */ - setSheet(sheet: TextsSheet): TextsSheet; - - /** Removes a text sheet */ - removeSheet(id: string): boolean; - - /** Retrieves the current active sheet id */ - getActiveSheet(): string; - - /** Sets the current active sheet id */ - setActiveSheet(id: string): void; - - /** Retrieves a text from the current active sheet */ - get(key: string | GetTextCallback, def?: any): any; - - /** Updates a text key in the current active sheet */ - set(key: string, value: any): void; -} diff --git a/packages/core/lib/Texts/index.js b/packages/core/lib/Texts/index.ts similarity index 70% rename from packages/core/lib/Texts/index.js rename to packages/core/lib/Texts/index.ts index 0eab8db71..b6ea5cde3 100644 --- a/packages/core/lib/Texts/index.js +++ b/packages/core/lib/Texts/index.ts @@ -1,14 +1,43 @@ import { get, set } from '@junipero/core'; import Emitter from '../Emitter'; -import { TextsSheet } from '../types'; +import { GetTextCallback, TextsSheet, TextsSheetObject } from '../types'; +import Builder from '../Builder'; -export default class Texts extends Emitter { +export declare class ITexts { + constructor(options?: { builder: Builder }); + + /** Retrieves a text sheet using its id */ + getSheet(id: string): TextsSheet; + + /** Adds a new texts sheet */ + addSheet(sheet: TextsSheetObject | TextsSheet): TextsSheet; + + /** Updates an existing text sheet */ + setSheet(sheet: TextsSheet): TextsSheet; + + /** Removes a text sheet */ + removeSheet(id: string): boolean; + + /** Retrieves the current active sheet id */ + getActiveSheet(): string; + + /** Sets the current active sheet id */ + setActiveSheet(id: string): void; + + /** Retrieves a text from the current active sheet */ + get(key: string | GetTextCallback, def?: any): any; + + /** Updates a text key in the current active sheet */ + set(key: string, value: any): void; +} + +export default class Texts extends Emitter implements ITexts { #sheets = []; #activeSheet = null; #builder = null; - constructor ({ builder } = {}) { + constructor ({ builder }: { builder?: Builder } = {}) { super(); this.#builder = builder; diff --git a/packages/core/lib/index.js b/packages/core/lib/index.ts similarity index 100% rename from packages/core/lib/index.js rename to packages/core/lib/index.ts diff --git a/packages/core/lib/types.d.ts b/packages/core/lib/types.d.ts deleted file mode 100644 index a7232599a..000000000 --- a/packages/core/lib/types.d.ts +++ /dev/null @@ -1,337 +0,0 @@ -import { Builder } from './Builder'; -import { Logger } from './Logger'; - -export declare interface GetTextCallback { - (key: string | GetTextCallback, def?: any): any; -} - -export declare type ElementId = string | number; - -export declare interface ElementObject { - id?: ElementId; - type: string; - [_: string]: any -} - -export declare class BuilderOptions { - debug?: boolean; - historyLimit?: number; - overrideStrategy?: 'last' | 'merge'; - generateId?(): string | number; -} - -export declare interface ComponentOptionObject { - icon: any; - render?(): any; -} - -export declare class ComponentOption { - constructor(props: object); - icon: any; - render?(): any; -} - -export declare interface ComponentSettingsFieldKeyTuple { - from: string; - to: string; - default: any; -} - -export declare interface FieldObject { - type: string; - props?: object; - render?(props: any): any; -} - -export declare class Field { - static FIND_PREDICATE(type: string): (field: Field) => boolean; - - constructor(props: object); - type: string; - props: object; - render?(): any; -} - -export declare interface ComponentOverrideObject { - id?: string; - type?: string; - targets?: string[]; - fields?: ComponentSettingsFieldObject[]; - construct?(opts?: { builder?: Builder }): ElementObject; - render?(props?: any): any; - sanitize?(): any; - duplicate?(elmt?: ElementObject): ElementObject; -} - -export declare class ComponentOverride { - constructor(props: object); - id: string; - type: string; - targets: string[]; - fields: ComponentSettingsField[]; - construct(opts?: { builder?: Builder }): ElementObject; - render?(props?: any): any; - sanitize?(): any; - duplicate?(elmt?: ElementObject): ElementObject; -} - -export declare interface FieldOverrideObject { - id: string; - type: string; - targets: string[]; - props: Record; - render?(): any; -} - -export declare class FieldOverride { - constructor(props: object); - id: string; - type: string; - targets: string[]; - props: Record; - render?(): any; -} - -export declare interface SettingOverrideObject { - type: string; - targets: string[]; - key: string | string[] | ComponentSettingsFieldKeyTuple[]; - id?: string; - label?: string | GetTextCallback; - info?: string | GetTextCallback; - description?: string | GetTextCallback; - placeholder?: string | GetTextCallback; - default?: any; - displayable?: boolean; - valueType?: string; - priority?: number; - fields?: (ComponentSettingsField | ComponentSettingsFieldObject)[]; - props?: Record; - condition?(element: Element | ElementObject, opts?: { - component: Component | ComponentObject; - builder: Builder; - }): boolean; -} - -export declare class SettingOverride { - constructor(props: Record); - type: string; - targets: string[]; - key: string | string[] | ComponentSettingsFieldKeyTuple[]; - id: string; - label: string | GetTextCallback; - info: string | GetTextCallback; - description: string | GetTextCallback; - placeholder: string; - default: any; - displayable: boolean; - valueType: string; - priority: number; - fields: (ComponentSettingsField | ComponentSettingsFieldObject)[]; - props: Record; - condition?(element: Element | ElementObject, opts?: { - component: Component | ComponentObject; - builder: Builder; - }): boolean; -} - -export declare interface ComponentSettingsFieldOptionObject { - value?: any; - title?: string | GetTextCallback; - imageTransformation?: { - width: number; - height: number; - }; -} - -export declare interface ComponentSettingsFieldObject { - priority?: number; - type: string; - key: string | string[] | ComponentSettingsFieldKeyTuple[]; - tab?: string; - id?: string; - label?: string | GetTextCallback; - info?: string | GetTextCallback; - description?: string | GetTextCallback; - placeholder?: string | GetTextCallback; - default?: any; - options?: ComponentSettingsFieldOptionObject[] | Record[]; - displayable?: boolean; - valueType?: string; - fields?: ComponentSettingsFieldObject[]; - props?: Record; - condition?(element: Element | ElementObject, opts?: { - component: Component | ComponentObject; - builder: Builder; - }): boolean; -} - -export declare class ComponentSettingsField { - static FIND_PREDICATE(type: string): - (field: ComponentSettingsField) => boolean; - - constructor(props: Record); - priority: number; - type: string; - tab: string; - id: string; - key: string | string[] | ComponentSettingsFieldKeyTuple[]; - placeholder: string | GetTextCallback; - default: any; - label: string | GetTextCallback; - info: string | GetTextCallback; - description: string | GetTextCallback; - displayable: boolean; - valueType: string; - fields: ComponentSettingsField[]; - props: Record; - condition?(element: Element | ElementObject, opts?: { - component: Component | ComponentObject; - builder: Builder; - }): boolean; -} - -export declare interface ComponentSettingsTabObject { - id: string; - priority?: number; - title?: string | GetTextCallback; - fields?: (ComponentSettingsField | ComponentSettingsFieldObject)[]; - condition?(element: Element | ElementObject, opts?: { - component: Component | ComponentObject; - builder: Builder; - }): boolean; -} - -export declare class ComponentSettingsTab { - static FIND_PREDICATE(id: string): (tab: ComponentSettingsTab) => boolean; - - constructor(props: Record); - type: string; - id: string; - priority: number; - title: string | GetTextCallback; - fields: ComponentSettingsField[]; - condition?(element: Element | ElementObject, opts?: { - component: Component | ComponentObject; - builder: Builder; - }): boolean; -} - -export declare class ComponentSettingsFormObject { - title?: string | GetTextCallback; - floatingSettings?: Record; - defaults?: any; - fields?: ( - ComponentSettingsTab | - ComponentSettingsTabObject | - ComponentSettingsField | - ComponentSettingsFieldObject - )[]; -} - -export declare class ComponentSettingsForm { - constructor(props: Record); - title?: string | GetTextCallback; - floatingSettings?: Record; - defaults?: any; - fields?: (ComponentSettingsTab | ComponentSettingsField)[]; -} - -export declare interface ComponentObject { - type?: string; - id?: string; - group?: string; - icon?: any; - name?: string | GetTextCallback; - hasCustomInnerContent?: boolean; - draggable?: boolean; - droppable?: boolean; - usable?: boolean; - editable?: boolean; - options?: (ComponentOption | ComponentOptionObject)[]; - settings?: ComponentSettingsForm | ComponentSettingsFormObject; - disallow?: string[]; - render?(props?: any): any; - sanitize?(): any; - construct?(opts?: { builder?: Builder }): ElementObject; - duplicate?(elmt?: ElementObject): ElementObject; - getContainers?(element: ElementObject): ElementObject[]; -} - -export declare class Component { - static FIND_PREDICATE(id: string): (component: Component) => boolean; - - constructor(props: Record); - type: string; - id: string; - group: string; - icon: any; - name: string | GetTextCallback; - hasCustomInnerContent: boolean; - draggable: boolean; - droppable: boolean; - usable: boolean; - editable: boolean; - options: ComponentOption[]; - settings: ComponentSettingsForm; - disallow: Array; - render(): any; - sanitize(): any; - construct(): ElementObject; - duplicate(): ElementObject; - getContainers(element: ElementObject): ElementObject[]; -} - -export declare class ComponentsGroup { - static FIND_PREDICATE(id: string): (group: ComponentsGroup) => boolean; - - constructor(props: Record); - type: string; - id: string; - name: string; - usable: boolean; - components: Component[]; -} -export declare interface ComponentsGroupObject { - type: string; - id: string; - name: string; - usable: boolean; - components: (Component | ComponentObject)[]; -} - -export declare interface TextsSheetObject { - id: string; - texts: Record; -} - -export declare class TextsSheet { - static FIND_PREDICATE(id: string): (sheet: TextsSheet) => boolean; - - constructor(props: Record); - id: string; - texts: Record; -} - -export declare interface ComponentTabOject { - id: string; - title: string | GetTextCallback; - components: (Component | ComponentObject)[]; -} -export declare interface AddonObject { - components?: (Component | ComponentObject | ComponentTabOject)[]; - fields?: (Field | FieldObject)[]; - texts?: (TextsSheet | TextsSheetObject)[]; - overrides?: ( - ComponentOverride | - ComponentOverrideObject | - FieldOverride | - FieldOverrideObject - )[]; - settings?: ( - ComponentSettingsTab | - ComponentSettingsTabObject | - ComponentSettingsField | - ComponentSettingsFieldObject - )[]; -} diff --git a/packages/core/lib/types.js b/packages/core/lib/types.js deleted file mode 100644 index 6fd78572b..000000000 --- a/packages/core/lib/types.js +++ /dev/null @@ -1,192 +0,0 @@ -export class BuilderOptions { - constructor (props) { - this.debug = props.debug || false; - this.generateId = props.generateId; - this.historyLimit = props.historyLimit || 20; - this.overrideStrategy = props.overrideStrategy || 'last'; - } -} - -export class Component { - static FIND_PREDICATE = id => c => c.id === id; - - constructor (props) { - if (!props.id) { - throw new Error('Component must have an id'); - } - - this.type = 'component'; - this.id = props.id; - this.group = props.group; - this.render = props.render; - this.sanitize = props.sanitize; - this.construct = props.construct; - this.duplicate = props.duplicate; - this.icon = props.icon; - this.getContainers = props.getContainers; - this.name = props.name || ''; - this.hasCustomInnerContent = props.hasCustomInnerContent ?? false; - this.draggable = props.draggable ?? true; - this.droppable = props.droppable ?? true; - this.usable = props.usable ?? true; - this.editable = props.editable ?? true; - this.disallow = props.disallow || []; - this.options = (props.options || []).map(o => new ComponentOption(o)); - this.settings = new ComponentSettingsForm(props.settings || {}); - } -} - -export class ComponentsGroup { - static FIND_PREDICATE = id => g => g.id === id; - - constructor (props) { - if (!props.id) { - throw new Error('Component Group must have an id'); - } - - this.type = 'group'; - this.id = props.id; - this.name = props.name; - this.usable = props.usable ?? true; - this.components = (props.components || []).map(c => - c instanceof Component ? c : new Component(c) - ); - } -} - -export class Field { - static FIND_PREDICATE = type => f => f.type === type; - - constructor (props) { - if (!props.type) { - throw new Error('Field must have a type'); - } - - this.type = props.type; - this.render = props.render; - this.props = props.props || {}; - } -} - -export class ComponentOverride { - constructor (props) { - this.type = 'component'; - this.id = props.id; - this.targets = props.targets || []; - this.fields = props.fields || []; - this.render = props.render; - this.sanitize = props.sanitize; - this.construct = props.construct; - this.duplicate = props.duplicate; - } -} - -export class FieldOverride { - constructor (props) { - this.type = 'field'; - this.id = props.id; - this.targets = props.targets || []; - this.render = props.render; - this.props = props.props || {}; - } -} - -export class SettingOverride { - constructor (props) { - this.type = 'setting'; - this.key = props.key; - this.targets = props.targets || []; - this.id = props.id; - this.placeholder = props.placeholder; - this.default = props.default; - this.options = props.options; - this.label = props.label; - this.description = props.description; - this.displayable = props.displayable; - this.valueType = props.valueType; - this.condition = props.condition; - this.priority = props.priority || 0; - this.fields = (props.fields || []).map(f => new ComponentSettingsField(f)); - this.props = props.props; - } -} - -export class ComponentOption { - constructor (props) { - this.icon = props.icon; - this.render = props.render; - } -} - -export class ComponentSettingsForm { - constructor (props) { - this.title = props.title; - this.floatingSettings = props.floatingSettings; - this.defaults = props.defaults || {}; - this.fields = (props.fields || []).map(t => - t.type === 'tab' - ? t instanceof ComponentSettingsTab ? t : new ComponentSettingsTab(t) - : t instanceof ComponentSettingsField - ? t : new ComponentSettingsField(t) - ); - } -} - -export class ComponentSettingsTab { - static FIND_PREDICATE = id => t => t.id === id; - - constructor (props) { - if (!props.id) { - throw new Error('ComponentSettingsTab must have an id'); - } - - this.type = 'tab'; - this.id = props.id; - this.priority = props.priority || 0; - this.title = props.title; - this.condition = props.condition; - this.fields = (props.fields || []).map(f => - f instanceof ComponentSettingsField ? f : new ComponentSettingsField(f)); - } -} - -export class ComponentSettingsField { - static FIND_PREDICATE = id => f => f.id === id || f.key === id; - - constructor (props) { - if (!props.fields && !props.type) { - throw new Error('ComponentSettingsField must have a type (or be ' + - 'a group of fields)'); - } - - this.type = props.type; - this.tab = props.tab; - this.key = props.key; - this.id = props.id; - this.placeholder = props.placeholder; - this.default = props.default; - this.options = props.options; - this.label = props.label; - this.info = props.info; - this.description = props.description; - this.displayable = props.displayable; - this.valueType = props.valueType; - this.condition = props.condition; - this.priority = props.priority || 0; - this.fields = (props.fields || []).map(f => new ComponentSettingsField(f)); - this.props = props.props; - } -} - -export class TextsSheet { - static FIND_PREDICATE = id => s => s.id === id; - - constructor (props) { - if (!props.id) { - throw new Error('TextsSheet must have an id'); - } - - this.id = props.id; - this.texts = props.texts || {}; - } -} diff --git a/packages/core/lib/types.ts b/packages/core/lib/types.ts index 6903a94ae..352df0642 100644 --- a/packages/core/lib/types.ts +++ b/packages/core/lib/types.ts @@ -109,7 +109,7 @@ export class ComponentOverride { sanitize?: Function; construct: Function; duplicate: Function; - + priority: number; constructor (props) { this.type = 'component'; this.id = props.id; @@ -119,6 +119,7 @@ export class ComponentOverride { this.sanitize = props.sanitize; this.construct = props.construct; this.duplicate = props.duplicate; + this.priority = props.priority || 0; } } @@ -128,12 +129,13 @@ export class FieldOverride { targets: Array; render: Function; props: object; - + priority: number; constructor (props) { this.type = 'field'; this.id = props.id; this.targets = props.targets || []; this.render = props.render; + this.priority = props.priority || 0; this.props = props.props || {}; } } @@ -188,7 +190,7 @@ export class ComponentSettingsForm { title: string; floatingSettings: any; defaults: object; - fields: Array; + fields: Array; constructor (props) { this.title = props.title; @@ -323,6 +325,7 @@ export declare interface ComponentOverrideObject { render?(props?: any): any; sanitize?(): any; duplicate?(elmt?: ElementObject): ElementObject; + priority?: number; } export declare interface FieldOverrideObject { @@ -331,6 +334,7 @@ export declare interface FieldOverrideObject { targets: string[]; props: Record; render?(): any; + priority?: number; } export declare interface SettingOverrideObject { @@ -377,7 +381,10 @@ export declare interface ComponentSettingsFieldObject { placeholder?: string | GetTextCallback; default?: any; options?: ComponentSettingsFieldOptionObject[] | Record[]; - displayable?: boolean; + displayable?: boolean | ((element: Element | ElementObject, opts?: { + component: Component | ComponentObject; + builder: Builder; + }) => boolean); valueType?: string; fields?: ComponentSettingsFieldObject[]; props?: Record; diff --git a/packages/core/package.json b/packages/core/package.json index c55dac58e..4fef25e17 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -47,5 +47,8 @@ "import": "./dist/esm/addons.js", "require": "./dist/oak-core.cjs.js" } + }, + "devDependencies": { + "rollup": "^4.14.3" } } diff --git a/packages/core/rollup.config.mjs b/packages/core/rollup.config.mjs index 555aba1ec..d092ee553 100644 --- a/packages/core/rollup.config.mjs +++ b/packages/core/rollup.config.mjs @@ -1,70 +1,108 @@ import path from 'path'; +import fs from 'node:fs'; -import babel from '@rollup/plugin-babel'; +import swc from '@rollup/plugin-swc'; import resolve from '@rollup/plugin-node-resolve'; import commonjs from '@rollup/plugin-commonjs'; import terser from '@rollup/plugin-terser'; -import dts from 'rollup-plugin-dts'; +import typescript from '@rollup/plugin-typescript'; +import { dts } from 'rollup-plugin-dts'; -const input = './lib/index.js'; -const defaultOutput = './dist'; +const input = './lib/index.ts'; +const output = './dist'; const name = 'oak-core'; -const libName = 'OakCore'; const formats = ['umd', 'cjs', 'esm']; -const defaultExternals = []; -const defaultGlobals = {}; - const defaultPlugins = [ - babel({ - exclude: /node_modules/, - babelHelpers: 'runtime', - }), + commonjs({ include: /node_modules/ }), resolve({ rootDir: path.resolve('../../'), + extensions: ['.js', '.ts', '.json', '.node'], }), - commonjs(), - terser({ mangle: false }), + terser(), ]; -const getConfig = (format, { - output = defaultOutput, - globals = defaultGlobals, - external = defaultExternals, -} = {}) => ({ - input, - plugins: [ - ...defaultPlugins, - ], - external, - output: { - ...(format === 'esm' ? { - dir: `${output}/esm`, - chunkFileNames: '[name].js', - } : { - file: `${output}/${name}.${format}.js`, - }), - format, - name: libName, - sourcemap: true, - globals, - ...(format === 'esm' ? { - manualChunks: id => { - if (/packages\/core\/lib\/(\w+)\/index.js/.test(id)) { - return path.parse(id).dir.split('/').pop(); - } else { - return id.includes('node_modules') ? 'vendor' : path.parse(id).name; - } - }, - } : {}), - }, -}); +const defaultExternals = []; +const defaultGlobals = {}; export default [ - ...formats.map(f => getConfig(f)), - { - input: './lib/index.d.ts', + ...formats.map(f => ({ + input, + plugins: [ + swc({ + swc: { + jsc: { + parser: { + syntax: 'typescript', + jsx: true, + tsx: true, + }, + }, + }, + }), + ...defaultPlugins, + ], + external: defaultExternals, + output: { + ...(f === 'esm' ? { + dir: `${output}/esm`, + chunkFileNames: '[name].js', + } : { + file: `${output}/${name}.${f}.js`, + }), + format: f, + name, + sourcemap: true, + globals: defaultGlobals, + ...(f === 'esm' ? { + manualChunks: id => { + if (/packages\/core\/lib\/(\w+)\/index.ts/.test(id)) { + return path.parse(id).dir.split('/').pop(); + } else { + return id.includes('node_modules') ? 'vendor' : path.parse(id).name; + } + }, + } : {}), + }, + })), { + input: './lib/index.ts', + output: [{ file: `./dist/${name}.d.ts`, format: 'es' }], + plugins: [ + typescript({ + emitDeclarationOnly: true, + declaration: true, + declarationDir: './types', + tsconfig: path.resolve('./tsconfig.json'), + outputToFilesystem: true, + incremental: false, + include: ['lib/**/*.ts'], + exclude: [ + '**/*.test.ts', + '**/tests/**/*', + ], + }), + ...defaultPlugins, + { + writeBundle () { + fs.unlinkSync(`./dist/${name}.d.ts`); + }, + }, + ], + }, { + input: './dist/types/index.d.ts', output: [{ file: `dist/${name}.d.ts`, format: 'es' }], - plugins: [dts()], + external: defaultExternals, + plugins: [ + resolve({ + rootDir: path.resolve('../../'), + extensions: ['.js', '.ts', '.json', '.node'], + }), + dts({ respectExternal: true }), + { + writeBundle () { + fs.rmSync('./dist/types', { recursive: true, force: true }); + }, + }, + ], }, ]; diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json new file mode 100644 index 000000000..9acad019d --- /dev/null +++ b/packages/core/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "exclude": ["node_modules/**/*"], + "include": ["./lib/**/*"], + "compilerOptions": { + "declarationDir": "./dist/types", + } +} \ No newline at end of file diff --git a/packages/react/lib/Builder/HistoryButtons.js b/packages/react/lib/Builder/HistoryButtons.tsx similarity index 67% rename from packages/react/lib/Builder/HistoryButtons.js rename to packages/react/lib/Builder/HistoryButtons.tsx index d2d855d95..d5b066dd1 100644 --- a/packages/react/lib/Builder/HistoryButtons.js +++ b/packages/react/lib/Builder/HistoryButtons.tsx @@ -1,10 +1,13 @@ import { Tooltip, Button } from '@junipero/react'; +import { MutableRefObject } from 'react'; import { useBuilder } from '../hooks'; import Text from '../Text'; import Icon from '../Icon'; -const HistoryButtons = ({ canUndo, canRedo }) => { +const HistoryButtons = ( + { canUndo, canRedo }: { canUndo: boolean, canRedo: boolean} +) => { const { builder, rootRef, floatingsRef, rootBoundary } = useBuilder(); return ( @@ -13,8 +16,10 @@ const HistoryButtons = ({ canUndo, canRedo }) => { disabled={!canUndo} container={floatingsRef.current} floatingOptions={{ - boundary: rootBoundary?.current || rootRef?.current, - rootBoundary: rootBoundary?.current || rootRef?.current, + boundary: (rootBoundary as MutableRefObject)?.current || + rootRef?.current, + rootBoundary: (rootBoundary as MutableRefObject)?.current || + rootRef?.current, }} text={Undo} > @@ -30,8 +35,10 @@ const HistoryButtons = ({ canUndo, canRedo }) => { disabled={!canRedo} container={floatingsRef.current} floatingOptions={{ - boundary: rootBoundary?.current || rootRef?.current, - rootBoundary: rootBoundary?.current || rootRef?.current, + boundary: (rootBoundary as MutableRefObject)?.current || + rootRef?.current, + rootBoundary: (rootBoundary as MutableRefObject)?.current || + rootRef?.current, }} text={Redo} > diff --git a/packages/react/lib/Builder/index.d.ts b/packages/react/lib/Builder/index.d.ts deleted file mode 100644 index 810ac8460..000000000 --- a/packages/react/lib/Builder/index.d.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { - ReactNode, - ComponentPropsWithRef, - FormEvent, - MutableRefObject, -} from 'react'; -import { - AddonObject, - Builder as CoreBuilder, - BuilderOptions, - ElementObject, - ComponentSettingsField, - ComponentSettingsFieldObject, -} from '@oakjs/core'; - -export declare interface ImageUploadCallbackResult { - url: string; - name: string; - [key: string]: any; -} - -export declare interface BuilderContextValue { - builder: CoreBuilder; - content: Array; - rootBoundary: MutableRefObject | Element | DocumentFragment; - onImageUpload?(event: FormEvent): Promise; - rootRef: MutableRefObject; - floatingsRef: MutableRefObject; -} - -export declare type BuilderRef = { - builder: CoreBuilder; - content: Array; - isOak: boolean; - catalogueRef: MutableRefObject; - innerRef: MutableRefObject; -}; - -export declare interface BuilderProps extends ComponentPropsWithRef { - activeTextSheet?: string; - addons: Array; - bottomHistoryButtonsContainer?: string | Element | DocumentFragment; - bottomHistoryButtonsEnabled?: boolean; - defaultValue?: Array; - historyEnabled?: boolean; - options?: BuilderOptions; - rootBoundary?: string | Element | DocumentFragment; - topHistoryButtonsContainer?: string | Element | DocumentFragment; - topHistoryButtonsEnabled?: boolean; - value?: Array; - [key: string]: any; - onChange?(content: Array): void; - onImageUpload?(event: FormEvent, opts: { - element?: ElementObject; - setting?: ComponentSettingsFieldObject | ComponentSettingsField; - }): Promise; - ref?: MutableRefObject; -} - -declare function Builder(props: BuilderProps): ReactNode | JSX.Element; - -export default Builder; diff --git a/packages/react/lib/Builder/index.js b/packages/react/lib/Builder/index.tsx similarity index 60% rename from packages/react/lib/Builder/index.js rename to packages/react/lib/Builder/index.tsx index 4f0488ac8..fe2d40428 100644 --- a/packages/react/lib/Builder/index.js +++ b/packages/react/lib/Builder/index.tsx @@ -1,12 +1,65 @@ -import { forwardRef, useCallback, useRef, useImperativeHandle } from 'react'; +import { forwardRef, useCallback, useRef, useImperativeHandle, MutableRefObject, FormEvent, ComponentPropsWithRef } from 'react'; import { createPortal } from 'react-dom'; import { classNames, ensureNode } from '@junipero/react'; +import { + AddonObject, + Builder as CoreBuilder, + BuilderOptions, + ElementObject, + ComponentSettingsField, + ComponentSettingsFieldObject, +} from '@oakjs/core'; -import { BuilderContext } from '../contexts'; import { useRootBuilder } from '../hooks'; import Element from '../Element'; import Catalogue from '../Catalogue'; import HistoryButtons from './HistoryButtons'; +import { BuilderContext } from '../contexts'; + +export declare interface ImageUploadCallbackResult { + url: string; + name: string; + [key: string]: any; +} + +export declare interface BuilderContextValue { + builder: CoreBuilder; + content: Array; + rootBoundary: MutableRefObject | Element | DocumentFragment; + onImageUpload?(event: FormEvent): Promise; + rootRef: MutableRefObject; + floatingsRef: MutableRefObject; +} + +export declare type BuilderRef = { + builder: CoreBuilder; + content: Array; + isOak: boolean; + catalogueRef: MutableRefObject; + innerRef: MutableRefObject; + close?: () => void +}; + +export declare interface BuilderProps extends ComponentPropsWithRef { + activeTextSheet?: string; + addons: Array; + bottomHistoryButtonsContainer?: string | Element | DocumentFragment; + bottomHistoryButtonsEnabled?: boolean; + defaultValue?: Array; + historyEnabled?: boolean; + options?: BuilderOptions; + rootBoundary?: MutableRefObject | string | Element | DocumentFragment; + topHistoryButtonsContainer?: string | Element | DocumentFragment; + topHistoryButtonsEnabled?: boolean; + value?: Array; + [key: string]: any; + onChange?(content: Array): void; + onImageUpload?(event: FormEvent, opts: { + element?: ElementObject; + setting?: ComponentSettingsFieldObject | ComponentSettingsField; + }): Promise; + ref?: MutableRefObject; +} const Builder = forwardRef(({ className, @@ -22,10 +75,10 @@ const Builder = forwardRef(({ topHistoryButtonsEnabled = true, bottomHistoryButtonsEnabled = true, ...opts -}, ref) => { +}: BuilderProps, ref) => { const innerRef = useRef(); - const catalogueRef = useRef(); - const floatingsRef = useRef(); + const catalogueRef = useRef(); + const floatingsRef = useRef(); const { builder, content, addons, canUndo, canRedo } = useRootBuilder({ content: value, defaultContent: defaultValue, @@ -46,7 +99,7 @@ const Builder = forwardRef(({ builder, content, addons, - rootBoundary: rootBoundary?.current + rootBoundary: (rootBoundary as MutableRefObject)?.current ? rootBoundary : { current: rootBoundary }, onImageUpload, rootRef: innerRef, @@ -84,7 +137,7 @@ const Builder = forwardRef(({ { historyEnabled && topHistoryButtonsEnabled && ( topHistoryButtonsContainer ? createPortal(historyButtons, - ensureNode(topHistoryButtonsContainer)) + ensureNode(topHistoryButtonsContainer)as any)//TODO fix it : historyButtons ) }
@@ -117,7 +170,7 @@ const Builder = forwardRef(({ { historyEnabled && bottomHistoryButtonsEnabled && ( bottomHistoryButtonsContainer ? createPortal(historyButtons, - ensureNode(bottomHistoryButtonsContainer)) + ensureNode(bottomHistoryButtonsContainer) as any)// TODO fix it : historyButtons ) } diff --git a/packages/react/lib/Catalogue/index.js b/packages/react/lib/Catalogue/index.tsx similarity index 87% rename from packages/react/lib/Catalogue/index.js rename to packages/react/lib/Catalogue/index.tsx index ec3979c8e..3ba630f24 100644 --- a/packages/react/lib/Catalogue/index.js +++ b/packages/react/lib/Catalogue/index.tsx @@ -4,6 +4,8 @@ import { useReducer, useRef, useMemo, + MutableRefObject, + ComponentPropsWithRef, } from 'react'; import { createPortal } from 'react-dom'; import { @@ -22,11 +24,30 @@ import { offset, shift, } from '@floating-ui/react'; +import { ComponentObject, ElementObject } from '@oakjs/core'; import { useBuilder } from '../hooks'; import Icon from '../Icon'; import Text from '../Text'; +export declare type CatalogueRef = { + open: () => void; + close: () => void; + toggle: () => void; + opened: boolean; + isOak: boolean; + innerRef: MutableRefObject; +}; + +export declare interface CatalogueProps extends ComponentPropsWithRef { + className?: string; + placement?: string; + onToggle?(props: { opened: boolean }): void; + onAppend?(props: { component: ComponentObject }): void; + onPaste?(clipboardData: ElementObject): void; + ref?: MutableRefObject; +} + const Catalogue = forwardRef(({ component, className, @@ -34,7 +55,7 @@ const Catalogue = forwardRef(({ onToggle, onAppend, onPaste, -}, ref) => { +}: CatalogueProps, ref) => { const innerRef = useRef(); const { builder, rootRef, rootBoundary, floatingsRef } = useBuilder(); const [state, dispatch] = useReducer(mockState, { @@ -47,7 +68,8 @@ const Catalogue = forwardRef(({ middleware: [ offset(16), shift({ - rootBoundary: rootBoundary?.current || rootRef?.current, + rootBoundary: (rootBoundary as MutableRefObject)?.current || + rootRef?.current, }), ], }); @@ -208,7 +230,7 @@ const Catalogue = forwardRef(({ ) }
- ), { opened: state.opened }), ensureNode(floatingsRef?.current)) } + ), { opened: state.opened }), ensureNode(floatingsRef?.current) as any) } {/*TODO fix it*/} ); }); diff --git a/packages/react/lib/Container/index.d.ts b/packages/react/lib/Container/index.d.ts deleted file mode 100644 index 22e240755..000000000 --- a/packages/react/lib/Container/index.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ReactNode, ComponentPropsWithoutRef } from 'react'; -import { - ElementObject, - ComponentObject, - Component, -} from '@oakjs/core'; - -export declare interface ContainerProps extends ComponentPropsWithoutRef { - element?: ElementObject; - content?: Array; - component?: ComponentObject | Component; - depth?: number; -} - -declare function Container(props: ContainerProps): ReactNode | JSX.Element; - -export default Container; diff --git a/packages/react/lib/Container/index.js b/packages/react/lib/Container/index.tsx similarity index 75% rename from packages/react/lib/Container/index.js rename to packages/react/lib/Container/index.tsx index e71715560..115a66d8a 100644 --- a/packages/react/lib/Container/index.js +++ b/packages/react/lib/Container/index.tsx @@ -1,9 +1,18 @@ -import { useRef } from 'react'; +import { ComponentPropsWithoutRef, useRef } from 'react'; import { Droppable, classNames } from '@junipero/react'; +import { Component, ComponentObject, ElementObject } from '@oakjs/core'; import { useBuilder } from '../hooks'; import Element from '../Element'; -import Catalogue from '../Catalogue'; +import Catalogue, { CatalogueRef } from '../Catalogue'; + +export declare interface ContainerProps extends ComponentPropsWithoutRef { + element?: ElementObject; + className?: string; + content?: Array; + component?: ComponentObject | Component; + depth?: number; +} const Container = ({ element, @@ -11,12 +20,12 @@ const Container = ({ className, content = [], depth = 0, -}) => { - const prependCatalogueRef = useRef(); - const appendCatalogueRef = useRef(); +}: ContainerProps) => { + const prependCatalogueRef = useRef(); + const appendCatalogueRef = useRef(); const { builder } = useBuilder(); - const onPrepend = c => { + const onPrepend = (c: Component | ComponentObject) => { prependCatalogueRef.current?.close(); builder.addElement?.({}, { parent: content, @@ -25,7 +34,7 @@ const Container = ({ }); }; - const onAppend = c => { + const onAppend = (c: Component | ComponentObject) => { appendCatalogueRef.current?.close(); builder.addElement?.({}, { parent: content, @@ -34,7 +43,7 @@ const Container = ({ }); }; - const onDrop = data => { + const onDrop = (data: ElementObject) => { if (component?.disallow?.includes?.(data.type)) { return; } @@ -45,7 +54,7 @@ const Container = ({ }); }; - const onPasteBefore = elmt => { + const onPasteBefore = (elmt: ElementObject) => { prependCatalogueRef.current?.close(); builder.addElements([].concat(elmt || []), { parent: content, @@ -54,7 +63,7 @@ const Container = ({ }); }; - const onPasteAfter = elmt => { + const onPasteAfter = (elmt: ElementObject) => { appendCatalogueRef.current?.close(); builder.addElements([].concat(elmt || []), { parent: content, diff --git a/packages/react/lib/DisplayableSettings/index.js b/packages/react/lib/DisplayableSettings/index.tsx similarity index 73% rename from packages/react/lib/DisplayableSettings/index.js rename to packages/react/lib/DisplayableSettings/index.tsx index 3baa5d6d7..e68a6aa1c 100644 --- a/packages/react/lib/DisplayableSettings/index.js +++ b/packages/react/lib/DisplayableSettings/index.tsx @@ -1,11 +1,24 @@ -import { Fragment, useMemo } from 'react'; +import { ComponentPropsWithoutRef, Fragment, useMemo } from 'react'; import { classNames } from '@junipero/react'; +import { Component, ComponentObject, ComponentOverride, ComponentOverrideObject, ElementObject } from '@oakjs/core'; import { useBuilder } from '../hooks'; import Text from '../Text'; import Property from './Property'; -const DisplayableSettings = ({ className, element, component, override }) => { +export declare interface DisplayableSettingsProps + extends ComponentPropsWithoutRef { + element?: ElementObject; + component?: ComponentObject | Component; + override?: ComponentOverrideObject | ComponentOverride; +} + +const DisplayableSettings = ({ + className, + element, + component, + override, +}: DisplayableSettingsProps) => { const { builder } = useBuilder(); const getSettingPriority = setting => { diff --git a/packages/react/lib/Text/index.d.ts b/packages/react/lib/Text/index.d.ts index 340cb109e..99752a77d 100644 --- a/packages/react/lib/Text/index.d.ts +++ b/packages/react/lib/Text/index.d.ts @@ -4,7 +4,7 @@ import { ReactNode, ComponentPropsWithoutRef } from 'react'; export declare interface TextProps extends ComponentPropsWithoutRef { children?: ReactNode | JSX.Element | GetTextCallback; name?: string; - default: ReactNode | JSX.Element | GetTextCallback; + default?: ReactNode | JSX.Element | GetTextCallback; } declare function Text(props: TextProps): ReactNode | JSX.Element; diff --git a/packages/react/lib/contexts.d.ts b/packages/react/lib/contexts.d.ts deleted file mode 100644 index 4c5d92b3c..000000000 --- a/packages/react/lib/contexts.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ChangeEvent, Context, MutableRefObject } from 'react'; -import { - AddonObject, - Builder, - ComponentSettingsField, - ElementObject, -} from '@oakjs/core'; - -export declare type BuilderContext = Context<{ - builder: Builder; - content: ElementObject[]; - addons: AddonObject[]; - rootBoundary: MutableRefObject; - onImageUpload(event: ChangeEvent, opts?: { - element?: ElementObject; - setting?: ComponentSettingsField; - }): { name?: string; url?: string; }; - rootRef: MutableRefObject; - floatingsRef: MutableRefObject[]; -}>; diff --git a/packages/react/lib/contexts.js b/packages/react/lib/contexts.js deleted file mode 100644 index 20e16362a..000000000 --- a/packages/react/lib/contexts.js +++ /dev/null @@ -1,3 +0,0 @@ -import { createContext } from 'react'; - -export const BuilderContext = createContext({}); diff --git a/packages/react/lib/contexts.ts b/packages/react/lib/contexts.ts new file mode 100644 index 000000000..1dde827ca --- /dev/null +++ b/packages/react/lib/contexts.ts @@ -0,0 +1,29 @@ +import { AddonObject, Builder, ComponentSettingsField, ElementObject } from '@oakjs/core'; +import { ChangeEvent, MutableRefObject, createContext } from 'react'; + +import { ImageUploadCallbackResult } from './Builder'; + +declare type BuilderContextType = { + builder?: Builder; + content?: ElementObject[]; + addons?: AddonObject[]; + rootBoundary?: + MutableRefObject | + string | + Element | + DocumentFragment; + boundary?: + MutableRefObject | + string | + Element | + DocumentFragment; + onImageUpload?(event: ChangeEvent, opts?: { + element?: ElementObject; + setting?: ComponentSettingsField; + }): Promise; + rootRef?: MutableRefObject; + floatingsRef?: + MutableRefObject[] | + MutableRefObject; +}; +export const BuilderContext = createContext({}); diff --git a/packages/react/lib/hooks.d.ts b/packages/react/lib/hooks.d.ts index da5e71cba..cec83436a 100644 --- a/packages/react/lib/hooks.d.ts +++ b/packages/react/lib/hooks.d.ts @@ -5,6 +5,9 @@ import { BuilderContextValue } from './Builder'; export declare function useRootBuilder(opts?: Partial; activeTextSheet?: string; + addons?: Array; + content?: Array; + onChange?(content: Array): void; }>): { builder: Builder; content: Array; diff --git a/tsconfig.json b/tsconfig.json index de8de596a..af28803b6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,10 @@ { "compilerOptions": { + "declaration": true, "target": "ES2015", + "moduleResolution": "Bundler", + "jsx": "react-jsx", + "lib": ["DOM", "ES2022"], "paths": { "@oakjs/core": [ "./packages/core/lib" @@ -12,7 +16,7 @@ }, "include": [ "**/*.ts" - ], +, "packages/react/lib/Builder/HistoryButtons.tsx" ], "exclude": [ "node_modules", "**/dist" diff --git a/yarn.lock b/yarn.lock index 4628e2655..b2ac6c066 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4806,6 +4806,7 @@ __metadata: "@babel/runtime-corejs3": "npm:7.24.4" "@junipero/core": "npm:3.4.11" core-js: "npm:3.36.1" + rollup: "npm:^4.14.3" uuid: "npm:9.0.1" languageName: unknown linkType: soft @@ -7257,7 +7258,7 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-commonjs@npm:25.0.7": +"@rollup/plugin-commonjs@npm:^25.0.7": version: 25.0.7 resolution: "@rollup/plugin-commonjs@npm:25.0.7" dependencies: @@ -7276,7 +7277,7 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-node-resolve@npm:15.2.3": +"@rollup/plugin-node-resolve@npm:^15.2.3": version: 15.2.3 resolution: "@rollup/plugin-node-resolve@npm:15.2.3" dependencies: @@ -7295,7 +7296,23 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-terser@npm:0.4.4": +"@rollup/plugin-swc@npm:^0.3.0": + version: 0.3.0 + resolution: "@rollup/plugin-swc@npm:0.3.0" + dependencies: + "@rollup/pluginutils": "npm:^5.0.1" + smob: "npm:^1.4.0" + peerDependencies: + "@swc/core": ^1.3.0 + rollup: ^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10/c2887c6c0a4383133ac89e00dfee14d14d30cdfe0354a409f64bafaf4ff515f49a89bf7ca00e6f7a7c86ea61f8cd2d598e59a960b7d04c2980c5098b0df9a8b9 + languageName: node + linkType: hard + +"@rollup/plugin-terser@npm:^0.4.4": version: 0.4.4 resolution: "@rollup/plugin-terser@npm:0.4.4" dependencies: @@ -7311,7 +7328,26 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^5.0.1": +"@rollup/plugin-typescript@npm:^11.1.6": + version: 11.1.6 + resolution: "@rollup/plugin-typescript@npm:11.1.6" + dependencies: + "@rollup/pluginutils": "npm:^5.1.0" + resolve: "npm:^1.22.1" + peerDependencies: + rollup: ^2.14.0||^3.0.0||^4.0.0 + tslib: "*" + typescript: ">=3.7.0" + peerDependenciesMeta: + rollup: + optional: true + tslib: + optional: true + checksum: 10/4ae4d6cfc929393171288df2f18b5eb837fa53d8689118d9661b3064567341f6f6cf8389af55f1d5f015e3682abf30a64ab609fdf75ecb5a84224505e407eb69 + languageName: node + linkType: hard + +"@rollup/pluginutils@npm:^5.0.1, @rollup/pluginutils@npm:^5.1.0": version: 5.1.0 resolution: "@rollup/pluginutils@npm:5.1.0" dependencies: @@ -7334,6 +7370,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-android-arm-eabi@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.14.3" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@rollup/rollup-android-arm64@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-android-arm64@npm:4.14.1" @@ -7341,6 +7384,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-android-arm64@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-android-arm64@npm:4.14.3" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@rollup/rollup-darwin-arm64@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-darwin-arm64@npm:4.14.1" @@ -7348,6 +7398,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-darwin-arm64@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-darwin-arm64@npm:4.14.3" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@rollup/rollup-darwin-x64@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-darwin-x64@npm:4.14.1" @@ -7355,6 +7412,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-darwin-x64@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-darwin-x64@npm:4.14.3" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@rollup/rollup-linux-arm-gnueabihf@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.14.1" @@ -7362,6 +7426,20 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-arm-gnueabihf@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.14.3" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-musleabihf@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.14.3" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@rollup/rollup-linux-arm64-gnu@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.14.1" @@ -7369,6 +7447,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-arm64-gnu@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.14.3" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-arm64-musl@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-linux-arm64-musl@npm:4.14.1" @@ -7376,6 +7461,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-arm64-musl@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.14.3" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@rollup/rollup-linux-powerpc64le-gnu@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.14.1" @@ -7383,6 +7475,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.14.3" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-riscv64-gnu@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.14.1" @@ -7390,6 +7489,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-riscv64-gnu@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.14.3" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-s390x-gnu@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.14.1" @@ -7397,6 +7503,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-s390x-gnu@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.14.3" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-x64-gnu@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-linux-x64-gnu@npm:4.14.1" @@ -7404,6 +7517,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-x64-gnu@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.14.3" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-x64-musl@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-linux-x64-musl@npm:4.14.1" @@ -7411,6 +7531,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-x64-musl@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.14.3" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@rollup/rollup-win32-arm64-msvc@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.14.1" @@ -7418,6 +7545,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-win32-arm64-msvc@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.14.3" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@rollup/rollup-win32-ia32-msvc@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.14.1" @@ -7425,6 +7559,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-win32-ia32-msvc@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.14.3" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@rollup/rollup-win32-x64-msvc@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-win32-x64-msvc@npm:4.14.1" @@ -7432,6 +7573,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-win32-x64-msvc@npm:4.14.3": + version: 4.14.3 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.14.3" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@seznam/compose-react-refs@npm:^1.0.6": version: 1.0.6 resolution: "@seznam/compose-react-refs@npm:1.0.6" @@ -21336,7 +21484,7 @@ __metadata: languageName: node linkType: hard -"rollup-plugin-dts@npm:6.1.0": +"rollup-plugin-dts@npm:^6.1.0": version: 6.1.0 resolution: "rollup-plugin-dts@npm:6.1.0" dependencies: @@ -21444,6 +21592,69 @@ __metadata: languageName: node linkType: hard +"rollup@npm:^4.14.3": + version: 4.14.3 + resolution: "rollup@npm:4.14.3" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.14.3" + "@rollup/rollup-android-arm64": "npm:4.14.3" + "@rollup/rollup-darwin-arm64": "npm:4.14.3" + "@rollup/rollup-darwin-x64": "npm:4.14.3" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.14.3" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.14.3" + "@rollup/rollup-linux-arm64-gnu": "npm:4.14.3" + "@rollup/rollup-linux-arm64-musl": "npm:4.14.3" + "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.14.3" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.14.3" + "@rollup/rollup-linux-s390x-gnu": "npm:4.14.3" + "@rollup/rollup-linux-x64-gnu": "npm:4.14.3" + "@rollup/rollup-linux-x64-musl": "npm:4.14.3" + "@rollup/rollup-win32-arm64-msvc": "npm:4.14.3" + "@rollup/rollup-win32-ia32-msvc": "npm:4.14.3" + "@rollup/rollup-win32-x64-msvc": "npm:4.14.3" + "@types/estree": "npm:1.0.5" + fsevents: "npm:~2.3.2" + dependenciesMeta: + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-powerpc64le-gnu": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 10/caff654b734788cbb053886c30c3a7f733af4197b5efc47e82969e9ace1698949cc843755e4aeeb5cf3c2e754e4075022af183fde103fc5e6fdc8664a8e85a1e + languageName: node + linkType: hard + "root-workspace-0b6124@workspace:.": version: 0.0.0-use.local resolution: "root-workspace-0b6124@workspace:." @@ -21485,9 +21696,11 @@ __metadata: "@remirror/react": "npm:2.0.35" "@rollup/plugin-alias": "npm:5.1.0" "@rollup/plugin-babel": "npm:6.0.4" - "@rollup/plugin-commonjs": "npm:25.0.7" - "@rollup/plugin-node-resolve": "npm:15.2.3" - "@rollup/plugin-terser": "npm:0.4.4" + "@rollup/plugin-commonjs": "npm:^25.0.7" + "@rollup/plugin-node-resolve": "npm:^15.2.3" + "@rollup/plugin-swc": "npm:^0.3.0" + "@rollup/plugin-terser": "npm:^0.4.4" + "@rollup/plugin-typescript": "npm:^11.1.6" "@storybook/addon-actions": "npm:7.6.17" "@storybook/react": "npm:7.6.17" "@storybook/react-webpack5": "npm:7.6.17" @@ -21522,7 +21735,7 @@ __metadata: remirror: "npm:2.0.38" resolve-url-loader: "npm:5.0.0" rollup: "npm:4.14.1" - rollup-plugin-dts: "npm:6.1.0" + rollup-plugin-dts: "npm:^6.1.0" rollup-plugin-postcss: "npm:4.0.2" sass: "npm:1.74.1" sass-loader: "npm:14.1.1" @@ -22017,6 +22230,13 @@ __metadata: languageName: node linkType: hard +"smob@npm:^1.4.0": + version: 1.5.0 + resolution: "smob@npm:1.5.0" + checksum: 10/a1ea453bcea89989062626ea30a1fcb42c62e96255619c8641ffa1d7ab42baf415975c67c718127036901b9e487d8bf4c46219e50cec54295412c1227700b8fe + languageName: node + linkType: hard + "socks-proxy-agent@npm:^6.0.0": version: 6.2.1 resolution: "socks-proxy-agent@npm:6.2.1" From cdd6222070b88eb878579656391d7721ea1b2d28 Mon Sep 17 00:00:00 2001 From: maxime Da Silva Date: Thu, 18 Apr 2024 11:17:13 +0200 Subject: [PATCH 05/50] feat(typescript): wip typescript --- .../react/lib/Editable/{Field.js => Field.ts} | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) rename packages/react/lib/Editable/{Field.js => Field.ts} (59%) diff --git a/packages/react/lib/Editable/Field.js b/packages/react/lib/Editable/Field.ts similarity index 59% rename from packages/react/lib/Editable/Field.js rename to packages/react/lib/Editable/Field.ts index 0a7817c46..8509634cb 100644 --- a/packages/react/lib/Editable/Field.js +++ b/packages/react/lib/Editable/Field.ts @@ -1,6 +1,38 @@ -import { useMemo } from 'react'; +import { ComponentPropsWithoutRef, MutableRefObject, useMemo } from 'react'; import { useBuilder } from '../hooks'; +import { + Component, + ComponentObject, + ComponentSettingsField, + ComponentSettingsFieldKeyTuple, + ComponentSettingsFieldObject, + ComponentSettingsTab, + ComponentSettingsTabObject, + ElementObject, + FieldOverride, + FieldOverrideObject, +} from '../../../core/lib/types'; + +export declare interface FieldProps extends ComponentPropsWithoutRef { + setting?: ComponentSettingsTab | + ComponentSettingsTabObject | + ComponentSettingsField | + ComponentSettingsFieldObject; + element?: ElementObject; + component?: ComponentObject | Component; + overrides?: FieldOverrideObject | FieldOverride; + onChange?( + key: string | ComponentSettingsFieldKeyTuple, + field: { value: any; valid: boolean } + ): void; + onCustomChange?( + key: string | ComponentSettingsFieldKeyTuple, + overrides: FieldOverrideObject | FieldOverride, + field: { value: any; valid: boolean } + ): void; + editableRef: MutableRefObject; +} const Field = ({ setting: fieldSetting, @@ -18,6 +50,8 @@ const Field = ({ }), settings: builder .getOverride('setting', element.type, { setting: fieldSetting }), + //TODO fix it, it used to know which onChange to use @dackmin + onChange: false, }), [element, fieldSetting, addons]); const field = useMemo(() => ( From f4ca25f4535a6028b1ec128597cae5ad5e5f20e6 Mon Sep 17 00:00:00 2001 From: maxime Da Silva Date: Thu, 18 Apr 2024 17:40:22 +0200 Subject: [PATCH 06/50] feat(typescript): wip typescript - react package --- packages/core/lib/Builder/index.ts | 4 +- packages/react/README.md | 2 +- packages/react/lib/Catalogue/index.d.ts | 24 ---- .../{Property.js => Property.tsx} | 18 ++- .../react/lib/DisplayableSettings/index.d.ts | 20 ---- .../react/lib/Editable/{Form.js => Form.tsx} | 31 +++-- packages/react/lib/Editable/index.d.ts | 63 ---------- .../lib/Editable/{index.js => index.tsx} | 34 ++++-- packages/react/lib/Element/index.d.ts | 17 --- .../react/lib/Element/{index.js => index.tsx} | 14 ++- packages/react/lib/Icon/index.d.ts | 7 -- .../react/lib/Icon/{index.js => index.tsx} | 8 +- packages/react/lib/Option/index.d.ts | 42 ------- packages/react/lib/Option/index.js | 77 ------------ packages/react/lib/Option/index.tsx | 111 ++++++++++++++++++ packages/react/lib/Text/index.d.ts | 12 -- packages/react/lib/Text/index.js | 18 --- packages/react/lib/Text/index.tsx | 27 +++++ packages/react/lib/addons.d.ts | 30 ----- packages/react/lib/{addons.js => addons.tsx} | 2 +- .../react/lib/components/Button/index.d.ts | 10 -- .../components/Button/{index.js => index.tsx} | 5 +- packages/react/lib/components/Col/index.d.ts | 10 -- .../components/Col/{index.js => index.tsx} | 27 +++-- .../lib/components/EmptySpace/index.d.ts | 10 -- .../EmptySpace/{index.js => index.tsx} | 0 .../react/lib/components/Foldable/index.d.ts | 18 --- .../Foldable/{index.js => index.tsx} | 17 ++- .../react/lib/components/Image/index.d.ts | 10 -- .../components/Image/{index.js => index.tsx} | 8 +- packages/react/lib/components/Row/index.d.ts | 18 --- .../components/Row/{index.js => index.tsx} | 12 +- packages/react/lib/components/Text/index.d.ts | 10 -- .../components/Text/{index.js => index.tsx} | 8 +- .../react/lib/components/Title/index.d.ts | 10 -- .../components/Title/{index.js => index.tsx} | 8 +- packages/react/lib/components/index.d.ts | 8 -- .../lib/components/{index.js => index.ts} | 0 packages/react/lib/contexts.ts | 4 +- .../react/lib/fields/ImageField/index.d.ts | 18 --- .../fields/ImageField/{index.js => index.tsx} | 24 +++- packages/react/lib/fields/index.d.ts | 1 - .../react/lib/fields/{index.js => index.ts} | 0 packages/react/lib/hooks.d.ts | 22 ---- packages/react/lib/{hooks.js => hooks.ts} | 11 +- packages/react/lib/index.d.ts | 71 ----------- packages/react/lib/{index.js => index.ts} | 0 packages/react/lib/options.d.ts | 4 - .../react/lib/{options.js => options.tsx} | 4 +- packages/react/lib/utils.d.ts | 3 - packages/react/lib/{utils.js => utils.ts} | 4 +- tsconfig.json | 2 +- 52 files changed, 323 insertions(+), 595 deletions(-) delete mode 100644 packages/react/lib/Catalogue/index.d.ts rename packages/react/lib/DisplayableSettings/{Property.js => Property.tsx} (61%) delete mode 100644 packages/react/lib/DisplayableSettings/index.d.ts rename packages/react/lib/Editable/{Form.js => Form.tsx} (89%) delete mode 100644 packages/react/lib/Editable/index.d.ts rename packages/react/lib/Editable/{index.js => index.tsx} (77%) delete mode 100644 packages/react/lib/Element/index.d.ts rename packages/react/lib/Element/{index.js => index.tsx} (93%) delete mode 100644 packages/react/lib/Icon/index.d.ts rename packages/react/lib/Icon/{index.js => index.tsx} (54%) delete mode 100644 packages/react/lib/Option/index.d.ts delete mode 100644 packages/react/lib/Option/index.js create mode 100644 packages/react/lib/Option/index.tsx delete mode 100644 packages/react/lib/Text/index.d.ts delete mode 100644 packages/react/lib/Text/index.js create mode 100644 packages/react/lib/Text/index.tsx delete mode 100644 packages/react/lib/addons.d.ts rename packages/react/lib/{addons.js => addons.tsx} (98%) delete mode 100644 packages/react/lib/components/Button/index.d.ts rename packages/react/lib/components/Button/{index.js => index.tsx} (65%) delete mode 100644 packages/react/lib/components/Col/index.d.ts rename packages/react/lib/components/Col/{index.js => index.tsx} (90%) delete mode 100644 packages/react/lib/components/EmptySpace/index.d.ts rename packages/react/lib/components/EmptySpace/{index.js => index.tsx} (100%) delete mode 100644 packages/react/lib/components/Foldable/index.d.ts rename packages/react/lib/components/Foldable/{index.js => index.tsx} (83%) delete mode 100644 packages/react/lib/components/Image/index.d.ts rename packages/react/lib/components/Image/{index.js => index.tsx} (79%) delete mode 100644 packages/react/lib/components/Row/index.d.ts rename packages/react/lib/components/Row/{index.js => index.tsx} (86%) delete mode 100644 packages/react/lib/components/Text/index.d.ts rename packages/react/lib/components/Text/{index.js => index.tsx} (51%) delete mode 100644 packages/react/lib/components/Title/index.d.ts rename packages/react/lib/components/Title/{index.js => index.tsx} (70%) delete mode 100644 packages/react/lib/components/index.d.ts rename packages/react/lib/components/{index.js => index.ts} (100%) delete mode 100644 packages/react/lib/fields/ImageField/index.d.ts rename packages/react/lib/fields/ImageField/{index.js => index.tsx} (85%) delete mode 100644 packages/react/lib/fields/index.d.ts rename packages/react/lib/fields/{index.js => index.ts} (100%) delete mode 100644 packages/react/lib/hooks.d.ts rename packages/react/lib/{hooks.js => hooks.ts} (87%) delete mode 100644 packages/react/lib/index.d.ts rename packages/react/lib/{index.js => index.ts} (100%) delete mode 100644 packages/react/lib/options.d.ts rename packages/react/lib/{options.js => options.tsx} (93%) delete mode 100644 packages/react/lib/utils.d.ts rename packages/react/lib/{utils.js => utils.ts} (83%) diff --git a/packages/core/lib/Builder/index.ts b/packages/core/lib/Builder/index.ts index abb99bf2e..bdc3f835a 100644 --- a/packages/core/lib/Builder/index.ts +++ b/packages/core/lib/Builder/index.ts @@ -14,7 +14,7 @@ import Settings from '../Settings'; declare interface IBuilder { //TODO do } - +//TODO type this export default class Builder extends Emitter implements IBuilder { logger = null; options = null; @@ -158,7 +158,7 @@ export default class Builder extends Emitter implements IBuilder { return this.#fields.get(type); } - getOverride (type, target, opts) { + getOverride (type, target, opts?: any) { return this.#overrides.get(type, target, opts); } diff --git a/packages/react/README.md b/packages/react/README.md index 1acd760a8..98328e3ac 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -21,7 +21,7 @@ A React renderer for the (maybe) popular block-based builder # Installation ```sh -yarn add @oakjs/react @oakjs/theme +yarn add @oakjs/react @oakjs/theme‡ ``` # Usage diff --git a/packages/react/lib/Catalogue/index.d.ts b/packages/react/lib/Catalogue/index.d.ts deleted file mode 100644 index fe5b7856e..000000000 --- a/packages/react/lib/Catalogue/index.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ComponentObject, ElementObject } from '@oakjs/core'; -import { ReactNode, MutableRefObject, ComponentPropsWithRef } from 'react'; - -export declare type CatalogueRef = { - open: () => void; - close: () => void; - toggle: () => void; - opened: boolean; - isOak: boolean; - innerRef: MutableRefObject; -}; - -export declare interface CatalogueProps extends ComponentPropsWithRef { - className?: string; - placement?: string; - onToggle?(props: { opened: boolean }): void; - onAppend?(props: { component: ComponentObject }): void; - onPaste?(clipboardData: ElementObject): void; - ref?: MutableRefObject; -} - -declare function Catalogue(props: CatalogueProps): ReactNode | JSX.Element; - -export default Catalogue; diff --git a/packages/react/lib/DisplayableSettings/Property.js b/packages/react/lib/DisplayableSettings/Property.tsx similarity index 61% rename from packages/react/lib/DisplayableSettings/Property.js rename to packages/react/lib/DisplayableSettings/Property.tsx index 2da6c3a0a..37ed9d324 100644 --- a/packages/react/lib/DisplayableSettings/Property.js +++ b/packages/react/lib/DisplayableSettings/Property.tsx @@ -1,19 +1,31 @@ -import { useMemo } from 'react'; +import { ComponentPropsWithoutRef, useMemo } from 'react'; import { get } from '@junipero/react'; import Text from '../Text'; +import { ComponentOverride, ComponentOverrideObject, ElementObject } from '../../../core/lib/types'; + +export declare interface PropertyProps extends ComponentPropsWithoutRef { + element: ElementObject; + field: { + key: string; + label: string; + default?: any; + options?: { value: any, title: string }[]; + }; + override?: ComponentOverrideObject | ComponentOverride; +} const Property = ({ element, field: setting, override, -}) => { +}: PropertyProps) => { const field = useMemo(() => ({ ...setting, ...override?.fields?.find(f => f.key === setting.key) || {}, }), [setting, override]); - const value = get(element, field.key, field.default); + const value = get(element, field.key as string, field.default); const option = useMemo(() => ( field.options diff --git a/packages/react/lib/DisplayableSettings/index.d.ts b/packages/react/lib/DisplayableSettings/index.d.ts deleted file mode 100644 index c2e2253aa..000000000 --- a/packages/react/lib/DisplayableSettings/index.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ReactNode, ComponentPropsWithoutRef } from 'react'; -import { - ElementObject, - ComponentObject, - Component, - ComponentOverride, - ComponentOverrideObject, -} from '@oakjs/core'; - -export declare interface DisplayableSettingsProps - extends ComponentPropsWithoutRef { - element?: ElementObject; - component?: ComponentObject | Component; - override?: ComponentOverrideObject | ComponentOverride; -} - -declare function DisplayableSettings(props: DisplayableSettingsProps): - ReactNode | JSX.Element; - -export default DisplayableSettings; diff --git a/packages/react/lib/Editable/Form.js b/packages/react/lib/Editable/Form.tsx similarity index 89% rename from packages/react/lib/Editable/Form.js rename to packages/react/lib/Editable/Form.tsx index 8633b26b6..1962a5aec 100644 --- a/packages/react/lib/Editable/Form.js +++ b/packages/react/lib/Editable/Form.tsx @@ -1,4 +1,4 @@ -import { useReducer } from 'react'; +import { ComponentPropsWithoutRef, MutableRefObject, useReducer } from 'react'; import { Button, Tabs, @@ -16,6 +16,17 @@ import { useBuilder } from '../hooks'; import Text from '../Text'; import Icon from '../Icon'; import Field from './Field'; +import { Component, ComponentObject, ElementObject } from '../../../core/lib/types'; + +export declare interface FormProps extends ComponentPropsWithoutRef { + placement?: string; + element?: ElementObject; + component?: ComponentObject | Component; + className?: string; + onSave?(): void; + onCancel?(): void; + editableRef?: MutableRefObject; +} const Form = ({ placement, @@ -26,9 +37,9 @@ const Form = ({ onCancel, editableRef, ...rest -}) => { +}: FormProps) => { const { builder } = useBuilder(); - const overrides = builder.getOverride('component', element.type); + const overrides = builder?.getOverride('component', element.type); const deserialize = overrides?.deserialize || component?.deserialize || (e => e); @@ -41,7 +52,7 @@ const Form = ({ }; const onSettingChange_ = (name, field) => { - builder.setElementSettings(state.element, name, + builder?.setElementSettings(state.element, name, field.checked ?? field.value); dispatch({ element: state.element }); }; @@ -53,19 +64,19 @@ const Form = ({ }; const onSave_ = () => { - builder.setElement(element.id, state.element || {}, { element }); - onSave(); + builder?.setElement(element?.id, state.element || {}, { element }); + onSave?.(); }; const onCancel_ = () => { dispatch({ element: deserialize(cloneDeep(element)) }); - onCancel(); + onCancel?.(); }; const getFieldPriority = field => { const fieldOverride = { - ...builder.getOverride('setting', element.type, { setting: field }), - ...builder.getOverride('component', element.type, { + ...builder?.getOverride('setting', element?.type, { setting: field }), + ...builder?.getOverride('component', element?.type, { output: 'field', setting: field, }), }; @@ -78,7 +89,7 @@ const Form = ({ const hasSubfields = setting => Array.isArray(setting.fields) && setting.fields.length > 0; - const tabs = builder.getAvailableSettings(); + const tabs = builder?.getAvailableSettings(); return (
{ - children?: ReactNode | JSX.Element; - element?: ElementObject; - component?: ComponentObject | Component; - onToggle?(props: { opened: boolean }); -} - -declare function Editable(props: EditableProps): ReactNode | JSX.Element; - -export default Editable; - -export declare interface FormProps extends ComponentPropsWithoutRef { - placement?: string; - element?: ElementObject; - component?: ComponentObject | Component; - className?: string; - onSave?(): void; - onCancel?(): void; - editableRef?: MutableRefObject; -} - -export declare function Form(props: FormProps): ReactNode | JSX.Element; - -export declare interface FieldProps extends ComponentPropsWithoutRef { - setting?: ComponentSettingsTab | - ComponentSettingsTabObject | - ComponentSettingsField | - ComponentSettingsFieldObject; - element?: ElementObject; - component?: ComponentObject | Component; - overrides?: FieldOverrideObject | FieldOverride; - onChange?( - key: string | ComponentSettingsFieldKeyTuple, - field: { value: any; valid: boolean } - ): void; - onCustomChange?( - key: string | ComponentSettingsFieldKeyTuple, - overrides: FieldOverrideObject | FieldOverride, - field: { value: any; valid: boolean } - ): void; - editableRef: MutableRefObject; -} - -export declare function Field(props: FieldProps): ReactNode | JSX.Element; diff --git a/packages/react/lib/Editable/index.js b/packages/react/lib/Editable/index.tsx similarity index 77% rename from packages/react/lib/Editable/index.js rename to packages/react/lib/Editable/index.tsx index 0b7288c07..17e043a08 100644 --- a/packages/react/lib/Editable/index.js +++ b/packages/react/lib/Editable/index.tsx @@ -6,6 +6,10 @@ import { useReducer, useImperativeHandle, useRef, + ComponentPropsWithRef, + ReactNode, + MutableRefObject, + ForwardedRef, } from 'react'; import { createPortal } from 'react-dom'; import { mockState, classNames, ensureNode } from '@junipero/react'; @@ -24,14 +28,26 @@ import { import { useBuilder } from '../hooks'; import Form from './Form'; +import { Component, ComponentObject, ElementObject } from '../../../core/lib/types'; +export declare interface EditableRef { + isOak: boolean; +} + +export declare interface EditableProps extends ComponentPropsWithRef { + children?: ReactNode | JSX.Element; + element?: ElementObject; + component?: ComponentObject | Component; + onToggle?(props: { opened: boolean }); + ref?: MutableRefObject; +} const Editable = forwardRef(({ children, element, component, onToggle, -}, ref) => { - const innerRef = useRef(); +}: EditableProps, ref) => { + const innerRef = useRef(); const { rootBoundary, floatingsRef } = useBuilder(); const [state, dispatch] = useReducer(mockState, { opened: false, @@ -50,17 +66,17 @@ const Editable = forwardRef(({ middleware: [ offset(5), ...(floatingSettings?.shift?.enabled !== false ? [shift({ - boundary: rootBoundary?.current, + boundary: (rootBoundary as MutableRefObject)?.current, limiter: limitShift(), ...floatingSettings.shift || {}, })] : []), ...(floatingSettings?.autoPlacement?.enabled !== false ? [autoPlacement({ - boundary: rootBoundary?.current, + boundary: (rootBoundary as MutableRefObject)?.current, allowedPlacements: ['bottom'], ...floatingSettings.autoPlacement || {}, })] : []), ...(floatingSettings?.flip?.enabled !== false ? [flip({ - boundary: rootBoundary?.current, + boundary: (rootBoundary as MutableRefObject)?.current, ...floatingSettings.flip || {}, })] : []), ...floatingSettings.middleware || [], @@ -100,7 +116,7 @@ const Editable = forwardRef(({ dispatch({ visible: false }); }; - const child = Children.only(children); + const child = Children.only(children) as JSX.Element; return ( <> @@ -124,7 +140,8 @@ const Editable = forwardRef(({ }} data-placement={context.placement} ref={ref => { - refs.setFloating(ref?.isOak ? ref?.innerRef.current : ref); + refs.setFloating((ref as any)?.isOak + ? (ref as any)?.innerRef.current : ref);//TODO fix it innerRef.current = ref; }} {...getFloatingProps()} @@ -140,7 +157,8 @@ const Editable = forwardRef(({ /> ), { opened: state.opened, onExited: onAnimationExit }) }
- ), ensureNode(floatingsRef.current)) } + ), ensureNode(floatingsRef.current) as any) } + {/*TODO FIX UPPER LINE */} ); }); diff --git a/packages/react/lib/Element/index.d.ts b/packages/react/lib/Element/index.d.ts deleted file mode 100644 index 773754e25..000000000 --- a/packages/react/lib/Element/index.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ReactNode, ComponentPropsWithoutRef } from 'react'; -import { - ElementObject, - ComponentObject, - Component, -} from '@oakjs/core'; - -export declare interface ElementProps extends ComponentPropsWithoutRef { - depth?: number; - element?: ElementObject; - parent?: Array; - parentComponent?: ComponentObject | Component; -} - -declare function Element(props: ElementProps): ReactNode | JSX.Element; - -export default Element; diff --git a/packages/react/lib/Element/index.js b/packages/react/lib/Element/index.tsx similarity index 93% rename from packages/react/lib/Element/index.js rename to packages/react/lib/Element/index.tsx index 8442622ac..986293c78 100644 --- a/packages/react/lib/Element/index.js +++ b/packages/react/lib/Element/index.tsx @@ -1,4 +1,4 @@ -import { Fragment, useMemo, useRef, useState } from 'react'; +import { ComponentPropsWithoutRef, Fragment, useMemo, useRef, useState } from 'react'; import { Draggable, Droppable, Tooltip, classNames } from '@junipero/react'; import { copyToClipboard } from '../utils'; @@ -8,6 +8,14 @@ import Text from '../Text'; import Option from '../Option'; import Editable from '../Editable'; import DisplayableSettings from '../DisplayableSettings'; +import { Component, ComponentObject, ElementObject } from '../../../core/lib/types'; + +export declare interface ElementProps extends ComponentPropsWithoutRef { + depth?: number; + element?: ElementObject; + parent?: Array; + parentComponent?: ComponentObject | Component; +} const Element = ({ element, @@ -15,9 +23,9 @@ const Element = ({ parentComponent, className, depth = 0, -}) => { +}: ElementProps) => { const innerRef = useRef(); - const editableRef = useRef(); + const editableRef = useRef(); const [editableOpened, setEditableOpened] = useState(false); const { builder, addons } = useBuilder(); const component = useMemo(() => ( diff --git a/packages/react/lib/Icon/index.d.ts b/packages/react/lib/Icon/index.d.ts deleted file mode 100644 index 153e162a9..000000000 --- a/packages/react/lib/Icon/index.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ReactNode, ComponentPropsWithRef, ForwardRefRenderFunction } from 'react'; - -export declare interface IconProps extends ComponentPropsWithRef {} - -declare function Icon(props: IconProps): ReactNode | JSX.Element; - -export default Icon; diff --git a/packages/react/lib/Icon/index.js b/packages/react/lib/Icon/index.tsx similarity index 54% rename from packages/react/lib/Icon/index.js rename to packages/react/lib/Icon/index.tsx index bd07d611c..0c54b982e 100644 --- a/packages/react/lib/Icon/index.js +++ b/packages/react/lib/Icon/index.tsx @@ -1,7 +1,11 @@ -import { forwardRef } from 'react'; +import { ComponentPropsWithRef, ForwardedRef, forwardRef } from 'react'; import { classNames } from '@junipero/react'; -const Icon = forwardRef(({ className, children, ...rest }, ref) => +export declare interface IconProps extends ComponentPropsWithRef {} + +const Icon = forwardRef(( + { className, children, ...rest }: IconProps, ref: ForwardedRef +) => typeof children === 'function' ? children({ ref }) : ( ; - tooltipRef: MutableRefObject; -}; - -export declare interface OptionObject { - icon?: ReactNode | JSX.Element; - render?(props: { - option: OptionObject; - className: string; - element: ElementObject; - elementInnerRef: MutableRefObject; - editableRef: MutableRefObject; - parent: Array; - component: ComponentObject | Component; - builder: Builder; - index: number; - }): ReactNode | JSX.Element; -} - -export declare interface OptionProps extends ComponentPropsWithRef { - className?: string; - iconClassName?: string; - option: OptionObject, - draggable?: boolean; - name?: ReactNode | JSX.Element; - renderIcon(): ReactNode | JSX.Element; - ref?: MutableRefObject; -} - -declare function Option(props: OptionProps): ReactNode | JSX.Element; - -export default Option; diff --git a/packages/react/lib/Option/index.js b/packages/react/lib/Option/index.js deleted file mode 100644 index 49ecda56d..000000000 --- a/packages/react/lib/Option/index.js +++ /dev/null @@ -1,77 +0,0 @@ -import { forwardRef, useImperativeHandle, useMemo, useRef } from 'react'; -import { Tooltip, classNames } from '@junipero/react'; - -import { useBuilder } from '../hooks'; -import Icon from '../Icon'; - -const Option = forwardRef(({ - className, - iconClassName, - option, - renderIcon, - draggable, - name, - onClick, - tooltipProps, - ...props -}, ref) => { - const { rootRef, rootBoundary, floatingsRef } = useBuilder(); - const innerRef = useRef(); - const tooltipRef = useRef(); - - useImperativeHandle(ref, () => ({ - isOak: true, - innerRef, - tooltipRef, - }), [innerRef.current]); - - const floatingOptions = useMemo(() => ({ - boundary: rootBoundary?.current || rootRef?.current, - rootBoundary: rootBoundary?.current || rootRef?.current, - }), []); - - const onClick_ = e => { - tooltipRef.current?.close(); - onClick?.(e); - }; - - const inner = ( - - { renderIcon ? renderIcon() : ( - - ) } - - ); - - return name ? ( - { - tooltipRef.current = r; - innerRef.current = r?.handleRef?.current; - }} - floatingOptions={floatingOptions} - text={name} - { ...tooltipProps } - > - { inner } - - ) : inner; -}); - -Option.displayName = 'Option'; - -export default Option; diff --git a/packages/react/lib/Option/index.tsx b/packages/react/lib/Option/index.tsx new file mode 100644 index 000000000..61b1b6d08 --- /dev/null +++ b/packages/react/lib/Option/index.tsx @@ -0,0 +1,111 @@ +import { ComponentPropsWithRef, forwardRef, MutableRefObject, ReactNode, useImperativeHandle, useMemo, useRef } from 'react'; +import { Tooltip, TooltipRef, classNames } from '@junipero/react'; + +import { useBuilder } from '../hooks'; +import Icon from '../Icon'; +import { Component, ComponentObject, ElementObject } from '../../../core/lib/types'; +import Builder from '../../../core/lib/Builder'; + +export declare interface OptionObject { + icon?: ReactNode | JSX.Element; + render?(props: { + option: OptionObject; + className: string; + element: ElementObject; + elementInnerRef: MutableRefObject; + editableRef: MutableRefObject; + parent: Array; + component: ComponentObject | Component; + builder: Builder; + index: number; + }): ReactNode | JSX.Element; +} + +export declare type OptionRef = { + isOak: boolean; + innerRef: MutableRefObject; + tooltipRef: MutableRefObject; +}; + +export declare interface OptionProps extends ComponentPropsWithRef { + className?: string; + iconClassName?: string; + option: OptionObject, + draggable?: boolean; + name?: ReactNode | JSX.Element; + renderIcon?(): ReactNode | JSX.Element; +} + +const Option = forwardRef(({ + className, + iconClassName, + option, + renderIcon, + draggable, + name, + onClick, + tooltipProps, + ...props +}: OptionProps, ref: MutableRefObject) => { + const { rootRef, rootBoundary, floatingsRef } = useBuilder(); + const innerRef = useRef(); + const tooltipRef = useRef(); + + useImperativeHandle(ref, () => ({ + isOak: true, + innerRef, + tooltipRef, + }), [innerRef.current]); + + const floatingOptions = useMemo(() => ({ + boundary: (rootBoundary as MutableRefObject)?.current || + rootRef?.current, + rootBoundary: (rootBoundary as MutableRefObject)?.current || + rootRef?.current, + }), []); + + const onClick_ = e => { + tooltipRef.current?.close(); + onClick?.(e); + }; + + const inner = ( + + { renderIcon ? renderIcon() : ( + + ) } + + ); + + return name ? ( + { + tooltipRef.current = r; + innerRef.current = r?.handleRef?.current; + }} + floatingOptions={floatingOptions} + text={name} + { ...tooltipProps } + > + { inner } + + ) : inner; +}); + +Option.displayName = 'Option'; + +export default Option; diff --git a/packages/react/lib/Text/index.d.ts b/packages/react/lib/Text/index.d.ts deleted file mode 100644 index 99752a77d..000000000 --- a/packages/react/lib/Text/index.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { GetTextCallback } from '@oakjs/core'; -import { ReactNode, ComponentPropsWithoutRef } from 'react'; - -export declare interface TextProps extends ComponentPropsWithoutRef { - children?: ReactNode | JSX.Element | GetTextCallback; - name?: string; - default?: ReactNode | JSX.Element | GetTextCallback; -} - -declare function Text(props: TextProps): ReactNode | JSX.Element; - -export default Text; diff --git a/packages/react/lib/Text/index.js b/packages/react/lib/Text/index.js deleted file mode 100644 index e2a2f511f..000000000 --- a/packages/react/lib/Text/index.js +++ /dev/null @@ -1,18 +0,0 @@ -import { useBuilder } from '../hooks'; - -const Text = ({ - children, - name, - default: def, -}) => { - const { builder } = useBuilder(); - const handler = name || children; - - return typeof handler === 'function' - ? handler(builder.getText.bind(builder)) - : builder.getText?.(handler, def || children || null) || def || null; -}; - -Text.displayName = 'Text'; - -export default Text; diff --git a/packages/react/lib/Text/index.tsx b/packages/react/lib/Text/index.tsx new file mode 100644 index 000000000..ebf272bab --- /dev/null +++ b/packages/react/lib/Text/index.tsx @@ -0,0 +1,27 @@ +import { ComponentPropsWithoutRef, ReactNode } from 'react'; + +import { useBuilder } from '../hooks'; +import { GetTextCallback } from '../../../core/lib/types'; + +export declare interface TextProps extends ComponentPropsWithoutRef { + children?: ReactNode | JSX.Element | GetTextCallback; + name?: string; + default?: ReactNode | JSX.Element | GetTextCallback; +} + +const Text = ({ + children, + name, + default: def, +}: TextProps) => { + const { builder } = useBuilder(); + const handler = name || children; + + return typeof handler === 'function' + ? handler(builder?.getText.bind(builder)) + : builder?.getText?.(handler, def || children || null) || def || null; +}; + +Text.displayName = 'Text'; + +export default Text; diff --git a/packages/react/lib/addons.d.ts b/packages/react/lib/addons.d.ts deleted file mode 100644 index f3848a7f2..000000000 --- a/packages/react/lib/addons.d.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { - AddonObject, - ComponentObject, - ComponentsGroupObject, - FieldObject, -} from '@oakjs/core'; - -export declare function textField(props?: object): FieldObject; -export declare function textAreaField(props?: object): FieldObject; -export declare function selectField(props?: object): FieldObject; -export declare function colorField(props?: object): FieldObject; -export declare function imageField(props?: object): FieldObject; -export declare function dateField(props?: object): FieldObject; -export declare function toggleField(props?: object): FieldObject; - -export declare function rowComponent(props?: object): ComponentObject; -export declare function colComponent(props?: object): ComponentObject; -export declare function emptySpaceComponent(props?: object): ComponentObject; -export declare function titleComponent(props?: object): ComponentObject; -export declare function textComponent(props?: object): ComponentObject; -export declare function imageComponent(props?: object): ComponentObject; -export declare function buttonComponent(props?: object): ComponentObject; -export declare function foldableComponent(props?: object): ComponentObject; - -export declare function baseFields(): Array; -export declare function baseComponents(): Array; - -export declare function coreComponentsGroups(): ComponentsGroupObject; - -export declare function baseAddon(): AddonObject; diff --git a/packages/react/lib/addons.js b/packages/react/lib/addons.tsx similarity index 98% rename from packages/react/lib/addons.js rename to packages/react/lib/addons.tsx index 3dce0107a..32cde46ff 100644 --- a/packages/react/lib/addons.js +++ b/packages/react/lib/addons.tsx @@ -24,7 +24,7 @@ import Text from './Text'; export const textField = props => ({ ...coreAddons.textField(), - render: (fieldProps, { setting, t } = {}) => ( + render: (fieldProps, { setting, t }: { setting?: any, t?: any} = {}) => ( { - element: ElementObject; -} - -declare function Button(props: ButtonProps): ReactNode | JSX.Element; - -export default Button; diff --git a/packages/react/lib/components/Button/index.js b/packages/react/lib/components/Button/index.tsx similarity index 65% rename from packages/react/lib/components/Button/index.js rename to packages/react/lib/components/Button/index.tsx index 3c6c6e944..dbcdeebb3 100644 --- a/packages/react/lib/components/Button/index.js +++ b/packages/react/lib/components/Button/index.tsx @@ -1,8 +1,11 @@ import { Button, classNames } from '@junipero/react'; import { sanitizeHTML } from '../../utils'; +import { ElementObject } from '../../../../core/lib/types'; -const Button_ = ({ element, className }) => !element.content ? null : ( +const Button_ = ( + { element, className }: { element: ElementObject, className: string } +) => !element.content ? null : (