mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-19 07:29:14 +00:00
Compare commits
1 Commits
native-cod
...
inheritanc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3dc526c948 |
69
docs/docs/experimental/inherit.md
Normal file
69
docs/docs/experimental/inherit.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
title: Inheritance & Default value tests
|
||||||
|
---
|
||||||
|
|
||||||
|
Button variant should default to `neutral`:
|
||||||
|
|
||||||
|
```html {.example}
|
||||||
|
<wa-button>Neutral</wa-button>
|
||||||
|
<wa-button variant="neutral">Neutral</wa-button>
|
||||||
|
<wa-button variant="brand">Brand</wa-button>
|
||||||
|
```
|
||||||
|
|
||||||
|
Callout variant should default to `brand`.
|
||||||
|
Buttons within an element with a variant should inherit that variant unless they have a variant of their own.
|
||||||
|
|
||||||
|
```html {.example}
|
||||||
|
<wa-callout>
|
||||||
|
Brand
|
||||||
|
<wa-button>Brand</wa-button>
|
||||||
|
<wa-button variant="neutral">Neutral</wa-button>
|
||||||
|
<wa-button variant="brand">Brand</wa-button>
|
||||||
|
<button>Brand</button>
|
||||||
|
<button class="wa-neutral">Neutral</button>
|
||||||
|
<button class="wa-brand">Brand</button>
|
||||||
|
</wa-callout>
|
||||||
|
<wa-callout variant="neutral">
|
||||||
|
Neutral
|
||||||
|
<wa-button>Neutral</wa-button>
|
||||||
|
<wa-button variant="neutral">Neutral</wa-button>
|
||||||
|
<wa-button variant="brand">Brand</wa-button>
|
||||||
|
<button>Neutral</button>
|
||||||
|
<button class="wa-neutral">Neutral</button>
|
||||||
|
<button class="wa-brand">Brand</button>
|
||||||
|
</wa-callout>
|
||||||
|
```
|
||||||
|
|
||||||
|
Nested callouts:
|
||||||
|
|
||||||
|
|
||||||
|
```html {.example}
|
||||||
|
<wa-callout>
|
||||||
|
Brand
|
||||||
|
<wa-callout>Brand</wa-callout>
|
||||||
|
</wa-callout>
|
||||||
|
<wa-callout variant="neutral">
|
||||||
|
Neutral
|
||||||
|
<wa-callout>Neutral</wa-callout>
|
||||||
|
</wa-callout>
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```html {.example}
|
||||||
|
<wa-callout>
|
||||||
|
Brand
|
||||||
|
<wa-button>Brand</wa-button>
|
||||||
|
<wa-button variant="neutral">Neutral</wa-button>
|
||||||
|
<button>Brand</button>
|
||||||
|
<button class="wa-neutral">Neutral</button>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<wa-callout variant="neutral">
|
||||||
|
Neutral
|
||||||
|
<wa-button>Neutral</wa-button>
|
||||||
|
<wa-button variant="brand">Brand</wa-button>
|
||||||
|
<button>Neutral</button>
|
||||||
|
<button class="wa-brand">Brand</button>
|
||||||
|
</wa-callout>
|
||||||
|
</wa-callout>
|
||||||
|
```
|
||||||
@@ -69,7 +69,8 @@ export default class WaButton extends WebAwesomeFormAssociatedElement {
|
|||||||
@property() title = ''; // make reactive to pass through
|
@property() title = ''; // make reactive to pass through
|
||||||
|
|
||||||
/** The button's theme variant. */
|
/** The button's theme variant. */
|
||||||
@property({ reflect: true }) variant: 'neutral' | 'brand' | 'success' | 'warning' | 'danger' = 'neutral';
|
@property({ reflect: true, initial: 'neutral' })
|
||||||
|
variant: 'neutral' | 'brand' | 'success' | 'warning' | 'danger' | 'inherit' = 'inherit';
|
||||||
|
|
||||||
/** The button's visual appearance. */
|
/** The button's visual appearance. */
|
||||||
@property({ reflect: true, default: 'accent' })
|
@property({ reflect: true, default: 'accent' })
|
||||||
|
|||||||
@@ -28,7 +28,13 @@ export default class WaCallout extends WebAwesomeElement {
|
|||||||
static shadowStyle = [variantStyles, appearanceStyles, sizeStyles, nativeStyles, styles];
|
static shadowStyle = [variantStyles, appearanceStyles, sizeStyles, nativeStyles, styles];
|
||||||
|
|
||||||
/** The callout's theme variant. */
|
/** The callout's theme variant. */
|
||||||
@property({ reflect: true }) variant: 'brand' | 'success' | 'neutral' | 'warning' | 'danger' = 'brand';
|
@property({ reflect: true, initial: 'brand' }) variant:
|
||||||
|
| 'brand'
|
||||||
|
| 'success'
|
||||||
|
| 'neutral'
|
||||||
|
| 'warning'
|
||||||
|
| 'danger'
|
||||||
|
| 'inherit' = 'inherit';
|
||||||
|
|
||||||
/** The callout's visual appearance. */
|
/** The callout's visual appearance. */
|
||||||
@property({ reflect: true }) appearance:
|
@property({ reflect: true }) appearance:
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ declare module 'lit' {
|
|||||||
* Specifies the property’s default value
|
* Specifies the property’s default value
|
||||||
*/
|
*/
|
||||||
default?: any;
|
default?: any;
|
||||||
|
initial?: any;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +25,13 @@ export default class WebAwesomeElement extends LitElement {
|
|||||||
/* eslint-disable-next-line */
|
/* eslint-disable-next-line */
|
||||||
console.error('Element internals are not supported in your browser. Consider using a polyfill');
|
console.error('Element internals are not supported in your browser. Consider using a polyfill');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let Self = this.constructor as typeof WebAwesomeElement;
|
||||||
|
for (let [property, spec] of Self.elementProperties) {
|
||||||
|
if (spec.default === 'inherit' && spec.initial !== undefined && typeof property === 'string') {
|
||||||
|
this.toggleCustomState(`initial-${property}-${spec.initial}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make localization attributes reactive
|
// Make localization attributes reactive
|
||||||
@@ -160,36 +168,69 @@ export default class WebAwesomeElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static createProperty(name: PropertyKey, options?: PropertyDeclaration): void {
|
static createProperty(name: PropertyKey, options?: PropertyDeclaration): void {
|
||||||
if (options && options.default !== undefined && options.converter === undefined) {
|
if (options) {
|
||||||
// Wrap the default converter to remove the attribute if the value is the default
|
if (options.initial !== undefined && options.default === undefined) {
|
||||||
// This effectively prevents the component sprouting attributes that have not been specified
|
// Set "inherit" value as default if no default is specified but the initial value is
|
||||||
let converter = {
|
// This saves us having to tediously specify default: "inherit", initial: "foo" for every property
|
||||||
...defaultConverter,
|
options.default = 'inherit';
|
||||||
toAttribute(value: string, type: unknown): unknown {
|
}
|
||||||
if (value === options!.default) {
|
|
||||||
return null;
|
if (options.default !== undefined && options.converter === undefined) {
|
||||||
}
|
// Wrap the default converter to remove the attribute if the value is the default
|
||||||
return defaultConverter.toAttribute!(value, type);
|
// This effectively prevents the component sprouting attributes that have not been specified
|
||||||
},
|
let converter = {
|
||||||
};
|
...defaultConverter,
|
||||||
options = { ...options, converter };
|
toAttribute(value: string, type: unknown): unknown {
|
||||||
|
if (value === options!.default) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return defaultConverter.toAttribute!(value, type);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
options = { ...options, converter };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.createProperty(name, options);
|
super.createProperty(name, options);
|
||||||
|
|
||||||
// Wrap the default accessor with logic to return the default value if the value is null
|
// Wrap the default accessor with logic to return the default value if the value is null
|
||||||
if (options && options.default !== undefined) {
|
if (options) {
|
||||||
const descriptor = Object.getOwnPropertyDescriptor(this.prototype, name as string);
|
if (options.default !== undefined) {
|
||||||
|
const descriptor = Object.getOwnPropertyDescriptor(this.prototype, name as string);
|
||||||
|
|
||||||
if (descriptor?.get) {
|
if (descriptor?.get) {
|
||||||
const getter = descriptor.get;
|
const getter = descriptor.get;
|
||||||
|
|
||||||
Object.defineProperty(this.prototype, name, {
|
Object.defineProperty(this.prototype, name, {
|
||||||
...descriptor,
|
...descriptor,
|
||||||
get() {
|
get() {
|
||||||
return getter.call(this) ?? options.default;
|
return getter.call(this) ?? options.default;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.default === 'inherit') {
|
||||||
|
// Add getter for "computed" value (taking ancestors into account)
|
||||||
|
let capitalizedName = name.toString().replace(/^\w/, c => c.toUpperCase());
|
||||||
|
Object.defineProperty(this.prototype, `computed${capitalizedName}`, {
|
||||||
|
get() {
|
||||||
|
let value;
|
||||||
|
let element = this;
|
||||||
|
|
||||||
|
do {
|
||||||
|
value = element[name as string];
|
||||||
|
element = element.parentElement;
|
||||||
|
} while (value === 'inherit' && element.parentElement);
|
||||||
|
|
||||||
|
if (value === 'inherit') {
|
||||||
|
// If we've reached this point and we still have `inherit`, we just ran out of parents
|
||||||
|
return options.initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user