sprintify-ui 0.6.83 → 0.6.85

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 (48) hide show
  1. package/dist/style.css +1 -1
  2. package/dist/types/components/BaseAutocomplete.vue.d.ts +7 -7
  3. package/dist/types/components/BaseAutocompleteDrawer.vue.d.ts +1 -1
  4. package/dist/types/components/BaseAutocompleteFetch.vue.d.ts +5 -5
  5. package/dist/types/components/BaseBelongsTo.vue.d.ts +4 -4
  6. package/dist/types/components/BaseBelongsToFetch.vue.d.ts +5 -5
  7. package/dist/types/components/BaseButtonGroup.vue.d.ts +11 -11
  8. package/dist/types/components/BaseColor.vue.d.ts +6 -6
  9. package/dist/types/components/BaseDropdownAutocomplete.vue.d.ts +7 -7
  10. package/dist/types/components/BaseHasMany.vue.d.ts +5 -5
  11. package/dist/types/components/BaseJsonReader.vue.d.ts +6 -3
  12. package/dist/types/components/BaseJsonReaderItem.vue.d.ts +25 -0
  13. package/dist/types/components/BaseRadioGroup.vue.d.ts +3 -3
  14. package/dist/types/components/BaseSelect.vue.d.ts +4 -4
  15. package/dist/types/components/BaseTagAutocomplete.vue.d.ts +6 -6
  16. package/dist/types/components/BaseTagAutocompleteFetch.vue.d.ts +4 -4
  17. package/dist/types/composables/hasOptions.d.ts +2 -2
  18. package/dist/types/types/Media.d.ts +1 -1
  19. package/dist/types/types/Notification.d.ts +1 -1
  20. package/dist/types/types/UploadedFile.d.ts +1 -1
  21. package/dist/types/types/User.d.ts +1 -1
  22. package/dist/types/types/index.d.ts +6 -2
  23. package/dist/types/utils/sizes.d.ts +2 -1
  24. package/package.json +1 -1
  25. package/src/assets/main.css +0 -1
  26. package/src/components/BaseAutocomplete.vue +5 -5
  27. package/src/components/BaseAutocompleteFetch.vue +4 -4
  28. package/src/components/BaseBelongsTo.vue +3 -3
  29. package/src/components/BaseBelongsToFetch.vue +4 -4
  30. package/src/components/BaseButtonGroup.vue +5 -5
  31. package/src/components/BaseColor.vue +4 -4
  32. package/src/components/BaseDropdownAutocomplete.vue +5 -5
  33. package/src/components/BaseHasMany.vue +4 -4
  34. package/src/components/BaseJsonReader.stories.js +1 -1
  35. package/src/components/BaseJsonReader.vue +19 -165
  36. package/src/components/BaseJsonReaderItem.vue +112 -0
  37. package/src/components/BaseRadioGroup.vue +2 -2
  38. package/src/components/BaseSelect.vue +2 -2
  39. package/src/components/BaseTagAutocomplete.vue +3 -3
  40. package/src/components/BaseTagAutocompleteFetch.vue +3 -3
  41. package/src/composables/hasOptions.ts +3 -3
  42. package/src/types/Media.ts +1 -1
  43. package/src/types/Notification.ts +1 -1
  44. package/src/types/UploadedFile.ts +1 -1
  45. package/src/types/User.ts +1 -1
  46. package/src/types/index.ts +8 -2
  47. package/src/utils/sizes.ts +3 -1
  48. package/src/assets/base-json-reader.css +0 -32
@@ -45,7 +45,7 @@
45
45
 
46
46
  <script lang="ts" setup>
47
47
  import { debounce } from 'lodash';
48
- import { Option } from '@/types';
48
+ import { RawOption } from '@/types';
49
49
  import { config } from '@/index';
50
50
  import { PropType } from 'vue';
51
51
  import BaseTagAutocompleteFetch from './BaseTagAutocompleteFetch.vue';
@@ -97,7 +97,7 @@ const props = defineProps({
97
97
  default() {
98
98
  return undefined;
99
99
  },
100
- type: Array as PropType<Option[] | undefined>,
100
+ type: Array as PropType<RawOption[] | undefined>,
101
101
  },
102
102
  hasError: {
103
103
  default: false,
@@ -113,7 +113,7 @@ const tagAutocompleteFetch = ref<InstanceType<
113
113
  typeof BaseTagAutocompleteFetch
114
114
  > | null>(null);
115
115
 
116
- const models = ref<Option[]>([]);
116
+ const models = ref<RawOption[]>([]);
117
117
  const ensureModelIsFilledDebounced = debounce(() => ensureModelsAreFilled(), 100);
118
118
 
119
119
  watch(
@@ -130,7 +130,7 @@ watch(
130
130
 
131
131
  ensureModelIsFilledDebounced();
132
132
 
133
- function onUpdate(newModels: Option[]) {
133
+ function onUpdate(newModels: RawOption[]) {
134
134
  models.value = newModels;
135
135
  emit(
136
136
  'update:modelValue',
@@ -114,7 +114,7 @@ const Template = (args) => ({
114
114
  return { value, args };
115
115
  },
116
116
  template: `
117
- <BaseJsonReader v-model="value" v-bind="args">
117
+ <BaseJsonReader v-model="value" v-bind="args" class="bg-red-50 border p-5 text-red-900 rounded-none">
118
118
  </BaseJsonReader>
119
119
  <ShowValue :value="value" />
120
120
  `,
@@ -1,12 +1,17 @@
1
1
  <template>
2
2
  <div
3
- class="base-json-reader"
4
3
  :class="classes"
5
- @click="handleClick"
6
4
  >
7
- <div
8
- v-html="renderObject(modelValue)"
9
- />
5
+ <ul>
6
+ <BaseJsonReaderItem
7
+ v-for="(value, key) in modelValue"
8
+ :key="key"
9
+ :size="size"
10
+ :label="key"
11
+ :variant="variant"
12
+ :model-value="value"
13
+ />
14
+ </ul>
10
15
  </div>
11
16
  </template>
12
17
 
@@ -14,186 +19,35 @@
14
19
  import { Size, sizes } from '@/utils/sizes';
15
20
  import { twMerge } from 'tailwind-merge';
16
21
  import { defineProps } from 'vue';
22
+ import BaseJsonReaderItem from './BaseJsonReaderItem.vue';
23
+ import { JsonData } from '@/types';
17
24
 
18
- interface JsonData {
19
- [key: string]: string | number | null | undefined | JsonData[];
20
- }
25
+ defineOptions({
26
+ inheritAttrs: false,
27
+ })
21
28
 
22
29
  const props = withDefaults(
23
30
  defineProps<{
24
31
  modelValue: JsonData;
25
32
  size?: Size;
26
33
  variant?: 'list' | 'collapse';
34
+ class?: string | string[];
27
35
  }>(),
28
36
  {
29
37
  size: 'sm',
30
38
  variant: 'list',
39
+ class: undefined,
31
40
  }
32
41
  );
33
42
 
34
43
  const classes = computed(() => {
35
44
  const base = 'bg-slate-100 p-2 rounded-md text-sm text-slate-800';
36
45
  const sizeConfig = sizes[props.size];
37
-
46
+
38
47
  return twMerge(
39
48
  base,
40
49
  sizeConfig.fontSize,
50
+ props.class,
41
51
  );
42
52
  });
43
-
44
- const classSizeChevron = computed(() => {
45
- const chevronSizes = {
46
- xs: {
47
- width: 'w-[1em]',
48
- height: 'h-[1em]',
49
- marginBottom: 'mb-[-2.5px]'
50
- },
51
- sm: {
52
- width: 'w-[1.1em]',
53
- height: 'h-[1.1em]',
54
- marginBottom: 'mb-[-3.5px]'
55
- },
56
- md: {
57
- width: 'w-[1.2em]',
58
- height: 'h-[1.2em]',
59
- marginBottom: 'mb-[-5px]'
60
- },
61
- };
62
-
63
- const sizeConfig = chevronSizes[props.size];
64
-
65
- return twMerge(
66
- sizeConfig.height,
67
- sizeConfig.width,
68
- sizeConfig.marginBottom
69
- );
70
- });
71
-
72
- const expandedKeys = ref<string[]>([]);
73
-
74
- function toggleExpand(key: string) {
75
- if (isExpanded(key)) {
76
- expandedKeys.value = expandedKeys.value.filter(k => k !== key);
77
- } else {
78
- expandedKeys.value.push(key);
79
- }
80
- }
81
-
82
- function isExpanded(key: string): boolean {
83
- return expandedKeys.value.includes(key);
84
- }
85
-
86
- // Expand when created
87
- function recursiveExpand(data: JsonData | JsonData[] , parentKey = '') {
88
- if (props.variant !== 'collapse') {
89
- return;
90
- }
91
-
92
- if (Array.isArray(data)) {
93
- data.forEach((item, index) => {
94
- const uniqueKey = parentKey ? `${parentKey}[${index}]` : `[${index}]`;
95
- expandedKeys.value.push(uniqueKey);
96
- recursiveExpand(item, uniqueKey);
97
- });
98
- } else {
99
- Object.entries(data).forEach(([key, value], index) => {
100
- const uniqueKey = parentKey ? `${parentKey}[${index}]` : `[${index}]`;
101
- expandedKeys.value.push(uniqueKey);
102
-
103
- if (typeof value === 'object' && value !== null) {
104
- recursiveExpand(value, uniqueKey);
105
- }
106
- });
107
- }
108
- }
109
-
110
- recursiveExpand(props.modelValue);
111
-
112
- function handleClick(event: MouseEvent) {
113
- if (props.variant !== 'collapse') {
114
- return;
115
- }
116
-
117
- const target = event.target as HTMLElement;
118
- if (target.classList.contains('chevron')) {
119
- const key = target.dataset.key;
120
-
121
- if (key) {
122
- toggleExpand(key);
123
- }
124
- }
125
- }
126
-
127
- function renderContent(data: JsonData | JsonData[], uniqueKey = ''): string {
128
- if (Array.isArray(data)) {
129
- return renderArray(data, uniqueKey);
130
- }
131
-
132
- else if (typeof data === 'object' && data !== null) {
133
- return renderObject(data, uniqueKey);
134
- }
135
-
136
- return `<span>${data}</span>`;
137
- }
138
-
139
- // If data is an array
140
- function renderArray(data: JsonData[], parentKey = ''): string {
141
- let result = '<ul>';
142
-
143
- data.forEach((item, index) => {
144
- const uniqueKey = parentKey ? `${parentKey}[${index}]` : `[${index}]`;
145
-
146
- if (typeof item === 'object' && item !== null) {
147
- result += `${renderContent(item, uniqueKey)}`;
148
- }
149
- else {
150
- result += `<li>${renderContent(item, uniqueKey)}</li>`;
151
- }
152
-
153
- });
154
-
155
- result += '</ul>';
156
-
157
- return result;
158
- }
159
-
160
- // If data is an object
161
- function renderObject(data: JsonData, parentKey = ''): string {
162
- let result = '<ul>';
163
-
164
- Object.entries(data).forEach(([key, value], index) => {
165
- const uniqueKey = parentKey ? `${parentKey}[${index}]` : `[${index}]`;
166
- console.log('uniqueKey', uniqueKey, 'parentKey', parentKey, 'index', index);
167
-
168
-
169
- if (props.variant === 'collapse') {
170
- result += `<li> <b data-key="${uniqueKey}" class="${(typeof value === 'object' && value !== null) ? 'chevron' : ''}">${key}</b>`;
171
- } else {
172
- result += `<li> <b>${key}</b>`;
173
- }
174
-
175
- if (typeof value === 'object' && value !== null) {
176
- if (props.variant === 'collapse') {
177
- result += `<span data-key="${uniqueKey}" class="chevron ml-[-2px]"> ${renderChevron(uniqueKey)} </span>`;
178
- }
179
-
180
- if (isExpanded(uniqueKey) || props.variant !== 'collapse') {
181
- result += renderContent(value, uniqueKey);
182
- }
183
- } else {
184
- result += ` <span>${value}</span>`;
185
- }
186
-
187
- result += '</li>';
188
- });
189
-
190
- result += '</ul>';
191
-
192
- return result;
193
- }
194
-
195
- function renderChevron(key: string): string {
196
- return isExpanded(key) ? `<span class="chevron heroicons--chevron-right-16-solid w-1 h-1 ${classSizeChevron.value}" data-key="${key}"></span>`
197
- : `<span class="chevron heroicons--chevron-down-16-solid ${classSizeChevron.value}" data-key="${key}"></span>`;
198
- }
199
53
  </script>
@@ -0,0 +1,112 @@
1
+ <template>
2
+ <li>
3
+ <p class="flex items-center gap-1">
4
+ <button
5
+ v-if="variant == 'collapse'"
6
+ type="button"
7
+ class="duration-200 transform"
8
+ :class="[isPrimitive ? 'opacity-0 cursor-default' : '', visible ? 'rotate-0' : '-rotate-90']"
9
+ @click="toggle"
10
+ >
11
+ <BaseIcon
12
+ :class="classSizeChevron"
13
+ icon="ion:caret-down"
14
+ />
15
+ </button>
16
+ <span :class="[typeof label == 'number' ? '' : 'font-semibold']">
17
+ {{ label }}
18
+ </span>
19
+
20
+ <span
21
+ v-if="isPrimitive"
22
+ class="font-semibold"
23
+ >:</span>
24
+
25
+ <span v-if="isPrimitive">
26
+ {{ modelValue }}
27
+ </span>
28
+ <span
29
+ v-else
30
+ class="opacity-50"
31
+ >{<template v-if="true">{{ count }}</template>}</span>
32
+ </p>
33
+ <ul
34
+ v-show="visible"
35
+ v-if="isIterable"
36
+ class="pl-3"
37
+ >
38
+ <BaseJsonReaderItem
39
+ v-for="(value, key) in modelValue"
40
+ :key="key"
41
+ :label="key"
42
+ :model-value="value"
43
+ :size="size"
44
+ :variant="variant"
45
+ />
46
+ </ul>
47
+ </li>
48
+ </template>
49
+
50
+ <script lang="ts" setup>
51
+ import { JsonDataItem } from '@/types';
52
+ import { Size } from '@/utils/sizes';
53
+ import { isBoolean, isNull, isNumber, isString, isArray, isObject } from 'lodash';
54
+
55
+ const props = defineProps<{
56
+ modelValue: JsonDataItem;
57
+ label: string | number;
58
+ size: Size;
59
+ class?: string | string[];
60
+ variant: 'list' | 'collapse';
61
+ }>();
62
+
63
+ const visible = ref(true);
64
+
65
+ function toggle() {
66
+ visible.value = !visible.value;
67
+ }
68
+
69
+ const count = computed(() => {
70
+ if (isArray(props.modelValue)) {
71
+ return props.modelValue.length;
72
+ }
73
+ if (isObject(props.modelValue)) {
74
+ return Object.keys(props.modelValue).length;
75
+ }
76
+ return 0;
77
+ });
78
+
79
+ const isPrimitive = computed(() => {
80
+ return isString(props.modelValue) || isNumber(props.modelValue) || isBoolean(props.modelValue) || isNull(props.modelValue) || isNumber(props.modelValue);
81
+ });
82
+
83
+ const isIterable = computed(() => {
84
+ if (isPrimitive.value) return false;
85
+ return isArray(props.modelValue) || isObject(props.modelValue);
86
+ });
87
+
88
+ const classSizeChevron = computed(() => {
89
+ const chevronSizes = {
90
+ xs: {
91
+ width: 'w-2.5',
92
+ height: 'h-2.5',
93
+ },
94
+ sm: {
95
+ width: 'w-3',
96
+ height: 'h-3',
97
+ },
98
+ md: {
99
+ width: 'w-3.5',
100
+ height: 'h-3.5',
101
+ },
102
+ };
103
+
104
+ const sizeConfig = chevronSizes[props.size];
105
+
106
+ return [
107
+ sizeConfig.height,
108
+ sizeConfig.width,
109
+ ];
110
+ });
111
+
112
+ </script>
@@ -36,7 +36,7 @@
36
36
 
37
37
  <script lang="ts" setup>
38
38
  import { PropType } from 'vue';
39
- import { NormalizedOption, Option, OptionValue } from '@/types';
39
+ import { NormalizedOption, RawOption, OptionValue } from '@/types';
40
40
  import { useField } from '@/composables/field';
41
41
  import { uniqueId } from 'lodash';
42
42
 
@@ -61,7 +61,7 @@ const props = defineProps({
61
61
  },
62
62
  options: {
63
63
  required: true,
64
- type: Array as PropType<Option[]>,
64
+ type: Array as PropType<RawOption[]>,
65
65
  },
66
66
  labelKey: {
67
67
  required: true,
@@ -41,7 +41,7 @@
41
41
  import { PropType } from 'vue';
42
42
  import { get, isArray } from 'lodash';
43
43
  import { useField } from '@/composables/field';
44
- import { NormalizedOption, OptionValue, Option } from '@/types';
44
+ import { NormalizedOption, OptionValue, RawOption } from '@/types';
45
45
  import { t } from '@/i18n';
46
46
  import { twMerge } from 'tailwind-merge';
47
47
  import { Size, sizes } from '@/utils/sizes';
@@ -90,7 +90,7 @@ const props = defineProps({
90
90
  },
91
91
  options: {
92
92
  default: undefined,
93
- type: Array as PropType<Option[]>,
93
+ type: Array as PropType<RawOption[]>,
94
94
  },
95
95
  labelKey: {
96
96
  default: undefined,
@@ -92,7 +92,7 @@
92
92
  <script lang="ts" setup>
93
93
  import { cloneDeep, get } from 'lodash';
94
94
  import { PropType, ComputedRef } from 'vue';
95
- import { NormalizedOption, Option } from '@/types';
95
+ import { NormalizedOption, RawOption } from '@/types';
96
96
  import { useHasOptions } from '@/composables/hasOptions';
97
97
  import { useField } from '@/composables/field';
98
98
  import { useClickOutside } from '@/composables/clickOutside';
@@ -107,11 +107,11 @@ const notifications = useNotificationsStore();
107
107
  const props = defineProps({
108
108
  modelValue: {
109
109
  required: true,
110
- type: [Array, null] as PropType<Option[] | null>,
110
+ type: [Array, null] as PropType<RawOption[] | null>,
111
111
  },
112
112
  options: {
113
113
  required: true,
114
- type: Array as PropType<Option[]>,
114
+ type: Array as PropType<RawOption[]>,
115
115
  },
116
116
  labelKey: {
117
117
  required: true,
@@ -63,7 +63,7 @@ import { config } from '@/index';
63
63
  import { PropType } from 'vue';
64
64
  import {
65
65
  Collection,
66
- Option,
66
+ RawOption,
67
67
  PaginatedCollection,
68
68
  ResourceCollection,
69
69
  } from '@/types';
@@ -74,7 +74,7 @@ import { t } from '@/i18n';
74
74
  const props = defineProps({
75
75
  modelValue: {
76
76
  required: true,
77
- type: Array as PropType<Option[]>,
77
+ type: Array as PropType<RawOption[]>,
78
78
  },
79
79
  url: {
80
80
  required: true,
@@ -131,7 +131,7 @@ const fetching = ref(false);
131
131
  const firstSearch = ref(false);
132
132
  const keywords = ref('');
133
133
  const page = ref(1);
134
- const options = ref<Option[]>([]);
134
+ const options = ref<RawOption[]>([]);
135
135
 
136
136
  const data = ref<null | ResourceCollection | PaginatedCollection | Collection>(
137
137
  null
@@ -1,10 +1,10 @@
1
1
  import { Ref } from 'vue';
2
- import { NormalizedOption, Option } from '@/types';
2
+ import { NormalizedOption, RawOption } from '@/types';
3
3
  import { isArray, isObject } from 'lodash';
4
4
 
5
5
  export function useHasOptions(
6
- modelValue: Ref<Option[] | Option | null | undefined>,
7
- options: Ref<Option[]>,
6
+ modelValue: Ref<RawOption[] | RawOption | null | undefined>,
7
+ options: Ref<RawOption[]>,
8
8
  labelKey: Ref<string>,
9
9
  valueKey: Ref<string>,
10
10
  multiple: Ref<boolean> = ref(false)
@@ -7,4 +7,4 @@ interface Media {
7
7
  url: string;
8
8
  }
9
9
 
10
- export { Media };
10
+ export type { Media };
@@ -8,4 +8,4 @@ interface Notification {
8
8
  created_at?: string;
9
9
  }
10
10
 
11
- export { Notification };
11
+ export type { Notification };
@@ -8,4 +8,4 @@ interface UploadedFile {
8
8
  data_url?: string;
9
9
  }
10
10
 
11
- export { UploadedFile };
11
+ export type { UploadedFile };
package/src/types/User.ts CHANGED
@@ -4,4 +4,4 @@ interface User {
4
4
  avatar_url?: string;
5
5
  }
6
6
 
7
- export { User };
7
+ export type { User };
@@ -34,10 +34,10 @@ export interface DataTableQuery extends Record<string, any> {
34
34
 
35
35
  export type OptionValue = string | number | null;
36
36
 
37
- export type Option = Record<string, any>;
37
+ export type RawOption = Record<string, any>;
38
38
 
39
39
  export type NormalizedOption = {
40
- option: Option;
40
+ option: RawOption;
41
41
  value: OptionValue;
42
42
  label: string;
43
43
  };
@@ -268,3 +268,9 @@ export interface TimelineItem {
268
268
  onEdit?: () => void | Promise<void>;
269
269
  onDelete?: () => void | Promise<void>;
270
270
  }
271
+
272
+ export type JsonDataItem = string | number | null | undefined | JsonData[] | JsonData;
273
+
274
+ export interface JsonData {
275
+ [key: string]: JsonDataItem;
276
+ }
@@ -18,4 +18,6 @@ const sizes = {
18
18
 
19
19
  type Size = keyof typeof sizes;
20
20
 
21
- export { sizes, Size }
21
+ export { sizes };
22
+
23
+ export type { Size };
@@ -1,32 +0,0 @@
1
- .base-json-reader {
2
- ul {
3
- list-style-type: disc !important;
4
- padding-left: 20px !important;
5
- }
6
-
7
- li {
8
- margin-bottom: 5px !important;
9
- }
10
-
11
- .chevron {
12
- cursor: pointer;
13
- }
14
-
15
- .heroicons--chevron-right-16-solid,
16
- .heroicons--chevron-down-16-solid {
17
- display: inline-block;
18
- background-color: currentColor;
19
- -webkit-mask-image: var(--svg);
20
- mask-image: var(--svg);
21
- -webkit-mask-repeat: no-repeat;
22
- mask-repeat: no-repeat;
23
- -webkit-mask-size: 100% 100%;
24
- mask-size: 100% 100%;
25
- }
26
- .heroicons--chevron-right-16-solid {
27
- --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23000' fill-rule='evenodd' d='M6.22 4.22a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06L8.94 8L6.22 5.28a.75.75 0 0 1 0-1.06' clip-rule='evenodd'/%3E%3C/svg%3E");
28
- }
29
- .heroicons--chevron-down-16-solid {
30
- --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23000' fill-rule='evenodd' d='M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06' clip-rule='evenodd'/%3E%3C/svg%3E");
31
- }
32
- }