Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion editor/components/app-runner/vanilla-app-runner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export function VanillaRunner({
if (ref.current && enableInspector) {
ref.current.onload = () => {
const matches = ref.current.contentDocument.querySelectorAll(
"div, span, button, img, image, svg"
"div, span, img, image, svg" // button, input - disabled due to interaction testing (for users)
);
matches.forEach((el) => {
const tint = "rgba(20, 0, 255, 0.2)";
Expand Down
2 changes: 1 addition & 1 deletion externals/reflect-core
21 changes: 13 additions & 8 deletions packages/builder-css-styles/padding/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ import { px } from "../dimensions";

type PaddingValue = number | "auto";

export function padding(p: EdgeInsets): CSSProperties {
switch (edgeInsetsShorthandMode(p)) {
export function padding(
p: EdgeInsets,
options?: {
explicit?: boolean;
}
): CSSProperties {
switch (edgeInsetsShorthandMode(p, options)) {
case EdgeInsetsShorthandMode.empty: {
return {};
}
Expand All @@ -31,10 +36,10 @@ export function padding(p: EdgeInsets): CSSProperties {
case EdgeInsetsShorthandMode.trbl:
default: {
return {
"padding-bottom": _makeifRequired(p?.bottom),
"padding-top": _makeifRequired(p?.top),
"padding-left": _makeifRequired(p?.left),
"padding-right": _makeifRequired(p?.right),
"padding-bottom": _makeifRequired(p?.bottom, options?.explicit),
"padding-top": _makeifRequired(p?.top, options?.explicit),
"padding-left": _makeifRequired(p?.left, options?.explicit),
"padding-right": _makeifRequired(p?.right, options?.explicit),
};
}
}
Expand All @@ -55,8 +60,8 @@ function _pv(pv: PaddingValue) {
return px(pv);
}

function _makeifRequired(val: number): string | undefined {
if (val && val > 0) {
function _makeifRequired(val: number, explicit?: boolean): string | undefined {
if (explicit || (val && val > 0)) {
return px(val);
}
}
2 changes: 1 addition & 1 deletion packages/builder-css-styles/text-shadow/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { color } from "../color";
import { px } from "../dimensions";

export function textShadow(ts: TextShadowManifest[]): string {
if (ts.length === 0) {
if (!ts || ts.length === 0) {
return;
}

Expand Down
12 changes: 6 additions & 6 deletions packages/builder-web-core/widget-core/widget-with-style.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { JsxWidget, IMultiChildJsxWidget, JSXElementConfig } from ".";
import { CSSProperties } from "@coli.codes/css";
import { ElementCssProperties, ElementCssStyleData } from "@coli.codes/css";
import {
Color,
DimensionLength,
Expand All @@ -15,13 +15,13 @@ import { WidgetKey } from "../widget-key";
import { positionAbsolute } from "@web-builder/styles";

export interface IWidgetWithStyle {
styleData(): CSSProperties;
styleData(): ElementCssStyleData;
}

/**
* Since html based framework's widget can be represented withou any style definition, this WidgetWithStyle class indicates, that the sub instance of this class will contain style data within it.
*/
export abstract class WidgetWithStyle<OUTSTYLE = CSSProperties>
export abstract class WidgetWithStyle<OUTSTYLE = ElementCssStyleData>
extends JsxWidget
implements
IWHStyleWidget,
Expand Down Expand Up @@ -81,8 +81,8 @@ export abstract class WidgetWithStyle<OUTSTYLE = CSSProperties>

abstract jsxConfig(): JSXElementConfig;

private extendedStyle: CSSProperties = {};
extendStyle<T = CSSProperties>(style: T) {
private extendedStyle: ElementCssProperties = {};
extendStyle<T = ElementCssProperties>(style: T) {
this.extendedStyle = {
...this.extendedStyle,
...style,
Expand All @@ -102,7 +102,7 @@ export abstract class MultiChildWidgetWithStyle
constructor({ key }: { key: WidgetKey }) {
super({ key: key });
}
abstract styleData(): CSSProperties;
abstract styleData(): ElementCssStyleData;

abstract jsxConfig(): JSXElementConfig;
}
208 changes: 193 additions & 15 deletions packages/builder-web-core/widgets-native/html-button/index.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,207 @@
import { JSXElementConfig, WidgetKey } from "@web-builder/core";
import { JSX, JSXAttribute, Snippet } from "coli";
import { ReactWidget } from "..";
import type { CSSProperties, ElementCssStyleData } from "@coli.codes/css";
import type { JSXElementConfig, StylableJsxWidget } from "@web-builder/core";
import type {
IButtonStyleButton,
IButtonStyleButtonProps,
ITextStyle,
ButtonStyle,
IWHStyleWidget,
Widget,
} from "@reflect-ui/core";
import { Text } from "@reflect-ui/core";
import { Container } from "..";
import { WidgetKey } from "../../widget-key";
import { JSX } from "coli";
import * as css from "@web-builder/styles";

export class Button extends ReactWidget {
constructor({ key }: { key: WidgetKey }) {
super({ key });
}
/**
* Html5 Button Will have built in support for...
*
*
* - onClick callback
* - hover styles
* - focus styles
* - disabled styles
* - active styles
*
*
* Learn more at
* - [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button)
* - [html spec](https://html.spec.whatwg.org/multipage/form-elements.html#the-button-element)
*
*/
export class HtmlButton extends Container implements IButtonStyleButton {
_type = "button";

/**
* The name of the button, submitted as a pair with the button’s value as part of the form data, when that button is used to submit the form.
*/
name?: string;

/**
* The default behavior of the button. Possible values are:
* - `submit`: The button submits the form data to the server. This is the default if the attribute is not specified for buttons associated with a <form>, or if the attribute is an empty or invalid value.
* - `reset`: The button resets all the controls to their initial values, like <input type="reset">. (This behavior tends to annoy users.)
* - `button`: The button has no default behavior, and does nothing when pressed by default. It can have client-side scripts listen to the element's events, which are triggered when the events occur.
*/
type: "submit" | "reset" | "button" = "button";

// #region @ButtonStyleButton
autofocus?: boolean;
style: ButtonStyle;
/**
* This Boolean attribute prevents the user from interacting with the button: it cannot be pressed or focused.
*/
disabled?: boolean;
// TextManifest
child: Widget;
// #endregion @ButtonStyleButton

constructor({
key,
name,
autofocus,
disabled,
style,
child,
...rest
}: { key: WidgetKey } & {
name?: string;
} & IButtonStyleButtonProps &
IWHStyleWidget) {
super({ key, ...rest });

// set button properties
this.name = name;

this.autofocus = autofocus;
this.disabled = disabled;
this.style = style;
this.child = child;

children = [
//
];
this.children = this.makechildren();
}

makechildren() {
if (this.child instanceof Text) {
return [
<StylableJsxWidget>{
key: new WidgetKey(`${this.key.id}.text`, "text"),
styleData: () => null,
jsxConfig: () => {
return <JSXElementConfig>{
type: "static-tree",
tree: JSX.text((this.child as Text).data as string),
};
},
},
];
}

return [];
}

styleData(): ElementCssStyleData {
const containerstyle = super.styleData();

// wip
return {
// general layouts, continer ---------------------
...containerstyle,
// -----------------------------------------------

// padding
...css.padding(this.style.padding?.default),
"box-sizing": (this.padding && "border-box") || undefined,

styleData() {
return {};
// background
"background-color": this.style.backgroundColor
? css.color(this.style.backgroundColor.default)
: undefined,

// text styles --------------------------------------------
color: css.color((this.style.textStyle.default as ITextStyle)?.color),
// "text-overflow": this.overflow,
"font-size": css.px(this.style.textStyle.default.fontSize),
"font-family": css.fontFamily(this.style.textStyle.default.fontFamily),
"font-weight": css.convertToCssFontWeight(
this.style.textStyle.default.fontWeight
),
// "word-spacing": this.style.wordSpacing,
"letter-spacing": css.letterSpacing(
this.style.textStyle.default.letterSpacing
),
"line-height": css.length(this.style.textStyle.default.lineHeight),
// "text-align": this.textAlign,
"text-decoration": css.textDecoration(
this.style.textStyle.default.decoration
),
"text-shadow": css.textShadow(this.style.textStyle.default.textShadow),
"text-transform": css.textTransform(
this.style.textStyle.default.textTransform
),
// text styles --------------------------------------------

//
width: undefined, // clear fixed width
"min-width": css.length(this.minWidth),
"min-height": css.length(this.minHeight),

border: containerstyle["border"] ?? "none",
outline: containerstyle["outline"] ?? "none",

// button cursor
cursor: "pointer",

":hover": _button_hover_style,
":disabled": _button_disabled_style,
":active": _button_active_style,
":focus": _button_focus_style,
};
}

// @ts-ignore
jsxConfig() {
return <JSXElementConfig>{
tag: JSX.identifier("button"),
attributes: [
new JSXAttribute(
"onClick",
Snippet.fromStatic("() => { alert(`button click`) }")
),
// wip
// TODO: this only works for React. (wont' work for vanilla html)
// new JSXAttribute(
// "onClick",
// JSX.exp(
// // Snippet.fromStatic()
// // TODO: type check
// "() => { /* add onclick callback */ }" as any
// )
// ),
],
};
}

get finalStyle() {
const superstyl = super.finalStyle;

// width override. ------------------------------------------------------------------------------------------
return {
...superstyl,
width: undefined,
};
// ----------------------------------------------------------------------------------------------------------
}
}

const _button_hover_style: CSSProperties = {
opacity: 0.8,
};

const _button_disabled_style: CSSProperties = {
opacity: 0.5,
};

const _button_active_style: CSSProperties = {
opacity: 1,
};

const _button_focus_style: CSSProperties = {};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CSSProperties } from "@coli.codes/css";
import { CSSProperties, ElementCssStyleData } from "@coli.codes/css";
import { StylableJSXElementConfig, WidgetKey } from "../..";
import * as css from "@web-builder/styles";
import { JSX, JSXAttribute, StringLiteral } from "coli";
Expand Down Expand Up @@ -113,7 +113,7 @@ export class HtmlInputText extends Container implements ITextFieldManifest {
this.padding = this.decoration.contentPadding;
}

styleData(): CSSProperties {
styleData(): ElementCssStyleData {
// TODO:
// - support placeholder text color styling
const containerstyle = super.styleData();
Expand Down Expand Up @@ -153,6 +153,19 @@ export class HtmlInputText extends Container implements ITextFieldManifest {
"text-shadow": css.textShadow(this.style.textShadow),
"text-transform": css.textTransform(this.style.textTransform),
// text styles --------------------------------------------

...(this.decoration?.placeholderStyle
? {
"::placeholder": {
// TODO: optmiize - assign only diffferent properties values
// TODO: not all properties are assigned
color: css.color(this.decoration.placeholderStyle.color),
"font-size": css.px(this.style.fontSize),
"font-family": css.fontFamily(this.style.fontFamily),
"font-weight": css.convertToCssFontWeight(this.style.fontWeight),
},
}
: {}),
};
}

Expand Down
1 change: 1 addition & 0 deletions packages/builder-web-core/widgets-native/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export * from "./stack";
export * from "./html-text-element";
export * from "./html-svg";
export * from "./html-image";
export * from "./html-button";
export * from "./html-input";
export * from "./error-widget";

Expand Down
Loading