diff --git a/ReadMe.md b/ReadMe.md index aba2e55e..03caf1b5 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -14,37 +14,70 @@ ## Usage +### Installation + ```shell -npm install boot-cell iterable-observer @nuintun/qrcode +npm install dom-renderer web-cell boot-cell +npm install parcel @parcel/config-default @parcel/transformer-typescript-tsc -D +``` + +#### `package.json` + +```json +{ + "scripts": { + "start": "parcel source/index.html --open", + "build": "parcel build source/index.html --public-url ." + } +} +``` + +#### `tsconfig.json` + +```json +{ + "compilerOptions": { + "target": "ES6", + "module": "ES2020", + "moduleResolution": "Node", + "useDefineForClassFields": true, + "jsx": "react-jsx", + "jsxImportSource": "dom-renderer" + } +} ``` -`index.html` +#### `.parcelrc` + +```json +{ + "extends": "@parcel/config-default", + "transformers": { + "*.{ts,tsx}": ["@parcel/transformer-typescript-tsc"] + } +} +``` + +### `source/index.html` ```html - - - - - - + + + + + ``` ## Components diff --git a/package.json b/package.json index 728aff50..ab69d01a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "boot-cell", - "version": "2.0.0-beta.4", + "version": "2.0.0-beta.6", "license": "LGPL-3.0", "author": "shiy2008@gmail.com", "description": "Web Components UI library based on WebCell v3, BootStrap v5, BootStrap Icon v1 & FontAwesome v6", diff --git a/source/Button.tsx b/source/Button.tsx index c4c93d5f..6bfaa363 100644 --- a/source/Button.tsx +++ b/source/Button.tsx @@ -17,7 +17,7 @@ export interface ButtonProps export const Button: FC = ({ className, href, - variant = 'primary', + variant, active, children, ...props @@ -30,14 +30,14 @@ export const Button: FC = ({ role="button" className={classNames(Class, { disabled, active })} tabIndex={disabled ? -1 : tabIndex} - ariaDisabled={disabled + ''} - ariaPressed={active + ''} - {...props} + ariaDisabled={disabled?.toString()} + ariaPressed={active?.toString()} + {...{ href, ...props }} > {children} ) : ( - ); diff --git a/source/Dropdown.tsx b/source/Dropdown.tsx index 4b2bc120..2ce7eee5 100644 --- a/source/Dropdown.tsx +++ b/source/Dropdown.tsx @@ -46,6 +46,8 @@ export const DropdownItem: FC> = ({ ); export interface DropdownButtonProps extends WebCellProps, ButtonProps { + boxClass?: string; + buttonClass?: string; caption: JsxChildren; } @@ -57,6 +59,14 @@ export interface DropdownButtonProps extends WebCellProps, ButtonProps { export class DropdownButton extends HTMLElement { declare props: DropdownButtonProps; + @attribute + @observable + accessor boxClass: string; + + @attribute + @observable + accessor buttonClass: string; + @attribute @observable accessor variant: ButtonProps['variant']; @@ -68,18 +78,23 @@ export class DropdownButton extends HTMLElement { @observable accessor caption: JsxChildren; + @attribute + @observable + accessor disabled = false; + @attribute @observable accessor show = false; renderContent() { - const { variant, size, caption, show } = this; + const { boxClass, buttonClass, variant, size, caption } = this, + { disabled, show } = this; return ( - + (this.show = !show)} > {caption} diff --git a/source/Nav.tsx b/source/Nav.tsx index bd5c1a4f..c91b17fe 100644 --- a/source/Nav.tsx +++ b/source/Nav.tsx @@ -1,9 +1,11 @@ -import { JsxProps } from 'dom-renderer'; +import { JsxChildren } from 'dom-renderer'; import { FC, WebCell, WebCellProps, component } from 'web-cell'; +import { ButtonProps } from './Button'; +import { DropdownButton } from './Dropdown'; import { OffcanvasNavbar } from './Navbar'; -export interface NavLinkProps extends JsxProps { +export interface NavLinkProps extends WebCellProps { active?: boolean; } @@ -18,6 +20,27 @@ export const NavLink: FC = ({ ); +export interface NavDropdownProps + extends Omit, + Pick { + title: JsxChildren; +} + +export const NavDropdown: FC = ({ + title, + children, + ...props +}) => ( + + {children} + +); + export interface Nav extends WebCell {} @component({ diff --git a/source/Navbar.tsx b/source/Navbar.tsx index e7fa52a6..4287d3c6 100644 --- a/source/Navbar.tsx +++ b/source/Navbar.tsx @@ -1,7 +1,14 @@ import { JsxProps, VNode } from 'dom-renderer'; import { observable } from 'mobx'; -import { FC, WebCellProps, attribute, component, observer } from 'web-cell'; -import { uniqueID } from 'web-utility'; +import { + FC, + WebCell, + WebCellProps, + attribute, + component, + observer +} from 'web-cell'; +import { delegate, uniqueID } from 'web-utility'; import { Container, ContainerProps } from './Grid'; import { @@ -73,12 +80,14 @@ export interface OffcanvasNavbarProps brand?: VNode; } +export interface OffcanvasNavbar extends WebCell {} + @component({ tagName: 'offcanvas-navbar', mode: 'open' }) @observer -export class OffcanvasNavbar extends HTMLElement { +export class OffcanvasNavbar extends HTMLElement implements WebCell { declare props: OffcanvasNavbarProps; @attribute @@ -124,6 +133,30 @@ export class OffcanvasNavbar extends HTMLElement { @observable accessor closeButton = true; + connectedCallback() { + globalThis.addEventListener?.('keyup', this.close, true); + + this.addEventListener('click', this.handleLink); + } + + disconnectedCallback() { + globalThis.removeEventListener?.('keyup', this.close, true); + + this.addEventListener('click', this.handleLink); + } + + close = (event?: KeyboardEvent | MouseEvent) => { + if ( + event instanceof KeyboardEvent && + !['Escape', 'Enter'].includes(event.key) + ) + return; + + this.open = false; + }; + + handleLink = delegate('a[href].nav-link', this.close); + renderContent() { const { variant, bg, expand, fixed, sticky, fluid, brand } = this, { title, titleId, offcanvasId, open, closeButton } = this; @@ -141,6 +174,7 @@ export class OffcanvasNavbar extends HTMLElement { id={offcanvasId} aria-labelledby={titleId} show={open} + onHide={this.close} > > = ({ +export const OffcanvasTitle: FC> = ({ className = '', children, ...props @@ -14,7 +13,7 @@ export const OffcanvasTitle: FC> = ({ ); -export interface OffcanvasHeaderProps extends JsxProps { +export interface OffcanvasHeaderProps extends WebCellProps { closeButton?: boolean; onHide?: () => any; } @@ -33,7 +32,7 @@ export const OffcanvasHeader: FC = ({ ); -export const OffcanvasBody: FC> = ({ +export const OffcanvasBody: FC> = ({ className = '', children, ...props @@ -43,7 +42,8 @@ export const OffcanvasBody: FC> = ({ ); -export interface OffcanvasProps extends JsxProps { +export interface OffcanvasProps + extends Omit { backdrop?: boolean | 'static'; show?: boolean; } @@ -52,6 +52,7 @@ export const Offcanvas: FC = ({ className = '', backdrop = true, show, + onHide, children, ...props }) => ( @@ -66,7 +67,8 @@ export const Offcanvas: FC = ({ > {children} - {show &&
} + + {show &&
} ); @@ -77,14 +79,20 @@ export interface OffcanvasBoxProps } export const OffcanvasBox: FC = ({ + style, title, titleId = uniqueID(), closeButton, + onHide, children, ...props }) => ( - - + + {title} {children}