diff --git a/lib/components/DmIcon.tsx b/lib/components/DmIcon.tsx index e0aeab1..cf3132c 100644 --- a/lib/components/DmIcon.tsx +++ b/lib/components/DmIcon.tsx @@ -2,7 +2,7 @@ import type { ReactNode } from 'react'; import type { BoxProps } from './Box'; import { Image } from './Image'; -enum Direction { +export enum Direction { NORTH = 1, SOUTH = 2, EAST = 4, diff --git a/lib/components/ImageButton.tsx b/lib/components/ImageButton.tsx index 2ae069d..ad5d5dd 100644 --- a/lib/components/ImageButton.tsx +++ b/lib/components/ImageButton.tsx @@ -9,7 +9,7 @@ import type { ReactNode } from 'react'; import { type BooleanLike, classes } from '../common/react'; import { computeBoxProps } from '../common/ui'; import type { BoxProps } from './Box'; -import { DmIcon } from './DmIcon'; +import { type Direction, DmIcon } from './DmIcon'; import { Icon } from './Icon'; import { Image } from './Image'; import { Stack } from './Stack'; @@ -28,11 +28,11 @@ type Props = Partial<{ */ buttons: ReactNode; /** - * Enables alternate layout for `buttons` container. - * Without fluid, buttons will be on top and with `pointer-events: none`, useful for text info. - * With fluid, buttons will be in "hamburger" style. + * Same as buttons, but. Have disabled pointer-events on content inside if non-fluid. + * Fluid version have humburger layout. + * Can be used with buttons prop. */ - buttonsAlt: boolean; + buttonsAlt: ReactNode; /** Content under image. Or on the right if fluid. */ children: ReactNode; /** Applies a CSS class to the element. */ @@ -51,6 +51,8 @@ type Props = Partial<{ dmIcon: string | null; /** Parameter `icon_state` of component `DmIcon`. */ dmIconState: string | null; + /** Parameter `direction` of component `DmIcon`. */ + dmDirection: Direction; /** * Changes the layout of the button, making it fill the entire horizontally available space. * Allows the use of `title` @@ -58,7 +60,7 @@ type Props = Partial<{ fluid: boolean; /** Parameter responsible for the size of the image, component and standard "stubs". */ imageSize: number; - /** Prop `src` of Image component. Example: `imageSrc={resolveAsset(thing.image}` */ + /** Prop `src` of Image component. Example: `imageSrc={resolveAsset(thing.image)}` */ imageSrc: string; /** Called when button is clicked with LMB. */ onClick: (e: any) => void; @@ -75,6 +77,12 @@ type Props = Partial<{ }> & BoxProps; +/** + * Stylized button, with the ability to easily and simply insert any picture into it. + * - Without image, will be default question icon. + * - If an image is specified but for some reason cannot be displayed, there will be a spinner fallback until it is loaded. + * - Component has no **hover** effects, if `onClick` or `onRightClick` is not specified. + */ export function ImageButton(props: Props) { const { asset, @@ -119,7 +127,8 @@ export function ImageButton(props: Props) {
{buttons}
)} + {buttonsAlt && ( +
+ {buttonsAlt} +
+ )} ); } diff --git a/lib/styles/components/ImageButton.scss b/lib/styles/components/ImageButton.scss index 8469213..8c33ca5 100644 --- a/lib/styles/components/ImageButton.scss +++ b/lib/styles/components/ImageButton.scss @@ -116,6 +116,7 @@ $bg-map: colors.$bg-map !default; } .ImageButton { + /* Better replace via inline-flex after Byond 516 will be stable */ display: inline-table; position: relative; text-align: center; @@ -178,7 +179,7 @@ $bg-map: colors.$bg-map !default; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - padding: 0.25em 0.5em; + padding: 0.25em 0.33em; margin: -1px; border-radius: 0 0 0.33em 0.33em; z-index: 2; @@ -190,7 +191,7 @@ $bg-map: colors.$bg-map !default; flex-direction: row; position: relative; text-align: center; - margin: 0 0 0.5em 0; + margin: 0 0 0.33em 0; user-select: none; -ms-user-select: none; diff --git a/stories/ImageButton.stories.tsx b/stories/ImageButton.stories.tsx index 04032bf..f896902 100644 --- a/stories/ImageButton.stories.tsx +++ b/stories/ImageButton.stories.tsx @@ -1,9 +1,14 @@ import type { Meta, StoryObj } from '@storybook/react'; -import type { ComponentProps } from 'react'; -import { ImageButton } from '../lib/components/ImageButton'; +import { type ComponentProps, useState } from 'react'; +import { Button, Icon, ImageButton } from '../lib/components'; -type StoryProps = ComponentProps; +const soulFish = ( + SoulFish +); +const soulFishImage = + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgBAMAAACBVGfHAAAAIVBMVEXAwMAAAP8AAMwAZv9mMwCZZjMAAAD/mTP/zGb/ADMHBwd3bPqIAAAAAXRSTlMAQObYZgAAAI5JREFUKJFjYBhkQAiNz2iEJiAMEmBxQBIAaXENQOgwBgqwhEJVsKWlJRkbCsAF2NLKy9OSjQ0FVWEC5Rlt5cnGxsKmIVADKjo62oWBAoYwMyo6Z6AKlHd0lAMFlK1cYXrKywuNgQIL4AIMDEpAFauA9iIcthjkMgYXuACTlLKhAornFFctQvUtkyLDgAIAaJcdwdTNoTsAAAAASUVORK5CYII='; +type StoryProps = ComponentProps; export default { component: ImageButton, title: 'Components/ImageButton', @@ -16,3 +21,196 @@ export const Default: Story = { children: 'ImageButton', }, }; + +export const DefaultFluid: Story = { + args: { + fluid: true, + title: 'ImageButton', + children: 'It will take up the entire available width', + }, +}; + +export const FilledDefault: Story = { + render: (args) => { + const [disabled, setDisabled] = useState(false); + const [selected, setSelected] = useState(false); + + return ( + setDisabled(!disabled)} + /> + } + buttonsAlt={soulFish} + tooltip={'Also, you can Right Click on it'} + tooltipPosition={'bottom'} + onClick={() => setSelected(!selected)} + onRightClick={() => setDisabled(!disabled)} + > + Hover me + + ); + }, +}; + +export const FilledFluid: Story = { + render: (args) => { + const [disabled, setDisabled] = useState(false); + const [selected, setSelected] = useState(false); + + return ( + setDisabled(!disabled)} + > + +
+ {disabled ? 'Enable' : 'Disable'} + + } + tooltip={'Also, you can Right Click on it'} + tooltipPosition={'bottom'} + onClick={() => setSelected(!selected)} + onRightClick={() => setDisabled(!disabled)} + > + You can put any component you want inside "buttons" or "buttonsAlt" + props +
+ ); + }, +}; + +export const Mixed: Story = { + render: (args) => { + const [disabled, setDisabled] = useState(false); + const [selected, setSelected] = useState(false); + const [compact, setCompact] = useState(false); + + const info = ( + <> + You can mix layouts without making new constants for each one. +
+ If you are MAD enough. + + ); + + const controls = ( + <> +