@nectary/components 0.42.1 → 0.44.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.js +3 -3
- package/action-menu/index.js +1 -2
- package/card-container/index.js +1 -1
- package/color-menu/index.d.ts +3 -3
- package/color-menu/index.js +2 -3
- package/color-menu/types.d.ts +2 -2
- package/date-picker/index.js +173 -64
- package/date-picker/types.d.ts +6 -0
- package/date-picker/utils.d.ts +6 -3
- package/date-picker/utils.js +19 -4
- package/dialog/index.js +2 -2
- package/emoji/index.d.ts +11 -0
- package/emoji/index.js +47 -0
- package/emoji/types.d.ts +11 -0
- package/emoji/types.js +1 -0
- package/emoji/utils.d.ts +1 -0
- package/emoji/utils.js +46 -0
- package/emoji-picker/index.d.ts +28 -0
- package/emoji-picker/index.js +319 -0
- package/emoji-picker/types.d.ts +25 -0
- package/emoji-picker/types.js +1 -0
- package/file-drop/types.d.ts +2 -2
- package/file-picker/types.d.ts +1 -1
- 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.js +1 -1
- package/package.json +2 -2
- package/pop/index.js +1 -2
- package/popover/index.js +1 -2
- package/segment/index.js +1 -1
- package/segmented-icon-control/index.js +3 -3
- package/select-menu/index.js +3 -4
- package/stop-events/index.js +3 -3
- package/tabs/index.js +24 -76
- package/tabs/types.d.ts +9 -2
- package/tabs-icon-option/index.d.ts +11 -0
- package/tabs-icon-option/index.js +75 -0
- package/tabs-icon-option/types.d.ts +19 -0
- package/tabs-icon-option/types.js +1 -0
- package/tabs-option/index.d.ts +1 -0
- package/tabs-option/index.js +8 -15
- package/tabs-option/types.d.ts +13 -5
- package/theme/emoji.css +6 -0
- package/theme/fonts.css +9 -0
- package/theme/fonts.json +9 -0
- package/theme/icon.css +7 -0
- package/theme.css +2 -0
- package/tile-control/index.js +3 -3
- package/tooltip/index.js +78 -31
- package/utils/csv.d.ts +5 -0
- package/utils/csv.js +22 -0
- package/utils/dom.d.ts +30 -0
- package/utils/dom.js +143 -0
- package/utils/element.d.ts +12 -0
- package/utils/element.js +38 -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 +8 -57
- package/utils/index.js +8 -301
- package/utils/rect.d.ts +4 -0
- package/utils/rect.js +29 -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 +25 -0
- /package/{utils/animation.d.ts → tooltip/tooltip-state.d.ts} +0 -0
- /package/{utils/animation.js → tooltip/tooltip-state.js} +0 -0
package/tooltip/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import '../text';
|
|
2
2
|
import '../pop';
|
|
3
3
|
import { defineCustomElement, getBooleanAttribute, getAttribute, getLiteralAttribute, updateBooleanAttribute, updateAttribute, updateLiteralAttribute, NectaryElement, setClass, rectOverlap } from '../utils';
|
|
4
|
-
import { TooltipState } from '../utils/animation';
|
|
5
4
|
const templateHTML = '<style>:host{display:contents}#content-wrapper{padding-bottom:8px}#content{position:relative;display:block;max-width:300px;padding:2px 6px;box-sizing:border-box;color:var(--sinch-color-text-default);background-color:var(--sinch-color-snow-600);border-radius:var(--sinch-shape-radius-xs);pointer-events:none;opacity:0}:host([orientation=left]) #content-wrapper{padding-bottom:0;padding-right:8px}:host([orientation=right]) #content-wrapper{padding-bottom:0;padding-left:8px}:host([orientation^=bottom]) #content-wrapper{padding-bottom:0;padding-top:8px}#text{word-break:break-word;pointer-events:none}#tip{position:absolute;left:50%;top:100%;transform:translateX(-50%) rotate(0);transform-origin:top center;fill:var(--sinch-color-snow-600);pointer-events:none}#tip.hidden{display:none}:host([orientation=left]) #tip{transform:translateX(-50%) rotate(270deg);top:50%;left:100%}:host([orientation=right]) #tip{transform:translateX(-50%) rotate(90deg);top:50%;left:0}:host([orientation^=bottom]) #tip{transform:translateX(-50%) rotate(180deg);top:0}:host([inverted]:not([inverted=false])) #content{background-color:var(--sinch-color-stormy-500);color:var(--sinch-color-text-inverted)}:host([inverted]:not([inverted=false])) #tip{fill:var(--sinch-color-stormy-500)}</style><sinch-pop id="pop"><slot id="target" slot="target"></slot><div id="content-wrapper" slot="content"><div id="content"><sinch-text id="text" type="s"></sinch-text><svg id="tip" width="8" height="4" aria-hidden="true"><path d="m4 4 4-4h-8l4 4Z"/></svg></div></div></sinch-pop>';
|
|
5
|
+
import { TooltipState } from './tooltip-state';
|
|
6
6
|
import { assertOrientation, getPopOrientation, orientationValues } from './utils';
|
|
7
7
|
const TIP_SIZE = 8;
|
|
8
8
|
const SHOW_DELAY = 1000;
|
|
9
|
-
const HIDE_DELAY =
|
|
10
|
-
const ANIMATION_DURATION =
|
|
9
|
+
const HIDE_DELAY = 0;
|
|
10
|
+
const ANIMATION_DURATION = 50;
|
|
11
11
|
const template = document.createElement('template');
|
|
12
12
|
template.innerHTML = templateHTML;
|
|
13
13
|
defineCustomElement('sinch-tooltip', class extends NectaryElement {
|
|
@@ -21,6 +21,8 @@ defineCustomElement('sinch-tooltip', class extends NectaryElement {
|
|
|
21
21
|
#tooltipState;
|
|
22
22
|
#animation = null;
|
|
23
23
|
#shouldReduceMotion = false;
|
|
24
|
+
#isConnected = false;
|
|
25
|
+
#isSubscribed = false;
|
|
24
26
|
constructor() {
|
|
25
27
|
super();
|
|
26
28
|
const shadowRoot = this.attachShadow();
|
|
@@ -36,35 +38,20 @@ defineCustomElement('sinch-tooltip', class extends NectaryElement {
|
|
|
36
38
|
showDelay: SHOW_DELAY,
|
|
37
39
|
hideDelay: this.#shouldReduceMotion ? HIDE_DELAY + ANIMATION_DURATION : HIDE_DELAY,
|
|
38
40
|
hideAnimationDuration: this.#shouldReduceMotion ? 0 : ANIMATION_DURATION,
|
|
39
|
-
onShow: this.#
|
|
40
|
-
onHideStart: this.#
|
|
41
|
-
onHideEnd: this.#
|
|
41
|
+
onShow: this.#onStateShow,
|
|
42
|
+
onHideStart: this.#onStateHideStart,
|
|
43
|
+
onHideEnd: this.#onStateHideEnd
|
|
42
44
|
});
|
|
43
45
|
}
|
|
44
46
|
connectedCallback() {
|
|
47
|
+
this.#isConnected = true;
|
|
45
48
|
this.#controller = new AbortController();
|
|
46
|
-
const {
|
|
47
|
-
signal
|
|
48
|
-
}
|
|
49
|
-
this.#$pop.addEventListener('-close', this.#onPopClose,
|
|
50
|
-
signal
|
|
51
|
-
});
|
|
52
|
-
this.#$target.addEventListener('mousedown', this.#onMouseDown, {
|
|
53
|
-
signal
|
|
54
|
-
});
|
|
55
|
-
this.#$target.addEventListener('mouseenter', this.#onMouseEnter, {
|
|
56
|
-
signal
|
|
57
|
-
});
|
|
58
|
-
this.#$target.addEventListener('mouseleave', this.#onMouseLeave, {
|
|
59
|
-
signal
|
|
60
|
-
});
|
|
61
|
-
this.#$contentWrapper.addEventListener('mouseenter', this.#onMouseEnter, {
|
|
62
|
-
signal
|
|
63
|
-
});
|
|
64
|
-
this.#$contentWrapper.addEventListener('mouseleave', this.#onMouseLeave, {
|
|
65
|
-
signal
|
|
66
|
-
});
|
|
49
|
+
const options = {
|
|
50
|
+
signal: this.#controller.signal
|
|
51
|
+
};
|
|
52
|
+
this.#$pop.addEventListener('-close', this.#onPopClose, options);
|
|
67
53
|
updateAttribute(this.#$pop, 'orientation', getPopOrientation(this.orientation));
|
|
54
|
+
this.#updateText();
|
|
68
55
|
}
|
|
69
56
|
disconnectedCallback() {
|
|
70
57
|
this.#controller.abort();
|
|
@@ -101,7 +88,7 @@ defineCustomElement('sinch-tooltip', class extends NectaryElement {
|
|
|
101
88
|
switch (name) {
|
|
102
89
|
case 'text':
|
|
103
90
|
{
|
|
104
|
-
this
|
|
91
|
+
this.#updateText();
|
|
105
92
|
break;
|
|
106
93
|
}
|
|
107
94
|
case 'orientation':
|
|
@@ -118,19 +105,28 @@ defineCustomElement('sinch-tooltip', class extends NectaryElement {
|
|
|
118
105
|
}
|
|
119
106
|
#onMouseDown = () => {
|
|
120
107
|
this.#tooltipState.interrupt();
|
|
108
|
+
this.#unsubscribeScroll();
|
|
121
109
|
};
|
|
122
110
|
#onPopClose = () => {
|
|
123
111
|
this.#tooltipState.destroy();
|
|
112
|
+
this.#unsubscribeScroll();
|
|
124
113
|
};
|
|
125
114
|
#onMouseEnter = () => {
|
|
126
115
|
this.#tooltipState.show();
|
|
116
|
+
this.#subscribeScroll();
|
|
117
|
+
this.#subscribeMouseLeaveEvents();
|
|
127
118
|
};
|
|
128
119
|
#onMouseLeave = e => {
|
|
129
120
|
if (!this.#isOpen() || e.relatedTarget !== this.#$contentWrapper && e.relatedTarget !== this.#$target) {
|
|
130
121
|
this.#tooltipState.hide();
|
|
122
|
+
this.#unsubscribeScroll();
|
|
131
123
|
}
|
|
132
124
|
};
|
|
133
|
-
#
|
|
125
|
+
#onScroll = () => {
|
|
126
|
+
this.#tooltipState.destroy();
|
|
127
|
+
this.#unsubscribeScroll();
|
|
128
|
+
};
|
|
129
|
+
#onStateShow = () => {
|
|
134
130
|
updateBooleanAttribute(this.#$pop, 'open', true);
|
|
135
131
|
requestAnimationFrame(this.#updateTipOrientation);
|
|
136
132
|
if (this.#animation !== null) {
|
|
@@ -146,14 +142,15 @@ defineCustomElement('sinch-tooltip', class extends NectaryElement {
|
|
|
146
142
|
});
|
|
147
143
|
}
|
|
148
144
|
};
|
|
149
|
-
#
|
|
145
|
+
#onStateHideStart = () => {
|
|
150
146
|
this.#animation.updatePlaybackRate(-1);
|
|
151
147
|
this.#animation.play();
|
|
152
148
|
};
|
|
153
|
-
#
|
|
149
|
+
#onStateHideEnd = () => {
|
|
154
150
|
this.#animation.finish();
|
|
155
151
|
this.#resetTipOrientation();
|
|
156
152
|
updateBooleanAttribute(this.#$pop, 'open', false);
|
|
153
|
+
this.#unsubscribeMouseLeaveEvents();
|
|
157
154
|
};
|
|
158
155
|
#resetTipOrientation() {
|
|
159
156
|
this.#$tip.style.top = '';
|
|
@@ -180,6 +177,56 @@ defineCustomElement('sinch-tooltip', class extends NectaryElement {
|
|
|
180
177
|
}
|
|
181
178
|
setClass(this.#$tip, 'hidden', rectOverlap(targetRect, contentRect));
|
|
182
179
|
};
|
|
180
|
+
#updateText() {
|
|
181
|
+
if (!this.#isConnected) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const value = this.text;
|
|
185
|
+
this.#$tooltipText.textContent = value;
|
|
186
|
+
if (value.length === 0) {
|
|
187
|
+
if (this.#isSubscribed) {
|
|
188
|
+
this.#tooltipState.destroy();
|
|
189
|
+
this.#unsubscribeMouseEnterEvent();
|
|
190
|
+
this.#unsubscribeMouseLeaveEvents();
|
|
191
|
+
}
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
this.#subscribeMouseEnterEvent();
|
|
195
|
+
}
|
|
196
|
+
#subscribeMouseEnterEvent() {
|
|
197
|
+
if (!this.#isConnected || this.#isSubscribed) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
this.#$target.addEventListener('mouseenter', this.#onMouseEnter, {
|
|
201
|
+
signal: this.#controller.signal
|
|
202
|
+
});
|
|
203
|
+
this.#isSubscribed = true;
|
|
204
|
+
}
|
|
205
|
+
#unsubscribeMouseEnterEvent() {
|
|
206
|
+
this.#$target.removeEventListener('mouseenter', this.#onMouseEnter);
|
|
207
|
+
this.#isSubscribed = false;
|
|
208
|
+
}
|
|
209
|
+
#subscribeMouseLeaveEvents() {
|
|
210
|
+
const options = {
|
|
211
|
+
signal: this.#controller.signal
|
|
212
|
+
};
|
|
213
|
+
this.#$target.addEventListener('mousedown', this.#onMouseDown, options);
|
|
214
|
+
this.#$target.addEventListener('mouseleave', this.#onMouseLeave, options);
|
|
215
|
+
this.#$contentWrapper.addEventListener('mouseenter', this.#onMouseEnter, options);
|
|
216
|
+
this.#$contentWrapper.addEventListener('mouseleave', this.#onMouseLeave, options);
|
|
217
|
+
}
|
|
218
|
+
#unsubscribeMouseLeaveEvents() {
|
|
219
|
+
this.#$target.removeEventListener('mousedown', this.#onMouseDown);
|
|
220
|
+
this.#$target.removeEventListener('mouseleave', this.#onMouseLeave);
|
|
221
|
+
this.#$contentWrapper.removeEventListener('mouseenter', this.#onMouseEnter);
|
|
222
|
+
this.#$contentWrapper.removeEventListener('mouseleave', this.#onMouseLeave);
|
|
223
|
+
}
|
|
224
|
+
#subscribeScroll() {
|
|
225
|
+
window.addEventListener('wheel', this.#onScroll, true);
|
|
226
|
+
}
|
|
227
|
+
#unsubscribeScroll() {
|
|
228
|
+
window.removeEventListener('wheel', this.#onScroll, true);
|
|
229
|
+
}
|
|
183
230
|
#isOpen() {
|
|
184
231
|
return this.#$pop.hasAttribute('open');
|
|
185
232
|
}
|
package/utils/csv.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const CSV_DELIMITER = ",";
|
|
2
|
+
export declare const packCsv: (values: string[]) => string;
|
|
3
|
+
export declare const unpackCsv: (csv: string) => string[];
|
|
4
|
+
export declare const updateCsv: (csv: string, value: string, setActive: boolean) => string;
|
|
5
|
+
export declare const getFirstCsvValue: (acc: string) => string | null;
|
package/utils/csv.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const CSV_DELIMITER = ',';
|
|
2
|
+
export const packCsv = values => {
|
|
3
|
+
return values.join(CSV_DELIMITER);
|
|
4
|
+
};
|
|
5
|
+
export const unpackCsv = csv => {
|
|
6
|
+
return csv.length === 0 ? [] : csv.split(CSV_DELIMITER);
|
|
7
|
+
};
|
|
8
|
+
export const updateCsv = (csv, value, setActive) => {
|
|
9
|
+
const values = unpackCsv(csv);
|
|
10
|
+
const index = values.indexOf(value);
|
|
11
|
+
if (setActive) {
|
|
12
|
+
if (index < 0) {
|
|
13
|
+
values.push(value);
|
|
14
|
+
}
|
|
15
|
+
} else if (index >= 0) {
|
|
16
|
+
values.splice(index, 1);
|
|
17
|
+
}
|
|
18
|
+
return packCsv(values);
|
|
19
|
+
};
|
|
20
|
+
export const getFirstCsvValue = acc => {
|
|
21
|
+
return acc.length === 0 ? null : unpackCsv(acc)[0];
|
|
22
|
+
};
|
package/utils/dom.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const updateExplicitBooleanAttribute: ($element: Element, attrName: string, attrValue: boolean | null | undefined) => void;
|
|
2
|
+
export declare const isAttrTrue: (attrValue: string | null) => boolean;
|
|
3
|
+
export declare const getBooleanAttribute: ($element: Element, attrName: string) => boolean;
|
|
4
|
+
export declare const updateBooleanAttribute: ($element: Element, attrName: string, attrValue: boolean | null | undefined) => void;
|
|
5
|
+
export declare const updateAttribute: ($element: Element, attrName: string, attrValue: string | number | boolean | null | undefined) => void;
|
|
6
|
+
export declare function getAttribute($element: Element, attrName: string): string | null;
|
|
7
|
+
export declare function getAttribute($element: Element, attrName: string, defaultValue: string): string;
|
|
8
|
+
export declare const isLiteralValue: <T extends readonly string[]>(literals: T, value: string | null | undefined) => value is T[number];
|
|
9
|
+
export declare const updateLiteralAttribute: <T extends readonly string[]>($element: Element, literals: T, attrName: string, attrValue: string | null | undefined) => void;
|
|
10
|
+
export declare function getLiteralAttribute<T extends readonly string[]>($element: Element, literals: T, attrName: string): T[number];
|
|
11
|
+
export declare function getLiteralAttribute<T extends readonly string[]>($element: Element, literals: T, attrName: string, defaultValue: null): T[number] | null;
|
|
12
|
+
export declare function getLiteralAttribute<T extends readonly string[]>($element: Element, literals: T, attrName: string, defaultValue: T[number]): T[number];
|
|
13
|
+
export declare const clampNumber: (value: number, min: number, max: number) => number;
|
|
14
|
+
declare type IntegerOptions = {
|
|
15
|
+
min?: number;
|
|
16
|
+
max?: number;
|
|
17
|
+
defaultValue?: number | null;
|
|
18
|
+
itemSizeMultiplier?: number;
|
|
19
|
+
itemSpaceBetween?: number;
|
|
20
|
+
};
|
|
21
|
+
export declare const attrValueToInteger: (value: string | null, options?: IntegerOptions) => number | null;
|
|
22
|
+
export declare const attrValueToPixels: (value: string | null, options?: IntegerOptions) => string;
|
|
23
|
+
export declare const updateIntegerAttribute: ($element: Element, attrName: string, attrValue: string | number | null | undefined, options?: IntegerOptions) => void;
|
|
24
|
+
export declare function getIntegerAttribute($element: Element, attrName: string): number | undefined;
|
|
25
|
+
export declare function getIntegerAttribute($element: Element, attrName: string, defaultValue: null): number | null;
|
|
26
|
+
export declare function getIntegerAttribute($element: Element, attrName: string, defaultValue: number): number;
|
|
27
|
+
export declare const setClass: (elem: Element, name: string, isSet: boolean) => void;
|
|
28
|
+
export declare const getCssVar: (element: Element, variableName: string) => string | null;
|
|
29
|
+
export declare const cloneNode: (el: Element, deep: boolean) => Element;
|
|
30
|
+
export {};
|
package/utils/dom.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
export const updateExplicitBooleanAttribute = ($element, attrName, attrValue) => {
|
|
2
|
+
$element.setAttribute(attrName, attrValue === true ? 'true' : 'false');
|
|
3
|
+
};
|
|
4
|
+
export const isAttrTrue = attrValue => {
|
|
5
|
+
return attrValue === '' || attrValue !== 'false' && attrValue !== null;
|
|
6
|
+
};
|
|
7
|
+
export const getBooleanAttribute = ($element, attrName) => {
|
|
8
|
+
return isAttrTrue($element.getAttribute(attrName));
|
|
9
|
+
};
|
|
10
|
+
export const updateBooleanAttribute = ($element, attrName, attrValue) => {
|
|
11
|
+
const currentAttrValue = $element.getAttribute(attrName);
|
|
12
|
+
if (attrValue === true) {
|
|
13
|
+
if (!isAttrTrue(currentAttrValue)) {
|
|
14
|
+
$element.setAttribute(attrName, '');
|
|
15
|
+
}
|
|
16
|
+
} else if (currentAttrValue !== null) {
|
|
17
|
+
$element.removeAttribute(attrName);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
export const updateAttribute = ($element, attrName, attrValue) => {
|
|
21
|
+
if (attrValue != null) {
|
|
22
|
+
$element.setAttribute(attrName, String(attrValue));
|
|
23
|
+
} else {
|
|
24
|
+
$element.removeAttribute(attrName);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
export function getAttribute($element, attrName) {
|
|
28
|
+
let defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
29
|
+
return $element.getAttribute(attrName) ?? defaultValue;
|
|
30
|
+
}
|
|
31
|
+
export const isLiteralValue = (literals, value) => {
|
|
32
|
+
return value != null && literals.includes(value);
|
|
33
|
+
};
|
|
34
|
+
export const updateLiteralAttribute = ($element, literals, attrName, attrValue) => {
|
|
35
|
+
if (isLiteralValue(literals, attrValue)) {
|
|
36
|
+
$element.setAttribute(attrName, attrValue);
|
|
37
|
+
} else {
|
|
38
|
+
$element.removeAttribute(attrName);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
export function getLiteralAttribute($element, literals, attrName, defaultValue) {
|
|
42
|
+
const attrValue = $element.getAttribute(attrName);
|
|
43
|
+
if (isLiteralValue(literals, attrValue)) {
|
|
44
|
+
return attrValue;
|
|
45
|
+
}
|
|
46
|
+
if (typeof defaultValue === 'undefined') {
|
|
47
|
+
throw new Error(`Invalid attribute value: ${attrName} = ${attrValue}`);
|
|
48
|
+
}
|
|
49
|
+
return defaultValue;
|
|
50
|
+
}
|
|
51
|
+
export const clampNumber = (value, min, max) => {
|
|
52
|
+
return Math.min(max, Math.max(min, value));
|
|
53
|
+
};
|
|
54
|
+
const DEFAULT_INTEGER_OPTIONS = {
|
|
55
|
+
itemSizeMultiplier: 1,
|
|
56
|
+
itemSpaceBetween: 0,
|
|
57
|
+
defaultValue: null
|
|
58
|
+
};
|
|
59
|
+
const applyRange = (value, _ref) => {
|
|
60
|
+
let {
|
|
61
|
+
min,
|
|
62
|
+
max
|
|
63
|
+
} = _ref;
|
|
64
|
+
let result = value;
|
|
65
|
+
if (min != null) {
|
|
66
|
+
result = Math.max(min, result);
|
|
67
|
+
}
|
|
68
|
+
if (max != null) {
|
|
69
|
+
result = Math.min(max, result);
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
};
|
|
73
|
+
export const attrValueToInteger = function (value) {
|
|
74
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_INTEGER_OPTIONS;
|
|
75
|
+
const {
|
|
76
|
+
defaultValue = null,
|
|
77
|
+
itemSizeMultiplier = 1,
|
|
78
|
+
itemSpaceBetween = 0
|
|
79
|
+
} = options;
|
|
80
|
+
let intValue = defaultValue;
|
|
81
|
+
if (value !== null) {
|
|
82
|
+
const int = parseInt(value);
|
|
83
|
+
if (Number.isInteger(int)) {
|
|
84
|
+
intValue = applyRange(int, options);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (intValue !== null) {
|
|
88
|
+
return intValue * itemSizeMultiplier + Math.max(intValue - 1, 0) * itemSpaceBetween;
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
};
|
|
92
|
+
export const attrValueToPixels = function (value) {
|
|
93
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_INTEGER_OPTIONS;
|
|
94
|
+
const int = attrValueToInteger(value, options);
|
|
95
|
+
return int === null ? 'unset' : `${int}px`;
|
|
96
|
+
};
|
|
97
|
+
export const updateIntegerAttribute = function ($element, attrName, attrValue) {
|
|
98
|
+
let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : DEFAULT_INTEGER_OPTIONS;
|
|
99
|
+
const {
|
|
100
|
+
defaultValue = null,
|
|
101
|
+
itemSizeMultiplier: multiplier = 1
|
|
102
|
+
} = options;
|
|
103
|
+
let intValue = null;
|
|
104
|
+
if (typeof attrValue === 'string') {
|
|
105
|
+
intValue = attrValueToInteger(attrValue, options);
|
|
106
|
+
} else if (typeof attrValue === 'number') {
|
|
107
|
+
intValue = applyRange(attrValue, options) * multiplier;
|
|
108
|
+
} else {
|
|
109
|
+
intValue = defaultValue;
|
|
110
|
+
}
|
|
111
|
+
if (intValue === null) {
|
|
112
|
+
$element.removeAttribute(attrName);
|
|
113
|
+
} else {
|
|
114
|
+
$element.setAttribute(attrName, intValue.toFixed(0));
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
export function getIntegerAttribute($element, attrName, defaultValue) {
|
|
118
|
+
return attrValueToInteger($element.getAttribute(attrName)) ?? defaultValue;
|
|
119
|
+
}
|
|
120
|
+
export const setClass = (elem, name, isSet) => {
|
|
121
|
+
isSet ? elem.classList.add(name) : elem.classList.remove(name);
|
|
122
|
+
};
|
|
123
|
+
export const getCssVar = (element, variableName) => {
|
|
124
|
+
const result = getComputedStyle(element).getPropertyValue(variableName);
|
|
125
|
+
return result === '' ? null : result;
|
|
126
|
+
};
|
|
127
|
+
export const cloneNode = (el, deep) => {
|
|
128
|
+
const root = el.getRootNode();
|
|
129
|
+
if (root !== document && Reflect.has(root, 'createElement')) {
|
|
130
|
+
const cloned = root.createElement(el.tagName.toLowerCase());
|
|
131
|
+
for (const attr of el.getAttributeNames()) {
|
|
132
|
+
cloned.setAttribute(attr, el.getAttribute(attr));
|
|
133
|
+
}
|
|
134
|
+
if (deep) {
|
|
135
|
+
for (let i = 0; i < el.children.length; i++) {
|
|
136
|
+
const clonedChild = cloneNode(el.children[i], deep);
|
|
137
|
+
cloned.appendChild(clonedChild);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return cloned;
|
|
141
|
+
}
|
|
142
|
+
return el.cloneNode(deep);
|
|
143
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const defineCustomElement: (name: string, constructor: CustomElementConstructor) => void;
|
|
2
|
+
export declare const setNectaryRegistry: (registry: CustomElementRegistry) => void;
|
|
3
|
+
declare global {
|
|
4
|
+
interface ShadowRootInit {
|
|
5
|
+
customElements?: CustomElementRegistry;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export declare class NectaryElement extends HTMLElement {
|
|
9
|
+
attachShadow(options?: Partial<ShadowRootInit>): ShadowRoot;
|
|
10
|
+
version: string;
|
|
11
|
+
get focusable(): boolean;
|
|
12
|
+
}
|
package/utils/element.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import pkg from '../package.json';
|
|
2
|
+
const nectaryDefinitions = new Map();
|
|
3
|
+
let nectaryRegistry = null;
|
|
4
|
+
export const defineCustomElement = (name, constructor) => {
|
|
5
|
+
if (nectaryRegistry !== null) {
|
|
6
|
+
if (nectaryRegistry.get(name) == null) {
|
|
7
|
+
nectaryRegistry.define(name, constructor);
|
|
8
|
+
}
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
nectaryDefinitions.set(name, constructor);
|
|
12
|
+
};
|
|
13
|
+
export const setNectaryRegistry = registry => {
|
|
14
|
+
if (nectaryRegistry !== null) {
|
|
15
|
+
throw new Error('Nectary elements already registered');
|
|
16
|
+
}
|
|
17
|
+
nectaryRegistry = registry;
|
|
18
|
+
for (const [name, ctor] of nectaryDefinitions.entries()) {
|
|
19
|
+
if (nectaryRegistry.get(name) == null) {
|
|
20
|
+
nectaryRegistry.define(name, ctor);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
nectaryDefinitions.clear();
|
|
24
|
+
};
|
|
25
|
+
export class NectaryElement extends HTMLElement {
|
|
26
|
+
attachShadow(options) {
|
|
27
|
+
return super.attachShadow({
|
|
28
|
+
mode: 'closed',
|
|
29
|
+
delegatesFocus: false,
|
|
30
|
+
customElements: nectaryRegistry,
|
|
31
|
+
...options
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
version = pkg.version;
|
|
35
|
+
get focusable() {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getReactEventHandler: ($element: HTMLElement, handlerName: string) => ((arg?: any) => void) | null;
|
package/utils/index.d.ts
CHANGED
|
@@ -1,57 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export declare class NectaryElement extends HTMLElement {
|
|
10
|
-
attachShadow(options?: Partial<ShadowRootInit>): ShadowRoot;
|
|
11
|
-
version: string;
|
|
12
|
-
get focusable(): boolean;
|
|
13
|
-
}
|
|
14
|
-
export declare const getReactEventHandler: ($element: HTMLElement, handlerName: string) => ((arg?: any) => void) | null;
|
|
15
|
-
export declare const updateExplicitBooleanAttribute: ($element: Element, attrName: string, attrValue: boolean | null | undefined) => void;
|
|
16
|
-
export declare const isAttrTrue: (attrValue: string | null) => boolean;
|
|
17
|
-
export declare const getBooleanAttribute: ($element: Element, attrName: string) => boolean;
|
|
18
|
-
export declare const updateBooleanAttribute: ($element: Element, attrName: string, attrValue: boolean | null | undefined) => void;
|
|
19
|
-
export declare const updateAttribute: ($element: Element, attrName: string, attrValue: string | number | boolean | null | undefined) => void;
|
|
20
|
-
export declare function getAttribute($element: Element, attrName: string): string | null;
|
|
21
|
-
export declare function getAttribute($element: Element, attrName: string, defaultValue: string): string;
|
|
22
|
-
export declare const isLiteralValue: <T extends readonly string[]>(literals: T, value: string | null | undefined) => value is T[number];
|
|
23
|
-
export declare const updateLiteralAttribute: <T extends readonly string[]>($element: Element, literals: T, attrName: string, attrValue: string | null | undefined) => void;
|
|
24
|
-
export declare function getLiteralAttribute<T extends readonly string[]>($element: Element, literals: T, attrName: string): T[number];
|
|
25
|
-
export declare function getLiteralAttribute<T extends readonly string[]>($element: Element, literals: T, attrName: string, defaultValue: null): T[number] | null;
|
|
26
|
-
export declare function getLiteralAttribute<T extends readonly string[]>($element: Element, literals: T, attrName: string, defaultValue: T[number]): T[number];
|
|
27
|
-
export declare const clampNumber: (value: number, min: number, max: number) => number;
|
|
28
|
-
declare type IntegerOptions = {
|
|
29
|
-
min?: number;
|
|
30
|
-
max?: number;
|
|
31
|
-
defaultValue?: number | null;
|
|
32
|
-
itemSizeMultiplier?: number;
|
|
33
|
-
itemSpaceBetween?: number;
|
|
34
|
-
};
|
|
35
|
-
export declare const attrValueToInteger: (value: string | null, options?: IntegerOptions) => number | null;
|
|
36
|
-
export declare const attrValueToPixels: (value: string | null, options?: IntegerOptions) => string;
|
|
37
|
-
export declare const updateIntegerAttribute: ($element: Element, attrName: string, attrValue: string | number | null | undefined, options?: IntegerOptions) => void;
|
|
38
|
-
export declare function getIntegerAttribute($element: Element, attrName: string): number | undefined;
|
|
39
|
-
export declare function getIntegerAttribute($element: Element, attrName: string, defaultValue: null): number | null;
|
|
40
|
-
export declare function getIntegerAttribute($element: Element, attrName: string, defaultValue: number): number;
|
|
41
|
-
export declare const getCsvSet: (acc: string) => Set<string>;
|
|
42
|
-
export declare const updateCsv: (acc: string, value: string, setActive: boolean) => string;
|
|
43
|
-
export declare const getFirstCsvValue: (acc: string) => string | null;
|
|
44
|
-
export declare const getRect: (el: Element) => TRect;
|
|
45
|
-
export declare const setClass: (elem: Element, name: string, isSet: boolean) => void;
|
|
46
|
-
export declare const getCssVar: (element: Element, variableName: string) => string | null;
|
|
47
|
-
export declare const throttleAnimationFrame: (cb: (...args: any[]) => void) => {
|
|
48
|
-
fn: (...args: any[]) => void;
|
|
49
|
-
cancel: () => void;
|
|
50
|
-
};
|
|
51
|
-
export declare const getFirstSlotElement: (root: HTMLSlotElement, isDeep?: boolean) => HTMLElement | null;
|
|
52
|
-
export declare const getFirstFocusableElement: (root: Element) => NectaryElement | null;
|
|
53
|
-
export declare const cloneNode: (el: Element, deep: boolean) => Element;
|
|
54
|
-
export declare const isElementFocused: ($el: Element | null) => boolean;
|
|
55
|
-
export declare const rectOverlap: (targetRect: TRect, contentRect: TRect) => boolean;
|
|
56
|
-
export declare const getTargetRect: (slot: HTMLSlotElement) => TRect | null;
|
|
57
|
-
export {};
|
|
1
|
+
export * from './context';
|
|
2
|
+
export * from './csv';
|
|
3
|
+
export * from './dom';
|
|
4
|
+
export * from './element';
|
|
5
|
+
export * from './rect';
|
|
6
|
+
export * from './slot';
|
|
7
|
+
export * from './throttle';
|
|
8
|
+
export * from './get-react-event-handler';
|