@globalbrain/sefirot 4.23.1 → 4.25.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/config/vite.js +7 -3
- package/lib/components/SActionMenu.vue +1 -1
- package/lib/components/SButton.vue +3 -3
- package/lib/components/SControlActionMenu.vue +1 -1
- package/lib/components/SControlButton.vue +1 -1
- package/lib/components/SLocalNavActions.vue +2 -1
- package/lib/components/SMarkdown.vue +12 -40
- package/lib/components/SMount.vue +2 -2
- package/lib/components/STooltip.vue +3 -3
- package/lib/composables/Markdown.ts +41 -127
- package/package.json +23 -22
- package/lib/composables/markdown/LinkPlugin.ts +0 -45
package/config/vite.js
CHANGED
|
@@ -46,8 +46,10 @@ export const baseConfig = {
|
|
|
46
46
|
'sefirot/': fileURLToPath(new URL('../lib/', import.meta.url))
|
|
47
47
|
},
|
|
48
48
|
|
|
49
|
+
// list the client-side direct dependencies/peerDependencies which get bundled
|
|
49
50
|
dedupe: [
|
|
50
51
|
'@sentry/browser',
|
|
52
|
+
'@sentry/vue',
|
|
51
53
|
'@tanstack/vue-virtual',
|
|
52
54
|
'@tinyhttp/content-disposition',
|
|
53
55
|
'@tinyhttp/cookie',
|
|
@@ -56,10 +58,12 @@ export const baseConfig = {
|
|
|
56
58
|
'@vuelidate/validators',
|
|
57
59
|
'@vueuse/core',
|
|
58
60
|
'body-scroll-lock',
|
|
59
|
-
'dayjs',
|
|
60
61
|
'd3',
|
|
62
|
+
'dayjs',
|
|
63
|
+
'dompurify',
|
|
61
64
|
'file-saver',
|
|
62
65
|
'fuse.js',
|
|
66
|
+
'html2canvas',
|
|
63
67
|
'lodash-es',
|
|
64
68
|
'markdown-it',
|
|
65
69
|
'normalize.css',
|
|
@@ -67,8 +71,8 @@ export const baseConfig = {
|
|
|
67
71
|
'pinia',
|
|
68
72
|
'qs',
|
|
69
73
|
'v-calendar',
|
|
70
|
-
'vue
|
|
71
|
-
'vue'
|
|
74
|
+
'vue',
|
|
75
|
+
'vue-router'
|
|
72
76
|
]
|
|
73
77
|
},
|
|
74
78
|
|
|
@@ -22,8 +22,8 @@ export type Mode =
|
|
|
22
22
|
| 'danger'
|
|
23
23
|
|
|
24
24
|
export interface Tooltip {
|
|
25
|
-
tag?: string
|
|
26
|
-
triggerTag?: string
|
|
25
|
+
tag?: Component | string
|
|
26
|
+
triggerTag?: Component | string
|
|
27
27
|
text?: MaybeRef<string | null>
|
|
28
28
|
position?: Position
|
|
29
29
|
display?: 'inline' | 'inline-block' | 'block'
|
|
@@ -32,7 +32,7 @@ export interface Tooltip {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
const props = defineProps<{
|
|
35
|
-
tag?: string
|
|
35
|
+
tag?: Component | string
|
|
36
36
|
size?: Size
|
|
37
37
|
type?: Type
|
|
38
38
|
mode?: Mode
|
|
@@ -3,7 +3,7 @@ import { type Component } from 'vue'
|
|
|
3
3
|
import SButton, { type Mode, type Tooltip, type Type } from './SButton.vue'
|
|
4
4
|
|
|
5
5
|
export interface Action {
|
|
6
|
-
tag?: string
|
|
6
|
+
tag?: Component | string
|
|
7
7
|
type?: Type
|
|
8
8
|
mode?: Mode
|
|
9
9
|
icon?: Component
|
|
@@ -29,6 +29,7 @@ defineProps<{
|
|
|
29
29
|
<div v-for="action, i in actions" :key="i" class="action">
|
|
30
30
|
<SButton
|
|
31
31
|
size="small"
|
|
32
|
+
:tag="action.tag"
|
|
32
33
|
:type="action.type"
|
|
33
34
|
:mode="action.mode"
|
|
34
35
|
:icon="action.icon"
|
|
@@ -1,52 +1,24 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { type Component, computed } from 'vue'
|
|
3
|
+
import { useMarkdown } from '../composables/Markdown'
|
|
4
4
|
|
|
5
|
-
const props = defineProps<{
|
|
6
|
-
tag?: string
|
|
5
|
+
const props = withDefaults(defineProps<{
|
|
6
|
+
tag?: Component | string
|
|
7
7
|
content: string
|
|
8
|
-
|
|
8
|
+
html?: boolean
|
|
9
9
|
inline?: boolean
|
|
10
|
-
}>()
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
clicked: [payload: LinkSubscriberPayload]
|
|
14
|
-
}>()
|
|
15
|
-
|
|
16
|
-
const container = shallowRef<Element | null>(null)
|
|
17
|
-
|
|
18
|
-
const { addListeners, subscribe } = useLink({
|
|
19
|
-
container,
|
|
20
|
-
callbacks: props.callbacks
|
|
10
|
+
}>(), {
|
|
11
|
+
tag: 'div',
|
|
12
|
+
html: true
|
|
21
13
|
})
|
|
22
14
|
|
|
23
|
-
const markdown = useMarkdown()
|
|
24
|
-
const rendered = computed(() => markdown(props.content
|
|
25
|
-
|
|
26
|
-
watch(
|
|
27
|
-
rendered,
|
|
28
|
-
() => nextTick(() => addListeners()),
|
|
29
|
-
{ immediate: true }
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
subscribe((payload) => emit('clicked', payload))
|
|
15
|
+
const markdown = useMarkdown({ html: props.html, inline: props.inline })
|
|
16
|
+
const rendered = computed(() => markdown(props.content))
|
|
33
17
|
</script>
|
|
34
18
|
|
|
35
19
|
<template>
|
|
36
|
-
<component
|
|
37
|
-
v-if="$slots.default"
|
|
38
|
-
:is="tag ?? 'div'"
|
|
39
|
-
class="SMarkdown-container"
|
|
40
|
-
ref="container"
|
|
41
|
-
>
|
|
20
|
+
<component v-if="$slots.default" :is="tag" class="SMarkdown-container">
|
|
42
21
|
<slot v-bind="{ rendered }" />
|
|
43
22
|
</component>
|
|
44
|
-
|
|
45
|
-
<component
|
|
46
|
-
v-else
|
|
47
|
-
:is="tag ?? 'div'"
|
|
48
|
-
class="SMarkdown-container"
|
|
49
|
-
ref="container"
|
|
50
|
-
v-html="rendered"
|
|
51
|
-
/>
|
|
23
|
+
<component v-else :is="tag" class="SMarkdown-container" v-html="rendered" />
|
|
52
24
|
</template>
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { onClickOutside, onKeyStroke, useElementHover, useFocusWithin } from '@vueuse/core'
|
|
3
|
-
import { computed, onBeforeUnmount, ref, shallowRef, watch } from 'vue'
|
|
3
|
+
import { type Component, computed, onBeforeUnmount, ref, shallowRef, watch } from 'vue'
|
|
4
4
|
import { type Position, useTooltip } from '../composables/Tooltip'
|
|
5
5
|
|
|
6
6
|
const props = withDefaults(defineProps<{
|
|
7
|
-
tag?: string
|
|
8
|
-
triggerTag?: string
|
|
7
|
+
tag?: Component | string
|
|
8
|
+
triggerTag?: Component | string
|
|
9
9
|
text?: string
|
|
10
10
|
position?: Position
|
|
11
11
|
display?: 'inline' | 'inline-block' | 'block'
|
|
@@ -1,34 +1,54 @@
|
|
|
1
|
+
import DOMPurify, { type Config } from 'dompurify'
|
|
1
2
|
import MarkdownIt, { type Options as MarkdownItOptions } from 'markdown-it'
|
|
2
|
-
import { type Ref, onUnmounted } from 'vue'
|
|
3
|
-
import { useRouter } from 'vue-router'
|
|
4
|
-
import { type LinkAttrs, isCallbackUrl, isExternalUrl, linkPlugin } from './markdown/LinkPlugin'
|
|
5
3
|
|
|
6
|
-
export type UseMarkdown = (source: string, inline
|
|
4
|
+
export type UseMarkdown = (source: string, inline?: boolean) => string
|
|
7
5
|
|
|
8
6
|
export interface UseMarkdownOptions extends MarkdownItOptions {
|
|
9
|
-
linkAttrs?: LinkAttrs
|
|
10
7
|
config?: (md: MarkdownIt) => void
|
|
8
|
+
/** @default false */
|
|
9
|
+
inline?: boolean
|
|
10
|
+
domPurifyOptions?: Config
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
const md = new MarkdownIt({
|
|
15
|
-
html: true,
|
|
16
|
-
linkify: true,
|
|
17
|
-
...options
|
|
18
|
-
})
|
|
13
|
+
const EXTERNAL_URL_RE = /^(?:[a-z]+:|\/\/)/i
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
if (typeof document !== 'undefined') {
|
|
16
|
+
DOMPurify.addHook('afterSanitizeAttributes', (node) => {
|
|
17
|
+
if (node.tagName === 'A') {
|
|
18
|
+
const target = node.getAttribute('target')
|
|
19
|
+
if (target && target !== '_blank' && target !== '_self') {
|
|
20
|
+
node.removeAttribute('target')
|
|
21
|
+
}
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
const href = node.getAttribute('href')
|
|
24
|
+
if (href && EXTERNAL_URL_RE.test(href)) {
|
|
25
|
+
node.setAttribute('target', '_blank')
|
|
26
|
+
node.setAttribute('rel', 'noreferrer')
|
|
27
|
+
}
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
node.classList.add('SMarkdown-link')
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function useMarkdown({
|
|
35
|
+
config,
|
|
36
|
+
inline: _inline,
|
|
37
|
+
domPurifyOptions,
|
|
38
|
+
...options
|
|
39
|
+
}: UseMarkdownOptions = {}): UseMarkdown {
|
|
40
|
+
//
|
|
41
|
+
|
|
42
|
+
const md = new MarkdownIt({ html: true, linkify: true, ...options })
|
|
43
|
+
config?.(md)
|
|
44
|
+
|
|
45
|
+
return (source, inline = _inline) => {
|
|
46
|
+
const html = inline ? md.renderInline(source) : md.render(source)
|
|
47
|
+
return DOMPurify.sanitize(html, {
|
|
48
|
+
USE_PROFILES: { html: true },
|
|
49
|
+
ADD_ATTR: ['target'],
|
|
50
|
+
...domPurifyOptions
|
|
51
|
+
})
|
|
32
52
|
}
|
|
33
53
|
}
|
|
34
54
|
|
|
@@ -45,109 +65,3 @@ export function useLinkifyIt() {
|
|
|
45
65
|
|
|
46
66
|
return (source: string) => md.renderInline(source)
|
|
47
67
|
}
|
|
48
|
-
|
|
49
|
-
export interface UseLink {
|
|
50
|
-
addListeners(): void
|
|
51
|
-
removeListeners(): void
|
|
52
|
-
subscribe(cb: LinkSubscriber): () => void
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface UseLinkOptions {
|
|
56
|
-
container: Ref<Element | null>
|
|
57
|
-
callbacks?: LinkCallback[]
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export interface LinkSubscriberPayload {
|
|
61
|
-
event: Event
|
|
62
|
-
target: HTMLAnchorElement
|
|
63
|
-
isExternal: boolean
|
|
64
|
-
isCallback: boolean
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export type LinkSubscriber = (payload: LinkSubscriberPayload) => void
|
|
68
|
-
|
|
69
|
-
export type LinkCallback = () => void
|
|
70
|
-
|
|
71
|
-
export function useLink({ container, callbacks }: UseLinkOptions): UseLink {
|
|
72
|
-
const router = useRouter()
|
|
73
|
-
const subscribers: LinkSubscriber[] = []
|
|
74
|
-
|
|
75
|
-
onUnmounted(() => removeListeners())
|
|
76
|
-
|
|
77
|
-
function handler(event: Event): void {
|
|
78
|
-
const target = event.target as HTMLAnchorElement
|
|
79
|
-
const href = target.getAttribute('href')!
|
|
80
|
-
|
|
81
|
-
if (!href) {
|
|
82
|
-
return
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const isExternal = isExternalUrl(href)
|
|
86
|
-
const isCallback = isCallbackUrl(href)
|
|
87
|
-
|
|
88
|
-
subscribers.forEach((sub) => sub({
|
|
89
|
-
event,
|
|
90
|
-
target,
|
|
91
|
-
isExternal,
|
|
92
|
-
isCallback
|
|
93
|
-
}))
|
|
94
|
-
|
|
95
|
-
if (isExternal) {
|
|
96
|
-
return
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (!event.defaultPrevented) {
|
|
100
|
-
event.preventDefault()
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (isCallback) {
|
|
104
|
-
const idx = Number.parseInt(target.dataset.callbackId || '')
|
|
105
|
-
const callback = (callbacks ?? [])[idx]
|
|
106
|
-
|
|
107
|
-
if (!callback) {
|
|
108
|
-
throw new Error(`Callback not found at index: ${idx}`)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return callback()
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
router.push(href)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function addListeners(): void {
|
|
118
|
-
removeListeners()
|
|
119
|
-
|
|
120
|
-
if (container.value) {
|
|
121
|
-
findLinks(container.value).forEach((element) => {
|
|
122
|
-
element.addEventListener('click', handler)
|
|
123
|
-
})
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function removeListeners(): void {
|
|
128
|
-
if (container.value) {
|
|
129
|
-
findLinks(container.value).forEach((element) => {
|
|
130
|
-
element.removeEventListener('click', handler)
|
|
131
|
-
})
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function subscribe(fn: LinkSubscriber): () => void {
|
|
136
|
-
subscribers.push(fn)
|
|
137
|
-
|
|
138
|
-
return () => {
|
|
139
|
-
const idx = subscribers.indexOf(fn)
|
|
140
|
-
idx > -1 && subscribers.splice(idx, 1)
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return {
|
|
145
|
-
addListeners,
|
|
146
|
-
removeListeners,
|
|
147
|
-
subscribe
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function findLinks(target: Element) {
|
|
152
|
-
return target.querySelectorAll('a.SMarkdown-link')
|
|
153
|
-
}
|
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.25.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>",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"@types/body-scroll-lock": "^3.1.2",
|
|
49
49
|
"@types/lodash-es": "^4.17.12",
|
|
50
50
|
"@types/markdown-it": "^14.1.2",
|
|
51
|
-
"@vue/reactivity": "^3.5.
|
|
51
|
+
"@vue/reactivity": "^3.5.16",
|
|
52
52
|
"@vuelidate/core": "^2.0.3",
|
|
53
53
|
"@vuelidate/validators": "^2.0.4",
|
|
54
54
|
"@vueuse/core": "^12 || ^13",
|
|
@@ -58,23 +58,24 @@
|
|
|
58
58
|
"lodash-es": "^4.17.21",
|
|
59
59
|
"markdown-it": "^14.1.0",
|
|
60
60
|
"normalize.css": "^8.0.1",
|
|
61
|
-
"pinia": "^3.0.
|
|
62
|
-
"postcss": "^8.5.
|
|
61
|
+
"pinia": "^3.0.3",
|
|
62
|
+
"postcss": "^8.5.5",
|
|
63
63
|
"postcss-nested": "^7.0.2",
|
|
64
64
|
"v-calendar": "3.0.1",
|
|
65
|
-
"vue": "^3.5.
|
|
66
|
-
"vue-router": "^4.5.
|
|
65
|
+
"vue": "^3.5.16",
|
|
66
|
+
"vue-router": "^4.5.1"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"@sentry/browser": "^9.
|
|
70
|
-
"@sentry/vue": "^9.
|
|
69
|
+
"@sentry/browser": "^9.29.0",
|
|
70
|
+
"@sentry/vue": "^9.29.0",
|
|
71
71
|
"@tanstack/vue-virtual": "3.0.0-beta.62",
|
|
72
72
|
"@tinyhttp/content-disposition": "^2.2.2",
|
|
73
73
|
"@tinyhttp/cookie": "^2.1.1",
|
|
74
74
|
"@types/d3": "^7.4.3",
|
|
75
75
|
"@types/file-saver": "^2.0.7",
|
|
76
|
-
"@types/qs": "^6.
|
|
76
|
+
"@types/qs": "^6.14.0",
|
|
77
77
|
"d3": "^7.9.0",
|
|
78
|
+
"dompurify": "^3.2.6",
|
|
78
79
|
"file-saver": "^2.0.5",
|
|
79
80
|
"html2canvas": "^1.4.1",
|
|
80
81
|
"magic-string": "^0.30.17",
|
|
@@ -91,10 +92,10 @@
|
|
|
91
92
|
"@types/body-scroll-lock": "^3.1.2",
|
|
92
93
|
"@types/lodash-es": "^4.17.12",
|
|
93
94
|
"@types/markdown-it": "^14.1.2",
|
|
94
|
-
"@types/node": "^
|
|
95
|
-
"@vitejs/plugin-vue": "^5.2.
|
|
96
|
-
"@vitest/coverage-v8": "^3.
|
|
97
|
-
"@vue/reactivity": "^3.5.
|
|
95
|
+
"@types/node": "^24.0.1",
|
|
96
|
+
"@vitejs/plugin-vue": "^5.2.4",
|
|
97
|
+
"@vitest/coverage-v8": "^3.2.3",
|
|
98
|
+
"@vue/reactivity": "^3.5.16",
|
|
98
99
|
"@vue/test-utils": "^2.4.6",
|
|
99
100
|
"@vuelidate/core": "^2.0.3",
|
|
100
101
|
"@vuelidate/validators": "^2.0.4",
|
|
@@ -103,23 +104,23 @@
|
|
|
103
104
|
"dayjs": "^1.11.13",
|
|
104
105
|
"eslint": "8.57.0",
|
|
105
106
|
"fuse.js": "^7.1.0",
|
|
106
|
-
"happy-dom": "^
|
|
107
|
+
"happy-dom": "^18.0.1",
|
|
107
108
|
"histoire": "0.16.5",
|
|
108
109
|
"lodash-es": "^4.17.21",
|
|
109
110
|
"markdown-it": "^14.1.0",
|
|
110
111
|
"normalize.css": "^8.0.1",
|
|
111
|
-
"pinia": "^3.0.
|
|
112
|
-
"postcss": "^8.5.
|
|
112
|
+
"pinia": "^3.0.3",
|
|
113
|
+
"postcss": "^8.5.5",
|
|
113
114
|
"postcss-nested": "^7.0.2",
|
|
114
115
|
"punycode": "^2.3.1",
|
|
115
|
-
"release-it": "^19.0.
|
|
116
|
+
"release-it": "^19.0.3",
|
|
116
117
|
"typescript": "~5.8.3",
|
|
117
118
|
"v-calendar": "3.0.1",
|
|
118
|
-
"vite": "^6.3.
|
|
119
|
-
"vitepress": "
|
|
120
|
-
"vitest": "^3.
|
|
121
|
-
"vue": "^3.5.
|
|
122
|
-
"vue-router": "^4.5.
|
|
119
|
+
"vite": "^6.3.5",
|
|
120
|
+
"vitepress": "^2.0.0-alpha.6",
|
|
121
|
+
"vitest": "^3.2.3",
|
|
122
|
+
"vue": "^3.5.16",
|
|
123
|
+
"vue-router": "^4.5.1",
|
|
123
124
|
"vue-tsc": "^2.2.10"
|
|
124
125
|
}
|
|
125
126
|
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type MarkdownIt from 'markdown-it'
|
|
2
|
-
|
|
3
|
-
export type LinkAttrs = Record<string, string>
|
|
4
|
-
|
|
5
|
-
const EXTERNAL_REGEX = /^https?:/
|
|
6
|
-
const CALLBACK_REGEX = /\{([\d}]+)\}/
|
|
7
|
-
const CALLBACK_HREF = '#callback'
|
|
8
|
-
|
|
9
|
-
export function linkPlugin(md: MarkdownIt, linkAttrs: LinkAttrs = {}): void {
|
|
10
|
-
md.renderer.rules.link_open = (tokens, idx, options, _env, self) => {
|
|
11
|
-
const token = tokens[idx]
|
|
12
|
-
const hrefIndex = token.attrIndex('href')
|
|
13
|
-
|
|
14
|
-
if (hrefIndex >= 0) {
|
|
15
|
-
const hrefAttr = token.attrs![hrefIndex]
|
|
16
|
-
const url = decodeURIComponent(hrefAttr[1])
|
|
17
|
-
|
|
18
|
-
if (isExternalUrl(url)) {
|
|
19
|
-
Object.entries(linkAttrs).forEach(([key, val]) => {
|
|
20
|
-
token.attrSet(key, val)
|
|
21
|
-
})
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (isCallbackUrl(url)) {
|
|
25
|
-
const matched = url.match(CALLBACK_REGEX)![1]
|
|
26
|
-
|
|
27
|
-
token.attrSet('data-callback-id', matched)
|
|
28
|
-
|
|
29
|
-
hrefAttr[1] = CALLBACK_HREF
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
token.attrSet('class', 'SMarkdown-link')
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return self.renderToken(tokens, idx, options)
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function isExternalUrl(url: string): boolean {
|
|
40
|
-
return EXTERNAL_REGEX.test(url)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function isCallbackUrl(url: string): boolean {
|
|
44
|
-
return url === CALLBACK_HREF || CALLBACK_REGEX.test(decodeURIComponent(url))
|
|
45
|
-
}
|