@spark-web/text 1.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/CHANGELOG.md +17 -0
- package/README.md +137 -0
- package/dist/declarations/src/Strong.d.ts +5 -0
- package/dist/declarations/src/Text.d.ts +32 -0
- package/dist/declarations/src/context.d.ts +11 -0
- package/dist/declarations/src/defaultTextProps.d.ts +16 -0
- package/dist/declarations/src/index.d.ts +11 -0
- package/dist/declarations/src/useForegroundTone.d.ts +3 -0
- package/dist/declarations/src/useOverflowStrategy.d.ts +27 -0
- package/dist/declarations/src/useText.d.ts +29 -0
- package/dist/spark-web-text.cjs.d.ts +1 -0
- package/dist/spark-web-text.cjs.dev.js +266 -0
- package/dist/spark-web-text.cjs.js +7 -0
- package/dist/spark-web-text.cjs.prod.js +266 -0
- package/dist/spark-web-text.esm.js +250 -0
- package/package.json +21 -0
- package/src/Strong.tsx +13 -0
- package/src/Text.stories.tsx +20 -0
- package/src/Text.tsx +113 -0
- package/src/context.ts +13 -0
- package/src/defaultTextProps.tsx +48 -0
- package/src/index.ts +17 -0
- package/src/useForegroundTone.ts +36 -0
- package/src/useOverflowStrategy.ts +28 -0
- package/src/useText.ts +56 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { createContext, useContext, useMemo } from 'react';
|
|
3
|
+
|
|
4
|
+
import type { UseTextProps } from './useText';
|
|
5
|
+
|
|
6
|
+
type DefaultTextProps = {
|
|
7
|
+
size?: NonNullable<UseTextProps['size']>;
|
|
8
|
+
tone?: NonNullable<UseTextProps['tone']>;
|
|
9
|
+
weight?: NonNullable<UseTextProps['weight']>;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const DefaultTextPropsContext = createContext<DefaultTextProps>({
|
|
13
|
+
size: undefined,
|
|
14
|
+
tone: undefined,
|
|
15
|
+
weight: undefined,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export function DefaultTextPropsProvider({
|
|
19
|
+
children,
|
|
20
|
+
size,
|
|
21
|
+
tone,
|
|
22
|
+
weight,
|
|
23
|
+
}: DefaultTextProps & { children: ReactNode }) {
|
|
24
|
+
const defaultTextProps = useMemo(
|
|
25
|
+
() => ({ size, tone, weight }),
|
|
26
|
+
[size, tone, weight]
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<DefaultTextPropsContext.Provider value={defaultTextProps}>
|
|
31
|
+
{children}
|
|
32
|
+
</DefaultTextPropsContext.Provider>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const useDefaultTextProps = ({
|
|
37
|
+
size: sizeProp,
|
|
38
|
+
tone: toneProp,
|
|
39
|
+
weight: weightProp,
|
|
40
|
+
}: DefaultTextProps) => {
|
|
41
|
+
const { size, tone, weight } = useContext(DefaultTextPropsContext);
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
size: sizeProp ?? size ?? 'standard',
|
|
45
|
+
tone: toneProp ?? tone ?? 'neutral',
|
|
46
|
+
weight: weightProp ?? weight ?? 'regular',
|
|
47
|
+
};
|
|
48
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { useTextContext } from './context';
|
|
2
|
+
export {
|
|
3
|
+
DefaultTextPropsProvider,
|
|
4
|
+
useDefaultTextProps,
|
|
5
|
+
} from './defaultTextProps';
|
|
6
|
+
export { Strong } from './Strong';
|
|
7
|
+
export { Text } from './Text';
|
|
8
|
+
export { useForegroundTone } from './useForegroundTone';
|
|
9
|
+
export { useOverflowStrategy } from './useOverflowStrategy';
|
|
10
|
+
export { createTextStyles, useText } from './useText';
|
|
11
|
+
|
|
12
|
+
// types
|
|
13
|
+
|
|
14
|
+
export type { StrongProps } from './Strong';
|
|
15
|
+
export type { TextProps } from './Text';
|
|
16
|
+
export type { ForegroundTone } from './useForegroundTone';
|
|
17
|
+
export type { TextOverflowStrategy } from './useOverflowStrategy';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useBackgroundLightness } from '@spark-web/box';
|
|
2
|
+
import type { BrighteTheme } from '@spark-web/theme';
|
|
3
|
+
import { useTheme } from '@spark-web/theme';
|
|
4
|
+
|
|
5
|
+
export type ForegroundTone = keyof Omit<
|
|
6
|
+
BrighteTheme['color']['foreground'],
|
|
7
|
+
'neutralInverted' | 'mutedInverted'
|
|
8
|
+
>;
|
|
9
|
+
|
|
10
|
+
const invertableTones = {
|
|
11
|
+
neutral: {
|
|
12
|
+
dark: 'neutralInverted',
|
|
13
|
+
light: 'neutral',
|
|
14
|
+
},
|
|
15
|
+
muted: {
|
|
16
|
+
dark: 'mutedInverted',
|
|
17
|
+
light: 'muted',
|
|
18
|
+
},
|
|
19
|
+
link: {
|
|
20
|
+
dark: 'neutralInverted',
|
|
21
|
+
light: 'link',
|
|
22
|
+
},
|
|
23
|
+
} as const;
|
|
24
|
+
|
|
25
|
+
export function useForegroundTone(tone: ForegroundTone) {
|
|
26
|
+
const theme = useTheme();
|
|
27
|
+
const backgroundLightness = useBackgroundLightness();
|
|
28
|
+
|
|
29
|
+
if (tone in invertableTones) {
|
|
30
|
+
return theme.color.foreground[
|
|
31
|
+
invertableTones[tone as keyof typeof invertableTones][backgroundLightness]
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return theme.color.foreground[tone];
|
|
36
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const strategyMap = {
|
|
2
|
+
truncate: {
|
|
3
|
+
display: 'block',
|
|
4
|
+
overflow: 'hidden',
|
|
5
|
+
textOverflow: 'ellipsis',
|
|
6
|
+
whiteSpace: 'nowrap',
|
|
7
|
+
},
|
|
8
|
+
nowrap: {
|
|
9
|
+
whiteSpace: 'nowrap',
|
|
10
|
+
},
|
|
11
|
+
// https://css-tricks.com/better-line-breaks-for-long-urls/
|
|
12
|
+
breakword: {
|
|
13
|
+
display: 'block',
|
|
14
|
+
overflowWrap: 'break-word',
|
|
15
|
+
wordBreak: 'break-word',
|
|
16
|
+
wordWrap: 'break-word',
|
|
17
|
+
},
|
|
18
|
+
} as const;
|
|
19
|
+
|
|
20
|
+
export type TextOverflowStrategy = keyof typeof strategyMap;
|
|
21
|
+
|
|
22
|
+
export function useOverflowStrategy(strategy?: TextOverflowStrategy) {
|
|
23
|
+
if (!strategy) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return strategyMap[strategy];
|
|
28
|
+
}
|
package/src/useText.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { BrighteTextDefinition, BrighteTheme } from '@spark-web/theme';
|
|
2
|
+
import { useTheme } from '@spark-web/theme';
|
|
3
|
+
|
|
4
|
+
import type { ForegroundTone } from './useForegroundTone';
|
|
5
|
+
import { useForegroundTone } from './useForegroundTone';
|
|
6
|
+
|
|
7
|
+
export type UseTextProps = {
|
|
8
|
+
/** Apply leading-trim styles. */
|
|
9
|
+
baseline?: boolean;
|
|
10
|
+
/** The size of the text. */
|
|
11
|
+
size: keyof BrighteTheme['typography']['text'];
|
|
12
|
+
/** The tone of the text. */
|
|
13
|
+
tone: ForegroundTone;
|
|
14
|
+
/** The weight of the text. */
|
|
15
|
+
weight: keyof BrighteTheme['typography']['fontWeight'];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function useText({ baseline = true, size, tone, weight }: UseTextProps) {
|
|
19
|
+
const { typography, utils } = useTheme();
|
|
20
|
+
const color = useForegroundTone(tone);
|
|
21
|
+
const { mobile, tablet } = typography.text[size];
|
|
22
|
+
const responsiveStyles = utils.responsiveStyles({
|
|
23
|
+
mobile: createTextStyles(mobile, { includeTrims: baseline }),
|
|
24
|
+
tablet: createTextStyles(tablet, { includeTrims: baseline }),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const styles = [
|
|
28
|
+
{
|
|
29
|
+
color,
|
|
30
|
+
fontFamily: typography.fontFamily.sans.name,
|
|
31
|
+
fontWeight: typography.fontWeight[weight],
|
|
32
|
+
},
|
|
33
|
+
responsiveStyles,
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
return styles;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function createTextStyles(
|
|
40
|
+
{ fontSize, lineHeight, trims }: BrighteTextDefinition,
|
|
41
|
+
{ includeTrims = true } = {}
|
|
42
|
+
) {
|
|
43
|
+
const pseudo = { content: '" "', display: 'table' };
|
|
44
|
+
const leadingTrim = includeTrims
|
|
45
|
+
? {
|
|
46
|
+
'::before': { ...pseudo, marginBottom: trims.capHeightTrim },
|
|
47
|
+
'::after': { ...pseudo, marginTop: trims.baselineTrim },
|
|
48
|
+
}
|
|
49
|
+
: null;
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
fontSize,
|
|
53
|
+
lineHeight,
|
|
54
|
+
...leadingTrim,
|
|
55
|
+
};
|
|
56
|
+
}
|