yuyeon 0.0.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.
Files changed (77) hide show
  1. package/package.json +38 -0
  2. package/src/components/button/index.ts +3 -0
  3. package/src/components/button/y-btn.scss +79 -0
  4. package/src/components/button/y-btn.ts +104 -0
  5. package/src/components/card/index.ts +6 -0
  6. package/src/components/card/y-card-body.ts +8 -0
  7. package/src/components/card/y-card-footer.ts +8 -0
  8. package/src/components/card/y-card-header.ts +8 -0
  9. package/src/components/card/y-card.scss +30 -0
  10. package/src/components/card/y-card.ts +16 -0
  11. package/src/components/checkbox/IconCheckbox.vue +24 -0
  12. package/src/components/checkbox/YCheckbox.vue +113 -0
  13. package/src/components/checkbox/YInputCheckbox.vue +108 -0
  14. package/src/components/checkbox/index.ts +8 -0
  15. package/src/components/checkbox/y-checkbox.scss +48 -0
  16. package/src/components/checkbox/y-input-checkbox.scss +86 -0
  17. package/src/components/chip/index.ts +3 -0
  18. package/src/components/chip/y-chip.scss +28 -0
  19. package/src/components/chip/y-chip.vue +69 -0
  20. package/src/components/dialog/index.ts +3 -0
  21. package/src/components/dialog/y-dialog.scss +5 -0
  22. package/src/components/dialog/y-dialog.vue +46 -0
  23. package/src/components/field-input/index.scss +5 -0
  24. package/src/components/field-input/index.ts +11 -0
  25. package/src/components/field-input/y-field-input.scss +65 -0
  26. package/src/components/field-input/y-field-input.ts +214 -0
  27. package/src/components/form/index.ts +9 -0
  28. package/src/components/form/y-form.ts +93 -0
  29. package/src/components/icons/icon-clearable.ts +6 -0
  30. package/src/components/index.ts +17 -0
  31. package/src/components/input/index.scss +5 -0
  32. package/src/components/input/index.ts +9 -0
  33. package/src/components/input/y-input.scss +209 -0
  34. package/src/components/input/y-input.ts +368 -0
  35. package/src/components/layer/index.ts +3 -0
  36. package/src/components/layer/y-layer.scss +32 -0
  37. package/src/components/layer/y-layer.vue +146 -0
  38. package/src/components/lottie-player.ts +41 -0
  39. package/src/components/progress-bar/index.ts +3 -0
  40. package/src/components/progress-bar/y-progress-bar.vue +144 -0
  41. package/src/components/ring-spinner/y-ring-spinner.scss +25 -0
  42. package/src/components/ring-spinner/y-ring-spinner.vue +31 -0
  43. package/src/components/switch/YSwitch.vue +217 -0
  44. package/src/components/switch/index.scss +5 -0
  45. package/src/components/switch/index.ts +11 -0
  46. package/src/components/switch/y-switch.scss +206 -0
  47. package/src/components/text-highlighter/index.scss +5 -0
  48. package/src/components/text-highlighter/index.ts +3 -0
  49. package/src/components/text-highlighter/y-text-highlighter.scss +7 -0
  50. package/src/components/text-highlighter/y-text-highlighter.ts +89 -0
  51. package/src/composables/layer-group.ts +31 -0
  52. package/src/composables/lazy.ts +30 -0
  53. package/src/composables/progress.ts +19 -0
  54. package/src/composables/theme.ts +25 -0
  55. package/src/directives/complement-click/index.ts +123 -0
  56. package/src/directives/plate-wave/index.ts +114 -0
  57. package/src/directives/plate-wave/plate-wave.scss +33 -0
  58. package/src/directives/theme-class.ts +14 -0
  59. package/src/file-extension.d.ts +14 -0
  60. package/src/index.ts +21 -0
  61. package/src/mixins/di.ts +23 -0
  62. package/src/mixins/rebind-attrs.ts +36 -0
  63. package/src/styles/base.scss +28 -0
  64. package/src/styles/palette.scss +94 -0
  65. package/src/styles/theme/dark.scss +35 -0
  66. package/src/styles/theme/index.scss +8 -0
  67. package/src/styles/theme/light.scss +32 -0
  68. package/src/styles/util/helper.scss +6 -0
  69. package/src/styles/util/theme.scss +16 -0
  70. package/src/styles/variables.scss +1 -0
  71. package/src/util/common.ts +59 -0
  72. package/src/util/date-time.ts +41 -0
  73. package/src/util/dom.ts +6 -0
  74. package/src/util/string.ts +9 -0
  75. package/src/util/ui.ts +39 -0
  76. package/src/util/validation.ts +9 -0
  77. package/src/util/vue-component.ts +18 -0
@@ -0,0 +1,206 @@
1
+ /*!
2
+ * Created by yeonyu 2022.
3
+ */
4
+ @use '../../styles/palette';
5
+ @use '../../styles/variables';
6
+
7
+ .y-switch {
8
+ $primary: palette.$basic-violet-400;
9
+ font-size: 1rem;
10
+
11
+ &__slot {
12
+ display: flex;
13
+ cursor: pointer;
14
+ align-items: center;
15
+ color: inherit;
16
+ min-height: inherit;
17
+ position: relative;
18
+ }
19
+
20
+ &__input {
21
+ width: 3em;
22
+ height: 1.5em;
23
+ position: relative;
24
+ display: inline-flex;
25
+ user-select: none;
26
+ color: inherit;
27
+ flex: 0 0 auto;
28
+
29
+ input[role='switch'] {
30
+ position: absolute;
31
+ opacity: 0;
32
+ width: 100%;
33
+ height: 100%;
34
+ cursor: pointer;
35
+ user-select: none;
36
+ }
37
+ }
38
+ &:not(&--loading) &__input:active &__thumb {
39
+ width: 1em;
40
+ }
41
+
42
+ &__track {
43
+ width: 100%;
44
+ height: 100%;
45
+ border-radius: 2em;
46
+ background-color: #a0a0a0;
47
+ position: absolute;
48
+ left: 0;
49
+ top: 0;
50
+ transition: 300ms;
51
+ }
52
+
53
+ &__thumb {
54
+ width: 1.1em;
55
+ height: 1.1em;
56
+ top: calc(50% - 0.56em);
57
+ left: 0.2em;
58
+ border-radius: 50%;
59
+ display: flex;
60
+ justify-content: center;
61
+ align-items: center;
62
+ background-color: #fff;
63
+ pointer-events: none;
64
+ position: relative;
65
+ transition: 180ms cubic-bezier(0.78, 0.04, 0.9, 0.18);
66
+ }
67
+
68
+ &__spinner {
69
+ position: relative;
70
+ width: 100%;
71
+ height: 100%;
72
+ border-radius: 50%;
73
+ animation: rotate 2s linear infinite;
74
+ contain: paint;
75
+
76
+ @keyframes spinner-blur {
77
+ 0% {
78
+ filter: blur(4px);
79
+ }
80
+ 50% {
81
+ filter: blur(1px);
82
+ }
83
+ 100% {
84
+ filter: blur(4px);
85
+ }
86
+ }
87
+
88
+ &:before {
89
+ content: '';
90
+ position: absolute;
91
+ top: 2px;
92
+ left: 2px;
93
+ right: 2px;
94
+ bottom: 2px;
95
+ border-radius: 50%;
96
+ border-width: 2px 2px 0 0;
97
+ border-style: solid;
98
+ border-color: $primary transparent;
99
+ }
100
+
101
+ &:after {
102
+ content: '';
103
+ position: absolute;
104
+ left: 0;
105
+ top: 0;
106
+ right: 0;
107
+ bottom: 0;
108
+ background: linear-gradient(0deg, transparent 60%, rgba($primary, 0.4));
109
+ filter: blur(4px);
110
+ animation: spinner-blur 3s infinite;
111
+ }
112
+ }
113
+
114
+ &:hover:not(&--disabled) {
115
+ .y-switch__thumb {
116
+ //background: map-get($light-theme, 'hover-bg');
117
+ }
118
+ }
119
+
120
+ &--active {
121
+ .y-switch__track {
122
+ background-color: $primary;
123
+ }
124
+
125
+ .y-switch__thumb {
126
+ left: 1.7em;
127
+ //transform: translateX(1.6em);
128
+ }
129
+ }
130
+ &--active:not(&--loading):active &__thumb {
131
+ //left: 0.2em;
132
+ left: 1.8em;
133
+ }
134
+
135
+ &--focused {
136
+ .y-switch__thumb:before {
137
+ content: '';
138
+ position: absolute;
139
+ top: 2px;
140
+ bottom: 2px;
141
+ left: 2px;
142
+ right: 2px;
143
+ border-radius: 50%;
144
+ background-color: rgba($primary, 0.4);
145
+ }
146
+ }
147
+
148
+ &--stick-out {
149
+ .y-switch__thumb {
150
+ box-shadow: 0 1px 4px 1px rgba(0, 0, 0, 0.32);
151
+ }
152
+
153
+ .y-switch__track {
154
+ width: 90%;
155
+ height: 80%;
156
+ left: 5%;
157
+ top: 12%;
158
+ box-shadow: inset 0 0 4px 0 rgba(0, 0, 0, 0.4);
159
+ }
160
+ }
161
+
162
+ &--disabled {
163
+ opacity: 0.8;
164
+ filter: brightness(0.88);
165
+
166
+ .y-switch__thumb {
167
+ opacity: 0.4;
168
+ }
169
+ }
170
+ &--disabled &__slot,
171
+ &--disabled &__input input {
172
+ cursor: default;
173
+ }
174
+
175
+ &__state {
176
+ position: relative;
177
+ width: 100%;
178
+ height: 100%;
179
+ contain: content;
180
+ }
181
+
182
+ &__state-label {
183
+ font-size: 12px;
184
+ color: #ffffff;
185
+ position: absolute;
186
+ height: 100%;
187
+ display: flex;
188
+ align-items: center;
189
+ transition: transform 180ms cubic-bezier(0.16, 0.85, 0.36, 0.96);
190
+
191
+ &--on {
192
+ left: -40px;
193
+ }
194
+ &--off {
195
+ right: 10px;
196
+ }
197
+ }
198
+
199
+ &--active &__state-label {
200
+ transform: translateX(50px);
201
+ }
202
+
203
+ &--stick-out &__state-label--off {
204
+ right: 7px;
205
+ }
206
+ }
@@ -0,0 +1,5 @@
1
+ /*!
2
+ * Created by yeonyu 2022.
3
+ */
4
+
5
+ @import 'packages/yuyeon/src/components/text-highlighter/y-text-highlighter';
@@ -0,0 +1,3 @@
1
+ import YTextHighlighter from './y-text-highlighter';
2
+
3
+ export { YTextHighlighter };
@@ -0,0 +1,7 @@
1
+ .y-text-highlighter {
2
+ &__item {
3
+ &--highlight {
4
+ background-color: #ffff00;
5
+ }
6
+ }
7
+ }
@@ -0,0 +1,89 @@
1
+ import { VNode, defineComponent, h } from 'vue';
2
+ // style
3
+ import './index.scss';
4
+
5
+ export default defineComponent({
6
+ name: 'y-text-highlighter',
7
+ props: {
8
+ text: {
9
+ type: String,
10
+ },
11
+ keyword: {
12
+ type: String,
13
+ },
14
+ color: {
15
+ type: String,
16
+ },
17
+ sensitive: {
18
+ type: Boolean,
19
+ },
20
+ },
21
+ computed: {
22
+ splitText(): { text: string; isKeyword: boolean }[] {
23
+ const { keyword, text } = this;
24
+ if (keyword && text) {
25
+ const split: { text: string; isKeyword: boolean }[] = [];
26
+ let stack = text;
27
+ const keyExp = new RegExp(keyword, this.sensitive ? '' : 'i');
28
+ while (stack.length > 0) {
29
+ const index = stack.search(keyExp);
30
+ if (index < 0) {
31
+ split.push({ text: stack, isKeyword: false });
32
+ stack = '';
33
+ } else if (index < 1) {
34
+ split.push({
35
+ text: stack.substring(0, keyword.length),
36
+ isKeyword: true,
37
+ });
38
+ stack = stack.substring(keyword.length, stack.length);
39
+ } else {
40
+ split.push({ text: stack.substring(0, index), isKeyword: false });
41
+ split.push({
42
+ text: stack.substring(index, index + keyword.length),
43
+ isKeyword: true,
44
+ });
45
+ stack = stack.substring(index + keyword.length, stack.length);
46
+ }
47
+ }
48
+ return split;
49
+ }
50
+ return [{ text: this.text || '', isKeyword: false }];
51
+ },
52
+ },
53
+ methods: {
54
+ createItem(text: string): VNode {
55
+ return h(
56
+ 'span',
57
+ {
58
+ staticClass: 'y-text-highlighter__item',
59
+ },
60
+ [text],
61
+ );
62
+ },
63
+ createHighlightKeywordItem(text: string): VNode {
64
+ return h(
65
+ 'span',
66
+ {
67
+ staticClass: 'y-text-highlighter__item',
68
+ class: 'y-text-highlighter__item--highlight',
69
+ style: {
70
+ backgroundColor: this.color,
71
+ },
72
+ },
73
+ [text],
74
+ );
75
+ },
76
+ createSplitTexts(): VNode[] {
77
+ return this.splitText.map((splitItem) => {
78
+ if (splitItem.isKeyword) {
79
+ return this.createHighlightKeywordItem(splitItem.text);
80
+ }
81
+ return this.createItem(splitItem.text);
82
+ });
83
+ },
84
+ },
85
+ render(): VNode {
86
+ const children = this.createSplitTexts();
87
+ return h('span', { staticClass: 'y-text-highlighter' }, children);
88
+ },
89
+ });
@@ -0,0 +1,31 @@
1
+ import { computed } from 'vue';
2
+
3
+ import type { Ref } from 'vue';
4
+
5
+ export const Y_LAYER_GROUP_CLASS_NAME = 'y-layer-group';
6
+
7
+ export function useLayerGroup(target?: Ref<string | Element>) {
8
+ const layerGroup = computed(() => {
9
+ const refTarget = target?.value;
10
+ let targetEl: Element = document.body;
11
+ if (typeof refTarget === 'string') {
12
+ const el = document.querySelector(refTarget);
13
+ if (el) {
14
+ targetEl = el;
15
+ }
16
+ }
17
+ if (refTarget && (refTarget as Element).nodeType === 1) {
18
+ targetEl = refTarget as Element;
19
+ }
20
+ //
21
+ let layerEl = targetEl.querySelector(`.${Y_LAYER_GROUP_CLASS_NAME}`);
22
+ if (!layerEl) {
23
+ layerEl = document.createElement('div');
24
+ layerEl.className = Y_LAYER_GROUP_CLASS_NAME;
25
+ targetEl.appendChild(layerEl);
26
+ }
27
+ return layerEl;
28
+ });
29
+
30
+ return { layerGroup };
31
+ }
@@ -0,0 +1,30 @@
1
+ import { computed, Ref, ref, watch } from "vue";
2
+
3
+ export function useLazy(eager: boolean, updated: Ref<any>) {
4
+ const tick = ref(false);
5
+ const tack = ref();
6
+ tack.value = updated.value;
7
+ const lazyValue = computed(() => {
8
+ if (eager) return updated.value;
9
+ return tack.value;
10
+ });
11
+ watch(updated, () => {
12
+ if (!tick.value) {
13
+ tack.value = updated.value;
14
+ }
15
+ if (!eager) {
16
+ tick.value = true
17
+ }
18
+ });
19
+ function onAfterUpdate() {
20
+ tack.value = updated.value;
21
+ if (!eager) {
22
+ tick.value = false;
23
+ }
24
+ }
25
+ return {
26
+ entered: tick,
27
+ lazyValue,
28
+ onAfterUpdate,
29
+ }
30
+ }
@@ -0,0 +1,19 @@
1
+ import { computed } from 'vue';
2
+
3
+ export function useProgress(props: any) {
4
+ const numValue = computed(() => {
5
+ const { value } = props;
6
+ const numValue = Number(value);
7
+ if (Number.isNaN(numValue) || numValue < 0) {
8
+ return 0;
9
+ }
10
+ if (numValue > 100) {
11
+ return 100;
12
+ }
13
+ return numValue;
14
+ });
15
+
16
+ return {
17
+ numValue,
18
+ };
19
+ }
@@ -0,0 +1,25 @@
1
+ import { App } from 'vue';
2
+
3
+ export const Y_THEME_PREFIX = 'y-theme';
4
+
5
+ const defaultThemeTemplates: any = {
6
+ light: {
7
+ dark: false,
8
+ palette: {
9
+ background: '#ffffff',
10
+ 'font-color': '#323232',
11
+ },
12
+ variables: {
13
+ //
14
+ },
15
+ },
16
+ };
17
+
18
+ export function bindTheme(options: any) {
19
+ function install(app: App) {
20
+ //
21
+ }
22
+ return {
23
+ install,
24
+ };
25
+ }
@@ -0,0 +1,123 @@
1
+ import { DirectiveBinding } from 'vue';
2
+ import { documentRoot } from '../../util/dom';
3
+
4
+ interface ComplementClickDirectiveElementImplanted {
5
+ onClick: EventListener;
6
+ onMousedown: EventListener;
7
+ }
8
+
9
+ declare global {
10
+ interface Element {
11
+ _complementClick?: Record<
12
+ number,
13
+ ComplementClickDirectiveElementImplanted | undefined
14
+ > & { lastMousedownWasOutside: boolean };
15
+ }
16
+ }
17
+
18
+ export interface ComplementClickBindingOptions {
19
+ handler: (mouseEvent: MouseEvent) => void;
20
+ determine?: (event: Event) => boolean;
21
+ include?: () => HTMLElement[];
22
+ }
23
+
24
+ export interface ComplementClickBinding extends DirectiveBinding {
25
+ value: ((mouseEvent: MouseEvent) => void) | ComplementClickBindingOptions;
26
+ }
27
+
28
+ function defaultDetermine() {
29
+ return true;
30
+ }
31
+
32
+ function directive(
33
+ mouseEvent: MouseEvent,
34
+ element: HTMLElement,
35
+ binding: ComplementClickBinding,
36
+ ) {
37
+ const { value } = binding;
38
+ const handler = typeof value === 'function' ? value : value.handler;
39
+ element._complementClick!.lastMousedownWasOutside &&
40
+ checkEvent(mouseEvent, element, binding) &&
41
+ setTimeout(() => {
42
+ determine(mouseEvent, binding) && handler && handler(mouseEvent);
43
+ }, 0);
44
+ }
45
+
46
+ function checkEvent(
47
+ mouseEvent: MouseEvent,
48
+ element: HTMLElement,
49
+ binding: ComplementClickBinding,
50
+ ): boolean {
51
+ if (!mouseEvent || determine(mouseEvent, binding) === false) {
52
+ return false;
53
+ }
54
+ const root = documentRoot(element);
55
+ if (typeof ShadowRoot !== 'undefined' && root instanceof ShadowRoot && root.host === mouseEvent.target) {
56
+ return false;
57
+ }
58
+ const elements = ((typeof binding.value === 'object' && binding.value.include) || (() => []))();
59
+ elements.push(element);
60
+ return !elements.some((el) => el?.contains(mouseEvent.target as Node));
61
+ }
62
+
63
+ function determine(
64
+ event: MouseEvent,
65
+ binding: ComplementClickBinding,
66
+ ): boolean {
67
+ const { value } = binding;
68
+ const determineFn =
69
+ (typeof value === 'object' && value.determine) || defaultDetermine;
70
+ return determineFn && determineFn?.(event);
71
+ }
72
+
73
+ function implant(
74
+ element: HTMLElement,
75
+ callback: (app: HTMLDocument | ShadowRoot | null) => void,
76
+ ) {
77
+ const root = documentRoot(element);
78
+ callback(document);
79
+ if (typeof ShadowRoot !== 'undefined' && root instanceof ShadowRoot) {
80
+ callback(root);
81
+ }
82
+ }
83
+
84
+ export const ComplementClick = {
85
+ mounted(element: HTMLElement, binding: ComplementClickBinding) {
86
+ const onClick = (event: Event) =>
87
+ directive(event as MouseEvent, element, binding);
88
+ const onMousedown = (event: Event) => {
89
+ element._complementClick!.lastMousedownWasOutside = checkEvent(
90
+ event as MouseEvent,
91
+ element,
92
+ binding,
93
+ );
94
+ };
95
+ implant(element, (app) => {
96
+ app?.addEventListener('click', onClick, true);
97
+ app?.addEventListener('mousedown', onMousedown, true);
98
+ });
99
+ if (!element._complementClick) {
100
+ element._complementClick = {
101
+ lastMousedownWasOutside: true,
102
+ };
103
+ }
104
+ const _uid = binding.instance!.$.uid;
105
+ element._complementClick[_uid] = {
106
+ onClick,
107
+ onMousedown,
108
+ };
109
+ },
110
+ unmounted(element: HTMLElement, binding: ComplementClickBinding) {
111
+ if (!element._complementClick) return;
112
+ const _uid = binding.instance!.$.uid;
113
+ implant(element, (app) => {
114
+ const old = element._complementClick?.[_uid];
115
+ if (old) {
116
+ const { onClick, onMousedown } = old;
117
+ app?.removeEventListener('click', onClick, true);
118
+ app?.removeEventListener('mousedown', onMousedown, true);
119
+ }
120
+ });
121
+ delete element._complementClick[_uid];
122
+ },
123
+ };
@@ -0,0 +1,114 @@
1
+ import './plate-wave.scss';
2
+
3
+ import type { DirectiveBinding } from 'vue';
4
+
5
+ export interface PlateWaveBinding
6
+ extends Omit<DirectiveBinding, 'modifiers' | 'value'> {
7
+ value?: boolean;
8
+ modifiers: { stop?: boolean };
9
+ }
10
+
11
+ const CLASS_NAME = 'y-plate-wave__animation';
12
+
13
+ function showAnimation(el: HTMLElement | null) {
14
+ if (!el) return;
15
+ const animation = document.createElement('span');
16
+ animation.className = CLASS_NAME;
17
+ el.appendChild(animation);
18
+ animation.dataset.activated = String(performance.now());
19
+ }
20
+
21
+ function hideAnimation(el: HTMLElement | null) {
22
+ if (!el) {
23
+ return;
24
+ }
25
+ const animations = el.getElementsByClassName(CLASS_NAME);
26
+ if (animations.length === 0) return;
27
+ const animation = animations[animations.length - 1] as HTMLElement;
28
+ if (animation.dataset.isHiding) return;
29
+ animation.dataset.isHiding = 'true';
30
+ const diff = performance.now() - Number(animation.dataset.activated);
31
+ const delay = Math.max(250 - diff, 0);
32
+ setTimeout(() => {
33
+ if (animation) {
34
+ el.removeChild(animation);
35
+ }
36
+ }, delay + 300);
37
+ }
38
+
39
+ /*
40
+ * Event
41
+ * */
42
+
43
+ let keyboardEventFlag = false;
44
+
45
+ function spawn(event: Event) {
46
+ showAnimation(event.currentTarget as HTMLElement);
47
+ }
48
+
49
+ function clean(event: Event) {
50
+ hideAnimation(event.currentTarget as HTMLElement);
51
+ }
52
+
53
+ function stop(event: Event) {
54
+ //
55
+ }
56
+
57
+ function keyboardSpawn(event: KeyboardEvent) {
58
+ if (!keyboardEventFlag && (event.key === 'Enter' || event.key === 'Space')) {
59
+ keyboardEventFlag = true;
60
+ showAnimation(event.currentTarget as HTMLElement);
61
+ }
62
+ }
63
+
64
+ function keyboardClean(event: KeyboardEvent) {
65
+ keyboardEventFlag = false;
66
+ hideAnimation(event.currentTarget as HTMLElement);
67
+ }
68
+
69
+ function destroyListeners(el: HTMLElement) {
70
+ el.removeEventListener('mousedown', spawn);
71
+ el.removeEventListener('mouseup', clean);
72
+ el.removeEventListener('mouseleave', clean);
73
+ el.removeEventListener('keydown', keyboardSpawn);
74
+ el.removeEventListener('keyup', keyboardClean);
75
+ }
76
+
77
+ function attachWave(el: HTMLElement, binding: PlateWaveBinding, init = false) {
78
+ const { value, modifiers } = binding;
79
+ const enabled = !!value;
80
+ if (!enabled) hideAnimation(el);
81
+
82
+ if (enabled && init) {
83
+ if (modifiers.stop) {
84
+ el.addEventListener('mousedown', stop);
85
+ return;
86
+ }
87
+
88
+ el.addEventListener('mousedown', spawn);
89
+ el.addEventListener('mouseup', clean);
90
+ el.addEventListener('mouseleave', clean);
91
+ el.addEventListener('keydown', keyboardSpawn);
92
+ el.addEventListener('keyup', keyboardClean);
93
+ el.addEventListener('blur', clean);
94
+ } else if (!enabled && !init) {
95
+ destroyListeners(el);
96
+ }
97
+ }
98
+
99
+ export const PlateWave = {
100
+ mounted(el: HTMLElement, binding: PlateWaveBinding) {
101
+ attachWave(el, binding, true);
102
+ },
103
+ updated(el: HTMLElement, binding: PlateWaveBinding) {
104
+ if (binding.value === binding.oldValue) {
105
+ return;
106
+ }
107
+ attachWave(el, binding);
108
+ },
109
+ unmount(el: HTMLElement) {
110
+ destroyListeners(el);
111
+ },
112
+ };
113
+
114
+ export default PlateWave;
@@ -0,0 +1,33 @@
1
+ .y-plate-wave {
2
+ &__animation {
3
+ color: inherit;
4
+ position: absolute;
5
+ top: 0;
6
+ left: 0;
7
+ right: 0;
8
+ bottom: 0;
9
+ width: 100%;
10
+ height: 100%;
11
+ opacity: 0;
12
+ pointer-events: none;
13
+ overflow: hidden;
14
+ border: 1px solid currentColor;
15
+ border-radius: inherit;
16
+ will-change: transform, opacity;
17
+ animation: plate-wave 250ms ease;
18
+ }
19
+ }
20
+
21
+ @keyframes plate-wave {
22
+ 0% {
23
+ opacity: 0;
24
+ transform: scale(0.8);
25
+ }
26
+ 80% {
27
+ opacity: 0.4;
28
+ }
29
+ 100% {
30
+ opacity: 0;
31
+ transform: scale(1);
32
+ }
33
+ }
@@ -0,0 +1,14 @@
1
+ import { FunctionDirective } from 'vue';
2
+
3
+ const bindThemeClass: FunctionDirective = (el, binding) => {
4
+ const themeName = binding.value;
5
+ const themeClass = `theme--${themeName}`;
6
+ el.classList.forEach((classToken: string) => {
7
+ if (classToken.startsWith('theme--') && classToken !== themeClass) {
8
+ el.classList.remove(classToken);
9
+ }
10
+ });
11
+ el.classList.add(themeClass);
12
+ };
13
+
14
+ export default bindThemeClass;