Technical Specs Sheet
blockecommerceComprehensive engineering technical specifications sheet with Metric/Imperial SI toggles, parameter category filters, search, and downloadable PDF trigger.
Installation
$pnpm dlx shadcn@latest add https://uipkge.dev/r/lit/technical-specs-sheet.json$npx shadcn@latest add https://uipkge.dev/r/lit/technical-specs-sheet.json$yarn dlx shadcn@latest add https://uipkge.dev/r/lit/technical-specs-sheet.json$bunx shadcn@latest add https://uipkge.dev/r/lit/technical-specs-sheet.jsonManifest:
https://uipkge.dev/r/lit/technical-specs-sheet.jsonInstalls to:src/uip/blocks/technical-specs-sheet/Variants
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
model-number | string | APX-950-PRO | optional |
revision | string | Rev 2.4 (2026) | optional |
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
SpecIteminterface SpecItem {
id: string
category: 'acoustic' | 'electrical' | 'physical' | 'connectivity' | 'compliance'
parameter: string
metricValue: string
imperialValue: string
tolerance?: string
testCondition?: string
highlight?: boolean
}HTMLElementTagNameMapinterface HTMLElementTagNameMap {
'uip-technical-specs-sheet': UipTechnicalSpecsSheet
}
}Files installed (1)
src/uip/blocks/technical-specs-sheet/technical-specs-sheet.ts17.3 kB
import { LitElement, css, html, nothing } from 'lit' import { FileDown, ShieldCheck, CheckCircle2, Search, Info } from 'lucide' import { tailwind } from '../../lib/styles' import { ThemeController } from '../../lib/theme' import { icon } from '../../lib/icon' // Side-effect imports: register the composed elements for standalone use // (consumers who install only this block still get working primitives). import '../../components/badge/badge' import '../../components/button/button' import '../../components/card/card' import '../../components/input/input' import type { UipInput } from '../../components/input/input' export interface SpecItem { id: string category: 'acoustic' | 'electrical' | 'physical' | 'connectivity' | 'compliance' parameter: string metricValue: string imperialValue: string tolerance?: string testCondition?: string highlight?: boolean } const defaultSpecs: SpecItem[] = [ { id: 's1', category: 'acoustic', parameter: 'Transducer Type', metricValue: '50mm Planar-Magnetic with Neodymium N52 Array', imperialValue: '1.97 in Planar-Magnetic with Neodymium N52 Array', highlight: true, }, { id: 's2', category: 'acoustic', parameter: 'Frequency Response', metricValue: '5 Hz – 52,000 Hz', imperialValue: '5 Hz – 52,000 Hz', tolerance: '± 0.5 dB (20 Hz - 20 kHz)', highlight: true, }, { id: 's3', category: 'acoustic', parameter: 'Total Harmonic Distortion (THD)', metricValue: '< 0.04% @ 1 kHz, 100 dB SPL', imperialValue: '< 0.04% @ 1 kHz, 100 dB SPL', testCondition: 'IEC 60268-7 Standard', }, { id: 's4', category: 'acoustic', parameter: 'Sound Pressure Level (SPL)', metricValue: '106 dB / 1 mW @ 1 kHz', imperialValue: '106 dB / 1 mW @ 1 kHz', testCondition: 'Free-field calibrated', }, { id: 's5', category: 'acoustic', parameter: 'Acoustic Enclosure', metricValue: 'Open-Back CNC Milled Aircraft-Grade Aluminum Grille', imperialValue: 'Open-Back CNC Milled Aircraft-Grade Aluminum Grille', }, { id: 's6', category: 'electrical', parameter: 'Nominal Impedance', metricValue: '32 Ω pure resistive load', imperialValue: '32 Ω pure resistive load', tolerance: '± 5% @ 1 kHz', highlight: true, }, { id: 's7', category: 'electrical', parameter: 'Maximum Input Power Handling', metricValue: '3,000 mW (3.0 W Continuous)', imperialValue: '3,000 mW (3.0 W Continuous)', testCondition: 'Thermal peak 5,000 mW (100ms)', }, { id: 's8', category: 'electrical', parameter: 'Recommended Amplifier Output', metricValue: '250 mW – 2,000 mW @ 32 Ω', imperialValue: '250 mW – 2,000 mW @ 32 Ω', }, { id: 's9', category: 'physical', parameter: 'Weight (excluding cable)', metricValue: '385 grams', imperialValue: '13.58 oz (0.85 lbs)', tolerance: '± 5g', highlight: true, }, { id: 's10', category: 'physical', parameter: 'Ear Cushion Dimensions (Inner ID)', metricValue: '68 mm (H) × 52 mm (W) × 26 mm (D)', imperialValue: '2.68 in (H) × 2.05 in (W) × 1.02 in (D)', }, { id: 's11', category: 'physical', parameter: 'Headband Clamping Force', metricValue: '4.2 Newtons', imperialValue: '0.94 lbf (Pound-force)', tolerance: '± 0.3 N', }, { id: 's12', category: 'physical', parameter: 'Earpad Material Composition', metricValue: 'Perforated Lambskin + Cooling Gel Memory Foam Core', imperialValue: 'Perforated Lambskin + Cooling Gel Memory Foam Core', }, { id: 's13', category: 'connectivity', parameter: 'Headphone Terminals', metricValue: 'Dual 3.5mm Gold-Plated TRRS Balanced Sockets', imperialValue: 'Dual 1/8 in Gold-Plated TRRS Balanced Sockets', }, { id: 's14', category: 'connectivity', parameter: 'Included Studio Cable', metricValue: '2.5 meter 8-Core Monocrystalline Silver-Plated Copper (OCC)', imperialValue: '8.20 feet 8-Core Monocrystalline Silver-Plated Copper (OCC)', highlight: true, }, { id: 's15', category: 'connectivity', parameter: 'Source Termination', metricValue: '4.4mm Pentaconn Balanced + 6.35mm Gold-Plated Adapter', imperialValue: '4.4mm Pentaconn Balanced + 1/4 in Gold-Plated Adapter', }, { id: 's16', category: 'compliance', parameter: 'Certifications & Directives', metricValue: 'Hi-Res Audio Certified, CE Mark, FCC Class B, RoHS 3, WEEE', imperialValue: 'Hi-Res Audio Certified, CE Mark, FCC Class B, RoHS 3, WEEE', highlight: true, }, { id: 's17', category: 'compliance', parameter: 'Operating Temperature & Humidity', metricValue: '-10°C to +45°C (10% to 90% RH non-condensing)', imperialValue: '14°F to 113°F (10% to 90% RH non-condensing)', }, ] const categories = [ { id: 'all', label: 'All Specifications' }, { id: 'acoustic', label: 'Acoustic Architecture' }, { id: 'electrical', label: 'Electrical & Power' }, { id: 'physical', label: 'Dimensions & Weight' }, { id: 'connectivity', label: 'Cables & Interconnects' }, { id: 'compliance', label: 'Standards & Compliance' }, ] /** * <uip-technical-specs-sheet> — the registry TechnicalSpecsSheet block as a web component. * * Class strings and spec data are React's verbatim. React state becomes * { state: true } fields; `specs` is a property (attribute: false — set it from * JS). React's `downloadPdf` alert becomes a `download-pdf` CustomEvent * (bubbles, composed). The spec grid uses a native <table> with the registry * Table part classes copied verbatim — <uip-table>'s data-driven API can't * express per-row highlight classes or the empty-state spanning row. The * search icon moves from an absolute overlay into <uip-input>'s prefix slot. */ export class UipTechnicalSpecsSheet extends LitElement { static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true } // :host display can't be a utility class (the host has no template of its own). static styles = [tailwind, css`:host { display: block; }`] static properties = { modelNumber: { attribute: 'model-number' }, revision: {}, specs: { attribute: false }, isMetric: { state: true }, activeCategory: { state: true }, searchQuery: { state: true }, } modelNumber = 'APX-950-PRO' revision = 'Rev 2.4 (2026)' specs: SpecItem[] = defaultSpecs private isMetric = true private activeCategory = 'all' private searchQuery = '' constructor() { super() new ThemeController(this) } connectedCallback() { super.connectedCallback() this.setAttribute('data-uipkge', '') this.setAttribute('data-slot', 'technical-specs-sheet') } private get filteredSpecs(): SpecItem[] { return (this.specs ?? []).filter((item) => { const matchesCat = this.activeCategory === 'all' || item.category === this.activeCategory const matchesSearch = this.searchQuery.trim() === '' || item.parameter.toLowerCase().includes(this.searchQuery.toLowerCase()) || item.metricValue.toLowerCase().includes(this.searchQuery.toLowerCase()) || item.imperialValue.toLowerCase().includes(this.searchQuery.toLowerCase()) return matchesCat && matchesSearch }) } render() { const filteredSpecs = this.filteredSpecs // data-slot lives on this wrapper: <uip-card> stamps its own // data-slot="card" on connect, which would clobber the block slot. return html` <div data-slot="technical-specs-sheet"> <uip-card class="border-border w-full shadow-xs"> <uip-card-header class="border-border bg-muted/20 border-b pb-4"> <div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between"> <div> <div class="flex items-center gap-2"> <span class="text-muted-foreground font-mono text-xs font-semibold tracking-wider uppercase"> ${this.modelNumber} · ${this.revision} </span> <uip-badge variant="outline" class="text-success font-mono text-xs">Laboratory Certified</uip-badge> </div> <uip-card-title class="text-foreground text-lg font-semibold tracking-tight sm:text-xl"> Engineering & Technical Specifications Sheet </uip-card-title> <uip-card-description class="text-xs"> Comprehensive acoustic measurements, electrical parameters, material tolerances, and compliance standards. </uip-card-description> </div> <div class="flex flex-wrap items-center gap-2.5"> <div class="border-border bg-background flex items-center rounded-lg border p-0.5 text-xs shadow-2xs"> <button type="button" class=${`rounded-md px-2.5 py-1 font-medium transition-colors ${ this.isMetric ? 'bg-primary text-primary-foreground font-semibold shadow-2xs' : 'text-muted-foreground hover:text-foreground' }`} @click=${() => { this.isMetric = true }} > Metric (SI) </button> <button type="button" class=${`rounded-md px-2.5 py-1 font-medium transition-colors ${ !this.isMetric ? 'bg-primary text-primary-foreground font-semibold shadow-2xs' : 'text-muted-foreground hover:text-foreground' }`} @click=${() => { this.isMetric = false }} > Imperial (US) </button> </div> <uip-button variant="outline" size="sm" class="gap-1.5 text-xs shadow-2xs" @click=${() => this.dispatchEvent(new CustomEvent('download-pdf', { bubbles: true, composed: true }))} > ${icon(FileDown, 'file-down', 'size-3.5')} <span>Download Spec PDF</span> </uip-button> </div> </div> <div class="mt-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between"> <div class="flex flex-wrap items-center gap-1.5"> ${categories.map( (cat) => html`<button type="button" class=${`rounded-md px-2.5 py-1 text-xs font-medium transition-colors ${ this.activeCategory === cat.id ? 'bg-foreground text-background shadow-2xs' : 'bg-muted/60 text-muted-foreground hover:bg-muted hover:text-foreground border border-transparent' }`} @click=${() => { this.activeCategory = cat.id }} > ${cat.label} </button>`, )} </div> <uip-input .value=${this.searchQuery} placeholder="Search parameters..." class="h-8 w-full text-xs sm:w-64" @input=${(e: Event) => { this.searchQuery = (e.target as UipInput).value ?? '' }} > <span slot="prefix">${icon(Search, 'search', 'size-3.5')}</span> </uip-input> </div> </uip-card-header> <uip-card-content class="p-0"> <div data-uipkge="" data-slot="table-container" class="relative w-full overflow-auto"> <table data-uipkge="" data-slot="table" class="w-full caption-bottom text-sm"> <thead data-uipkge="" data-slot="table-header" class="bg-muted/50 [&_tr]:border-b"> <tr data-uipkge="" data-slot="table-row" class="border-b transition-colors duration-150 hover:bg-transparent"> <th data-uipkge="" data-slot="table-head" class="text-foreground h-10 px-3 text-left align-middle text-sm font-medium whitespace-nowrap w-[280px]" > Parameter / Measurement </th> <th data-uipkge="" data-slot="table-head" class="text-foreground h-10 px-3 text-left align-middle text-sm font-medium whitespace-nowrap" > Specification (${this.isMetric ? 'Metric' : 'Imperial'}) </th> <th data-uipkge="" data-slot="table-head" class="text-foreground h-10 px-3 text-left align-middle text-sm font-medium whitespace-nowrap w-[180px]" > Tolerance / Range </th> <th data-uipkge="" data-slot="table-head" class="text-foreground h-10 px-3 text-left align-middle text-sm font-medium whitespace-nowrap w-[220px]" > Test Standard / Method </th> </tr> </thead> <tbody data-uipkge="" data-slot="table-body" class="[&_tr:last-child]:border-0"> ${filteredSpecs.map( (spec) => html`<tr data-uipkge="" data-slot="table-row" class=${`border-b transition-colors duration-150 hover:bg-muted/50 ${spec.highlight ? 'bg-primary/5' : ''}`} > <td data-uipkge="" data-slot="table-cell" class="px-3 py-2 align-middle text-sm whitespace-nowrap"> <div class="flex items-center gap-2"> <span class="text-foreground text-xs font-medium">${spec.parameter}</span> ${spec.highlight ? html`<uip-badge variant="secondary" class="h-4.5 px-1.5 font-mono text-xs font-semibold uppercase"> Key Spec </uip-badge>` : nothing} </div> </td> <td data-uipkge="" data-slot="table-cell" class="px-3 py-2 align-middle text-sm whitespace-nowrap"> <span class="text-foreground font-mono text-xs font-semibold" >${this.isMetric ? spec.metricValue : spec.imperialValue}</span > </td> <td data-uipkge="" data-slot="table-cell" class="px-3 py-2 align-middle text-sm whitespace-nowrap"> <span class="text-muted-foreground font-mono text-xs">${spec.tolerance || '—'}</span> </td> <td data-uipkge="" data-slot="table-cell" class="px-3 py-2 align-middle text-sm whitespace-nowrap"> <span class="text-muted-foreground text-xs">${spec.testCondition || 'Factory Standard Q/C'}</span> </td> </tr>`, )} ${filteredSpecs.length === 0 ? html`<tr data-uipkge="" data-slot="table-row" class="border-b transition-colors duration-150"> <td data-uipkge="" data-slot="table-cell" colSpan="4" class="px-3 py-2 align-middle text-sm whitespace-nowrap text-muted-foreground h-28 text-center text-xs" > No matching specifications found for "${this.searchQuery}". </td> </tr>` : nothing} </tbody> </table> </div> <div class="border-border bg-muted/20 flex flex-wrap items-center justify-between gap-3 border-t p-4 text-xs"> <div class="text-muted-foreground flex flex-wrap items-center gap-4"> <div class="flex items-center gap-1.5"> ${icon(ShieldCheck, 'shield-check', 'text-primary size-4')} <span class="text-foreground font-medium">Calibrated Precision</span> </div> <div class="flex items-center gap-1.5"> ${icon(CheckCircle2, 'circle-check', 'text-success size-4')} <span>3-Year Studio Warranty Included</span> </div> <div class="flex items-center gap-1.5"> ${icon(Info, 'info', 'text-info size-4')} <span>Serial matched drivers (± 0.3 dB stereo tracking)</span> </div> </div> <span class="text-muted-foreground font-mono text-xs">Document ID: SPEC-APX-${this.modelNumber}-2026</span> </div> </uip-card-content> </uip-card> </div> ` } } customElements.get('uip-technical-specs-sheet') || customElements.define('uip-technical-specs-sheet', UipTechnicalSpecsSheet) declare global { interface HTMLElementTagNameMap { 'uip-technical-specs-sheet': UipTechnicalSpecsSheet } }
Raw manifest:https://uipkge.dev/r/lit/technical-specs-sheet.json