@recursica/mui-adapter 0.34.4 → 0.36.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 +22 -0
- package/dist/index.d.ts +38 -38
- package/dist/mui-adapter.cjs +14 -14
- package/dist/mui-adapter.cjs.map +1 -1
- package/dist/mui-adapter.css +1 -1
- package/dist/mui-adapter.js +1884 -1882
- package/dist/mui-adapter.js.map +1 -1
- package/package.json +2 -2
- package/src/Introduction.stories.tsx +15 -15
- package/src/OverStyling.tsx +3 -3
- package/src/Version.tsx +3 -3
- package/src/components/Autocomplete/AUTOCOMPLETE_IMPLEMENTATION_NOTES.md +6 -1
- package/src/components/Autocomplete/Autocomplete.module.css +4 -1
- package/src/components/Button/BUTTON_IMPLEMENTATION_NOTES.md +12 -0
- package/src/components/Button/Button.module.css +4 -1
- package/src/components/Card/USAGE.md +1 -1
- package/src/components/Dropdown/DROPDOWN_IMPLEMENTATION_NOTES.md +6 -1
- package/src/components/Dropdown/Dropdown.module.css +4 -1
- package/src/components/{Title/Title.stories.tsx → Heading/Heading.stories.tsx} +13 -13
- package/src/components/Heading/Heading.test.tsx +1 -0
- package/src/components/{Title/Title.tsx → Heading/Heading.tsx} +5 -5
- package/src/components/{Title → Heading}/USAGE.md +5 -5
- package/src/components/Heading/index.ts +1 -0
- package/src/components/Modal/MODAL_IMPLEMENTATION_NOTES.md +12 -0
- package/src/components/Modal/Modal.module.css +4 -1
- package/src/components/Panel/PANEL_IMPLEMENTATION_NOTES.md +10 -0
- package/src/components/Panel/Panel.module.css +4 -1
- package/src/components/Text/Text.stories.tsx +1 -1
- package/src/components/Typography/TYPOGRAPHY_IMPLEMENTATION_NOTES.md +17 -0
- package/src/components/Typography/Typography.module.css +13 -0
- package/src/components/Typography/Typography.tsx +4 -3
- package/src/components/index.ts +1 -1
- package/src/index.ts +3 -3
- package/src/components/Title/Title.test.tsx +0 -1
- package/src/components/Title/index.ts +0 -1
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"url": "git+https://github.com/borderux/recursica.git",
|
|
14
14
|
"directory": "packages/mui-adapter"
|
|
15
15
|
},
|
|
16
|
-
"version": "0.
|
|
16
|
+
"version": "0.36.0",
|
|
17
17
|
"publishConfig": {
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"vitest": "^3.2.4"
|
|
108
108
|
},
|
|
109
109
|
"dependencies": {
|
|
110
|
-
"@recursica/adapter-common": "^0.
|
|
110
|
+
"@recursica/adapter-common": "^0.26.0",
|
|
111
111
|
"@recursica/official-release": "^2.8.0",
|
|
112
112
|
"dayjs": "^1.11.21"
|
|
113
113
|
},
|
|
@@ -6,7 +6,7 @@ import { OverStylingInfo } from "./OverStyling";
|
|
|
6
6
|
const DOCS_URL = "https://recursica.com";
|
|
7
7
|
const FORGE_URL = "https://forge.recursica.com";
|
|
8
8
|
|
|
9
|
-
import { Container, Box, Group,
|
|
9
|
+
import { Container, Box, Group, Heading, Text, Link } from "./components";
|
|
10
10
|
|
|
11
11
|
function IntroductionContent() {
|
|
12
12
|
return (
|
|
@@ -14,9 +14,9 @@ function IntroductionContent() {
|
|
|
14
14
|
<Group gap="rec-md" mb={2}>
|
|
15
15
|
<MuiLogo width={40} height={40} />
|
|
16
16
|
<Box>
|
|
17
|
-
<
|
|
17
|
+
<Heading order={1} m={0}>
|
|
18
18
|
Recursica Design System (MUI Adapter)
|
|
19
|
-
</
|
|
19
|
+
</Heading>
|
|
20
20
|
<Link href="https://mui.com" target="_blank" rel="noreferrer">
|
|
21
21
|
mui.com
|
|
22
22
|
</Link>
|
|
@@ -29,9 +29,9 @@ function IntroductionContent() {
|
|
|
29
29
|
</Text>
|
|
30
30
|
|
|
31
31
|
<Box component="section" sx={{ mb: 4 }}>
|
|
32
|
-
<
|
|
32
|
+
<Heading order={2} mb={1}>
|
|
33
33
|
Looking for another UI Kit?
|
|
34
|
-
</
|
|
34
|
+
</Heading>
|
|
35
35
|
<Text>
|
|
36
36
|
Are you using a different UI Kit (like Mantine)? Recursica provides
|
|
37
37
|
multiple adapters for different frameworks.
|
|
@@ -85,9 +85,9 @@ function IntroductionContent() {
|
|
|
85
85
|
</Box>
|
|
86
86
|
|
|
87
87
|
<Box component="section" sx={{ mb: 4 }}>
|
|
88
|
-
<
|
|
88
|
+
<Heading order={2} mb={1}>
|
|
89
89
|
Installation
|
|
90
|
-
</
|
|
90
|
+
</Heading>
|
|
91
91
|
<Text>To install the MUI adapter in your project, run:</Text>
|
|
92
92
|
<Box
|
|
93
93
|
component="pre"
|
|
@@ -107,9 +107,9 @@ function IntroductionContent() {
|
|
|
107
107
|
</Box>
|
|
108
108
|
|
|
109
109
|
<Box component="section" sx={{ mb: 4 }}>
|
|
110
|
-
<
|
|
110
|
+
<Heading order={2} mb={1}>
|
|
111
111
|
Tokens
|
|
112
|
-
</
|
|
112
|
+
</Heading>
|
|
113
113
|
<Text>
|
|
114
114
|
Raw design tokens (colors, sizes, font weights, opacities, etc.) that
|
|
115
115
|
feed the theme and components. These are the primitive values defined
|
|
@@ -118,9 +118,9 @@ function IntroductionContent() {
|
|
|
118
118
|
</Box>
|
|
119
119
|
|
|
120
120
|
<Box component="section" sx={{ mb: 4 }}>
|
|
121
|
-
<
|
|
121
|
+
<Heading order={2} mb={1}>
|
|
122
122
|
Theme
|
|
123
|
-
</
|
|
123
|
+
</Heading>
|
|
124
124
|
<Text>
|
|
125
125
|
Brand and theme layer built on top of tokens. Typography types,
|
|
126
126
|
dimensions, and layout grids are defined here. Theme uses the tokens
|
|
@@ -130,9 +130,9 @@ function IntroductionContent() {
|
|
|
130
130
|
</Box>
|
|
131
131
|
|
|
132
132
|
<Box component="section" sx={{ mb: 4 }}>
|
|
133
|
-
<
|
|
133
|
+
<Heading order={2} mb={1}>
|
|
134
134
|
Configuring Recursica
|
|
135
|
-
</
|
|
135
|
+
</Heading>
|
|
136
136
|
<Text>
|
|
137
137
|
To modify the Recursica configuration (tokens, brand, theme), go to{" "}
|
|
138
138
|
<Link href={FORGE_URL} target="_blank" rel="noopener noreferrer">
|
|
@@ -143,9 +143,9 @@ function IntroductionContent() {
|
|
|
143
143
|
</Box>
|
|
144
144
|
|
|
145
145
|
<Box component="section" sx={{ mb: 4 }}>
|
|
146
|
-
<
|
|
146
|
+
<Heading order={2} mb={1}>
|
|
147
147
|
Documentation
|
|
148
|
-
</
|
|
148
|
+
</Heading>
|
|
149
149
|
<Text>
|
|
150
150
|
For full documentation, guides, and API reference, visit{" "}
|
|
151
151
|
<Link href={DOCS_URL} target="_blank" rel="noopener noreferrer">
|
package/src/OverStyling.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
Stack,
|
|
6
6
|
Box,
|
|
7
7
|
Text as RawText,
|
|
8
|
-
|
|
8
|
+
Heading,
|
|
9
9
|
Switch as RawSwitch,
|
|
10
10
|
} from "./components";
|
|
11
11
|
import { Button as RawButton } from "./components/Button/Button";
|
|
@@ -31,9 +31,9 @@ export const OverStylingInfo = () => {
|
|
|
31
31
|
|
|
32
32
|
<Divider sx={{ my: 4 }} />
|
|
33
33
|
|
|
34
|
-
<
|
|
34
|
+
<Heading order={6} mb={2}>
|
|
35
35
|
Try It Yourself
|
|
36
|
-
</
|
|
36
|
+
</Heading>
|
|
37
37
|
|
|
38
38
|
<Stack direction="row" alignItems="center" spacing="rec-sm" mb="rec-md">
|
|
39
39
|
<Switch
|
package/src/Version.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ReactMarkdown from "react-markdown";
|
|
2
2
|
import { Paper, Divider } from "@mui/material";
|
|
3
|
-
import { Container,
|
|
3
|
+
import { Container, Heading, Group, Link, Box } from "./components";
|
|
4
4
|
import pkg from "../package.json";
|
|
5
5
|
import changelog from "../CHANGELOG.md?raw";
|
|
6
6
|
|
|
@@ -8,9 +8,9 @@ export const VersionInfo = () => {
|
|
|
8
8
|
return (
|
|
9
9
|
<Container size="md" style={{ padding: "32px 0" }}>
|
|
10
10
|
<Paper variant="outlined" sx={{ p: 4, borderRadius: 2 }}>
|
|
11
|
-
<
|
|
11
|
+
<Heading order={1} mb={1}>
|
|
12
12
|
MUI Adapter v{pkg.version}
|
|
13
|
-
</
|
|
13
|
+
</Heading>
|
|
14
14
|
<Group mb={4} gap="rec-md">
|
|
15
15
|
<Link
|
|
16
16
|
href="https://github.com/borderux/recursica"
|
|
@@ -10,7 +10,12 @@ New CSS classes (`.optionContent`/`.optionIcon`/`.optionText`/`.optionSupporting
|
|
|
10
10
|
|
|
11
11
|
## `wrapItemText`
|
|
12
12
|
|
|
13
|
-
`label`/`supportingText` default to single-line truncation with an ellipsis (`.optionText > *` — `overflow:
|
|
13
|
+
`label`/`supportingText` default to single-line truncation with an ellipsis (`.optionText > *` — `overflow: clip; overflow-clip-margin: 0.35em; text-overflow: ellipsis; white-space: nowrap`). Passing `wrapItemText` adds `.optionTextWrap` alongside `.optionText`, re-enabling wrapping (`white-space: normal; overflow-wrap: anywhere`) for both children — later-cascade-wins, equal specificity. `renderRichOptionContent` takes `wrapItemText` as a third parameter and combines the two class names when it's true.
|
|
14
|
+
|
|
15
|
+
`.optionText > *` used plain `overflow: hidden` until 2026-08-28 (Matt Massey) — it clipped
|
|
16
|
+
descenders (e.g. "g") whenever `text_line-height` is tighter than the font's natural
|
|
17
|
+
ascent+descent. `overflow-clip-margin` gives ink a small bleed allowance while still clipping
|
|
18
|
+
genuinely overflowing text; same project-wide fix as Chip's `CHIP_IMPLEMENTATION_NOTES.md`.
|
|
14
19
|
|
|
15
20
|
## Selected Option Highlight (bug fix)
|
|
16
21
|
|
|
@@ -323,7 +323,10 @@
|
|
|
323
323
|
|
|
324
324
|
/* Default: label/supportingText each truncate to a single line with an ellipsis. */
|
|
325
325
|
.optionText > * {
|
|
326
|
-
overflow: hidden
|
|
326
|
+
overflow: clip; /* HARDCODE: `hidden` clips descenders (e.g. "g") when text_line-height is
|
|
327
|
+
tighter than the font's natural ascent+descent; overflow-clip-margin gives ink a small bleed
|
|
328
|
+
allowance while still clipping genuinely overflowing text (see Chip's IMPLEMENTATION_NOTES.md). */
|
|
329
|
+
overflow-clip-margin: 0.35em;
|
|
327
330
|
text-overflow: ellipsis;
|
|
328
331
|
white-space: nowrap;
|
|
329
332
|
}
|
|
@@ -75,3 +75,15 @@ We explicitly pass `disableRipple` and `disableElevation` to block MUI's dynamic
|
|
|
75
75
|
**Root cause:** `.root` has `width: fit-content` (to hug its own content instead of stretching in flex columns) but no `max-width`. Verified via Playwright: the wrapper measured exactly 250px, but `fit-content` on `.root` still resolved to its 534px `max-content` size — it doesn't reliably clamp against a narrower containing block on its own. Same root cause and identical fix in mantine-adapter.
|
|
76
76
|
|
|
77
77
|
**Fix:** added `max-width: 100%` to `.root`. It's a no-op when the parent is wide enough (confirmed no change to `Default`/`IconOnly`/`TextWithIcon` story widths), and clamps the button to the parent's resolved width when the parent is narrower — at which point the existing `overflow: hidden` (`.root`) + `text-overflow: ellipsis`/`white-space: nowrap` (`.labelText`) take over, exactly as already documented above.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## `.labelText` descender clipping (Matt Massey, 2026-08-28)
|
|
82
|
+
|
|
83
|
+
`.labelText` used plain `overflow: hidden` to make `text-overflow: ellipsis` work, which also
|
|
84
|
+
clips descenders (e.g. the "g" in a long label) whenever `text_line-height` is tighter than the
|
|
85
|
+
font's natural ascent+descent. Switched to `overflow: clip; overflow-clip-margin: 0.35em;` — same
|
|
86
|
+
truncation, but ink can bleed slightly past the line box before it's actually clipped. `.root`'s
|
|
87
|
+
own `overflow: hidden` (the max-width truncation bounding box, above) is untouched — it has
|
|
88
|
+
padding around the label so it isn't tight against the glyphs the way `.labelText` is.
|
|
89
|
+
Project-wide fix; see Chip's `CHIP_IMPLEMENTATION_NOTES.md` for the original discovery.
|
|
@@ -68,7 +68,10 @@
|
|
|
68
68
|
.labelText {
|
|
69
69
|
display: block;
|
|
70
70
|
min-width: 0;
|
|
71
|
-
overflow: hidden
|
|
71
|
+
overflow: clip; /* HARDCODE: `hidden` clips descenders (e.g. "g") when text_line-height is
|
|
72
|
+
tighter than the font's natural ascent+descent; overflow-clip-margin gives ink a small bleed
|
|
73
|
+
allowance while still clipping genuinely overflowing text (see Chip's IMPLEMENTATION_NOTES.md). */
|
|
74
|
+
overflow-clip-margin: 0.35em;
|
|
72
75
|
text-overflow: ellipsis;
|
|
73
76
|
white-space: nowrap;
|
|
74
77
|
font-size: inherit;
|
|
@@ -12,4 +12,9 @@ New CSS classes (`.optionContent`/`.optionIcon`/`.optionText`/`.optionSupporting
|
|
|
12
12
|
|
|
13
13
|
## `wrapItemText`
|
|
14
14
|
|
|
15
|
-
`label`/`supportingText` default to single-line truncation with an ellipsis (`.optionText > *` — `overflow:
|
|
15
|
+
`label`/`supportingText` default to single-line truncation with an ellipsis (`.optionText > *` — `overflow: clip; overflow-clip-margin: 0.35em; text-overflow: ellipsis; white-space: nowrap`). Passing `wrapItemText` adds `.optionTextWrap` alongside `.optionText`, re-enabling wrapping (`white-space: normal; overflow-wrap: anywhere`) for both children — later-cascade-wins, equal specificity. `renderRichOptionContent` takes `wrapItemText` as a third parameter and combines the two class names when it's true. `Dropdown.tsx` exposes this as a public prop; `BareDropdown.tsx` (internal-only, not part of the public `Dropdown`/`AutoComplete` API this was requested for) doesn't take the prop and always truncates.
|
|
16
|
+
|
|
17
|
+
`.optionText > *` used plain `overflow: hidden` until 2026-08-28 (Matt Massey) — it clipped
|
|
18
|
+
descenders (e.g. "g") whenever `text_line-height` is tighter than the font's natural
|
|
19
|
+
ascent+descent. `overflow-clip-margin` gives ink a small bleed allowance while still clipping
|
|
20
|
+
genuinely overflowing text; same project-wide fix as Chip's `CHIP_IMPLEMENTATION_NOTES.md`.
|
|
@@ -454,7 +454,10 @@
|
|
|
454
454
|
|
|
455
455
|
/* Default: label/supportingText each truncate to a single line with an ellipsis. */
|
|
456
456
|
.optionText > * {
|
|
457
|
-
overflow: hidden
|
|
457
|
+
overflow: clip; /* HARDCODE: `hidden` clips descenders (e.g. "g") when text_line-height is
|
|
458
|
+
tighter than the font's natural ascent+descent; overflow-clip-margin gives ink a small bleed
|
|
459
|
+
allowance while still clipping genuinely overflowing text (see Chip's IMPLEMENTATION_NOTES.md). */
|
|
460
|
+
overflow-clip-margin: 0.35em;
|
|
458
461
|
text-overflow: ellipsis;
|
|
459
462
|
white-space: nowrap;
|
|
460
463
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
-
import {
|
|
2
|
+
import { Heading } from "./Heading";
|
|
3
3
|
|
|
4
|
-
const meta: Meta<typeof
|
|
5
|
-
title: "UI-Kit/
|
|
6
|
-
component:
|
|
4
|
+
const meta: Meta<typeof Heading> = {
|
|
5
|
+
title: "UI-Kit/Heading",
|
|
6
|
+
component: Heading,
|
|
7
7
|
tags: ["autodocs"],
|
|
8
8
|
parameters: {
|
|
9
9
|
docs: {
|
|
10
10
|
description: {
|
|
11
11
|
component:
|
|
12
|
-
"The semantic `<
|
|
12
|
+
"The semantic `<Heading>` abstraction intrinsically links pure `h1-h6` tag generation with exact Recursica design boundaries to preserve SEO and screen reader trees uniformly globally.",
|
|
13
13
|
},
|
|
14
14
|
},
|
|
15
15
|
},
|
|
@@ -25,26 +25,26 @@ const meta: Meta<typeof Title> = {
|
|
|
25
25
|
|
|
26
26
|
export default meta;
|
|
27
27
|
|
|
28
|
-
type Story = StoryObj<typeof
|
|
28
|
+
type Story = StoryObj<typeof Heading>;
|
|
29
29
|
|
|
30
30
|
export const Default: Story = {
|
|
31
31
|
args: {
|
|
32
32
|
order: 1,
|
|
33
33
|
children: "Semantic H1 Document Boundary",
|
|
34
34
|
},
|
|
35
|
-
render: ({ ...args }) => <
|
|
35
|
+
render: ({ ...args }) => <Heading {...args} />,
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
export const StaticVariations: Story = {
|
|
39
39
|
args: {},
|
|
40
40
|
render: () => (
|
|
41
41
|
<div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
|
|
42
|
-
<
|
|
43
|
-
<
|
|
44
|
-
<
|
|
45
|
-
<
|
|
46
|
-
<
|
|
47
|
-
<
|
|
42
|
+
<Heading order={1}>H1 Heading</Heading>
|
|
43
|
+
<Heading order={2}>H2 Heading</Heading>
|
|
44
|
+
<Heading order={3}>H3 Heading</Heading>
|
|
45
|
+
<Heading order={4}>H4 Heading</Heading>
|
|
46
|
+
<Heading order={5}>H5 Heading</Heading>
|
|
47
|
+
<Heading order={6}>H6 Heading</Heading>
|
|
48
48
|
</div>
|
|
49
49
|
),
|
|
50
50
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Placeholder for future Heading component tests. Add tests here if/when needed.
|
|
@@ -2,13 +2,13 @@ import React, { forwardRef } from "react";
|
|
|
2
2
|
import { type TypographyProps as MuiTypographyProps } from "@mui/material";
|
|
3
3
|
import { Typography } from "../Typography/Typography";
|
|
4
4
|
import { type RecursicaOverStyled } from "../../utils/filterStylingProps";
|
|
5
|
-
import { type
|
|
5
|
+
import { type RecursicaHeadingProps } from "@recursica/adapter-common";
|
|
6
6
|
|
|
7
|
-
export type
|
|
8
|
-
Omit<MuiTypographyProps, "variant" | "classes"> &
|
|
7
|
+
export type HeadingProps = RecursicaOverStyled<
|
|
8
|
+
Omit<MuiTypographyProps, "variant" | "classes"> & RecursicaHeadingProps
|
|
9
9
|
>;
|
|
10
10
|
|
|
11
|
-
export const
|
|
11
|
+
export const Heading = forwardRef<HTMLElement, HeadingProps>(function Heading(
|
|
12
12
|
{ order = 1, component, ...rest },
|
|
13
13
|
ref,
|
|
14
14
|
) {
|
|
@@ -25,4 +25,4 @@ export const Title = forwardRef<HTMLElement, TitleProps>(function Title(
|
|
|
25
25
|
);
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
Heading.displayName = "Heading";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Heading - Usage Guide
|
|
2
2
|
|
|
3
|
-
This document describes how to integrate and use the `
|
|
3
|
+
This document describes how to integrate and use the `Heading` component in your projects using `@recursica/mui-adapter`.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## 1. Import Reference
|
|
8
8
|
|
|
9
9
|
```tsx
|
|
10
|
-
import {
|
|
10
|
+
import { Heading } from "@recursica/mui-adapter";
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
---
|
|
@@ -16,10 +16,10 @@ import { Title } from "@recursica/mui-adapter";
|
|
|
16
16
|
|
|
17
17
|
```tsx
|
|
18
18
|
import React from "react";
|
|
19
|
-
import {
|
|
19
|
+
import { Heading } from "@recursica/mui-adapter";
|
|
20
20
|
|
|
21
21
|
export default function Demo() {
|
|
22
|
-
return <
|
|
22
|
+
return <Heading order={1}>This is a Heading 1</Heading>;
|
|
23
23
|
}
|
|
24
24
|
```
|
|
25
25
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Heading";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Modal Implementation Notes
|
|
2
|
+
|
|
3
|
+
## `.title` descender clipping (Matt Massey, 2026-08-28)
|
|
4
|
+
|
|
5
|
+
`.title` truncates with an ellipsis (`white-space: nowrap; text-overflow: ellipsis`) rather than
|
|
6
|
+
wrapping, needing `flex: 1 1 auto; min-width: 0;` since it's a flex child of `.header` alongside
|
|
7
|
+
the close button. It used plain `overflow: hidden` to make the ellipsis work, which also clips
|
|
8
|
+
descenders (e.g. the "g" in a long title) whenever `text_line-height` is tighter than the font's
|
|
9
|
+
natural ascent+descent. Switched to `overflow: clip; overflow-clip-margin: 0.35em;` — same
|
|
10
|
+
truncation, but ink can bleed slightly past the line box before it's actually clipped.
|
|
11
|
+
Project-wide fix; see Chip's `CHIP_IMPLEMENTATION_NOTES.md` for the original discovery. Matches
|
|
12
|
+
mantine-adapter's equivalent `.title` rule (see its own `MODAL_IMPLEMENTATION_NOTES.md`).
|
|
@@ -66,7 +66,10 @@
|
|
|
66
66
|
.title {
|
|
67
67
|
flex: 1 1 auto; /* HARDCODE: let the title claim the space between the header edge and the close button */
|
|
68
68
|
min-width: 0; /* HARDCODE: required for text-overflow ellipsis to take effect on a flex child */
|
|
69
|
-
overflow: hidden
|
|
69
|
+
overflow: clip; /* HARDCODE: `hidden` clips descenders (e.g. "g") when text_line-height is
|
|
70
|
+
tighter than the font's natural ascent+descent; overflow-clip-margin gives ink a small bleed
|
|
71
|
+
allowance while still clipping genuinely overflowing text (see Chip's IMPLEMENTATION_NOTES.md). */
|
|
72
|
+
overflow-clip-margin: 0.35em;
|
|
70
73
|
white-space: nowrap;
|
|
71
74
|
text-overflow: ellipsis;
|
|
72
75
|
|
|
@@ -62,3 +62,13 @@ No tokens from other component namespaces are referenced.
|
|
|
62
62
|
**Decision:** Accept `opened` prop to match the standard Recursica component API.
|
|
63
63
|
|
|
64
64
|
**Implementation:** MUI Drawer natively expects the `open` boolean prop. The wrapper maps the incoming framework-agnostic `opened` prop to MUI's `open={Boolean(opened)}`, allowing consistent usage across both adapter implementations.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## `.titleTruncate` descender clipping (Matt Massey, 2026-08-28)
|
|
69
|
+
|
|
70
|
+
`.titleTruncate` used plain `overflow: hidden` to make `text-overflow: ellipsis` work, which also
|
|
71
|
+
clips descenders (e.g. the "g" in a long title) whenever `text_line-height` is tighter than the
|
|
72
|
+
font's natural ascent+descent. Switched to `overflow: clip; overflow-clip-margin: 0.35em;` — same
|
|
73
|
+
truncation, but ink can bleed slightly past the line box before it's actually clipped.
|
|
74
|
+
Project-wide fix; see Chip's `CHIP_IMPLEMENTATION_NOTES.md` for the original discovery.
|
|
@@ -96,7 +96,10 @@
|
|
|
96
96
|
.titleTruncate {
|
|
97
97
|
composes: title;
|
|
98
98
|
white-space: nowrap;
|
|
99
|
-
overflow: hidden
|
|
99
|
+
overflow: clip; /* HARDCODE: `hidden` clips descenders (e.g. "g") when text_line-height is
|
|
100
|
+
tighter than the font's natural ascent+descent; overflow-clip-margin gives ink a small bleed
|
|
101
|
+
allowance while still clipping genuinely overflowing text (see Chip's IMPLEMENTATION_NOTES.md). */
|
|
102
|
+
overflow-clip-margin: 0.35em;
|
|
100
103
|
text-overflow: ellipsis;
|
|
101
104
|
display: block;
|
|
102
105
|
flex: 1;
|
|
@@ -9,7 +9,7 @@ const meta: Meta<typeof Text> = {
|
|
|
9
9
|
docs: {
|
|
10
10
|
description: {
|
|
11
11
|
component:
|
|
12
|
-
"The standard `<Text>` component controls common body sizing scales and implicit paragraphs governed by the active theme layer. For semantic headings (`h1` through `h6`), use `<
|
|
12
|
+
"The standard `<Text>` component controls common body sizing scales and implicit paragraphs governed by the active theme layer. For semantic headings (`h1` through `h6`), use `<Heading>` instead.",
|
|
13
13
|
},
|
|
14
14
|
},
|
|
15
15
|
},
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Typography – Implementation Notes
|
|
2
|
+
|
|
3
|
+
`Typography` is the shared rendering base for both `Text` and `Heading` in mui-adapter — anything
|
|
4
|
+
applied here reaches both components.
|
|
5
|
+
|
|
6
|
+
## `.root` `text-wrap: balance` (Matt Massey, 2026-08-28)
|
|
7
|
+
|
|
8
|
+
**Decision:** Added `text-wrap: balance` via a new `Typography.module.css` `.root` class, merged
|
|
9
|
+
onto the typography class alongside the caller's own `className`. Since both `Text` and `Heading`
|
|
10
|
+
render through this component, it covers all `order` heading levels (h1–h6) and paragraph text in
|
|
11
|
+
one place.
|
|
12
|
+
|
|
13
|
+
**Implementation:** UX asked for more evenly balanced multi-line wrapping instead of a ragged last
|
|
14
|
+
line. Not a design token — it's a layout algorithm choice, so it's hardcoded rather than pulled
|
|
15
|
+
from `recursica_variables_scoped.css`. Most effective on short text (headings); Chromium/Firefox
|
|
16
|
+
only balance up to ~6 lines, so long paragraphs silently fall back to normal wrapping past that
|
|
17
|
+
point. No fallback needed — browsers that don't support the value just ignore the declaration.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* HARDCODED VALUES
|
|
3
|
+
* - `.root` `text-wrap: balance` — not a design token; a layout algorithm choice requested by
|
|
4
|
+
* UX (Matt Massey, 2026-08-28) to even out wrapped line lengths. See TEXT_IMPLEMENTATION_NOTES.md.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
.root {
|
|
8
|
+
/* HARDCODE: balances wrapped line lengths instead of leaving a ragged short last line. Most
|
|
9
|
+
effective on short text; browsers cap balancing at ~6 lines, so long paragraphs silently
|
|
10
|
+
fall back to normal wrapping past that point — no fallback needed, unsupported browsers
|
|
11
|
+
just ignore the declaration. */
|
|
12
|
+
text-wrap: balance;
|
|
13
|
+
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
filterStylingProps,
|
|
8
8
|
type RecursicaOverStyled,
|
|
9
9
|
} from "../../utils/filterStylingProps";
|
|
10
|
+
import styles from "./Typography.module.css";
|
|
10
11
|
|
|
11
12
|
export type TypographyProps = RecursicaOverStyled<
|
|
12
13
|
Omit<MuiTypographyProps, "variant"> & {
|
|
@@ -24,9 +25,9 @@ export const Typography = forwardRef<HTMLElement, TypographyProps>(
|
|
|
24
25
|
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
25
26
|
|
|
26
27
|
const classNameProp = restRecord.className as string | undefined;
|
|
27
|
-
const finalClass = classNameProp
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const finalClass = [typographyClass, styles.root, classNameProp]
|
|
29
|
+
.filter(Boolean)
|
|
30
|
+
.join(" ");
|
|
30
31
|
|
|
31
32
|
return (
|
|
32
33
|
<MuiTypography
|
package/src/components/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ export * from "./FormControlLayout";
|
|
|
19
19
|
export * from "./FormControlWrapper";
|
|
20
20
|
export * from "./Grid";
|
|
21
21
|
export * from "./Group";
|
|
22
|
+
export * from "./Heading";
|
|
22
23
|
export * from "./HoverCard";
|
|
23
24
|
export * from "./Label";
|
|
24
25
|
export * from "./Link";
|
|
@@ -43,7 +44,6 @@ export * from "./TextArea";
|
|
|
43
44
|
export * from "./TextField";
|
|
44
45
|
export * from "./TimePicker";
|
|
45
46
|
export * from "./Timeline";
|
|
46
|
-
export * from "./Title";
|
|
47
47
|
export * from "./Toast";
|
|
48
48
|
export * from "./Tooltip";
|
|
49
49
|
export * from "./TransferList";
|
package/src/index.ts
CHANGED
|
@@ -75,6 +75,9 @@ export const FormControlLayout = wrapComponent(
|
|
|
75
75
|
export const FormControlWrapper = wrapComponent(
|
|
76
76
|
rawComponents.FormControlWrapper,
|
|
77
77
|
) as typeof rawComponents.FormControlWrapper;
|
|
78
|
+
export const Heading = wrapComponent(
|
|
79
|
+
rawComponents.Heading,
|
|
80
|
+
) as typeof rawComponents.Heading;
|
|
78
81
|
export const HoverCard = wrapComponent(
|
|
79
82
|
rawComponents.HoverCard,
|
|
80
83
|
) as typeof rawComponents.HoverCard;
|
|
@@ -166,9 +169,6 @@ export const Timeline = wrapComponent(
|
|
|
166
169
|
export const TimelineItem = wrapComponent(
|
|
167
170
|
rawComponents.TimelineItem,
|
|
168
171
|
) as typeof rawComponents.TimelineItem;
|
|
169
|
-
export const Title = wrapComponent(
|
|
170
|
-
rawComponents.Title,
|
|
171
|
-
) as typeof rawComponents.Title;
|
|
172
172
|
export const Toast = wrapComponent(
|
|
173
173
|
rawComponents.Toast,
|
|
174
174
|
) as typeof rawComponents.Toast;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
// Placeholder for future Title component tests. Add tests here if/when needed.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./Title";
|