mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat(core): add mute button component (#455)
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
export { applyElementProps } from './element-props';
|
||||
export { logMissingFeature } from './log';
|
||||
export type { StateAttrMap } from './state-data-attrs';
|
||||
export { applyStateDataAttrs, getStateDataAttrs } from './state-data-attrs';
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
export type StateAttrMap<State> = {
|
||||
[Key in keyof State]?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert state object to data attributes.
|
||||
*
|
||||
@@ -11,17 +15,23 @@
|
||||
* getStateDataAttrs(state);
|
||||
* // { 'data-paused': '', 'data-volume': '0.5' }
|
||||
* ```
|
||||
*
|
||||
* When a mapping is provided, only mapped keys are converted.
|
||||
*/
|
||||
export function getStateDataAttrs<State extends object>(state: State): Record<string, string> {
|
||||
export function getStateDataAttrs<State extends object>(
|
||||
state: State,
|
||||
map?: StateAttrMap<State>
|
||||
): Record<string, string> {
|
||||
const attrs: Record<string, string> = {};
|
||||
|
||||
for (const key in state) {
|
||||
const value = state[key];
|
||||
const name = map?.[key] ?? toDataAttrName(key),
|
||||
value = state[key];
|
||||
|
||||
if (value === true) {
|
||||
attrs[`data-${key.toLowerCase()}`] = '';
|
||||
attrs[name] = '';
|
||||
} else if (value) {
|
||||
attrs[`data-${key.toLowerCase()}`] = String(value);
|
||||
attrs[name] = String(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,17 +52,25 @@ export function getStateDataAttrs<State extends object>(state: State): Record<st
|
||||
* // element has data-paused="", data-ended is removed
|
||||
* ```
|
||||
*/
|
||||
export function applyStateDataAttrs<State extends object>(element: HTMLElement, state: State): void {
|
||||
export function applyStateDataAttrs<State extends object>(
|
||||
element: HTMLElement,
|
||||
state: State,
|
||||
map?: StateAttrMap<State>
|
||||
): void {
|
||||
for (const key in state) {
|
||||
const value = state[key];
|
||||
const attrName = `data-${key.toLowerCase()}`;
|
||||
const name = map?.[key] ?? toDataAttrName(key),
|
||||
value = state[key];
|
||||
|
||||
if (value === true) {
|
||||
element.setAttribute(attrName, '');
|
||||
element.setAttribute(name, '');
|
||||
} else if (value) {
|
||||
element.setAttribute(attrName, String(value));
|
||||
element.setAttribute(name, String(value));
|
||||
} else {
|
||||
element.removeAttribute(attrName);
|
||||
element.removeAttribute(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toDataAttrName(key: string): string {
|
||||
return `data-${key.toLowerCase()}`;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,29 @@ describe('getStateDataAttrs', () => {
|
||||
const state = { label: '' };
|
||||
expect(getStateDataAttrs(state)).toEqual({});
|
||||
});
|
||||
|
||||
it('supports explicit attribute mapping', () => {
|
||||
const state = { muted: true, volumeLevel: 'low' };
|
||||
const mapping = {
|
||||
muted: 'data-muted',
|
||||
volumeLevel: 'data-volume-level',
|
||||
};
|
||||
|
||||
expect(getStateDataAttrs(state, mapping)).toEqual({
|
||||
'data-muted': '',
|
||||
'data-volume-level': 'low',
|
||||
});
|
||||
});
|
||||
|
||||
it('allows unmapped keys when mapping is provided', () => {
|
||||
const state = { muted: true, volumeLevel: 'low' };
|
||||
const mapping = { muted: 'data-muted' };
|
||||
|
||||
expect(getStateDataAttrs(state, mapping)).toEqual({
|
||||
'data-muted': '',
|
||||
'data-volumelevel': 'low',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('applyStateDataAttrs', () => {
|
||||
@@ -134,4 +157,17 @@ describe('applyStateDataAttrs', () => {
|
||||
expect(element.hasAttribute('data-ended')).toBe(true);
|
||||
expect(element.hasAttribute('data-volume')).toBe(false);
|
||||
});
|
||||
|
||||
it('removes mapped attributes when values become falsy', () => {
|
||||
const element = document.createElement('div');
|
||||
const mapping = { muted: 'data-muted', volumeLevel: 'data-volume-level' };
|
||||
|
||||
applyStateDataAttrs(element, { muted: true, volumeLevel: 'high' }, mapping);
|
||||
expect(element.getAttribute('data-muted')).toBe('');
|
||||
expect(element.getAttribute('data-volume-level')).toBe('high');
|
||||
|
||||
applyStateDataAttrs(element, { muted: false, volumeLevel: '' }, mapping);
|
||||
expect(element.hasAttribute('data-muted')).toBe(false);
|
||||
expect(element.hasAttribute('data-volume-level')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user