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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,8 @@ class CustomState extends State {
// Define the events this state will handle as a static property.
static handledEvents = ['onpointerdown', 'onkeydown'];

enter(context, customOptions) {
super.enter(context);
enter(store, customOptions) {
super.enter(store);
console.log('CustomState has started.', customOptions);
}

Expand All @@ -461,7 +461,7 @@ class CustomState extends State {
onkeydown(event) {
if (event.key === 'Escape') {
// Switch to the 'selection' state (the default state).
this.context.stateManager.setState('selection');
this.store.stateManager.setState('selection');
}
// Return PROPAGATE_EVENT to propagate the event to the next state in the stack.
return PROPAGATE_EVENT;
Expand Down Expand Up @@ -501,7 +501,7 @@ The default state that handles user selection and drag events. It is automatical
- `onUp` (optional, function): Callback fired on `pointerup` if it was not a drag operation.
- `onClick` (optional, function): Callback fired when a complete 'click' is detected. This will not fire if `onDoubleClick` fires.
- `onDoubleClick` (optional, function): Callback fired when a complete 'double-click' is detected. Based on `e.detail === 2`.
- `onRightClick` (optional, function): Callback fired when a complete right-click is detected. The browser's default context menu is automatically prevented within the canvas area.
- `onRightClick` (optional, function): Callback fired when a complete right-click is detected. The browser's default store menu is automatically prevented within the canvas area.
- `onDragStart` (optional, function): Callback fired *once* when a drag operation (for multi-selection) begins (after moving beyond a threshold).
- `onDrag` (optional, function): Callback fired repeatedly *during* a drag operation.
- `onDragEnd` (optional, function): Callback fired when the drag operation *ends* (`pointerup`).
Expand Down
6 changes: 3 additions & 3 deletions README_KR.md
Original file line number Diff line number Diff line change
Expand Up @@ -453,8 +453,8 @@ class CustomState extends State {
// 이 상태가 처리할 이벤트를 static 속성으로 정의합니다.
static handledEvents = ['onpointerdown', 'onkeydown'];

enter(context, customOptions) {
super.enter(context);
enter(store, customOptions) {
super.enter(store);
console.log('CustomState가 시작되었습니다.', customOptions);
}

Expand All @@ -471,7 +471,7 @@ class CustomState extends State {
onkeydown(event) {
if (event.key === 'Escape') {
// 'selection' 상태(기본 상태)로 전환합니다.
this.context.stateManager.setState('selection');
this.store.stateManager.setState('selection');
}
// 이벤트를 스택의 다음 상태로 전파하려면 PROPAGATE_EVENT를 반환합니다.
return PROPAGATE_EVENT;
Expand Down
73 changes: 35 additions & 38 deletions src/assets/textures/rect.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
import { Graphics } from 'pixi.js';
import { EachRadius } from '../../display/data-schema/primitive-schema';
import { getColor } from '../../utils/get';
import { Rect } from '../../display/elements/Rect';
import { cacheKey, generateTexture } from './utils';

const DEFAULT_RECT_OPTS = {
fill: 'transparent',
borderWidth: 0,
borderColor: 'black',
radius: 0,
};

const normalizeRectOpts = (rectOpts = {}) => {
const normalized = { ...rectOpts };
for (const key of ['fill', 'borderWidth', 'borderColor', 'radius']) {
if (normalized[key] == null) delete normalized[key];
}
return normalized;
};

export const createRectTexture = (renderer, theme, rectOpts) => {
const normalizedRectOpts = normalizeRectOpts(rectOpts);
const {
fill = null,
borderWidth = null,
borderColor = null,
radius = null,
} = rectOpts;
fill = DEFAULT_RECT_OPTS.fill,
borderWidth = DEFAULT_RECT_OPTS.borderWidth,
borderColor = DEFAULT_RECT_OPTS.borderColor,
radius = DEFAULT_RECT_OPTS.radius,
} = normalizedRectOpts;
const rect = createRect(theme, { fill, borderWidth, borderColor, radius });
const texture = generateTexture(rect, renderer);

Expand All @@ -34,36 +48,19 @@ export const createRectTexture = (renderer, theme, rectOpts) => {
};

const createRect = (theme, { fill, borderWidth, borderColor, radius }) => {
const graphics = new Graphics();
const size = 20 + borderWidth;

const xywh = [0, 0, size, size];
const parsedRadius = EachRadius.safeParse(radius);
if (typeof radius === 'number' && radius > 0) {
graphics.roundRect(...xywh, radius);
} else if (parsedRadius.success) {
const r = parsedRadius.data;
graphics.roundShape(
[
{ x: 0, y: 0, radius: r.topLeft },
{ x: size, y: 0, radius: r.topRight },
{ x: size, y: size, radius: r.bottomRight },
{ x: 0, y: size, radius: r.bottomLeft },
],
0,
);
} else {
graphics.rect(...xywh);
}

if (fill) graphics.fill(getColor(theme, fill));
if (borderWidth) {
graphics.stroke({
width: borderWidth,
color: getColor(theme, borderColor),
});
}
return graphics;
const safeBorderWidth = borderWidth ?? 0;
const size = 20 + safeBorderWidth;
const stroke =
safeBorderWidth > 0
? { width: safeBorderWidth, color: borderColor }
: undefined;
const rect = new Rect({ theme });
const changes = { size: { width: size, height: size } };
if (fill !== undefined) changes.fill = fill;
if (stroke !== undefined) changes.stroke = stroke;
if (radius !== undefined) changes.radius = radius;
rect.apply(changes);
return rect;
};

const getSliceDimension = (radius, key1, key2) => {
Expand Down
2 changes: 1 addition & 1 deletion src/assets/textures/texture.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { cacheKey } from './utils';
export const getTexture = (renderer, theme, config) => {
let texture = null;
if (typeof config === 'string') {
texture = Assets.get(config);
texture = Assets.cache.has(config) ? Assets.get(config) : null;
} else {
texture = Assets.cache.has(cacheKey(renderer, config))
? Assets.cache.get(cacheKey(renderer, config))
Expand Down
12 changes: 7 additions & 5 deletions src/command/commands/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export class UpdateCommand extends Command {
this.elementId = element.id;

this.parent = element.parent;
this.context = element.context;
this.store = element.store;

this.changes = changes;
this.options = options;
Expand Down Expand Up @@ -52,9 +52,9 @@ export class UpdateCommand extends Command {
}
}

if (this.context?.viewport && !this.context.viewport.destroyed) {
if (this.store?.viewport && !this.store.viewport.destroyed) {
const candidates = collectCandidates(
this.context.viewport,
this.store.viewport,
(node) => node.id === targetId,
);
if (candidates[0]) {
Expand All @@ -81,9 +81,11 @@ export class UpdateCommand extends Command {
changes.attrs !== null &&
typeof changes.attrs === 'object'
) {
const prevAttrs = {};
const prevAttrs = this._deepClone(currentProps.attrs || {});
for (const attrKey of Object.keys(changes.attrs)) {
prevAttrs[attrKey] = this._deepClone(this.element[attrKey]);
if (!(attrKey in prevAttrs)) {
prevAttrs[attrKey] = this._deepClone(this.element[attrKey]);
}
}
slice.attrs = prevAttrs;
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/display/Viewport.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const ComposedViewport = mixins(Viewport, Base, Childrenable);

export default class BaseViewport extends ComposedViewport {
constructor(options) {
super({ type: 'canvas', ...options });
super({ type: 'canvas', sortableChildren: true, ...options });
}

apply(changes, options) {
Expand Down
4 changes: 2 additions & 2 deletions src/display/components/Background.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ const ComposedBackground = mixins(
export class Background extends ComposedBackground {
static respectsPadding = false;

constructor(context) {
super({ type: 'background', context, texture: Texture.WHITE });
constructor(store) {
super({ type: 'background', store, texture: Texture.WHITE });
}

apply(changes, options) {
Expand Down
4 changes: 2 additions & 2 deletions src/display/components/Bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ const ComposedBar = mixins(
);

export class Bar extends ComposedBar {
constructor(context) {
super({ type: 'bar', context, texture: Texture.WHITE });
constructor(store) {
super({ type: 'bar', store, texture: Texture.WHITE });

this.constructor.registerHandler(
EXTRA_KEYS.PLACEMENT,
Expand Down
4 changes: 2 additions & 2 deletions src/display/components/Icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ const ComposedIcon = mixins(
);

export class Icon extends ComposedIcon {
constructor(context) {
super({ type: 'icon', context, texture: Texture.WHITE });
constructor(store) {
super({ type: 'icon', store, texture: Texture.WHITE });

this.constructor.registerHandler(
EXTRA_KEYS.PLACEMENT,
Expand Down
6 changes: 4 additions & 2 deletions src/display/components/Text.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Base } from '../mixins/Base';
import { Placementable } from '../mixins/Placementable';
import { Showable } from '../mixins/Showable';
import { Textable } from '../mixins/Textable';
import { TextLayoutable } from '../mixins/TextLayoutable';
import { Textstyleable } from '../mixins/Textstyleable';
import { Tintable } from '../mixins/Tintable';
import { mixins } from '../mixins/utils';
Expand All @@ -18,13 +19,14 @@ const ComposedText = mixins(
Showable,
Textable,
Textstyleable,
TextLayoutable,
Tintable,
Placementable,
);

export class Text extends ComposedText {
constructor(context) {
super({ type: 'text', context, text: '' });
constructor(store) {
super({ type: 'text', store, text: '' });

this.constructor.registerHandler(
EXTRA_KEYS.PLACEMENT,
Expand Down
4 changes: 2 additions & 2 deletions src/display/components/creator.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ export const registerComponent = (type, componentClass) => {
creator[type] = componentClass;
};

export const newComponent = (type, context) => {
export const newComponent = (type, store) => {
if (!creator[type]) {
throw new Error(`Component type "${type}" has not been registered.`);
}
return new creator[type](context);
return new creator[type](store);
};
4 changes: 2 additions & 2 deletions src/display/data-schema/component-schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { z } from 'zod';
import {
Base,
Color,
LabelTextStyle,
Margin,
Placement,
PxOrPercentSize,
TextStyle,
TextureStyle,
} from './primitive-schema';

Expand Down Expand Up @@ -68,7 +68,7 @@ export const textSchema = Base.extend({
margin: Margin.default(0),
tint: Color,
text: z.string().default(''),
style: TextStyle,
style: LabelTextStyle,
split: z.number().int().default(0),
}).strict();

Expand Down
51 changes: 50 additions & 1 deletion src/display/data-schema/element-schema.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { z } from 'zod';
import { componentArraySchema } from './component-schema';
import { Base, Gap, Margin, RelationsStyle, Size } from './primitive-schema';
import {
Base,
Color,
EachRadius,
ElementTextStyle,
Gap,
Margin,
RelationsStyle,
Size,
StrokeStyle,
} from './primitive-schema';

/**
* A viewport is a container that can be panned and zoomed.
Expand Down Expand Up @@ -65,11 +75,50 @@ export const relationsSchema = Base.extend({
style: RelationsStyle,
}).strict();

/**
* Renders an image from a URL or an asset key.
* Visually represented by a `Container` containing a `Sprite`.
* @see {@link https://pixijs.download/release/docs/scene.Sprite.html}
*/
export const imageSchema = Base.extend({
type: z.literal('image'),
source: z.string(),
size: Size.optional(),
}).strict();

/**
* Renders text using BitmapText.
* Visually represented by a `Container` containing a `BitmapText`.
* @see {@link https://pixijs.download/release/docs/text_bitmap.BitmapText.html}
*/
export const textSchema = Base.extend({
type: z.literal('text'),
text: z.string().default(''),
style: ElementTextStyle,
size: Size.optional(),
}).strict();

/**
* Renders a rectangle using a Graphics object.
* Visually represented by a `Graphics`.
* @see {@link https://pixijs.download/release/docs/scene.Graphics.html}
*/
export const rectSchema = Base.extend({
type: z.literal('rect'),
size: Size,
fill: Color.optional(),
stroke: StrokeStyle.optional(),
radius: z.union([z.number().nonnegative(), EachRadius]).default(0),
}).strict();

export const elementTypes = z.discriminatedUnion('type', [
groupSchema,
gridSchema,
itemSchema,
relationsSchema,
imageSchema,
textSchema,
rectSchema,
]);

export const mapDataSchema = z
Expand Down
Loading