Releases: lume/element
v0.14.0 - JSX Intellisense
What's Changed
feat: improve the ElementAttributes
and ReactElementAttributes
JSX type helpers. by @trusktr in #34
This improves JSX types for Custom Elements in Solid JSX, React JSX, and Preact JSX, especially in React/Preact JSX whereas previously the React/Preact JSX prop types only accepted string values for dash-cased attributes.
If you have a get
ter/set
ter property in your element class, you can now define a dummy property prefixed with __set__<name-of-the-setter>
to specify the type of the set
ter, and this will be picked up and lead to improved types in JSX. For example, you can start using like so:
Before:
@element('some-element')
class SomeElement extends Element {
@attribute get someProp(): number {...}
@attribute set someProp(n: number | 'foo' | 'bar') {...}
}
declare module 'react' {
namespace JSX {
interface IntrinsicElements {
'some-element': ReactElementAttributes<SomeElement, 'someProp'>
}
}
}
and this JSX would have a type error:
return <some-element some-prop={'foo'} /> // Error: string is not assignable to number
After:
@element('some-element')
class SomeElement extends Element {
@attribute get someProp(): number {...}
@attribute set someProp(n: this['__set__someProp']) {...}
/** don't use this property, it is for JSX types. */
__set__someProp!: number | 'foo' | 'bar'
}
// ... the same React JSX definition as before ...
and now JSX prop types will allow setting the setter types:
return <some-element someProp={'foo'} /> // No error, yay!
Note, the property is camelCase instead of dash-case now.
BREAKING: This may introduce type errors into existing JSX templates, tested with React 19 (not tested with React 18 or below), but it is an inevitable upgrade for the better.
To migrate, there's likely nothing to do in Solid JSX, but in React JSX the selected properties are no longer converted to dash-case, so you'll want to use the original JS property names in React JSX templates. For example this,
return <some-element some-prop={...} />
becomes
return <some-element someProp={...} />
If you have any issues, please reach out here on GitHub or on Discord!
Full Changelog: v0.13.1...v0.14.0
v0.13.1
What's Changed
- document the new
static observedAttributeHandlers
by @trusktr in #28 - improve the static
LumeElement.defineElement()
method by @trusktr in #29 - improve attribute handling by @trusktr in #30
- rename
root
totemplateRoot
, update docs by @trusktr in #31
Details
feat:
Update classy-solid, which now requires placing getter/setter attribute decorators to be placed on both the getter and setter.
BREAKING: If you previously use an attribute decorator on a getter/setter, you need to ensure that you write the decorator on both the getter and the setter:
// BAD:
@element('my-el')
class MyEl extends Element {
#foo = 123
@numberAttribute
get foo() {return this.#foo}
set foo(n) {this.#foo = n}
}
// GOOD:
@element('my-el')
class MyEl extends Element {
#foo = 123
@numberAttribute
get foo() {return this.#foo}
@numberAttribute
set foo(n) {this.#foo = n}
}
If you're using @noSignal
, make sure to duplicate that on any getter/setter too:
@element('my-el')
class MyEl extends Element {
#foo = 123
@numberAttribute
@noSignal
get foo() {return this.#foo}
@numberAttribute
@noSignal
set foo(n) {this.#foo = n}
}
feat:
Increase interoperability by enforcing that JS values null and string values coming from attributes are treated the same as the values being set on to the respective JS properties. Basically, any null
or string
value assigned to an attribute JS property will be handled the same way as if removing the espective attribute or setting the respective attribute's value.
BREAKING: If you previously relied on setting an attribute-decorated JS property to a null value or string value without the string being coerced, you'll need to find another approach. All null values and string values assigned to attribute JS properties are now coerced just the same as string values from the attributes are. This means that this
el.someBoolean = 'false'
now behaves the same as this
el.setAttribute('some-boolean', 'false')
when the someBoolean
property was decorated with @booleanAttribute
decorator. Previously, the JS property value would have been the string literal "false"
but now it will be false
.
This improves support for frameworks like Preact which pass string values as-is from JSX props to custom element JS properties. Before this change, unexpected string values would break Lume, but now string values are properly coerced no matter how they arrive to the JS property (it'll work better anywhere, f.e. Vue, Svelte, Angular, etc).
feat:
A new .shadowOptions
instance property allows defining the options for an element's ShadowRoot. For example:
@element('my-el')
class MyEl extends Element {
shadowOptions = { mode: 'closed' }
}
deprecation:
root
has been renamed to templateRoot
to make it more obvious what it is for. The old root
property will be deleted in an upcoming release.
Full Changelog: v0.12.3...v0.13.1
v0.12.3
What's Changed
- feat: Deprecate the ability to define
static observedAttributes
as a map of attribute names to attribute handlers for non-decorator users, and instead create a newstatic observedAttributeHandlers
for that purpose. by @trusktr in #27- This keeps the type of
static observedAttributes
clean and aligned with the DOM spec, while the newstatic observedAttributeHandlers
has the type definition for the library-specific feature. Plus this prevents type issues downstream because the@element
decorator (callable as a function when not using decorators) coerces the object format into the standard array format, yet the object type will still sppear in subclasses despite that it is never an object in subclasses.- deprecation:
static observedAttributes = {}
is deprecated, and only the standardstatic observedAttribu tes = []
should be used. The object format will be removed in a breaking version bump.
- deprecation:
- infra: Unrestrict the
typescript
version so we can keep it updated with other packages in the lume repo.
- This keeps the type of
Full Changelog: v0.12.1...v0.12.3
v0.12.1
v0.12.0 - check yoself befo you wreck yoself
Fixes:
- fix: enable
noUncheckedIndexedAccess
in tsconfig and fix type errors, preventing errors in downstream projects when they've enablednoUncheckedIndexedAccess
too. 20893e7 - fix: improve
ElementAttributes
type helper so that union string prop types are not converted tostring
. Thanks to @bigmistqke for the tip in #21! 5f216f8- BREAKING: This could introduce a type error for someone, due to it making union string types more accurate.
- fix: guard against missing DOM API in element decorator (f.e. when an app imports things server-side in SSR setups like Solid Start, Astro, etc). 7a67b74
Full Changelog: v0.11.9...v0.12.0
v0.11.9
- Limit TS to 5.2.x for now. If you have any errors, try
"skipLibCheck": true
in tsconfig.
Infrastructure:
- Improve automated tests
Full Changelog: v0.11.8...v0.11.9
v0.11.8
What's Changed
- fix: apply
css
property style after template content so that it overrides any styles in atemplate
… by @trusktr in #13- This is useful because if the
template
contains<link>
elements to import other styles, we typically want our element's local styles (the ones written in thecss
property) to override or use the imported styles, rather than the imported styles overriding our local styles.
Example:class MyEl extends Element { template = () => html` <link href="./path/to/card.css" /> <div class="card"> ... </div> ` css = ` /* we want this to override the imported style */ .card { color: blue } ` }
- This is useful because if the
Full Changelog: v0.11.7...v0.11.8
v0.11.7 - *Effectively* manage side effects!
Features
- feat: include
Effectful
from Lume'sclassy-solid
package as a feature of LumeElement, adding a convenientcreateEffect()
class method for making effects and not having to manually clean them up indisconnectedCallback()
.
Before:
// ...
import {createRoot, createEffect} from 'solid-js'
@element('my-el')
class MyEl extends LumeElement {
// ...
#stop = () => {}
connectedCallback() {
super.connectedCallback()
createRoot(stop => {
this.#stop = stop
// create effects
createEffect(() => {...})
createEffect(() => {...})
})
}
disconnectedCallback() {
super.disconnectedCallback()
this.#stop()
}
}
After:
// ...
import {createRoot, createEffect} from 'solid-js'
@element('my-el')
class MyEl extends LumeElement {
// ...
connectedCallback() {
super.connectedCallback()
// create effects
this.createEffect(() => {...})
this.createEffect(() => {...})
}
}
Full Changelog: v0.11.0...v0.11.7
v0.11.0 - Classified!
Switch from @lume/variable
(deprecated) to classy-solid
for decorator implementation details. This gets onto the latest version of Solid.js while at it. It also removes a layer of concepts in @lume/variable
that were not aligned with Solid.js idioms (f.e. using autorun
instead of createEffect
, naming of the @reactive
class field decorator compared to the better-named @signal
, etc), allowing us to move forward in a way that will showcase Solid's features in ways more idiomatic and familiar to to users coming from Solid.js.
BREAKING:
With the update to classy-solid
we dropped legacy decorators, and now use the stage 3 decorator format. Stage 3 "standard decorators" are slated to be implemented in browsers, but this has not happened yet.
Migration:
- If you're using
@lume/element
's decorators, you'll need to update your tooling to support the latest spec: either use TypeScript v5 or higher which now supports standard decorators out of the box without a flag (using theexperimentalDecorators
option for legacy decoraators will no longer work), or use the latest version of the Babel compiler's decorators plugin. - If you were using
useDefineForClassFields
in TypeScript, orloose
mode with Babel's class properties, these are no longer supported because they do not align with native behavior of JavaScript, and using these modes may introduce unexpected runtime errors that may be very difficult to debug. You will most likely need to get your code working withuseDefineForClassFields
orloose
modes disabled. - Additionally, some uses of decorators may introduce (valid) type errors now (f.e. it does not make sense (to TypeScript) to use a class decorator that returns a subclass if the decorated class has a
private
constructor, etc). - If you're using plain JavaScript without decorators, the plain JS usage has changed a little bit. See the plain JS example in the tests, specifically the comments labeled "When not using decorators".
Full Changelog: v0.10.1...v0.11.0
v0.10.1 - Unglobalization
BREAKING: remove the global build. Migration: if you were importing the global/index.js file with a script tag, instead use import
syntax to import @lume/element
into your project.