Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add(widgets) fullscreen widget #8024

Merged
merged 48 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
fc6be2c
add(deck) _widget prop
chrisgervang Jul 25, 2023
cd67293
add(widgets) fullscreen widget scaffold
chrisgervang Jul 25, 2023
18835f1
Update modules/widgets/src/fullscreen-widget.ts
chrisgervang Jul 27, 2023
2fa64ad
Update modules/widgets/src/fullscreen-widget.ts
chrisgervang Jul 27, 2023
fceab53
add(deck) _widget prop
chrisgervang Jul 25, 2023
bfa10b6
declarative widgets api
Pessimistress Aug 3, 2023
adfc21a
Add comments
Pessimistress Aug 4, 2023
46be41a
fix test
Pessimistress Aug 4, 2023
f37b35e
simplify widget api
Pessimistress Aug 4, 2023
024d1bc
docs
chrisgervang Aug 8, 2023
3caa7e8
Merge branch 'master' into chr/deck-widgets-prop
chrisgervang Aug 8, 2023
e07fd97
Merge branch 'chr/deck-widgets-prop' into chr/fullscreen-widget
chrisgervang Aug 8, 2023
debbf1e
add(core) export types
chrisgervang Aug 8, 2023
f43cfdd
Merge branch 'chr/deck-widgets-prop' into chr/fullscreen-widget
chrisgervang Aug 8, 2023
ed185ff
add(examples) widgets example
chrisgervang Aug 15, 2023
f135eca
add(widgets) build with preact jsx
chrisgervang Aug 16, 2023
a5cd7b4
add(widget) fullscreen button + styles
chrisgervang Aug 16, 2023
efd612e
add(widget) fullscreen optional container
chrisgervang Aug 16, 2023
2f31eca
add(widget) theming with CSS variables
chrisgervang Aug 17, 2023
004c0aa
Merge branch 'master' into chr/fullscreen-widget
chrisgervang Aug 17, 2023
e02624b
add(widget) applications set theme
chrisgervang Aug 17, 2023
a87c7f9
comments
chrisgervang Aug 21, 2023
ee7a365
spell out widget
chrisgervang Aug 21, 2023
bda7bcd
add(widget) built-in themes
chrisgervang Aug 21, 2023
f9cc7ab
add(widget) add className prop
chrisgervang Aug 22, 2023
8df067a
add(widget) fullscreen and theme docs
chrisgervang Aug 22, 2023
a7aabfe
cleanup
chrisgervang Aug 22, 2023
24ce65d
style and className support modifications
chrisgervang Sep 9, 2023
4791fb8
icons, icon variables, onfullscreen handler, pseudo-fullscreen
chrisgervang Sep 9, 2023
a6f6268
docs and style examples
chrisgervang Sep 9, 2023
24bf325
comments
chrisgervang Sep 9, 2023
73afafd
Merge branch 'master' into chr/fullscreen-widget
chrisgervang Sep 9, 2023
61d2f55
types
chrisgervang Sep 9, 2023
bca3b89
luma core
chrisgervang Sep 12, 2023
17b6c13
lints
chrisgervang Sep 12, 2023
eebc3ad
Merge branch 'master' into chr/fullscreen-widget
chrisgervang Sep 14, 2023
993d850
drop gl
chrisgervang Sep 15, 2023
ed1906d
Implement icons in CSS as replaceable masks
chrisgervang Sep 17, 2023
814762f
lint
chrisgervang Sep 23, 2023
9d0ecc0
Merge branch 'master' into chr/fullscreen-widget
chrisgervang Sep 23, 2023
5f70324
docs
chrisgervang Sep 23, 2023
cb72e2c
Merge branch 'chr/fullscreen-widget' of https://github.com/visgl/deck…
chrisgervang Sep 23, 2023
59b1a56
use getCanvas
chrisgervang Sep 23, 2023
03dda1e
icon docs
chrisgervang Sep 23, 2023
254b319
docs
chrisgervang Sep 23, 2023
01d5c39
standard mask-image
chrisgervang Sep 23, 2023
e30fc53
Merge branch 'master' into chr/fullscreen-widget
chrisgervang Sep 25, 2023
c641626
remove viewId, add stateful labels
chrisgervang Sep 25, 2023
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
7 changes: 7 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ module.exports = getESLintConfig({
'import/named': 0,
'no-new': 0
}
},
{
files: ['modules/widgets/**/*.tsx'],
rules: {
// For widgets module. Disable React-style JSX linting since they conflict with Preact JSX.
'react/react-in-jsx-scope': 0
chrisgervang marked this conversation as resolved.
Show resolved Hide resolved
}
}
],

Expand Down
8 changes: 8 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ module.exports = getBabelConfig({
patterns: ['**/*.glsl.js', '**/*.glsl.ts']
}
]
],
overrides: [
chrisgervang marked this conversation as resolved.
Show resolved Hide resolved
{
include: './modules/widgets/**/*.{ts,tsx}',
// Parse preact-style JSX in @deck.gl/widgets.
presets: [['@babel/typescript', {jsxPragma: 'h'}]],
plugins: [['@babel/plugin-transform-react-jsx', {pragma: 'h'}]]
}
]
}
});
45 changes: 45 additions & 0 deletions docs/api-reference/widgets/fullscreen-widget.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# FullscreenWidget

## Props

### `id` (String)

Default: `'fullscreen'`

Unique identifier of the widget.

### `placement` (String, optional)

Default: `'top-left'`

Widget position within the view relatitive to the map container. Valid options are `top-left`, `top-right`, `bottom-left`, `bottom-right`, or `fill`.

### `container` (HTMLElement, optional)

Default: `undefined`

A [compatible DOM element](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullScreen#Compatible_elements) which should be made full screen. By default, the map container element will be made full screen.

### `enterLabel` (String, optional)

Toolip message displayed while hovering a mouse over the widget when out of fullscreen.

Default: `'Enter Fullscreen'`

### `exitLabel` (String, optional)

Toolip message displayed while hovering a mouse over the widget when fullscreen.

Default: `'Exit Fullscreen'`

### `style` (Object, optional)

Default: `{}`

Additional CSS styles for the canvas.

### `className` (String, optional)

Default: `undefined`

Class name to attach to the widget element. The element has the default class name of `deck-widget deck-fullscreen-widget`.
103 changes: 102 additions & 1 deletion docs/api-reference/widgets/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,119 @@ npm install @deck.gl/core @deck.gl/widgets

```js
import {FullscreenWidget} from '@deck.gl/widgets';
import '@deck.gl/widgets/stylesheet.css';

new FullscreenWidget({});
```

### Include the Standalone Bundle

```html
<script src="https://unpkg.com/deck.gl@^8.10.0/dist.min.js"></script>
<link src="https://unpkg.com/deck.gl@^8.10.0/widgets/stylesheet.css" rel='stylesheet' />
<!-- or -->
<script src="https://unpkg.com/@deck.gl/core@^8.10.0/dist.min.js"></script>
<script src="https://unpkg.com/@deck.gl/widgets@^8.10.0/dist.min.js"></script>
<link src="https://unpkg.com/deck.gl@^8.10.0/widgets/stylesheet.css" rel='stylesheet' />
```

```js
new deck.FullscreenWidget({});
```
```

## CSS Theming

Customizing the appearance of widgets can be achieved using CSS variables. This section provides guidance on how to theme widgets at different levels of specificity.

### Global Theming

Apply to all wigdets with the `.deck-widget` selector.

```css
.deck-widget {
--button-size: 48px;
}
```

> Note: While variables can be globally applied using the `:root` selector, ensuring their availability throughout the entire document, this method is not recommended. Applying variables globally can lead to naming conflicts, especially in larger projects or when integrating with other libraries.

### Type-specific Theming

Theme a specific type of widget using the `.deck-widget-[type]` selector.

```css
.deck-widget-fullscreen {
--button-size: 48px;
}
```

### Instance-specific Theming

Apply styles to a single instance of a widget using inline styles.

```js
new FullscreenWidget({ style: {'--button-size': '48px'}})
```

### Custom Class Theming

Define a custom class with your desired styles and apply it to a widget.

```css
.my-class {
--button-size: 48px;
}
```
```js
new FullscreenWidget({ className: 'my-class'})
```

## Customizable CSS Variables

We've provided a set of CSS variables to make styling UI Widgets more convenient. These variables allow for customization of widget sizes, colors, and other properties. Below is a comprehensive list of these variables, their expected types, and default values:

### Size

| Name | Type | Default |
| ---- | ---- | ------- |
| `--button-size` | [Dimension](https://developer.mozilla.org/en-US/docs/Web/CSS/dimension) | `28px` |
| `--button-border-radius` | [Dimension](https://developer.mozilla.org/en-US/docs/Web/CSS/dimension) | `12px` |
| `--widget-margin` | [Dimension](https://developer.mozilla.org/en-US/docs/Web/CSS/dimension) | `12px` |

### Color

| Name | Type | Default |
| ---- | ---- | ------- |
| `--button-background` | [Color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) | `#fff` |
| `--button-stroke` | [Color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) | `rgba(255, 255, 255, 0.3)` |
| `--button-inner-stroke` | [Border](https://developer.mozilla.org/en-US/docs/Web/CSS/border) | `unset` |
| `--button-shadow` | [Box Shadow](https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow) | `0px 0px 8px 0px rgba(0, 0, 0, 0.25)` |
| `--button-backdrop-filter` | [Backdrop Filter](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter) | `unset` |
| `--button-icon-idle` | [Color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) | `rgba(97, 97, 102, 1)`
| `--button-icon-hover` | [Color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) | `rgba(24, 24, 26, 1)`

### Icon
| Name | Type | Default |
| ---- | ---- | ------- |
| `--icon-fullscreen-enter` | [SVG Data Url](https://developer.mozilla.org/en-US/docs/Web/CSS/url#using_a_data_url) | [Material Symbol Fullscreen](https://fonts.google.com/icons?selected=Material+Symbols+Rounded:fullscreen:FILL@0;wght@400;GRAD@0;opsz@40) |
| `--icon-fullscreen-enter` | [SVG Data Url](https://developer.mozilla.org/en-US/docs/Web/CSS/url#using_a_data_url) | [Material Symbol Fullscreen Exit](https://fonts.google.com/icons?selected=Material+Symbols+Rounded:fullscreen_exit:FILL@0;wght@400;GRAD@0;opsz@40) |

#### Replacing Icons

Users can to customize icons to better align with their design preferences or branding. This section provides a step-by-step guide on how to replace and customize these icons.

1. Prepare Your Icons:
- Ensure your icons are available as [SVG Data Url](https://developer.mozilla.org/en-US/docs/Web/CSS/url#using_a_data_url). These will be used for a CSS [mask-image](https://developer.mozilla.org/en-US/docs/Web/CSS/mask-image).
2. Icon Replacement:
- Use CSS variables, such as `--icon-fullscreen-enter`, to replace the default icons with your customized ones.
3. Color Customization:
- The original color embedded in your SVG will be disregarded. However, it's crucial that the SVG isn't transparent.
- Customize the color of your icon using the appropriate CSS variable, such as `--button-icon-idle`.

Example:
```css
.deck-widget {
--icon-fullscreen-enter: url('path_to_your_svg_icon.svg');
--button-icon-idle: blue;
}
```
17 changes: 17 additions & 0 deletions examples/get-started/pure-js/widgets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## Example: Use deck.gl with widgets

Uses [Vite](https://vitejs.dev/) to bundle and serve files.

## Usage

To install dependencies:

```bash
npm install
# or
yarn
```

Commands:
* `npm start` is the development target, to serve the app and hot reload.
* `npm run build` is the production target, to create the final bundle and write to disk.
75 changes: 75 additions & 0 deletions examples/get-started/pure-js/widgets/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {Deck} from '@deck.gl/core';
import {GeoJsonLayer, ArcLayer} from '@deck.gl/layers';
import {FullscreenWidget, DarkGlassTheme, LightGlassTheme} from '@deck.gl/widgets';
import '@deck.gl/widgets/stylesheet.css';
import {luma} from '@luma.gl/core';
import {WebGLDevice} from '@luma.gl/webgl';

luma.registerDevices([WebGLDevice]);

const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
const widgetTheme = prefersDarkScheme.matches ? DarkGlassTheme : LightGlassTheme

// source: Natural Earth http://www.naturalearthdata.com/ via geojson.xyz
const COUNTRIES =
'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_admin_0_scale_rank.geojson'; //eslint-disable-line
const AIR_PORTS =
'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_airports.geojson';

const INITIAL_VIEW_STATE = {
latitude: 51.47,
longitude: 0.45,
zoom: 4,
bearing: 0,
pitch: 30
};

new Deck({
initialViewState: INITIAL_VIEW_STATE,
controller: true,
layers: [
new GeoJsonLayer({
id: 'base-map',
data: COUNTRIES,
// Styles
stroked: true,
filled: true,
lineWidthMinPixels: 2,
opacity: 0.4,
getLineColor: [60, 60, 60],
getFillColor: [200, 200, 200]
}),
new GeoJsonLayer({
id: 'airports',
data: AIR_PORTS,
// Styles
filled: true,
pointRadiusMinPixels: 2,
pointRadiusScale: 2000,
getPointRadius: f => 11 - f.properties.scalerank,
getFillColor: [200, 0, 80, 180],
// Interactive props
pickable: true,
autoHighlight: true,
onClick: info =>
// eslint-disable-next-line
info.object && alert(`${info.object.properties.name} (${info.object.properties.abbrev})`)
}),
new ArcLayer({
id: 'arcs',
data: AIR_PORTS,
dataTransform: d => d.features.filter(f => f.properties.scalerank < 4),
// Styles
getSourcePosition: f => [-0.4531566, 51.4709959], // London
getTargetPosition: f => f.geometry.coordinates,
getSourceColor: [0, 128, 200],
getTargetColor: [200, 0, 80],
getWidth: 1
})
],
widgets: [
new FullscreenWidget({}),
new FullscreenWidget({id: 'themed', style: widgetTheme}),
new FullscreenWidget({id: 'purple', className: 'purple'})
Comment on lines +71 to +73
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Pessimistress I was thinking of move these variations to a test app. I want to maintain coverage for edge cases somewhere, and keep getting started very simple. Thoughts?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes agreed

]
});
27 changes: 27 additions & 0 deletions examples/get-started/pure-js/widgets/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>deck.gl Example</title>
<style>
body {margin: 0; width: 100vw; height: 100vh; overflow: hidden;}

@media screen and (max-width: 600px) {
.deck-widget {
/* mobile */
--button-size: 48px;
--button-corner-radius: 12px;
}
}

.purple {
--button-background: hsl(240, 40%, 40%);
--button-stroke: hsla(240, 40%, 40%, 0.3);
--button-icon-hover: rgb(236, 236, 236);
--button-icon-idle: rgb(174, 174, 202);
}
</style>
</head>
<body></body>
<script type="module" src="app.js"></script>
</html>
21 changes: 21 additions & 0 deletions examples/get-started/pure-js/widgets/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "deckgl-example-pure-js-basic",
"version": "0.0.0",
"private": true,
"license": "MIT",
"scripts": {
"start": "vite --open",
"start-local": "vite --config ../../../vite.config.local.mjs",
"build": "vite build"
},
"dependencies": {
"@deck.gl/core": "^8.8.0",
"@deck.gl/layers": "^8.8.0",
"@deck.gl/widgets": "8.10.0-alpha.2",
"@luma.gl/core": "^8.6.0-alpha.1",
"@luma.gl/webgl": "^8.5.20"
},
"devDependencies": {
"vite": "^4.0.0"
}
}
3 changes: 2 additions & 1 deletion modules/widgets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"prepublishOnly": "npm run build-bundle && npm run build-bundle -- --env=dev"
},
"dependencies": {
"@babel/runtime": "^7.0.0"
"@babel/runtime": "^7.0.0",
"preact": "^10.17.0"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, I haven't really being paying attention. Are we using a react style library for our pure-js implementation? And then we will have react wrappers on top?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty certain we don't want the complexity or bundle size of react, but I like its api style.

My goal has been to pick something as close to the DOM as we can while also providing some convenience over document.createElement. preact seems to serve this niche well... It give us the ability to make basic components with JSX, and implements a thin virtual dom only adding 3kb to the bundle.

Re: react wrappers, I think of a widget as a deck component that happens to have UI. In a sense, how the UI is built within it is ideally isolated from other UI on the page so that deck can manage it. Let's say we used react to make UI widgets in @deckgl/widgets... I'd still ideally want them to create their own react root separate from the rest of application and other widgets. This way all integrations work through the same interface.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood and I agree with the principle that widgets should be free to choose implementation as long as they are externally independent. That said, I would not be happy to see a pure-js deck.gl module have react as a dependency in its package.json. I would think twice before using that in a pure-js app.

For a community widget that could be a different story of course.

preact seems like a reasonable choice.

},
"peerDependencies": {
"@deck.gl/core": "^8.0.0"
Expand Down
17 changes: 17 additions & 0 deletions modules/widgets/src/components.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {h, render} from 'preact';

export const IconButton = props => {
const {className, label, onClick} = props;
return (
<div className="deck-widget-button-border">
<button
className={`deck-widget-button ${className}`}
type="button"
onClick={onClick}
title={label}
>
<div className="deck-widget-icon" />
</button>
</div>
);
};
Loading
Loading