@podoba/react 0.0.39 → 0.0.40

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@podoba/react",
3
- "version": "0.0.39",
3
+ "version": "0.0.40",
4
4
  "type": "module",
5
5
  "description": "podoba React components — React Aria Components + Tailwind primitives + layout, built with uic.",
6
6
  "repository": {
@@ -28,8 +28,8 @@
28
28
  "typecheck": "tsc --build"
29
29
  },
30
30
  "dependencies": {
31
- "@podoba/tokens": "^0.0.39",
32
- "@podoba/tailwind": "^0.0.39",
31
+ "@podoba/tokens": "^0.0.40",
32
+ "@podoba/tailwind": "^0.0.40",
33
33
  "react-aria-components": "1.18.0",
34
34
  "class-variance-authority": "0.7.1",
35
35
  "clsx": "2.1.1",
@@ -89,9 +89,9 @@ export function AssetLibraryPreview({ label, selected, aspectRatio, tags, onPres
89
89
  }) {
90
90
  return <AriaButton aria-label={label} aria-pressed={selected} onPress={onPress}
91
91
  style={{ aspectRatio }}
92
- className={`group relative block min-h-[150px] max-h-[800px] w-full overflow-hidden rounded-lg border p-0 transition-transform duration-200 hover:-translate-y-0.5 hover:shadow-xs hover:border-border-muted active:translate-y-0 focus-visible:ring-2 focus-visible:ring-accent-blue focus-visible:ring-offset-2 motion-reduce:transition-none ${selected ? 'border-accent-blue bg-accent-blue/10' : 'border-border bg-surface-card'}`}>
92
+ className={`group relative block min-h-[150px] max-h-[800px] w-full overflow-hidden rounded-none border p-0 transition-transform duration-200 ease-[ease] hover:-translate-y-0.5 hover:shadow-xs hover:border-[#aba89c] active:translate-y-0 focus-visible:ring-2 focus-visible:ring-accent-blue focus-visible:ring-offset-2 motion-reduce:transition-none ${selected ? 'border-accent-blue bg-accent-blue/10' : 'border-border bg-surface-card'}`}>
93
93
  {children}
94
- {tags.length ? <span data-testid="asset-card-overlay" className="pointer-events-none absolute inset-x-0 bottom-0 flex flex-wrap items-center gap-1 bg-gradient-to-t from-black/70 to-transparent p-3 opacity-0 transition-opacity duration-250 group-hover:opacity-100 group-focus-visible:opacity-100 motion-reduce:transition-none">
94
+ {tags.length ? <span data-testid="asset-card-overlay" className="pointer-events-none absolute inset-x-0 bottom-0 flex flex-wrap items-center gap-1 bg-gradient-to-t from-black/70 to-transparent p-3 opacity-0 transition-opacity duration-250 ease-[ease] group-hover:opacity-100 group-focus-visible:opacity-100 motion-reduce:transition-none">
95
95
  {tags.slice(0, 3).map(tag => <span key={tag} className="ms-3 inline-flex h-6 items-center rounded-full bg-surface-muted px-2.5 text-label font-medium leading-5 text-(--color-neutral-600)">{tag}</span>)}
96
96
  {tags.length > 3 ? <span className="text-label font-medium text-white/90">+{tags.length - 3}</span> : null}
97
97
  </span> : null}
@@ -157,7 +157,7 @@ export function AssetSelectionGrid({ items, selectedId, onSelect, onContextMenu
157
157
  {positioned.map(({ item, top, left, height }) => {
158
158
  const className = `group relative block h-full w-full overflow-hidden rounded-lg border bg-surface-card p-0 transition-transform duration-200 hover:-translate-y-0.5 active:translate-y-0 motion-reduce:transition-none ${onSelect ? 'hover:shadow-xs hover:border-border-muted' : ''} ${selectedId === item.id ? 'border-accent-blue' : 'border-border'}`
159
159
  const contents = <>{item.preview}
160
- {item.tags.length ? <span className="pointer-events-none absolute inset-x-0 bottom-0 flex flex-wrap items-center gap-1 bg-gradient-to-t from-black/70 to-transparent p-3 opacity-0 transition-opacity duration-250 group-hover:opacity-100 group-focus-visible:opacity-100 motion-reduce:transition-none">
160
+ {item.tags.length ? <span className="pointer-events-none absolute inset-x-0 bottom-0 flex flex-wrap items-center gap-1 bg-gradient-to-t from-black/70 to-transparent p-3 opacity-0 transition-opacity duration-250 ease-[ease] group-hover:opacity-100 group-focus-visible:opacity-100 motion-reduce:transition-none">
161
161
  {item.tags.slice(0, 3).map(tag => <span key={tag} className="ms-3 inline-flex h-6 items-center rounded-full bg-surface-muted px-2.5 text-label font-medium leading-5 text-(--color-neutral-600)">{tag}</span>)}
162
162
  {item.tags.length > 3 ? <span className="text-label font-medium text-white/90">+{item.tags.length - 3}</span> : null}
163
163
  </span> : null}
@@ -88,7 +88,7 @@ export function SettingsDialogSurface({ variant, isOpen, onOpenChange, isPending
88
88
  <header className={catalog ? 'flex shrink-0 flex-col gap-2' : basic ? headerBottomPadding ? 'shrink-0 pb-4' : 'shrink-0' : create || csv ? 'shrink-0 pb-4' : 'shrink-0 pb-10 max-md:pb-8'}>
89
89
  <Container className={containerClass}>
90
90
  {catalog ? <Heading id={titleId} level="1" className="m-0 mb-4 max-w-5/6 whitespace-pre-line" style={{ letterSpacing: 0 }}>{title}</Heading>
91
- : <DisplayHeading id={titleId} className={`m-0 whitespace-pre-line pb-0.5 text-fg-muted ${create ? 'mb-4 max-w-5/6' : ''}`} style={{ letterSpacing: 0, ...(basic ? { maxWidth: '18ch' } : csv && isWide ? { maxWidth: '34ch' } : {}) }}>{title}</DisplayHeading>}
91
+ : <DisplayHeading id={titleId} className={`m-0 whitespace-pre-line pb-0.5 text-fg-muted ${create ? 'mb-4 max-w-5/6' : ''}`} style={{ letterSpacing: 0, ...(basic ? { maxWidth: '83.333%' } : csv && isWide ? { maxWidth: '34ch' } : {}) }}>{title}</DisplayHeading>}
92
92
  {description ? <p id={descriptionId} className="mb-0 mt-3 text-small font-normal text-fg-workflow-muted" style={{ maxWidth: '48ch' }}>{description}</p> : null}
93
93
  </Container>
94
94
  {filters ? <div className="w-full max-w-80">{filters}</div> : null}
@@ -39,5 +39,5 @@ export const Tab = uic(RACTab, {
39
39
 
40
40
  export const TabPanel = uic(RACTabPanel, {
41
41
  displayName: 'TabPanel',
42
- baseClass: 'py-4 text-small text-fg outline-none data-[focus-visible]:ring-2 data-[focus-visible]:ring-ring',
42
+ baseClass: 'py-6 text-small text-fg outline-none data-[focus-visible]:ring-2 data-[focus-visible]:ring-ring',
43
43
  }) as (props: TabPanelProps) => ReturnType<typeof RACTabPanel>
@@ -38,9 +38,25 @@ const SummaryHead = uic('div', { displayName: 'CatalogSummaryHead', baseClass: '
38
38
  export const CatalogSummaryBadge = uic('span', { displayName: 'CatalogSummaryBadge', baseClass: 'ml-3 flex h-6 shrink-0 items-center rounded-2xl px-2.5 text-micro font-medium leading-5', style: { fontFeatureSettings: '"liga" off, "clig" off' }, variants: { color: { green: 'bg-brand-green text-fg-on-brand', grey: 'bg-surface-muted text-(--color-neutral-600)' } }, defaultVariants: { color: 'grey' } })
39
39
  const SummaryTitle = uic('h2', { displayName: 'CatalogSummaryTitle', baseClass: 'm-0 min-w-0 truncate text-heading5 font-medium' })
40
40
  const SummaryTail = uic('div', { displayName: 'CatalogSummaryTail', baseClass: 'mt-auto flex flex-col gap-1 text-small font-normal text-fg-workflow-muted' })
41
- /** Display-only catalog tile. No synthetic imagery when a preview is absent. */
42
- export function CatalogSummaryCard({ title, badge, description, details }: { title: string; badge: ReactNode; description?: string; details: ReactNode }) {
43
- return <SummaryCard><SummaryHead><SummaryTitle>{title}</SummaryTitle><span className="shrink-0">{badge}</span></SummaryHead><SummaryTail>{description ? <p className="m-0">{description}</p> : null}<span>{details}</span></SummaryTail></SummaryCard>
41
+ /** Source gs Tile image cover: caller artwork under a transparent 30% → 50% black gradient. */
42
+ function CatalogCover({ preview }: { preview: ReactNode }) {
43
+ return <>
44
+ <div aria-hidden="true" className="absolute inset-0 -z-10 overflow-hidden [&_canvas]:size-full [&_canvas]:object-cover [&_img]:size-full [&_img]:object-cover">{preview}</div>
45
+ <div aria-hidden="true" className="absolute inset-0 -z-10 bg-linear-to-b from-black/0 via-black/30 to-black/50" />
46
+ </>
47
+ }
48
+
49
+ /**
50
+ * Display-only catalog tile. No synthetic imagery when a preview is absent. An optional
51
+ * real `preview` covers the card with the source gradient and switches the ink to white.
52
+ */
53
+ export function CatalogSummaryCard({ title, badge, description, details, preview }: { title: string; badge: ReactNode; description?: string; details: ReactNode; preview?: ReactNode }) {
54
+ const covered = preview != null
55
+ return <SummaryCard data-preview={covered || undefined} className={covered ? 'relative isolate' : undefined}>
56
+ {covered ? <CatalogCover preview={preview} /> : null}
57
+ <SummaryHead><SummaryTitle className={covered ? 'text-white' : undefined}>{title}</SummaryTitle><span className="shrink-0">{badge}</span></SummaryHead>
58
+ <SummaryTail className={covered ? 'text-white/88' : undefined}>{description ? <p className="m-0">{description}</p> : null}<span>{details}</span></SummaryTail>
59
+ </SummaryCard>
44
60
  }
45
61
 
46
62
  /**
@@ -52,10 +68,7 @@ export function CatalogSummaryCard({ title, badge, description, details }: { tit
52
68
  export function CatalogLaunchCard({ title, description, details, action, preview }: { title: string; description?: string; details: ReactNode; action: ReactNode; preview?: ReactNode }) {
53
69
  const covered = preview != null
54
70
  return <SummaryCard data-testid="scenario-launch-card" data-preview={covered || undefined} className="relative isolate h-70 min-h-70 max-h-70 transition-colors duration-200 focus-within:ring-2 focus-within:ring-ring">
55
- {covered ? <>
56
- <div aria-hidden="true" className="absolute inset-0 -z-10 overflow-hidden [&_canvas]:size-full [&_canvas]:object-cover [&_img]:size-full [&_img]:object-cover">{preview}</div>
57
- <div aria-hidden="true" className="absolute inset-0 -z-10 bg-linear-to-b from-black/0 via-black/30 to-black/50" />
58
- </> : null}
71
+ {covered ? <CatalogCover preview={preview} /> : null}
59
72
  <SummaryHead><SummaryTitle asChild className={covered ? 'text-white' : undefined}><h3>{title}</h3></SummaryTitle></SummaryHead>
60
73
  <SummaryTail className={covered ? 'text-white/88' : undefined}>{description ? <p className="m-0">{description}</p> : null}<span>{details}</span></SummaryTail>
61
74
  {action}