@meetelise/studio-components
v0.1.53
Published
Elise Studio component library — renderer, layout primitives, and data-fetching components for property websites
Keywords
Readme
elise-studio-components
Curated floor plan catalogs
FloorplanCatalog is a grouped, selector-and-accordion presentation of live
Elise floor plans. Each authored plan is a reference to an Elise floor plan id;
references missing from the authenticated property API are not rendered.
Authored JSON controls group order, marketing copy, actions, optional image
fallbacks, and an optional square-footage marketing label. API records remain
the source of identity, bed/bath values, availability, rent, and preferred
media. The component follows all cursor pages so a curated id is not lost
beyond the first response page, and stops safely if the API repeats a cursor.
The catalog uses Studio's keyed sm through 2xl responsive contract and a
semantic collapseAt breakpoint. Actions reuse the canonical Button contract,
navigation stays router-aware, analytics emit canonical API floor plan ids, and
images use the shared accessible Lightbox. FloorplanExplorer remains unchanged
for uncurated listing grids and lists. A validated compactPresentation object
controls accordion typography, rhythm, panel insets, and action alignment below
the collapse breakpoint without relying on arbitrary classes or site templates.
The opt-in desktopPresentation: "workspace" mode integrates a bounded,
scrollable grouped selector with a stable summary-and-drawing canvas for larger
catalogs. Selector headings, counts, and API-backed plan details are separately
configurable. Below collapseAt, compactDisclosure: "single" turns the same
catalog into a globally single-open inline accordion; responsive detail columns
and connected panel styling remain authored presentation choices. The default
split/perGroup behavior and API contract are unchanged.
Motion and background media
BackgroundMedia is a generic frame for decorative image or muted video
backgrounds. It accepts normal Studio children, so headings, buttons, and data
components remain independently editable. The optional parallax motion moves
only the media layer; overlay content and document layout stay fixed. Video is
paused outside the viewport and replaced by its poster or image when the visitor
requests reduced motion. If no still is authored, a paused first video frame is
used instead.
{
"type": "BackgroundMedia",
"props": {
"video": { "$content": "hero.video" },
"poster": { "$content": "hero.poster" },
"minHeight": "90vh",
"contentPosition": "bottom-left",
"motion": "parallax"
},
"children": [
{
"type": "Text",
"props": { "content": { "$content": "hero.headline" }, "variant": "display" }
}
]
}Parallax applies the same bounded, request-animation-frame scroll transform to
any child subtree. StickyFrame pins a subtree within its parent scroll range
and defaults to normal flow on mobile. Together with Grid, Container, and
ScrollReveal, these frames support sticky storytelling, independently moving
media, and layered editorial sections without site-specific JavaScript or CSS.
All motion is progressive enhancement: server output remains visible, unsupported
browsers retain a static layout, and operating-system reduced-motion preferences
disable continuous translation.
Atlas authoring contract
The exported component schema includes optional authoring metadata for Atlas and
semantic validators. It describes component roles, breakpoint-aware props,
composition constraints, required context, relative performance cost, stable repair
hints, and recommended recipe IDs. Runtime rendering ignores this metadata.
The generated dist/componentSchema.json versions the component schema, authoring
contract, and diagnostic envelope independently. Diagnostics use a shared shape and
may include existing Studio design operations for Atlas to apply:
{
"code": "STICKY_MEDIA_OVERLAP",
"severity": "error",
"nodeId": "hero-media",
"breakpoint": "sm",
"message": "The transformed media can leave its sticky boundary.",
"suggestedOperations": [
{
"type": "set_node_prop",
"node_id": "hero-media",
"prop_path": ["motion"],
"value": "none"
}
]
}validateAuthoringTree is the shared, side-effect-free semantic validator used by
Atlas, preview, and compiler consumers. It checks required props, component nesting,
authoring contexts, incompatibilities, deprecations, and an optional normalized
performance budget without resolving or rendering the tree:
const { diagnostics, performanceCost } = validateAuthoringTree(page.tree, {
availableContexts: ["property"],
performanceBudget: 24,
path: "pages[0].tree",
});Errors represent invalid authoring decisions; warnings cover deprecations, unknown props, and budget pressure. When a safe default exists, a diagnostic may include a typed Studio design operation that Atlas can apply as a repair.
Atlas composition recipes
The @meetelise/studio-components/recipes export and generated
dist/authoringRecipes.json provide versioned, validated section blueprints. Each
recipe declares its content fields, required site contexts, normalized performance
budget, and a normal Studio component tree using $content bindings. The initial
catalog includes editorial hero, split-media story, sticky-media story, and
availability/conversion compositions.
Recipes are build-validated against the canonical component schema and semantic validator. A build fails if a recipe references an unknown component, an undeclared content key, or a missing recipe ID. Atlas can therefore select a recipe, create its declared content fields, and insert the tree through ordinary typed Studio operations.
Amenity presentations
AmenityList keeps layout and ordering independent. Existing sites continue to
use the alphabetized icon-grid default, while order="source" preserves the
first occurrence of each amenity from either authored content or the Elise
property API. The opt-in bulleted layout emits semantic ul/li markup and
uses theme body typography. Its indentation, item spacing, and typography can
be adjusted through the validated bulletPresentation object without baking a
property's measurements into the shared component.
Navigation presentations
Nav keeps the inline, solid header and dropdown menu as its default. Sites may
opt into stacked or overlay layouts, compact links or equal-width tabs, separate
primary and utility actions, per-link desktop/mobile visibility, a scrolled logo,
an optional compact scroll effect, and a modal drawer. The existing sticky
flag controls viewport following while overlay controls whether the initial
header occupies document flow. collapseAt uses the shared sm/md/lg/xl/2xl
breakpoints. Optional validated lengths control logo bounds, link rhythm, content
width, section padding, tab borders, and drawer width without embedding a site
template in the component. For sticky compact navigation, optional topStyle
and scrolledStyle objects can independently control validated logo height,
frame padding and gap, background color/opacity, divider, shadow, backdrop blur, and
foreground scheme. A bounded pixel threshold and whitelisted transition timing
provide a two-state CSS transition with an optional logo crossfade; reduced-motion
preferences disable that motion. Button-style links consume the canonical Button
presentation contract. Omitting the presentation fields preserves the existing
inline/dropdown behavior.
Footer presentations
Footer keeps its columns-and-copyright output as the default. The optional
property presentation composes structured brand, address, contact, action,
badge, and legal content inside one semantic footer. Sections and responsive
grids follow the content that is present; actions reuse Button's canonical
presentation and routing behavior. propertyLayout and keyed
responsivePropertyLayout overrides use Studio's shared breakpoints and
validated CSS lengths, while colors come from the active theme.
Responsive layout overrides
Container and Stack keep their token spacing as the default design language. For
layouts that need exact authored geometry, Container also accepts optional base
edge padding values and keyed responsivePadding overrides. Studio uses the same
mobile-first scale as Tailwind: sm (40rem), md (48rem), lg (64rem), xl
(80rem), and 2xl (96rem). Stack and Grid use the same duplicate-free keyed
contract for authored gaps. Values are limited to simple CSS lengths with finite,
unit-specific bounds; malformed and extreme declarations are ignored. Container
bottom margin is signed so layout composition can intentionally overlap sections.
Button supports the same opt-in pattern for base/responsive font size, weight,
line-height, tracking, horizontal/vertical padding, border width, inset outline,
and bounded shadow presets. responsiveTypography can override font size, line
height, or signed letter spacing at the shared breakpoints. Focus presentation is
site-wide rather than per button: token themes may define focus.ring.width,
focus.ring.offset, and focus.ring.color. Unsafe values are ignored, and the
native focus indicator remains the fallback. Omitting presentation fields
preserves the existing variant/size output.
Background-image sections can opt into bgAttachment and
responsiveBgAttachment (scroll or fixed). Omitting both preserves the
browser default while allowing authored fixed-background behavior at any shared
breakpoint without runtime-authored CSS classes. Background position supports
edges and all four corners. bgOverlayOpacity controls the overlay layer
independently from its color and is bounded to the CSS opacity range.
Coordinate-aware property maps
PropertyMap renders a property coordinate on the same map runtime used by
Studio's unit marketplace. Its default MapLibre style is served by Elise; an
installation may instead configure Mapbox or an alternate style through the
existing Studio runtime configuration. Provider credentials are platform
configuration and are never authored into site JSON.
Authors control center, zoom, responsive height, the property marker, and an
optional list of nearby-place markers. Every marker can use an image or safe
custom/category color, a structured information card, and a generated or custom
Google Maps view/directions action. When nearby places are present the map fits
the property and visible places by default; authors may opt back into manual
center and zoom. Only one card opens at a time and it remains attached to its
coordinate while the visitor pans or zooms, flips and clamps inside the map
viewport, supports phone, email, and Google Maps actions, and can be dismissed
and reopened. Responsive values use Studio's keyed sm through 2xl contract.
MapEmbed remains the lightweight iframe option and retains its existing output
and TypeScript markers input.
Contact form presentations
ContactForm keeps its existing comfortable, stacked lead form as the default
and continues to submit through Elise's authenticated /v1/prospect endpoint.
Opt-in grid layout, one-to-three columns, compact density, grouped names,
configurable fields, labels, and requiredness are independent authoring choices.
The native date input remains the default; usText accepts editable numeric or
punctuated input, formats it on blur, validates the calendar date, and sends the
existing ISO move_in_date payload.
Base and keyed responsive values can control row, column, and label-to-control gaps. A bounded control-presentation object covers minimum heights, padding, border, radius, and label typography without embedding a site template. Submit buttons consume the canonical Button presentation contract and add independent base/responsive alignment. Invalid authored CSS values are ignored, fields keep theme colors and visible focus, and validation errors identify and focus the affected control.
Property SEO template tokens
A building_template: true page may use the following compile-time tokens in
plain string fields. Resolution is recursive, so the same tokens work in the
page path, search/social metadata, and nested seo.structuredData strings.
| Token | Merged content source |
| --- | --- |
| {{property.name}} | building.name |
| {{property.slug}} | vars.slug |
| {{property.city}} | building.city |
| {{property.state}} | building.state |
| {{property.neighborhood}} | building.neighborhood |
| {{property.address}} | building.address |
| {{property.shortDescription}} | building.short_description, then building.tagline |
| {{property.amenitySummary}} | building.amenity_summary |
| {{property.bedroomRange}} | building.bedroom_range |
| {{site.name}} | site.name, then merged meta.name / meta.title, then raw site name metadata |
The existing {{slug}} syntax remains an alias for vars.slug. A token whose
source is missing stays visibly unresolved so publish-time SEO checks can report
the missing data. Runtime {$data: "..."} bindings are never interpolated.
Property hero images are intentionally not string tokens. Author an image or
social-image field with the building-scoped object binding
{$content: "building.image"}; the resolver converts its AssetValue to that
building's CDN URL.
Typography theme tokens
Typography is configured by role so a bounded token set can cover every Text variant. All tokens are optional. Without an authored role override, each variant retains its built-in responsive size, weight, line-height, and tracking.
| Role | Family | Scale | Weight | Line height | Tracking |
| --- | --- | --- | --- | --- | --- |
| Heading (display, h1–h3) | font.heading | font.heading.scale | font.heading.weight | font.heading.line-height | font.heading.tracking |
| Body (subtitle, body, body-lg, caption, overline) | font.body | font.body.scale | font.body.weight | font.body.line-height | font.body.tracking |
Scale is a unitless multiplier such as "1.1". Weight and line-height accept
CSS values such as "600" and "1.4"; tracking accepts a CSS letter-spacing
value such as "-0.02em". All values may use the existing {$token} alias
shape, and building-mode overrides inherit through ThemeScope.
Individual Text nodes can override base font size, weight, line height,
letter spacing, transform, and alignment. The keyed responsiveTypography
object uses the same sm through 2xl contract as layout and Button, with
optional font-size, line-height, and signed letter-spacing values at each
minimum viewport. Values are validated and bounded before rendering; invalid
authored values are ignored without removing the variant defaults.
Body Google fonts include the regular italic face in addition to the upright weight range, allowing semantic emphasis to use the selected family without requesting every italic weight. Duplicate stylesheet requests are suppressed.
