@mouseless/baked 1.6.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/Bake.vue +1 -1
  3. package/dist/runtime/components/Button.vue +2 -1
  4. package/dist/runtime/components/DataContainer.vue +31 -14
  5. package/dist/runtime/components/FormPage.vue +1 -0
  6. package/dist/runtime/components/Input.d.vue.ts +9 -1
  7. package/dist/runtime/components/Input.vue +25 -6
  8. package/dist/runtime/components/Input.vue.d.ts +9 -1
  9. package/dist/runtime/components/InputNumber.vue +7 -7
  10. package/dist/runtime/components/InputText.vue +7 -7
  11. package/dist/runtime/components/Inputs.d.vue.ts +7 -0
  12. package/dist/runtime/components/Inputs.vue +5 -19
  13. package/dist/runtime/components/Inputs.vue.d.ts +7 -0
  14. package/dist/runtime/components/Labeler.vue +1 -4
  15. package/dist/runtime/components/Message.vue +17 -4
  16. package/dist/runtime/components/NavLink.vue +5 -2
  17. package/dist/runtime/components/Select.vue +8 -9
  18. package/dist/runtime/components/SelectButton.vue +8 -8
  19. package/dist/runtime/components/SimpleForm.vue +26 -19
  20. package/dist/runtime/components/Validation.d.vue.ts +1 -0
  21. package/dist/runtime/components/Validation.vue +24 -5
  22. package/dist/runtime/components/Validation.vue.d.ts +1 -0
  23. package/dist/runtime/composables/useContext.d.ts +7 -1
  24. package/dist/runtime/composables/useContext.js +32 -2
  25. package/dist/runtime/composables/useReactionHandler.js +2 -1
  26. package/dist/runtime/composables/useRedirect.d.ts +1 -1
  27. package/dist/runtime/composables/useRedirect.js +7 -1
  28. package/dist/runtime/composables/useValidation.d.ts +8 -0
  29. package/dist/runtime/composables/useValidation.js +42 -4
  30. package/package.json +3 -2
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mouseless/baked",
3
3
  "configKey": "baked",
4
- "version": "1.6.0",
4
+ "version": "1.6.2",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
@@ -73,7 +73,7 @@ const errorHandled = context.provideError(rawError);
73
73
  const error = normalizeError(rawError);
74
74
  context.providePath(path);
75
75
  context.provideDataDescriptor(descriptor.data);
76
- context.provideParentContext({ ...contextData.parent, data });
76
+ context.provideParentContext({ ...contextData.parent, data, grand: contextData.parent });
77
77
  if (shouldLoad) {
78
78
  context.provideLoading(loading);
79
79
  }
@@ -6,6 +6,7 @@
6
6
  :label="l(label)"
7
7
  :rounded
8
8
  :severity
9
+ :size
9
10
  :variant
10
11
  @click="$emit('submit')"
11
12
  />
@@ -21,6 +22,6 @@ const { schema } = defineProps({
21
22
  ready: { type: Boolean, default: true }
22
23
  });
23
24
  defineEmits(["submit"]);
24
- const { icon, label, rounded, severity = "secondary", variant } = schema;
25
+ const { icon, label, rounded, severity = "secondary", size, variant } = schema;
25
26
  const executing = context.injectExecuting();
26
27
  </script>
@@ -7,19 +7,36 @@
7
7
  "
8
8
  >
9
9
  <div
10
- v-if="inputs.length > 0"
11
- class="
12
- py-2 px-4
13
- bg-transparent
14
- rounded-none text-sm
15
- flex gap-2 items-center justify-end
16
- "
10
+ v-if="actions.length || inputs.length"
11
+ class="w-full flex justify-between py-2 px-4"
17
12
  >
18
- <Inputs
19
- :inputs="inputs"
20
- @ready="onReady"
21
- @changed="onChanged"
22
- />
13
+ <div
14
+ class="
15
+ min-w-min flex gap-2 row-span-2 items-end text-nowrap
16
+ max-xs:text-xs max-md:text-sm
17
+ md:max-md:items-center
18
+ "
19
+ >
20
+ <Bake
21
+ v-for="action in actions"
22
+ :key="action.schema.name"
23
+ :name="`actions/${action.schema.name}`"
24
+ :descriptor="action"
25
+ />
26
+ </div>
27
+ <div
28
+ class="
29
+ bg-transparent
30
+ rounded-none text-sm
31
+ flex gap-2 items-center justify-end
32
+ "
33
+ >
34
+ <Inputs
35
+ :inputs="inputs"
36
+ @ready="onReady"
37
+ @changed="onChanged"
38
+ />
39
+ </div>
23
40
  </div>
24
41
  <div
25
42
  class="p-4 [contain:inline-size]"
@@ -49,7 +66,7 @@ const { localize: lc } = useLocalization({ group: "DataContainer" });
49
66
  const { schema } = defineProps({
50
67
  schema: { type: null, required: true }
51
68
  });
52
- const { content, inputs } = schema;
69
+ const { actions = [], content, inputs } = schema;
53
70
  const contextData = context.injectContextData();
54
71
  const loaded = ref(true);
55
72
  const ready = ref(inputs.length === 0);
@@ -68,5 +85,5 @@ function onChanged(event) {
68
85
  </script>
69
86
 
70
87
  <style>
71
- .p-panel-content:has(.b-component--DataContainer) .b-component--DataContainer{@apply border-none rounded-none}.b-component--DataContainer div{@apply [&:has(.p-datatable)]:p-0}
88
+ .p-panel-content:has(.b-component--DataContainer) .b-component--DataContainer{@apply border-none rounded-none}.b-component--DataContainer div{@apply [&:has(.p-datatable)]:p-0}.b-component--DataContainer .p-button{@apply self-stretch}.b-component--DataContainer .p-button .p-button-icon+.p-button-label{@apply max-sm:hidden}
72
89
  </style>
@@ -74,6 +74,7 @@
74
74
  >
75
75
  <Inputs
76
76
  :inputs="inputGroup.inputs"
77
+ form-mode
77
78
  input-class="w-full"
78
79
  @ready="(value) => onReady(`${section.key}_${inputGroup.key}`, value)"
79
80
  @changed="onChanged"
@@ -5,6 +5,9 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
5
5
  type: ObjectConstructor;
6
6
  required: true;
7
7
  };
8
+ formMode: {
9
+ type: BooleanConstructor;
10
+ };
8
11
  modelValue: {
9
12
  type: import("vue").PropType<any>;
10
13
  required: true;
@@ -16,10 +19,15 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
16
19
  type: ObjectConstructor;
17
20
  required: true;
18
21
  };
22
+ formMode: {
23
+ type: BooleanConstructor;
24
+ };
19
25
  modelValue: {
20
26
  type: import("vue").PropType<any>;
21
27
  required: true;
22
28
  };
23
29
  }>> & Readonly<{
24
30
  "onUpdate:modelValue"?: ((value: any) => any) | undefined;
25
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
31
+ }>, {
32
+ formMode: boolean;
33
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -3,11 +3,13 @@
3
3
  v-model="model"
4
4
  :name="schema.name"
5
5
  :descriptor="schema.component"
6
+ :invalid
7
+ @blur="onBlur"
6
8
  />
7
9
  </template>
8
10
 
9
11
  <script setup>
10
- import { computed, watch } from "vue";
12
+ import { computed, ref, watch } from "vue";
11
13
  import { useRoute, useRouter } from "#app";
12
14
  import { useDataMounter, useContext } from "#imports";
13
15
  import { Bake } from "#components";
@@ -15,15 +17,32 @@ const context = useContext();
15
17
  const { mount: mountData, onAfterMount: onAfterMountData } = useDataMounter();
16
18
  const route = useRoute();
17
19
  const router = useRouter();
18
- const { schema } = defineProps({
19
- schema: { type: Object, required: true }
20
+ const { schema, formMode } = defineProps({
21
+ schema: { type: Object, required: true },
22
+ formMode: { type: Boolean }
20
23
  });
21
24
  const model = defineModel({ type: null, required: true });
22
25
  const validations = context.injectValidations();
26
+ const mutableValidations = context.injectMutableValidations();
23
27
  const defaultValue = mountData(schema.default);
24
28
  const query = schema.queryBound ? computed(() => route.query[schema.name]) : void 0;
25
- const validation = computed(() => validations.value[schema.name] || {});
26
- context.provideValidation(validation);
29
+ let validation = void 0;
30
+ let mutableValidation = void 0;
31
+ let touched = void 0;
32
+ let invalidInForm = void 0;
33
+ let invalid = void 0;
34
+ let onBlur = void 0;
35
+ if (validations) {
36
+ validation = computed(() => validations.value[schema.name]);
37
+ mutableValidation = ref({ valid: true });
38
+ touched = ref(false);
39
+ invalidInForm = computed(() => !validation.value?.valid && (validation.value?.persist || touched.value));
40
+ invalid = computed(() => !mutableValidation.value.valid || invalidInForm.value);
41
+ onBlur = () => touched.value = true;
42
+ mutableValidations[schema.name] = mutableValidation;
43
+ context.provideValidation(validation);
44
+ context.provideMutableValidation(mutableValidation);
45
+ }
27
46
  onAfterMountData(async () => {
28
47
  if (!checkValue(model.value)) {
29
48
  if (schema.queryBound && checkValue(query.value)) {
@@ -43,7 +62,7 @@ onAfterMountData(async () => {
43
62
  }, { immediate: true });
44
63
  }
45
64
  watch(model, async (newValue) => {
46
- if (!checkValue(newValue)) {
65
+ if (!checkValue(newValue) && !formMode) {
47
66
  newValue = schema.required ? defaultValue.value : void 0;
48
67
  }
49
68
  await set(newValue);
@@ -5,6 +5,9 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
5
5
  type: ObjectConstructor;
6
6
  required: true;
7
7
  };
8
+ formMode: {
9
+ type: BooleanConstructor;
10
+ };
8
11
  modelValue: {
9
12
  type: import("vue").PropType<any>;
10
13
  required: true;
@@ -16,10 +19,15 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
16
19
  type: ObjectConstructor;
17
20
  required: true;
18
21
  };
22
+ formMode: {
23
+ type: BooleanConstructor;
24
+ };
19
25
  modelValue: {
20
26
  type: import("vue").PropType<any>;
21
27
  required: true;
22
28
  };
23
29
  }>> & Readonly<{
24
30
  "onUpdate:modelValue"?: ((value: any) => any) | undefined;
25
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
31
+ }>, {
32
+ formMode: boolean;
33
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -1,10 +1,10 @@
1
1
  <template>
2
- <AwaitLoading>
3
- <template #loading>
4
- <div class="min-w-60">
5
- <Skeleton class="min-h-10" />
6
- </div>
7
- </template>
2
+ <AwaitLoading
3
+ :skeleton="{
4
+ height: label?.mode === 'ifta' ? '3.6rem' : '2.6rem',
5
+ class: 'min-w-60'
6
+ }"
7
+ >
8
8
  <Validation>
9
9
  <Labeler
10
10
  :label
@@ -23,7 +23,7 @@
23
23
  </template>
24
24
 
25
25
  <script setup>
26
- import { InputNumber, Skeleton } from "primevue";
26
+ import { InputNumber } from "primevue";
27
27
  import { useContext } from "#imports";
28
28
  import { AwaitLoading, Labeler, Validation } from "#components";
29
29
  const context = useContext();
@@ -1,10 +1,10 @@
1
1
  <template>
2
- <AwaitLoading>
3
- <template #loading>
4
- <div class="min-w-60">
5
- <Skeleton class="min-h-10" />
6
- </div>
7
- </template>
2
+ <AwaitLoading
3
+ :skeleton="{
4
+ height: label?.mode === 'ifta' ? '3.6rem' : '2.6rem',
5
+ class: 'min-w-60'
6
+ }"
7
+ >
8
8
  <Validation>
9
9
  <Labeler
10
10
  :label
@@ -23,7 +23,7 @@
23
23
 
24
24
  <script setup>
25
25
  import { ref, watch } from "vue";
26
- import { InputText, Skeleton } from "primevue";
26
+ import { InputText } from "primevue";
27
27
  import { useContext } from "#imports";
28
28
  import { AwaitLoading, Labeler, Validation } from "#components";
29
29
  const context = useContext();
@@ -5,6 +5,9 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
5
5
  type: ArrayConstructor;
6
6
  required: true;
7
7
  };
8
+ formMode: {
9
+ type: BooleanConstructor;
10
+ };
8
11
  inputClass: {
9
12
  type: StringConstructor;
10
13
  default: string;
@@ -17,6 +20,9 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
17
20
  type: ArrayConstructor;
18
21
  required: true;
19
22
  };
23
+ formMode: {
24
+ type: BooleanConstructor;
25
+ };
20
26
  inputClass: {
21
27
  type: StringConstructor;
22
28
  default: string;
@@ -25,5 +31,6 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
25
31
  onReady?: ((...args: any[]) => any) | undefined;
26
32
  onChanged?: ((...args: any[]) => any) | undefined;
27
33
  }>, {
34
+ formMode: boolean;
28
35
  inputClass: string;
29
36
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -4,26 +4,24 @@
4
4
  :key="input.name"
5
5
  v-model="models[input.name]"
6
6
  :schema="input"
7
+ :form-mode
7
8
  :class="inputClass"
8
- :invalid="invalid(input.name)"
9
- @blur="() => touched(input.name)"
10
9
  />
11
10
  </template>
12
11
 
13
12
  <script setup>
14
- import { computed, reactive, ref, watch } from "vue";
13
+ import { computed, reactive, watch } from "vue";
15
14
  import { useContext, useRoute } from "#imports";
16
15
  import { Input } from "#components";
17
16
  const context = useContext();
18
17
  const route = useRoute();
19
- const { inputs } = defineProps({
18
+ const { inputs, formMode } = defineProps({
20
19
  inputs: { type: Array, required: true },
20
+ formMode: { type: Boolean },
21
21
  inputClass: { type: String, default: "" }
22
22
  });
23
23
  const emit = defineEmits(["ready", "changed"]);
24
24
  const parentPath = context.injectPath();
25
- const validations = context.injectValidations();
26
- const inputEvents = ref({});
27
25
  const models = reactive({});
28
26
  const values = computed(
29
27
  () => inputs.reduce((result, input) => {
@@ -33,7 +31,7 @@ const values = computed(
33
31
  );
34
32
  context.providePath(`${parentPath}/inputs`);
35
33
  watch(values, (newValues) => {
36
- if (inputs.filter((i) => i.default || i.defaultSelfManaged).some((i) => !checkValue(newValues[i.name]))) {
34
+ if (!formMode && inputs.filter((i) => i.default || i.defaultSelfManaged).some((i) => !checkValue(newValues[i.name]))) {
37
35
  return;
38
36
  }
39
37
  emitChanged();
@@ -64,16 +62,4 @@ function getValue(input) {
64
62
  return models[input.name];
65
63
  }
66
64
  }
67
- function touched(key) {
68
- inputEvents.value[key] = { touched: true };
69
- }
70
- function invalid(input) {
71
- if (!Object.values(validations.value).length) {
72
- return;
73
- }
74
- if (!validations.value[input]?.valid && validations.value[input]?.persist) {
75
- return true;
76
- }
77
- return !validations.value[input]?.valid && inputEvents.value[input]?.touched || false;
78
- }
79
65
  </script>
@@ -5,6 +5,9 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
5
5
  type: ArrayConstructor;
6
6
  required: true;
7
7
  };
8
+ formMode: {
9
+ type: BooleanConstructor;
10
+ };
8
11
  inputClass: {
9
12
  type: StringConstructor;
10
13
  default: string;
@@ -17,6 +20,9 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
17
20
  type: ArrayConstructor;
18
21
  required: true;
19
22
  };
23
+ formMode: {
24
+ type: BooleanConstructor;
25
+ };
20
26
  inputClass: {
21
27
  type: StringConstructor;
22
28
  default: string;
@@ -25,5 +31,6 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
25
31
  onReady?: ((...args: any[]) => any) | undefined;
26
32
  onChanged?: ((...args: any[]) => any) | undefined;
27
33
  }>, {
34
+ formMode: boolean;
28
35
  inputClass: string;
29
36
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -12,10 +12,7 @@
12
12
  >
13
13
  <template #default>
14
14
  <slot />
15
- <label
16
- class="max-sm:truncate max-sm:w-5/6"
17
- :for="path"
18
- >
15
+ <label :for="path">
19
16
  {{ localizedText }}
20
17
  </label>
21
18
  </template>
@@ -1,6 +1,10 @@
1
1
  <template>
2
2
  <div
3
- class="b-message grid"
3
+ class="
4
+ b-message
5
+ grid grid-cols-[1fr_auto] gap-2
6
+ items-center
7
+ "
4
8
  :class="[`message-${severity}`, `message-${variant}`]"
5
9
  >
6
10
  <div class="min-h-0">
@@ -25,18 +29,27 @@
25
29
  <slot name="content" />
26
30
  </div>
27
31
  </div>
32
+ <div
33
+ v-if="action"
34
+ class="b-message-action px-2"
35
+ >
36
+ <Bake
37
+ name="action"
38
+ :descriptor="{ ...action, schema: { ...action.schema, severity } }"
39
+ />
40
+ </div>
28
41
  </div>
29
42
  </template>
30
43
 
31
44
  <script setup>
32
45
  import { computed, useLocalization } from "#imports";
33
- import { AwaitLoading } from "#components";
46
+ import { AwaitLoading, Bake } from "#components";
34
47
  const { localize: l } = useLocalization();
35
48
  const { schema, data } = defineProps({
36
49
  schema: { type: null, required: true },
37
50
  data: { type: null, required: true }
38
51
  });
39
- const { icon, localizeMessage, severity = "info", size, variant = "outlined" } = schema;
52
+ const { action, icon, localizeMessage, severity = "info", size, variant = "outlined" } = schema;
40
53
  const sizeClass = computed(() => {
41
54
  switch (size) {
42
55
  case "small":
@@ -50,7 +63,7 @@ const sizeClass = computed(() => {
50
63
  </script>
51
64
 
52
65
  <style scoped>
53
- .message-outlined{@apply border rounded-md}.message-outlined .b-message-body{@apply py-[0.50rem] px-[0.75rem] min-w-[10rem] min-h-[1.5rem]}.message-simple{@apply !bg-transparent}.message-simple .b-message-body{@apply px-0}.message-info{@apply bg-blue-50/95 text-blue-600 border-blue-200
66
+ .message-outlined{@apply border rounded-md}.message-outlined .b-message-body{@apply py-[0.50rem] px-[0.75rem] min-w-[10rem] min-h-[1.5rem]}.message-simple{@apply !bg-transparent}.message-simple .b-message-icon{@apply text-sm}.message-simple .b-message-body{@apply px-0}.message-info{@apply bg-blue-50/95 text-blue-600 border-blue-200
54
67
  dark:bg-blue-950/95 dark:text-blue-500 dark:border-blue-700/65}.message-error{@apply bg-red-50/95 text-red-600 border-red-200
55
68
  dark:bg-red-950/95 dark:text-red-500 dark:border-red-700/65}.message-warn{@apply bg-yellow-50/95 text-yellow-600 border-yellow-200
56
69
  dark:bg-yellow-950/95 dark:text-yellow-500 dark:border-yellow-700/65}.message-success{@apply bg-green-50/95 text-green-600 border-green-200
@@ -1,13 +1,15 @@
1
1
  <template>
2
2
  <AwaitLoading :skeleton="{ height: '1.5rem' }">
3
3
  <Button
4
+ v-if="data"
4
5
  :icon
5
- :label="data"
6
+ :label
6
7
  :to
7
8
  as="router-link"
8
9
  link
9
10
  class="m-0 p-0"
10
11
  />
12
+ <span v-else>-</span>
11
13
  </AwaitLoading>
12
14
  </template>
13
15
 
@@ -22,9 +24,10 @@ const { schema, data } = defineProps({
22
24
  schema: { type: null, required: true },
23
25
  data: { type: null, required: true }
24
26
  });
25
- const { icon, path, query: queryData, params: paramsData } = schema;
27
+ const { icon, labelProp, path, query: queryData, params: paramsData } = schema;
26
28
  const query = mountData(queryData);
27
29
  const params = mountData(paramsData);
30
+ const label = computed(() => labelProp ? data?.[labelProp] : data);
28
31
  const to = computed(() => ({
29
32
  path: params.value ? pathBuilder.build(path, params.value, { forRoute: true }) : path,
30
33
  query: query.value
@@ -1,10 +1,10 @@
1
1
  <template>
2
- <AwaitLoading>
3
- <template #loading>
4
- <div class="min-w-40">
5
- <Skeleton class="min-h-10" />
6
- </div>
7
- </template>
2
+ <AwaitLoading
3
+ :skeleton="{
4
+ height: label?.mode === 'ifta' ? '3.6rem' : '2.6rem',
5
+ class: 'min-w-40'
6
+ }"
7
+ >
8
8
  <Validation>
9
9
  <Labeler
10
10
  :label
@@ -21,7 +21,6 @@
21
21
  :auto-filter-focus="filter"
22
22
  :filter-fields="[optionLabel]"
23
23
  reset-filter-on-hide
24
- class="w-full"
25
24
  >
26
25
  <template #value="slotProps">
27
26
  <span>{{ getValueLabel(slotProps) }}</span>
@@ -37,7 +36,7 @@
37
36
 
38
37
  <script setup>
39
38
  import { ref, watch } from "vue";
40
- import { Select, Skeleton } from "primevue";
39
+ import { Select } from "primevue";
41
40
  import { useContext, useUiStates, useLocalization } from "#imports";
42
41
  import { AwaitLoading, Labeler, Validation } from "#components";
43
42
  const context = useContext();
@@ -97,5 +96,5 @@ function setSelected(value) {
97
96
  </script>
98
97
 
99
98
  <style>
100
- .b-component--Select .p-placeholder{opacity:0}.b-component--Select .p-select-label{font-size:inherit}
99
+ .b-component--Select .p-placeholder{opacity:0}.b-component--Select .p-select-label{font-size:inherit}.p-popover-content .b-component--Select{@apply max-md:w-full}
101
100
  </style>
@@ -1,10 +1,10 @@
1
1
  <template>
2
- <AwaitLoading>
3
- <template #loading>
4
- <div class="min-w-60">
5
- <Skeleton class="min-h-10" />
6
- </div>
7
- </template>
2
+ <AwaitLoading
3
+ :skeleton="{
4
+ height: label?.mode === 'ifta' ? '3.6rem' : '2.6rem',
5
+ class: 'min-w-60'
6
+ }"
7
+ >
8
8
  <Validation>
9
9
  <Labeler
10
10
  :label="{
@@ -46,7 +46,7 @@
46
46
 
47
47
  <script setup>
48
48
  import { ref, watch } from "vue";
49
- import { SelectButton, Skeleton } from "primevue";
49
+ import { SelectButton } from "primevue";
50
50
  import { useContext, useLocalization, useUiStates } from "#imports";
51
51
  import { AwaitLoading, Labeler, Validation } from "#components";
52
52
  const context = useContext();
@@ -109,7 +109,7 @@ function setSelected(value) {
109
109
  </script>
110
110
 
111
111
  <style>
112
- .p-togglebutton-content{@apply whitespace-nowrap}.p-popover-content .b-component--SelectButton .p-selectbutton{@apply max-sm:flex max-sm:flex-col}.p-popover-content .b-component--SelectButton .p-selectbutton .p-togglebutton:first-child{@apply max-sm:rounded-t-lg max-sm:rounded-es-none}.p-popover-content .b-component--SelectButton .p-selectbutton .p-togglebutton:last-child{@apply max-sm:rounded-b-lg max-sm:rounded-se-none}
112
+ .p-togglebutton-content{@apply whitespace-nowrap}.p-popover-content .b-component--SelectButton .p-selectbutton,.p-popover-content .b-component--SelectButton.p-selectbutton{@apply max-sm:flex max-sm:flex-col}.p-popover-content .b-component--SelectButton .p-selectbutton .p-togglebutton:first-child,.p-popover-content .b-component--SelectButton.p-selectbutton .p-togglebutton:first-child{@apply max-sm:rounded-t-lg max-sm:rounded-es-none}.p-popover-content .b-component--SelectButton .p-selectbutton .p-togglebutton:last-child,.p-popover-content .b-component--SelectButton.p-selectbutton .p-togglebutton:last-child{@apply max-sm:rounded-b-lg max-sm:rounded-se-none}
113
113
  </style>
114
114
 
115
115
  <style scoped>
@@ -55,34 +55,41 @@
55
55
  <template v-else>
56
56
  <div
57
57
  v-bind="$attrs"
58
- class="flex flex-col gap-8"
58
+ class="flex flex-col gap-4"
59
+ :class="{ 'gap-8': !horizontal }"
59
60
  >
60
- <h1 class="font-bold text-xl truncate">
61
+ <h2 class="font-bold text-xl truncate">
61
62
  {{ l(title) }}
62
- </h1>
63
- <div class="flex flex-col gap-4">
63
+ </h2>
64
+ <div
65
+ class="flex gap-4"
66
+ :class="{ 'flex-col': !horizontal }"
67
+ >
64
68
  <Inputs
65
69
  v-if="inputs"
66
70
  :inputs
71
+ form-mode
67
72
  input-class="w-full"
68
73
  @ready="onReady"
69
74
  @changed="onChanged"
70
75
  />
76
+ <Button
77
+ ref="submitRef"
78
+ v-tooltip.top="{
79
+ disabled: !showValidationSummary,
80
+ value: messages,
81
+ pt: { text: 'text-sm' }
82
+ }"
83
+ :schema="submit"
84
+ :ready
85
+ class="min-w-min"
86
+ :class="{ 'mt-4': !horizontal && inputs.length }"
87
+ @submit="$emit('submit', model)"
88
+ />
89
+ <ErrorPopover ref="errorPopoverRef">
90
+ <InlineError :error />
91
+ </ErrorPopover>
71
92
  </div>
72
- <Button
73
- ref="submitRef"
74
- v-tooltip.left="{
75
- disabled: !showValidationSummary,
76
- value: messages,
77
- pt: { text: 'text-sm' }
78
- }"
79
- :schema="submit"
80
- :ready
81
- @submit="$emit('submit', model)"
82
- />
83
- <ErrorPopover ref="errorPopoverRef">
84
- <InlineError :error />
85
- </ErrorPopover>
86
93
  </div>
87
94
  </template>
88
95
  </template>
@@ -99,7 +106,7 @@ const { schema } = defineProps({
99
106
  schema: { type: null, required: true }
100
107
  });
101
108
  const emit = defineEmits(["submit"]);
102
- const { dialogOptions, inputs, submit, title, validations = [], showValidationSummary = false } = schema;
109
+ const { dialogOptions, inputs, horizontal, submit, title, validations = [], showValidationSummary = false } = schema;
103
110
  const model = ref({});
104
111
  const readyData = ref({});
105
112
  const submitted = ref(false);
@@ -12,5 +12,6 @@ type __VLS_Slots = {
12
12
  } & {
13
13
  message?: ((props: {
14
14
  validation: any;
15
+ mutableValidation: any;
15
16
  }) => any) | undefined;
16
17
  };
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <template v-if="!validation">
2
+ <template v-if="validationHandled || !validation">
3
3
  <slot />
4
4
  </template>
5
5
  <div
@@ -10,15 +10,19 @@
10
10
  <slot
11
11
  name="message"
12
12
  :validation
13
+ :mutable-validation
13
14
  >
14
15
  <Message
15
- v-if="validation.message && validation.persist"
16
+ v-if="message"
17
+ :key="`${severity}:${icon}`"
18
+ icon="pi pi-info-circle"
16
19
  :schema="{
17
- severity: validation.severity,
20
+ severity,
18
21
  variant: 'simple',
19
- size: 'small'
22
+ size: 'small',
23
+ icon
20
24
  }"
21
- :data="validation.message || ''"
25
+ :data="message || ''"
22
26
  class="ml-3"
23
27
  />
24
28
  </slot>
@@ -26,8 +30,23 @@
26
30
  </template>
27
31
 
28
32
  <script setup>
33
+ import { computed } from "vue";
29
34
  import { useContext } from "#imports";
30
35
  import { Message } from "#components";
31
36
  const context = useContext();
37
+ const validationHandled = context.injectValidationHandled();
32
38
  const validation = context.injectValidation();
39
+ const mutableValidation = context.injectMutableValidation();
40
+ context.provideValidationHandled(true);
41
+ const message = computed(() => {
42
+ if (mutableValidation?.value.message) {
43
+ return mutableValidation.value.message;
44
+ }
45
+ if (validation.value?.message && validation.value?.persist) {
46
+ return validation.value.message;
47
+ }
48
+ return null;
49
+ });
50
+ const severity = computed(() => mutableValidation?.value.severity || validation?.value.severity);
51
+ const icon = computed(() => mutableValidation?.value.icon || validation?.value.icon);
33
52
  </script>
@@ -12,5 +12,6 @@ type __VLS_Slots = {
12
12
  } & {
13
13
  message?: ((props: {
14
14
  validation: any;
15
+ mutableValidation: any;
15
16
  }) => any) | undefined;
16
17
  };
@@ -17,12 +17,18 @@ export default function _default(): {
17
17
  provideExecuting: (value: any) => void;
18
18
  injectLoading: () => import("vue").Ref<boolean, boolean>;
19
19
  provideLoading: (value: any) => void;
20
+ injectMutableValidations: () => {};
21
+ provideMutableValidations: (value: any) => void;
22
+ injectMutableValidation: () => null;
23
+ provideMutableValidation: (value: any) => void;
20
24
  injectPageContext: () => any;
21
25
  providePageContext: (value: any) => void;
22
26
  injectParentContext: () => null;
23
27
  provideParentContext: (value: any) => void;
24
- injectValidations: () => import("vue").Ref<{}, {}>;
28
+ injectValidations: () => null;
25
29
  provideValidations: (value: any) => void;
26
30
  injectValidation: () => null;
27
31
  provideValidation: (value: any) => void;
32
+ injectValidationHandled: () => boolean;
33
+ provideValidationHandled: (value: any) => void;
28
34
  };
@@ -71,6 +71,22 @@ export default function() {
71
71
  provide("__bake_loading", value);
72
72
  }
73
73
 
74
+ function injectMutableValidations() {
75
+ return inject("__bake_mutable_validations", {});
76
+ }
77
+
78
+ function provideMutableValidations(value) {
79
+ provide("__bake_mutable_validations", value);
80
+ }
81
+
82
+ function injectMutableValidation() {
83
+ return inject("__bake_mutable_validation", null);
84
+ }
85
+
86
+ function provideMutableValidation(value) {
87
+ provide("__bake_mutable_validation", value);
88
+ }
89
+
74
90
  function injectPageContext() {
75
91
  return inject("__bake_page_context");
76
92
  }
@@ -88,7 +104,7 @@ export default function() {
88
104
  }
89
105
 
90
106
  function injectValidations() {
91
- return inject("__bake_validations", ref({}));
107
+ return inject("__bake_validations", null);
92
108
  }
93
109
 
94
110
  function provideValidations(value) {
@@ -103,6 +119,14 @@ export default function() {
103
119
  provide("__bake_validation", value);
104
120
  }
105
121
 
122
+ function injectValidationHandled() {
123
+ return inject("__bake_validation_handled", false);
124
+ }
125
+
126
+ function provideValidationHandled(value) {
127
+ provide("__bake_validation_handled", value);
128
+ }
129
+
106
130
  return {
107
131
  injectPath,
108
132
  providePath,
@@ -117,6 +141,10 @@ export default function() {
117
141
  provideExecuting,
118
142
  injectLoading,
119
143
  provideLoading,
144
+ injectMutableValidations,
145
+ provideMutableValidations,
146
+ injectMutableValidation,
147
+ provideMutableValidation,
120
148
  injectPageContext,
121
149
  providePageContext,
122
150
  injectParentContext,
@@ -124,6 +152,8 @@ export default function() {
124
152
  injectValidations,
125
153
  provideValidations,
126
154
  injectValidation,
127
- provideValidation
155
+ provideValidation,
156
+ injectValidationHandled,
157
+ provideValidationHandled
128
158
  };
129
159
  }
@@ -74,7 +74,8 @@ function On({ evaluate, eventId, events }) {
74
74
 
75
75
  function When({ contextData, evaluate }) {
76
76
  function bind({ trigger, react }) {
77
- watch(() => contextData.page[trigger.when], async value => {
77
+ watch(() => contextData[trigger.key ?? "page"][trigger.when], async value => {
78
+ react(false);
78
79
  react(await evaluate(trigger.constraint, value));
79
80
  }, { immediate: true });
80
81
 
@@ -1,3 +1,3 @@
1
1
  export default function _default(): {
2
- run: ({ route, back, expected, actual }?: {}) => Promise<void>;
2
+ run: ({ route, back, expected, actual, ...params }?: {}) => Promise<void>;
3
3
  };
@@ -1,11 +1,17 @@
1
1
  import { useRouter } from "#app";
2
+ import { usePathBuilder } from "#imports";
2
3
 
3
4
  export default function() {
4
5
  const router = useRouter();
6
+ const { build } = usePathBuilder();
5
7
 
6
- async function run({ route, back, expected, actual } = {}) {
8
+ async function run({ route, back, expected, actual, ...params } = {}) {
7
9
  if(expected && actual !== expected) { return; }
8
10
 
11
+ if(route && Object.keys(params).length > 0) {
12
+ route = build(route, params, { forRoute: true });
13
+ }
14
+
9
15
  if(back) {
10
16
  router.back();
11
17
  } else {
@@ -8,4 +8,12 @@ export default function _default(): {
8
8
  messages: import("vue").ComputedRef<string>;
9
9
  validations: import("vue").ComputedRef<any>;
10
10
  };
11
+ injectMutable: () => {
12
+ clear: () => void;
13
+ setError: (message: any) => void;
14
+ setMessage: (message: any, { persist, severity, icon }?: {
15
+ persist?: boolean | undefined;
16
+ severity?: string | undefined;
17
+ }) => void;
18
+ } | null;
11
19
  };
@@ -26,15 +26,19 @@ export default function() {
26
26
  }), {})
27
27
  );
28
28
 
29
+ const mutableValidations = {};
30
+
29
31
  context.provideValidations(validations);
32
+ context.provideMutableValidations(mutableValidations);
30
33
 
31
34
  const isValid = computed(() =>
32
- Object.values(validations.value).every(v => v.valid)
35
+ Object.values(validations.value).every(v => v.valid) &&
36
+ Object.values(mutableValidations).every(v => v.value.valid)
33
37
  );
34
38
 
35
39
  const messages = computed(() =>
36
- Object.values(validations.value)
37
- .filter(v => v.message)
40
+ [...Object.values(validations.value), ...Object.values(mutableValidations).map(v => v.value)]
41
+ .filter(v => v.message && v.severity === "error")
38
42
  .map((v, i) => `${i > 0 ? "\n" : ""} - ${v.message}`)
39
43
  .join("")
40
44
  );
@@ -42,7 +46,41 @@ export default function() {
42
46
  return { isValid, messages, validations };
43
47
  }
44
48
 
49
+ function injectMutable() {
50
+ const ref = context.injectMutableValidation();
51
+ if(!ref) { return null; }
52
+
53
+ return MutableValidation(ref);
54
+ }
55
+
56
+ return {
57
+ validate,
58
+ injectMutable
59
+ };
60
+ }
61
+
62
+ function MutableValidation(ref) {
63
+ function clear() {
64
+ ref.value.valid = true;
65
+ delete ref.value.message;
66
+ delete ref.value.severity;
67
+ }
68
+
69
+ function setError(message) {
70
+ setMessage(message, { persist: true, severity: "error" });
71
+ }
72
+
73
+ function setMessage(message, { persist = false, severity = "secondary", icon } = {}) {
74
+ ref.value.valid = severity !== "error";
75
+ ref.value.message = message;
76
+ ref.value.persist = persist;
77
+ ref.value.severity = severity;
78
+ ref.value.icon = icon;
79
+ }
80
+
45
81
  return {
46
- validate
82
+ clear,
83
+ setError,
84
+ setMessage
47
85
  };
48
86
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mouseless/baked",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "Baked is an opinionated framework for .NET and Vue. This is the UI package of Baked project.",
5
5
  "keywords": [
6
6
  "baked",
@@ -47,6 +47,7 @@
47
47
  "@nuxtjs/tailwindcss": "6.14.0",
48
48
  "@primeuix/themes": "2.0.3",
49
49
  "async-mutex": "0.5.0",
50
+ "playwright": "^1.60.0",
50
51
  "primeicons": "7.0.0",
51
52
  "primevue": "4.5.5"
52
53
  },
@@ -71,4 +72,4 @@
71
72
  "@oxc-parser/binding-linux-x64-musl": "0.133.0",
72
73
  "@oxc-parser/binding-win32-x64-msvc": "0.133.0"
73
74
  }
74
- }
75
+ }