@glennjong/pixel-window 0.1.4 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,3 +1,38 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+
5
+ declare const PixelWindow: ({ style, stroke, frame, background, pixel, children, }: {
6
+ style?: React.CSSProperties;
7
+ pixel?: number;
8
+ stroke?: string;
9
+ frame?: string;
10
+ background?: string;
11
+ children: ReactNode;
12
+ }) => react_jsx_runtime.JSX.Element;
13
+ declare const FreePixelWindow: ({ name, children, pixel, stroke, frame, background, position: initialPosition, style, minWidth, minHeight, onChange, }: {
14
+ name?: string;
15
+ children: ReactNode;
16
+ pixel?: number;
17
+ stroke?: string;
18
+ frame?: string;
19
+ background?: string;
20
+ position?: {
21
+ x: number;
22
+ y: number;
23
+ };
24
+ style?: React.CSSProperties;
25
+ minWidth?: number;
26
+ minHeight?: number;
27
+ onChange?: (position: {
28
+ x: number;
29
+ y: number;
30
+ }, size: {
31
+ width: number;
32
+ height: number;
33
+ }) => void;
34
+ }) => react.ReactPortal;
35
+
1
36
  declare function getFrame({ size, stroke, frame, background }: {
2
37
  size: number;
3
38
  stroke: string;
@@ -8,4 +43,4 @@ declare const frame: string;
8
43
  declare const checkbox: string;
9
44
  declare const checkboxLight: string;
10
45
 
11
- export { checkbox, checkboxLight, frame, getFrame };
46
+ export { FreePixelWindow, PixelWindow, checkbox, checkboxLight, frame, getFrame };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,38 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+
5
+ declare const PixelWindow: ({ style, stroke, frame, background, pixel, children, }: {
6
+ style?: React.CSSProperties;
7
+ pixel?: number;
8
+ stroke?: string;
9
+ frame?: string;
10
+ background?: string;
11
+ children: ReactNode;
12
+ }) => react_jsx_runtime.JSX.Element;
13
+ declare const FreePixelWindow: ({ name, children, pixel, stroke, frame, background, position: initialPosition, style, minWidth, minHeight, onChange, }: {
14
+ name?: string;
15
+ children: ReactNode;
16
+ pixel?: number;
17
+ stroke?: string;
18
+ frame?: string;
19
+ background?: string;
20
+ position?: {
21
+ x: number;
22
+ y: number;
23
+ };
24
+ style?: React.CSSProperties;
25
+ minWidth?: number;
26
+ minHeight?: number;
27
+ onChange?: (position: {
28
+ x: number;
29
+ y: number;
30
+ }, size: {
31
+ width: number;
32
+ height: number;
33
+ }) => void;
34
+ }) => react.ReactPortal;
35
+
1
36
  declare function getFrame({ size, stroke, frame, background }: {
2
37
  size: number;
3
38
  stroke: string;
@@ -8,4 +43,4 @@ declare const frame: string;
8
43
  declare const checkbox: string;
9
44
  declare const checkboxLight: string;
10
45
 
11
- export { checkbox, checkboxLight, frame, getFrame };
46
+ export { FreePixelWindow, PixelWindow, checkbox, checkboxLight, frame, getFrame };
package/dist/index.js CHANGED
@@ -56,7 +56,7 @@ var checkboxLight = getCheckbox({
56
56
  color: "#000"
57
57
  });
58
58
 
59
- // src/index.tsx
59
+ // src/PixelWindow.tsx
60
60
  var import_react = require("react");
61
61
  var import_react_dom = require("react-dom");
62
62
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -105,7 +105,8 @@ var FreePixelWindow = ({
105
105
  position: initialPosition = { x: 100, y: 100 },
106
106
  style,
107
107
  minWidth = 120,
108
- minHeight = 100
108
+ minHeight = 100,
109
+ onChange
109
110
  }) => {
110
111
  const [position, setPosition] = (0, import_react.useState)(() => {
111
112
  if (name) {
@@ -122,6 +123,11 @@ var FreePixelWindow = ({
122
123
  const [isResizing, setIsResizing] = (0, import_react.useState)(false);
123
124
  const [dragStart, setDragStart] = (0, import_react.useState)({ x: 0, y: 0 });
124
125
  const [resizeStart, setResizeStart] = (0, import_react.useState)({ width: 0, height: 0, mouseX: 0, mouseY: 0 });
126
+ (0, import_react.useEffect)(() => {
127
+ if (onChange) {
128
+ onChange(position, size);
129
+ }
130
+ }, [position, size, onChange]);
125
131
  (0, import_react.useEffect)(() => {
126
132
  if (name) {
127
133
  localStorage.setItem(`${name}-position`, JSON.stringify(position));
@@ -213,6 +219,8 @@ var FreePixelWindow = ({
213
219
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
214
220
  padding: `${pixel}px`,
215
221
  paddingTop: 0,
222
+ height: `calc(100% - ${pixel}px)`,
223
+ boxSizing: "border-box",
216
224
  ...style
217
225
  }, children }),
218
226
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/frame.ts","../src/index.tsx"],"sourcesContent":["export * from './index';\nexport * from './frame';\n","export function getFrame({ size, stroke, frame, background }: { size: number; stroke: string; frame: string; background: string }): string {\n const height = size; // Assuming square frames\n const svg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"{{size}}\" height=\"{{height}}\" viewBox=\"0 0 12 12\"><path fill=\"{{stroke}}\" d=\"M2 0h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9zM1 1h1v1H1z\"/><path fill=\"{{frame}}\" d=\"M2 1h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{stroke}}\" d=\"M10 1h1v1h-1zM0 2h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 2h1v1H1zm1 0h1v1H2z\"/><path fill=\"{{stroke}}\" d=\"M3 2h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{frame}}\" d=\"M9 2h1v1H9zm1 0h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 2h1v1h-1zM0 3h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 3h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 3h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 3h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 3h1v1h-1zM0 4h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 4h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 4h1v1H2zm1 0h1v1H3z\"/><path fill=\"{{background}}\" d=\"M4 4h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7z\"/><path fill=\"{{stroke}}\" d=\"M8 4h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 4h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 4h1v1h-1zM0 5h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 5h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 5h1v1H2z\"/><path fill=\"{{background}}\" d=\"M3 5h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{stroke}}\" d=\"M9 5h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 5h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 5h1v1h-1zM0 6h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 6h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 6h1v1H2z\"/><path fill=\"{{background}}\" d=\"M3 6h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{stroke}}\" d=\"M9 6h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 6h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 6h1v1h-1zM0 7h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 7h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 7h1v1H2z\"/><path fill=\"{{background}}\" d=\"M3 7h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{stroke}}\" d=\"M9 7h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 7h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 7h1v1h-1zM0 8h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 8h1v1H1zm1 0h1v1H2z\"/><path fill=\"{{stroke}}\" d=\"M3 8h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{frame}}\" d=\"M9 8h1v1H9zm1 0h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 8h1v1h-1zM0 9h1v1H0zm1 0h1v1H1z\"/><path fill=\"{{frame}}\" d=\"M2 9h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{stroke}}\" d=\"M10 9h1v1h-1zm-9 1h1v1H1zm1 0h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9zm1 0h1v1h-1zm-8 1h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/></svg>'\n .replace(/\\{\\{size\\}\\}/g, size.toString())\n .replace(/\\{\\{height\\}\\}/g, height.toString())\n .replace(/\\{\\{stroke\\}\\}/g, stroke)\n .replace(/\\{\\{frame\\}\\}/g, frame)\n .replace(/\\{\\{background\\}\\}/g, background);\n\n // Encode SVG to Base64 safely\n const encodedSvg = encodeURIComponent(svg)\n .replace(/%([0-9A-F]{2})/g, (_, p1) => String.fromCharCode(parseInt(p1, 16)));\n\n return `data:image/svg+xml;base64,${btoa(encodedSvg)}`;\n}\n\nfunction getCheckbox({ size, color }: { size: number; color: string }) {\n const svg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"{{width}}\" height=\"{{height}}\" viewBox=\"0 0 12 6\"><rect width=\"1\" height=\"1\" x=\"1\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"4\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"7\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"8\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"9\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"10\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"1\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"4\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"7\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"8\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"9\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"10\" y=\"5\" fill=\"{{color}}\"></rect></svg>'\n .replace(/\\{\\{width\\}\\}/g, (size*2).toString())\n .replace(/\\{\\{height\\}\\}/g, size.toString())\n .replace(/\\{\\{color\\}\\}/g, color)\n \n const encodedSvg = encodeURIComponent(svg)\n .replace(/%([0-9A-F]{2})/g, (_, p1) => String.fromCharCode(parseInt(p1, 16)))\n .replace(/#/g, '%23');\n\n return `data:image/svg+xml;base64,${btoa(encodedSvg)}`;\n\n}\n\nexport const frame = getFrame({\n size: 160,\n stroke: '#000',\n frame: '#333',\n background: '#DDD',\n});\n\nexport const checkbox = getCheckbox({\n size: 12,\n color: '#000',\n});\nexport const checkboxLight = getCheckbox({\n size: 12,\n color: '#000',\n});\n","import { getFrame } from './frame';\nimport { useCallback, useEffect, useState, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nexport const PixelWindow = ({\n style = {},\n stroke = '#000',\n frame = '#333',\n background = '#DDD',\n pixel = 160,\n children,\n}: {\n style?: React.CSSProperties,\n pixel?: number,\n stroke?: string\n frame?: string\n background?: string\n children: ReactNode;\n}) => {\n\n const pixelFrame = getFrame({\n size: pixel,\n stroke,\n frame,\n background,\n });\n\n\n return (\n <div\n className=\"window\"\n style={{\n width: '100%',\n height: '100%',\n borderImage: `url(${pixelFrame})`,\n borderImageSlice: '49% 49% fill',\n borderImageWidth: `${pixel}px`,\n }}\n >\n <div style={{ padding: `${pixel}px`}}>\n <div\n style={{ boxSizing: 'border-box', ...style }}\n >\n {children}\n </div>\n </div>\n </div>\n );\n};\n\nexport const FreePixelWindow = ({\n name,\n children,\n pixel = 16,\n stroke = '#000',\n frame = '#333',\n background = '#DDD',\n position: initialPosition = { x: 100, y: 100 },\n style,\n minWidth = 120,\n minHeight = 100,\n}: {\n name?: string;\n children: ReactNode;\n pixel?: number;\n stroke?: string;\n frame?: string;\n background?: string;\n position?: { x: number; y: number };\n style?: React.CSSProperties;\n minWidth?: number;\n minHeight?: number;\n}) => {\n\n const [position, setPosition] = useState(() => {\n if (name) {\n const savedPosition = localStorage.getItem(`${name}-position`);\n return savedPosition ? JSON.parse(savedPosition) : initialPosition;\n }\n return initialPosition;\n });\n\n const [size, setSize] = useState(() => {\n const savedSize = localStorage.getItem(`${name}-size`);\n return savedSize ? JSON.parse(savedSize) : { width: 300, height: 200 };\n });\n\n const [isDragging, setIsDragging] = useState(false);\n const [isResizing, setIsResizing] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [resizeStart, setResizeStart] = useState({ width: 0, height: 0, mouseX: 0, mouseY: 0 });\n\n useEffect(() => {\n if (name) {\n localStorage.setItem(`${name}-position`, JSON.stringify(position));\n localStorage.setItem(`${name}-size`, JSON.stringify(size));\n\n }\n }, [name, position, size]);\n\n const handleMouseMove = useCallback((e: MouseEvent) => {\n if (isDragging) {\n setPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n });\n } else if (isResizing) {\n const deltaX = e.clientX - resizeStart.mouseX;\n const deltaY = e.clientY - resizeStart.mouseY;\n\n setSize({\n width: Math.max(resizeStart.width + deltaX, minWidth),\n height: Math.max(resizeStart.height + deltaY, minHeight),\n });\n }\n }, [isDragging, isResizing, dragStart, resizeStart, minWidth, minHeight]);\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n setIsResizing(false);\n }, []);\n\n useEffect(() => {\n if (isDragging || isResizing) {\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n } else {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n }\n\n return () => {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n };\n }, [isDragging, isResizing, handleMouseMove, handleMouseUp]);\n\n const handleMouseDown = (e: React.MouseEvent) => {\n setIsDragging(true);\n setDragStart({ x: e.clientX - position.x, y: e.clientY - position.y });\n };\n\n const handleResizeStart = (e: React.MouseEvent) => {\n e.stopPropagation();\n setIsResizing(true);\n setResizeStart({\n width: size.width,\n height: size.height,\n mouseX: e.clientX,\n mouseY: e.clientY,\n });\n };\n\n const pixelFrame = getFrame({\n size: pixel,\n stroke,\n frame,\n background,\n });\n\n return createPortal(\n <div\n style={{\n position: 'absolute',\n overflow: 'hidden',\n resize: 'none',\n top: position.y,\n left: position.x,\n width: size.width,\n height: size.height,\n borderImage: `url(${pixelFrame})`,\n borderImageSlice: '49% 49% fill',\n borderImageWidth: `${pixel}px`,\n }}\n onMouseUp={handleMouseUp}\n >\n <div \n onMouseDown={handleMouseDown}\n onMouseUp={handleMouseUp}\n style={{\n height: `${pixel}px`,\n cursor: \"grab\",\n userSelect: \"none\"\n }}\n ></div>\n <div style={{\n padding: `${pixel}px`,\n paddingTop: 0,\n ...style\n }}>{children}</div>\n <div\n onMouseDown={handleResizeStart}\n style={{\n position: 'absolute',\n width: `${pixel}px`,\n height: `${pixel}px`,\n cursor: 'se-resize',\n bottom: 0,\n right: 0,\n }}\n ></div>\n </div>,\n document.body\n );\n};\n"],"mappings":"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","names":["frame","frame"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/frame.ts","../src/PixelWindow.tsx"],"sourcesContent":["export * from './PixelWindow';\nexport * from './frame';","export function getFrame({ size, stroke, frame, background }: { size: number; stroke: string; frame: string; background: string }): string {\n const height = size; // Assuming square frames\n const svg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"{{size}}\" height=\"{{height}}\" viewBox=\"0 0 12 12\"><path fill=\"{{stroke}}\" d=\"M2 0h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9zM1 1h1v1H1z\"/><path fill=\"{{frame}}\" d=\"M2 1h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{stroke}}\" d=\"M10 1h1v1h-1zM0 2h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 2h1v1H1zm1 0h1v1H2z\"/><path fill=\"{{stroke}}\" d=\"M3 2h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{frame}}\" d=\"M9 2h1v1H9zm1 0h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 2h1v1h-1zM0 3h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 3h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 3h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 3h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 3h1v1h-1zM0 4h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 4h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 4h1v1H2zm1 0h1v1H3z\"/><path fill=\"{{background}}\" d=\"M4 4h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7z\"/><path fill=\"{{stroke}}\" d=\"M8 4h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 4h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 4h1v1h-1zM0 5h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 5h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 5h1v1H2z\"/><path fill=\"{{background}}\" d=\"M3 5h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{stroke}}\" d=\"M9 5h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 5h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 5h1v1h-1zM0 6h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 6h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 6h1v1H2z\"/><path fill=\"{{background}}\" d=\"M3 6h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{stroke}}\" d=\"M9 6h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 6h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 6h1v1h-1zM0 7h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 7h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 7h1v1H2z\"/><path fill=\"{{background}}\" d=\"M3 7h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{stroke}}\" d=\"M9 7h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 7h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 7h1v1h-1zM0 8h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 8h1v1H1zm1 0h1v1H2z\"/><path fill=\"{{stroke}}\" d=\"M3 8h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{frame}}\" d=\"M9 8h1v1H9zm1 0h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 8h1v1h-1zM0 9h1v1H0zm1 0h1v1H1z\"/><path fill=\"{{frame}}\" d=\"M2 9h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{stroke}}\" d=\"M10 9h1v1h-1zm-9 1h1v1H1zm1 0h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9zm1 0h1v1h-1zm-8 1h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/></svg>'\n .replace(/\\{\\{size\\}\\}/g, size.toString())\n .replace(/\\{\\{height\\}\\}/g, height.toString())\n .replace(/\\{\\{stroke\\}\\}/g, stroke)\n .replace(/\\{\\{frame\\}\\}/g, frame)\n .replace(/\\{\\{background\\}\\}/g, background);\n\n // Encode SVG to Base64 safely\n const encodedSvg = encodeURIComponent(svg)\n .replace(/%([0-9A-F]{2})/g, (_, p1) => String.fromCharCode(parseInt(p1, 16)));\n\n return `data:image/svg+xml;base64,${btoa(encodedSvg)}`;\n}\n\nfunction getCheckbox({ size, color }: { size: number; color: string }) {\n const svg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"{{width}}\" height=\"{{height}}\" viewBox=\"0 0 12 6\"><rect width=\"1\" height=\"1\" x=\"1\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"4\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"7\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"8\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"9\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"10\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"1\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"4\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"7\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"8\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"9\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"10\" y=\"5\" fill=\"{{color}}\"></rect></svg>'\n .replace(/\\{\\{width\\}\\}/g, (size*2).toString())\n .replace(/\\{\\{height\\}\\}/g, size.toString())\n .replace(/\\{\\{color\\}\\}/g, color)\n \n const encodedSvg = encodeURIComponent(svg)\n .replace(/%([0-9A-F]{2})/g, (_, p1) => String.fromCharCode(parseInt(p1, 16)))\n .replace(/#/g, '%23');\n\n return `data:image/svg+xml;base64,${btoa(encodedSvg)}`;\n\n}\n\nexport const frame = getFrame({\n size: 160,\n stroke: '#000',\n frame: '#333',\n background: '#DDD',\n});\n\nexport const checkbox = getCheckbox({\n size: 12,\n color: '#000',\n});\nexport const checkboxLight = getCheckbox({\n size: 12,\n color: '#000',\n});\n","import { getFrame } from './frame';\nimport { useCallback, useEffect, useState, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nexport const PixelWindow = ({\n style = {},\n stroke = '#000',\n frame = '#333',\n background = '#DDD',\n pixel = 160,\n children,\n}: {\n style?: React.CSSProperties,\n pixel?: number,\n stroke?: string\n frame?: string\n background?: string\n children: ReactNode;\n}) => {\n\n const pixelFrame = getFrame({\n size: pixel,\n stroke,\n frame,\n background,\n });\n\n return (\n <div\n className=\"window\"\n style={{\n width: '100%',\n height: '100%',\n borderImage: `url(${pixelFrame})`,\n borderImageSlice: '49% 49% fill',\n borderImageWidth: `${pixel}px`,\n }}\n >\n <div style={{ padding: `${pixel}px`}}>\n <div\n style={{ boxSizing: 'border-box', ...style }}\n >\n {children}\n </div>\n </div>\n </div>\n );\n};\n\nexport const FreePixelWindow = ({\n name,\n children,\n pixel = 16,\n stroke = '#000',\n frame = '#333',\n background = '#DDD',\n position: initialPosition = { x: 100, y: 100 },\n style,\n minWidth = 120,\n minHeight = 100,\n onChange,\n}: {\n name?: string;\n children: ReactNode;\n pixel?: number;\n stroke?: string;\n frame?: string;\n background?: string;\n position?: { x: number; y: number };\n style?: React.CSSProperties;\n minWidth?: number;\n minHeight?: number;\n onChange?: (position: { x: number; y: number }, size: { width: number; height: number }) => void;\n}) => {\n\n const [position, setPosition] = useState(() => {\n if (name) {\n const savedPosition = localStorage.getItem(`${name}-position`);\n return savedPosition ? JSON.parse(savedPosition) : initialPosition;\n }\n return initialPosition;\n });\n\n const [size, setSize] = useState(() => {\n const savedSize = localStorage.getItem(`${name}-size`);\n return savedSize ? JSON.parse(savedSize) : { width: 300, height: 200 };\n });\n\n const [isDragging, setIsDragging] = useState(false);\n const [isResizing, setIsResizing] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [resizeStart, setResizeStart] = useState({ width: 0, height: 0, mouseX: 0, mouseY: 0 });\n\n useEffect(() => {\n if (onChange) {\n onChange(position, size);\n }\n }, [position, size, onChange]);\n\n useEffect(() => {\n if (name) {\n localStorage.setItem(`${name}-position`, JSON.stringify(position));\n localStorage.setItem(`${name}-size`, JSON.stringify(size));\n }\n }, [name, position, size]);\n\n const handleMouseMove = useCallback((e: MouseEvent) => {\n if (isDragging) {\n setPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n });\n } else if (isResizing) {\n const deltaX = e.clientX - resizeStart.mouseX;\n const deltaY = e.clientY - resizeStart.mouseY;\n\n setSize({\n width: Math.max(resizeStart.width + deltaX, minWidth),\n height: Math.max(resizeStart.height + deltaY, minHeight),\n });\n }\n }, [isDragging, isResizing, dragStart, resizeStart, minWidth, minHeight]);\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n setIsResizing(false);\n }, []);\n\n useEffect(() => {\n if (isDragging || isResizing) {\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n } else {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n }\n\n return () => {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n };\n }, [isDragging, isResizing, handleMouseMove, handleMouseUp]);\n\n const handleMouseDown = (e: React.MouseEvent) => {\n setIsDragging(true);\n setDragStart({ x: e.clientX - position.x, y: e.clientY - position.y });\n };\n\n const handleResizeStart = (e: React.MouseEvent) => {\n e.stopPropagation();\n setIsResizing(true);\n setResizeStart({\n width: size.width,\n height: size.height,\n mouseX: e.clientX,\n mouseY: e.clientY,\n });\n };\n\n const pixelFrame = getFrame({\n size: pixel,\n stroke,\n frame,\n background,\n });\n\n return createPortal(\n <div\n style={{\n position: 'absolute',\n overflow: 'hidden',\n resize: 'none',\n top: position.y,\n left: position.x,\n width: size.width,\n height: size.height,\n borderImage: `url(${pixelFrame})`,\n borderImageSlice: '49% 49% fill',\n borderImageWidth: `${pixel}px`,\n }}\n onMouseUp={handleMouseUp}\n >\n <div \n onMouseDown={handleMouseDown}\n onMouseUp={handleMouseUp}\n style={{\n height: `${pixel}px`,\n cursor: \"grab\",\n userSelect: \"none\"\n }}\n ></div>\n <div style={{\n padding: `${pixel}px`,\n paddingTop: 0,\n height: `calc(100% - ${pixel}px)`,\n boxSizing: 'border-box',\n ...style\n }}>{children}</div>\n <div\n onMouseDown={handleResizeStart}\n style={{\n position: 'absolute',\n width: `${pixel}px`,\n height: `${pixel}px`,\n cursor: 'se-resize',\n bottom: 0,\n right: 0,\n }}\n ></div>\n </div>,\n document.body\n );\n};\n"],"mappings":"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","names":["frame","frame"]}
package/dist/index.mjs CHANGED
@@ -25,7 +25,7 @@ var checkboxLight = getCheckbox({
25
25
  color: "#000"
26
26
  });
27
27
 
28
- // src/index.tsx
28
+ // src/PixelWindow.tsx
29
29
  import { useCallback, useEffect, useState } from "react";
30
30
  import { createPortal } from "react-dom";
31
31
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -74,7 +74,8 @@ var FreePixelWindow = ({
74
74
  position: initialPosition = { x: 100, y: 100 },
75
75
  style,
76
76
  minWidth = 120,
77
- minHeight = 100
77
+ minHeight = 100,
78
+ onChange
78
79
  }) => {
79
80
  const [position, setPosition] = useState(() => {
80
81
  if (name) {
@@ -91,6 +92,11 @@ var FreePixelWindow = ({
91
92
  const [isResizing, setIsResizing] = useState(false);
92
93
  const [dragStart, setDragStart] = useState({ x: 0, y: 0 });
93
94
  const [resizeStart, setResizeStart] = useState({ width: 0, height: 0, mouseX: 0, mouseY: 0 });
95
+ useEffect(() => {
96
+ if (onChange) {
97
+ onChange(position, size);
98
+ }
99
+ }, [position, size, onChange]);
94
100
  useEffect(() => {
95
101
  if (name) {
96
102
  localStorage.setItem(`${name}-position`, JSON.stringify(position));
@@ -182,6 +188,8 @@ var FreePixelWindow = ({
182
188
  /* @__PURE__ */ jsx("div", { style: {
183
189
  padding: `${pixel}px`,
184
190
  paddingTop: 0,
191
+ height: `calc(100% - ${pixel}px)`,
192
+ boxSizing: "border-box",
185
193
  ...style
186
194
  }, children }),
187
195
  /* @__PURE__ */ jsx(
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/frame.ts","../src/index.tsx"],"sourcesContent":["export function getFrame({ size, stroke, frame, background }: { size: number; stroke: string; frame: string; background: string }): string {\n const height = size; // Assuming square frames\n const svg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"{{size}}\" height=\"{{height}}\" viewBox=\"0 0 12 12\"><path fill=\"{{stroke}}\" d=\"M2 0h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9zM1 1h1v1H1z\"/><path fill=\"{{frame}}\" d=\"M2 1h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{stroke}}\" d=\"M10 1h1v1h-1zM0 2h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 2h1v1H1zm1 0h1v1H2z\"/><path fill=\"{{stroke}}\" d=\"M3 2h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{frame}}\" d=\"M9 2h1v1H9zm1 0h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 2h1v1h-1zM0 3h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 3h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 3h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 3h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 3h1v1h-1zM0 4h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 4h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 4h1v1H2zm1 0h1v1H3z\"/><path fill=\"{{background}}\" d=\"M4 4h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7z\"/><path fill=\"{{stroke}}\" d=\"M8 4h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 4h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 4h1v1h-1zM0 5h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 5h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 5h1v1H2z\"/><path fill=\"{{background}}\" d=\"M3 5h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{stroke}}\" d=\"M9 5h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 5h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 5h1v1h-1zM0 6h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 6h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 6h1v1H2z\"/><path fill=\"{{background}}\" d=\"M3 6h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{stroke}}\" d=\"M9 6h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 6h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 6h1v1h-1zM0 7h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 7h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 7h1v1H2z\"/><path fill=\"{{background}}\" d=\"M3 7h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{stroke}}\" d=\"M9 7h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 7h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 7h1v1h-1zM0 8h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 8h1v1H1zm1 0h1v1H2z\"/><path fill=\"{{stroke}}\" d=\"M3 8h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{frame}}\" d=\"M9 8h1v1H9zm1 0h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 8h1v1h-1zM0 9h1v1H0zm1 0h1v1H1z\"/><path fill=\"{{frame}}\" d=\"M2 9h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{stroke}}\" d=\"M10 9h1v1h-1zm-9 1h1v1H1zm1 0h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9zm1 0h1v1h-1zm-8 1h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/></svg>'\n .replace(/\\{\\{size\\}\\}/g, size.toString())\n .replace(/\\{\\{height\\}\\}/g, height.toString())\n .replace(/\\{\\{stroke\\}\\}/g, stroke)\n .replace(/\\{\\{frame\\}\\}/g, frame)\n .replace(/\\{\\{background\\}\\}/g, background);\n\n // Encode SVG to Base64 safely\n const encodedSvg = encodeURIComponent(svg)\n .replace(/%([0-9A-F]{2})/g, (_, p1) => String.fromCharCode(parseInt(p1, 16)));\n\n return `data:image/svg+xml;base64,${btoa(encodedSvg)}`;\n}\n\nfunction getCheckbox({ size, color }: { size: number; color: string }) {\n const svg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"{{width}}\" height=\"{{height}}\" viewBox=\"0 0 12 6\"><rect width=\"1\" height=\"1\" x=\"1\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"4\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"7\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"8\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"9\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"10\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"1\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"4\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"7\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"8\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"9\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"10\" y=\"5\" fill=\"{{color}}\"></rect></svg>'\n .replace(/\\{\\{width\\}\\}/g, (size*2).toString())\n .replace(/\\{\\{height\\}\\}/g, size.toString())\n .replace(/\\{\\{color\\}\\}/g, color)\n \n const encodedSvg = encodeURIComponent(svg)\n .replace(/%([0-9A-F]{2})/g, (_, p1) => String.fromCharCode(parseInt(p1, 16)))\n .replace(/#/g, '%23');\n\n return `data:image/svg+xml;base64,${btoa(encodedSvg)}`;\n\n}\n\nexport const frame = getFrame({\n size: 160,\n stroke: '#000',\n frame: '#333',\n background: '#DDD',\n});\n\nexport const checkbox = getCheckbox({\n size: 12,\n color: '#000',\n});\nexport const checkboxLight = getCheckbox({\n size: 12,\n color: '#000',\n});\n","import { getFrame } from './frame';\nimport { useCallback, useEffect, useState, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nexport const PixelWindow = ({\n style = {},\n stroke = '#000',\n frame = '#333',\n background = '#DDD',\n pixel = 160,\n children,\n}: {\n style?: React.CSSProperties,\n pixel?: number,\n stroke?: string\n frame?: string\n background?: string\n children: ReactNode;\n}) => {\n\n const pixelFrame = getFrame({\n size: pixel,\n stroke,\n frame,\n background,\n });\n\n\n return (\n <div\n className=\"window\"\n style={{\n width: '100%',\n height: '100%',\n borderImage: `url(${pixelFrame})`,\n borderImageSlice: '49% 49% fill',\n borderImageWidth: `${pixel}px`,\n }}\n >\n <div style={{ padding: `${pixel}px`}}>\n <div\n style={{ boxSizing: 'border-box', ...style }}\n >\n {children}\n </div>\n </div>\n </div>\n );\n};\n\nexport const FreePixelWindow = ({\n name,\n children,\n pixel = 16,\n stroke = '#000',\n frame = '#333',\n background = '#DDD',\n position: initialPosition = { x: 100, y: 100 },\n style,\n minWidth = 120,\n minHeight = 100,\n}: {\n name?: string;\n children: ReactNode;\n pixel?: number;\n stroke?: string;\n frame?: string;\n background?: string;\n position?: { x: number; y: number };\n style?: React.CSSProperties;\n minWidth?: number;\n minHeight?: number;\n}) => {\n\n const [position, setPosition] = useState(() => {\n if (name) {\n const savedPosition = localStorage.getItem(`${name}-position`);\n return savedPosition ? JSON.parse(savedPosition) : initialPosition;\n }\n return initialPosition;\n });\n\n const [size, setSize] = useState(() => {\n const savedSize = localStorage.getItem(`${name}-size`);\n return savedSize ? JSON.parse(savedSize) : { width: 300, height: 200 };\n });\n\n const [isDragging, setIsDragging] = useState(false);\n const [isResizing, setIsResizing] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [resizeStart, setResizeStart] = useState({ width: 0, height: 0, mouseX: 0, mouseY: 0 });\n\n useEffect(() => {\n if (name) {\n localStorage.setItem(`${name}-position`, JSON.stringify(position));\n localStorage.setItem(`${name}-size`, JSON.stringify(size));\n\n }\n }, [name, position, size]);\n\n const handleMouseMove = useCallback((e: MouseEvent) => {\n if (isDragging) {\n setPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n });\n } else if (isResizing) {\n const deltaX = e.clientX - resizeStart.mouseX;\n const deltaY = e.clientY - resizeStart.mouseY;\n\n setSize({\n width: Math.max(resizeStart.width + deltaX, minWidth),\n height: Math.max(resizeStart.height + deltaY, minHeight),\n });\n }\n }, [isDragging, isResizing, dragStart, resizeStart, minWidth, minHeight]);\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n setIsResizing(false);\n }, []);\n\n useEffect(() => {\n if (isDragging || isResizing) {\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n } else {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n }\n\n return () => {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n };\n }, [isDragging, isResizing, handleMouseMove, handleMouseUp]);\n\n const handleMouseDown = (e: React.MouseEvent) => {\n setIsDragging(true);\n setDragStart({ x: e.clientX - position.x, y: e.clientY - position.y });\n };\n\n const handleResizeStart = (e: React.MouseEvent) => {\n e.stopPropagation();\n setIsResizing(true);\n setResizeStart({\n width: size.width,\n height: size.height,\n mouseX: e.clientX,\n mouseY: e.clientY,\n });\n };\n\n const pixelFrame = getFrame({\n size: pixel,\n stroke,\n frame,\n background,\n });\n\n return createPortal(\n <div\n style={{\n position: 'absolute',\n overflow: 'hidden',\n resize: 'none',\n top: position.y,\n left: position.x,\n width: size.width,\n height: size.height,\n borderImage: `url(${pixelFrame})`,\n borderImageSlice: '49% 49% fill',\n borderImageWidth: `${pixel}px`,\n }}\n onMouseUp={handleMouseUp}\n >\n <div \n onMouseDown={handleMouseDown}\n onMouseUp={handleMouseUp}\n style={{\n height: `${pixel}px`,\n cursor: \"grab\",\n userSelect: \"none\"\n }}\n ></div>\n <div style={{\n padding: `${pixel}px`,\n paddingTop: 0,\n ...style\n }}>{children}</div>\n <div\n onMouseDown={handleResizeStart}\n style={{\n position: 'absolute',\n width: `${pixel}px`,\n height: `${pixel}px`,\n cursor: 'se-resize',\n bottom: 0,\n right: 0,\n }}\n ></div>\n </div>,\n document.body\n );\n};\n"],"mappings":"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","names":["frame","frame"]}
1
+ {"version":3,"sources":["../src/frame.ts","../src/PixelWindow.tsx"],"sourcesContent":["export function getFrame({ size, stroke, frame, background }: { size: number; stroke: string; frame: string; background: string }): string {\n const height = size; // Assuming square frames\n const svg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"{{size}}\" height=\"{{height}}\" viewBox=\"0 0 12 12\"><path fill=\"{{stroke}}\" d=\"M2 0h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9zM1 1h1v1H1z\"/><path fill=\"{{frame}}\" d=\"M2 1h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{stroke}}\" d=\"M10 1h1v1h-1zM0 2h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 2h1v1H1zm1 0h1v1H2z\"/><path fill=\"{{stroke}}\" d=\"M3 2h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{frame}}\" d=\"M9 2h1v1H9zm1 0h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 2h1v1h-1zM0 3h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 3h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 3h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 3h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 3h1v1h-1zM0 4h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 4h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 4h1v1H2zm1 0h1v1H3z\"/><path fill=\"{{background}}\" d=\"M4 4h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7z\"/><path fill=\"{{stroke}}\" d=\"M8 4h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 4h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 4h1v1h-1zM0 5h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 5h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 5h1v1H2z\"/><path fill=\"{{background}}\" d=\"M3 5h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{stroke}}\" d=\"M9 5h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 5h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 5h1v1h-1zM0 6h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 6h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 6h1v1H2z\"/><path fill=\"{{background}}\" d=\"M3 6h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{stroke}}\" d=\"M9 6h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 6h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 6h1v1h-1zM0 7h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 7h1v1H1z\"/><path fill=\"{{stroke}}\" d=\"M2 7h1v1H2z\"/><path fill=\"{{background}}\" d=\"M3 7h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{stroke}}\" d=\"M9 7h1v1H9z\"/><path fill=\"{{frame}}\" d=\"M10 7h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 7h1v1h-1zM0 8h1v1H0z\"/><path fill=\"{{frame}}\" d=\"M1 8h1v1H1zm1 0h1v1H2z\"/><path fill=\"{{stroke}}\" d=\"M3 8h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8z\"/><path fill=\"{{frame}}\" d=\"M9 8h1v1H9zm1 0h1v1h-1z\"/><path fill=\"{{stroke}}\" d=\"M11 8h1v1h-1zM0 9h1v1H0zm1 0h1v1H1z\"/><path fill=\"{{frame}}\" d=\"M2 9h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/><path fill=\"{{stroke}}\" d=\"M10 9h1v1h-1zm-9 1h1v1H1zm1 0h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9zm1 0h1v1h-1zm-8 1h1v1H2zm1 0h1v1H3zm1 0h1v1H4zm1 0h1v1H5zm1 0h1v1H6zm1 0h1v1H7zm1 0h1v1H8zm1 0h1v1H9z\"/></svg>'\n .replace(/\\{\\{size\\}\\}/g, size.toString())\n .replace(/\\{\\{height\\}\\}/g, height.toString())\n .replace(/\\{\\{stroke\\}\\}/g, stroke)\n .replace(/\\{\\{frame\\}\\}/g, frame)\n .replace(/\\{\\{background\\}\\}/g, background);\n\n // Encode SVG to Base64 safely\n const encodedSvg = encodeURIComponent(svg)\n .replace(/%([0-9A-F]{2})/g, (_, p1) => String.fromCharCode(parseInt(p1, 16)));\n\n return `data:image/svg+xml;base64,${btoa(encodedSvg)}`;\n}\n\nfunction getCheckbox({ size, color }: { size: number; color: string }) {\n const svg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"{{width}}\" height=\"{{height}}\" viewBox=\"0 0 12 6\"><rect width=\"1\" height=\"1\" x=\"1\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"4\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"7\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"8\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"9\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"10\" y=\"0\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"1\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"2\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"3\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"0\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"5\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"6\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"11\" y=\"4\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"1\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"2\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"3\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"4\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"7\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"8\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"9\" y=\"5\" fill=\"{{color}}\"></rect><rect width=\"1\" height=\"1\" x=\"10\" y=\"5\" fill=\"{{color}}\"></rect></svg>'\n .replace(/\\{\\{width\\}\\}/g, (size*2).toString())\n .replace(/\\{\\{height\\}\\}/g, size.toString())\n .replace(/\\{\\{color\\}\\}/g, color)\n \n const encodedSvg = encodeURIComponent(svg)\n .replace(/%([0-9A-F]{2})/g, (_, p1) => String.fromCharCode(parseInt(p1, 16)))\n .replace(/#/g, '%23');\n\n return `data:image/svg+xml;base64,${btoa(encodedSvg)}`;\n\n}\n\nexport const frame = getFrame({\n size: 160,\n stroke: '#000',\n frame: '#333',\n background: '#DDD',\n});\n\nexport const checkbox = getCheckbox({\n size: 12,\n color: '#000',\n});\nexport const checkboxLight = getCheckbox({\n size: 12,\n color: '#000',\n});\n","import { getFrame } from './frame';\nimport { useCallback, useEffect, useState, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nexport const PixelWindow = ({\n style = {},\n stroke = '#000',\n frame = '#333',\n background = '#DDD',\n pixel = 160,\n children,\n}: {\n style?: React.CSSProperties,\n pixel?: number,\n stroke?: string\n frame?: string\n background?: string\n children: ReactNode;\n}) => {\n\n const pixelFrame = getFrame({\n size: pixel,\n stroke,\n frame,\n background,\n });\n\n return (\n <div\n className=\"window\"\n style={{\n width: '100%',\n height: '100%',\n borderImage: `url(${pixelFrame})`,\n borderImageSlice: '49% 49% fill',\n borderImageWidth: `${pixel}px`,\n }}\n >\n <div style={{ padding: `${pixel}px`}}>\n <div\n style={{ boxSizing: 'border-box', ...style }}\n >\n {children}\n </div>\n </div>\n </div>\n );\n};\n\nexport const FreePixelWindow = ({\n name,\n children,\n pixel = 16,\n stroke = '#000',\n frame = '#333',\n background = '#DDD',\n position: initialPosition = { x: 100, y: 100 },\n style,\n minWidth = 120,\n minHeight = 100,\n onChange,\n}: {\n name?: string;\n children: ReactNode;\n pixel?: number;\n stroke?: string;\n frame?: string;\n background?: string;\n position?: { x: number; y: number };\n style?: React.CSSProperties;\n minWidth?: number;\n minHeight?: number;\n onChange?: (position: { x: number; y: number }, size: { width: number; height: number }) => void;\n}) => {\n\n const [position, setPosition] = useState(() => {\n if (name) {\n const savedPosition = localStorage.getItem(`${name}-position`);\n return savedPosition ? JSON.parse(savedPosition) : initialPosition;\n }\n return initialPosition;\n });\n\n const [size, setSize] = useState(() => {\n const savedSize = localStorage.getItem(`${name}-size`);\n return savedSize ? JSON.parse(savedSize) : { width: 300, height: 200 };\n });\n\n const [isDragging, setIsDragging] = useState(false);\n const [isResizing, setIsResizing] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [resizeStart, setResizeStart] = useState({ width: 0, height: 0, mouseX: 0, mouseY: 0 });\n\n useEffect(() => {\n if (onChange) {\n onChange(position, size);\n }\n }, [position, size, onChange]);\n\n useEffect(() => {\n if (name) {\n localStorage.setItem(`${name}-position`, JSON.stringify(position));\n localStorage.setItem(`${name}-size`, JSON.stringify(size));\n }\n }, [name, position, size]);\n\n const handleMouseMove = useCallback((e: MouseEvent) => {\n if (isDragging) {\n setPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n });\n } else if (isResizing) {\n const deltaX = e.clientX - resizeStart.mouseX;\n const deltaY = e.clientY - resizeStart.mouseY;\n\n setSize({\n width: Math.max(resizeStart.width + deltaX, minWidth),\n height: Math.max(resizeStart.height + deltaY, minHeight),\n });\n }\n }, [isDragging, isResizing, dragStart, resizeStart, minWidth, minHeight]);\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n setIsResizing(false);\n }, []);\n\n useEffect(() => {\n if (isDragging || isResizing) {\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n } else {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n }\n\n return () => {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n };\n }, [isDragging, isResizing, handleMouseMove, handleMouseUp]);\n\n const handleMouseDown = (e: React.MouseEvent) => {\n setIsDragging(true);\n setDragStart({ x: e.clientX - position.x, y: e.clientY - position.y });\n };\n\n const handleResizeStart = (e: React.MouseEvent) => {\n e.stopPropagation();\n setIsResizing(true);\n setResizeStart({\n width: size.width,\n height: size.height,\n mouseX: e.clientX,\n mouseY: e.clientY,\n });\n };\n\n const pixelFrame = getFrame({\n size: pixel,\n stroke,\n frame,\n background,\n });\n\n return createPortal(\n <div\n style={{\n position: 'absolute',\n overflow: 'hidden',\n resize: 'none',\n top: position.y,\n left: position.x,\n width: size.width,\n height: size.height,\n borderImage: `url(${pixelFrame})`,\n borderImageSlice: '49% 49% fill',\n borderImageWidth: `${pixel}px`,\n }}\n onMouseUp={handleMouseUp}\n >\n <div \n onMouseDown={handleMouseDown}\n onMouseUp={handleMouseUp}\n style={{\n height: `${pixel}px`,\n cursor: \"grab\",\n userSelect: \"none\"\n }}\n ></div>\n <div style={{\n padding: `${pixel}px`,\n paddingTop: 0,\n height: `calc(100% - ${pixel}px)`,\n boxSizing: 'border-box',\n ...style\n }}>{children}</div>\n <div\n onMouseDown={handleResizeStart}\n style={{\n position: 'absolute',\n width: `${pixel}px`,\n height: `${pixel}px`,\n cursor: 'se-resize',\n bottom: 0,\n right: 0,\n }}\n ></div>\n </div>,\n document.body\n );\n};\n"],"mappings":"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","names":["frame","frame"]}
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "@glennjong/pixel-window",
3
- "version": "0.1.4",
3
+ "version": "0.1.7",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
7
- "files": ["dist"],
7
+ "files": [
8
+ "dist"
9
+ ],
8
10
  "exports": {
9
11
  ".": {
10
12
  "import": "./dist/index.mjs",