Skip to content

ConstrainedText: align the text, and style it without a nested Text - #1221

Merged
bert-e merged 1 commit into
development/1.0from
improvement/constrainedtext-align-text-props
Sep 17, 2026
Merged

bert-e merged 1 commit into
development/1.0from
improvement/constrainedtext-align-text-props

Conversation

@JeanMarcMilletScality

@JeanMarcMilletScality JeanMarcMilletScality commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

TL;DR — ConstrainedText could only inherit its alignment or be forced to centre, and ignored every Text styling prop but color; it now takes an explicit align and the whole Text prop set.

align start align center align end

Constrained Text → Default story, text="Aligned" in its fixed 100px box — the dashed outline is a capture-time annotation marking the box edges, not something the component draws. align set to start, center, end; measured text offsets inside the box are 0/53.5px, 26.8/26.8px and 53.5/0px.

Context / Why

ConstrainedText is the library's truncate-and-tooltip primitive, and two things kept callers from reaching for it.

Alignment could not be stated — only inherited from the container, or forced to centre by centered — so a caller wanting the text on a specific edge had to arrange it from the outside.

And styling arrived through two doors: color was a prop, but variant, isEmphazed, isGentleEmphazed and compact were only reachable by nesting a second <Text> inside the text prop.

// before
<ConstrainedText
  color="textSecondary"
  text={<Text variant="Smaller">{content}</Text>}
/>

// after
<ConstrainedText
  color="textSecondary"
  variant="Smaller"
  text={content}
/>

Since the prop is named text, passing a string is the obvious reading — and it silently gave you the default size.

🧩 Approach

One prop surface, rewritten once. align is added, centered stays as a deprecated alias that resolves to it, and TextProps is mixed into the props and forwarded to the internal wrapper:

// before
type Props = {
  text: string | number | JSX.Element | JSX.Element[];
  lineClamp?: number;
  centered?: boolean;
  color?: keyof CoreUITheme;
};

// after
type Props = {
  text: string | number | JSX.Element | JSX.Element[];
  lineClamp?: number;
  align?: 'start' | 'center' | 'end';        // ←
  /** @deprecated use `align="center"` instead. */
  centered?: boolean;
} & TextProps;                                // ←

color is not dropped — it arrives via TextProps instead, so every existing call keeps compiling. With neither align nor centered set the rule stays text-align: inherit, exactly as before.

The component used to build its <Text><ConstrainedTextContainer> subtree twice, once in each branch of the tooltip conditional, through a four-positional-argument helper. It is now built once and wrapped conditionally, so a forwarded prop cannot land on the tooltip branch and miss the bare one.

Removing the file's // @ts-nocheck surfaced a dead import: $PropertyType from utility-types, a package that is not a dependency of this repo and had no other importer. It never failed at runtime because TypeScript elides type-only imports. It is replaced with a native indexed access type.

The nested-<Text> form still works — an inner element's own props win over the wrapper's — so the one in-repo call site written that way (charts/common/SharedComponents.tsx) is untouched and keeps rendering identically.

📷 Screenshots

variant Smaller with a plain string text

Same story and box. text="Aligned" passed as a plain string with variant="Smaller" — computed font-size 9.94px against the 14px default. Before this change variant was ignored unless a <Text> was nested inside text.

🔍 Review focus

  • 🟡 constrainedtext/Constrainedtext.component.tsx › ConstrainedText — the ...textProps rest spread forwards anything not destructured to the internal Text, where extra props were previously dropped. TypeScript rejects unknown props for a typed caller, so the guard here is the type, not the runtime.
  • 🟡 constrainedtext/Constrainedtext.component.tsx › ConstrainedTextContainer — the text-align fallback has to stay inherit when neither prop is set; an in-repo caller (the Heatmap row-label gutter) relies on that inheritance rather than passing alignment itself.
  • ⚪ text/Text.component.tsx › TextProps — the type was declared but not exported, and is now exported from the package index too.

🧪 How to test

  1. npm run storybook, then open Components → Constrained Text → Default. The text sits in a fixed 100px-wide box.
  2. In the Controls panel set text to something short (Aligned) and step align through start, center and end — the text moves to the matching edge of the box.
  3. Clear align and tick centered — still centred, since the deprecated alias resolves to align: 'center'.
  4. Untick centered, leave text a plain string, and set variant to Smaller — the text gets smaller. Before this change that needed a <Text> nested inside text.
  5. Restore the long default phrase and hover it — the tooltip still shows the full text, and Constrained Text On Multiple Lines still clamps at two lines.

Follow-up

Two parts of this component's known gaps are deliberately not in this PR:

  • BlockTooltip is still unconditionally width: stretch, so the label fills its container rather than being shrink-to-fit, and a flex parent's justify-content cannot govern it. Five in-repo call sites were written against that, so changing it needs a before/after pass over each.
  • Overflow is still detected once, via a ref callback keyed on text. There is no ResizeObserver, so a container that resizes after mount can leave the tooltip stale — which matters most where a column resizes with its content.

Table headers still truncate without a tooltip; adopting this component there is the follow-on that the align prop was needed for.

What changed

Three files. The component itself carries the prop-surface change and the @ts-nocheck removal. Text.component.tsx changes by one word (TextProps becomes exported) and index.ts by one line (re-exporting that type for consumers typing their own wrappers).

No call site is changed, so no story or test needed updating — this is an additive prop surface, verified against the existing Constrained Text stories rather than a new one.

🤖 Generated with Claude Code

… styling props

Alignment could only be inherited from the container or forced to centre, so a
caller had no way to state it. Add `align: 'start' | 'center' | 'end'`, keeping
`centered` as a deprecated alias; with neither set the rule stays `inherit`.

Accept the Text props natively and forward them to the internal wrapper, so
`variant` and its neighbours no longer need a second Text nested inside `text`
while `color` arrives as a prop.

Removing the file's `// @ts-nocheck` surfaced an import of `utility-types`,
which is not a dependency of this package and had no other importer. It is
replaced with a native indexed access type.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@bert-e

bert-e commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Hello jeanmarcmilletscality,

My role is to assist you with the merge of this
pull request. Please type @bert-e help to get information
on this process, or consult the user documentation.

Available options
name description privileged authored
/after_pull_request Wait for the given pull request id to be merged before continuing with the current one.
/bypass_author_approval Bypass the pull request author's approval ⭐
/bypass_build_status Bypass the build and test status ⭐
/bypass_commit_size Bypass the check on the size of the changeset TBA ⭐
/bypass_incompatible_branch Bypass the check on the source branch prefix ⭐
/bypass_jira_check Bypass the Jira issue check ⭐
/bypass_peer_approval Bypass the pull request peers' approval ⭐
/bypass_leader_approval Bypass the pull request leaders' approval ⭐
/bypass_source_branch_lineage Bypass the cross-branch contamination check ⭐
/approve Instruct Bert-E that the author has approved the pull request. ✍️
/create_pull_requests Allow the creation of integration pull requests.
/create_integration_branches Allow the creation of integration branches.
/no_octopus Prevent Wall-E from doing any octopus merge and use multiple consecutive merge instead
/unanimity Change review acceptance criteria from one reviewer at least to all reviewers
/wait Instruct Bert-E not to run until further notice.
Available commands
name description privileged
/help Print Bert-E's manual in the pull request.
/status Print Bert-E's current status in the pull request.
/clear Remove all comments from Bert-E from the history TBA
/retry Re-start a fresh build TBA
/build Re-start a fresh build TBA
/force_reset Delete integration branches & pull requests, and restart merge process from the beginning.
/reset Try to remove integration branches unless there are commits on them which do not appear on the source branch.

Status report is not available.

@bert-e

bert-e commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Waiting for approval

The following approvals are needed before I can proceed with the merge:

  • the author

  • one peer

Peer approvals must include at least 1 approval from the following list:

@JeanMarcMilletScality
JeanMarcMilletScality marked this pull request as ready for review September 15, 2026 14:40
@JeanMarcMilletScality

Copy link
Copy Markdown
Contributor Author

/approve

@bert-e

bert-e commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

In the queue

The changeset has received all authorizations and has been added to the
relevant queue(s). The queue(s) will be merged in the target development
branch(es) as soon as builds have passed.

The changeset will be merged in:

  • ✔️ development/1.0

There is no action required on your side. You will be notified here once
the changeset has been merged. In the unlikely event that the changeset
fails permanently on the queue, a member of the admin team will
contact you to help resolve the matter.

IMPORTANT

Please do not attempt to modify this pull request.

  • Any commit you add on the source branch will trigger a new cycle after the
    current queue is merged.
  • Any commit you add on one of the integration branches will be lost.

If you need this pull request to be removed from the queue, please contact a
member of the admin team now.

The following options are set: approve

@bert-e

bert-e commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

I have successfully merged the changeset of this pull request
into targetted development branches:

  • ✔️ development/1.0

Please check the status of the associated issue None.

Goodbye jeanmarcmilletscality.

@bert-e
bert-e merged commit 2584c23 into development/1.0 Sep 17, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants