@@ -72,6 +72,13 @@ function getTextureStyle(token: string): CSSProperties {
'linear-gradient(var(--concrete-lattice) var(--concrete-border-width-hairline), transparent var(--concrete-border-width-hairline)), linear-gradient(90deg, var(--concrete-lattice) var(--concrete-border-width-hairline), transparent var(--concrete-border-width-hairline))',
backgroundSize: 'var(--concrete-grid-unit) var(--concrete-grid-unit)'
}
+ case 'depth':
+ return {
+ backgroundColor: 'var(--concrete-depth-background)',
+ backgroundImage: 'var(--concrete-depth-background-image)',
+ backgroundSize:
+ 'var(--concrete-size-full) var(--concrete-size-full), var(--concrete-grid-unit) var(--concrete-grid-unit), var(--concrete-grid-unit) var(--concrete-grid-unit), var(--concrete-size-full) var(--concrete-size-full)'
+ }
default:
return {}
}
@@ -85,6 +92,8 @@ function getTextureDescription(token: string): string {
return 'reading and rows'
case 'lattice':
return 'diagram coordinates'
+ case 'depth':
+ return 'perspective grounds'
default:
return 'texture ground'
}
diff --git a/packages/concrete/src/foundations/textures/schema.ts b/packages/concrete/src/foundations/textures/schema.ts
index 40f1e14..8454433 100644
--- a/packages/concrete/src/foundations/textures/schema.ts
+++ b/packages/concrete/src/foundations/textures/schema.ts
@@ -2,11 +2,11 @@ import { z } from 'zod/v4'
export const textureFoundationSchema = z
.object({
- variant: z.enum(['dots', 'lattice', 'lines']).default('lattice')
+ variant: z.enum(['dots', 'lattice', 'lines', 'depth']).default('lattice')
})
.strict()
-export const textureTokens = ['lattice', 'dots', 'lines'] as const
+export const textureTokens = ['lattice', 'dots', 'lines', 'depth'] as const
export type TextureFoundationInput = z.input
export type TextureFoundationValue = z.output
diff --git a/packages/concrete/src/foundations/textures/styles.css b/packages/concrete/src/foundations/textures/styles.css
index ba38d37..8bbb3e0 100644
--- a/packages/concrete/src/foundations/textures/styles.css
+++ b/packages/concrete/src/foundations/textures/styles.css
@@ -29,6 +29,27 @@
--concrete-lattice: rgb(10 11 15 / 3.5%);
--concrete-dots: rgb(10 11 15 / 14%);
--concrete-lines: rgb(10 11 15 / 6%);
+ --concrete-depth: var(--concrete-inverse-background);
+ --concrete-depth-background: #070a10;
+ --concrete-depth-line: rgb(78 139 222 / 18%);
+ --concrete-depth-line-strong: rgb(78 139 222 / 32%);
+ --concrete-depth-glow: rgb(31 111 212 / 18%);
+ --concrete-depth-fade: rgb(7 10 16 / 92%);
+ --concrete-depth-background-image:
+ radial-gradient(circle at 50% 0, var(--concrete-depth-glow), transparent 42%),
+ linear-gradient(var(--concrete-depth-line) 1px, transparent 1px),
+ linear-gradient(90deg, var(--concrete-depth-line) 1px, transparent 1px),
+ linear-gradient(180deg, transparent 12%, var(--concrete-depth-glow) 54%, transparent);
+ --concrete-tilt-frame-glare-background: linear-gradient(
+ 135deg,
+ rgb(255 255 255 / 12%),
+ transparent 36% 70%,
+ rgb(78 139 222 / 8%)
+ );
+ --concrete-tilt-frame-glare-shadow:
+ inset 0 0 0 1px rgb(78 139 222 / 14%),
+ inset 0 14px 24px -22px rgb(78 139 222 / 32%),
+ inset 0 -18px 28px -26px rgb(10 11 15 / 28%);
}
.concrete-lattice {
diff --git a/packages/concrete/src/primitives/index.tsx b/packages/concrete/src/primitives/index.tsx
index 1c7a361..e516ace 100644
--- a/packages/concrete/src/primitives/index.tsx
+++ b/packages/concrete/src/primitives/index.tsx
@@ -71,6 +71,7 @@ export * from './radio'
export * from './rail'
export * from './range'
export * from './row'
+export * from './scale-frame'
export * from './scroll-area'
export * from './search-input'
export * from './section'
@@ -93,6 +94,7 @@ export * from './tag'
export * from './target-line'
export * from './text'
export * from './textarea'
+export * from './tilt-frame'
export * from './time-list'
export * from './token'
export * from './token-rail'
diff --git a/packages/concrete/src/primitives/scale-frame/component.tsx b/packages/concrete/src/primitives/scale-frame/component.tsx
new file mode 100644
index 0000000..cba32e0
--- /dev/null
+++ b/packages/concrete/src/primitives/scale-frame/component.tsx
@@ -0,0 +1,56 @@
+import type { CSSProperties, HTMLAttributes, ReactNode } from 'react'
+import { concreteClassNames } from '../../styles/class-names'
+import { cn } from '../utils'
+
+export type ScaleFrameAlign = 'center' | 'end' | 'start'
+export type ScaleFrameSurface = 'raised' | 'sunken' | 'transparent'
+
+export type ScaleFrameProps = HTMLAttributes & {
+ align?: ScaleFrameAlign
+ children?: ReactNode
+ scale?: number
+ surface?: ScaleFrameSurface
+}
+
+type ScaleFrameStyle = CSSProperties & {
+ '--concrete-scale-frame-scale'?: string
+}
+
+// TECH-DEBT: Low-quality docs-preview primitive. The raw numeric scale prop and inline
+// custom property adapter should be replaced by tokenized preview/composition primitives.
+export function ScaleFrame({
+ align = 'center',
+ children,
+ className,
+ scale = 1,
+ style,
+ surface = 'transparent',
+ ...props
+}: ScaleFrameProps) {
+ const frameStyle: ScaleFrameStyle = {
+ '--concrete-scale-frame-scale': String(getSafeScale(scale)),
+ ...style
+ }
+
+ return (
+
+ )
+}
+
+function getSafeScale(scale: number): number {
+ if (!Number.isFinite(scale)) {
+ return 1
+ }
+
+ return Math.min(Math.max(scale, 0.15), 1.25)
+}
diff --git a/packages/concrete/src/primitives/scale-frame/examples.tsx b/packages/concrete/src/primitives/scale-frame/examples.tsx
new file mode 100644
index 0000000..057795e
--- /dev/null
+++ b/packages/concrete/src/primitives/scale-frame/examples.tsx
@@ -0,0 +1,30 @@
+import { defineExamples } from '../../factories/createExamples'
+import { Button } from '../button'
+import { Input } from '../input'
+import { ScaleFrame } from './component'
+
+export const scaleFrameExamples = defineExamples({
+ controls: {
+ description: 'A larger control group scaled inside fixed preview bounds.',
+ render: function renderControls() {
+ return (
+
+
+
+
+ )
+ }
+ },
+ panel: {
+ description: 'Static product surfaces keep their layout while fitting dense previews.',
+ render: function renderPanel() {
+ return (
+
+ Latency p95
+ 184ms
+ Scaled output remains deterministic.
+
+ )
+ }
+ }
+})
diff --git a/packages/concrete/src/primitives/scale-frame/index.tsx b/packages/concrete/src/primitives/scale-frame/index.tsx
new file mode 100644
index 0000000..68c3dc0
--- /dev/null
+++ b/packages/concrete/src/primitives/scale-frame/index.tsx
@@ -0,0 +1,30 @@
+import { exampleStates, renderExample } from '../../factories/createExamples'
+import { createPrimitive } from '../../factories/createItems'
+import { ScaleFrame } from './component'
+import { scaleFrameExamples } from './examples'
+import { scaleFrameMeta } from './meta'
+import { type ScaleFrameValue, scaleFrameSchema } from './schema'
+
+export type { ScaleFrameAlign, ScaleFrameProps, ScaleFrameSurface } from './component'
+export { ScaleFrame } from './component'
+export type { ScaleFrameInput, ScaleFrameValue } from './schema'
+export { scaleFramePropsSchema, scaleFrameSchema } from './schema'
+
+export const scaleFramePrimitiveDefinition = createPrimitive({
+ ...scaleFrameMeta,
+ component: ScaleFrame,
+ kind: 'primitive',
+ renderExample: (state?: string) => renderExample(scaleFrameExamples, state),
+ renderInput: input => renderScaleFrameInput(scaleFrameSchema.parse(input)),
+ schema: scaleFrameSchema,
+ slug: 'scale-frame',
+ states: exampleStates(scaleFrameExamples, ['controls', 'panel'])
+})
+
+function renderScaleFrameInput({ align, body, scale, surface }: ScaleFrameValue) {
+ return (
+
+ {body}
+
+ )
+}
diff --git a/packages/concrete/src/primitives/scale-frame/meta.ts b/packages/concrete/src/primitives/scale-frame/meta.ts
new file mode 100644
index 0000000..498cc90
--- /dev/null
+++ b/packages/concrete/src/primitives/scale-frame/meta.ts
@@ -0,0 +1,26 @@
+import { prop } from '../../registry/props'
+import type { ConcretePressure, PrimitiveCategory } from '../../schemas'
+
+type ScaleFrameMeta = {
+ category: PrimitiveCategory
+ description: string
+ guidance: string
+ name: string
+ pressure: readonly ConcretePressure[]
+ props: readonly ReturnType[]
+}
+
+export const scaleFrameMeta = {
+ category: 'surface',
+ description: 'Fixed-bounds preview container for scaled product surfaces.',
+ guidance:
+ 'Use ScaleFrame when a real primitive, component, or interface must fit a constrained preview without changing its internal layout.',
+ name: 'ScaleFrame',
+ pressure: ['product', 'generative', 'educational'],
+ props: [
+ prop('scale', 'number', 'Visual scale applied inside stable frame bounds.', '1'),
+ prop('align', "'start' | 'center' | 'end'", 'Content alignment inside the frame.', 'center'),
+ prop('surface', "'raised' | 'sunken' | 'transparent'", 'Optional frame surface.', 'transparent'),
+ prop('children', 'ReactNode', 'Scaled frame content.')
+ ]
+} as const satisfies ScaleFrameMeta
diff --git a/packages/concrete/src/primitives/scale-frame/schema.ts b/packages/concrete/src/primitives/scale-frame/schema.ts
new file mode 100644
index 0000000..05679f8
--- /dev/null
+++ b/packages/concrete/src/primitives/scale-frame/schema.ts
@@ -0,0 +1,14 @@
+import { z } from 'zod/v4'
+
+export const scaleFrameSchema = z
+ .object({
+ align: z.enum(['start', 'center', 'end']).default('center'),
+ body: z.string().default('Scaled preview content'),
+ scale: z.number().min(0.15).max(1.25).default(1),
+ surface: z.enum(['raised', 'sunken', 'transparent']).default('transparent')
+ })
+ .strict()
+
+export { scaleFrameSchema as scaleFramePropsSchema }
+export type ScaleFrameInput = z.input
+export type ScaleFrameValue = z.output
diff --git a/packages/concrete/src/primitives/scale-frame/styles.css b/packages/concrete/src/primitives/scale-frame/styles.css
new file mode 100644
index 0000000..bd8bd3f
--- /dev/null
+++ b/packages/concrete/src/primitives/scale-frame/styles.css
@@ -0,0 +1,43 @@
+.concrete-scale-frame {
+ display: grid;
+ min-width: var(--concrete-space-0);
+}
+
+.concrete-scale-frame-surface {
+ display: grid;
+ width: var(--concrete-size-full);
+ min-width: var(--concrete-space-0);
+ overflow: hidden;
+ border: var(--concrete-border-width-hairline) solid transparent;
+ border-radius: var(--concrete-radius-4);
+}
+
+.concrete-scale-frame[data-surface="raised"] .concrete-scale-frame-surface {
+ border-color: var(--concrete-border);
+ background: var(--concrete-surface);
+ box-shadow: var(--concrete-shadow-1);
+}
+
+.concrete-scale-frame[data-surface="sunken"] .concrete-scale-frame-surface {
+ border-color: var(--concrete-border-soft);
+ background: var(--concrete-sunken);
+}
+
+.concrete-scale-frame-content {
+ display: grid;
+ gap: var(--concrete-space-2);
+ min-width: var(--concrete-space-0);
+ place-self: center;
+ transform: scale(var(--concrete-scale-frame-scale));
+ transform-origin: center;
+}
+
+.concrete-scale-frame[data-align="start"] .concrete-scale-frame-content {
+ place-self: start;
+ transform-origin: top left;
+}
+
+.concrete-scale-frame[data-align="end"] .concrete-scale-frame-content {
+ place-self: end;
+ transform-origin: right bottom;
+}
diff --git a/packages/concrete/src/primitives/tilt-frame/component.tsx b/packages/concrete/src/primitives/tilt-frame/component.tsx
new file mode 100644
index 0000000..df0e6fa
--- /dev/null
+++ b/packages/concrete/src/primitives/tilt-frame/component.tsx
@@ -0,0 +1,126 @@
+'use client'
+
+import type { HTMLAttributes, PointerEvent, ReactNode } from 'react'
+import { useEffect, useRef } from 'react'
+import { concreteClassNames } from '../../styles/class-names'
+import { cn } from '../utils'
+
+export type TiltFrameIntensity = 'medium' | 'subtle'
+export type TiltFrameSurface = 'raised' | 'sunken' | 'transparent'
+
+export type TiltFrameProps = HTMLAttributes & {
+ children?: ReactNode
+ /** Enables cursor-driven rotation. */
+ interactive?: boolean
+ /** Rotation strength. Keep hero/product uses subtle. */
+ intensity?: TiltFrameIntensity
+ surface?: TiltFrameSurface
+}
+
+const tiltIntensityDegrees = {
+ medium: 6.5,
+ subtle: 3.5
+} satisfies Record
+
+type PendingTilt = {
+ rotateX: number
+ rotateY: number
+ target: HTMLDivElement
+}
+
+// TECH-DEBT: Low-quality landing-page primitive. Cursor-driven visual depth is too
+// aesthetic-specific for the core surface vocabulary and needs a stricter role contract.
+export function TiltFrame({
+ children,
+ className,
+ interactive = true,
+ intensity = 'subtle',
+ onPointerLeave,
+ onPointerMove,
+ surface = 'raised',
+ ...props
+}: TiltFrameProps) {
+ const frameReference = useRef(null)
+ const pendingTiltReference = useRef(null)
+
+ useEffect(() => {
+ return () => {
+ if (frameReference.current !== null) {
+ window.cancelAnimationFrame(frameReference.current)
+ }
+ }
+ }, [])
+
+ function updateTilt(event: PointerEvent) {
+ onPointerMove?.(event)
+
+ if (!interactive) {
+ return
+ }
+
+ const bounds = event.currentTarget.getBoundingClientRect()
+ const x = clampTiltAxis((event.clientX - bounds.left) / bounds.width - 0.5)
+ const y = clampTiltAxis((event.clientY - bounds.top) / bounds.height - 0.5)
+ const degrees = tiltIntensityDegrees[intensity]
+
+ queueTilt(event.currentTarget, roundTiltValue(-y * degrees), roundTiltValue(x * degrees))
+ }
+
+ function resetTilt(event: PointerEvent) {
+ onPointerLeave?.(event)
+
+ pendingTiltReference.current = null
+
+ if (frameReference.current !== null) {
+ window.cancelAnimationFrame(frameReference.current)
+ frameReference.current = null
+ }
+
+ event.currentTarget.style.removeProperty('--concrete-tilt-rotate-x')
+ event.currentTarget.style.removeProperty('--concrete-tilt-rotate-y')
+ }
+
+ function queueTilt(target: HTMLDivElement, rotateX: number, rotateY: number) {
+ pendingTiltReference.current = { rotateX, rotateY, target }
+
+ if (frameReference.current !== null) {
+ return
+ }
+
+ frameReference.current = window.requestAnimationFrame(() => {
+ const pendingTilt = pendingTiltReference.current
+ frameReference.current = null
+
+ if (!pendingTilt) {
+ return
+ }
+
+ pendingTilt.target.style.setProperty('--concrete-tilt-rotate-x', `${pendingTilt.rotateX}deg`)
+ pendingTilt.target.style.setProperty('--concrete-tilt-rotate-y', `${pendingTilt.rotateY}deg`)
+ })
+ }
+
+ return (
+
+ )
+}
+
+function clampTiltAxis(value: number): number {
+ return Math.max(-0.5, Math.min(0.5, value))
+}
+
+function roundTiltValue(value: number): number {
+ return Math.round(value * 100) / 100
+}
diff --git a/packages/concrete/src/primitives/tilt-frame/examples.tsx b/packages/concrete/src/primitives/tilt-frame/examples.tsx
new file mode 100644
index 0000000..506dd8d
--- /dev/null
+++ b/packages/concrete/src/primitives/tilt-frame/examples.tsx
@@ -0,0 +1,31 @@
+import { defineExamples } from '../../factories/createExamples'
+import { Button } from '../button'
+import { Input } from '../input'
+import { Slider } from '../slider'
+import { Switch } from '../switch'
+import { TiltFrame } from './component'
+
+export const tiltFrameExamples = defineExamples({
+ controls: {
+ description: 'Stable container for live controls with subtle pointer depth.',
+ render: () => (
+
+
+
+
+
+
+ )
+ },
+ surface: {
+ description: 'Sunken depth keeps the highlight quiet inside dense product surfaces.',
+ render: () => (
+
+ Generated panel
+ One focused output, returned from typed props.
+
+ )
+ }
+})
diff --git a/packages/concrete/src/primitives/tilt-frame/index.tsx b/packages/concrete/src/primitives/tilt-frame/index.tsx
new file mode 100644
index 0000000..7baafdd
--- /dev/null
+++ b/packages/concrete/src/primitives/tilt-frame/index.tsx
@@ -0,0 +1,30 @@
+import { exampleStates, renderExample } from '../../factories/createExamples'
+import { createPrimitive } from '../../factories/createItems'
+import { TiltFrame } from './component'
+import { tiltFrameExamples } from './examples'
+import { tiltFrameMeta } from './meta'
+import { type TiltFrameValue, tiltFrameSchema } from './schema'
+
+export type { TiltFrameIntensity, TiltFrameProps, TiltFrameSurface } from './component'
+export { TiltFrame } from './component'
+export type { TiltFrameInput, TiltFrameValue } from './schema'
+export { tiltFramePropsSchema, tiltFrameSchema } from './schema'
+
+export const tiltFramePrimitiveDefinition = createPrimitive({
+ ...tiltFrameMeta,
+ component: TiltFrame,
+ kind: 'primitive',
+ renderExample: (state?: string) => renderExample(tiltFrameExamples, state),
+ renderInput: input => renderTiltFrameInput(tiltFrameSchema.parse(input)),
+ schema: tiltFrameSchema,
+ slug: 'tilt-frame',
+ states: exampleStates(tiltFrameExamples, ['controls', 'surface'])
+})
+
+function renderTiltFrameInput({ body, interactive, intensity, surface }: TiltFrameValue) {
+ return (
+
+ {body}
+
+ )
+}
diff --git a/packages/concrete/src/primitives/tilt-frame/meta.ts b/packages/concrete/src/primitives/tilt-frame/meta.ts
new file mode 100644
index 0000000..d082961
--- /dev/null
+++ b/packages/concrete/src/primitives/tilt-frame/meta.ts
@@ -0,0 +1,26 @@
+import { prop } from '../../registry/props'
+import type { ConcretePressure, PrimitiveCategory } from '../../schemas'
+
+type TiltFrameMeta = {
+ category: PrimitiveCategory
+ description: string
+ guidance: string
+ name: string
+ pressure: readonly ConcretePressure[]
+ props: readonly ReturnType[]
+}
+
+export const tiltFrameMeta = {
+ category: 'surface',
+ description: 'Pointer-aware depth container for one highlighted surface.',
+ guidance:
+ 'Use TiltFrame for one highlighted surface, not for every card in a dense grid. Keep the intensity subtle and pair with ScaleFrame when fixed preview scaling is needed.',
+ name: 'TiltFrame',
+ pressure: ['product', 'generative', 'educational'],
+ props: [
+ prop('interactive', 'boolean', 'Enables cursor-driven rotation.', 'true'),
+ prop('intensity', "'subtle' | 'medium'", 'Rotation strength.', 'subtle'),
+ prop('surface', "'raised' | 'sunken' | 'transparent'", 'Frame surface treatment.', 'raised'),
+ prop('children', 'ReactNode', 'Frame content.')
+ ]
+} as const satisfies TiltFrameMeta
diff --git a/packages/concrete/src/primitives/tilt-frame/schema.ts b/packages/concrete/src/primitives/tilt-frame/schema.ts
new file mode 100644
index 0000000..ddd4a57
--- /dev/null
+++ b/packages/concrete/src/primitives/tilt-frame/schema.ts
@@ -0,0 +1,14 @@
+import { z } from 'zod/v4'
+
+export const tiltFrameSchema = z
+ .object({
+ body: z.string().default('Depth-aware surface'),
+ intensity: z.enum(['subtle', 'medium']).default('subtle'),
+ interactive: z.boolean().default(true),
+ surface: z.enum(['raised', 'sunken', 'transparent']).default('raised')
+ })
+ .strict()
+
+export { tiltFrameSchema as tiltFramePropsSchema }
+export type TiltFrameInput = z.input
+export type TiltFrameValue = z.output
diff --git a/packages/concrete/src/primitives/tilt-frame/styles.css b/packages/concrete/src/primitives/tilt-frame/styles.css
new file mode 100644
index 0000000..9a3eb9a
--- /dev/null
+++ b/packages/concrete/src/primitives/tilt-frame/styles.css
@@ -0,0 +1,67 @@
+.concrete-tilt-frame {
+ display: grid;
+ min-width: var(--concrete-space-0);
+ perspective: var(--concrete-size-tilt-frame-perspective);
+}
+
+.concrete-tilt-frame-surface {
+ position: relative;
+ display: grid;
+ min-width: var(--concrete-space-0);
+ overflow: hidden;
+ border: var(--concrete-border-width-hairline) solid var(--concrete-border);
+ border-radius: var(--concrete-radius-4);
+ background: var(--concrete-surface);
+ box-shadow: var(--concrete-shadow-2);
+ transform: rotateX(var(--concrete-tilt-rotate-x, 0deg))
+ rotateY(var(--concrete-tilt-rotate-y, 0deg)) translate3d(0, 0, 0);
+ transform-origin: center;
+ transform-style: preserve-3d;
+ transition:
+ transform var(--concrete-duration-fast) var(--concrete-ease),
+ border-color var(--concrete-duration-fast) var(--concrete-ease),
+ box-shadow var(--concrete-duration-fast) var(--concrete-ease);
+ backface-visibility: hidden;
+ contain: paint;
+ will-change: transform;
+}
+
+.concrete-tilt-frame[data-surface="sunken"] .concrete-tilt-frame-surface {
+ border-color: var(--concrete-border-soft);
+ background: var(--concrete-sunken);
+ box-shadow: inset var(--concrete-space-0) var(--concrete-border-width-hairline)
+ var(--concrete-space-0) var(--concrete-surface);
+}
+
+.concrete-tilt-frame[data-surface="transparent"] .concrete-tilt-frame-surface {
+ border-color: transparent;
+ background: transparent;
+ box-shadow: none;
+}
+
+.concrete-tilt-frame[data-interactive="true"]:hover .concrete-tilt-frame-surface {
+ border-color: var(--concrete-border-strong);
+ box-shadow: var(--concrete-shadow-2);
+}
+
+.concrete-tilt-frame-content {
+ display: grid;
+ gap: var(--concrete-space-2);
+ min-width: var(--concrete-space-0);
+ padding: var(--concrete-space-4);
+}
+
+.concrete-tilt-frame-glare {
+ position: absolute;
+ inset: var(--concrete-space-0);
+ border-radius: inherit;
+ background: var(--concrete-tilt-frame-glare-background);
+ box-shadow: var(--concrete-tilt-frame-glare-shadow);
+ opacity: var(--concrete-opacity-hidden);
+ pointer-events: none;
+ transition: opacity var(--concrete-duration-fast) var(--concrete-ease);
+}
+
+.concrete-tilt-frame[data-interactive="true"]:hover .concrete-tilt-frame-glare {
+ opacity: var(--concrete-opacity-tilt-frame-glare);
+}
diff --git a/packages/concrete/src/registry/items.tsx b/packages/concrete/src/registry/items.tsx
index 80f1490..5b68b33 100644
--- a/packages/concrete/src/registry/items.tsx
+++ b/packages/concrete/src/registry/items.tsx
@@ -8,6 +8,7 @@ import { datePickerComponentDefinition } from '../components/date-picker'
import { dateRangePickerComponentDefinition } from '../components/date-range-picker'
import { diagramCanvasComponentDefinition } from '../components/diagram-canvas'
import { donutChartComponentDefinition } from '../components/donut-chart'
+import { featureCardComponentDefinition } from '../components/feature-card'
import { fileUploadComponentDefinition } from '../components/file-upload'
import { flowDiagramComponentDefinition } from '../components/flow-diagram'
import { formDialogComponentDefinition } from '../components/form-dialog'
@@ -104,6 +105,7 @@ import { radioPrimitiveDefinition } from '../primitives/radio'
import { railPrimitiveDefinition } from '../primitives/rail'
import { rangePrimitiveDefinition } from '../primitives/range'
import { rowPrimitiveDefinition } from '../primitives/row'
+import { scaleFramePrimitiveDefinition } from '../primitives/scale-frame'
import { scrollAreaPrimitiveDefinition } from '../primitives/scroll-area'
import { searchInputPrimitiveDefinition } from '../primitives/search-input'
import { sectionPrimitiveDefinition } from '../primitives/section'
@@ -126,6 +128,7 @@ import { tagPrimitiveDefinition } from '../primitives/tag'
import { targetLinePrimitiveDefinition } from '../primitives/target-line'
import { textPrimitiveDefinition } from '../primitives/text'
import { textareaPrimitiveDefinition } from '../primitives/textarea'
+import { tiltFramePrimitiveDefinition } from '../primitives/tilt-frame'
import { timeListPrimitiveDefinition } from '../primitives/time-list'
import { tokenPrimitiveDefinition } from '../primitives/token'
import { tokenRailPrimitiveDefinition } from '../primitives/token-rail'
@@ -245,6 +248,8 @@ export const primitiveDefinitions = [
framePrimitiveDefinition,
timeListPrimitiveDefinition,
toolCallPanelPrimitiveDefinition,
+ tiltFramePrimitiveDefinition,
+ scaleFramePrimitiveDefinition,
brandMarkPrimitiveDefinition,
wordmarkPrimitiveDefinition,
iconPrimitiveDefinition
@@ -277,6 +282,7 @@ export const componentDefinitions = [
donutChartComponentDefinition,
heatmapComponentDefinition,
chartComponentDefinition,
+ featureCardComponentDefinition,
dataTableComponentDefinition,
flowDiagramComponentDefinition,
diagramCanvasComponentDefinition,
diff --git a/packages/concrete/src/registry/types.ts b/packages/concrete/src/registry/types.ts
index efee518..50e1817 100644
--- a/packages/concrete/src/registry/types.ts
+++ b/packages/concrete/src/registry/types.ts
@@ -88,6 +88,7 @@ export type PrimitiveSlug =
| 'rail'
| 'range'
| 'row'
+ | 'scale-frame'
| 'scroll-area'
| 'search-input'
| 'select'
@@ -111,6 +112,7 @@ export type PrimitiveSlug =
| 'textarea'
| 'text'
| 'time-list'
+ | 'tilt-frame'
| 'token'
| 'tooltip'
| 'tool-call-panel'
@@ -131,6 +133,7 @@ export type ComponentSlug =
| 'data-table'
| 'date-picker'
| 'date-range-picker'
+ | 'feature-card'
| 'file-upload'
| 'flow-diagram'
| 'form-dialog'
diff --git a/packages/concrete/src/styles/class-names.ts b/packages/concrete/src/styles/class-names.ts
index ea0dc18..ce147dc 100644
--- a/packages/concrete/src/styles/class-names.ts
+++ b/packages/concrete/src/styles/class-names.ts
@@ -52,7 +52,7 @@ optionRowCopy optionRowIcon
pill progressError progressFill progressLined progressRing progressRingCenter progressRingFill progressRingTrack
progressRingUnit progressShuttle progressSky progressTerminal progressThick progressThin progressTrack progressUltra
radio radioChecked radioDot rail tokenRailItem range rangeTrack rangeValues root row rowIcon rowInteractive
-rowLabel rowMeta
+rowLabel rowMeta scaleFrame scaleFrameContent scaleFrameSurface
`,
`
section sectionBody segmentedProgress select selectWrap composerSendButton skeleton slider
@@ -62,7 +62,8 @@ stat statDisplay statLabel statLarge statMeta statMuted statNumber statSky
split splitAside splitBody stack statSmall statUnit statValue statXlarge statXsmall composerSubmitDock surface switch switchChecked
switchTrack syntaxAttribute syntaxComment syntaxFunction syntaxIdentifier syntaxKeyword syntaxNumber syntaxOperator
syntaxPunctuation syntaxString syntaxType tag tagActive tagClose tagError tagLarge text
-tagOutline tagSelected tagSky tagSmall tagTerminal tagUltra textarea timeMenu
+tagOutline tagSelected tagSky tagSmall tagTerminal tagUltra textarea tiltFrame tiltFrameContent
+tiltFrameGlare tiltFrameSurface timeMenu
trace traceStatus traceSteps traceSummaryMain traceSummaryText
`,
`
diff --git a/packages/concrete/src/styles/manifest.ts b/packages/concrete/src/styles/manifest.ts
index 9c758c2..860248c 100644
--- a/packages/concrete/src/styles/manifest.ts
+++ b/packages/concrete/src/styles/manifest.ts
@@ -111,6 +111,7 @@ export const primitiveStyleSources = [
{ kind: 'primitive', path: 'src/primitives/rail/styles.css' },
{ kind: 'primitive', path: 'src/primitives/range/styles.css' },
{ kind: 'primitive', path: 'src/primitives/row/styles.css' },
+ { kind: 'primitive', path: 'src/primitives/scale-frame/styles.css' },
{ kind: 'primitive', path: 'src/primitives/scroll-area/styles.css' },
{ kind: 'primitive', path: 'src/primitives/search-input/styles.css' },
{ kind: 'primitive', path: 'src/primitives/select/styles.css' },
@@ -134,6 +135,7 @@ export const primitiveStyleSources = [
{ kind: 'primitive', path: 'src/primitives/textarea/styles.css' },
{ kind: 'primitive', path: 'src/primitives/text/styles.css' },
{ kind: 'primitive', path: 'src/primitives/time-list/styles.css' },
+ { kind: 'primitive', path: 'src/primitives/tilt-frame/styles.css' },
{ kind: 'primitive', path: 'src/primitives/token/styles.css' },
{ kind: 'primitive', path: 'src/primitives/tooltip/styles.css' },
{ kind: 'primitive', path: 'src/primitives/tool-call-panel/styles.css' },
diff --git a/packages/concrete/src/tests/import-boundaries.test.ts b/packages/concrete/src/tests/import-boundaries.test.ts
index 859dfbb..f138988 100644
--- a/packages/concrete/src/tests/import-boundaries.test.ts
+++ b/packages/concrete/src/tests/import-boundaries.test.ts
@@ -101,6 +101,7 @@ const dynamicPrimitiveInlineStyleFiles = [
'packages/concrete/src/primitives/heatmap-grid/component.tsx',
'packages/concrete/src/primitives/progress/component.tsx',
'packages/concrete/src/primitives/range/component.tsx',
+ 'packages/concrete/src/primitives/scale-frame/component.tsx',
'packages/concrete/src/primitives/skeleton/component.tsx',
'packages/concrete/src/primitives/slider/component.tsx',
'packages/concrete/src/primitives/table/component.tsx',
@@ -499,7 +500,7 @@ describe('Import boundaries', () => {
([key, value]) => value !== toConcreteSelector(key)
)
- expect(concreteClassNameEntries.length).toBe(507)
+ expect(concreteClassNameEntries.length).toBe(514)
expect(classNameRecord.button).toBe('concrete-button')
expect(classNameRecord.diagramCanvasEdgeSelected).toBe('concrete-diagram-canvas-edge-selected')
expect(classNameRecord.alertAction).toBe('concrete-alert-action')
diff --git a/packages/concrete/src/tests/registry.test.ts b/packages/concrete/src/tests/registry.test.ts
index 3329950..c2f84b0 100644
--- a/packages/concrete/src/tests/registry.test.ts
+++ b/packages/concrete/src/tests/registry.test.ts
@@ -666,6 +666,8 @@ describe('Concrete registry', () => {
'frame',
'time-list',
'tool-call-panel',
+ 'tilt-frame',
+ 'scale-frame',
'brand-mark',
'wordmark',
'icon'
@@ -697,6 +699,7 @@ describe('Concrete registry', () => {
'donut-chart',
'heatmap',
'chart',
+ 'feature-card',
'data-table',
'flow-diagram',
'diagram-canvas',