@hotosm/ui 0.2.0-b3 → 0.2.0-b4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -45,6 +45,9 @@ The components are
45
45
  [Web Components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components),
46
46
  currently written in **Lit**, using TypeScript.
47
47
 
48
+ Compositie components (header, sidebar, etc) are generated using Shoelace, with
49
+ the remaining low-level components exported from the Shoelace library too.
50
+
48
51
  ## Install
49
52
 
50
53
  There are two options for install:
@@ -64,22 +67,30 @@ There are two options for install:
64
67
 
65
68
  ```html
66
69
  <script>
70
+ import '@hotosm/ui/dist/style.css';
67
71
  import '@hotosm/ui/dist/components.js';
68
72
  </script>
69
73
 
70
74
  // Use the components in your templates
71
- <hot-button disabled> </hot-button>
75
+ <hot-header @login="someFunction()"> </hot-header>
72
76
  ```
73
77
 
74
78
  #### Via CDN
75
79
 
76
80
  ```html
81
+ // Import the styles (or create your own)
82
+ <link
83
+ rel="stylesheet"
84
+ href="https://s3.amazonaws.com/hotosm-ui/latest/style.css"
85
+ />
86
+
87
+ // Import the components
77
88
  <script
78
89
  type="module"
79
90
  src="https://cdn.jsdelivr.net/npm/@hotosm/ui@latest/dist/components.js"
80
91
  ></script>
81
92
 
82
- <hot-button disabled> </hot-button>
93
+ <hot-header @login="someFunction()> </hot-header>
83
94
  ```
84
95
 
85
96
  The `jsdelivr` CDN only includes package releases, with `@latest` pointing to the
@@ -94,28 +105,24 @@ There is also an S3-based CDN, where `latest` tracks the `main` branch of the re
94
105
  'tree-shaking' can remove the remaining ones you don't use.
95
106
  - If you are developing an application that uses `@hotosm/ui` components,
96
107
  including a bundler such as rollup/vite/webpack, this is probably the best approach.
97
- - However, you must first add Shoelace as a `peerDependency` in your `package.json`:
108
+ - However, you must first add Lit as a `peerDependency` in your `package.json`:
98
109
 
99
110
  ```json
100
111
  "peerDependencies": {
101
- "@shoelace-style/shoelace": "^2.15.1"
112
+ "lit": "^3.1.0"
102
113
  }
103
114
  ```
104
115
 
105
- > Ideally the version of Shoelace installed should match the version used in
116
+ > Ideally the version of Lit installed should match the version used in
106
117
  > hotosm/ui.
107
118
 
108
- - This will also install subdependencies such as Lit.
109
- - If there is a conflict between Lit versions, the `lit` package can also be pinned
110
- via `peerDependency`.
111
-
112
119
  Example:
113
120
 
114
121
  ```js
115
- import '@hotosm/ui/components/Toolbar';
122
+ import '@hotosm/ui/components/header/header';
116
123
 
117
124
  // Then in your template
118
- <hot-button>Click Me</hot-button>
125
+ <hot-header @login="${someFunction()}"></hot-header>
119
126
  ```
120
127
 
121
128
  ### React
@@ -130,7 +137,7 @@ pnpm install @hotosm/ui
130
137
  ```
131
138
 
132
139
  ```js
133
- import { Button } from '@hotosm/ui/react/Button'
140
+ import { Button } from '@hotosm/ui/react/Header'
134
141
 
135
142
  const HomePage = ({}) => {
136
143
  return (
@@ -138,7 +145,7 @@ const HomePage = ({}) => {
138
145
  <div
139
146
  ...
140
147
  >
141
- <Button disabled />
148
+ <Header @onLogin="${someFunction()}" />
142
149
  </div>
143
150
  </div>
144
151
  );
@@ -152,20 +159,21 @@ export default HomePage;
152
159
 
153
160
  ## Using Extra Shoelace Components
154
161
 
155
- The UI library is not comprehensive & you may wish to use additional components
156
- from Shoelace in your app.
162
+ The UI library contains many composite components, such as headers, sidebars,
163
+ tracking banners, etc, and does not re-invent the wheel for low-level components.
157
164
 
158
- Ideally you should install the same version of @shoelace-style/shoelace as this
159
- library (particularly if using the ES Modules)
165
+ Shoelace is an excellent UI library that is exported directly from `@hotosm/ui`.
160
166
 
161
- To determine which version:
167
+ To access the low-level components, such as buttons, dropdowns, modals, etc,
168
+ simply import the component of the same name from the [Shoelace docs]
169
+ (<https://shoelace.style>):
162
170
 
163
- - View the
164
- [@hotosm/ui](https://www.npmjs.com/package/@hotosm/ui?activeTab=versions)
165
- package on npmjs.com.
166
- - Select the version you are using.
167
- - Go to the `Code` tab, then open the `package.json` file.
168
- - The version of shoelace used should be in the `dependencies` section.
171
+ ```js
172
+ import '@hotosm/ui/components/button/button';
173
+
174
+ // Then in your template
175
+ <hot-button disabled variant="secondary">Can't Click Me</hot-button>
176
+ ```
169
177
 
170
178
  If you are using a bundler, you must bundle the (icon) assets yourself,
171
179
  described in the Shoelace docs.
@@ -0,0 +1,30 @@
1
+ import "../../theme/sl-custom.css";
2
+ import '@shoelace-style/shoelace/dist/components/icon-button/icon-button.js';
3
+ import '@shoelace-style/shoelace/dist/components/tab-panel/tab-panel.js';
4
+ import '@shoelace-style/shoelace/dist/components/tab-group/tab-group.js';
5
+ import '@shoelace-style/shoelace/dist/components/tab/tab.js';
6
+ import { LitElement } from "lit";
7
+ type sizes = "small" | "large";
8
+ interface MenuItem {
9
+ label: string;
10
+ clickEvent: () => void;
11
+ }
12
+ export declare class Header extends LitElement {
13
+ name: string;
14
+ /** Use a text-based title in the header. */
15
+ title: string;
16
+ /** Display a logo on the left of the header. */
17
+ logo: string | URL;
18
+ /** Add a drawer icon with a click event to e.g. open a sidebar. */
19
+ drawer: boolean;
20
+ /** Array of menu items to include as navigation tabs. */
21
+ tabs: MenuItem[];
22
+ /** Size of toolbar vertically. */
23
+ size: sizes;
24
+ private selectedTab;
25
+ static styles: import("lit").CSSResult[];
26
+ protected render(): import("lit").TemplateResult<1>;
27
+ private _selectTab;
28
+ private _handleLogin;
29
+ }
30
+ export default Header;
@@ -0,0 +1,237 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import "../../theme/sl-custom.css";
8
+ import '@shoelace-style/shoelace/dist/components/icon-button/icon-button.js';
9
+ import '@shoelace-style/shoelace/dist/components/tab-panel/tab-panel.js';
10
+ import '@shoelace-style/shoelace/dist/components/tab-group/tab-group.js';
11
+ import '@shoelace-style/shoelace/dist/components/tab/tab.js';
12
+ import { LitElement, css, html } from "lit";
13
+ import { property, state } from "lit/decorators.js";
14
+ import { cva } from "class-variance-authority";
15
+ import registerBundledIcons from '../../components/icons';
16
+ registerBundledIcons();
17
+ const headerVariants = cva(
18
+ // Defaults to include in all variants
19
+ `
20
+ flex flex-row bg-[var(--hot-white)] items-center justify-between
21
+ sm:justify-around p-2 border-b-2 border-b-gray-100 border-b-solid
22
+ `, {
23
+ variants: {
24
+ size: {
25
+ small: "h-8",
26
+ large: "h-14",
27
+ },
28
+ },
29
+ });
30
+ export class Header extends LitElement {
31
+ constructor() {
32
+ super(...arguments);
33
+ this.name = "hot-header";
34
+ /** Use a text-based title in the header. */
35
+ this.title = '';
36
+ /** Display a logo on the left of the header. */
37
+ this.logo = `
38
+ data:image/png;base64,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
104
+ `;
105
+ /** Add a drawer icon with a click event to e.g. open a sidebar. */
106
+ this.drawer = true;
107
+ /** Array of menu items to include as navigation tabs. */
108
+ this.tabs = [];
109
+ /** Size of toolbar vertically. */
110
+ this.size = "large";
111
+ this.selectedTab = 0;
112
+ }
113
+ render() {
114
+ const logoSrc = typeof this.logo === 'string' || this.logo instanceof URL ? (typeof this.logo === 'string' ? this.logo : this.logo.href) : '';
115
+ return html `
116
+ <header class=${headerVariants({ size: this.size })}>
117
+ <a href="/" class="flex flex-row">
118
+ ${(logoSrc.length > 0) ? html `
119
+ <img
120
+ id="logo"
121
+ src="${this.logo}"
122
+ alt="Logo"
123
+ class="h-10 px-10 hover:opacity-90"
124
+ >
125
+ ` : null}
126
+
127
+ ${(this.title.length > 0) ? html `
128
+ <h1 class="text-2xl color-primary font-sans font-bold pl-3 m-0">${this.title}</h1>
129
+ ` : null}
130
+ </a>
131
+
132
+ ${ /* Navigation bar for desktop, hide on mobile */''}
133
+ <nav className="hidden sm:flex justify-between items-center gap-4 font-semibold">
134
+ <sl-tab-group>
135
+ ${this.tabs.map((item, index) => html `
136
+ <sl-tab
137
+ slot="nav"
138
+ panel="general"
139
+ @click=${(e) => { this._selectTab(e, item.clickEvent, index); }}
140
+ ?selected=${this.selectedTab === index}
141
+ >${item.label}</sl-tab>
142
+ `)}
143
+ </sl-tab-group>
144
+ </nav>
145
+
146
+ ${ /* Stacked navigation drawer for mobile */''}
147
+ ${ /* NOTE this should probably be in a drawer instead */''}
148
+ <nav className="sm:hidden flex flex-col items-end gap-1 font-semibold">
149
+ </nav>
150
+
151
+ <div id="right-section" style="display: flex; align-items: center;">
152
+ <sl-icon-button
153
+ library="bundled"
154
+ name="person-circle"
155
+ style="font-size: 1.8rem;"
156
+ label="login"
157
+ @click=${(e) => { this._handleLogin(e); }}
158
+ ></sl-icon-button>
159
+
160
+ <div id="drawer-block" style="font-size: 2rem;">
161
+ ${this.drawer ? html `
162
+ <sl-icon-button library="bundled" name="list" label="drawer-open"></sl-icon-button>
163
+ ` : null}
164
+ </div>
165
+ </div>
166
+ </header>
167
+ `;
168
+ }
169
+ _selectTab(_e, clickAction, index) {
170
+ this.selectedTab = index;
171
+ clickAction();
172
+ }
173
+ _handleLogin(_e) {
174
+ this.dispatchEvent(new Event("login"));
175
+ }
176
+ }
177
+ Header.styles = [
178
+ css `@unocss-placeholder;`,
179
+ css `
180
+ #right-section {
181
+ display: flex;
182
+ align-items: center;
183
+ }
184
+
185
+ sl-tab-group {
186
+ display: flex;
187
+ }
188
+
189
+ sl-tab::part(base) {
190
+ font-size: 1rem;
191
+ border-bottom: 2px solid transparent;
192
+ }
193
+
194
+ sl-tab[selected]::part(base) {
195
+ border-bottom: 2px solid white;
196
+ }
197
+
198
+ #drawer-block {
199
+ display: flex;
200
+ align-items: center;
201
+ padding-right: 30px;
202
+ }
203
+
204
+ @media(prefers-color-scheme: light) {
205
+ header {
206
+ color: black;
207
+ }
208
+ #break {
209
+ background-color: black;
210
+ }
211
+ }
212
+ `
213
+ ];
214
+ __decorate([
215
+ property()
216
+ ], Header.prototype, "name", void 0);
217
+ __decorate([
218
+ property({ type: String })
219
+ ], Header.prototype, "title", void 0);
220
+ __decorate([
221
+ property({ type: String })
222
+ ], Header.prototype, "logo", void 0);
223
+ __decorate([
224
+ property({ type: Boolean })
225
+ ], Header.prototype, "drawer", void 0);
226
+ __decorate([
227
+ property({ type: Array })
228
+ ], Header.prototype, "tabs", void 0);
229
+ __decorate([
230
+ property({ type: String })
231
+ ], Header.prototype, "size", void 0);
232
+ __decorate([
233
+ state()
234
+ ], Header.prototype, "selectedTab", void 0);
235
+ export default Header;
236
+ // Define web component
237
+ customElements.define("hot-header", Header);
@@ -0,0 +1,237 @@
1
+ import "../../theme/sl-custom.css";
2
+
3
+ import '@shoelace-style/shoelace/dist/components/icon-button/icon-button.js';
4
+ import '@shoelace-style/shoelace/dist/components/tab-panel/tab-panel.js';
5
+ import '@shoelace-style/shoelace/dist/components/tab-group/tab-group.js';
6
+ import '@shoelace-style/shoelace/dist/components/tab/tab.js';
7
+
8
+ import { LitElement, css, html } from "lit";
9
+ import { property, state } from "lit/decorators.js";
10
+ import { cva } from "class-variance-authority";
11
+
12
+ import registerBundledIcons from '../../components/icons';
13
+
14
+ registerBundledIcons();
15
+
16
+
17
+ const headerVariants = cva(
18
+ // Defaults to include in all variants
19
+ `
20
+ flex flex-row bg-[var(--hot-white)] items-center justify-between
21
+ sm:justify-around p-2 border-b-2 border-b-gray-100 border-b-solid
22
+ `,
23
+ {
24
+ variants: {
25
+ size: {
26
+ small: "h-8",
27
+ large: "h-14",
28
+ },
29
+ },
30
+ },
31
+ );
32
+ type sizes = "small" | "large";
33
+
34
+ interface MenuItem {
35
+ label: string,
36
+ clickEvent: () => void;
37
+ }
38
+
39
+ export class Header extends LitElement {
40
+ @property() name = "hot-header";
41
+
42
+ /** Use a text-based title in the header. */
43
+ @property({ type: String }) title: string = '';
44
+
45
+ /** Display a logo on the left of the header. */
46
+ @property({ type: String }) logo: string | URL = `
47
+ data:image/png;base64,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
113
+ `;
114
+
115
+ /** Add a drawer icon with a click event to e.g. open a sidebar. */
116
+ @property({ type: Boolean }) drawer: boolean = true;
117
+
118
+ /** Array of menu items to include as navigation tabs. */
119
+ @property({ type: Array }) tabs: MenuItem[] = [];
120
+
121
+ /** Size of toolbar vertically. */
122
+ @property({ type: String }) size: sizes = "large";
123
+
124
+ @state() private selectedTab: number = 0;
125
+
126
+ static styles = [
127
+ css`@unocss-placeholder;`,
128
+ css`
129
+ #right-section {
130
+ display: flex;
131
+ align-items: center;
132
+ }
133
+
134
+ sl-tab-group {
135
+ display: flex;
136
+ }
137
+
138
+ sl-tab::part(base) {
139
+ font-size: 1rem;
140
+ border-bottom: 2px solid transparent;
141
+ }
142
+
143
+ sl-tab[selected]::part(base) {
144
+ border-bottom: 2px solid white;
145
+ }
146
+
147
+ #drawer-block {
148
+ display: flex;
149
+ align-items: center;
150
+ padding-right: 30px;
151
+ }
152
+
153
+ @media(prefers-color-scheme: light) {
154
+ header {
155
+ color: black;
156
+ }
157
+ #break {
158
+ background-color: black;
159
+ }
160
+ }
161
+ `
162
+ ];
163
+
164
+ protected render() {
165
+ const logoSrc = typeof this.logo === 'string' || this.logo instanceof URL ? (typeof this.logo === 'string' ? this.logo : this.logo.href) : '';
166
+
167
+ return html`
168
+ <header class=${headerVariants({size: this.size})}>
169
+ <a href="/" class="flex flex-row">
170
+ ${(logoSrc.length > 0) ? html`
171
+ <img
172
+ id="logo"
173
+ src="${this.logo}"
174
+ alt="Logo"
175
+ class="h-10 px-10 hover:opacity-90"
176
+ >
177
+ ` : null}
178
+
179
+ ${(this.title.length > 0) ? html`
180
+ <h1 class="text-2xl color-primary font-sans font-bold pl-3 m-0">${this.title}</h1>
181
+ ` : null}
182
+ </a>
183
+
184
+ ${ /* Navigation bar for desktop, hide on mobile */'' }
185
+ <nav className="hidden sm:flex justify-between items-center gap-4 font-semibold">
186
+ <sl-tab-group>
187
+ ${this.tabs.map(
188
+ (item, index) => html`
189
+ <sl-tab
190
+ slot="nav"
191
+ panel="general"
192
+ @click=${(e: MouseEvent) => { this._selectTab(e, item.clickEvent, index); }}
193
+ ?selected=${this.selectedTab === index}
194
+ >${item.label}</sl-tab>
195
+ `
196
+ )}
197
+ </sl-tab-group>
198
+ </nav>
199
+
200
+ ${ /* Stacked navigation drawer for mobile */'' }
201
+ ${ /* NOTE this should probably be in a drawer instead */'' }
202
+ <nav className="sm:hidden flex flex-col items-end gap-1 font-semibold">
203
+ </nav>
204
+
205
+ <div id="right-section" style="display: flex; align-items: center;">
206
+ <sl-icon-button
207
+ library="bundled"
208
+ name="person-circle"
209
+ style="font-size: 1.8rem;"
210
+ label="login"
211
+ @click=${(e: MouseEvent) => { this._handleLogin(e)}}
212
+ ></sl-icon-button>
213
+
214
+ <div id="drawer-block" style="font-size: 2rem;">
215
+ ${this.drawer ? html`
216
+ <sl-icon-button library="bundled" name="list" label="drawer-open"></sl-icon-button>
217
+ ` : null}
218
+ </div>
219
+ </div>
220
+ </header>
221
+ `;
222
+ }
223
+
224
+ private _selectTab(_e: MouseEvent, clickAction: () => void, index: number) {
225
+ this.selectedTab = index;
226
+ clickAction();
227
+ }
228
+
229
+ private _handleLogin(_e: MouseEvent) {
230
+ this.dispatchEvent(new Event("login"));
231
+ }
232
+ }
233
+
234
+ export default Header;
235
+
236
+ // Define web component
237
+ customElements.define("hot-header", Header);
@@ -57,6 +57,12 @@ const icons = {
57
57
  <path fill-rule="evenodd" d="M6 12.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-4-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/>
58
58
  </svg>
59
59
  `,
60
+ 'person-circle': `
61
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person-circle" viewBox="0 0 16 16">
62
+ <path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/>
63
+ <path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1z"/>
64
+ </svg>
65
+ `
60
66
  };
61
67
  const libraryResolver = (name) => {
62
68
  if (name in icons) {