Packages
noora
0.86.0
0.86.0
0.85.0
0.84.1
0.84.0
0.83.2
0.83.1
0.83.0
0.82.7
0.82.6
0.82.5
0.82.4
0.82.3
0.82.2
0.82.1
0.82.0
0.81.4
0.81.3
0.81.2
0.81.1
0.81.0
0.80.1
0.80.0
0.79.1
0.79.0
0.78.1
0.78.0
0.77.4
0.77.3
0.77.2
0.77.1
0.77.0
0.76.0
0.75.0
0.74.0
0.73.0
0.72.0
0.71.0
0.70.0
0.69.1
0.69.0
0.68.0
0.67.0
0.66.0
0.65.0
0.64.2
0.64.1
0.64.0
0.63.2
0.63.1
0.63.0
0.62.0
0.61.0
0.60.0
0.59.0
0.58.0
0.57.0
0.56.1
0.56.0
0.55.0
0.54.0
0.53.1
0.53.0
0.52.1
0.52.0
0.51.0
0.50.1
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.3
0.44.2
0.44.1
0.44.0
0.43.0
0.42.0
0.41.0
0.40.6
0.40.5
0.40.4
0.40.3
0.40.2
0.40.1
0.40.0
0.39.1
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.1
0.32.0
0.31.0
0.30.0
0.29.2
0.29.1
0.29.0
0.28.5
0.28.4
0.28.3
0.28.2
0.28.1
0.28.0
0.27.0
0.26.1
0.26.0
0.25.0
0.24.0
0.23.1
0.23.0
0.22.1
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.1
0.12.0
0.11.2
0.11.1
0.11.0
0.10.0
0.9.0
0.8.0
0.7.0
0.6.1
0.6.0
0.5.1
0.5.0
0.4.0
0.3.2
0.3.1
0.3.0
0.2.2
0.2.0
0.1.0
0.1.0-rc.2
0.1.0-rc.1
0.1.0-alpha.6
0.1.0-alpha.5
0.1.0-alpha.4
0.1.0-alpha.3
0.1.0-alpha.2
0.1.0-alpha.1
A component library for Phoenix LiveView applications
Current section
Files
Jump to
Current section
Files
js/web-components/Contract.js
export function contractAttribute(contract, name) {
const attribute = contract.attributes.find(
(candidate) => candidate.name === name,
);
if (!attribute) {
throw new Error(`${contract.tagName} does not define ${name}`);
}
return attribute;
}
export function contractProperties(contract) {
const propertyEntries = (contract.properties ?? []).map((property) => [
property.name,
{ attribute: false },
]);
return Object.fromEntries([
...contract.attributes.map((attribute) => {
const options = {};
const defaultValue = () =>
Object.hasOwn(attribute, "default")
? structuredClone(attribute.default)
: undefined;
if (attribute.property !== attribute.name) {
options.attribute = attribute.name;
}
if (attribute.type === "boolean") {
options.type = Boolean;
}
if (attribute.type === "number") {
options.converter = {
fromAttribute(value) {
if (value === null) return defaultValue();
const number = Number(value);
return Number.isFinite(number) ? number : defaultValue();
},
toAttribute(value) {
return Number.isFinite(value) ? String(value) : null;
},
};
}
if (attribute.type === "json") {
options.converter = {
fromAttribute(value) {
if (value === null) return defaultValue();
try {
const parsed = JSON.parse(value);
const fallback = defaultValue();
if (Array.isArray(fallback) && !Array.isArray(parsed)) {
return fallback;
}
if (
fallback &&
typeof fallback === "object" &&
!Array.isArray(fallback) &&
(typeof parsed !== "object" ||
parsed === null ||
Array.isArray(parsed))
) {
return fallback;
}
return parsed;
} catch {
return defaultValue();
}
},
toAttribute(value) {
return value === undefined ? null : JSON.stringify(value);
},
};
}
if (attribute.reflect) {
options.reflect = true;
}
return [attribute.property, options];
}),
...propertyEntries,
]);
}
export function initializeContractDefaults(element, contract) {
const inputs = [
...contract.attributes.map((attribute) => ({
...attribute,
name: attribute.property,
})),
...(contract.properties ?? []),
];
for (const input of inputs) {
if (Object.hasOwn(input, "default")) {
element[input.name] =
input.type === "json" ? structuredClone(input.default) : input.default;
}
}
}
export function resolveContractValue(value, attribute) {
return !attribute.values || attribute.values.includes(value)
? value
: attribute.default;
}
export function contractByTag(contracts, tagName) {
const contract = contracts.find((candidate) => candidate.tagName === tagName);
if (!contract) {
throw new Error(`Missing contract for ${tagName}`);
}
return contract;
}