dynamic rich text color
This commit is contained in:
@@ -156,6 +156,7 @@
|
|||||||
"lodash.isequal": "^4.5.0",
|
"lodash.isequal": "^4.5.0",
|
||||||
"lodash.shuffle": "^4.2.0",
|
"lodash.shuffle": "^4.2.0",
|
||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
|
"mix-css-color": "^0.2.0",
|
||||||
"multiformats": "^13.1.0",
|
"multiformats": "^13.1.0",
|
||||||
"nanoid": "^5.0.5",
|
"nanoid": "^5.0.5",
|
||||||
"normalize-url": "^8.0.0",
|
"normalize-url": "^8.0.0",
|
||||||
@@ -200,6 +201,7 @@
|
|||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
"tlds": "^1.234.0",
|
"tlds": "^1.234.0",
|
||||||
"tldts": "^6.1.46",
|
"tldts": "^6.1.46",
|
||||||
|
"wcag-contrast": "^3.0.0",
|
||||||
"zeego": "^1.6.2",
|
"zeego": "^1.6.2",
|
||||||
"zod": "^3.20.2"
|
"zod": "^3.20.2"
|
||||||
},
|
},
|
||||||
@@ -227,6 +229,7 @@
|
|||||||
"@types/react-dom": "^18.2.18",
|
"@types/react-dom": "^18.2.18",
|
||||||
"@types/react-responsive": "^8.0.5",
|
"@types/react-responsive": "^8.0.5",
|
||||||
"@types/react-test-renderer": "^17.0.1",
|
"@types/react-test-renderer": "^17.0.1",
|
||||||
|
"@types/wcag-contrast": "^3.0.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||||
"@typescript-eslint/parser": "^7.18.0",
|
"@typescript-eslint/parser": "^7.18.0",
|
||||||
"babel-jest": "^29.7.0",
|
"babel-jest": "^29.7.0",
|
||||||
|
|||||||
+14
-14
@@ -8,13 +8,14 @@ import {useNavigation} from '@react-navigation/native'
|
|||||||
import {NavigationProp} from '#/lib/routes/types'
|
import {NavigationProp} from '#/lib/routes/types'
|
||||||
import {toShortUrl} from '#/lib/strings/url-helpers'
|
import {toShortUrl} from '#/lib/strings/url-helpers'
|
||||||
import {isNative} from '#/platform/detection'
|
import {isNative} from '#/platform/detection'
|
||||||
import {atoms as a, flatten, native, TextStyleProp, useTheme, web} from '#/alf'
|
import {atoms as a, flatten, native, TextStyleProp, web} from '#/alf'
|
||||||
import {isOnlyEmoji} from '#/alf/typography'
|
import {isOnlyEmoji} from '#/alf/typography'
|
||||||
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
||||||
import {InlineLinkText, LinkProps} from '#/components/Link'
|
import {InlineLinkText, LinkProps} from '#/components/Link'
|
||||||
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
||||||
import {TagMenu, useTagMenuControl} from '#/components/TagMenu'
|
import {TagMenu, useTagMenuControl} from '#/components/TagMenu'
|
||||||
import {Text, TextProps} from '#/components/Typography'
|
import {Text, TextProps} from '#/components/Typography'
|
||||||
|
import {useDynamicColor} from './hooks/useDynamicColor'
|
||||||
|
|
||||||
const WORD_WRAP = {wordWrap: 1}
|
const WORD_WRAP = {wordWrap: 1}
|
||||||
|
|
||||||
@@ -29,6 +30,7 @@ export type RichTextProps = TextStyleProp &
|
|||||||
onLinkPress?: LinkProps['onPress']
|
onLinkPress?: LinkProps['onPress']
|
||||||
interactiveStyle?: TextStyle
|
interactiveStyle?: TextStyle
|
||||||
emojiMultiplier?: number
|
emojiMultiplier?: number
|
||||||
|
dynamicColor?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RichText({
|
export function RichText({
|
||||||
@@ -43,6 +45,7 @@ export function RichText({
|
|||||||
onLinkPress,
|
onLinkPress,
|
||||||
interactiveStyle,
|
interactiveStyle,
|
||||||
emojiMultiplier = 1.85,
|
emojiMultiplier = 1.85,
|
||||||
|
dynamicColor = false,
|
||||||
}: RichTextProps) {
|
}: RichTextProps) {
|
||||||
const richText = React.useMemo(
|
const richText = React.useMemo(
|
||||||
() =>
|
() =>
|
||||||
@@ -50,10 +53,13 @@ export function RichText({
|
|||||||
[value],
|
[value],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const interactiveColor = useDynamicColor({enabled: dynamicColor})
|
||||||
|
|
||||||
const flattenedStyle = flatten(style)
|
const flattenedStyle = flatten(style)
|
||||||
const plainStyles = [a.leading_snug, flattenedStyle]
|
const plainStyles = [a.leading_snug, flattenedStyle]
|
||||||
const interactiveStyles = [
|
const interactiveStyles = [
|
||||||
a.leading_snug,
|
a.leading_snug,
|
||||||
|
interactiveColor,
|
||||||
flatten(interactiveStyle),
|
flatten(interactiveStyle),
|
||||||
flattenedStyle,
|
flattenedStyle,
|
||||||
]
|
]
|
||||||
@@ -182,7 +188,6 @@ function RichTextTag({
|
|||||||
selectable?: boolean
|
selectable?: boolean
|
||||||
authorHandle?: string
|
authorHandle?: string
|
||||||
} & TextStyleProp) {
|
} & TextStyleProp) {
|
||||||
const t = useTheme()
|
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const control = useTagMenuControl()
|
const control = useTagMenuControl()
|
||||||
const {
|
const {
|
||||||
@@ -224,22 +229,17 @@ function RichTextTag({
|
|||||||
{...web({
|
{...web({
|
||||||
onMouseEnter: onHoverIn,
|
onMouseEnter: onHoverIn,
|
||||||
onMouseLeave: onHoverOut,
|
onMouseLeave: onHoverOut,
|
||||||
|
onFocus: onFocus,
|
||||||
|
onBlur: onBlur,
|
||||||
})}
|
})}
|
||||||
// @ts-ignore
|
|
||||||
onFocus={onFocus}
|
|
||||||
onBlur={onBlur}
|
|
||||||
style={[
|
style={[
|
||||||
web({
|
web({cursor: 'pointer'}),
|
||||||
cursor: 'pointer',
|
web(
|
||||||
}),
|
(hovered || focused) && {
|
||||||
{color: t.palette.primary_500},
|
|
||||||
(hovered || focused) && {
|
|
||||||
...web({
|
|
||||||
outline: 0,
|
outline: 0,
|
||||||
textDecorationLine: 'underline',
|
textDecorationLine: 'underline',
|
||||||
textDecorationColor: t.palette.primary_500,
|
},
|
||||||
}),
|
),
|
||||||
},
|
|
||||||
style,
|
style,
|
||||||
]}>
|
]}>
|
||||||
{text}
|
{text}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import {useMemo} from 'react'
|
||||||
|
import {StyleProp, TextStyle} from 'react-native'
|
||||||
|
import mixColors from 'mix-css-color'
|
||||||
|
import {rgb as compareContrast} from 'wcag-contrast'
|
||||||
|
|
||||||
|
import {useTheme} from '#/alf'
|
||||||
|
|
||||||
|
export function useDynamicColor({enabled} = {enabled: false}) {
|
||||||
|
const t = useTheme()
|
||||||
|
|
||||||
|
const color = enabled
|
||||||
|
? getDynamicColor(t.name !== 'light', t.palette.primary_500)
|
||||||
|
: t.palette.primary_500
|
||||||
|
|
||||||
|
return useMemo(
|
||||||
|
() =>
|
||||||
|
({
|
||||||
|
color,
|
||||||
|
textDecorationColor: color,
|
||||||
|
} satisfies StyleProp<TextStyle>),
|
||||||
|
[color],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// the goal is to return a blue color that should be an acceptable constrast with
|
||||||
|
// the background color. the default blue is rgb(16, 131, 254)
|
||||||
|
// we want to color mix it with the background color
|
||||||
|
// and flip to whiteish if it's going to be unacceptable low contrast
|
||||||
|
const BASE_COLOR_LIGHT = 'rgb(16, 131, 254)'
|
||||||
|
const BASE_COLOR_DARK = 'rgb(32, 139, 254)'
|
||||||
|
function getDynamicColor(dark: boolean, themeColor: string) {
|
||||||
|
const baseColor = dark ? BASE_COLOR_DARK : BASE_COLOR_LIGHT
|
||||||
|
const blendedColor = mixColors(baseColor, themeColor, 75)
|
||||||
|
debugColorContrast(
|
||||||
|
blendedColor,
|
||||||
|
// for debug, we simulate the linear gradient on the profile
|
||||||
|
mixColors(themeColor, '#ffffff', 30),
|
||||||
|
)
|
||||||
|
let [h, s, l] = blendedColor.hsla
|
||||||
|
return `hsl(${h}, ${s}%, ${l * 1.1}%)`
|
||||||
|
}
|
||||||
|
|
||||||
|
function debugColorContrast(
|
||||||
|
foreground: ReturnType<typeof mixColors>,
|
||||||
|
background: ReturnType<typeof mixColors>,
|
||||||
|
) {
|
||||||
|
const score = getContrastScore(foreground, background)
|
||||||
|
console.log(
|
||||||
|
`%c ${score > 4.5 ? 'PASS' : 'FAIL'}: ${Math.trunc(score * 10) / 10} `,
|
||||||
|
`color: ${foreground.hex}; background: ${background.hex}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContrastScore(
|
||||||
|
foreground: ReturnType<typeof mixColors>,
|
||||||
|
background: ReturnType<typeof mixColors>,
|
||||||
|
) {
|
||||||
|
const [r1, g1, b1] = foreground.rgba
|
||||||
|
const [r2, g2, b2] = background.rgba
|
||||||
|
return compareContrast([r1, g1, b1], [r2, g2, b2])
|
||||||
|
}
|
||||||
@@ -264,6 +264,7 @@ let ProfileHeaderLabeler = ({
|
|||||||
value={descriptionRT}
|
value={descriptionRT}
|
||||||
enableTags
|
enableTags
|
||||||
authorHandle={profile.handle}
|
authorHandle={profile.handle}
|
||||||
|
dynamicColor
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
|
|||||||
@@ -257,6 +257,7 @@ let ProfileHeaderStandard = ({
|
|||||||
value={descriptionRT}
|
value={descriptionRT}
|
||||||
enableTags
|
enableTags
|
||||||
authorHandle={profile.handle}
|
authorHandle={profile.handle}
|
||||||
|
dynamicColor
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
|
|||||||
@@ -7204,6 +7204,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz#60be8d21baab8c305132eb9cb912ed497852aadc"
|
resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz#60be8d21baab8c305132eb9cb912ed497852aadc"
|
||||||
integrity sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==
|
integrity sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==
|
||||||
|
|
||||||
|
"@types/wcag-contrast@^3.0.3":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/wcag-contrast/-/wcag-contrast-3.0.3.tgz#0b0339ab210b859eeee555b3fef58d293216905c"
|
||||||
|
integrity sha512-oprevfwJSLfpQK4KaWsRKJuNoebV76+xhmbXiWJGy+FkS34LpCgCMNIwRXWTb8xmmSxUE2ycFOYE7uyRVRm3LA==
|
||||||
|
|
||||||
"@types/ws@^8.5.5":
|
"@types/ws@^8.5.5":
|
||||||
version "8.5.5"
|
version "8.5.5"
|
||||||
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb"
|
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb"
|
||||||
@@ -8871,7 +8876,7 @@ color-name@1.1.3:
|
|||||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||||
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
||||||
|
|
||||||
color-name@^1.0.0, color-name@~1.1.4:
|
color-name@^1.0.0, color-name@^1.1.4, color-name@~1.1.4:
|
||||||
version "1.1.4"
|
version "1.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||||
@@ -10314,6 +10319,11 @@ eslint@^8.19.0:
|
|||||||
strip-ansi "^6.0.1"
|
strip-ansi "^6.0.1"
|
||||||
text-table "^0.2.0"
|
text-table "^0.2.0"
|
||||||
|
|
||||||
|
esm@^3.0.84:
|
||||||
|
version "3.2.25"
|
||||||
|
resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
|
||||||
|
integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
|
||||||
|
|
||||||
espree@^9.6.0, espree@^9.6.1:
|
espree@^9.6.0, espree@^9.6.1:
|
||||||
version "9.6.1"
|
version "9.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
|
resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
|
||||||
@@ -11707,6 +11717,11 @@ hermes-profile-transformer@^0.0.6:
|
|||||||
dependencies:
|
dependencies:
|
||||||
source-map "^0.7.3"
|
source-map "^0.7.3"
|
||||||
|
|
||||||
|
hex-rgb@^4.1.0:
|
||||||
|
version "4.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/hex-rgb/-/hex-rgb-4.3.0.tgz#af5e974e83bb2fefe44d55182b004ec818c07776"
|
||||||
|
integrity sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==
|
||||||
|
|
||||||
history@^5.3.0:
|
history@^5.3.0:
|
||||||
version "5.3.0"
|
version "5.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b"
|
resolved "https://registry.yarnpkg.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b"
|
||||||
@@ -14296,6 +14311,14 @@ minizlib@^2.1.1:
|
|||||||
minipass "^3.0.0"
|
minipass "^3.0.0"
|
||||||
yallist "^4.0.0"
|
yallist "^4.0.0"
|
||||||
|
|
||||||
|
mix-css-color@^0.2.0:
|
||||||
|
version "0.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/mix-css-color/-/mix-css-color-0.2.0.tgz#413a2346effcb36a815b1d09bcbac12bcf3aac63"
|
||||||
|
integrity sha512-mZugANySFPE21tjELbQddhC6HAZNzqp7gDxmW8fJFURSWtJ0nuXU26dyrb/1AR6ZYxdEAtW2bbWT9QnRtI6Jzg==
|
||||||
|
dependencies:
|
||||||
|
parse-css-color "^0.1.2"
|
||||||
|
pure-color "^1.3.0"
|
||||||
|
|
||||||
mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3:
|
mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3:
|
||||||
version "0.5.3"
|
version "0.5.3"
|
||||||
resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
|
resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
|
||||||
@@ -14931,6 +14954,14 @@ parent-module@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
callsites "^3.0.0"
|
callsites "^3.0.0"
|
||||||
|
|
||||||
|
parse-css-color@^0.1.2:
|
||||||
|
version "0.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/parse-css-color/-/parse-css-color-0.1.2.tgz#9d178f2d2b5eb7245c0deb22ea35046b79ff3f83"
|
||||||
|
integrity sha512-z7v/tf0edGsnlm9VONQtH+u/YVrdUqZXrSBzqM13scef8Abl2VyZfYsZaJoyb/AyY4SIxtoJChSQ4MURHfY3Sg==
|
||||||
|
dependencies:
|
||||||
|
color-name "^1.1.4"
|
||||||
|
hex-rgb "^4.1.0"
|
||||||
|
|
||||||
parse-json@^4.0.0:
|
parse-json@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
|
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
|
||||||
@@ -15934,6 +15965,11 @@ punycode@^2.1.0, punycode@^2.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
|
||||||
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
|
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
|
||||||
|
|
||||||
|
pure-color@^1.3.0:
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e"
|
||||||
|
integrity sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==
|
||||||
|
|
||||||
pure-rand@^6.0.0:
|
pure-rand@^6.0.0:
|
||||||
version "6.0.2"
|
version "6.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.2.tgz#a9c2ddcae9b68d736a8163036f088a2781c8b306"
|
resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.2.tgz#a9c2ddcae9b68d736a8163036f088a2781c8b306"
|
||||||
@@ -16655,6 +16691,13 @@ relateurl@^0.2.7:
|
|||||||
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
|
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
|
||||||
integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==
|
integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==
|
||||||
|
|
||||||
|
relative-luminance@^2.0.0:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/relative-luminance/-/relative-luminance-2.0.1.tgz#2babddf3a5a59673227d6f02e0f68e13989e3d13"
|
||||||
|
integrity sha512-wFuITNthJilFPwkK7gNJcULxXBcfFZvZORsvdvxeOdO44wCeZnuQkf3nFFzOR/dpJNxYsdRZJLsepWbyKhnMww==
|
||||||
|
dependencies:
|
||||||
|
esm "^3.0.84"
|
||||||
|
|
||||||
remove-trailing-slash@^0.1.0:
|
remove-trailing-slash@^0.1.0:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz#be2285a59f39c74d1bce4f825950061915e3780d"
|
resolved "https://registry.yarnpkg.com/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz#be2285a59f39c74d1bce4f825950061915e3780d"
|
||||||
@@ -18763,6 +18806,13 @@ wbuf@^1.1.0, wbuf@^1.7.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
minimalistic-assert "^1.0.0"
|
minimalistic-assert "^1.0.0"
|
||||||
|
|
||||||
|
wcag-contrast@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/wcag-contrast/-/wcag-contrast-3.0.0.tgz#51c2df43f15162993006454b3362844205889efb"
|
||||||
|
integrity sha512-RWbpg/S7FOXDCwqC2oFhN/vh8dHzj0OS6dpyOSDHyQFSmqmR+lAUStV/ziTT1GzDqL9wol+nZQB4vCi5yEak+w==
|
||||||
|
dependencies:
|
||||||
|
relative-luminance "^2.0.0"
|
||||||
|
|
||||||
wcwidth@^1.0.1:
|
wcwidth@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
|
resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
|
||||||
|
|||||||
Reference in New Issue
Block a user