From 20867a1b0adcfec0da47bdec9f07ed7211cb402d Mon Sep 17 00:00:00 2001 From: Antonio Contreras Date: Wed, 8 Oct 2025 19:06:52 +0200 Subject: [PATCH 1/3] create input-stepper shape --- public/rich-components/input-stepper.svg | 15 +++ .../front-rich-components/index.ts | 1 + .../front-rich-components/input-stepper.tsx | 110 ++++++++++++++++++ src/core/model/index.ts | 4 +- src/pods/canvas/model/shape-size.mapper.ts | 2 + src/pods/canvas/shape-renderer/index.tsx | 3 + .../simple-rich-components/index.ts | 1 + .../input-stepper.renderer.tsx | 30 +++++ .../rich-components-gallery-data/index.ts | 4 + 9 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 public/rich-components/input-stepper.svg create mode 100644 src/common/components/mock-components/front-rich-components/input-stepper.tsx create mode 100644 src/pods/canvas/shape-renderer/simple-rich-components/input-stepper.renderer.tsx diff --git a/public/rich-components/input-stepper.svg b/public/rich-components/input-stepper.svg new file mode 100644 index 00000000..22ca7b92 --- /dev/null +++ b/public/rich-components/input-stepper.svg @@ -0,0 +1,15 @@ + + + + + + 0 + + + + + + + + + diff --git a/src/common/components/mock-components/front-rich-components/index.ts b/src/common/components/mock-components/front-rich-components/index.ts index b1e5f180..c29428d6 100644 --- a/src/common/components/mock-components/front-rich-components/index.ts +++ b/src/common/components/mock-components/front-rich-components/index.ts @@ -20,3 +20,4 @@ export * from './togglelightdark-shape'; export * from './gauge/gauge'; export * from './fab-button/fab-button'; export * from './file-tree/file-tree'; +export * from './input-stepper'; diff --git a/src/common/components/mock-components/front-rich-components/input-stepper.tsx b/src/common/components/mock-components/front-rich-components/input-stepper.tsx new file mode 100644 index 00000000..99914cff --- /dev/null +++ b/src/common/components/mock-components/front-rich-components/input-stepper.tsx @@ -0,0 +1,110 @@ +import { forwardRef } from 'react'; +import { Group, Rect, Text } from 'react-konva'; +import { ShapeSizeRestrictions, ShapeType } from '@/core/model'; +import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions'; +import { ShapeProps } from '../shape.model'; +import { useGroupShapeProps } from '../mock-components.utils'; + +const InputStepperShapeSizeRestrictions: ShapeSizeRestrictions = { + minWidth: 100, + minHeight: 100, + maxWidth: -1, + maxHeight: -1, + defaultWidth: 250, + defaultHeight: 150, +}; + +export const getInputStepperShapeSizeRestrictions = (): ShapeSizeRestrictions => + InputStepperShapeSizeRestrictions; + +const shapeType: ShapeType = 'inputStepper'; + +export const InputStepperShape = forwardRef((props, ref) => { + const { x, y, width, height, id, onSelected, ...shapeProps } = props; + const restrictedSize = fitSizeToShapeSizeRestrictions( + InputStepperShapeSizeRestrictions, + width, + height + ); + + const inputWidth = width - 30; // Reservar espacio para el stepper + const buttonHeight = height / 2; + + const commonGroupProps = useGroupShapeProps( + props, + restrictedSize, + shapeType, + ref + ); + + return ( + + {/* Caja del input */} + + + {/* Texto del input */} + + + {/* Botón de incremento (flecha arriba) */} + + + + + + {/* Botón de decremento (flecha abajo) */} + + + + + + ); +}); + +export default InputStepperShape; diff --git a/src/core/model/index.ts b/src/core/model/index.ts index bf189305..8c13a80e 100644 --- a/src/core/model/index.ts +++ b/src/core/model/index.ts @@ -86,7 +86,8 @@ export type ShapeType = | 'textScribbled' | 'paragraphScribbled' | 'fabButton' - | 'fileTree'; + | 'fileTree' + | 'inputStepper'; export const ShapeDisplayName: Record = { multiple: 'multiple', @@ -162,6 +163,7 @@ export const ShapeDisplayName: Record = { paragraphScribbled: 'Paragraph Scribbled', fabButton: 'Fab Button', fileTree: 'File Tree', + inputStepper: 'Input Stepper', }; export type EditType = 'input' | 'textarea' | 'imageupload'; diff --git a/src/pods/canvas/model/shape-size.mapper.ts b/src/pods/canvas/model/shape-size.mapper.ts index 3c4ea531..d73980d2 100644 --- a/src/pods/canvas/model/shape-size.mapper.ts +++ b/src/pods/canvas/model/shape-size.mapper.ts @@ -66,6 +66,7 @@ import { getGaugeShapeSizeRestrictions, getFabButtonShapeSizeRestrictions, getFileTreeShapeSizeRestrictions, + getInputStepperShapeSizeRestrictions, // other imports } from '@/common/components/mock-components/front-rich-components'; import { @@ -175,6 +176,7 @@ const shapeSizeMap: Record ShapeSizeRestrictions> = { paragraphScribbled: getParagraphScribbledShapeRestrictions, fabButton: getFabButtonShapeSizeRestrictions, fileTree: getFileTreeShapeSizeRestrictions, + inputStepper: getInputStepperShapeSizeRestrictions, }; export default shapeSizeMap; diff --git a/src/pods/canvas/shape-renderer/index.tsx b/src/pods/canvas/shape-renderer/index.tsx index 37a59949..c7fb0a3d 100644 --- a/src/pods/canvas/shape-renderer/index.tsx +++ b/src/pods/canvas/shape-renderer/index.tsx @@ -50,6 +50,7 @@ import { renderLoadingIndicator, renderFabButton, renderFileTree, + renderInputStepper, } from './simple-rich-components'; import { renderDiamond, @@ -235,6 +236,8 @@ export const renderShapeComponent = ( return renderTextScribbled(shape, shapeRenderedProps); case 'paragraphScribbled': return renderParagraphScribbled(shape, shapeRenderedProps); + case 'inputStepper': + return renderInputStepper(shape, shapeRenderedProps); default: return renderNotFound(shape, shapeRenderedProps); } diff --git a/src/pods/canvas/shape-renderer/simple-rich-components/index.ts b/src/pods/canvas/shape-renderer/simple-rich-components/index.ts index 2a32d3d1..d00fb7c2 100644 --- a/src/pods/canvas/shape-renderer/simple-rich-components/index.ts +++ b/src/pods/canvas/shape-renderer/simple-rich-components/index.ts @@ -22,3 +22,4 @@ export * from './loading-indicator.renderer'; export * from './videoconference.renderer'; export * from './fab-button.renderer'; export * from './file-tree.renderer'; +export * from './input-stepper.renderer'; diff --git a/src/pods/canvas/shape-renderer/simple-rich-components/input-stepper.renderer.tsx b/src/pods/canvas/shape-renderer/simple-rich-components/input-stepper.renderer.tsx new file mode 100644 index 00000000..f856150f --- /dev/null +++ b/src/pods/canvas/shape-renderer/simple-rich-components/input-stepper.renderer.tsx @@ -0,0 +1,30 @@ +import { InputStepperShape } from '@/common/components/mock-components/front-rich-components'; +import { ShapeRendererProps } from '../model'; +import { ShapeModel } from '@/core/model'; + +export const renderInputStepper = ( + shape: ShapeModel, + shapeRenderedProps: ShapeRendererProps +) => { + const { handleSelected, shapeRefs, handleDragEnd, handleTransform } = + shapeRenderedProps; + + return ( + + ); +}; diff --git a/src/pods/galleries/rich-components-gallery/rich-components-gallery-data/index.ts b/src/pods/galleries/rich-components-gallery/rich-components-gallery-data/index.ts index b44eee90..3a26cb76 100644 --- a/src/pods/galleries/rich-components-gallery/rich-components-gallery-data/index.ts +++ b/src/pods/galleries/rich-components-gallery/rich-components-gallery-data/index.ts @@ -44,4 +44,8 @@ export const mockRichComponentsCollection: ItemInfo[] = [ thumbnailSrc: '/rich-components/file-tree.svg', type: 'fileTree', }, + { + thumbnailSrc: '/rich-components/input-stepper.svg', + type: 'inputStepper', + }, ]; From d1bcb17faad4cab65414ce06257afc681d624437 Mon Sep 17 00:00:00 2001 From: Antonio Contreras Date: Thu, 9 Oct 2025 10:21:06 +0200 Subject: [PATCH 2/3] fix component --- .../front-rich-components/input-stepper.tsx | 102 +++++++++++------- .../canvas/model/shape-other-props.utils.ts | 9 ++ 2 files changed, 73 insertions(+), 38 deletions(-) diff --git a/src/common/components/mock-components/front-rich-components/input-stepper.tsx b/src/common/components/mock-components/front-rich-components/input-stepper.tsx index 99914cff..c89e64f0 100644 --- a/src/common/components/mock-components/front-rich-components/input-stepper.tsx +++ b/src/common/components/mock-components/front-rich-components/input-stepper.tsx @@ -4,14 +4,16 @@ import { ShapeSizeRestrictions, ShapeType } from '@/core/model'; import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions'; import { ShapeProps } from '../shape.model'; import { useGroupShapeProps } from '../mock-components.utils'; +import { useShapeProps } from '@/common/components/shapes/use-shape-props.hook'; +import { INPUT_SHAPE } from '../front-components/shape.const'; const InputStepperShapeSizeRestrictions: ShapeSizeRestrictions = { - minWidth: 100, - minHeight: 100, - maxWidth: -1, - maxHeight: -1, - defaultWidth: 250, - defaultHeight: 150, + minWidth: 60, + minHeight: 35, + maxWidth: 500, + maxHeight: 35, + defaultWidth: 100, + defaultHeight: 35, }; export const getInputStepperShapeSizeRestrictions = (): ShapeSizeRestrictions => @@ -20,15 +22,29 @@ export const getInputStepperShapeSizeRestrictions = (): ShapeSizeRestrictions => const shapeType: ShapeType = 'inputStepper'; export const InputStepperShape = forwardRef((props, ref) => { - const { x, y, width, height, id, onSelected, ...shapeProps } = props; + const { x, y, width, height, id, onSelected, otherProps, ...shapeProps } = + props; + const restrictedSize = fitSizeToShapeSizeRestrictions( InputStepperShapeSizeRestrictions, width, height ); - const inputWidth = width - 30; // Reservar espacio para el stepper - const buttonHeight = height / 2; + const { width: restrictedWidth, height: restrictedHeight } = restrictedSize; + + const handleButtonWidth = (restrictedWidth: number): number => { + const buttonWidth = restrictedWidth * 0.3; + const minButtonWidth = 30; + const maxButtonWidth = 70; + + if (buttonWidth < minButtonWidth) return minButtonWidth; + if (buttonWidth > maxButtonWidth) return maxButtonWidth; + return buttonWidth; + }; + + const buttonWidth = handleButtonWidth(restrictedWidth); + const buttonHeight = restrictedHeight / 2; const commonGroupProps = useGroupShapeProps( props, @@ -37,70 +53,80 @@ export const InputStepperShape = forwardRef((props, ref) => { ref ); + const { stroke, strokeStyle, fill, textColor } = useShapeProps( + otherProps, + INPUT_SHAPE + ); + return ( {/* Caja del input */} {/* Texto del input */} {/* Botón de incremento (flecha arriba) */} - + {/* Botón de decremento (flecha abajo) */} - + diff --git a/src/pods/canvas/model/shape-other-props.utils.ts b/src/pods/canvas/model/shape-other-props.utils.ts index f2c1007f..eb2c9198 100644 --- a/src/pods/canvas/model/shape-other-props.utils.ts +++ b/src/pods/canvas/model/shape-other-props.utils.ts @@ -287,6 +287,15 @@ export const generateDefaultOtherProps = ( textColor: '#000000', strokeStyle: [], }; + case 'inputStepper': + return { + stroke: INPUT_SHAPE.DEFAULT_STROKE_COLOR, + backgroundColor: INPUT_SHAPE.DEFAULT_FILL_BACKGROUND, + textColor: INPUT_SHAPE.DEFAULT_FILL_TEXT, + borderRadius: `${INPUT_SHAPE.DEFAULT_CORNER_RADIUS}`, + disabled: INPUT_SHAPE.DEFAULT_DISABLED, + strokeStyle: [], + }; default: return undefined; } From 810ebd896a98c36f24b3f712573b41aa049bc1f1 Mon Sep 17 00:00:00 2001 From: Antonio Contreras Date: Thu, 9 Oct 2025 13:07:13 +0200 Subject: [PATCH 3/3] fix --- .../front-rich-components/input-stepper.tsx | 20 +++++++++++++------ .../canvas/model/inline-editable.model.ts | 2 ++ .../canvas/model/shape-other-props.utils.ts | 2 -- src/pods/canvas/model/transformer.model.ts | 1 + .../input-stepper.renderer.tsx | 8 ++++++-- 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/common/components/mock-components/front-rich-components/input-stepper.tsx b/src/common/components/mock-components/front-rich-components/input-stepper.tsx index c89e64f0..a10facfd 100644 --- a/src/common/components/mock-components/front-rich-components/input-stepper.tsx +++ b/src/common/components/mock-components/front-rich-components/input-stepper.tsx @@ -22,8 +22,17 @@ export const getInputStepperShapeSizeRestrictions = (): ShapeSizeRestrictions => const shapeType: ShapeType = 'inputStepper'; export const InputStepperShape = forwardRef((props, ref) => { - const { x, y, width, height, id, onSelected, otherProps, ...shapeProps } = - props; + const { + x, + y, + width, + height, + id, + text, + onSelected, + otherProps, + ...shapeProps + } = props; const restrictedSize = fitSizeToShapeSizeRestrictions( InputStepperShapeSizeRestrictions, @@ -33,7 +42,7 @@ export const InputStepperShape = forwardRef((props, ref) => { const { width: restrictedWidth, height: restrictedHeight } = restrictedSize; - const handleButtonWidth = (restrictedWidth: number): number => { + const getButtonWidth = (restrictedWidth: number): number => { const buttonWidth = restrictedWidth * 0.3; const minButtonWidth = 30; const maxButtonWidth = 70; @@ -43,7 +52,7 @@ export const InputStepperShape = forwardRef((props, ref) => { return buttonWidth; }; - const buttonWidth = handleButtonWidth(restrictedWidth); + const buttonWidth = getButtonWidth(restrictedWidth); const buttonHeight = restrictedHeight / 2; const commonGroupProps = useGroupShapeProps( @@ -60,7 +69,6 @@ export const InputStepperShape = forwardRef((props, ref) => { return ( - {/* Caja del input */} ((props, ref) => { width={restrictedWidth - buttonWidth - 8} x={0} // Alinear a la derecha dependiendo de la cantidad de dígitos y={restrictedHeight / 2 - 6} // Centrar verticalmente - text={'0'} + text={text} fontFamily={INPUT_SHAPE.DEFAULT_FONT_FAMILY} fontSize={INPUT_SHAPE.DEFAULT_FONT_SIZE + 2} fill={textColor} diff --git a/src/pods/canvas/model/inline-editable.model.ts b/src/pods/canvas/model/inline-editable.model.ts index bc99eecc..e4a06a8a 100644 --- a/src/pods/canvas/model/inline-editable.model.ts +++ b/src/pods/canvas/model/inline-editable.model.ts @@ -84,6 +84,7 @@ const shapeTypesWithDefaultText = new Set([ 'loading-indicator', 'gauge', 'fileTree', + 'inputStepper', ]); // Map of ShapeTypes to their default text values @@ -125,6 +126,7 @@ const defaultTextValueMap: Partial> = { browser: 'https://example.com', modalDialog: 'Title here...', 'loading-indicator': 'Loading...', + inputStepper: '0', }; export const generateDefaultTextValue = ( diff --git a/src/pods/canvas/model/shape-other-props.utils.ts b/src/pods/canvas/model/shape-other-props.utils.ts index eb2c9198..1483182f 100644 --- a/src/pods/canvas/model/shape-other-props.utils.ts +++ b/src/pods/canvas/model/shape-other-props.utils.ts @@ -292,8 +292,6 @@ export const generateDefaultOtherProps = ( stroke: INPUT_SHAPE.DEFAULT_STROKE_COLOR, backgroundColor: INPUT_SHAPE.DEFAULT_FILL_BACKGROUND, textColor: INPUT_SHAPE.DEFAULT_FILL_TEXT, - borderRadius: `${INPUT_SHAPE.DEFAULT_CORNER_RADIUS}`, - disabled: INPUT_SHAPE.DEFAULT_DISABLED, strokeStyle: [], }; default: diff --git a/src/pods/canvas/model/transformer.model.ts b/src/pods/canvas/model/transformer.model.ts index bf601b42..3cc690cc 100644 --- a/src/pods/canvas/model/transformer.model.ts +++ b/src/pods/canvas/model/transformer.model.ts @@ -71,6 +71,7 @@ export const generateTypeOfTransformer = (shapeType: ShapeType): string[] => { case 'buttonBar': case 'slider': case 'chip': + case 'inputStepper': return ['middle-left', 'middle-right']; case 'verticalLine': case 'verticalScrollBar': diff --git a/src/pods/canvas/shape-renderer/simple-rich-components/input-stepper.renderer.tsx b/src/pods/canvas/shape-renderer/simple-rich-components/input-stepper.renderer.tsx index f856150f..26b456b3 100644 --- a/src/pods/canvas/shape-renderer/simple-rich-components/input-stepper.renderer.tsx +++ b/src/pods/canvas/shape-renderer/simple-rich-components/input-stepper.renderer.tsx @@ -13,18 +13,22 @@ export const renderInputStepper = ( ); };