diff --git a/public/rich-components/input-stepper.svg b/public/rich-components/input-stepper.svg new file mode 100644 index 00000000..be747f48 --- /dev/null +++ b/public/rich-components/input-stepper.svg @@ -0,0 +1,15 @@ + + + + + + 0 + + + + + + + + + \ No newline at end of file diff --git a/src/common/components/mock-components/front-rich-components/horizontal-menu/horizontal-menu.tsx b/src/common/components/mock-components/front-rich-components/horizontal-menu/horizontal-menu.tsx index c50151b1..39121266 100644 --- a/src/common/components/mock-components/front-rich-components/horizontal-menu/horizontal-menu.tsx +++ b/src/common/components/mock-components/front-rich-components/horizontal-menu/horizontal-menu.tsx @@ -10,7 +10,6 @@ import { splitCSVContentIntoRows, } from '@/common/utils/active-element-selector.utils'; import { useGroupShapeProps } from '../../mock-components.utils'; -import { useResizeOnFontSizeChange } from '../../front-text-components/front-text-hooks/resize-fontsize-change.hook'; const horizontalMenuShapeSizeRestrictions: ShapeSizeRestrictions = { minWidth: 200, @@ -42,7 +41,7 @@ export const HorizontalMenu = forwardRef((props, ref) => { const csvData = splitCSVContentIntoRows(text); const headers = extractCSVHeaders(csvData[0]); const itemLabels = headers.map(header => header.text); - const verticalPadding = 8; + const numberOfItems = itemLabels.length; const itemSpacing = 10; @@ -55,15 +54,10 @@ export const HorizontalMenu = forwardRef((props, ref) => { const totalMargins = restrictedWidth - itemSpacing * (numberOfItems + 1); const itemWidth = totalMargins / numberOfItems; - const { - stroke, - strokeStyle, - fill, - textColor, - borderRadius, - fontSize, - fontVariant, - } = useShapeProps(otherProps, BASIC_SHAPE); + const { stroke, strokeStyle, fill, textColor, borderRadius } = useShapeProps( + otherProps, + BASIC_SHAPE + ); const itemVerticalPadding = 4; @@ -75,7 +69,7 @@ export const HorizontalMenu = forwardRef((props, ref) => { shapeType, ref ); - useResizeOnFontSizeChange(id, { x, y }, text, fontSize, fontVariant); + return ( ((props, ref) => { x={itemSpacing * (index + 1) + itemWidth * index} y={itemVerticalPadding} width={itemWidth} - height={restrictedHeight - verticalPadding} + height={restrictedHeight - 2 * itemVerticalPadding} fill={index === activeSelected ? 'lightblue' : fill} /> ))} 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..0ef87edb 100644 --- a/src/common/components/mock-components/front-rich-components/index.ts +++ b/src/common/components/mock-components/front-rich-components/index.ts @@ -2,6 +2,7 @@ export * from './accordion'; export * from './breadcrumb/breadcrumb'; export * from './pie-chart'; export * from './horizontal-menu/horizontal-menu'; +export * from './input-stepper'; export * from './map-chart'; export * from './video-player'; export * from './bar-chart'; 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..9d60dd2a --- /dev/null +++ b/src/common/components/mock-components/front-rich-components/input-stepper.tsx @@ -0,0 +1,127 @@ +import { forwardRef } from 'react'; +import { Group, Rect, Text } from 'react-konva'; +import { ShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions'; +import { useGroupShapeProps } from '../mock-components.utils'; +import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions'; +import { ShapeType } from '@/core/model'; +import { ShapeProps } from '../shape.model'; +import { useShapeProps } from '../../shapes/use-shape-props.hook'; +import { INPUT_SHAPE } from '../front-components/shape.const'; + +// Size restrictions (igual patrón que file-tree) +export const inputStepperShapeRestrictions: ShapeSizeRestrictions = { + minWidth: 80, + minHeight: 24, + maxWidth: -1, + maxHeight: -1, + defaultWidth: 120, + defaultHeight: 32, +}; + +export const getInputStepperShapeSizeRestrictions = (): ShapeSizeRestrictions => + inputStepperShapeRestrictions; + +export const InputWithStepper = forwardRef((props, ref) => { + const { x, y, width, height, text, onSelect, otherProps, id, ...shapeProps } = + props; + + const inputWidth = width - 30; // Reservar espacio para el stepper + const buttonHeight = height / 2; + + const restrictedSize = fitSizeToShapeSizeRestrictions( + inputStepperShapeRestrictions, + width, + height + ); + + const shapeType: ShapeType = 'input-stepper'; + + const commonGroupProps = useGroupShapeProps( + props, + restrictedSize, + shapeType, + ref + ); + const { stroke, textColor, strokeStyle, fill, strokeWidth } = useShapeProps( + otherProps, + INPUT_SHAPE + ); + + const { width: restrictedWidth } = restrictedSize; + + return ( + + {/* Caja del input */} + + + {/* Texto del input */} + + + {/* Botón de incremento (flecha arriba) */} + + + + + + {/* Botón de decremento (flecha abajo) */} + + + + + + ); +}); + +export default InputWithStepper; diff --git a/src/core/model/index.ts b/src/core/model/index.ts index bf189305..f2dbc4b4 100644 --- a/src/core/model/index.ts +++ b/src/core/model/index.ts @@ -38,6 +38,7 @@ export type ShapeType = | 'accordion' | 'pie' | 'horizontal-menu' + | 'input-stepper' | 'breadcrumb' | 'map' | 'circle' @@ -130,6 +131,7 @@ export const ShapeDisplayName: Record = { link: 'Link', triangle: 'Triangle', 'horizontal-menu': 'Horizontal Menu', + 'input-stepper': 'Input Stepper', largeArrow: 'Large Arrow', icon: 'Icon', bar: 'Bar Chart', @@ -238,3 +240,8 @@ export interface ShapeModel { text?: string; otherProps?: OtherProps; } + +export interface inputStepper { + id: string; + min: number; +} diff --git a/src/pods/canvas/model/inline-editable.model.ts b/src/pods/canvas/model/inline-editable.model.ts index bc99eecc..cbdf7709 100644 --- a/src/pods/canvas/model/inline-editable.model.ts +++ b/src/pods/canvas/model/inline-editable.model.ts @@ -40,6 +40,7 @@ const inlineEditableShapes = new Set([ 'gauge', 'loading-indicator', 'fileTree', + 'input-stepper', ]); // Check if a shape type allows inline editing @@ -62,6 +63,7 @@ const shapeTypesWithDefaultText = new Set([ 'listbox', 'horizontal-menu', 'vertical-menu', + 'input-stepper', 'heading1', 'heading2', 'heading3', @@ -125,6 +127,7 @@ const defaultTextValueMap: Partial> = { browser: 'https://example.com', modalDialog: 'Title here...', 'loading-indicator': 'Loading...', + 'input-stepper': '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 6e06de10..8ad7a6d3 100644 --- a/src/pods/canvas/model/shape-other-props.utils.ts +++ b/src/pods/canvas/model/shape-other-props.utils.ts @@ -48,8 +48,13 @@ export const generateDefaultOtherProps = ( strokeStyle: [], borderRadius: `${BASIC_SHAPE.DEFAULT_CORNER_RADIUS}`, activeElement: 0, - fontSize: FONT_SIZE_VALUES.NORMALTEXT, - fontVariant: `${INPUT_SHAPE.DEFAULT_FONT_VARIANT}`, + }; + case 'input-stepper': + return { + stroke: INPUT_SHAPE.DEFAULT_STROKE_COLOR, + backgroundColor: INPUT_SHAPE.DEFAULT_FILL_BACKGROUND, + textColor: INPUT_SHAPE.DEFAULT_FILL_TEXT, + strokeStyle: [], }; case 'datepickerinput': case 'timepickerinput': diff --git a/src/pods/canvas/model/shape-size.mapper.ts b/src/pods/canvas/model/shape-size.mapper.ts index 3c4ea531..19dcbf18 100644 --- a/src/pods/canvas/model/shape-size.mapper.ts +++ b/src/pods/canvas/model/shape-size.mapper.ts @@ -1,5 +1,6 @@ // src/common/shape-utils/shapeSizeMap.ts import { ShapeType, ShapeSizeRestrictions } from '@/core/model'; +import { getInputStepperShapeSizeRestrictions } from '@/common/components/mock-components/front-rich-components/input-stepper'; import { getButtonShapeSizeRestrictions, getCheckboxShapeSizeRestrictions, @@ -128,6 +129,7 @@ const shapeSizeMap: Record ShapeSizeRestrictions> = { postit: getPostItShapeSizeRestrictions, pie: getPieChartShapeSizeRestrictions, 'horizontal-menu': getHorizontalMenuShapeSizeRestrictions, + 'input-stepper': getInputStepperShapeSizeRestrictions, 'vertical-menu': getVerticalMenuShapeSizeRestrictions, breadcrumb: getBreadcrumbShapeSizeRestrictions, map: getMapChartShapeSizeRestrictions, @@ -172,9 +174,9 @@ const shapeSizeMap: Record ShapeSizeRestrictions> = { rectangleLow: getRectangleLowShapeRestrictions, circleLow: getCircleLowShapeSizeRestrictions, textScribbled: getTextScribbledShapeRestrictions, - paragraphScribbled: getParagraphScribbledShapeRestrictions, fabButton: getFabButtonShapeSizeRestrictions, fileTree: getFileTreeShapeSizeRestrictions, + paragraphScribbled: getParagraphScribbledShapeRestrictions, }; export default shapeSizeMap; diff --git a/src/pods/canvas/model/transformer.model.ts b/src/pods/canvas/model/transformer.model.ts index bf601b42..e6a71e22 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 'input-stepper': return ['middle-left', 'middle-right']; case 'verticalLine': case 'verticalScrollBar': diff --git a/src/pods/canvas/shape-renderer/index.tsx b/src/pods/canvas/shape-renderer/index.tsx index 37a59949..62cdc417 100644 --- a/src/pods/canvas/shape-renderer/index.tsx +++ b/src/pods/canvas/shape-renderer/index.tsx @@ -29,6 +29,7 @@ import { } from './simple-container'; import { renderVideoPlayer, + renderInputStepper, renderAccordion, renderHorizontalMenu, renderPieChart, @@ -153,6 +154,8 @@ export const renderShapeComponent = ( return renderTriangle(shape, shapeRenderedProps); case 'horizontal-menu': return renderHorizontalMenu(shape, shapeRenderedProps); + case 'input-stepper': + return renderInputStepper(shape, shapeRenderedProps); case 'vertical-menu': return renderVerticalMenuShape(shape, shapeRenderedProps); case 'breadcrumb': 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..48b03e78 100644 --- a/src/pods/canvas/shape-renderer/simple-rich-components/index.ts +++ b/src/pods/canvas/shape-renderer/simple-rich-components/index.ts @@ -6,6 +6,7 @@ export * from './breadcrumb.renderer'; export * from './button-bar.renderer'; export * from './calendar.renderer'; export * from './horizontal-menu.renderer'; +export * from './input-stepper.renderer'; export * from './line-chart.renderer'; export * from './map-chart.renderer'; export * from './table.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..2cbc2e8f --- /dev/null +++ b/src/pods/canvas/shape-renderer/simple-rich-components/input-stepper.renderer.tsx @@ -0,0 +1,32 @@ +import { InputWithStepper } from '@/common/components/mock-components/front-rich-components/input-stepper'; +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..a96a8ca5 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: 'input-stepper', + }, ];