-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
301 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"@fessional/razor-common": patch | ||
"@fessional/razor-mobile": patch | ||
--- | ||
|
||
✨ utils for element interact #51 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { mount } from '@vue/test-utils'; | ||
import { describe, it, expect } from 'vitest'; | ||
import DpiImg from '../components/DpiImg.vue'; | ||
|
||
describe('DpiImg', () => { | ||
it('renders the correct src and srcset attributes', () => { | ||
const props = { | ||
alt: 'Sample image', | ||
srcset: ['image1.jpg', 'image2.jpg', 'image3.jpg'], | ||
}; | ||
|
||
const wrapper = mount(DpiImg, { | ||
props, | ||
}); | ||
|
||
const img = wrapper.find('img'); | ||
expect(img.exists()).toBe(true); | ||
|
||
expect(img.attributes('src')).toBe('image1.jpg'); | ||
|
||
const expectedSrcset = 'image1.jpg 1x, image2.jpg 2x, image3.jpg 3x'; | ||
expect(img.attributes('srcset')).toBe(expectedSrcset); | ||
|
||
expect(img.attributes('alt')).toBe(props.alt); | ||
}); | ||
|
||
it('renders with default alt when none is provided', () => { | ||
const props = { | ||
srcset: ['image1.jpg', 'image2.jpg'], | ||
}; | ||
|
||
const wrapper = mount(DpiImg, { | ||
props, | ||
}); | ||
|
||
const img = wrapper.find('img'); | ||
|
||
expect(img.attributes('alt')).toBe(undefined); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { describe, it, expect, vi } from 'vitest'; | ||
import { ref, nextTick } from 'vue'; | ||
import { selectElement, focusElement, scrollElement } from '../utils/vue-element'; | ||
|
||
describe('selectElement', () => { | ||
it('should return the element by id', () => { | ||
const mockElement = document.createElement('div'); | ||
mockElement.id = 'test-element'; | ||
document.body.appendChild(mockElement); | ||
|
||
const result = selectElement('test-element'); | ||
expect(result).toBe(mockElement); | ||
|
||
// Clean up | ||
document.body.removeChild(mockElement); | ||
}); | ||
|
||
it('should return the element from Ref', () => { | ||
const mockElement = document.createElement('div'); | ||
const mockRef = ref({ $el: mockElement }); | ||
|
||
const result = selectElement(mockRef); | ||
expect(result).toBe(mockElement); | ||
}); | ||
}); | ||
|
||
describe('focusElement', () => { | ||
it('should call setFocus if the method exists', async () => { | ||
const mockElement = { | ||
setFocus: vi.fn(), | ||
scrollIntoView: vi.fn(), | ||
}; | ||
const mockRef = ref({ $el: mockElement }); | ||
|
||
await focusElement(mockRef); | ||
await nextTick(); // wait for nextTick | ||
|
||
expect(mockElement.setFocus).toHaveBeenCalled(); | ||
expect(mockElement.scrollIntoView).toHaveBeenCalledWith({ behavior: 'smooth', block: 'center' }); | ||
}); | ||
|
||
it('should call focus if setFocus does not exist', async () => { | ||
const mockElement = { | ||
focus: vi.fn(), | ||
scrollIntoView: vi.fn(), | ||
}; | ||
const mockRef = ref({ $el: mockElement }); | ||
|
||
await focusElement(mockRef); | ||
await nextTick(); // wait for nextTick | ||
|
||
expect(mockElement.focus).toHaveBeenCalled(); | ||
expect(mockElement.scrollIntoView).toHaveBeenCalledWith({ behavior: 'smooth', block: 'center' }); | ||
}); | ||
}); | ||
|
||
describe('scrollElement', () => { | ||
it('should call scrollIntoView', async () => { | ||
const mockElement = { | ||
scrollIntoView: vi.fn(), | ||
}; | ||
const mockRef = ref({ $el: mockElement }); | ||
|
||
await scrollElement(mockRef); | ||
await nextTick(); // wait for nextTick | ||
|
||
expect(mockElement.scrollIntoView).toHaveBeenCalledWith({ behavior: 'smooth', block: 'center' }); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/** | ||
* select element by its ref or id | ||
* | ||
* @param element the element Ref or id | ||
* @returns the element | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export function selectElement(element: Ref<any> | string): HTMLElement & { setFocus?(): void } { | ||
return typeof element === 'string' | ||
? document.getElementById(element) | ||
: element.value.$el; | ||
} | ||
|
||
/** | ||
* focus the element and scroll it to center, support setFocus() method | ||
* @param element the element Ref or id | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export function focusElement(element: Ref<any> | string) { | ||
nextTick(() => { | ||
const ele = selectElement(element); | ||
|
||
if (typeof ele.setFocus === 'function') { | ||
ele.setFocus(); | ||
} | ||
else { | ||
ele.focus(); | ||
} | ||
|
||
ele.scrollIntoView({ behavior: 'smooth', block: 'center' }); | ||
}); | ||
} | ||
|
||
/** | ||
* scroll the element to center | ||
* @param element the element Ref or id | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export function scrollElement(element: Ref<any> | string) { | ||
nextTick(() => { | ||
const ele = selectElement(element); | ||
ele.scrollIntoView({ behavior: 'smooth', block: 'center' }); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Import testing utilities | ||
import { describe, it, expect, vi } from 'vitest'; | ||
import { ref } from 'vue'; | ||
import { validateIonicInput } from '../utils/ionic-validator'; | ||
|
||
// Mock Ionic IonInput component | ||
const mockClassList = { | ||
add: vi.fn(), | ||
remove: vi.fn(), | ||
}; | ||
|
||
const mockInputRef = ref({ | ||
$el: { | ||
classList: mockClassList, | ||
}, | ||
}); | ||
|
||
describe('validateIonicInput', () => { | ||
// Test case: valid input using regex pattern | ||
it('should add ion-valid class for valid input', () => { | ||
const validateFn = validateIonicInput(mockInputRef, /^[1-9][0-9]?$/); | ||
|
||
// Simulate valid input | ||
const inputEvent = { target: { value: '10' } } as unknown as Event; | ||
const result = validateFn(inputEvent); | ||
|
||
expect(result).toBe(true); | ||
expect(mockClassList.add).toHaveBeenCalledWith('ion-valid'); | ||
expect(mockClassList.remove).toHaveBeenCalledWith('ion-invalid'); | ||
}); | ||
|
||
// Test case: invalid input using regex pattern | ||
it('should add ion-invalid class for invalid input', () => { | ||
const validateFn = validateIonicInput(mockInputRef, /^[1-9][0-9]?$/); | ||
|
||
// Simulate invalid input | ||
const inputEvent = { target: { value: '100' } } as unknown as Event; | ||
const result = validateFn(inputEvent); | ||
|
||
expect(result).toBe(false); | ||
expect(mockClassList.add).toHaveBeenCalledWith('ion-invalid'); | ||
expect(mockClassList.remove).toHaveBeenCalledWith('ion-valid'); | ||
}); | ||
|
||
// Test case: input blur event | ||
it('should add ion-touched class on blur', () => { | ||
const validateFn = validateIonicInput(mockInputRef, /^[1-9][0-9]?$/); | ||
|
||
// Simulate blur event | ||
const blurEvent = new Event('blur'); | ||
const result = validateFn(blurEvent); | ||
|
||
expect(result).toBeNull(); | ||
expect(mockClassList.add).toHaveBeenCalledWith('ion-touched'); | ||
}); | ||
|
||
// Test case: direct string input | ||
it('should add ion-valid class for valid string input', () => { | ||
const validateFn = validateIonicInput(mockInputRef, /^[1-9][0-9]?$/); | ||
|
||
// Simulate valid string input | ||
const result = validateFn('5'); | ||
|
||
expect(result).toBe(true); | ||
expect(mockClassList.add).toHaveBeenCalledWith('ion-valid'); | ||
expect(mockClassList.remove).toHaveBeenCalledWith('ion-invalid'); | ||
}); | ||
|
||
// Test case: invalid string input | ||
it('should add ion-invalid class for invalid string input', () => { | ||
const validateFn = validateIonicInput(mockInputRef, /^[1-9][0-9]?$/); | ||
|
||
// Simulate invalid string input | ||
const result = validateFn('100'); | ||
|
||
expect(result).toBe(false); | ||
expect(mockClassList.add).toHaveBeenCalledWith('ion-invalid'); | ||
expect(mockClassList.remove).toHaveBeenCalledWith('ion-valid'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/** | ||
* ```tsx | ||
* <template> | ||
* <IonInput | ||
* ref="pkgInputRef" | ||
* v-model="pkgInput" | ||
* type="number" | ||
* error-text="need a positive number" | ||
* @ion-input="onPkgInput" | ||
* @ion-blur="onPkgInput" | ||
* /> | ||
* </template> | ||
* <script setup lang="ts"> | ||
* const pkgInputRef = ref(); | ||
* const onPkgInput = validateIonicInput(pkgInputRef, /^[1-9][0-9]?$/); | ||
* </script> | ||
* ``` | ||
* | ||
* generate a validator function for ionic input. | ||
* @param inputRef input ref | ||
* @param checkFun check function or regex | ||
*/ | ||
export function validateIonicInput( | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
inputRef: Ref<any>, | ||
checkFun: RegExp | ((value: string, event?: Event) => boolean), | ||
): (ev: Event | string) => boolean | null { | ||
return (ev: Event | string) => { | ||
const classList = inputRef.value.$el.classList; | ||
const isValue = typeof ev === 'string'; | ||
|
||
if (isValue || /blur/i.test(ev.type)) { | ||
classList.add('ion-touched'); | ||
if (!isValue) return null; | ||
} | ||
|
||
const value = isValue ? ev : (ev.target as HTMLInputElement).value; | ||
const valid = typeof checkFun === 'function' ? checkFun(value, isValue ? undefined : ev) : checkFun.test(value); | ||
|
||
if (valid) { | ||
classList.add('ion-valid'); | ||
classList.remove('ion-invalid'); | ||
} | ||
else { | ||
classList.remove('ion-valid'); | ||
classList.add('ion-invalid'); | ||
} | ||
|
||
return valid; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters