@globalbrain/sefirot 4.29.1 → 4.30.0
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.
- package/lib/components/SInputCheckbox.vue +2 -3
- package/lib/components/SInputCheckboxes.vue +2 -3
- package/lib/components/SInputDate.vue +4 -3
- package/lib/components/SInputDropdown.vue +1 -0
- package/lib/components/SInputDropdownItem.vue +3 -2
- package/lib/components/SInputFile.vue +5 -4
- package/lib/components/SInputFileUpload.vue +2 -2
- package/lib/components/SInputHMS.vue +1 -0
- package/lib/components/SInputImage.vue +3 -3
- package/lib/components/SInputNumber.vue +2 -0
- package/lib/components/SInputRadio.vue +2 -3
- package/lib/components/SInputRadios.vue +2 -3
- package/lib/components/SInputSegments.vue +3 -5
- package/lib/components/SInputSegmentsOption.vue +3 -1
- package/lib/components/SInputSelect.vue +3 -0
- package/lib/components/SInputSwitch.vue +3 -4
- package/lib/components/SInputSwitches.vue +3 -4
- package/lib/components/SInputText.vue +3 -0
- package/lib/components/SInputTextarea.vue +3 -0
- package/lib/components/SInputYMD.vue +1 -0
- package/lib/components/STooltip.vue +1 -1
- package/lib/composables/Api.ts +5 -2
- package/lib/composables/App.ts +1 -1
- package/lib/composables/Http.ts +3 -2
- package/lib/http/Http.ts +16 -58
- package/lib/stores/HttpConfig.ts +53 -0
- package/package.json +2 -2
|
@@ -3,10 +3,9 @@ import IconCheck from '~icons/ph/check-bold'
|
|
|
3
3
|
import IconMinus from '~icons/ph/minus-bold'
|
|
4
4
|
import { type Component, computed } from 'vue'
|
|
5
5
|
import { type Validatable } from '../composables/Validation'
|
|
6
|
-
import SInputBase from './SInputBase.vue'
|
|
6
|
+
import SInputBase, { type Color, type Size } from './SInputBase.vue'
|
|
7
7
|
|
|
8
|
-
export type
|
|
9
|
-
export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
8
|
+
export type { Color, Size }
|
|
10
9
|
|
|
11
10
|
const props = withDefaults(defineProps<{
|
|
12
11
|
size?: Size
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { type Component, computed } from 'vue'
|
|
3
3
|
import { type Validatable } from '../composables/Validation'
|
|
4
|
-
import SInputBase from './SInputBase.vue'
|
|
4
|
+
import SInputBase, { type Color, type Size } from './SInputBase.vue'
|
|
5
5
|
import SInputCheckbox from './SInputCheckbox.vue'
|
|
6
6
|
|
|
7
|
-
export type
|
|
8
|
-
export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
7
|
+
export type { Color, Size }
|
|
9
8
|
|
|
10
9
|
export type Value = any
|
|
11
10
|
|
|
@@ -3,10 +3,9 @@ import { DatePicker } from 'v-calendar'
|
|
|
3
3
|
import { type Component, computed } from 'vue'
|
|
4
4
|
import { type Validatable } from '../composables/Validation'
|
|
5
5
|
import { type Day, day } from '../support/Day'
|
|
6
|
-
import SInputBase from './SInputBase.vue'
|
|
6
|
+
import SInputBase, { type Color, type Size } from './SInputBase.vue'
|
|
7
7
|
|
|
8
|
-
export type
|
|
9
|
-
export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
8
|
+
export type { Color, Size }
|
|
10
9
|
|
|
11
10
|
const props = defineProps<{
|
|
12
11
|
size?: Size
|
|
@@ -20,6 +19,7 @@ const props = defineProps<{
|
|
|
20
19
|
checkColor?: Color
|
|
21
20
|
block?: boolean
|
|
22
21
|
disabled?: boolean
|
|
22
|
+
tabindex?: -1 | 0 | number
|
|
23
23
|
modelValue: Day | null
|
|
24
24
|
validation?: Validatable
|
|
25
25
|
hideError?: boolean
|
|
@@ -86,6 +86,7 @@ function emitBlur() {
|
|
|
86
86
|
autocomplete="off"
|
|
87
87
|
:value="inputValue"
|
|
88
88
|
:disabled
|
|
89
|
+
:tabindex
|
|
89
90
|
v-on="disabled ? {} : inputEvents"
|
|
90
91
|
@blur="emitBlur"
|
|
91
92
|
>
|
|
@@ -10,6 +10,7 @@ import SDropdown from './SDropdown.vue'
|
|
|
10
10
|
import SInputBase, { type Props as BaseProps } from './SInputBase.vue'
|
|
11
11
|
import SInputDropdownItem from './SInputDropdownItem.vue'
|
|
12
12
|
|
|
13
|
+
export type { Color, Size } from './SInputBase.vue'
|
|
13
14
|
export interface Props extends BaseProps {
|
|
14
15
|
placeholder?: string
|
|
15
16
|
options: Option[]
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import IconX from '~icons/ph/x'
|
|
3
3
|
import SAvatar from './SAvatar.vue'
|
|
4
|
+
import { type Size } from './SInputBase.vue'
|
|
5
|
+
|
|
6
|
+
export type { Size }
|
|
4
7
|
|
|
5
8
|
export type Item = ItemText | ItemAvatar
|
|
6
9
|
|
|
@@ -20,8 +23,6 @@ export interface ItemAvatar extends ItemBase {
|
|
|
20
23
|
image?: string | null
|
|
21
24
|
}
|
|
22
25
|
|
|
23
|
-
export type Size = 'sm' | 'md' | 'mini' | 'small' | 'medium'
|
|
24
|
-
|
|
25
26
|
defineProps<{
|
|
26
27
|
item: Item | Item[]
|
|
27
28
|
size: Size
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { type Component, computed, ref } from 'vue'
|
|
3
3
|
import { type Validatable } from '../composables/Validation'
|
|
4
|
-
import SInputBase from './SInputBase.vue'
|
|
4
|
+
import SInputBase, { type Color, type Size } from './SInputBase.vue'
|
|
5
5
|
|
|
6
|
-
export type
|
|
7
|
-
export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
6
|
+
export type { Color, Size }
|
|
8
7
|
|
|
9
8
|
const props = defineProps<{
|
|
10
9
|
size?: Size
|
|
@@ -16,6 +15,7 @@ const props = defineProps<{
|
|
|
16
15
|
placeholder?: string
|
|
17
16
|
accept?: string
|
|
18
17
|
multiple?: boolean
|
|
18
|
+
tabindex?: -1 | 0 | number
|
|
19
19
|
checkIcon?: Component
|
|
20
20
|
checkText?: string
|
|
21
21
|
checkColor?: Color
|
|
@@ -82,12 +82,13 @@ function onChange(e: Event) {
|
|
|
82
82
|
type="file"
|
|
83
83
|
:accept
|
|
84
84
|
:multiple
|
|
85
|
+
:tabindex
|
|
85
86
|
@change="onChange"
|
|
86
87
|
>
|
|
87
88
|
|
|
88
89
|
<div class="box" role="button" @click="open">
|
|
89
90
|
<div class="action">
|
|
90
|
-
<button class="button">
|
|
91
|
+
<button class="button" :tabindex>
|
|
91
92
|
{{ text ?? 'Choose File' }}
|
|
92
93
|
</button>
|
|
93
94
|
</div>
|
|
@@ -9,12 +9,12 @@ import SButton, { type Mode as ButtonMode } from './SButton.vue'
|
|
|
9
9
|
import SCard from './SCard.vue'
|
|
10
10
|
import SCardBlock from './SCardBlock.vue'
|
|
11
11
|
import { type State as IndicatorState } from './SIndicator.vue'
|
|
12
|
-
import SInputBase from './SInputBase.vue'
|
|
12
|
+
import SInputBase, { type Color } from './SInputBase.vue'
|
|
13
13
|
import SInputFileUploadItem from './SInputFileUploadItem.vue'
|
|
14
14
|
import STrans from './STrans.vue'
|
|
15
15
|
|
|
16
16
|
export type Size = 'mini' | 'small' | 'medium'
|
|
17
|
-
export type Color
|
|
17
|
+
export type { Color }
|
|
18
18
|
|
|
19
19
|
export type ModelType = 'file' | 'object'
|
|
20
20
|
export type ModelValue<T extends ModelType> = T extends 'file' ? File : FileObject
|
|
@@ -4,10 +4,10 @@ import { type Component, computed, ref } from 'vue'
|
|
|
4
4
|
import { useImageSrcFromFile } from '../composables/Image'
|
|
5
5
|
import { type Validatable } from '../composables/Validation'
|
|
6
6
|
import SButton from './SButton.vue'
|
|
7
|
-
import SInputBase from './SInputBase.vue'
|
|
7
|
+
import SInputBase, { type Color } from './SInputBase.vue'
|
|
8
8
|
|
|
9
9
|
export type Size = 'mini' | 'small' | 'medium'
|
|
10
|
-
export type
|
|
10
|
+
export type { Color }
|
|
11
11
|
export type ImageType = 'rectangle' | 'circle'
|
|
12
12
|
|
|
13
13
|
const props = withDefaults(defineProps<{
|
|
@@ -18,7 +18,7 @@ const props = withDefaults(defineProps<{
|
|
|
18
18
|
help?: string
|
|
19
19
|
checkIcon?: Component
|
|
20
20
|
checkText?: string
|
|
21
|
-
checkColor?:
|
|
21
|
+
checkColor?: Color
|
|
22
22
|
imageType?: ImageType
|
|
23
23
|
imageWidth?: string
|
|
24
24
|
imageAspectRatio?: string
|
|
@@ -12,6 +12,7 @@ export interface Props extends BaseProps {
|
|
|
12
12
|
separator?: boolean
|
|
13
13
|
align?: Align
|
|
14
14
|
disabled?: boolean
|
|
15
|
+
tabindex?: -1 | 0 | number
|
|
15
16
|
value?: number | null
|
|
16
17
|
modelValue?: number | null
|
|
17
18
|
displayValue?: string | null
|
|
@@ -91,6 +92,7 @@ function emitUpdate(value: string | null) {
|
|
|
91
92
|
:text-color="_textColor"
|
|
92
93
|
:align
|
|
93
94
|
:disabled
|
|
95
|
+
:tabindex
|
|
94
96
|
:display-value
|
|
95
97
|
:model-value="_value == null ? null : String(_value)"
|
|
96
98
|
:validation
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { type Component, computed } from 'vue'
|
|
3
3
|
import { type Validatable } from '../composables/Validation'
|
|
4
|
-
import SInputBase from './SInputBase.vue'
|
|
4
|
+
import SInputBase, { type Color, type Size } from './SInputBase.vue'
|
|
5
5
|
|
|
6
|
-
export type
|
|
7
|
-
export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
6
|
+
export type { Color, Size }
|
|
8
7
|
|
|
9
8
|
const props = defineProps<{
|
|
10
9
|
size?: Size
|
|
@@ -8,11 +8,10 @@
|
|
|
8
8
|
>
|
|
9
9
|
import { type Component, computed } from 'vue'
|
|
10
10
|
import { type Validatable } from '../composables/Validation'
|
|
11
|
-
import SInputBase from './SInputBase.vue'
|
|
11
|
+
import SInputBase, { type Color, type Size } from './SInputBase.vue'
|
|
12
12
|
import SInputRadio from './SInputRadio.vue'
|
|
13
13
|
|
|
14
|
-
export type
|
|
15
|
-
export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
14
|
+
export type { Color, Size }
|
|
16
15
|
|
|
17
16
|
export interface Option<
|
|
18
17
|
ValueType extends string | number | boolean = string | number | boolean
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts" generic="T extends string | number | boolean">
|
|
2
2
|
import { type Component, computed } from 'vue'
|
|
3
3
|
import { type Validatable } from '../composables/Validation'
|
|
4
|
-
import SInputBase from './SInputBase.vue'
|
|
4
|
+
import SInputBase, { type Color, type Size } from './SInputBase.vue'
|
|
5
5
|
import SInputSegmentsOption, { type Mode } from './SInputSegmentsOption.vue'
|
|
6
6
|
|
|
7
|
-
export type
|
|
8
|
-
export type Color = 'default' | 'mute' | 'neutral' | 'info' | 'success' | 'warning' | 'danger'
|
|
9
|
-
export type CheckColor = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
7
|
+
export type { Color, Size }
|
|
10
8
|
|
|
11
9
|
export interface Option<T extends string | number | boolean> {
|
|
12
10
|
label: string
|
|
@@ -24,7 +22,7 @@ const props = defineProps<{
|
|
|
24
22
|
help?: string
|
|
25
23
|
checkIcon?: Component
|
|
26
24
|
checkText?: string
|
|
27
|
-
checkColor?:
|
|
25
|
+
checkColor?: Color
|
|
28
26
|
options: Option<T>[]
|
|
29
27
|
block?: boolean
|
|
30
28
|
disabled?: boolean
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts" generic="T extends string | number | boolean">
|
|
2
|
-
|
|
2
|
+
import { type Size } from './SInputBase.vue'
|
|
3
|
+
|
|
4
|
+
export type { Size }
|
|
3
5
|
export type Mode = 'default' | 'mute' | 'neutral' | 'info' | 'success' | 'warning' | 'danger'
|
|
4
6
|
|
|
5
7
|
const props = defineProps<{
|
|
@@ -4,11 +4,13 @@ import IconCaretUp from '~icons/ph/caret-up'
|
|
|
4
4
|
import { computed, ref } from 'vue'
|
|
5
5
|
import SInputBase, { type Props as BaseProps } from './SInputBase.vue'
|
|
6
6
|
|
|
7
|
+
export type { Color, Size } from './SInputBase.vue'
|
|
7
8
|
export interface Props extends BaseProps {
|
|
8
9
|
placeholder?: string
|
|
9
10
|
options: Option[]
|
|
10
11
|
nullable?: boolean
|
|
11
12
|
disabled?: boolean
|
|
13
|
+
tabindex?: -1 | 0 | number
|
|
12
14
|
value?: Value
|
|
13
15
|
modelValue?: Value
|
|
14
16
|
}
|
|
@@ -85,6 +87,7 @@ function emitChange(e: any): void {
|
|
|
85
87
|
class="select"
|
|
86
88
|
:class="{ 'is-not-selected': isNotSelected }"
|
|
87
89
|
:disabled
|
|
90
|
+
:tabindex
|
|
88
91
|
@focus="isFocused = true"
|
|
89
92
|
@blur="isFocused = false"
|
|
90
93
|
@change="emitChange"
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { type Component, computed } from 'vue'
|
|
3
3
|
import { type Validatable } from '../composables/Validation'
|
|
4
|
-
import SInputBase from './SInputBase.vue'
|
|
4
|
+
import SInputBase, { type Color, type Size } from './SInputBase.vue'
|
|
5
5
|
|
|
6
|
-
export type
|
|
6
|
+
export type { Color, Size }
|
|
7
7
|
export type ActiveColor = 'info' | 'success' | 'warning' | 'danger'
|
|
8
|
-
export type CheckColor = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
9
8
|
|
|
10
9
|
const props = withDefaults(defineProps<{
|
|
11
10
|
size?: Size
|
|
@@ -18,7 +17,7 @@ const props = withDefaults(defineProps<{
|
|
|
18
17
|
help?: string
|
|
19
18
|
checkIcon?: Component
|
|
20
19
|
checkText?: string
|
|
21
|
-
checkColor?:
|
|
20
|
+
checkColor?: Color
|
|
22
21
|
disabled?: boolean
|
|
23
22
|
value?: boolean
|
|
24
23
|
modelValue?: boolean
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { type Component, computed } from 'vue'
|
|
3
3
|
import { type Validatable } from '../composables/Validation'
|
|
4
|
-
import SInputBase from './SInputBase.vue'
|
|
4
|
+
import SInputBase, { type Color, type Size } from './SInputBase.vue'
|
|
5
5
|
import SInputSwitch from './SInputSwitch.vue'
|
|
6
6
|
|
|
7
|
-
export type
|
|
8
|
-
export type CheckColor = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
7
|
+
export type { Color, Size }
|
|
9
8
|
|
|
10
9
|
export interface Option {
|
|
11
10
|
label: string
|
|
@@ -21,7 +20,7 @@ const props = defineProps<{
|
|
|
21
20
|
help?: string
|
|
22
21
|
checkIcon?: Component
|
|
23
22
|
checkText?: string
|
|
24
|
-
checkColor?:
|
|
23
|
+
checkColor?: Color
|
|
25
24
|
options: Option[]
|
|
26
25
|
disabled?: boolean
|
|
27
26
|
modelValue: any[]
|
|
@@ -3,6 +3,7 @@ import { type Component, computed, ref } from 'vue'
|
|
|
3
3
|
import { isString } from '../support/Utils'
|
|
4
4
|
import SInputBase, { type Props as BaseProps } from './SInputBase.vue'
|
|
5
5
|
|
|
6
|
+
export type { Color, Size } from './SInputBase.vue'
|
|
6
7
|
export interface Props extends BaseProps {
|
|
7
8
|
type?: string
|
|
8
9
|
placeholder?: string
|
|
@@ -11,6 +12,7 @@ export interface Props extends BaseProps {
|
|
|
11
12
|
textColor?: TextColor | ((value: string | null) => TextColor)
|
|
12
13
|
align?: Align
|
|
13
14
|
disabled?: boolean
|
|
15
|
+
tabindex?: -1 | 0 | number
|
|
14
16
|
modelValue: string | null
|
|
15
17
|
displayValue?: string | null
|
|
16
18
|
}
|
|
@@ -134,6 +136,7 @@ function getValue(e: Event | FocusEvent | KeyboardEvent): string | null {
|
|
|
134
136
|
:type="type ?? 'text'"
|
|
135
137
|
:placeholder
|
|
136
138
|
:disabled
|
|
139
|
+
:tabindex
|
|
137
140
|
:value="modelValue"
|
|
138
141
|
ref="input"
|
|
139
142
|
@focus="onFocus"
|
|
@@ -3,9 +3,11 @@ import { computed, ref } from 'vue'
|
|
|
3
3
|
import SInputBase, { type Props as BaseProps } from './SInputBase.vue'
|
|
4
4
|
import SInputSegments from './SInputSegments.vue'
|
|
5
5
|
|
|
6
|
+
export type { Color, Size } from './SInputBase.vue'
|
|
6
7
|
export interface Props extends BaseProps {
|
|
7
8
|
placeholder?: string
|
|
8
9
|
disabled?: boolean
|
|
10
|
+
tabindex?: 0 | -1 | number
|
|
9
11
|
rows?: number | 'fill'
|
|
10
12
|
autoResize?: boolean | number
|
|
11
13
|
value?: string | null
|
|
@@ -115,6 +117,7 @@ const isPreview = ref(false)
|
|
|
115
117
|
:placeholder
|
|
116
118
|
:rows="rows === 'fill' ? 3 : rows"
|
|
117
119
|
:disabled
|
|
120
|
+
:tabindex
|
|
118
121
|
:value="_value ?? undefined"
|
|
119
122
|
@input="emitInput"
|
|
120
123
|
@blur="emitBlur"
|
package/lib/composables/Api.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useHttpConfig } from 'sefirot/stores/HttpConfig'
|
|
1
2
|
import { type Ref, type WatchSource, ref, watch } from 'vue'
|
|
2
3
|
import { Http } from '../http/Http'
|
|
3
4
|
import { tryOnMounted } from './Utils'
|
|
@@ -45,6 +46,7 @@ export function useQuery<Data = any>(
|
|
|
45
46
|
): Query<Data> {
|
|
46
47
|
const loading = ref(false)
|
|
47
48
|
const data = ref<Data | undefined>()
|
|
49
|
+
const httpConfig = useHttpConfig()
|
|
48
50
|
|
|
49
51
|
if (options.immediate !== false) {
|
|
50
52
|
tryOnMounted(execute)
|
|
@@ -57,7 +59,7 @@ export function useQuery<Data = any>(
|
|
|
57
59
|
async function execute({ assign = true, silent = false } = {}): Promise<Data> {
|
|
58
60
|
if (!silent) { loading.value = true }
|
|
59
61
|
|
|
60
|
-
const res: Data = await req(new Http())
|
|
62
|
+
const res: Data = await req(new Http(httpConfig))
|
|
61
63
|
if (assign) { data.value = res }
|
|
62
64
|
|
|
63
65
|
loading.value = false
|
|
@@ -72,11 +74,12 @@ export function useMutation<Data = any, Args extends any[] = any[]>(
|
|
|
72
74
|
): Mutation<Data, Args> {
|
|
73
75
|
const loading = ref(false)
|
|
74
76
|
const data = ref<Data | undefined>()
|
|
77
|
+
const httpConfig = useHttpConfig()
|
|
75
78
|
|
|
76
79
|
async function execute(...args: Args): Promise<Data> {
|
|
77
80
|
loading.value = true
|
|
78
81
|
|
|
79
|
-
const res: Data = await req(new Http(), ...args)
|
|
82
|
+
const res: Data = await req(new Http(httpConfig), ...args)
|
|
80
83
|
data.value = res
|
|
81
84
|
|
|
82
85
|
loading.value = false
|
package/lib/composables/App.ts
CHANGED
package/lib/composables/Http.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Lang, useBrowserLang } from 'sefirot/composables/Lang'
|
|
2
|
-
import {
|
|
2
|
+
import { type HttpOptions, useHttpConfig } from 'sefirot/stores/HttpConfig'
|
|
3
3
|
|
|
4
4
|
export interface HasLang {
|
|
5
5
|
lang: Lang
|
|
@@ -7,9 +7,10 @@ export interface HasLang {
|
|
|
7
7
|
|
|
8
8
|
export function useSetupHttp(): (user?: HasLang | null, options?: HttpOptions) => void {
|
|
9
9
|
const browserLang = useBrowserLang()
|
|
10
|
+
const httpConfig = useHttpConfig()
|
|
10
11
|
|
|
11
12
|
return (user, options = {}) => {
|
|
12
|
-
|
|
13
|
+
httpConfig.apply({
|
|
13
14
|
lang: user?.lang ?? browserLang,
|
|
14
15
|
...options
|
|
15
16
|
})
|
package/lib/http/Http.ts
CHANGED
|
@@ -1,70 +1,28 @@
|
|
|
1
1
|
import { parse as parseContentDisposition } from '@tinyhttp/content-disposition'
|
|
2
2
|
import { parse as parseCookie } from '@tinyhttp/cookie'
|
|
3
3
|
import FileSaver from 'file-saver'
|
|
4
|
-
import { FetchError, type FetchOptions, type
|
|
5
|
-
import {
|
|
6
|
-
import { type Lang } from '../composables/Lang'
|
|
4
|
+
import { FetchError, type FetchOptions, type FetchResponse } from 'ofetch'
|
|
5
|
+
import { stringify } from 'qs'
|
|
7
6
|
import { isBlob, isError, isFormData, isRequest, isResponse, isString } from '../support/Utils'
|
|
8
7
|
|
|
9
|
-
type
|
|
10
|
-
|
|
11
|
-
export interface HttpClient {
|
|
12
|
-
(request: FetchRequest, options?: Omit<FetchOptions, 'method'>): Promise<any>
|
|
13
|
-
raw(request: FetchRequest, options?: Omit<FetchOptions, 'method'>): Promise<FetchResponse<any>>
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface HttpOptions {
|
|
17
|
-
baseUrl?: string
|
|
18
|
-
xsrfUrl?: string | false
|
|
19
|
-
client?: HttpClient
|
|
20
|
-
lang?: Lang
|
|
21
|
-
payloadKey?: string
|
|
22
|
-
headers?: () => Awaitable<Record<string, string>>
|
|
23
|
-
stringifyOptions?: IStringifyOptions
|
|
24
|
-
}
|
|
8
|
+
type Config = ReturnType<typeof import('../stores/HttpConfig').useHttpConfig>
|
|
25
9
|
|
|
26
10
|
export class Http {
|
|
27
|
-
private
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
private static payloadKey = '__payload__'
|
|
32
|
-
private static headers: () => Awaitable<Record<string, string>> = async () => ({})
|
|
33
|
-
private static stringifyOptions: IStringifyOptions = {}
|
|
34
|
-
|
|
35
|
-
static config(options: HttpOptions): void {
|
|
36
|
-
if (options.baseUrl) {
|
|
37
|
-
Http.baseUrl = options.baseUrl
|
|
38
|
-
}
|
|
39
|
-
if (options.xsrfUrl !== undefined) {
|
|
40
|
-
Http.xsrfUrl = options.xsrfUrl
|
|
41
|
-
}
|
|
42
|
-
if (options.client) {
|
|
43
|
-
Http.client = options.client
|
|
44
|
-
}
|
|
45
|
-
if (options.lang) {
|
|
46
|
-
Http.lang = options.lang
|
|
47
|
-
}
|
|
48
|
-
if (options.payloadKey) {
|
|
49
|
-
Http.payloadKey = options.payloadKey
|
|
50
|
-
}
|
|
51
|
-
if (options.headers) {
|
|
52
|
-
Http.headers = options.headers
|
|
53
|
-
}
|
|
54
|
-
if (options.stringifyOptions) {
|
|
55
|
-
Http.stringifyOptions = options.stringifyOptions
|
|
56
|
-
}
|
|
11
|
+
private config: Config
|
|
12
|
+
|
|
13
|
+
constructor(options: Config) {
|
|
14
|
+
this.config = options
|
|
57
15
|
}
|
|
58
16
|
|
|
59
17
|
private async ensureXsrfToken(): Promise<string | undefined> {
|
|
60
|
-
if (!
|
|
18
|
+
if (!this.config.xsrfUrl) {
|
|
61
19
|
return undefined
|
|
62
20
|
}
|
|
63
21
|
|
|
64
22
|
let xsrfToken = parseCookie(document.cookie)['XSRF-TOKEN']
|
|
65
23
|
|
|
66
24
|
if (!xsrfToken) {
|
|
67
|
-
await this.head(
|
|
25
|
+
await this.head(this.config.xsrfUrl)
|
|
68
26
|
xsrfToken = parseCookie(document.cookie)['XSRF-TOKEN']
|
|
69
27
|
}
|
|
70
28
|
|
|
@@ -75,20 +33,20 @@ export class Http {
|
|
|
75
33
|
const { method, params, query, ...options } = _options
|
|
76
34
|
const xsrfToken = ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method || '') && (await this.ensureXsrfToken())
|
|
77
35
|
|
|
78
|
-
const queryString = stringify({ ...params, ...query }, { encodeValuesOnly: true, ...
|
|
36
|
+
const queryString = stringify({ ...params, ...query }, { encodeValuesOnly: true, ...this.config.stringifyOptions })
|
|
79
37
|
|
|
80
38
|
return [
|
|
81
39
|
`${url}${queryString ? `?${queryString}` : ''}`,
|
|
82
40
|
{
|
|
83
|
-
baseURL:
|
|
41
|
+
baseURL: this.config.baseUrl,
|
|
84
42
|
method,
|
|
85
43
|
credentials: 'include',
|
|
86
44
|
...options,
|
|
87
45
|
headers: {
|
|
88
46
|
Accept: 'application/json',
|
|
89
|
-
...(await
|
|
47
|
+
...(await this.config.headers()),
|
|
90
48
|
...(xsrfToken && { 'X-Xsrf-Token': xsrfToken }),
|
|
91
|
-
...(
|
|
49
|
+
...(this.config.lang && { 'Accept-Language': this.config.lang }),
|
|
92
50
|
...options.headers
|
|
93
51
|
}
|
|
94
52
|
}
|
|
@@ -96,11 +54,11 @@ export class Http {
|
|
|
96
54
|
}
|
|
97
55
|
|
|
98
56
|
private async performRequest<T>(url: string, options: FetchOptions = {}): Promise<T> {
|
|
99
|
-
return
|
|
57
|
+
return this.config.client(...(await this.buildRequest(url, options)))
|
|
100
58
|
}
|
|
101
59
|
|
|
102
60
|
private async performRequestRaw<T>(url: string, options: FetchOptions = {}): Promise<FetchResponse<T>> {
|
|
103
|
-
return
|
|
61
|
+
return this.config.client.raw(...(await this.buildRequest(url, options)))
|
|
104
62
|
}
|
|
105
63
|
|
|
106
64
|
async get<T = any>(url: string, options?: FetchOptions): Promise<T> {
|
|
@@ -125,7 +83,7 @@ export class Http {
|
|
|
125
83
|
|
|
126
84
|
if (hasFile) {
|
|
127
85
|
const formData = this.objectToFormData(body, undefined, undefined, true)
|
|
128
|
-
formData.append(
|
|
86
|
+
formData.append(this.config.payloadKey, payload)
|
|
129
87
|
body = formData
|
|
130
88
|
} else {
|
|
131
89
|
body = payload
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type FetchOptions, type FetchRequest, type FetchResponse, ofetch } from 'ofetch'
|
|
2
|
+
import { defineStore } from 'pinia'
|
|
3
|
+
import { type IStringifyOptions } from 'qs'
|
|
4
|
+
import { computed, ref } from 'vue'
|
|
5
|
+
import { type Lang } from '../composables/Lang'
|
|
6
|
+
|
|
7
|
+
type Awaitable<T> = T | PromiseLike<T>
|
|
8
|
+
|
|
9
|
+
export interface HttpClient {
|
|
10
|
+
(request: FetchRequest, options?: Omit<FetchOptions, 'method'>): Promise<any>
|
|
11
|
+
raw(request: FetchRequest, options?: Omit<FetchOptions, 'method'>): Promise<FetchResponse<any>>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface HttpOptions {
|
|
15
|
+
baseUrl?: string
|
|
16
|
+
xsrfUrl?: string | false
|
|
17
|
+
client?: HttpClient
|
|
18
|
+
lang?: Lang
|
|
19
|
+
payloadKey?: string
|
|
20
|
+
headers?: () => Awaitable<Record<string, string>>
|
|
21
|
+
stringifyOptions?: IStringifyOptions
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const useHttpConfig = defineStore('sefirot-http-config', () => {
|
|
25
|
+
const baseUrl = ref<string | undefined>(undefined)
|
|
26
|
+
const xsrfUrl = ref<string | false>('/api/csrf-cookie')
|
|
27
|
+
const client = ref<HttpClient>(ofetch)
|
|
28
|
+
const lang = ref<Lang | undefined>(undefined)
|
|
29
|
+
const payloadKey = ref<string>('__payload__')
|
|
30
|
+
const headers = ref<() => Awaitable<Record<string, string>>>(async () => ({}))
|
|
31
|
+
const stringifyOptions = ref<IStringifyOptions>({})
|
|
32
|
+
|
|
33
|
+
function apply(options: HttpOptions): void {
|
|
34
|
+
if (options.baseUrl != null) { baseUrl.value = options.baseUrl }
|
|
35
|
+
if (options.xsrfUrl != null) { xsrfUrl.value = options.xsrfUrl }
|
|
36
|
+
if (options.client != null) { client.value = options.client }
|
|
37
|
+
if (options.lang != null) { lang.value = options.lang }
|
|
38
|
+
if (options.payloadKey != null) { payloadKey.value = options.payloadKey }
|
|
39
|
+
if (options.headers != null) { headers.value = options.headers }
|
|
40
|
+
if (options.stringifyOptions != null) { stringifyOptions.value = options.stringifyOptions }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
baseUrl: computed(() => baseUrl.value),
|
|
45
|
+
xsrfUrl: computed(() => xsrfUrl.value),
|
|
46
|
+
client: computed(() => client.value),
|
|
47
|
+
lang: computed(() => lang.value),
|
|
48
|
+
payloadKey: computed(() => payloadKey.value),
|
|
49
|
+
headers: computed(() => headers.value),
|
|
50
|
+
stringifyOptions: computed(() => stringifyOptions.value),
|
|
51
|
+
apply
|
|
52
|
+
}
|
|
53
|
+
})
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@globalbrain/sefirot",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.30.0",
|
|
5
5
|
"packageManager": "pnpm@9.15.4",
|
|
6
6
|
"description": "Vue Components for Global Brain Design System.",
|
|
7
7
|
"author": "Kia Ishii <ka.ishii@globalbrains.com>",
|
|
@@ -121,6 +121,6 @@
|
|
|
121
121
|
"vitest": "^3.2.3",
|
|
122
122
|
"vue": "^3.5.16",
|
|
123
123
|
"vue-router": "^4.5.1",
|
|
124
|
-
"vue-tsc": "^
|
|
124
|
+
"vue-tsc": "^3.0.4"
|
|
125
125
|
}
|
|
126
126
|
}
|