@nectary/components 2.9.0 → 2.11.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/accordion/index.d.ts +11 -0
- package/accordion/index.js +86 -0
- package/accordion/types.d.ts +21 -0
- package/accordion/types.js +1 -0
- package/accordion-item/index.d.ts +14 -0
- package/accordion-item/index.js +95 -0
- package/accordion-item/types.d.ts +36 -0
- package/accordion-item/types.js +1 -0
- package/accordion-item/utils.d.ts +2 -0
- package/accordion-item/utils.js +1 -0
- package/action-menu/index.d.ts +11 -0
- package/action-menu/index.js +195 -0
- package/action-menu/types.d.ts +13 -0
- package/action-menu/types.js +1 -0
- package/action-menu-option/index.d.ts +12 -0
- package/action-menu-option/index.js +82 -0
- package/action-menu-option/types.d.ts +23 -0
- package/action-menu-option/types.js +1 -0
- package/action-menu-option/utils.d.ts +2 -0
- package/action-menu-option/utils.js +3 -0
- package/alert/index.d.ts +14 -0
- package/alert/index.js +48 -0
- package/alert/types.d.ts +18 -0
- package/alert/types.js +1 -0
- package/alert/utils.d.ts +2 -0
- package/alert/utils.js +1 -0
- package/avatar/index.d.ts +11 -0
- package/avatar/index.js +94 -0
- package/avatar/types.d.ts +37 -0
- package/avatar/types.js +1 -0
- package/avatar/utils.d.ts +4 -0
- package/avatar/utils.js +7 -0
- package/badge/index.d.ts +11 -0
- package/badge/index.js +114 -0
- package/badge/types.d.ts +34 -0
- package/badge/types.js +1 -0
- package/badge/utils.d.ts +2 -0
- package/badge/utils.js +1 -0
- package/button/index.d.ts +11 -0
- package/button/index.js +182 -0
- package/button/types.d.ts +53 -0
- package/button/types.js +1 -0
- package/button/utils.d.ts +2 -0
- package/button/utils.js +1 -0
- package/card/index.d.ts +13 -0
- package/card/index.js +133 -0
- package/card/types.d.ts +28 -0
- package/card/types.js +1 -0
- package/card-container/index.d.ts +11 -0
- package/card-container/index.js +11 -0
- package/card-container/types.d.ts +3 -0
- package/card-container/types.js +1 -0
- package/chat/index.d.ts +11 -0
- package/chat/index.js +11 -0
- package/chat/types.d.ts +3 -0
- package/chat/types.js +1 -0
- package/chat-block/index.d.ts +11 -0
- package/chat-block/index.js +86 -0
- package/chat-block/types.d.ts +30 -0
- package/chat-block/types.js +1 -0
- package/chat-bubble/index.d.ts +11 -0
- package/chat-bubble/index.js +41 -0
- package/chat-bubble/types.d.ts +20 -0
- package/chat-bubble/types.js +1 -0
- package/chat-bubble/utils.d.ts +3 -0
- package/chat-bubble/utils.js +2 -0
- package/checkbox/index.d.ts +11 -0
- package/checkbox/index.js +126 -0
- package/checkbox/types.d.ts +49 -0
- package/checkbox/types.js +1 -0
- package/chip/index.d.ts +13 -0
- package/chip/index.js +144 -0
- package/chip/types.d.ts +37 -0
- package/chip/types.js +1 -0
- package/chip/utils.d.ts +2 -0
- package/chip/utils.js +6 -0
- package/code-tag/index.d.ts +11 -0
- package/code-tag/index.js +31 -0
- package/code-tag/types.d.ts +11 -0
- package/code-tag/types.js +1 -0
- package/color-menu/index.d.ts +11 -0
- package/color-menu/index.js +308 -0
- package/color-menu/types.d.ts +32 -0
- package/color-menu/types.js +1 -0
- package/color-menu/utils.d.ts +1 -0
- package/color-menu/utils.js +11 -0
- package/color-menu-option/index.d.ts +13 -0
- package/color-menu-option/index.js +48 -0
- package/color-menu-option/types.d.ts +11 -0
- package/color-menu-option/types.js +1 -0
- package/color-menu-option/utils.d.ts +1 -0
- package/color-menu-option/utils.js +11 -0
- package/color-swatch/index.d.ts +12 -0
- package/color-swatch/index.js +54 -0
- package/color-swatch/types.d.ts +11 -0
- package/color-swatch/types.js +1 -0
- package/color-swatch/utils.d.ts +2 -0
- package/color-swatch/utils.js +6 -0
- package/date-picker/index.d.ts +14 -0
- package/date-picker/index.js +381 -0
- package/date-picker/types.d.ts +70 -0
- package/date-picker/types.js +1 -0
- package/date-picker/utils.d.ts +28 -0
- package/date-picker/utils.js +142 -0
- package/dialog/index.d.ts +15 -0
- package/dialog/index.js +144 -0
- package/dialog/types.d.ts +28 -0
- package/dialog/types.js +1 -0
- package/dialog/utils.d.ts +2 -0
- package/dialog/utils.js +18 -0
- package/emoji/index.d.ts +11 -0
- package/emoji/index.js +46 -0
- package/emoji/types.d.ts +11 -0
- package/emoji/types.js +1 -0
- package/emoji/utils.d.ts +3 -0
- package/emoji/utils.js +47 -0
- package/emoji-picker/index.d.ts +22 -0
- package/emoji-picker/index.js +308 -0
- package/emoji-picker/types.d.ts +26 -0
- package/emoji-picker/types.js +1 -0
- package/field/index.d.ts +11 -0
- package/field/index.js +120 -0
- package/field/types.d.ts +35 -0
- package/field/types.js +1 -0
- package/file-drop/index.d.ts +13 -0
- package/file-drop/index.js +205 -0
- package/file-drop/types.d.ts +50 -0
- package/file-drop/types.js +1 -0
- package/file-drop/utils.d.ts +2 -0
- package/file-drop/utils.js +31 -0
- package/file-picker/index.d.ts +11 -0
- package/file-picker/index.js +103 -0
- package/file-picker/types.d.ts +32 -0
- package/file-picker/types.js +1 -0
- package/file-picker/utils.d.ts +1 -0
- package/file-picker/utils.js +8 -0
- package/file-status/index.d.ts +14 -0
- package/file-status/index.js +61 -0
- package/file-status/types.d.ts +18 -0
- package/file-status/types.js +1 -0
- package/file-status/utils.d.ts +2 -0
- package/file-status/utils.js +1 -0
- package/flag/index.d.ts +11 -0
- package/flag/index.js +46 -0
- package/flag/types.d.ts +11 -0
- package/flag/types.js +1 -0
- package/flag/utils.d.ts +1 -0
- package/flag/utils.js +17 -0
- package/grid/index.d.ts +11 -0
- package/grid/index.js +11 -0
- package/grid/types.d.ts +3 -0
- package/grid/types.js +1 -0
- package/grid-item/index.d.ts +11 -0
- package/grid-item/index.js +35 -0
- package/grid-item/types.d.ts +17 -0
- package/grid-item/types.js +1 -0
- package/help-tooltip/index.d.ts +13 -0
- package/help-tooltip/index.js +74 -0
- package/help-tooltip/types.d.ts +3 -0
- package/help-tooltip/types.js +1 -0
- package/horizontal-stepper/index.d.ts +11 -0
- package/horizontal-stepper/index.js +61 -0
- package/horizontal-stepper/types.d.ts +13 -0
- package/horizontal-stepper/types.js +1 -0
- package/horizontal-stepper-item/index.d.ts +14 -0
- package/horizontal-stepper-item/index.js +61 -0
- package/horizontal-stepper-item/types.d.ts +24 -0
- package/horizontal-stepper-item/types.js +1 -0
- package/horizontal-stepper-item/utils.d.ts +2 -0
- package/horizontal-stepper-item/utils.js +1 -0
- package/icon/index.d.ts +11 -0
- package/icon/index.js +32 -0
- package/icon/types.d.ts +11 -0
- package/icon/types.js +1 -0
- package/icon-button/index.d.ts +12 -0
- package/icon-button/index.js +175 -0
- package/icon-button/types.d.ts +44 -0
- package/icon-button/types.js +1 -0
- package/icon-button/utils.d.ts +2 -0
- package/icon-button/utils.js +1 -0
- package/inline-alert/index.d.ts +15 -0
- package/inline-alert/index.js +83 -0
- package/inline-alert/types.d.ts +15 -0
- package/inline-alert/types.js +1 -0
- package/inline-alert/utils.d.ts +2 -0
- package/inline-alert/utils.js +1 -0
- package/input/index.d.ts +11 -0
- package/input/index.js +642 -0
- package/input/types.d.ts +86 -0
- package/input/types.js +1 -0
- package/input/utils.d.ts +26 -0
- package/input/utils.js +302 -0
- package/link/index.d.ts +12 -0
- package/link/index.js +150 -0
- package/link/types.d.ts +59 -0
- package/link/types.js +1 -0
- package/list/index.d.ts +11 -0
- package/list/index.js +14 -0
- package/list/types.d.ts +3 -0
- package/list/types.js +1 -0
- package/list-item/index.d.ts +11 -0
- package/list-item/index.js +14 -0
- package/list-item/types.d.ts +3 -0
- package/list-item/types.js +1 -0
- package/package.json +1 -1
- package/pagination/index.d.ts +12 -0
- package/pagination/index.js +147 -0
- package/pagination/types.d.ts +16 -0
- package/pagination/types.js +1 -0
- package/pop/index.d.ts +11 -0
- package/pop/index.js +425 -0
- package/pop/types.d.ts +35 -0
- package/pop/types.js +1 -0
- package/pop/utils.d.ts +4 -0
- package/pop/utils.js +16 -0
- package/popover/index.d.ts +12 -0
- package/popover/index.js +146 -0
- package/popover/types.d.ts +38 -0
- package/popover/types.js +1 -0
- package/popover/utils.d.ts +4 -0
- package/popover/utils.js +10 -0
- package/progress/index.d.ts +12 -0
- package/progress/index.js +58 -0
- package/progress/types.d.ts +12 -0
- package/progress/types.js +1 -0
- package/progress-stepper/index.d.ts +11 -0
- package/progress-stepper/index.js +206 -0
- package/progress-stepper/types.d.ts +22 -0
- package/progress-stepper/types.js +1 -0
- package/progress-stepper-item/index.d.ts +12 -0
- package/progress-stepper-item/index.js +82 -0
- package/progress-stepper-item/types.d.ts +23 -0
- package/progress-stepper-item/types.js +1 -0
- package/progress-stepper-item/utils.d.ts +11 -0
- package/progress-stepper-item/utils.js +13 -0
- package/radio/index.d.ts +11 -0
- package/radio/index.js +154 -0
- package/radio/types.d.ts +14 -0
- package/radio/types.js +1 -0
- package/radio-option/index.d.ts +11 -0
- package/radio-option/index.js +79 -0
- package/radio-option/types.d.ts +18 -0
- package/radio-option/types.js +1 -0
- package/rich-text/index.d.ts +14 -0
- package/rich-text/index.js +75 -0
- package/rich-text/types.d.ts +12 -0
- package/rich-text/types.js +1 -0
- package/rich-text/utils.d.ts +7 -0
- package/rich-text/utils.js +107 -0
- package/rich-textarea/index.d.ts +11 -0
- package/rich-textarea/index.js +464 -0
- package/rich-textarea/types.d.ts +48 -0
- package/rich-textarea/types.js +1 -0
- package/rich-textarea/utils.d.ts +39 -0
- package/rich-textarea/utils.js +1730 -0
- package/segment/index.d.ts +12 -0
- package/segment/index.js +109 -0
- package/segment/types.d.ts +16 -0
- package/segment/types.js +1 -0
- package/segment/utils.d.ts +3 -0
- package/segment/utils.js +16 -0
- package/segment-collapse/index.d.ts +13 -0
- package/segment-collapse/index.js +60 -0
- package/segment-collapse/types.d.ts +11 -0
- package/segment-collapse/types.js +1 -0
- package/segmented-control/index.d.ts +11 -0
- package/segmented-control/index.js +85 -0
- package/segmented-control/types.d.ts +11 -0
- package/segmented-control/types.js +1 -0
- package/segmented-control-option/index.d.ts +11 -0
- package/segmented-control-option/index.js +95 -0
- package/segmented-control-option/types.d.ts +19 -0
- package/segmented-control-option/types.js +1 -0
- package/segmented-icon-control/index.d.ts +11 -0
- package/segmented-icon-control/index.js +101 -0
- package/segmented-icon-control/types.d.ts +14 -0
- package/segmented-icon-control/types.js +1 -0
- package/segmented-icon-control-option/index.d.ts +11 -0
- package/segmented-icon-control-option/index.js +82 -0
- package/segmented-icon-control-option/types.d.ts +16 -0
- package/segmented-icon-control-option/types.js +1 -0
- package/select-button/index.d.ts +13 -0
- package/select-button/index.js +202 -0
- package/select-button/types.d.ts +50 -0
- package/select-button/types.js +1 -0
- package/select-menu/index.d.ts +15 -0
- package/select-menu/index.js +339 -0
- package/select-menu/types.d.ts +41 -0
- package/select-menu/types.js +1 -0
- package/select-menu-option/index.d.ts +28 -0
- package/select-menu-option/index.js +65 -0
- package/select-menu-option/types.d.ts +26 -0
- package/select-menu-option/types.js +1 -0
- package/skeleton/index.d.ts +11 -0
- package/skeleton/index.js +108 -0
- package/skeleton/types.d.ts +9 -0
- package/skeleton/types.js +1 -0
- package/skeleton-item/index.d.ts +11 -0
- package/skeleton-item/index.js +11 -0
- package/skeleton-item/types.d.ts +13 -0
- package/skeleton-item/types.js +1 -0
- package/spinner/index.d.ts +11 -0
- package/spinner/index.js +58 -0
- package/spinner/types.d.ts +12 -0
- package/spinner/types.js +1 -0
- package/standalone.d.ts +85 -0
- package/standalone.js +87 -0
- package/stop-events/index.d.ts +1 -0
- package/stop-events/index.js +27 -0
- package/table/index.d.ts +11 -0
- package/table/index.js +14 -0
- package/table/types.d.ts +3 -0
- package/table/types.js +1 -0
- package/table-body/index.d.ts +11 -0
- package/table-body/index.js +14 -0
- package/table-body/types.d.ts +3 -0
- package/table-body/types.js +1 -0
- package/table-cell/index.d.ts +11 -0
- package/table-cell/index.js +21 -0
- package/table-cell/types.d.ts +9 -0
- package/table-cell/types.js +1 -0
- package/table-cell/utils.d.ts +2 -0
- package/table-cell/utils.js +1 -0
- package/table-head/index.d.ts +11 -0
- package/table-head/index.js +14 -0
- package/table-head/types.d.ts +3 -0
- package/table-head/types.js +1 -0
- package/table-head-cell/index.d.ts +12 -0
- package/table-head-cell/index.js +57 -0
- package/table-head-cell/types.d.ts +15 -0
- package/table-head-cell/types.js +1 -0
- package/table-row/index.d.ts +11 -0
- package/table-row/index.js +42 -0
- package/table-row/types.d.ts +11 -0
- package/table-row/types.js +1 -0
- package/tabs/index.d.ts +11 -0
- package/tabs/index.js +80 -0
- package/tabs/types.d.ts +18 -0
- package/tabs/types.js +1 -0
- package/tabs-icon-option/index.d.ts +11 -0
- package/tabs-icon-option/index.js +79 -0
- package/tabs-icon-option/types.d.ts +19 -0
- package/tabs-icon-option/types.js +1 -0
- package/tabs-option/index.d.ts +12 -0
- package/tabs-option/index.js +86 -0
- package/tabs-option/types.d.ts +25 -0
- package/tabs-option/types.js +1 -0
- package/tag/index.d.ts +12 -0
- package/tag/index.js +84 -0
- package/tag/types.d.ts +23 -0
- package/tag/types.js +1 -0
- package/tag/utils.d.ts +2 -0
- package/tag/utils.js +6 -0
- package/text/index.d.ts +11 -0
- package/text/index.js +64 -0
- package/text/types.d.ts +30 -0
- package/text/types.js +1 -0
- package/text/utils.d.ts +2 -0
- package/text/utils.js +1 -0
- package/textarea/index.d.ts +11 -0
- package/textarea/index.js +322 -0
- package/textarea/types.d.ts +60 -0
- package/textarea/types.js +1 -0
- package/tile-control/index.d.ts +11 -0
- package/tile-control/index.js +110 -0
- package/tile-control/types.d.ts +37 -0
- package/tile-control/types.js +1 -0
- package/tile-control-option/index.d.ts +11 -0
- package/tile-control-option/index.js +98 -0
- package/tile-control-option/types.d.ts +37 -0
- package/tile-control-option/types.js +1 -0
- package/time-picker/index.d.ts +15 -0
- package/time-picker/index.js +337 -0
- package/time-picker/types.d.ts +34 -0
- package/time-picker/types.js +1 -0
- package/time-picker/utils.d.ts +11 -0
- package/time-picker/utils.js +75 -0
- package/title/index.d.ts +11 -0
- package/title/index.js +60 -0
- package/title/types.d.ts +31 -0
- package/title/types.js +1 -0
- package/title/utils.d.ts +3 -0
- package/title/utils.js +17 -0
- package/toast/index.d.ts +13 -0
- package/toast/index.js +86 -0
- package/toast/types.d.ts +28 -0
- package/toast/types.js +1 -0
- package/toast/utils.d.ts +2 -0
- package/toast/utils.js +1 -0
- package/toast-manager/index.d.ts +13 -0
- package/toast-manager/index.js +170 -0
- package/toast-manager/types.d.ts +13 -0
- package/toast-manager/types.js +1 -0
- package/toast-manager/utils.d.ts +2 -0
- package/toast-manager/utils.js +1 -0
- package/toggle/index.d.ts +11 -0
- package/toggle/index.js +141 -0
- package/toggle/types.d.ts +23 -0
- package/toggle/types.js +1 -0
- package/tooltip/index.d.ts +13 -0
- package/tooltip/index.js +275 -0
- package/tooltip/tooltip-state.d.ts +19 -0
- package/tooltip/tooltip-state.js +126 -0
- package/tooltip/types.d.ts +42 -0
- package/tooltip/types.js +1 -0
- package/tooltip/utils.d.ts +6 -0
- package/tooltip/utils.js +18 -0
- package/utils/context.d.ts +20 -0
- package/utils/context.js +84 -0
- package/utils/countries.d.ts +6 -0
- package/utils/countries.js +2 -0
- package/utils/csv.d.ts +5 -0
- package/utils/csv.js +22 -0
- package/utils/debounce.d.ts +8 -0
- package/utils/debounce.js +22 -0
- package/utils/dom.d.ts +34 -0
- package/utils/dom.js +154 -0
- package/utils/element.d.ts +16 -0
- package/utils/element.js +48 -0
- package/utils/event-target.d.ts +4 -0
- package/utils/event-target.js +26 -0
- package/utils/get-react-event-handler.d.ts +1 -0
- package/utils/get-react-event-handler.js +8 -0
- package/utils/index.d.ts +12 -0
- package/utils/index.js +12 -0
- package/utils/markdown.d.ts +19 -0
- package/utils/markdown.js +143 -0
- package/utils/rect.d.ts +4 -0
- package/utils/rect.js +28 -0
- package/utils/size.d.ts +5 -0
- package/utils/size.js +3 -0
- package/utils/slot.d.ts +4 -0
- package/utils/slot.js +38 -0
- package/utils/throttle.d.ts +4 -0
- package/utils/throttle.js +20 -0
- package/utils/uid.d.ts +1 -0
- package/utils/uid.js +13 -0
- package/vertical-stepper/index.d.ts +11 -0
- package/vertical-stepper/index.js +57 -0
- package/vertical-stepper/types.d.ts +13 -0
- package/vertical-stepper/types.js +1 -0
- package/vertical-stepper-item/index.d.ts +14 -0
- package/vertical-stepper-item/index.js +61 -0
- package/vertical-stepper-item/types.d.ts +24 -0
- package/vertical-stepper-item/types.js +1 -0
- package/vertical-stepper-item/utils.d.ts +2 -0
- package/vertical-stepper-item/utils.js +1 -0
package/dialog/index.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import '../icon-button';
|
|
2
|
+
import '../icon';
|
|
3
|
+
import '../stop-events';
|
|
4
|
+
import '../title';
|
|
5
|
+
import { defineCustomElement, getAttribute, getBooleanAttribute, getRect, isAttrTrue, updateAttribute, getReactEventHandler, NectaryElement, updateBooleanAttribute, setClass, isTargetEqual, isAttrEqual } from '../utils';
|
|
6
|
+
const templateHTML = '<style>:host{display:contents;--sinch-comp-dialog-max-width:512px;--sinch-comp-dialog-max-height:90vh;--sinch-comp-dialog-width:fit-content}#dialog{position:fixed;left:0;right:0;margin:auto;display:flex;flex-direction:column;padding:24px 0;width:var(--sinch-comp-dialog-width);max-width:var(--sinch-comp-dialog-max-width);max-height:var(--sinch-comp-dialog-max-height);border-radius:var(--sinch-comp-dialog-shape-radius);box-sizing:border-box;contain:content;background-color:var(--sinch-comp-dialog-color-default-background-initial);border:none;box-shadow:var(--sinch-comp-dialog-shadow);outline:0}#dialog:not([open]){display:none}dialog::backdrop{background-color:#000;opacity:.55}#header{display:flex;flex-direction:row;align-items:flex-start;margin-bottom:12px;padding:0 24px;gap:8px;--sinch-global-size-icon:24px;--sinch-global-color-icon:var(--sinch-comp-dialog-color-default-icon-initial)}#caption{--sinch-global-color-text:var(--sinch-comp-dialog-color-default-title-initial);--sinch-comp-title-font:var(--sinch-comp-dialog-font-title)}#content{min-height:0;overflow:auto;padding:4px 24px}#action{display:flex;flex-direction:row;justify-content:flex-end;gap:16px;margin-top:20px;padding:0 24px}#action.empty{display:none}#close{position:relative;left:4px;top:-4px;margin-left:auto}</style><dialog id="dialog"><div id="header"><slot id="icon" name="icon"></slot><sinch-title id="caption" type="m" level="3"></sinch-title><sinch-icon-button id="close" size="s"><sinch-icon id="icon-close" slot="icon" name="close"></sinch-icon></sinch-icon-button></div><div id="content"><sinch-stop-events events="close"><slot name="content"></slot></sinch-stop-events></div><div id="action"><sinch-stop-events events="close"><slot name="buttons"></slot></sinch-stop-events></div></dialog>';
|
|
7
|
+
import { disableScroll, enableScroll } from './utils';
|
|
8
|
+
const template = document.createElement('template');
|
|
9
|
+
template.innerHTML = templateHTML;
|
|
10
|
+
defineCustomElement('sinch-dialog', class extends NectaryElement {
|
|
11
|
+
#$dialog;
|
|
12
|
+
#$closeButton;
|
|
13
|
+
#$caption;
|
|
14
|
+
#$actionWrapper;
|
|
15
|
+
#$actionSlot;
|
|
16
|
+
#controller = null;
|
|
17
|
+
constructor() {
|
|
18
|
+
super();
|
|
19
|
+
const shadowRoot = this.attachShadow();
|
|
20
|
+
shadowRoot.appendChild(template.content.cloneNode(true));
|
|
21
|
+
this.#$dialog = shadowRoot.querySelector('#dialog');
|
|
22
|
+
this.#$closeButton = shadowRoot.querySelector('#close');
|
|
23
|
+
this.#$caption = shadowRoot.querySelector('#caption');
|
|
24
|
+
this.#$actionWrapper = shadowRoot.querySelector('#action');
|
|
25
|
+
this.#$actionSlot = shadowRoot.querySelector('slot[name="buttons"]');
|
|
26
|
+
}
|
|
27
|
+
connectedCallback() {
|
|
28
|
+
super.connectedCallback();
|
|
29
|
+
this.#controller = new AbortController();
|
|
30
|
+
const options = {
|
|
31
|
+
signal: this.#controller.signal
|
|
32
|
+
};
|
|
33
|
+
this.role = 'dialog';
|
|
34
|
+
this.#$closeButton.addEventListener('click', this.#onCloseClick, options);
|
|
35
|
+
this.#$dialog.addEventListener('mousedown', this.#onBackdropMouseDown, options);
|
|
36
|
+
this.#$dialog.addEventListener('cancel', this.#onCancel, options);
|
|
37
|
+
this.#$actionSlot.addEventListener('slotchange', this.#onActionSlotChange, options);
|
|
38
|
+
this.addEventListener('-close', this.#onCloseReactHandler, options);
|
|
39
|
+
this.#onActionSlotChange();
|
|
40
|
+
if (this.open) {
|
|
41
|
+
this.#onExpand();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
disconnectedCallback() {
|
|
45
|
+
super.disconnectedCallback();
|
|
46
|
+
this.#onCollapse();
|
|
47
|
+
this.#controller.abort();
|
|
48
|
+
this.#controller = null;
|
|
49
|
+
}
|
|
50
|
+
static get observedAttributes() {
|
|
51
|
+
return ['caption', 'open', 'close-aria-label'];
|
|
52
|
+
}
|
|
53
|
+
attributeChangedCallback(name, oldVal, newVal) {
|
|
54
|
+
if (isAttrEqual(oldVal, newVal)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
switch (name) {
|
|
58
|
+
case 'caption':
|
|
59
|
+
{
|
|
60
|
+
updateAttribute(this.#$caption, 'text', newVal);
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
case 'open':
|
|
64
|
+
{
|
|
65
|
+
const shouldOpen = isAttrTrue(newVal);
|
|
66
|
+
if (shouldOpen) {
|
|
67
|
+
requestAnimationFrame(() => {
|
|
68
|
+
this.#onExpand();
|
|
69
|
+
});
|
|
70
|
+
} else {
|
|
71
|
+
this.#onCollapse();
|
|
72
|
+
}
|
|
73
|
+
updateBooleanAttribute(this, 'open', shouldOpen);
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
case 'close-aria-label':
|
|
77
|
+
{
|
|
78
|
+
updateAttribute(this.#$closeButton, 'aria-label', newVal);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
set caption(caption) {
|
|
84
|
+
updateAttribute(this, 'caption', caption);
|
|
85
|
+
}
|
|
86
|
+
get caption() {
|
|
87
|
+
return getAttribute(this, 'caption', '');
|
|
88
|
+
}
|
|
89
|
+
set open(isOpen) {
|
|
90
|
+
updateBooleanAttribute(this, 'open', isOpen);
|
|
91
|
+
}
|
|
92
|
+
get open() {
|
|
93
|
+
return getBooleanAttribute(this, 'open');
|
|
94
|
+
}
|
|
95
|
+
get dialogRect() {
|
|
96
|
+
return getRect(this.#$dialog);
|
|
97
|
+
}
|
|
98
|
+
get closeButtonRect() {
|
|
99
|
+
return getRect(this.#$closeButton);
|
|
100
|
+
}
|
|
101
|
+
#onCancel = e => {
|
|
102
|
+
e.preventDefault();
|
|
103
|
+
e.stopPropagation();
|
|
104
|
+
this.#dispatchCloseEvent('escape');
|
|
105
|
+
};
|
|
106
|
+
#onCloseClick = () => {
|
|
107
|
+
this.#dispatchCloseEvent('close');
|
|
108
|
+
};
|
|
109
|
+
#onBackdropMouseDown = e => {
|
|
110
|
+
if (isTargetEqual(e, this.#$dialog)) {
|
|
111
|
+
const rect = this.dialogRect;
|
|
112
|
+
const isInside = e.x >= rect.x && e.x < rect.x + rect.width && e.y >= rect.y && e.y < rect.y + rect.height;
|
|
113
|
+
if (!isInside) {
|
|
114
|
+
e.stopPropagation();
|
|
115
|
+
this.#dispatchCloseEvent('backdrop');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
#onCloseReactHandler = e => {
|
|
120
|
+
getReactEventHandler(this, 'on-close')?.(e);
|
|
121
|
+
};
|
|
122
|
+
#dispatchCloseEvent(detail) {
|
|
123
|
+
this.dispatchEvent(new CustomEvent('-close', {
|
|
124
|
+
detail
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
#onExpand() {
|
|
128
|
+
if (!this.isDomConnected || this.#$dialog.open || !this.open) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
this.#$dialog.showModal();
|
|
132
|
+
disableScroll();
|
|
133
|
+
}
|
|
134
|
+
#onCollapse() {
|
|
135
|
+
if (!this.#$dialog.open) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
this.#$dialog.close?.();
|
|
139
|
+
enableScroll();
|
|
140
|
+
}
|
|
141
|
+
#onActionSlotChange = () => {
|
|
142
|
+
setClass(this.#$actionWrapper, 'empty', this.#$actionSlot.assignedElements().length === 0);
|
|
143
|
+
};
|
|
144
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { TRect, TSinchElementReact } from '../types';
|
|
2
|
+
export type TSinchDialogCloseDetail = 'close' | 'escape' | 'backdrop';
|
|
3
|
+
export type TSinchDialogElement = HTMLElement & {
|
|
4
|
+
/** Open/close state */
|
|
5
|
+
open: boolean;
|
|
6
|
+
/** Dialog caption */
|
|
7
|
+
caption: string;
|
|
8
|
+
readonly dialogRect: TRect;
|
|
9
|
+
readonly closeButtonRect: TRect;
|
|
10
|
+
/** close event handler */
|
|
11
|
+
addEventListener(type: '-close', listener: (e: CustomEvent<TSinchDialogCloseDetail>) => void): void;
|
|
12
|
+
/** Dialog caption */
|
|
13
|
+
setAttribute(name: 'caption', value: string): void;
|
|
14
|
+
/** Close button label that is used for a11y */
|
|
15
|
+
setAttribute(name: 'close-aria-label', value: string): void;
|
|
16
|
+
};
|
|
17
|
+
export type TSinchDialogReact = TSinchElementReact<TSinchDialogElement> & {
|
|
18
|
+
/** Controls whether the dialog should be open */
|
|
19
|
+
open: boolean;
|
|
20
|
+
/** Dialog caption */
|
|
21
|
+
caption: string;
|
|
22
|
+
/** Label that is used for a11y */
|
|
23
|
+
'aria-label': string;
|
|
24
|
+
/** Close button label that is used for a11y */
|
|
25
|
+
'close-aria-label': string;
|
|
26
|
+
/** close event handler */
|
|
27
|
+
'on-close'?: (e: CustomEvent<TSinchDialogCloseDetail>) => void;
|
|
28
|
+
};
|
package/dialog/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dialog/utils.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const bodyEl = document.body;
|
|
2
|
+
export const disableScroll = () => {
|
|
3
|
+
bodyEl.__dialog_counter__ = (bodyEl.__dialog_counter__ ?? 0) + 1;
|
|
4
|
+
if (bodyEl.__dialog_counter__ === 1) {
|
|
5
|
+
const scrollWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
6
|
+
bodyEl.style.overflow = 'hidden';
|
|
7
|
+
if (scrollWidth > 0) {
|
|
8
|
+
bodyEl.style.setProperty('padding-right', `${scrollWidth}px`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
export const enableScroll = () => {
|
|
13
|
+
bodyEl.__dialog_counter__ = Math.max(0, (bodyEl.__dialog_counter__ ?? 0) - 1);
|
|
14
|
+
if (bodyEl.__dialog_counter__ === 0) {
|
|
15
|
+
bodyEl.style.overflow = '';
|
|
16
|
+
bodyEl.style.removeProperty('padding-right');
|
|
17
|
+
}
|
|
18
|
+
};
|
package/emoji/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TSinchEmojiElement, TSinchEmojiReact } from './types';
|
|
2
|
+
declare global {
|
|
3
|
+
namespace JSX {
|
|
4
|
+
interface IntrinsicElements {
|
|
5
|
+
'sinch-emoji': TSinchEmojiReact;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
interface HTMLElementTagNameMap {
|
|
9
|
+
'sinch-emoji': TSinchEmojiElement;
|
|
10
|
+
}
|
|
11
|
+
}
|
package/emoji/index.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { defineCustomElement, getAttribute, NectaryElement, updateAttribute } from '../utils';
|
|
2
|
+
const templateHTML = '<style>:host{display:contents;--sinch-comp-emoji-vertical-align:initial}#image{vertical-align:var(--sinch-comp-emoji-vertical-align);pointer-events:none;width:var(--sinch-global-size-icon,48px);height:var(--sinch-global-size-icon,48px)}</style><img id="image" src="" alt="" loading="lazy"/>';
|
|
3
|
+
import { getEmojiBaseUrl, getEmojiUrl } from './utils';
|
|
4
|
+
const template = document.createElement('template');
|
|
5
|
+
template.innerHTML = templateHTML;
|
|
6
|
+
defineCustomElement('sinch-emoji', class extends NectaryElement {
|
|
7
|
+
#$img;
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
const shadowRoot = this.attachShadow();
|
|
11
|
+
shadowRoot.appendChild(template.content.cloneNode(true));
|
|
12
|
+
this.#$img = shadowRoot.querySelector('#image');
|
|
13
|
+
}
|
|
14
|
+
connectedCallback() {
|
|
15
|
+
super.connectedCallback();
|
|
16
|
+
this.#updateChar();
|
|
17
|
+
}
|
|
18
|
+
disconnectedCallback() {
|
|
19
|
+
super.disconnectedCallback();
|
|
20
|
+
}
|
|
21
|
+
static get observedAttributes() {
|
|
22
|
+
return ['char'];
|
|
23
|
+
}
|
|
24
|
+
attributeChangedCallback(name, _, newVal) {
|
|
25
|
+
switch (name) {
|
|
26
|
+
case 'char':
|
|
27
|
+
{
|
|
28
|
+
this.#$img.alt = newVal ?? '';
|
|
29
|
+
this.#updateChar();
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
set char(value) {
|
|
35
|
+
updateAttribute(this, 'char', value);
|
|
36
|
+
}
|
|
37
|
+
get char() {
|
|
38
|
+
return getAttribute(this, 'char', '');
|
|
39
|
+
}
|
|
40
|
+
#updateChar() {
|
|
41
|
+
if (!this.isDomConnected) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
this.#$img.src = getEmojiUrl(getEmojiBaseUrl(this), this.char);
|
|
45
|
+
}
|
|
46
|
+
});
|
package/emoji/types.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TSinchElementReact } from '../types';
|
|
2
|
+
export type TSinchEmojiElement = HTMLElement & {
|
|
3
|
+
/** Emoji character */
|
|
4
|
+
char: string;
|
|
5
|
+
/** Emoji character */
|
|
6
|
+
setAttribute(name: 'char', value: string): void;
|
|
7
|
+
};
|
|
8
|
+
export type TSinchEmojiReact = TSinchElementReact<TSinchEmojiElement> & {
|
|
9
|
+
/** Emoji character */
|
|
10
|
+
char: string;
|
|
11
|
+
};
|
package/emoji/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/emoji/utils.d.ts
ADDED
package/emoji/utils.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getAttribute, getCssVar, updateAttribute } from '../utils/dom';
|
|
2
|
+
const vs16RegExp = /\uFE0F/g;
|
|
3
|
+
const zeroWidthJoiner = String.fromCharCode(0x200d);
|
|
4
|
+
const removeVS16s = rawEmoji => rawEmoji.indexOf(zeroWidthJoiner) < 0 ? rawEmoji.replace(vs16RegExp, '') : rawEmoji;
|
|
5
|
+
function toCodePoints(unicodeSurrogates) {
|
|
6
|
+
const points = [];
|
|
7
|
+
let char = 0;
|
|
8
|
+
let previous = 0;
|
|
9
|
+
let i = 0;
|
|
10
|
+
while (i < unicodeSurrogates.length) {
|
|
11
|
+
char = unicodeSurrogates.charCodeAt(i++);
|
|
12
|
+
if (previous !== 0) {
|
|
13
|
+
points.push((0x10000 + (previous - 0xd800 << 10) + (char - 0xdc00)).toString(16));
|
|
14
|
+
previous = 0;
|
|
15
|
+
} else if (char > 0xd800 && char <= 0xdbff) {
|
|
16
|
+
previous = char;
|
|
17
|
+
} else {
|
|
18
|
+
points.push(char.toString(16));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return points;
|
|
22
|
+
}
|
|
23
|
+
const BASE_URL_ATTR = 'data-emoji-base-url';
|
|
24
|
+
export const setEmojiBaseUrl = (emojiEl, baseUrl) => {
|
|
25
|
+
updateAttribute(emojiEl, BASE_URL_ATTR, baseUrl);
|
|
26
|
+
};
|
|
27
|
+
export const getEmojiBaseUrl = root => {
|
|
28
|
+
let baseUrl = getAttribute(root, BASE_URL_ATTR);
|
|
29
|
+
if (baseUrl !== null) {
|
|
30
|
+
return baseUrl;
|
|
31
|
+
}
|
|
32
|
+
baseUrl = getCssVar(root, '--sinch-emoji-src-url');
|
|
33
|
+
if (baseUrl !== null) {
|
|
34
|
+
return baseUrl.replaceAll('"', '').trim();
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
};
|
|
38
|
+
export const getEmojiUrl = (baseUrl, char) => {
|
|
39
|
+
if (char === null || char.length === 0 || baseUrl === null) {
|
|
40
|
+
return '';
|
|
41
|
+
}
|
|
42
|
+
let codepoints = toCodePoints(removeVS16s(char)).join('-');
|
|
43
|
+
if (codepoints === '1f441-fe0f-200d-1f5e8-fe0f') {
|
|
44
|
+
codepoints = '1f441-200d-1f5e8';
|
|
45
|
+
}
|
|
46
|
+
return baseUrl.replace('%s', codepoints);
|
|
47
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import '../input';
|
|
2
|
+
import '../icon-button';
|
|
3
|
+
import '../color-swatch';
|
|
4
|
+
import '../color-menu';
|
|
5
|
+
import '../color-menu-option';
|
|
6
|
+
import '../popover';
|
|
7
|
+
import '../tabs';
|
|
8
|
+
import '../tabs-icon-option';
|
|
9
|
+
import '../emoji';
|
|
10
|
+
import '../text';
|
|
11
|
+
import '../icon';
|
|
12
|
+
import type { TSinchEmojiPickerElement, TSinchEmojiPickerReact } from './types';
|
|
13
|
+
declare global {
|
|
14
|
+
namespace JSX {
|
|
15
|
+
interface IntrinsicElements {
|
|
16
|
+
'sinch-emoji-picker': TSinchEmojiPickerReact;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
interface HTMLElementTagNameMap {
|
|
20
|
+
'sinch-emoji-picker': TSinchEmojiPickerElement;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import '../input';
|
|
2
|
+
import '../icon-button';
|
|
3
|
+
import '../color-swatch';
|
|
4
|
+
import '../color-menu';
|
|
5
|
+
import '../color-menu-option';
|
|
6
|
+
import '../popover';
|
|
7
|
+
import '../tabs';
|
|
8
|
+
import '../tabs-icon-option';
|
|
9
|
+
import '../emoji';
|
|
10
|
+
import '../text';
|
|
11
|
+
import '../icon';
|
|
12
|
+
import { getEmojiBaseUrl, setEmojiBaseUrl } from '../emoji/utils';
|
|
13
|
+
import { defineCustomElement, getAttribute, getBooleanAttribute, NectaryElement, updateAttribute, updateBooleanAttribute, getReactEventHandler, getRect, debounceTimeout, setClass } from '../utils';
|
|
14
|
+
import dataJson from './data.json';
|
|
15
|
+
const templateHTML = '<style>:host{display:block}#wrapper{width:384px;max-height:504px;display:flex;flex-direction:column;gap:8px;padding:12px 0}#toolbar{display:flex;gap:8px;padding:0 12px}#search{flex:1;min-width:0}#search-clear:not(.active){display:none}#list-wrapper{overflow-y:auto;overflow-x:hidden;width:384px;box-sizing:border-box;scrollbar-gutter:stable}#list{display:flex;flex-wrap:wrap;gap:8px;padding:4px 12px 0;width:384px;box-sizing:border-box}#not-found{display:none;width:100%;height:48px;align-items:center;justify-content:center;pointer-events:none;user-select:none;--sinch-global-color-text:var(--sinch-comp-emoji-picker-color-default-text-not-found);--sinch-comp-text-font:var(--sinch-comp-emoji-picker-font-not-found)}#not-found.active{display:flex}sinch-tabs-icon-option>svg{pointer-events:none;height:var(--sinch-global-size-icon);fill:var(--sinch-global-color-icon)}</style><div id="wrapper"><div id="toolbar"><sinch-input id="search" size="l" aria-label="Search emojis"><sinch-icon id="icon-search" slot="icon" name="search"></sinch-icon><sinch-icon-button id="search-clear" slot="right" aria-label="Clear"><sinch-icon slot="icon" name="close"></sinch-icon></sinch-icon-button></sinch-input><sinch-popover id="skin-popover" orientation="bottom-left" aria-label="Emoji skin tone select"><sinch-icon-button id="skin-button" slot="target" size="l" aria-label="Select emoji skin tones"><sinch-color-swatch id="skin-swatch" slot="icon" name="skintone-default"></sinch-color-swatch></sinch-icon-button><sinch-color-menu id="skin-menu" slot="content" cols="1" value="skintone-default" aria-label="Emoji skin tone menu"><sinch-color-menu-option value="skintone-default"></sinch-color-menu-option><sinch-color-menu-option value="skintone-light"></sinch-color-menu-option><sinch-color-menu-option value="skintone-light-medium"></sinch-color-menu-option><sinch-color-menu-option value="skintone-medium"></sinch-color-menu-option><sinch-color-menu-option value="skintone-medium-dark"></sinch-color-menu-option><sinch-color-menu-option value="skintone-dark"></sinch-color-menu-option></sinch-color-menu></sinch-popover></div><sinch-tabs id="tabs" aria-label="Emoji groups"><sinch-tabs-icon-option id="tab-emotions"><svg slot="icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M15.5 11a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm-7 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"/><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2ZM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8Zm4.41-6.11a.745.745 0 0 0-1.03.24A3.98 3.98 0 0 1 12 16c-1.38 0-2.64-.7-3.38-1.88a.747.747 0 1 0-1.27.79A5.446 5.446 0 0 0 12 17.5c1.9 0 3.63-.97 4.65-2.58.22-.35.11-.81-.24-1.03Z"/></svg></sinch-tabs-icon-option><sinch-tabs-icon-option id="tab-people"><svg slot="icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 6a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z"/><path d="M15.89 8.11C15.5 7.72 14.83 7 13.53 7h-2.54a5.023 5.023 0 0 1-4.92-4.15.998.998 0 0 0-.98-.85c-.61 0-1.09.54-1 1.14A7.037 7.037 0 0 0 9 8.71V21c0 .55.45 1 1 1s1-.45 1-1v-5h2v5c0 .55.45 1 1 1s1-.45 1-1V10.05l3.24 3.24a.996.996 0 1 0 1.41-1.41l-3.76-3.77Z"/></svg></sinch-tabs-icon-option><sinch-tabs-icon-option id="tab-animals"><svg slot="icon" viewBox="0 0 24 24"><path d="M17 14c-.24-.24-.44-.49-.65-.75C17.51 11.5 19 8.56 19 5c0-1.95-.74-3-2-3-1.54 0-3.96 2.06-5 5.97C10.96 4.06 8.54 2 7 2 5.74 2 5 3.05 5 5c0 3.56 1.49 6.5 2.65 8.25-.21.26-.41.51-.65.75-.25.25-2 1.39-2 3.5C5 19.98 7.02 22 9.5 22c1.5 0 2.5-.5 2.5-.5s1 .5 2.5.5c2.48 0 4.5-2.02 4.5-4.5 0-2.11-1.75-3.25-2-3.5Zm-.12-9.97c.06.17.12.48.12.97 0 2.84-1.11 5.24-2.07 6.78-.38-.26-.83-.48-1.4-.62.24-4.52 2.44-6.83 3.35-7.13ZM7 5c0-.49.06-.8.12-.97.91.3 3.11 2.61 3.36 7.13-.58.14-1.03.35-1.4.62C8.11 10.24 7 7.84 7 5Zm7.5 15c-1 0-1.8-.33-2.22-.56.42-.18.72-.71.72-.94 0-.28-.45-.5-1-.5s-1 .22-1 .5c0 .23.3.76.72.94-.42.23-1.22.56-2.22.56A2.5 2.5 0 0 1 7 17.5c0-.7.43-1.24 1-1.73.44-.36.61-.52 1.3-1.37.76-.95 1.09-1.4 2.7-1.4s1.94.45 2.7 1.4c.69.85.86 1.01 1.3 1.37.57.49 1 1.03 1 1.73a2.5 2.5 0 0 1-2.5 2.5Zm-.5-4c0 .41-.22.75-.5.75s-.5-.34-.5-.75.22-.75.5-.75.5.34.5.75Zm-3 0c0 .41-.22.75-.5.75s-.5-.34-.5-.75.22-.75.5-.75.5.34.5.75Z"/></svg></sinch-tabs-icon-option><sinch-tabs-icon-option id="tab-food"><svg slot="icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M19 19H3c-.55 0-1 .45-1 1s.45 1 1 1h16c.55 0 1-.45 1-1s-.45-1-1-1Zm1-16H9v2.4l1.81 1.45c.12.09.19.24.19.39v4.26c0 .28-.22.5-.5.5h-4c-.28 0-.5-.22-.5-.5V7.24c0-.15.07-.3.19-.39L8 5.4V3H6c-1.1 0-2 .9-2 2v8c0 2.21 1.79 4 4 4h6c2.21 0 4-1.79 4-4v-3h2c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2Zm0 5h-2V5h2v3Z"/></svg></sinch-tabs-icon-option><sinch-tabs-icon-option id="tab-travel"><svg slot="icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="m21.99 14.77-1.43-4.11c-.14-.4-.52-.66-.97-.66H12.4c-.46 0-.83.26-.98.66L10 14.77v5.24c0 .55.45.99 1 .99s1-.45 1-1v-1h8v1a1 1 0 0 0 2 .01l-.01-5.24Zm-10.38-1.43.69-2c.05-.2.24-.34.46-.34h6.48c.21 0 .4.14.47.34l.69 2a.5.5 0 0 1-.47.66h-7.85a.5.5 0 0 1-.47-.66Zm.38 3.66c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1Zm8 0c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1Z"/><path d="M14 4.5V9h1V4c0-.55-.45-1-1-1H8c-.55 0-1 .45-1 1v4H3c-.55 0-1 .45-1 1v12h1V9.5c0-.28.22-.5.5-.5h4c.28 0 .5-.22.5-.5v-4c0-.28.22-.5.5-.5h5c.28 0 .5.22.5.5Z"/><path d="M7 11H5v2h2v-2Zm5-6h-2v2h2V5ZM7 15H5v2h2v-2Zm0 4H5v2h2v-2Z"/></svg></sinch-tabs-icon-option><sinch-tabs-icon-option id="tab-sports"><svg slot="icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M19.52 2.49C17.18.15 12.9.62 9.97 3.55c-1.6 1.6-2.52 3.87-2.54 5.46-.02 1.58.26 3.89-1.35 5.5l-3.54 3.53c-.39.39-.39 1.02 0 1.42.39.39 1.02.39 1.42 0l3.53-3.54c1.61-1.61 3.92-1.33 5.5-1.35 1.58-.02 3.86-.94 5.46-2.54 2.93-2.92 3.41-7.2 1.07-9.54Zm-9.2 9.19c-1.53-1.53-1.05-4.61 1.06-6.72 2.11-2.11 5.18-2.59 6.72-1.06 1.53 1.53 1.05 4.61-1.06 6.72-2.11 2.11-5.18 2.59-6.72 1.06ZM18 17c.53 0 1.04.21 1.41.59.78.78.78 2.05 0 2.83-.37.37-.88.58-1.41.58-.53 0-1.04-.21-1.41-.59-.78-.78-.78-2.05 0-2.83.37-.37.88-.58 1.41-.58Zm0-2a3.998 3.998 0 0 0-2.83 6.83c.78.78 1.81 1.17 2.83 1.17a3.998 3.998 0 0 0 2.83-6.83A3.998 3.998 0 0 0 18 15Z"/></svg></sinch-tabs-icon-option><sinch-tabs-icon-option id="tab-objects"><svg slot="icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 3c-.46 0-.93.04-1.4.14-2.76.53-4.96 2.76-5.48 5.52-.48 2.61.48 5.01 2.22 6.56.43.38.66.91.66 1.47V19c0 1.1.9 2 2 2h.28a1.98 1.98 0 0 0 3.44 0H14c1.1 0 2-.9 2-2v-2.31c0-.55.22-1.09.64-1.46A6.956 6.956 0 0 0 19 10c0-3.87-3.13-7-7-7Zm.5 11h-1v-2.59L9.67 9.59l.71-.71L12 10.5l1.62-1.62.71.71-1.83 1.83V14Zm1 5c-.01 0-.02-.01-.03-.01V19h-2.94v-.01c-.01 0-.02.01-.03.01-.28 0-.5-.22-.5-.5s.22-.5.5-.5c.01 0 .02.01.03.01V18h2.94v.01c.01 0 .02-.01.03-.01.28 0 .5.22.5.5s-.22.5-.5.5Zm0-2h-3c-.28 0-.5-.22-.5-.5s.22-.5.5-.5h3c.28 0 .5.22.5.5s-.22.5-.5.5Z"/></svg></sinch-tabs-icon-option><sinch-tabs-icon-option id="tab-symbols"><svg slot="icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M10 5H4c-.55 0-1 .45-1 1s.45 1 1 1h2v3c0 .55.45 1 1 1s1-.45 1-1V7h2c.55 0 1-.45 1-1s-.45-1-1-1Zm0-3H4c-.55 0-1 .45-1 1s.45 1 1 1h6c.55 0 1-.45 1-1s-.45-1-1-1Zm10.89 11.11a.996.996 0 0 0-1.41 0l-6.36 6.36a.996.996 0 1 0 1.41 1.41l6.36-6.36a.996.996 0 0 0 0-1.41ZM14.5 16a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm5 5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm-4-10A2.5 2.5 0 0 0 18 8.5V4h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1v3.51c-.42-.32-.93-.51-1.5-.51a2.5 2.5 0 0 0 0 5Zm-5.05 7.09a.996.996 0 1 0-1.41-1.41l-.71.71-.71-.71.35-.35a2.499 2.499 0 0 0-1.77-4.27 2.499 2.499 0 0 0-1.77 4.27l.35.35-1.06 1.06c-.98.98-.98 2.56 0 3.54.5.48 1.14.72 1.78.72.64 0 1.28-.24 1.77-.73l1.06-1.06.71.71a.996.996 0 1 0 1.41-1.41l-.71-.71.71-.71Zm-4.6-3.89a.5.5 0 0 1 .35-.15.5.5 0 0 1 .35.15c.19.2.19.51 0 .71l-.35.35-.35-.36a.5.5 0 0 1-.15-.35.5.5 0 0 1 .15-.35Zm0 5.65a.5.5 0 0 1-.35.15.5.5 0 0 1-.35-.15.5.5 0 0 1-.15-.35.5.5 0 0 1 .15-.35l1.06-1.06.71.71-1.07 1.05Z"/></svg></sinch-tabs-icon-option></sinch-tabs><div id="list-wrapper"><div id="list"></div><div id="not-found"><sinch-text type="m">No results</sinch-text></div></div></div>';
|
|
16
|
+
const groupLabels = ['Emotions', 'People', 'Animals and nature', 'Food and drinks', 'Travel and places', 'Sports and activities', 'Objects', 'Symbols and flags'];
|
|
17
|
+
const data = dataJson;
|
|
18
|
+
const template = document.createElement('template');
|
|
19
|
+
const MIN_SEARCH_LENGTH = 2;
|
|
20
|
+
const SEARCH_DEBOUNCE_TIMEOUT = 300;
|
|
21
|
+
template.innerHTML = templateHTML;
|
|
22
|
+
defineCustomElement('sinch-emoji-picker', class extends NectaryElement {
|
|
23
|
+
#$tabs;
|
|
24
|
+
#$searchInput;
|
|
25
|
+
#$searchClearButton;
|
|
26
|
+
#$skinPopover;
|
|
27
|
+
#$skinMenu;
|
|
28
|
+
#$skinSwatch;
|
|
29
|
+
#$skinButton;
|
|
30
|
+
#$list;
|
|
31
|
+
#$notFound;
|
|
32
|
+
#controller = null;
|
|
33
|
+
#$sh;
|
|
34
|
+
#searchDebounce;
|
|
35
|
+
#currentSkinTone = 0;
|
|
36
|
+
#prevTabsValue = null;
|
|
37
|
+
constructor() {
|
|
38
|
+
super();
|
|
39
|
+
const shadowRoot = this.attachShadow();
|
|
40
|
+
shadowRoot.appendChild(template.content.cloneNode(true));
|
|
41
|
+
this.#$sh = shadowRoot;
|
|
42
|
+
this.#$tabs = shadowRoot.querySelector('#tabs');
|
|
43
|
+
this.#$searchInput = shadowRoot.querySelector('#search');
|
|
44
|
+
this.#$searchClearButton = shadowRoot.querySelector('#search-clear');
|
|
45
|
+
this.#$skinPopover = shadowRoot.querySelector('#skin-popover');
|
|
46
|
+
this.#$skinMenu = shadowRoot.querySelector('#skin-menu');
|
|
47
|
+
this.#$skinSwatch = shadowRoot.querySelector('#skin-swatch');
|
|
48
|
+
this.#$skinButton = shadowRoot.querySelector('#skin-button');
|
|
49
|
+
this.#$list = shadowRoot.querySelector('#list');
|
|
50
|
+
this.#$notFound = shadowRoot.querySelector('#not-found');
|
|
51
|
+
this.#searchDebounce = debounceTimeout(SEARCH_DEBOUNCE_TIMEOUT)(this.#updateSearch);
|
|
52
|
+
}
|
|
53
|
+
connectedCallback() {
|
|
54
|
+
this.#controller = new AbortController();
|
|
55
|
+
const {
|
|
56
|
+
signal
|
|
57
|
+
} = this.#controller;
|
|
58
|
+
this.#$tabs.addEventListener('-change', this.#onTabsChange, {
|
|
59
|
+
signal
|
|
60
|
+
});
|
|
61
|
+
this.#$searchInput.addEventListener('-change', this.#onSearchChange, {
|
|
62
|
+
signal
|
|
63
|
+
});
|
|
64
|
+
this.#$searchClearButton.addEventListener('-click', this.#onSearchClearClick, {
|
|
65
|
+
signal
|
|
66
|
+
});
|
|
67
|
+
this.#$skinButton.addEventListener('-click', this.#onSkinButtonClick, {
|
|
68
|
+
signal
|
|
69
|
+
});
|
|
70
|
+
this.#$skinPopover.addEventListener('-close', this.#onSkinPopoverClose, {
|
|
71
|
+
signal
|
|
72
|
+
});
|
|
73
|
+
this.#$skinMenu.addEventListener('-change', this.#onSkinMenuChange, {
|
|
74
|
+
signal
|
|
75
|
+
});
|
|
76
|
+
this.#$list.addEventListener('click', this.#onListClick, {
|
|
77
|
+
signal
|
|
78
|
+
});
|
|
79
|
+
this.addEventListener('-change', this.#onChangeReactHandler, {
|
|
80
|
+
signal
|
|
81
|
+
});
|
|
82
|
+
this.#updateTabs();
|
|
83
|
+
this.#updateEmojis();
|
|
84
|
+
}
|
|
85
|
+
disconnectedCallback() {
|
|
86
|
+
this.#searchDebounce.cancel();
|
|
87
|
+
this.#controller.abort();
|
|
88
|
+
this.#controller = null;
|
|
89
|
+
}
|
|
90
|
+
get skinToneButtonRect() {
|
|
91
|
+
return getRect(this.#$skinButton);
|
|
92
|
+
}
|
|
93
|
+
get searchInputRect() {
|
|
94
|
+
return getRect(this.#$searchInput);
|
|
95
|
+
}
|
|
96
|
+
get searchClearButtonRect() {
|
|
97
|
+
return getRect(this.#$searchClearButton);
|
|
98
|
+
}
|
|
99
|
+
nthSkinToneRect(index) {
|
|
100
|
+
return this.#$skinMenu.nthItemRect(index);
|
|
101
|
+
}
|
|
102
|
+
nthTabRect(index) {
|
|
103
|
+
return this.#$tabs.nthOptionRect(index);
|
|
104
|
+
}
|
|
105
|
+
nthEmojiRect(index) {
|
|
106
|
+
const $el = this.#$list.children[index];
|
|
107
|
+
return $el != null ? getRect($el) : null;
|
|
108
|
+
}
|
|
109
|
+
#onListClick = e => {
|
|
110
|
+
const value = e.target.getAttribute('data-value');
|
|
111
|
+
if (value === null) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
this.dispatchEvent(new CustomEvent('-change', {
|
|
115
|
+
detail: value
|
|
116
|
+
}));
|
|
117
|
+
};
|
|
118
|
+
#onTabsChange = e => {
|
|
119
|
+
const value = e.detail;
|
|
120
|
+
updateAttribute(this.#$tabs, 'value', value);
|
|
121
|
+
updateAttribute(this.#$searchInput, 'value', '');
|
|
122
|
+
this.#updateEmojis();
|
|
123
|
+
};
|
|
124
|
+
#onSearchChange = e => {
|
|
125
|
+
this.#$searchInput.value = e.detail;
|
|
126
|
+
this.#searchDebounce.fn();
|
|
127
|
+
setClass(this.#$searchClearButton, 'active', e.detail.length > 0);
|
|
128
|
+
};
|
|
129
|
+
#onSearchClearClick = () => {
|
|
130
|
+
this.#$searchInput.value = '';
|
|
131
|
+
this.#$searchInput.focus();
|
|
132
|
+
this.#searchDebounce.fn();
|
|
133
|
+
setClass(this.#$searchClearButton, 'active', false);
|
|
134
|
+
};
|
|
135
|
+
#onChangeReactHandler = e => {
|
|
136
|
+
getReactEventHandler(this, 'on-change')?.(e);
|
|
137
|
+
};
|
|
138
|
+
get focusable() {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
#getDocumentRoot() {
|
|
142
|
+
return Reflect.has(this.#$sh, 'createElement') ? this.#$sh : document;
|
|
143
|
+
}
|
|
144
|
+
#updateSearch = () => {
|
|
145
|
+
const value = this.#$searchInput.value;
|
|
146
|
+
if (value.length < MIN_SEARCH_LENGTH) {
|
|
147
|
+
if (this.#isSearchMode()) {
|
|
148
|
+
if (this.#prevTabsValue !== null) {
|
|
149
|
+
this.#$tabs.setAttribute('value', this.#prevTabsValue);
|
|
150
|
+
}
|
|
151
|
+
this.#updateEmojis();
|
|
152
|
+
}
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const currentActiveTab = this.#$tabs.getAttribute('value');
|
|
156
|
+
if (currentActiveTab !== null) {
|
|
157
|
+
this.#prevTabsValue = currentActiveTab;
|
|
158
|
+
}
|
|
159
|
+
this.#$tabs.removeAttribute('value');
|
|
160
|
+
this.#updateSearchEmojis();
|
|
161
|
+
};
|
|
162
|
+
#updateTabs() {
|
|
163
|
+
const tabOptions = this.#$tabs.querySelectorAll('sinch-tabs-icon-option');
|
|
164
|
+
const activeTabName = data[0].name;
|
|
165
|
+
const numTabs = Math.min(data.length, tabOptions.length);
|
|
166
|
+
for (let i = 0; i < numTabs; i++) {
|
|
167
|
+
const group = data[i];
|
|
168
|
+
const tabOption = tabOptions[i];
|
|
169
|
+
tabOption.setAttribute('value', group.name);
|
|
170
|
+
tabOption.setAttribute('aria-label', groupLabels[i]);
|
|
171
|
+
}
|
|
172
|
+
updateAttribute(this.#$tabs, 'value', activeTabName);
|
|
173
|
+
}
|
|
174
|
+
*#iterateSearchEmojis(searchValue, skinTone) {
|
|
175
|
+
for (const group of data) {
|
|
176
|
+
for (const entry of group.emojis) {
|
|
177
|
+
if (entry.label.toLowerCase().includes(searchValue)) {
|
|
178
|
+
const hasSkins = entry.skins != null;
|
|
179
|
+
if (skinTone === 0 || !hasSkins) {
|
|
180
|
+
yield entry;
|
|
181
|
+
} else if (hasSkins) {
|
|
182
|
+
for (const skin of entry.skins) {
|
|
183
|
+
if (skinTone === skin.tone || Array.isArray(skin.tone) && skin.tone.includes(skinTone)) {
|
|
184
|
+
yield skin;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
*#iterateGroupEmojis(group, skinTone) {
|
|
193
|
+
for (const entry of group.emojis) {
|
|
194
|
+
const hasSkins = entry.skins != null;
|
|
195
|
+
if (skinTone === 0 || !hasSkins) {
|
|
196
|
+
yield entry;
|
|
197
|
+
} else if (hasSkins) {
|
|
198
|
+
for (const skin of entry.skins) {
|
|
199
|
+
if (skinTone === skin.tone || Array.isArray(skin.tone) && skin.tone.includes(skinTone)) {
|
|
200
|
+
yield skin;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
#updateSearchEmojis() {
|
|
207
|
+
const searchValue = this.#$searchInput.value;
|
|
208
|
+
if (searchValue.length < MIN_SEARCH_LENGTH) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const doc = this.#getDocumentRoot();
|
|
212
|
+
const fragment = document.createDocumentFragment();
|
|
213
|
+
const emojiBaseUrl = getEmojiBaseUrl(this);
|
|
214
|
+
let someFound = false;
|
|
215
|
+
for (const entry of this.#iterateSearchEmojis(searchValue, this.#currentSkinTone)) {
|
|
216
|
+
const el = this.#createEmojiElement(doc, entry, emojiBaseUrl);
|
|
217
|
+
someFound = true;
|
|
218
|
+
fragment.appendChild(el);
|
|
219
|
+
}
|
|
220
|
+
setClass(this.#$notFound, 'active', !someFound);
|
|
221
|
+
this.#$list.replaceChildren(fragment);
|
|
222
|
+
this.#$list.scrollTo(0, 0);
|
|
223
|
+
}
|
|
224
|
+
#updateEmojis() {
|
|
225
|
+
if (this.#isSearchMode()) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const activeGroup = getAttribute(this.#$tabs, 'value');
|
|
229
|
+
const group = data.find(group => group.name === activeGroup);
|
|
230
|
+
if (group == null) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const doc = this.#getDocumentRoot();
|
|
234
|
+
const fragment = document.createDocumentFragment();
|
|
235
|
+
const emojiBaseUrl = getEmojiBaseUrl(this);
|
|
236
|
+
for (const entry of this.#iterateGroupEmojis(group, this.#currentSkinTone)) {
|
|
237
|
+
const el = this.#createEmojiElement(doc, entry, emojiBaseUrl);
|
|
238
|
+
fragment.appendChild(el);
|
|
239
|
+
}
|
|
240
|
+
this.#$list.replaceChildren(fragment);
|
|
241
|
+
this.#$list.scrollTo(0, 0);
|
|
242
|
+
}
|
|
243
|
+
#onSkinButtonClick = () => {
|
|
244
|
+
updateBooleanAttribute(this.#$skinPopover, 'open', !getBooleanAttribute(this.#$skinPopover, 'open'));
|
|
245
|
+
};
|
|
246
|
+
#onSkinPopoverClose = () => {
|
|
247
|
+
updateBooleanAttribute(this.#$skinPopover, 'open', false);
|
|
248
|
+
};
|
|
249
|
+
#onSkinMenuChange = e => {
|
|
250
|
+
this.#$skinSwatch.name = e.detail;
|
|
251
|
+
this.#$skinMenu.value = e.detail;
|
|
252
|
+
switch (e.detail) {
|
|
253
|
+
case 'skintone-default':
|
|
254
|
+
{
|
|
255
|
+
this.#currentSkinTone = 0;
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
case 'skintone-light':
|
|
259
|
+
{
|
|
260
|
+
this.#currentSkinTone = 1;
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
case 'skintone-light-medium':
|
|
264
|
+
{
|
|
265
|
+
this.#currentSkinTone = 2;
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
case 'skintone-medium':
|
|
269
|
+
{
|
|
270
|
+
this.#currentSkinTone = 3;
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
case 'skintone-medium-dark':
|
|
274
|
+
{
|
|
275
|
+
this.#currentSkinTone = 4;
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
case 'skintone-dark':
|
|
279
|
+
{
|
|
280
|
+
this.#currentSkinTone = 5;
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
this.#onSkinPopoverClose();
|
|
285
|
+
if (this.#isSearchMode()) {
|
|
286
|
+
this.#updateSearchEmojis();
|
|
287
|
+
} else {
|
|
288
|
+
this.#updateEmojis();
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
#isSearchMode() {
|
|
292
|
+
const activeTab = getAttribute(this.#$tabs, 'value');
|
|
293
|
+
return activeTab === null || activeTab.length === 0;
|
|
294
|
+
}
|
|
295
|
+
#createEmojiElement(doc, emoji, baseUrl) {
|
|
296
|
+
const btn = doc.createElement('sinch-icon-button');
|
|
297
|
+
const el = doc.createElement('sinch-emoji');
|
|
298
|
+
el.setAttribute('slot', 'icon');
|
|
299
|
+
el.setAttribute('char', emoji.emoji);
|
|
300
|
+
el.setAttribute('label', emoji.label);
|
|
301
|
+
setEmojiBaseUrl(el, baseUrl);
|
|
302
|
+
btn.setAttribute('aria-label', emoji.label);
|
|
303
|
+
btn.setAttribute('size', 's');
|
|
304
|
+
btn.setAttribute('data-value', emoji.emoji);
|
|
305
|
+
btn.appendChild(el);
|
|
306
|
+
return btn;
|
|
307
|
+
}
|
|
308
|
+
});
|