vscode-webview-ui-toolkit icon indicating copy to clipboard operation
vscode-webview-ui-toolkit copied to clipboard

React button not showing icon

Open StephaneAdeso opened this issue 1 year ago • 13 comments

I am developing an extension for vscode with React and using the WebUi Toolkit library for components. I want to add a "save" icon to my button.

I have followed the documentation to add my button in react and add an icon. So the resulting code is:

import { VSCodeButton } from '@vscode/webview-ui-toolkit/react';    

<VSCodeButton >
    Save
    <span slot="start" className="codicon codicon-save"></span>
</VSCodeButton>

But the icon is not showing. How to add the icon to the button?

image

StephaneAdeso avatar Sep 29 '23 18:09 StephaneAdeso

Hey @StephaneAdeso! Out of curiosity what does your content security policy look like in your extension? This looks like a case where the icon is being blocked from rendering.

As an example, your CSP should probably look something like this: https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/frameworks/component-gallery-react/src/panels/ComponentGalleryPanel.ts#L122

In particular, the font-src CSP rule should allow the codicons.ttf (required to render Codicons) file to be rendered.

hawkticehurst avatar Oct 06 '23 22:10 hawkticehurst

Thank you very much for answering. After several days without finding a solution, I finally decided to use an icon library. I must also say that you are right. I did not have any content security policy established. As soon as I have some time I'll try it. Thank you so much.

StephaneAdeso avatar Oct 07 '23 16:10 StephaneAdeso

Of course! Please let me know how it goes so I can know if this issue is resolved and I can close it :)

hawkticehurst avatar Oct 09 '23 20:10 hawkticehurst

Sorry, i was unable to find a correct CSP configuration that works. All variations i tried throw errors so i removed it.

StephaneAdeso avatar Oct 18 '23 17:10 StephaneAdeso

Hmm okay, in that case, could you create/provide a link to a GitHub repo with a small reproduction of the issue so I can see if I can figure out what the problem might be?

hawkticehurst avatar Oct 19 '23 23:10 hawkticehurst

I'm using vue with the web components and I have the same issue.

My CSP is the following:

      <meta
        http-equiv="Content-Security-Policy"
        content="
          default-src 'none';
          object-src 'none';
          base-uri 'none';
          style-src ${allowedSource} 'unsafe-inline';
          img-src ${allowedSource} https: data:;
          script-src 'strict-dynamic' 'nonce-${nonce}' 'unsafe-inline' https:;
        "
      >

But I don't think it's a CSP issue because I get no CSP-related issues logged in the webview's dev tools' console and even if I delete the whole CSP I still have the icons not showing.

Repro steps

  1. $ git clone [email protected]:cytechmobile/radicle-vscode-extension.git
  2. $ git checkout 4ee3787d591a1612242b43b663bd7167fbee9fad (or browse source code)
  3. F5 (no need to install node modules)
  4. Ctrl + Shift + P (to open Cmd Palette) and select command "Open dat webview"

you should be seeing this

https://github.com/microsoft/vscode-webview-ui-toolkit/assets/7542054/146d0118-aea1-4536-8773-6426f38f5d1f

The related code can be found under src/webviews/src/components/Counter.vue and looks like this

    <vscode-button appearance="icon" @click="showInfoNotifWithCount">
      <span class="codicon codicon-megaphone"></span>
    </vscode-button>

maninak avatar Dec 13 '23 05:12 maninak

You are missing the font-src directive, so default-src 'none' is taking precedence.

r3m0t avatar Dec 13 '23 20:12 r3m0t

@r3m0t if you could share a diff so that I can better understand where I'm missing it that would help a lot, thank you!

I Ctrl + F for "font-src" in the docs and don't find anything.

That's what's shown in the docs image

maninak avatar Dec 13 '23 23:12 maninak

Hey @maninak! Yes, as @r3m0t said this looks like a case of not including the font-src CSP directive (thank you for chiming in @r3m0t btw 😊).

You would add the font-src CSP to the content attribute in the meta tag you wrote out above. Something like this:

<meta 
  http-equiv="Content-Security-Policy" 
  content="
    default-src 'none'; 
    script-src 'nonce-${nonce}';
    style-src ${webview.cspSource}; 
    font-src ${webview.cspSource};   // <-- here!
">

The above example is specifically pulled from our component-gallery sample extension. Feel free to look there for more context.

Also, the content security policy docs live in Webview API VS Code documentation since CSP is a topic that applies to webview extension development in general, not just in the Webview UI Toolkit.

Hope that helps, but please let me know if there are any other questions you have!

hawkticehurst avatar Dec 13 '23 23:12 hawkticehurst

Thank you both for the quick respons and especially @hawkticehurst for the detailed hints.

I've changed my CSP to be


      <meta
        http-equiv="Content-Security-Policy"
        content="
          default-src 'none';
          object-src 'none';
          base-uri 'none';
          style-src ${allowedSource} 'unsafe-inline';
          img-src ${allowedSource} https: data:;
          script-src 'strict-dynamic' 'nonce-${nonce}' 'unsafe-inline' https:;
          font-src ${allowedSource};
        "
      >

The above seemed to have no effect. Noteworthy is that the chromium devtools report no CSP warnings or errors! Neither did they before nor do they now after adding the font-src directive.

maninak avatar Dec 14 '23 02:12 maninak

What does the Network tab show after filtering for Font?

Is the codicon.css stylesheet referenced in your project?

r3m0t avatar Dec 14 '23 07:12 r3m0t

Hey @r3m0t, after reading your comment I didn't know to which codicon.css you were referring to. There's no mention of it on the Readme nor the Getting Started Guide.

After checking the link @hawkticehurst shared above I found that in that sample there's an explicit import for codicon.css which also imports codicon.ttf and both are local in the repo.

I copy-pasted those into my vue repo's assets/ folder. The vue repo is nested in my vscode extension which meant that the actual path is src/webviews/src/assets/codicon.css. Then I imported the css like so inside my App.vue.

<style>
@import './assets/codicon.css';
</style>

In codicon.css the font is loaded like so

 @font-face {
  font-family: "codicon";
  font-display: block;
  src: url("./codicon.ttf") format("truetype");
}

Here's is also a screencap of the filetree showing that those files coexist and colocate inside the dist dir that vite produces

See image

This has definitely moved me closer but now I'm seeing this in the console and the network tab image image

In my webview options I have localResourceRoots set with what seems to be a correct path to the location of the above assets:

  const webviewOptions: WebviewOptions = {
    enableScripts: true,
    localResourceRoots: [
      Uri.joinPath(getExtensionContext().extensionUri, 'dist'),
      Uri.joinPath(getExtensionContext().extensionUri, 'assets'),
      Uri.joinPath(getExtensionContext().extensionUri, 'src', 'webviews', 'dist'),
    ],
  }

It looks like it's a problem with how the ttf file's path resolves and honestly I have no clue how to fix it.

For reference, the index.css file gets loaded correctly and its path seems to be different (I guess vite patches behind the scenes) image

Shouldn't this very important info about copying and importing those files be in the readme/guide? Better yet, why isn't this an implementation detail handled by the UI lib itself and I have to copy and import those manually? Perhaps I am doing it wrong?

Thank you so much for your assistance! :pray:

maninak avatar Dec 15 '23 08:12 maninak

OK, so after copying the css and ttf file under assets/ and importing it in my App.vue what was left was setting base: '' in the vue app's vite.config.ts which, for the sake of completion, now looks like this:

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
      'lib': fileURLToPath(new URL('../../lib', import.meta.url)),
      'utils': fileURLToPath(new URL('../utils', import.meta.url)),
    }
  },
  build: {
    rollupOptions: {
      external: ['vscode'],
      // produce predictable filenames without cache-busting SHA suffix
      output: {
        entryFileNames: `assets/[name].js`,
        chunkFileNames: `assets/[name].js`,
        assetFileNames: `assets/[name].[ext]`,
      },
    },
  },
  base: '', // <-- this fixed the problem with the resolved path to codicons.ttf :man_shrugging: 
})

Of course, this is more specific to my use case, but I'd argue that it is tangential to the scope of this issue, since I wouldn't have to deal with all of this if the UI library would make sure to import its necessary assets by itself and if the necessity for the font-src CSP directive was documented.

maninak avatar Dec 15 '23 10:12 maninak