Merge branch 'main' into feature/various-clean-up-and-corrections

This commit is contained in:
Jacob Overgaard
2023-10-06 11:48:36 +02:00
committed by GitHub
8 changed files with 353 additions and 33 deletions

View File

@@ -17874,9 +17874,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.27",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
"integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"dev": true,
"funding": [
{

View File

@@ -17,6 +17,7 @@ export * from './input-checkbox-list/index.js';
export * from './input-color/index.js';
export * from './input-eye-dropper/index.js';
export * from './input-list-base/index.js';
export * from './input-markdown-editor/index.js';
export * from './input-multi-url/index.js';
export * from './input-tiny-mce/index.js';
export * from './input-number-range/index.js';

View File

@@ -0,0 +1 @@
export * from './input-markdown.element.js';

View File

@@ -0,0 +1,81 @@
import { UmbCodeEditorElement, loadCodeEditor } from '@umbraco-cms/backoffice/code-editor';
import { css, html, customElement, query, property } from '@umbraco-cms/backoffice/external/lit';
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
/**
* @element umb-input-markdown
* @fires change - when the value of the input changes
*/
@customElement('umb-input-markdown')
export class UmbInputMarkdownElement extends FormControlMixin(UmbLitElement) {
protected getFormElement() {
return undefined;
}
@property({ type: Boolean })
preview?: boolean;
#isCodeEditorReady = new UmbBooleanState(false);
isCodeEditorReady = this.#isCodeEditorReady.asObservable();
@query('umb-code-editor')
_codeEditor?: UmbCodeEditorElement;
constructor() {
super();
this.#loadCodeEditor();
}
async #loadCodeEditor() {
try {
await loadCodeEditor();
this._codeEditor?.editor?.updateOptions({
lineNumbers: false,
minimap: false,
folding: false,
});
this.#isCodeEditorReady.next(true);
} catch (error) {
console.error(error);
}
}
render() {
return html` <div id="actions"></div>
<umb-code-editor language="markdown" .code=${this.value as string}></umb-code-editor>
${this.renderPreview()}`;
}
renderPreview() {
if (!this.preview) return;
return html`<div>TODO Preview</div>`;
}
static styles = [
css`
:host {
display: flex;
flex-direction: column;
}
#actions {
background-color: var(--uui-color-background-alt);
display: flex;
}
umb-code-editor {
height: 200px;
border-radius: var(--uui-border-radius);
border: 1px solid var(--uui-color-divider-emphasis);
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
'umb-input-markdown': UmbInputMarkdownElement;
}
}

View File

@@ -0,0 +1,13 @@
import { Meta, StoryObj } from '@storybook/web-components';
import './input-markdown.element.js';
import type { UmbInputMarkdownElement } from './input-markdown.element.js';
const meta: Meta<UmbInputMarkdownElement> = {
title: 'Components/Inputs/Markdown',
component: 'umb-input-markdown',
};
export default meta;
type Story = StoryObj<UmbInputMarkdownElement>;
export const Overview: Story = {};

View File

@@ -3,6 +3,7 @@ import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
import { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import { UmbInputMarkdownElement } from '@umbraco-cms/backoffice/components';
/**
* @element umb-property-editor-ui-markdown-editor
@@ -15,11 +16,24 @@ export class UmbPropertyEditorUIMarkdownEditorElement
@property()
value = '';
@state()
private _preview?: boolean;
@property({ attribute: false })
public config?: UmbPropertyEditorConfigCollection;
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this._preview = config?.getValueByAlias('preview');
}
#onChange(e: Event) {
this.value = (e.target as UmbInputMarkdownElement).value as string;
this.dispatchEvent(new CustomEvent('property-value-change'));
}
render() {
return html`<div>umb-property-editor-ui-markdown-editor</div>`;
return html`<umb-input-markdown
?preview=${this._preview}
@change=${this.#onChange}
.value=${this.value}></umb-input-markdown>`;
}
static styles = [UmbTextStyles];

View File

@@ -0,0 +1,186 @@
import { Canvas, Meta } from '@storybook/addon-docs';
import * as LocalizeStories from './sorter.stories';
<Meta title="API/Drag and Drop/Intro" />
# Drag and Drop
Drag and Drop can be done by using the `UmbSorterController`
To get started using drag and drop, finish the following steps:
- Preparing the model
- Setting the configuration
- Registering the controller
#### Preparing the model
The SorterController needs a model to know what item it is we are dealing with.
```typescript
type MySortEntryType = {
id: string;
value: string;
};
const awesomeModel: Array<MySortEntryType> = [
{
id: '0',
value: 'Entry 0',
},
{
id: '1',
value: 'Entry 1',
},
{
id: '2',
value: 'Entry 2',
},
];
```
#### Setting the configuration
When you know the model of which that is being sorted, you can set up the configuration.
The configuration has a lot of optional options, but the required ones are:
- compareElementToModel()
- querySelectModelToElement()
- identifier
- itemSelector
- containerSelector
It can be set up as following:
```typescript
import { UmbSorterConfig, UmbSorterController } from '@umbraco-cms/backoffice/sorter';
type MySortEntryType = {...}
const awesomeModel: Array<MySortEntryType> = [...]
const MY_SORTER_CONFIG: UmbSorterConfig<MySortEntryType> = {
compareElementToModel: (element: HTMLElement, model: MySortEntryType) => {
return element.getAttribute('data-sort-entry-id') === model.id;
},
querySelectModelToElement: (container: HTMLElement, modelEntry: MySortEntryType) => {
return container.querySelector('data-sort-entry-id=[' + modelEntry.id + ']');
},
identifier: 'test-sorter',
itemSelector: 'li',
containerSelector: 'ul',
};
export class MyElement extends UmbElementMixin(LitElement) {
render() {
return html`
<ul>
${awesomeModel.map(
(entry) =>
html`<li data-sort-entry-id="${entry.id}">
<span>${entry.value}</span>
</li>`,
)}
</ul>
`;
}
}
```
#### Registering the controller
When the model and configuration are available we can register the controller and tell the controller what model we are using.
```typescript
import { UmbSorterController, UmbSorterController } from '@umbraco-cms/backoffice/sorter';
type MySortEntryType = {...}
const awesomeModel: Array<MySortEntryType> = [...]
const MY_SORTER_CONFIG: UmbSorterConfig<MySortEntryType> = {...}
export class MyElement extends UmbElementMixin(LitElement) {
#sorter = new UmbSorterController(this, MY_SORTER_CONFIG);
constructor() {
this.#sorter.setModel(awesomeModel);
}
render() {
return html`
<ul>
${awesomeModel.map(
(entry) =>
html`<li data-sort-entry-id="${entry.id}">
<span>${entry.value}</span>
</li>`,
)}
</ul>
`;
}
}
```
### Placeholder
While dragging an entry, the entry will get an additional class that can be styled.
The class is by default `--umb-sorter-placeholder` but can be changed via the configuration to a different value.
```typescript
const MY_SORTER_CONFIG: UmbSorterConfig<MySortEntryType> = {
...
placeholderClass: 'dragging-now',
};
```
```typescript
static styles = [
css`
li {
display:relative;
}
li.dragging-now span {
visibility: hidden;
}
li.dragging-now::after {
content: '';
position: absolute;
inset: 0px;
border: 1px dashed grey;
}
`,
];
```
### Horizontal sorting
By default, the sorter controller will sort vertically. You can sort your model horizontally by setting the `resolveVerticalDirection` to return false.
```typescript
const MY_SORTER_CONFIG: UmbSorterConfig<MySortEntryType> = {
...
resolveVerticalDirection: () => return false,
};
```
### Performing logic when using the controller (TODO: Better title)
Let's say your model has a property sortOrder that you would like to update when the entry is being sorted.
You can add your code logic in the configuration option `performItemInsert` and `performItemRemove`
```typescript
export class MyElement extends UmbElementMixin(LitElement) {
#sorter = new UmbSorterController(this, {
...SORTER_CONFIG,
performItemInsert: ({ item, newIndex }) => {
console.log(item, newIndex);
// Perform some logic here to calculate the new sortOrder & save it.
return true;
},
performItemRemove: () => true,
});
}
```

View File

@@ -1,24 +1,23 @@
import { UmbSorterConfig, UmbSorterController } from '../sorter.controller.js';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import { css, customElement, html } from '@umbraco-cms/backoffice/external/lit';
import { css, customElement, html, state } from '@umbraco-cms/backoffice/external/lit';
type SortEntryType = {
id: string;
value: string;
};
const sorterConfig: UmbSorterConfig<SortEntryType> = {
const SORTER_CONFIG: UmbSorterConfig<SortEntryType> = {
compareElementToModel: (element: HTMLElement, model: SortEntryType) => {
return element.getAttribute('data-sort-entry-id') === model.id;
},
querySelectModelToElement: (container: HTMLElement, modelEntry: SortEntryType) => {
return container.querySelector('data-sort-entry-id[' + modelEntry.id + ']');
return container.querySelector('data-sort-entry-id=[' + modelEntry.id + ']');
},
identifier: 'test-sorter',
itemSelector: 'li',
containerSelector: 'ul',
};
const model: Array<SortEntryType> = [
{
id: '0',
@@ -38,18 +37,35 @@ const model: Array<SortEntryType> = [
export default class UmbTestSorterControllerElement extends UmbLitElement {
public sorter;
@state()
private vertical = true;
constructor() {
super();
this.sorter = new UmbSorterController(this, sorterConfig);
this.sorter = new UmbSorterController(this, {
...SORTER_CONFIG,
resolveVerticalDirection: () => {
this.vertical ? true : false;
},
});
this.sorter.setModel(model);
}
#toggle() {
this.vertical = !this.vertical;
}
render() {
return html`
<ul>
<uui-button label="Change direction" look="outline" color="positive" @click=${this.#toggle}>
Horizontal/Vertical
</uui-button>
<ul class="${this.vertical ? 'vertical' : 'horizontal'}">
${model.map(
(entry) => html`<li id="${'sort' + entry.id}" data-sort-entry-id="${entry.id}">${entry.value}</li>`
(entry) =>
html`<li class="item" data-sort-entry-id="${entry.id}">
<span><uui-icon name="umb:wand"></uui-icon>${entry.value}</span>
</li>`,
)}
</ul>
`;
@@ -59,39 +75,47 @@ export default class UmbTestSorterControllerElement extends UmbLitElement {
css`
:host {
display: block;
box-sizing: border-box;
}
ul {
display: flex;
flex-direction: column;
gap: 5px;
list-style: none;
padding: 0;
margin: 0;
margin: 10px 0;
}
ul.horizontal {
flex-direction: row;
}
li {
cursor: grab;
position: relative;
flex: 1;
border-radius: var(--uui-border-radius);
}
li span {
display: flex;
align-items: center;
gap: 5px;
padding: 10px;
margin: 5px;
background: #eee;
background-color: rgba(0, 255, 0, 0.3);
}
li:hover {
background: #ddd !important;
cursor: move;
li.--umb-sorter-placeholder span {
visibility: hidden;
}
li:active {
background: #ccc;
}
#sort0 {
background: #f00;
}
#sort1 {
background: #0f0;
}
#sort2 {
background: #c9da10;
li.--umb-sorter-placeholder::after {
content: '';
position: absolute;
inset: 0px;
border-radius: var(--uui-border-radius);
border: 1px dashed var(--uui-color-divider-emphasis);
}
`,
];