Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Making of paint.js.org—a Web Component-based Productivity PWA

Making of paint.js.org—a Web Component-based Productivity PWA

Progressive Web Apps and the new powerful web APIs provided by Project Fugu allow developers to implement desktop-class productivity apps using web technologies. In this session, Thinktecture's Christian Liebel shows you the critical parts of how paint.js.org was made, a remake of the productivity app dinosaur Microsoft Paint. It runs great as a standalone application, and since it is based on Web Components, it can even be embedded into other applications. And since everything is web-based, it runs on all operating systems, desktop or mobile, not just Windows 95.

12c88a3a10478fa18d0363b3ba3d9df1?s=128

Christian Liebel
PRO

June 14, 2022
Tweet

More Decks by Christian Liebel

Other Decks in Programming

Transcript

  1. Making of paint.js.org A Web Component-based Productivity PWA Christian Liebel

    @christianliebel Consultant
  2. Hello, it’s me. Making of paint.js.org A Web Component-based Productivity

    PWA Christian Liebel Twitter: @christianliebel Email: christian.liebel @thinktecture.com Angular & PWA Slides: thinktecture.com /christian-liebel
  3. https://paint.js.org – Productivity app – Draw images – Lots of

    actions & tools – Installable – Read/save files – Copy/paste images from/to clipboard – Share files to other apps – Register for file extensions Making of paint.js.org A Web Component-based Productivity PWA Demo
  4. Web Components and Architecture Canvas and Input Offline Capability and

    Installability Copy and Paste File Access and File Handling Dark Mode Making of paint.js.org A Web Component-based Productivity PWA Agenda
  5. Web Components and Architecture Canvas and Input Offline Capability and

    Installability Copy and Paste File Access and File Handling Dark Mode Making of paint.js.org A Web Component-based Productivity PWA Agenda
  6. Web Components <my-component value="3"> </my-component> – The web’s native component

    model – Easy interop – Very basic: No data binding, dependency injection, … Making of paint.js.org A Web Component-based Productivity PWA Web Components and Architecture
  7. Related APIs Custom Elements API Definition of custom HTML elements

    Interaction via custom DOM attributes, properties, and events Shadow DOM Can prevent DOM access from outside Can prevent CSS manipulation from outside HTML Templates (not used in this demo) Making of paint.js.org A Web Component-based Productivity PWA Web Components and Architecture
  8. Lit – Provided by Google – Lightweight library (5 KB)

    – Custom lifecycle on top of Web Components – Tagged template literals for HTML and CSS to prevent XSS attacks including support for data binding – TypeScript decorators for component registration and attribute/property declaration Making of paint.js.org A Web Component-based Productivity PWA Web Components and Architecture
  9. Lit @customElement('paint-tool-box') export class ToolBox { render(): TemplateResult { return

    html` ${tools.map( (tool) => html`<paint-tool .tool=${tool} title="${tool.tooltip}" class="${this.drawingContext?.tool === tool ? 'active' : ''} ${tool.instance ? '' : 'unavailable'}" @pointerup="${() => this.selectTool(tool)}" ></paint-tool>`, )} `; } } Making of paint.js.org A Web Component-based Productivity PWA Web Components and Architecture
  10. Web Components Making of paint.js.org A Web Component-based Productivity PWA

    Web Components and Architecture
  11. Store Pattern Making of paint.js.org A Web Component-based Productivity PWA

    Web Components and Architecture
  12. Embedded https://node-projects.github.io/web-component-designer-demo/index.html Making of paint.js.org A Web Component-based Productivity PWA

    Web Components and Architecture
  13. Web Components and Architecture Canvas and Input Offline Capability and

    Installability Copy and Paste File Access and File Handling Dark Mode Making of paint.js.org A Web Component-based Productivity PWA Agenda
  14. Canvas – Plain bitmap for the web – Cross-platform, hardware-

    accelerated graphics operations – Supports different contexts (2D, 3D: WebGL, WebGL 2.0) – Supported on all evergreen browsers and on IE 9+ Making of paint.js.org A Web Component-based Productivity PWA Canvas and Input
  15. Canvas 2D Context fillRect(x, y, width, height) strokeRect(x, y, width,

    height) beginPath() moveTo(x, y) lineTo(x, y) fill() stroke() Making of paint.js.org A Web Component-based Productivity PWA Canvas and Input
  16. Pointer Events Making of paint.js.org A Web Component-based Productivity PWA

    Canvas and Input Users nowadays use different input methods, cross-platform apps should cover all of them Pointer Events offer an abstract interface to catch all input methods (pointerdown, pointermove, pointerup) event.offsetX/event.offsetY contain the pointer’s position relative to the listener
  17. Web Components and Architecture Canvas and Input Offline Capability and

    Installability Copy and Paste File Access and File Handling Dark Mode Making of paint.js.org A Web Component-based Productivity PWA Agenda
  18. A Web Component-based Productivity PWA Making of paint.js.org Responsive Linkable

    Discoverable Installable App-like Connectivity Independent Fresh Safe Re-engageable Progressive
  19. Making of paint.js.org A Web Component-based Productivity PWA Web App

    Manifest Service Worker
  20. Web App Manifest Distinguishes Web Apps from Websites JSON-based file

    containing metadata for apps only Apps can be identified by search engines, app store providers, etc. Making of paint.js.org A Web Component-based Productivity PWA Offline Capability and Installability
  21. manifest.webmanifest { "short_name": "Paint", "name": "Paint Workshop", "theme_color": "white", "icons":

    [{ "src": "icon.png", "sizes": "512x512" }], "start_url": "/index.html", "display": "standalone", "shortcuts": [/* … */] } Making of paint.js.org A Web Component-based Productivity PWA Offline Capability and Installability Names Icons Display Mode Shortcuts Start URL Theme color (status bar/window bar)
  22. Service Worker JavaScript snippet executed in an own thread, registered

    by the website Acts as a controller, proxy, or interceptor Has a cache to store responses (for offline availability and performance) Can wake up even when the website is closed and perform background tasks (e.g., push notifications or sync) Making of paint.js.org A Web Component-based Productivity PWA Offline Capability and Installability
  23. Service Worker Making of paint.js.org A Web Component-based Productivity PWA

    Offline Capability and Installability Service Worker Internet Website HTML/JS Cache fetch
  24. Web Components and Architecture Canvas and Input Offline Capability and

    Installability Copy and Paste File Access and File Handling Dark Mode Making of paint.js.org A Web Component-based Productivity PWA Agenda
  25. Making of paint.js.org A Web Component-based Productivity PWA

  26. Project Fugu Making of paint.js.org A Web Component-based Productivity PWA

    Capabilities »Let’s bring the web back – API by API« Thomas Steiner, Google
  27. Making of paint.js.org A Web Component-based Productivity PWA Capabilities https://goo.gle/fugu-api-tracker

  28. Browser Making of paint.js.org A Web Component-based Productivity PWA Capabilities

    navigator.share({ url: 'http://example.com' }); ShareIntent DataTransferManager … NSSharingServicePicker
  29. Async Clipboard API Allows reading from/writing to the clipboard in

    an asynchronous manner (UI won’t freeze during long-running operations) Reading from the clipboard requires user consent first (privacy!) Supported by Chrome, Edge and Safari Making of paint.js.org A Web Component-based Productivity PWA Copy and Paste
  30. Async Clipboard API const btnCopy = document.querySelector('#copy'); btnCopy.addEventListener('click', async ()

    => { const blob = await toBlob(canvas); await navigator.clipboard.write([ new ClipboardItem({[blob.type]: blob}) ]); }); Making of paint.js.org A Web Component-based Productivity PWA Copy and Paste
  31. Async Clipboard API const btnPaste = document.querySelector('#paste'); btnPaste.addEventListener('click', async ()

    => { const clipboardItems = await navigator.clipboard.read(); for (const clipboardItem of clipboardItems) { for (const type of clipboardItem.types) { if (type === 'image/png') { const blob = await clipboardItem.getType(type); const image = await getImage(blob); ctx.drawImage(image, 0, 0); } } } }); Making of paint.js.org A Web Component-based Productivity PWA Copy and Paste
  32. Web Components and Architecture Canvas and Input Offline Capability and

    Installability Copy and Paste File Access and File Handling Dark Mode Making of paint.js.org A Web Component-based Productivity PWA Agenda
  33. File System Access API Some applications heavily rely on working

    with files (e.g. Visual Studio Code, Adobe Photoshop, …) File System Access API allows you to open, save and override files and directories Supported by Chrome, Edge Making of paint.js.org A Web Component-based Productivity PWA File Access and File Handling
  34. File System Access API btnSave.addEventListener('click', async () => { const

    blob = await toBlob(canvas); const handle = await window.showSaveFilePicker(fileOptions); const writable = await handle.createWritable(); await writable.write(blob); await writable.close(); }); Making of paint.js.org A Web Component-based Productivity PWA File Access and File Handling
  35. File System Access API btnOpen.addEventListener('click', async () => { const

    [handle] = await window.showOpenFilePicker(fileOptions); const file = await handle.getFile(); const image = await getImage(file); ctx.drawImage(image, 0, 0); }); Making of paint.js.org A Web Component-based Productivity PWA File Access and File Handling
  36. File Handling API Register your PWA as a handler for

    file extensions Requires installing the application first Declare supported extensions in Web App Manifest and add imperative code to your application logic Making of paint.js.org A Web Component-based Productivity PWA File Access and File Handling
  37. File Handling API "file_handlers": [{ "action": "/index.html", "accept": { "image/png":

    [".png"] } }] Making of paint.js.org A Web Component-based Productivity PWA File Access and File Handling
  38. File Handling API if ('launchQueue' in window) { launchQueue.setConsumer(async params

    => { const [handle] = params.files; if (handle) { const file = await handle.getFile(); const image = await getImage(file); ctx.drawImage(image, 0, 0); } }); } Making of paint.js.org A Web Component-based Productivity PWA File Access and File Handling
  39. Web Components and Architecture Canvas and Input Offline Capability and

    Installability Copy and Paste File Access and File Handling Dark Mode Making of paint.js.org A Web Component-based Productivity PWA Agenda
  40. CSS Custom Properties – Also known as “CSS variables” –

    Cascade even through Shadow DOM boundaries, i.e. they can be accessed by subordinate components – Paint.js.org defines the Windows 95 color scheme on app root level :host { --button-face: rgb(192 192 192); --button-light: white; --button-dark: rgb(128 128 128); --button-darker: black; --button-text: black; } Making of paint.js.org A Web Component-based Productivity PWA Dark Mode
  41. prefers-color-scheme CSS Media Feature – The prefers-color-scheme CSS media feature

    indicates which color scheme the user prefers – Takes two values: – light, if the user prefers a dark-on-light color scheme (or didn’t actively make a decision) – dark, if the user prefers a light-on-dark color scheme – Preference is usually inherited form the operating system’s settings – Changes are automatically reflected (e.g., when the operating system switches between light and dark mode based on time) Making of paint.js.org A Web Component-based Productivity PWA Dark Mode
  42. CSS-Only Light Mode :host { --button-face: rgb(192 192 192); --button-light:

    white; --button-dark: rgb(128 128 128); --button-darker: black; --button-text: black; } Dark Mode @media (prefers-color-scheme: dark) { :host { --button-face: rgb(64 64 64); --button-light: rgb(128 128 128); --button-dark: rgb(32 32 32); --button-text: white; } } Making of paint.js.org A Web Component-based Productivity PWA Dark Mode
  43. Making of paint.js.org A Web Component-based Productivity PWA Dark Mode

  44. Web Components: Very robust, works consistently across evergreen browsers, perfect

    for integration scenarios. Lit: Shares basic concepts with other frameworks/libraries (such as Angular), but is much more lightweight. Paint.js.org is smaller (= transferred bytes) than the Windows 95 of Paint (320K)! Capabilities: Powerful APIs available on Chromium and WebKit-based browsers, fallbacks are used for other browsers. Conclusion: Successful project! 🥳 You can perfectly implement web- based (= cross-platform), desktop-class productivity applications. Making of paint.js.org A Web Component-based Productivity PWA Summary
  45. Making of paint.js.org A Web Component-based Productivity PWA Outlook

  46. Thank you for your kind attention! Christian Liebel @christianliebel christian.liebel@thinktecture.com