luxen-ui 0.9.3 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cdn/chunks/picker.js +5 -0
- package/cdn/chunks/picker.js.map +1 -0
- package/cdn/custom-elements.json +145 -121
- package/cdn/elements/avatar/avatar.d.ts +1 -0
- package/cdn/elements/avatar/avatar.d.ts.map +1 -1
- package/cdn/elements/avatar/avatar.js +1 -1
- package/cdn/elements/avatar/avatar.js.map +1 -1
- package/cdn/elements/prose-editor/prose-editor.d.ts +39 -11
- package/cdn/elements/prose-editor/prose-editor.d.ts.map +1 -1
- package/cdn/elements/prose-editor/prose-editor.js +36 -36
- package/cdn/elements/prose-editor/prose-editor.js.map +1 -1
- package/cdn/standalone.js +1767 -4165
- package/cdn/standalone.js.map +1 -1
- package/dist/custom-elements.json +145 -121
- package/dist/elements/avatar/avatar.css +10 -10
- package/dist/elements/avatar/avatar.d.ts +1 -0
- package/dist/elements/avatar/avatar.d.ts.map +1 -1
- package/dist/elements/avatar/avatar.js +1 -0
- package/dist/elements/prose-editor/prose-editor.d.ts +39 -11
- package/dist/elements/prose-editor/prose-editor.d.ts.map +1 -1
- package/dist/elements/prose-editor/prose-editor.js +114 -38
- package/dist/metadata/avatar.json +5 -0
- package/dist/metadata/index.json +14 -1
- package/dist/metadata/prose-editor.json +8 -0
- package/dist/templates/elements/avatar.md +23 -0
- package/dist/templates/elements/prose-editor.md +11 -0
- package/package.json +2 -3
- package/cdn/chunks/module.js +0 -717
- package/cdn/chunks/module.js.map +0 -1
- package/cdn/chunks/native.js +0 -2
- package/cdn/chunks/native.js.map +0 -1
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
function e(e){if(typeof e!=`string`||!e)throw Error(`expected a non-empty string, got: `+e)}function t(e){if(typeof e!=`number`)throw Error(`expected a number, got: `+e)}var n=1,r=1,i=`emoji`,a=`keyvalue`,o=`favorites`,s=`tokens`,c=`tokens`,l=`unicode`,u=`count`,d=`group`,f=`order`,p=`group-order`,m=`eTag`,h=`url`,g=`skinTone`,_=`readonly`,v=`readwrite`,y=`skinUnicodes`,b=`skinUnicodes`,x=`https://cdn.jsdelivr.net/npm/emoji-picker-element-data@^1/en/emojibase/data.json`,ee=`en`;function te(e,t){let n=new Set,r=[];for(let i of e){let e=t(i);n.has(e)||(n.add(e),r.push(i))}return r}function S(e){return te(e,e=>e.unicode)}function ne(e){function t(t,n,r){let i=n?e.createObjectStore(t,{keyPath:n}):e.createObjectStore(t);if(r)for(let[e,[t,n]]of Object.entries(r))i.createIndex(e,t,{multiEntry:n});return i}t(a),t(i,l,{[c]:[s,!0],[p]:[[d,f]],[y]:[b,!0]}),t(o,void 0,{[u]:[``]})}var C={},w={},T={};function E(e,t,n){n.onerror=()=>t(n.error),n.onblocked=()=>t(Error(`IDB blocked`)),n.onsuccess=()=>e(n.result)}async function re(e){let t=await new Promise((t,i)=>{let a=indexedDB.open(e,n);C[e]=a,a.onupgradeneeded=e=>{e.oldVersion<r&&ne(a.result)},E(t,i,a)});return t.onclose=()=>O(e),t}function ie(e){return w[e]||(w[e]=re(e)),w[e]}function D(e,t,n,r){return new Promise((i,a)=>{let o=e.transaction(t,n,{durability:`relaxed`}),s=typeof t==`string`?o.objectStore(t):t.map(e=>o.objectStore(e)),c;r(s,o,e=>{c=e}),o.oncomplete=()=>i(c),o.onerror=()=>a(o.error)})}function O(e){let t=C[e],n=t&&t.result;if(n){n.close();let t=T[e];if(t)for(let e of t)e()}delete C[e],delete w[e],delete T[e]}function ae(e){return new Promise((t,n)=>{O(e),E(t,n,indexedDB.deleteDatabase(e))})}function k(e,t){let n=T[e];n||=T[e]=[],n.push(t)}var oe=new Set(`:D.XD.:'D.O:).:X.:P.;P.XP.:L.:Z.:j.8D.XO.8).:B.:O.:S.:'o.Dx.X(.D:.:C.>0).:3.</3.<3.\\M/.:E.8#`.split(`.`));function A(e){return e.split(/[\s_]+/).map(e=>!e.match(/\w/)||oe.has(e)?e.toLowerCase():e.replace(/[)(:,]/g,``).replace(/’/g,`'`).toLowerCase()).filter(Boolean)}var se=2;function j(e){return e.filter(Boolean).map(e=>e.toLowerCase()).filter(e=>e.length>=se)}function ce(e){return e.map(({annotation:e,emoticon:t,group:n,order:r,shortcodes:i,skins:a,tags:o,emoji:s,version:c})=>{let l={annotation:e,group:n,order:r,tags:o,tokens:[...new Set(j([...(i||[]).map(A).flat(),...(o||[]).map(A).flat(),...A(e),t]))].sort(),unicode:s,version:c};if(t&&(l.emoticon=t),i&&(l.shortcodes=i),a){l.skinTones=[],l.skinUnicodes=[],l.skinVersions=[];for(let{tone:e,emoji:t,version:n}of a)l.skinTones.push(e),l.skinUnicodes.push(t),l.skinVersions.push(n)}return l})}function M(e,t,n,r){e[t](n).onsuccess=e=>r&&r(e.target.result)}function N(e,t,n){M(e,`get`,t,n)}function P(e,t,n){M(e,`getAll`,t,n)}function F(e){e.commit&&e.commit()}function le(e,t){let n=e[0];for(let r=1;r<e.length;r++){let i=e[r];t(n)>t(i)&&(n=i)}return n}function ue(e,t){let n=le(e,e=>e.length),r=[];for(let i of n)e.some(e=>e.findIndex(e=>t(e)===t(i))===-1)||r.push(i);return r}async function de(e){return!await I(e,a,h)}async function fe(e,t,n){let[r,i]=await Promise.all([m,h].map(t=>I(e,a,t)));return r===n&&i===t}async function pe(e,t){return D(e,i,_,(e,n,r)=>{let i,a=()=>{e.getAll(i&&IDBKeyRange.lowerBound(i,!0),50).onsuccess=e=>{let n=e.target.result;for(let e of n)if(i=e.unicode,t(e))return r(e);if(n.length<50)return r();a()}};a()})}async function me(e,t,n,r){try{let o=ce(t);await D(e,[i,a],v,([e,t],i)=>{let a,s,c=0;function l(){++c===2&&u()}function u(){if(!(a===r&&s===n)){e.clear();for(let t of o)e.put(t);t.put(r,m),t.put(n,h),F(i)}}N(t,m,e=>{a=e,l()}),N(t,h,e=>{s=e,l()})})}finally{}}async function he(e,t){return D(e,i,_,(e,n,r)=>{let i=IDBKeyRange.bound([t,0],[t+1,0],!1,!0);P(e.index(p),i,r)})}async function ge(e,t){let n=j(A(t));return n.length?D(e,i,_,(e,t,r)=>{let i=[],a=()=>{i.length===n.length&&o()},o=()=>{r(ue(i,e=>e.unicode).sort((e,t)=>e.order<t.order?-1:1))};for(let t=0;t<n.length;t++){let r=n[t],o=t===n.length-1?IDBKeyRange.bound(r,r+``,!1,!0):IDBKeyRange.only(r);P(e.index(c),o,e=>{i.push(e),a()})}}):[]}async function _e(e,t){let n=await ge(e,t);return n.length?n.filter(e=>(e.shortcodes||[]).map(e=>e.toLowerCase()).includes(t.toLowerCase()))[0]||null:await pe(e,e=>(e.shortcodes||[]).includes(t.toLowerCase()))||null}async function ve(e,t){return D(e,i,_,(e,n,r)=>N(e,t,n=>{if(n)return r(n);N(e.index(y),t,e=>r(e||null))}))}function I(e,t,n){return D(e,t,_,(e,t,r)=>N(e,n,r))}function ye(e,t,n,r){return D(e,t,v,(e,t)=>{e.put(r,n),F(t)})}function be(e,t){return D(e,o,v,(e,n)=>N(e,t,r=>{e.put((r||0)+1,t),F(n)}))}function xe(e,t,n){return n===0?[]:D(e,[o,i],_,([e,r],i,a)=>{let o=[];e.index(u).openCursor(void 0,`prev`).onsuccess=e=>{let i=e.target.result;if(!i)return a(o);function s(e){if(o.push(e),o.length===n)return a(o);i.continue()}let c=i.primaryKey,l=t.byName(c);if(l)return s(l);N(r,c,e=>{if(e)return s(e);i.continue()})}})}var L=``;function Se(e,t){let n=new Map;for(let r of e){let e=t(r);for(let t of e){let e=n;for(let n=0;n<t.length;n++){let r=t.charAt(n),i=e.get(r);i||(i=new Map,e.set(r,i)),e=i}let i=e.get(L);i||(i=[],e.set(L,i)),i.push(r)}}return(e,t)=>{let r=n;for(let t=0;t<e.length;t++){let n=e.charAt(t),i=r.get(n);if(i)r=i;else return[]}if(t)return r.get(L)||[];let i=[],a=[r];for(;a.length;){let e=[...a.shift().entries()].sort((e,t)=>e[0]<t[0]?-1:1);for(let[t,n]of e)t===L?i.push(...n):a.push(n)}return i}}var Ce=[`name`,`url`];function we(e){let t=e&&Array.isArray(e),n=t&&e.length&&(!e[0]||Ce.some(t=>!(t in e[0])));if(!t||n)throw Error(`Custom emojis are in the wrong format`)}function Te(e){we(e);let t=(e,t)=>e.name.toLowerCase()<t.name.toLowerCase()?-1:1,n=e.sort(t),r=Se(e,e=>{let t=new Set;if(e.shortcodes)for(let n of e.shortcodes)for(let e of A(n))t.add(e);return t}),i=e=>r(e,!0),a=e=>r(e,!1),o=e=>{let n=A(e);return ue(n.map((e,t)=>(t<n.length-1?i:a)(e)),e=>e.name).sort(t)},s=new Map,c=new Map;for(let t of e){c.set(t.name.toLowerCase(),t);for(let e of t.shortcodes||[])s.set(e.toLowerCase(),t)}return{all:n,search:o,byShortcode:e=>s.get(e.toLowerCase()),byName:e=>c.get(e.toLowerCase())}}var Ee=typeof wrappedJSObject<`u`;function R(e){if(!e)return e;if(Ee&&(e=structuredClone(e)),delete e.tokens,e.skinTones){let t=e.skinTones.length;e.skins=Array(t);for(let n=0;n<t;n++)e.skins[n]={tone:e.skinTones[n],unicode:e.skinUnicodes[n],version:e.skinVersions[n]};delete e.skinTones,delete e.skinUnicodes,delete e.skinVersions}return e}function De(e){e||console.warn(`emoji-picker-element is more efficient if the dataSource server exposes an ETag header.`)}var Oe=[`annotation`,`emoji`,`group`,`order`,`version`];function ke(e){if(!e||!Array.isArray(e)||!e[0]||typeof e[0]!=`object`||Oe.some(t=>!(t in e[0])))throw Error(`Emoji data is in the wrong format`)}function Ae(e,t){if(Math.floor(e.status/100)!==2)throw Error(`Failed to fetch: `+t+`: `+e.status)}async function je(e){let t=await fetch(e,{method:`HEAD`});Ae(t,e);let n=t.headers.get(`etag`);return De(n),n}async function z(e){let t=await fetch(e);Ae(t,e);let n=t.headers.get(`etag`);De(n);let r=await t.json();return ke(r),[n,r]}function Me(e){for(var t=``,n=new Uint8Array(e),r=n.byteLength,i=-1;++i<r;)t+=String.fromCharCode(n[i]);return t}function Ne(e){for(var t=e.length,n=new ArrayBuffer(t),r=new Uint8Array(n),i=-1;++i<t;)r[i]=e.charCodeAt(i);return n}async function Pe(e){let t=Ne(JSON.stringify(e)),n=Me(await crypto.subtle.digest(`SHA-1`,t));return btoa(n)}async function Fe(e,t){let n,r=await je(t);if(!r){let e=await z(t);r=e[0],n=e[1],r||=await Pe(n)}await fe(e,t,r)||(n||=(await z(t))[1],await me(e,n,t,r))}async function Ie(e,t){let[n,r]=await z(t);n||=await Pe(r),await me(e,r,t,n)}async function Le(e,t){try{await Fe(e,t)}catch(e){if(e.name!==`InvalidStateError`)throw e}}var Re=class{constructor({dataSource:e=x,locale:t=ee,customEmoji:n=[]}={}){this.dataSource=e,this.locale=t,this._dbName=`emoji-picker-element-${this.locale}`,this._db=void 0,this._lazyUpdate=void 0,this._custom=Te(n),this._clear=this._clear.bind(this),this._ready=this._init()}async _init(){let e=this._db=await ie(this._dbName);k(this._dbName,this._clear);let t=this.dataSource;await de(e)?await Ie(e,t):this._lazyUpdate=Le(e,t)}async ready(){let e=async()=>(this._ready||=this._init(),this._ready);await e(),this._db||await e()}async getEmojiByGroup(e){return t(e),await this.ready(),S(await he(this._db,e)).map(R)}async getEmojiBySearchQuery(t){e(t),await this.ready();let n=this._custom.search(t),r=S(await ge(this._db,t)).map(R);return[...n,...r]}async getEmojiByShortcode(t){return e(t),await this.ready(),this._custom.byShortcode(t)||R(await _e(this._db,t))}async getEmojiByUnicodeOrName(t){return e(t),await this.ready(),this._custom.byName(t)||R(await ve(this._db,t))}async getPreferredSkinTone(){return await this.ready(),await I(this._db,a,g)||0}async setPreferredSkinTone(e){return t(e),await this.ready(),ye(this._db,a,g,e)}async incrementFavoriteEmojiCount(t){return e(t),await this.ready(),be(this._db,t)}async getTopFavoriteEmoji(e){return t(e),await this.ready(),(await xe(this._db,this._custom,e)).map(R)}set customEmoji(e){this._custom=Te(e)}get customEmoji(){return this._custom.all}async _shutdown(){await this.ready();try{await this._lazyUpdate}catch{}}_clear(){this._db=this._ready=this._lazyUpdate=void 0}async close(){await this._shutdown(),await O(this._dbName)}async delete(){await this._shutdown(),await ae(this._dbName)}},B=[[-1,`✨`,`custom`],[0,`😀`,`smileys-emotion`],[1,`👋`,`people-body`],[3,`🐱`,`animals-nature`],[4,`🍎`,`food-drink`],[5,`🏠️`,`travel-places`],[6,`⚽`,`activities`],[7,`📝`,`objects`],[8,`⛔️`,`symbols`],[9,`🏁`,`flags`]].map(([e,t,n])=>({id:e,emoji:t,name:n})),V=B.slice(1),ze=2,Be=6,Ve=typeof requestIdleCallback==`function`?requestIdleCallback:setTimeout;function He(e){return e.unicode.includes(``)}var Ue={"":17,"":16,"🫨":15.1,"🫠":14,"🥲":13.1,"🥻":12.1,"🥰":11,"🤩":5,"👱♀️":4,"🤣":3,"👁️🗨️":2,"😀":1,"😐️":.7,"😃":.6},We=1e3,Ge=`🖐️`,Ke=8,qe=[`😊`,`😒`,`❤️`,`👍️`,`😍`,`😂`,`😭`,`☺️`,`😔`,`😩`,`😏`,`💕`,`🙌`,`😘`],Je=`"Twemoji Mozilla","Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji","EmojiOne Color","Android Emoji",sans-serif`,Ye=(e,t)=>e<t?-1:+(e>t),Xe=(e,t)=>{let n=document.createElement(`canvas`);n.width=n.height=1;let r=n.getContext(`2d`,{willReadFrequently:!0});return r.textBaseline=`top`,r.font=`100px ${Je}`,r.fillStyle=t,r.scale(.01,.01),r.fillText(e,0,0),r.getImageData(0,0,1,1).data},Ze=(e,t)=>{let n=[...e].join(`,`);return n===[...t].join(`,`)&&!n.startsWith(`0,0,0,`)};function Qe(e){let t=Xe(e,`#000`),n=Xe(e,`#fff`);return t&&n&&Ze(t,n)}function $e(){let e=Object.entries(Ue);try{for(let[t,n]of e)if(Qe(t))return n}catch{}return e[0][1]}var et,H=()=>(et||=new Promise(e=>Ve(()=>e($e()))),et),U=new Map,tt=`️`,nt=`\ud83c`,rt=``,it=127995,at=57339;function ot(e,t){if(t===0)return e;let n=e.indexOf(rt);return n===-1?(e.endsWith(tt)&&(e=e.substring(0,e.length-1)),e+nt+String.fromCodePoint(at+t-1)):e.substring(0,n)+String.fromCodePoint(it+t-1)+e.substring(n)}function W(e){e.preventDefault(),e.stopPropagation()}function G(e,t,n){return t+=e?-1:1,t<0?t=n.length-1:t>=n.length&&(t=0),t}function st(e,t){let n=new Set,r=[];for(let i of e){let e=t(i);n.has(e)||(n.add(e),r.push(i))}return r}function ct(e,t){let n=e=>{let n={};for(let r of e)typeof r.tone==`number`&&r.version<=t&&(n[r.tone]=r.unicode);return n};return e.map(({unicode:e,skins:t,shortcodes:r,url:i,name:a,category:o,annotation:s})=>({unicode:e,name:a,shortcodes:r,url:i,category:o,annotation:s,id:e||a,skins:t&&n(t)}))}var K=requestAnimationFrame,lt=typeof ResizeObserver==`function`;function ut(e,t,n){let r;lt?(r=new ResizeObserver(n),r.observe(e)):K(n),t.addEventListener(`abort`,()=>{r&&r.disconnect()})}function dt(e){{let t=document.createRange();return t.selectNode(e.firstChild),t.getBoundingClientRect().width}}var ft=`😀`,q,J;function pt(e,t,n){let r=dt(t);if(!r){if(!J){J=n.cloneNode(!0);let e=getComputedStyle(n);for(let t of[`font-family`,`line-height`,`width`,`height`,`font-size`,`display`,`align-items`,`justify-content`])J.style.setProperty(t,e.getPropertyValue(t),`important`)}try{return document.body.appendChild(J),J.firstChild.nodeValue=e,dt(J)}finally{J.remove()}}return r}function mt(e,t,n){let r=!0;for(let i of e){let e=n(i);if(!e)continue;q===void 0&&(q=pt(ft,t,t));let a=pt(i.unicode,e,t)/1.8<q;U.set(i.unicode,a),a||(r=!1)}return r}function ht(e){return st(e,e=>e)}function gt(e){e&&(e.scrollTop=0)}function Y(e,t,n){let r=e.get(t);return r||(r=n(),e.set(t,r)),r}function _t(e){return``+e}function vt(e){let t=document.createElement(`template`);return t.innerHTML=e,t}var yt=new WeakMap,bt=new WeakMap,xt=Symbol(`un-keyed`),St=`replaceChildren`in Element.prototype;function Ct(e,t){St?e.replaceChildren(...t):(e.innerHTML=``,e.append(...t))}function wt(e,t){let n=e.firstChild,r=0;for(;n;){if(t[r]!==n)return!0;n=n.nextSibling,r++}return r!==t.length}function Tt(e,t){let{targetNode:n}=t,{targetParentNode:r}=t,i=!1;r?i=wt(r,e):(i=!0,t.targetNode=void 0,t.targetParentNode=r=n.parentNode),i&&Ct(r,e)}function Et(e,t){for(let n of t){let{targetNode:t,currentExpression:r,binding:{expressionIndex:i,attributeName:a,attributeValuePre:o,attributeValuePost:s}}=n,c=e[i];if(r!==c)if(n.currentExpression=c,a)if(c===null)t.removeAttribute(a);else{let e=o+_t(c)+s;t.setAttribute(a,e)}else{let e;Array.isArray(c)?Tt(c,n):c instanceof Element?(e=c,t.replaceWith(e)):t.nodeValue=_t(c),e&&(n.targetNode=e)}}}function Dt(e){let t=``,n=!1,r=!1,i=-1,a=new Map,o=[],s=0;for(let c=0,l=e.length;c<l;c++){let u=e[c];if(t+=u.slice(s),c===l-1)break;for(let e=0;e<u.length;e++)switch(u.charAt(e)){case`<`:u.charAt(e+1)===`/`?o.pop():(n=!0,o.push(++i));break;case`>`:n=!1,r=!1;break;case`=`:r=!0;break}let d=o[o.length-1],f=Y(a,d,()=>[]),p,m,h;if(r){let n=/(\S+)="?([^"=]*)$/.exec(u);p=n[1],m=n[2];let r=/^([^">]*)("?)/.exec(e[c+1]);h=r[1],t=t.slice(0,-1*n[0].length),s=r[0].length}else s=0;let g={attributeName:p,attributeValuePre:m,attributeValuePost:h,expressionIndex:c};f.push(g),!n&&!r&&(t+=` `)}return{template:vt(t),elementsToBindings:a}}function Ot(e,t,n){for(let r=0;r<e.length;r++){let i=e[r],a={binding:i,targetNode:i.attributeName?t:t.firstChild,targetParentNode:void 0,currentExpression:void 0};n.push(a)}}function kt(e,t){let n=[],r;if(t.size===1&&(r=t.get(0)))Ot(r,e,n);else{let r=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT),i=e,a=-1;do{let e=t.get(++a);e&&Ot(e,i,n)}while(i=r.nextNode())}return n}function At(e){let{template:t,elementsToBindings:n}=Y(yt,e,()=>Dt(e)),r=t.cloneNode(!0).content.firstElementChild,i=kt(r,n);return function(e){return Et(e,i),r}}function jt(e){let t=Y(bt,e,()=>new Map),n=xt;function r(e,...r){return Y(Y(t,e,()=>new Map),n,()=>At(e))(r)}function i(e,t,r){return e.map((e,i)=>{let a=n;n=r(e);try{return t(e,i)}finally{n=a}})}return{map:i,html:r}}function Mt(e,t,n,r,i,a,o,s,c){let{labelWithSkin:l,titleForEmoji:u,unicodeWithSkin:d}=n,{html:f,map:p}=jt(t);function m(e,n,r){return p(e,(e,i)=>f`<button role="${n?`option`:`menuitem`}" aria-selected="${n?i===t.activeSearchItem:null}" aria-label="${l(e,t.currentSkinTone)}" title="${u(e)}" class="${`emoji`+(n&&i===t.activeSearchItem?` active`:``)+(e.unicode?``:` custom-emoji`)}" id="${`${r}-${e.id}`}" style="${e.unicode?null:`--custom-emoji-background: url(${JSON.stringify(e.url)})`}">${e.unicode?d(e,t.currentSkinTone):``}</button>`,e=>`${r}-${e.id}`)}let h=f`<section data-ref="rootElement" class="picker" aria-label="${t.i18n.regionLabel}" style="${t.pickerStyle||``}"><div class="pad-top"></div><div class="search-row"><div class="search-wrapper"><input id="search" class="search" type="search" role="combobox" enterkeyhint="search" placeholder="${t.i18n.searchLabel}" autocapitalize="none" autocomplete="off" spellcheck="true" aria-expanded="${!!(t.searchMode&&t.currentEmojis.length)}" aria-controls="search-results" aria-describedby="search-description" aria-autocomplete="list" aria-activedescendant="${t.activeSearchItemId?`emo-${t.activeSearchItemId}`:null}" data-ref="searchElement" data-on-input="onSearchInput" data-on-keydown="onSearchKeydown"><label class="sr-only" for="search">${t.i18n.searchLabel}</label> <span id="search-description" class="sr-only">${t.i18n.searchDescription}</span></div><div class="skintone-button-wrapper ${t.skinTonePickerExpandedAfterAnimation?`expanded`:``}"><button id="skintone-button" class="emoji ${t.skinTonePickerExpanded?`hide-focus`:``}" aria-label="${t.skinToneButtonLabel}" title="${t.skinToneButtonLabel}" aria-describedby="skintone-description" aria-haspopup="listbox" aria-expanded="${t.skinTonePickerExpanded}" aria-controls="skintone-list" data-on-click="onClickSkinToneButton">${t.skinToneButtonText||``}</button></div><span id="skintone-description" class="sr-only">${t.i18n.skinToneDescription}</span><div data-ref="skinToneDropdown" id="skintone-list" class="skintone-list hide-focus ${t.skinTonePickerExpanded?``:`hidden no-animate`}" style="transform:translateY(${t.skinTonePickerExpanded?0:`calc(-1 * var(--num-skintones) * var(--total-emoji-size))`})" role="listbox" aria-label="${t.i18n.skinTonesLabel}" aria-activedescendant="skintone-${t.activeSkinTone}" aria-hidden="${!t.skinTonePickerExpanded}" tabIndex="-1" data-on-focusout="onSkinToneOptionsFocusOut" data-on-click="onSkinToneOptionsClick" data-on-keydown="onSkinToneOptionsKeydown" data-on-keyup="onSkinToneOptionsKeyup">${p(t.skinTones,(e,n)=>f`<div id="skintone-${n}" class="emoji ${n===t.activeSkinTone?`active`:``}" aria-selected="${n===t.activeSkinTone}" role="option" title="${t.i18n.skinTones[n]}" aria-label="${t.i18n.skinTones[n]}">${e}</div>`,e=>e)}</div></div><div class="nav" role="tablist" style="grid-template-columns:repeat(${t.groups.length},1fr)" aria-label="${t.i18n.categoriesLabel}" data-on-keydown="onNavKeydown" data-on-click="onNavClick">${p(t.groups,e=>f`<button role="tab" class="nav-button" aria-controls="tab-${e.id}" aria-label="${t.i18n.categories[e.name]}" aria-selected="${!t.searchMode&&t.currentGroup.id===e.id}" title="${t.i18n.categories[e.name]}" data-group-id="${e.id}"><div class="nav-emoji emoji">${e.emoji}</div></button>`,e=>e.id)}</div><div class="indicator-wrapper"><div class="indicator" style="transform:translateX(${(t.isRtl?-1:1)*t.currentGroupIndex*100}%)"></div></div><div class="message ${t.message?``:`gone`}" role="alert" aria-live="polite">${t.message||``}</div><div data-ref="tabpanelElement" class="tabpanel ${!t.databaseLoaded||t.message?`gone`:``}" role="${t.searchMode?`region`:`tabpanel`}" aria-label="${t.searchMode?t.i18n.searchResultsLabel:t.i18n.categories[t.currentGroup.name]}" id="${t.searchMode?null:`tab-${t.currentGroup.id}`}" tabIndex="0" data-on-click="onEmojiClick"><div data-action="calculateEmojiGridStyle">${p(t.currentEmojisWithCategories,(e,n)=>f`<div><div id="menu-label-${n}" class="category ${t.currentEmojisWithCategories.length===1&&t.currentEmojisWithCategories[0].category===``?`gone`:``}" aria-hidden="true">${t.searchMode?t.i18n.searchResultsLabel:e.category?e.category:t.currentEmojisWithCategories.length>1?t.i18n.categories.custom:t.i18n.categories[t.currentGroup.name]}</div><div class="emoji-menu ${n!==0&&!t.searchMode&&t.currentGroup.id===-1?`visibility-auto`:``}" style="${`--num-rows: ${Math.ceil(e.emojis.length/t.numColumns)}`}" data-action="updateOnIntersection" role="${t.searchMode?`listbox`:`menu`}" aria-labelledby="menu-label-${n}" id="${t.searchMode?`search-results`:null}">${m(e.emojis,t.searchMode,`emo`)}</div></div>`,e=>e.category)}</div></div><div class="favorites onscreen emoji-menu ${t.message?`gone`:``}" role="menu" aria-label="${t.i18n.favoritesLabel}" data-on-click="onEmojiClick">${m(t.currentFavorites,!1,`fav`)}</div><button data-ref="baselineEmoji" aria-hidden="true" tabindex="-1" class="abs-pos hidden emoji baseline-emoji">😀</button></section>`,g=(t,n)=>{for(let r of e.querySelectorAll(`[${t}]`))n(r,r.getAttribute(t))};if(c){e.appendChild(h);for(let e of[`click`,`focusout`,`input`,`keydown`,`keyup`])g(`data-on-${e}`,(t,n)=>{t.addEventListener(e,r[n])});g(`data-ref`,(e,t)=>{a[t]=e}),o.addEventListener(`abort`,()=>{e.removeChild(h)})}g(`data-action`,(e,t)=>{let n=s.get(t);n||s.set(t,n=new WeakSet),n.has(e)||(n.add(e),i[t](e))})}var X=typeof queueMicrotask==`function`?queueMicrotask:e=>Promise.resolve().then(e);function Nt(e){let t=!1,n,r=new Map,i=new Set,a,o=()=>{if(t)return;let e=[...i];i.clear();try{for(let t of e)t()}finally{a=!1,i.size&&(a=!0,X(o))}},s=new Proxy({},{get(e,t){if(n){let e=r.get(t);e||(e=new Set,r.set(t,e)),e.add(n)}return e[t]},set(e,t,n){if(e[t]!==n){e[t]=n;let s=r.get(t);if(s){for(let e of s)i.add(e);a||(a=!0,X(o))}}return!0}});return e.addEventListener(`abort`,()=>{t=!0}),{state:s,createEffect:e=>{let t=()=>{let r=n;n=t;try{return e()}finally{n=r}};return t()}}}function Z(e,t,n){if(e.length!==t.length)return!1;for(let r=0;r<e.length;r++)if(!n(e[r],t[r]))return!1;return!0}var Pt=new WeakMap;function Ft(e,t,n){{let r=e.closest(`.tabpanel`),i=Pt.get(r);i||(i=new IntersectionObserver(n,{root:r,rootMargin:`50% 0px 50% 0px`,threshold:0}),Pt.set(r,i),t.addEventListener(`abort`,()=>{i.disconnect()})),i.observe(e)}}var It=[],{assign:Q}=Object;function Lt(e,t){let n={},r=new AbortController,i=r.signal,{state:a,createEffect:o}=Nt(i),s=new Map;Q(a,{skinToneEmoji:void 0,i18n:void 0,database:void 0,customEmoji:void 0,customCategorySorting:void 0,emojiVersion:void 0}),Q(a,t),Q(a,{initialLoad:!0,currentEmojis:[],currentEmojisWithCategories:[],rawSearchText:``,searchText:``,searchMode:!1,activeSearchItem:-1,message:void 0,skinTonePickerExpanded:!1,skinTonePickerExpandedAfterAnimation:!1,currentSkinTone:0,activeSkinTone:0,skinToneButtonText:void 0,pickerStyle:void 0,skinToneButtonLabel:``,skinTones:[],currentFavorites:[],defaultFavoriteEmojis:void 0,numColumns:Ke,isRtl:!1,currentGroupIndex:0,groups:V,databaseLoaded:!1,activeSearchItemId:void 0}),o(()=>{a.currentGroup!==a.groups[a.currentGroupIndex]&&(a.currentGroup=a.groups[a.currentGroupIndex])});let c=t=>{e.getElementById(t).focus()},l=t=>e.getElementById(`emo-${t.id}`),u=(e,t)=>{n.rootElement.dispatchEvent(new CustomEvent(e,{detail:t,bubbles:!0,composed:!0}))},d=(e,t)=>e.id===t.id,f=(e,t)=>{let{category:n,emojis:r}=e,{category:i,emojis:a}=t;return n===i?Z(r,a,d):!1},p=e=>{Z(a.currentEmojis,e,d)||(a.currentEmojis=e)},m=e=>{a.searchMode!==e&&(a.searchMode=e)},h=e=>{Z(a.currentEmojisWithCategories,e,f)||(a.currentEmojisWithCategories=e)},g=(e,t)=>t&&e.skins&&e.skins[t]||e.unicode,_={labelWithSkin:(e,t)=>ht([e.name||g(e,t),e.annotation,...e.shortcodes||It].filter(Boolean)).join(`, `),titleForEmoji:e=>e.annotation||(e.shortcodes||It).join(`, `),unicodeWithSkin:g},v={onClickSkinToneButton:j,onEmojiClick:oe,onNavClick:D,onNavKeydown:O,onSearchKeydown:ie,onSkinToneOptionsClick:se,onSkinToneOptionsFocusOut:N,onSkinToneOptionsKeydown:ce,onSkinToneOptionsKeyup:M,onSearchInput:P},y={calculateEmojiGridStyle:ee,updateOnIntersection:te},b=!0;o(()=>{Mt(e,a,_,v,y,n,i,s,b),b=!1}),a.emojiVersion||H().then(e=>{e||(a.message=a.i18n.emojiUnsupportedMessage)}),o(()=>{async function e(){let e=!1,t=setTimeout(()=>{e=!0,a.message=a.i18n.loadingMessage},We);try{await a.database.ready(),a.databaseLoaded=!0}catch(e){console.error(e),a.message=a.i18n.networkErrorMessage}finally{clearTimeout(t),e&&(e=!1,a.message=``)}}a.database&&e()}),o(()=>{a.pickerStyle=`
|
|
2
|
+
--num-groups: ${a.groups.length};
|
|
3
|
+
--indicator-opacity: ${+!a.searchMode};
|
|
4
|
+
--num-skintones: ${Be};`}),o(()=>{a.customEmoji&&a.database&&x()}),o(()=>{a.customEmoji&&a.customEmoji.length?a.groups!==B&&(a.groups=B):a.groups!==V&&(a.currentGroupIndex&&a.currentGroupIndex--,a.groups=V)}),o(()=>{async function e(){a.databaseLoaded&&(a.currentSkinTone=await a.database.getPreferredSkinTone())}e()}),o(()=>{a.skinTones=Array(Be).fill().map((e,t)=>ot(a.skinToneEmoji,t))}),o(()=>{a.skinToneButtonText=a.skinTones[a.currentSkinTone]}),o(()=>{a.skinToneButtonLabel=a.i18n.skinToneLabel.replace(`{skinTone}`,a.i18n.skinTones[a.currentSkinTone])}),o(()=>{async function e(){let{database:e}=a;a.defaultFavoriteEmojis=(await Promise.all(qe.map(t=>e.getEmojiByUnicodeOrName(t)))).filter(Boolean)}a.databaseLoaded&&e()});function x(){let{customEmoji:e,database:t}=a,n=e||It;t.customEmoji!==n&&(t.customEmoji=n)}o(()=>{async function e(){x();let{database:e,defaultFavoriteEmojis:t,numColumns:n}=a;a.currentFavorites=await T(st([...await e.getTopFavoriteEmoji(n),...t],e=>e.unicode||e.name).slice(0,n))}a.databaseLoaded&&a.defaultFavoriteEmojis&&e()});function ee(e){ut(e,i,()=>{{let e=getComputedStyle(n.rootElement),t=parseInt(e.getPropertyValue(`--num-columns`),10),r=e.getPropertyValue(`direction`)===`rtl`;a.numColumns=t,a.isRtl=r}})}function te(e){Ft(e,i,e=>{for(let{target:t,isIntersecting:n}of e)t.classList.toggle(`onscreen`,n)})}o(()=>{async function e(){let{searchText:e,currentGroup:t,databaseLoaded:n,customEmoji:r}=a;if(!n)a.currentEmojis=[],a.searchMode=!1;else if(e.length>=ze){let t=await re(e);a.searchText===e&&(p(t),m(!0))}else{let{id:e}=t;if(e!==-1||r&&r.length){let t=await E(e);a.currentGroup.id===e&&(p(t),m(!1))}}}e()});let S=()=>{K(()=>gt(n.tabpanelElement))};o(()=>{let{currentEmojis:e,emojiVersion:t}=a,n=e.filter(e=>e.unicode).filter(e=>He(e)&&!U.has(e.unicode));!t&&n.length?(p(e),K(()=>ne(n))):(p(t?e:e.filter(C)),S())});function ne(e){mt(e,n.baselineEmoji,l)?S():a.currentEmojis=[...a.currentEmojis]}function C(e){return!e.unicode||!He(e)||U.get(e.unicode)}async function w(e){let t=a.emojiVersion||await H();return e.filter(({version:e})=>!e||e<=t)}async function T(e){return ct(e,a.emojiVersion||await H())}async function E(e){return T(await w(e===-1?a.customEmoji:await a.database.getEmojiByGroup(e)))}async function re(e){return T(await w(await a.database.getEmojiBySearchQuery(e)))}o(()=>{}),o(()=>{function e(){let{searchMode:e,currentEmojis:t}=a;if(e)return[{category:``,emojis:t}];let n=new Map;for(let e of t){let t=e.category||``,r=n.get(t);r||(r=[],n.set(t,r)),r.push(e)}return[...n.entries()].map(([e,t])=>({category:e,emojis:t})).sort((e,t)=>a.customCategorySorting(e.category,t.category))}h(e())}),o(()=>{a.activeSearchItemId=a.activeSearchItem!==-1&&a.currentEmojis[a.activeSearchItem].id}),o(()=>{let{rawSearchText:e}=a;Ve(()=>{a.searchText=(e||``).trim(),a.activeSearchItem=-1})});function ie(e){if(!a.searchMode||!a.currentEmojis.length)return;let t=t=>{W(e),a.activeSearchItem=G(t,a.activeSearchItem,a.currentEmojis)};switch(e.key){case`ArrowDown`:return t(!1);case`ArrowUp`:return t(!0);case`Enter`:if(a.activeSearchItem===-1)a.activeSearchItem=0;else return W(e),k(a.currentEmojis[a.activeSearchItem].id)}}function D(e){let{target:t}=e,r=t.closest(`.nav-button`);if(!r)return;let i=parseInt(r.dataset.groupId,10);n.searchElement.value=``,a.rawSearchText=``,a.searchText=``,a.activeSearchItem=-1,a.currentGroupIndex=a.groups.findIndex(e=>e.id===i)}function O(e){let{target:t,key:n}=e,r=t=>{t&&(W(e),t.focus())};switch(n){case`ArrowLeft`:return r(t.previousElementSibling);case`ArrowRight`:return r(t.nextElementSibling);case`Home`:return r(t.parentElement.firstElementChild);case`End`:return r(t.parentElement.lastElementChild)}}async function ae(e){let t=await a.database.getEmojiByUnicodeOrName(e),n=[...a.currentEmojis,...a.currentFavorites].find(t=>t.id===e),r=n.unicode&&g(n,a.currentSkinTone);return await a.database.incrementFavoriteEmojiCount(e),{emoji:t,skinTone:a.currentSkinTone,...r&&{unicode:r},...n.name&&{name:n.name}}}async function k(e){let t=ae(e);u(`emoji-click-sync`,t),u(`emoji-click`,await t)}function oe(e){let{target:t}=e;t.classList.contains(`emoji`)&&(W(e),k(t.id.substring(4)))}function A(e){a.currentSkinTone=e,a.skinTonePickerExpanded=!1,c(`skintone-button`),u(`skin-tone-change`,{skinTone:e}),a.database.setPreferredSkinTone(e)}function se(e){let{target:{id:t}}=e,n=t&&t.match(/^skintone-(\d)/);n&&(W(e),A(parseInt(n[1],10)))}function j(e){a.skinTonePickerExpanded=!a.skinTonePickerExpanded,a.activeSkinTone=a.currentSkinTone,a.skinTonePickerExpanded&&(W(e),K(()=>c(`skintone-list`)))}o(()=>{a.skinTonePickerExpanded?n.skinToneDropdown.addEventListener(`transitionend`,()=>{a.skinTonePickerExpandedAfterAnimation=!0},{once:!0}):a.skinTonePickerExpandedAfterAnimation=!1});function ce(e){if(!a.skinTonePickerExpanded)return;let t=async t=>{W(e),a.activeSkinTone=t};switch(e.key){case`ArrowUp`:return t(G(!0,a.activeSkinTone,a.skinTones));case`ArrowDown`:return t(G(!1,a.activeSkinTone,a.skinTones));case`Home`:return t(0);case`End`:return t(a.skinTones.length-1);case`Enter`:return W(e),A(a.activeSkinTone);case`Escape`:return W(e),a.skinTonePickerExpanded=!1,c(`skintone-button`)}}function M(e){if(a.skinTonePickerExpanded)switch(e.key){case` `:return W(e),A(a.activeSkinTone)}}async function N(e){let{relatedTarget:t}=e;(!t||t.id!==`skintone-list`)&&(a.skinTonePickerExpanded=!1)}function P(e){a.rawSearchText=e.target.value}return{$set(e){Q(a,e)},$destroy(){r.abort()}}}var Rt=`https://cdn.jsdelivr.net/npm/emoji-picker-element-data@^1/en/emojibase/data.json`,zt=`en`,Bt={categoriesLabel:`Categories`,emojiUnsupportedMessage:`Your browser does not support color emoji.`,favoritesLabel:`Favorites`,loadingMessage:`Loading…`,networkErrorMessage:`Could not load emoji.`,regionLabel:`Emoji picker`,searchDescription:`When search results are available, press up or down to select and enter to choose.`,searchLabel:`Search`,searchResultsLabel:`Search results`,skinToneDescription:`When expanded, press up or down to select and enter to choose.`,skinToneLabel:`Choose a skin tone (currently {skinTone})`,skinTonesLabel:`Skin tones`,skinTones:[`Default`,`Light`,`Medium-Light`,`Medium`,`Medium-Dark`,`Dark`],categories:{custom:`Custom`,"smileys-emotion":`Smileys and emoticons`,"people-body":`People and body`,"animals-nature":`Animals and nature`,"food-drink":`Food and drink`,"travel-places":`Travel and places`,activities:`Activities`,objects:`Objects`,symbols:`Symbols`,flags:`Flags`}},Vt=`:host{--emoji-size:1.375rem;--emoji-padding:0.5rem;--category-emoji-size:var(--emoji-size);--category-emoji-padding:var(--emoji-padding);--indicator-height:3px;--input-border-radius:0.5rem;--input-border-size:1px;--input-font-size:1rem;--input-line-height:1.5;--input-padding:0.25rem;--num-columns:8;--outline-size:2px;--border-size:1px;--border-radius:0;--skintone-border-radius:1rem;--category-font-size:1rem;display:flex;width:min-content;height:400px}:host,:host(.light){color-scheme:light;--background:#fff;--border-color:#e0e0e0;--indicator-color:#385ac1;--input-border-color:#999;--input-font-color:#111;--input-placeholder-color:#999;--outline-color:#999;--category-font-color:#111;--button-active-background:#e6e6e6;--button-hover-background:#d9d9d9}:host(.dark){color-scheme:dark;--background:#222;--border-color:#444;--indicator-color:#5373ec;--input-border-color:#ccc;--input-font-color:#efefef;--input-placeholder-color:#ccc;--outline-color:#fff;--category-font-color:#efefef;--button-active-background:#555555;--button-hover-background:#484848}@media (prefers-color-scheme:dark){:host{color-scheme:dark;--background:#222;--border-color:#444;--indicator-color:#5373ec;--input-border-color:#ccc;--input-font-color:#efefef;--input-placeholder-color:#ccc;--outline-color:#fff;--category-font-color:#efefef;--button-active-background:#555555;--button-hover-background:#484848}}:host([hidden]){display:none}button{margin:0;padding:0;border:0;background:0 0;box-shadow:none;-webkit-tap-highlight-color:transparent}button::-moz-focus-inner{border:0}input{padding:0;margin:0;line-height:1.15;font-family:inherit}input[type=search]{-webkit-appearance:none}:focus{outline:var(--outline-color) solid var(--outline-size);outline-offset:calc(-1*var(--outline-size))}:host([data-js-focus-visible]) :focus:not([data-focus-visible-added]){outline:0}:focus:not(:focus-visible){outline:0}.hide-focus{outline:0}*{box-sizing:border-box}.picker{contain:content;display:flex;flex-direction:column;background:var(--background);border:var(--border-size) solid var(--border-color);border-radius:var(--border-radius);width:100%;height:100%;overflow:hidden;--total-emoji-size:calc(var(--emoji-size) + (2 * var(--emoji-padding)));--total-category-emoji-size:calc(var(--category-emoji-size) + (2 * var(--category-emoji-padding)))}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.hidden{opacity:0;pointer-events:none}.abs-pos{position:absolute;left:0;top:0}.gone{display:none!important}.skintone-button-wrapper,.skintone-list{background:var(--background);z-index:3}.skintone-button-wrapper.expanded{z-index:1}.skintone-list{position:absolute;inset-inline-end:0;top:0;z-index:2;overflow:visible;border-bottom:var(--border-size) solid var(--border-color);border-radius:0 0 var(--skintone-border-radius) var(--skintone-border-radius);will-change:transform;transition:transform .2s ease-in-out;transform-origin:center 0}@media (prefers-reduced-motion:reduce){.skintone-list{transition-duration:.001s}}@supports not (inset-inline-end:0){.skintone-list{right:0}}.skintone-list.no-animate{transition:none}.tabpanel{overflow-y:auto;scrollbar-gutter:stable;-webkit-overflow-scrolling:touch;will-change:transform;min-height:0;flex:1;contain:content}.emoji-menu{display:grid;grid-template-columns:repeat(var(--num-columns),var(--total-emoji-size));justify-content:space-around;align-items:flex-start;width:100%}.emoji-menu.visibility-auto{content-visibility:auto;contain-intrinsic-size:calc(var(--num-columns)*var(--total-emoji-size)) calc(var(--num-rows)*var(--total-emoji-size))}.category{padding:var(--emoji-padding);font-size:var(--category-font-size);color:var(--category-font-color)}.emoji,button.emoji{font-size:var(--emoji-size);display:flex;align-items:center;justify-content:center;border-radius:100%;height:var(--total-emoji-size);width:var(--total-emoji-size);line-height:1;overflow:hidden;font-family:var(--emoji-font-family);cursor:pointer}@media (hover:hover) and (pointer:fine){.emoji:hover,button.emoji:hover{background:var(--button-hover-background)}}.emoji.active,.emoji:active,button.emoji.active,button.emoji:active{background:var(--button-active-background)}.onscreen .custom-emoji::after{content:"";width:var(--emoji-size);height:var(--emoji-size);background-repeat:no-repeat;background-position:center center;background-size:contain;background-image:var(--custom-emoji-background)}.nav,.nav-button{align-items:center}.nav{display:grid;justify-content:space-between;contain:content}.nav-button{display:flex;justify-content:center}.nav-emoji{font-size:var(--category-emoji-size);width:var(--total-category-emoji-size);height:var(--total-category-emoji-size)}.indicator-wrapper{display:flex;border-bottom:1px solid var(--border-color)}.indicator{width:calc(100%/var(--num-groups));height:var(--indicator-height);opacity:var(--indicator-opacity);background-color:var(--indicator-color);will-change:transform,opacity;transition:opacity .1s linear,transform .25s ease-in-out}@media (prefers-reduced-motion:reduce){.indicator{will-change:opacity;transition:opacity .1s linear}}.pad-top,input.search{background:var(--background);width:100%}.pad-top{height:var(--emoji-padding);z-index:3}.search-row{display:flex;align-items:center;position:relative;padding-inline-start:var(--emoji-padding);padding-bottom:var(--emoji-padding)}.search-wrapper{flex:1;min-width:0}input.search{padding:var(--input-padding);border-radius:var(--input-border-radius);border:var(--input-border-size) solid var(--input-border-color);color:var(--input-font-color);font-size:var(--input-font-size);line-height:var(--input-line-height)}input.search::placeholder{color:var(--input-placeholder-color)}.favorites{overflow-y:auto;scrollbar-gutter:stable;display:flex;flex-direction:row;border-top:var(--border-size) solid var(--border-color);contain:content}.message{padding:var(--emoji-padding)}`,Ht=[`customEmoji`,`customCategorySorting`,`database`,`dataSource`,`i18n`,`locale`,`skinToneEmoji`,`emojiVersion`],Ut=`:host{--emoji-font-family:${Je}}`,$=class extends HTMLElement{constructor(e){super(),this.attachShadow({mode:`open`});let t=document.createElement(`style`);t.textContent=Vt+Ut,this.shadowRoot.appendChild(t),this._ctx={locale:zt,dataSource:Rt,skinToneEmoji:Ge,customCategorySorting:Ye,customEmoji:null,i18n:Bt,emojiVersion:null,...e};for(let e of Ht)e!==`database`&&Object.prototype.hasOwnProperty.call(this,e)&&(this._ctx[e]=this[e],delete this[e]);this._dbFlush()}connectedCallback(){Gt(this),this._cmp||=Lt(this.shadowRoot,this._ctx)}disconnectedCallback(){Gt(this),X(()=>{if(!this.isConnected&&this._cmp){this._cmp.$destroy(),this._cmp=void 0;let{database:e}=this._ctx;e.close().catch(e=>console.error(e))}})}static get observedAttributes(){return[`locale`,`data-source`,`skin-tone-emoji`,`emoji-version`]}attributeChangedCallback(e,t,n){this._set(e.replace(/-([a-z])/g,(e,t)=>t.toUpperCase()),e===`emoji-version`?parseFloat(n):n)}_set(e,t){this._ctx[e]=t,this._cmp&&this._cmp.$set({[e]:t}),[`locale`,`dataSource`].includes(e)&&this._dbFlush()}_dbCreate(){let{locale:e,dataSource:t,database:n}=this._ctx;(!n||n.locale!==e||n.dataSource!==t)&&this._set(`database`,new Re({locale:e,dataSource:t}))}_dbFlush(){X(()=>this._dbCreate())}},Wt={};for(let e of Ht)Wt[e]={get(){return e===`database`&&this._dbCreate(),this._ctx[e]},set(t){if(e===`database`)throw Error(`database is read-only`);this._set(e,t)}};Object.defineProperties($.prototype,Wt);function Gt(e){e instanceof $||Object.setPrototypeOf(e,customElements.get(e.tagName.toLowerCase()).prototype)}customElements.get(`emoji-picker`)||customElements.define(`emoji-picker`,$);export{$ as default};
|
|
5
|
+
//# sourceMappingURL=picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"picker.js","names":["DEFAULT_DATA_SOURCE","DEFAULT_LOCALE","uniqBy","MIN_SEARCH_TEXT_LENGTH"],"sources":["../../../../node_modules/.pnpm/emoji-picker-element@1.29.1/node_modules/emoji-picker-element/database.js","../../../../node_modules/.pnpm/emoji-picker-element@1.29.1/node_modules/emoji-picker-element/picker.js"],"sourcesContent":["function assertNonEmptyString (str) {\n if (typeof str !== 'string' || !str) {\n throw new Error('expected a non-empty string, got: ' + str)\n }\n}\n\nfunction assertNumber (number) {\n if (typeof number !== 'number') {\n throw new Error('expected a number, got: ' + number)\n }\n}\n\nconst DB_VERSION_CURRENT = 1;\nconst DB_VERSION_INITIAL = 1;\nconst STORE_EMOJI = 'emoji';\nconst STORE_KEYVALUE = 'keyvalue';\nconst STORE_FAVORITES = 'favorites';\nconst FIELD_TOKENS = 'tokens';\nconst INDEX_TOKENS = 'tokens';\nconst FIELD_UNICODE = 'unicode';\nconst INDEX_COUNT = 'count';\nconst FIELD_GROUP = 'group';\nconst FIELD_ORDER = 'order';\nconst INDEX_GROUP_AND_ORDER = 'group-order';\nconst KEY_ETAG = 'eTag';\nconst KEY_URL = 'url';\nconst KEY_PREFERRED_SKINTONE = 'skinTone';\nconst MODE_READONLY = 'readonly';\nconst MODE_READWRITE = 'readwrite';\nconst INDEX_SKIN_UNICODE = 'skinUnicodes';\nconst FIELD_SKIN_UNICODE = 'skinUnicodes';\n\nconst DEFAULT_DATA_SOURCE = 'https://cdn.jsdelivr.net/npm/emoji-picker-element-data@^1/en/emojibase/data.json';\nconst DEFAULT_LOCALE = 'en';\n\n// like lodash's uniqBy but much smaller\nfunction uniqBy (arr, func) {\n const set = new Set();\n const res = [];\n for (const item of arr) {\n const key = func(item);\n if (!set.has(key)) {\n set.add(key);\n res.push(item);\n }\n }\n return res\n}\n\nfunction uniqEmoji (emojis) {\n return uniqBy(emojis, _ => _.unicode)\n}\n\nfunction initialMigration (db) {\n function createObjectStore (name, keyPath, indexes) {\n const store = keyPath\n ? db.createObjectStore(name, { keyPath })\n : db.createObjectStore(name);\n if (indexes) {\n for (const [indexName, [keyPath, multiEntry]] of Object.entries(indexes)) {\n store.createIndex(indexName, keyPath, { multiEntry });\n }\n }\n return store\n }\n\n createObjectStore(STORE_KEYVALUE);\n createObjectStore(STORE_EMOJI, /* keyPath */ FIELD_UNICODE, {\n [INDEX_TOKENS]: [FIELD_TOKENS, /* multiEntry */ true],\n [INDEX_GROUP_AND_ORDER]: [[FIELD_GROUP, FIELD_ORDER]],\n [INDEX_SKIN_UNICODE]: [FIELD_SKIN_UNICODE, /* multiEntry */ true]\n });\n createObjectStore(STORE_FAVORITES, undefined, {\n [INDEX_COUNT]: ['']\n });\n}\n\nconst openIndexedDBRequests = {};\nconst databaseCache = {};\nconst onCloseListeners = {};\n\nfunction handleOpenOrDeleteReq (resolve, reject, req) {\n // These things are almost impossible to test with fakeIndexedDB sadly\n /* istanbul ignore next */\n req.onerror = () => reject(req.error);\n /* istanbul ignore next */\n req.onblocked = () => reject(new Error('IDB blocked'));\n req.onsuccess = () => resolve(req.result);\n}\n\nasync function createDatabase (dbName) {\n const db = await new Promise((resolve, reject) => {\n const req = indexedDB.open(dbName, DB_VERSION_CURRENT);\n openIndexedDBRequests[dbName] = req;\n req.onupgradeneeded = e => {\n // Technically there is only one version, so we don't need this `if` check\n // But if an old version of the JS is in another browser tab\n // and it gets upgraded in the future and we have a new DB version, well...\n // better safe than sorry.\n /* istanbul ignore else */\n if (e.oldVersion < DB_VERSION_INITIAL) {\n initialMigration(req.result);\n }\n };\n handleOpenOrDeleteReq(resolve, reject, req);\n });\n // Handle abnormal closes, e.g. \"delete database\" in chrome dev tools.\n // No need for removeEventListener, because once the DB can no longer\n // fire \"close\" events, it will auto-GC.\n db.onclose = () => closeDatabase(dbName);\n return db\n}\n\nfunction openDatabase (dbName) {\n if (!databaseCache[dbName]) {\n databaseCache[dbName] = createDatabase(dbName);\n }\n return databaseCache[dbName]\n}\n\nfunction dbPromise (db, storeName, readOnlyOrReadWrite, cb) {\n return new Promise((resolve, reject) => {\n // Use relaxed durability because neither the emoji data nor the favorites/preferred skin tone\n // are really irreplaceable data. IndexedDB is just a cache in this case.\n const txn = db.transaction(storeName, readOnlyOrReadWrite, { durability: 'relaxed' });\n const store = typeof storeName === 'string'\n ? txn.objectStore(storeName)\n : storeName.map(name => txn.objectStore(name));\n let res;\n cb(store, txn, (result) => {\n res = result;\n });\n\n txn.oncomplete = () => resolve(res);\n /* istanbul ignore next */\n txn.onerror = () => reject(txn.error);\n })\n}\n\nfunction closeDatabase (dbName) {\n // close any open requests\n const req = openIndexedDBRequests[dbName];\n const db = req && req.result;\n if (db) {\n db.close();\n const listeners = onCloseListeners[dbName];\n /* istanbul ignore else */\n if (listeners) {\n for (const listener of listeners) {\n listener();\n }\n }\n }\n delete openIndexedDBRequests[dbName];\n delete databaseCache[dbName];\n delete onCloseListeners[dbName];\n}\n\nfunction deleteDatabase (dbName) {\n return new Promise((resolve, reject) => {\n // close any open requests\n closeDatabase(dbName);\n const req = indexedDB.deleteDatabase(dbName);\n handleOpenOrDeleteReq(resolve, reject, req);\n })\n}\n\n// The \"close\" event occurs during an abnormal shutdown, e.g. a user clearing their browser data.\n// However, it doesn't occur with the normal \"close\" event, so we handle that separately.\n// https://www.w3.org/TR/IndexedDB/#close-a-database-connection\nfunction addOnCloseListener (dbName, listener) {\n let listeners = onCloseListeners[dbName];\n if (!listeners) {\n listeners = onCloseListeners[dbName] = [];\n }\n listeners.push(listener);\n}\n\n// list of emoticons that don't match a simple \\W+ regex\n// extracted using:\n// require('emoji-picker-element-data/en/emojibase/data.json').map(_ => _.emoticon).filter(Boolean).filter(_ => !/^\\W+$/.test(_))\nconst irregularEmoticons = new Set([\n ':D', 'XD', \":'D\", 'O:)',\n ':X', ':P', ';P', 'XP',\n ':L', ':Z', ':j', '8D',\n 'XO', '8)', ':B', ':O',\n ':S', \":'o\", 'Dx', 'X(',\n 'D:', ':C', '>0)', ':3',\n '</3', '<3', '\\\\M/', ':E',\n '8#'\n]);\n\nfunction extractTokens (str) {\n return str\n .split(/[\\s_]+/)\n .map(word => {\n if (!word.match(/\\w/) || irregularEmoticons.has(word)) {\n // for pure emoticons like :) or :-), just leave them as-is\n return word.toLowerCase()\n }\n\n return word\n .replace(/[)(:,]/g, '')\n .replace(/’/g, \"'\")\n .toLowerCase()\n }).filter(Boolean)\n}\n\nconst MIN_SEARCH_TEXT_LENGTH = 2;\n\n// This is an extra step in addition to extractTokens(). The difference here is that we expect\n// the input to have already been run through extractTokens(). This is useful for cases like\n// emoticons, where we don't want to do any tokenization (because it makes no sense to split up\n// \">:)\" by the colon) but we do want to lowercase it to have consistent search results, so that\n// the user can type ':P' or ':p' and still get the same result.\nfunction normalizeTokens (str) {\n return str\n .filter(Boolean)\n .map(_ => _.toLowerCase())\n .filter(_ => _.length >= MIN_SEARCH_TEXT_LENGTH)\n}\n\n// Transform emoji data for storage in IDB\nfunction transformEmojiData (emojiData) {\n const res = emojiData.map(({ annotation, emoticon, group, order, shortcodes, skins, tags, emoji, version }) => {\n const tokens = [...new Set(\n normalizeTokens([\n ...(shortcodes || []).map(extractTokens).flat(),\n ...(tags || []).map(extractTokens).flat(),\n ...extractTokens(annotation),\n emoticon\n ])\n )].sort();\n const res = {\n annotation,\n group,\n order,\n tags,\n tokens,\n unicode: emoji,\n version\n };\n if (emoticon) {\n res.emoticon = emoticon;\n }\n if (shortcodes) {\n res.shortcodes = shortcodes;\n }\n if (skins) {\n res.skinTones = [];\n res.skinUnicodes = [];\n res.skinVersions = [];\n for (const { tone, emoji, version } of skins) {\n res.skinTones.push(tone);\n res.skinUnicodes.push(emoji);\n res.skinVersions.push(version);\n }\n }\n return res\n });\n return res\n}\n\n// helper functions that help compress the code better\n\nfunction callStore (store, method, key, cb) {\n store[method](key).onsuccess = e => (cb && cb(e.target.result));\n}\n\nfunction getIDB (store, key, cb) {\n callStore(store, 'get', key, cb);\n}\n\nfunction getAllIDB (store, key, cb) {\n callStore(store, 'getAll', key, cb);\n}\n\nfunction commit (txn) {\n /* istanbul ignore else */\n if (txn.commit) {\n txn.commit();\n }\n}\n\n// like lodash's minBy\nfunction minBy (array, func) {\n let minItem = array[0];\n for (let i = 1; i < array.length; i++) {\n const item = array[i];\n if (func(minItem) > func(item)) {\n minItem = item;\n }\n }\n return minItem\n}\n\n// return an array of results representing all items that are found in each one of the arrays\n//\n\nfunction findCommonMembers (arrays, uniqByFunc) {\n const shortestArray = minBy(arrays, _ => _.length);\n const results = [];\n for (const item of shortestArray) {\n // if this item is included in every array in the intermediate results, add it to the final results\n if (!arrays.some(array => array.findIndex(_ => uniqByFunc(_) === uniqByFunc(item)) === -1)) {\n results.push(item);\n }\n }\n return results\n}\n\nasync function isEmpty (db) {\n return !(await get(db, STORE_KEYVALUE, KEY_URL))\n}\n\nasync function hasData (db, url, eTag) {\n const [oldETag, oldUrl] = await Promise.all([KEY_ETAG, KEY_URL]\n .map(key => get(db, STORE_KEYVALUE, key)));\n return (oldETag === eTag && oldUrl === url)\n}\n\nasync function doFullDatabaseScanForSingleResult (db, predicate) {\n // This batching algorithm is just a perf improvement over a basic\n // cursor. The BATCH_SIZE is an estimate of what would give the best\n // perf for doing a full DB scan (worst case).\n //\n // Mini-benchmark for determining the best batch size:\n //\n // PERF=1 pnpm build:rollup && pnpm test:adhoc\n //\n // (async () => {\n // performance.mark('start')\n // await $('emoji-picker').database.getEmojiByShortcode('doesnotexist')\n // performance.measure('total', 'start')\n // console.log(performance.getEntriesByName('total').slice(-1)[0].duration)\n // })()\n const BATCH_SIZE = 50; // Typically around 150ms for 6x slowdown in Chrome for above benchmark\n return dbPromise(db, STORE_EMOJI, MODE_READONLY, (emojiStore, txn, cb) => {\n let lastKey;\n\n const processNextBatch = () => {\n emojiStore.getAll(lastKey && IDBKeyRange.lowerBound(lastKey, true), BATCH_SIZE).onsuccess = e => {\n const results = e.target.result;\n for (const result of results) {\n lastKey = result.unicode;\n if (predicate(result)) {\n return cb(result)\n }\n }\n if (results.length < BATCH_SIZE) {\n return cb()\n }\n processNextBatch();\n };\n };\n processNextBatch();\n })\n}\n\nasync function loadData (db, emojiData, url, eTag) {\n try {\n const transformedData = transformEmojiData(emojiData);\n await dbPromise(db, [STORE_EMOJI, STORE_KEYVALUE], MODE_READWRITE, ([emojiStore, metaStore], txn) => {\n let oldETag;\n let oldUrl;\n let todo = 0;\n\n function checkFetched () {\n if (++todo === 2) { // 2 requests made\n onFetched();\n }\n }\n\n function onFetched () {\n if (oldETag === eTag && oldUrl === url) {\n // check again within the transaction to guard against concurrency, e.g. multiple browser tabs\n return\n }\n // delete old data\n emojiStore.clear();\n // insert new data\n for (const data of transformedData) {\n emojiStore.put(data);\n }\n metaStore.put(eTag, KEY_ETAG);\n metaStore.put(url, KEY_URL);\n commit(txn);\n }\n\n getIDB(metaStore, KEY_ETAG, result => {\n oldETag = result;\n checkFetched();\n });\n\n getIDB(metaStore, KEY_URL, result => {\n oldUrl = result;\n checkFetched();\n });\n });\n } finally {\n }\n}\n\nasync function getEmojiByGroup (db, group) {\n return dbPromise(db, STORE_EMOJI, MODE_READONLY, (emojiStore, txn, cb) => {\n const range = IDBKeyRange.bound([group, 0], [group + 1, 0], false, true);\n getAllIDB(emojiStore.index(INDEX_GROUP_AND_ORDER), range, cb);\n })\n}\n\nasync function getEmojiBySearchQuery (db, query) {\n const tokens = normalizeTokens(extractTokens(query));\n\n if (!tokens.length) {\n return []\n }\n\n return dbPromise(db, STORE_EMOJI, MODE_READONLY, (emojiStore, txn, cb) => {\n // get all results that contain all tokens (i.e. an AND query)\n const intermediateResults = [];\n\n const checkDone = () => {\n if (intermediateResults.length === tokens.length) {\n onDone();\n }\n };\n\n const onDone = () => {\n const results = findCommonMembers(intermediateResults, _ => _.unicode);\n cb(results.sort((a, b) => a.order < b.order ? -1 : 1));\n };\n\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n const range = i === tokens.length - 1\n ? IDBKeyRange.bound(token, token + '\\uffff', false, true) // treat last token as a prefix search\n : IDBKeyRange.only(token); // treat all other tokens as an exact match\n getAllIDB(emojiStore.index(INDEX_TOKENS), range, result => {\n intermediateResults.push(result);\n checkDone();\n });\n }\n })\n}\n\n// This could have been implemented as an IDB index on shortcodes, but it seemed wasteful to do that\n// when we can already query by tokens and this will give us what we're looking for 99.9% of the time\nasync function getEmojiByShortcode (db, shortcode) {\n const emojis = await getEmojiBySearchQuery(db, shortcode);\n\n // In very rare cases (e.g. the shortcode \"v\" as in \"v for victory\"), we cannot search because\n // there are no usable tokens (too short in this case). In that case, we have to do an inefficient\n // full-database scan, which I believe is an acceptable tradeoff for not having to have an extra\n // index on shortcodes.\n\n if (!emojis.length) {\n const predicate = _ => ((_.shortcodes || []).includes(shortcode.toLowerCase()));\n return (await doFullDatabaseScanForSingleResult(db, predicate)) || null\n }\n\n return emojis.filter(_ => {\n const lowerShortcodes = (_.shortcodes || []).map(_ => _.toLowerCase());\n return lowerShortcodes.includes(shortcode.toLowerCase())\n })[0] || null\n}\n\nasync function getEmojiByUnicode (db, unicode) {\n return dbPromise(db, STORE_EMOJI, MODE_READONLY, (emojiStore, txn, cb) => (\n getIDB(emojiStore, unicode, result => {\n if (result) {\n return cb(result)\n }\n getIDB(emojiStore.index(INDEX_SKIN_UNICODE), unicode, result => cb(result || null));\n })\n ))\n}\n\nfunction get (db, storeName, key) {\n return dbPromise(db, storeName, MODE_READONLY, (store, txn, cb) => (\n getIDB(store, key, cb)\n ))\n}\n\nfunction set (db, storeName, key, value) {\n return dbPromise(db, storeName, MODE_READWRITE, (store, txn) => {\n store.put(value, key);\n commit(txn);\n })\n}\n\nfunction incrementFavoriteEmojiCount (db, unicode) {\n return dbPromise(db, STORE_FAVORITES, MODE_READWRITE, (store, txn) => (\n getIDB(store, unicode, result => {\n store.put((result || 0) + 1, unicode);\n commit(txn);\n })\n ))\n}\n\nfunction getTopFavoriteEmoji (db, customEmojiIndex, limit) {\n if (limit === 0) {\n return []\n }\n return dbPromise(db, [STORE_FAVORITES, STORE_EMOJI], MODE_READONLY, ([favoritesStore, emojiStore], txn, cb) => {\n const results = [];\n favoritesStore.index(INDEX_COUNT).openCursor(undefined, 'prev').onsuccess = e => {\n const cursor = e.target.result;\n if (!cursor) { // no more results\n return cb(results)\n }\n\n function addResult (result) {\n results.push(result);\n if (results.length === limit) {\n return cb(results) // done, reached the limit\n }\n cursor.continue();\n }\n\n const unicodeOrName = cursor.primaryKey;\n const custom = customEmojiIndex.byName(unicodeOrName);\n if (custom) {\n return addResult(custom)\n }\n // This could be done in parallel (i.e. make the cursor and the get()s parallelized),\n // but my testing suggests it's not actually faster.\n getIDB(emojiStore, unicodeOrName, emoji => {\n if (emoji) {\n return addResult(emoji)\n }\n // emoji not found somehow, ignore (may happen if custom emoji change)\n cursor.continue();\n });\n };\n })\n}\n\n// trie data structure for prefix searches\n// loosely based on https://github.com/nolanlawson/substring-trie\n\nconst CODA_MARKER = ''; // marks the end of the string\n\nfunction trie (arr, itemToTokens) {\n const map = new Map();\n for (const item of arr) {\n const tokens = itemToTokens(item);\n for (const token of tokens) {\n let currentMap = map;\n for (let i = 0; i < token.length; i++) {\n const char = token.charAt(i);\n let nextMap = currentMap.get(char);\n if (!nextMap) {\n nextMap = new Map();\n currentMap.set(char, nextMap);\n }\n currentMap = nextMap;\n }\n let valuesAtCoda = currentMap.get(CODA_MARKER);\n if (!valuesAtCoda) {\n valuesAtCoda = [];\n currentMap.set(CODA_MARKER, valuesAtCoda);\n }\n valuesAtCoda.push(item);\n }\n }\n\n const search = (query, exact) => {\n let currentMap = map;\n for (let i = 0; i < query.length; i++) {\n const char = query.charAt(i);\n const nextMap = currentMap.get(char);\n if (nextMap) {\n currentMap = nextMap;\n } else {\n return []\n }\n }\n\n if (exact) {\n const results = currentMap.get(CODA_MARKER);\n return results || []\n }\n\n const results = [];\n // traverse\n const queue = [currentMap];\n while (queue.length) {\n const currentMap = queue.shift();\n const entriesSortedByKey = [...currentMap.entries()].sort((a, b) => a[0] < b[0] ? -1 : 1);\n for (const [key, value] of entriesSortedByKey) {\n if (key === CODA_MARKER) { // CODA_MARKER always comes first; it's the empty string\n results.push(...value);\n } else {\n queue.push(value);\n }\n }\n }\n return results\n };\n\n return search\n}\n\nconst requiredKeys$1 = [\n 'name',\n 'url'\n];\n\nfunction assertCustomEmojis (customEmojis) {\n const isArray = customEmojis && Array.isArray(customEmojis);\n const firstItemIsFaulty = isArray &&\n customEmojis.length &&\n (!customEmojis[0] || requiredKeys$1.some(key => !(key in customEmojis[0])));\n if (!isArray || firstItemIsFaulty) {\n throw new Error('Custom emojis are in the wrong format')\n }\n}\n\nfunction customEmojiIndex (customEmojis) {\n assertCustomEmojis(customEmojis);\n\n const sortByName = (a, b) => a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;\n\n //\n // all()\n //\n const all = customEmojis.sort(sortByName);\n\n //\n // search()\n //\n const emojiToTokens = emoji => {\n const set = new Set();\n if (emoji.shortcodes) {\n for (const shortcode of emoji.shortcodes) {\n for (const token of extractTokens(shortcode)) {\n set.add(token);\n }\n }\n }\n return set\n };\n const searchTrie = trie(customEmojis, emojiToTokens);\n const searchByExactMatch = _ => searchTrie(_, true);\n const searchByPrefix = _ => searchTrie(_, false);\n\n // Search by query for custom emoji. Similar to how we do this in IDB, the last token\n // is treated as a prefix search, but every other one is treated as an exact match.\n // Then we AND the results together\n const search = query => {\n const tokens = extractTokens(query);\n const intermediateResults = tokens.map((token, i) => (\n (i < tokens.length - 1 ? searchByExactMatch : searchByPrefix)(token)\n ));\n return findCommonMembers(intermediateResults, _ => _.name).sort(sortByName)\n };\n\n //\n // byShortcode, byName\n //\n const shortcodeToEmoji = new Map();\n const nameToEmoji = new Map();\n for (const customEmoji of customEmojis) {\n nameToEmoji.set(customEmoji.name.toLowerCase(), customEmoji);\n for (const shortcode of (customEmoji.shortcodes || [])) {\n shortcodeToEmoji.set(shortcode.toLowerCase(), customEmoji);\n }\n }\n\n const byShortcode = shortcode => shortcodeToEmoji.get(shortcode.toLowerCase());\n const byName = name => nameToEmoji.get(name.toLowerCase());\n\n return {\n all,\n search,\n byShortcode,\n byName\n }\n}\n\nconst isFirefoxContentScript = typeof wrappedJSObject !== 'undefined';\n\n// remove some internal implementation details, i.e. the \"tokens\" array on the emoji object\n// essentially, convert the emoji from the version stored in IDB to the version used in-memory\nfunction cleanEmoji (emoji) {\n if (!emoji) {\n return emoji\n }\n // if inside a Firefox content script, need to clone the emoji object to prevent Firefox from complaining about\n // cross-origin object. See: https://github.com/nolanlawson/emoji-picker-element/issues/356\n /* istanbul ignore if */\n if (isFirefoxContentScript) {\n emoji = structuredClone(emoji);\n }\n delete emoji.tokens;\n if (emoji.skinTones) {\n const len = emoji.skinTones.length;\n emoji.skins = Array(len);\n for (let i = 0; i < len; i++) {\n emoji.skins[i] = {\n tone: emoji.skinTones[i],\n unicode: emoji.skinUnicodes[i],\n version: emoji.skinVersions[i]\n };\n }\n delete emoji.skinTones;\n delete emoji.skinUnicodes;\n delete emoji.skinVersions;\n }\n return emoji\n}\n\nfunction warnETag (eTag) {\n if (!eTag) {\n console.warn('emoji-picker-element is more efficient if the dataSource server exposes an ETag header.');\n }\n}\n\nconst requiredKeys = [\n 'annotation',\n 'emoji',\n 'group',\n 'order',\n 'version'\n];\n\nfunction assertEmojiData (emojiData) {\n if (!emojiData ||\n !Array.isArray(emojiData) ||\n !emojiData[0] ||\n (typeof emojiData[0] !== 'object') ||\n requiredKeys.some(key => (!(key in emojiData[0])))) {\n throw new Error('Emoji data is in the wrong format')\n }\n}\n\nfunction assertStatus (response, dataSource) {\n if (Math.floor(response.status / 100) !== 2) {\n throw new Error('Failed to fetch: ' + dataSource + ': ' + response.status)\n }\n}\n\nasync function getETag (dataSource) {\n const response = await fetch(dataSource, { method: 'HEAD' });\n assertStatus(response, dataSource);\n const eTag = response.headers.get('etag');\n warnETag(eTag);\n return eTag\n}\n\nasync function getETagAndData (dataSource) {\n const response = await fetch(dataSource);\n assertStatus(response, dataSource);\n const eTag = response.headers.get('etag');\n warnETag(eTag);\n const emojiData = await response.json();\n assertEmojiData(emojiData);\n return [eTag, emojiData]\n}\n\n// TODO: including these in blob-util.ts causes typedoc to generate docs for them,\n// even with --excludePrivate ¯\\_(ツ)_/¯\n/** @private */\n/**\n * Convert an `ArrayBuffer` to a binary string.\n *\n * Example:\n *\n * ```js\n * var myString = blobUtil.arrayBufferToBinaryString(arrayBuff)\n * ```\n *\n * @param buffer - array buffer\n * @returns binary string\n */\nfunction arrayBufferToBinaryString(buffer) {\n var binary = '';\n var bytes = new Uint8Array(buffer);\n var length = bytes.byteLength;\n var i = -1;\n while (++i < length) {\n binary += String.fromCharCode(bytes[i]);\n }\n return binary;\n}\n/**\n * Convert a binary string to an `ArrayBuffer`.\n *\n * ```js\n * var myBuffer = blobUtil.binaryStringToArrayBuffer(binaryString)\n * ```\n *\n * @param binary - binary string\n * @returns array buffer\n */\nfunction binaryStringToArrayBuffer(binary) {\n var length = binary.length;\n var buf = new ArrayBuffer(length);\n var arr = new Uint8Array(buf);\n var i = -1;\n while (++i < length) {\n arr[i] = binary.charCodeAt(i);\n }\n return buf;\n}\n\n// generate a checksum based on the stringified JSON\nasync function jsonChecksum (object) {\n const inString = JSON.stringify(object);\n let inBuffer = binaryStringToArrayBuffer(inString);\n\n // this does not need to be cryptographically secure, SHA-1 is fine\n const outBuffer = await crypto.subtle.digest('SHA-1', inBuffer);\n const outBinString = arrayBufferToBinaryString(outBuffer);\n const res = btoa(outBinString);\n return res\n}\n\nasync function doCheckForUpdates (db, dataSource) {\n // just do a simple HEAD request first to see if the eTags match\n let emojiData;\n let eTag = await getETag(dataSource);\n if (!eTag) { // work around lack of ETag/Access-Control-Expose-Headers\n const eTagAndData = await getETagAndData(dataSource);\n eTag = eTagAndData[0];\n emojiData = eTagAndData[1];\n if (!eTag) {\n eTag = await jsonChecksum(emojiData);\n }\n }\n if (await hasData(db, dataSource, eTag)) ; else {\n if (!emojiData) {\n const eTagAndData = await getETagAndData(dataSource);\n emojiData = eTagAndData[1];\n }\n await loadData(db, emojiData, dataSource, eTag);\n }\n}\n\nasync function loadDataForFirstTime (db, dataSource) {\n let [eTag, emojiData] = await getETagAndData(dataSource);\n if (!eTag) {\n // Handle lack of support for ETag or Access-Control-Expose-Headers\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers#Browser_compatibility\n eTag = await jsonChecksum(emojiData);\n }\n\n await loadData(db, emojiData, dataSource, eTag);\n}\n\nasync function checkForUpdates (db, dataSource) {\n try {\n await doCheckForUpdates(db, dataSource);\n } catch (err) {\n // Checking for updates is not a critical operation, and it can fail if e.g. the picker is quickly removed and\n // re-added to the DOM. In those cases, we may get an IndexedDB InvalidStateError because we are attempting to close\n // the database connection, possibly while another request is inflight. So there's effectively no way to prevent\n // InvalidStateErrors unless we were to carefully sequence our IndexedDB operations. Much more simply, we can just\n // ignore IndexedDB InvalidStateErrors here and give users one less useless error message in their console.\n if (err.name !== 'InvalidStateError') {\n throw err\n }\n }\n}\n\nclass Database {\n constructor ({ dataSource = DEFAULT_DATA_SOURCE, locale = DEFAULT_LOCALE, customEmoji = [] } = {}) {\n this.dataSource = dataSource;\n this.locale = locale;\n this._dbName = `emoji-picker-element-${this.locale}`;\n this._db = undefined;\n this._lazyUpdate = undefined;\n this._custom = customEmojiIndex(customEmoji);\n\n this._clear = this._clear.bind(this);\n this._ready = this._init();\n }\n\n async _init () {\n const db = this._db = await openDatabase(this._dbName);\n\n addOnCloseListener(this._dbName, this._clear);\n const dataSource = this.dataSource;\n const empty = await isEmpty(db);\n\n if (empty) {\n await loadDataForFirstTime(db, dataSource);\n } else { // offline-first - do an update asynchronously\n this._lazyUpdate = checkForUpdates(db, dataSource);\n }\n }\n\n async ready () {\n const checkReady = async () => {\n if (!this._ready) {\n this._ready = this._init();\n }\n return this._ready\n };\n await checkReady();\n // There's a possibility of a race condition where the element gets added, removed, and then added again\n // with a particular timing, which would set the _db to undefined.\n // We *could* do a while loop here, but that seems excessive and could lead to an infinite loop.\n if (!this._db) {\n await checkReady();\n }\n }\n\n async getEmojiByGroup (group) {\n assertNumber(group);\n await this.ready();\n return uniqEmoji(await getEmojiByGroup(this._db, group)).map(cleanEmoji)\n }\n\n async getEmojiBySearchQuery (query) {\n assertNonEmptyString(query);\n await this.ready();\n const customs = this._custom.search(query);\n const natives = uniqEmoji(await getEmojiBySearchQuery(this._db, query)).map(cleanEmoji);\n return [\n ...customs,\n ...natives\n ]\n }\n\n async getEmojiByShortcode (shortcode) {\n assertNonEmptyString(shortcode);\n await this.ready();\n const custom = this._custom.byShortcode(shortcode);\n if (custom) {\n return custom\n }\n return cleanEmoji(await getEmojiByShortcode(this._db, shortcode))\n }\n\n async getEmojiByUnicodeOrName (unicodeOrName) {\n assertNonEmptyString(unicodeOrName);\n await this.ready();\n const custom = this._custom.byName(unicodeOrName);\n if (custom) {\n return custom\n }\n return cleanEmoji(await getEmojiByUnicode(this._db, unicodeOrName))\n }\n\n async getPreferredSkinTone () {\n await this.ready();\n return (await get(this._db, STORE_KEYVALUE, KEY_PREFERRED_SKINTONE)) || 0\n }\n\n async setPreferredSkinTone (skinTone) {\n assertNumber(skinTone);\n await this.ready();\n return set(this._db, STORE_KEYVALUE, KEY_PREFERRED_SKINTONE, skinTone)\n }\n\n async incrementFavoriteEmojiCount (unicodeOrName) {\n assertNonEmptyString(unicodeOrName);\n await this.ready();\n return incrementFavoriteEmojiCount(this._db, unicodeOrName)\n }\n\n async getTopFavoriteEmoji (limit) {\n assertNumber(limit);\n await this.ready();\n return (await getTopFavoriteEmoji(this._db, this._custom, limit)).map(cleanEmoji)\n }\n\n set customEmoji (customEmojis) {\n this._custom = customEmojiIndex(customEmojis);\n }\n\n get customEmoji () {\n return this._custom.all\n }\n\n async _shutdown () {\n await this.ready(); // reopen if we've already been closed/deleted\n try {\n await this._lazyUpdate; // allow any lazy updates to process before closing/deleting\n } catch (err) { /* ignore network errors (offline-first) */ }\n }\n\n // clear references to IDB, e.g. during a close event\n _clear () {\n // We don't need to call removeEventListener or remove the manual \"close\" listeners.\n // The memory leak tests prove this is unnecessary. It's because:\n // 1) IDBDatabases that can no longer fire \"close\" automatically have listeners GCed\n // 2) we clear the manual close listeners in databaseLifecycle.js.\n this._db = this._ready = this._lazyUpdate = undefined;\n }\n\n async close () {\n await this._shutdown();\n await closeDatabase(this._dbName);\n }\n\n async delete () {\n await this._shutdown();\n await deleteDatabase(this._dbName);\n }\n}\n\nexport { Database as default };\n","import Database from './database.js';\n\n// via https://unpkg.com/browse/emojibase-data@6.0.0/meta/groups.json\nconst allGroups = [\n [-1, '✨', 'custom'],\n [0, '😀', 'smileys-emotion'],\n [1, '👋', 'people-body'],\n [3, '🐱', 'animals-nature'],\n [4, '🍎', 'food-drink'],\n [5, '🏠️', 'travel-places'],\n [6, '⚽', 'activities'],\n [7, '📝', 'objects'],\n [8, '⛔️', 'symbols'],\n [9, '🏁', 'flags']\n].map(([id, emoji, name]) => ({ id, emoji, name }));\n\nconst groups = allGroups.slice(1);\n\nconst MIN_SEARCH_TEXT_LENGTH = 2;\nconst NUM_SKIN_TONES = 6;\n\n/* istanbul ignore next */\nconst rIC = typeof requestIdleCallback === 'function' ? requestIdleCallback : setTimeout;\n\n// check for ZWJ (zero width joiner) character\nfunction hasZwj (emoji) {\n return emoji.unicode.includes('\\u200d')\n}\n\n// Find one good representative emoji from each version to test by checking its color.\n// Ideally it should have color in the center. For some inspiration, see:\n// https://about.gitlab.com/blog/2018/05/30/journey-in-native-unicode-emoji/\n//\n// Note that for certain versions (12.1, 13.1), there is no point in testing them explicitly, because\n// all the emoji from this version are compound-emoji from previous versions. So they would pass a color\n// test, even in browsers that display them as double emoji. (E.g. \"face in clouds\" might render as\n// \"face without mouth\" plus \"fog\".) These emoji can only be filtered using the width test,\n// which happens in checkZwjSupport.js.\nconst versionsAndTestEmoji = {\n '': 17, // distorted face\n '': 16, // face with bags under eyes\n '🫨': 15.1, // shaking head, technically from v15 but see note above\n '🫠': 14,\n '🥲': 13.1, // smiling face with tear, technically from v13 but see note above\n '🥻': 12.1, // sari, technically from v12 but see note above\n '🥰': 11,\n '🤩': 5,\n '👱♀️': 4,\n '🤣': 3,\n '👁️🗨️': 2,\n '😀': 1,\n '😐️': 0.7,\n '😃': 0.6\n};\n\nconst TIMEOUT_BEFORE_LOADING_MESSAGE = 1000; // 1 second\nconst DEFAULT_SKIN_TONE_EMOJI = '🖐️';\nconst DEFAULT_NUM_COLUMNS = 8;\n\n// Based on https://fivethirtyeight.com/features/the-100-most-used-emojis/ and\n// https://blog.emojipedia.org/facebook-reveals-most-and-least-used-emojis/ with\n// a bit of my own curation. (E.g. avoid the \"OK\" gesture because of connotations:\n// https://emojipedia.org/ok-hand/)\nconst MOST_COMMONLY_USED_EMOJI = [\n '😊',\n '😒',\n '❤️',\n '👍️',\n '😍',\n '😂',\n '😭',\n '☺️',\n '😔',\n '😩',\n '😏',\n '💕',\n '🙌',\n '😘'\n];\n\n// It's important to list Twemoji Mozilla before everything else, because Mozilla bundles their\n// own font on some platforms (notably Windows and Linux as of this writing). Typically, Mozilla\n// updates faster than the underlying OS, and we don't want to render older emoji in one font and\n// newer emoji in another font:\n// https://github.com/nolanlawson/emoji-picker-element/pull/268#issuecomment-1073347283\nconst FONT_FAMILY = '\"Twemoji Mozilla\",\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",' +\n '\"Noto Color Emoji\",\"EmojiOne Color\",\"Android Emoji\",sans-serif';\n\n/* istanbul ignore next */\nconst DEFAULT_CATEGORY_SORTING = (a, b) => a < b ? -1 : a > b ? 1 : 0;\n\n// Test if an emoji is supported by rendering it to canvas and checking that the color is not black\n// See https://about.gitlab.com/blog/2018/05/30/journey-in-native-unicode-emoji/\n// and https://www.npmjs.com/package/if-emoji for inspiration\n// This implementation is largely borrowed from if-emoji, adding the font-family\n\n\nconst getTextFeature = (text, color) => {\n const canvas = document.createElement('canvas');\n canvas.width = canvas.height = 1;\n\n const ctx = canvas.getContext('2d', {\n // Improves the performance of `getImageData()`\n // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getContextAttributes#willreadfrequently\n willReadFrequently: true\n });\n ctx.textBaseline = 'top';\n ctx.font = `100px ${FONT_FAMILY}`;\n ctx.fillStyle = color;\n ctx.scale(0.01, 0.01);\n ctx.fillText(text, 0, 0);\n\n return ctx.getImageData(0, 0, 1, 1).data\n};\n\nconst compareFeatures = (feature1, feature2) => {\n const feature1Str = [...feature1].join(',');\n const feature2Str = [...feature2].join(',');\n // This is RGBA, so for 0,0,0, we are checking that the first RGB is not all zeroes.\n // Most of the time when unsupported this is 0,0,0,0, but on Chrome on Mac it is\n // 0,0,0,61 - there is a transparency here.\n return feature1Str === feature2Str && !feature1Str.startsWith('0,0,0,')\n};\n\nfunction testColorEmojiSupported (text) {\n // Render white and black and then compare them to each other and ensure they're the same\n // color, and neither one is black. This shows that the emoji was rendered in color.\n const feature1 = getTextFeature(text, '#000');\n const feature2 = getTextFeature(text, '#fff');\n return feature1 && feature2 && compareFeatures(feature1, feature2)\n}\n\n// rather than check every emoji ever, which would be expensive, just check some representatives from the\n// different emoji releases to determine what the font supports\n\nfunction determineEmojiSupportLevel () {\n const entries = Object.entries(versionsAndTestEmoji);\n try {\n // start with latest emoji and work backwards\n for (const [emoji, version] of entries) {\n if (testColorEmojiSupported(emoji)) {\n return version\n }\n }\n } catch (e) { // canvas error\n } finally {\n }\n // In case of an error, be generous and just assume all emoji are supported (e.g. for canvas errors\n // due to anti-fingerprinting add-ons). Better to show some gray boxes than nothing at all.\n return entries[0][1] // first one in the list is the most recent version\n}\n\n// Check which emojis we know for sure aren't supported, based on Unicode version level\nlet promise;\nconst detectEmojiSupportLevel = () => {\n if (!promise) {\n // Delay so it can run while the IDB database is being created by the browser (on another thread).\n // This helps especially with first load – we want to start pre-populating the database on the main thread,\n // and then wait for IDB to commit everything, and while waiting we run this check.\n promise = new Promise(resolve => (\n rIC(() => (\n resolve(determineEmojiSupportLevel()) // delay so ideally this can run while IDB is first populating\n ))\n ));\n }\n return promise\n};\n// determine which emojis containing ZWJ (zero width joiner) characters\n// are supported (rendered as one glyph) rather than unsupported (rendered as two or more glyphs)\nconst supportedZwjEmojis = new Map();\n\nconst VARIATION_SELECTOR = '\\ufe0f';\nconst SKINTONE_MODIFIER = '\\ud83c';\nconst ZWJ = '\\u200d';\nconst LIGHT_SKIN_TONE = 0x1F3FB;\nconst LIGHT_SKIN_TONE_MODIFIER = 0xdffb;\n\n// TODO: this is a naive implementation, we can improve it later\n// It's only used for the skintone picker, so as long as people don't customize with\n// really exotic emoji then it should work fine\nfunction applySkinTone (str, skinTone) {\n if (skinTone === 0) {\n return str\n }\n const zwjIndex = str.indexOf(ZWJ);\n if (zwjIndex !== -1) {\n return str.substring(0, zwjIndex) +\n String.fromCodePoint(LIGHT_SKIN_TONE + skinTone - 1) +\n str.substring(zwjIndex)\n }\n if (str.endsWith(VARIATION_SELECTOR)) {\n str = str.substring(0, str.length - 1);\n }\n return str + SKINTONE_MODIFIER + String.fromCodePoint(LIGHT_SKIN_TONE_MODIFIER + skinTone - 1)\n}\n\nfunction halt (event) {\n event.preventDefault();\n event.stopPropagation();\n}\n\n// Implementation left/right or up/down navigation, circling back when you\n// reach the start/end of the list\nfunction incrementOrDecrement (decrement, val, arr) {\n val += (decrement ? -1 : 1);\n if (val < 0) {\n val = arr.length - 1;\n } else if (val >= arr.length) {\n val = 0;\n }\n return val\n}\n\n// like lodash's uniqBy but much smaller\nfunction uniqBy (arr, func) {\n const set = new Set();\n const res = [];\n for (const item of arr) {\n const key = func(item);\n if (!set.has(key)) {\n set.add(key);\n res.push(item);\n }\n }\n return res\n}\n\n// We don't need all the data on every emoji, and there are specific things we need\n// for the UI, so build a \"view model\" from the emoji object we got from the database\n\nfunction summarizeEmojisForUI (emojis, emojiSupportLevel) {\n const toSimpleSkinsMap = skins => {\n const res = {};\n for (const skin of skins) {\n // ignore arrays like [1, 2] with multiple skin tones\n // also ignore variants that are in an unsupported emoji version\n // (these do exist - variants from a different version than their base emoji)\n if (typeof skin.tone === 'number' && skin.version <= emojiSupportLevel) {\n res[skin.tone] = skin.unicode;\n }\n }\n return res\n };\n\n return emojis.map(({ unicode, skins, shortcodes, url, name, category, annotation }) => ({\n unicode,\n name,\n shortcodes,\n url,\n category,\n annotation,\n id: unicode || name,\n skins: skins && toSimpleSkinsMap(skins)\n }))\n}\n\n// import rAF from one place so that the bundle size is a bit smaller\nconst rAF = requestAnimationFrame;\n\n// \"Svelte action\"-like utility to detect layout changes via ResizeObserver.\n// If ResizeObserver is unsupported, we just use rAF once and don't bother to update.\n\n\nlet resizeObserverSupported = typeof ResizeObserver === 'function';\n\nfunction resizeObserverAction (node, abortSignal, onUpdate) {\n let resizeObserver;\n if (resizeObserverSupported) {\n resizeObserver = new ResizeObserver(onUpdate);\n resizeObserver.observe(node);\n } else { // just run once, don't bother trying to track it\n rAF(onUpdate);\n }\n\n // cleanup function (called on destroy)\n abortSignal.addEventListener('abort', () => {\n if (resizeObserver) {\n resizeObserver.disconnect();\n }\n });\n}\n\n// get the width of the text inside of a DOM node, via https://stackoverflow.com/a/59525891/680742\nfunction calculateTextWidth (node) {\n // skip running this in jest/vitest because we don't need to check for emoji support in that environment\n /* istanbul ignore else */\n {\n const range = document.createRange();\n range.selectNode(node.firstChild);\n return range.getBoundingClientRect().width\n }\n}\n\nconst BASELINE_EMOJI = '😀';\n\nlet baselineEmojiWidth;\nlet fallbackNode;\n\nfunction calculateTextWidthWithFallback (unicode, domNode, baselineEmojiNode) {\n const result = calculateTextWidth(domNode);\n /* istanbul ignore if */\n if (!result) {\n // If result is 0 then very likely the emoji-picker has `display:none` or equivalent. In that case, we fall back to\n // cloning the baseline emoji, putting that in the `document.body`, and measuring that instead. This is a perf hit,\n // but it's better than mistakenly filtering emoji: https://github.com/nolanlawson/emoji-picker-element/issues/514\n if (!fallbackNode) {\n fallbackNode = baselineEmojiNode.cloneNode(true);\n // We have to copy styles because we're copying from an element in the shadow DOM to the light DOM\n // We can't use the shadow DOM because it's likely the entire picker is `display:none`\n const styles = getComputedStyle(baselineEmojiNode);\n // probably don't need display/align-items/justify-content but let's play it safe\n for (const prop of ['font-family', 'line-height', 'width', 'height', 'font-size', 'display', 'align-items', 'justify-content']) {\n // set `!important` just in case some global styles might try to overwrite this\n fallbackNode.style.setProperty(prop, styles.getPropertyValue(prop), 'important');\n }\n }\n try {\n document.body.appendChild(fallbackNode);\n fallbackNode.firstChild.nodeValue = unicode;\n return calculateTextWidth(fallbackNode)\n } finally {\n // avoid actually rendering the test emoji\n fallbackNode.remove();\n }\n }\n return result\n}\n\n/**\n * Check if the given emojis containing ZWJ characters are supported by the current browser (don't render\n * as double characters) and return true if all are supported.\n * @param zwjEmojisToCheck\n * @param baselineEmojiNode\n * @param emojiToDomNode\n */\nfunction checkZwjSupport (zwjEmojisToCheck, baselineEmojiNode, emojiToDomNode) {\n let allSupported = true;\n for (const emoji of zwjEmojisToCheck) {\n const domNode = emojiToDomNode(emoji);\n // sanity check to make sure the node is defined properly\n /* istanbul ignore if */\n if (!domNode) {\n // This is a race condition that can occur when the component is unmounted/remounted\n // It doesn't really matter what we do here since the old context is not going to render anymore.\n // Just bail out of emoji support detection and return `allSupported=true` since the rendering context is gone\n continue\n }\n if (typeof baselineEmojiWidth === 'undefined') { // calculate the baseline emoji width only once\n baselineEmojiWidth = calculateTextWidthWithFallback(BASELINE_EMOJI, baselineEmojiNode, baselineEmojiNode);\n }\n const emojiWidth = calculateTextWidthWithFallback(emoji.unicode, domNode, baselineEmojiNode);\n // On Windows, some supported emoji are ~50% bigger than the baseline emoji, but what we really want to guard\n // against are the ones that are 2x the size, because those are truly broken (person with red hair = person with\n // floating red wig, black cat = cat with black square, polar bear = bear with snowflake, etc.)\n // So here we set the threshold at 1.8 times the size of the baseline emoji.\n const supported = emojiWidth / 1.8 < baselineEmojiWidth;\n supportedZwjEmojis.set(emoji.unicode, supported);\n\n if (!supported) {\n allSupported = false;\n }\n }\n return allSupported\n}\n\n// like lodash's uniq\n\nfunction uniq (arr) {\n return uniqBy(arr, _ => _)\n}\n\n// Note we put this in its own function outside Picker.js to avoid Svelte doing an invalidation on the \"setter\" here.\n// At best the invalidation is useless, at worst it can cause infinite loops:\n// https://github.com/nolanlawson/emoji-picker-element/pull/180\n// https://github.com/sveltejs/svelte/issues/6521\n// Also note tabpanelElement can be null if the element is disconnected immediately after connected\nfunction resetScrollTopIfPossible (element) {\n /* istanbul ignore else */\n if (element) { // Makes me nervous not to have this `if` guard\n element.scrollTop = 0;\n }\n}\n\nfunction getFromMap (cache, key, func) {\n let cached = cache.get(key);\n if (!cached) {\n cached = func();\n cache.set(key, cached);\n }\n return cached\n}\n\nfunction toString (value) {\n return '' + value\n}\n\nfunction parseTemplate (htmlString) {\n const template = document.createElement('template');\n template.innerHTML = htmlString;\n return template\n}\n\nconst parseCache = new WeakMap();\nconst domInstancesCache = new WeakMap();\n// This needs to be a symbol because it needs to be different from any possible output of a key function\nconst unkeyedSymbol = Symbol('un-keyed');\n\n// Not supported in Safari <=13\nconst hasReplaceChildren = 'replaceChildren' in Element.prototype;\nfunction replaceChildren (parentNode, newChildren) {\n /* istanbul ignore else */\n if (hasReplaceChildren) {\n parentNode.replaceChildren(...newChildren);\n } else { // minimal polyfill for Element.prototype.replaceChildren\n parentNode.innerHTML = '';\n parentNode.append(...newChildren);\n }\n}\n\nfunction doChildrenNeedRerender (parentNode, newChildren) {\n let oldChild = parentNode.firstChild;\n let oldChildrenCount = 0;\n // iterate using firstChild/nextSibling because browsers use a linked list under the hood\n while (oldChild) {\n const newChild = newChildren[oldChildrenCount];\n // check if the old child and new child are the same\n if (newChild !== oldChild) {\n return true\n }\n oldChild = oldChild.nextSibling;\n oldChildrenCount++;\n }\n // if new children length is different from old, we must re-render\n return oldChildrenCount !== newChildren.length\n}\n\nfunction patchChildren (newChildren, instanceBinding) {\n const { targetNode } = instanceBinding;\n let { targetParentNode } = instanceBinding;\n\n let needsRerender = false;\n\n if (targetParentNode) { // already rendered once\n needsRerender = doChildrenNeedRerender(targetParentNode, newChildren);\n } else { // first render of list\n needsRerender = true;\n instanceBinding.targetNode = undefined; // placeholder node not needed anymore, free memory\n instanceBinding.targetParentNode = targetParentNode = targetNode.parentNode;\n }\n // avoid re-rendering list if the dom nodes are exactly the same before and after\n if (needsRerender) {\n replaceChildren(targetParentNode, newChildren);\n }\n}\n\nfunction patch (expressions, instanceBindings) {\n for (const instanceBinding of instanceBindings) {\n const {\n targetNode,\n currentExpression,\n binding: {\n expressionIndex,\n attributeName,\n attributeValuePre,\n attributeValuePost\n }\n } = instanceBinding;\n\n const expression = expressions[expressionIndex];\n\n if (currentExpression === expression) {\n // no need to update, same as before\n continue\n }\n\n instanceBinding.currentExpression = expression;\n\n if (attributeName) { // attribute replacement\n if (expression === null) {\n // null is treated as a special case by the framework - we don't render an attribute at all in this case\n targetNode.removeAttribute(attributeName);\n } else {\n // attribute value is not null; set a new attribute\n const newValue = attributeValuePre + toString(expression) + attributeValuePost;\n targetNode.setAttribute(attributeName, newValue);\n }\n } else { // text node / child element / children replacement\n let newNode;\n if (Array.isArray(expression)) { // array of DOM elements produced by tag template literals\n patchChildren(expression, instanceBinding);\n } else if (expression instanceof Element) { // html tag template returning a DOM element\n newNode = expression;\n targetNode.replaceWith(newNode);\n } else { // primitive - string, number, etc\n // nodeValue is faster than textContent supposedly https://www.youtube.com/watch?v=LY6y3HbDVmg\n // note we may be replacing the value in a placeholder text node\n targetNode.nodeValue = toString(expression);\n }\n if (newNode) {\n instanceBinding.targetNode = newNode;\n }\n }\n }\n}\n\nfunction parse (tokens) {\n let htmlString = '';\n\n let withinTag = false;\n let withinAttribute = false;\n let elementIndexCounter = -1; // depth-first traversal order\n\n const elementsToBindings = new Map();\n const elementIndexes = [];\n\n let skipTokenChars = 0;\n for (let i = 0, len = tokens.length; i < len; i++) {\n const token = tokens[i];\n htmlString += token.slice(skipTokenChars);\n\n if (i === len - 1) {\n break // no need to process characters - no more expressions to be found\n }\n\n for (let j = 0; j < token.length; j++) {\n const char = token.charAt(j);\n switch (char) {\n case '<': {\n const nextChar = token.charAt(j + 1);\n if (nextChar === '/') { // closing tag\n // leaving an element\n elementIndexes.pop();\n } else { // not a closing tag\n withinTag = true;\n elementIndexes.push(++elementIndexCounter);\n }\n break\n }\n case '>': {\n withinTag = false;\n withinAttribute = false;\n break\n }\n case '=': {\n withinAttribute = true;\n break\n }\n }\n }\n\n const elementIndex = elementIndexes[elementIndexes.length - 1];\n const bindings = getFromMap(elementsToBindings, elementIndex, () => []);\n\n let attributeName;\n let attributeValuePre;\n let attributeValuePost;\n if (withinAttribute) {\n // I never use single-quotes for attribute values in HTML, so just support double-quotes or no-quotes\n const attributePreMatch = /(\\S+)=\"?([^\"=]*)$/.exec(token);\n attributeName = attributePreMatch[1];\n attributeValuePre = attributePreMatch[2];\n const attributePostMatch = /^([^\">]*)(\"?)/.exec(tokens[i + 1]);\n attributeValuePost = attributePostMatch[1];\n // Optimization: remove the attribute itself, so we don't create a default attribute which is either empty or just\n // the \"pre\" text, e.g. `<div foo>` or `<div foo=\"prefix\">`. It will be replaced by the expression anyway.\n htmlString = htmlString.slice(0, -1 * attributePreMatch[0].length);\n skipTokenChars = attributePostMatch[0].length;\n } else {\n skipTokenChars = 0;\n }\n\n const binding = {\n attributeName,\n attributeValuePre,\n attributeValuePost,\n expressionIndex: i\n };\n\n bindings.push(binding);\n\n if (!withinTag && !withinAttribute) {\n // Add a placeholder text node, so we can find it later. Note we only support one dynamic child text node\n htmlString += ' ';\n }\n }\n\n const template = parseTemplate(htmlString);\n\n return {\n template,\n elementsToBindings\n }\n}\n\nfunction applyBindings (bindings, element, instanceBindings) {\n for (let i = 0; i < bindings.length; i++) {\n const binding = bindings[i];\n\n const targetNode = binding.attributeName\n ? element // attribute binding, just use the element itself\n : element.firstChild; // not an attribute binding, so has a placeholder text node\n\n const instanceBinding = {\n binding,\n targetNode,\n targetParentNode: undefined,\n currentExpression: undefined\n };\n\n instanceBindings.push(instanceBinding);\n }\n}\n\nfunction traverseAndSetupBindings (rootElement, elementsToBindings) {\n const instanceBindings = [];\n\n let topLevelBindings;\n if (elementsToBindings.size === 1 && (topLevelBindings = elementsToBindings.get(0))) {\n // Optimization for the common case where there's only one element and one binding\n // Skip creating a TreeWalker entirely and just handle the root DOM element\n applyBindings(topLevelBindings, rootElement, instanceBindings);\n } else {\n // traverse dom\n const treeWalker = document.createTreeWalker(rootElement, NodeFilter.SHOW_ELEMENT);\n\n let element = rootElement;\n let elementIndex = -1;\n do {\n const bindings = elementsToBindings.get(++elementIndex);\n if (bindings) {\n applyBindings(bindings, element, instanceBindings);\n }\n } while ((element = treeWalker.nextNode()))\n }\n\n return instanceBindings\n}\n\nfunction parseHtml (tokens) {\n // All templates and bound expressions are unique per tokens array\n const { template, elementsToBindings } = getFromMap(parseCache, tokens, () => parse(tokens));\n\n // When we parseHtml, we always return a fresh DOM instance ready to be updated\n const dom = template.cloneNode(true).content.firstElementChild;\n const instanceBindings = traverseAndSetupBindings(dom, elementsToBindings);\n\n return function updateDomInstance (expressions) {\n patch(expressions, instanceBindings);\n return dom\n }\n}\n\nfunction createFramework (state) {\n const domInstances = getFromMap(domInstancesCache, state, () => new Map());\n let domInstanceCacheKey = unkeyedSymbol;\n\n function html (tokens, ...expressions) {\n // Each unique lexical usage of map() is considered unique due to the html`` tagged template call it makes,\n // which has lexically unique tokens. The unkeyed symbol is just used for html`` usage outside of a map().\n const domInstancesForTokens = getFromMap(domInstances, tokens, () => new Map());\n const updateDomInstance = getFromMap(domInstancesForTokens, domInstanceCacheKey, () => parseHtml(tokens));\n\n return updateDomInstance(expressions) // update with expressions\n }\n\n function map (array, callback, keyFunction) {\n return array.map((item, index) => {\n const originalCacheKey = domInstanceCacheKey;\n domInstanceCacheKey = keyFunction(item);\n try {\n return callback(item, index)\n } finally {\n domInstanceCacheKey = originalCacheKey;\n }\n })\n }\n\n return { map, html }\n}\n\nfunction render (container, state, helpers, events, actions, refs, abortSignal, actionContext, firstRender) {\n const { labelWithSkin, titleForEmoji, unicodeWithSkin } = helpers;\n const { html, map } = createFramework(state);\n\n function emojiList (emojis, searchMode, prefix) {\n return map(emojis, (emoji, i) => {\n return html`<button role=\"${searchMode ? 'option' : 'menuitem'}\" aria-selected=\"${searchMode ? i === state.activeSearchItem : null}\" aria-label=\"${labelWithSkin(emoji, state.currentSkinTone)}\" title=\"${titleForEmoji(emoji)}\" class=\"${\n 'emoji' +\n (searchMode && i === state.activeSearchItem ? ' active' : '') +\n (emoji.unicode ? '' : ' custom-emoji')\n }\" id=\"${`${prefix}-${emoji.id}`}\" style=\"${emoji.unicode ? null : `--custom-emoji-background: url(${JSON.stringify(emoji.url)})`}\">${\n emoji.unicode\n ? unicodeWithSkin(emoji, state.currentSkinTone)\n : ''\n }</button>`\n // It's important for the cache key to be unique based on the prefix, because the framework caches based on the\n // unique tokens + cache key, and the same emoji may be used in the tab as well as in the fav bar\n }, emoji => `${prefix}-${emoji.id}`)\n }\n\n const section = () => {\n return html`<section data-ref=\"rootElement\" class=\"picker\" aria-label=\"${state.i18n.regionLabel}\" style=\"${state.pickerStyle || ''}\"><div class=\"pad-top\"></div><div class=\"search-row\"><div class=\"search-wrapper\"><input id=\"search\" class=\"search\" type=\"search\" role=\"combobox\" enterkeyhint=\"search\" placeholder=\"${state.i18n.searchLabel}\" autocapitalize=\"none\" autocomplete=\"off\" spellcheck=\"true\" aria-expanded=\"${!!(state.searchMode && state.currentEmojis.length)}\" aria-controls=\"search-results\" aria-describedby=\"search-description\" aria-autocomplete=\"list\" aria-activedescendant=\"${state.activeSearchItemId ? `emo-${state.activeSearchItemId}` : null}\" data-ref=\"searchElement\" data-on-input=\"onSearchInput\" data-on-keydown=\"onSearchKeydown\"><label class=\"sr-only\" for=\"search\">${state.i18n.searchLabel}</label> <span id=\"search-description\" class=\"sr-only\">${state.i18n.searchDescription}</span></div><div class=\"skintone-button-wrapper ${state.skinTonePickerExpandedAfterAnimation ? 'expanded' : ''}\"><button id=\"skintone-button\" class=\"emoji ${state.skinTonePickerExpanded ? 'hide-focus' : ''}\" aria-label=\"${state.skinToneButtonLabel}\" title=\"${state.skinToneButtonLabel}\" aria-describedby=\"skintone-description\" aria-haspopup=\"listbox\" aria-expanded=\"${state.skinTonePickerExpanded}\" aria-controls=\"skintone-list\" data-on-click=\"onClickSkinToneButton\">${state.skinToneButtonText || ''}</button></div><span id=\"skintone-description\" class=\"sr-only\">${state.i18n.skinToneDescription}</span><div data-ref=\"skinToneDropdown\" id=\"skintone-list\" class=\"skintone-list hide-focus ${state.skinTonePickerExpanded ? '' : 'hidden no-animate'}\" style=\"transform:translateY(${state.skinTonePickerExpanded ? 0 : 'calc(-1 * var(--num-skintones) * var(--total-emoji-size))'})\" role=\"listbox\" aria-label=\"${state.i18n.skinTonesLabel}\" aria-activedescendant=\"skintone-${state.activeSkinTone}\" aria-hidden=\"${!state.skinTonePickerExpanded}\" tabIndex=\"-1\" data-on-focusout=\"onSkinToneOptionsFocusOut\" data-on-click=\"onSkinToneOptionsClick\" data-on-keydown=\"onSkinToneOptionsKeydown\" data-on-keyup=\"onSkinToneOptionsKeyup\">${\n map(state.skinTones, (skinTone, i) => {\n return html`<div id=\"skintone-${i}\" class=\"emoji ${i === state.activeSkinTone ? 'active' : ''}\" aria-selected=\"${i === state.activeSkinTone}\" role=\"option\" title=\"${state.i18n.skinTones[i]}\" aria-label=\"${state.i18n.skinTones[i]}\">${skinTone}</div>`\n }, skinTone => skinTone)\n }</div></div><div class=\"nav\" role=\"tablist\" style=\"grid-template-columns:repeat(${state.groups.length},1fr)\" aria-label=\"${state.i18n.categoriesLabel}\" data-on-keydown=\"onNavKeydown\" data-on-click=\"onNavClick\">${\n map(state.groups, (group) => {\n return html`<button role=\"tab\" class=\"nav-button\" aria-controls=\"tab-${group.id}\" aria-label=\"${state.i18n.categories[group.name]}\" aria-selected=\"${!state.searchMode && state.currentGroup.id === group.id}\" title=\"${state.i18n.categories[group.name]}\" data-group-id=\"${group.id}\"><div class=\"nav-emoji emoji\">${group.emoji}</div></button>`\n }, group => group.id)\n }</div><div class=\"indicator-wrapper\"><div class=\"indicator\" style=\"transform:translateX(${(/* istanbul ignore next */ (state.isRtl ? -1 : 1)) * state.currentGroupIndex * 100}%)\"></div></div><div class=\"message ${state.message ? '' : 'gone'}\" role=\"alert\" aria-live=\"polite\">${state.message || ''}</div><div data-ref=\"tabpanelElement\" class=\"tabpanel ${(!state.databaseLoaded || state.message) ? 'gone' : ''}\" role=\"${state.searchMode ? 'region' : 'tabpanel'}\" aria-label=\"${state.searchMode ? state.i18n.searchResultsLabel : state.i18n.categories[state.currentGroup.name]}\" id=\"${state.searchMode ? null : `tab-${state.currentGroup.id}`}\" tabIndex=\"0\" data-on-click=\"onEmojiClick\"><div data-action=\"calculateEmojiGridStyle\">${\n map(state.currentEmojisWithCategories, (emojiWithCategory, i) => {\n return html`<div><div id=\"menu-label-${i}\" class=\"category ${state.currentEmojisWithCategories.length === 1 && state.currentEmojisWithCategories[0].category === '' ? 'gone' : ''}\" aria-hidden=\"true\">${\n state.searchMode\n ? state.i18n.searchResultsLabel\n : (\n emojiWithCategory.category\n ? emojiWithCategory.category\n : (\n state.currentEmojisWithCategories.length > 1\n ? state.i18n.categories.custom\n : state.i18n.categories[state.currentGroup.name]\n )\n )\n }</div><div class=\"emoji-menu ${i !== 0 && !state.searchMode && state.currentGroup.id === -1 ? 'visibility-auto' : ''}\" style=\"${`--num-rows: ${Math.ceil(emojiWithCategory.emojis.length / state.numColumns)}`}\" data-action=\"updateOnIntersection\" role=\"${state.searchMode ? 'listbox' : 'menu'}\" aria-labelledby=\"menu-label-${i}\" id=\"${state.searchMode ? 'search-results' : null}\">${\n emojiList(emojiWithCategory.emojis, state.searchMode, /* prefix */ 'emo')\n }</div></div>`\n }, emojiWithCategory => emojiWithCategory.category)\n }</div></div><div class=\"favorites onscreen emoji-menu ${state.message ? 'gone' : ''}\" role=\"menu\" aria-label=\"${state.i18n.favoritesLabel}\" data-on-click=\"onEmojiClick\">${\n emojiList(state.currentFavorites, /* searchMode */ false, /* prefix */ 'fav')\n }</div><button data-ref=\"baselineEmoji\" aria-hidden=\"true\" tabindex=\"-1\" class=\"abs-pos hidden emoji baseline-emoji\">😀</button></section>`\n };\n\n const rootDom = section();\n\n // helper for traversing the dom, finding elements by an attribute, and getting the attribute value\n const forElementWithAttribute = (attributeName, callback) => {\n for (const element of container.querySelectorAll(`[${attributeName}]`)) {\n callback(element, element.getAttribute(attributeName));\n }\n };\n\n if (firstRender) { // not a re-render\n container.appendChild(rootDom);\n\n // we only bind events/refs once - there is no need to find them again given this component structure\n\n // bind events\n for (const eventName of ['click', 'focusout', 'input', 'keydown', 'keyup']) {\n forElementWithAttribute(`data-on-${eventName}`, (element, listenerName) => {\n element.addEventListener(eventName, events[listenerName]);\n });\n }\n\n // find refs\n forElementWithAttribute('data-ref', (element, ref) => {\n refs[ref] = element;\n });\n\n // destroy/abort logic\n abortSignal.addEventListener('abort', () => {\n container.removeChild(rootDom);\n });\n }\n\n // set up actions - these are re-bound on every render\n forElementWithAttribute('data-action', (element, action) => {\n let boundActions = actionContext.get(action);\n if (!boundActions) {\n actionContext.set(action, (boundActions = new WeakSet()));\n }\n\n // avoid applying the same action to the same element multiple times\n if (!boundActions.has(element)) {\n boundActions.add(element);\n actions[action](element);\n }\n });\n}\n\n/* istanbul ignore next */\nconst qM = typeof queueMicrotask === 'function' ? queueMicrotask : callback => Promise.resolve().then(callback);\n\nfunction createState (abortSignal) {\n let destroyed = false;\n let currentObserver;\n\n const propsToObservers = new Map();\n const dirtyObservers = new Set();\n\n let queued;\n\n const flush = () => {\n if (destroyed) {\n return\n }\n const observersToRun = [...dirtyObservers];\n dirtyObservers.clear(); // clear before running to force any new updates to run in another tick of the loop\n try {\n for (const observer of observersToRun) {\n observer();\n }\n } finally {\n queued = false;\n if (dirtyObservers.size) { // new updates, queue another one\n queued = true;\n qM(flush);\n }\n }\n };\n\n const state = new Proxy({}, {\n get (target, prop) {\n if (currentObserver) {\n let observers = propsToObservers.get(prop);\n if (!observers) {\n observers = new Set();\n propsToObservers.set(prop, observers);\n }\n observers.add(currentObserver);\n }\n return target[prop]\n },\n set (target, prop, newValue) {\n if (target[prop] !== newValue) {\n target[prop] = newValue;\n const observers = propsToObservers.get(prop);\n if (observers) {\n for (const observer of observers) {\n dirtyObservers.add(observer);\n }\n if (!queued) {\n queued = true;\n qM(flush);\n }\n }\n }\n return true\n }\n });\n\n const createEffect = (callback) => {\n const runnable = () => {\n const oldObserver = currentObserver;\n currentObserver = runnable;\n try {\n return callback()\n } finally {\n currentObserver = oldObserver;\n }\n };\n return runnable()\n };\n\n // destroy logic\n abortSignal.addEventListener('abort', () => {\n destroyed = true;\n });\n\n return {\n state,\n createEffect\n }\n}\n\n// Compare two arrays, with a function called on each item in the two arrays that returns true if the items are equal\nfunction arraysAreEqualByFunction (left, right, areEqualFunc) {\n if (left.length !== right.length) {\n return false\n }\n for (let i = 0; i < left.length; i++) {\n if (!areEqualFunc(left[i], right[i])) {\n return false\n }\n }\n return true\n}\n\nconst intersectionObserverCache = new WeakMap();\n\nfunction intersectionObserverAction (node, abortSignal, listener) {\n /* istanbul ignore else */\n {\n // The scroll root is always `.tabpanel`\n const root = node.closest('.tabpanel');\n\n let observer = intersectionObserverCache.get(root);\n if (!observer) {\n // TODO: replace this with the contentvisibilityautostatechange event when all supported browsers support it.\n // For now we use IntersectionObserver because it has better cross-browser support, and it would be bad for\n // old Safari versions if they eagerly downloaded all custom emoji all at once.\n observer = new IntersectionObserver(listener, {\n root,\n // trigger if we are 1/2 scroll container height away so that the images load a bit quicker while scrolling\n rootMargin: '50% 0px 50% 0px',\n // trigger if any part of the emoji grid is intersecting\n threshold: 0\n });\n\n // avoid creating a new IntersectionObserver for every category; just use one for the whole root\n intersectionObserverCache.set(root, observer);\n\n // assume that the abortSignal is always the same for this root node; just add one event listener\n abortSignal.addEventListener('abort', () => {\n observer.disconnect();\n });\n }\n\n observer.observe(node);\n }\n}\n\n/* eslint-disable prefer-const,no-labels,no-inner-declarations */\n\n// constants\nconst EMPTY_ARRAY = [];\n\nconst { assign } = Object;\n\nfunction createRoot (shadowRoot, props) {\n const refs = {};\n const abortController = new AbortController();\n const abortSignal = abortController.signal;\n const { state, createEffect } = createState(abortSignal);\n const actionContext = new Map();\n\n // initial state\n assign(state, {\n skinToneEmoji: undefined,\n i18n: undefined,\n database: undefined,\n customEmoji: undefined,\n customCategorySorting: undefined,\n emojiVersion: undefined\n });\n\n // public props\n assign(state, props);\n\n // private props\n assign(state, {\n initialLoad: true,\n currentEmojis: [],\n currentEmojisWithCategories: [],\n rawSearchText: '',\n searchText: '',\n searchMode: false,\n activeSearchItem: -1,\n message: undefined,\n skinTonePickerExpanded: false,\n skinTonePickerExpandedAfterAnimation: false,\n currentSkinTone: 0,\n activeSkinTone: 0,\n skinToneButtonText: undefined,\n pickerStyle: undefined,\n skinToneButtonLabel: '',\n skinTones: [],\n currentFavorites: [],\n defaultFavoriteEmojis: undefined,\n numColumns: DEFAULT_NUM_COLUMNS,\n isRtl: false,\n currentGroupIndex: 0,\n groups: groups,\n databaseLoaded: false,\n activeSearchItemId: undefined\n });\n\n //\n // Update the current group based on the currentGroupIndex\n //\n createEffect(() => {\n if (state.currentGroup !== state.groups[state.currentGroupIndex]) {\n state.currentGroup = state.groups[state.currentGroupIndex];\n }\n });\n\n //\n // Utils/helpers\n //\n\n const focus = id => {\n shadowRoot.getElementById(id).focus();\n };\n\n const emojiToDomNode = emoji => shadowRoot.getElementById(`emo-${emoji.id}`);\n\n // fire a custom event that crosses the shadow boundary\n const fireEvent = (name, detail) => {\n refs.rootElement.dispatchEvent(new CustomEvent(name, {\n detail,\n bubbles: true,\n composed: true\n }));\n };\n\n //\n // Comparison utils\n //\n\n const compareEmojiArrays = (a, b) => a.id === b.id;\n\n const compareCurrentEmojisWithCategories = (a, b) => {\n const { category: aCategory, emojis: aEmojis } = a;\n const { category: bCategory, emojis: bEmojis } = b;\n\n if (aCategory !== bCategory) {\n return false\n }\n\n return arraysAreEqualByFunction(aEmojis, bEmojis, compareEmojiArrays)\n };\n\n //\n // Update utils to avoid excessive re-renders\n //\n\n // avoid excessive re-renders by checking the value before setting\n const updateCurrentEmojis = (newEmojis) => {\n if (!arraysAreEqualByFunction(state.currentEmojis, newEmojis, compareEmojiArrays)) {\n state.currentEmojis = newEmojis;\n }\n };\n\n // avoid excessive re-renders\n const updateSearchMode = (newSearchMode) => {\n if (state.searchMode !== newSearchMode) {\n state.searchMode = newSearchMode;\n }\n };\n\n // avoid excessive re-renders\n const updateCurrentEmojisWithCategories = (newEmojisWithCategories) => {\n if (!arraysAreEqualByFunction(state.currentEmojisWithCategories, newEmojisWithCategories, compareCurrentEmojisWithCategories)) {\n state.currentEmojisWithCategories = newEmojisWithCategories;\n }\n };\n\n // Helpers used by PickerTemplate\n\n const unicodeWithSkin = (emoji, currentSkinTone) => (\n (currentSkinTone && emoji.skins && emoji.skins[currentSkinTone]) || emoji.unicode\n );\n\n const labelWithSkin = (emoji, currentSkinTone) => (\n uniq([\n (emoji.name || unicodeWithSkin(emoji, currentSkinTone)),\n emoji.annotation,\n ...(emoji.shortcodes || EMPTY_ARRAY)\n ].filter(Boolean)).join(', ')\n );\n\n const titleForEmoji = (emoji) => (\n emoji.annotation || (emoji.shortcodes || EMPTY_ARRAY).join(', ')\n );\n\n const helpers = {\n labelWithSkin, titleForEmoji, unicodeWithSkin\n };\n const events = {\n onClickSkinToneButton,\n onEmojiClick,\n onNavClick,\n onNavKeydown,\n onSearchKeydown,\n onSkinToneOptionsClick,\n onSkinToneOptionsFocusOut,\n onSkinToneOptionsKeydown,\n onSkinToneOptionsKeyup,\n onSearchInput\n };\n const actions = {\n calculateEmojiGridStyle,\n updateOnIntersection\n };\n\n let firstRender = true;\n createEffect(() => {\n render(shadowRoot, state, helpers, events, actions, refs, abortSignal, actionContext, firstRender);\n firstRender = false;\n });\n\n //\n // Determine the emoji support level (in requestIdleCallback)\n //\n\n // mount logic\n if (!state.emojiVersion) {\n detectEmojiSupportLevel().then(level => {\n // Can't actually test emoji support in Jest/Vitest/JSDom, emoji never render in color in Cairo\n /* istanbul ignore next */\n if (!level) {\n state.message = state.i18n.emojiUnsupportedMessage;\n }\n });\n }\n\n //\n // Set or update the database object\n //\n\n createEffect(() => {\n // show a Loading message if it takes a long time, or show an error if there's a network/IDB error\n async function handleDatabaseLoading () {\n let showingLoadingMessage = false;\n const timeoutHandle = setTimeout(() => {\n showingLoadingMessage = true;\n state.message = state.i18n.loadingMessage;\n }, TIMEOUT_BEFORE_LOADING_MESSAGE);\n try {\n await state.database.ready();\n state.databaseLoaded = true; // eslint-disable-line no-unused-vars\n } catch (err) {\n console.error(err);\n state.message = state.i18n.networkErrorMessage;\n } finally {\n clearTimeout(timeoutHandle);\n if (showingLoadingMessage) { // Seems safer than checking the i18n string, which may change\n showingLoadingMessage = false;\n state.message = ''; // eslint-disable-line no-unused-vars\n }\n }\n }\n\n if (state.database) {\n /* no await */\n handleDatabaseLoading();\n }\n });\n\n //\n // Global styles for the entire picker\n //\n\n createEffect(() => {\n state.pickerStyle = `\n --num-groups: ${state.groups.length}; \n --indicator-opacity: ${state.searchMode ? 0 : 1}; \n --num-skintones: ${NUM_SKIN_TONES};`;\n });\n\n //\n // Set or update the customEmoji\n //\n\n createEffect(() => {\n if (state.customEmoji && state.database) {\n updateCustomEmoji(); // re-run whenever customEmoji change\n }\n });\n\n createEffect(() => {\n if (state.customEmoji && state.customEmoji.length) {\n if (state.groups !== allGroups) { // don't update unnecessarily\n state.groups = allGroups;\n }\n } else if (state.groups !== groups) {\n if (state.currentGroupIndex) {\n // If the current group is anything other than \"custom\" (which is first), decrement.\n // This fixes the odd case where you set customEmoji, then pick a category, then unset customEmoji\n state.currentGroupIndex--;\n }\n state.groups = groups;\n }\n });\n\n //\n // Set or update the preferred skin tone\n //\n\n createEffect(() => {\n async function updatePreferredSkinTone () {\n if (state.databaseLoaded) {\n state.currentSkinTone = await state.database.getPreferredSkinTone();\n }\n }\n\n /* no await */ updatePreferredSkinTone();\n });\n\n createEffect(() => {\n state.skinTones = Array(NUM_SKIN_TONES).fill().map((_, i) => applySkinTone(state.skinToneEmoji, i));\n });\n\n createEffect(() => {\n state.skinToneButtonText = state.skinTones[state.currentSkinTone];\n });\n\n createEffect(() => {\n state.skinToneButtonLabel = state.i18n.skinToneLabel.replace('{skinTone}', state.i18n.skinTones[state.currentSkinTone]);\n });\n\n //\n // Set or update the favorites emojis\n //\n\n createEffect(() => {\n async function updateDefaultFavoriteEmojis () {\n const { database } = state;\n const favs = (await Promise.all(MOST_COMMONLY_USED_EMOJI.map(unicode => (\n database.getEmojiByUnicodeOrName(unicode)\n )))).filter(Boolean); // filter because in Jest/Vitest tests we don't have all the emoji in the DB\n state.defaultFavoriteEmojis = favs;\n }\n\n if (state.databaseLoaded) {\n /* no await */ updateDefaultFavoriteEmojis();\n }\n });\n\n function updateCustomEmoji () {\n // Certain effects have an implicit dependency on customEmoji since it affects the database\n // Getting it here on the state ensures this effect re-runs when customEmoji change.\n const { customEmoji, database } = state;\n const databaseCustomEmoji = customEmoji || EMPTY_ARRAY;\n if (database.customEmoji !== databaseCustomEmoji) {\n // Avoid setting this if the customEmoji have _not_ changed, because the setter triggers a re-computation of the\n // `customEmojiIndex`. Note we don't bother with deep object changes.\n database.customEmoji = databaseCustomEmoji;\n }\n }\n\n createEffect(() => {\n async function updateFavorites () {\n updateCustomEmoji(); // re-run whenever customEmoji change\n const { database, defaultFavoriteEmojis, numColumns } = state;\n const dbFavorites = await database.getTopFavoriteEmoji(numColumns);\n const favorites = await summarizeEmojis(uniqBy([\n ...dbFavorites,\n ...defaultFavoriteEmojis\n ], _ => (_.unicode || _.name)).slice(0, numColumns));\n state.currentFavorites = favorites;\n }\n\n if (state.databaseLoaded && state.defaultFavoriteEmojis) {\n /* no await */ updateFavorites();\n }\n });\n\n //\n // Re-run whenever the emoji grid changes size, and re-calc style/layout-related state variables:\n // 1) Re-calculate the --num-columns var because it may have changed\n // 2) Re-calculate whether we're in RTL mode or not.\n //\n // The benefit of doing this in one place is to align with rAF/ResizeObserver\n // and do all the calculations in one go. RTL vs LTR is not strictly layout-related,\n // but since we're already reading the style here, and since it's already aligned with\n // the rAF loop, this is the most appropriate place to do it perf-wise.\n //\n\n function calculateEmojiGridStyle (node) {\n resizeObserverAction(node, abortSignal, () => {\n /* istanbul ignore next */\n { // jsdom throws errors for this kind of fancy stuff\n // read all the style/layout calculations we need to make\n const style = getComputedStyle(refs.rootElement);\n const newNumColumns = parseInt(style.getPropertyValue('--num-columns'), 10);\n const newIsRtl = style.getPropertyValue('direction') === 'rtl';\n\n // write to state variables\n state.numColumns = newNumColumns;\n state.isRtl = newIsRtl;\n }\n });\n }\n\n // Re-run whenever the custom emoji in a category are shown/hidden. This is an optimization that simulates\n // what we'd get from `<img loading=lazy>` but without rendering an `<img>`.\n function updateOnIntersection (node) {\n intersectionObserverAction(node, abortSignal, (entries) => {\n for (const { target, isIntersecting } of entries) {\n target.classList.toggle('onscreen', isIntersecting);\n }\n });\n }\n\n //\n // Set or update the currentEmojis. Check for invalid ZWJ renderings\n // (i.e. double emoji).\n //\n\n createEffect(() => {\n async function updateEmojis () {\n const { searchText, currentGroup, databaseLoaded, customEmoji } = state;\n if (!databaseLoaded) {\n state.currentEmojis = [];\n state.searchMode = false;\n } else if (searchText.length >= MIN_SEARCH_TEXT_LENGTH) {\n const newEmojis = await getEmojisBySearchQuery(searchText);\n if (state.searchText === searchText) { // if the situation changes asynchronously, do not update\n updateCurrentEmojis(newEmojis);\n updateSearchMode(true);\n }\n } else { // database is loaded and we're not in search mode, so we're in normal category mode\n const { id: currentGroupId } = currentGroup;\n // avoid race condition where currentGroupId is -1 and customEmoji is undefined/empty\n if (currentGroupId !== -1 || (customEmoji && customEmoji.length)) {\n const newEmojis = await getEmojisByGroup(currentGroupId);\n if (state.currentGroup.id === currentGroupId) { // if the situation changes asynchronously, do not update\n updateCurrentEmojis(newEmojis);\n updateSearchMode(false);\n }\n }\n }\n }\n\n /* no await */ updateEmojis();\n });\n\n const resetScrollTopInRaf = () => {\n rAF(() => resetScrollTopIfPossible(refs.tabpanelElement));\n };\n\n // Some emojis have their ligatures rendered as two or more consecutive emojis\n // We want to treat these the same as unsupported emojis, so we compare their\n // widths against the baseline widths and remove them as necessary\n createEffect(() => {\n const { currentEmojis, emojiVersion } = state;\n const zwjEmojisToCheck = currentEmojis\n .filter(emoji => emoji.unicode) // filter custom emoji\n .filter(emoji => hasZwj(emoji) && !supportedZwjEmojis.has(emoji.unicode));\n if (!emojiVersion && zwjEmojisToCheck.length) {\n // render now, check their length later\n updateCurrentEmojis(currentEmojis);\n rAF(() => checkZwjSupportAndUpdate(zwjEmojisToCheck));\n } else {\n const newEmojis = emojiVersion ? currentEmojis : currentEmojis.filter(isZwjSupported);\n updateCurrentEmojis(newEmojis);\n // Reset scroll top to 0 when emojis change\n resetScrollTopInRaf();\n }\n });\n\n function checkZwjSupportAndUpdate (zwjEmojisToCheck) {\n const allSupported = checkZwjSupport(zwjEmojisToCheck, refs.baselineEmoji, emojiToDomNode);\n if (allSupported) {\n // Even if all emoji are supported, we still need to reset the scroll top to 0 when emojis change\n resetScrollTopInRaf();\n } else {\n // Force update. We only do this if there are any unsupported ZWJ characters since otherwise,\n // for browsers that support all emoji, it would be an unnecessary extra re-render.\n state.currentEmojis = [...state.currentEmojis];\n }\n }\n\n function isZwjSupported (emoji) {\n return !emoji.unicode || !hasZwj(emoji) || supportedZwjEmojis.get(emoji.unicode)\n }\n\n async function filterEmojisByVersion (emojis) {\n const emojiSupportLevel = state.emojiVersion || await detectEmojiSupportLevel();\n // !version corresponds to custom emoji\n return emojis.filter(({ version }) => !version || version <= emojiSupportLevel)\n }\n\n async function summarizeEmojis (emojis) {\n return summarizeEmojisForUI(emojis, state.emojiVersion || await detectEmojiSupportLevel())\n }\n\n async function getEmojisByGroup (group) {\n // -1 is custom emoji\n const emoji = group === -1 ? state.customEmoji : await state.database.getEmojiByGroup(group);\n return summarizeEmojis(await filterEmojisByVersion(emoji))\n }\n\n async function getEmojisBySearchQuery (query) {\n return summarizeEmojis(await filterEmojisByVersion(await state.database.getEmojiBySearchQuery(query)))\n }\n\n createEffect(() => {\n });\n\n //\n // Derive currentEmojisWithCategories from currentEmojis. This is always done even if there\n // are no categories, because it's just easier to code the HTML this way.\n //\n\n createEffect(() => {\n function calculateCurrentEmojisWithCategories () {\n const { searchMode, currentEmojis } = state;\n if (searchMode) {\n return [\n {\n category: '',\n emojis: currentEmojis\n }\n ]\n }\n const categoriesToEmoji = new Map();\n for (const emoji of currentEmojis) {\n const category = emoji.category || '';\n let emojis = categoriesToEmoji.get(category);\n if (!emojis) {\n emojis = [];\n categoriesToEmoji.set(category, emojis);\n }\n emojis.push(emoji);\n }\n return [...categoriesToEmoji.entries()]\n .map(([category, emojis]) => ({ category, emojis }))\n .sort((a, b) => state.customCategorySorting(a.category, b.category))\n }\n\n const newEmojisWithCategories = calculateCurrentEmojisWithCategories();\n updateCurrentEmojisWithCategories(newEmojisWithCategories);\n });\n\n //\n // Handle active search item (i.e. pressing up or down while searching)\n //\n\n createEffect(() => {\n state.activeSearchItemId = state.activeSearchItem !== -1 && state.currentEmojis[state.activeSearchItem].id;\n });\n\n //\n // Handle user input on the search input\n //\n\n createEffect(() => {\n const { rawSearchText } = state;\n rIC(() => {\n state.searchText = (rawSearchText || '').trim(); // defer to avoid input delays, plus we can trim here\n state.activeSearchItem = -1;\n });\n });\n\n function onSearchKeydown (event) {\n if (!state.searchMode || !state.currentEmojis.length) {\n return\n }\n\n const goToNextOrPrevious = (previous) => {\n halt(event);\n state.activeSearchItem = incrementOrDecrement(previous, state.activeSearchItem, state.currentEmojis);\n };\n\n switch (event.key) {\n case 'ArrowDown':\n return goToNextOrPrevious(false)\n case 'ArrowUp':\n return goToNextOrPrevious(true)\n case 'Enter':\n if (state.activeSearchItem === -1) {\n // focus the first option in the list since the list must be non-empty at this point (it's verified above)\n state.activeSearchItem = 0;\n } else { // there is already an active search item\n halt(event);\n return clickEmoji(state.currentEmojis[state.activeSearchItem].id)\n }\n }\n }\n\n //\n // Handle user input on nav\n //\n\n function onNavClick (event) {\n const { target } = event;\n const closestTarget = target.closest('.nav-button');\n /* istanbul ignore if */\n if (!closestTarget) {\n return // This should never happen, but makes me nervous not to have it\n }\n const groupId = parseInt(closestTarget.dataset.groupId, 10);\n refs.searchElement.value = ''; // clear search box input\n state.rawSearchText = '';\n state.searchText = '';\n state.activeSearchItem = -1;\n state.currentGroupIndex = state.groups.findIndex(_ => _.id === groupId);\n }\n\n function onNavKeydown (event) {\n const { target, key } = event;\n\n const doFocus = el => {\n if (el) {\n halt(event);\n el.focus();\n }\n };\n\n switch (key) {\n case 'ArrowLeft':\n return doFocus(target.previousElementSibling)\n case 'ArrowRight':\n return doFocus(target.nextElementSibling)\n case 'Home':\n return doFocus(target.parentElement.firstElementChild)\n case 'End':\n return doFocus(target.parentElement.lastElementChild)\n }\n }\n\n async function getDetailForClickEvent (unicodeOrName) {\n const emoji = await state.database.getEmojiByUnicodeOrName(unicodeOrName);\n const emojiSummary = [...state.currentEmojis, ...state.currentFavorites]\n .find(_ => (_.id === unicodeOrName));\n const skinTonedUnicode = emojiSummary.unicode && unicodeWithSkin(emojiSummary, state.currentSkinTone);\n await state.database.incrementFavoriteEmojiCount(unicodeOrName);\n return {\n emoji,\n skinTone: state.currentSkinTone,\n ...(skinTonedUnicode && { unicode: skinTonedUnicode }),\n ...(emojiSummary.name && { name: emojiSummary.name })\n }\n }\n\n //\n // Handle user input on an emoji\n //\n async function clickEmoji (unicodeOrName) {\n const promiseForDetail = getDetailForClickEvent(unicodeOrName);\n // sync event to work around a safari bug: https://bugs.webkit.org/show_bug.cgi?id=222262\n fireEvent('emoji-click-sync', promiseForDetail);\n // async event for most normal use cases that don't need to work around the safari bug\n fireEvent('emoji-click', await promiseForDetail);\n }\n\n function onEmojiClick (event) {\n const { target } = event;\n /* istanbul ignore if */\n if (!target.classList.contains('emoji')) {\n // This should never happen, but makes me nervous not to have it\n return\n }\n halt(event);\n const id = target.id.substring(4); // replace 'emo-' or 'fav-' prefix\n\n /* no await */ clickEmoji(id);\n }\n\n //\n // Handle user input on the skintone picker\n //\n\n function changeSkinTone (skinTone) {\n state.currentSkinTone = skinTone;\n state.skinTonePickerExpanded = false;\n focus('skintone-button');\n fireEvent('skin-tone-change', { skinTone });\n /* no await */ state.database.setPreferredSkinTone(skinTone);\n }\n\n function onSkinToneOptionsClick (event) {\n const { target: { id } } = event;\n const match = id && id.match(/^skintone-(\\d)/); // skintone option format\n /* istanbul ignore if */\n if (!match) { // not a skintone option\n return // This should never happen, but makes me nervous not to have it\n }\n halt(event);\n const skinTone = parseInt(match[1], 10); // remove 'skintone-' prefix\n changeSkinTone(skinTone);\n }\n\n function onClickSkinToneButton (event) {\n state.skinTonePickerExpanded = !state.skinTonePickerExpanded;\n state.activeSkinTone = state.currentSkinTone;\n // this should always be true, since the button is obscured by the listbox, so this `if` is just to be sure\n if (state.skinTonePickerExpanded) {\n halt(event);\n rAF(() => focus('skintone-list'));\n }\n }\n\n // To make the animation nicer, change the z-index of the skintone picker button\n // *after* the animation has played. This makes it appear that the picker box\n // is expanding \"below\" the button\n createEffect(() => {\n if (state.skinTonePickerExpanded) {\n refs.skinToneDropdown.addEventListener('transitionend', () => {\n state.skinTonePickerExpandedAfterAnimation = true; // eslint-disable-line no-unused-vars\n }, { once: true });\n } else {\n state.skinTonePickerExpandedAfterAnimation = false; // eslint-disable-line no-unused-vars\n }\n });\n\n function onSkinToneOptionsKeydown (event) {\n // this should never happen, but makes me nervous not to have it\n /* istanbul ignore if */\n if (!state.skinTonePickerExpanded) {\n return\n }\n const changeActiveSkinTone = async nextSkinTone => {\n halt(event);\n state.activeSkinTone = nextSkinTone;\n };\n\n switch (event.key) {\n case 'ArrowUp':\n return changeActiveSkinTone(incrementOrDecrement(true, state.activeSkinTone, state.skinTones))\n case 'ArrowDown':\n return changeActiveSkinTone(incrementOrDecrement(false, state.activeSkinTone, state.skinTones))\n case 'Home':\n return changeActiveSkinTone(0)\n case 'End':\n return changeActiveSkinTone(state.skinTones.length - 1)\n case 'Enter':\n // enter on keydown, space on keyup. this is just how browsers work for buttons\n // https://lists.w3.org/Archives/Public/w3c-wai-ig/2019JanMar/0086.html\n halt(event);\n return changeSkinTone(state.activeSkinTone)\n case 'Escape':\n halt(event);\n state.skinTonePickerExpanded = false;\n return focus('skintone-button')\n }\n }\n\n function onSkinToneOptionsKeyup (event) {\n // this should never happen, but makes me nervous not to have it\n /* istanbul ignore if */\n if (!state.skinTonePickerExpanded) {\n return\n }\n switch (event.key) {\n case ' ':\n // enter on keydown, space on keyup. this is just how browsers work for buttons\n // https://lists.w3.org/Archives/Public/w3c-wai-ig/2019JanMar/0086.html\n halt(event);\n return changeSkinTone(state.activeSkinTone)\n }\n }\n\n async function onSkinToneOptionsFocusOut (event) {\n // On blur outside of the skintone listbox, collapse the skintone picker.\n const { relatedTarget } = event;\n // The `else` should never happen, but makes me nervous not to have it\n /* istanbul ignore else */\n if (!relatedTarget || relatedTarget.id !== 'skintone-list') {\n state.skinTonePickerExpanded = false;\n }\n }\n\n function onSearchInput (event) {\n state.rawSearchText = event.target.value;\n }\n\n return {\n $set (newState) {\n assign(state, newState);\n },\n $destroy () {\n abortController.abort();\n }\n }\n}\n\nconst DEFAULT_DATA_SOURCE = 'https://cdn.jsdelivr.net/npm/emoji-picker-element-data@^1/en/emojibase/data.json';\nconst DEFAULT_LOCALE = 'en';\n\nvar enI18n = {\n categoriesLabel: 'Categories',\n emojiUnsupportedMessage: 'Your browser does not support color emoji.',\n favoritesLabel: 'Favorites',\n loadingMessage: 'Loading…',\n networkErrorMessage: 'Could not load emoji.',\n regionLabel: 'Emoji picker',\n searchDescription: 'When search results are available, press up or down to select and enter to choose.',\n searchLabel: 'Search',\n searchResultsLabel: 'Search results',\n skinToneDescription: 'When expanded, press up or down to select and enter to choose.',\n skinToneLabel: 'Choose a skin tone (currently {skinTone})',\n skinTonesLabel: 'Skin tones',\n skinTones: [\n 'Default',\n 'Light',\n 'Medium-Light',\n 'Medium',\n 'Medium-Dark',\n 'Dark'\n ],\n categories: {\n custom: 'Custom',\n 'smileys-emotion': 'Smileys and emoticons',\n 'people-body': 'People and body',\n 'animals-nature': 'Animals and nature',\n 'food-drink': 'Food and drink',\n 'travel-places': 'Travel and places',\n activities: 'Activities',\n objects: 'Objects',\n symbols: 'Symbols',\n flags: 'Flags'\n }\n};\n\nvar baseStyles = \":host{--emoji-size:1.375rem;--emoji-padding:0.5rem;--category-emoji-size:var(--emoji-size);--category-emoji-padding:var(--emoji-padding);--indicator-height:3px;--input-border-radius:0.5rem;--input-border-size:1px;--input-font-size:1rem;--input-line-height:1.5;--input-padding:0.25rem;--num-columns:8;--outline-size:2px;--border-size:1px;--border-radius:0;--skintone-border-radius:1rem;--category-font-size:1rem;display:flex;width:min-content;height:400px}:host,:host(.light){color-scheme:light;--background:#fff;--border-color:#e0e0e0;--indicator-color:#385ac1;--input-border-color:#999;--input-font-color:#111;--input-placeholder-color:#999;--outline-color:#999;--category-font-color:#111;--button-active-background:#e6e6e6;--button-hover-background:#d9d9d9}:host(.dark){color-scheme:dark;--background:#222;--border-color:#444;--indicator-color:#5373ec;--input-border-color:#ccc;--input-font-color:#efefef;--input-placeholder-color:#ccc;--outline-color:#fff;--category-font-color:#efefef;--button-active-background:#555555;--button-hover-background:#484848}@media (prefers-color-scheme:dark){:host{color-scheme:dark;--background:#222;--border-color:#444;--indicator-color:#5373ec;--input-border-color:#ccc;--input-font-color:#efefef;--input-placeholder-color:#ccc;--outline-color:#fff;--category-font-color:#efefef;--button-active-background:#555555;--button-hover-background:#484848}}:host([hidden]){display:none}button{margin:0;padding:0;border:0;background:0 0;box-shadow:none;-webkit-tap-highlight-color:transparent}button::-moz-focus-inner{border:0}input{padding:0;margin:0;line-height:1.15;font-family:inherit}input[type=search]{-webkit-appearance:none}:focus{outline:var(--outline-color) solid var(--outline-size);outline-offset:calc(-1*var(--outline-size))}:host([data-js-focus-visible]) :focus:not([data-focus-visible-added]){outline:0}:focus:not(:focus-visible){outline:0}.hide-focus{outline:0}*{box-sizing:border-box}.picker{contain:content;display:flex;flex-direction:column;background:var(--background);border:var(--border-size) solid var(--border-color);border-radius:var(--border-radius);width:100%;height:100%;overflow:hidden;--total-emoji-size:calc(var(--emoji-size) + (2 * var(--emoji-padding)));--total-category-emoji-size:calc(var(--category-emoji-size) + (2 * var(--category-emoji-padding)))}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.hidden{opacity:0;pointer-events:none}.abs-pos{position:absolute;left:0;top:0}.gone{display:none!important}.skintone-button-wrapper,.skintone-list{background:var(--background);z-index:3}.skintone-button-wrapper.expanded{z-index:1}.skintone-list{position:absolute;inset-inline-end:0;top:0;z-index:2;overflow:visible;border-bottom:var(--border-size) solid var(--border-color);border-radius:0 0 var(--skintone-border-radius) var(--skintone-border-radius);will-change:transform;transition:transform .2s ease-in-out;transform-origin:center 0}@media (prefers-reduced-motion:reduce){.skintone-list{transition-duration:.001s}}@supports not (inset-inline-end:0){.skintone-list{right:0}}.skintone-list.no-animate{transition:none}.tabpanel{overflow-y:auto;scrollbar-gutter:stable;-webkit-overflow-scrolling:touch;will-change:transform;min-height:0;flex:1;contain:content}.emoji-menu{display:grid;grid-template-columns:repeat(var(--num-columns),var(--total-emoji-size));justify-content:space-around;align-items:flex-start;width:100%}.emoji-menu.visibility-auto{content-visibility:auto;contain-intrinsic-size:calc(var(--num-columns)*var(--total-emoji-size)) calc(var(--num-rows)*var(--total-emoji-size))}.category{padding:var(--emoji-padding);font-size:var(--category-font-size);color:var(--category-font-color)}.emoji,button.emoji{font-size:var(--emoji-size);display:flex;align-items:center;justify-content:center;border-radius:100%;height:var(--total-emoji-size);width:var(--total-emoji-size);line-height:1;overflow:hidden;font-family:var(--emoji-font-family);cursor:pointer}@media (hover:hover) and (pointer:fine){.emoji:hover,button.emoji:hover{background:var(--button-hover-background)}}.emoji.active,.emoji:active,button.emoji.active,button.emoji:active{background:var(--button-active-background)}.onscreen .custom-emoji::after{content:\\\"\\\";width:var(--emoji-size);height:var(--emoji-size);background-repeat:no-repeat;background-position:center center;background-size:contain;background-image:var(--custom-emoji-background)}.nav,.nav-button{align-items:center}.nav{display:grid;justify-content:space-between;contain:content}.nav-button{display:flex;justify-content:center}.nav-emoji{font-size:var(--category-emoji-size);width:var(--total-category-emoji-size);height:var(--total-category-emoji-size)}.indicator-wrapper{display:flex;border-bottom:1px solid var(--border-color)}.indicator{width:calc(100%/var(--num-groups));height:var(--indicator-height);opacity:var(--indicator-opacity);background-color:var(--indicator-color);will-change:transform,opacity;transition:opacity .1s linear,transform .25s ease-in-out}@media (prefers-reduced-motion:reduce){.indicator{will-change:opacity;transition:opacity .1s linear}}.pad-top,input.search{background:var(--background);width:100%}.pad-top{height:var(--emoji-padding);z-index:3}.search-row{display:flex;align-items:center;position:relative;padding-inline-start:var(--emoji-padding);padding-bottom:var(--emoji-padding)}.search-wrapper{flex:1;min-width:0}input.search{padding:var(--input-padding);border-radius:var(--input-border-radius);border:var(--input-border-size) solid var(--input-border-color);color:var(--input-font-color);font-size:var(--input-font-size);line-height:var(--input-line-height)}input.search::placeholder{color:var(--input-placeholder-color)}.favorites{overflow-y:auto;scrollbar-gutter:stable;display:flex;flex-direction:row;border-top:var(--border-size) solid var(--border-color);contain:content}.message{padding:var(--emoji-padding)}\";\n\nconst PROPS = [\n 'customEmoji',\n 'customCategorySorting',\n 'database',\n 'dataSource',\n 'i18n',\n 'locale',\n 'skinToneEmoji',\n 'emojiVersion'\n];\n\n// Styles injected ourselves, so we can declare the FONT_FAMILY variable in one place\nconst EXTRA_STYLES = `:host{--emoji-font-family:${FONT_FAMILY}}`;\n\nclass PickerElement extends HTMLElement {\n constructor (props) {\n super();\n this.attachShadow({ mode: 'open' });\n const style = document.createElement('style');\n style.textContent = baseStyles + EXTRA_STYLES;\n this.shadowRoot.appendChild(style);\n this._ctx = {\n // Set defaults\n locale: DEFAULT_LOCALE,\n dataSource: DEFAULT_DATA_SOURCE,\n skinToneEmoji: DEFAULT_SKIN_TONE_EMOJI,\n customCategorySorting: DEFAULT_CATEGORY_SORTING,\n customEmoji: null,\n i18n: enI18n,\n emojiVersion: null,\n ...props\n };\n // Handle properties set before the element was upgraded\n for (const prop of PROPS) {\n if (prop !== 'database' && Object.prototype.hasOwnProperty.call(this, prop)) {\n this._ctx[prop] = this[prop];\n delete this[prop];\n }\n }\n this._dbFlush(); // wait for a flush before creating the db, in case the user calls e.g. a setter or setAttribute\n }\n\n connectedCallback () {\n rescueElementPrototype(this);\n // The _cmp may be defined if the component was immediately disconnected and then reconnected. In that case,\n // do nothing (preserve the state)\n if (!this._cmp) {\n this._cmp = createRoot(this.shadowRoot, this._ctx);\n }\n }\n\n disconnectedCallback () {\n rescueElementPrototype(this);\n // Check in a microtask if the element is still connected. If so, treat this as a \"move\" rather than a disconnect\n // Inspired by Vue: https://vuejs.org/guide/extras/web-components.html#building-custom-elements-with-vue\n qM(() => {\n // this._cmp may be defined if connect-disconnect-connect-disconnect occurs synchronously\n if (!this.isConnected && this._cmp) {\n this._cmp.$destroy();\n this._cmp = undefined;\n\n const { database } = this._ctx;\n database.close()\n // only happens if the database failed to load in the first place, so we don't care\n .catch(err => console.error(err));\n }\n });\n }\n\n static get observedAttributes () {\n return ['locale', 'data-source', 'skin-tone-emoji', 'emoji-version'] // complex objects aren't supported, also use kebab-case\n }\n\n attributeChangedCallback (attrName, oldValue, newValue) {\n this._set(\n // convert from kebab-case to camelcase\n // see https://github.com/sveltejs/svelte/issues/3852#issuecomment-665037015\n attrName.replace(/-([a-z])/g, (_, up) => up.toUpperCase()),\n // convert string attribute to float if necessary\n attrName === 'emoji-version' ? parseFloat(newValue) : newValue\n );\n }\n\n _set (prop, newValue) {\n this._ctx[prop] = newValue;\n if (this._cmp) {\n this._cmp.$set({ [prop]: newValue });\n }\n if (['locale', 'dataSource'].includes(prop)) {\n this._dbFlush();\n }\n }\n\n _dbCreate () {\n const { locale, dataSource, database } = this._ctx;\n // only create a new database if we really need to\n if (!database || database.locale !== locale || database.dataSource !== dataSource) {\n this._set('database', new Database({ locale, dataSource }));\n }\n }\n\n // Update the Database in one microtask if the locale/dataSource change. We do one microtask\n // so we don't create two Databases if e.g. both the locale and the dataSource change\n _dbFlush () {\n qM(() => (\n this._dbCreate()\n ));\n }\n}\n\nconst definitions = {};\n\nfor (const prop of PROPS) {\n definitions[prop] = {\n get () {\n if (prop === 'database') {\n // in rare cases, the microtask may not be flushed yet, so we need to instantiate the DB\n // now if the user is asking for it\n this._dbCreate();\n }\n return this._ctx[prop]\n },\n set (val) {\n if (prop === 'database') {\n throw new Error('database is read-only')\n }\n this._set(prop, val);\n }\n };\n}\n\nObject.defineProperties(PickerElement.prototype, definitions);\n\n// See https://jakearchibald.com/2025/firefox-custom-elements-iframes-bug/\n// TODO: remove when the Firefox bug is fixed: https://bugzilla.mozilla.org/show_bug.cgi?id=1502814\nfunction rescueElementPrototype (element) {\n /* istanbul ignore if */\n if (!(element instanceof PickerElement)) {\n Object.setPrototypeOf(element, customElements.get(element.tagName.toLowerCase()).prototype);\n }\n}\n\n/* istanbul ignore else */\nif (!customElements.get('emoji-picker')) { // if already defined, do nothing (e.g. same script imported twice)\n customElements.define('emoji-picker', PickerElement);\n}\n\nexport { PickerElement as default, rescueElementPrototype };\n"],"x_google_ignoreList":[0,1],"mappings":"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"}
|