Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow changing of seed and strength parameters #17

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ yarn-error.log*
*.tsbuildinfo
next-env.d.ts

.env
.env
.idea
2 changes: 2 additions & 0 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ export default function Home() {
w: 512,
h: 512,
name: '',
strength: 0.65,
seed: Math.floor(Math.random() * 10000),
},
})
}
Expand Down
65 changes: 31 additions & 34 deletions src/components/FrameHeading.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import {
SelectionEdge,
TLShapeId,
canonicalizeRotation,
getPointerInfo,
toDomPrecision,
useEditor,
useIsEditing,
useValue,
TLFrameShape,
} from '@tldraw/editor'
import { preventDefault, stopEventPropagation } from '@tldraw/tldraw'
import { useCallback, useEffect, useRef } from 'react'
Expand All @@ -17,18 +15,17 @@ export function FrameHeading({
name,
width,
height,
labelSide,
labelTranslate,
}: {
id: TLShapeId
name: string
width: number
height: number
labelSide: SelectionEdge
labelTranslate: string
}) {
const editor = useEditor()
const pageRotation = useValue(
'shape rotation',
() => canonicalizeRotation(editor.getShapePageTransform(id)!.rotation()),
[editor, id]
)

const isEditing = useIsEditing(id)

Expand Down Expand Up @@ -72,31 +69,6 @@ export function FrameHeading({
}
}, [rInput, isEditing])

// rotate right 45 deg
const offsetRotation = pageRotation + Math.PI / 4
const scaledRotation = (offsetRotation * (2 / Math.PI) + 4) % 4
const labelSide: SelectionEdge = (['top', 'left', 'bottom', 'right'] as const)[
Math.floor(scaledRotation)
]

let labelTranslate: string
switch (labelSide) {
case 'top':
labelTranslate = ``
break
case 'right':
labelTranslate = `translate(${toDomPrecision(width)}px, 0px) rotate(90deg)`
break
case 'bottom':
labelTranslate = `translate(${toDomPrecision(width)}px, ${toDomPrecision(
height
)}px) rotate(180deg)`
break
case 'left':
labelTranslate = `translate(0px, ${toDomPrecision(height)}px) rotate(270deg)`
break
}

return (
<div
className="tl-frame-heading"
Expand All @@ -111,7 +83,32 @@ export function FrameHeading({
onPointerDown={handlePointerDown}
>
<div className="tl-frame-heading-hit-area">
<FrameLabelInput ref={rInput} id={id} name={name} isEditing={isEditing} />
<FrameLabelInput
type={'text'}
ref={rInput}
id={id}
value={name}
onValueChange={(value) => {
const shape = editor.getShape<TLFrameShape>(id)
if (!shape) return

const name = shape.props.name
if (name === value) return

editor.updateShapes(
[
{
id,
type: 'frame',
props: {name: value},
},
],
{squashing: true}
)
}}
placeholder={'Double click prompt to edit'}
showOnlyIfEditing={true}
/>
</div>
</div>
)
Expand Down
109 changes: 66 additions & 43 deletions src/components/FrameLabelInput.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
import { TLFrameShape, TLShapeId, stopEventPropagation, useEditor } from '@tldraw/editor'
import { TLShapeId, stopEventPropagation, useEditor, useIsEditing } from '@tldraw/editor'
import { forwardRef, useCallback } from 'react'

export const FrameLabelInput = forwardRef<
HTMLInputElement,
{ id: TLShapeId; name: string; isEditing: boolean }
>(function FrameLabelInput({ id, name, isEditing }, ref) {
{
id: TLShapeId;
showOnlyIfEditing?: boolean;
} & ({
type: 'number',
value: number,
onValueChange?: (value: number) => void,
min?: number,
max?: number,
step?: number,
} | {
type: 'text',
value: string,
placeholder?: string,
onValueChange?: (value: string) => void,
})
>(function FrameLabelInput(props, ref) {
const {id, type, value, showOnlyIfEditing} = props

const editor = useEditor()
const isEditing = useIsEditing(id)

const handleKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
Expand All @@ -20,66 +38,71 @@ export const FrameLabelInput = forwardRef<
[editor]
)

const tryUpdateValue = useCallback(
(wantedValue: string) => {
switch (props.type) {
case 'number':
const numberValue = parseFloat(wantedValue)
if (isNaN(numberValue)) return
props.onValueChange?.(numberValue)
break;
case 'text':
props.onValueChange?.(wantedValue)
break;
default:
throw new Error(`Unexpected value type: ${typeof wantedValue}`);
}
},
[props.type]
)

const handleBlur = useCallback(
(e: React.FocusEvent<HTMLInputElement>) => {
const shape = editor.getShape<TLFrameShape>(id)
if (!shape) return

const name = shape.props.name
const value = e.currentTarget.value.trim()
if (name === value) return

editor.updateShapes(
[
{
id,
type: 'frame',
props: { name: value },
},
],
{ squashing: true }
)
tryUpdateValue(e.currentTarget.value.trim())
},
[id, editor]
)

const handleChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const shape = editor.getShape<TLFrameShape>(id)
if (!shape) return

const name = shape.props.name
const value = e.currentTarget.value
if (name === value) return

editor.updateShapes(
[
{
id,
type: 'frame',
props: { name: value },
},
],
{ squashing: true }
)
tryUpdateValue(e.currentTarget.value) // do not trim, that will be done on blur
},
[id, editor]
)

let valueToDisplay: string;
switch (props.type) {
case 'number':
valueToDisplay = props.value.toFixed(2);
break;
case 'text':
valueToDisplay = defaultEmptyAs(props.value, props.placeholder ?? '');
break;
default:
throw new Error(`Unexpected value type: ${typeof value}`);
}

const showInput = !showOnlyIfEditing || isEditing

return (
<div className={`tl-frame-label ${isEditing ? 'tl-frame-label__editing' : ''}`}>
<div className={`tl-frame-label ${showInput ? 'tl-frame-label__editing' : ''}`}>
<input
className="tl-frame-name-input"
// using search to make lastpass ignore it 😅
className="tl-frame-name-input search"
type={type}
ref={ref}
style={{ display: isEditing ? undefined : 'none' }}
value={name}
autoFocus
style={{display: showInput ? undefined : 'none'}}
value={value}
autoFocus={showOnlyIfEditing}
onKeyDown={handleKeyDown}
onBlur={handleBlur}
onChange={handleChange}
onPointerDown={stopEventPropagation}
min={props.type === 'number' ? props.min : undefined}
max={props.type === 'number' ? props.max : undefined}
step={props.type === 'number' ? props.step : undefined}
/>
{defaultEmptyAs(name, 'Double click prompt to edit') + String.fromCharCode(8203)}
{valueToDisplay + String.fromCharCode(8203)}
</div>
)
})
Expand Down
Loading