@scalable.software/pin 0.1.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/LICENSE +144 -0
- package/README.md +367 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/pin.d.ts +193 -0
- package/dist/pin.js +267 -0
- package/dist/pin.meta.d.ts +99 -0
- package/dist/pin.meta.js +67 -0
- package/dist/pin.style.css +133 -0
- package/dist/pin.template.html +26 -0
- package/dist/pin.validation.d.ts +15 -0
- package/dist/pin.validation.js +27 -0
- package/package.json +54 -0
- package/report/component.report.json +1305 -0
- package/src/index.ts +16 -0
- package/src/pin.meta.ts +108 -0
- package/src/pin.style.css +133 -0
- package/src/pin.template.html +26 -0
- package/src/pin.ts +322 -0
- package/src/pin.validation.ts +29 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { type Configuration } from "@scalable.software/component";
|
|
2
|
+
|
|
3
|
+
export {
|
|
4
|
+
Tag,
|
|
5
|
+
Attributes,
|
|
6
|
+
State,
|
|
7
|
+
Visible,
|
|
8
|
+
Status,
|
|
9
|
+
Operation,
|
|
10
|
+
Event,
|
|
11
|
+
Gesture,
|
|
12
|
+
} from "./pin.meta.js";
|
|
13
|
+
|
|
14
|
+
export { Validate } from "./pin.validation.js";
|
|
15
|
+
|
|
16
|
+
export { Pin } from "./pin.js";
|
package/src/pin.meta.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Component
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export const Tag = "pin-button" as const;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* HTML Attributes available to set
|
|
9
|
+
* @category Metadata: State
|
|
10
|
+
* @enum
|
|
11
|
+
*/
|
|
12
|
+
export const Attributes = {
|
|
13
|
+
VISIBLE: "visible",
|
|
14
|
+
STATUS: "status",
|
|
15
|
+
} as const;
|
|
16
|
+
/**
|
|
17
|
+
* HTML Attributes available to set
|
|
18
|
+
* @category Metadata: State
|
|
19
|
+
*/
|
|
20
|
+
export type Attributes = typeof Attributes;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* HTML Attributes available to set
|
|
24
|
+
* @category Metadata: State
|
|
25
|
+
* @enum
|
|
26
|
+
*/
|
|
27
|
+
export const State = {
|
|
28
|
+
...Attributes,
|
|
29
|
+
} as const;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* HTML Attributes available to set
|
|
33
|
+
* @category Metadata: State
|
|
34
|
+
*/
|
|
35
|
+
export type State = (typeof State)[keyof typeof State];
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Visible state used to show or hide the component
|
|
39
|
+
* @category Metadata: State
|
|
40
|
+
* @enum
|
|
41
|
+
*/
|
|
42
|
+
export const Visible = {
|
|
43
|
+
YES: "yes",
|
|
44
|
+
NO: "no",
|
|
45
|
+
} as const;
|
|
46
|
+
/**
|
|
47
|
+
* Visible state used to show or hide the component
|
|
48
|
+
* @category Metadata: State
|
|
49
|
+
*/
|
|
50
|
+
export type Visible = (typeof Visible)[keyof typeof Visible];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @category Metadata: State
|
|
54
|
+
* @enum
|
|
55
|
+
*/
|
|
56
|
+
export const Status = {
|
|
57
|
+
PINNED: "pinned",
|
|
58
|
+
UNPINNED: "unpinned",
|
|
59
|
+
} as const;
|
|
60
|
+
/**
|
|
61
|
+
* @category Metadata: State
|
|
62
|
+
*/
|
|
63
|
+
export type Status = (typeof Status)[keyof typeof Status];
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @category Metadata: Operations
|
|
67
|
+
* @enum
|
|
68
|
+
*/
|
|
69
|
+
export const Operation = {
|
|
70
|
+
HIDE: "hide",
|
|
71
|
+
SHOW: "show",
|
|
72
|
+
PIN: "pin",
|
|
73
|
+
UNPIN: "unpin",
|
|
74
|
+
TOGGLE: "toggle",
|
|
75
|
+
} as const;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @category Metadata: Operations
|
|
79
|
+
*/
|
|
80
|
+
export type Operation = (typeof Operation)[keyof typeof Operation];
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @category Metadata: Events
|
|
84
|
+
* @enum
|
|
85
|
+
*/
|
|
86
|
+
export const Event = {
|
|
87
|
+
ON: "on",
|
|
88
|
+
ON_HIDE: "onhide",
|
|
89
|
+
ON_SHOW: "onshow",
|
|
90
|
+
ON_PIN: "onpin",
|
|
91
|
+
ON_UNPIN: "onunpin",
|
|
92
|
+
} as const;
|
|
93
|
+
/**
|
|
94
|
+
* @category Metadata: Events
|
|
95
|
+
*/
|
|
96
|
+
export type Event = (typeof Event)[keyof typeof Event];
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @category Metadata: Gesture
|
|
100
|
+
* @enum
|
|
101
|
+
*/
|
|
102
|
+
export const Gesture = {
|
|
103
|
+
CLICK: "click",
|
|
104
|
+
} as const;
|
|
105
|
+
/**
|
|
106
|
+
* @category Metadata: Gesture
|
|
107
|
+
*/
|
|
108
|
+
export type Gesture = (typeof Gesture)[keyof typeof Gesture];
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* =======================
|
|
2
|
+
Host Element Styles
|
|
3
|
+
======================= */
|
|
4
|
+
:host {
|
|
5
|
+
/* Light mode color variables */
|
|
6
|
+
--button-background-color: #ffffff;
|
|
7
|
+
--button-hover-background-color: #f3f3f3;
|
|
8
|
+
--button-active-background-color: #e1e1e1;
|
|
9
|
+
--button-border-color: #d1d1d1;
|
|
10
|
+
--button-border-hover-color: #a1a1a1;
|
|
11
|
+
--button-shadow-hover: 0 2px 6px rgba(0, 0, 0, 0.15);
|
|
12
|
+
--svg-fill-color: #5a5a5a;
|
|
13
|
+
--svg-hover-fill-color: #404040;
|
|
14
|
+
/* Shadow and radius */
|
|
15
|
+
--button-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
|
16
|
+
--button-radius: 8px;
|
|
17
|
+
/* Sizes and margins */
|
|
18
|
+
--icon-size: 40px;
|
|
19
|
+
--icon-margin: 4px;
|
|
20
|
+
--svg-size: 24px;
|
|
21
|
+
--svg-margin: 8px;
|
|
22
|
+
display: inline-block;
|
|
23
|
+
}
|
|
24
|
+
/* Dark Mode Variables */
|
|
25
|
+
@media (prefers-color-scheme: dark) {
|
|
26
|
+
:host {
|
|
27
|
+
/* Dark mode color variables */
|
|
28
|
+
--button-background-color: #1e1e1e;
|
|
29
|
+
--button-hover-background-color: #2a2a2a;
|
|
30
|
+
--button-active-background-color: #333333;
|
|
31
|
+
--button-border-color: #3c3c3c;
|
|
32
|
+
--button-border-hover-color: #4a4a4a;
|
|
33
|
+
--button-shadow: 0 1px 3px rgba(255, 255, 255, 0.12),
|
|
34
|
+
0 3px 8px rgba(0, 0, 0, 0.6);
|
|
35
|
+
--button-shadow-hover: 0 2px 6px rgba(255, 255, 255, 0.16),
|
|
36
|
+
0 6px 12px rgba(0, 0, 0, 0.6);
|
|
37
|
+
--svg-fill-color: #cfcfcf;
|
|
38
|
+
--svg-hover-fill-color: #ffffff;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* =======================
|
|
43
|
+
Icon Styles
|
|
44
|
+
======================= */
|
|
45
|
+
.icon {
|
|
46
|
+
position: relative;
|
|
47
|
+
margin: var(--icon-margin);
|
|
48
|
+
display: inline-flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
justify-content: center;
|
|
51
|
+
width: var(--icon-size);
|
|
52
|
+
height: var(--icon-size);
|
|
53
|
+
background-color: var(--button-background-color);
|
|
54
|
+
border: 1px solid var(--button-border-color);
|
|
55
|
+
border-radius: var(--button-radius);
|
|
56
|
+
box-shadow: var(--button-shadow);
|
|
57
|
+
cursor: pointer;
|
|
58
|
+
transition: background-color 0.2s, border-color 0.2s, box-shadow 0.2s;
|
|
59
|
+
}
|
|
60
|
+
/* Active state styles for the icon (when clicked or tapped) */
|
|
61
|
+
.icon:active {
|
|
62
|
+
background-color: var(--button-active-background-color);
|
|
63
|
+
border-color: var(--button-border-hover-color);
|
|
64
|
+
box-shadow: none;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* =======================
|
|
68
|
+
Icon Hover Styles
|
|
69
|
+
======================= */
|
|
70
|
+
@media (hover: hover) {
|
|
71
|
+
.icon:hover {
|
|
72
|
+
background-color: var(--button-hover-background-color);
|
|
73
|
+
border-color: var(--button-border-hover-color);
|
|
74
|
+
box-shadow: var(--button-shadow-hover);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* =======================
|
|
79
|
+
SVG Icon Styles
|
|
80
|
+
======================= */
|
|
81
|
+
svg {
|
|
82
|
+
margin: var(--svg-margin);
|
|
83
|
+
width: var(--svg-size);
|
|
84
|
+
height: var(--svg-size);
|
|
85
|
+
fill: var(--svg-fill-color);
|
|
86
|
+
transition: fill 0.2s, opacity 0.2s;
|
|
87
|
+
}
|
|
88
|
+
/* Hover effect for the SVG icons */
|
|
89
|
+
@media (hover: hover) {
|
|
90
|
+
.icon:hover svg {
|
|
91
|
+
fill: var(--svg-hover-fill-color);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* =======================
|
|
96
|
+
State Visibility
|
|
97
|
+
======================= */
|
|
98
|
+
:host([visible="no"]) {
|
|
99
|
+
display: none;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* =======================
|
|
103
|
+
State Status
|
|
104
|
+
======================= */
|
|
105
|
+
.pinned {
|
|
106
|
+
display: none;
|
|
107
|
+
}
|
|
108
|
+
.unpinned {
|
|
109
|
+
display: inline-block;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* =======================
|
|
113
|
+
State Status: Pinned
|
|
114
|
+
======================= */
|
|
115
|
+
:host([status="pinned"]) .icon {
|
|
116
|
+
background-color: var(--button-active-background-color);
|
|
117
|
+
border-color: var(--button-border-hover-color);
|
|
118
|
+
}
|
|
119
|
+
:host([status="pinned"]) .pinned {
|
|
120
|
+
display: inline-block;
|
|
121
|
+
}
|
|
122
|
+
:host([status="pinned"]) .unpinned {
|
|
123
|
+
display: none;
|
|
124
|
+
}
|
|
125
|
+
/* =======================
|
|
126
|
+
State Status: Unpinned
|
|
127
|
+
======================= */
|
|
128
|
+
:host([status="unpinned"]) .pinned {
|
|
129
|
+
display: none;
|
|
130
|
+
}
|
|
131
|
+
:host([status="unpinned"]) .unpinned {
|
|
132
|
+
display: inline-block;
|
|
133
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<template id="pin-button">
|
|
2
|
+
<div class="icon">
|
|
3
|
+
<svg
|
|
4
|
+
class="pinned"
|
|
5
|
+
height="24px"
|
|
6
|
+
width="24px"
|
|
7
|
+
viewBox="0 0 20 20"
|
|
8
|
+
fill="#212121"
|
|
9
|
+
>
|
|
10
|
+
<path
|
|
11
|
+
d="M2.85355 2.14645C2.65829 1.95118 2.34171 1.95118 2.14645 2.14645C1.95118 2.34171 1.95118 2.65829 2.14645 2.85355L6.896 7.60309L4.01834 8.75415C3.35177 9.02078 3.17498 9.88209 3.68262 10.3897L6.29289 13L3 16.2929V17H3.70711L7 13.7071L9.61027 16.3174C10.1179 16.825 10.9792 16.6482 11.2459 15.9817L12.3969 13.104L17.1464 17.8536C17.3417 18.0488 17.6583 18.0488 17.8536 17.8536C18.0488 17.6583 18.0488 17.3417 17.8536 17.1464L2.85355 2.14645ZM11.6276 12.3347L10.3174 15.6103L4.38973 9.68263L7.66531 8.3724L11.6276 12.3347ZM12.9565 10.7127C12.9294 10.7263 12.9026 10.7403 12.8761 10.7548L13.6202 11.4989L16.8622 9.87793C18.0832 9.26743 18.3473 7.64015 17.382 6.67486L13.3251 2.61804C12.3599 1.65275 10.7326 1.91683 10.1221 3.13783L8.5011 6.37977L9.24523 7.1239C9.25971 7.09739 9.27373 7.07059 9.28728 7.04349L11.0165 3.58504C11.3218 2.97454 12.1354 2.8425 12.618 3.32514L16.6749 7.38197C17.1575 7.86461 17.0255 8.67826 16.415 8.98351L12.9565 10.7127Z"
|
|
12
|
+
/>
|
|
13
|
+
</svg>
|
|
14
|
+
<svg
|
|
15
|
+
class="unpinned"
|
|
16
|
+
height="24px"
|
|
17
|
+
width="24px"
|
|
18
|
+
viewBox="0 0 20 20"
|
|
19
|
+
fill="#212121"
|
|
20
|
+
>
|
|
21
|
+
<path
|
|
22
|
+
d="M10.1221 3.13782C10.7326 1.91683 12.3599 1.65275 13.3251 2.61804L17.382 6.67486C18.3472 7.64015 18.0832 9.26743 16.8622 9.87793L13.4037 11.6072C13.0751 11.7715 12.8183 12.0506 12.6818 12.3917L11.2459 15.9817C10.9792 16.6482 10.1179 16.825 9.61027 16.3174L7 13.7071L3.70711 17H3V16.2929L6.29289 13L3.68262 10.3897C3.17498 9.88209 3.35177 9.02078 4.01834 8.75415L7.60829 7.31817C7.94939 7.18173 8.22855 6.92486 8.39285 6.59628L10.1221 3.13782ZM12.618 3.32514C12.1354 2.8425 11.3217 2.97454 11.0165 3.58504L9.28727 7.04349C9.01345 7.59113 8.54818 8.01925 7.97968 8.24665L4.38973 9.68263L10.3174 15.6103L11.7534 12.0203C11.9808 11.4518 12.4089 10.9866 12.9565 10.7127L16.415 8.9835C17.0255 8.67826 17.1575 7.86461 16.6749 7.38197L12.618 3.32514Z"
|
|
23
|
+
/>
|
|
24
|
+
</svg>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
package/src/pin.ts
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Component
|
|
3
|
+
*/
|
|
4
|
+
import { Component, Template } from "@scalable.software/component";
|
|
5
|
+
import { type Configuration, type Handler } from "@scalable.software/component";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
Tag,
|
|
9
|
+
Attributes,
|
|
10
|
+
Visible,
|
|
11
|
+
Status,
|
|
12
|
+
Event,
|
|
13
|
+
Gesture,
|
|
14
|
+
} from "./pin.meta.js";
|
|
15
|
+
|
|
16
|
+
import { Validate } from "./pin.validation.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Configuration required for components with custom layout and style
|
|
20
|
+
* @category Configuration
|
|
21
|
+
*/
|
|
22
|
+
export const configuration: Configuration = {
|
|
23
|
+
url: import.meta.url,
|
|
24
|
+
template: {
|
|
25
|
+
id: Tag,
|
|
26
|
+
},
|
|
27
|
+
css: {
|
|
28
|
+
name: "pin.style.css",
|
|
29
|
+
},
|
|
30
|
+
} as const;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A pin button that can be:
|
|
34
|
+
* 1. pinned and unpinned
|
|
35
|
+
* 2. hidden and shown
|
|
36
|
+
* @category Components
|
|
37
|
+
*/
|
|
38
|
+
export class Pin extends Component {
|
|
39
|
+
/**
|
|
40
|
+
* The tag name of the component
|
|
41
|
+
* @category Configuration
|
|
42
|
+
*/
|
|
43
|
+
public static get Tag() {
|
|
44
|
+
return Tag;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Only attributes defined the Attributes object will be observed in DOM
|
|
49
|
+
* @category Configuration
|
|
50
|
+
*/
|
|
51
|
+
public static get Attributes(): Attributes {
|
|
52
|
+
return Attributes;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Helper function to load the component template into DOM
|
|
57
|
+
* @category Utility
|
|
58
|
+
*/
|
|
59
|
+
public static Template = new Template(import.meta.url);
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Cache element references to improve performance
|
|
63
|
+
* @category State
|
|
64
|
+
* @hidden
|
|
65
|
+
*/
|
|
66
|
+
protected elements: { icon: HTMLDivElement | null } = { icon: null };
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Internal Visibility state of the component
|
|
70
|
+
* @category State
|
|
71
|
+
* @default Visible.YES
|
|
72
|
+
* @hidden
|
|
73
|
+
*/
|
|
74
|
+
private _visible: Visible = Visible.YES;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Internal Status state of the component
|
|
78
|
+
* @category State
|
|
79
|
+
* @default
|
|
80
|
+
* @hidden
|
|
81
|
+
*/
|
|
82
|
+
private _status: Status = Status.UNPINNED;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* on triggered when any event is triggered
|
|
86
|
+
* @category Events
|
|
87
|
+
* @hidden
|
|
88
|
+
*/
|
|
89
|
+
private _on: Handler = null;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* onhide triggered when pin visibility changes to hidden
|
|
93
|
+
* @category Events
|
|
94
|
+
* @hidden
|
|
95
|
+
*/
|
|
96
|
+
private _onhide: Handler = null;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* onshow triggered when pin visibility changes to visible
|
|
100
|
+
* @category Events
|
|
101
|
+
* @hidden
|
|
102
|
+
*/
|
|
103
|
+
private _onshow: Handler = null;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* onpin triggered when pin status changes to pinned
|
|
107
|
+
* @category Events
|
|
108
|
+
* @hidden
|
|
109
|
+
*/
|
|
110
|
+
private _onpin: Handler = null;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* onunpin triggered when pin state changes to unpinned
|
|
114
|
+
* @category Events
|
|
115
|
+
* @hidden
|
|
116
|
+
*/
|
|
117
|
+
private _onunpin: Handler = null;
|
|
118
|
+
|
|
119
|
+
constructor() {
|
|
120
|
+
super(configuration);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get and Sets the visibility of the pin button
|
|
125
|
+
* @category State
|
|
126
|
+
*/
|
|
127
|
+
public get visible() {
|
|
128
|
+
return this.hasAttribute(Attributes.VISIBLE)
|
|
129
|
+
? (this.getAttribute(Attributes.VISIBLE) as Visible)
|
|
130
|
+
: this._visible;
|
|
131
|
+
}
|
|
132
|
+
public set visible(visible: Visible) {
|
|
133
|
+
visible = visible ?? Visible.YES;
|
|
134
|
+
|
|
135
|
+
visible = Validate.visible(visible);
|
|
136
|
+
|
|
137
|
+
if (this._visible === visible) return;
|
|
138
|
+
|
|
139
|
+
this._visible = visible;
|
|
140
|
+
|
|
141
|
+
visible === Visible.YES && this.removeAttribute(Attributes.VISIBLE);
|
|
142
|
+
visible === Visible.NO && this.setAttribute(Attributes.VISIBLE, visible);
|
|
143
|
+
|
|
144
|
+
const event = { detail: { visible } };
|
|
145
|
+
|
|
146
|
+
visible === Visible.NO && this._dispatchEvent(Event.ON_HIDE, event);
|
|
147
|
+
visible === Visible.YES && this._dispatchEvent(Event.ON_SHOW, event);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get and Sets the status of the pin button
|
|
152
|
+
* @category State
|
|
153
|
+
*/
|
|
154
|
+
public get status(): Status {
|
|
155
|
+
return this.hasAttribute(Attributes.STATUS)
|
|
156
|
+
? (this.getAttribute(Attributes.STATUS) as Status)
|
|
157
|
+
: this._status;
|
|
158
|
+
}
|
|
159
|
+
public set status(status: Status) {
|
|
160
|
+
status = Validate.status(status);
|
|
161
|
+
|
|
162
|
+
if (this._status === status) return;
|
|
163
|
+
|
|
164
|
+
this._status = status;
|
|
165
|
+
|
|
166
|
+
this.setAttribute(Attributes.STATUS, status);
|
|
167
|
+
|
|
168
|
+
const event = { detail: { status } };
|
|
169
|
+
|
|
170
|
+
status === Status.PINNED && this._dispatchEvent(Event.ON_PIN, event);
|
|
171
|
+
status === Status.UNPINNED && this._dispatchEvent(Event.ON_UNPIN, event);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Triggered on any event
|
|
176
|
+
* @event
|
|
177
|
+
* @category Events
|
|
178
|
+
*/
|
|
179
|
+
public set on(handler: Handler) {
|
|
180
|
+
Object.values(Event)
|
|
181
|
+
.filter((event): event is Event => event !== Event.ON)
|
|
182
|
+
.forEach((event: Event) => {
|
|
183
|
+
this._on && this.removeEventListener(event, this._on);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
this._on = handler;
|
|
187
|
+
|
|
188
|
+
Object.values(Event)
|
|
189
|
+
.filter((event): event is Event => event !== Event.ON)
|
|
190
|
+
.forEach((event: Event) => {
|
|
191
|
+
this._on && this.addEventListener(event, this._on);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Triggered via `.hide()`
|
|
197
|
+
* @event
|
|
198
|
+
* @category Events
|
|
199
|
+
*/
|
|
200
|
+
public set onhide(handler: Handler) {
|
|
201
|
+
this._onhide && this.removeEventListener(Event.ON_HIDE, this._onhide);
|
|
202
|
+
this._onhide = handler;
|
|
203
|
+
this._onhide && this.addEventListener(Event.ON_HIDE, this._onhide);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Triggered via `.show()`
|
|
208
|
+
* @event
|
|
209
|
+
* @category Events
|
|
210
|
+
*/
|
|
211
|
+
public set onshow(handler: Handler) {
|
|
212
|
+
this._onshow && this.removeEventListener(Event.ON_SHOW, this._onshow);
|
|
213
|
+
this._onshow = handler;
|
|
214
|
+
this._onshow && this.addEventListener(Event.ON_SHOW, this._onshow);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Triggered via `.pin()`
|
|
219
|
+
* @event
|
|
220
|
+
* @category Events
|
|
221
|
+
*/
|
|
222
|
+
public set onpin(handler: Handler) {
|
|
223
|
+
this._onpin && this.removeEventListener(Event.ON_PIN, this._onpin);
|
|
224
|
+
this._onpin = handler;
|
|
225
|
+
this._onpin && this.addEventListener(Event.ON_PIN, this._onpin);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Triggered via `.unpin()`
|
|
230
|
+
* @event
|
|
231
|
+
* @category Events
|
|
232
|
+
*/
|
|
233
|
+
public set onunpin(handler: Handler) {
|
|
234
|
+
this._onunpin && this.removeEventListener(Event.ON_UNPIN, this._onunpin);
|
|
235
|
+
this._onunpin = handler;
|
|
236
|
+
this._onunpin && this.addEventListener(Event.ON_UNPIN, this._onunpin);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Hide the pin button when it is visible
|
|
241
|
+
* @category Operations
|
|
242
|
+
*/
|
|
243
|
+
public hide = () => (this.visible = Visible.NO);
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Show the pin button when it is hidden
|
|
247
|
+
* @category Operations
|
|
248
|
+
*/
|
|
249
|
+
public show = () => (this.visible = Visible.YES);
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Pin the pin button when it is unpinned
|
|
253
|
+
* @category Operations
|
|
254
|
+
*/
|
|
255
|
+
public pin = () => (this.status = Status.PINNED);
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Unpin the pin button when it is pinned
|
|
259
|
+
* @category Operations
|
|
260
|
+
*/
|
|
261
|
+
public unpin = () => (this.status = Status.UNPINNED);
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Toggle the pin button between pinned and unpinned
|
|
265
|
+
* @category Operations
|
|
266
|
+
*/
|
|
267
|
+
public toggle = () =>
|
|
268
|
+
(this.status =
|
|
269
|
+
this.status === Status.PINNED ? Status.UNPINNED : Status.PINNED);
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* List operations to perform for selected attributes being observed in the DOM.
|
|
273
|
+
* @category Configuration
|
|
274
|
+
* @hidden
|
|
275
|
+
*/
|
|
276
|
+
protected _attributeHandlers = {
|
|
277
|
+
[Attributes.VISIBLE]: (value) => (this.visible = value),
|
|
278
|
+
[Attributes.STATUS]: (value) => (this.status = value),
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Initialize component attributes with default values
|
|
283
|
+
* @category Configuration
|
|
284
|
+
* @hidden
|
|
285
|
+
*/
|
|
286
|
+
protected _initialize = () => {
|
|
287
|
+
!this.hasAttribute(Attributes.STATUS) &&
|
|
288
|
+
this.setAttribute(Attributes.STATUS, this._status);
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Cache element references to improve performance
|
|
293
|
+
* @category Configuration
|
|
294
|
+
* @hidden
|
|
295
|
+
*/
|
|
296
|
+
protected _cache = () => {
|
|
297
|
+
this.elements.icon = this.root.querySelector(".icon");
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Called by the connectedCallback prototypical method
|
|
302
|
+
* @category Configuration
|
|
303
|
+
* @hidden
|
|
304
|
+
*/
|
|
305
|
+
protected _addEventListeners = () =>
|
|
306
|
+
this.elements.icon.addEventListener(Gesture.CLICK, this._handleClick);
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Called by the disconnectedCallback prototypical method
|
|
310
|
+
* @category Configuration
|
|
311
|
+
* @hidden
|
|
312
|
+
*/
|
|
313
|
+
protected _removeEventListeners = () =>
|
|
314
|
+
this.elements.icon.removeEventListener(Gesture.CLICK, this._handleClick);
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Handles the click event
|
|
318
|
+
* @category Gesture
|
|
319
|
+
* @hidden
|
|
320
|
+
*/
|
|
321
|
+
private _handleClick = (event: MouseEvent | TouchEvent) => this.toggle();
|
|
322
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Visible, Status } from "./pin.meta.js";
|
|
2
|
+
|
|
3
|
+
export class Validate {
|
|
4
|
+
/**
|
|
5
|
+
* Validates that the value is a member of the `Visible` enum.
|
|
6
|
+
* Throws if the value is not a recognized visible state.
|
|
7
|
+
* @category Validation
|
|
8
|
+
*/
|
|
9
|
+
public static visible = (value: string) => {
|
|
10
|
+
const valid = Object.values(Visible).includes(value as Visible);
|
|
11
|
+
if (!valid) {
|
|
12
|
+
throw new Error(`Invalid visible value: ${value}`);
|
|
13
|
+
}
|
|
14
|
+
return value as Visible;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Validates that the value is a member of the `Status` enum.
|
|
19
|
+
* Throws if the value is not a recognized status state.
|
|
20
|
+
* @category Validation
|
|
21
|
+
*/
|
|
22
|
+
public static status = (value: string) => {
|
|
23
|
+
const valid = Object.values(Status).includes(value as Status);
|
|
24
|
+
if (!valid) {
|
|
25
|
+
throw new Error(`Invalid status value: ${value}`);
|
|
26
|
+
}
|
|
27
|
+
return value as Status;
|
|
28
|
+
};
|
|
29
|
+
}
|