Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7cc210f
remove unnessecary interface
nielslyngsoe Jan 17, 2024
9992459
use _tabsStructureHelper
nielslyngsoe Jan 17, 2024
4faeac7
clean up + logs
nielslyngsoe Jan 17, 2024
b15916e
simplify contentTypeNameOf
nielslyngsoe Jan 17, 2024
15b6cb3
create block methods
nielslyngsoe Jan 18, 2024
02367d0
prop correction
nielslyngsoe Jan 18, 2024
41d763e
encode and decode udi
nielslyngsoe Jan 18, 2024
27df80e
routeable workspace for block creation
nielslyngsoe Jan 18, 2024
e568880
todo note
nielslyngsoe Jan 18, 2024
38f9f89
remove double slash
nielslyngsoe Jan 18, 2024
1e8b40b
use routable create modal
nielslyngsoe Jan 18, 2024
2302304
clean up imports
nielslyngsoe Jan 18, 2024
3615258
implement sorting
nielslyngsoe Jan 18, 2024
56192c0
placeholder style
nielslyngsoe Jan 18, 2024
e05ac6b
Merge remote-tracking branch 'origin/main' into feature/block-list-ed…
nielslyngsoe Jan 18, 2024
896d44e
better data binding + inline mode
nielslyngsoe Jan 19, 2024
4ca76e3
to string for context token
nielslyngsoe Jan 19, 2024
c35bd93
simple inline editing
nielslyngsoe Jan 19, 2024
079cd0a
ownerTabId
nielslyngsoe Jan 19, 2024
b07f4f7
Merge remote-tracking branch 'origin/main' into feature/block-list-ed…
nielslyngsoe Jan 22, 2024
85675e4
imports
nielslyngsoe Jan 22, 2024
b4b36b4
update import
nielslyngsoe Jan 22, 2024
9ca2bc5
hideSingleGroup
nielslyngsoe Jan 22, 2024
ddf1fcb
pre live editing
nielslyngsoe Jan 22, 2024
5407c99
correct models
nielslyngsoe Jan 22, 2024
1cb689d
live editing mode
nielslyngsoe Jan 22, 2024
255f913
type export
nielslyngsoe Jan 22, 2024
9050fe2
create block at a decired index
nielslyngsoe Jan 22, 2024
fb7ce28
correct interface names
madsrasmussen Jan 23, 2024
7a475b6
correct import
madsrasmussen Jan 23, 2024
afc5eb9
fix tsc
nielslyngsoe Jan 23, 2024
04fc64e
Merge branch 'main' into feature/block-list-editor-take-2
madsrasmussen Jan 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/libs/observable-api/states/array-state.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { partialUpdateFrozenArray } from '../utils/partial-update-frozen-array.function.js';
import { pushAtToUniqueArray } from '../utils/push-at-to-unique-array.function.js';
import { pushToUniqueArray } from '../utils/push-to-unique-array.function.js';
import { UmbDeepState } from './deep-state.js';

Expand Down Expand Up @@ -166,6 +167,33 @@ export class UmbArrayState<T> extends UmbDeepState<T[]> {
return this;
}

/**
* @method appendOneAt
* @param {T} entry - new data to be added in this Subject.
* @param {T} index - index of where to append this data into the Subject.
* @return {UmbArrayState<T>} Reference to it self.
* @description - Append some new data to this Subject.
* @example <caption>Example append some data.</caption>
* const data = [
* { key: 1, value: 'foo'},
* { key: 3, value: 'bar'}
* ];
* const myState = new UmbArrayState(data);
* myState.appendOneAt({ key: 2, value: 'in-between'}, 1);
*/
appendOneAt(entry: T, index: number) {
const next = [...this.getValue()];
if (this.getUniqueMethod) {
pushAtToUniqueArray(next, entry, this.getUniqueMethod, index);
} else if (index === -1 || index >= next.length) {
next.push(entry);
} else {
next.splice(index, 0, entry);
}
this.setValue(next);
return this;
}

/**
* @method append
* @param {T[]} entries - A array of new data to be added in this Subject.
Expand Down
8 changes: 8 additions & 0 deletions src/libs/observable-api/states/string-state.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { createObservablePart, type MappingFunction, type MemoizationFunction } from '../index.js';
import { UmbBasicState } from './basic-state.js';

/**
Expand All @@ -10,4 +11,11 @@ export class UmbStringState<T> extends UmbBasicState<T | string> {
constructor(initialData: T | string) {
super(initialData);
}

asObservablePart<ReturnType>(
mappingFunction: MappingFunction<T | string, ReturnType>,
memoizationFunction?: MemoizationFunction<ReturnType>,
) {
return createObservablePart(this._subject, mappingFunction, memoizationFunction);
}
}
29 changes: 29 additions & 0 deletions src/libs/observable-api/utils/push-at-to-unique-array.function.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* @export
* @method pushToUniqueArray
* @param {T[]} data - An array of objects.
* @param {T} entry - The object to insert or replace with.
* @param {getUniqueMethod: (entry: T) => unknown} [getUniqueMethod] - Method to get the unique value of an entry.
* @description - Append or replaces an item of an Array.
* @example <caption>Example append new entry for a Array. Where the key is unique and the item will be updated if matched with existing.</caption>
* const entry = {key: 'myKey', value: 'myValue'};
* const newDataSet = pushToUniqueArray([], entry, x => x.key === key, 1);
* mySubject.next(newDataSet);
*/
export function pushAtToUniqueArray<T>(
data: T[],
entry: T,
getUniqueMethod: (entry: T) => unknown,
index: number,
): T[] {
const unique = getUniqueMethod(entry);
const indexToReplace = data.findIndex((x) => getUniqueMethod(x) === unique);
if (indexToReplace !== -1) {
data[indexToReplace] = entry;
} else if (index === -1 || index >= data.length) {
data.push(entry);
} else {
data.splice(index, 0, entry);
}
return data;
}
9 changes: 8 additions & 1 deletion src/mocks/data/data-type/data-type.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,6 @@ export const data: Array<UmbMockDataTypeModel> = [
editorSize: 'medium',
icon: 'icon-coffee',
},

{
label: 'Headline',
contentElementTypeKey: 'headline-umbraco-demo-block-id',
Expand Down Expand Up @@ -574,6 +573,14 @@ export const data: Array<UmbMockDataTypeModel> = [
},
],
},
{
alias: 'useInlineEditingAsDefault',
value: true,
},
{
alias: 'useLiveEditing',
value: true,
},
],
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { UmbBlockTypeBase, UmbInputBlockTypeElement } from '../../../block-type/index.js';
import type { UmbBlockTypeBaseModel, UmbInputBlockTypeElement } from '../../../block-type/index.js';
import '../../../block-type/components/input-block-type/index.js';
import { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
Expand All @@ -15,7 +15,7 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement
implements UmbPropertyEditorUiElement
{
@property({ attribute: false })
value: UmbBlockTypeBase[] = [];
value: UmbBlockTypeBaseModel[] = [];

@property({ type: Object, attribute: false })
public config?: UmbPropertyEditorConfigCollection;
Expand Down
4 changes: 2 additions & 2 deletions src/packages/block/block-grid/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { UmbBlockTypeBase } from '../block-type/index.js';
import type { UmbBlockTypeBaseModel } from '../block-type/index.js';

export interface UmbBlockGridType extends UmbBlockTypeBase {
export interface UmbBlockGridType extends UmbBlockTypeBaseModel {
columnSpanOptions: Array<number>;
allowAtRoot: boolean;
allowInAreas: boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { UmbBlockWorkspaceData } from '../../index.js';
import { UmbModalToken, UmbWorkspaceData, UmbWorkspaceValue } from '@umbraco-cms/backoffice/modal';

export interface UmbBlockGridWorkspaceData
extends UmbBlockWorkspaceData<{
index: number;
parentId: string | null;
}> {}

export const UMB_BLOCK_GRID_WORKSPACE_MODAL = new UmbModalToken<UmbBlockGridWorkspaceData, UmbWorkspaceValue>(
'Umb.Modal.Workspace',
{
modal: {
type: 'sidebar',
size: 'medium',
},
data: { entityType: 'block', preset: {}, originData: { index: -1, parentId: null } },
// Recast the type, so the entityType data prop is not required:
},
) as UmbModalToken<Omit<UmbWorkspaceData, 'entityType'>, UmbWorkspaceValue>;
1 change: 1 addition & 0 deletions src/packages/block/block-grid/workspace/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const UMB_BLOCK_GRID_TYPE_WORKSPACE_ALIAS = 'Umb.Workspace.BlockGridType';
export * from './block-grid-workspace.modal-token.js';
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { UmbBlockListContext } from '../../context/block-list.context.js';
import { html, css, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import { type UmbBlockLayoutBaseModel } from '@umbraco-cms/backoffice/block';
import '../ref-list-block/index.js';
import { UmbBlockContext } from '@umbraco-cms/backoffice/block';
import '../inline-list-block/index.js';
import { UMB_CONFIRM_MODAL, UMB_MODAL_MANAGER_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/modal';

/**
Expand All @@ -22,7 +23,7 @@ export class UmbPropertyEditorUIBlockListBlockElement extends UmbLitElement impl
}
private _layout?: UmbBlockLayoutBaseModel | undefined;

#context = new UmbBlockContext(this);
#context = new UmbBlockListContext(this);

@state()
_contentUdi?: string;
Expand All @@ -31,22 +32,25 @@ export class UmbPropertyEditorUIBlockListBlockElement extends UmbLitElement impl
_label = '';

@state()
_workspacePath?: string;
_workspaceEditPath?: string;

@state()
_inlineEditingMode?: boolean;

constructor() {
super();

this.observe(this.#context.workspacePath, (workspacePath) => {
this._workspacePath = workspacePath;
this.observe(this.#context.workspaceEditPath, (workspaceEditPath) => {
this._workspaceEditPath = workspaceEditPath;
});
this.observe(this.#context.contentUdi, (contentUdi) => {
this._contentUdi = contentUdi;
});
this.observe(this.#context.label, (label) => {
this._label = label;
});
this.observe(this.#context.layout, (layout) => {
console.log('layout', layout);
this.observe(this.#context.inlineEditingMode, (inlineEditingMode) => {
this._inlineEditingMode = inlineEditingMode;
});
}

Expand All @@ -66,19 +70,19 @@ export class UmbPropertyEditorUIBlockListBlockElement extends UmbLitElement impl
}

#renderRefBlock() {
return html`<umb-ref-list-block .name=${this._label}> </umb-ref-list-block>`;
return html`<umb-ref-list-block .name=${this._label}></umb-ref-list-block>`;
}

/*#renderInlineBlock() {
return html`<umb-inline-list-block name="block" }}></umb-inline-list-block>`;
}*/
#renderInlineBlock() {
return html`<umb-inline-list-block .name=${this._label}></umb-inline-list-block>`;
}

#renderBlock() {
return html`
${this.#renderRefBlock()}
${this._inlineEditingMode ? this.#renderInlineBlock() : this.#renderRefBlock()}
<uui-action-bar>
${this._workspacePath
? html`<uui-button label="edit" compact href=${this._workspacePath + 'edit/' + this._contentUdi}>
${this._workspaceEditPath
? html`<uui-button label="edit" compact href=${this._workspaceEditPath}>
<uui-icon name="icon-edit"></uui-icon>
</uui-button>`
: ''}
Expand All @@ -90,7 +94,7 @@ export class UmbPropertyEditorUIBlockListBlockElement extends UmbLitElement impl
}

render() {
return this.layout ? this.#renderBlock() : '';
return this.layout && this._contentUdi ? this.#renderBlock() : '';
}

static styles = [
Expand All @@ -104,6 +108,10 @@ export class UmbPropertyEditorUIBlockListBlockElement extends UmbLitElement impl
top: var(--uui-size-2);
right: var(--uui-size-2);
}

:host([drag-placeholder]) {
opacity: 0.2;
}
`,
];
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,99 @@
import { customElement } from '@umbraco-cms/backoffice/external/lit';
import { UMB_BLOCK_LIST_CONTEXT } from '../../index.js';
import { UMB_BLOCK_WORKSPACE_ALIAS, UMB_BLOCK_WORKSPACE_CONTEXT } from '../../../block/index.js';
import { UmbExtensionsApiInitializer, createExtensionApi } from '@umbraco-cms/backoffice/extension-api';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { css, customElement, html, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import '../../../block/workspace/views/edit/block-workspace-view-edit-no-router.element.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';

/**
* @element umb-inline-list-block
*/
@customElement('umb-inline-list-block')
export class UmbInlineListBlockElement extends UmbLitElement {
#blockContext?: typeof UMB_BLOCK_LIST_CONTEXT.TYPE;
#workspaceContext?: typeof UMB_BLOCK_WORKSPACE_CONTEXT.TYPE;
#contentUdi?: string;

@state()
_label = '';

@state()
_isOpen = false;

constructor() {
super();

this.consumeContext(UMB_BLOCK_LIST_CONTEXT, (blockContext) => {
this.#blockContext = blockContext;
this.observe(
this.#blockContext.contentUdi,
(contentUdi) => {
this.#contentUdi = contentUdi;
this.#load();
},
'observeContentUdi',
);
this.observe(blockContext.label, (label) => {
this._label = label;
});
});
this.observe(umbExtensionsRegistry.getByTypeAndAlias('workspace', UMB_BLOCK_WORKSPACE_ALIAS), (manifest) => {
if (manifest) {
createExtensionApi(manifest, [this, { manifest: manifest }]).then((context) => {
if (context) {
this.#workspaceContext = context as typeof UMB_BLOCK_WORKSPACE_CONTEXT.TYPE;
this.#load();
this.#workspaceContext.content.createPropertyDatasetContext(this);

new UmbExtensionsApiInitializer(this, umbExtensionsRegistry, 'workspaceContext', [
this,
this.#workspaceContext,
]);
}
});
}
});
}

#load() {
if (!this.#workspaceContext || !this.#contentUdi) return;
this.#workspaceContext.load(this.#contentUdi);
}

render() {
return 'inline mode..';
return html` <uui-box>
<button
slot="header"
id="accordion-button"
@click=${() => {
this._isOpen = !this._isOpen;
}}>
<uui-icon name="icon-document"></uui-icon>
<uui-symbol-expand .open=${this._isOpen}></uui-symbol-expand>
<span>${this._label}</span>
</button>
${this._isOpen === true
? html`<umb-block-workspace-view-edit-no-router></umb-block-workspace-view-edit-no-router>`
: ''}
</uui-box>`;
}

static styles = [
css`
#accordion-button {
display: flex;
text-align: left;
align-items: center;
justify-content: flex-start;
width: 100%;
border: none;
background: none;
padding: 0;
}
`,
];
}

export default UmbInlineListBlockElement;
Expand Down
Loading