Repository: exadel-inc/esl
Pull request #1846 (2023-08-04 09:49:27)

[:rocket: esl-share]: add out of the box share config default
Closes: #1823 



Patch:
diff --git a/package.json b/package.json
index 3beec00a6..46d2cd095 100644
--- a/package.json
+++ b/package.json
@@ -45,8 +45,10 @@
     "src/modules/lib.ts",
     "modules/esl-media/providers/**/*.js",
     "modules/esl-share/actions/**/*.js",
+    "modules/esl-share/buttons/**/*.js",
     "src/modules/esl-media/providers/**/*.ts",
     "src/modules/esl-share/actions/**/*.ts",
+    "src/modules/esl-share/buttons/**/*.ts",
     "polyfills/**/*.js",
     "src/polyfills/**/*.ts",
     "pages/src/**/*.ts"
diff --git a/src/modules/esl-share/README.md b/src/modules/esl-share/README.md
index 856a01b31..df5cdb3ac 100644
--- a/src/modules/esl-share/README.md
+++ b/src/modules/esl-share/README.md
@@ -22,15 +22,70 @@ Next, you have two options for using the share component. The first option is to
 
 The second option to use the share component is to define the component configuration and bind it to the ESLShare. After that, all you have to do is to add an element with names or groups of social networks to the ESLShare markup. The item content, consisting of a set of buttons, will be generated automatically. It's the same as you would add each button to the markup and prescribe its configuration manually.
 
-To use this option it is necessary to set the configuration for the list of buttons
-```typescript
+To use this option it is necessary to set the configuration for the list of buttons and then register the item
+`ESLShare.register();`
+
+### Binding a component configuration
+
+If you want to define the behavior of the share components only by specifying a name or a group of buttons, you will have to specify the configuration of the components.
+
+There are several different ways to do this. And you can easily determine the most suitable way for you.
+
+The first option is an asynchronous way to load the config. You prepare a configuration file or service in advance that will return a configuration object. You just should write the provider function of the config
+```
+() => fetch('/assets/share/config.json').then((response) => response.json())
+```
+and setup configuration in this manner
+```
+ESLShareConfig.set(() => fetch('/assets/share/config.json').then((response) => response.json()));
+```
+or can use the alias
+```
 ESLShare.config(() => fetch('/assets/share/config.json').then((response) => response.json()));
 ```
-and then register the item
-`ESLShare.register();`
+
+The following option is very similar to the first, but instead of an asynchronous configuration provider function, you use a pre-prepared configuration object.
+```
+ESLShareConfig.create(myShareConfigurationObject);
+```
+or can use 
+```
+ESLShareConfig.set(myShareConfigurationObject);
+```
+
+The difference between these two methods is obtained only in the fact that in the first case, the configuration instance is returned and in the second case promise is returned.
+
+There is also a third way to set the configuration. You do not need to prepare an object with the definition of the configuration in advance. You just need to create an empty configuration object and add the commands you need. You can also add groups to the configuration. For example
+```
+ESLShareConfig.create().add(
+  [
+    facebook,
+    linkedin,
+    copy
+  ],
+  [
+    {name: 'mygroup', list: 'facebook linkedin copy'}
+  ]
+);
+```
+
+Thus, we added 3 buttons `facebook`, `linkedin`, `copy` and described the `mygroup` group containing these buttons. You can prepare the button configurations yourself, or you can import them from the `/src/modules/esl-share/config/` directory. There we have prepared for you in advance about 20 configurations for various actions to share.
+
+You can also override the settings of any buttons or groups in the runtime.
+For example, a different set of share buttons for the Japanese locale and override the copy button.
+```
+ESLShare.config(() => fetch('/assets/share/config.json').then((response) => response.json()))
+  .then((config) => {
+    if (locale === 'ja') config.add([anotherCopy], [{name: 'mygroup', list: 'hatena linkedin copy'}]);
+  });
+```
+
+In the example above, the configuration will be received by an asynchronous request, and then, if the condition is met, the button and the group `mygroup` will be inserted or replaced (if the configuration for an entity with the same name already exists).
 
 ### ESLShare config
 
+Above it was told and shown how you can set the configuration of the component. But what is a configuration object?
+
 Config is a javascript object that contains two properties. The first one is `buttons` describing the configuration of the buttons. The second is `groups` which configures the groups. Both properties are arrays containing objects describing buttons and groups respectively.
 
 An example of a description of the button configuration:
@@ -107,15 +162,6 @@ ESLShare provides several actions available for you to use:
 
 For using actions you should import the required actions before setting up the configuration and registering ESLShare components. When an unregistered action is specified for a button, the button will not be able to perform the share action and will be marked as 'unavailable'. The same behavior occurs if the action is unavailable on the user's device, e.g. native action on the user's desktop.
 
-### Setting the ESLShare configuration
-
-Before registering an ESLShare item, you must set the component configuration. To do this, use the static `ESLShare.config()` method of the component, which either receives as an argument a config object or a provider function that returns a promise of a config object.
-
-For example:
-```typescript
-ESLShare.config(() => fetch('/assets/share/config.json').then((response) => response.json()));
-```
-
 ### ESLShareButton
 
 #### Attributes / Properties
diff --git a/src/modules/esl-share/buttons/blogger.ts b/src/modules/esl-share/buttons/blogger.ts
new file mode 100644
index 000000000..a5891cdff
--- /dev/null
+++ b/src/modules/esl-share/buttons/blogger.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const blogger: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 32 32"><path d="M19.864 21.38H11.84a1.712 1.712 0 010-3.425h8.024a1.712 1.712 0 010 3.425zm-7.542-11.27l4.012.063a1.712 1.712 0 01-.054 3.424l-4.012-.064a1.712 1.712 0 01.054-3.424zm13.4 9.404c-.007-.374-.008-.71-.01-1.014-.006-1.58-.012-2.83-1.016-3.803-.716-.694-1.565-.914-2.855-.962.176-.747.226-1.575.145-2.47-.02-2.973-2.234-5.18-5.304-5.264h-.043l-4.692.072c-1.844-.007-3.3.53-4.332 1.606-.638.666-1.362 1.83-1.45 3.72H6.16v.057a8.6 8.6 0 00-.006.393l-.12 7.125c-.008.143-.015.288-.016.437-.12 2.088.372 3.728 1.463 4.876 1.078 1.132 2.664 1.706 4.715 1.706h7.32c1.84-.017 3.393-.624 4.494-1.757 1.1-1.132 1.692-2.743 1.713-4.66v-.06z" fill-rule="evenodd"/></svg>',
+  iconBackground: '#f57d00',
+  link: '//blogger.com/blog-this.g?n={t}&u={u}',
+  name: 'blogger',
+  title: 'Blogger'
+};
+ESLShareConfig.instance.appendButton(blogger);
diff --git a/src/modules/esl-share/buttons/copy.ts b/src/modules/esl-share/buttons/copy.ts
new file mode 100644
index 000000000..4e4d91d5b
--- /dev/null
+++ b/src/modules/esl-share/buttons/copy.ts
@@ -0,0 +1,18 @@
+/* eslint-disable max-len */
+import '../actions/copy-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const copy: ESLShareButtonConfig = {
+  action: 'copy',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 28 28"><path d="M17 9.69l-7.43 7.43 1.18 1.18 7.43-7.43L17 9.69z"/><path d="M4.31 17.8c-.481.481-.48 1.29.00138 1.77l4.02 4.02c.481.481 1.29.483 1.77.00138l4.95-4.95c.481-.481.481-1.29-7e-7-1.78l-4.02-4.02c-.481-.481-1.29-.481-1.78 0l-4.95 4.95zm1.47.887l4.36-4.36 3.44 3.44-4.36 4.36-3.44-3.44zm7-9.37c-.481.481-.481 1.29 2.8e-7 1.78l4.02 4.02c.481.481 1.29.481 1.78 0l4.95-4.95c.481-.481.48-1.29-.00138-1.77l-4.02-4.02c-.481-.481-1.29-.483-1.77-.00138l-4.95 4.95zm1.47.889l4.36-4.36 3.44 3.44-4.36 4.36-3.44-3.44z"/></svg>',
+  iconBackground: '#a0522d',
+  link: '',
+  name: 'copy',
+  title: 'Copy',
+  additional: {
+    alertText: 'Copied to clipboard'
+  }
+};
+ESLShareConfig.instance.appendButton(copy);
diff --git a/src/modules/esl-share/buttons/facebook.ts b/src/modules/esl-share/buttons/facebook.ts
new file mode 100644
index 000000000..e5d44e723
--- /dev/null
+++ b/src/modules/esl-share/buttons/facebook.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const facebook: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 27.99 28"><path d="M23 17.11l.55-4.24h-4.2v-2.71c0-1.23.34-2.06 2.1-2.06h2.25V4.29a31.62 31.62 0 00-3.28-.16c-3.24 0-5.46 2-5.46 5.61v3.13h-3.63v4.24H15V28h4.39V17.11z"/></svg>',
+  iconBackground: '#3c5996',
+  link: '//www.facebook.com/sharer.php?u={u}',
+  name: 'facebook',
+  title: 'Facebook'
+};
+ESLShareConfig.instance.appendButton(facebook);
diff --git a/src/modules/esl-share/buttons/hatena.ts b/src/modules/esl-share/buttons/hatena.ts
new file mode 100644
index 000000000..40a48e085
--- /dev/null
+++ b/src/modules/esl-share/buttons/hatena.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const hatena: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 32 32"><path d="M6.96 8.22h7.33c1.25 0 2.21.37 2.88 1.1s1 1.64 1 2.72c0 .91-.24 1.69-.72 2.34-.32.43-.78.77-1.4 1.02.93.27 1.61.72 2.05 1.37.44.65.66 1.46.66 2.43 0 .8-.16 1.51-.47 2.15-.31.64-.74 1.14-1.28 1.51-.34.23-.84.4-1.52.5-.9.14-1.5.21-1.79.21H6.96V8.22zm3.88 6.02h1.74c.62 0 1.06-.13 1.3-.38.24-.26.37-.62.37-1.1 0-.44-.12-.8-.37-1.05-.24-.25-.67-.38-1.27-.38h-1.77v2.91zm0 6.03h2.04c.69 0 1.18-.15 1.46-.43s.43-.68.43-1.17c0-.45-.14-.82-.42-1.09-.28-.28-.77-.41-1.47-.41h-2.03c-.01-.01-.01 3.1-.01 3.1zM21.21 8.41h3.58v9.58h-3.58z"/><circle cx="23" cy="21.53" r="2.04"/></svg>',
+  iconBackground: '#08aed9',
+  link: '//b.hatena.ne.jp/entry/panel/?url={u}&btitle={t}',
+  name: 'hatena',
+  title: 'Hatena'
+};
+ESLShareConfig.instance.appendButton(hatena);
diff --git a/src/modules/esl-share/buttons/kakao.ts b/src/modules/esl-share/buttons/kakao.ts
new file mode 100644
index 000000000..72f28a3e0
--- /dev/null
+++ b/src/modules/esl-share/buttons/kakao.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const kakao: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 32 32"><path d="M20.826 6h-9.652C10.524 6 10 6.51 10 7.138v9.336c0 .63.525 1.14 1.174 1.14h4.45c-.03 1.11-.507 2.318-1.196 3.39-.775 1.207-2.426 2.543-2.44 2.555-.13.12-.226.26-.23.456 0 .15.08.263.167.385l3.104 3.395s.15.154.274.183c.14.033.3.037.41-.045 5.374-4.032 6.15-9.085 6.285-11.82V7.137C22 6.508 21.475 6 20.826 6" fill-rule="evenodd"/></svg>',
+  iconBackground: '#fab900',
+  link: '//story.kakao.com/share?url={u}',
+  name: 'kakao',
+  title: 'Kakao'
+};
+ESLShareConfig.instance.appendButton(kakao);
diff --git a/src/modules/esl-share/buttons/line.ts b/src/modules/esl-share/buttons/line.ts
new file mode 100644
index 000000000..1c3c3f807
--- /dev/null
+++ b/src/modules/esl-share/buttons/line.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const line: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 32 32"><path d="M27 14.927c0 1.97-.764 3.744-2.358 5.492-2.307 2.655-7.468 5.89-8.642 6.385-1.174.495-1-.315-.953-.593l.157-.94c.037-.282.075-.718-.035-.996-.125-.306-.612-.465-.97-.542-5.287-.7-9.2-4.395-9.2-8.807C5 10.005 9.935 6 16 6c6.066 0 11 4.005 11 8.927zm-13.235-2.38h-.772a.214.214 0 00-.214.215v4.793c0 .118.095.214.213.214h.772a.214.214 0 00.214-.215v-4.793a.214.214 0 00-.215-.214zm5.31 0h-.77a.214.214 0 00-.215.215v2.848l-2.197-2.967a.235.235 0 00-.017-.023l-.014-.013-.003-.004c-.005-.003-.01-.006-.013-.01-.002 0-.003-.002-.005-.004l-.01-.008a.262.262 0 00-.018-.01c-.004 0-.006-.003-.008-.004a.605.605 0 00-.013-.005l-.007-.002a.106.106 0 00-.02-.005.098.098 0 00-.012-.003h-.01c-.003-.002-.006-.002-.01-.003-.004 0-.007 0-.01-.002h-.78a.214.214 0 00-.214.214v4.793c0 .118.095.214.214.214h.77a.214.214 0 00.216-.215v-2.847l2.2 2.97c.014.022.033.04.053.053 0 .002.002.002.002.003l.014.008c0 .002.003.003.005.004l.01.005c.003 0 .007.002.01.004.003 0 .004 0 .007.002l.014.005s.002 0 .003.002a.206.206 0 00.054.007h.772a.214.214 0 00.214-.215v-4.793a.214.214 0 00-.214-.214zm-7.17 4.022H9.81V12.76a.214.214 0 00-.216-.214h-.77a.214.214 0 00-.216.214v4.793c0 .058.023.11.06.148l.003.003c.002 0 .003.002.005.003.038.036.09.06.147.06h3.083a.214.214 0 00.214-.215v-.772a.214.214 0 00-.215-.214zm11.432-2.822a.214.214 0 00.214-.214v-.77a.214.214 0 00-.213-.216h-3.082a.213.213 0 00-.15.06s0 .002-.002.003c0 .002-.003.003-.004.005a.214.214 0 00-.06.147v4.793c0 .057.023.11.06.148l.003.003.003.003c.04.036.09.06.148.06h3.083a.214.214 0 00.214-.215v-.772a.214.214 0 00-.213-.214H21.24v-.812h2.097a.214.214 0 00.214-.214v-.77a.214.214 0 00-.213-.216H21.24v-.81h2.097z" fill-rule="evenodd"/></svg>',
+  iconBackground: '#00b900',
+  link: '//social-plugins.line.me/lineit/share?url={u}',
+  name: 'line',
+  title: 'LINE'
+};
+ESLShareConfig.instance.appendButton(line);
diff --git a/src/modules/esl-share/buttons/linkedin.ts b/src/modules/esl-share/buttons/linkedin.ts
new file mode 100644
index 000000000..9f105e63f
--- /dev/null
+++ b/src/modules/esl-share/buttons/linkedin.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const linkedin: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 27.99 27.99"><path d="M6.37 11.33h3.25v10.45H6.37zM8 6.13A1.88 1.88 0 116.12 8 1.88 1.88 0 018 6.13M11.65 11.33h3.12v1.43h.05a3.4 3.4 0 013.07-1.69c3.29 0 3.9 2.17 3.9 5v5.73h-3.25v-5.11c0-1.21 0-2.77-1.69-2.77s-1.94 1.32-1.94 2.69v5.17h-3.25V11.33z"/></svg>',
+  iconBackground: '#0b77b3',
+  link: '//www.linkedin.com/sharing/share-offsite/?url={u}',
+  name: 'linkedin',
+  title: 'LinkedIn'
+};
+ESLShareConfig.instance.appendButton(linkedin);
diff --git a/src/modules/esl-share/buttons/mail.ts b/src/modules/esl-share/buttons/mail.ts
new file mode 100644
index 000000000..2770c3038
--- /dev/null
+++ b/src/modules/esl-share/buttons/mail.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/external-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const mail: ESLShareButtonConfig = {
+  action: 'external',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 28 28"><path d="M4.63 6.94v14.1h18.8V6.94H4.63zm2.44 1.78h13.9l-6.93 5.67-6.93-5.67zm14.6 1.72v8.82H6.47v-8.79l7.59 6.21 7.63-6.24z"/></svg>',
+  iconBackground: '#ff1493',
+  link: 'mailto:?subject={title}&body={url}',
+  name: 'mail',
+  title: 'Mail'
+};
+ESLShareConfig.instance.appendButton(mail);
diff --git a/src/modules/esl-share/buttons/mix.ts b/src/modules/esl-share/buttons/mix.ts
new file mode 100644
index 000000000..b620745a6
--- /dev/null
+++ b/src/modules/esl-share/buttons/mix.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const mix: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 32 32"><path d="M26 6v11.077C26 18.123 25.105 19 24 19s-2-.877-2-1.923v-1a2 2 0 00-2-2 2 2 0 00-2 2v2.846c-.02 1.046-.915 1.923-2 1.923-1.12 0-2.013-.877-2-1.923V11.23a2.036 2.036 0 00-2-2c-1.062.024-1.922.822-2 1.847-.003.025-.003 4.275 0 12.75 0 1.045-.895 1.923-2 1.923s-2-.878-2-1.923V6h20z" opacity=".8"/><path d="M6 6v10.77c2.135-.006 3.878-1.648 4-3.693V11.23a.702.702 0 010-.153c.078-1.025.938-1.823 2-1.846 1.092.024 1.986.902 2 2v7.693c-.013 1.046.88 1.923 2 1.923 1.085 0 1.98-.877 2-1.923v-5.23C17.98 9.458 21.502 6 25.846 6H6"/></svg>',
+  iconBackground: '#eb4924',
+  link: '//mix.com/add?url={u}',
+  name: 'mix',
+  title: 'MIX'
+};
+ESLShareConfig.instance.appendButton(mix);
diff --git a/src/modules/esl-share/buttons/mixi.ts b/src/modules/esl-share/buttons/mixi.ts
new file mode 100644
index 000000000..57f66fb3d
--- /dev/null
+++ b/src/modules/esl-share/buttons/mixi.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const mixi: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 32 32"><path d="M16.087 5.36c-6.414 0-11.97 3.93-11.97 11.265 0 6.865 7.628 10.092 12.635 8.918v2.348S27.88 24.958 27.88 15.04c0-6.043-4.458-9.68-11.793-9.68zm6.768 14.63h-1.643v-5.634c0-.703-.506-1.565-1.566-1.565-.89 0-2.504.374-2.504 2.06v5.14H15.5v-5.202c0-1.57-.782-2.073-1.486-2.073-1.14 0-2.698.802-2.698 2.384v4.89H9.673v-8.92h1.643v1.02c.654-.538 1.548-1.02 2.698-1.02 1.21 0 2.07.428 2.58 1.27a4.444 4.444 0 013.052-1.19c1.947 0 3.21 1.772 3.21 3.172v5.667z"/></svg>',
+  iconBackground: '#cfab59',
+  link: '//mixi.jp/share.pl?u={u}',
+  name: 'mixi',
+  title: 'Mixi'
+};
+ESLShareConfig.instance.appendButton(mixi);
diff --git a/src/modules/esl-share/buttons/myspace.ts b/src/modules/esl-share/buttons/myspace.ts
new file mode 100644
index 000000000..7887c16db
--- /dev/null
+++ b/src/modules/esl-share/buttons/myspace.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const myspace: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 32 32"><path d="M19.996 11.757c1.905 0 3.45-1.513 3.45-3.38C23.445 6.513 21.9 5 19.995 5c-1.903 0-3.448 1.512-3.448 3.378s1.545 3.38 3.448 3.38zm4.995 5.233c-.09-2.574-2.242-4.638-4.893-4.638a4.934 4.934 0 00-3.24 1.206 3.62 3.62 0 00-3.318-2.133c-.944 0-1.8.356-2.443.935a2.596 2.596 0 00-2.494-1.82c-1.407 0-2.55 1.093-2.6 2.462H6v4.783h3.92v3.712h5.276V26H25v-9.01h-.01zm-11.526-6.006c1.405 0 2.545-1.116 2.545-2.492C16.01 7.115 14.87 6 13.463 6 12.06 6 10.92 7.114 10.92 8.49c0 1.376 1.14 2.492 2.544 2.492zm-4.914-.762c1.012 0 1.83-.803 1.83-1.794 0-.992-.818-1.795-1.83-1.795-1.01 0-1.83.804-1.83 1.795 0 .99.82 1.794 1.83 1.794z" fill-rule="evenodd"/></svg>',
+  iconBackground: '#282828',
+  link: '//myspace.com/post?u={u}',
+  name: 'myspace',
+  title: 'Myspace'
+};
+ESLShareConfig.instance.appendButton(myspace);
diff --git a/src/modules/esl-share/buttons/native-share.ts b/src/modules/esl-share/buttons/native-share.ts
new file mode 100644
index 000000000..e09431dbf
--- /dev/null
+++ b/src/modules/esl-share/buttons/native-share.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/native-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const nativeShare: ESLShareButtonConfig = {
+  action: 'native',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 24 24"><path d="m21.7 10.2-6.6-6c-.5-.5-1.1 0-1.1.8v3c-4.7 0-8.7 2.9-10.6 6.8-.7 1.3-1.1 2.7-1.4 4.1-.2 1 1.3 1.5 1.9.6C6.1 16 9.8 13.7 14 13.7V17c0 .8.6 1.3 1.1.8l6.6-6c.4-.4.4-1.2 0-1.6z"/></svg>',
+  iconBackground: '#ff6347',
+  link: '',
+  name: 'native-share',
+  title: 'Share page'
+};
+ESLShareConfig.instance.appendButton(nativeShare);
diff --git a/src/modules/esl-share/buttons/pinterest.ts b/src/modules/esl-share/buttons/pinterest.ts
new file mode 100644
index 000000000..a4145de9e
--- /dev/null
+++ b/src/modules/esl-share/buttons/pinterest.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const pinterest: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 24 24"><path d="M12.486 4.771c-4.23 0-6.363 3.033-6.363 5.562 0 1.533.581 2.894 1.823 3.401.205.084.387.004.446-.221l.182-.717c.061-.221.037-.3-.127-.495-.359-.422-.588-.972-.588-1.747 0-2.25 1.683-4.264 4.384-4.264 2.392 0 3.706 1.463 3.706 3.412 0 2.568-1.137 4.734-2.824 4.734-.932 0-1.629-.77-1.405-1.715.268-1.13.786-2.347.786-3.16 0-.729-.392-1.336-1.2-1.336-.952 0-1.718.984-1.718 2.304 0 .841.286 1.409.286 1.409L8.728 16.79c-.34 1.44-.051 3.206-.025 3.385.013.104.149.131.21.051.088-.115 1.223-1.517 1.607-2.915.111-.396.627-2.445.627-2.445.311.589 1.213 1.108 2.175 1.108 2.863 0 4.804-2.608 4.804-6.103-.003-2.64-2.24-5.1-5.64-5.1z"/></svg>',
+  iconBackground: '#e60023',
+  link: '//www.pinterest.com/pin/create/button/?url={u}&description={t}',
+  name: 'pinterest',
+  title: 'Pinterest'
+};
+ESLShareConfig.instance.appendButton(pinterest);
diff --git a/src/modules/esl-share/buttons/print.ts b/src/modules/esl-share/buttons/print.ts
new file mode 100644
index 000000000..9dfb8a4ee
--- /dev/null
+++ b/src/modules/esl-share/buttons/print.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/print-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const print: ESLShareButtonConfig = {
+  action: 'print',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 247.1 247.1"><path d="M75.4 175.5h97v6.5h-97zM75.4 194.9h97v6.5h-97z"/><circle stroke-width="2" stroke-miterlimit="10" cx="178.9" cy="117.3" r="6.5"/><path d="M198.3 84.9h-12.9V39.6c0-7.1-5.8-12.9-12.9-12.9h-97c-7.1 0-12.9 5.8-12.9 12.9v45.3H49.5c-11 0-19.4 8.4-19.4 19.4v58.2c0 11 8.4 19.4 19.4 19.4h12.9v25.9c0 7.1 5.8 12.9 12.9 12.9h97c7.1 0 12.9-5.8 12.9-12.9v-25.9h12.9c11 0 19.4-8.4 19.4-19.4v-58.2c.2-11-8.2-19.4-19.2-19.4zM68.9 39.6c0-3.2 2.6-6.5 6.5-6.5h97c3.2 0 6.5 2.6 6.5 6.5v45.3h-110V39.6zm110 168.2c0 3.2-2.6 6.5-6.5 6.5h-97c-3.2 0-6.5-2.6-6.5-6.5v-45.3h110v45.3zm32.3-45.3c0 7.1-5.8 12.9-12.9 12.9h-12.9V156h-123v19.4H49.5c-7.1 0-12.9-5.8-12.9-12.9v-58.2c0-7.1 5.8-12.9 12.9-12.9h148.8c7.1 0 12.9 5.8 12.9 12.9v58.2z"/></svg>',
+  iconBackground: '#2f4f4f',
+  link: '',
+  name: 'print',
+  title: 'Print page'
+};
+ESLShareConfig.instance.appendButton(print);
diff --git a/src/modules/esl-share/buttons/pusha.ts b/src/modules/esl-share/buttons/pusha.ts
new file mode 100644
index 000000000..0292f2188
--- /dev/null
+++ b/src/modules/esl-share/buttons/pusha.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const pusha: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 32 32"><path d="M29.27 22.19V8.07l-12.06 6.85 3.84 2.33C15.72 24.14 5.9 29.31 0 31.96V32h19.64c3.68-4.86 7.03-11.46 7.03-11.46l2.6 1.65z"/></svg>',
+  iconBackground: '#0878ba',
+  link: '//www.pusha.se/posta?url={u}&title={t}',
+  name: 'pusha',
+  title: 'Pusha'
+};
+ESLShareConfig.instance.appendButton(pusha);
diff --git a/src/modules/esl-share/buttons/reddit.ts b/src/modules/esl-share/buttons/reddit.ts
new file mode 100644
index 000000000..375d1a013
--- /dev/null
+++ b/src/modules/esl-share/buttons/reddit.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const reddit: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 32 32"><path d="M27 15.5a2.452 2.452 0 01-1.338 2.21c.098.38.147.777.147 1.19 0 1.283-.437 2.47-1.308 3.563-.872 1.092-2.06 1.955-3.567 2.588-1.506.634-3.143.95-4.91.95-1.768 0-3.403-.316-4.905-.95-1.502-.632-2.69-1.495-3.56-2.587-.872-1.092-1.308-2.28-1.308-3.562 0-.388.045-.777.135-1.166a2.47 2.47 0 01-1.006-.912c-.253-.4-.38-.842-.38-1.322 0-.678.237-1.26.712-1.744a2.334 2.334 0 011.73-.726c.697 0 1.29.26 1.78.782 1.785-1.258 3.893-1.928 6.324-2.01l1.424-6.467a.42.42 0 01.184-.26.4.4 0 01.32-.063l4.53 1.006c.147-.306.368-.553.662-.74a1.78 1.78 0 01.97-.278c.508 0 .94.18 1.302.54.36.36.54.796.54 1.31 0 .512-.18.95-.54 1.315-.36.364-.794.546-1.302.546-.507 0-.94-.18-1.295-.54a1.793 1.793 0 01-.533-1.308l-4.1-.92-1.277 5.86c2.455.074 4.58.736 6.37 1.985a2.315 2.315 0 011.757-.757c.68 0 1.256.242 1.73.726.476.484.713 1.066.713 1.744zm-16.868 2.47c0 .513.178.95.534 1.315.356.365.787.547 1.295.547.508 0 .942-.182 1.302-.547.36-.364.54-.802.54-1.315 0-.513-.18-.95-.54-1.31-.36-.36-.794-.54-1.3-.54-.5 0-.93.183-1.29.547a1.79 1.79 0 00-.54 1.303zm9.944 4.406c.09-.09.135-.2.135-.323a.444.444 0 00-.44-.447c-.124 0-.23.042-.32.124-.336.348-.83.605-1.486.77a7.99 7.99 0 01-1.964.248 7.99 7.99 0 01-1.964-.248c-.655-.165-1.15-.422-1.486-.77a.456.456 0 00-.32-.124.414.414 0 00-.306.124.41.41 0 00-.135.317.45.45 0 00.134.33c.352.355.837.636 1.455.843.617.207 1.118.33 1.503.366a11.6 11.6 0 001.117.056c.36 0 .733-.02 1.117-.056.385-.037.886-.16 1.504-.366.62-.207 1.104-.488 1.456-.844zm-.037-2.544c.507 0 .938-.182 1.294-.547.356-.364.534-.802.534-1.315 0-.505-.18-.94-.54-1.303a1.75 1.75 0 00-1.29-.546c-.506 0-.94.18-1.3.54-.36.36-.54.797-.54 1.31s.18.95.54 1.315c.36.365.794.547 1.3.547z" fill-rule="evenodd"/></svg>',
+  iconBackground: '#ff5700',
+  link: '//www.reddit.com/submit?url={u}&title={t}',
+  name: 'reddit',
+  title: 'Reddit'
+};
+ESLShareConfig.instance.appendButton(reddit);
diff --git a/src/modules/esl-share/buttons/sina-weibo.ts b/src/modules/esl-share/buttons/sina-weibo.ts
new file mode 100644
index 000000000..f6d84a6e0
--- /dev/null
+++ b/src/modules/esl-share/buttons/sina-weibo.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const sinaWeibo: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 32 32"><path d="M14.24 23.808c-3.64.367-6.785-1.307-7.022-3.734-.236-2.43 2.525-4.693 6.164-5.06 3.642-.367 6.786 1.307 7.02 3.734.24 2.43-2.522 4.696-6.16 5.06m7.28-8.063c-.31-.096-.523-.157-.362-.57.352-.898.39-1.672.006-2.227-.713-1.036-2.667-.98-4.907-.028 0 0-.705.312-.523-.253.343-1.125.29-2.065-.243-2.61-1.214-1.238-4.446.045-7.216 2.86C6.205 15.023 5 17.26 5 19.192c0 3.694 4.664 5.942 9.226 5.942 5.98 0 9.96-3.53 9.96-6.333.003-1.695-1.402-2.657-2.665-3.055m3.973-6.763a5.76 5.76 0 00-5.542-1.823.855.855 0 00-.646 1.015.84.84 0 001 .657c1.398-.303 2.912.138 3.938 1.295a4.254 4.254 0 01.865 4.113c-.144.45.1.93.542 1.076a.84.84 0 001.06-.55v-.002a5.973 5.973 0 00-1.218-5.78"/><path d="M23.276 11.018a2.8 2.8 0 00-2.698-.885.74.74 0 00-.56.876c.086.396.472.65.86.563.467-.102.977.046 1.32.432.343.388.437.915.29 1.378a.742.742 0 00.466.928.724.724 0 00.913-.474c.3-.947.113-2.026-.59-2.818M14.44 19.41c-.126.223-.408.328-.627.235-.218-.09-.285-.34-.16-.555.127-.215.397-.32.612-.234.22.08.298.33.176.555m-1.16 1.512c-.353.57-1.11.82-1.676.558-.56-.26-.726-.922-.374-1.48.35-.555 1.078-.802 1.642-.56.57.25.753.905.407 1.482m1.322-4.04c-1.733-.46-3.69.42-4.443 1.97-.77 1.583-.025 3.34 1.723 3.914 1.815.595 3.95-.318 4.695-2.023.734-1.67-.182-3.39-1.976-3.86"/></svg>',
+  iconBackground: '#e6162d',
+  link: '//service.weibo.com/share/share.php?url={u}&title={t}',
+  name: 'sina-weibo',
+  title: 'Sina Weibo'
+};
+ESLShareConfig.instance.appendButton(sinaWeibo);
diff --git a/src/modules/esl-share/buttons/telegram.ts b/src/modules/esl-share/buttons/telegram.ts
new file mode 100644
index 000000000..befd13428
--- /dev/null
+++ b/src/modules/esl-share/buttons/telegram.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const telegram: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 455.731 455.731"><path d="M358.844 100.6 54.091 219.359c-9.871 3.847-9.273 18.012.888 21.012l77.441 22.868 28.901 91.706c3.019 9.579 15.158 12.483 22.185 5.308l40.039-40.882 78.56 57.665c9.614 7.057 23.306 1.814 25.747-9.859l52.031-248.76c2.548-12.185-9.44-22.337-21.039-17.817zm-38.208 55.206L179.08 280.984c-1.411 1.248-2.309 2.975-2.519 4.847l-5.45 48.448c-.178 1.58-2.389 1.789-2.861.271l-22.423-72.253c-1.027-3.308.312-6.892 3.255-8.717l167.163-103.676c3.844-2.386 7.78 2.906 4.391 5.902z"/></svg>',
+  iconBackground: '#61a8de',
+  link: '//t.me/share/url?url={u}&text={t}',
+  name: 'telegram',
+  title: 'Telegram'
+};
+ESLShareConfig.instance.appendButton(telegram);
diff --git a/src/modules/esl-share/buttons/twitter.ts b/src/modules/esl-share/buttons/twitter.ts
new file mode 100644
index 000000000..0fff5ab64
--- /dev/null
+++ b/src/modules/esl-share/buttons/twitter.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const twitter: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 27.99 27.99"><path d="M21.84 9.14a6.34 6.34 0 01-1.84.51 3.25 3.25 0 001.4-1.78 6.22 6.22 0 01-2 .78 3.22 3.22 0 00-5.57 2.2 2.92 2.92 0 00.09.73 9.11 9.11 0 01-6.67-3.36 3.16 3.16 0 00-.43 1.62 3.21 3.21 0 001.43 2.68 3.25 3.25 0 01-1.46-.41 3.23 3.23 0 002.58 3.16 3 3 0 01-.84.11 3 3 0 01-.61-.05 3.22 3.22 0 003 2.23 6.39 6.39 0 01-4 1.38 6.19 6.19 0 01-.76-.05 9.14 9.14 0 0014.08-7.71v-.41a6.36 6.36 0 001.6-1.63z"/></svg>',
+  iconBackground: '#26a1ef',
+  link: '//twitter.com/intent/tweet?text={t}&url={u}',
+  name: 'twitter',
+  title: 'Twitter'
+};
+ESLShareConfig.instance.appendButton(twitter);
diff --git a/src/modules/esl-share/buttons/wykop.ts b/src/modules/esl-share/buttons/wykop.ts
new file mode 100644
index 000000000..498333e32
--- /dev/null
+++ b/src/modules/esl-share/buttons/wykop.ts
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+import '../actions/media-action';
+import {ESLShareConfig} from '../core/esl-share-config';
+
+import type {ESLShareButtonConfig} from '../core/esl-share-config';
+
+export const wykop: ESLShareButtonConfig = {
+  action: 'media',
+  icon: '<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 32 32"><path d="M14.722 19.784l-3.48-6.832-2.667 1.36 3.82 7.497.056-.03.313.61 10.608-5.404-.48-.944-3.65-7.165-2.667 1.36 3.48 6.83-1.332.68-3.48-6.832-2.666 1.358 3.48 6.832-1.332.68z"/><path d="M7.372 12.77c0-2.38 1.86-4.308 4.152-4.308h8.952c2.294 0 4.152 1.928 4.152 4.308v6.46c0 2.38-1.86 4.308-4.152 4.308h-8.952c-2.294 0-4.152-1.928-4.152-4.308v-6.46zM5 12.77v6.46C5 22.97 7.92 26 11.524 26h8.952C24.08 26 27 22.97 27 19.23v-6.46C27 9.03 24.08 6 20.476 6h-8.952C7.92 6 5 9.03 5 12.77z"/></svg>',
+  iconBackground: '#fb803f',
+  link: '//www.wykop.pl/dodaj?url={u}&title={t}',
+  name: 'wykop',
+  title: 'Wykop'
+};
+ESLShareConfig.instance.appendButton(wykop);
diff --git a/src/modules/esl-share/core.ts b/src/modules/esl-share/core.ts
index 45e215bd5..73850fce7 100644
--- a/src/modules/esl-share/core.ts
+++ b/src/modules/esl-share/core.ts
@@ -2,4 +2,5 @@ export * from './core/esl-share';
 export * from './core/esl-share-action';
 export * from './core/esl-share-action-registry';
 export * from './core/esl-share-button';
+export * from './core/esl-share-config';
 export * from './core/esl-share-trigger';
diff --git a/src/modules/esl-share/core/esl-share-config.ts b/src/modules/esl-share/core/esl-share-config.ts
index 9924f6854..d33041e2c 100644
--- a/src/modules/esl-share/core/esl-share-config.ts
+++ b/src/modules/esl-share/core/esl-share-config.ts
@@ -1,4 +1,8 @@
-/** {@link ESLShareConfig} provider type definition */
+import {decorate, memoize} from '../../esl-utils/decorators';
+import {microtask} from '../../esl-utils/async/microtask';
+import {SyntheticEventTarget} from '../../esl-utils/dom/events/target';
+
+/** {@link ESLShareConfigShape} provider type definition */
 export type ESLShareConfigProviderType = () => Promise<ESLShareConfig>;
 
 /** The definition of the sharing button */
@@ -31,32 +35,114 @@ export interface ESLShareGroupConfig {
   list: string;
 }
 
-/** The definition of `ESLShare` component configuration */
-export interface ESLShareConfig {
-  /** List of sharing buttons configuration */
-  buttons: ESLShareButtonConfig[];
-  /** List of share button groups configurations */
-  groups: ESLShareGroupConfig[];
-}
-
+/** Gets item of the section by name */
 function getConfigSectionItem<T extends ESLShareButtonConfig | ESLShareGroupConfig>(section: T[], name: string): T | undefined {
   return section.find((item) => item.name === name);
 }
 
-/**
- * Selects the buttons for the given list and returns their configuration.
- * @returns config of buttons
- */
-export function selectButtonsForList(config: ESLShareConfig, list: string): ESLShareButtonConfig[] {
-  return list.split(' ').reduce((res, item) => {
-    const [btnName, groupName] = item.split('group:');
-    if (groupName) {
-      const groupConfig = getConfigSectionItem(config.groups, groupName);
-      if (groupConfig) return res.concat(selectButtonsForList(config, groupConfig.list));
-    } else {
-      const btnConfig = getConfigSectionItem(config.buttons, btnName);
-      if (btnConfig) res.push(btnConfig);
+/** Inserts item into section or updates if exists */
+function setConfigSectionItem<T extends ESLShareButtonConfig | ESLShareGroupConfig>(section: T[], item: T): void {
+  const index = section.findIndex((i) => i.name === item.name);
+  if (index >= 0) section[index] = item;
+  else section.push(item);
+}
+
+/** Class for managing share buttons configurations */
+export class ESLShareConfig extends SyntheticEventTarget {
+  @memoize()
+  public static get instance(): ESLShareConfig {
+    return new ESLShareConfig();
+  }
+
+  /**
+   * Sets config with a promise of a new config object or using a config provider function.
+   * Each of the buttons and groups specified in the new config will be appended to the current config.
+   * @returns Promise of the current config
+   */
+  public static async set(
+    provider?: ESLShareConfigProviderType | Promise<ESLShareConfig> | ESLShareConfig
+  ): Promise<ESLShareConfig> {
+    if (typeof provider === 'function') return this.set(provider());
+    if (typeof provider === 'object') ESLShareConfig.append(provider instanceof Promise ? await provider : provider);
+    return ESLShareConfig.instance;
+  }
+
+  /**
+   * Appends buttons and groups from the passed config to the current config.
+   * @returns config instance
+   */
+  protected static append(cfg: ESLShareConfig): ESLShareConfig {
+    const {instance} = ESLShareConfig;
+    if (cfg) {
+      cfg.buttons.forEach((button) => instance.appendButton(button));
+      cfg.groups.forEach((group) => instance.appendGroup(group));
     }
-    return res;
-  }, [] as ESLShareButtonConfig[]);
+    return instance;
+  }
+
+  public readonly buttons: ESLShareButtonConfig[] = [];
+  public readonly groups: ESLShareGroupConfig[] = [];
+
+  protected constructor() {
+    super();
+  }
+
+  /**
+   * Selects the buttons for the given list and returns their configuration.
+   * @returns config of buttons
+   */
+  public getList(list: string): ESLShareButtonConfig[] {
+    return list.split(' ').reduce((res, item) => {
+      const [btnName, groupName] = item.split('group:');
+      if (groupName) {
+        const groupConfig = this.getGroup(groupName);
+        if (groupConfig) return res.concat(this.getList(groupConfig.list));
+      } else {
+        const btnConfig = this.getButton(btnName);
+        if (btnConfig) res.push(btnConfig);
+      }
+      return res;
+    }, [] as ESLShareButtonConfig[]);
+  }
+
+  /**
+   * Gets the group of buttons configuration.
+   * @returns config of group
+   */
+  public getGroup(groupName: string): ESLShareGroupConfig | undefined {
+    return getConfigSectionItem(this.groups, groupName);
+  }
+
+  /**
+   * Gets the button configuration.
+   * @returns config of button
+   */
+  public getButton(name: string): ESLShareButtonConfig | undefined {
+    return getConfigSectionItem(this.buttons, name);
+  }
+
+  /**
+   * Appends button (inserts or updates) to the current config.
+   * @returns config instance
+   */
+  public appendButton(button: ESLShareButtonConfig): ESLShareConfig {
+    setConfigSectionItem(this.buttons, button);
+    this._onUpdate();
+    return this;
+  }
+
+  /**
+   * Appends group (inserts or updates) to the current config.
+   * @returns config instance
+   */
+  public appendGroup(group: ESLShareGroupConfig): ESLShareConfig {
+    setConfigSectionItem(this.groups, group);
+    this._onUpdate();
+    return this;
+  }
+
+  @decorate(microtask)
+  protected _onUpdate(): void {
+    this.dispatchEvent(new CustomEvent('change'));
+  }
 }
diff --git a/src/modules/esl-share/core/esl-share.ts b/src/modules/esl-share/core/esl-share.ts
index 8ce9b96fb..1da2cd2e1 100644
--- a/src/modules/esl-share/core/esl-share.ts
+++ b/src/modules/esl-share/core/esl-share.ts
@@ -1,16 +1,13 @@
 import {ESLBaseElement} from '../../esl-base-element/core';
 import {ESLPopup} from '../../esl-popup/core';
 import {sequentialUID} from '../../esl-utils/misc/uid';
-import {attr, bind, boolAttr, prop} from '../../esl-utils/decorators';
-import {selectButtonsForList} from './esl-share-config';
+import {attr, bind, boolAttr, listen, prop} from '../../esl-utils/decorators';
 import {ESLShareButton} from './esl-share-button';
 import {ESLShareTrigger} from './esl-share-trigger';
+import {ESLShareConfig} from './esl-share-config';
 
 import type {PopupActionParams} from '../../esl-popup/core';
-import type {ESLShareConfig, ESLShareButtonConfig} from './esl-share-config';
-
-/** {@link ShareConfig} provider type definition */
-export type ESLShareConfigProviderType = () => Promise<ESLShareConfig>;
+import type {ESLShareButtonConfig, ESLShareConfigProviderType} from './esl-share-config';
 
 /**
  * ESLShare
@@ -20,7 +17,6 @@ export type ESLShareConfigProviderType = () => Promise<ESLShareConfig>;
  */
 export class ESLShare extends ESLBaseElement {
   public static override is = 'esl-share';
-  protected static _config: Promise<ESLShareConfig>;
   protected static _popupStore: Map<string, ESLPopup> = new Map<string, ESLPopup>();
 
   /** Register {@link ESLShare} component and dependent {@link ESLShareButton} */
@@ -32,12 +28,11 @@ export class ESLShare extends ESLBaseElement {
 
   /**
    * Gets or updates config with a promise of a new config object or using a config provider function.
-   * @returns Promise of the current config
+   * @returns Promise of the current config {@link ESLShareConfig}
+   * @deprecated alias for ESLShareConfig.set(), will be removed soon
    */
   public static config(provider?: ESLShareConfigProviderType | ESLShareConfig): Promise<ESLShareConfig> {
-    if (typeof provider === 'function') ESLShare._config = provider();
-    if (typeof provider === 'object') ESLShare._config = Promise.resolve(provider);
-    return ESLShare._config ?? Promise.reject('Configuration is not set');
+    return ESLShareConfig.set(provider);
   }
 
   /** Event to dispatch on ready state of {@link ESLShare} */
@@ -66,15 +61,14 @@ export class ESLShare extends ESLBaseElement {
   @attr() public mode: 'list' | 'popup';
 
   /** @readonly Ready state marker */
-  @boolAttr({readonly: true}) public ready: boolean;
+  @boolAttr({readonly: false}) public ready: boolean;
 
   protected _content: string;
 
   /** @returns config of buttons specified by the list attribute */
-  public get buttonsConfig(): Promise<ESLShareButtonConfig[]> {
-    return (this.constructor as typeof ESLShare).config().then((config) => {
-      return (this.list !== 'all') ? selectButtonsForList(config, this.list) : config.buttons;
-    });
+  public get buttonsConfig(): ESLShareButtonConfig[] {
+    const config = ESLShareConfig.instance;
+    return (this.list !== 'all') ? config.getList(this.list) : config.buttons;
   }
 
   public override connectedCallback(): void {
@@ -82,33 +76,31 @@ export class ESLShare extends ESLBaseElement {
     this.init();
   }
 
-  protected init(): void {
-    if (this.ready) return;
+  protected init(force?: boolean): void {
+    if (this.ready && !force) return;
     if (!this.mode) this.mode = 'list';
     if (!this._content) this._content = this.innerHTML;
-    this.buttonsConfig
-      .then(this.buildContent)
-      .then(() => this.$$fire(this.SHARE_READY_EVENT, {bubbles: false}))
-      .catch((e) => console.error(`[${this.baseTagName}]: ${e}`));
+    this.buildContent();
+    this.$$fire(this.SHARE_READY_EVENT, {bubbles: false});
   }
 
   /** Builds component's content from received `ESLShareButtonConfig` list */
   @bind
-  protected buildContent(btnConfig: ESLShareButtonConfig[]): void {
+  protected buildContent(): void {
     this.innerHTML = '';
 
     if (this.mode === 'list') {
-      this.appendButtonsTo(this, btnConfig);
+      this.appendButtonsTo(this);
       return;
     }
 
-    const $popup = this.getStoredPopup() || this.createPopup(btnConfig);
+    const $popup = this.getStoredPopup() || this.createPopup();
     this.appendTrigger(`#${$popup.id}`);
   }
 
   /** Appends buttons to the passed element. */
-  protected appendButtonsTo($el: Element, btnConfig: ESLShareButtonConfig[]): void {
-    btnConfig.forEach((cfg) => {
+  protected appendButtonsTo($el: Element): void {
+    this.buttonsConfig.forEach((cfg) => {
       const btn = this.createButton(cfg);
       btn && $el.appendChild(btn);
     });
@@ -140,7 +132,7 @@ export class ESLShare extends ESLBaseElement {
   }
 
   /** Creates popup element with share buttons. */
-  protected createPopup(btnConfig: ESLShareButtonConfig[]): ESLPopup {
+  protected createPopup(): ESLPopup {
     const $popup = ESLPopup.create();
     const id = sequentialUID(this.baseTagName + '-');
     Object.assign($popup, {id, ...this.popupInitialParams});
@@ -148,7 +140,7 @@ export class ESLShare extends ESLBaseElement {
     document.body.appendChild($popup);
     this.storePopup($popup);
 
-    this.appendButtonsTo($popup, btnConfig);
+    this.appendButtonsTo($popup);
     return $popup;
   }
 
@@ -161,4 +153,9 @@ export class ESLShare extends ESLBaseElement {
   protected storePopup(value: ESLPopup): void {
     (this.constructor as typeof ESLShare)._popupStore.set(this.list, value);
   }
+
+  @listen({event: 'change', target: ESLShareConfig.instance})
+  protected onConfigChange(): void {
+    this.init(true);
+  }
 }
diff --git a/tsconfig.json b/tsconfig.json
index 20a8b2570..d62a0f850 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -18,7 +18,8 @@
       "DOM.Iterable"
     ],
     "rootDir": "src",
-    "outDir": "./"
+    "outDir": "./",
+    "resolveJsonModule": true
   },
   "include": [
     "pages/src",


Test patch:
diff --git a/src/modules/esl-share/test/buttons/blogger.test.ts b/src/modules/esl-share/test/buttons/blogger.test.ts
new file mode 100644
index 000000000..7a54e9993
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/blogger.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/blogger';
+
+describe(
+  'ESLShare: "blogger" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "blogger" button object config matches button config',
+  createButtonMatchingTestPlan('blogger', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/button-test-plan-factory.ts b/src/modules/esl-share/test/buttons/button-test-plan-factory.ts
new file mode 100644
index 000000000..950967210
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/button-test-plan-factory.ts
@@ -0,0 +1,50 @@
+import {ESLShareConfig} from '../../core/esl-share-config';
+import {ESLShareActionRegistry} from '../../core/esl-share-action-registry';
+
+export function createImportCheckTestPlan(actionName: string): () => void {
+  return () => {
+    test('config instance has 1 button', () => {
+      expect(ESLShareConfig.instance.buttons.length).toBe(1);
+    });
+
+    test(`"${actionName}" action was registered when importing the button`, () => {
+      expect(ESLShareActionRegistry.instance.has(actionName)).toBe(true);
+    });
+  };
+}
+
+export function createButtonMatchingTestPlan(name: string, action: string): () => void {
+  return () => {
+    test('button from config has action property', () => {
+      expect(ESLShareConfig.instance.buttons[0]).toHaveProperty('action');
+    });
+
+    test(`button from config has action property set to "${action}"`, () => {
+      expect(ESLShareConfig.instance.buttons[0].action).toBe(action);
+    });
+
+    test('button from config has icon property', () => {
+      expect(ESLShareConfig.instance.buttons[0]).toHaveProperty('icon');
+    });
+
+    test('button from config has iconBackground property', () => {
+      expect(ESLShareConfig.instance.buttons[0]).toHaveProperty('iconBackground');
+    });
+
+    test('button from config has link property', () => {
+      expect(ESLShareConfig.instance.buttons[0]).toHaveProperty('link');
+    });
+
+    test('button from config has name property', () => {
+      expect(ESLShareConfig.instance.buttons[0]).toHaveProperty('name');
+    });
+
+    test(`button from config has name property set to "${name}"`, () => {
+      expect(ESLShareConfig.instance.buttons[0].name).toBe(name);
+    });
+
+    test('button from config has title property', () => {
+      expect(ESLShareConfig.instance.buttons[0]).toHaveProperty('title');
+    });
+  };
+}
diff --git a/src/modules/esl-share/test/buttons/copy.test.ts b/src/modules/esl-share/test/buttons/copy.test.ts
new file mode 100644
index 000000000..b32902ebd
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/copy.test.ts
@@ -0,0 +1,20 @@
+import {ESLShareConfig} from '../../core/esl-share-config';
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/copy';
+
+describe(
+  'ESLShare: "copy" button import appends button to config and registers the "copy" action',
+  createImportCheckTestPlan('copy')
+);
+
+describe(
+  'ESLShare: "copy" button object config matches button config',
+  createButtonMatchingTestPlan('copy', 'copy')
+);
+
+describe('ESLShare: "copy" button has specific unique properties', () => {
+  test('button from config has additional property', () => {
+    expect(ESLShareConfig.instance.buttons[0]).toHaveProperty('additional');
+  });
+});
diff --git a/src/modules/esl-share/test/buttons/facebook.test.ts b/src/modules/esl-share/test/buttons/facebook.test.ts
new file mode 100644
index 000000000..ca62cc937
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/facebook.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/facebook';
+
+describe(
+  'ESLShare: "facebook" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "facebook" button object config matches button config',
+  createButtonMatchingTestPlan('facebook', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/hatena.test.ts b/src/modules/esl-share/test/buttons/hatena.test.ts
new file mode 100644
index 000000000..068820d6c
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/hatena.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/hatena';
+
+describe(
+  'ESLShare: "hatena" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "hatena" button object config matches button config',
+  createButtonMatchingTestPlan('hatena', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/kakao.test.ts b/src/modules/esl-share/test/buttons/kakao.test.ts
new file mode 100644
index 000000000..e29fdf9d0
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/kakao.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/kakao';
+
+describe(
+  'ESLShare: "kakao" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "kakao" button object config matches button config',
+  createButtonMatchingTestPlan('kakao', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/line.test.ts b/src/modules/esl-share/test/buttons/line.test.ts
new file mode 100644
index 000000000..a177e7f29
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/line.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/line';
+
+describe(
+  'ESLShare: "line" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "line" button object config matches button config',
+  createButtonMatchingTestPlan('line', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/linkedin.test.ts b/src/modules/esl-share/test/buttons/linkedin.test.ts
new file mode 100644
index 000000000..78f5552eb
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/linkedin.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/linkedin';
+
+describe(
+  'ESLShare: "linkedin" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "linkedin" button object config matches button config',
+  createButtonMatchingTestPlan('linkedin', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/mail.test.ts b/src/modules/esl-share/test/buttons/mail.test.ts
new file mode 100644
index 000000000..362705fe0
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/mail.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/mail';
+
+describe(
+  'ESLShare: "mail" button import appends button to config and registers the "external" action',
+  createImportCheckTestPlan('external')
+);
+
+describe(
+  'ESLShare: "mail" button object config matches button config',
+  createButtonMatchingTestPlan('mail', 'external')
+);
diff --git a/src/modules/esl-share/test/buttons/mix.test.ts b/src/modules/esl-share/test/buttons/mix.test.ts
new file mode 100644
index 000000000..e8b6edebb
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/mix.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/mix';
+
+describe(
+  'ESLShare: "mix" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "mix" button object config matches button config',
+  createButtonMatchingTestPlan('mix', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/mixi.test.ts b/src/modules/esl-share/test/buttons/mixi.test.ts
new file mode 100644
index 000000000..e93c7e8bc
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/mixi.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/mixi';
+
+describe(
+  'ESLShare: "mixi" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "mixi" button object config matches button config',
+  createButtonMatchingTestPlan('mixi', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/myspace.test.ts b/src/modules/esl-share/test/buttons/myspace.test.ts
new file mode 100644
index 000000000..bdf2eb775
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/myspace.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/myspace';
+
+describe(
+  'ESLShare: "myspace" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "myspace" button object config matches button config',
+  createButtonMatchingTestPlan('myspace', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/native-share.test.ts b/src/modules/esl-share/test/buttons/native-share.test.ts
new file mode 100644
index 000000000..27b2bbd45
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/native-share.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/native-share';
+
+describe(
+  'ESLShare: "native-share" button import appends button to config and registers the "native" action',
+  createImportCheckTestPlan('native')
+);
+
+describe(
+  'ESLShare: "native-share" button object config matches button config',
+  createButtonMatchingTestPlan('native-share', 'native')
+);
diff --git a/src/modules/esl-share/test/buttons/pinterest.test.ts b/src/modules/esl-share/test/buttons/pinterest.test.ts
new file mode 100644
index 000000000..2f43f84bf
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/pinterest.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/pinterest';
+
+describe(
+  'ESLShare: "pinterest" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "pinterest" button object config matches button config',
+  createButtonMatchingTestPlan('pinterest', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/print.test.ts b/src/modules/esl-share/test/buttons/print.test.ts
new file mode 100644
index 000000000..a1cc9a011
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/print.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/print';
+
+describe(
+  'ESLShare: "print" button import appends button to config and registers the "print" action',
+  createImportCheckTestPlan('print')
+);
+
+describe(
+  'ESLShare: "print" button object config matches button config',
+  createButtonMatchingTestPlan('print', 'print')
+);
diff --git a/src/modules/esl-share/test/buttons/pusha.test.ts b/src/modules/esl-share/test/buttons/pusha.test.ts
new file mode 100644
index 000000000..a328ec2c1
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/pusha.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/pusha';
+
+describe(
+  'ESLShare: "pusha" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "pusha" button object config matches button config',
+  createButtonMatchingTestPlan('pusha', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/reddit.test.ts b/src/modules/esl-share/test/buttons/reddit.test.ts
new file mode 100644
index 000000000..157026a2b
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/reddit.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/reddit';
+
+describe(
+  'ESLShare: "reddit" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "reddit" button object config matches button config',
+  createButtonMatchingTestPlan('reddit', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/sina-weibo.test.ts b/src/modules/esl-share/test/buttons/sina-weibo.test.ts
new file mode 100644
index 000000000..e9c1e8b12
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/sina-weibo.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/sina-weibo';
+
+describe(
+  'ESLShare: "sina-weibo" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "sina-weibo" button object config matches button config',
+  createButtonMatchingTestPlan('sina-weibo', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/telegram.test.ts b/src/modules/esl-share/test/buttons/telegram.test.ts
new file mode 100644
index 000000000..083bffc21
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/telegram.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/telegram';
+
+describe(
+  'ESLShare: "telegram" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "telegram" button object config matches button config',
+  createButtonMatchingTestPlan('telegram', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/twitter.test.ts b/src/modules/esl-share/test/buttons/twitter.test.ts
new file mode 100644
index 000000000..00b4e30ea
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/twitter.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/twitter';
+
+describe(
+  'ESLShare: "twitter" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "twitter" button object config matches button config',
+  createButtonMatchingTestPlan('twitter', 'media')
+);
diff --git a/src/modules/esl-share/test/buttons/wykop.test.ts b/src/modules/esl-share/test/buttons/wykop.test.ts
new file mode 100644
index 000000000..67857d6e1
--- /dev/null
+++ b/src/modules/esl-share/test/buttons/wykop.test.ts
@@ -0,0 +1,13 @@
+import {createImportCheckTestPlan, createButtonMatchingTestPlan} from './button-test-plan-factory';
+
+import '../../buttons/wykop';
+
+describe(
+  'ESLShare: "wykop" button import appends button to config and registers the "media" action',
+  createImportCheckTestPlan('media')
+);
+
+describe(
+  'ESLShare: "wykop" button object config matches button config',
+  createButtonMatchingTestPlan('wykop', 'media')
+);