From 23b63af69f3d5012ba5bfffacba703859e9fd60a Mon Sep 17 00:00:00 2001 From: nearnshaw Date: Mon, 22 Jul 2024 17:35:17 -0300 Subject: [PATCH 1/2] relative positions --- README.md | 103 ++++++------------ .../prompts/FillInPrompt/index.tsx | 4 + src/ui-entities/prompts/OkPrompt/index.tsx | 4 + .../prompts/OptionPrompt/index.tsx | 4 + .../Prompt/components/Button/index.tsx | 13 ++- .../Prompt/components/Checkbox/index.tsx | 12 +- .../prompts/Prompt/components/Icon/index.tsx | 11 +- .../prompts/Prompt/components/Input/index.tsx | 6 +- .../Prompt/components/Switch/index.tsx | 12 +- .../prompts/Prompt/components/Text/index.tsx | 13 ++- src/ui-entities/prompts/Prompt/index.tsx | 22 +++- 11 files changed, 114 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index 8c90038..461aa7c 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,6 @@ A collection of tools for common UI requirements for Decentraland scenes. - [Contribute](#contribute) - [CI/CD](#cicd) - ## Install the library ## Via the Decentraland Editor @@ -44,14 +43,14 @@ To use any of the helpers provided by the utils library, follow the steps in [Ma 4. Import the library into the scene's script. Add this line at the start of your `index.ts` file, or any other TypeScript files that require it: ```ts -import * as ui from 'dcl-ui-toolkit' +import * as ui from 'dcl-ui-toolkit' ``` 5. Add following to your scene intialization code: - ```ts - ReactEcsRenderer.setUiRenderer(ui.render) - ``` + ```ts + ReactEcsRenderer.setUiRenderer(ui.render) + ``` 6. Add the following permissions for fetching media on the 'scene.json' file. See [Required Permissions](https://docs.decentraland.org/creator/development-guide/sdk7/scene-metadata/#required-permissions) for more details: @@ -63,30 +62,30 @@ import * as ui from 'dcl-ui-toolkit' "decentraland.org" ], ``` - + ## Via the CLI - + To use any of the helpers provided by the utils library 1. Install it as an `npm` package. Run this command in your scene's project folder: - ``` - npm install dcl-ui-toolkit - ``` + ``` + npm install dcl-ui-toolkit + ``` 2. Run `dcl start` or `dcl build` so the dependencies are correctly installed. 3. Import the library into the scene's script. Add this line at the start of your `game.ts` file, or any other TypeScript files that require it: - ```ts - import * as ui from 'dcl-ui-toolkit' - ``` -4. Add following to your scene intialization code: + ```ts + import * as ui from 'dcl-ui-toolkit' + ``` - ```ts - ReactEcsRenderer.setUiRenderer(ui.render) - ``` +4. Add following to your scene intialization code: + ```ts + ReactEcsRenderer.setUiRenderer(ui.render) + ``` 5. Add the following permissions for fetching media on the 'scene.json' file. See [Required Permissions](https://docs.decentraland.org/creator/development-guide/sdk7/scene-metadata/#required-permissions) for more details: @@ -99,7 +98,6 @@ To use any of the helpers provided by the utils library ], ``` - ## Text Announcement To display a text announcement on the center of the screen for a specified amount of time, use the `Announcement` class. @@ -570,8 +568,6 @@ const prompt = ui.createComponent(ui.OkPrompt, { }, acceptLabel: 'Ok', useDarkTheme: true, - width: 450, - height: 300, startHidden: false, }) @@ -620,7 +616,7 @@ When instancing a new Option Prompt, you can pass the following parameters: ```ts ReactEcsRenderer.setUiRenderer(ui.render) -const prompt = ui.createComponent(ui.OptionPrompt, { +const optionPrompt = ui.createComponent(ui.OptionPrompt, { title: 'Pick an option!', text: 'What will you choose?', acceptLabel: 'Pick A', @@ -1029,22 +1025,16 @@ export const customPrompt = ui.createComponent(ui.CustomPrompt, { const promptTitle = customPrompt.addText({ value: 'What will you do?', - xPosition: 0, - yPosition: 250, color: Color4.Yellow(), size: 30, }) const promptText = customPrompt.addText({ value: "It's an important decision", - xPosition: 0, - yPosition: 200, }) const promptCheckbox = customPrompt.addCheckbox({ text: "Don't show again", - xPosition: -80, - yPosition: 150, onCheck: () => { console.log('checkbox checked') }, @@ -1055,8 +1045,6 @@ const promptCheckbox = customPrompt.addCheckbox({ const promptSwitch = customPrompt.addSwitch({ text: 'Turn me', - xPosition: -60, - yPosition: 50, onCheck: () => { console.log('switch checked') }, @@ -1067,8 +1055,6 @@ const promptSwitch = customPrompt.addSwitch({ const promptTextBox = customPrompt.addTextBox({ placeholder: 'Enter text', - xPosition: 0, - yPosition: 100, onChange: (value) => { console.log('textbox changed:', value) }, @@ -1077,8 +1063,6 @@ const promptTextBox = customPrompt.addTextBox({ const promptButtonE = customPrompt.addButton({ style: ui.ButtonStyles.E, text: 'Yeah', - xPosition: 0, - yPosition: -150, onMouseDown: () => { console.log('Yeah clicked') }, @@ -1087,8 +1071,6 @@ const promptButtonE = customPrompt.addButton({ const promptButtonF = customPrompt.addButton({ style: ui.ButtonStyles.F, text: 'Nope', - xPosition: 0, - yPosition: -225, onMouseDown: () => { console.log('Nope clicked') }, @@ -1096,8 +1078,6 @@ const promptButtonF = customPrompt.addButton({ const promptIcon = customPrompt.addIcon({ image: 'images/scene-thumbnail.png', - xPosition: 0, - yPosition: -50, }) customPrompt.show() @@ -1110,12 +1090,10 @@ customPrompt.show() If you want to combine elements from the UI Toolkit with your own [custom UI elements](https://docs.decentraland.org/creator/development-guide/sdk7/onscreen-ui/) in the same scene, you need to render all of the UI via a single call to the `ReactEcsRenderer.setUiRenderer` function. You can combine both into a single call in the following way: ```ts -const uiComponent = () => ( - [ - ui.render(), - // Functions returning custom UI - ] -) +const uiComponent = () => [ + ui.render(), + // Functions returning custom UI +] ReactEcsRenderer.setUiRenderer(uiComponent) ``` @@ -1123,38 +1101,27 @@ ReactEcsRenderer.setUiRenderer(uiComponent) For example: ```ts -const uiComponent = () => ( - [ - ui.render(), - MyCustomUI() - ] -) +const uiComponent = () => [ui.render(), MyCustomUI()] ReactEcsRenderer.setUiRenderer(uiComponent) - function MyCustomUI() { - - return - + return ( + + + ) } ``` - - --- ## Contribute diff --git a/src/ui-entities/prompts/FillInPrompt/index.tsx b/src/ui-entities/prompts/FillInPrompt/index.tsx index 919657d..392f550 100644 --- a/src/ui-entities/prompts/FillInPrompt/index.tsx +++ b/src/ui-entities/prompts/FillInPrompt/index.tsx @@ -68,6 +68,8 @@ export class FillInPrompt extends Prompt { onClose = fillInPromptInitialConfig.onClose, width = fillInPromptInitialConfig.width, height = fillInPromptInitialConfig.height, + minWidth = fillInPromptInitialConfig.minWidth, + minHeight = fillInPromptInitialConfig.minHeight, }: FillInPromptConfig) { super( { @@ -75,6 +77,8 @@ export class FillInPrompt extends Prompt { style: useDarkTheme ? PromptStyles.DARK : PromptStyles.LIGHT, width: width, height: height, + minWidth: minWidth, + minHeight: minHeight, onClose, }) diff --git a/src/ui-entities/prompts/OkPrompt/index.tsx b/src/ui-entities/prompts/OkPrompt/index.tsx index 441ba83..aba4f93 100644 --- a/src/ui-entities/prompts/OkPrompt/index.tsx +++ b/src/ui-entities/prompts/OkPrompt/index.tsx @@ -63,6 +63,8 @@ export class OkPrompt extends Prompt { filter = okPromptInitialConfig.filter, width = okPromptInitialConfig.width, height = okPromptInitialConfig.height, + minWidth = okPromptInitialConfig.minWidth, + minHeight = okPromptInitialConfig.minHeight, }: OkPromptConfig) { super( { @@ -70,6 +72,8 @@ export class OkPrompt extends Prompt { style: useDarkTheme ? PromptStyles.DARK : PromptStyles.LIGHT, width: width, height: height, + minWidth: minWidth, + minHeight: minHeight, onClose, }) diff --git a/src/ui-entities/prompts/OptionPrompt/index.tsx b/src/ui-entities/prompts/OptionPrompt/index.tsx index 6a13954..6242447 100644 --- a/src/ui-entities/prompts/OptionPrompt/index.tsx +++ b/src/ui-entities/prompts/OptionPrompt/index.tsx @@ -85,6 +85,8 @@ export class OptionPrompt extends Prompt { onClose = optionPromptInitialConfig.onClose, width = optionPromptInitialConfig.width, height = optionPromptInitialConfig.height, + minWidth = optionPromptInitialConfig.minWidth, + minHeight = optionPromptInitialConfig.minHeight, }: OptionPromptConfig) { super( { @@ -92,6 +94,8 @@ export class OptionPrompt extends Prompt { style: useDarkTheme ? PromptStyles.DARK : PromptStyles.LIGHT, width: width, height: height, + minWidth: minWidth, + minHeight: minHeight, onClose, }) diff --git a/src/ui-entities/prompts/Prompt/components/Button/index.tsx b/src/ui-entities/prompts/Prompt/components/Button/index.tsx index 6691383..febbb85 100644 --- a/src/ui-entities/prompts/Prompt/components/Button/index.tsx +++ b/src/ui-entities/prompts/Prompt/components/Button/index.tsx @@ -62,7 +62,7 @@ const promptButtonInitialConfig: Omit, 'parent'> = text: '', xPosition: 0, yPosition: 0, - positionAbsolute: true, + positionAbsolute: false, onMouseDown: () => { }, style: PromptButtonStyles.ROUNDSILVER, buttonSize: 'auto' @@ -170,7 +170,8 @@ export class PromptButton extends InPromptUIObject { uiTransform: { justifyContent: 'flex-end', width: typeof (buttonSize) == 'number' ? buttonSize as number : 'auto', - height: this._height, + height: 'auto', + minHeight: 46, margin: { top: 30, bottom: 20 }, maxWidth: 300, }, @@ -189,7 +190,7 @@ export class PromptButton extends InPromptUIObject { this.imageElementCorner = { uiTransform: { - height: this._height, + height: this.imageElement.height, width: 12 }, uiBackground: { @@ -207,7 +208,7 @@ export class PromptButton extends InPromptUIObject { this.imageElementEdge = { uiTransform: { - height: this._height, + height: this.imageElement.height, width: 12, margin: { right: 10 } }, @@ -233,6 +234,7 @@ export class PromptButton extends InPromptUIObject { position: { top: '50%', }, + margin: {right: 10}, }, uiBackground: { textureMode: 'stretch', @@ -272,7 +274,7 @@ export class PromptButton extends InPromptUIObject { public render(key?: string): ReactEcs.JSX.Element { this._xPosition = this.promptWidth / -2 + this._width / 2 + this.xPosition - this._yPosition = this.promptHeight / 2 + this._height / -2 + this.yPosition + this._yPosition = this.promptHeight / 2 + this.imageElement.height / -2 + this.yPosition return ( void onUncheck?: () => void large?: boolean startChecked?: boolean + positionAbsolute?: boolean } const promptCheckboxInitialConfig: Omit, 'parent'> = { @@ -39,6 +40,7 @@ const promptCheckboxInitialConfig: Omit, 'parent' onUncheck: () => {}, large: false, startChecked: false, + positionAbsolute: false, } as const /** @@ -62,6 +64,7 @@ export class PromptCheckbox extends InPromptUIObject { public yPosition: number public large: boolean public startChecked: boolean + public absolute: boolean public onUncheck: () => void public onCheck: () => void @@ -79,6 +82,7 @@ export class PromptCheckbox extends InPromptUIObject { startChecked = promptCheckboxInitialConfig.startChecked, onUncheck = promptCheckboxInitialConfig.onUncheck, onCheck = promptCheckboxInitialConfig.onCheck, + positionAbsolute = promptCheckboxInitialConfig.positionAbsolute, }: PromptCheckboxConfig) { super({ startHidden, @@ -92,6 +96,7 @@ export class PromptCheckbox extends InPromptUIObject { this.startChecked = startChecked this.onUncheck = onUncheck this.onCheck = onCheck + this.absolute = positionAbsolute this._checked = this.startChecked @@ -151,8 +156,9 @@ export class PromptCheckbox extends InPromptUIObject { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', - positionType: 'absolute', + positionType: this.absolute ? 'absolute' : 'relative', position: { bottom: this._yPosition, right: this._xPosition * -1 }, + margin: { right: 10, left: 10, top: 10, bottom: 10 }, }} > , 'section' | 'parent'> = { @@ -31,6 +32,7 @@ const promptIconInitialConfig: Omit, 'section' | 'par height: 128, xPosition: 0, yPosition: 0, + positionAbsolute: false, } as const /** @@ -52,6 +54,7 @@ export class PromptIcon extends InPromptUIObject { public height: number public xPosition: number public yPosition: number + public absolute: boolean public section: ImageAtlasData | undefined private _xPosition: number | undefined @@ -66,6 +69,7 @@ export class PromptIcon extends InPromptUIObject { height = promptIconInitialConfig.height, xPosition = promptIconInitialConfig.xPosition, yPosition = promptIconInitialConfig.yPosition, + positionAbsolute = promptIconInitialConfig.positionAbsolute, }: PromptIconConfig) { super({ startHidden, @@ -77,11 +81,12 @@ export class PromptIcon extends InPromptUIObject { this.xPosition = xPosition this.yPosition = yPosition this.image = image + this.absolute = positionAbsolute if (section) this.section = section this.imageElement = { uiTransform: { - positionType: 'absolute', + positionType: this.absolute, }, uiBackground: { textureMode: 'stretch', @@ -108,7 +113,9 @@ export class PromptIcon extends InPromptUIObject { uiTransform={{ ...this.imageElement.uiTransform, display: this.visible ? 'flex' : 'none', - position: { bottom: this._yPosition, right: this._xPosition * -1 }, + positionType: this.absolute ? 'absolute' : 'relative', + position: this.absolute? { bottom: this._yPosition, right: this._xPosition * -1 } : {}, + alignSelf: 'center', width: this.width, height: this.height, }} diff --git a/src/ui-entities/prompts/Prompt/components/Input/index.tsx b/src/ui-entities/prompts/Prompt/components/Input/index.tsx index 8aafb36..be49e19 100644 --- a/src/ui-entities/prompts/Prompt/components/Input/index.tsx +++ b/src/ui-entities/prompts/Prompt/components/Input/index.tsx @@ -27,7 +27,7 @@ const promptInputInitialConfig: Omit, 'parent'> = { placeholder: 'Fill in', xPosition: 0, yPosition: 0, - positionAbsolute: true, + positionAbsolute: false, onChange: () => { }, } as const @@ -104,11 +104,11 @@ export class PromptInput extends InPromptUIObject { (!this.positionAbsolute) ? {...this.fillInBoxElement.uiTransform, display: this.visible ? 'flex' : 'none', - margin: {right: 10, left: 10, top: 10}, + margin: {right: 10, left: 10, top: 10, bottom: 10}, alignSelf: 'center'} : {...this.fillInBoxElement.uiTransform, display: this.visible ? 'flex' : 'none', - positionType: 'absolute', + positionType: this.positionAbsolute ? 'absolute' : 'relative', position: { bottom: this._yPosition, right: this._xPosition * -1 }, margin: {left: '50%', top: '50%'}}} onChange={this.onChange} diff --git a/src/ui-entities/prompts/Prompt/components/Switch/index.tsx b/src/ui-entities/prompts/Prompt/components/Switch/index.tsx index 5acbb8e..cfc13ea 100644 --- a/src/ui-entities/prompts/Prompt/components/Switch/index.tsx +++ b/src/ui-entities/prompts/Prompt/components/Switch/index.tsx @@ -25,12 +25,13 @@ export enum PromptSwitchStyles { export type PromptSwitchConfig = InPromptUIObjectConfig & { text: string | number - xPosition: number - yPosition: number + xPosition?: number + yPosition?: number onCheck?: () => void onUncheck?: () => void startChecked?: boolean style?: PromptSwitchStyles + positionAbsolute?: boolean } const promptSwitchInitialConfig: Omit, 'parent'> = { @@ -42,6 +43,7 @@ const promptSwitchInitialConfig: Omit, 'parent'> = onUncheck: () => {}, startChecked: false, style: PromptSwitchStyles.ROUNDGREEN, + positionAbsolute: false, } as const /** @@ -64,6 +66,7 @@ export class PromptSwitch extends InPromptUIObject { public yPosition: number public style: PromptSwitchStyles public startChecked: boolean + public absolute: boolean public onUncheck: () => void public onCheck: () => void @@ -81,6 +84,7 @@ export class PromptSwitch extends InPromptUIObject { onUncheck = promptSwitchInitialConfig.onUncheck, startChecked = promptSwitchInitialConfig.startChecked, style = promptSwitchInitialConfig.style, + positionAbsolute = promptSwitchInitialConfig.positionAbsolute, }: PromptSwitchConfig) { super({ startHidden, @@ -94,6 +98,7 @@ export class PromptSwitch extends InPromptUIObject { this.startChecked = startChecked this.onUncheck = onUncheck this.onCheck = onCheck + this.absolute = positionAbsolute this._checked = startChecked @@ -152,7 +157,8 @@ export class PromptSwitch extends InPromptUIObject { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', - positionType: 'absolute', + positionType: this.absolute ? 'absolute' : 'relative', + margin: { right: 10, left: 10, top: 25, bottom: 25 }, position: { bottom: this._yPosition, right: this._xPosition * -1 }, }} > diff --git a/src/ui-entities/prompts/Prompt/components/Text/index.tsx b/src/ui-entities/prompts/Prompt/components/Text/index.tsx index 982f7e7..0ed4a39 100644 --- a/src/ui-entities/prompts/Prompt/components/Text/index.tsx +++ b/src/ui-entities/prompts/Prompt/components/Text/index.tsx @@ -26,7 +26,7 @@ const promptTextInitialConfig: Omit, 'parent'> = { value: '', xPosition: 0, yPosition: 0, - positionAbsolute: true, + positionAbsolute: false, color: Color4.Black(), size: 15, } as const @@ -106,16 +106,19 @@ export class PromptText extends InPromptUIObject { value={lineBreak(String(this.value), 50)} color={this.color || (this.isDarkTheme ? Color4.White() : promptTextInitialConfig.color)} fontSize={this.size} + textAlign='middle-center' uiTransform={ (!this.positionAbsolute) ? {display: this.visible ? 'flex' : 'none', margin: { top: 20, left: 20, right: 20 }, height: 'auto', - alignSelf: 'center'} + alignSelf: 'center', + alignContent: 'center' } : {display: this.visible ? 'flex' : 'none', - positionType: 'absolute', - position: { top: '50%', left: '50%' }, - margin: { left: this.xPosition, top: this.yPosition * -1 }} + positionType: this.positionAbsolute? 'absolute' : 'relative', + // position: { top: '50%', left: '50%' }, + // margin: { left: this.xPosition, top: this.yPosition * -1 } + } } /> ) diff --git a/src/ui-entities/prompts/Prompt/index.tsx b/src/ui-entities/prompts/Prompt/index.tsx index 046d194..866de7d 100644 --- a/src/ui-entities/prompts/Prompt/index.tsx +++ b/src/ui-entities/prompts/Prompt/index.tsx @@ -33,6 +33,8 @@ export type PromptExternalConfig = UIObjectConfig & { width?: number | 'auto' height?: number | 'auto' onClose?: Callback + minWidth?: number | undefined + minHeight?: number | undefined } export type PromptConfig = PromptExternalConfig & { @@ -44,6 +46,8 @@ const promptInitialConfig: Required = { style: PromptStyles.LIGHT, width: 400, height: 250, + minWidth: 400, + minHeight: 250, onClose: () => { }, } as const @@ -65,6 +69,8 @@ export class Prompt extends UIObject implements IPrompt { public posWidth: number | undefined public posHeight: number | undefined public onClose: Callback + public minWidth: number | undefined + public minHeight: number | undefined private _texture: AtlasTheme private _section: ImageAtlasData @@ -99,6 +105,9 @@ export class Prompt extends UIObject implements IPrompt { this.height = height this.onClose = onClose + this.minHeight = promptInitialConfig.minHeight + this.minWidth = promptInitialConfig.minWidth + this._texture = AtlasTheme.ATLAS_PATH_LIGHT this._section = { @@ -218,6 +227,8 @@ export class Prompt extends UIObject implements IPrompt { justifyContent: 'center', width: this.width != 'auto' ? this.width : 'auto', height: this.height != 'auto' ? this.height : 'auto', + minWidth: this.minWidth? this.minWidth : undefined, + minHeight: this.minHeight? this.minHeight : undefined }} > @@ -241,9 +259,11 @@ export class Prompt extends UIObject implements IPrompt { uiTransform={{ flexDirection: 'column', alignSelf: 'center', - justifyContent: 'flex-end', + justifyContent: 'center', width: this.width != 'auto' ? width : 'auto', height: this.height != 'auto' ? height : 'auto', + minWidth: this.minWidth? this.minWidth : undefined, + minHeight: this.minHeight? this.minHeight : undefined, margin: {top: 20} }} > From 895299b4b4d8412ac405e1c919d8beedf201820a Mon Sep 17 00:00:00 2001 From: nearnshaw Date: Tue, 23 Jul 2024 10:18:03 -0300 Subject: [PATCH 2/2] minor fixes --- README.md | 2 +- src/ui-entities/prompts/Prompt/components/Icon/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 461aa7c..2b3845e 100644 --- a/README.md +++ b/README.md @@ -632,7 +632,7 @@ const optionPrompt = ui.createComponent(ui.OptionPrompt, { startHidden: false, }) -prompt.show() +optionPrompt.show() ``` diff --git a/src/ui-entities/prompts/Prompt/components/Icon/index.tsx b/src/ui-entities/prompts/Prompt/components/Icon/index.tsx index b1eaa06..2b9fb20 100644 --- a/src/ui-entities/prompts/Prompt/components/Icon/index.tsx +++ b/src/ui-entities/prompts/Prompt/components/Icon/index.tsx @@ -86,7 +86,7 @@ export class PromptIcon extends InPromptUIObject { this.imageElement = { uiTransform: { - positionType: this.absolute, + positionType: this.absolute ? 'absolute' : 'relative', }, uiBackground: { textureMode: 'stretch',