From 870d58e220423cd0764bbef6eb8b61888a20d7a1 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 11:59:28 +0000 Subject: [PATCH 1/5] Add comprehensive DOM element creation capabilities - Add DOMTable class for creating HTML table structures (table, thead, tbody, tfoot, tr, th, td, caption) - Add DOMMedia class for creating media elements (img with accessibility support) - Add DOMSemantic class for semantic HTML5 elements (article, section, nav, header, footer, aside, main) - Enhance DOMNested class with ordered lists (ol) and definition lists (dl, dt, dd) - Enhance DOMInput class with select dropdowns (select, option, optgroup) - Add comprehensive test coverage for all new DOM classes - Add example plugin demonstrating all new DOM element capabilities - Update README.md with documentation of new features - Add CHANGELOG.md documenting all changes All new classes follow existing architecture patterns, include full JSDoc documentation, support custom styling via goober CSS-in-JS, and maintain backward compatibility. Co-Authored-By: onikiten@softserveinc.com --- CHANGELOG.md | 73 ++++++++++ README.md | 101 +++++++++++++- examples/dom_elements_plugin.ts | 125 +++++++++++++++++ src/DOMInput.ts | 79 ++++++++++- src/DOMMedia.ts | 41 ++++++ src/DOMNested.ts | 114 +++++++++++++++- src/DOMSemantic.ts | 193 ++++++++++++++++++++++++++ src/DOMTable.ts | 231 ++++++++++++++++++++++++++++++++ src/index.ts | 3 + tests/DOMInput.test.ts | 102 +++++++++++++- tests/DOMMedia.test.ts | 51 +++++++ tests/DOMNested.test.ts | 98 ++++++++++++++ tests/DOMSemantic.test.ts | 103 ++++++++++++++ tests/DOMTable.test.ts | 126 +++++++++++++++++ 14 files changed, 1436 insertions(+), 4 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 examples/dom_elements_plugin.ts create mode 100644 src/DOMMedia.ts create mode 100644 src/DOMSemantic.ts create mode 100644 src/DOMTable.ts create mode 100644 tests/DOMMedia.test.ts create mode 100644 tests/DOMSemantic.test.ts create mode 100644 tests/DOMTable.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..0388d89 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,73 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- **DOMTable class** for creating HTML table structures + - `createTable()` - Create table element + - `createTableHead()` - Create thead element + - `createTableBody()` - Create tbody element + - `createTableFoot()` - Create tfoot element + - `createTableRow()` - Create tr element + - `createTableHeader()` - Create th element with scope support + - `createTableCell()` - Create td element with colspan/rowspan support + - `createCaption()` - Create caption element + +- **DOMMedia class** for creating media elements + - `createImage()` - Create img element with src, alt, width, height, and loading attributes + +- **DOMSemantic class** for creating semantic HTML5 elements + - `createArticle()` - Create article element + - `createSection()` - Create section element + - `createNav()` - Create nav element + - `createHeader()` - Create header element + - `createFooter()` - Create footer element + - `createAside()` - Create aside element + - `createMain()` - Create main element + +- **Enhanced DOMNested class** with additional list types + - `createOrderedList()` - Create ol element + - `createDefinitionList()` - Create dl element + - `createDefinitionTerm()` - Create dt element + - `createDefinitionDescription()` - Create dd element + +- **Enhanced DOMInput class** with select dropdown support + - `createSelect()` - Create select element with onChange handler support + - `createOption()` - Create option element with value and selected attributes + - `createOptgroup()` - Create optgroup element for grouping options + +- **Example plugin** (`examples/dom_elements_plugin.ts`) demonstrating all new DOM element capabilities + +- **Comprehensive test coverage** for all new DOM classes and methods + - Unit tests for DOMTable, DOMMedia, DOMSemantic + - Enhanced tests for DOMNested and DOMInput + - Integration tests demonstrating real-world usage + +### Changed + +- Updated README.md with comprehensive documentation of new DOM element capabilities +- Updated index.ts to export new DOM classes (DOMTable, DOMMedia, DOMSemantic) + +### Technical Details + +- All new DOM classes extend the base DOM class and follow existing architecture patterns +- Full TypeScript type safety with strict mode enabled +- JSDoc documentation with @uiName tags for all public methods +- CSS-in-JS integration via goober for styling support +- Custom attributes support for all new elements +- Event handler support for interactive elements +- Maintains backward compatibility with existing DOM classes + +## [1.0.15] - Previous Release + +- Initial release with core DOM classes (DOMText, DOMButton, DOMInput, DOMLink, DOMNested, DOMMisc) +- Plugin framework with FDO_SDK base class +- IPC communication system +- Storage backends (StoreDefault, StoreJson) +- Logging and system integration utilities diff --git a/README.md b/README.md index f10e8e2..7e92331 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,102 @@ # SDK for FlexDevOPs Application modules -Information about how to test example plugin is at examples/example_plugin.ts +## Overview + +The FDO SDK provides a comprehensive toolkit for building application modules (plugins) for the FlexDevOps (FDO) desktop application ecosystem. This SDK enables developers to create modular extensions with rich UI capabilities using server-side HTML generation. + +## Features + +### DOM Element Generation + +The SDK provides extensive DOM element creation capabilities through specialized classes: + +- **DOMTable**: Create HTML tables with thead, tbody, tfoot, tr, th, td, and caption elements +- **DOMMedia**: Create media elements including images with accessibility support +- **DOMSemantic**: Create semantic HTML5 elements (article, section, nav, header, footer, aside, main) +- **DOMNested**: Create container elements including ordered lists (ol), definition lists (dl, dt, dd), and more +- **DOMInput**: Create form inputs including select dropdowns with options and optgroups +- **DOMText**: Create text elements (headings, paragraphs, spans, etc.) +- **DOMButton**: Create button elements with event handlers +- **DOMLink**: Create anchor elements +- **DOMMisc**: Create miscellaneous elements like horizontal rules + +All DOM classes support: +- Custom CSS styling via goober CSS-in-JS +- Custom classes and inline styles +- Custom HTML attributes +- Event handlers +- Accessibility attributes + +### Plugin Framework + +- **FDO_SDK Base Class**: Abstract base class with lifecycle hooks (init, render) +- **IPC Communication**: Message-based communication between plugin workers and main application +- **Data Persistence**: Multiple storage backends (in-memory, JSON file-based) +- **System Integration**: Logging, file operations, and privilege elevation + +## Getting Started + +### Installation + +```bash +npm install @anikitenko/fdo-sdk +``` + +### Creating a Plugin + +```typescript +import { FDO_SDK, FDOInterface, PluginMetadata } from "@anikitenko/fdo-sdk"; + +export default class MyPlugin extends FDO_SDK implements FDOInterface { + private readonly _metadata: PluginMetadata = { + name: "My Plugin", + version: "1.0.0", + author: "Your Name", + description: "Plugin description", + icon: "icon.png" + }; + + get metadata(): PluginMetadata { + return this._metadata; + } + + init(): void { + this.log("MyPlugin initialized!"); + } + + render(): string { + return "
Hello World
"; + } +} +``` + +### Example Usage + +See `examples/example_plugin.ts` for a basic plugin example. + +See `examples/dom_elements_plugin.ts` for comprehensive examples of using the new DOM element creation capabilities including tables, media, semantic HTML, lists, and form controls. + +## Development + +### Building + +```bash +npm run build # Build webpack bundle +npm run build:types # Generate TypeScript declarations +``` + +### Testing + +```bash +npm test # Run Jest tests +``` + +## Documentation + +- Full API documentation is available in the TypeScript declaration files +- All public methods include JSDoc comments with usage examples +- See the `examples/` directory for working plugin implementations + +## License + +ISC diff --git a/examples/dom_elements_plugin.ts b/examples/dom_elements_plugin.ts new file mode 100644 index 0000000..30ee8e2 --- /dev/null +++ b/examples/dom_elements_plugin.ts @@ -0,0 +1,125 @@ +import { FDO_SDK, FDOInterface, PluginMetadata, DOMTable, DOMMedia, DOMSemantic, DOMNested, DOMInput } from "../src"; + +/** + * Example plugin demonstrating the new DOM element creation capabilities. + * This plugin showcases tables, media elements, semantic HTML5 structures, + * ordered/definition lists, and select dropdowns. + */ +export default class DOMElementsExamplePlugin extends FDO_SDK implements FDOInterface { + private readonly _metadata: PluginMetadata = { + name: "DOM Elements Example", + version: "1.0.0", + author: "FDO SDK Team", + description: "Example plugin demonstrating new DOM element creation capabilities", + icon: "dom-icon.png" + }; + + get metadata(): PluginMetadata { + return this._metadata; + } + + init(): void { + this.log("DOM Elements Example Plugin initialized!"); + } + + render(): string { + const domTable = new DOMTable(); + const domMedia = new DOMMedia(); + const domSemantic = new DOMSemantic(); + const domNested = new DOMNested(); + const domInput = new DOMInput("example-select", {}); + + const tableHeader1 = domTable.createTableHeader(["Name"], {}, undefined, { scope: "col" }); + const tableHeader2 = domTable.createTableHeader(["Age"], {}, undefined, { scope: "col" }); + const tableHeader3 = domTable.createTableHeader(["Role"], {}, undefined, { scope: "col" }); + const headerRow = domTable.createTableRow([tableHeader1, tableHeader2, tableHeader3]); + const thead = domTable.createTableHead([headerRow]); + + const cell1 = domTable.createTableCell(["John Doe"]); + const cell2 = domTable.createTableCell(["30"]); + const cell3 = domTable.createTableCell(["Developer"]); + const dataRow1 = domTable.createTableRow([cell1, cell2, cell3]); + + const cell4 = domTable.createTableCell(["Jane Smith"]); + const cell5 = domTable.createTableCell(["28"]); + const cell6 = domTable.createTableCell(["Designer"]); + const dataRow2 = domTable.createTableRow([cell4, cell5, cell6]); + + const tbody = domTable.createTableBody([dataRow1, dataRow2]); + const caption = domTable.createCaption(["Employee Directory"]); + const table = domTable.createTable([caption, thead, tbody], { classes: ["employee-table"] }); + + const image = domMedia.createImage( + "/assets/logo.png", + "Company Logo", + { classes: ["logo-image"] }, + undefined, + { width: "200", height: "100", loading: "lazy" } + ); + + const header = domSemantic.createHeader(["

Welcome to FDO SDK

"]); + const nav = domSemantic.createNav([ + "Home", + "Documentation", + "Examples" + ]); + const article = domSemantic.createArticle([ + "

New DOM Elements

", + "

This plugin demonstrates the new DOM element creation capabilities.

" + ]); + const aside = domSemantic.createAside(["

Quick Links

"]); + const footer = domSemantic.createFooter(["

© 2025 FDO SDK

"]); + + const listItem1 = domNested.createListItem(["Install the SDK"]); + const listItem2 = domNested.createListItem(["Create your plugin"]); + const listItem3 = domNested.createListItem(["Build and test"]); + const orderedList = domNested.createOrderedList([listItem1, listItem2, listItem3], { classes: ["steps-list"] }); + + const term1 = domNested.createDefinitionTerm(["FDO"]); + const desc1 = domNested.createDefinitionDescription(["FlexDevOps - A desktop application framework"]); + const term2 = domNested.createDefinitionTerm(["SDK"]); + const desc2 = domNested.createDefinitionDescription(["Software Development Kit"]); + const definitionList = domNested.createDefinitionList([term1, desc1, term2, desc2], { classes: ["glossary"] }); + + const option1 = new DOMInput("", {}).createOption("Select an option", "", true); + const option2 = new DOMInput("", {}).createOption("Option A", "a"); + const option3 = new DOMInput("", {}).createOption("Option B", "b"); + const option4 = new DOMInput("", {}).createOption("Option C", "c"); + const select = domInput.createSelect([option1, option2, option3, option4], () => { + console.log("Selection changed"); + }); + + const groupOpt1 = new DOMInput("", {}).createOption("Item 1", "1"); + const groupOpt2 = new DOMInput("", {}).createOption("Item 2", "2"); + const optgroup1 = new DOMInput("", {}).createOptgroup("Group 1", [groupOpt1, groupOpt2]); + + const groupOpt3 = new DOMInput("", {}).createOption("Item 3", "3"); + const groupOpt4 = new DOMInput("", {}).createOption("Item 4", "4"); + const optgroup2 = new DOMInput("", {}).createOptgroup("Group 2", [groupOpt3, groupOpt4]); + + const groupedSelect = new DOMInput("grouped-select", {}).createSelect([optgroup1, optgroup2]); + + const mainContent = domSemantic.createMain([ + header, + nav, + "

Example 1: Data Table

", + table, + "

Example 2: Image

", + image, + "

Example 3: Semantic Structure

", + article, + aside, + "

Example 4: Ordered List

", + orderedList, + "

Example 5: Definition List

", + definitionList, + "

Example 6: Select Dropdown

", + select, + "

Example 7: Grouped Select

", + groupedSelect, + footer + ]); + + return mainContent; + } +} diff --git a/src/DOMInput.ts b/src/DOMInput.ts index f199c0f..09d7f8a 100644 --- a/src/DOMInput.ts +++ b/src/DOMInput.ts @@ -46,4 +46,81 @@ export class DOMInput extends DOM { return this.createElement("textarea", {...props, ...this.props}); } -} \ No newline at end of file + + /** + * Creates a select dropdown element. + * @param children - The option or optgroup children of the select. + * @param onChange - Optional change event handler. + * @returns {string} - The rendered select element. + * @uiName Create select + * @example Create a select dropdown with options. + * const option1 = new DOMInput("", {}).createOption("Option 1", "value1"); + * const option2 = new DOMInput("", {}).createOption("Option 2", "value2"); + * const select = new DOMInput("my-select", {}).createSelect([option1, option2]); + */ + public createSelect(children: any[], onChange?: Function): string { + const props = this.combineProperties("", this.options, this.id); + const selectProps = onChange ? {...props, onChange, ...this.props} : {...props, ...this.props}; + + const attributes = this.createAttributes(selectProps); + const onAttributes = onChange ? this.createOnAttributes(selectProps) : ""; + const content = this.flattenChildren(children).join(''); + + let openTag; + if (attributes && onAttributes) { + openTag = ``; + } else if (onAttributes) { + openTag = ``; + } + + return `${openTag}${content}`; + } + + /** + * Creates an option element for use within a select. + * @param label - The visible text of the option. + * @param value - The value of the option. + * @param selected - Whether the option is selected by default. + * @param otherProps - Additional properties for the option. + * @returns {string} - The rendered option element. + * @uiName Create option + * @example Create an option element. + * const option = new DOMInput("", {}).createOption("Choose me", "value1", false); + */ + public createOption(label: string, value: string, selected: boolean = false, otherProps?: Record): string { + const props = this.combineProperties("", this.options, this.id); + const optionProps = {...props, value, selected, ...otherProps}; + + const attributes = this.createAttributes(optionProps); + const openTag = attributes ? ``; + } + + /** + * Creates an optgroup element for grouping options within a select. + * @param label - The label for the option group. + * @param children - The option children of the optgroup. + * @param otherProps - Additional properties for the optgroup. + * @returns {string} - The rendered optgroup element. + * @uiName Create optgroup + * @example Create an optgroup with options. + * const option1 = new DOMInput("", {}).createOption("Sub 1", "val1"); + * const option2 = new DOMInput("", {}).createOption("Sub 2", "val2"); + * const optgroup = new DOMInput("", {}).createOptgroup("Group Label", [option1, option2]); + */ + public createOptgroup(label: string, children: any[], otherProps?: Record): string { + const props = this.combineProperties("", this.options, this.id); + const optgroupProps = {...props, label, ...otherProps}; + + const attributes = this.createAttributes(optgroupProps); + const content = this.flattenChildren(children).join(''); + const openTag = attributes ? `` : ``; + + return `${openTag}${content}`; + } +} diff --git a/src/DOMMedia.ts b/src/DOMMedia.ts new file mode 100644 index 0000000..8506867 --- /dev/null +++ b/src/DOMMedia.ts @@ -0,0 +1,41 @@ +import {DOM} from "./DOM"; + +export class DOMMedia extends DOM { + /** + * Creates a new DOMMedia instance. + * @constructor - Creates a new DOMMedia instance for self-closing media elements. + */ + constructor() { + super(true); // Media elements like img are self-closing + } + + /** + * Creates an img element. + * @param src - The source URL of the image. + * @param alt - The alternative text for the image. + * @param options - The options to apply to the image. + * @param id - The id of the image. + * @param otherProps - Additional properties like width, height, loading. + * @returns {string} - The rendered img element. + * @uiName Create image + * @example Create an image with alt text and dimensions. + * const img = new DOMMedia().createImage("/path/to/image.png", "Description", {}, undefined, { width: "300", height: "200", loading: "lazy" }); + */ + public createImage( + src: string, + alt: string, + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string, + otherProps?: Record + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("img", {...props, src, alt, ...otherProps}); + } +} diff --git a/src/DOMNested.ts b/src/DOMNested.ts index 41059e9..9649f39 100644 --- a/src/DOMNested.ts +++ b/src/DOMNested.ts @@ -174,4 +174,116 @@ export class DOMNested extends DOM { return this.createElement("form", props, children); } -} \ No newline at end of file + + /** + * Creates a new ordered list + * @param children - The children of the ordered list. + * @uiName Create ordered list + * @param options - The options to apply to the ordered list. + * @param id - The id of the ordered list. + * @returns {string} - The rendered ordered list. + * @example Create a new ordered list. + * const child1 = new DOMNested().createListItem(["First item"]); + * const child2 = new DOMNested().createListItem(["Second item"]); + * const ol = new DOMNested().createOrderedList([child1, child2]); + */ + public createOrderedList( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id) + + // Merge custom attributes (like data-static) into props + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value + } + } + + return this.createElement("ol", props, children); + } + + /** + * Creates a new definition list + * @param children - The children of the definition list (dt and dd elements). + * @uiName Create definition list + * @param options - The options to apply to the definition list. + * @param id - The id of the definition list. + * @returns {string} - The rendered definition list. + * @example Create a new definition list. + * const term1 = new DOMNested().createDefinitionTerm(["Term 1"]); + * const desc1 = new DOMNested().createDefinitionDescription(["Description 1"]); + * const dl = new DOMNested().createDefinitionList([term1, desc1]); + */ + public createDefinitionList( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id) + + // Merge custom attributes (like data-static) into props + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value + } + } + + return this.createElement("dl", props, children); + } + + /** + * Creates a new definition term + * @param children - The children of the definition term. + * @uiName Create definition term + * @param options - The options to apply to the definition term. + * @param id - The id of the definition term. + * @returns {string} - The rendered definition term. + * @example Create a new definition term. + * const dt = new DOMNested().createDefinitionTerm(["API"]); + */ + public createDefinitionTerm( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id) + + // Merge custom attributes (like data-static) into props + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value + } + } + + return this.createElement("dt", props, children); + } + + /** + * Creates a new definition description + * @param children - The children of the definition description. + * @uiName Create definition description + * @param options - The options to apply to the definition description. + * @param id - The id of the definition description. + * @returns {string} - The rendered definition description. + * @example Create a new definition description. + * const dd = new DOMNested().createDefinitionDescription(["Application Programming Interface"]); + */ + public createDefinitionDescription( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id) + + // Merge custom attributes (like data-static) into props + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value + } + } + + return this.createElement("dd", props, children); + } +} diff --git a/src/DOMSemantic.ts b/src/DOMSemantic.ts new file mode 100644 index 0000000..ee93919 --- /dev/null +++ b/src/DOMSemantic.ts @@ -0,0 +1,193 @@ +import {DOM} from "./DOM"; + +export class DOMSemantic extends DOM { + /** + * Creates a new DOMSemantic instance. + * @constructor - Creates a new DOMSemantic instance. + */ + constructor() { + super(); + } + + /** + * Creates an article element. + * @param children - The children of the article. + * @param options - The options to apply to the article. + * @param id - The id of the article. + * @returns {string} - The rendered article element. + * @uiName Create article + * @example Create an article section. + * const article = new DOMSemantic().createArticle(["

Article Title

Content...

"]); + */ + public createArticle( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("article", props, children); + } + + /** + * Creates a section element. + * @param children - The children of the section. + * @param options - The options to apply to the section. + * @param id - The id of the section. + * @returns {string} - The rendered section element. + * @uiName Create section + * @example Create a section. + * const section = new DOMSemantic().createSection(["

Section Title

Content...

"]); + */ + public createSection( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("section", props, children); + } + + /** + * Creates a nav element. + * @param children - The children of the nav (navigation links). + * @param options - The options to apply to the nav. + * @param id - The id of the nav. + * @returns {string} - The rendered nav element. + * @uiName Create nav + * @example Create a navigation menu. + * const nav = new DOMSemantic().createNav(["HomeAbout"]); + */ + public createNav( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("nav", props, children); + } + + /** + * Creates a header element. + * @param children - The children of the header. + * @param options - The options to apply to the header. + * @param id - The id of the header. + * @returns {string} - The rendered header element. + * @uiName Create header + * @example Create a page header. + * const header = new DOMSemantic().createHeader(["

Site Title

"]); + */ + public createHeader( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("header", props, children); + } + + /** + * Creates a footer element. + * @param children - The children of the footer. + * @param options - The options to apply to the footer. + * @param id - The id of the footer. + * @returns {string} - The rendered footer element. + * @uiName Create footer + * @example Create a page footer. + * const footer = new DOMSemantic().createFooter(["

© 2025 Company Name

"]); + */ + public createFooter( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("footer", props, children); + } + + /** + * Creates an aside element. + * @param children - The children of the aside. + * @param options - The options to apply to the aside. + * @param id - The id of the aside. + * @returns {string} - The rendered aside element. + * @uiName Create aside + * @example Create a sidebar. + * const aside = new DOMSemantic().createAside(["

Related Links

    ...
"]); + */ + public createAside( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("aside", props, children); + } + + /** + * Creates a main element. + * @param children - The children of the main content area. + * @param options - The options to apply to the main. + * @param id - The id of the main. + * @returns {string} - The rendered main element. + * @uiName Create main + * @example Create the main content area. + * const main = new DOMSemantic().createMain(["
...
"]); + */ + public createMain( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("main", props, children); + } +} diff --git a/src/DOMTable.ts b/src/DOMTable.ts new file mode 100644 index 0000000..35b5ed1 --- /dev/null +++ b/src/DOMTable.ts @@ -0,0 +1,231 @@ +import {DOM} from "./DOM"; + +export class DOMTable extends DOM { + /** + * Creates a new DOMTable instance. + * @constructor - Creates a new DOMTable instance. + */ + constructor() { + super(); + } + + /** + * Creates a table element. + * @param children - The children of the table (thead, tbody, tfoot, caption). + * @param options - The options to apply to the table. + * @param id - The id of the table. + * @returns {string} - The rendered table element. + * @uiName Create table + * @example Create a table with headers and rows. + * const thead = new DOMTable().createTableHead([...]); + * const tbody = new DOMTable().createTableBody([...]); + * const table = new DOMTable().createTable([thead, tbody]); + */ + public createTable( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("table", props, children); + } + + /** + * Creates a thead element. + * @param children - The children of the thead (typically tr elements with th). + * @param options - The options to apply to the thead. + * @param id - The id of the thead. + * @returns {string} - The rendered thead element. + * @uiName Create table head + * @example Create a table head with header row. + * const headerRow = new DOMTable().createTableRow([...]); + * const thead = new DOMTable().createTableHead([headerRow]); + */ + public createTableHead( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("thead", props, children); + } + + /** + * Creates a tbody element. + * @param children - The children of the tbody (typically tr elements with td). + * @param options - The options to apply to the tbody. + * @param id - The id of the tbody. + * @returns {string} - The rendered tbody element. + * @uiName Create table body + * @example Create a table body with data rows. + * const row1 = new DOMTable().createTableRow([...]); + * const row2 = new DOMTable().createTableRow([...]); + * const tbody = new DOMTable().createTableBody([row1, row2]); + */ + public createTableBody( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("tbody", props, children); + } + + /** + * Creates a tfoot element. + * @param children - The children of the tfoot (typically tr elements). + * @param options - The options to apply to the tfoot. + * @param id - The id of the tfoot. + * @returns {string} - The rendered tfoot element. + * @uiName Create table foot + * @example Create a table footer with summary row. + * const footerRow = new DOMTable().createTableRow([...]); + * const tfoot = new DOMTable().createTableFoot([footerRow]); + */ + public createTableFoot( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("tfoot", props, children); + } + + /** + * Creates a tr (table row) element. + * @param children - The children of the row (th or td elements). + * @param options - The options to apply to the row. + * @param id - The id of the row. + * @returns {string} - The rendered tr element. + * @uiName Create table row + * @example Create a table row with cells. + * const cell1 = new DOMTable().createTableCell(["Data 1"]); + * const cell2 = new DOMTable().createTableCell(["Data 2"]); + * const row = new DOMTable().createTableRow([cell1, cell2]); + */ + public createTableRow( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("tr", props, children); + } + + /** + * Creates a th (table header cell) element. + * @param children - The content of the header cell. + * @param options - The options to apply to the header cell. + * @param id - The id of the header cell. + * @param otherProps - Additional properties like scope, colspan, rowspan. + * @returns {string} - The rendered th element. + * @uiName Create table header + * @example Create a table header cell. + * const header = new DOMTable().createTableHeader(["Name"], {}, undefined, { scope: "col" }); + */ + public createTableHeader( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string, + otherProps?: Record + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("th", {...props, ...otherProps}, children); + } + + /** + * Creates a td (table data cell) element. + * @param children - The content of the data cell. + * @param options - The options to apply to the data cell. + * @param id - The id of the data cell. + * @param otherProps - Additional properties like colspan, rowspan. + * @returns {string} - The rendered td element. + * @uiName Create table cell + * @example Create a table data cell. + * const cell = new DOMTable().createTableCell(["John Doe"]); + */ + public createTableCell( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string, + otherProps?: Record + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("td", {...props, ...otherProps}, children); + } + + /** + * Creates a caption element for a table. + * @param children - The content of the caption. + * @param options - The options to apply to the caption. + * @param id - The id of the caption. + * @returns {string} - The rendered caption element. + * @uiName Create caption + * @example Create a table caption. + * const caption = new DOMTable().createCaption(["Employee List"]); + */ + public createCaption( + children: any[], + options: Partial }> = DOM.DEFAULT_OPTIONS, + id?: string + ): string { + const props = this.combineProperties("", options, id); + + if (options.customAttributes) { + for (const [attr, value] of Object.entries(options.customAttributes)) { + props[attr] = value; + } + } + + return this.createElement("caption", props, children); + } +} diff --git a/src/index.ts b/src/index.ts index ad72ca3..a63992d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,6 +20,9 @@ export * from "./DOMLink"; export * from "./DOMNested"; export * from "./DOMText"; export * from "./DOMMisc"; +export * from "./DOMTable"; +export * from "./DOMMedia"; +export * from "./DOMSemantic"; declare global { interface Window { diff --git a/tests/DOMInput.test.ts b/tests/DOMInput.test.ts index 2e0268c..465bf37 100644 --- a/tests/DOMInput.test.ts +++ b/tests/DOMInput.test.ts @@ -31,4 +31,104 @@ describe("DOMInput", () => { const textarea = domInput.createTextarea(); expect(textarea).toBe(`