@contember/utilities 0.0.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/dist/development/assert-types/AssertionError.js +9 -0
- package/dist/development/assert-types/AssertionError.js.map +1 -0
- package/dist/development/assert-types/Predicates.js +108 -0
- package/dist/development/assert-types/Predicates.js.map +1 -0
- package/dist/development/assert-types/assert.js +10 -0
- package/dist/development/assert-types/assert.js.map +1 -0
- package/dist/development/assert-types/assertNever.js +7 -0
- package/dist/development/assert-types/assertNever.js.map +1 -0
- package/dist/development/class-name/colorSchemeClassName.js +16 -0
- package/dist/development/class-name/colorSchemeClassName.js.map +1 -0
- package/dist/development/class-name/constants.js +7 -0
- package/dist/development/class-name/constants.js.map +1 -0
- package/dist/development/class-name/deduplicateClassName.js +7 -0
- package/dist/development/class-name/deduplicateClassName.js.map +1 -0
- package/dist/development/class-name/filterThemedClassName.js +68 -0
- package/dist/development/class-name/filterThemedClassName.js.map +1 -0
- package/dist/development/class-name/flatClassNameList.js +16 -0
- package/dist/development/class-name/flatClassNameList.js.map +1 -0
- package/dist/development/class-name/listClassName.js +9 -0
- package/dist/development/class-name/listClassName.js.map +1 -0
- package/dist/development/class-name/stateClassName.js +11 -0
- package/dist/development/class-name/stateClassName.js.map +1 -0
- package/dist/development/class-name/themeClassName.js +18 -0
- package/dist/development/class-name/themeClassName.js.map +1 -0
- package/dist/development/css-utilities/px.js +7 -0
- package/dist/development/css-utilities/px.js.map +1 -0
- package/dist/development/deprecate/deprecate.js +6 -0
- package/dist/development/deprecate/deprecate.js.map +1 -0
- package/dist/development/deprecate/fallback.js +11 -0
- package/dist/development/deprecate/fallback.js.map +1 -0
- package/dist/development/dom/dataAttribute.js +13 -0
- package/dist/development/dom/dataAttribute.js.map +1 -0
- package/dist/development/dom/getElementDimensions.js +22 -0
- package/dist/development/dom/getElementDimensions.js.map +1 -0
- package/dist/development/dom/getMatchingParentElement.js +17 -0
- package/dist/development/dom/getMatchingParentElement.js.map +1 -0
- package/dist/development/dom/getSizeFromResizeObserverEntry.js +24 -0
- package/dist/development/dom/getSizeFromResizeObserverEntry.js.map +1 -0
- package/dist/development/dom/isScrollable.js +22 -0
- package/dist/development/dom/isScrollable.js.map +1 -0
- package/dist/development/dom/parseTransformMatrix.js +29 -0
- package/dist/development/dom/parseTransformMatrix.js.map +1 -0
- package/dist/development/dom/stateDataAttributes.js +11 -0
- package/dist/development/dom/stateDataAttributes.js.map +1 -0
- package/dist/development/dom/svgSizeProps.js +15 -0
- package/dist/development/dom/svgSizeProps.js.map +1 -0
- package/dist/development/functional/extend.js +33 -0
- package/dist/development/functional/extend.js.map +1 -0
- package/dist/development/functional/omit.js +15 -0
- package/dist/development/functional/omit.js.map +1 -0
- package/dist/development/functional/pick.js +15 -0
- package/dist/development/functional/pick.js.map +1 -0
- package/dist/development/functional/range.js +7 -0
- package/dist/development/functional/range.js.map +1 -0
- package/dist/development/functional/setHasOneOf.js +7 -0
- package/dist/development/functional/setHasOneOf.js.map +1 -0
- package/dist/development/index.js +94 -0
- package/dist/development/index.js.map +1 -0
- package/dist/development/string-utilities/capitalize.js +7 -0
- package/dist/development/string-utilities/capitalize.js.map +1 -0
- package/dist/development/string-utilities/kebabCase.js +8 -0
- package/dist/development/string-utilities/kebabCase.js.map +1 -0
- package/dist/development/string-utilities/trimString.js +8 -0
- package/dist/development/string-utilities/trimString.js.map +1 -0
- package/dist/production/assert-types/AssertionError.js +9 -0
- package/dist/production/assert-types/AssertionError.js.map +1 -0
- package/dist/production/assert-types/Predicates.js +108 -0
- package/dist/production/assert-types/Predicates.js.map +1 -0
- package/dist/production/assert-types/assert.js +10 -0
- package/dist/production/assert-types/assert.js.map +1 -0
- package/dist/production/assert-types/assertNever.js +7 -0
- package/dist/production/assert-types/assertNever.js.map +1 -0
- package/dist/production/class-name/colorSchemeClassName.js +16 -0
- package/dist/production/class-name/colorSchemeClassName.js.map +1 -0
- package/dist/production/class-name/constants.js +7 -0
- package/dist/production/class-name/constants.js.map +1 -0
- package/dist/production/class-name/deduplicateClassName.js +7 -0
- package/dist/production/class-name/deduplicateClassName.js.map +1 -0
- package/dist/production/class-name/filterThemedClassName.js +68 -0
- package/dist/production/class-name/filterThemedClassName.js.map +1 -0
- package/dist/production/class-name/flatClassNameList.js +16 -0
- package/dist/production/class-name/flatClassNameList.js.map +1 -0
- package/dist/production/class-name/listClassName.js +9 -0
- package/dist/production/class-name/listClassName.js.map +1 -0
- package/dist/production/class-name/stateClassName.js +11 -0
- package/dist/production/class-name/stateClassName.js.map +1 -0
- package/dist/production/class-name/themeClassName.js +18 -0
- package/dist/production/class-name/themeClassName.js.map +1 -0
- package/dist/production/css-utilities/px.js +7 -0
- package/dist/production/css-utilities/px.js.map +1 -0
- package/dist/production/deprecate/deprecate.js +6 -0
- package/dist/production/deprecate/deprecate.js.map +1 -0
- package/dist/production/deprecate/fallback.js +11 -0
- package/dist/production/deprecate/fallback.js.map +1 -0
- package/dist/production/dom/dataAttribute.js +13 -0
- package/dist/production/dom/dataAttribute.js.map +1 -0
- package/dist/production/dom/getElementDimensions.js +22 -0
- package/dist/production/dom/getElementDimensions.js.map +1 -0
- package/dist/production/dom/getMatchingParentElement.js +17 -0
- package/dist/production/dom/getMatchingParentElement.js.map +1 -0
- package/dist/production/dom/getSizeFromResizeObserverEntry.js +24 -0
- package/dist/production/dom/getSizeFromResizeObserverEntry.js.map +1 -0
- package/dist/production/dom/isScrollable.js +22 -0
- package/dist/production/dom/isScrollable.js.map +1 -0
- package/dist/production/dom/parseTransformMatrix.js +29 -0
- package/dist/production/dom/parseTransformMatrix.js.map +1 -0
- package/dist/production/dom/stateDataAttributes.js +11 -0
- package/dist/production/dom/stateDataAttributes.js.map +1 -0
- package/dist/production/dom/svgSizeProps.js +15 -0
- package/dist/production/dom/svgSizeProps.js.map +1 -0
- package/dist/production/functional/extend.js +33 -0
- package/dist/production/functional/extend.js.map +1 -0
- package/dist/production/functional/omit.js +15 -0
- package/dist/production/functional/omit.js.map +1 -0
- package/dist/production/functional/pick.js +15 -0
- package/dist/production/functional/pick.js.map +1 -0
- package/dist/production/functional/range.js +7 -0
- package/dist/production/functional/range.js.map +1 -0
- package/dist/production/functional/setHasOneOf.js +7 -0
- package/dist/production/functional/setHasOneOf.js.map +1 -0
- package/dist/production/index.js +94 -0
- package/dist/production/index.js.map +1 -0
- package/dist/production/string-utilities/capitalize.js +7 -0
- package/dist/production/string-utilities/capitalize.js.map +1 -0
- package/dist/production/string-utilities/kebabCase.js +8 -0
- package/dist/production/string-utilities/kebabCase.js.map +1 -0
- package/dist/production/string-utilities/trimString.js +8 -0
- package/dist/production/string-utilities/trimString.js.map +1 -0
- package/dist/types/assert-types/AssertionError.d.ts +4 -0
- package/dist/types/assert-types/AssertionError.d.ts.map +1 -0
- package/dist/types/assert-types/Predicates.d.ts +27 -0
- package/dist/types/assert-types/Predicates.d.ts.map +1 -0
- package/dist/types/assert-types/assert.d.ts +3 -0
- package/dist/types/assert-types/assert.d.ts.map +1 -0
- package/dist/types/assert-types/assertNever.d.ts +2 -0
- package/dist/types/assert-types/assertNever.d.ts.map +1 -0
- package/dist/types/assert-types/index.d.ts +6 -0
- package/dist/types/assert-types/index.d.ts.map +1 -0
- package/dist/types/assert-types/types.d.ts +5 -0
- package/dist/types/assert-types/types.d.ts.map +1 -0
- package/dist/types/class-name/colorSchemeClassName.d.ts +35 -0
- package/dist/types/class-name/colorSchemeClassName.d.ts.map +1 -0
- package/dist/types/class-name/constants.d.ts +42 -0
- package/dist/types/class-name/constants.d.ts.map +1 -0
- package/dist/types/class-name/deduplicateClassName.d.ts +2 -0
- package/dist/types/class-name/deduplicateClassName.d.ts.map +1 -0
- package/dist/types/class-name/filterThemedClassName.d.ts +7 -0
- package/dist/types/class-name/filterThemedClassName.d.ts.map +1 -0
- package/dist/types/class-name/flatClassNameList.d.ts +3 -0
- package/dist/types/class-name/flatClassNameList.d.ts.map +1 -0
- package/dist/types/class-name/index.d.ts +10 -0
- package/dist/types/class-name/index.d.ts.map +1 -0
- package/dist/types/class-name/listClassName.d.ts +9 -0
- package/dist/types/class-name/listClassName.d.ts.map +1 -0
- package/dist/types/class-name/stateClassName.d.ts +19 -0
- package/dist/types/class-name/stateClassName.d.ts.map +1 -0
- package/dist/types/class-name/themeClassName.d.ts +87 -0
- package/dist/types/class-name/themeClassName.d.ts.map +1 -0
- package/dist/types/class-name/types.d.ts +13 -0
- package/dist/types/class-name/types.d.ts.map +1 -0
- package/dist/types/css-utilities/index.d.ts +2 -0
- package/dist/types/css-utilities/index.d.ts.map +1 -0
- package/dist/types/css-utilities/px.d.ts +6 -0
- package/dist/types/css-utilities/px.d.ts.map +1 -0
- package/dist/types/deprecate/deprecate.d.ts +19 -0
- package/dist/types/deprecate/deprecate.d.ts.map +1 -0
- package/dist/types/deprecate/fallback.d.ts +2 -0
- package/dist/types/deprecate/fallback.d.ts.map +1 -0
- package/dist/types/deprecate/index.d.ts +4 -0
- package/dist/types/deprecate/index.d.ts.map +1 -0
- package/dist/types/deprecate/types.d.ts +2 -0
- package/dist/types/deprecate/types.d.ts.map +1 -0
- package/dist/types/dom/dataAttribute.d.ts +2 -0
- package/dist/types/dom/dataAttribute.d.ts.map +1 -0
- package/dist/types/dom/getElementDimensions.d.ts +14 -0
- package/dist/types/dom/getElementDimensions.d.ts.map +1 -0
- package/dist/types/dom/getMatchingParentElement.d.ts +2 -0
- package/dist/types/dom/getMatchingParentElement.d.ts.map +1 -0
- package/dist/types/dom/getSizeFromResizeObserverEntry.d.ts +5 -0
- package/dist/types/dom/getSizeFromResizeObserverEntry.d.ts.map +1 -0
- package/dist/types/dom/index.d.ts +9 -0
- package/dist/types/dom/index.d.ts.map +1 -0
- package/dist/types/dom/isScrollable.d.ts +7 -0
- package/dist/types/dom/isScrollable.d.ts.map +1 -0
- package/dist/types/dom/parseTransformMatrix.d.ts +15 -0
- package/dist/types/dom/parseTransformMatrix.d.ts.map +1 -0
- package/dist/types/dom/stateDataAttributes.d.ts +4 -0
- package/dist/types/dom/stateDataAttributes.d.ts.map +1 -0
- package/dist/types/dom/svgSizeProps.d.ts +7 -0
- package/dist/types/dom/svgSizeProps.d.ts.map +1 -0
- package/dist/types/functional/extend.d.ts +5 -0
- package/dist/types/functional/extend.d.ts.map +1 -0
- package/dist/types/functional/index.d.ts +6 -0
- package/dist/types/functional/index.d.ts.map +1 -0
- package/dist/types/functional/omit.d.ts +2 -0
- package/dist/types/functional/omit.d.ts.map +1 -0
- package/dist/types/functional/pick.d.ts +2 -0
- package/dist/types/functional/pick.d.ts.map +1 -0
- package/dist/types/functional/range.d.ts +9 -0
- package/dist/types/functional/range.d.ts.map +1 -0
- package/dist/types/functional/setHasOneOf.d.ts +2 -0
- package/dist/types/functional/setHasOneOf.d.ts.map +1 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/string-utilities/capitalize.d.ts +2 -0
- package/dist/types/string-utilities/capitalize.d.ts.map +1 -0
- package/dist/types/string-utilities/index.d.ts +4 -0
- package/dist/types/string-utilities/index.d.ts.map +1 -0
- package/dist/types/string-utilities/kebabCase.d.ts +2 -0
- package/dist/types/string-utilities/kebabCase.d.ts.map +1 -0
- package/dist/types/string-utilities/trimString.d.ts +9 -0
- package/dist/types/string-utilities/trimString.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/dist/types/types/Any.d.ts +4 -0
- package/dist/types/types/Any.d.ts.map +1 -0
- package/dist/types/types/DeepPartial.d.ts +4 -0
- package/dist/types/types/DeepPartial.d.ts.map +1 -0
- package/dist/types/types/Narrow.d.ts +11 -0
- package/dist/types/types/Narrow.d.ts.map +1 -0
- package/dist/types/types/NonNullableRequired.d.ts +4 -0
- package/dist/types/types/NonNullableRequired.d.ts.map +1 -0
- package/dist/types/types/NonOptional.d.ts +8 -0
- package/dist/types/types/NonOptional.d.ts.map +1 -0
- package/dist/types/types/ObjectKeyValue.d.ts +4 -0
- package/dist/types/types/ObjectKeyValue.d.ts.map +1 -0
- package/dist/types/types/PolymorphicRefs.d.ts +46 -0
- package/dist/types/types/PolymorphicRefs.d.ts.map +1 -0
- package/dist/types/types/Primitive.d.ts +2 -0
- package/dist/types/types/Primitive.d.ts.map +1 -0
- package/dist/types/types/RequiredDeepPlainObject.d.ts +4 -0
- package/dist/types/types/RequiredDeepPlainObject.d.ts.map +1 -0
- package/dist/types/types/Try.d.ts +2 -0
- package/dist/types/types/Try.d.ts.map +1 -0
- package/dist/types/types/TypeofStringLiteral.d.ts +2 -0
- package/dist/types/types/TypeofStringLiteral.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +13 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/package.json +42 -0
- package/src/assert-types/AssertionError.ts +5 -0
- package/src/assert-types/Predicates.ts +88 -0
- package/src/assert-types/assert.ts +15 -0
- package/src/assert-types/assertNever.ts +3 -0
- package/src/assert-types/index.ts +5 -0
- package/src/assert-types/types.ts +5 -0
- package/src/class-name/colorSchemeClassName.ts +46 -0
- package/src/class-name/constants.ts +43 -0
- package/src/class-name/deduplicateClassName.ts +3 -0
- package/src/class-name/filterThemedClassName.ts +86 -0
- package/src/class-name/flatClassNameList.ts +18 -0
- package/src/class-name/index.ts +9 -0
- package/src/class-name/listClassName.ts +13 -0
- package/src/class-name/stateClassName.ts +32 -0
- package/src/class-name/themeClassName.ts +116 -0
- package/src/class-name/types.ts +17 -0
- package/src/css-utilities/index.ts +1 -0
- package/src/css-utilities/px.ts +16 -0
- package/src/deprecate/deprecate.ts +31 -0
- package/src/deprecate/fallback.ts +7 -0
- package/src/deprecate/index.ts +3 -0
- package/src/deprecate/types.ts +2 -0
- package/src/dom/dataAttribute.ts +11 -0
- package/src/dom/getElementDimensions.ts +36 -0
- package/src/dom/getMatchingParentElement.ts +13 -0
- package/src/dom/getSizeFromResizeObserverEntry.ts +26 -0
- package/src/dom/index.ts +8 -0
- package/src/dom/isScrollable.ts +24 -0
- package/src/dom/parseTransformMatrix.ts +35 -0
- package/src/dom/stateDataAttributes.ts +8 -0
- package/src/dom/svgSizeProps.ts +21 -0
- package/src/functional/extend.ts +37 -0
- package/src/functional/index.ts +5 -0
- package/src/functional/omit.ts +13 -0
- package/src/functional/pick.ts +13 -0
- package/src/functional/range.ts +11 -0
- package/src/functional/setHasOneOf.ts +3 -0
- package/src/index.ts +8 -0
- package/src/string-utilities/capitalize.ts +3 -0
- package/src/string-utilities/index.ts +3 -0
- package/src/string-utilities/kebabCase.ts +5 -0
- package/src/string-utilities/trimString.ts +12 -0
- package/src/tsconfig.json +6 -0
- package/src/types/Any.ts +3 -0
- package/src/types/DeepPartial.ts +7 -0
- package/src/types/Narrow.ts +21 -0
- package/src/types/NonNullableRequired.ts +1 -0
- package/src/types/NonOptional.ts +7 -0
- package/src/types/ObjectKeyValue.ts +1 -0
- package/src/types/PolymorphicRefs.ts +68 -0
- package/src/types/Primitive.ts +1 -0
- package/src/types/RequiredDeepPlainObject.ts +3 -0
- package/src/types/Try.ts +4 -0
- package/src/types/TypeofStringLiteral.ts +1 -0
- package/src/types/index.ts +24 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { KebabCase } from 'type-fest'
|
|
2
|
+
import { isColorSchemeClassName } from './colorSchemeClassName'
|
|
3
|
+
import { THEME_CLASS_NAME_REG_EXP } from './constants'
|
|
4
|
+
import { flatClassNameList } from './flatClassNameList'
|
|
5
|
+
import { contentThemeClassName, controlsThemeClassName } from './themeClassName'
|
|
6
|
+
import { ColorSchemeClassName, NestedClassName } from './types'
|
|
7
|
+
|
|
8
|
+
export type ThemeConfig = { content: string | undefined, controls: string | undefined }
|
|
9
|
+
|
|
10
|
+
export function filterThemedClassName(
|
|
11
|
+
nestedClassName: NestedClassName,
|
|
12
|
+
defaultColorSchemeContext: ColorSchemeClassName,
|
|
13
|
+
) {
|
|
14
|
+
const theme: ThemeConfig = { content: undefined, controls: undefined }
|
|
15
|
+
const stateThemes: Record<string, ThemeConfig> = {}
|
|
16
|
+
let colorScheme: ColorSchemeClassName | undefined = undefined
|
|
17
|
+
|
|
18
|
+
const flatClassName = flatClassNameList(nestedClassName).map(className => {
|
|
19
|
+
if (isColorSchemeClassName(className)) {
|
|
20
|
+
colorScheme = className
|
|
21
|
+
return undefined
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const match = className.match(THEME_CLASS_NAME_REG_EXP)
|
|
25
|
+
|
|
26
|
+
if (match) {
|
|
27
|
+
const name = match.groups!.name as KebabCase<string>
|
|
28
|
+
const scope = match.groups!.scope as KebabCase<string>
|
|
29
|
+
const state = match.groups!.state as `:${KebabCase<string>}`
|
|
30
|
+
|
|
31
|
+
if (state) {
|
|
32
|
+
stateThemes[state] = stateThemes[state] ?? { content: undefined, controls: undefined }
|
|
33
|
+
|
|
34
|
+
if (!scope) {
|
|
35
|
+
stateThemes[state].content = name
|
|
36
|
+
stateThemes[state].controls = name
|
|
37
|
+
} else if (scope === 'content') {
|
|
38
|
+
stateThemes[state].content = name
|
|
39
|
+
} else if (scope === 'controls') {
|
|
40
|
+
stateThemes[state].controls = name
|
|
41
|
+
} else {
|
|
42
|
+
throw new Error(`Unknown theme scope: ${scope}`)
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
if (!scope) {
|
|
46
|
+
theme.content = name
|
|
47
|
+
theme.controls = name
|
|
48
|
+
} else if (scope === 'content') {
|
|
49
|
+
theme.content = name
|
|
50
|
+
} else if (scope === 'controls') {
|
|
51
|
+
theme.controls = name
|
|
52
|
+
} else {
|
|
53
|
+
throw new Error(`Unknown theme scope: ${scope}`)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return undefined
|
|
58
|
+
} else {
|
|
59
|
+
return className
|
|
60
|
+
}
|
|
61
|
+
}).filter(Boolean) as string[]
|
|
62
|
+
|
|
63
|
+
const themeClassNames: (string | undefined)[] = []
|
|
64
|
+
|
|
65
|
+
const content = contentThemeClassName(theme.content)
|
|
66
|
+
const controls = controlsThemeClassName(theme.controls)
|
|
67
|
+
|
|
68
|
+
themeClassNames.push(content, controls)
|
|
69
|
+
|
|
70
|
+
for (const state in stateThemes) {
|
|
71
|
+
const { content, controls } = stateThemes[state]
|
|
72
|
+
|
|
73
|
+
const contentClassName = contentThemeClassName(content, state as `:${KebabCase<string>}`)
|
|
74
|
+
const controlsClassName = controlsThemeClassName(controls, state as `:${KebabCase<string>}`)
|
|
75
|
+
|
|
76
|
+
themeClassNames.push(contentClassName, controlsClassName)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const flatThemedClassName = flatClassNameList(themeClassNames)
|
|
80
|
+
|
|
81
|
+
if (flatThemedClassName.length > 0 || colorScheme) {
|
|
82
|
+
return [colorScheme ?? defaultColorSchemeContext, ...flatThemedClassName, ...flatClassName]
|
|
83
|
+
} else {
|
|
84
|
+
return flatClassName
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { assertNever } from '../assert-types'
|
|
2
|
+
import { NestedClassName } from './types'
|
|
3
|
+
|
|
4
|
+
export function flatClassNameList(className: NestedClassName): string[] {
|
|
5
|
+
if (!className) {
|
|
6
|
+
return []
|
|
7
|
+
} else if (typeof className === 'string') {
|
|
8
|
+
return className.split(' ').filter(Boolean)
|
|
9
|
+
} else if (Array.isArray(className)) {
|
|
10
|
+
return className.flatMap(flatClassNameList)
|
|
11
|
+
} else {
|
|
12
|
+
if (import.meta.env.DEV) {
|
|
13
|
+
console.error(`Unexpected className: ${JSON.stringify(className)}`)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
assertNever(className)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './colorSchemeClassName'
|
|
2
|
+
export * from './constants'
|
|
3
|
+
export * from './deduplicateClassName'
|
|
4
|
+
export * from './filterThemedClassName'
|
|
5
|
+
export * from './flatClassNameList'
|
|
6
|
+
export * from './listClassName'
|
|
7
|
+
export * from './stateClassName'
|
|
8
|
+
export * from './themeClassName'
|
|
9
|
+
export * from './types'
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { deduplicateClassName } from './deduplicateClassName'
|
|
2
|
+
import { flatClassNameList } from './flatClassNameList'
|
|
3
|
+
import { NestedClassName } from './types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Combines a list of class names into a single string, even nested
|
|
7
|
+
*
|
|
8
|
+
* @param list - List of class names
|
|
9
|
+
* @returns Combined class names as string
|
|
10
|
+
*/
|
|
11
|
+
export function listClassName(list: NestedClassName) {
|
|
12
|
+
return deduplicateClassName(flatClassNameList(list)).join(' ')
|
|
13
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { toKebabCase } from '../string-utilities'
|
|
2
|
+
import { ClassNameStateMap } from './types'
|
|
3
|
+
|
|
4
|
+
export interface StateClassNameOptions {
|
|
5
|
+
glue?: string;
|
|
6
|
+
removeFalsy?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Combines a state map of class names into a single string
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* stateClassName({ foo: true, bar: false, baz: 1 }) // => 'foo baz-1'
|
|
14
|
+
*
|
|
15
|
+
* @param state - State map object with class names as keys and literals as values.
|
|
16
|
+
* @param options - Options object
|
|
17
|
+
* @param options.glue - Glue to use between the class name and the value, default is '-'. Set to '' to disable.
|
|
18
|
+
* @param options.removeFalsy - Whether to remove falsy class names, default is true.
|
|
19
|
+
* @returns Combined class names as string
|
|
20
|
+
*/
|
|
21
|
+
export function stateClassName(
|
|
22
|
+
state: ClassNameStateMap | null = null,
|
|
23
|
+
{ glue = '-', removeFalsy = true }: StateClassNameOptions = {},
|
|
24
|
+
): string[] {
|
|
25
|
+
const entries = Object.entries(state ?? []).map(
|
|
26
|
+
([className, value]) => value || value === 0 || !removeFalsy
|
|
27
|
+
? (value === true ? toKebabCase(className) : `${toKebabCase(className)}${glue}${value}`)
|
|
28
|
+
: '',
|
|
29
|
+
).filter(Boolean)
|
|
30
|
+
|
|
31
|
+
return entries
|
|
32
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { KebabCase } from 'type-fest'
|
|
2
|
+
import { ThemeContentClassName, ThemeControlsClassName } from './types'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns a string with a content theme class name, prefixed with `theme-` and suffixed with `-content`
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: Make sure to use color scheme class in combination with theme class names.
|
|
8
|
+
*
|
|
9
|
+
* @param contentTheme - Theme name basis for content
|
|
10
|
+
* @param state - State of the theme starting with a ":", e.g. `":hover"`, `":focus"`, `":active"`, `":focus-visible"`
|
|
11
|
+
* @returns A content theme class name
|
|
12
|
+
*
|
|
13
|
+
* @see {@link controlsThemeClassName}
|
|
14
|
+
* @see {@link (colorSchemeClassName:3)}
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* const colorScheme = colorSchemeClassName('system')
|
|
19
|
+
* // ^ 'scheme-system'
|
|
20
|
+
* const contentThemeClassName = contentThemeClassName('default')
|
|
21
|
+
* // ^ 'theme-default-content:hover'
|
|
22
|
+
* const dangerOnMouseOverTheme = controlsThemeClassName('danger', ':hover')
|
|
23
|
+
* // ^ 'theme-danger-controls:hover'
|
|
24
|
+
*
|
|
25
|
+
* return (
|
|
26
|
+
* <div className={`${colorScheme} ${contentThemeClassName}`}>
|
|
27
|
+
* <button className={`${colorScheme} ${dangerOnMouseOverTheme}`}>Delete</button>
|
|
28
|
+
* </div>
|
|
29
|
+
* )
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function contentThemeClassName<
|
|
33
|
+
ContentTheme extends KebabCase<string> = KebabCase<string>,
|
|
34
|
+
State extends `:${KebabCase<string>}` | null | undefined = undefined,
|
|
35
|
+
>(
|
|
36
|
+
theme: ContentTheme | null | undefined,
|
|
37
|
+
state?: State | null | undefined,
|
|
38
|
+
) {
|
|
39
|
+
return theme ? `theme-${theme}-content${state ?? ''}` as ThemeContentClassName<ContentTheme, State> : undefined
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Returns a string with a controls theme class name, prefixed with `theme-` and suffixed with `-controls`
|
|
44
|
+
*
|
|
45
|
+
* IMPORTANT: Make sure to use color scheme class in combination with theme class names.
|
|
46
|
+
*
|
|
47
|
+
* @param theme - Theme name basis for controls
|
|
48
|
+
* @param state - State of the theme starting with a ":", e.g. `":hover"`, `":focus"`, `":active"`, `":focus-visible"`
|
|
49
|
+
* @returns A controls theme class name
|
|
50
|
+
*
|
|
51
|
+
* @see {@link contentThemeClassName}
|
|
52
|
+
* @see {@link (colorSchemeClassName:3)}
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* const colorScheme = colorSchemeClassName('system')
|
|
57
|
+
* // ^ 'scheme-system'
|
|
58
|
+
* const contentThemeClassName = contentThemeClassName('default')
|
|
59
|
+
* // ^ 'theme-default-content:hover'
|
|
60
|
+
* const dangerOnMouseOverTheme = controlsThemeClassName('danger', ':hover')
|
|
61
|
+
* // ^ 'theme-danger-controls:hover'
|
|
62
|
+
*
|
|
63
|
+
* return (
|
|
64
|
+
* <div className={`${colorScheme} ${contentThemeClassName}`}>
|
|
65
|
+
* <button className={`${colorScheme} ${dangerOnMouseOverTheme}`}>Delete</button>
|
|
66
|
+
* </div>
|
|
67
|
+
* )
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export function controlsThemeClassName<
|
|
71
|
+
ControlsTheme extends KebabCase<string> = KebabCase<string>,
|
|
72
|
+
State extends `:${KebabCase<string>}` | null | undefined = undefined,
|
|
73
|
+
>(
|
|
74
|
+
theme: ControlsTheme | null | undefined,
|
|
75
|
+
state?: State | null | undefined,
|
|
76
|
+
) {
|
|
77
|
+
return theme ? `theme-${theme}-controls${state ?? ''}` as ThemeControlsClassName<ControlsTheme, State> : undefined
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Returns a tuple with a content theme class name and a controls theme class name, prefixed with `theme-` and suffixed with `-content` and `-controls` respectively
|
|
82
|
+
*
|
|
83
|
+
* IMPORTANT: Make sure to use color scheme class in combination with theme class names.
|
|
84
|
+
*
|
|
85
|
+
* @param theme - Theme name basis for content and controls
|
|
86
|
+
* @param state - State of the theme starting with a ":", e.g. `":hover"`, `":focus"`, `":active"`, `":focus-visible"`
|
|
87
|
+
* @returns A tuple with a content theme class name and a controls theme class name
|
|
88
|
+
*
|
|
89
|
+
* @see {@link contentThemeClassName}
|
|
90
|
+
* @see {@link controlsThemeClassName}
|
|
91
|
+
* @see {@link (colorSchemeClassName:3)}
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```tsx
|
|
95
|
+
* const colorScheme = colorSchemeClassName('system')
|
|
96
|
+
* // ^ 'scheme-system'
|
|
97
|
+
* const errorTheme = themeClassName('danger').join(' ')
|
|
98
|
+
* // ^ 'theme-danger-content theme-danger-controls'
|
|
99
|
+
*
|
|
100
|
+
* return (
|
|
101
|
+
* <div className={`${colorScheme} ${errorTheme}`}>File not found</div>
|
|
102
|
+
* )
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export function themeClassName<
|
|
106
|
+
Theme extends KebabCase<string> = KebabCase<string>,
|
|
107
|
+
State extends `:${KebabCase<string>}` | null | undefined = undefined,
|
|
108
|
+
>(
|
|
109
|
+
theme: Theme | null | undefined,
|
|
110
|
+
state?: State | null | undefined,
|
|
111
|
+
) {
|
|
112
|
+
return [
|
|
113
|
+
contentThemeClassName(theme, state),
|
|
114
|
+
controlsThemeClassName(theme, state),
|
|
115
|
+
] as const
|
|
116
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { KebabCase } from 'type-fest'
|
|
2
|
+
|
|
3
|
+
export type NestedClassName = string | false | null | undefined | (string | false | null | undefined)[] | NestedClassName[]
|
|
4
|
+
export type ClassNameStateMap = { [key: string]: string | number | boolean | null | undefined }
|
|
5
|
+
|
|
6
|
+
export interface ComponentClassNameProps {
|
|
7
|
+
className?: NestedClassName;
|
|
8
|
+
componentClassName?: string | string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type ColorSchemeClassName<T extends KebabCase<string> = KebabCase<string>> = `scheme-${T}`
|
|
12
|
+
export type ThemeContentClassName<T extends KebabCase<string> = KebabCase<string>, S extends `:${KebabCase<string>}` | null | undefined = undefined> = S extends string
|
|
13
|
+
? `theme-${T}-content${S}`
|
|
14
|
+
: `theme-${T}-content`
|
|
15
|
+
export type ThemeControlsClassName<T extends KebabCase<string> = KebabCase<string>, S extends `:${KebabCase<string>}` | null | undefined = undefined> = S extends string
|
|
16
|
+
? `theme-${T}-controls${S}`
|
|
17
|
+
: `theme-${T}-controls`
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './px'
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function px<V extends number>(value: V): `${V}px`;
|
|
2
|
+
export function px<V extends false>(value: V): '';
|
|
3
|
+
export function px<V extends null>(value: V): '';
|
|
4
|
+
export function px<V extends undefined>(value: V): '';
|
|
5
|
+
// NOTE: Next overload fixes:
|
|
6
|
+
// The call would have succeeded against this implementation, but implementation signatures of overloads are not externally visible.
|
|
7
|
+
export function px<V extends number | false | null | undefined>(value?: V): string;
|
|
8
|
+
/**
|
|
9
|
+
* Converts a value to a string in the format '10px'
|
|
10
|
+
*
|
|
11
|
+
* @param value - The value to convert to a string.
|
|
12
|
+
* @returns Returns a string in the format '10px' or '' when value is falsy.
|
|
13
|
+
*/
|
|
14
|
+
export function px<V extends number | false | null | undefined>(value?: V): string {
|
|
15
|
+
return typeof value === 'number' && !(isNaN(value) || value === Infinity || value === -Infinity) ? value + 'px' : ''
|
|
16
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SemverString } from './types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Logs a deprecation warning if the assertion is `false`.
|
|
5
|
+
* @internal
|
|
6
|
+
*
|
|
7
|
+
* @param removal - Version when the deprecated feature will be removed
|
|
8
|
+
* @param condition - Condition under which the deprecation warning will be logged
|
|
9
|
+
* @param deprecated - Name of the deprecated feature
|
|
10
|
+
* @param replacement - Name of the feature that replaces the deprecated feature
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const { visible } = props
|
|
15
|
+
* deprecate(visible !== 'default', '1.3.0', '"default"', '"hidden"')
|
|
16
|
+
* // Logs: Use of "default" is deprecated and might be removed in the next release. Use "hidden" instead.
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function deprecate(removal: SemverString, condition: boolean, deprecated: string, replacement: string | null): void {
|
|
20
|
+
if (condition === true) {
|
|
21
|
+
if (import.meta.env.DEV) {
|
|
22
|
+
const shouldThrow = Boolean(import.meta.env.VITE_CONTEMBER_ADMIN_STRICT_DEPRECATIONS)
|
|
23
|
+
|
|
24
|
+
if (shouldThrow) {
|
|
25
|
+
throw new Error(`Support for ${deprecated} was planned to be removed in the ${removal} release.${replacement ? ` Replace it with ${replacement} instead.` : 'Remove it.'}`)
|
|
26
|
+
} else {
|
|
27
|
+
console.warn(`Use of ${deprecated} is deprecated and might be removed in the next release.${replacement ? ` Use ${replacement} instead.` : 'There is no replacement.'}`)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function dataAttribute(value: unknown): string | true | undefined {
|
|
2
|
+
if (value === false || value === undefined || value === null) {
|
|
3
|
+
return undefined
|
|
4
|
+
} else if (value === true) {
|
|
5
|
+
// Closest to HTML: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#boolean-attributes
|
|
6
|
+
// React issue: https://github.com/facebook/react/issues/24812
|
|
7
|
+
return ''
|
|
8
|
+
} else {
|
|
9
|
+
return String(value)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calls the callback with the element's dimensions.
|
|
3
|
+
*
|
|
4
|
+
* @param element - The element to observe for dimensions
|
|
5
|
+
* @param callback - The callback to call with the element's dimensions
|
|
6
|
+
*/
|
|
7
|
+
export function getElementDimensionsCallback(
|
|
8
|
+
element: HTMLElement,
|
|
9
|
+
callback: (dimensions: DOMRectReadOnly) => void,
|
|
10
|
+
) {
|
|
11
|
+
const observer = new IntersectionObserver((entries, observer) => {
|
|
12
|
+
if (entries.length === 1) {
|
|
13
|
+
callback(entries[0].boundingClientRect)
|
|
14
|
+
} else {
|
|
15
|
+
const entry = entries.find(entry => entry.boundingClientRect.width > 0 || entry.boundingClientRect.height > 0) || entries[0]
|
|
16
|
+
callback(entry.boundingClientRect)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
observer.disconnect()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
observer.observe(element)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Returns a promise that resolves with the element's dimensions.
|
|
27
|
+
* @param element - The element to observe for dimensions
|
|
28
|
+
* @returns A promise that resolves with the element's dimensions
|
|
29
|
+
*/
|
|
30
|
+
export function getElementDimensions(
|
|
31
|
+
element: HTMLElement,
|
|
32
|
+
): Promise<DOMRectReadOnly> {
|
|
33
|
+
return new Promise(resolve => {
|
|
34
|
+
getElementDimensionsCallback(element, resolve)
|
|
35
|
+
})
|
|
36
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function getMatchingParentElement(element: HTMLElement | null, predicate: (element: HTMLElement | null) => boolean | Promise<boolean>): HTMLElement {
|
|
2
|
+
if (!element || !element.parentElement) {
|
|
3
|
+
if (document.scrollingElement instanceof HTMLElement) {
|
|
4
|
+
return document.scrollingElement
|
|
5
|
+
} else {
|
|
6
|
+
return document.body
|
|
7
|
+
}
|
|
8
|
+
} else if (predicate(element.parentElement)) {
|
|
9
|
+
return element.parentElement
|
|
10
|
+
} else {
|
|
11
|
+
return getMatchingParentElement(element.parentElement, predicate)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function getSizeFromResizeObserverEntryFactory(box: ResizeObserverOptions['box']) {
|
|
2
|
+
return function getSizeFromResizeObserverEntry(entry: ResizeObserverEntry): { height: number, width: number } {
|
|
3
|
+
const boxSize = box === 'border-box'
|
|
4
|
+
? entry.borderBoxSize
|
|
5
|
+
: box === 'content-box'
|
|
6
|
+
? entry.contentBoxSize
|
|
7
|
+
: entry.devicePixelContentBoxSize
|
|
8
|
+
|
|
9
|
+
if (boxSize) {
|
|
10
|
+
const formatBoxSize: ResizeObserverSize[] = Array.isArray(boxSize) ? boxSize : [boxSize]
|
|
11
|
+
|
|
12
|
+
return formatBoxSize.reduce(
|
|
13
|
+
(previous, { inlineSize, blockSize }) => ({
|
|
14
|
+
width: previous.width + inlineSize,
|
|
15
|
+
height: previous.height + blockSize,
|
|
16
|
+
}),
|
|
17
|
+
{ height: 0, width: 0 },
|
|
18
|
+
)
|
|
19
|
+
} else {
|
|
20
|
+
return {
|
|
21
|
+
width: entry.contentRect.width,
|
|
22
|
+
height: entry.contentRect.height,
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/dom/index.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './dataAttribute'
|
|
2
|
+
export * from './getElementDimensions'
|
|
3
|
+
export * from './getMatchingParentElement'
|
|
4
|
+
export * from './getSizeFromResizeObserverEntry'
|
|
5
|
+
export * from './isScrollable'
|
|
6
|
+
export * from './parseTransformMatrix'
|
|
7
|
+
export * from './stateDataAttributes'
|
|
8
|
+
export * from './svgSizeProps'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if an element is scrollable
|
|
3
|
+
* @param element - Element to check
|
|
4
|
+
* @returns Boolean indicating if the element is scrollable
|
|
5
|
+
*/
|
|
6
|
+
export function isScrollable(element: HTMLElement | null) {
|
|
7
|
+
if (element === document.scrollingElement) {
|
|
8
|
+
return true
|
|
9
|
+
} else if (element instanceof HTMLElement) {
|
|
10
|
+
const contentOverflows = element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth
|
|
11
|
+
|
|
12
|
+
if (contentOverflows) {
|
|
13
|
+
if ((getComputedStyle(element)).overflow === 'hidden') {
|
|
14
|
+
return false
|
|
15
|
+
} else {
|
|
16
|
+
return contentOverflows
|
|
17
|
+
}
|
|
18
|
+
} else {
|
|
19
|
+
return false
|
|
20
|
+
}
|
|
21
|
+
} else {
|
|
22
|
+
return false
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { assert, isNumber } from '../assert-types'
|
|
2
|
+
|
|
3
|
+
const MATRIX_REG_EXP = /^matrix\((.+)\)/
|
|
4
|
+
|
|
5
|
+
function isTransformMatrixTuple(value: unknown): value is [number, number, number, number, number, number] {
|
|
6
|
+
if (Array.isArray(value) && value.length === 6 && value.filter(isNumber).length === 6) {
|
|
7
|
+
return true
|
|
8
|
+
} else {
|
|
9
|
+
return false
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Parses a CSS transform matrix string into an object.
|
|
15
|
+
*
|
|
16
|
+
* @param transform - CSS transform matrix string.
|
|
17
|
+
* @returns Object with the transform matrix values or undefined.
|
|
18
|
+
*/
|
|
19
|
+
export function parseTransformMatrix(transform = '') {
|
|
20
|
+
let matches: RegExpMatchArray | null = null
|
|
21
|
+
|
|
22
|
+
if (matches = transform.match(MATRIX_REG_EXP)) {
|
|
23
|
+
const vector = matches[1].split(',').map(value => parseFloat(value))
|
|
24
|
+
assert('transform matrix is tuple of six numbers', vector, isTransformMatrixTuple)
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
scaleX: vector[0],
|
|
28
|
+
skewY: vector[1],
|
|
29
|
+
skewX: vector[2],
|
|
30
|
+
scaleY: vector[3],
|
|
31
|
+
translateX: vector[4],
|
|
32
|
+
translateY: vector[5],
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { toKebabCase } from '../string-utilities'
|
|
2
|
+
import { dataAttribute } from './dataAttribute'
|
|
3
|
+
|
|
4
|
+
export function stateDataAttributes(state: Record<string, unknown>) {
|
|
5
|
+
return Object.fromEntries(Object.entries(state).map(
|
|
6
|
+
([key, value]) => [`data-${toKebabCase(key).toLowerCase()}`, dataAttribute(value)],
|
|
7
|
+
))
|
|
8
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface SvgSizeProps {
|
|
2
|
+
width: number;
|
|
3
|
+
height: number;
|
|
4
|
+
viewBox: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function svgSizeProps(
|
|
8
|
+
width: number,
|
|
9
|
+
height?: number,
|
|
10
|
+
crop: number = 0,
|
|
11
|
+
): SvgSizeProps {
|
|
12
|
+
const viewBoxWidth = width - crop * 2
|
|
13
|
+
const viewBoxHeight = (height ?? width) - crop * 2
|
|
14
|
+
const viewBoxX = crop
|
|
15
|
+
const viewBoxY = crop
|
|
16
|
+
return {
|
|
17
|
+
width: viewBoxWidth,
|
|
18
|
+
height: viewBoxHeight,
|
|
19
|
+
viewBox: `${viewBoxX} ${viewBoxY} ${viewBoxWidth} ${viewBoxHeight}`,
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** @internal */
|
|
2
|
+
export function extend<B, E>(
|
|
3
|
+
base: B,
|
|
4
|
+
extension: E,
|
|
5
|
+
) {
|
|
6
|
+
base = Object.freeze(base)
|
|
7
|
+
extension = Object.freeze(extension)
|
|
8
|
+
|
|
9
|
+
if (typeof base !== typeof extension) {
|
|
10
|
+
return extension === undefined ? base : extension
|
|
11
|
+
} else {
|
|
12
|
+
if (typeof base === 'object' && typeof extension === 'object') {
|
|
13
|
+
if (Array.isArray(base) && Array.isArray(extension)) {
|
|
14
|
+
return Object.freeze([...base, ...extension])
|
|
15
|
+
} else if (base && extension) {
|
|
16
|
+
if ('$$typeof' in extension) {
|
|
17
|
+
return extension
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const keys = [...new Set([
|
|
21
|
+
...Object.keys(base),
|
|
22
|
+
...Object.keys(extension),
|
|
23
|
+
])]
|
|
24
|
+
|
|
25
|
+
const entries: [string, unknown][] = keys.map(
|
|
26
|
+
key => [key, extend((base as Record<string, unknown>)[key], (extension as Record<string, unknown>)[key])],
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
return Object.freeze(Object.fromEntries(entries))
|
|
30
|
+
} else {
|
|
31
|
+
return extension
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
return extension
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function omit<T extends Object, K extends keyof T>(object: T, properties: ReadonlyArray<K>, strict: boolean = false): Omit<T, K> {
|
|
2
|
+
const next: Partial<T> = { ...object }
|
|
3
|
+
|
|
4
|
+
for (let key of properties) {
|
|
5
|
+
if (key in object) {
|
|
6
|
+
delete next[key]
|
|
7
|
+
} else if (strict) {
|
|
8
|
+
throw new Error(`Key "${String(key)}" does not exist in object ${JSON.stringify(object)}`)
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return next as Omit<T, K>
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function pick<T extends Object, K extends keyof T>(object: T, properties: ReadonlyArray<K>): Pick<T, K> {
|
|
2
|
+
const next: Partial<Pick<T, K>> = {}
|
|
3
|
+
|
|
4
|
+
for (let key of properties) {
|
|
5
|
+
if (key in object) {
|
|
6
|
+
next[key] = object[key]
|
|
7
|
+
} else {
|
|
8
|
+
throw new Error(`Key "${String(key)}" does not exist in object ${JSON.stringify(object)}`)
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return next as Pick<T, K>
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Get a list of numbers between start and end, inclusive, with the given step size (defaulting to 1)
|
|
4
|
+
* @param start - The starting number.
|
|
5
|
+
* @param end - The ending number.
|
|
6
|
+
* @param step - The step size, optional, defaults to 1.
|
|
7
|
+
* @returns A list of numbers between start and end, inclusive, with the given step size (defaulting to 1)
|
|
8
|
+
*/
|
|
9
|
+
export function range(start: number, end: number, step = 1): number[] {
|
|
10
|
+
return Array.from({ length: Math.floor(Math.abs(end - start) / step) + 1 }, (_, i) => start + i * (end > start ? 1 : -1) * Math.abs(step))
|
|
11
|
+
}
|
package/src/index.ts
ADDED