Skip to content

Commit 1177c1d

Browse files
committed
feat(tasty): selector affix for sub-elements
1 parent d229748 commit 1177c1d

File tree

3 files changed

+93
-0
lines changed

3 files changed

+93
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@cube-dev/ui-kit": patch
3+
---
4+
5+
Enhanced selector affix syntax (`$`) for sub-element styling in tasty. Capitalized words in the affix are now automatically transformed to sub-element selectors, allowing complex selector chains like `$: '> Body > Row >'` which generates `.table > [data-element="Body"] > [data-element="Row"] > [data-element="Cell"]`.
6+

src/stories/Tasty.docs.mdx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,33 @@ const Card = tasty({
567567
</Card>
568568
```
569569

570+
#### Selector Affix (`$`)
571+
572+
Control sub-element selector combinator using the `$` property:
573+
574+
```jsx
575+
const Table = tasty({
576+
styles: {
577+
// Direct child selector
578+
Row: {
579+
$: '>', // .table > [data-element="Row"]
580+
padding: '1x',
581+
},
582+
583+
// Chained selectors (auto-transforms capitalized words)
584+
Cell: {
585+
$: '> Body > Row >', // .table > [data-element="Body"] > [data-element="Row"] > [data-element="Cell"]
586+
border: '1bw solid #border',
587+
},
588+
589+
// Default: descendant selector (space)
590+
Text: {
591+
color: '#text', // .table [data-element="Text"]
592+
},
593+
},
594+
});
595+
```
596+
570597
### Variants & Theming
571598

572599
Create themed component variations:

src/tasty/tasty.test.tsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,6 +1170,66 @@ describe('tastyGlobal() API', () => {
11701170
expect(styleContent).not.toMatch(/>\s*\[data-element="Content"\]/);
11711171
});
11721172

1173+
it('should support empty affix for sub-elements with $: ""', () => {
1174+
const Card = tasty({
1175+
styles: {
1176+
padding: '2x',
1177+
Content: {
1178+
$: '',
1179+
color: '#primary',
1180+
},
1181+
},
1182+
});
1183+
1184+
render(
1185+
<Card>
1186+
<div data-element="Content">Content text</div>
1187+
</Card>,
1188+
);
1189+
1190+
const styleElements = document.head.querySelectorAll('[data-tasty]');
1191+
const styleContent = Array.from(styleElements)
1192+
.map((el) => el.textContent)
1193+
.join('');
1194+
1195+
// Empty affix should result in descendant selector (space only)
1196+
expect(styleContent).toMatch(/\s+\[data-element="Content"\]/);
1197+
expect(styleContent).not.toMatch(/>\s*\[data-element="Content"\]/);
1198+
});
1199+
1200+
it('should support complex selector chain with $: "> Body > Row >"', () => {
1201+
const Table = tasty({
1202+
styles: {
1203+
display: 'table',
1204+
Cell: {
1205+
$: '> Body > Row >',
1206+
padding: '1x',
1207+
border: '1px solid #border',
1208+
},
1209+
},
1210+
});
1211+
1212+
render(
1213+
<Table>
1214+
<div data-element="Body">
1215+
<div data-element="Row">
1216+
<div data-element="Cell">Cell content</div>
1217+
</div>
1218+
</div>
1219+
</Table>,
1220+
);
1221+
1222+
const styleElements = document.head.querySelectorAll('[data-tasty]');
1223+
const styleContent = Array.from(styleElements)
1224+
.map((el) => el.textContent)
1225+
.join('');
1226+
1227+
// Should transform to: > [data-element="Body"] > [data-element="Row"] > [data-element="Cell"]
1228+
expect(styleContent).toMatch(
1229+
/>\s*\[data-element="Body"\]\s*>\s*\[data-element="Row"\]\s*>\s*\[data-element="Cell"\]/,
1230+
);
1231+
});
1232+
11731233
it('should support multiple global style components with different selectors', () => {
11741234
const GlobalHeading = tasty('h1.special', {
11751235
preset: 'h1',

0 commit comments

Comments
 (0)