Releases: webtides/element-library
Releases · webtides/element-library
v0.2.0
Packaging
- Added: a new
@webtides/element-library/catalogexport — the recommended way to consume this library under server-side rendering with@webtides/element-js-ssr-renderer.catalog.jsis a generated, bundler-traceableCatalog({ "el-button": () => import("./src/components/button/button.js"), … }) covering all 26 components. Because it ships inside the package, its specifiers are package-internal relative paths that resolve in any consumer's bundle regardless ofnode_moduleslayout, so SSR works on every target (plain Node, Nitro, edge/Workers, webpack, Vite) with no consumer codegen and no hand-written import map:import catalog from "@webtides/element-library/catalog"then pass it to the renderer'sresolve. Distinct from./all(a client-side side-effect bundle that registers every component for hydration) — the catalog defines nothing and runs nodefine(), it only tells the SSR renderer how to load each class. Regenerated automatically on release via theprepackhook (and on demand withnpm run gen:catalog), so it can never drift from the components; a Node SSR smoke test (npm run test:catalog, run in CI) verifies a known tag still resolves to its class through the renderer.
v0.1.2
Packaging
- Fixed: the published tarball now ships the runtime
src/utils/*.jsfiles. Thefilesallowlist inpackage.jsonincludedsrc/components/**/*.jsbut notsrc/utils/**/*.js, so0.1.1shipped only thetypes/src/utils/*.d.tsdeclarations while the runtime modules were dropped. Components that import them —el-notificationandel-dialog(../../utils/transitions.js,../../utils/body-scroll.js) — failed to resolve those imports from the published package, breaking downstream builds (e.g.nuxt build). This is independent of thepatch-packagepostinstallfix in0.1.1.
v0.1.1
Packaging
- Fixed: a clean
npm install @webtides/element-libraryno longer fails.0.1.0ran"postinstall": "patch-package"without shippingpatch-package, so consumers without it onPATHgotsh: patch-package: command not found(exit 127) and the install aborted. Thepostinstallhook, thepatch-packagedevDependency, and thepatches/directory have all been removed.
Components
- Fixed (
el-carousel): the carousel now bundles in consumer projects. It deep-imports Glide'ssrc/components/html.js, whose pristine source imports a non-existentexistexport — whichesbuild/Vite reject as a hard build error.0.1.0"fixed" this with apatch-packagepatch applied viapostinstall, but a dependency'spostinstallruns from its own nested directory and can never reach the consumer's hoisted@glidejs/glide, so the patch never applied downstream. The fixed Glidehtml.jscomponent is now vendored into the carousel (glide/components/glide-html.js) instead, removing the dependency on patching consumers'node_modules.
v0.1.0
Components
- Added: new
el-buttoncomponent — a themeable button modelled on Shoelace's<sl-button>(variants, sizes, outline/pill/circle, caret, loading, prefix/suffix slots, link mode). - Added: new
el-dialogcomponent — a modal dialog built on the native<dialog>element (platform-provided focus trap, backgroundinert, focus restore and<form method="dialog">auto-close), with an animated, cancelable open/close lifecycle and ref-counted body-scroll locking that compensates for the removed scrollbar width (no layout shift on open). API modelled on Shoelace's<sl-dialog>. - Added: new
el-notificationcomponent — an alert/notification that can be shown inline or as a transient toast (toast()floats it into a shared top-right stack). Semantic variants, optional close button, optional auto-dismiss that pauses on hover/focus, and an ARIA live-region host (role="alert"for danger/warning,role="status"otherwise). API modelled on Shoelace's<sl-alert>. - Added: new
el-radio-fieldcomponent — a single-choice radio group extendingFormField, rendering a native<fieldset>/<legend>of mutually-exclusive radios from anoptionsarray (strings or{ value, label?, disabled? }) with a custom, headless-by-default indicator. Inherits theinput-changeevent andtouched/valid/invalidstates. - Added: new
el-switch-fieldcomponent — an on/off toggle extendingFormField, rendering a native<input type="checkbox">withrole="switch"behind a custom, headless-by-default track/thumb. Reflectschecked, adds acheckedcustom state, and inherits theinput-changeevent andtouched/valid/invalidstates. - Added: new
el-password-fieldcomponent — a masked password input extendingInputField, pinning the inputtypetopassword(flipping totextwhile revealed) and adding an optional show/hide reveal button (password-toggle, default on). Inherits theinput-changeevent andtouched/valid/invalidstates. All three shipped themes decorate its native input identically toel-input-field, so themed password and text fields match. - Changed (BREAKING): dropped the
-elementsuffix from five components. The tagsel-accordion-element / el-carousel-element / el-dropdown-element / el-slider-element / el-sticky-elementare nowel-accordion / el-carousel / el-dropdown / el-slider / el-sticky; their import subpaths (@webtides/element-library/<name>and/<name>/define) and exported classes (AccordionElement → Accordion,CarouselElement → Carousel,DropdownElement → Dropdown,SliderElement → Slider,StickyElement → Sticky) change to match.accordion-groupis unchanged.
Theming
- Added: dialog tokens (
--el-dialog-width,--el-dialog-overlay-background) wired into all three shipped themes (default / high-contrast / sketchy), so themedel-dialogs get a visible, per-theme overlay scrim. Unthemed dialogs keep atransparentbackdrop (headless). Documented in the Storybook Docs / Theming token reference. - Added: opt-in default theme stylesheet at
@webtides/element-library/themes/default.css. Defines the--el-*token vocabulary at:rootwithlight-dark()color values; without it imported, components stay headless. - Added: opt-in high-contrast theme stylesheet at
@webtides/element-library/themes/high-contrast.css. Same token contract, accessibility-leaning identity: near-black/white surfaces, 2px borders, 3px focus rings, no shadows, larger touch targets. Supports both color schemes vialight-dark(). - Added: Storybook toolbar gains a "Theme" switch (None / Default / High contrast) and a "Color scheme" switch (System / Light / Dark) for previewing themed and unthemed states.
- Added: Theming docs page in Storybook (
Docs / Theming) covering the headless philosophy, themes vs color schemes, the full--el-*token reference, and a recipe for writing custom themes. README gains a short Theming section pointing at it. - Added: both shipped themes respect
prefers-reduced-motion: reduce(collapses--el-duration-mdto0s). Default theme also responds toprefers-contrast: more(bumps fg/border to pure black/white, raises border-width to 2px and focus-ring-width to 3px). High-contrast theme is already at its contrast ceiling. - Added: both shipped themes suppress the native
<select>chevron and positionel-select-field's.dropdown-indicatorover the right edge, so themed selects show a single, theme-colored glyph instead of duplicating the native one. Unthemed selects still render the native chevron with the custom indicator hidden — no double chevron either way. - Added: Storybook preview decorator mirrors the active theme's
--el-color-bg/--el-color-fgonto the iframe<body>, so flipping Theme or Color scheme also flips the page background. Stays inside Storybook; doesn't leak into consumer themes. - Changed:
el-dropdownpanel now reads--el-shadow-lgand--el-radius-lg(previously-md). Floating surfaces conventionally use more pronounced elevation. Themes that already set both tokens get the upgrade automatically. - Changed: expanded token-driven surfaces across components so the theme toggle is actually visible — dropdown panel, accordion title/content padding + divider, checkbox indicator + accent, tab-link active accent + hover, tab-group bottom border, form-field label margin/color, amount-field wrapper border + button/input padding. All fallbacks are null-ish (
0widths,transparentcolors,noneshadows) so unthemed components remain headless. - Changed: default theme decorates native form controls (
input,textarea,select) directly via component selectors, since those live in light DOM and can't be safely overridden from component CSS without losing the native unthemed look. - Changed: slider fallbacks for dot color and arrow background are now
currentColor/transparentinstead of#333/white— unthemed slider matches surrounding text instead of imposing a light-mode-assuming palette. - Changed: both themes render native form controls (
input,textarea,select) full-width (width: 100%; box-sizing: border-box), so themed forms are consistent and the select's custom chevron sits flush at the control's right edge.
accordion
- Added:
opencustom state on the host (:host(:state(open))). - Changed (BREAKING): renamed CSS parts
title-wrapper→titleandcontent-wrapper→content; the internal.content-wrapperclass is now.content. - Changed (BREAKING): replaced the
open-icon/close-iconparts with a singleiconpart — one SVG chevron that rotates 180° when open — instead of two∨/∧text glyphs. - Changed: internal style now uses
:host(:state(open))instead of:host([open='true']). The reflectedopenattribute is unchanged. - Changed: expand/collapse transition is token-driven (
--el-duration-md,--el-ease). - Fixed: collapsed content no longer leaves a padding-sized sliver — the
.contentpadding moved to an inner.content-innerwrapper so closing the accordion clips it. Only surfaced once a theme set--el-space-3.
accordion-group
- Fixed: single-open mode (
show-multiple="false") now correctly closes the previously open accordion when one starts open declaratively. Theconnected()preselection scan had an inverted guard (it ran only in multi-open mode) and queried the whole document instead of the group's own children.
carousel
- Fixed:
ShadowHtmlnow forwards Glide'sEventsargument to the wrapped html component (like the otherShadow*wrappers). It previously called the factory with(Glide, Components)only, soEvents.on('update', …)threwCannot read properties of undefined (reading 'on')on every mount. - Fixed: Glide's core + theme CSS is inlined into the component style instead of
@import-ed. The@importwas dropped inside the shadow-DOM adopted stylesheet, so arrows/bullets weren't positioned over the slides (they appeared as a strip below the image) and the track wasn't clipped.
checkbox-field
- Added:
checkedcustom state on the host. Inherits thetouched / valid / invalidstates fromFormField. - Fixed: the native
<input type="checkbox">is now visually hidden (still focusable / in the a11y tree) instead of rendering a second box next to the custom indicator; the duplicated label is gone (the baseFormFieldlabel is suppressed in favour of the inline one)..checked-indicatorgainedcurrentColorfallbacks so unthemed checkboxes stay visible, plus:focus-visiblestyling.
dropdown
- Added:
opencustom state on the host.
form-field
- Added: host-level
touched,validandinvalidcustom states. Inherited by all field subclasses. The inner.field.is-*classes still exist for internal use.
input-field
- Changed: hardcoded values now reference design tokens (
--el-space-*,--el-color-success,--el-color-danger,--el-font-size-sm) with the previous values as fallbacks. - Fixed: the
patternattribute is now omitted when unset (via element-js'soptionalAttributedirective) instead of falling back to a[sS]*regex that matched only runs ofs/Sand so rejected any ordinary value as invalid.
lazy-src
- Added:
loadedcustom state on the host (alongside the existing reflectedloadedattribute).
select-field
- Changed (BREAKING): renamed the dropdown indicator's CSS class from
.iconto.dropdown-indicator. - Changed: the
.dropdown-indicatorrenders an SVG chevron (currentColor) instead of the∨text glyph. Still hidden by default; themes show and position it.
slider
- Changed: hardcoded colors and paddings now reference design tokens (
--el-color-fg,--el-color-bg,--el-space-*). Color fallbacks uselight-dark()so unthemed dark mode renders sensibly.
sticky
- Changed (BREAKING): replaced the
.is-sticky / .is-up / .is-downhost classes with the custom states `:state(sti...