Adding An Emoji Picker
We can use the willRenderShapePresetToolbar
hook to add custom shape preset tools to the sticker and preset toolbars.
In the example below we use emoji-picker-element
to add an Emoji picker to the preset tab of the annotation util. We can see an example of this control on Edit • Photo
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="./pintura.css" />
</head>
<style>
.pintura-editor {
height: 600px;
}
</style>
<div id="editor"></div>
<script type="module">
import { appendDefaultEditor, createNode, appendNode } from './pintura.js';
const addSmiley = (editor, addPreset, smiley) => {
// update the recent smileys
const recent = new Set([smiley, ...editor.annotatePresets]);
const recentArr = Array.from(recent);
// max of five
if (recentArr.length > 5) recentArr.length = 5;
editor.annotatePresets = recentArr;
// add the smiley to the canvas
addPreset(smiley);
};
let picker = undefined;
let imported = false;
const editor = appendDefaultEditor('#editor', {
src: 'image.jpeg',
util: 'annotate',
willRenderShapePresetToolbar: (toolbar, addPreset, env, redraw) => {
// import from unpkg
if (!imported) {
import('https://unpkg.com/emoji-picker-element')
.then(() => {
imported = true;
redraw();
})
// silently error out
.catch(console.log);
return toolbar;
}
// create root
if (!picker) {
// create the picker
const emojiPicker = document.createElement('emoji-picker');
// enable touch scroll of Pintura child element on iOS
emojiPicker.dataset.touchScroll = 'true';
// exit if no shadow root
if (!emojiPicker.shadowRoot) return toolbar;
// set custom styles to make it fit better
const style = document.createElement('style');
style.textContent = `
.favorites { display: none }
.emoji { border-radius: 0 }
button.emoji { border-radius: 0 }
.tabpanel {
scrollbar-color:#ddd transparent;
scrollbar-width: thin;
}
.tabpanel::-webkit-scrollbar {
width: 1rem;
cursor: pointer;
}
.tabpanel::-webkit-scrollbar-track {
background: none;
}
.tabpanel::-webkit-scrollbar-thumb {
cursor: pointer;
background-clip: padding-box;
background-color: #ddd;
border-radius: 9999rem;
border: 0.3125rem solid rgba(0, 0, 0, 0);
}
`;
emojiPicker.shadowRoot.appendChild(style);
// set theme, light or dark
emojiPicker.className = 'light';
// handle picking an emoji
emojiPicker.addEventListener('emoji-click', (e) =>
addSmiley(editor, addPreset, e.detail.unicode)
);
picker = emojiPicker;
}
// append the picker Panel
appendNode(
createNode('Panel', 'emoji', {
buttonLabel: 'Emoji',
root: picker,
}),
toolbar
);
return toolbar;
},
});
</script>
import '@pqina/pintura/pintura.css';
import './App.css';
import { useRef, useState } from 'react';
import { PinturaEditor } from '@pqina/react-pintura';
import { getEditorDefaults, createNode, appendNode } from '@pqina/pintura';
const editorDefaults = getEditorDefaults();
const addSmiley = (editor, addPreset, smiley) => {
// update the recent smileys
const recent = new Set([smiley, ...editor.annotatePresets]);
const recentArr = Array.from(recent);
// max of five
if (recentArr.length > 5) recentArr.length = 5;
editor.annotatePresets = recentArr;
// add the smiley to the canvas
addPreset(smiley);
};
function App() {
const [picker, setPicker] = useState(undefined);
const [imported, setImported] = useState(false);
const editorRef = useRef(null);
const willRenderShapePresetToolbar = (toolbar, addPreset, env, redraw) => {
// import from unpkg
if (!imported) {
import('https://unpkg.com/emoji-picker-element')
.then(() => {
setImported(true);
redraw();
})
// silently error out
.catch(console.log);
return toolbar;
}
// create root
if (!picker) {
// create the picker
const emojiPicker = document.createElement('emoji-picker');
// enable touch scroll of Pintura child element on iOS
emojiPicker.dataset.touchScroll = 'true';
// exit if no shadow root
if (!emojiPicker.shadowRoot) return toolbar;
// set custom styles to make it fit better
const style = document.createElement('style');
style.textContent = `
.favorites { display: none }
.emoji { border-radius: 0 }
button.emoji { border-radius: 0 }
.tabpanel {
scrollbar-color:#ddd transparent;
scrollbar-width: thin;
}
.tabpanel::-webkit-scrollbar {
width: 1rem;
cursor: pointer;
}
.tabpanel::-webkit-scrollbar-track {
background: none;
}
.tabpanel::-webkit-scrollbar-thumb {
cursor: pointer;
background-clip: padding-box;
background-color: #ddd;
border-radius: 9999rem;
border: 0.3125rem solid rgba(0, 0, 0, 0);
}
`;
emojiPicker.shadowRoot.appendChild(style);
// set theme, light or dark
emojiPicker.className = 'light';
// handle picking an emoji
emojiPicker.addEventListener('emoji-click', (e) =>
addSmiley(editorRef.current.editor, addPreset, e.detail.unicode)
);
setPicker(emojiPicker);
}
// append the picker Panel
appendNode(
createNode('Panel', 'emoji', {
buttonLabel: 'Emoji',
root: picker,
}),
toolbar
);
return toolbar;
};
return (
<div className="App">
<PinturaEditor
ref={editorRef}
{...editorDefaults}
src={'image.jpeg'}
util={'annotate'}
willRenderShapePresetToolbar={willRenderShapePresetToolbar}
/>
</div>
);
}
export default App;
.pintura-editor {
height: 600px;
}
<template>
<div>
<PinturaEditor
ref="editor"
v-bind="editorDefaults"
src="image.jpeg"
util="annotate"
:willRenderShapePresetToolbar="willRenderShapePresetToolbar"
/>
</div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import { getEditorDefaults, createNode, appendNode } from '@pqina/pintura';
const addSmiley = function (editor, addPreset, smiley) {
// update the recent smileys
const recent = new Set([smiley, ...editor.annotatePresets]);
const recentArr = Array.from(recent);
// max of five
if (recentArr.length > 5) recentArr.length = 5;
editor.annotatePresets = recentArr;
// add the smiley to the canvas
addPreset(smiley);
};
export default {
name: 'App',
components: {
PinturaEditor,
},
data() {
return {
editorDefaults: getEditorDefaults(),
picker: undefined,
imported: false,
willRenderShapePresetToolbar: (toolbar, addPreset, env, redraw) => {
// import from unpkg
if (!this.imported) {
import('https://unpkg.com/emoji-picker-element')
.then(() => {
this.imported = true;
redraw();
})
// silently error out
.catch(console.log);
return toolbar;
}
// create root
if (!this.picker) {
// create the picker
const emojiPicker = document.createElement('emoji-picker');
// enable touch scroll of Pintura child element on iOS
emojiPicker.dataset.touchScroll = 'true';
// exit if no shadow root
if (!emojiPicker.shadowRoot) return toolbar;
// set custom styles to make it fit better
const style = document.createElement('style');
style.textContent = `
.favorites { display: none }
.emoji { border-radius: 0 }
button.emoji { border-radius: 0 }
.tabpanel {
scrollbar-color:#ddd transparent;
scrollbar-width: thin;
}
.tabpanel::-webkit-scrollbar {
width: 1rem;
cursor: pointer;
}
.tabpanel::-webkit-scrollbar-track {
background: none;
}
.tabpanel::-webkit-scrollbar-thumb {
cursor: pointer;
background-clip: padding-box;
background-color: #ddd;
border-radius: 9999rem;
border: 0.3125rem solid rgba(0, 0, 0, 0);
}
`;
emojiPicker.shadowRoot.appendChild(style);
// set theme, light or dark
emojiPicker.className = 'light';
// handle picking an emoji
emojiPicker.addEventListener('emoji-click', (e) =>
addSmiley(
this.$refs.editor.editor,
addPreset,
e.detail.unicode
)
);
this.picker = emojiPicker;
}
// append the picker Panel
appendNode(
createNode('Panel', 'emoji', {
buttonLabel: 'Emoji',
root: this.picker,
}),
toolbar
);
return toolbar;
},
};
},
methods: {},
};
</script>
<style>
@import '@pqina/pintura/pintura.css';
.pintura-editor {
height: 600px;
}
</style>
<script>
import { PinturaEditor } from '@pqina/svelte-pintura';
import { getEditorDefaults, createNode, appendNode } from '@pqina/pintura';
import '@pqina/pintura/pintura.css';
const addSmiley = (editor, addPreset, smiley) => {
// update the recent smileys
const recent = new Set([smiley, ...editor.annotatePresets]);
const recentArr = Array.from(recent);
// max of five
if (recentArr.length > 5) recentArr.length = 5;
editor.annotatePresets = recentArr;
// add the smiley to the canvas
addPreset(smiley);
};
let editorDefaults = getEditorDefaults();
let picker = undefined;
let imported = false;
let editor;
const willRenderShapePresetToolbar = (toolbar, addPreset, env, redraw) => {
// import from unpkg
if (!imported) {
import('https://unpkg.com/emoji-picker-element')
.then(() => {
imported = true;
redraw();
})
// silently error out
.catch(console.log);
return toolbar;
}
// create root
if (!picker) {
// create the picker
const emojiPicker = document.createElement('emoji-picker');
// enable touch scroll of Pintura child element on iOS
emojiPicker.dataset.touchScroll = 'true';
// exit if no shadow root
if (!emojiPicker.shadowRoot) return toolbar;
// set custom styles to make it fit better
const style = document.createElement('style');
style.textContent = `
.favorites { display: none }
.emoji { border-radius: 0 }
button.emoji { border-radius: 0 }
.tabpanel {
scrollbar-color:#ddd transparent;
scrollbar-width: thin;
}
.tabpanel::-webkit-scrollbar {
width: 1rem;
cursor: pointer;
}
.tabpanel::-webkit-scrollbar-track {
background: none;
}
.tabpanel::-webkit-scrollbar-thumb {
cursor: pointer;
background-clip: padding-box;
background-color: #ddd;
border-radius: 9999rem;
border: 0.3125rem solid rgba(0, 0, 0, 0);
}
`;
emojiPicker.shadowRoot.appendChild(style);
// set theme, light or dark
emojiPicker.className = 'light';
// handle picking an emoji
emojiPicker.addEventListener('emoji-click', (e) =>
addSmiley(editor, addPreset, e.detail.unicode)
);
picker = emojiPicker;
}
// append the picker Panel
appendNode(
createNode('Panel', 'emoji', {
buttonLabel: 'Emoji',
root: picker,
}),
toolbar
);
return toolbar;
};
</script>
<div>
<PinturaEditor
bind:this={editor}
{...editorDefaults}
src={'image.jpeg'}
util={'annotate'}
{willRenderShapePresetToolbar}
/>
</div>
<style>
div :global(.pintura-editor) {
height: 600px;
}
</style>
import { Component, ViewChild } from '@angular/core';
import {
getEditorDefaults,
createNode,
appendNode,
PinturaNode,
Sticker,
} from '@pqina/pintura';
const addSmiley = (
editor: any,
addPreset: (preset: Sticker) => void,
smiley: string
): void => {
// update the recent smileys
const recent = new Set([smiley, ...editor.annotatePresets]);
const recentArr = Array.from(recent);
// max of five
if (recentArr.length > 5) recentArr.length = 5;
editor.annotatePresets = recentArr;
// add the smiley to the canvas
addPreset(smiley);
};
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
@ViewChild('editor') editor?: any;
editorDefaults: any = getEditorDefaults();
picker: HTMLElement | undefined = undefined;
imported: Boolean = false;
willRenderShapePresetToolbar = (
toolbar: PinturaNode[],
addPreset: (preset: Sticker) => void,
env: any,
redraw: () => void
): PinturaNode[] => {
// import from unpkg
if (!this.imported) {
import('emoji-picker-element')
.then(() => {
this.imported = true;
redraw();
})
// silently error out
.catch(console.log);
return toolbar;
}
// create root
if (!this.picker) {
// create the picker
const emojiPicker = document.createElement('emoji-picker');
// enable touch scroll of Pintura child element on iOS
emojiPicker.dataset.touchScroll = 'true';
// exit if no shadow root
if (!emojiPicker.shadowRoot) return toolbar;
// set custom styles to make it fit better
const style = document.createElement('style');
style.textContent = `
.favorites { display: none }
.emoji { border-radius: 0 }
button.emoji { border-radius: 0 }
.tabpanel {
scrollbar-color:#ddd transparent;
scrollbar-width: thin;
}
.tabpanel::-webkit-scrollbar {
width: 1rem;
cursor: pointer;
}
.tabpanel::-webkit-scrollbar-track {
background: none;
}
.tabpanel::-webkit-scrollbar-thumb {
cursor: pointer;
background-clip: padding-box;
background-color: #ddd;
border-radius: 9999rem;
border: 0.3125rem solid rgba(0, 0, 0, 0);
}
`;
emojiPicker.shadowRoot.appendChild(style);
// set theme, light or dark
emojiPicker.className = 'light';
// handle picking an emoji
emojiPicker.addEventListener('emoji-click', (e) =>
addSmiley(this.editor.editor, addPreset, e.detail.unicode)
);
this.picker = emojiPicker;
}
// append the picker Panel
appendNode(
createNode('Panel', 'emoji', {
buttonLabel: 'Emoji',
root: this.picker,
}),
toolbar
);
return toolbar;
};
}
<pintura-editor
#editor
[options]="editorDefaults"
src="image.jpeg"
util="annotate"
[willRenderShapePresetToolbar]="willRenderShapePresetToolbar"
></pintura-editor>
::ng-deep .pintura-editor {
height: 600px;
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, AngularPinturaModule],
exports: [AppComponent],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="./pintura/pintura.css" />
</head>
<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>
<style>
.pintura-editor {
height: 600px;
}
</style>
<div id="editor"></div>
<script>
useEditorWithJQuery(jQuery, pintura);
$(function () {
var { createNode, appendNode } = $.fn.pintura;
const addSmiley = (editor, addPreset, smiley) => {
// update the recent smileys
const recent = new Set([smiley, ...editor.annotatePresets]);
const recentArr = Array.from(recent);
// max of five
if (recentArr.length > 5) recentArr.length = 5;
editor.annotatePresets = recentArr;
// add the smiley to the canvas
addPreset(smiley);
};
var picker = undefined;
var imported = false;
var editor = $('#editor').pinturaDefault({
src: 'image.jpeg',
util: 'annotate',
willRenderShapePresetToolbar: (toolbar, addPreset, env, redraw) => {
// import from unpkg
if (!imported) {
import('https://unpkg.com/emoji-picker-element')
.then(() => {
imported = true;
redraw();
})
// silently error out
.catch(console.log);
return toolbar;
}
// create root
if (!picker) {
// create the picker
const emojiPicker = document.createElement('emoji-picker');
// enable touch scroll of Pintura child element on iOS
emojiPicker.dataset.touchScroll = 'true';
// exit if no shadow root
if (!emojiPicker.shadowRoot) return toolbar;
// set custom styles to make it fit better
const style = document.createElement('style');
style.textContent = `
.favorites { display: none }
.emoji { border-radius: 0 }
button.emoji { border-radius: 0 }
.tabpanel {
scrollbar-color:#ddd transparent;
scrollbar-width: thin;
}
.tabpanel::-webkit-scrollbar {
width: 1rem;
cursor: pointer;
}
.tabpanel::-webkit-scrollbar-track {
background: none;
}
.tabpanel::-webkit-scrollbar-thumb {
cursor: pointer;
background-clip: padding-box;
background-color: #ddd;
border-radius: 9999rem;
border: 0.3125rem solid rgba(0, 0, 0, 0);
}
`;
emojiPicker.shadowRoot.appendChild(style);
// set theme, light or dark
emojiPicker.className = 'light';
// handle picking an emoji
emojiPicker.addEventListener('emoji-click', (e) =>
addSmiley(editor, addPreset, e.detail.unicode)
);
picker = emojiPicker;
}
// append the picker Panel
appendNode(
createNode('Panel', 'emoji', {
buttonLabel: 'Emoji',
root: picker,
}),
toolbar
);
return toolbar;
},
});
});
</script>