diff --git a/apps/admin-component-tests/src/TestSuite.ts b/apps/admin-component-tests/src/TestSuite.ts index 78a36371..c0a08e6c 100644 --- a/apps/admin-component-tests/src/TestSuite.ts +++ b/apps/admin-component-tests/src/TestSuite.ts @@ -125,9 +125,11 @@ export class TestSuite< element: string, wrapper: VueWrapper, ): DOMWrapper { - const byComponentName = wrapper.findByTestId([this.componentName, element]); + const byComponentName = wrapper.findByTestId(this.componentName); - return (byComponentName.exists() ? byComponentName : wrapper.find(element)) as unknown as DOMWrapper; + return (byComponentName.exists() + ? byComponentName?.find(element) + : wrapper.find(element)) as unknown as DOMWrapper; } private resolveOptions( diff --git a/apps/admin-component-tests/src/__tests__/__snapshots__/exports.spec.ts.snap b/apps/admin-component-tests/src/__tests__/__snapshots__/exports.spec.ts.snap index 58ae8c58..263f0c53 100644 --- a/apps/admin-component-tests/src/__tests__/__snapshots__/exports.spec.ts.snap +++ b/apps/admin-component-tests/src/__tests__/__snapshots__/exports.spec.ts.snap @@ -151,6 +151,7 @@ exports[`exports > exports from index.ts 1`] = ` "useSelectInputContext", "useShippingMethodsInputContext", "useStoreQuery", + "useToggleInputContext", "useTriStateInputContext", "useUpdateAccountMutation", "useUpdateOrdersMutation", diff --git a/apps/admin-component-tests/src/components/runToggleInputTest.ts b/apps/admin-component-tests/src/components/runToggleInputTest.ts index 5a3007ff..20d914e7 100644 --- a/apps/admin-component-tests/src/components/runToggleInputTest.ts +++ b/apps/admin-component-tests/src/components/runToggleInputTest.ts @@ -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: { diff --git a/apps/admin-demo/src/components/pdk/DemoToggleInput.vue b/apps/admin-demo/src/components/pdk/DemoToggleInput.vue index 6d693cd7..2b001e44 100644 --- a/apps/admin-demo/src/components/pdk/DemoToggleInput.vue +++ b/apps/admin-demo/src/components/pdk/DemoToggleInput.vue @@ -1,43 +1,50 @@ diff --git a/apps/admin-js/src/__tests__/__snapshots__/exports.spec.ts.snap b/apps/admin-js/src/__tests__/__snapshots__/exports.spec.ts.snap index f3fc04a0..4ec67047 100644 --- a/apps/admin-js/src/__tests__/__snapshots__/exports.spec.ts.snap +++ b/apps/admin-js/src/__tests__/__snapshots__/exports.spec.ts.snap @@ -148,6 +148,7 @@ exports[`exports > exports from index.ts 1`] = ` "useSelectInputContext", "useShippingMethodsInputContext", "useStoreQuery", + "useToggleInputContext", "useTriStateInputContext", "useUpdateAccountMutation", "useUpdateOrdersMutation", diff --git a/apps/admin-preset-default/src/components/DefaultToggleInput.vue b/apps/admin-preset-default/src/components/DefaultToggleInput.vue index a777594b..01863648 100644 --- a/apps/admin-preset-default/src/components/DefaultToggleInput.vue +++ b/apps/admin-preset-default/src/components/DefaultToggleInput.vue @@ -1,18 +1,25 @@ diff --git a/apps/admin/src/__tests__/__snapshots__/exports.spec.ts.snap b/apps/admin/src/__tests__/__snapshots__/exports.spec.ts.snap index f3fc04a0..4ec67047 100644 --- a/apps/admin/src/__tests__/__snapshots__/exports.spec.ts.snap +++ b/apps/admin/src/__tests__/__snapshots__/exports.spec.ts.snap @@ -148,6 +148,7 @@ exports[`exports > exports from index.ts 1`] = ` "useSelectInputContext", "useShippingMethodsInputContext", "useStoreQuery", + "useToggleInputContext", "useTriStateInputContext", "useUpdateAccountMutation", "useUpdateOrdersMutation", diff --git a/apps/admin/src/composables/index.ts b/apps/admin/src/composables/index.ts index 9eefcfdd..6bcbb67e 100644 --- a/apps/admin/src/composables/index.ts +++ b/apps/admin/src/composables/index.ts @@ -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'; diff --git a/apps/admin/src/composables/useToggleInputContext.ts b/apps/admin/src/composables/useToggleInputContext.ts new file mode 100644 index 00000000..e113c192 --- /dev/null +++ b/apps/admin/src/composables/useToggleInputContext.ts @@ -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; + toggleId: string; + toggleModel: Ref; +} + +type UseToggleInputContext = (props: ToggleInputProps, emit: ToggleInputEmits) => ToggleInputContext; + +export const useToggleInputContext: UseToggleInputContext = (props, emit) => { + const toggleModel = ref(triStateToBoolean(get(props.modelValue))); + const {id, model} = useElementContext(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, + }; +}; diff --git a/apps/admin/src/composables/useTriStateInputContext.ts b/apps/admin/src/composables/useTriStateInputContext.ts index bacc8ab7..ce9efd64 100644 --- a/apps/admin/src/composables/useTriStateInputContext.ts +++ b/apps/admin/src/composables/useTriStateInputContext.ts @@ -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, @@ -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(TriState.Inherit === get(props.modelValue)); const toggleModel = ref(triStateToBoolean(get(props.modelValue))); @@ -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))), @@ -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 @@ -93,7 +91,7 @@ export const useTriStateInputContext: UseTriStateInputContext = (props, emit) => } if (!inherit) { - model.value = toTriState(toggleModel.value); + model.value = booleanToTriState(toggleModel.value); return; } diff --git a/apps/admin/src/index.ts b/apps/admin/src/index.ts index 8cb786c7..5d020412 100644 --- a/apps/admin/src/index.ts +++ b/apps/admin/src/index.ts @@ -110,6 +110,7 @@ export { useSelectInputContext, useShippingMethodsInputContext, useStoreQuery, + useToggleInputContext, useTriStateInputContext, useWeekdays, } from './composables'; diff --git a/apps/admin/src/types/component-bindings.types.ts b/apps/admin/src/types/component-bindings.types.ts index e8270aa5..73d900f3 100644 --- a/apps/admin/src/types/component-bindings.types.ts +++ b/apps/admin/src/types/component-bindings.types.ts @@ -132,7 +132,7 @@ export type TimeInputEmits = PdkElementEmits; * @see AdminComponent.ToggleInput */ -export type ToggleInputModelValue = boolean; +export type ToggleInputModelValue = TriState.On | TriState.Off; export type ToggleInputProps = PdkElementProps; diff --git a/apps/admin/src/utils/booleanToTriState.spec.ts b/apps/admin/src/utils/booleanToTriState.spec.ts new file mode 100644 index 00000000..84ee8844 --- /dev/null +++ b/apps/admin/src/utils/booleanToTriState.spec.ts @@ -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); + }); +}); diff --git a/apps/admin/src/utils/booleanToTriState.ts b/apps/admin/src/utils/booleanToTriState.ts new file mode 100644 index 00000000..5043ed18 --- /dev/null +++ b/apps/admin/src/utils/booleanToTriState.ts @@ -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; +}; diff --git a/apps/admin/src/utils/index.ts b/apps/admin/src/utils/index.ts index 11e0be57..94f0dce2 100644 --- a/apps/admin/src/utils/index.ts +++ b/apps/admin/src/utils/index.ts @@ -1,3 +1,4 @@ +export * from './booleanToTriState'; export * from './convertDotNotationToObject'; export * from './createAssetUrl'; export * from './createClasses'; @@ -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'; diff --git a/apps/admin/src/utils/toTriState.spec.ts b/apps/admin/src/utils/toTriState.spec.ts deleted file mode 100644 index d3c00be2..00000000 --- a/apps/admin/src/utils/toTriState.spec.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {describe, expect, it} from 'vitest'; -import {TriState} from '@myparcel-pdk/common'; -import {toTriState} from './toTriState'; - -describe('toTriStateValue', () => { - it.each([ - [undefined, TriState.Off], - [null, TriState.Off], - [false, TriState.Off], - [true, TriState.On], - [TriState.Off, TriState.Off], - [TriState.On, TriState.On], - [TriState.Inherit, TriState.Inherit], - ])('should return %s for %s', (value, expected) => { - expect(toTriState(value)).toEqual(expected); - }); -}); diff --git a/apps/admin/src/utils/toTriState.ts b/apps/admin/src/utils/toTriState.ts deleted file mode 100644 index dfe5fc78..00000000 --- a/apps/admin/src/utils/toTriState.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {TriState} from '@myparcel-pdk/common'; - -export const toTriState = (value?: unknown): TriState => { - if (TriState.Inherit === value) { - return value; - } - - return value ? TriState.On : TriState.Off; -};