routie dev init since i didn't adhere to any proper guidance up until now
This commit is contained in:
+190
@@ -0,0 +1,190 @@
|
||||
import type { PropType, Ref, VNode } from 'vue';
|
||||
import type { GenericProps } from '../../util/index.js';
|
||||
export type VConfirmEditSlots<T> = {
|
||||
default: {
|
||||
model: Ref<T>;
|
||||
save: () => void;
|
||||
cancel: () => void;
|
||||
isPristine: boolean;
|
||||
get actions(): (props?: {}) => VNode;
|
||||
};
|
||||
};
|
||||
export declare const makeVConfirmEditProps: <Defaults extends {
|
||||
modelValue?: unknown;
|
||||
color?: unknown;
|
||||
cancelText?: unknown;
|
||||
okText?: unknown;
|
||||
disabled?: unknown;
|
||||
hideActions?: unknown;
|
||||
} = {}>(defaults?: Defaults | undefined) => {
|
||||
modelValue: unknown extends Defaults["modelValue"] ? null : {
|
||||
type: PropType<unknown extends Defaults["modelValue"] ? any : any>;
|
||||
default: unknown extends Defaults["modelValue"] ? any : any;
|
||||
};
|
||||
color: unknown extends Defaults["color"] ? StringConstructor : {
|
||||
type: PropType<unknown extends Defaults["color"] ? string : string | Defaults["color"]>;
|
||||
default: unknown extends Defaults["color"] ? string : string | Defaults["color"];
|
||||
};
|
||||
cancelText: unknown extends Defaults["cancelText"] ? {
|
||||
type: StringConstructor;
|
||||
default: string;
|
||||
} : Omit<{
|
||||
type: StringConstructor;
|
||||
default: string;
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["cancelText"] ? string : string | Defaults["cancelText"]>;
|
||||
default: unknown extends Defaults["cancelText"] ? string : string | Defaults["cancelText"];
|
||||
};
|
||||
okText: unknown extends Defaults["okText"] ? {
|
||||
type: StringConstructor;
|
||||
default: string;
|
||||
} : Omit<{
|
||||
type: StringConstructor;
|
||||
default: string;
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["okText"] ? string : string | Defaults["okText"]>;
|
||||
default: unknown extends Defaults["okText"] ? string : string | Defaults["okText"];
|
||||
};
|
||||
disabled: unknown extends Defaults["disabled"] ? {
|
||||
type: PropType<boolean | ('save' | 'cancel')[]>;
|
||||
default: undefined;
|
||||
} : Omit<{
|
||||
type: PropType<boolean | ('save' | 'cancel')[]>;
|
||||
default: undefined;
|
||||
}, "default" | "type"> & {
|
||||
type: PropType<unknown extends Defaults["disabled"] ? boolean | ("cancel" | "save")[] : boolean | ("cancel" | "save")[] | Defaults["disabled"]>;
|
||||
default: unknown extends Defaults["disabled"] ? boolean | ("cancel" | "save")[] : Defaults["disabled"] | NonNullable<boolean | ("cancel" | "save")[]>;
|
||||
};
|
||||
hideActions: unknown extends Defaults["hideActions"] ? BooleanConstructor : {
|
||||
type: PropType<unknown extends Defaults["hideActions"] ? boolean : boolean | Defaults["hideActions"]>;
|
||||
default: unknown extends Defaults["hideActions"] ? boolean : boolean | Defaults["hideActions"];
|
||||
};
|
||||
};
|
||||
export declare const VConfirmEdit: {
|
||||
new (...args: any[]): import("vue").CreateComponentPublicInstanceWithMixins<{
|
||||
cancelText: string;
|
||||
okText: string;
|
||||
hideActions: boolean;
|
||||
} & {
|
||||
color?: string | undefined;
|
||||
disabled?: boolean | ("cancel" | "save")[] | undefined;
|
||||
} & {
|
||||
onCancel?: (() => any) | undefined;
|
||||
}, {
|
||||
save: () => void;
|
||||
cancel: () => void;
|
||||
isPristine: import("vue").ComputedRef<boolean>;
|
||||
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, Omit<{
|
||||
cancel: () => true;
|
||||
save: (value: any) => true;
|
||||
'update:modelValue': (value: any) => true;
|
||||
}, "$children" | "modelValue" | "save" | "update:modelValue" | "v-slot:default" | "v-slots">, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, {
|
||||
cancelText: string;
|
||||
okText: string;
|
||||
disabled: boolean | ("cancel" | "save")[];
|
||||
hideActions: boolean;
|
||||
}, true, {}, import("vue").SlotsType<Partial<{
|
||||
default: (arg: {
|
||||
model: Ref<unknown, unknown>;
|
||||
save: () => void;
|
||||
cancel: () => void;
|
||||
isPristine: boolean;
|
||||
readonly actions: (props?: {}) => VNode;
|
||||
}) => VNode[];
|
||||
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, {}, any, import("vue").ComponentProvideOptions, {
|
||||
P: {};
|
||||
B: {};
|
||||
D: {};
|
||||
C: {};
|
||||
M: {};
|
||||
Defaults: {};
|
||||
}, {
|
||||
cancelText: string;
|
||||
okText: string;
|
||||
hideActions: boolean;
|
||||
} & {
|
||||
color?: string | undefined;
|
||||
disabled?: boolean | ("cancel" | "save")[] | undefined;
|
||||
} & {
|
||||
onCancel?: (() => any) | undefined;
|
||||
}, {
|
||||
save: () => void;
|
||||
cancel: () => void;
|
||||
isPristine: import("vue").ComputedRef<boolean>;
|
||||
}, {}, {}, {}, {
|
||||
cancelText: string;
|
||||
okText: string;
|
||||
disabled: boolean | ("cancel" | "save")[];
|
||||
hideActions: boolean;
|
||||
}>;
|
||||
__isFragment?: never;
|
||||
__isTeleport?: never;
|
||||
__isSuspense?: never;
|
||||
} & import("vue").ComponentOptionsBase<{
|
||||
cancelText: string;
|
||||
okText: string;
|
||||
hideActions: boolean;
|
||||
} & {
|
||||
color?: string | undefined;
|
||||
disabled?: boolean | ("cancel" | "save")[] | undefined;
|
||||
} & {
|
||||
onCancel?: (() => any) | undefined;
|
||||
}, {
|
||||
save: () => void;
|
||||
cancel: () => void;
|
||||
isPristine: import("vue").ComputedRef<boolean>;
|
||||
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, Omit<{
|
||||
cancel: () => true;
|
||||
save: (value: any) => true;
|
||||
'update:modelValue': (value: any) => true;
|
||||
}, "$children" | "modelValue" | "save" | "update:modelValue" | "v-slot:default" | "v-slots">, string, {
|
||||
cancelText: string;
|
||||
okText: string;
|
||||
disabled: boolean | ("cancel" | "save")[];
|
||||
hideActions: boolean;
|
||||
}, {}, string, import("vue").SlotsType<Partial<{
|
||||
default: (arg: {
|
||||
model: Ref<unknown, unknown>;
|
||||
save: () => void;
|
||||
cancel: () => void;
|
||||
isPristine: boolean;
|
||||
readonly actions: (props?: {}) => VNode;
|
||||
}) => VNode[];
|
||||
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps & (new <T>(props: {
|
||||
modelValue?: T;
|
||||
'onUpdate:modelValue'?: (value: T) => void;
|
||||
'onSave'?: (value: T) => void;
|
||||
}, slots: VConfirmEditSlots<T>) => GenericProps<typeof props, typeof slots>) & import("../../util/index.js").FilterPropsOptions<{
|
||||
modelValue: null;
|
||||
color: StringConstructor;
|
||||
cancelText: {
|
||||
type: StringConstructor;
|
||||
default: string;
|
||||
};
|
||||
okText: {
|
||||
type: StringConstructor;
|
||||
default: string;
|
||||
};
|
||||
disabled: {
|
||||
type: PropType<boolean | ('save' | 'cancel')[]>;
|
||||
default: undefined;
|
||||
};
|
||||
hideActions: BooleanConstructor;
|
||||
}, import("vue").ExtractPropTypes<{
|
||||
modelValue: null;
|
||||
color: StringConstructor;
|
||||
cancelText: {
|
||||
type: StringConstructor;
|
||||
default: string;
|
||||
};
|
||||
okText: {
|
||||
type: StringConstructor;
|
||||
default: string;
|
||||
};
|
||||
disabled: {
|
||||
type: PropType<boolean | ('save' | 'cancel')[]>;
|
||||
default: undefined;
|
||||
};
|
||||
hideActions: BooleanConstructor;
|
||||
}>>;
|
||||
export type VConfirmEdit = InstanceType<typeof VConfirmEdit>;
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
import { Fragment as _Fragment, mergeProps as _mergeProps, createVNode as _createVNode, createElementVNode as _createElementVNode } from "vue";
|
||||
// Components
|
||||
import { VBtn } from "../VBtn/index.js"; // Composables
|
||||
import { useLocale } from "../../composables/locale.js";
|
||||
import { useProxiedModel } from "../../composables/proxiedModel.js"; // Utilities
|
||||
import { computed, ref, watchEffect } from 'vue';
|
||||
import { deepEqual, deepToRaw, genericComponent, propsFactory, useRender } from "../../util/index.js"; // Types
|
||||
export const makeVConfirmEditProps = propsFactory({
|
||||
modelValue: null,
|
||||
color: String,
|
||||
cancelText: {
|
||||
type: String,
|
||||
default: '$vuetify.confirmEdit.cancel'
|
||||
},
|
||||
okText: {
|
||||
type: String,
|
||||
default: '$vuetify.confirmEdit.ok'
|
||||
},
|
||||
disabled: {
|
||||
type: [Boolean, Array],
|
||||
default: undefined
|
||||
},
|
||||
hideActions: Boolean
|
||||
}, 'VConfirmEdit');
|
||||
export const VConfirmEdit = genericComponent()({
|
||||
name: 'VConfirmEdit',
|
||||
props: makeVConfirmEditProps(),
|
||||
emits: {
|
||||
cancel: () => true,
|
||||
save: value => true,
|
||||
'update:modelValue': value => true
|
||||
},
|
||||
setup(props, {
|
||||
emit,
|
||||
slots
|
||||
}) {
|
||||
const model = useProxiedModel(props, 'modelValue');
|
||||
const internalModel = ref();
|
||||
watchEffect(() => {
|
||||
internalModel.value = structuredClone(deepToRaw(model.value));
|
||||
});
|
||||
const {
|
||||
t
|
||||
} = useLocale();
|
||||
const isPristine = computed(() => {
|
||||
return deepEqual(model.value, internalModel.value);
|
||||
});
|
||||
function isActionDisabled(action) {
|
||||
if (typeof props.disabled === 'boolean') {
|
||||
return props.disabled;
|
||||
}
|
||||
if (Array.isArray(props.disabled)) {
|
||||
return props.disabled.includes(action);
|
||||
}
|
||||
return isPristine.value;
|
||||
}
|
||||
const isSaveDisabled = computed(() => isActionDisabled('save'));
|
||||
const isCancelDisabled = computed(() => isActionDisabled('cancel'));
|
||||
function save() {
|
||||
model.value = internalModel.value;
|
||||
emit('save', internalModel.value);
|
||||
}
|
||||
function cancel() {
|
||||
internalModel.value = structuredClone(deepToRaw(model.value));
|
||||
emit('cancel');
|
||||
}
|
||||
function actions(actionsProps) {
|
||||
return _createElementVNode(_Fragment, null, [_createVNode(VBtn, _mergeProps({
|
||||
"disabled": isCancelDisabled.value,
|
||||
"variant": "text",
|
||||
"color": props.color,
|
||||
"onClick": cancel,
|
||||
"text": t(props.cancelText)
|
||||
}, actionsProps), null), _createVNode(VBtn, _mergeProps({
|
||||
"disabled": isSaveDisabled.value,
|
||||
"variant": "text",
|
||||
"color": props.color,
|
||||
"onClick": save,
|
||||
"text": t(props.okText)
|
||||
}, actionsProps), null)]);
|
||||
}
|
||||
let actionsUsed = false;
|
||||
useRender(() => {
|
||||
return _createElementVNode(_Fragment, null, [slots.default?.({
|
||||
model: internalModel,
|
||||
save,
|
||||
cancel,
|
||||
isPristine: isPristine.value,
|
||||
get actions() {
|
||||
actionsUsed = true;
|
||||
return actions;
|
||||
}
|
||||
}), !props.hideActions && !actionsUsed && actions()]);
|
||||
});
|
||||
return {
|
||||
save,
|
||||
cancel,
|
||||
isPristine
|
||||
};
|
||||
}
|
||||
});
|
||||
//# sourceMappingURL=VConfirmEdit.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
Generated
Vendored
+76
@@ -0,0 +1,76 @@
|
||||
import { createElementVNode as _createElementVNode, createVNode as _createVNode, Fragment as _Fragment, createTextVNode as _createTextVNode } from "vue";
|
||||
// Components
|
||||
import { VConfirmEdit } from "../index.js"; // Utilities
|
||||
import { render, screen, userEvent } from '@test';
|
||||
import { nextTick, shallowRef } from 'vue';
|
||||
describe('VConfirmEdit', () => {
|
||||
it('mirrors external updates', async () => {
|
||||
const externalModel = shallowRef('foo');
|
||||
render(() => _createVNode(VConfirmEdit, {
|
||||
"modelValue": externalModel.value
|
||||
}, {
|
||||
default: ({
|
||||
model
|
||||
}) => _createElementVNode("p", null, [model.value])
|
||||
}));
|
||||
expect(screen.getByText('foo')).toBeVisible();
|
||||
externalModel.value = 'bar';
|
||||
await nextTick();
|
||||
expect(screen.getByText('bar')).toBeVisible();
|
||||
});
|
||||
it("doesn't mutate the original value", async () => {
|
||||
const externalModel = shallowRef(['foo']);
|
||||
render(() => _createVNode(VConfirmEdit, {
|
||||
"modelValue": externalModel.value,
|
||||
"onUpdate:modelValue": $event => externalModel.value = $event
|
||||
}, {
|
||||
default: ({
|
||||
model
|
||||
}) => _createElementVNode(_Fragment, null, [_createElementVNode("p", null, [model.value.join(',')]), _createElementVNode("button", {
|
||||
"data-testid": "push",
|
||||
"onClick": () => model.value.push('bar')
|
||||
}, [_createTextVNode("Push")])])
|
||||
}));
|
||||
expect(screen.getByText('foo')).toBeVisible();
|
||||
await userEvent.click(screen.getByTestId('push'));
|
||||
expect(screen.getByText('foo,bar')).toBeVisible();
|
||||
expect(externalModel.value).toEqual(['foo']);
|
||||
await userEvent.click(screen.getByText('OK'));
|
||||
expect(externalModel.value).toEqual(['foo', 'bar']);
|
||||
});
|
||||
describe('hides actions if used from the slot', () => {
|
||||
it('nothing', () => {
|
||||
render(() => _createVNode(VConfirmEdit, null, null));
|
||||
expect(screen.getAllByCSS('button')).toHaveLength(2);
|
||||
});
|
||||
it('consume model', () => {
|
||||
render(() => _createVNode(VConfirmEdit, null, {
|
||||
default: ({
|
||||
model
|
||||
}) => {
|
||||
void model;
|
||||
}
|
||||
}));
|
||||
expect(screen.getAllByCSS('button')).toHaveLength(2);
|
||||
});
|
||||
it('consume actions', () => {
|
||||
render(() => _createVNode(VConfirmEdit, null, {
|
||||
default: ({
|
||||
actions
|
||||
}) => {
|
||||
void actions;
|
||||
}
|
||||
}));
|
||||
expect(screen.queryAllByCSS('button')).toHaveLength(0);
|
||||
});
|
||||
it('render actions', () => {
|
||||
render(() => _createVNode(VConfirmEdit, null, {
|
||||
default: ({
|
||||
actions
|
||||
}) => actions()
|
||||
}));
|
||||
expect(screen.getAllByCSS('button')).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
//# sourceMappingURL=VConfirmEdit.spec.browser.js.map
|
||||
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
export { VConfirmEdit } from './VConfirmEdit.js';
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export { VConfirmEdit } from "./VConfirmEdit.js";
|
||||
//# sourceMappingURL=index.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","names":["VConfirmEdit"],"sources":["../../../src/components/VConfirmEdit/index.ts"],"sourcesContent":["export { VConfirmEdit } from './VConfirmEdit'\n"],"mappings":"SAASA,YAAY","ignoreList":[]}
|
||||
Reference in New Issue
Block a user