@nectary/components 4.5.1 → 4.6.1

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.
@@ -0,0 +1,11 @@
1
+ import type { TSinchCardV2Element, TSinchCardV2React } from './types';
2
+ declare global {
3
+ namespace JSX {
4
+ interface IntrinsicElements {
5
+ 'sinch-card-v2': TSinchCardV2React;
6
+ }
7
+ }
8
+ interface HTMLElementTagNameMap {
9
+ 'sinch-card-v2': TSinchCardV2Element;
10
+ }
11
+ }
@@ -0,0 +1,134 @@
1
+ import { defineCustomElement, NectaryElement, updateBooleanAttribute, getReactEventHandler, getBooleanAttribute, updateAttribute, isAttrTrue, setClass } from '../utils';
2
+ const templateHTML = '<style>:host{display:block}.empty{display:none!important}#card{border-radius:var(--sinch-comp-card-v2-shape-radius);border:1px solid var(--sinch-comp-card-v2-color-default-border-initial);background-color:var(--sinch-comp-card-v2-color-default-background-initial);box-shadow:var(--sinch-comp-card-v2-shadow-initial);overflow:hidden;transition:.15s linear}#card-media{display:block;overflow:hidden}#body{display:flex;flex-direction:column;padding:16px;gap:8px;align-self:stretch}#card-title{display:flex;flex-direction:row;align-items:center;gap:8px;align-self:stretch}#card-content{display:flex;gap:10px;align-self:stretch}#card-footer{display:flex;flex-direction:row;align-items:center;gap:16px;align-self:stretch}:host([selected]:not([selected=false])) #card{background-color:var(--sinch-comp-card-v2-color-selected-background-initial);border-color:var(--sinch-comp-card-v2-color-selected-border-initial);cursor:pointer}:host([clickable]:not([clickable=false])) #card{cursor:pointer}:host([disabled]:not([disabled=false])) #card{box-shadow:var(--sinch-comp-card-v2-shadow-disabled);background-color:var(--sinch-comp-card-v2-color-default-background-disabled);border-color:var(--sinch-comp-card-v2-color-default-border-disabled);cursor:not-allowed}:host([clickable]:not([clickable=false]):is(:not([disabled]),[disabled=false]):hover) #card{background-color:var(--sinch-comp-card-v2-color-default-background-hover);border-color:var(--sinch-comp-card-v2-color-default-border-hover);box-shadow:var(--sinch-comp-card-v2-shadow-hover)}:host([clickable]:not([clickable=false]):is(:not([disabled]),[disabled=false]):active) #card{background-color:var(--sinch-comp-card-v2-color-default-background-active);border-color:var(--sinch-comp-card-v2-color-default-border-active);box-shadow:var(--sinch-comp-card-v2-shadow-active)}:host([selected]:not([selected=false]):is(:not([disabled]),[disabled=false]):hover) #card{background-color:var(--sinch-comp-card-v2-color-selected-background-hover);border-color:var(--sinch-comp-card-v2-color-selected-border-hover)}:host([selected]:not([selected=false]):is(:not([disabled]),[disabled=false]):active) #card{background-color:var(--sinch-comp-card-v2-color-selected-background-active);border-color:var(--sinch-comp-card-v2-color-selected-border-active)}:host([selected]:not([selected=false])[disabled]:not([disabled=false])) #card{background-color:var(--sinch-comp-card-v2-color-selected-background-disabled);border-color:var(--sinch-comp-card-v2-color-selected-border-disabled)}::slotted([slot=content]){max-width:100%;color:var(--sinch-comp-card-v2-color-default-description-initial);font-size:var(--sinch-comp-card-v2-font-description)}::slotted([slot=title]){max-width:100%}::slotted([slot=footer]){max-width:100%}:host([selected]:not([selected=false])) ::slotted([slot=content]){color:var(--sinch-comp-card-v2-color-selected-description-initial)}:host([disabled]:not([disabled=false])) ::slotted([slot=content]){color:var(--sinch-comp-card-v2-color-default-description-disabled)}:host([selected]:not([selected=false])[disabled]:not([disabled=false])) ::slotted([slot=content]){color:var(--sinch-comp-card-v2-color-selected-description-disabled)}</style><div id="card"><div id="card-media"><slot name="media"></slot></div><div id="body"><div id="card-title"><slot name="title"></slot></div><div id="card-content"><slot name="content"></slot></div><div id="card-footer"><slot name="footer"></slot></div></div></div>';
3
+ const template = document.createElement('template');
4
+ template.innerHTML = templateHTML;
5
+ const CLICK_EVENTS = ['click', '-click'];
6
+ defineCustomElement('sinch-card-v2', class extends NectaryElement {
7
+ #$slots;
8
+ #controller = null;
9
+ #clickEventListeners = (() => new Map())();
10
+ constructor() {
11
+ super();
12
+ const shadowRoot = this.attachShadow();
13
+ shadowRoot.appendChild(template.content.cloneNode(true));
14
+ this.#$slots = shadowRoot.querySelectorAll('slot');
15
+ }
16
+ connectedCallback() {
17
+ super.connectedCallback();
18
+ this.#setupEventListeners();
19
+ this.#updateClickableState();
20
+ }
21
+ disconnectedCallback() {
22
+ super.disconnectedCallback();
23
+ this.#controller?.abort();
24
+ this.#controller = null;
25
+ }
26
+ addEventListener(type, listener, options) {
27
+ let isInitial = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
28
+ super.addEventListener(type, listener, options);
29
+ if (!isInitial && this.#isClickEvent(type)) {
30
+ this.#handleClickListenerAdded(type, listener);
31
+ }
32
+ }
33
+ removeEventListener(type, listener, options) {
34
+ super.removeEventListener(type, listener, options);
35
+ if (this.#isClickEvent(type)) {
36
+ this.#handleClickListenerRemoved(type, listener);
37
+ }
38
+ }
39
+ #isClickEvent(type) {
40
+ return CLICK_EVENTS.includes(type);
41
+ }
42
+ #setupEventListeners() {
43
+ this.#controller = new AbortController();
44
+ const options = {
45
+ signal: this.#controller.signal
46
+ };
47
+ const handleClick = e => {
48
+ if (this.disabled) {
49
+ e.stopPropagation();
50
+ e.preventDefault();
51
+ } else {
52
+ this.dispatchEvent(new CustomEvent('-click'));
53
+ }
54
+ };
55
+ const handleReactClick = e => {
56
+ getReactEventHandler(this, 'on-click')?.(e);
57
+ };
58
+ this.addEventListener('click', handleClick, options, true);
59
+ this.addEventListener('-click', handleReactClick, options, true);
60
+ const handleSlotChange = slot => {
61
+ const isEmpty = slot.assignedNodes().length <= 0;
62
+ setClass(slot.parentElement, 'empty', isEmpty);
63
+ };
64
+ this.#$slots.forEach(slot => {
65
+ handleSlotChange(slot);
66
+ slot.addEventListener('slotchange', () => handleSlotChange(slot), options);
67
+ });
68
+ }
69
+ #updateClickableState() {
70
+ const hasClickHandler = this.hasAttribute('onclick') || Boolean(getReactEventHandler(this, 'on-click'));
71
+ if (!this.hasAttribute('clickable') && hasClickHandler) {
72
+ updateBooleanAttribute(this, 'clickable', true);
73
+ }
74
+ }
75
+ #handleClickListenerAdded(type, listener) {
76
+ const listeners = this.#clickEventListeners.get(type) ?? new Set();
77
+ if (!listeners.has(listener)) {
78
+ listeners.add(listener);
79
+ this.#clickEventListeners.set(type, listeners);
80
+ }
81
+ if (!this.hasAttribute('clickable')) {
82
+ updateBooleanAttribute(this, 'clickable', true);
83
+ }
84
+ }
85
+ #handleClickListenerRemoved(type, listener) {
86
+ const listeners = this.#clickEventListeners.get(type);
87
+ listeners?.delete(listener);
88
+ const hasListeners = Array.from(this.#clickEventListeners.values()).some(set => set.size > 0);
89
+ if (!hasListeners && this.getAttribute('clickable') === '') {
90
+ updateBooleanAttribute(this, 'clickable', false);
91
+ }
92
+ }
93
+ static get observedAttributes() {
94
+ return ['clickable', 'disabled', 'selected'];
95
+ }
96
+ attributeChangedCallback(name, _oldVal, newVal) {
97
+ switch (name) {
98
+ case 'clickable':
99
+ {
100
+ const isClickable = isAttrTrue(newVal);
101
+ if (isClickable) {
102
+ updateAttribute(this, 'role', 'button');
103
+ updateAttribute(this, 'tabindex', '0');
104
+ } else {
105
+ updateAttribute(this, 'role', null);
106
+ updateAttribute(this, 'tabindex', null);
107
+ }
108
+ break;
109
+ }
110
+ case 'selected':
111
+ case 'disabled':
112
+ {
113
+ const bool = isAttrTrue(newVal);
114
+ const titleElement = this.querySelector('sinch-card-v2-title');
115
+ if (titleElement != null) {
116
+ updateBooleanAttribute(titleElement, name, bool);
117
+ }
118
+ break;
119
+ }
120
+ }
121
+ }
122
+ get disabled() {
123
+ return getBooleanAttribute(this, 'disabled');
124
+ }
125
+ set disabled(value) {
126
+ updateBooleanAttribute(this, 'disabled', value);
127
+ }
128
+ get selected() {
129
+ return getBooleanAttribute(this, 'selected');
130
+ }
131
+ set selected(value) {
132
+ updateBooleanAttribute(this, 'selected', value);
133
+ }
134
+ });
@@ -0,0 +1,63 @@
1
+ import type { TSinchElementReact } from '../types';
2
+ export type TSinchCardV2Element = HTMLElement & {
3
+ /** Disabled */
4
+ disabled: boolean;
5
+ /** Selected */
6
+ selected: boolean;
7
+ /** Clickable
8
+ * @default true if a click event is provided.
9
+ */
10
+ clickable: boolean;
11
+ /** Click event */
12
+ addEventListener(type: '-click', listener: (e: CustomEvent<void>) => void): void;
13
+ /** Disabled */
14
+ setAttribute(name: 'disabled', value: ''): void;
15
+ /** Selected */
16
+ setAttribute(name: 'selected', value: ''): void;
17
+ /** Clickable
18
+ * @default true if a click event is provided.
19
+ */
20
+ setAttribute(name: 'clickable', value: ''): void;
21
+ };
22
+ export type TSinchCardV2React = TSinchElementReact<TSinchCardV2Element> & {
23
+ /** Disabled */
24
+ disabled?: boolean;
25
+ /** Selected */
26
+ selected?: boolean;
27
+ /** Clickable
28
+ * @default true if a click event is provided.
29
+ */
30
+ clickable?: boolean;
31
+ /** Click even handler */
32
+ 'on-click'?: (e: CustomEvent<void>) => void;
33
+ } & {
34
+ style?: {
35
+ '--sinch-comp-card-v2-shape-radius'?: string;
36
+ '--sinch-comp-card-v2-shadow-initial'?: string;
37
+ '--sinch-comp-card-v2-shadow-hover'?: string;
38
+ '--sinch-comp-card-v2-shadow-disabled'?: string;
39
+ '--sinch-comp-card-v2-shadow-active'?: string;
40
+ '--sinch-comp-card-v2-font-title'?: string;
41
+ '--sinch-comp-card-v2-font-description'?: string;
42
+ '--sinch-comp-card-v2-color-default-border-initial'?: string;
43
+ '--sinch-comp-card-v2-color-default-border-hover'?: string;
44
+ '--sinch-comp-card-v2-color-default-border-disabled'?: string;
45
+ '--sinch-comp-card-v2-color-default-border-active'?: string;
46
+ '--sinch-comp-card-v2-color-default-background-initial'?: string;
47
+ '--sinch-comp-card-v2-color-default-background-hover'?: string;
48
+ '--sinch-comp-card-v2-color-default-background-disabled'?: string;
49
+ '--sinch-comp-card-v2-color-default-background-active'?: string;
50
+ '--sinch-comp-card-v2-color-default-description-initial'?: string;
51
+ '--sinch-comp-card-v2-color-default-description-disabled'?: string;
52
+ '--sinch-comp-card-v2-color-selected-border-initial'?: string;
53
+ '--sinch-comp-card-v2-color-selected-border-hover'?: string;
54
+ '--sinch-comp-card-v2-color-selected-border-disabled'?: string;
55
+ '--sinch-comp-card-v2-color-selected-border-active'?: string;
56
+ '--sinch-comp-card-v2-color-selected-background-initial'?: string;
57
+ '--sinch-comp-card-v2-color-selected-background-hover'?: string;
58
+ '--sinch-comp-card-v2-color-selected-background-disabled'?: string;
59
+ '--sinch-comp-card-v2-color-selected-background-active'?: string;
60
+ '--sinch-comp-card-v2-color-selected-description-initial'?: string;
61
+ '--sinch-comp-card-v2-color-selected-description-disabled'?: string;
62
+ };
63
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { TSinchCardTitleElement, TSinchCardTitleReact } from './types';
2
+ declare global {
3
+ namespace JSX {
4
+ interface IntrinsicElements {
5
+ 'sinch-card-v2-title': TSinchCardTitleReact;
6
+ }
7
+ }
8
+ interface HTMLElementTagNameMap {
9
+ 'sinch-card-v2-title': TSinchCardTitleElement;
10
+ }
11
+ }
@@ -0,0 +1,55 @@
1
+ import { defineCustomElement, getAttribute, updateAttribute, NectaryElement, updateBooleanAttribute, getBooleanAttribute, isAttrTrue } from '../utils';
2
+ const templateHTML = '<style>:host{display:block}#title{display:flex;align-items:center;flex-direction:row}#title-text{font:var(--sinch-comp-card-v2-font-title);color:var(--sinch-comp-card-v2-color-default-title-initial)}#title-icon{display:flex}:host([orientation=vertical]) #title{align-items:start;flex-direction:column}:host([disabled]:not([disabled=false])) #title-text{color:var(--sinch-comp-card-v2-color-default-title-disabled)}:host([selected]:not([selected=false])[disabled]:not([disabled=false])) #title-text{color:var(--sinch-comp-card-v2-color-selected-title-disabled)}::slotted([slot=icon]){--sinch-global-color-icon:var(--sinch-comp-card-v2-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-card-v2-size-icon);margin-right:8px;margin-bottom:0}:host([orientation=vertical]) ::slotted([slot=icon]){margin-right:0;margin-bottom:8px}:host([selected]:not([selected=false])) ::slotted([slot=icon]){--sinch-global-color-icon:var(--sinch-comp-card-v2-color-selected-icon-initial)}:host([disabled]:not([disabled=false])) ::slotted([slot=icon]){--sinch-global-color-icon:var(--sinch-comp-card-v2-color-default-icon-disabled)}:host([selected]:not([selected=false])[disabled]:not([disabled=false])) ::slotted([slot=icon]){--sinch-global-color-icon:var(--sinch-comp-card-v2-color-selected-icon-disabled)}</style><div id="title"><div id="title-icon"><slot name="icon"></slot></div><sinch-text id="title-text" type="m"></sinch-text></div>';
3
+ const template = document.createElement('template');
4
+ template.innerHTML = templateHTML;
5
+ defineCustomElement('sinch-card-v2-title', class extends NectaryElement {
6
+ #$text;
7
+ constructor() {
8
+ super();
9
+ const shadowRoot = this.attachShadow();
10
+ shadowRoot.appendChild(template.content.cloneNode(true));
11
+ this.#$text = shadowRoot.querySelector('#title-text');
12
+ }
13
+ connectedCallback() {
14
+ super.connectedCallback();
15
+ if (!this.hasAttribute('orientation')) {
16
+ this.setAttribute('orientation', 'horizontal');
17
+ }
18
+ }
19
+ static get observedAttributes() {
20
+ return ['text', 'ellipsis'];
21
+ }
22
+ attributeChangedCallback(name, oldVal, newVal) {
23
+ switch (name) {
24
+ case 'text':
25
+ {
26
+ this.#$text.textContent = newVal;
27
+ break;
28
+ }
29
+ case 'ellipsis':
30
+ {
31
+ const bool = isAttrTrue(newVal);
32
+ updateBooleanAttribute(this.#$text, 'ellipsis', bool);
33
+ break;
34
+ }
35
+ }
36
+ }
37
+ get text() {
38
+ return getAttribute(this, 'text', '');
39
+ }
40
+ set text(value) {
41
+ updateAttribute(this, 'text', value);
42
+ }
43
+ get orientation() {
44
+ return getAttribute(this, 'orientation', '');
45
+ }
46
+ set orientation(value) {
47
+ updateAttribute(this, 'orientation', value);
48
+ }
49
+ set ellipsis(isEllipsis) {
50
+ updateBooleanAttribute(this, 'ellipsis', isEllipsis);
51
+ }
52
+ get ellipsis() {
53
+ return getBooleanAttribute(this, 'ellipsis');
54
+ }
55
+ });
@@ -0,0 +1,44 @@
1
+ import type { TSinchElementReact } from '../types';
2
+ export type TSinchOrientation = 'horizontal' | 'vertical';
3
+ export type TSinchCardTitleElement = HTMLElement & {
4
+ /** Text */
5
+ text: string;
6
+ /** Orientation relative to the icon slot */
7
+ orientation: TSinchOrientation;
8
+ /** Cuts the long text with “…” ellipsis */
9
+ ellipsis: boolean;
10
+ /** Text */
11
+ setAttribute(name: 'text', value: string): void;
12
+ /**
13
+ * Orientation relative to the icon slot
14
+ * @default "horizontal"
15
+ */
16
+ setAttribute(name: 'orientation', value: TSinchOrientation): void;
17
+ /** Cuts the long text with “…” ellipsis */
18
+ setAttribute(name: 'ellipsis', value: ''): void;
19
+ };
20
+ export type TSinchCardTitleReact = TSinchElementReact<TSinchCardTitleElement> & {
21
+ /** Text */
22
+ text: string;
23
+ /**
24
+ * Orientation relative to the icon slot
25
+ * @default "horizontal"
26
+ */
27
+ orientation?: TSinchOrientation;
28
+ /** Cuts the long text with “…” ellipsis */
29
+ ellipsis?: boolean;
30
+ } & {
31
+ style?: {
32
+ '--sinch-comp-card-v2-font-title'?: string;
33
+ '--sinch-comp-card-v2-color-default-title-initial'?: string;
34
+ '--sinch-comp-card-v2-color-default-title-disabled'?: string;
35
+ '--sinch-comp-card-v2-color-default-icon-initial'?: string;
36
+ '--sinch-comp-card-v2-color-default-icon-disabled'?: string;
37
+ '--sinch-comp-card-v2-color-selected-title-disabled'?: string;
38
+ '--sinch-comp-card-v2-color-selected-icon-initial'?: string;
39
+ '--sinch-comp-card-v2-color-selected-icon-disabled'?: string;
40
+ '--sinch-comp-card-v2-size-icon'?: string;
41
+ '--sinch-global-color-icon'?: string;
42
+ '--sinch-global-size-icon'?: string;
43
+ };
44
+ };
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nectary/components",
3
- "version": "4.5.1",
3
+ "version": "4.6.1",
4
4
  "files": [
5
5
  "**/*/*.css",
6
6
  "**/*/*.json",
package/standalone.d.ts CHANGED
@@ -9,6 +9,8 @@ import './button-group-item/index.js';
9
9
  import './button-group/index.js';
10
10
  import './button/index.js';
11
11
  import './card-container/index.js';
12
+ import './card-v2-title/index.js';
13
+ import './card-v2/index.js';
12
14
  import './card/index.js';
13
15
  import './checkbox/index.js';
14
16
  import './chip/index.js';
package/standalone.js CHANGED
@@ -11,6 +11,8 @@ import './button-group-item/index.js';
11
11
  import './button-group/index.js';
12
12
  import './button/index.js';
13
13
  import './card-container/index.js';
14
+ import './card-v2-title/index.js';
15
+ import './card-v2/index.js';
14
16
  import './card/index.js';
15
17
  import './checkbox/index.js';
16
18
  import './chip/index.js';
package/standalone.ts CHANGED
@@ -17,6 +17,8 @@ import './button-group-item/index.js'
17
17
  import './button-group/index.js'
18
18
  import './button/index.js'
19
19
  import './card-container/index.js'
20
+ import './card-v2-title/index.js'
21
+ import './card-v2/index.js'
20
22
  import './card/index.js'
21
23
  import './checkbox/index.js'
22
24
  import './chip/index.js'