@htlkg/components 0.0.1 → 0.0.2

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,33 @@
1
+ /**
2
+ * User Store
3
+ *
4
+ * Nanostore for sharing user data across components
5
+ * without props (lower hydration cost)
6
+ */
7
+
8
+ import { atom } from 'nanostores';
9
+
10
+ export interface User {
11
+ username?: string;
12
+ email?: string;
13
+ avatar?: string;
14
+ isAdmin?: boolean;
15
+ attributes?: {
16
+ email?: string;
17
+ [key: string]: any;
18
+ };
19
+ [key: string]: any;
20
+ }
21
+
22
+ // User store
23
+ export const $user = atom<User | null>(null);
24
+
25
+ // Helper function to set user
26
+ export function setUser(user: User | null) {
27
+ $user.set(user);
28
+ }
29
+
30
+ // Helper function to clear user
31
+ export function clearUser() {
32
+ $user.set(null);
33
+ }
@@ -0,0 +1,235 @@
1
+ import { config } from '@vue/test-utils';
2
+ import { h, defineComponent } from 'vue';
3
+
4
+ // Stub for uiInput from @hotelinking/ui
5
+ const uiInputStub = defineComponent({
6
+ name: 'uiInput',
7
+ props: ['name', 'label', 'type', 'value', 'placeholder', 'error', 'color', 'loading', 'requiredText', 'min', 'max', 'autocomplete'],
8
+ emits: ['input-changed'],
9
+ setup(props, { emit }) {
10
+ return () => h('div', { class: 'ui-input' }, [
11
+ props.label && h('label', props.label),
12
+ h('input', {
13
+ name: props.name,
14
+ value: props.value,
15
+ type: props.type || 'text',
16
+ placeholder: props.placeholder,
17
+ disabled: props.loading,
18
+ onInput: (e: Event) => emit('input-changed', { value: (e.target as HTMLInputElement).value })
19
+ }),
20
+ props.error && h('span', { class: 'error' }, props.error)
21
+ ]);
22
+ }
23
+ });
24
+
25
+ // Stub for uiSelect from @hotelinking/ui
26
+ const uiSelectStub = defineComponent({
27
+ name: 'uiSelect',
28
+ props: ['label', 'items', 'select', 'placeholder', 'error', 'color', 'loading', 'requiredText'],
29
+ emits: ['select-changed'],
30
+ setup(props, { emit }) {
31
+ return () => h('div', { class: 'ui-select' }, [
32
+ props.label && h('label', props.label),
33
+ h('select', {
34
+ value: props.select?.id,
35
+ disabled: props.loading,
36
+ onChange: (e: Event) => {
37
+ const value = (e.target as HTMLSelectElement).value;
38
+ const item = props.items?.find((i: any) => i.id === value);
39
+ emit('select-changed', item);
40
+ }
41
+ }, props.items?.map((opt: any) =>
42
+ h('option', { value: opt.id }, opt.label || opt.name)
43
+ )),
44
+ props.error && h('span', { class: 'error' }, props.error)
45
+ ]);
46
+ }
47
+ });
48
+
49
+ // Stub for uiToggle from @hotelinking/ui
50
+ const uiToggleStub = defineComponent({
51
+ name: 'uiToggle',
52
+ props: ['item', 'checked', 'loading'],
53
+ emits: ['toggle-changed'],
54
+ setup(props, { emit }) {
55
+ return () => h('div', { class: 'ui-toggle' }, [
56
+ h('input', {
57
+ type: 'checkbox',
58
+ checked: props.checked,
59
+ disabled: props.loading,
60
+ onChange: (e: Event) => emit('toggle-changed', { active: (e.target as HTMLInputElement).checked })
61
+ }),
62
+ props.item?.title && h('label', props.item.title)
63
+ ]);
64
+ }
65
+ });
66
+
67
+ // Stub for uiTextArea from @hotelinking/ui
68
+ const uiTextAreaStub = defineComponent({
69
+ name: 'uiTextArea',
70
+ props: ['name', 'label', 'value', 'placeholder', 'error', 'color', 'loading', 'requiredText', 'rows'],
71
+ emits: ['input-changed'],
72
+ setup(props, { emit }) {
73
+ return () => h('div', { class: 'ui-textarea' }, [
74
+ props.label && h('label', props.label),
75
+ h('textarea', {
76
+ name: props.name,
77
+ value: props.value,
78
+ placeholder: props.placeholder,
79
+ disabled: props.loading,
80
+ rows: props.rows,
81
+ onInput: (e: Event) => emit('input-changed', { value: (e.target as HTMLTextAreaElement).value })
82
+ }),
83
+ props.error && h('span', { class: 'error' }, props.error)
84
+ ]);
85
+ }
86
+ });
87
+
88
+ // Stub for uiRangeSlider from @hotelinking/ui
89
+ const uiRangeSliderStub = defineComponent({
90
+ name: 'uiRangeSlider',
91
+ props: ['label', 'min', 'max', 'sliderValue', 'loading', 'requiredText'],
92
+ emits: ['sliderUpdated'],
93
+ setup(props, { emit }) {
94
+ return () => h('div', { class: 'ui-slider' }, [
95
+ props.label && h('label', props.label),
96
+ h('input', {
97
+ type: 'range',
98
+ value: props.sliderValue,
99
+ min: props.min,
100
+ max: props.max,
101
+ disabled: props.loading,
102
+ onInput: (e: Event) => emit('sliderUpdated', Number((e.target as HTMLInputElement).value))
103
+ })
104
+ ]);
105
+ }
106
+ });
107
+
108
+ // Stub for uiButton from @hotelinking/ui
109
+ const uiButtonStub = defineComponent({
110
+ name: 'uiButton',
111
+ props: ['type', 'color', 'loading', 'disabled'],
112
+ setup(props, { slots }) {
113
+ return () => h('button', {
114
+ class: 'ui-button',
115
+ type: props.type || 'button',
116
+ disabled: props.disabled || props.loading
117
+ }, slots.default?.());
118
+ }
119
+ });
120
+
121
+ // Stub for uiAlert from @hotelinking/ui
122
+ const uiAlertStub = defineComponent({
123
+ name: 'uiAlert',
124
+ props: ['title', 'type', 'actions', 'loading'],
125
+ emits: ['alert-event'],
126
+ setup(props, { slots, emit }) {
127
+ return () => h('div', { class: 'ui-alert', 'data-type': props.type }, [
128
+ h('div', { class: 'alert-title' }, props.title),
129
+ slots.default?.(),
130
+ props.actions?.map((action: any) =>
131
+ h('button', {
132
+ class: 'alert-action',
133
+ onClick: () => emit('alert-event', action.event)
134
+ }, action.name)
135
+ )
136
+ ]);
137
+ }
138
+ });
139
+
140
+ // Stub for uiModal from @hotelinking/ui
141
+ const uiModalStub = defineComponent({
142
+ name: 'UiModal',
143
+ props: ['title', 'content', 'modalName', 'open', 'actions'],
144
+ emits: ['modalAction'],
145
+ setup(props, { slots, emit }) {
146
+ return () => props.open ? h('div', { class: 'ui-modal' }, [
147
+ h('div', { class: 'modal-title' }, props.title),
148
+ h('div', { class: 'modal-content' }, props.content),
149
+ slots.default?.(),
150
+ slots.header?.(),
151
+ slots.footer?.(),
152
+ props.actions?.map((action: any) =>
153
+ h('button', {
154
+ class: 'modal-action',
155
+ onClick: () => emit('modalAction', { modal: props.modalName, action: action.value })
156
+ }, action.text)
157
+ )
158
+ ]) : null;
159
+ }
160
+ });
161
+
162
+ // Stub for uiTag from @hotelinking/ui
163
+ const uiTagStub = defineComponent({
164
+ name: 'uiTag',
165
+ props: ['color', 'size'],
166
+ setup(props, { slots }) {
167
+ return () => h('span', {
168
+ class: `ui-tag ui-tag-${props.color || 'gray'}`
169
+ }, slots.default?.());
170
+ }
171
+ });
172
+
173
+ // Stub for uiAvatar from @hotelinking/ui
174
+ const uiAvatarStub = defineComponent({
175
+ name: 'uiAvatar',
176
+ props: ['src', 'alt', 'size', 'initials'],
177
+ setup(props) {
178
+ return () => h('div', { class: 'ui-avatar' }, [
179
+ props.src
180
+ ? h('img', { src: props.src, alt: props.alt })
181
+ : h('span', { class: 'initials' }, props.initials)
182
+ ]);
183
+ }
184
+ });
185
+
186
+ // Register global stubs
187
+ config.global.stubs = {
188
+ uiAlert: uiAlertStub,
189
+ uiModal: uiModalStub,
190
+ UiModal: uiModalStub,
191
+ uiButton: uiButtonStub,
192
+ uiInput: uiInputStub,
193
+ uiToggle: uiToggleStub,
194
+ uiSelect: uiSelectStub,
195
+ uiRangeSlider: uiRangeSliderStub,
196
+ uiTextArea: uiTextAreaStub,
197
+ uiTag: uiTagStub,
198
+ uiAvatar: uiAvatarStub,
199
+ };
200
+
201
+ // Mock ResizeObserver
202
+ if (typeof global.ResizeObserver === 'undefined') {
203
+ global.ResizeObserver = class ResizeObserver {
204
+ observe() {}
205
+ unobserve() {}
206
+ disconnect() {}
207
+ };
208
+ }
209
+
210
+ // Mock IntersectionObserver
211
+ if (typeof global.IntersectionObserver === 'undefined') {
212
+ global.IntersectionObserver = class IntersectionObserver {
213
+ constructor() {}
214
+ observe() {}
215
+ unobserve() {}
216
+ disconnect() {}
217
+ root = null;
218
+ rootMargin = '';
219
+ thresholds = [];
220
+ takeRecords() { return []; }
221
+ };
222
+ }
223
+
224
+ export {
225
+ uiAlertStub,
226
+ uiModalStub,
227
+ uiButtonStub,
228
+ uiInputStub,
229
+ uiToggleStub,
230
+ uiSelectStub,
231
+ uiRangeSliderStub,
232
+ uiTextAreaStub,
233
+ uiTagStub,
234
+ uiAvatarStub
235
+ };