@spark-web/text 5.3.0-rc.0 → 5.3.1

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 CHANGED
@@ -1,17 +1,63 @@
1
1
  # @spark-web/text
2
2
 
3
- ## 5.3.0-rc.0
3
+ ## 5.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#782](https://github.com/brighte-labs/spark-web/pull/782)
8
+ [`bb41800`](https://github.com/brighte-labs/spark-web/commit/bb418004d21165f72f4bf2456afea844ee04a21c)
9
+ Thanks [@jacobporci-brighte](https://github.com/jacobporci-brighte)! -
10
+ **docs:** add CLAUDE.md AI context files to foundation and form packages;
11
+ patch data-table with manual sort and spinner overlay patterns
12
+ - Updated dependencies
13
+ [[`bb41800`](https://github.com/brighte-labs/spark-web/commit/bb418004d21165f72f4bf2456afea844ee04a21c)]:
14
+ - @spark-web/box@6.0.1
15
+
16
+ ## 5.3.0
4
17
 
5
18
  ### Minor Changes
6
19
 
7
- - update react version and other packages
20
+ - [#667](https://github.com/brighte-labs/spark-web/pull/667)
21
+ [`80d9c15`](https://github.com/brighte-labs/spark-web/commit/80d9c156a40bbcd2b1a91a2d0403b3c8e9b47b4e)
22
+ Thanks [@Leo704099](https://github.com/Leo704099)! - Support react 17 to 19
8
23
 
9
24
  ### Patch Changes
10
25
 
11
- - Updated dependencies []:
12
- - @spark-web/theme@5.12.0-rc.0
13
- - @spark-web/utils@5.1.0-rc.0
14
- - @spark-web/box@6.0.0-rc.0
26
+ - Updated dependencies
27
+ [[`80d9c15`](https://github.com/brighte-labs/spark-web/commit/80d9c156a40bbcd2b1a91a2d0403b3c8e9b47b4e)]:
28
+ - @spark-web/theme@5.13.0
29
+ - @spark-web/utils@5.1.0
30
+ - @spark-web/box@6.0.0
31
+
32
+ ## 5.2.3
33
+
34
+ ### Patch Changes
35
+
36
+ - [#698](https://github.com/brighte-labs/spark-web/pull/698)
37
+ [`814b373`](https://github.com/brighte-labs/spark-web/commit/814b373cbe9fcf0757738c78eef6b516624df62c)
38
+ Thanks [@michtntbrighte](https://github.com/michtntbrighte)! - Bump version
39
+
40
+ - Updated dependencies
41
+ [[`814b373`](https://github.com/brighte-labs/spark-web/commit/814b373cbe9fcf0757738c78eef6b516624df62c)]:
42
+ - @spark-web/box@5.2.2
43
+ - @spark-web/theme@5.12.1
44
+
45
+ ## 5.2.2
46
+
47
+ ### Patch Changes
48
+
49
+ - Updated dependencies
50
+ [[`1995db7`](https://github.com/brighte-labs/spark-web/commit/1995db7f4342803732c7648ab3ca6d32442cc347)]:
51
+ - @spark-web/theme@5.12.0
52
+
53
+ ## 5.2.1
54
+
55
+ ### Patch Changes
56
+
57
+ - [#685](https://github.com/brighte-labs/spark-web/pull/685)
58
+ [`ffbfa06`](https://github.com/brighte-labs/spark-web/commit/ffbfa066a4b2f72a838e68b49dd2c63ac44621a1)
59
+ Thanks [@michtntbrighte](https://github.com/michtntbrighte)! - : add truncate
60
+ the text with an ellipsis by number of lines
15
61
 
16
62
  ## 5.2.0
17
63
 
package/CLAUDE.md ADDED
@@ -0,0 +1,91 @@
1
+ # @spark-web/text — AI Context
2
+
3
+ ## What this is
4
+
5
+ The primary text rendering component. Applies theme typography tokens (size,
6
+ weight, tone, baseline trimming) and renders as a block `div` by default. Use
7
+ for body copy, labels, captions, status messages, and cell content inside
8
+ tables.
9
+
10
+ ## What this is NOT
11
+
12
+ - Not a heading — use `@spark-web/heading` for semantic headings (h1–h4)
13
+ - Not a link — use `@spark-web/text-link` for anchor text
14
+ - Not a layout container — do not put layout logic inside `Text`
15
+
16
+ ## Props interface
17
+
18
+ | Prop | Type | Default | Notes |
19
+ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | -------------------------------------------------------------------------------------------------- |
20
+ | `size` | `'xsmall' \| 'small' \| 'standard' \| 'large'` | `'standard'` | Typography scale |
21
+ | `tone` | `'neutral' \| 'muted' \| 'link' \| 'disabled' \| 'field' \| 'fieldAccent' \| 'placeholder' \| 'accent' \| 'primary' \| 'primaryHover' \| 'primaryActive' \| 'secondary' \| 'secondaryHover' \| 'secondaryActive' \| 'caution' \| 'critical' \| 'info' \| 'positive' \| 'dark' \| 'brandSubtle'` | `'neutral'` | Text color |
22
+ | `weight` | `'regular' \| 'semibold'` | — | Font weight override |
23
+ | `align` | `'left' \| 'center' \| 'right'` | — | Block variant only (not compatible with `inline`) |
24
+ | `inline` | `boolean` | `false` | Renders as `<span>` with `display: inline` |
25
+ | `baseline` | `boolean` | `true` | Apply leading-trim (cap-height) — set `false` when not adjacent to other baseline-trimmed elements |
26
+ | `overflowStrategy` | `'truncate' \| 'nowrap'` | — | Block variant only |
27
+ | `numberOfLines` | `number` | — | Clamp to N lines with ellipsis |
28
+ | `tabularNumbers` | `boolean` | `false` | Monospace-width numerals |
29
+ | `transform` | CSS `textTransform` value | — | `'uppercase'`, `'capitalize'`, etc. |
30
+ | `as` | HTML element tag | `'div'` | Use `'span'`, `'p'`, `'label'`, etc. as needed |
31
+ | `data` | `DataAttributeMap` | — | Test/analytics attributes |
32
+
33
+ ## Token usage
34
+
35
+ All typography values come from `theme.typography`. Text internally uses
36
+ `useText()` which maps `size` → responsive font-size/line-height and applies
37
+ baseline trimming. Never compute font sizes or colors directly — always use
38
+ `Text` props.
39
+
40
+ ## Common patterns
41
+
42
+ ### Table cell content
43
+
44
+ ```tsx
45
+ // Always size="small" in table cells
46
+ <Text size="small">{row.name}</Text>
47
+ ```
48
+
49
+ ### Muted supporting text
50
+
51
+ ```tsx
52
+ <Text tone="muted" size="small">
53
+ No records found
54
+ </Text>
55
+ ```
56
+
57
+ ### Inline label within a block
58
+
59
+ ```tsx
60
+ <Text>
61
+ Status:{' '}
62
+ <Text inline tone="positive">
63
+ Active
64
+ </Text>
65
+ </Text>
66
+ ```
67
+
68
+ ### Truncate long values
69
+
70
+ ```tsx
71
+ <Text size="small" overflowStrategy="truncate">
72
+ {longValue}
73
+ </Text>
74
+ ```
75
+
76
+ ## Composition
77
+
78
+ `Text` renders a `Box` internally. It provides a `TextContext` so nested `Text`
79
+ components inherit `size`, `tone`, and `weight` — override only what differs
80
+ from the parent.
81
+
82
+ ## Do NOTs
83
+
84
+ - NEVER use raw CSS for font-size, color, or line-height — always use `Text`
85
+ props
86
+ - NEVER use `tone="neutralInverted"` or `tone="mutedInverted"` directly — these
87
+ are automatic inversions applied by the `background` context
88
+ - NEVER set `baseline={true}` (the default) on a `Text` that is not inside a
89
+ layout component that accounts for leading-trim — set `baseline={false}` when
90
+ in doubt for non-standard layouts
91
+ - NEVER use `Text` for headings — use `@spark-web/heading`
@@ -1,11 +1,10 @@
1
- /// <reference types="react" />
2
1
  export declare const TextContext: import("react").Context<{
3
- size: import("@spark-web/theme/src/themes/_types/typography").TypographySizing;
4
- tone: string | number;
5
- weight: "medium" | "light" | "bold" | "thin" | "black" | "extralight" | "regular" | "semibold" | "extrabold" | undefined;
2
+ size: NonNullable<import("@spark-web/theme/src/themes/_types/typography").TypographySizing>;
3
+ tone: NonNullable<string | number>;
4
+ weight: NonNullable<"medium" | "light" | "bold" | "black" | "thin" | "extralight" | "regular" | "semibold" | "extrabold" | undefined> | undefined;
6
5
  } | undefined>;
7
6
  export declare function useTextContext(): {
8
- size: import("@spark-web/theme/src/themes/_types/typography").TypographySizing;
9
- tone: string | number;
10
- weight: "medium" | "light" | "bold" | "thin" | "black" | "extralight" | "regular" | "semibold" | "extrabold" | undefined;
7
+ size: NonNullable<import("@spark-web/theme/src/themes/_types/typography").TypographySizing>;
8
+ tone: NonNullable<string | number>;
9
+ weight: NonNullable<"medium" | "light" | "bold" | "black" | "thin" | "extralight" | "regular" | "semibold" | "extrabold" | undefined> | undefined;
11
10
  } | undefined;
@@ -1,6 +1,6 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import type { UseTextProps } from "./use-text.js";
3
- declare type DefaultTextProps = {
3
+ type DefaultTextProps = {
4
4
  size?: NonNullable<UseTextProps['size']>;
5
5
  tone?: NonNullable<UseTextProps['tone']>;
6
6
  weight?: NonNullable<UseTextProps['weight']>;
@@ -9,8 +9,8 @@ export declare function DefaultTextPropsProvider({ children, size, tone, weight,
9
9
  children: ReactNode;
10
10
  }): import("@emotion/react/jsx-runtime").JSX.Element;
11
11
  export declare const useDefaultTextProps: ({ size: sizeProp, tone: toneProp, weight: weightProp, }: DefaultTextProps) => {
12
- size: import("@spark-web/theme/src/themes/_types/typography").TypographySizing;
13
- tone: string | number;
14
- weight: "medium" | "light" | "bold" | "thin" | "black" | "extralight" | "regular" | "semibold" | "extrabold" | undefined;
12
+ size: NonNullable<import("@spark-web/theme/src/themes/_types/typography").TypographySizing>;
13
+ tone: NonNullable<string | number>;
14
+ weight: NonNullable<"medium" | "light" | "bold" | "black" | "thin" | "extralight" | "regular" | "semibold" | "extrabold" | undefined> | undefined;
15
15
  };
16
16
  export {};
@@ -3,6 +3,7 @@ export { DefaultTextPropsProvider, useDefaultTextProps, } from "./default-text-p
3
3
  export { Strong } from "./strong.js";
4
4
  export { Text } from "./text.js";
5
5
  export { useForegroundTone } from "./use-foreground-tone.js";
6
+ export { useNumberOfLines } from "./use-number-of-lines.js";
6
7
  export { useOverflowStrategy } from "./use-overflow-strategy.js";
7
8
  export { createTextStyles, useText } from "./use-text.js";
8
9
  export type { StrongProps } from "./strong.js";
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
- export declare type StrongProps = {
2
+ export type StrongProps = {
3
3
  children: ReactNode;
4
4
  };
5
5
  export declare const Strong: ({ children }: StrongProps) => import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,24 +1,23 @@
1
- /** @jsxImportSource @emotion/react */
2
1
  import type { CSSObject } from '@emotion/react';
3
2
  import type { BoxProps } from '@spark-web/box';
4
3
  import type { DataAttributeMap } from '@spark-web/utils/internal';
5
4
  import type { CSSProperties, ReactNode } from 'react';
6
5
  import type { TextOverflowStrategy } from "./use-overflow-strategy.js";
7
6
  import type { UseTextProps } from "./use-text.js";
8
- declare type InlineProps = {
7
+ type InlineProps = {
9
8
  align?: never;
10
9
  /** Display as an inline element. */
11
10
  inline?: boolean;
12
11
  overflowStrategy?: never;
13
12
  };
14
- declare type BlockProps = {
13
+ type BlockProps = {
15
14
  /** The horizontal alignment. */
16
15
  align?: 'left' | 'center' | 'right';
17
16
  inline?: never;
18
17
  /** Manage how text behaves with regard to overflow. */
19
18
  overflowStrategy?: TextOverflowStrategy;
20
19
  };
21
- export declare type TextProps = Partial<UseTextProps> & {
20
+ export type TextProps = Partial<UseTextProps> & {
22
21
  /** The text content. */
23
22
  children?: ReactNode;
24
23
  /** Customizes the component element. */
@@ -31,9 +30,12 @@ export declare type TextProps = Partial<UseTextProps> & {
31
30
  tabularNumbers?: boolean;
32
31
  /** Transform the text casing. */
33
32
  transform?: CSSProperties['textTransform'];
33
+ /** Truncate the text with an ellipsis after computing the text layout, including line wrapping,
34
+ * such that the total number of lines does not exceed this number. */
35
+ numberOfLines?: number;
34
36
  } & (InlineProps | BlockProps);
35
- export declare const Text: <Comp extends import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> = "div">(props: {
37
+ export declare const Text: <Comp extends import("react").ElementType = "div">(props: {
36
38
  as?: Comp | undefined;
37
- ref?: import("react").Ref<Comp extends "symbol" | "text" | "svg" | "animate" | "animateMotion" | "animateTransform" | "circle" | "clipPath" | "defs" | "desc" | "ellipse" | "feBlend" | "feColorMatrix" | "feComponentTransfer" | "feComposite" | "feConvolveMatrix" | "feDiffuseLighting" | "feDisplacementMap" | "feDistantLight" | "feDropShadow" | "feFlood" | "feFuncA" | "feFuncB" | "feFuncG" | "feFuncR" | "feGaussianBlur" | "feImage" | "feMerge" | "feMergeNode" | "feMorphology" | "feOffset" | "fePointLight" | "feSpecularLighting" | "feSpotLight" | "feTile" | "feTurbulence" | "filter" | "foreignObject" | "g" | "image" | "line" | "linearGradient" | "marker" | "mask" | "metadata" | "mpath" | "path" | "pattern" | "polygon" | "polyline" | "radialGradient" | "rect" | "set" | "stop" | "switch" | "textPath" | "tspan" | "use" | "view" | keyof HTMLElementTagNameMap ? (HTMLElementTagNameMap & Pick<SVGElementTagNameMap, "symbol" | "text" | "svg" | "animate" | "animateMotion" | "animateTransform" | "circle" | "clipPath" | "defs" | "desc" | "ellipse" | "feBlend" | "feColorMatrix" | "feComponentTransfer" | "feComposite" | "feConvolveMatrix" | "feDiffuseLighting" | "feDisplacementMap" | "feDistantLight" | "feDropShadow" | "feFlood" | "feFuncA" | "feFuncB" | "feFuncG" | "feFuncR" | "feGaussianBlur" | "feImage" | "feMerge" | "feMergeNode" | "feMorphology" | "feOffset" | "fePointLight" | "feSpecularLighting" | "feSpotLight" | "feTile" | "feTurbulence" | "filter" | "foreignObject" | "g" | "image" | "line" | "linearGradient" | "marker" | "mask" | "metadata" | "mpath" | "path" | "pattern" | "polygon" | "polyline" | "radialGradient" | "rect" | "set" | "stop" | "switch" | "textPath" | "tspan" | "use" | "view">)[Comp] : Comp extends new (...args: any) => any ? InstanceType<Comp> : undefined> | undefined;
38
- } & Omit<import("react").PropsWithoutRef<import("react").ComponentProps<Comp>>, "as"> & TextProps) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
39
+ ref?: import("react").Ref<Comp extends "symbol" | "text" | "clipPath" | "filter" | "mask" | "marker" | "svg" | "animate" | "animateMotion" | "animateTransform" | "circle" | "defs" | "desc" | "ellipse" | "feBlend" | "feColorMatrix" | "feComponentTransfer" | "feComposite" | "feConvolveMatrix" | "feDiffuseLighting" | "feDisplacementMap" | "feDistantLight" | "feDropShadow" | "feFlood" | "feFuncA" | "feFuncB" | "feFuncG" | "feFuncR" | "feGaussianBlur" | "feImage" | "feMerge" | "feMergeNode" | "feMorphology" | "feOffset" | "fePointLight" | "feSpecularLighting" | "feSpotLight" | "feTile" | "feTurbulence" | "foreignObject" | "g" | "image" | "line" | "linearGradient" | "metadata" | "mpath" | "path" | "pattern" | "polygon" | "polyline" | "radialGradient" | "rect" | "set" | "stop" | "switch" | "textPath" | "tspan" | "use" | "view" | keyof HTMLElementTagNameMap ? (HTMLElementTagNameMap & Pick<SVGElementTagNameMap, "symbol" | "text" | "clipPath" | "filter" | "mask" | "marker" | "svg" | "animate" | "animateMotion" | "animateTransform" | "circle" | "defs" | "desc" | "ellipse" | "feBlend" | "feColorMatrix" | "feComponentTransfer" | "feComposite" | "feConvolveMatrix" | "feDiffuseLighting" | "feDisplacementMap" | "feDistantLight" | "feDropShadow" | "feFlood" | "feFuncA" | "feFuncB" | "feFuncG" | "feFuncR" | "feGaussianBlur" | "feImage" | "feMerge" | "feMergeNode" | "feMorphology" | "feOffset" | "fePointLight" | "feSpecularLighting" | "feSpotLight" | "feTile" | "feTurbulence" | "foreignObject" | "g" | "image" | "line" | "linearGradient" | "metadata" | "mpath" | "path" | "pattern" | "polygon" | "polyline" | "radialGradient" | "rect" | "set" | "stop" | "switch" | "textPath" | "tspan" | "use" | "view">)[Comp] : Comp extends new (...args: any) => any ? InstanceType<Comp> : undefined> | undefined;
40
+ } & (Omit<import("react").PropsWithoutRef<import("react").ComponentProps<Comp>>, "as"> & TextProps)) => import("react").ReactElement;
39
41
  export {};
@@ -1,3 +1,3 @@
1
1
  import type { SparkTheme } from '@spark-web/theme';
2
- export declare type ForegroundTone = keyof Omit<SparkTheme['color']['foreground'], 'neutralInverted' | 'mutedInverted'>;
2
+ export type ForegroundTone = keyof Omit<SparkTheme['color']['foreground'], 'neutralInverted' | 'mutedInverted'>;
3
3
  export declare function useForegroundTone(tone: ForegroundTone): string;
@@ -0,0 +1,2 @@
1
+ import type { CSSProperties } from 'react';
2
+ export declare const useNumberOfLines: (numberOfLines?: number) => CSSProperties;
@@ -15,7 +15,7 @@ declare const strategyMap: {
15
15
  readonly wordWrap: "break-word";
16
16
  };
17
17
  };
18
- export declare type TextOverflowStrategy = keyof typeof strategyMap;
18
+ export type TextOverflowStrategy = keyof typeof strategyMap;
19
19
  export declare function useOverflowStrategy(strategy?: TextOverflowStrategy): {
20
20
  readonly whiteSpace: "nowrap";
21
21
  } | {
@@ -1,6 +1,6 @@
1
1
  import type { SparkTextDefinition, SparkTheme } from '@spark-web/theme';
2
2
  import type { ForegroundTone } from "./use-foreground-tone.js";
3
- export declare type UseTextProps = {
3
+ export type UseTextProps = {
4
4
  /** Apply leading-trim styles. */
5
5
  baseline?: boolean;
6
6
  /** The size of the text. */
@@ -1,2 +1,2 @@
1
- export * from "./declarations/src/index";
1
+ export * from "./declarations/src/index.js";
2
2
  //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3Bhcmstd2ViLXRleHQuY2pzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuL2RlY2xhcmF0aW9ucy9zcmMvaW5kZXguZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSJ9
@@ -66,6 +66,23 @@ var Strong = function Strong(_ref) {
66
66
  });
67
67
  };
68
68
 
69
+ var useNumberOfLines = function useNumberOfLines(numberOfLines) {
70
+ if (!numberOfLines) {
71
+ return {};
72
+ }
73
+ return {
74
+ overflow: 'hidden',
75
+ display: '-webkit-box',
76
+ WebkitLineClamp: numberOfLines,
77
+ lineClamp: numberOfLines,
78
+ WebkitBoxOrient: 'vertical',
79
+ textOverflow: 'ellipsis',
80
+ overflowWrap: 'break-word',
81
+ wordBreak: 'break-word',
82
+ wordWrap: 'break-word'
83
+ };
84
+ };
85
+
69
86
  var strategyMap = {
70
87
  truncate: {
71
88
  display: 'block',
@@ -171,7 +188,7 @@ function createTextStyles(_ref2) {
171
188
  }, leadingTrim);
172
189
  }
173
190
 
174
- var _excluded = ["as", "children", "data", "id", "align", "baseline", "css", "inline", "overflowStrategy", "size", "tabularNumbers", "tone", "transform", "weight"];
191
+ var _excluded = ["as", "children", "data", "id", "align", "baseline", "css", "inline", "overflowStrategy", "size", "tabularNumbers", "tone", "transform", "weight", "numberOfLines"];
175
192
  var Text = ts.forwardRefWithAs(function (_ref, forwardedRef) {
176
193
  var as = _ref.as,
177
194
  children = _ref.children,
@@ -187,6 +204,7 @@ var Text = ts.forwardRefWithAs(function (_ref, forwardedRef) {
187
204
  toneProp = _ref.tone,
188
205
  transform = _ref.transform,
189
206
  weightProp = _ref.weight,
207
+ numberOfLines = _ref.numberOfLines,
190
208
  consumerProps = _objectWithoutProperties(_ref, _excluded);
191
209
  var overflowStyles = useOverflowStrategy(overflowStrategy);
192
210
  var textContext = useTextContext();
@@ -205,6 +223,7 @@ var Text = ts.forwardRefWithAs(function (_ref, forwardedRef) {
205
223
  tone: tone,
206
224
  weight: weight
207
225
  });
226
+ var numberOfLinesStyle = useNumberOfLines(numberOfLines);
208
227
  var styles = [textStyles, {
209
228
  display: inline ? 'inline' : 'block',
210
229
  fontVariantNumeric: tabularNumbers ? 'tabular-nums' : undefined,
@@ -225,12 +244,21 @@ var Text = ts.forwardRefWithAs(function (_ref, forwardedRef) {
225
244
  }
226
245
 
227
246
  // prepare block variant
228
- var content = overflowStrategy ?
229
- // eslint-disable-next-line react/no-unknown-property
230
- jsxRuntime.jsx("span", {
231
- css: react$1.css(overflowStyles),
232
- children: children
233
- }) : children;
247
+ var content = function content() {
248
+ if (overflowStrategy) {
249
+ return jsxRuntime.jsx("span", {
250
+ css: react$1.css(overflowStyles),
251
+ children: children
252
+ });
253
+ }
254
+ if (numberOfLines) {
255
+ return jsxRuntime.jsx("span", {
256
+ style: numberOfLinesStyle,
257
+ children: children
258
+ });
259
+ }
260
+ return children;
261
+ };
234
262
  var textContextValue = react.useMemo(function () {
235
263
  return {
236
264
  size: size,
@@ -246,7 +274,7 @@ var Text = ts.forwardRefWithAs(function (_ref, forwardedRef) {
246
274
  ref: forwardedRef,
247
275
  id: id,
248
276
  css: react$1.css(styles, cssProps),
249
- children: content
277
+ children: content()
250
278
  }))
251
279
  });
252
280
  });
@@ -257,6 +285,7 @@ exports.Text = Text;
257
285
  exports.createTextStyles = createTextStyles;
258
286
  exports.useDefaultTextProps = useDefaultTextProps;
259
287
  exports.useForegroundTone = useForegroundTone;
288
+ exports.useNumberOfLines = useNumberOfLines;
260
289
  exports.useOverflowStrategy = useOverflowStrategy;
261
290
  exports.useText = useText;
262
291
  exports.useTextContext = useTextContext;
@@ -66,6 +66,23 @@ var Strong = function Strong(_ref) {
66
66
  });
67
67
  };
68
68
 
69
+ var useNumberOfLines = function useNumberOfLines(numberOfLines) {
70
+ if (!numberOfLines) {
71
+ return {};
72
+ }
73
+ return {
74
+ overflow: 'hidden',
75
+ display: '-webkit-box',
76
+ WebkitLineClamp: numberOfLines,
77
+ lineClamp: numberOfLines,
78
+ WebkitBoxOrient: 'vertical',
79
+ textOverflow: 'ellipsis',
80
+ overflowWrap: 'break-word',
81
+ wordBreak: 'break-word',
82
+ wordWrap: 'break-word'
83
+ };
84
+ };
85
+
69
86
  var strategyMap = {
70
87
  truncate: {
71
88
  display: 'block',
@@ -171,7 +188,7 @@ function createTextStyles(_ref2) {
171
188
  }, leadingTrim);
172
189
  }
173
190
 
174
- var _excluded = ["as", "children", "data", "id", "align", "baseline", "css", "inline", "overflowStrategy", "size", "tabularNumbers", "tone", "transform", "weight"];
191
+ var _excluded = ["as", "children", "data", "id", "align", "baseline", "css", "inline", "overflowStrategy", "size", "tabularNumbers", "tone", "transform", "weight", "numberOfLines"];
175
192
  var Text = ts.forwardRefWithAs(function (_ref, forwardedRef) {
176
193
  var as = _ref.as,
177
194
  children = _ref.children,
@@ -187,6 +204,7 @@ var Text = ts.forwardRefWithAs(function (_ref, forwardedRef) {
187
204
  toneProp = _ref.tone,
188
205
  transform = _ref.transform,
189
206
  weightProp = _ref.weight,
207
+ numberOfLines = _ref.numberOfLines,
190
208
  consumerProps = _objectWithoutProperties(_ref, _excluded);
191
209
  var overflowStyles = useOverflowStrategy(overflowStrategy);
192
210
  var textContext = useTextContext();
@@ -205,6 +223,7 @@ var Text = ts.forwardRefWithAs(function (_ref, forwardedRef) {
205
223
  tone: tone,
206
224
  weight: weight
207
225
  });
226
+ var numberOfLinesStyle = useNumberOfLines(numberOfLines);
208
227
  var styles = [textStyles, {
209
228
  display: inline ? 'inline' : 'block',
210
229
  fontVariantNumeric: tabularNumbers ? 'tabular-nums' : undefined,
@@ -225,12 +244,21 @@ var Text = ts.forwardRefWithAs(function (_ref, forwardedRef) {
225
244
  }
226
245
 
227
246
  // prepare block variant
228
- var content = overflowStrategy ?
229
- // eslint-disable-next-line react/no-unknown-property
230
- jsxRuntime.jsx("span", {
231
- css: react$1.css(overflowStyles),
232
- children: children
233
- }) : children;
247
+ var content = function content() {
248
+ if (overflowStrategy) {
249
+ return jsxRuntime.jsx("span", {
250
+ css: react$1.css(overflowStyles),
251
+ children: children
252
+ });
253
+ }
254
+ if (numberOfLines) {
255
+ return jsxRuntime.jsx("span", {
256
+ style: numberOfLinesStyle,
257
+ children: children
258
+ });
259
+ }
260
+ return children;
261
+ };
234
262
  var textContextValue = react.useMemo(function () {
235
263
  return {
236
264
  size: size,
@@ -246,7 +274,7 @@ var Text = ts.forwardRefWithAs(function (_ref, forwardedRef) {
246
274
  ref: forwardedRef,
247
275
  id: id,
248
276
  css: react$1.css(styles, cssProps),
249
- children: content
277
+ children: content()
250
278
  }))
251
279
  });
252
280
  });
@@ -257,6 +285,7 @@ exports.Text = Text;
257
285
  exports.createTextStyles = createTextStyles;
258
286
  exports.useDefaultTextProps = useDefaultTextProps;
259
287
  exports.useForegroundTone = useForegroundTone;
288
+ exports.useNumberOfLines = useNumberOfLines;
260
289
  exports.useOverflowStrategy = useOverflowStrategy;
261
290
  exports.useText = useText;
262
291
  exports.useTextContext = useTextContext;
@@ -62,6 +62,23 @@ var Strong = function Strong(_ref) {
62
62
  });
63
63
  };
64
64
 
65
+ var useNumberOfLines = function useNumberOfLines(numberOfLines) {
66
+ if (!numberOfLines) {
67
+ return {};
68
+ }
69
+ return {
70
+ overflow: 'hidden',
71
+ display: '-webkit-box',
72
+ WebkitLineClamp: numberOfLines,
73
+ lineClamp: numberOfLines,
74
+ WebkitBoxOrient: 'vertical',
75
+ textOverflow: 'ellipsis',
76
+ overflowWrap: 'break-word',
77
+ wordBreak: 'break-word',
78
+ wordWrap: 'break-word'
79
+ };
80
+ };
81
+
65
82
  var strategyMap = {
66
83
  truncate: {
67
84
  display: 'block',
@@ -167,7 +184,7 @@ function createTextStyles(_ref2) {
167
184
  }, leadingTrim);
168
185
  }
169
186
 
170
- var _excluded = ["as", "children", "data", "id", "align", "baseline", "css", "inline", "overflowStrategy", "size", "tabularNumbers", "tone", "transform", "weight"];
187
+ var _excluded = ["as", "children", "data", "id", "align", "baseline", "css", "inline", "overflowStrategy", "size", "tabularNumbers", "tone", "transform", "weight", "numberOfLines"];
171
188
  var Text = forwardRefWithAs(function (_ref, forwardedRef) {
172
189
  var as = _ref.as,
173
190
  children = _ref.children,
@@ -183,6 +200,7 @@ var Text = forwardRefWithAs(function (_ref, forwardedRef) {
183
200
  toneProp = _ref.tone,
184
201
  transform = _ref.transform,
185
202
  weightProp = _ref.weight,
203
+ numberOfLines = _ref.numberOfLines,
186
204
  consumerProps = _objectWithoutProperties(_ref, _excluded);
187
205
  var overflowStyles = useOverflowStrategy(overflowStrategy);
188
206
  var textContext = useTextContext();
@@ -201,6 +219,7 @@ var Text = forwardRefWithAs(function (_ref, forwardedRef) {
201
219
  tone: tone,
202
220
  weight: weight
203
221
  });
222
+ var numberOfLinesStyle = useNumberOfLines(numberOfLines);
204
223
  var styles = [textStyles, {
205
224
  display: inline ? 'inline' : 'block',
206
225
  fontVariantNumeric: tabularNumbers ? 'tabular-nums' : undefined,
@@ -221,12 +240,21 @@ var Text = forwardRefWithAs(function (_ref, forwardedRef) {
221
240
  }
222
241
 
223
242
  // prepare block variant
224
- var content = overflowStrategy ?
225
- // eslint-disable-next-line react/no-unknown-property
226
- jsx("span", {
227
- css: css(overflowStyles),
228
- children: children
229
- }) : children;
243
+ var content = function content() {
244
+ if (overflowStrategy) {
245
+ return jsx("span", {
246
+ css: css(overflowStyles),
247
+ children: children
248
+ });
249
+ }
250
+ if (numberOfLines) {
251
+ return jsx("span", {
252
+ style: numberOfLinesStyle,
253
+ children: children
254
+ });
255
+ }
256
+ return children;
257
+ };
230
258
  var textContextValue = useMemo(function () {
231
259
  return {
232
260
  size: size,
@@ -242,9 +270,9 @@ var Text = forwardRefWithAs(function (_ref, forwardedRef) {
242
270
  ref: forwardedRef,
243
271
  id: id,
244
272
  css: css(styles, cssProps),
245
- children: content
273
+ children: content()
246
274
  }))
247
275
  });
248
276
  });
249
277
 
250
- export { DefaultTextPropsProvider, Strong, Text, createTextStyles, useDefaultTextProps, useForegroundTone, useOverflowStrategy, useText, useTextContext };
278
+ export { DefaultTextPropsProvider, Strong, Text, createTextStyles, useDefaultTextProps, useForegroundTone, useNumberOfLines, useOverflowStrategy, useText, useTextContext };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spark-web/text",
3
- "version": "5.3.0-rc.0",
3
+ "version": "5.3.1",
4
4
  "homepage": "https://github.com/brighte-labs/spark-web#readme",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,22 +11,23 @@
11
11
  "module": "dist/spark-web-text.esm.js",
12
12
  "files": [
13
13
  "CHANGELOG.md",
14
+ "CLAUDE.md",
14
15
  "dist",
15
16
  "README.md"
16
17
  ],
17
18
  "dependencies": {
18
19
  "@babel/runtime": "^7.25.0",
19
20
  "@emotion/react": "^11.14.0",
20
- "@spark-web/box": "^6.0.0-rc.0",
21
- "@spark-web/theme": "^5.12.0-rc.0",
22
- "@spark-web/utils": "^5.1.0-rc.0"
21
+ "@spark-web/box": "^6.0.1",
22
+ "@spark-web/theme": "^5.13.0",
23
+ "@spark-web/utils": "^5.1.0"
23
24
  },
24
25
  "devDependencies": {
25
26
  "@types/react": "^19.1.0",
26
27
  "react": "^19.1.0"
27
28
  },
28
29
  "peerDependencies": {
29
- "react": ">=19.1.0"
30
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
30
31
  },
31
32
  "engines": {
32
33
  "node": ">=14"