@podoba/react 0.0.8 → 0.0.10
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/package.json +3 -3
- package/src/components/collapsible-card.tsx +121 -0
- package/src/components/text.tsx +6 -2
- package/src/index.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@podoba/react",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "podoba React components — React Aria Components + Tailwind primitives + layout, built with uic.",
|
|
6
6
|
"repository": {
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"typecheck": "tsc --build"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@podoba/tokens": "^0.0.
|
|
29
|
-
"@podoba/tailwind": "^0.0.
|
|
28
|
+
"@podoba/tokens": "^0.0.10",
|
|
29
|
+
"@podoba/tailwind": "^0.0.10",
|
|
30
30
|
"react-aria-components": "1.18.0",
|
|
31
31
|
"class-variance-authority": "0.7.1",
|
|
32
32
|
"clsx": "2.1.1",
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Button as RACButton,
|
|
3
|
+
Disclosure as RACDisclosure,
|
|
4
|
+
DisclosurePanel as RACDisclosurePanel,
|
|
5
|
+
type DisclosureProps as RACDisclosureProps,
|
|
6
|
+
} from 'react-aria-components'
|
|
7
|
+
import type { ReactNode } from 'react'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* CollapsibleCard — a titled, expandable card (title + description + chevron,
|
|
11
|
+
* expanding to reveal a body).
|
|
12
|
+
*
|
|
13
|
+
* Styled composition over React Aria Components' `Disclosure` (see
|
|
14
|
+
* `./disclosure.tsx` for the unstyled primitive): RAC supplies the WAI-ARIA
|
|
15
|
+
* disclosure wiring (`aria-expanded` / `aria-controls`, keyboard activation,
|
|
16
|
+
* hidden-until-expanded panel) and, on its root element, a `data-expanded`
|
|
17
|
+
* attribute. We make the root a Tailwind `group`, so the chevron rotates via
|
|
18
|
+
* `group-data-[expanded]:rotate-90` — no render-prop plumbing needed.
|
|
19
|
+
*
|
|
20
|
+
* Token mapping (Tailwind + `@podoba/tokens` CSS vars — no SCSS, hard rule #3):
|
|
21
|
+
* - surface → `bg-surface-card` (#f7f6f2), 1px `border-border`, `rounded-lg`
|
|
22
|
+
* (8px) — same skin as `Card` / `StatsCard`.
|
|
23
|
+
* - title → `text-heading4` (1.125rem) `font-medium text-fg`.
|
|
24
|
+
* - description → `text-body text-fg-muted`.
|
|
25
|
+
*
|
|
26
|
+
* Presentational only (hard rule #1): all copy via props, no API/i18n.
|
|
27
|
+
*
|
|
28
|
+
* Controlled or uncontrolled — pass `isExpanded` + `onExpandedChange` to control,
|
|
29
|
+
* or `defaultExpanded` to seed the uncontrolled state.
|
|
30
|
+
*
|
|
31
|
+
* <CollapsibleCard title="Variables" description="Shared variables applied across this template.">
|
|
32
|
+
* <Select label="Color theme" …/>
|
|
33
|
+
* </CollapsibleCard>
|
|
34
|
+
*/
|
|
35
|
+
export type CollapsibleCardProps = {
|
|
36
|
+
/** Bold card title (the always-visible header line). */
|
|
37
|
+
title: ReactNode
|
|
38
|
+
/** Optional muted supporting line under the title. */
|
|
39
|
+
description?: ReactNode
|
|
40
|
+
/** The collapsible body, revealed when expanded. */
|
|
41
|
+
children?: ReactNode
|
|
42
|
+
/** Seed the uncontrolled expanded state. */
|
|
43
|
+
defaultExpanded?: boolean
|
|
44
|
+
/** Controlled expanded state (pair with `onExpandedChange`). */
|
|
45
|
+
isExpanded?: boolean
|
|
46
|
+
/** Fires when the user toggles the card. */
|
|
47
|
+
onExpandedChange?: (isExpanded: boolean) => void
|
|
48
|
+
/** Disable expand/collapse. */
|
|
49
|
+
isDisabled?: boolean
|
|
50
|
+
/** Extra classes merged onto the card root. */
|
|
51
|
+
className?: string
|
|
52
|
+
'data-testid'?: string
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const Chevron = () => (
|
|
56
|
+
<svg
|
|
57
|
+
width="16"
|
|
58
|
+
height="16"
|
|
59
|
+
viewBox="0 0 16 16"
|
|
60
|
+
fill="none"
|
|
61
|
+
aria-hidden="true"
|
|
62
|
+
className="mt-0.5 shrink-0 text-fg transition-transform duration-150 group-data-[expanded]:rotate-90"
|
|
63
|
+
>
|
|
64
|
+
<path
|
|
65
|
+
d="M6 4l4 4-4 4"
|
|
66
|
+
stroke="currentColor"
|
|
67
|
+
strokeWidth="1.5"
|
|
68
|
+
strokeLinecap="round"
|
|
69
|
+
strokeLinejoin="round"
|
|
70
|
+
/>
|
|
71
|
+
</svg>
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
export function CollapsibleCard({
|
|
75
|
+
title,
|
|
76
|
+
description,
|
|
77
|
+
children,
|
|
78
|
+
defaultExpanded,
|
|
79
|
+
isExpanded,
|
|
80
|
+
onExpandedChange,
|
|
81
|
+
isDisabled,
|
|
82
|
+
className,
|
|
83
|
+
...rest
|
|
84
|
+
}: CollapsibleCardProps) {
|
|
85
|
+
const disclosureProps: RACDisclosureProps = {
|
|
86
|
+
defaultExpanded,
|
|
87
|
+
isExpanded,
|
|
88
|
+
onExpandedChange,
|
|
89
|
+
isDisabled,
|
|
90
|
+
}
|
|
91
|
+
return (
|
|
92
|
+
<RACDisclosure
|
|
93
|
+
{...disclosureProps}
|
|
94
|
+
data-testid={rest['data-testid']}
|
|
95
|
+
className={[
|
|
96
|
+
'group overflow-hidden rounded-lg border border-border bg-surface-card',
|
|
97
|
+
className,
|
|
98
|
+
]
|
|
99
|
+
.filter(Boolean)
|
|
100
|
+
.join(' ')}
|
|
101
|
+
>
|
|
102
|
+
<RACButton
|
|
103
|
+
slot="trigger"
|
|
104
|
+
className={
|
|
105
|
+
'flex w-full items-center justify-between gap-4 rounded-lg p-6 text-left outline-none ' +
|
|
106
|
+
'data-[disabled]:cursor-not-allowed data-[disabled]:opacity-60 ' +
|
|
107
|
+
'data-[focus-visible]:ring-2 data-[focus-visible]:ring-ring data-[focus-visible]:ring-inset'
|
|
108
|
+
}
|
|
109
|
+
>
|
|
110
|
+
<span className="flex flex-col gap-1">
|
|
111
|
+
<span className="text-heading4 font-medium leading-tight text-fg">{title}</span>
|
|
112
|
+
{description ? (
|
|
113
|
+
<span className="text-body leading-snug text-fg-muted">{description}</span>
|
|
114
|
+
) : null}
|
|
115
|
+
</span>
|
|
116
|
+
<Chevron />
|
|
117
|
+
</RACButton>
|
|
118
|
+
<RACDisclosurePanel className="px-6 pb-6">{children}</RACDisclosurePanel>
|
|
119
|
+
</RACDisclosure>
|
|
120
|
+
)
|
|
121
|
+
}
|
package/src/components/text.tsx
CHANGED
|
@@ -36,11 +36,15 @@ export const Text = uic('span', {
|
|
|
36
36
|
headline: 'text-headline',
|
|
37
37
|
display: 'text-display',
|
|
38
38
|
},
|
|
39
|
+
// NC Fontina caps at medium (500) as the heaviest weight in the system, so
|
|
40
|
+
// `semibold` and `bold` are kept as API-compatible aliases that render
|
|
41
|
+
// medium rather than going heavier. Keeping the keys avoids a breaking
|
|
42
|
+
// change for consumers already passing weight="semibold" / "bold".
|
|
39
43
|
weight: {
|
|
40
44
|
regular: 'font-normal',
|
|
41
45
|
medium: 'font-medium',
|
|
42
|
-
semibold: 'font-
|
|
43
|
-
bold: 'font-
|
|
46
|
+
semibold: 'font-medium',
|
|
47
|
+
bold: 'font-medium',
|
|
44
48
|
},
|
|
45
49
|
tone: {
|
|
46
50
|
default: 'text-fg',
|
package/src/index.ts
CHANGED
|
@@ -35,6 +35,7 @@ export * from "./components/context-menu";
|
|
|
35
35
|
export * from "./components/tooltip";
|
|
36
36
|
export * from "./components/toast";
|
|
37
37
|
export * from "./components/disclosure";
|
|
38
|
+
export * from "./components/collapsible-card";
|
|
38
39
|
export * from "./components/tabs";
|
|
39
40
|
export * from "./components/section-tabs";
|
|
40
41
|
export * from "./components/separator";
|