npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

code-bubble

v1.0.0

Published

Reusable components for displaying code examples and providing links to a sandbox environment.

Downloads

282

Readme

Code Bubble

This is a platform agnostic web component designed to showcase code examples and generate sandbox environments in CodePen or StackBlitz.

code bubble example

code bubble example with source code open

Features:

  • ✅ Global configuration
  • ✅ Create multiple instances of the bubble with unique configurations
  • ✅ Code preview
  • ✅ Supports examples from multiple languages
  • ✅ Language code toggle
  • ✅ RTL toggle
  • ✅ Open in Sandbox (currently supports CodePen and StackBlitz)
  • ✅ Copy code button
  • ✅ Framework example selection sync across instances
  • ✅ Persist selected language
  • ✅ Custom labels
  • ✅ Custom icons
  • ✅ Event hooks
  • ✅ Preview resize

Open in StackBlitz

Usage

Import the desired sandbox configuration at the root of your project:

import { CodeBubble, CodeBubbleConfig } from 'code-bubble';

const options: CodeBubbleConfig {
  /* configuration options */
};

new CodeBubble(options);

Use the Components

Once the project is configured, that's it! Start using the components.

If you are using it markdown, be sure to include new lines between the markdown code block.

<code-bubble>

```html
<my-button appearance="accent">Accent</my-button>
``` 

```jsx
<MyButton appearance="accent">Accent</MyButton>
```

</code-bubble>

If you are using it HTML, the component will be looking for <pre> element with a nested <code> element.

Unfortunately, markdown parsers don't follow a consistent pattern for identifying the language for a code block so the componet will look for class="language-html" or data-language="html" on the parent, pre, or code elements to help identify which code block it is (for react it would be class="language-jsx"/data-language="jsx").

The <code> element should contain escaped characters for the tags to properly render the examples.

<code-bubble>
  <pre>
    <code class="language-html">
&lt;my-button appearance=&quot;accent&quot;&gt;Accent&lt;/my-button&gt;
    </code>
  </pre>

  <pre>
    <code class="language-jsx">
&lt;MyButton appearance=&quot;accent&quot;&gt;Accent&lt;/MyButton&gt;
    </code>
  </pre>
</code-bubble>

Configuration

The components are pre-configured and should work without any custom configuration, but if you would like to customize the implementation, each sandbox has it's own options.

/** Global configuration for a code bubble instance */
type CodeBubbleConfig = {
  /** Which sandbox environment your code will open in */
  sandbox?: 'codepen' | 'stackblitz';
  /** Configuration for the component rendered on the site */
  component?: ComponentConfig;
  /** Configurations for the sandboxes */
  sandboxConfig?: {
    /** CodePen sandbox configuration */
    codePen?: FrameworkConfig<CodePen>;
    /** StackBlitz sandbox configuration */
    stackBlitz?: FrameworkConfig<StackBlitz>;
  };
  /** Callback functions for the code bubble component */
  hooks?: {
    /** Callback function that runs when the code is copied */
    onCopy?: () => void;
    /** Callback function when the RTL button is toggled */
    onRtl?: (isRtl: boolean) => void;
    /** Callback function that runs when a sandbox is opened */
    onSandboxOpen?: (config: ProjectConfig<CodePen | StackBlitz>) => void;
    /** Callback function that runs when the code is shown */
    onShowCode?: (isShowCode: boolean) => void;
    /** Callback function that runs when a language is selected */
    onLanguageChange?: (language: string) => void;
  };
};

Component Configuration

The component configuration is the same for each of the sandbox environments. These globally control the component behavior.

/** Configuration for the component rendered on the site */
type ComponentConfig = {
  /** Code bubble component tag name - must contain a dash, start with a letter and be lower-case */
  tagName?: string;
  /** Opens the "show code" section by default */
  showCode?: boolean;
  /** Indicates which example to show by default */
  defaultExample?: string;
  /** Configuration for the code preview */
  preview?: {
    /** Hides the preview window where the code is rendered */
    hide?: boolean;
  };
  /** Configuration for the copy code button */
  copyCodeButton?: {
    /** Text displayed in the "copy code" button */
    label?: string;
    /** Text displayed in the "copy code" button when the code has been copied */
    copiedLabel?: string;
    /** Hides the "copy code" button */
    hide?: boolean;
    /** Icon displayed in the "copy code" button - SVG string */
    icon?: string;
    /** Visually hides the label text */
    hideLabel?: boolean;
  };
  /** Configuration for the RTL button */
  rtlButton?: {
    /** Text displayed in the "RTL" button */
    label?: string;
    /** Hides the "RTL" button */
    hide?: boolean;
    /** Icon displayed in the "RTL" button - SVG string */
    icon?: string;
    /** Visually hides the label text */
    hideLabel?: boolean;
  };
  /** Configuration for the sandbox button */
  sandboxButton?: {
    /** Text displayed in the "sandbox" button */
    label?: string;
    /** Hides the "sandbox" button */
    hide?: boolean;
    /** Icon displayed in the "sandbox" button - SVG string */
    icon?: string;
    /** Visually hides the label text */
    hideLabel?: boolean;
  };
  /** Configuration for the resize button */
  resizeButton?: {
    /** Text displayed in the "sandbox" button */
    label?: string;
    /** Hides the "sandbox" button */
    hide?: boolean;
    /** Icon displayed in the "sandbox" button - SVG string */
    icon?: string;
  };
  /** Configuration for the framework toggle buttons */
  frameworkButtons?: {
    /** Hides the HTML and React code toggle buttons */
    hide?: boolean;
    /** Text displayed in the framework buttons  */
    label?: (framework: string) => string;
    /** Icon displayed in the framework buttons - SVG string */
    icon?: (framework: string) => string;
    /** Visually hides the label text */
    hideLabel?: boolean;
  };
  /** Configuration for the "show code" toggle button */
  showCodeButton?: {
    /** Text displayed when example code is opened  */
    openedLabel?: string;
    /** Text displayed when example code is closed  */
    closedLabel?: string;
    /** Icon displayed in the button when closed - SVG string */
    openedIcon?: string;
    /** Icon displayed in the button when opened - SVG string */
    closedIcon?: string;
    /** Hides the "show code" button */
    hide?: boolean;
    /** Visually hides the label text */
    hideLabel?: boolean;
  };
};

Defining Framework Labels

When specifying a code block, developers can specify a framework label.


```html
```

```jsx
```

```ruby
```

These labels will be used by default for the framework toggle buttons at the bottom of the code bubble. These may not be as useful as you would like them to be for your users (or you may need to provide translations), so you can map new labels for them.

new CodeBlock({
  component: {
    frameworkButtonLabel: (framework) => ({
      html: 'HTML',
      jsx: 'React',
      ruby: 'Ruby'
    }[framework] || framework),
  },
});

Sandbox Configuration

Each sandbox supports any framework variation.

type FrameworkConfig<T extends CodePen | StackBlitz> = {
  /** CodePen project configuration for language examples */
  [key: string]: ProjectConfig<T>;
};

type ProjectConfig<T extends CodePen | StackBlitz> = {
  /** Sandbox API configuration */
  project?: T;
  /** Controls how the code is rendered in the example */
  exampleTemplate: ExampleTemplateConfig;
};

export type ExampleTemplateConfig = {
  /** Indicates which code block has the template */
  // eslint-disable-next-line @typescript-eslint/ban-types
  fileName: 'html' | 'css' | 'js' | (string & {});
  /** Template function that returns the code block with the example in it */
  template: string;
};

CodePen

type CodePen = {
  /** Pen title */
  title?: string;
  /** Pen description */
  description?: string;
  /** When the Pen is saved, it will save as Private if logged in user has that privledge, otherwise it will save as public */
  private?: boolean;
  /** If supplied, the Pen will save as a fork of this id. Note it's not the slug, but ID. You can find the ID of a Pen with `window.CP.pen.id` in the browser console. */
  parent?: string;
  /** Words to help identify and categorize the sandbox */
  tags?: string[];
  /** Set which editors are open. "1" is open and "0" is collapsed. The order is "HTML", "CSS", and "JS" */
  editors?: '001' | '010' | '100' | '011' | '101' | '110' | '111';
  /** Determines the position of the code */
  layout?: 'top' | 'left' | 'right';
  /** Content in the HTML panel */
  html?: string;
  /** Specifies an alternative markup syntax  */
  html_pre_processor?: 'none' | 'slim' | 'haml' | 'markdown';
  /** Content in the HTML panel */
  css?: string;
  /** Specifies an alternative style syntax */
  css_pre_processor?: 'none' | 'less' | 'scss' | 'sass' | 'stylus';
  /** Adds a CSS reset or normalizer to your pen */
  css_starter?: 'normalize' | 'reset' | 'neither';
  /** Adds vendor prefixes to your CSS */
  css_prefix?: 'autoprefixer' | 'prefixfree' | 'neither';
  /** Content in the HTML panel */
  js?: string;
  /** Specifies an alternative script syntax */
  js_pre_processor?:
    | 'none'
    | 'coffeescript'
    | 'babel'
    | 'livescript'
    | 'typescript';
  /** Class names applied to the `<html>` element */
  html_classes?: string;
  /** Content for the `<head>` tag */
  head?: string;
  /** Semi-colon separate list of CDN urls to include in the pen */
  css_external?: string;
  /** Semi-colon separate list of CDN urls to include in the pen */
  js_external?: string;
};

StackBlitz

type StackBlitz = {
  title?: string;
  description?: string;
  /**
   * Provide project files, as code strings.
   *
   * Binary files and blobs are not supported.
   */
  files?: {
    [name: string]: string;
  };
};

Customizing the Code Example

Each of the project configurations has an exampleTemplate property that allows you configure how your example gets rendered. The fileName indicates which file or code block them template is in and template shows an example of how your example code should be rendered in the template file.

const config: FrameworkConfig<StackBlitz> = {
  html: {
    exampleTemplate: {
      fileName: 'index.html',
      template: `<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
  </head>
  <body>
    <div id="app">
      %example%
    </div>
    <script type="module" src="/main.js"></script>
  </body>
</html>`,
    },
  },
};

Creating Different Code Bubble Types

You may need to be able to create code bubbles with different configurations. To do that, you create a new instance of the CodeBubble with a custom tag name.

new CodeBubble({
  /* <code-bubble> - default code bubble config */
});

new CodeBubble({
  /* <ts-bubble> - code bubble config for TypeScript examples */
  component: {
    tagName: 'ts-bubble'
  }
});

You will now have an alternative custom element for your TypeScript examples.

<code-bubble>

```html
```

```jsx
```

</code-bubble>
<ts-bubble>

```ts
```

```js
```

</ts-bubble>

Globally Setting Framework

If you need to globally set the set the selected framework, the CodeBubble instance has a setLanguage(lang: string) method that can be used to globally set the components associated to that instance's selected framework.

const bubble = new CodeBubble({
  /* code bubble config */
});

bubble.setLanguage('ruby');

Setting Custom Preview

The preview will be generated based on the HTML example provided. If the preview needs to be rendered by a framework or templating language, you can slot in a preview and allow the code to be executed so it can be rendered correctly.

<code-bubble>

<div slot="preview">
  <MyButton>Button Content</MyButton>
</div>

```vue
<MyButton>Button Content</MyButton>
```

</code-bubble>

Hooks

These hooks are designed to allow you to tap into component interactions to create custom behaviors within your application.

{
  /** Callback function that runs when the code is copied */
  onCopy?: () => void;
  /** Callback function when the RTL button is toggled */
  onRtl?: (isRtl: boolean) => void;
  /** Callback function that runs when a sandbox is opened */
  onSandboxOpen?: (config: ProjectConfig<CodePen | StackBlitz>) => void;
  /** Callback function that runs when the code section is toggled */
  onShowCode?: (isShowCode: boolean) => void;
  /** Callback function that runs when a language is selected */
  onLanguageChange: (language: string) => void;
}

onCopy

This is called when the "copy code" button is clicked within the example.

onRtl

This is called when the "RTL" button is toggled, after the isRtl value is updated.

onSandboxOpen

This will be called before the standbox is opened and the config parameter gives you access to the sandbox configuration so you can update any values to capture any real-time contextual information like the selected theme or light/dark mode settings.

onShowCode

This is called when the example code window is toggled after the isShowCode value is updated.

onLanguageChange

This is called when the language example is changed and the language value has been updated.

Component-level Overrides

Code bubble is managed using a global configuration, but there may be times where specific instances need to behave differently. The following attributes can be added to the component to modify the behavior.

| Attribute | Description | | --------- | ----------- | | hide-preview | Hides the preview display | | hide-copy-code | Hides the copy code button | | hide-rtl | Hides the RTL button | | hide-sandbox | Hides the sandbox button | | hide-resize | Hides the resize button | | hide-frameworks | Hides the framework buttons | | hide-show-code | Hides the show code button | | open-show-code | Opens the show code button |

<code-bubble 
  hide-preview 
  hide-copy-code 
  hide-rtl 
  hide-sandbox
  hide-resize
  hide-frameworks
  hide-show-code
  open-show-code
  >
</code-bubble>

Styling

The following CSS custom properties and parts are available to customize the appearance of the component.

CSS Custom Properties

| CSS Property | Description | | --------------------------------------------- | ---------------------------------------------------------------------- | | --code-bubble-border-color | The border color of the component and the controls | | --code-bubble-border-radius | The border radius of the component and the controls | | --code-bubble-border-width | The border width of the component and the controls | | --code-bubble-preview-padding | The padding of the rendered code example | | --code-bubble-snippet-padding | The padding for the example code | | --code-bubble-button-font-weight | The font weight for the controls | | --code-bubble-button-icon-gap | The gap between the button text and icon | | --code-bubble-button-padding-x | The horizontal padding for the controls at the bottom of the component | | --code-bubble-button-padding-y | The vertical padding for the controls at the bottom of the component | | --code-bubble-copy-button-font-weight | The font weight for the copy code button | | --code-bubble-copy-button-padding-x | The horizontal padding for the copy button | | --code-bubble-copy-button-padding-y | The vertical padding for the copy button | | --code-bubble-outline | The outline style when elements have keyboard focus | | --code-bubble-outline-offset | The offset of the outline when an element has keyboard focus | | --code-bubble-button-bg-color | The background color of the bottom controls | | --code-bubble-button-border-color | The border color of the bottom controls | | --code-bubble-button-fg-color | The text color of the bottom controls | | --code-bubble-copy-button-bg-color | The background color of the copy code button | | --code-bubble-copy-button-border-color | The border color of the copy code button | | --code-bubble-copy-button-fg-color | The text color of the copy code button | | --code-bubble-button-hover-bg-color | The background color of the bottom controls on hover | | --code-bubble-button-hover-border-color | The border color of the bottom controls on hover | | --code-bubble-button-hover-fg-color | The text color of the bottom controls on hover | | --code-bubble-copy-button-hover-bg-color | The background color of the copy code button on hover | | --code-bubble-copy-button-hover-border-color | The border color of the copy code button on hover | | --code-bubble-copy-button-hover-fg-color | The text color of the copy code button on hover | | --code-bubble-button-focus-bg-color | The background color of the bottom controls on focus | | --code-bubble-button-focus-border-color | The border color of the bottom controls on hover | | --code-bubble-button-focus-fg-color | The text color of the bottom controls on hover | | --code-bubble-copy-button-focus-bg-color | The background color of the copy code button on focus | | --code-bubble-copy-button-focus-border-color | The border color of the copy code button on focus | | --code-bubble-copy-button-focus-fg-color | The text color of the copy code button on focus | | --code-bubble-button-active-bg-color | The background color of the bottom controls on active | | --code-bubble-button-active-border-color | The border color of the bottom controls on active | | --code-bubble-button-active-fg-color | The text color of the bottom controls on active | | --code-bubble-button-active-font-weight | The font weight of the bottom controls on active | | --code-bubble-copy-button-active-bg-color | The background color of the copy code button on active | | --code-bubble-copy-button-active-border-color | The border color of the copy code button on active | | --code-bubble-copy-button-active-fg-color | The text color of the copy code button on active |

CSS Parts

| CSS Part | Description | | ----------------------- | ------------------------------------------------------------------ | | code-bubble-base | The base wrapper for the internal component | | code-bubble-preview | The element that wraps the rendered example | | code-bubble-code | The element that wraps the source code section | | code-bubble-copy-button | The button used to copy code to the clipboard | | code-bubble-controls | The element that wraps the controls at the bottom of the component | | code-bubble-control | The buttons at the bottom of the component | | code-bubble-show-source | The "show source" button | | code-bubble-framework | The framework toggle buttons | | code-bubble-rtl | The "RTL" button |