Skip to content

Commit

Permalink
feat(admin): add useToggleInputContext composable (#223)
Browse files Browse the repository at this point in the history
  • Loading branch information
EdieLemoine authored Oct 16, 2024
1 parent 2f72250 commit c0e1f59
Show file tree
Hide file tree
Showing 17 changed files with 112 additions and 65 deletions.
6 changes: 4 additions & 2 deletions apps/admin-component-tests/src/TestSuite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,11 @@ export class TestSuite<
element: string,
wrapper: VueWrapper<Component>,
): DOMWrapper<NodeType> {
const byComponentName = wrapper.findByTestId([this.componentName, element]);
const byComponentName = wrapper.findByTestId(this.componentName);

return (byComponentName.exists() ? byComponentName : wrapper.find(element)) as unknown as DOMWrapper<NodeType>;
return (byComponentName.exists()
? byComponentName?.find(element)
: wrapper.find(element)) as unknown as DOMWrapper<NodeType>;
}

private resolveOptions(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ exports[`exports > exports from index.ts 1`] = `
"useSelectInputContext",
"useShippingMethodsInputContext",
"useStoreQuery",
"useToggleInputContext",
"useTriStateInputContext",
"useUpdateAccountMutation",
"useUpdateOrdersMutation",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {type AdminComponentTest} from '../tests';
import {TestSuite} from '../TestSuite';

export const runToggleInputTest = ((component) => {
const suite = new TestSuite(AdminComponent.SelectInput, component);
const suite = new TestSuite(AdminComponent.ToggleInput, component);

suite.setOptions({
props: {
Expand Down
43 changes: 25 additions & 18 deletions apps/admin-demo/src/components/pdk/DemoToggleInput.vue
Original file line number Diff line number Diff line change
@@ -1,43 +1,50 @@
<template>
<label
:for="id"
:for="toggleId"
class="cursor-pointer flex items-center">
<input
:id="id"
v-model="model"
class="invisible"
type="hidden" />

<div
class="relative"
v-test="AdminComponent.ToggleInput"
:class="{
'opacity-50': element.isDisabled || element.isSuspended || element.isReadOnly,
}">
}"
class="relative">
<input
:id="id"
v-model="model"
type="checkbox"
class="sr-only"
:id="toggleId"
v-model="toggleModel"
:disabled="element.isDisabled || element.isSuspended || element.isReadOnly"
:readonly="element.isReadOnly" />
:readonly="element.isReadOnly"
class="sr-only"
type="checkbox" />

<div
class="bg-gray-600 block h-8 rounded-full transition-colors w-14"
:class="{
'bg-green-400 dark:bg-green-600': model,
'bg-gray-600': !model,
}" />
'bg-green-400 dark:bg-green-600': toggleModel,
'bg-gray-600': !toggleModel,
}"
class="bg-gray-600 block h-8 rounded-full transition-colors w-14" />

<div
class="absolute bg-white h-6 left-1 rounded-full top-1 transition w-6"
:class="{
'translate-x-6': model,
'translate-x-0': !model,
}" />
'translate-x-6': toggleModel,
'translate-x-0': !toggleModel,
}"
class="absolute bg-white h-6 left-1 rounded-full top-1 transition w-6" />
</div>
</label>
</template>

<script lang="ts" setup>
import {type ToggleInputEmits, type ToggleInputProps, useElementContext} from '@myparcel-pdk/admin';
import {AdminComponent, type ToggleInputEmits, type ToggleInputProps, useToggleInputContext} from '@myparcel-pdk/admin';
// eslint-disable-next-line vue/no-unused-properties
const props = defineProps<ToggleInputProps>();
const emit = defineEmits<ToggleInputEmits>();
const {id, model} = useElementContext(props, emit);
const {id, model, toggleId, toggleModel} = useToggleInputContext(props, emit);
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ exports[`exports > exports from index.ts 1`] = `
"useSelectInputContext",
"useShippingMethodsInputContext",
"useStoreQuery",
"useToggleInputContext",
"useTriStateInputContext",
"useUpdateAccountMutation",
"useUpdateOrdersMutation",
Expand Down
27 changes: 17 additions & 10 deletions apps/admin-preset-default/src/components/DefaultToggleInput.vue
Original file line number Diff line number Diff line change
@@ -1,34 +1,41 @@
<template>
<label v-test="[AdminComponent.ToggleInput, element]">
<div>
<input
:id="id"
v-model="model"
:name="id"
:disabled="element.isDisabled || element.isSuspended || element.isReadOnly"
:readonly="element.isReadOnly"
:value="true"
type="checkbox" />
type="hidden" />

<label :for="id">
{{ translate(`toggle_${model ? 'yes' : 'no'}`) }}
<label v-test="AdminComponent.ToggleInput">
<input
:id="toggleId"
v-model="toggleModel"
:disabled="element.isDisabled || element.isSuspended || element.isReadOnly"
:readonly="element.isReadOnly"
:value="true"
type="checkbox" />

<label :for="toggleId">
{{ translate(`toggle_${toggleModel ? 'yes' : 'no'}`) }}
</label>
</label>
</label>
</div>
</template>

<script lang="ts" setup>
import {
AdminComponent,
type ToggleInputEmits,
type ToggleInputProps,
useElementContext,
useLanguage,
useToggleInputContext,
} from '@myparcel-pdk/admin';
// eslint-disable-next-line vue/no-unused-properties
const props = defineProps<ToggleInputProps>();
const emit = defineEmits<ToggleInputEmits>();
const {id, model} = useElementContext(props, emit);
const {id, model, toggleId, toggleModel} = useToggleInputContext(props, emit);
const {translate} = useLanguage();
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ exports[`exports > exports from index.ts 1`] = `
"useSelectInputContext",
"useShippingMethodsInputContext",
"useStoreQuery",
"useToggleInputContext",
"useTriStateInputContext",
"useUpdateAccountMutation",
"useUpdateOrdersMutation",
Expand Down
1 change: 1 addition & 0 deletions apps/admin/src/composables/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ export * from './useSelectInputContext';
export * from './useShippingMethodsInputContext';
export * from './useStoreContextQuery';
export * from './useStoreQuery';
export * from './useToggleInputContext';
export * from './useTriStateInputContext';
export * from './useWeekdays';
36 changes: 36 additions & 0 deletions apps/admin/src/composables/useToggleInputContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {ref, type Ref, watch, type WritableComputedRef} from 'vue';
import {get} from '@vueuse/core';
import {booleanToTriState, triStateToBoolean} from '../utils';
import {type ToggleInputEmits, type ToggleInputModelValue, type ToggleInputProps} from '../types';
import {useElementContext} from './useElementContext';

interface ToggleInputContext {
id: string;
model: WritableComputedRef<ToggleInputModelValue>;
toggleId: string;
toggleModel: Ref<boolean>;
}

type UseToggleInputContext = (props: ToggleInputProps, emit: ToggleInputEmits) => ToggleInputContext;

export const useToggleInputContext: UseToggleInputContext = (props, emit) => {
const toggleModel = ref<boolean>(triStateToBoolean(get(props.modelValue)));
const {id, model} = useElementContext<ToggleInputModelValue>(props, emit);

// When the toggle is changed, the model is updated to 1/0
watch(toggleModel, (toggle) => {
model.value = booleanToTriState(toggle);
});

// When the model is changed manually, like from another element, the toggle is updated
watch(model, (model) => {
toggleModel.value = triStateToBoolean(model);
});

return {
id,
model,
toggleId: `${id}__toggle`,
toggleModel,
};
};
10 changes: 4 additions & 6 deletions apps/admin/src/composables/useTriStateInputContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {computed, markRaw, reactive, ref, type Ref, watch, type WritableComputed
import {get} from '@vueuse/core';
import {TriState} from '@myparcel-pdk/common';
import {type AnyElementConfiguration, defineField, useForm} from '@myparcel/vue-form-builder';
import {toTriState, triStateToBoolean} from '../utils';
import {booleanToTriState, triStateToBoolean} from '../utils';
import {
type ElementInstance,
type PdkElementProps,
Expand Down Expand Up @@ -34,8 +34,6 @@ export const useTriStateInputContext: UseTriStateInputContext = (props, emit) =>
const {translate} = useLanguage();
const form = useForm();

const toggleName = `${props.element.name}__toggle`;

const inheritModel = ref<boolean>(TriState.Inherit === get(props.modelValue));
const toggleModel = ref<boolean>(triStateToBoolean(get(props.modelValue)));

Expand Down Expand Up @@ -69,7 +67,7 @@ export const useTriStateInputContext: UseTriStateInputContext = (props, emit) =>
const toggleElement = reactive(
defineField({
...commonFieldProperties,
name: toggleName,
name: `${props.element.name}__toggle`,
ref: toggleModel,
// The toggle is readonly when inherit is enabled or the element itself is set to readonly.
isReadOnly: markRaw(computed(() => get(inheritModel) || get(props.element.isReadOnly))),
Expand All @@ -82,7 +80,7 @@ export const useTriStateInputContext: UseTriStateInputContext = (props, emit) =>
return;
}

model.value = toTriState(toggle);
model.value = booleanToTriState(toggle);
});

// When inherit is disabled, the model is updated to the current toggle value
Expand All @@ -93,7 +91,7 @@ export const useTriStateInputContext: UseTriStateInputContext = (props, emit) =>
}

if (!inherit) {
model.value = toTriState(toggleModel.value);
model.value = booleanToTriState(toggleModel.value);
return;
}

Expand Down
1 change: 1 addition & 0 deletions apps/admin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export {
useSelectInputContext,
useShippingMethodsInputContext,
useStoreQuery,
useToggleInputContext,
useTriStateInputContext,
useWeekdays,
} from './composables';
2 changes: 1 addition & 1 deletion apps/admin/src/types/component-bindings.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export type TimeInputEmits = PdkElementEmits<TimeInputModelValue>;
* @see AdminComponent.ToggleInput
*/

export type ToggleInputModelValue = boolean;
export type ToggleInputModelValue = TriState.On | TriState.Off;

export type ToggleInputProps = PdkElementProps<ToggleInputModelValue>;

Expand Down
13 changes: 13 additions & 0 deletions apps/admin/src/utils/booleanToTriState.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {describe, expect, it} from 'vitest';
import {TriState} from '@myparcel-pdk/common';
import {booleanToTriState} from './booleanToTriState';

describe('booleanToTriState', () => {
it.each([
[true, TriState.On],
[false, TriState.Off],
[undefined, TriState.Off],
])('should return %s for %s', (value, expected) => {
expect(booleanToTriState(value)).toEqual(expected);
});
});
5 changes: 5 additions & 0 deletions apps/admin/src/utils/booleanToTriState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {TriState} from '@myparcel-pdk/common';

export const booleanToTriState = (value?: boolean): TriState.On | TriState.Off => {
return value ? TriState.On : TriState.Off;
};
2 changes: 1 addition & 1 deletion apps/admin/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './booleanToTriState';
export * from './convertDotNotationToObject';
export * from './createAssetUrl';
export * from './createClasses';
Expand All @@ -13,7 +14,6 @@ export * from './openUrl';
export * from './prefixComponent';
export * from './query';
export * from './resolveCarrier';
export * from './toTriState';
export * from './translations';
export * from './triStateToBoolean';
export * from './unprefixComponent';
Expand Down
17 changes: 0 additions & 17 deletions apps/admin/src/utils/toTriState.spec.ts

This file was deleted.

9 changes: 0 additions & 9 deletions apps/admin/src/utils/toTriState.ts

This file was deleted.

0 comments on commit c0e1f59

Please sign in to comment.