fixing hitTest bounds for clickable. using Constructors for Clickable events. starting to think about design systems..
This commit is contained in:
parent
5af3af6b6c
commit
86996ed4ef
8 changed files with 67 additions and 26 deletions
38
src/design-tokens.cg
Normal file
38
src/design-tokens.cg
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
colors = {
|
||||||
|
primary = "#0066cc",
|
||||||
|
primaryDark = "#0052a3",
|
||||||
|
danger = "#dc3545",
|
||||||
|
success = "#28a745",
|
||||||
|
bg = "#ffffff",
|
||||||
|
bgGray = "#f8f9fa",
|
||||||
|
text = "#212529",
|
||||||
|
textLight = "#6c757d",
|
||||||
|
border = "#dee2e6"
|
||||||
|
};
|
||||||
|
|
||||||
|
spacing = {
|
||||||
|
xs = 4,
|
||||||
|
sm = 8,
|
||||||
|
md = 16,
|
||||||
|
lg = 32,
|
||||||
|
xl = 64
|
||||||
|
};
|
||||||
|
|
||||||
|
primaryStyle = {
|
||||||
|
bg = colors.primary,
|
||||||
|
fg = colors.bg,
|
||||||
|
px = spacing.md,
|
||||||
|
py = spacing.sm
|
||||||
|
};
|
||||||
|
|
||||||
|
dangerStyle = {
|
||||||
|
bg = colors.danger,
|
||||||
|
fg = colors.bg,
|
||||||
|
px = spacing.md,
|
||||||
|
py = spacing.sm
|
||||||
|
};
|
||||||
|
|
||||||
|
theme = {
|
||||||
|
colors = colors,
|
||||||
|
spacing = spacing
|
||||||
|
};
|
||||||
|
|
@ -5,18 +5,21 @@ import { Parser } from './parser'
|
||||||
import { runApp } from './runtime';
|
import { runApp } from './runtime';
|
||||||
import { builtins } from './builtins';
|
import { builtins } from './builtins';
|
||||||
|
|
||||||
import counterApp from './counter.cg?raw';
|
|
||||||
import stdlibCode from './stdlib.cg?raw';
|
import stdlibCode from './stdlib.cg?raw';
|
||||||
|
import designTokensCode from './design-tokens.cg?raw';
|
||||||
import uiComponentsCode from './ui-components.cg?raw';
|
import uiComponentsCode from './ui-components.cg?raw';
|
||||||
|
|
||||||
import textInputCode from './textinput-test.cg?raw';
|
import textInputCode from './textinput-test.cg?raw';
|
||||||
import testCode from './test.cg?raw';
|
import testCode from './test.cg?raw';
|
||||||
|
import counterApp from './counter.cg?raw';
|
||||||
|
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
canvas.width = 800;
|
canvas.width = 800;
|
||||||
canvas.height = 600;
|
canvas.height = 600;
|
||||||
|
canvas.style.border = "1px solid #000";
|
||||||
document.body.appendChild(canvas);
|
document.body.appendChild(canvas);
|
||||||
|
|
||||||
const cgCode = stdlibCode + '\n' + uiComponentsCode + '\n' + textInputCode;
|
const cgCode = stdlibCode + '\n' + designTokensCode + '\n' + uiComponentsCode + '\n' + textInputCode;
|
||||||
|
|
||||||
const tokens = tokenize(cgCode);
|
const tokens = tokenize(cgCode);
|
||||||
const parser = new Parser(tokens);
|
const parser = new Parser(tokens);
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ export function runApp(app: App, canvas: HTMLCanvasElement) {
|
||||||
if (app.view.kind !== 'closure')
|
if (app.view.kind !== 'closure')
|
||||||
throw new Error('view must be a function');
|
throw new Error('view must be a function');
|
||||||
|
|
||||||
const viewport = {
|
const viewport: Value = {
|
||||||
kind: 'record',
|
kind: 'record',
|
||||||
fields: {
|
fields: {
|
||||||
width: { kind: 'int', value: canvas.width },
|
width: { kind: 'int', value: canvas.width },
|
||||||
|
|
@ -61,13 +61,9 @@ export function runApp(app: App, canvas: HTMLCanvasElement) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const eventName = hitTest(x, y);
|
|
||||||
if (eventName) {
|
const event = hitTest(x, y);
|
||||||
const event: Value = {
|
if (event) {
|
||||||
kind: 'constructor',
|
|
||||||
name: eventName,
|
|
||||||
args: []
|
|
||||||
}
|
|
||||||
handleEvent(event);
|
handleEvent(event);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,22 @@ init = { text = "" };
|
||||||
|
|
||||||
update = state event \ event
|
update = state event \ event
|
||||||
| UpdateText newText \ state.{ text = newText }
|
| UpdateText newText \ state.{ text = newText }
|
||||||
| Submit _ \ state.{ text = "" };
|
| Submit _ \ state.{ text = "" }
|
||||||
# | _ \ state;
|
| Go \ state.{ text = "" };
|
||||||
|
|
||||||
view = state viewport \
|
view = state viewport \
|
||||||
Column {
|
Column {
|
||||||
gap = 20,
|
gap = 20,
|
||||||
children = [
|
children = [
|
||||||
|
Text {
|
||||||
|
content = "window: " & str(viewport.width) & " x " & str(viewport.height),
|
||||||
|
x = 0,
|
||||||
|
y = 20
|
||||||
|
},
|
||||||
Text { content = "You typed: " & state.text, x = 0, y = 20 },
|
Text { content = "You typed: " & state.text, x = 0, y = 20 },
|
||||||
Stack {
|
Stack {
|
||||||
children = [
|
children = [
|
||||||
Rect { w = 300, h = 40, color = "white" },
|
Rect { w = viewport.width, h = 40, color = "blue" },
|
||||||
TextInput {
|
TextInput {
|
||||||
value = state.text,
|
value = state.text,
|
||||||
placeholder = "Type something...",
|
placeholder = "Type something...",
|
||||||
|
|
@ -24,9 +29,9 @@ view = state viewport \
|
||||||
onInput = UpdateText,
|
onInput = UpdateText,
|
||||||
onSubmit = Submit
|
onSubmit = Submit
|
||||||
}
|
}
|
||||||
# button ({ label = "Go", event = Go })
|
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
button { label = "Go", event = Go, theme = theme }
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ export type UIValue =
|
||||||
| { kind: 'text', content: string, x: number, y: number }
|
| { kind: 'text', content: string, x: number, y: number }
|
||||||
| { kind: 'row', children: UIValue[], gap: number }
|
| { kind: 'row', children: UIValue[], gap: number }
|
||||||
| { kind: 'column', children: UIValue[], gap: number }
|
| { kind: 'column', children: UIValue[], gap: number }
|
||||||
| { kind: 'clickable', child: UIValue, event: string }
|
| { kind: 'clickable', child: UIValue, event: Value }
|
||||||
| { kind: 'padding', child: UIValue, amount: number }
|
| { kind: 'padding', child: UIValue, amount: number }
|
||||||
| { kind: 'stack', children: UIValue[] }
|
| { kind: 'stack', children: UIValue[] }
|
||||||
| { kind: 'text-input', value: string, placeholder: string, x: number, y: number, w: number, h: number, focused: boolean, onInput: Value, onSubmit: Value }
|
| { kind: 'text-input', value: string, placeholder: string, x: number, y: number, w: number, h: number, focused: boolean, onInput: Value, onSubmit: Value }
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
|
# button : Record -> UI
|
||||||
button = config \
|
button = config \
|
||||||
Clickable {
|
Clickable {
|
||||||
event = config.event,
|
event = config.event,
|
||||||
child = Stack {
|
child = Stack {
|
||||||
children = [
|
children = [
|
||||||
Rect { w = 100, h = 40, color = "blue" },
|
Rect { w = 100, h = 40, color = config.theme.colors.primary },
|
||||||
Text { content = config.label, x = 10, y = 25}
|
Text { content = config.label, x = 10, y = 25, color = config.theme.colors.bg }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ type ClickRegion = {
|
||||||
y: number;
|
y: number;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
event: string;
|
event: Value;
|
||||||
};
|
};
|
||||||
|
|
||||||
type TextInputRegion = {
|
type TextInputRegion = {
|
||||||
|
|
@ -171,14 +171,12 @@ function measure(ui: UIValue): { width: number, height: number } {
|
||||||
case 'text-input':
|
case 'text-input':
|
||||||
return { width: ui.w, height: ui.h };
|
return { width: ui.w, height: ui.h };
|
||||||
}
|
}
|
||||||
|
|
||||||
// return { width: 0, height: 0 };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hitTest(x: number, y: number): string | null {
|
export function hitTest(x: number, y: number): Value | null {
|
||||||
for (const region of clickRegions) {
|
for (const region of clickRegions) {
|
||||||
if (x >= region.x && x < region.x + region.width &&
|
if (x >= region.x && x < region.x + region.width &&
|
||||||
x >= region.y && y < region.y + region.height) {
|
y >= region.y && y < region.y + region.height) {
|
||||||
return region.event;
|
return region.event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,10 @@ export function valueToUI(value: Value): UIValue {
|
||||||
const child = fields.child;
|
const child = fields.child;
|
||||||
const event = fields.event;
|
const event = fields.event;
|
||||||
|
|
||||||
if (event.kind !== 'string')
|
if (event.kind !== 'constructor')
|
||||||
throw new Error('Invalid Clickable fields');
|
throw new Error('Clickable event must be a constructor');
|
||||||
|
|
||||||
return { kind: 'clickable', event: event.value, child: valueToUI(child) };
|
return { kind: 'clickable', event: event, child: valueToUI(child) };
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'Padding': {
|
case 'Padding': {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue