Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: List 2.0 #76

Merged
merged 43 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
16d85dd
implemented dev model
e11sy Aug 1, 2024
88eb6c6
added ol and ul list renderer classes
e11sy Aug 1, 2024
d057bca
patched types
e11sy Aug 1, 2024
da80ff6
added styles for checklist
e11sy Aug 1, 2024
2afda74
pathced style names
e11sy Aug 1, 2024
e7a585e
added checklist renderer
e11sy Aug 1, 2024
7cbd0d7
separated list renderer classes
e11sy Aug 1, 2024
7452185
types separated
e11sy Aug 1, 2024
d949cbc
added tabulator class
e11sy Aug 1, 2024
df88c86
added new index
e11sy Aug 2, 2024
d46b8dd
list types switch implemented
e11sy Aug 2, 2024
5bae2c0
content is editable
e11sy Aug 2, 2024
dd576b9
ordered list item numbering improved
e11sy Aug 3, 2024
0da5fd1
children styles updated
e11sy Aug 3, 2024
3227a52
fixed saving and content format
e11sy Aug 3, 2024
d484ff8
refactored checkbox styles
e11sy Aug 3, 2024
e04e8df
now tool saving data with meta field
e11sy Aug 3, 2024
a180404
comments improved
e11sy Aug 3, 2024
3d1ef9d
get rid of ex.ts
e11sy Aug 3, 2024
9064c1b
comments improved in types
e11sy Aug 3, 2024
d9110c9
removed unneded for dev mode tools from index
e11sy Aug 3, 2024
f899714
for ordered and unordered list item meta would be {}
e11sy Aug 3, 2024
fdac5a2
added private class properties
e11sy Aug 3, 2024
78d8f32
moved click event delegation from `toggleCheckbox()`
e11sy Aug 3, 2024
8de6984
separated types
e11sy Aug 3, 2024
b4cf738
added `currentLevel` property for ListTabulator
e11sy Aug 3, 2024
91b7cfa
minor fix
e11sy Aug 3, 2024
cf25166
separated css styles for different classes
e11sy Aug 3, 2024
717f079
comments improved
e11sy Aug 3, 2024
99eebd6
files renaming
e11sy Aug 3, 2024
a9e2507
files renaming
e11sy Aug 3, 2024
5903be0
list css classes interface now extended
e11sy Aug 3, 2024
7314e07
style fix
e11sy Aug 3, 2024
348da48
removed itemBody
e11sy Aug 5, 2024
1a012b2
changed addTab behaviour
e11sy Aug 6, 2024
20e6073
file renaming
e11sy Aug 7, 2024
e2a8d6f
file renaming
e11sy Aug 7, 2024
a9abfa3
file renaming
e11sy Aug 7, 2024
c60e9fe
renaming
e11sy Aug 7, 2024
ac07f38
renaming
e11sy Aug 7, 2024
3bb7736
List renderer now interface
e11sy Aug 7, 2024
3d87c88
filled list renderer interface
e11sy Aug 7, 2024
d38e7b2
comment improved
e11sy Aug 7, 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
406 changes: 406 additions & 0 deletions index.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@
"vite-plugin-dts": "^3.9.1"
},
"dependencies": {
"@codexteam/icons": "^0.0.2"
"@codexteam/icons": "^0.3.2"
}
}
141 changes: 141 additions & 0 deletions src/ListRenderer/checklistRenderer.ts
neSpecc marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { IconCheck } from '@codexteam/icons'
import ItemMeta from "../types/itemMeta";
import { NestedListConfig } from "../types/listParams";
import * as Dom from '../utils/dom';
import { ListRenderer } from './listRenderer';

/**
* Class that is responsible for checklist rendering
*/
export class CheckListRenderer extends ListRenderer {
/**
* Tool's configuration
*/
protected config?: NestedListConfig;

/**
* Is NestedList Tool read-only option
*/
readOnly: boolean;
neSpecc marked this conversation as resolved.
Show resolved Hide resolved

constructor(readonly: boolean, config?: NestedListConfig) {
super();
this.config = config;
this.readOnly = readonly;
}

/**
* Renders ol wrapper for list
* @returns - created html ol element
*/
renderWrapper(): HTMLOListElement {
const listWrapper = Dom.make('ul', [ListRenderer.CSS.wrapper, ListRenderer.CSS.wrapperChecklist]) as HTMLOListElement;

listWrapper.addEventListener('click', (event) => {
this.toggleCheckbox(event);
neSpecc marked this conversation as resolved.
Show resolved Hide resolved
});

return listWrapper;
}

/**
* Render wrapper of child list
* @returns wrapper element of the child list
*/
renderSublistWrapper(): HTMLElement {
const divElement = Dom.make('ul', [ListRenderer.CSS.wrapperChecklist, ListRenderer.CSS.itemChildren]) as HTMLElement;

return divElement;
}

/**
* Redners list item element
* @param content - content of the list item
* @returns - created html list item element
*/
renderItem(content: string, meta: ItemMeta): HTMLLIElement {
neSpecc marked this conversation as resolved.
Show resolved Hide resolved
const itemWrapper = Dom.make('li', [ListRenderer.CSS.item, ListRenderer.CSS.item]);
const itemBody = Dom.make('div', ListRenderer.CSS.itemBody);
const itemContent = Dom.make('div', ListRenderer.CSS.itemContent, {
innerHTML: content,
contentEditable: (!this.readOnly).toString(),
});

const checkbox = Dom.make('span', ListRenderer.CSS.checkbox);
const checkboxContainer = Dom.make('div', ListRenderer.CSS.checkboxContainer);

if (meta && meta.checked === true) {
checkboxContainer.classList.add(ListRenderer.CSS.itemChecked);
}

checkbox.innerHTML = IconCheck;
checkboxContainer.appendChild(checkbox);

itemBody.appendChild(itemContent);
itemWrapper.appendChild(checkboxContainer);
itemWrapper.appendChild(itemBody);

return itemWrapper as HTMLLIElement;
}

/**
* Return the item content
*
* @param {Element} item - item wrapper (<li>)
* @returns {string}
*/
getItemContent(item: Element): string {
const contentNode = item.querySelector(`.${ListRenderer.CSS.itemContent}`);
if (!contentNode) {
return '';
}

if (Dom.isEmpty(contentNode)) {
return '';
}

return contentNode.innerHTML;
}

/**
* Return meta object of certain element
* @param {Element} item - item of the list to get meta from
* @returns {ItemMeta} Item meta object
*/
getItemMeta(item: Element): ItemMeta {
neSpecc marked this conversation as resolved.
Show resolved Hide resolved
const checkbox = item.querySelector(`.${ListRenderer.CSS.checkboxContainer}`);

return {
checked: checkbox ? checkbox.classList.contains(ListRenderer.CSS.itemChecked) : undefined,
}
}

/**
* Toggle checklist item state
*
* @private
* @param {MouseEvent} event - click
* @returns {void}
*/
private toggleCheckbox(event: any): void {
const checkbox = event.target.closest(`.${ListRenderer.CSS.checkboxContainer}`);

if (checkbox && checkbox.contains(event.target)) {
checkbox.classList.toggle(ListRenderer.CSS.itemChecked);
checkbox.classList.add(ListRenderer.CSS.noHover);
checkbox.addEventListener('mouseleave', () => this.removeSpecialHoverBehavior(checkbox), { once: true });
}
}

/**
* Removes class responsible for special hover behavior on an item
*
* @private
* @param {Element} el - item wrapper
* @returns {Element}
*/
private removeSpecialHoverBehavior(el: HTMLElement) {
el.classList.remove(ListRenderer.CSS.noHover);
}
}

6 changes: 6 additions & 0 deletions src/ListRenderer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { CheckListRenderer } from "./checklistRenderer";
import { OrderedListRenderer } from "./orderedListRenderer";
import { UnorderedListRenderer } from "./unorderedListRenderer";
import { ListRenderer } from './listRenderer';

export { CheckListRenderer, OrderedListRenderer, UnorderedListRenderer, ListRenderer };
48 changes: 48 additions & 0 deletions src/ListRenderer/listRenderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* CSS classes for the Nested List Tool
*/
interface NestedListCssClasses {
wrapper: string;
wrapperOrdered: string;
wrapperUnordered: string;
wrapperChecklist: string;
neSpecc marked this conversation as resolved.
Show resolved Hide resolved
item: string;
itemBody: string;
itemContent: string;
itemChildren: string;
settingsWrapper: string;
itemChecked: string;
noHover: string;
checkbox: string;
checkboxContainer: string;
neSpecc marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* List renderer class
* Used for storing css classes and
*/
export abstract class ListRenderer {
/**
* Styles
*
* @returns {NestedListCssClasses} - CSS classes names by keys
* @private
*/
static get CSS(): NestedListCssClasses {
return {
wrapper: 'cdx-nested-list',
wrapperOrdered: 'cdx-nested-list--ordered',
wrapperUnordered: 'cdx-nested-list--unordered',
wrapperChecklist: 'cdx-nested-list--checklist',
item: 'cdx-nested-list__item',
itemBody: 'cdx-nested-list__item-body',
itemContent: 'cdx-nested-list__item-content',
itemChildren: 'cdx-nested-list__item-children',
settingsWrapper: 'cdx-nested-list__settings',
itemChecked: 'cdx-nested-list__checkbox--checked',
noHover: 'cdx-nested-list__checkbox--no-hover',
checkbox: 'cdx-nested-list__checkbox-check',
checkboxContainer: 'cdx-nested-list__checkbox'
};
}
}
91 changes: 91 additions & 0 deletions src/ListRenderer/orderedListRenderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import ItemMeta from "../types/itemMeta";
import { NestedListConfig } from "../types/listParams";
import * as Dom from '../utils/dom';
import { ListRenderer } from './listRenderer';

/**
* Class that is responsible for ordered list rendering
*/
export class OrderedListRenderer extends ListRenderer {
/**
* Tool's configuration
*/
protected config?: NestedListConfig;

/**
* Is NestedList Tool read-only option
*/
readOnly: boolean;

constructor(readonly: boolean, config?: NestedListConfig) {
super();
this.config = config;
this.readOnly = readonly;
}

/**
* Renders ol wrapper for list
* @returns - created html ol element
*/
renderWrapper(): HTMLOListElement {
return Dom.make('ol', [ListRenderer.CSS.wrapper, ListRenderer.CSS.wrapperOrdered]) as HTMLOListElement;
}

/**
* Render wrapper of child list
* @returns wrapper element of the child list
*/
renderSublistWrapper(): HTMLElement {
const divElement = Dom.make('ol', [ListRenderer.CSS.wrapperOrdered, ListRenderer.CSS.itemChildren]) as HTMLElement;

return divElement;
}

/**
* Redners list item element
* @param content - content of the list item
* @returns - created html list item element
*/
renderItem(content: string): HTMLLIElement {
const itemWrapper = Dom.make('li', ListRenderer.CSS.item);
const itemBody = Dom.make('div', ListRenderer.CSS.itemBody);
const itemContent = Dom.make('div', ListRenderer.CSS.itemContent, {
innerHTML: content,
contentEditable: (!this.readOnly).toString(),
});

itemBody.appendChild(itemContent);
itemWrapper.appendChild(itemBody);

return itemWrapper as HTMLLIElement;
}

/**
* Return the item content
*
* @param {Element} item - item wrapper (<li>)
* @returns {string}
*/
getItemContent(item: Element): string {
const contentNode = item.querySelector(`.${ListRenderer.CSS.itemContent}`);
if (!contentNode) {
return '';
}

if (Dom.isEmpty(contentNode)) {
return '';
}

return contentNode.innerHTML;
}

/**
* Returns item meta, for ordered list checked will be always undefined
* @returns Item meta object
*/
getItemMeta(): ItemMeta {
neSpecc marked this conversation as resolved.
Show resolved Hide resolved
return {
checked: undefined,
}
neSpecc marked this conversation as resolved.
Show resolved Hide resolved
}
}
95 changes: 95 additions & 0 deletions src/ListRenderer/unorderedListRenderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import ItemMeta from "../types/itemMeta";
import { NestedListConfig } from "../types/listParams";
import * as Dom from '../utils/dom';
import { ListRenderer } from './listRenderer';

/**
* Class that is responsible for unordered list rendering
*/
export class UnorderedListRenderer extends ListRenderer {
/**
* Tool's configuration
*/
protected config?: NestedListConfig;

/**
* Is NestedList Tool read-only option
*/
readOnly: boolean;

constructor(readonly: boolean, config?: NestedListConfig) {
super();
this.config = config;
this.readOnly = readonly;
}

/**
* Renders ol wrapper for list
* @returns - created html ol element
*/
renderWrapper(): HTMLOListElement {

const ulElement = Dom.make('ul', [ListRenderer.CSS.wrapper, ListRenderer.CSS.wrapperUnordered]) as HTMLOListElement;

return ulElement;
}

/**
* Render wrapper of child list
* @returns wrapper element of the child list
*/
renderSublistWrapper(): HTMLElement {
const divElement = Dom.make('ul', [ListRenderer.CSS.wrapperUnordered, ListRenderer.CSS.itemChildren]) as HTMLElement;

return divElement;
}

/**
* Redners list item element
* @param content - content of the list item
* @returns - created html list item element
*/
renderItem(content: string): HTMLLIElement {
const itemWrapper = Dom.make('li', ListRenderer.CSS.item);
const itemBody = Dom.make('div', ListRenderer.CSS.itemBody);
const itemContent = Dom.make('div', ListRenderer.CSS.itemContent, {
innerHTML: content,
contentEditable: (!this.readOnly).toString(),
});

itemBody.appendChild(itemContent);
itemWrapper.appendChild(itemBody);

return itemWrapper as HTMLLIElement;
}

/**
* Return the item content
*
* @param {Element} item - item wrapper (<li>)
* @returns {string}
*/
getItemContent(item: Element): string {
const contentNode = item.querySelector(`.${ListRenderer.CSS.itemContent}`);
if (!contentNode) {
return '';
}

if (Dom.isEmpty(contentNode)) {
return '';
}

return contentNode.innerHTML;
}


/**
* Returns item meta, for undered list checked will be always undefined
* @returns Item meta object
*/
getItemMeta(): ItemMeta {
return {
checked: undefined,
neSpecc marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Loading
Loading