Skip to content
Merged
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: 1 addition & 1 deletion .github/workflows/visual-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
jobs:
visual-test:
runs-on: ubuntu-latest
timeout-minutes: 20
timeout-minutes: 40
steps:
- name: Checkout 🛎️
uses: actions/checkout@v2
Expand Down
80 changes: 59 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,91 @@
# UI Toolkit for Jupyter

**WIP this is very early work in progress and nothing is yet working.** But don't hesitate to open issues and PRs if you want to help.
**WIP this is early work in progress.** But don't hesitate to open issues and PRs if you want to
help.

![Extension status](https://img.shields.io/badge/status-draft-critical 'Not yet working')
[![Extension status](https://img.shields.io/badge/status-draft-critical 'Not yet working')](https://jupyterlab-contrib.github.io/)
[![NPM Version](https://img.shields.io/npm/v/@jupyter-notebook/web-components?color=blue)](https://www.npmjs.com/package/@jupyter-notebook/web-components)
[![Toolkit CI Status](https://github.com/jupyterlab-contrib/jupyter-ui-toolkit/actions/workflows/ci.yml/badge.svg)](https://github.com/jupyterlab-contrib/jupyter-ui-toolkit/actions/workflows/ci.yml)
![Deploy Docs Status](https://github.com/jupyterlab-contrib/jupyter-ui-toolkit/actions/workflows/docs-cd.yml/badge.svg)
[![Deploy Docs Status](https://github.com/jupyterlab-contrib/jupyter-ui-toolkit/actions/workflows/docs-cd.yml/badge.svg)](https://jupyterlab-contrib.github.io/jupyter-ui-toolkit/)
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jupyterlab-contrib/jupyter-ui-toolkit/main)

![Toolkit for Jupyter Artwork](./packages/components/docs/assets/toolkit-artwork.png)
![Toolkit for Jupyter Artwork](https://raw.githubusercontent.com/jupyterlab-contrib/jupyter-ui-toolkit/main/packages/components/docs/assets/toolkit-artwork.png)

## Introduction

The UI Toolkit is a component library for building web interfaces in Jupyter ecosystem (JupyterHub, Jupyter Widgets, JupyterLab,...).
The UI Toolkit is a component library for building web interfaces in Jupyter ecosystem (JupyterHub,
Jupyter Widgets, JupyterLab,...).

Features of the library include:

- **Implements the Jupyter design language:** All components follow the design language of Jupyter – enabling developers to create extensions that have a consistent look and feel with the rest of the ecosystem.
- **Automatic support for color themes:** All components are designed with theming in mind and will automatically display the current application theme.
- **Use any tech stack:** The library ships as a set of web components, meaning developers can use the toolkit no matter what tech stack (React, Vue, Svelte, etc.) their extension is built with.
- **Accessible out of the box:** All components ship with web standard compliant ARIA labels and keyboard navigation.

Note this project started as a fork of the [WebView toolkit for Visual Studio Code](https://github.com/microsoft/vscode-webview-ui-toolkit) (licensed under MIT) on which Jupyter design specification. The fundamental technology used is [Fast Design](https://www.fast.design/).
- **Implements the Jupyter design language:** All components follow the design language of Jupyter
– enabling developers to create extensions that have a consistent look and feel with the rest of
the ecosystem.
- **Automatic support for color themes:** All components are designed with theming in mind and will
automatically display the current application theme.
- **Use any tech stack:** The library ships as a set of web components, meaning developers can use
the toolkit no matter what tech stack (React, Vue, Svelte, etc.) their extension is built with.
- **Accessible out of the box:** All components ship with web standard compliant ARIA labels and
keyboard navigation.

This repository contains three packages:

- [`@jupyter-notebook/web-components`](https://github.com/jupyterlab-contrib/jupyter-ui-toolkit/tree/main/packages/components/):
The main package defining the web components.
- [`@jupyter-notebook/react-components`](https://github.com/jupyterlab-contrib/jupyter-ui-toolkit/tree/main/packages/react-components):
Wrapped the web components to use them with [React](https://reactjs.org).
- [`jupyter-ui-demo`](https://github.com/jupyterlab-contrib/jupyter-ui-toolkit/tree/main/packages/lab-example):
Unpublished JupyterLab extension to demonstrate the integration of the toolkit.

Those features are brought through the [Fast Design](https://www.fast.design/). And it is inspired
by the [WebView toolkit for Visual Studio Code](https://github.com/microsoft/vscode-webview-ui-toolkit)
as example for creating a customized toolkit.

## Release

The UI Toolkit is currently in a proof of concept. Track progress towards 1.0 [here](https://github.com/jupyterlab-contrib/jupyter-ui-toolkit/issues?q=is%3Aopen+is%3Aissue+milestone%3Av1.0). Styles and API
are not guarantee between minor versions prior to v1.0.0.
The UI Toolkit is currently in a proof of concept. Track progress towards 1.0 [here](https://github.com/jupyterlab-contrib/jupyter-ui-toolkit/issues?q=is%3Aopen+is%3Aissue+milestone%3Av1.0).
Styles and API are not guarantee between minor versions prior to v1.0.0.

## Getting started

<!--
Follow the [Getting Started Guide](./docs/getting-started.md).
You will need to install `yarn` (for example with `npm install --global yarn`).

To build the components packages, execute:

```sh
yarn install
yarn build
```

If you already have a webview-based extension, you can install the toolkit with the following command:
Then to interactively test or develop web components:

```sh
cd packages/components
yarn start
```
npm install --save @vscode/webview-ui-toolkit

### JupyterLab demo extension

To test locally the JupyterLab demo extension, using `conda` package manager:

```sh
conda create -n jupyter-toolkit -c conda-forge -y nodejs yarn jupyterlab=3
conda activate jupyter-toolkit
yarn install
yarn build
pip install -e .
jupyter labextension develop --overwrite .
```
-->

## Documentation

Further documentation can be found in the following places:

- [Component Docs](./packages/components/docs/components.md)
- [Component Docs](https://github.com/jupyterlab-contrib/jupyter-ui-toolkit/tree/main/packages/components/docs/components.md)
- [Storybook (Interactive Component Sandbox)](https://jupyterlab-contrib.github.io/jupyter-ui-toolkit/)
- [Toolkit Extension Samples](./packages/lab-example)
- [Toolkit Extension Samples](https://github.com/jupyterlab-contrib/jupyter-ui-toolkit/tree/main/packages/lab-example):
[Try online](https://mybinder.org/v2/gh/jupyterlab-contrib/jupyter-ui-toolkit/main)

## Contributing

See the [contributing](./CONTRIBUTING.md) documentation.
See the [contributing](https://github.com/jupyterlab-contrib/jupyter-ui-toolkit/tree/main/CONTRIBUTING.md) documentation.
6 changes: 3 additions & 3 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
"sideEffects": false,
"scripts": {
"start": "start-storybook -p 6006",
"start:ci": "start-storybook -p 6006 --ci",
"start:ci": "start-storybook -p 6006 --ci --quiet",
"build": "rollup -c && tsc -p ./tsconfig.json",
"build:docs": "build-storybook",
"deploy:docs": "yarn run build:docs && gh-pages -d storybook-static",
"doc": "api-extractor run --local",
"prettier:check": "prettier --config ./.prettierrc --check \"**/*.{ts,js,md}\"",
"prettier": "prettier --config ./.prettierrc --write \"**/*.{ts,js,md}\"",
"prettier:check": "prettier --config ../../.prettierrc --check \"src/**/*.ts\"",
"prettier": "prettier --config ../../.prettierrc --write \"src/**/*.ts\"",
"eslint:check": "eslint . --ext .ts",
"eslint": "eslint . --ext .ts --fix",
"prepublishOnly": "yarn run build",
Expand Down
2 changes: 1 addition & 1 deletion packages/components/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const config: PlaywrightTestConfig = {
trace: 'on-first-retry',
launchOptions: {
// Force slow motion to let storybook the time to update styles
slowMo: 30
slowMo: 40
}
},
projects: [
Expand Down
75 changes: 75 additions & 0 deletions packages/components/src/avatar/avatar.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import { setTheme } from '../utilities/storybook';

export default {
title: 'Avatar',
argTypes: {
shape: { control: 'select', options: ['circle', 'square', 'default'] },
fill: {
control: 'select',
options: ['accent-primary', 'accent-secondary']
},
color: { control: 'select', options: ['foo', 'bar'] },
image: { control: 'boolean' }
},
parameters: {
actions: {
disabled: true
}
},
decorators: [
story => `<style>
jp-avatar {
--avatar-fill-accent-primary: #cf4073;
--avatar-fill-accent-secondary: #0078d4;
--avatar-color-foo: hsl(0, 0%, 100%);
--avatar-color-bar: grey;
--avatar-text-ratio: 3;
}
</style>
${story()}`
]
};

const Template = (
args,
{ globals: { backgrounds, accent }, parameters }
): string => {
setTheme(accent, parameters.backgrounds, backgrounds);

return `<jp-avatar
alt="John's avatar"
link="#"
shape="${args.shape}"
fill="${args.fill}"
color="${args.color}"
>
${
args.image
? '<img class="image" slot="media" src="https://via.placeholder.com/32" />'
: 'JS'
}
</jp-avatar>`;
};

export const Default = Template.bind({});
Default.args = {
shape: 'circle',
fill: 'accent-primary',
color: 'foo',
image: false
};

export const Square = Template.bind({});
Square.args = {
...Default.args,
shape: 'square'
};

export const WithImage = Template.bind({});
WithImage.args = {
...Default.args,
image: true
};
30 changes: 30 additions & 0 deletions packages/components/src/avatar/avatar.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import { test, expect } from '@playwright/test';

test.describe('Avatar', () => {
test('Default', async ({ page }) => {
await page.goto('/iframe.html?id=avatar--default');

expect(await page.locator('jp-avatar').screenshot()).toMatchSnapshot(
'avatar-default.png'
);
});

test('Square', async ({ page }) => {
await page.goto('/iframe.html?id=avatar--square');

expect(await page.locator('jp-avatar').screenshot()).toMatchSnapshot(
'avatar-square.png'
);
});

test('With Image', async ({ page }) => {
await page.goto('/iframe.html?id=avatar--with-image');

expect(await page.locator('jp-avatar').screenshot()).toMatchSnapshot(
'avatar-with-image.png'
);
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 56 additions & 0 deletions packages/components/src/avatar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) Jupyter Development Team.
// Copyright (c) Microsoft Corporation.
// Distributed under the terms of the Modified BSD License.

import {
accentFillRest,
Avatar,
avatarStyles as styles,
foregroundOnAccentRest,
imgTemplate
} from '@microsoft/fast-components';
import { css, ElementStyles } from '@microsoft/fast-element';
import {
Avatar as FoundationAvatar,
AvatarOptions,
avatarTemplate as template,
FoundationElementTemplate
} from '@microsoft/fast-foundation';

export { Avatar } from '@microsoft/fast-components';

export const avatarStyles: FoundationElementTemplate<
ElementStyles,
AvatarOptions
> = (context, definition: AvatarOptions) => css`
${styles(context, definition)}

.backplate {
min-width: var(--avatar-size, var(--avatar-size-default));
background-color: ${accentFillRest};
}

.link {
color: ${foregroundOnAccentRest};
}
`;

/**
* A function that returns a {@link @microsoft/fast-foundation#Avatar} registration for configuring the component with a DesignSystem.
* {@link @microsoft/fast-foundation#avatarTemplate}
*
*
* @public
* @remarks
* Generates HTML Element: `<jp-avatar>`
*/
export const jpAvatar = Avatar.compose<AvatarOptions>({
baseName: 'avatar',
baseClass: FoundationAvatar,
template,
styles: avatarStyles,
media: imgTemplate,
shadowOptions: {
delegatesFocus: true
}
});
53 changes: 53 additions & 0 deletions packages/components/src/breadcrumb-item/breadcrumb-item.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import { getFaIcon, setTheme } from '../utilities/storybook';

export default {
title: 'Breadcrumb Item',
argTypes: {
href: { control: 'boolean' },
startIcon: { control: 'boolean' },
endIcon: { control: 'boolean' }
}
};

const Template = (
args,
{ globals: { backgrounds, accent }, parameters }
): string => {
setTheme(accent, parameters.backgrounds, backgrounds);

return `<jp-breadcrumb-item
${args.href ? 'href="#"' : ''}
>
${args.startIcon ? getFaIcon('folder', 'start') : ''}
Breadcrumb item
${args.endIcon ? getFaIcon('robot', 'end') : ''}
</jp-breadcrumb-item>`;
};

export const Default = Template.bind({});
Default.args = {
href: true,
startIcon: false,
endIcon: false
};

export const WithoutHref = Template.bind({});
WithoutHref.args = {
...Default.args,
href: false
};

export const WithStartIcon = Template.bind({});
WithStartIcon.args = {
...Default.args,
startIcon: true
};

export const WithEndIcon = Template.bind({});
WithEndIcon.args = {
...Default.args,
endIcon: true
};
Loading