Skip to content

Commit 5245ea1

Browse files
committed
feat: modal content slot
BREAKING CHANGE: no gaping modifier & no modalTarget on form response
1 parent f0cc7e9 commit 5245ea1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+459
-462
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"release": "yarn workspaces run semantic-release",
3131
"release:dry": "yarn workspaces run semantic-release --dry-run"
3232
},
33+
"packageManager": "[email protected]",
3334
"engines": {
3435
"node": ">=18",
3536
"yarn": ">=1.22.4"

packages/common-helpers/src/form/composable.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,16 @@ export default function useForm(options: iPluginOptions = {}) {
4242
event?: Event,
4343
silent = false,
4444
plainValues = true
45-
): Promise<iFormResponse<R, HTMLElement | string>> {
45+
): Promise<iFormResponse<R>> {
4646
const { values, invalidInputs } = getFormValues<RV>(inputs, plainValues);
47-
const modalTarget = (event?.target as HTMLElement)?.closest("dialog") || "body";
4847
const withSwal = !silent && isBrowser;
4948
let errors;
5049
let requestHadErrors = false;
5150
let newResponse: iFetchResponse<R> = {};
5251

5352
if (!invalidInputs.length) {
5453
try {
55-
if (withSwal) Swal.fireLoader({ target: modalTarget });
54+
if (withSwal) Swal.fireLoader({ target: event });
5655

5756
newResponse = await request(values);
5857
// request went ok, but still returned errors
@@ -77,7 +76,7 @@ export default function useForm(options: iPluginOptions = {}) {
7776
timer: undefined,
7877
showConfirmButton: true,
7978
confirmButtonText: t("swal.connection_error_confirm"),
80-
target: modalTarget,
79+
target: event,
8180
});
8281

8382
// Page reload if user wish to
@@ -90,7 +89,6 @@ export default function useForm(options: iPluginOptions = {}) {
9089
requestHadErrors: true,
9190
validationHadErrors: false,
9291
errors,
93-
modalTarget,
9492
};
9593
}
9694
} else if (withSwal) {
@@ -99,7 +97,7 @@ export default function useForm(options: iPluginOptions = {}) {
9997
title: t("swal.incomplete_data"),
10098
text: t("swal.incomplete_data_message"),
10199
icon: "warning",
102-
target: modalTarget,
100+
target: event,
103101
});
104102
}
105103

@@ -117,7 +115,6 @@ export default function useForm(options: iPluginOptions = {}) {
117115
requestHadErrors,
118116
validationHadErrors,
119117
errors,
120-
modalTarget,
121118
};
122119
}
123120

packages/common-helpers/src/form/input.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,10 +289,12 @@ export interface iForm {
289289
/**
290290
* Optional form key
291291
*/
292-
key?: string | number;
292+
key?: string;
293293
title?: string;
294294
inputs: FormInput[];
295295
listen?: boolean;
296296
/** Make all inputs read only by disabling them */
297297
readonly?: boolean;
298+
/** Message when no valid inputs are rendered */
299+
emptyMessage?: string;
298300
}

packages/common-helpers/src/swal.ts

Lines changed: 77 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,20 @@ import DefaultSwal, {
33
type SweetAlertResult,
44
} from "sweetalert2/dist/sweetalert2.js";
55

6-
import type { iPluginOptions, tSwal } from "@open-xamu-co/ui-common-types";
6+
import type { iPluginOptions, tSwal, tSwalOptions } from "@open-xamu-co/ui-common-types";
77

88
import useI18n from "./i18n.js";
99

10+
function getTarget(possibleTarget?: tSwalOptions["target"]): string | HTMLElement {
11+
if (possibleTarget instanceof Event) {
12+
const dialog = (possibleTarget?.target as HTMLElement)?.closest("dialog");
13+
14+
if (dialog) return dialog;
15+
}
16+
17+
return "body";
18+
}
19+
1020
/**
1121
* Swal composable
1222
*
@@ -18,63 +28,83 @@ import useI18n from "./i18n.js";
1828
export default function useSwal(options: iPluginOptions = {}, overrides: SweetAlertOptions = {}) {
1929
const { t } = useI18n(options);
2030
const { swal } = options;
21-
const swalDefaults: SweetAlertOptions = {
22-
timer: 1700,
23-
showConfirmButton: false,
24-
heightAuto: false,
25-
reverseButtons: true,
26-
buttonsStyling: false,
27-
cancelButtonText: t("swal.cancel"),
28-
allowOutsideClick: () => !Swal.isLoading(),
29-
allowEscapeKey: () => !Swal.isLoading(),
30-
customClass: {
31-
confirmButton: "bttn",
32-
cancelButton: "bttnToggle",
33-
denyButton: "link",
31+
32+
const swalDefaults: SweetAlertOptions = Object.assign(
33+
{
34+
timer: 1700,
35+
showConfirmButton: false,
36+
heightAuto: false,
37+
reverseButtons: true,
38+
buttonsStyling: false,
39+
cancelButtonText: t("swal.cancel"),
40+
allowOutsideClick: () => !Swal.isLoading(),
41+
allowEscapeKey: () => !Swal.isLoading(),
42+
customClass: {
43+
confirmButton: "bttn",
44+
cancelButton: "bttnToggle",
45+
denyButton: "link",
46+
},
3447
},
35-
};
36-
const swalDefaultsOverrides: SweetAlertOptions = Object.assign(
37-
{},
38-
swalDefaults,
3948
swal?.overrides,
4049
overrides
4150
);
42-
const Swal = <tSwal>DefaultSwal.mixin(swalDefaultsOverrides);
43-
const swalFirePreventDefaults: SweetAlertOptions = {
44-
icon: "warning",
45-
timer: undefined,
46-
showCancelButton: true,
47-
showConfirmButton: true,
48-
confirmButtonText: t("swal.continue"),
49-
allowOutsideClick: () => !Swal.isLoading(),
50-
allowEscapeKey: () => !Swal.isLoading(),
51-
customClass: {
52-
confirmButton: ["bttn", "--tm-danger-light"],
53-
cancelButton: "bttnToggle",
54-
denyButton: "link",
51+
const swalPreventDefaults: SweetAlertOptions = Object.assign(
52+
{},
53+
swalDefaults,
54+
{
55+
icon: "warning",
56+
timer: undefined,
57+
showCancelButton: true,
58+
showConfirmButton: true,
59+
confirmButtonText: t("swal.continue"),
60+
allowOutsideClick: () => !Swal.isLoading(),
61+
allowEscapeKey: () => !Swal.isLoading(),
62+
customClass: {
63+
confirmButton: ["bttn", "--tm-danger-light"],
64+
cancelButton: "bttnToggle",
65+
denyButton: "link",
66+
},
5567
},
68+
swal?.preventOverrides
69+
);
70+
const swalLoaderDefaults: SweetAlertOptions = Object.assign(
71+
{},
72+
swalDefaults,
73+
{
74+
title: t("loading"),
75+
text: t("swal.dont_close_window"),
76+
timer: undefined,
77+
willOpen: () => Swal.showLoading(),
78+
allowOutsideClick: () => !Swal.isLoading(),
79+
allowEscapeKey: () => !Swal.isLoading(),
80+
},
81+
swal?.loaderOverrides
82+
);
83+
84+
const Swal = <tSwal>DefaultSwal.mixin({});
85+
86+
Swal.fire = function <T>(swalOverrides: tSwalOptions = {}) {
87+
const overrides: SweetAlertOptions = Object.assign({}, swalDefaults, swalOverrides);
88+
89+
overrides.target = getTarget(overrides.target);
90+
91+
return <Promise<SweetAlertResult<Awaited<T>>>>DefaultSwal.fire(overrides);
5692
};
57-
const swalFireLoaderDefaults: SweetAlertOptions = {
58-
title: t("loading"),
59-
text: t("swal.dont_close_window"),
60-
timer: undefined,
61-
willOpen: () => Swal.showLoading(),
62-
allowOutsideClick: () => !Swal.isLoading(),
63-
allowEscapeKey: () => !Swal.isLoading(),
64-
};
65-
const swalFirePreventOverrides = { ...swalFirePreventDefaults, ...swal?.preventOverrides };
66-
const swalFireLoaderOverrides = { ...swalFireLoaderDefaults, ...swal?.loaderOverrides };
6793

68-
Swal.firePrevent = function <T>(firePreventOverrides: SweetAlertOptions = {}) {
69-
const overrides = Object.assign({}, swalFirePreventOverrides, firePreventOverrides);
94+
Swal.firePrevent = function <T>(swalPreventOverrides: tSwalOptions = {}) {
95+
const overrides = Object.assign({}, swalPreventDefaults, swalPreventOverrides);
7096

71-
return <Promise<SweetAlertResult<Awaited<T>>>>Swal.fire(overrides);
97+
overrides.target = getTarget(overrides.target);
98+
99+
return <Promise<SweetAlertResult<Awaited<T>>>>DefaultSwal.fire(overrides);
72100
};
73101

74-
Swal.fireLoader = function <T>(fireLoaderOverrides: SweetAlertOptions = {}) {
75-
const overrides = Object.assign({}, swalFireLoaderOverrides, fireLoaderOverrides);
102+
Swal.fireLoader = function <T>(swalLoaderOverrides: tSwalOptions = {}) {
103+
const overrides = Object.assign({}, swalLoaderDefaults, swalLoaderOverrides);
104+
105+
overrides.target = getTarget(overrides.target);
76106

77-
return <Promise<SweetAlertResult<Awaited<T>>>>Swal.fire(overrides);
107+
return <Promise<SweetAlertResult<Awaited<T>>>>DefaultSwal.fire(overrides);
78108
};
79109

80110
return Swal;

packages/common-types/src/form.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ export interface iFormInput<V extends iFormValue = iFormValue>
149149
/**
150150
* Sended form values
151151
*/
152-
export interface iFormResponse<R = any, T = any> {
152+
export interface iFormResponse<R = any> {
153153
response?: R;
154154
invalidInputs: iInvalidInput[];
155155
/**
@@ -169,12 +169,6 @@ export interface iFormResponse<R = any, T = any> {
169169
* 401 will be reported but not failed
170170
*/
171171
errors?: any;
172-
/**
173-
* Swal target
174-
*
175-
* If the swal was triggered from a modal, then use it as render target
176-
*/
177-
modalTarget?: T;
178172
}
179173

180174
export interface iFetchResponse<R = any> {

packages/common-types/src/swal.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
import DefaultSwal, { type SweetAlertOptions, type SweetAlertResult } from "sweetalert2";
22

3+
export type tSwalOptions = Omit<SweetAlertOptions, "target"> & {
4+
target?: SweetAlertOptions["target"] | Event;
5+
};
6+
37
/**
48
* Extended SweetAlert2 class
59
*
10+
* Defaults should use Event as target
11+
*
612
* Do not deestructure this
713
*/
8-
export type tSwal = typeof DefaultSwal & {
9-
firePrevent: <T = unknown>(
10-
options?: SweetAlertOptions
11-
) => Promise<SweetAlertResult<Awaited<T>>>;
14+
export type tSwal = Omit<typeof DefaultSwal, "fire"> & {
15+
fire: <T = any>(options?: tSwalOptions) => Promise<SweetAlertResult<Awaited<T>>>;
16+
firePrevent: <T = any>(options?: tSwalOptions) => Promise<SweetAlertResult<Awaited<T>>>;
17+
fireLoader: <T = any>(options?: tSwalOptions) => Promise<SweetAlertResult<Awaited<T>>>;
1218
firePreventDefaults: SweetAlertOptions;
13-
fireLoader: <T = unknown>(options?: SweetAlertOptions) => Promise<SweetAlertResult<Awaited<T>>>;
1419
fireLoaderDefaults: SweetAlertOptions;
1520
};

packages/common-types/src/values.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ export interface iSelectOption {
99
*
1010
* Useful for table actions like creating, updating and deleting nodes
1111
*/
12-
export type iNodeFn<T extends Record<string, any>> = (
13-
n: T
12+
export type iNodeFn<T extends Record<string, any>, Ta extends [T?] = [T]> = (
13+
...args: Ta
1414
) => boolean | undefined | Promise<boolean | undefined>;
1515

1616
/**
@@ -21,5 +21,17 @@ export interface iProperty<T extends Record<string, any> = Record<string, any>>
2121
/**
2222
* Function to create a node within the relation
2323
*/
24-
createNode?: (n?: T) => boolean | undefined | Promise<boolean | undefined>;
24+
createNode?: iNodeFn<T, [T?]>;
25+
/**
26+
* Function to clone a node within the relation
27+
*/
28+
cloneNode?: iNodeFn<T, [T?]>;
29+
/**
30+
* Function to update a node within the relation
31+
*/
32+
updateNode?: iNodeFn<T, [T?]>;
33+
/**
34+
* Function to delete a node within the relation
35+
*/
36+
deleteNode?: iNodeFn<T, [T?]>;
2537
}

packages/components-vue/src/components/components.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as ActionButtonLink from "./action/ButtonLink.stories";
88
<div className="view-item">
99
<div className="holder flx --flxColumn --flx-center-start --gap-30">
1010
<h1 className="--txtColor">Vue components playground</h1>
11-
<div className="txt --gaping-none">
11+
<div className="txt --gap-none">
1212
<p className="--txtWeight-bold">Test your vue components here</p>
1313
<p className="--txtSize-sm --txtColor-dark5">
1414
Also please remember to not version anything within this playground

packages/components-vue/src/components/form/Input.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
>
1212
<div
1313
v-if="!!input.options?.length"
14-
class="flx --flxRow-wrap --flx-center --flx-start-center:md --maxWidth-440"
14+
class="flx --flxRow-wrap --flx-start-center --gap-5 --gap-10:sm --gap:md"
1515
>
1616
<component
1717
:is="input.multiple ? ActionButtonToggle : ActionButton"

packages/components-vue/src/components/form/InputLoop.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
/**
5959
* Require options
6060
*
61+
* TODO: automatically add additional inputs (less clicks or remove add button)
62+
*
6163
* @component
6264
*/
6365

0 commit comments

Comments
 (0)