Skip to content
This repository has been archived by the owner on Dec 16, 2021. It is now read-only.

Commit

Permalink
feat(*): expose clipboardJsError event & fix for latest StencilJS and…
Browse files Browse the repository at this point in the history
… PrismJS

You can now listen for errors from ClipboardJS by providing the clipboardJsError event. The library
has also been overall fixed for the latest StencilJS as it was currently calling the wrong events
internally.
  • Loading branch information
favna committed Jan 26, 2021
1 parent 2eef205 commit 3c8cf80
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 263 deletions.
8 changes: 8 additions & 0 deletions packages/core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ declare namespace LocalJSX {
* @default html
*/
"language"?: string;
/**
* The callback that will be fired when ClipboardJS fails to copy the text
* @remark You can use this to, for example, show notifications to users
* @remark This event will bubble up through the DOM
* @default undefined
* @example ```html <body> <syntax-highlighter id="example-highlight" theme="dark" language="typescript" content="console.log('example')" /> <script> const syntaxHighlighterElement = document.querySelector('#example-highlight'); syntaxHighlighterElement.addEventListener('clipboardJsError', event => { console.log('handling'); }); </script> </body> ```
*/
"onClipboardJsError"?: (event: CustomEvent<ClipboardJS.Event>) => void;
/**
* The theme to use, one of light or dark
* @default dark
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/components/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
| `theme` | `theme` | The theme to use, one of light or dark | `"dark" \| "light"` | `'dark'` |


## Events

| Event | Description | Type |
| ------------------ | ----------------------------------------------------------------------- | -------------------- |
| `clipboardJsError` | The callback that will be fired when ClipboardJS fails to copy the text | `CustomEvent<Event>` |


----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*
94 changes: 51 additions & 43 deletions packages/core/src/components/syntax-highlighter.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component, h, Host, Prop } from '@stencil/core';
import { Component, ComponentInterface, ComponentWillLoad, Event, EventEmitter, h, Host, Prop } from '@stencil/core';
import ClipboardJS from 'clipboard';
import 'prismjs';
import Prism from 'prismjs';
import 'prismjs/components/prism-asciidoc.min.js';
import 'prismjs/components/prism-autohotkey.min.js';
import 'prismjs/components/prism-autoit.min.js';
Expand Down Expand Up @@ -58,65 +58,78 @@ import 'prismjs/components/prism-yaml.min.js';
tag: 'syntax-highlighter',
styleUrl: 'syntax-highlighter.css'
})
export class SyntaxHighlighter {
export class SyntaxHighlighter implements ComponentWillLoad, ComponentInterface {
/**
* The content to show in the syntax highlighter element
*/
@Prop()
content: string;
@Prop({ mutable: true, reflect: true })
public content: string;

/**
* The theme to use, one of light or dark
* @default dark
*/
@Prop()
theme: 'dark' | 'light' = 'dark';
@Prop({ mutable: true, reflect: true })
public theme: 'dark' | 'light' = 'dark';

/**
* The language to highlight for
* @default html
*/
@Prop()
language = 'html';

/**
* The internal code parsed by PrismJS
*/
code: string;

/** The internal ref to the code block */
codeBlockRef: HTMLInputElement;
@Prop({ mutable: true, reflect: true })
public language = 'html';

/**
* The text inside the "copy to clipboard" button
* @remark This is primarily for if you want to provide i18n with your syntax highlighted component
* @example "Kopieer naar klembord"
* @default "Copy to clipboard"
*/
@Prop()
copyButtonLabel = 'Copy to clipboard';
@Prop({ mutable: true, reflect: true })
public copyButtonLabel = 'Copy to clipboard';

componentDidLoad() {
Prism.hooks.add<{ code: string } & Record<PropertyKey, unknown>>('complete', env => {
this.code = env.code;
});
Prism.highlightAll();
/**
* The callback that will be fired when ClipboardJS fails to copy the text
* @remark You can use this to, for example, show notifications to users
* @remark This event will bubble up through the DOM
* @default undefined
* @example
* ```html
* <body>
* <syntax-highlighter id="example-highlight" theme="dark" language="typescript" content="console.log('example')" />
* <script>
* const syntaxHighlighterElement = document.querySelector('#example-highlight');
* syntaxHighlighterElement.addEventListener('clipboardJsError', event => {
* console.log('handling');
* });
* </script>
* </body>
* ```
*/
@Event({ bubbles: true })
public clipboardJsError: EventEmitter<ClipboardJS.Event>;

/** The internal ref to the code block */
private codeBlockRef: HTMLInputElement;

new ClipboardJS('#syntaxhighlighter__ctc-button');
private clipboardJsInstance: ClipboardJS;

public componentWillLoad() {
this.clipboardJsInstance = new ClipboardJS('#syntaxhighlighter__ctc-button');
this.clipboardJsInstance //
.on('success', event => event.clearSelection()) //
.on('error', event => this.clipboardJsError.emit(event));
}

componentDidUpdate() {
public componentDidRender() {
Prism.highlightAll();
}

encodeContent(str?: string) {
if (!str) {
return undefined;
}
return Prism.util.encode(str);
public componentDidUpdate() {
Prism.highlightAll();
}

render() {
public render() {
return (
<Host class="syntaxhighlighter" ref={() => this.codeBlockRef}>
{/* prevent anything from rendering that is between component selector */}
Expand Down Expand Up @@ -151,16 +164,11 @@ export class SyntaxHighlighter {
</Host>
);
}
}

declare global {
const Prism: {
hooks: {
add<CBT>(name: string, callback: (environment: CBT) => void): void;
};
highlightAll(): void;
util: {
encode(tokens: string): string;
};
};
private encodeContent(str?: string): string | undefined {
if (!str) {
return undefined;
}
return Prism.util.encode(str) as string;
}
}
70 changes: 11 additions & 59 deletions packages/core/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,28 +42,20 @@ <h1 class="logo">@favware/syntax-highlighter-core</h1>
<span>[<a target="_blank" rel="noopener noreferrer" href="https://github.com/favware/syntax-highlighter/">Github</a>]</span>
</div>
<main>
<div>
<h3 class="title">A simple ES6 import</h3>
<syntax-highlighter
theme="dark"
language="javascript"
content="import { SyntaxHighlighter } from @favware/syntax-highlighter-react"
/>
</div>

<div>
<h3 class="title">
Sample code from
<a target="__blank" rel="noreferrer" href="https://github.com/favware/graphql-pokemon">favware/graphql-pokemon</a>
</h3>
<syntax-highlighter
id="example-highlight"
theme="dark"
language="typescript"
content="
import { Query } from '@favware/graphql-pokemon';
interface GraphQLPokemonResponse<K extends keyof Omit<Query, '__typename'>> {
data: Record<K, Omit<Query[K], '__typename'>>;
data: Record<K, Omit<Query[K], '__typename'>>;
}
fetch('https://graphqlpokemon.favware.tech/', {
Expand All @@ -73,69 +65,29 @@ <h3 class="title">
},
body: JSON.stringify({
query: `
{
{
getPokemonDetails(pokemon: dragonite skip: 0 take: 2 reverse: true) {
sprite
num
species
color
}
}
}
`
})
})
.then(res => res.json() as Promise<GraphQLPokemonResponse<'getPokemonDetails'>>)
.then(json => console.log(json.data));"
/>
</div>

<div>
<h3 class="title">
Sample code from
<a target="__blank" rel="noreferrer" href="https://doc.rust-lang.org/rust-by-example/hello.html"
>Rust - Hello World</a
>
</h3>
<syntax-highlighter
theme="dark"
language="rust"
content='
// This is a comment, and is ignored by the compiler
// This is the main function
fn main() {
// Statements here are executed when the compiled binary is called
// Print text to the console
println!("Hello World!");
}'
/>
</div>

<div>
<h3 class="title">
A very light Hello World for C#
</h3>
<p>Note: C# language string is <em>csharp</em>, not <em>c#</em>!</p>
<syntax-highlighter
theme="light"
language="csharp"
content='
using System;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}'
/>
</div>
</main>
</div>
<script>
const syntaxHighlighterElement = document.querySelector('#example-highlight');
syntaxHighlighterElement.addEventListener('clipboardJsError', event => {
console.log('handling');
console.log(event);
});
</script>
</body>
</html>
3 changes: 2 additions & 1 deletion packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { createReactComponent } from './react-component-lib';

import type { JSX } from '@favware/syntax-highlighter-core';

import { defineCustomElements } from '@favware/syntax-highlighter-core/loader';


defineCustomElements();
export const SyntaxHighlighter = /*@__PURE__*/createReactComponent<JSX.SyntaxHighlighter, HTMLSyntaxHighlighterElement>('syntax-highlighter');
2 changes: 1 addition & 1 deletion packages/react/src/react-component-lib/createComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const createReactComponent = <
const { children, forwardedRef, style, className, ref, ...cProps } = this.props;

let propsToPass = Object.keys(cProps).reduce((acc, name) => {
if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) {
if (name.startsWith('on') && name[2] === name[2].toUpperCase()) {
const eventName = name.substring(2).toLowerCase();
if (typeof document !== 'undefined' && isCoveredByReact(eventName, document)) {
(acc as any)[name] = (cProps as any)[name];
Expand Down

This file was deleted.

Loading

0 comments on commit 3c8cf80

Please sign in to comment.