@vc-shell/framework 1.0.189 → 1.0.190

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 (66) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/core/types/index.ts +12 -1
  3. package/dist/core/types/index.d.ts +1 -1
  4. package/dist/core/types/index.d.ts.map +1 -1
  5. package/dist/framework.js +30667 -20092
  6. package/dist/index.css +1 -1
  7. package/dist/shared/components/error-interceptor/interceptor.d.ts.map +1 -1
  8. package/dist/shared/modules/dynamic/components/fields/EditorField.d.ts.map +1 -1
  9. package/dist/shared/modules/dynamic/components/fields/InputField.d.ts.map +1 -1
  10. package/dist/shared/modules/dynamic/components/fields/TextareaField.d.ts.map +1 -1
  11. package/dist/shared/modules/dynamic/components/fields/storybook/Card.stories.d.ts.map +1 -1
  12. package/dist/shared/modules/dynamic/components/fields/storybook/Checkbox.stories.d.ts.map +1 -1
  13. package/dist/shared/modules/dynamic/components/fields/storybook/ContentField.stories.d.ts.map +1 -1
  14. package/dist/shared/modules/dynamic/components/fields/storybook/EditorField.stories.d.ts +9 -0
  15. package/dist/shared/modules/dynamic/components/fields/storybook/EditorField.stories.d.ts.map +1 -1
  16. package/dist/shared/modules/dynamic/components/fields/storybook/InputField.stories.d.ts +12 -0
  17. package/dist/shared/modules/dynamic/components/fields/storybook/InputField.stories.d.ts.map +1 -1
  18. package/dist/shared/modules/dynamic/components/fields/storybook/TextareaField.stories.d.ts +12 -0
  19. package/dist/shared/modules/dynamic/components/fields/storybook/TextareaField.stories.d.ts.map +1 -1
  20. package/dist/shared/modules/dynamic/factories/types/index.d.ts +1 -0
  21. package/dist/shared/modules/dynamic/factories/types/index.d.ts.map +1 -1
  22. package/dist/shared/modules/dynamic/types/index.d.ts +15 -0
  23. package/dist/shared/modules/dynamic/types/index.d.ts.map +1 -1
  24. package/dist/tsconfig.tsbuildinfo +1 -1
  25. package/dist/ui/components/atoms/vc-card/vc-card.stories.d.ts +16 -16
  26. package/dist/ui/components/molecules/vc-editor/vc-editor.stories.d.ts +16 -4
  27. package/dist/ui/components/molecules/vc-editor/vc-editor.stories.d.ts.map +1 -1
  28. package/dist/ui/components/molecules/vc-editor/vc-editor.vue.d.ts +2 -1
  29. package/dist/ui/components/molecules/vc-editor/vc-editor.vue.d.ts.map +1 -1
  30. package/dist/ui/components/molecules/vc-input/vc-input.stories.d.ts +30 -16
  31. package/dist/ui/components/molecules/vc-input/vc-input.stories.d.ts.map +1 -1
  32. package/dist/ui/components/molecules/vc-input-currency/vc-input-currency.stories.d.ts +12 -12
  33. package/dist/ui/components/molecules/vc-textarea/vc-textarea.stories.d.ts +63 -63
  34. package/dist/ui/components/molecules/vc-textarea/vc-textarea.vue.d.ts +6 -6
  35. package/dist/ui/components/molecules/vc-textarea/vc-textarea.vue.d.ts.map +1 -1
  36. package/dist/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue.d.ts +1 -0
  37. package/dist/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue.d.ts.map +1 -1
  38. package/dist/ui/components/organisms/vc-table/_internal/vc-table-column-switcher/vc-table-column-switcher.vue.d.ts.map +1 -1
  39. package/dist/ui/components/organisms/vc-table/vc-table.stories.d.ts +8 -2
  40. package/dist/ui/components/organisms/vc-table/vc-table.stories.d.ts.map +1 -1
  41. package/dist/ui/components/organisms/vc-table/vc-table.vue.d.ts +3 -1
  42. package/dist/ui/components/organisms/vc-table/vc-table.vue.d.ts.map +1 -1
  43. package/package.json +8 -4
  44. package/shared/components/error-interceptor/interceptor.ts +1 -1
  45. package/shared/modules/dynamic/components/fields/EditorField.ts +1 -0
  46. package/shared/modules/dynamic/components/fields/InputField.ts +1 -0
  47. package/shared/modules/dynamic/components/fields/TextareaField.ts +1 -0
  48. package/shared/modules/dynamic/components/fields/storybook/Card.stories.ts +1 -2
  49. package/shared/modules/dynamic/components/fields/storybook/Checkbox.stories.ts +0 -1
  50. package/shared/modules/dynamic/components/fields/storybook/ContentField.stories.ts +1 -2
  51. package/shared/modules/dynamic/components/fields/storybook/EditorField.stories.ts +10 -3
  52. package/shared/modules/dynamic/components/fields/storybook/Fieldset.stories.ts +3 -3
  53. package/shared/modules/dynamic/components/fields/storybook/InputField.stories.ts +12 -0
  54. package/shared/modules/dynamic/components/fields/storybook/TextareaField.stories.ts +12 -0
  55. package/shared/modules/dynamic/factories/types/index.ts +2 -0
  56. package/shared/modules/dynamic/types/index.ts +15 -0
  57. package/shared/pages/LoginPage/components/login/Login.vue +1 -1
  58. package/ui/components/molecules/vc-editor/vc-editor.vue +24 -29
  59. package/ui/components/molecules/vc-input/vc-input.stories.ts +14 -0
  60. package/ui/components/molecules/vc-textarea/vc-textarea.stories.ts +1 -1
  61. package/ui/components/molecules/vc-textarea/vc-textarea.vue +4 -6
  62. package/ui/components/organisms/vc-blade/_internal/vc-blade-header/vc-blade-header.vue +1 -1
  63. package/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue +140 -108
  64. package/ui/components/organisms/vc-table/_internal/vc-table-column-switcher/vc-table-column-switcher.vue +20 -6
  65. package/ui/components/organisms/vc-table/vc-table.stories.ts +6 -2
  66. package/ui/components/organisms/vc-table/vc-table.vue +176 -125
@@ -25,6 +25,7 @@ export default {
25
25
  type: props.element.variant,
26
26
  currentLanguage: props.currentLocale,
27
27
  clearable: props.element.clearable || false,
28
+ maxlength: props.element.maxlength,
28
29
  },
29
30
  unrefNested(props.baseProps),
30
31
  {
@@ -16,6 +16,7 @@ export default {
16
16
  {
17
17
  currentLanguage: props.currentLocale,
18
18
  clearable: props.element.clearable || false,
19
+ maxlength: props.element.maxlength,
19
20
  },
20
21
  unrefNested(props.baseProps),
21
22
  {
@@ -1,7 +1,6 @@
1
1
  import { template, templateWithVisibilityToggle } from "./common/templates";
2
2
  import { Meta, StoryFn } from "@storybook/vue3";
3
- import Card from "../Card";
4
- import { computed, reactive, ref } from "vue";
3
+ import { reactive, ref } from "vue";
5
4
  import page from "./pages/DynamicRender";
6
5
  import * as _ from "lodash-es";
7
6
  import { SchemaBaseArgTypes } from "./common/args";
@@ -1,5 +1,4 @@
1
1
  import { Meta, StoryFn } from "@storybook/vue3";
2
- import Checkbox from "../Checkbox";
3
2
  import { computed, reactive, ref } from "vue";
4
3
  import page from "./pages/DynamicRender";
5
4
  import { template, templateWithVisibilityToggle } from "./common/templates";
@@ -1,6 +1,5 @@
1
1
  import { Meta, StoryFn } from "@storybook/vue3";
2
- import ContentField from "../ContentField";
3
- import { computed, reactive, ref } from "vue";
2
+ import { reactive, ref } from "vue";
4
3
  import page from "./pages/DynamicRender";
5
4
  import { template, templateWithVisibilityToggle } from "./common/templates";
6
5
  import * as _ from "lodash-es";
@@ -1,9 +1,7 @@
1
1
  import { Meta, StoryFn } from "@storybook/vue3";
2
- import EditorField from "../EditorField";
3
2
  import { template, templateWithVisibilityToggle } from "./common/templates";
4
3
  import page from "./pages/DynamicRender";
5
- import { nextTick, reactive, ref } from "vue";
6
- import * as _ from "lodash-es";
4
+ import { reactive, ref } from "vue";
7
5
  import { SchemaBaseArgTypes } from "./common/args";
8
6
  import { EditorSchema } from "../../..";
9
7
 
@@ -44,6 +42,15 @@ export default {
44
42
  },
45
43
  },
46
44
  },
45
+ maxlength: {
46
+ description: "Maximum length of the editor content.",
47
+ control: "number",
48
+ table: {
49
+ type: {
50
+ summary: "number",
51
+ },
52
+ },
53
+ },
47
54
  },
48
55
  parameters: {
49
56
  docs: {
@@ -73,13 +73,13 @@ export default {
73
73
  description: `Array of numbers that define the aspect ratio of each column.
74
74
  Example - If you have two columns - set to [1, 1] to make all columns equal width.
75
75
  Uses CSS flex-grow property to set the width of each column.`,
76
- control: "text",
76
+ control: "object",
77
77
  table: {
78
78
  type: {
79
- summary: "string",
79
+ summary: "array",
80
80
  },
81
81
  defaultValue: {
82
- summary: "1:1",
82
+ summary: "[1, 1]",
83
83
  },
84
84
  },
85
85
  },
@@ -87,6 +87,18 @@ export default {
87
87
  },
88
88
  },
89
89
  },
90
+ maxlength: {
91
+ description: "Maximum number of characters that can be entered.",
92
+ control: "number",
93
+ table: {
94
+ type: {
95
+ summary: "number",
96
+ },
97
+ defaultValue: {
98
+ summary: 1024,
99
+ },
100
+ },
101
+ },
90
102
  },
91
103
  parameters: {
92
104
  docs: {
@@ -38,6 +38,18 @@ export default {
38
38
  },
39
39
  },
40
40
  },
41
+ maxlength: {
42
+ description: "Maximum number of characters that can be entered.",
43
+ control: "number",
44
+ table: {
45
+ type: {
46
+ summary: "number",
47
+ },
48
+ defaultValue: {
49
+ summary: "1024",
50
+ },
51
+ },
52
+ },
41
53
  },
42
54
  parameters: {
43
55
  docs: {
@@ -80,6 +80,8 @@ export interface ListBaseBladeScope<Item = Record<string, any>, Query = Record<s
80
80
  breadcrumbs?: ComputedRef<Breadcrumbs[]>;
81
81
  }
82
82
 
83
+ export type TOpenBladeArgs = Omit<Parameters<ReturnType<typeof useBladeNavigation>["openBlade"]>["0"], "blade">;
84
+
83
85
  export interface DetailsBaseBladeScope extends BaseBladeScope {
84
86
  disabled?: ComputedRef<boolean | undefined>;
85
87
  multilanguage?: {
@@ -387,6 +387,11 @@ export interface TextareaSchema extends SchemaBase {
387
387
  * @type {boolean}
388
388
  */
389
389
  clearable?: boolean;
390
+ /**
391
+ * Maximum number of characters that can be entered.
392
+ * @type {number}
393
+ */
394
+ maxlength?: number;
390
395
  }
391
396
 
392
397
  /**
@@ -429,6 +434,11 @@ export interface InputSchema extends SchemaBase {
429
434
  * @type {ControlSchema}
430
435
  */
431
436
  prependInner?: ControlSchema;
437
+ /**
438
+ * Maximum number of characters that can be entered.
439
+ * @type {number}
440
+ */
441
+ maxlength?: number;
432
442
  }
433
443
 
434
444
  /**
@@ -628,6 +638,11 @@ export interface EditorSchema extends SchemaBase {
628
638
  * @type {string}
629
639
  */
630
640
  assetsFolder: string;
641
+ /**
642
+ * Maximum length of the editor content.
643
+ * @type {number}
644
+ */
645
+ maxlength?: number;
631
646
  }
632
647
 
633
648
  /**
@@ -197,7 +197,7 @@ const props = defineProps<Props>();
197
197
 
198
198
  const router = useRouter();
199
199
 
200
- const { setFieldError, resetForm, setErrors, validateField } = useForm({ validateOnMount: false });
200
+ const { validateField } = useForm({ validateOnMount: false });
201
201
  const { uiSettings, loading: customizationLoading } = useSettings();
202
202
  const { t } = useI18n({ useScope: "global" });
203
203
  let useLogin;
@@ -29,7 +29,7 @@
29
29
  :id="id"
30
30
  :key="`${id}-${disabled}`"
31
31
  ref="quillRef"
32
- :content="content"
32
+ :content="modelValue"
33
33
  class="quill-editor tw-border tw-border-solid tw-border-[color:var(--editor-border-color)] tw-rounded-b-[var(--editor-border-radius)] tw-h-[200px]"
34
34
  :class="{ 'tw-bg-[#fafafa] tw-text-[#424242] tw-cursor-default': disabled }"
35
35
  theme="snow"
@@ -39,7 +39,7 @@
39
39
  :read-only="disabled"
40
40
  :placeholder="placeholder"
41
41
  :options="options"
42
- @update:content="onInput"
42
+ @ready="initializeQuill"
43
43
  />
44
44
  <slot
45
45
  v-if="errorMessage"
@@ -53,15 +53,15 @@
53
53
  </template>
54
54
  <!-- eslint-disable @typescript-eslint/no-explicit-any -->
55
55
  <script lang="ts" setup>
56
- import { QuillEditor, Quill } from "@vueup/vue-quill";
56
+ import { QuillEditor } from "@vueup/vue-quill";
57
57
  import "@vueup/vue-quill/dist/vue-quill.snow.css";
58
- import { ref, unref, watch, onMounted, onUpdated, getCurrentInstance } from "vue";
58
+ import { ref, unref, onMounted, onUpdated, getCurrentInstance, Ref } from "vue";
59
59
  import ImageUploader from "quill-image-uploader";
60
60
  import { VcLabel, VcHint } from "../..";
61
61
 
62
62
  export interface Props {
63
63
  placeholder?: string;
64
- modelValue?: string | number | Date;
64
+ modelValue?: string;
65
65
  required?: boolean;
66
66
  disabled?: boolean;
67
67
  label?: string;
@@ -70,6 +70,7 @@ export interface Props {
70
70
  assetsFolder: string;
71
71
  multilanguage?: boolean;
72
72
  currentLanguage?: string;
73
+ maxlength?: number;
73
74
  }
74
75
 
75
76
  export interface Emits {
@@ -86,8 +87,9 @@ defineSlots<{
86
87
  error?: (props: any) => any;
87
88
  }>();
88
89
 
89
- const content = ref();
90
- const quillRef = ref<Quill | null>(null);
90
+ // const content = ref();
91
+ const quillRef = ref(null) as Ref<typeof QuillEditor | null>;
92
+ const quill = ref();
91
93
 
92
94
  const toolbar = {
93
95
  container: [
@@ -139,39 +141,32 @@ onUpdated(() => {
139
141
  removeBlankClass();
140
142
  });
141
143
 
142
- watch(
143
- () => props.modelValue,
144
- (value) => {
145
- if (value === "") {
146
- quillRef.value?.setText(value);
147
- return;
148
- }
149
- content.value = unref(value);
150
- },
151
- { immediate: true },
152
- );
144
+ function initializeQuill() {
145
+ quill.value = quillRef.value?.getQuill();
146
+ if (props.modelValue) {
147
+ quill.value.root.innerHTML = unref(props.modelValue);
148
+ }
149
+
150
+ quill.value.on("text-change", onTextChange);
151
+ }
153
152
 
154
153
  function removeBlankClass() {
155
154
  // fixes quill editor placeholder visibility issue when content is not empty
156
155
  const editor = document.getElementById(id)?.querySelector(".ql-editor.ql-blank");
157
- if (editor && content.value) {
156
+ if (editor && props.modelValue) {
158
157
  editor.classList.remove("ql-blank");
159
158
  }
160
159
  }
161
160
 
162
- function onInput(value: string) {
163
- if (isQuillEmpty(value)) {
164
- emit("update:modelValue", null);
165
- } else {
166
- emit("update:modelValue", value);
161
+ function onTextChange() {
162
+ const len = quill.value.getLength();
163
+ if (props.maxlength !== undefined && len > props.maxlength) {
164
+ quill.value.deleteText(props.maxlength, len);
167
165
  }
168
- }
169
166
 
170
- function isQuillEmpty(value: string) {
171
- if (value.replace(/<(.|\n)*?>/g, "").trim().length === 0) {
172
- return true;
167
+ if (quill.value.getText().trim() !== props.modelValue?.trim()) {
168
+ emit("update:modelValue", quill.value.root.innerHTML);
173
169
  }
174
- return false;
175
170
  }
176
171
  </script>
177
172
 
@@ -9,6 +9,20 @@ export default {
9
9
  label: "This is an input",
10
10
  placeholder: "Placeholder",
11
11
  },
12
+ argTypes: {
13
+ maxlength: {
14
+ description: "Maximum number of characters that can be entered.",
15
+ control: "number",
16
+ table: {
17
+ type: {
18
+ summary: "number",
19
+ },
20
+ defaultValue: {
21
+ summary: 1024,
22
+ },
23
+ },
24
+ },
25
+ },
12
26
  } satisfies Meta<typeof VcInput>;
13
27
 
14
28
  export const Template: StoryFn<typeof VcInput> = (args) => ({
@@ -48,6 +48,6 @@ Tooltip.args = {
48
48
  export const MaximumCharacters = Primary.bind({});
49
49
  MaximumCharacters.args = {
50
50
  label: "Textarea Label",
51
- maxchars: "10",
51
+ maxlength: "10",
52
52
  modelValue: "1234567890",
53
53
  };
@@ -30,7 +30,7 @@
30
30
  :placeholder="placeholder"
31
31
  :value="modelValue"
32
32
  :disabled="disabled"
33
- :maxlength="maxchars"
33
+ :maxlength="maxlength"
34
34
  @input="onInput"
35
35
  ></textarea>
36
36
  </div>
@@ -47,7 +47,6 @@
47
47
  </template>
48
48
 
49
49
  <script lang="ts" setup>
50
- import { watch } from "vue";
51
50
  import { VcHint, VcLabel } from "./../../";
52
51
 
53
52
  export interface Props {
@@ -58,7 +57,7 @@ export interface Props {
58
57
  label?: string;
59
58
  tooltip?: string;
60
59
  name?: string;
61
- maxchars?: string;
60
+ maxlength?: string;
62
61
  errorMessage?: string;
63
62
  multilanguage?: boolean;
64
63
  currentLanguage?: string;
@@ -69,13 +68,12 @@ export interface Emits {
69
68
  }
70
69
 
71
70
  defineSlots<{
72
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
73
- error: (props: any) => any;
71
+ error: void;
74
72
  }>();
75
73
 
76
74
  withDefaults(defineProps<Props>(), {
77
75
  name: "Field",
78
- maxchars: "1024",
76
+ maxlength: "1024",
79
77
  });
80
78
 
81
79
  const emit = defineEmits<Emits>();
@@ -14,7 +14,7 @@
14
14
 
15
15
  <div class="tw-overflow-hidden tw-grow tw-basis-0">
16
16
  <div
17
- class="tw-text-[color:var(--blade-header-title-color)] tw-text-lg tw-truncate"
17
+ class="tw-text-[color:var(--blade-header-title-color)] tw-text-lg/[23px] tw-truncate"
18
18
  :class="{
19
19
  '!tw-text-[length:var(--blade-header-title-font-size)] tw-font-medium': !subtitle,
20
20
  }"
@@ -1,124 +1,150 @@
1
1
  <template>
2
- <!-- Money cell -->
3
- <template v-if="cell.type === 'money'">
4
- <div
5
- v-if="typeof Number(value) === 'number' && Number(value) > 0"
6
- class="tw-truncate"
7
- >
8
- <span class="tw-truncate">{{ Math.trunc(Number(value)) }}</span
9
- ><span class="tw-text-[#a5a5a5] tw-text-xs tw-truncate"
10
- >.{{ `${(Number(value) * 100) % 100}`.padEnd(2, "0").slice(0, 2) }}</span
11
- >
12
- </div>
13
- <template v-else>
14
- <div class="tw-truncate">N/A</div>
15
- </template>
16
- </template>
17
-
18
- <!-- Date ago cell -->
19
- <span
20
- v-else-if="cell.type === 'date-ago'"
21
- class="tw-text-[#a5a5a5]"
22
- :title="(value instanceof Date && value.toLocaleString(locale)) || ''"
23
- >
24
- <div
25
- v-if="value"
26
- class="tw-truncate"
27
- >
28
- {{ moment(value).fromNow() }}
29
- </div>
30
- <div
31
- v-else
32
- class="tw-truncate"
33
- >
34
- N/A
35
- </div>
36
- </span>
37
-
38
- <!-- Date exact cell -->
39
- <div
40
- v-else-if="cell.type === 'date' || cell.type === 'time' || cell.type === 'date-time'"
41
- class="tw-text-[#a5a5a5] tw-truncate"
42
- >
43
- <template v-if="value">
2
+ <div>
3
+ <!-- Money cell -->
4
+ <template v-if="cell.type === 'money'">
44
5
  <div
45
- v-if="cell.format"
6
+ v-if="typeof Number(value) === 'number' && Number(value) > 0"
46
7
  class="tw-truncate"
8
+ :class="cell.class"
47
9
  >
48
- {{ moment(value).locale(locale).format(cell.format) }}
10
+ <span class="tw-truncate">{{ Math.trunc(Number(value)) }}</span
11
+ ><span class="tw-text-[#a5a5a5] tw-text-xs tw-truncate"
12
+ >.{{ `${(Number(value) * 100) % 100}`.padEnd(2, "0").slice(0, 2) }}</span
13
+ >
49
14
  </div>
50
15
  <template v-else>
51
16
  <div
52
- v-if="cell.type === 'date'"
53
17
  class="tw-truncate"
18
+ :class="cell.class"
54
19
  >
55
- {{ value instanceof Date && value.toLocaleDateString(locale) }}
20
+ N/A
56
21
  </div>
22
+ </template>
23
+ </template>
24
+
25
+ <!-- Date ago cell -->
26
+ <span
27
+ v-else-if="cell.type === 'date-ago'"
28
+ class="tw-text-[#a5a5a5]"
29
+ :class="cell.class"
30
+ :title="(value instanceof Date && value.toLocaleString(locale)) || ''"
31
+ >
32
+ <div
33
+ v-if="value"
34
+ class="tw-truncate"
35
+ >
36
+ {{ moment(value).fromNow() }}
37
+ </div>
38
+ <div
39
+ v-else
40
+ class="tw-truncate"
41
+ >
42
+ N/A
43
+ </div>
44
+ </span>
45
+
46
+ <!-- Date exact cell -->
47
+ <div
48
+ v-else-if="cell.type === 'date' || cell.type === 'time' || cell.type === 'date-time'"
49
+ class="tw-text-[#a5a5a5] tw-truncate"
50
+ :class="cell.class"
51
+ >
52
+ <template v-if="value">
57
53
  <div
58
- v-if="cell.type === 'time'"
54
+ v-if="cell.format"
59
55
  class="tw-truncate"
60
56
  >
61
- {{ value instanceof Date && value.toLocaleTimeString(locale) }}
57
+ {{ moment(value).locale(locale).format(cell.format) }}
62
58
  </div>
63
- <p
64
- v-if="cell.type === 'date-time'"
65
- class="tw-truncate"
66
- >
67
- {{ value instanceof Date && value.toLocaleString(locale) }}
68
- </p>
59
+ <template v-else>
60
+ <div
61
+ v-if="cell.type === 'date'"
62
+ class="tw-truncate"
63
+ >
64
+ {{ value instanceof Date && value.toLocaleDateString(locale) }}
65
+ </div>
66
+ <div
67
+ v-if="cell.type === 'time'"
68
+ class="tw-truncate"
69
+ >
70
+ {{ value instanceof Date && value.toLocaleTimeString(locale) }}
71
+ </div>
72
+ <p
73
+ v-if="cell.type === 'date-time'"
74
+ class="tw-truncate"
75
+ >
76
+ {{ value instanceof Date && value.toLocaleString(locale) }}
77
+ </p>
78
+ </template>
69
79
  </template>
80
+ <div
81
+ v-else
82
+ class="tw-truncate"
83
+ >
84
+ N/A
85
+ </div>
86
+ </div>
87
+
88
+ <!-- Image cell -->
89
+ <template v-else-if="cell.type === 'image'">
90
+ <VcImage
91
+ :bordered="true"
92
+ size="s"
93
+ aspect="1x1"
94
+ :src="value as string"
95
+ background="contain"
96
+ />
97
+ </template>
98
+
99
+ <!-- Status cell -->
100
+ <template v-else-if="cell.type === 'status'">
101
+ <VcStatus>{{ value }}</VcStatus>
70
102
  </template>
103
+
104
+ <!-- Status icon cell -->
71
105
  <div
72
- v-else
73
- class="tw-truncate"
106
+ v-else-if="cell.type === 'status-icon'"
107
+ class="tw-flex tw-justify-center"
108
+ :class="cell.class"
74
109
  >
75
- N/A
110
+ <VcStatusIcon :status="value as boolean"></VcStatusIcon>
76
111
  </div>
77
- </div>
78
112
 
79
- <!-- Image cell -->
80
- <template v-else-if="cell.type === 'image'">
81
- <VcImage
82
- :bordered="true"
83
- size="s"
84
- aspect="1x1"
85
- :src="value as string"
86
- background="contain"
87
- />
88
- </template>
89
-
90
- <!-- Status cell -->
91
- <template v-else-if="cell.type === 'status'">
92
- <VcStatus>{{ value }}</VcStatus>
93
- </template>
94
-
95
- <!-- Status icon cell -->
96
- <div
97
- v-else-if="cell.type === 'status-icon'"
98
- class="tw-flex tw-justify-center"
99
- >
100
- <VcStatusIcon :status="value as boolean"></VcStatusIcon>
101
- </div>
113
+ <!-- Number cell -->
114
+ <div
115
+ v-else-if="cell.type === 'number'"
116
+ class="tw-text-right tw-truncate"
117
+ :class="cell.class"
118
+ >
119
+ {{ Number(value).toFixed(0) }}
120
+ </div>
102
121
 
103
- <!-- Number cell -->
104
- <div
105
- v-else-if="cell.type === 'number'"
106
- class="tw-text-right tw-truncate"
107
- >
108
- {{ Number(value).toFixed(0) }}
109
- </div>
122
+ <!-- Link cell -->
123
+ <template v-else-if="cell.type === 'link'">
124
+ <VcLink
125
+ class="tw-truncate"
126
+ :class="cell.class"
127
+ >{{ value }}</VcLink
128
+ >
129
+ </template>
130
+
131
+ <!-- HTML cell -->
132
+ <template v-else-if="cell.type === 'html'">
133
+ <div
134
+ class="tw-p-1"
135
+ :class="cell.class"
136
+ v-html="truncatedHtml"
137
+ />
138
+ </template>
110
139
 
111
- <!-- Link cell -->
112
- <template v-else-if="cell.type === 'link'">
113
- <VcLink class="tw-truncate">{{ value }}</VcLink>
114
- </template>
115
-
116
- <!-- Default cell -->
117
- <div
118
- v-else
119
- class="tw-truncate"
120
- >
121
- {{ value }}
140
+ <!-- Default cell -->
141
+ <div
142
+ v-else
143
+ class="tw-truncate"
144
+ :class="cell.class"
145
+ >
146
+ {{ value }}
147
+ </div>
122
148
  </div>
123
149
  </template>
124
150
 
@@ -126,24 +152,30 @@
126
152
  import { computed } from "vue";
127
153
  import moment from "moment";
128
154
  import { ITableColumns } from "./../../../../../../core/types";
155
+ import * as _ from "lodash-es";
156
+ import htmlTruncate from "truncate-html";
157
+ import * as DOMPurify from "dompurify";
129
158
 
130
159
  export interface Props {
131
160
  cell: ITableColumns;
132
161
  item: Record<string, unknown>;
162
+ width?: number;
133
163
  }
134
164
 
135
165
  const props = defineProps<Props>();
136
166
 
137
167
  const locale = window.navigator.language;
138
168
 
139
- const value = computed((): unknown => {
140
- return (props.cell.field || props.cell.id).split(".").reduce((p: { [x: string]: unknown }, c: string) => {
141
- if (p && Array.isArray(p) && p.length) {
142
- const val = p && p[0][c];
143
- return val !== undefined ? val : null;
144
- }
145
- const val = p && p[c];
146
- return val !== undefined ? val : null;
147
- }, props.item);
169
+ const value = computed(() => _.get(props.item, props.cell.field || props.cell.id));
170
+
171
+ const sanitizedHtml = computed(() => {
172
+ if (props.cell.type === "html") {
173
+ return DOMPurify.default.sanitize(value.value as string, { USE_PROFILES: { html: true } });
174
+ }
175
+ return "";
148
176
  });
177
+
178
+ const truncatedHtml = computed(() =>
179
+ htmlTruncate(sanitizedHtml.value, +(typeof props.width !== "undefined" ? Math.floor(props.width / 5) : 30)),
180
+ );
149
181
  </script>