Releases: EchoTechFE/devicekit
Releases · EchoTechFE/devicekit
Release list
v0.4.0
@devicekit/frame@0.4.1-alpha.0
@devicekit/devices@0.4.1-alpha.0
Patch Changes
- 39f32b3: Test changeset to verify the OIDC trusted-publishing release pipeline end to end via an alpha prerelease. No functional change.
v0.3.0
Added
@devicekit/frame: addinteraction-mode(mobile,mobile-no-touch,desktop,desktop-touch) for touch or mouse preview affordances, including the frame demo control and React prop. Defaultmobilenow shows a centered touch-ring cursor over the screen, where previous releases used the normal cursor.@devicekit/devices: bundled profiles now includereleaseYear, and the preset exports usePresetDeviceProfileso selectors can sort models chronologically without handling a missing year.@devicekit/devicesand@devicekit/frame: add iPhone 18 Pro, iPhone 18 Pro Max, and beta iPhone Duo inner/outer profiles with foldable geometry, orientation-aware camera cutouts, Duo status chrome, and 1:1 CSS scaling in the frame demo.@devicekit/frame: rebuild the hosted demo with Astro, with a static page, canonical URL and JSON-LD for every device profile, plus sitemap and robots routes.
Changed
@devicekit/frame: sort each demo device group by release year, newest first, and select iPhone 18 Pro by default.@devicekit/devicesand@devicekit/frame: render separate iOS, stock Android, Samsung, HyperOS and HarmonyOS status-bar typography, spacing and project-owned glyph masks. The frame demo applies the matching UI family and profile system version to its Light/Dark preview chrome.
Fixed
@devicekit/frame: shells with asymmetric bezel insets now derive concentric per-corner radii without overriding an explicitbodyRadius.
v0.2.3
Fixed
- Home-button iPhones now render with thick top and bottom bezels and a physical Home button, including the correct chassis rotation in landscape.
- Hiding status-bar text no longer removes a phone's physical notch or Dynamic Island.
- Documented the per-edge shell geometry and reflected bezel variables.
v0.2.2
Fixed
@devicekit/devices: the 13 Home-button iPhones (iPhone 4 through iPhone 8 Plus, both SE models) had noshell, so they took the iOS default 38px screen radius and the rounded corner clipped the status-bar icons. Their flat LCD panels have square corners; they now resolve toscreenRadius: 0with a 38px body radius.
Also in this release: rewritten READMEs with rendered device images.
v0.2.1
Fixed
- The screen now paints its own background (
--device-screen-background, default#ffffff). Without anavigation-barslot the transparent status bar used to show the near-black frame body through, hiding black status-bar text. A dark page should set the variable to its own background so white status-bar text keeps its contrast.
v0.2.0
Added
@devicekit/devices:DEVICE_NAMES— every device name as a constant, soDEVICE_NAMES.iPhone_16_Proreplaces the hand-typed'iPhone 16 Pro'and the editor can autocomplete and check it. Keys are derived from the name bydeviceNameKey(runs of characters outside[A-Za-z0-9]become one_, so'iPhone 12/13 (Pro)'isiPhone_12_13_Pro); the table lives in a generated file kept in sync bypnpm --filter @devicekit/devices generate:device-namesand guarded by a test.@devicekit/devices:DeviceName, the union of every name in the table.@devicekit/frame/react: thedeviceprop acceptsDeviceNamefor autocomplete while still taking any string.
Changed
@devicekit/framenow depends on@devicekit/deviceswith a caret range instead of an exact version.
v0.1.0
Added
@devicekit/devices: device presets for iOS, Android and HarmonyOS phones and tablets, with screen, pixel ratio, status bar, safe area and user agent data.@devicekit/frame: a framework-agnostic<device-frame>custom element (plus a React wrapper) that draws a bezel, status bar and home indicator around any previewed page.@devicekit/frame: the default slot is laid out by the element itself — below the status and navigation bars, above the tab bar, the whole screen underimmersive— so a host no longer pads its own content.@devicekit/frame:refreshContentRect(), for re-measuring after a change aResizeObservercannot see, such as a CSStransform: scale()on an ancestor.@devicekit/frame:DeviceFrameElementEventMap, soaddEventListener('contentrectchange', ...)givesevent.detailitsContentRecttype.@devicekit/frame/react:os,cutout,width,height,pixelRatio,userAgent,statusBarHeightandsafeAreaTop/-Right/-Bottom/-Leftprops;statusBarnow takesboolean | 'live' | string.@devicekit/frame/react: JSX types for the raw<device-frame>tag under both React 18 and React 19.@devicekit/frame: importing the package under Node or during SSR no longer throws —defineDeviceFrame()is a no-op wherecustomElementsdoes not exist.@devicekit/frame:device,orientation,embeddedandimmersiveare writable properties that reflect to the same-named attributes, soel.device = 'iPhone 15'works like setting the attribute.pnpm run verify:pack: packs every workspace package, unpacks the tarball and importsdist/index.jsfrom plain Node, so a brokenpublishConfigcannot reach npm. The publish workflow runs it before publishing.
Fixed
@devicekit/frame: default-slot content was drawn under the status and navigation bars instead of below them.@devicekit/frame/react: under React 19 the wrapper threwTypeError: Cannot set property device ... which has only a getter, because React 19 assigns props that exist as element properties instead of setting attributes. Verified against the packed tarball with react-dom 19.2.@devicekit/devices: in landscape, Android and HarmonyOS devices without an explicitsafeAreaInsetsLandscapereported a safe-area top of0while the landscape status bar was 24 / 36 px, so immersive content was drawn under the status bar. The landscape default now mirrors portrait: top equals the landscape status bar height.@devicekit/devices:Surface Duo (inner)andHUAWEI Pura X Max (inner)were stored wider than tall; the table stores portrait sizes, soorientation="landscape"now yields the unfolded shape.@devicekit/frame: acontentrectchangelistener that changed an attribute (flippingimmersive, say) made listeners registered after it receive the new rect first and the stale one second, so a host positioning a native view from the event ended one step behind. Nested changes are now queued and re-dispatched after the outer event, in the order they happened.@devicekit/frame: the home indicator was drawn under the tab bar; it now sits above the tab bar and below the overlay, as on a real device.@devicekit/frame:status-bar="live"started a clock timer even when the element was not in the document (attribute set before connect, or after disconnect); the clock now only runs while connected.@devicekit/frame:defineDeviceFrame(tag)silently did nothing when the tag was already taken by an unrelated element class; it now throws a clear error, while re-registering the same implementation (hot reload, duplicate bundles) stays a no-op.- Publish workflow: the npm dist-tag is now decided from the package versions themselves — any pre-release version publishes to
next, and asking forlatestwith a pre-release version fails the job instead of publishing. - Publish workflow: a manual run from any branch could publish that branch to npm; the job now only runs for a GitHub Release or a dispatch on
main. - Workflows: every
uses:was a movable major tag (actions/checkout@v6); all are pinned to commit SHAs, with Dependabot moving the pins. - Pages workflow: the
buildjob heldpages: writeandid-token: writeit never used; only thedeployjob has them now. @devicekit/devices: the README and the source comment claimed iOS 26 added a 20 px top inset in landscape. No iPhone has a landscape top inset; the iPhone 17 line moved the landscape bottom inset from 21 to 20. The README also said Android and HarmonyOS landscape values equal their portrait values; unset landscape fields fall back to the platform defaults (24 / 36 px status bar) instead.@devicekit/frame/react: thestatusBarTextStyleJSDoc claimed the default ink color "follows the device";statusBarTextColoronly ever branches on'white'and otherwise returns black, with no device, platform or background input.@devicekit/frame: the READMEs were missingDeviceFrameIntrinsicAttributesfrom the API reference, and listed thedevice/orientationproperty setters as takingstring | nullwhen the d.ts isstring | null | undefined.@devicekit/frame: twocontentrectchangelisteners that each flipped a different attribute in response to the other could keep the element re-measuring forever and freeze the tab. The element now remembers every rect it published during one synchronous batch, stops as soon as the same rect would go out a third time, and logs oneconsole.errornaming thecontentrectchangelisteners as the cause;refreshContentRect()re-syncs afterwards.@devicekit/frame:package.jsondeclaredsideEffects: false, but@devicekit/frame/reactregisters<device-frame>at import time; a bundler could drop that registration. The field now lists the React entry as the only file with side effects.@devicekit/frame: styles were injected as an inline<style>in the shadow root, which a strictstyle-srcContent Security Policy blocks. Where the browser supports constructable stylesheets the styles are now attached throughadoptedStyleSheets(one shared sheet for every instance); the<style>fallback remains for older engines.@devicekit/frame: assigning a malformeddeviceProfile({},{ screen: null }, a negative width) crashed later inside layout withCannot read properties of undefined (reading 'width'). The setter andresolveDevice()now throw aTypeErrornaming the bad field, such asdeviceProfile.screen.width must be a finite number greater than 0, got -1.@devicekit/devices:resolveWindowSize()accepted a negative or non-finitenavigationBar/tabBarHeightand returned a window taller than the screen; it now throws aRangeErrornaming the option.@devicekit/frame/react: every optional prop ofDeviceFramePropsandDeviceFrameIntrinsicAttributesnow allowsundefinedexplicitly, so a consumer compiling withexactOptionalPropertyTypes: truecan passorientation={maybeOrientation}without TS2375. A type-test fixture compiled with that option is part ofcheck-types.- Publish workflow: a GitHub Release created from a tag that is not on
maincould still publish; the job now refuses any commit that is not an ancestor oforigin/main. @devicekit/devices:assertDeviceProfile()let a profile through withoutnameorpixelRatio, acceptedcutout: nullandshell: null, and never looked insidecutoutorshell; a profile withcutout: { shape: 'bogus' }then reached the status bar as a broken shape. Every required field is now required, and nested cutout / shell fields are checked for type and range.@devicekit/devices:Galaxy Z Fold 6 (inner)was stored as 744 x 860 @ 2.625, about 5 % larger than the panel's 1856 x 2160 physical pixels; it is now 707 x 823 @ 2.625.@devicekit/frame: the shared constructed stylesheet was built with the page's globalCSSStyleSheetand reused for every shadow root, so a<device-frame>created in, or moved into, another document (an iframe, a window opened by the host) either threwNotAllowedErroror silently lost its styles. Sheets are now built per document with that document's ownCSSStyleSheet, and the element re-checks its sheet every time it connects.@devicekit/frame: the iOS status-bar layout table was keyed bypixelRatioas well as screen width and status bar height, so changing only the pixel ratio of a profile moved the clock and battery by tens of pixels. The lookup now uses width and status bar height alone, which already identify every row.@devicekit/frame/react:<DeviceFrame onContentRectChange={...}>was neither typed nor wired, so the handler never ran. It is now a declared prop, registered once on the element and always calling the latest handler, and removed when the prop is dropped.@devicekit/frame: a property assigned before the element was defined (el.device = 'iPhone 15'and thencustomElements.define(...)) shadowed the class setter, sodevicestayed a string,deviceProfilewas silently lost, and the first render threwCannot read properties of undefined (reading 'width'). On connect the element now moves every such own property through its setter.@devicekit/devices: the generated iOS user agent saidiPhone OS 26_0for iOS 26 devices; Safari 26 froze that token at18_6and only bumpsVersion/26.0. iPads reported the mobile(iPad; CPU OS ...)form, while Safari on iPadOS 13 and later sends the desktopMacintoshuser agent by default; iPads now generate that.@devicekit/devices: every generated HarmonyOS user agent ended inHuaweiBrowser/5.0.4.303, which is the Huawei Browser app's own token and not part of the plain ArkWeb container's user agent. It is gone; a profile that needs it setsuserAgent.@devicekit/devices: the Android user agent always carriedMobile, so a custom tablet profile without its ownuserAgentlooked like a phone. Prof...