Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ You can also use [import maps](https://developer.mozilla.org/en-US/docs/Web/HTML
</html>
```

PS: If you're using the `<solid-ui-provider>` component to wrap your application, make sure to register it first. Otherwise, you may face errors or unexpected behaviour regarding global state.

## Development

When developing a component in solid-ui you can test it in isolation using Storybook:
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "solid-ui",
"version": "3.1.3-11",
"version": "3.1.3-12",
"description": "UI library for Solid applications",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts",
Expand Down
5 changes: 3 additions & 2 deletions src/components/account/Account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import styles from './Account.styles.css'
export interface AccountMenuItem {
label: string | TemplateResult
href?: string
selected?: boolean
onSelected?(): void
}

Expand Down Expand Up @@ -78,14 +79,14 @@ export default class Account extends WebComponent {
}

return html`
<solid-ui-menu placement="bottom-end" distance="5">
<solid-ui-menu placement="bottom-end">
<button type="button" slot="trigger">
<solid-ui-avatar></solid-ui-avatar>
<icon-lucide-chevron-down slot="right-icon"></icon-lucide-chevron-down>
</button>

${this.menuItems.map(menuItem => html`
<solid-ui-menu-item .href=${menuItem.href ?? nothing} @solid-ui-select=${() => menuItem.onSelected?.()}>
<solid-ui-menu-item .href=${menuItem.href ?? nothing} ?selected=${menuItem.selected} @solid-ui-select=${() => menuItem.onSelected?.()}>
${menuItem.label}
</solid-ui-menu-item>
`)}
Expand Down
1 change: 1 addition & 0 deletions src/components/all.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import.meta.glob(['./*/index.ts', '!./provider/index.ts'], { eager: true })
19 changes: 19 additions & 0 deletions src/components/avatar/Avatar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@ export default class Avatar extends WebComponent {
@consume({ context: authContext, subscribe: true })
private accessor auth: AuthContext = DEFAULT_AUTH_CONTEXT

private unsubscribeSessionUpdated?: () => void

connectedCallback () {
super.connectedCallback()

this.auth.loadProfile?.()

this.unsubscribeSessionUpdated = this.auth.onSessionUpdated(() => {
this.auth.loadProfile?.()
this.requestUpdate()
})
}

disconnectedCallback () {
super.disconnectedCallback()

this.unsubscribeSessionUpdated?.()
}

protected render () {
if (!this.auth.account?.avatarUrl) {
return html`
Expand Down
2 changes: 1 addition & 1 deletion src/components/button/Button.styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,5 @@
--background-color: transparent;
--hover-text-color: currentColor;
--hover-border-color: transparent;
--hover-background-color: color-mix(in srgb, currentColor 25%, transparent);
--hover-background-color: var(--solid-ui-color-primary-hover);
}
10 changes: 8 additions & 2 deletions src/components/combobox/Combobox.styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
border-radius: 5px;
box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.35);
overflow: hidden;
padding: 4px;
}

.input-wrapper {
Expand Down Expand Up @@ -50,21 +51,26 @@
.listbox {
display: flex;
flex-direction: column;
gap: 2px;
max-height: inherit;
overflow: auto;

[role="option"], .non-selectable-option {
color: var(--solid-ui-color-gray-700);
padding: 12px 8px;
border-radius: 5px;
}

[role="option"] {
border-bottom: 1px solid var(--solid-ui-color-gray-100);
cursor: pointer;

&:hover,
&[data-active] {
background: rgba(0, 0, 0, 0.05);
background: var(--solid-ui-color-primary-hover);
}

&[aria-selected="true"] {
background: var(--solid-ui-color-primary-selected);
}
}

Expand Down
4 changes: 1 addition & 3 deletions src/components/combobox/Combobox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,7 @@ export default class Combobox extends WebComponent {
? html`<div
id=${this.getOptionId(index)}
role="option"
aria-selected=${this.open && index === this.activeIndex
? 'true'
: 'false'}
aria-selected=${option.value === this.value ? 'true' : 'false'}
data-active=${index === this.activeIndex || nothing}
@mousemove=${() => this.setActiveIndex(index)}
>
Expand Down
4 changes: 2 additions & 2 deletions src/components/guard/Guard.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ const meta = {
} as const

const render = defineAuthStoryRender<typeof meta.argTypes>(() => html`
<solid-guard>
<solid-ui-guard>
<span slot="initializing">Initializing content</span>
<span slot="guest">Guest content</span>
<span>Logged in content</span>
</solid-guard>
</solid-ui-guard>
`)

export const Primary = { render }
Expand Down
7 changes: 6 additions & 1 deletion src/components/guard/Guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ import { consume } from '@lit/context'
import { html } from 'lit'
import { authContext, AuthContext, DEFAULT_AUTH_CONTEXT } from '@/lib/auth'

@customElement('solid-guard')
@customElement('solid-ui-guard')
export default class Guard extends WebComponent {
static states = {
initializing: (component: Guard) => !component.auth.initialized,
loggedIn: (component: Guard) => !!component.auth.account,
}

@consume({ context: authContext, subscribe: true })
private accessor auth: AuthContext = DEFAULT_AUTH_CONTEXT

Expand Down
5 changes: 4 additions & 1 deletion src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
import.meta.glob('./*/index.ts', { eager: true })
// Make sure that <solid-ui-provider> is registered first, so that contexts
// are available to nested components when they mount.
import './provider'
import './all'
6 changes: 3 additions & 3 deletions src/components/menu-item/MenuItem.styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
color: var(--solid-ui-color-gray-600);
font-weight: 500;
font-size: var(--solid-ui-font-size-md);
}

&:hover {
background-color: var(--solid-ui-color-slate-200);
&[data-selected] {
background: var(--solid-ui-color-primary-selected);
}
}

::slotted([slot="left-icon"]), ::slotted([slot="right-icon"]) {
Expand Down
7 changes: 5 additions & 2 deletions src/components/menu-item/MenuItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ export default class MenuItem extends WebComponent {
@property({ type: String, reflect: true })
accessor href: string | undefined

@property({ type: Boolean, reflect: true })
accessor selected: boolean = false

@query('a')
private accessor anchor: HTMLAnchorElement | null = null

render () {
if (this.href) {
return html`
<a href="${this.href}" target="_blank" rel="noopener noreferrer">
<a href="${this.href}" target="_blank" rel="noopener noreferrer" ?data-selected=${this.selected}>
<slot name="left-icon"></slot>
<slot></slot>
<slot name="right-icon"></slot>
Expand All @@ -26,7 +29,7 @@ export default class MenuItem extends WebComponent {
}

return html`
<div>
<div ?data-selected=${this.selected}>
<slot name="left-icon"></slot>
<slot></slot>
<slot name="right-icon"></slot>
Expand Down
20 changes: 18 additions & 2 deletions src/components/menu/Menu.stories.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { html } from 'lit'
import { defineStoryRender } from '@/storybook'
import type Menu from '@/components/menu/Menu'
import type MenuItem from '@/components/menu-item/MenuItem'

import '@/components/button'
import '@/components/menu-item'
Expand All @@ -10,14 +12,28 @@ const meta = {
title: 'Menu',
} as const

function select (event: Event, message: string) {
const selectedItem = event.target as MenuItem
const menu = selectedItem.parentElement as Menu
const items = menu.querySelectorAll<MenuItem>('solid-ui-menu-item')

for (const item of items) {
item.selected = false
}

selectedItem.selected = true

alert(message)
}

const render = defineStoryRender(() => html`
<solid-ui-menu>
<solid-ui-button slot="trigger" style="display:inline-block">
Open Menu
</solid-ui-button>

<solid-ui-menu-item @solid-ui-select=${() => alert('Selected One!')}>One</solid-ui-menu-item>
<solid-ui-menu-item @solid-ui-select=${() => alert('Selected Two!')}>Two</solid-ui-menu-item>
<solid-ui-menu-item @solid-ui-select=${(event: Event) => select(event, 'Selected One!')}>One</solid-ui-menu-item>
<solid-ui-menu-item @solid-ui-select=${(event: Event) => select(event, 'Selected Two!')}>Two</solid-ui-menu-item>
<solid-ui-menu-item href="https://solidproject.org">External Link</solid-ui-menu-item>
</solid-ui-menu>
`)
Expand Down
6 changes: 6 additions & 0 deletions src/components/menu/Menu.styles.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
wa-dropdown::part(menu) {
min-width: 300px;
box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.35);
gap: 2px;
}

wa-dropdown-item {
border-radius: 5px;
padding: 0px;

&:hover {
background-color: var(--solid-ui-color-primary-hover);
}
}
2 changes: 1 addition & 1 deletion src/components/menu/Menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default class Menu extends WebComponent {
accessor placement: WaDropdown['placement'] = 'bottom-start';

@property({ type: Number, reflect: true })
accessor distance: number = 0;
accessor distance: number = 5;

@query('wa-dropdown')
private accessor dropdown: WaDropdown | null = null;
Expand Down
13 changes: 13 additions & 0 deletions src/lib/auth/SolidAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ function findAccountImage (webId: string): string | undefined {

export default class SolidAuth implements AuthContext {
private _initialized = false
private profileLoaded = false
private listeners: (() => unknown)[] = []

constructor (public signupUrl: string = DEFAULT_SIGNUP_URL) {}
Expand All @@ -36,6 +37,18 @@ export default class SolidAuth implements AuthContext {
this.listeners.forEach(listener => listener())
}

async loadProfile () {
if (this.profileLoaded || !this.account) {
return
}

this.profileLoaded = true

await solidLogicSingleton.profile.loadMe()

this.listeners.forEach(listener => listener())
}

get initialized (): boolean {
return this._initialized
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/auth/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface AuthContext {
initialized: boolean;
account: Account | null;
login(loginUrl?: string): Promise<void>;
loadProfile?(): Promise<void>;
signup(): Promise<void>;
logout(): Promise<void>;
onSessionUpdated(callback: () => unknown): () => void;
Expand Down
7 changes: 6 additions & 1 deletion src/styles/theme.css
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
@import "@awesome.me/webawesome/dist/styles/webawesome.css";
@import "@awesome.me/webawesome/dist/styles/themes/default.css";
@import url('https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:wght@400;700&display=swap');

:root {
font-family: "Atkinson Hyperlegible Next", "Inter", "Noto Sans", sans-serif;
--font-family-ui: "Atkinson Hyperlegible Next", "Inter", "Noto Sans", sans-serif;
--wa-font-family-body: "Atkinson Hyperlegible Next", "Inter", "Noto Sans", sans-serif;
--solid-ui-color-primary: #7c4dff;
--solid-ui-color-primary-hover: var(--solid-ui-color-lavender-300);
--solid-ui-color-primary-selected: var(--solid-ui-color-lavender-400);
--solid-ui-color-tertiary: #083575;
--solid-ui-color-white: #ffffff;
--solid-ui-color-error: #b00020;
Expand All @@ -23,6 +25,9 @@
--solid-ui-color-slate-400: #90a1b9;
--solid-ui-color-slate-800: #1d293d;

--solid-ui-color-lavender-300: #e6dcff;
--solid-ui-color-lavender-400: #cbb9ff;

--solid-ui-color-red-500: #fb2c36;

--solid-ui-color-body-grey: #666;
Expand Down
Loading