@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.
@@ -0,0 +1,266 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var React = require('react');
6
+ var css = require('@emotion/css');
7
+ var theme = require('@spark-web/theme');
8
+ var box = require('@spark-web/box');
9
+ var ts = require('@spark-web/utils/ts');
10
+ var _defineProperty = require('@babel/runtime/helpers/esm/defineProperty');
11
+
12
+ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
13
+
14
+ var React__default = /*#__PURE__*/_interopDefault(React);
15
+
16
+ var TextContext = /*#__PURE__*/React.createContext(undefined);
17
+ function useTextContext() {
18
+ return React.useContext(TextContext);
19
+ }
20
+
21
+ var __jsx$2 = React__default["default"].createElement;
22
+ var DefaultTextPropsContext = /*#__PURE__*/React.createContext({
23
+ size: undefined,
24
+ tone: undefined,
25
+ weight: undefined
26
+ });
27
+ function DefaultTextPropsProvider(_ref) {
28
+ var children = _ref.children,
29
+ size = _ref.size,
30
+ tone = _ref.tone,
31
+ weight = _ref.weight;
32
+ var defaultTextProps = React.useMemo(function () {
33
+ return {
34
+ size: size,
35
+ tone: tone,
36
+ weight: weight
37
+ };
38
+ }, [size, tone, weight]);
39
+ return __jsx$2(DefaultTextPropsContext.Provider, {
40
+ value: defaultTextProps
41
+ }, children);
42
+ }
43
+ var useDefaultTextProps = function useDefaultTextProps(_ref2) {
44
+ var _ref3, _ref4, _ref5;
45
+
46
+ var sizeProp = _ref2.size,
47
+ toneProp = _ref2.tone,
48
+ weightProp = _ref2.weight;
49
+
50
+ var _useContext = React.useContext(DefaultTextPropsContext),
51
+ size = _useContext.size,
52
+ tone = _useContext.tone,
53
+ weight = _useContext.weight;
54
+
55
+ return {
56
+ size: (_ref3 = sizeProp !== null && sizeProp !== void 0 ? sizeProp : size) !== null && _ref3 !== void 0 ? _ref3 : 'standard',
57
+ tone: (_ref4 = toneProp !== null && toneProp !== void 0 ? toneProp : tone) !== null && _ref4 !== void 0 ? _ref4 : 'neutral',
58
+ weight: (_ref5 = weightProp !== null && weightProp !== void 0 ? weightProp : weight) !== null && _ref5 !== void 0 ? _ref5 : 'regular'
59
+ };
60
+ };
61
+
62
+ var __jsx$1 = React__default["default"].createElement;
63
+ var Strong = function Strong(_ref) {
64
+ var children = _ref.children;
65
+
66
+ var _useTheme = theme.useTheme(),
67
+ typography = _useTheme.typography;
68
+
69
+ var styles = {
70
+ fontWeight: typography.fontWeight.strong
71
+ };
72
+ return __jsx$1("strong", {
73
+ className: css.css(styles)
74
+ }, children);
75
+ };
76
+
77
+ var strategyMap = {
78
+ truncate: {
79
+ display: 'block',
80
+ overflow: 'hidden',
81
+ textOverflow: 'ellipsis',
82
+ whiteSpace: 'nowrap'
83
+ },
84
+ nowrap: {
85
+ whiteSpace: 'nowrap'
86
+ },
87
+ // https://css-tricks.com/better-line-breaks-for-long-urls/
88
+ breakword: {
89
+ display: 'block',
90
+ overflowWrap: 'break-word',
91
+ wordBreak: 'break-word',
92
+ wordWrap: 'break-word'
93
+ }
94
+ };
95
+ function useOverflowStrategy(strategy) {
96
+ if (!strategy) {
97
+ return null;
98
+ }
99
+
100
+ return strategyMap[strategy];
101
+ }
102
+
103
+ var invertableTones = {
104
+ neutral: {
105
+ dark: 'neutralInverted',
106
+ light: 'neutral'
107
+ },
108
+ muted: {
109
+ dark: 'mutedInverted',
110
+ light: 'muted'
111
+ },
112
+ link: {
113
+ dark: 'neutralInverted',
114
+ light: 'link'
115
+ }
116
+ };
117
+ function useForegroundTone(tone) {
118
+ var theme$1 = theme.useTheme();
119
+ var backgroundLightness = box.useBackgroundLightness();
120
+
121
+ if (tone in invertableTones) {
122
+ return theme$1.color.foreground[invertableTones[tone][backgroundLightness]];
123
+ }
124
+
125
+ return theme$1.color.foreground[tone];
126
+ }
127
+
128
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
129
+
130
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
131
+ function useText(_ref) {
132
+ var _ref$baseline = _ref.baseline,
133
+ baseline = _ref$baseline === void 0 ? true : _ref$baseline,
134
+ size = _ref.size,
135
+ tone = _ref.tone,
136
+ weight = _ref.weight;
137
+
138
+ var _useTheme = theme.useTheme(),
139
+ typography = _useTheme.typography,
140
+ utils = _useTheme.utils;
141
+
142
+ var color = useForegroundTone(tone);
143
+ var _typography$text$size = typography.text[size],
144
+ mobile = _typography$text$size.mobile,
145
+ tablet = _typography$text$size.tablet;
146
+ var responsiveStyles = utils.responsiveStyles({
147
+ mobile: createTextStyles(mobile, {
148
+ includeTrims: baseline
149
+ }),
150
+ tablet: createTextStyles(tablet, {
151
+ includeTrims: baseline
152
+ })
153
+ });
154
+ var styles = [{
155
+ color: color,
156
+ fontFamily: typography.fontFamily.sans.name,
157
+ fontWeight: typography.fontWeight[weight]
158
+ }, responsiveStyles];
159
+ return styles;
160
+ }
161
+ function createTextStyles(_ref2) {
162
+ var fontSize = _ref2.fontSize,
163
+ lineHeight = _ref2.lineHeight,
164
+ trims = _ref2.trims;
165
+
166
+ var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
167
+ _ref3$includeTrims = _ref3.includeTrims,
168
+ includeTrims = _ref3$includeTrims === void 0 ? true : _ref3$includeTrims;
169
+
170
+ var pseudo = {
171
+ content: '" "',
172
+ display: 'table'
173
+ };
174
+ var leadingTrim = includeTrims ? {
175
+ '::before': _objectSpread(_objectSpread({}, pseudo), {}, {
176
+ marginBottom: trims.capHeightTrim
177
+ }),
178
+ '::after': _objectSpread(_objectSpread({}, pseudo), {}, {
179
+ marginTop: trims.baselineTrim
180
+ })
181
+ } : null;
182
+ return _objectSpread({
183
+ fontSize: fontSize,
184
+ lineHeight: lineHeight
185
+ }, leadingTrim);
186
+ }
187
+
188
+ var __jsx = React__default["default"].createElement;
189
+ var Text = ts.forwardRefWithAs(function (_ref, forwardedRef) {
190
+ var as = _ref.as,
191
+ children = _ref.children,
192
+ id = _ref.id,
193
+ align = _ref.align,
194
+ baselineProp = _ref.baseline,
195
+ inline = _ref.inline,
196
+ overflowStrategy = _ref.overflowStrategy,
197
+ sizeProp = _ref.size,
198
+ tabularNumbers = _ref.tabularNumbers,
199
+ toneProp = _ref.tone,
200
+ transform = _ref.transform,
201
+ weightProp = _ref.weight;
202
+ var overflowStyles = useOverflowStrategy(overflowStrategy);
203
+ var textContext = useTextContext();
204
+
205
+ var _useDefaultTextProps = useDefaultTextProps({
206
+ size: sizeProp !== null && sizeProp !== void 0 ? sizeProp : textContext === null || textContext === void 0 ? void 0 : textContext.size,
207
+ tone: toneProp !== null && toneProp !== void 0 ? toneProp : textContext === null || textContext === void 0 ? void 0 : textContext.tone,
208
+ weight: weightProp !== null && weightProp !== void 0 ? weightProp : textContext === null || textContext === void 0 ? void 0 : textContext.weight
209
+ }),
210
+ size = _useDefaultTextProps.size,
211
+ tone = _useDefaultTextProps.tone,
212
+ weight = _useDefaultTextProps.weight;
213
+
214
+ var baseline = !inline && baselineProp;
215
+ var textStyles = useText({
216
+ baseline: baseline,
217
+ size: size,
218
+ tone: tone,
219
+ weight: weight
220
+ });
221
+ var styles = [textStyles, {
222
+ display: inline ? 'inline' : 'block',
223
+ fontVariantNumeric: tabularNumbers ? 'tabular-nums' : undefined,
224
+ textAlign: align,
225
+ textTransform: transform
226
+ }]; // early exit for inline variant
227
+
228
+ if (inline) {
229
+ return __jsx(box.Box, {
230
+ as: as !== null && as !== void 0 ? as : 'span',
231
+ ref: forwardedRef,
232
+ id: id,
233
+ className: css.css(styles)
234
+ }, children);
235
+ } // prepare block variant
236
+
237
+
238
+ var content = overflowStrategy ? __jsx("span", {
239
+ className: css.css(overflowStyles)
240
+ }, children) : children;
241
+ var textContextValue = React.useMemo(function () {
242
+ return {
243
+ size: size,
244
+ tone: tone,
245
+ weight: weight
246
+ };
247
+ }, [size, tone, weight]);
248
+ return __jsx(TextContext.Provider, {
249
+ value: textContextValue
250
+ }, __jsx(box.Box, {
251
+ as: as,
252
+ ref: forwardedRef,
253
+ id: id,
254
+ className: css.css(styles)
255
+ }, content));
256
+ });
257
+
258
+ exports.DefaultTextPropsProvider = DefaultTextPropsProvider;
259
+ exports.Strong = Strong;
260
+ exports.Text = Text;
261
+ exports.createTextStyles = createTextStyles;
262
+ exports.useDefaultTextProps = useDefaultTextProps;
263
+ exports.useForegroundTone = useForegroundTone;
264
+ exports.useOverflowStrategy = useOverflowStrategy;
265
+ exports.useText = useText;
266
+ exports.useTextContext = useTextContext;
@@ -0,0 +1,250 @@
1
+ import React, { useContext, createContext, useMemo } from 'react';
2
+ import { css } from '@emotion/css';
3
+ import { useTheme } from '@spark-web/theme';
4
+ import { useBackgroundLightness, Box } from '@spark-web/box';
5
+ import { forwardRefWithAs } from '@spark-web/utils/ts';
6
+ import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
7
+
8
+ var TextContext = /*#__PURE__*/createContext(undefined);
9
+ function useTextContext() {
10
+ return useContext(TextContext);
11
+ }
12
+
13
+ var __jsx$2 = React.createElement;
14
+ var DefaultTextPropsContext = /*#__PURE__*/createContext({
15
+ size: undefined,
16
+ tone: undefined,
17
+ weight: undefined
18
+ });
19
+ function DefaultTextPropsProvider(_ref) {
20
+ var children = _ref.children,
21
+ size = _ref.size,
22
+ tone = _ref.tone,
23
+ weight = _ref.weight;
24
+ var defaultTextProps = useMemo(function () {
25
+ return {
26
+ size: size,
27
+ tone: tone,
28
+ weight: weight
29
+ };
30
+ }, [size, tone, weight]);
31
+ return __jsx$2(DefaultTextPropsContext.Provider, {
32
+ value: defaultTextProps
33
+ }, children);
34
+ }
35
+ var useDefaultTextProps = function useDefaultTextProps(_ref2) {
36
+ var _ref3, _ref4, _ref5;
37
+
38
+ var sizeProp = _ref2.size,
39
+ toneProp = _ref2.tone,
40
+ weightProp = _ref2.weight;
41
+
42
+ var _useContext = useContext(DefaultTextPropsContext),
43
+ size = _useContext.size,
44
+ tone = _useContext.tone,
45
+ weight = _useContext.weight;
46
+
47
+ return {
48
+ size: (_ref3 = sizeProp !== null && sizeProp !== void 0 ? sizeProp : size) !== null && _ref3 !== void 0 ? _ref3 : 'standard',
49
+ tone: (_ref4 = toneProp !== null && toneProp !== void 0 ? toneProp : tone) !== null && _ref4 !== void 0 ? _ref4 : 'neutral',
50
+ weight: (_ref5 = weightProp !== null && weightProp !== void 0 ? weightProp : weight) !== null && _ref5 !== void 0 ? _ref5 : 'regular'
51
+ };
52
+ };
53
+
54
+ var __jsx$1 = React.createElement;
55
+ var Strong = function Strong(_ref) {
56
+ var children = _ref.children;
57
+
58
+ var _useTheme = useTheme(),
59
+ typography = _useTheme.typography;
60
+
61
+ var styles = {
62
+ fontWeight: typography.fontWeight.strong
63
+ };
64
+ return __jsx$1("strong", {
65
+ className: css(styles)
66
+ }, children);
67
+ };
68
+
69
+ var strategyMap = {
70
+ truncate: {
71
+ display: 'block',
72
+ overflow: 'hidden',
73
+ textOverflow: 'ellipsis',
74
+ whiteSpace: 'nowrap'
75
+ },
76
+ nowrap: {
77
+ whiteSpace: 'nowrap'
78
+ },
79
+ // https://css-tricks.com/better-line-breaks-for-long-urls/
80
+ breakword: {
81
+ display: 'block',
82
+ overflowWrap: 'break-word',
83
+ wordBreak: 'break-word',
84
+ wordWrap: 'break-word'
85
+ }
86
+ };
87
+ function useOverflowStrategy(strategy) {
88
+ if (!strategy) {
89
+ return null;
90
+ }
91
+
92
+ return strategyMap[strategy];
93
+ }
94
+
95
+ var invertableTones = {
96
+ neutral: {
97
+ dark: 'neutralInverted',
98
+ light: 'neutral'
99
+ },
100
+ muted: {
101
+ dark: 'mutedInverted',
102
+ light: 'muted'
103
+ },
104
+ link: {
105
+ dark: 'neutralInverted',
106
+ light: 'link'
107
+ }
108
+ };
109
+ function useForegroundTone(tone) {
110
+ var theme = useTheme();
111
+ var backgroundLightness = useBackgroundLightness();
112
+
113
+ if (tone in invertableTones) {
114
+ return theme.color.foreground[invertableTones[tone][backgroundLightness]];
115
+ }
116
+
117
+ return theme.color.foreground[tone];
118
+ }
119
+
120
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
121
+
122
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
123
+ function useText(_ref) {
124
+ var _ref$baseline = _ref.baseline,
125
+ baseline = _ref$baseline === void 0 ? true : _ref$baseline,
126
+ size = _ref.size,
127
+ tone = _ref.tone,
128
+ weight = _ref.weight;
129
+
130
+ var _useTheme = useTheme(),
131
+ typography = _useTheme.typography,
132
+ utils = _useTheme.utils;
133
+
134
+ var color = useForegroundTone(tone);
135
+ var _typography$text$size = typography.text[size],
136
+ mobile = _typography$text$size.mobile,
137
+ tablet = _typography$text$size.tablet;
138
+ var responsiveStyles = utils.responsiveStyles({
139
+ mobile: createTextStyles(mobile, {
140
+ includeTrims: baseline
141
+ }),
142
+ tablet: createTextStyles(tablet, {
143
+ includeTrims: baseline
144
+ })
145
+ });
146
+ var styles = [{
147
+ color: color,
148
+ fontFamily: typography.fontFamily.sans.name,
149
+ fontWeight: typography.fontWeight[weight]
150
+ }, responsiveStyles];
151
+ return styles;
152
+ }
153
+ function createTextStyles(_ref2) {
154
+ var fontSize = _ref2.fontSize,
155
+ lineHeight = _ref2.lineHeight,
156
+ trims = _ref2.trims;
157
+
158
+ var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
159
+ _ref3$includeTrims = _ref3.includeTrims,
160
+ includeTrims = _ref3$includeTrims === void 0 ? true : _ref3$includeTrims;
161
+
162
+ var pseudo = {
163
+ content: '" "',
164
+ display: 'table'
165
+ };
166
+ var leadingTrim = includeTrims ? {
167
+ '::before': _objectSpread(_objectSpread({}, pseudo), {}, {
168
+ marginBottom: trims.capHeightTrim
169
+ }),
170
+ '::after': _objectSpread(_objectSpread({}, pseudo), {}, {
171
+ marginTop: trims.baselineTrim
172
+ })
173
+ } : null;
174
+ return _objectSpread({
175
+ fontSize: fontSize,
176
+ lineHeight: lineHeight
177
+ }, leadingTrim);
178
+ }
179
+
180
+ var __jsx = React.createElement;
181
+ var Text = forwardRefWithAs(function (_ref, forwardedRef) {
182
+ var as = _ref.as,
183
+ children = _ref.children,
184
+ id = _ref.id,
185
+ align = _ref.align,
186
+ baselineProp = _ref.baseline,
187
+ inline = _ref.inline,
188
+ overflowStrategy = _ref.overflowStrategy,
189
+ sizeProp = _ref.size,
190
+ tabularNumbers = _ref.tabularNumbers,
191
+ toneProp = _ref.tone,
192
+ transform = _ref.transform,
193
+ weightProp = _ref.weight;
194
+ var overflowStyles = useOverflowStrategy(overflowStrategy);
195
+ var textContext = useTextContext();
196
+
197
+ var _useDefaultTextProps = useDefaultTextProps({
198
+ size: sizeProp !== null && sizeProp !== void 0 ? sizeProp : textContext === null || textContext === void 0 ? void 0 : textContext.size,
199
+ tone: toneProp !== null && toneProp !== void 0 ? toneProp : textContext === null || textContext === void 0 ? void 0 : textContext.tone,
200
+ weight: weightProp !== null && weightProp !== void 0 ? weightProp : textContext === null || textContext === void 0 ? void 0 : textContext.weight
201
+ }),
202
+ size = _useDefaultTextProps.size,
203
+ tone = _useDefaultTextProps.tone,
204
+ weight = _useDefaultTextProps.weight;
205
+
206
+ var baseline = !inline && baselineProp;
207
+ var textStyles = useText({
208
+ baseline: baseline,
209
+ size: size,
210
+ tone: tone,
211
+ weight: weight
212
+ });
213
+ var styles = [textStyles, {
214
+ display: inline ? 'inline' : 'block',
215
+ fontVariantNumeric: tabularNumbers ? 'tabular-nums' : undefined,
216
+ textAlign: align,
217
+ textTransform: transform
218
+ }]; // early exit for inline variant
219
+
220
+ if (inline) {
221
+ return __jsx(Box, {
222
+ as: as !== null && as !== void 0 ? as : 'span',
223
+ ref: forwardedRef,
224
+ id: id,
225
+ className: css(styles)
226
+ }, children);
227
+ } // prepare block variant
228
+
229
+
230
+ var content = overflowStrategy ? __jsx("span", {
231
+ className: css(overflowStyles)
232
+ }, children) : children;
233
+ var textContextValue = useMemo(function () {
234
+ return {
235
+ size: size,
236
+ tone: tone,
237
+ weight: weight
238
+ };
239
+ }, [size, tone, weight]);
240
+ return __jsx(TextContext.Provider, {
241
+ value: textContextValue
242
+ }, __jsx(Box, {
243
+ as: as,
244
+ ref: forwardedRef,
245
+ id: id,
246
+ className: css(styles)
247
+ }, content));
248
+ });
249
+
250
+ export { DefaultTextPropsProvider, Strong, Text, createTextStyles, useDefaultTextProps, useForegroundTone, useOverflowStrategy, useText, useTextContext };
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@spark-web/text",
3
+ "license": "MIT",
4
+ "version": "1.0.0",
5
+ "main": "dist/spark-web-text.cjs.js",
6
+ "module": "dist/spark-web-text.esm.js",
7
+ "devDependencies": {
8
+ "@types/react": "^17.0.12"
9
+ },
10
+ "dependencies": {
11
+ "@babel/runtime": "^7.14.6",
12
+ "@emotion/css": "^11.7.1",
13
+ "@spark-web/box": "^1.0.0",
14
+ "@spark-web/theme": "^1.0.0",
15
+ "@spark-web/utils": "^1.0.0",
16
+ "react": "^17.0.2"
17
+ },
18
+ "engines": {
19
+ "node": ">= 14.13"
20
+ }
21
+ }
package/src/Strong.tsx ADDED
@@ -0,0 +1,13 @@
1
+ import { css } from '@emotion/css';
2
+ import { useTheme } from '@spark-web/theme';
3
+ import type { ReactNode } from 'react';
4
+
5
+ export type StrongProps = {
6
+ children: ReactNode;
7
+ };
8
+
9
+ export const Strong = ({ children }: StrongProps) => {
10
+ const { typography } = useTheme();
11
+ const styles = { fontWeight: typography.fontWeight.strong };
12
+ return <strong className={css(styles)}>{children}</strong>;
13
+ };
@@ -0,0 +1,20 @@
1
+ import type { ComponentMeta, ComponentStory } from '@storybook/react';
2
+
3
+ import type { TextProps } from './Text';
4
+ import { Text } from './Text';
5
+
6
+ export default {
7
+ title: 'Typography / Text',
8
+ component: Text,
9
+ } as ComponentMeta<typeof Text>;
10
+
11
+ const LinkStory: ComponentStory<typeof Text> = (args: TextProps) => (
12
+ <Text {...args} />
13
+ );
14
+
15
+ export const Default = LinkStory.bind({});
16
+
17
+ Default.args = {
18
+ children:
19
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque rhoncus ex purus, nec rutrum lorem placerat vestibulum. Ut sit amet libero non tellus aliquam pretium nec ac dui. Vivamus erat nibh, placerat vitae nisi eu, aliquet auctor dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae;',
20
+ };
package/src/Text.tsx ADDED
@@ -0,0 +1,113 @@
1
+ import { css } from '@emotion/css';
2
+ import type { BoxProps } from '@spark-web/box';
3
+ import { Box } from '@spark-web/box';
4
+ import { forwardRefWithAs } from '@spark-web/utils/ts';
5
+ import type { CSSProperties, ReactNode } from 'react';
6
+ import { useMemo } from 'react';
7
+
8
+ import { TextContext, useTextContext } from './context';
9
+ import { useDefaultTextProps } from './defaultTextProps';
10
+ import type { TextOverflowStrategy } from './useOverflowStrategy';
11
+ import { useOverflowStrategy } from './useOverflowStrategy';
12
+ import type { UseTextProps } from './useText';
13
+ import { useText } from './useText';
14
+
15
+ type InlineProps = {
16
+ align?: never;
17
+ /** Display as an inline element. */
18
+ inline?: boolean;
19
+ overflowStrategy?: never;
20
+ };
21
+ type BlockProps = {
22
+ /** The horizontal alignment. */
23
+ align?: 'left' | 'center' | 'right';
24
+ inline?: never;
25
+ /** Manage how text behaves with regard to overflow. */
26
+ overflowStrategy?: TextOverflowStrategy;
27
+ };
28
+
29
+ export type TextProps = Partial<UseTextProps> & {
30
+ /** The text content. */
31
+ children?: ReactNode;
32
+ /** An identifier which must be unique in the whole document. */
33
+ id?: BoxProps['id'];
34
+ /** When enabled, numbers will be the same width. Similar to a monospaced font. */
35
+ tabularNumbers?: boolean;
36
+ /** Transform the text casing. */
37
+ transform?: CSSProperties['textTransform'];
38
+ } & (InlineProps | BlockProps);
39
+
40
+ export const Text = forwardRefWithAs<'div', TextProps>(
41
+ (
42
+ {
43
+ // box props
44
+ as,
45
+ children,
46
+ id,
47
+
48
+ //text props
49
+ align,
50
+ baseline: baselineProp,
51
+ inline,
52
+ overflowStrategy,
53
+ size: sizeProp,
54
+ tabularNumbers,
55
+ tone: toneProp,
56
+ transform,
57
+ weight: weightProp,
58
+ },
59
+ forwardedRef
60
+ ) => {
61
+ const overflowStyles = useOverflowStrategy(overflowStrategy);
62
+ const textContext = useTextContext();
63
+ const { size, tone, weight } = useDefaultTextProps({
64
+ size: sizeProp ?? textContext?.size,
65
+ tone: toneProp ?? textContext?.tone,
66
+ weight: weightProp ?? textContext?.weight,
67
+ });
68
+ const baseline = !inline && baselineProp;
69
+ const textStyles = useText({ baseline, size, tone, weight });
70
+ const styles = [
71
+ textStyles,
72
+ {
73
+ display: inline ? 'inline' : 'block',
74
+ fontVariantNumeric: tabularNumbers ? 'tabular-nums' : undefined,
75
+ textAlign: align,
76
+ textTransform: transform,
77
+ },
78
+ ];
79
+
80
+ // early exit for inline variant
81
+ if (inline) {
82
+ return (
83
+ <Box
84
+ as={as ?? 'span'}
85
+ ref={forwardedRef}
86
+ id={id}
87
+ className={css(styles)}
88
+ >
89
+ {children}
90
+ </Box>
91
+ );
92
+ }
93
+
94
+ // prepare block variant
95
+ const content = overflowStrategy ? (
96
+ <span className={css(overflowStyles)}>{children}</span>
97
+ ) : (
98
+ children
99
+ );
100
+ const textContextValue = useMemo(
101
+ () => ({ size, tone, weight }),
102
+ [size, tone, weight]
103
+ );
104
+
105
+ return (
106
+ <TextContext.Provider value={textContextValue}>
107
+ <Box as={as} ref={forwardedRef} id={id} className={css(styles)}>
108
+ {content}
109
+ </Box>
110
+ </TextContext.Provider>
111
+ );
112
+ }
113
+ );
package/src/context.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ import type { useDefaultTextProps } from './defaultTextProps';
4
+
5
+ type TextContextType = ReturnType<typeof useDefaultTextProps>;
6
+
7
+ export const TextContext = createContext<TextContextType | undefined>(
8
+ undefined
9
+ );
10
+
11
+ export function useTextContext() {
12
+ return useContext(TextContext);
13
+ }