Skip to content

Commit

Permalink
Merge pull request #23 from hotosm/feat/shoelace
Browse files Browse the repository at this point in the history
Extend composite components from shoelace web components
  • Loading branch information
spwoodcock authored May 27, 2024
2 parents 9d3c74a + cc29268 commit f984af8
Show file tree
Hide file tree
Showing 29 changed files with 1,328 additions and 188 deletions.
3 changes: 2 additions & 1 deletion .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Preview } from "@storybook/web-components";
import "../components/theme/hot.css";
import "../dist/ui.js";
import "../dist/style.css";

const preview: Preview = {
parameters: {
Expand Down
65 changes: 0 additions & 65 deletions components/button/Button.ts

This file was deleted.

22 changes: 19 additions & 3 deletions components/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
import "./theme/hot.css";
import { Button as ButtonImport } from "./button/Button";
export { Button } from "./button/Button";
import '@shoelace-style/shoelace/dist/themes/light.css';
import '@shoelace-style/shoelace/dist/themes/dark.css';

import '@shoelace-style/shoelace/dist/components/button/button.js';
import '@shoelace-style/shoelace/dist/components/button-group/button-group.js';
import '@shoelace-style/shoelace/dist/components/icon/icon.js';
import '@shoelace-style/shoelace/dist/components/tooltip/tooltip.js';

import { setBasePath } from '@shoelace-style/shoelace/dist/utilities/base-path.js';

import { Toolbar as ToolbarImport } from "./toolbar/Toolbar";

// Set the base path to the folder you copied Shoelace's assets to
setBasePath('/shoelace');

// import { Radio as RadioImport } from "./radio/Radio";

// export { Card } from "@/card/Card.js";
// export { Dropdown } from "@/dropdown/Dropdown.js";
// export { Toggle } from "@/toggle/Toggle.js";

customElements.define("hot-button", ButtonImport);
customElements.define("hot-toolbar", ToolbarImport);
// customElements.define("hot-radio", RadioImport);
Original file line number Diff line number Diff line change
@@ -1,34 +1,30 @@
import type { Meta, StoryObj } from "@storybook/web-components";
import "./Button";
import "./Toolbar";
import { html } from "lit";

const meta: Meta = {
component: "hot-button",
component: "hot-toolbar",
};
export default meta;

export const Template: StoryObj = {
args: {
intent: "primary",
disabled: false,
tooltipPosition: "top",
},
argTypes: {
intent: {
options: ["primary", "secondary"],
tooltipPosition: {
options: ["top", "bottom", "left", "right"],
control: {
type: "select",
},
},
},
render: (args) => {
return html`
<hot-button
intent=${args.intent}
?disabled=${args.disabled}
@click=${() => {alert("Button Clicked")}}
>
Button
</hot-button>
<hot-toolbar
tooltip-position="${args.tooltipPosition}"
@hot-redo-click=${() => {alert("Redo Clicked")}}
></hot-toolbar>
`;
},
};
114 changes: 114 additions & 0 deletions components/toolbar/Toolbar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { LitElement, css, html, unsafeCSS } from "lit";
import { property } from "lit/decorators.js";
import reset from "../tailwind-reset";
import { cva } from "class-variance-authority";

const toolbarStyle = cva(
"some-css-var",
{
variants: {
someProperty: {
true: "some-css-var",
false: "some-css-var",
},
},
},
);

export class Toolbar extends LitElement {
@property() name = "hot-toolbar";

/** Change the position of the tooltips relative to buttons. */
@property({ type: String, attribute: "tooltip-position" }) tooltipPosition = "top";

static styles = [
css`
@unocss-placeholder;
`,
unsafeCSS(reset),
];

// class=${toolbarStyle({
// someProperty: this.someProperty,
// })}
protected render() {
return html`
<div class="button-group-toolbar">
${this.renderButtonGroup('History', [
{ content: 'Undo', icon: 'arrow-counterclockwise', label: 'Undo', action: this.undo },
{ content: 'Redo', icon: 'arrow-clockwise', label: 'Redo', action: this.redo }
])}
${this.renderButtonGroup('Formatting', [
{ content: 'Bold', icon: 'type-bold', label: 'Bold', action: this.bold },
{ content: 'Italic', icon: 'type-italic', label: 'Italic', action: this.italic },
{ content: 'Underline', icon: 'type-underline', label: 'Underline', action: this.underline }
])}
${this.renderButtonGroup('Alignment', [
{ content: 'Align Left', icon: 'justify-left', label: 'Align Left', action: this.alignLeft },
{ content: 'Align Center', icon: 'justify', label: 'Align Center', action: this.alignCenter },
{ content: 'Align Right', icon: 'justify-right', label: 'Align Right', action: this.alignRight }
])}
</div>
`;
}

private renderButtonGroup(label: string, buttons: Array<{ content: string, icon: string, label: string, action?: (e: MouseEvent) => void }>) {
return html`
<sl-button-group label=${label}>
${buttons.map(button => this.renderButton(button))}
</sl-button-group>
`;
}

private renderButton({ content, icon, label, action }: { content: string, icon: string, label: string, action?: (e: MouseEvent) => void }) {
return html`
<sl-tooltip content=${content} placement="${this.tooltipPosition}">
<sl-button @click=${action ?? (() => {})}><sl-icon name=${icon} label=${label}></sl-icon></sl-button>
</sl-tooltip>
`;
}

private readonly undo = (e: MouseEvent) => {
// As the original event is also named 'click'
// stop propagation of the original event
e.stopPropagation();
this.dispatchEvent(new Event("hot-undo-click"));
}

private readonly redo = (e: MouseEvent) => {
e.stopPropagation();
this.dispatchEvent(new Event("hot-redo-click"));
}

private readonly bold = (e: MouseEvent) => {
e.stopPropagation();
this.dispatchEvent(new Event("hot-bold-click"));
}

private readonly italic = (e: MouseEvent) => {
e.stopPropagation();
this.dispatchEvent(new Event("hot-italic-click"));
}

private readonly underline = (e: MouseEvent) => {
e.stopPropagation();
this.dispatchEvent(new Event("hot-underline-click"));
}

private readonly alignLeft = (e: MouseEvent) => {
e.stopPropagation();
this.dispatchEvent(new Event("hot-leftalign-click"));
}

private readonly alignCenter = (e: MouseEvent) => {
e.stopPropagation();
this.dispatchEvent(new Event("hot-centeralign-click"));
}

private readonly alignRight = (e: MouseEvent) => {
e.stopPropagation();
this.dispatchEvent(new Event("hot-rightalign-click"));
}
}

export default Toolbar;
8 changes: 0 additions & 8 deletions components/utils/cva.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
import { cva } from "class-variance-authority";
import { type ClassValue } from "clsx";
import { Simplify } from "type-fest";
import {
type ClassProp,
type StringToBoolean,
} from "class-variance-authority/dist/types";
import { type LitElement } from "lit";

function decorateCva(cvaStyle: ReturnType<typeof hotcva>["variants"]) {
return function (target: LitElement, propertyKey: string) {
console.log("decorateCva", target, propertyKey);
};
}

export function generateCvaProperties(cvaReturn: ReturnType<typeof hotcva>) {
const cvaProperties: Record<
Expand Down
14 changes: 0 additions & 14 deletions docs/components/hot-button.md

This file was deleted.

21 changes: 21 additions & 0 deletions docs/components/hot-toolbar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# hot-toolbar

## Properties

| Property | Attribute | Type | Default | Description |
|-------------------|--------------------|----------|---------------|--------------------------------------------------|
| `name` | `name` | `string` | "hot-toolbar" | |
| `tooltipPosition` | `tooltip-position` | `string` | "top" | Change the position of the tooltips relative to buttons. |

## Events

| Event |
|-------------------------|
| `hot-bold-click` |
| `hot-centeralign-click` |
| `hot-italic-click` |
| `hot-leftalign-click` |
| `hot-redo-click` |
| `hot-rightalign-click` |
| `hot-underline-click` |
| `hot-undo-click` |
4 changes: 2 additions & 2 deletions examples/react/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
<link rel="icon" type="image/svg+xml" href="./favicon.ico">
<link
rel="stylesheet"
href="http://localhost:8080/style.css"
href="http://localhost:3000/style.css"
/>
<script
type="module"
src="http://localhost:8080/ui.js"
src="http://localhost:3000/ui.js"
></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HOTOSM UI React Example</title>
Expand Down
7 changes: 4 additions & 3 deletions examples/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
"version": "0.0.0",
"type": "module",
"scripts": {
"serve-web-components": "pnpm --prefix ../../ run serve",
"dev:build-web-components": "pnpm --prefix ../../ run build",
"dev:serve-web-components": "pnpm --prefix ../../ run serve",
"dev:start-server": "vite",
"dev": "pnpm run '/^dev:.*/'",
"build": "run-p type-check \"build-only {@}\" --",
"build": "vite build",
"preview": "vite preview",
"build-only": "vite build"
},
Expand All @@ -32,7 +32,8 @@
"@types/react-dom": "^18.2.23",
"@vitejs/plugin-react": "^4.2.1",
"typescript": "~5.4.0",
"vite": "^5.1.6"
"vite": "^5.1.6",
"vite-plugin-static-copy": "^1.0.2"
},
"dependencies": {
"react": "^18.2.0",
Expand Down
Loading

0 comments on commit f984af8

Please sign in to comment.