mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-09 05:26:24 +09:00
## Description This is a WIP PR, and will be adding more details about the feature and the changes that are going in... ## Steps for reproduction 1. click button 2. expect xyz ## Code Review - [ ] hi, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 5de6) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio-builder/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env.example` and the `builder/env-check.js` if mandatory --------- Co-authored-by: Bogdan Chadkin <trysound@yandex.ru> Co-authored-by: Oleg Isonen <oleg008@gmail.com>
194 lines
4.9 KiB
TypeScript
194 lines
4.9 KiB
TypeScript
import { units } from "./__generated__/units";
|
|
import type { properties } from "./__generated__/properties";
|
|
import { z } from "zod";
|
|
|
|
type Properties = typeof properties & {
|
|
[custom: CustomProperty]: {
|
|
appliesTo: "allElements";
|
|
initial: string;
|
|
inherited: boolean;
|
|
};
|
|
};
|
|
|
|
export type StyleProperty = keyof Properties;
|
|
|
|
type CustomProperty = `--${string}`;
|
|
|
|
export type AppliesTo = Properties[StyleProperty]["appliesTo"];
|
|
|
|
export type UnitGroup = keyof typeof units;
|
|
|
|
type UnitEnum = (typeof units)[UnitGroup][number];
|
|
|
|
const Unit = z.union([
|
|
// expected tuple with at least single element
|
|
// so cast to tuple with single union element to get correct inference
|
|
z.enum(Object.values(units).flat() as [UnitEnum]),
|
|
z.literal("number"),
|
|
]);
|
|
|
|
export type Unit = z.infer<typeof Unit>;
|
|
|
|
export const UnitValue = z.object({
|
|
type: z.literal("unit"),
|
|
unit: Unit,
|
|
value: z.number(),
|
|
});
|
|
|
|
export type UnitValue = z.infer<typeof UnitValue>;
|
|
|
|
export const KeywordValue = z.object({
|
|
type: z.literal("keyword"),
|
|
// @todo use exact type
|
|
value: z.string(),
|
|
});
|
|
export type KeywordValue = z.infer<typeof KeywordValue>;
|
|
|
|
/**
|
|
* Valid unparsed css value
|
|
**/
|
|
export const UnparsedValue = z.object({
|
|
type: z.literal("unparsed"),
|
|
value: z.string(),
|
|
// For the builder we want to be able to hide background-image
|
|
hidden: z.boolean().optional(),
|
|
});
|
|
|
|
export type UnparsedValue = z.infer<typeof UnparsedValue>;
|
|
|
|
const FontFamilyValue = z.object({
|
|
type: z.literal("fontFamily"),
|
|
value: z.array(z.string()),
|
|
});
|
|
export type FontFamilyValue = z.infer<typeof FontFamilyValue>;
|
|
|
|
const RgbValue = z.object({
|
|
type: z.literal("rgb"),
|
|
r: z.number(),
|
|
g: z.number(),
|
|
b: z.number(),
|
|
alpha: z.number(),
|
|
});
|
|
export type RgbValue = z.infer<typeof RgbValue>;
|
|
|
|
export const ImageValue = z.object({
|
|
type: z.literal("image"),
|
|
value: z.union([
|
|
z.object({ type: z.literal("asset"), value: z.string() }),
|
|
// url is not stored in db and only used by css-engine transformValue
|
|
// to prepare image value for rendering
|
|
z.object({ type: z.literal("url"), url: z.string() }),
|
|
]),
|
|
// For the builder we want to be able to hide images
|
|
hidden: z.boolean().optional(),
|
|
});
|
|
|
|
export type ImageValue = z.infer<typeof ImageValue>;
|
|
|
|
// We want to be able to render the invalid value
|
|
// and show it is invalid visually, without saving it to the db
|
|
export const InvalidValue = z.object({
|
|
type: z.literal("invalid"),
|
|
value: z.string(),
|
|
});
|
|
export type InvalidValue = z.infer<typeof InvalidValue>;
|
|
|
|
const UnsetValue = z.object({
|
|
type: z.literal("unset"),
|
|
value: z.literal(""),
|
|
});
|
|
export type UnsetValue = z.infer<typeof UnsetValue>;
|
|
|
|
export const TupleValueItem = z.union([
|
|
UnitValue,
|
|
KeywordValue,
|
|
UnparsedValue,
|
|
RgbValue,
|
|
]);
|
|
export type TupleValueItem = z.infer<typeof TupleValueItem>;
|
|
|
|
export const TupleValue = z.object({
|
|
type: z.literal("tuple"),
|
|
value: z.array(TupleValueItem),
|
|
hidden: z.boolean().optional(),
|
|
});
|
|
|
|
export type TupleValue = z.infer<typeof TupleValue>;
|
|
|
|
const LayerValueItem = z.union([
|
|
UnitValue,
|
|
KeywordValue,
|
|
UnparsedValue,
|
|
ImageValue,
|
|
TupleValue,
|
|
InvalidValue,
|
|
]);
|
|
|
|
export type LayerValueItem = z.infer<typeof LayerValueItem>;
|
|
// To support background layers https://developer.mozilla.org/en-US/docs/Web/CSS/background
|
|
// and similar comma separated css properties
|
|
// InvalidValue used in case of asset not found
|
|
export const LayersValue = z.object({
|
|
type: z.literal("layers"),
|
|
value: z.array(LayerValueItem),
|
|
});
|
|
|
|
export type LayersValue = z.infer<typeof LayersValue>;
|
|
|
|
const ValidStaticStyleValue = z.union([
|
|
ImageValue,
|
|
LayersValue,
|
|
UnitValue,
|
|
KeywordValue,
|
|
FontFamilyValue,
|
|
RgbValue,
|
|
UnparsedValue,
|
|
TupleValue,
|
|
]);
|
|
|
|
export type ValidStaticStyleValue = z.infer<typeof ValidStaticStyleValue>;
|
|
|
|
/**
|
|
* All StyleValue types that going to need wrapping into a CSS variable when rendered
|
|
* on canvas inside builder.
|
|
* Values like InvalidValue, UnsetValue, VarValue don't need to be wrapped
|
|
*/
|
|
export const isValidStaticStyleValue = (
|
|
styleValue: StyleValue
|
|
): styleValue is ValidStaticStyleValue => {
|
|
// guard against invalid checks
|
|
const staticStyleValue = styleValue as ValidStaticStyleValue;
|
|
return (
|
|
staticStyleValue.type === "image" ||
|
|
staticStyleValue.type === "layers" ||
|
|
staticStyleValue.type === "unit" ||
|
|
staticStyleValue.type === "keyword" ||
|
|
staticStyleValue.type === "fontFamily" ||
|
|
staticStyleValue.type === "rgb" ||
|
|
staticStyleValue.type === "unparsed" ||
|
|
staticStyleValue.type === "tuple"
|
|
);
|
|
};
|
|
|
|
const VarValue = z.object({
|
|
type: z.literal("var"),
|
|
value: z.string(),
|
|
fallbacks: z.array(ValidStaticStyleValue),
|
|
});
|
|
export type VarValue = z.infer<typeof VarValue>;
|
|
|
|
export const StyleValue = z.union([
|
|
ValidStaticStyleValue,
|
|
InvalidValue,
|
|
UnsetValue,
|
|
VarValue,
|
|
]);
|
|
|
|
export type StyleValue = z.infer<typeof StyleValue>;
|
|
|
|
const Style = z.record(z.string(), StyleValue);
|
|
|
|
export type Style = {
|
|
[property in StyleProperty]?: StyleValue;
|
|
} & { [property: CustomProperty]: StyleValue };
|