chore: add color validation + native color picker (#25355)
## Description
1. Reduced the number of default colors. Because the amount of suggested
options was too much: very little difference between shades and
sometimes with hues too. By removing half of them, we allow builders
make better choices faster. The transparent color has also been removed.
2. Added validation of color values because HTML colors are remarkably
easy to get wrong, because they allow so many different values and now
we support and validate all these guys
- `hex` - `#bada55`
- `name` - `LightGoldenrodYellow`
- `special name` - `currentColor`
- `rgb` - `rgb(0 0 0)`
- `rgba` - `rgba(0, 0, 0, .45)`
- `hsl` - `hsl(4.71239rad, 60%, 70%)`
- `hsla` - `hsla(180deg 100% 50% / .8)`
- `hwb` - `hwb(180deg 0% 0% / 100%)`
- `lab` - `lab(2000.1337% -8.6911 -159.131231 / .987189732)`
- `lch` - `lch(54.292% 106.839 40.853)`
<img width="283" alt="Снимок экрана 2023-08-02 в 17 58 07"
src="https://github.com/appsmithorg/appsmith/assets/11555074/a8fef365-506d-432e-85ad-cdb550de1f60">
3. Added support for a Full color picker. Now we can easily switch
between modes and builders can easily choose any colors.
<img width="259" alt="Снимок экрана 2023-08-02 в 17 43 34"
src="https://github.com/appsmithorg/appsmith/assets/11555074/be09cd92-7c69-43eb-812a-0b1fe3ac9ef6">
#### PR fixes following issue(s)
Fixes #22996
#### Media
https://www.loom.com/share/098e0116e49744e7b10689d4a18ab664?sid=15405577-160e-4b48-bfef-bc8dcfa97efe
#### Type of change
- New feature (non-breaking change which adds functionality)
## Testing
>
#### How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Also
list any relevant details for your test configuration.
> Delete anything that is not relevant
- [x] Manual
- [x] Jest
- [x] Cypress
## Checklist:
#### Dev activity
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
---------
Co-authored-by: Valera Melnikov <melnikov.vv@greendatasoft.ru>
This commit is contained in:
parent
75eea5b87d
commit
8be4936ca0
|
|
@ -29,7 +29,7 @@ describe("Entity explorer Drag and Drop widgets testcases", function () {
|
|||
cy.selectColor("backgroundcolor");
|
||||
cy.get(formWidgetsPage.formD)
|
||||
.should("have.css", "background-color")
|
||||
.and("eq", "rgb(126, 34, 206)");
|
||||
.and("eq", "rgb(219, 234, 254)");
|
||||
/**
|
||||
* @param{toggleButton Css} Assert to be checked
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ describe("Undo/Redo functionality", function () {
|
|||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.wait("@updateLayout");
|
||||
cy.readTextDataValidateCSS("color", "rgb(126, 34, 206)");
|
||||
cy.readTextDataValidateCSS("color", "rgb(219, 234, 254)");
|
||||
cy.get("body").click({ force: true }).type(`{${modifierKey}}z`);
|
||||
entityExplorer.NavigateToSwitcher("Explorer");
|
||||
entityExplorer.SelectEntityByName("Text1");
|
||||
|
|
@ -191,7 +191,7 @@ describe("Undo/Redo functionality", function () {
|
|||
cy.get(widgetsPage.textColor)
|
||||
.first()
|
||||
.invoke("attr", "value")
|
||||
.should("contain", "#7e22ce");
|
||||
.should("contain", "#dbeafe");
|
||||
});
|
||||
|
||||
it("8. checks undo/redo for option control for radio button", function () {
|
||||
|
|
|
|||
|
|
@ -364,7 +364,7 @@ describe("App Theming funtionality", function () {
|
|||
.find(".t--theme-card > main > main")
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
expect(backgroudColor).to.eq("rgb(131, 24, 67)");
|
||||
expect(backgroudColor).to.eq("rgb(236, 72, 153)");
|
||||
});
|
||||
|
||||
//Check if the saved theme is present under 'Yours Themes' section with Trash button
|
||||
|
|
@ -669,7 +669,7 @@ describe("App Theming funtionality", function () {
|
|||
.eq(0)
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
expect(backgroudColor).to.eq("rgb(126, 34, 206)");
|
||||
expect(backgroudColor).to.eq("rgb(219, 234, 254)");
|
||||
});
|
||||
|
||||
cy.contains("Applied theme")
|
||||
|
|
@ -680,7 +680,7 @@ describe("App Theming funtionality", function () {
|
|||
.eq(1)
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
expect(backgroudColor).to.eq("rgb(253, 224, 71)");
|
||||
expect(backgroudColor).to.eq("rgb(29, 78, 216)");
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
|
@ -696,17 +696,17 @@ describe("App Theming funtionality", function () {
|
|||
cy.xpath("//div[@id='root']//section/parent::div").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(253, 224, 71)",
|
||||
"rgb(29, 78, 216)",
|
||||
); //Background Color
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
); //Widget Color
|
||||
cy.get(publish.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
); //Widget Color
|
||||
|
||||
cy.get(widgetsPage.widgetBtn).should("have.css", "border-radius", "24px"); //Border Radius
|
||||
|
|
@ -738,12 +738,12 @@ describe("App Theming funtionality", function () {
|
|||
cy.get(".t--widget-button1 button").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
); //old widgets still conforming to theme color
|
||||
cy.get(widgetsPage.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -789,20 +789,20 @@ describe("App Theming funtionality", function () {
|
|||
cy.get(".t--widget-buttonwidget:nth-child(4) button").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(134, 239, 172)", //rgb(134, 239, 172)
|
||||
"rgb(190, 24, 93)",
|
||||
); //new widget with its own color
|
||||
|
||||
////old widgets still conforming to theme color
|
||||
cy.get(".t--widget-buttonwidget button").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
);
|
||||
|
||||
cy.get(publish.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
);
|
||||
|
||||
//Verify Border radius
|
||||
|
|
@ -845,7 +845,7 @@ describe("App Theming funtionality", function () {
|
|||
cy.get(".t--widget-button2 button").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
); //verify widget reverted to theme color
|
||||
cy.get(".t--property-control-borderradius .reset-button").then(($elem) => {
|
||||
$elem[0].removeAttribute("display: none");
|
||||
|
|
@ -866,12 +866,12 @@ describe("App Theming funtionality", function () {
|
|||
cy.xpath("//div[@id='root']//section/parent::div").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(253, 224, 71)",
|
||||
"rgb(29, 78, 216)",
|
||||
); //Background Color
|
||||
cy.get(".t--widget-button1 button").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
); //Widget Color
|
||||
cy.get("body").then(($ele) => {
|
||||
if ($ele.find(widgetsPage.widgetBtn).length <= 1) {
|
||||
|
|
@ -882,12 +882,12 @@ describe("App Theming funtionality", function () {
|
|||
cy.get(".t--widget-button2 button").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
); //Widget Color
|
||||
cy.get(publish.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
); //Widget Color
|
||||
|
||||
cy.get(".t--widget-button1 button").should(
|
||||
|
|
@ -1004,7 +1004,7 @@ describe("App Theming funtionality", function () {
|
|||
cy.get(".t--widget-button1 button").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(252, 165, 165)",
|
||||
"rgb(161, 98, 7)",
|
||||
); //new widget with its own color
|
||||
|
||||
////old widgets still conforming to theme color
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ describe("Theme validation usecases", function () {
|
|||
cy.get(themelocator.inputColor).clear({ force: true });
|
||||
cy.wait(2000);
|
||||
theme.ChangeThemeColor(16, "Background");
|
||||
cy.get(themelocator.inputColor).should("have.value", "#dc2626"); //Red
|
||||
cy.get(themelocator.inputColor).should("have.value", "#86efac"); //Red
|
||||
cy.wait(2000);
|
||||
|
||||
cy.get(themelocator.inputColor).eq(0).click({ force: true });
|
||||
|
|
@ -107,7 +107,7 @@ describe("Theme validation usecases", function () {
|
|||
cy.get(themelocator.inputColor).clear({ force: true });
|
||||
cy.wait(2000);
|
||||
theme.ChangeThemeColor(9, "Primary");
|
||||
cy.get(themelocator.inputColor).should("have.value", "#18181b"); //Black
|
||||
cy.get(themelocator.inputColor).should("have.value", "#7f1d1d"); //Black
|
||||
cy.wait(2000);
|
||||
cy.contains("Color").click({ force: true });
|
||||
appSettings.ClosePane();
|
||||
|
|
|
|||
|
|
@ -190,13 +190,13 @@ describe("List Widget Functionality", function () {
|
|||
agHelper.AssertCSS(
|
||||
locators._listWidget,
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
);
|
||||
// Verify List Item Background Color
|
||||
agHelper.AssertCSS(
|
||||
locators._itemContainerWidget,
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
);
|
||||
deployMode.NavigateBacktoEditor();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -37,13 +37,13 @@ describe("Container Widget Functionality", function () {
|
|||
cy.get(widgetsPage.listWidget).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
);
|
||||
// Verify List Item Background Color
|
||||
cy.get(widgetsPage.itemContainerWidget).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
);
|
||||
_.deployMode.NavigateBacktoEditor();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ describe("Table Widget property pane feature validation", function () {
|
|||
cy.wait(500);
|
||||
cy.wait("@updateLayout");
|
||||
// Verify the text color is green
|
||||
cy.readTabledataValidateCSS("1", "0", "color", "rgb(126, 34, 206)");
|
||||
cy.readTabledataValidateCSS("1", "0", "color", "rgb(219, 234, 254)");
|
||||
// Change the text color and enter purple in input field
|
||||
cy.get(widgetsPage.textColor)
|
||||
.scrollIntoView()
|
||||
|
|
@ -41,13 +41,15 @@ describe("Table Widget property pane feature validation", function () {
|
|||
"1",
|
||||
"1",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
);
|
||||
_.deployMode.NavigateBacktoEditor();
|
||||
cy.openPropertyPane("tablewidget");
|
||||
|
||||
// Change the cell background color and enter purple in input field
|
||||
cy.get(`${widgetsPage.cellBackground_tablev1} input`)
|
||||
cy.get(
|
||||
`${widgetsPage.cellBackground_tablev1} [data-testid='t--color-picker-input']`,
|
||||
)
|
||||
.clear({ force: true })
|
||||
.type("purple", { force: true });
|
||||
cy.wait("@updateLayout");
|
||||
|
|
|
|||
|
|
@ -28,23 +28,23 @@ describe("Table Widget empty row color validation", function () {
|
|||
"1",
|
||||
"0",
|
||||
"background-color",
|
||||
"rgb(99, 102, 241)",
|
||||
"rgb(185, 28, 28)",
|
||||
);
|
||||
// Verify the cell background color of second column
|
||||
cy.readTabledataValidateCSS(
|
||||
"1",
|
||||
"1",
|
||||
"background-color",
|
||||
"rgb(30, 58, 138)",
|
||||
"rgb(113, 113, 122)",
|
||||
);
|
||||
//Test 2. Validate empty row background
|
||||
// first cell of first row should be transparent
|
||||
cy.get(
|
||||
".t--widget-tablewidget .tbody div[data-testid='empty-row-0-cell-0']",
|
||||
).should("have.css", "background-color", "rgb(99, 102, 241)");
|
||||
).should("have.css", "background-color", "rgb(185, 28, 28)");
|
||||
// second cell of first row should be transparent
|
||||
cy.get(
|
||||
".t--widget-tablewidget .tbody div[data-testid='empty-row-0-cell-1']",
|
||||
).should("have.css", "background-color", "rgb(30, 58, 138)");
|
||||
).should("have.css", "background-color", "rgb(113, 113, 122)");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -171,12 +171,12 @@ describe("Table Widget property pane feature validation", function () {
|
|||
it("6. Test to validate text color and text background", function () {
|
||||
cy.openPropertyPane("tablewidget");
|
||||
|
||||
// Changing text color to rgb(126, 34, 206) and validate
|
||||
// Changing text color to rgb(219, 234, 254) and validate
|
||||
cy.selectColor("textcolor");
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(5000);
|
||||
cy.wait("@updateLayout");
|
||||
cy.readTabledataValidateCSS("1", "0", "color", "rgb(126, 34, 206)");
|
||||
cy.readTabledataValidateCSS("1", "0", "color", "rgb(219, 234, 254)");
|
||||
|
||||
// Changing text color to PURPLE and validate using JS
|
||||
cy.get(widgetsPage.toggleJsColor).click({ force: true });
|
||||
|
|
@ -185,13 +185,13 @@ describe("Table Widget property pane feature validation", function () {
|
|||
cy.wait("@updateLayout");
|
||||
cy.readTabledataValidateCSS("1", "0", "color", "rgb(128, 0, 128)");
|
||||
cy.get(commonlocators.editPropBackButton).click();
|
||||
// Changing Cell backgroud color to rgb(126, 34, 206) and validate
|
||||
// Changing Cell backgroud color to rgb(219, 234, 254) and validate
|
||||
cy.selectColor("cellbackgroundcolor");
|
||||
cy.readTabledataValidateCSS(
|
||||
"0",
|
||||
"0",
|
||||
"background",
|
||||
"rgb(126, 34, 206) none repeat scroll 0% 0% / auto padding-box border-box",
|
||||
"rgb(219, 234, 254) none repeat scroll 0% 0% / auto padding-box border-box",
|
||||
true,
|
||||
);
|
||||
// Changing Cell backgroud color to PURPLE and validate using JS
|
||||
|
|
|
|||
|
|
@ -325,20 +325,4 @@ describe("Table Widget property pane feature validation", function () {
|
|||
cy.wait(500);
|
||||
cy.get("[data-testid='t--property-pane-back-btn']").click({ force: true });
|
||||
});
|
||||
|
||||
it("7. Table widget test on button when transparent", () => {
|
||||
cy.openPropertyPane("tablewidget");
|
||||
// Open column details of "id".
|
||||
cy.editColumn("id");
|
||||
// Changing column "Button" color to transparent
|
||||
|
||||
cy.get(widgetsPage.buttonColor).click({ force: true });
|
||||
cy.wait(2000);
|
||||
cy.get(widgetsPage.transparent).click({ force: true });
|
||||
cy.get(".td[data-colindex=5][data-rowindex=0] .bp3-button").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgba(0, 0, 0, 0)",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ describe("Table Widget V2 property pane feature validation", function () {
|
|||
cy.wait(500);
|
||||
cy.wait("@updateLayout");
|
||||
// Verify the text color is green
|
||||
cy.readTableV2dataValidateCSS("1", "0", "color", "rgb(126, 34, 206)");
|
||||
cy.readTableV2dataValidateCSS("1", "0", "color", "rgb(219, 234, 254)");
|
||||
// Change the text color and enter purple in input field
|
||||
cy.get(widgetsPage.textColor)
|
||||
.scrollIntoView()
|
||||
|
|
@ -49,13 +49,15 @@ describe("Table Widget V2 property pane feature validation", function () {
|
|||
"1",
|
||||
"1",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
);
|
||||
_.deployMode.NavigateBacktoEditor();
|
||||
cy.openPropertyPane("tablewidgetv2");
|
||||
cy.moveToStyleTab();
|
||||
// Change the cell background color and enter purple in input field
|
||||
cy.get(`.t--property-control-cellbackgroundcolor input`)
|
||||
cy.get(
|
||||
`.t--property-control-cellbackgroundcolor [data-testid='t--color-picker-input']`,
|
||||
)
|
||||
.clear({ force: true })
|
||||
.type("purple", { force: true });
|
||||
cy.wait("@updateLayout");
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ describe("Table Widget V2 property pane feature validation", function () {
|
|||
cy.openPropertyPane("tablewidgetv2");
|
||||
cy.editColumn("id");
|
||||
cy.moveToStyleTab();
|
||||
// Changing text color to rgb(126, 34, 206) and validate
|
||||
// Changing text color to rgb(219, 234, 254) and validate
|
||||
cy.selectColor("textcolor");
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(5000);
|
||||
cy.wait("@updateLayout");
|
||||
cy.readTableV2dataValidateCSS("1", "0", "color", "rgb(126, 34, 206)");
|
||||
cy.readTableV2dataValidateCSS("1", "0", "color", "rgb(219, 234, 254)");
|
||||
|
||||
// Changing text color to PURPLE and validate using JS
|
||||
cy.get(widgetsPage.toggleJsColor).click();
|
||||
|
|
@ -31,13 +31,13 @@ describe("Table Widget V2 property pane feature validation", function () {
|
|||
cy.wait("@updateLayout");
|
||||
cy.readTableV2dataValidateCSS("1", "0", "color", "rgb(128, 0, 128)");
|
||||
|
||||
// Changing Cell backgroud color to rgb(126, 34, 206) and validate
|
||||
// Changing Cell backgroud color to rgb(219, 234, 254) and validate
|
||||
cy.selectColor("cellbackground");
|
||||
cy.readTableV2dataValidateCSS(
|
||||
"0",
|
||||
"0",
|
||||
"background",
|
||||
"rgb(113, 30, 184) none repeat scroll 0% 0% / auto padding-box border-box",
|
||||
"rgb(194, 220, 253) none repeat scroll 0% 0% / auto padding-box border-box",
|
||||
true,
|
||||
);
|
||||
// Changing Cell backgroud color to PURPLE and validate using JS
|
||||
|
|
|
|||
|
|
@ -289,20 +289,4 @@ describe("Table Widget V2 property pane feature validation", function () {
|
|||
cy.wait(500);
|
||||
cy.get("[data-testid='t--property-pane-back-btn']").click({ force: true });
|
||||
});
|
||||
|
||||
it("8. Table widget test on button when transparent", () => {
|
||||
cy.openPropertyPane("tablewidgetv2");
|
||||
// Open column details of "id".
|
||||
cy.editColumn("id");
|
||||
// Changing column "Button" color to transparent
|
||||
cy.moveToStyleTab();
|
||||
cy.get(widgetsPage.buttonColor).click({ force: true });
|
||||
cy.wait(2000);
|
||||
cy.get(widgetsPage.transparent).click({ force: true });
|
||||
cy.get(".td[data-colindex=5][data-rowindex=0] .bp3-button").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgba(0, 0, 0, 0)",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ describe("Text Widget Cell Background and Text Size Validation", function () {
|
|||
cy.get(`${widgetsPage.textWidget} .bp3-ui-text`).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
);
|
||||
|
||||
//Toggle to JS mode
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ describe("Text Widget color/font/alignment Functionality", function () {
|
|||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.wait("@updateLayout");
|
||||
cy.readTextDataValidateCSS("color", "rgb(126, 34, 206)");
|
||||
cy.readTextDataValidateCSS("color", "rgb(219, 234, 254)");
|
||||
cy.get(widgetsPage.textColor)
|
||||
.clear({ force: true })
|
||||
.type("purple", { force: true });
|
||||
|
|
@ -105,7 +105,7 @@ describe("Text Widget color/font/alignment Functionality", function () {
|
|||
cy.get(`${widgetsPage.textWidget} .bp3-ui-text`).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
"rgb(219, 234, 254)",
|
||||
);
|
||||
|
||||
//Toggle JS check with cell background:
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ describe("Json & JsonB Datatype tests", function () {
|
|||
agHelper.AddDsl("Datatypes/JsonDTdsl");
|
||||
|
||||
entityExplorer.NavigateToSwitcher("Widgets");
|
||||
appSettings.OpenPaneAndChangeThemeColors(33, 39);
|
||||
appSettings.OpenPaneAndChangeThemeColors(16, 20);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"popover": ".rc-tooltip-inner",
|
||||
"shadow": ".t--theme-appBoxShadow",
|
||||
"color": ".t--property-pane-sidebar .bp3-popover-target .cursor-pointer",
|
||||
"inputColor": ".t--colorpicker-v2-popover input",
|
||||
"inputColor": ".t--colorpicker-v2-popover [data-testid='t--color-picker-input']",
|
||||
"colorPicker": "[data-testid='color-picker']",
|
||||
"greenColor": "[style='background-color: rgb(21, 128, 61);']",
|
||||
"fontsSelected": ".leading-normal",
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
"inputPropsDataType": ".t--property-control-datatype input",
|
||||
"inputdatatypeplaceholder": ".t--property-control-placeholder",
|
||||
"buttonWidget": ".t--draggable-buttonwidget",
|
||||
"buttonColor": ".t--property-control-buttoncolor input",
|
||||
"buttonColor": ".t--property-control-buttoncolor [data-testid='t--color-picker-input']",
|
||||
"checkboxWidget": ".t--draggable-checkboxwidget",
|
||||
"buttonStyleDropdown": ".t--property-control-buttonstyle [name='downArrow']",
|
||||
"buttonBackground": ".sc-ecQjpJ > div > .bp3-button",
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
"requiredjs": ".t--property-control-required input",
|
||||
"visible": ".t--property-control-visible input",
|
||||
"disable": ".t--property-control-disabled",
|
||||
"menuColor": ".t--property-control-menucolor input",
|
||||
"menuColor": ".t--property-control-menucolor [data-testid='t--color-picker-input']",
|
||||
"menubar": ".bp3-menu",
|
||||
"menupop": ".bp3-popover",
|
||||
"defaultcheck": ".t--property-control-defaultstate input",
|
||||
|
|
@ -94,17 +94,16 @@
|
|||
"verticalTop": "[data-value='TOP']",
|
||||
"verticalCenter": "[data-value='CENTER']",
|
||||
"verticalBottom": "[data-value='BOTTOM']",
|
||||
"textColor": ".t--property-control-textcolor input",
|
||||
"textColor": ".t--property-control-textcolor [data-testid='t--color-picker-input']",
|
||||
"boadercolorPicker": ".t--property-control-bordercolour input",
|
||||
"boxShadowColorPicker": ".t--property-control-shadowcolor input",
|
||||
"boxShadow": ".t--property-control-boxshadow .bp3-button-group",
|
||||
"inputStepArrows": ".bp3-button-group",
|
||||
"backgroundcolorPicker": ".t--property-control-backgroundcolour input",
|
||||
"backgroundcolorPickerNew": ".t--property-control-backgroundcolor input",
|
||||
"backgroundcolorPickerNew": ".t--property-control-backgroundcolor [data-testid='t--color-picker-input']",
|
||||
"greenColorHex": "#03b365",
|
||||
"yellowColorHex": "#FFC13D",
|
||||
"greenColor": "//div[@color='#03b365']",
|
||||
"transparent": ".diagnol-cross",
|
||||
"yellowColor": "//div[@color='#FFC13D']",
|
||||
"blueColor": "//div[@color='#3366FF']",
|
||||
"toggleJsColor": ".t--property-control-textcolor .t--js-toggle",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export class ThemeSettings {
|
|||
"']//ancestor::div[@class= 'space-y-1 group']",
|
||||
_colorPickerV2Popover: ".t--colorpicker-v2-popover",
|
||||
_colorPickerV2Color:
|
||||
"//h3[text()='All Colors']/following-sibling::div//div[contains(@class,'t--colorpicker-v2-color')]",
|
||||
"[data-testid='t--all-colors'] .t--colorpicker-v2-color",
|
||||
_colorRingPrimary: "[data-testid='theme-primaryColor']",
|
||||
_colorRingBackground: "[data-testid='theme-backgroundColor']",
|
||||
_colorInput: (option: string) =>
|
||||
|
|
|
|||
|
|
@ -207,6 +207,7 @@
|
|||
"unescape-js": "^1.1.4",
|
||||
"url-search-params-polyfill": "^8.0.0",
|
||||
"uuid": "^9.0.0",
|
||||
"validate-color": "^2.2.4",
|
||||
"webfontloader": "^1.6.28",
|
||||
"webpack-retry-chunk-load-plugin": "^3.1.1",
|
||||
"yjs": "^13.5.12",
|
||||
|
|
|
|||
|
|
@ -56,13 +56,6 @@ and .Toastify__toast-container--bottom-center classes, which messes with the pla
|
|||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.diagnol-cross {
|
||||
background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' preserveAspectRatio='none' viewBox='0 0 100 100'><path d='M0 99 L99 0 L100 1 L1 100' fill='red' /></svg>");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-size: 100% 100%, auto;
|
||||
}
|
||||
|
||||
.hidden-scrollbar {
|
||||
-ms-overflow-style: none; /* for Internet Explorer, Edge */
|
||||
scrollbar-width: none; /* for Firefox */
|
||||
|
|
|
|||
|
|
@ -1901,3 +1901,6 @@ export const DEFAULT_CAMERA_LABEL_DESCRIPTION = () =>
|
|||
"Default choice for mobile users. Not applicable for other devices";
|
||||
export const FRONT_CAMERA_LABEL = () => "Front (Selfie)";
|
||||
export const BACK_CAMERA_LABEL = () => "Back (Rear)";
|
||||
|
||||
// Color picker
|
||||
export const FULL_COLOR_PICKER_LABEL = () => "Full color picker";
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ describe("<ColorPicker /> - Keyboard Navigation", () => {
|
|||
userEvent.tab();
|
||||
userEvent.keyboard("{Enter}");
|
||||
|
||||
userEvent.tab();
|
||||
userEvent.tab();
|
||||
expect(
|
||||
document.querySelectorAll("[tabindex='0'].t--colorpicker-v2-color")[0],
|
||||
|
|
@ -133,6 +134,7 @@ describe("<ColorPicker /> - Keyboard Navigation", () => {
|
|||
userEvent.tab();
|
||||
userEvent.keyboard("{Enter}");
|
||||
|
||||
userEvent.tab();
|
||||
userEvent.tab();
|
||||
userEvent.tab();
|
||||
|
||||
|
|
@ -153,6 +155,7 @@ describe("<ColorPicker /> - Keyboard Navigation", () => {
|
|||
userEvent.tab();
|
||||
userEvent.keyboard("{Enter}");
|
||||
|
||||
userEvent.tab();
|
||||
userEvent.tab();
|
||||
userEvent.tab();
|
||||
|
||||
|
|
@ -180,6 +183,7 @@ describe("<ColorPicker /> - Keyboard Navigation", () => {
|
|||
userEvent.tab();
|
||||
userEvent.keyboard("{Enter}");
|
||||
|
||||
userEvent.tab();
|
||||
userEvent.tab();
|
||||
userEvent.tab();
|
||||
|
||||
|
|
@ -199,6 +203,7 @@ describe("<ColorPicker /> - Keyboard Navigation", () => {
|
|||
userEvent.tab();
|
||||
userEvent.keyboard("{Enter}");
|
||||
|
||||
userEvent.tab();
|
||||
userEvent.tab();
|
||||
userEvent.tab();
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import React, {
|
|||
useCallback,
|
||||
} from "react";
|
||||
import styled from "styled-components";
|
||||
import { Icon } from "design-system";
|
||||
import { Icon, Switch } from "design-system";
|
||||
import {
|
||||
Popover,
|
||||
InputGroup,
|
||||
|
|
@ -21,11 +21,15 @@ import {
|
|||
getThemePropertyBinding,
|
||||
} from "constants/ThemeConstants";
|
||||
import { getWidgets } from "sagas/selectors";
|
||||
import { extractColorsFromString } from "utils/helpers";
|
||||
import { extractColorsFromString, isValidColor } from "utils/helpers";
|
||||
import { TAILWIND_COLORS } from "constants/ThemeConstants";
|
||||
import useDSEvent from "utils/hooks/useDSEvent";
|
||||
import { DSEventTypes } from "utils/AppsmithUtils";
|
||||
import { getBrandColors } from "@appsmith/selectors/tenantSelectors";
|
||||
import {
|
||||
createMessage,
|
||||
FULL_COLOR_PICKER_LABEL,
|
||||
} from "@appsmith/constants/messages";
|
||||
|
||||
const FocusTrap = require("focus-trap-react");
|
||||
|
||||
|
|
@ -46,6 +50,7 @@ interface ColorPickerProps {
|
|||
isOpen?: boolean;
|
||||
placeholderText?: string;
|
||||
portalContainer?: HTMLElement;
|
||||
onPopupClosed?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -73,7 +78,10 @@ const ColorPickerIconContainer = styled.div`
|
|||
z-index: 1;
|
||||
`;
|
||||
|
||||
const StyledInputGroup = styled(InputGroup)`
|
||||
const StyledInputGroup = styled(InputGroup)<{
|
||||
$isValid?: boolean;
|
||||
$isFullColorPicker?: boolean;
|
||||
}>`
|
||||
.${Classes.INPUT} {
|
||||
box-shadow: none;
|
||||
border: 1px solid var(--ads-v2-color-border);
|
||||
|
|
@ -83,23 +91,30 @@ const StyledInputGroup = styled(InputGroup)`
|
|||
}
|
||||
}
|
||||
&&& input {
|
||||
padding-left: 36px;
|
||||
padding: ${({ $isFullColorPicker }) =>
|
||||
$isFullColorPicker ? "0px 2px" : "0 10px 0 36px"};
|
||||
height: 36px;
|
||||
border: 1px solid var(--ads-v2-color-border);
|
||||
border: ${({ $isValid }) =>
|
||||
$isValid
|
||||
? "1px solid var(--ads-v2-color-border)"
|
||||
: "1px solid var(--ads-v2-color-border-error)"};
|
||||
background: ${(props) =>
|
||||
props.theme.colors.propertyPane.multiDropdownBoxHoverBg};
|
||||
color: ${(props) => props.theme.colors.propertyPane.label};
|
||||
|
||||
&:hover {
|
||||
border-color: var(--ads-v2-color-border-emphasis);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border: 1px solid var(--ads-v2-color-border-emphasis);
|
||||
outline: var(--ads-v2-border-width-outline) solid
|
||||
var(--ads-v2-color-outline);
|
||||
outline-offset: var(--ads-v2-offset-outline);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
border-color: ${({ $isValid }) =>
|
||||
$isValid
|
||||
? "var(--ads-v2-color-border-emphasis)"
|
||||
: "var(--ads-v2-color-border-error)"};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
@ -117,7 +132,6 @@ interface ColorPickerPopupProps {
|
|||
|
||||
const PopupContainer = styled.div`
|
||||
padding: 0.75rem;
|
||||
width: 18rem;
|
||||
border-radius: var(--ads-v2-border-radius);
|
||||
border: 1px solid var(--ads-v2-color-border);
|
||||
`;
|
||||
|
|
@ -126,10 +140,9 @@ function ColorPickerPopup(props: ColorPickerPopupProps) {
|
|||
const themeColors = useSelector(getSelectedAppThemeProperties).colors;
|
||||
const brandColors = useSelector(getBrandColors);
|
||||
const widgets = useSelector(getWidgets);
|
||||
const DSLStringified = JSON.stringify(widgets);
|
||||
const applicationColors = useMemo(() => {
|
||||
return extractColorsFromString(DSLStringified);
|
||||
}, [DSLStringified]);
|
||||
return extractColorsFromString(widgets);
|
||||
}, []);
|
||||
const {
|
||||
changeColor,
|
||||
color,
|
||||
|
|
@ -169,7 +182,7 @@ function ColorPickerPopup(props: ColorPickerPopupProps) {
|
|||
<h2 className="pb-2 font-semibold border-b">Color Styles</h2>
|
||||
<section className="space-y-2">
|
||||
<h3 className="text-xs">Theme Colors</h3>
|
||||
<div className="grid grid-cols-10 gap-2">
|
||||
<div className="grid grid-cols-5 gap-2">
|
||||
{Object.keys(themeColors).map((colorKey, colorIndex) => (
|
||||
<div
|
||||
className={`${COLOR_BOX_CLASSES} ${
|
||||
|
|
@ -199,7 +212,7 @@ function ColorPickerPopup(props: ColorPickerPopupProps) {
|
|||
{brandColors && Object.keys(brandColors).length > 0 && (
|
||||
<section className="space-y-2">
|
||||
<h3 className="text-xs">Brand Colors</h3>
|
||||
<div className="grid grid-cols-10 gap-2">
|
||||
<div className="grid grid-cols-5 gap-2">
|
||||
{Object.keys(brandColors).map(
|
||||
(colorKey: string, colorIndex: number) => (
|
||||
<div
|
||||
|
|
@ -223,7 +236,7 @@ function ColorPickerPopup(props: ColorPickerPopupProps) {
|
|||
{showApplicationColors && applicationColors.length > 0 && (
|
||||
<section className="space-y-2">
|
||||
<h3 className="text-xs">Application Colors</h3>
|
||||
<div className="grid grid-cols-10 gap-2">
|
||||
<div className="grid grid-cols-5 gap-2">
|
||||
{Object.values(applicationColors).map(
|
||||
(colorCode: string, colorIndex) => (
|
||||
<div
|
||||
|
|
@ -246,8 +259,15 @@ function ColorPickerPopup(props: ColorPickerPopupProps) {
|
|||
)}
|
||||
|
||||
<section className="space-y-2">
|
||||
<h3 className="text-xs">All Colors</h3>
|
||||
<div className="grid grid-cols-10 gap-2 t--tailwind-colors">
|
||||
{(showThemeColors ||
|
||||
(brandColors && Object.keys(brandColors).length > 0) ||
|
||||
(showApplicationColors && applicationColors.length > 0)) && (
|
||||
<h3 className="text-xs">All Colors</h3>
|
||||
)}
|
||||
<div
|
||||
className="grid grid-cols-5 gap-2 t--tailwind-colors"
|
||||
data-testid="t--all-colors"
|
||||
>
|
||||
{Object.keys(TAILWIND_COLORS).map((colorKey, rowIndex) =>
|
||||
Object.keys(get(TAILWIND_COLORS, `${colorKey}`)).map(
|
||||
(singleColorKey, colIndex) => (
|
||||
|
|
@ -275,27 +295,6 @@ function ColorPickerPopup(props: ColorPickerPopupProps) {
|
|||
),
|
||||
),
|
||||
)}
|
||||
|
||||
<div
|
||||
className={`${COLOR_BOX_CLASSES} ${
|
||||
color === "#fff" ? "ring-1" : ""
|
||||
}`}
|
||||
onClick={(e) => {
|
||||
setColor("#fff");
|
||||
changeColor("#fff", !e.isTrusted);
|
||||
}}
|
||||
tabIndex={-1}
|
||||
/>
|
||||
<div
|
||||
className={`${COLOR_BOX_CLASSES} diagnol-cross ${
|
||||
color === "transparent" ? "ring-1" : ""
|
||||
}`}
|
||||
onClick={(e) => {
|
||||
setColor("transparent");
|
||||
changeColor("transparent", !e.isTrusted);
|
||||
}}
|
||||
tabIndex={-1}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</PopupContainer>
|
||||
|
|
@ -329,7 +328,7 @@ interface LeftIconProps {
|
|||
}
|
||||
|
||||
function LeftIcon(props: LeftIconProps) {
|
||||
return props.color ? (
|
||||
return isValidColor(props.color) ? (
|
||||
<ColorIcon
|
||||
className="rounded-full cursor-pointer"
|
||||
color={props.color}
|
||||
|
|
@ -365,6 +364,8 @@ const ColorPickerComponent = React.forwardRef(
|
|||
props.evaluatedColorValue || props.color,
|
||||
);
|
||||
|
||||
const [isFullColorPicker, setFullColorPicker] = React.useState(false);
|
||||
|
||||
const debouncedOnChange = React.useCallback(
|
||||
debounce((color: string, isUpdatedViaKeyboard: boolean) => {
|
||||
props.changeColor(color, isUpdatedViaKeyboard);
|
||||
|
|
@ -417,7 +418,6 @@ const ColorPickerComponent = React.forwardRef(
|
|||
}
|
||||
break;
|
||||
case "Enter":
|
||||
case " ":
|
||||
emitKeyPressEvent(e.key);
|
||||
(document.activeElement as any)?.click();
|
||||
setTimeout(() => {
|
||||
|
|
@ -530,7 +530,9 @@ const ColorPickerComponent = React.forwardRef(
|
|||
|
||||
const handleChangeColor = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = event.target.value;
|
||||
debouncedOnChange(value, true);
|
||||
if (isValidColor(value)) {
|
||||
debouncedOnChange(value, true);
|
||||
}
|
||||
setColor(value);
|
||||
};
|
||||
|
||||
|
|
@ -544,9 +546,20 @@ const ColorPickerComponent = React.forwardRef(
|
|||
|
||||
const handleInputClick = () => {
|
||||
isClick.current = true;
|
||||
|
||||
if (isFullColorPicker && isOpen) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFullColorPickerClick = (value: boolean) => {
|
||||
setFullColorPicker(value);
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
const handleOnInteraction = (nextOpenState: boolean) => {
|
||||
if (isFullColorPicker && !isOpen) return;
|
||||
|
||||
if (isOpen !== nextOpenState) {
|
||||
if (isClick.current) setIsOpen(true);
|
||||
else setIsOpen(nextOpenState);
|
||||
|
|
@ -567,19 +580,26 @@ const ColorPickerComponent = React.forwardRef(
|
|||
isOpen={isOpen}
|
||||
minimal
|
||||
modifiers={POPOVER_MODFIER}
|
||||
onClosed={props.onPopupClosed}
|
||||
onInteraction={handleOnInteraction}
|
||||
popoverClassName="color-picker-input"
|
||||
portalContainer={props.portalContainer}
|
||||
>
|
||||
<StyledInputGroup
|
||||
$isFullColorPicker={isFullColorPicker}
|
||||
$isValid={isValidColor(color)}
|
||||
autoFocus={props.autoFocus}
|
||||
data-testid="t--color-picker-input"
|
||||
inputRef={inputGroupRef}
|
||||
leftIcon={
|
||||
<LeftIcon color={color} handleInputClick={handleInputClick} />
|
||||
!isFullColorPicker ? (
|
||||
<LeftIcon color={color} handleInputClick={handleInputClick} />
|
||||
) : null
|
||||
}
|
||||
onChange={handleChangeColor}
|
||||
onClick={handleInputClick}
|
||||
placeholder={placeholderText || "enter color name or hex"}
|
||||
type={isFullColorPicker ? "color" : "text"}
|
||||
value={color}
|
||||
/>
|
||||
|
||||
|
|
@ -593,6 +613,14 @@ const ColorPickerComponent = React.forwardRef(
|
|||
showThemeColors={props.showThemeColors}
|
||||
/>
|
||||
</Popover>
|
||||
<div className="mt-2">
|
||||
<Switch
|
||||
isSelected={isFullColorPicker}
|
||||
onChange={handleFullColorPickerClick}
|
||||
>
|
||||
{createMessage(FULL_COLOR_PICKER_LABEL)}
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -13,101 +13,54 @@ export type TailwindColors = {
|
|||
|
||||
export const TAILWIND_COLORS: TailwindColors = {
|
||||
gray: {
|
||||
50: "#fafafa",
|
||||
100: "#f4f4f5",
|
||||
200: "#e4e4e7",
|
||||
300: "#d4d4d8",
|
||||
400: "#a1a1aa",
|
||||
500: "#71717a",
|
||||
600: "#52525b",
|
||||
700: "#3f3f46",
|
||||
800: "#27272a",
|
||||
900: "#18181b",
|
||||
},
|
||||
red: {
|
||||
50: "#fef2f2",
|
||||
100: "#fee2e2",
|
||||
200: "#fecaca",
|
||||
300: "#fca5a5",
|
||||
400: "#f87171",
|
||||
500: "#ef4444",
|
||||
600: "#dc2626",
|
||||
700: "#b91c1c",
|
||||
800: "#991b1b",
|
||||
900: "#7f1d1d",
|
||||
},
|
||||
|
||||
yellow: {
|
||||
50: "#fefce8",
|
||||
100: "#fef9c3",
|
||||
200: "#fef08a",
|
||||
300: "#fde047",
|
||||
400: "#facc15",
|
||||
500: "#eab308",
|
||||
600: "#ca8a04",
|
||||
700: "#a16207",
|
||||
800: "#854d0e",
|
||||
900: "#713f12",
|
||||
},
|
||||
|
||||
green: {
|
||||
50: "#f0fdf4",
|
||||
100: "#dcfce7",
|
||||
200: "#bbf7d0",
|
||||
300: "#86efac",
|
||||
400: "#4ade80",
|
||||
500: "#22c55e",
|
||||
600: "#16a34a",
|
||||
700: "#15803d",
|
||||
800: "#166534",
|
||||
900: "#14532d",
|
||||
},
|
||||
blue: {
|
||||
50: "#eff6ff",
|
||||
100: "#dbeafe",
|
||||
200: "#bfdbfe",
|
||||
300: "#93c5fd",
|
||||
400: "#60a5fa",
|
||||
500: "#3b82f6",
|
||||
600: "#2563eb",
|
||||
700: "#1d4ed8",
|
||||
800: "#1e40af",
|
||||
900: "#1e3a8a",
|
||||
},
|
||||
indigo: {
|
||||
50: "#eef2ff",
|
||||
100: "#e0e7ff",
|
||||
200: "#c7d2fe",
|
||||
300: "#a5b4fc",
|
||||
400: "#818cf8",
|
||||
500: "#6366f1",
|
||||
600: "#4f46e5",
|
||||
700: "#4338ca",
|
||||
800: "#3730a3",
|
||||
900: "#312e81",
|
||||
},
|
||||
purple: {
|
||||
50: "#faf5ff",
|
||||
100: "#f3e8ff",
|
||||
200: "#e9d5ff",
|
||||
300: "#d8b4fe",
|
||||
400: "#c084fc",
|
||||
500: "#a855f7",
|
||||
600: "#9333ea",
|
||||
700: "#7e22ce",
|
||||
800: "#6b21a8",
|
||||
900: "#581c87",
|
||||
},
|
||||
pink: {
|
||||
50: "#fdf2f8",
|
||||
100: "#fce7f3",
|
||||
200: "#fbcfe8",
|
||||
300: "#f9a8d4",
|
||||
400: "#f472b6",
|
||||
500: "#ec4899",
|
||||
600: "#db2777",
|
||||
700: "#be185d",
|
||||
800: "#9d174d",
|
||||
900: "#831843",
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ function ThemeColorControl(props: ThemeColorControlProps) {
|
|||
color={userDefinedColors[selectedColor]}
|
||||
isOpen={autoFocus}
|
||||
key={selectedColor}
|
||||
onPopupClosed={() => setAutoFocus(false)}
|
||||
portalContainer={
|
||||
document.getElementById("app-settings-portal") || undefined
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { RenderModes } from "constants/WidgetConstants";
|
||||
import { ValidationTypes } from "constants/WidgetValidation";
|
||||
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
|
||||
import type { CanvasWidgetsReduxState } from "../reducers/entityReducers/canvasWidgetsReducer";
|
||||
import { AutocompleteDataType } from "./autocomplete/AutocompleteDataType";
|
||||
import {
|
||||
flattenObject,
|
||||
|
|
@ -550,20 +551,30 @@ describe("#captureInvalidDynamicBindingPath", () => {
|
|||
|
||||
describe("#extractColorsFromString", () => {
|
||||
it("Check if the extractColorsFromString returns rgb, rgb, hex color strings", () => {
|
||||
const borderWithHex = `2px solid ${Colors.GREEN}`;
|
||||
const borderWithRgb = "2px solid rgb(0,0,0)";
|
||||
const borderWithRgba = `2px solid ${Colors.BOX_SHADOW_DEFAULT_VARIANT1}`;
|
||||
const widgets = {
|
||||
0: { color: `${Colors.GREEN}` },
|
||||
1: { color: "rgb(0,0,0)" },
|
||||
2: { color: `${Colors.BOX_SHADOW_DEFAULT_VARIANT1}` },
|
||||
3: { color: `LightGoldenrodYellow` },
|
||||
4: { color: `lch(54.292% 106.839 40.853)` },
|
||||
} as unknown as CanvasWidgetsReduxState;
|
||||
|
||||
//Check Hex value
|
||||
expect(extractColorsFromString(borderWithHex)[0]).toEqual("#03b365");
|
||||
|
||||
//Check rgba value
|
||||
expect(extractColorsFromString(borderWithRgba)[0]).toEqual(
|
||||
"rgba(0, 0, 0, 0.25)",
|
||||
);
|
||||
expect(extractColorsFromString(widgets)[0]).toEqual("#03B365");
|
||||
|
||||
//Check rgb
|
||||
expect(extractColorsFromString(borderWithRgb)[0]).toEqual("rgb(0,0,0)");
|
||||
expect(extractColorsFromString(widgets)[1]).toEqual("rgb(0,0,0)");
|
||||
|
||||
//Check rgba value
|
||||
expect(extractColorsFromString(widgets)[2]).toEqual("rgba(0, 0, 0, 0.25)");
|
||||
|
||||
//Check name value
|
||||
expect(extractColorsFromString(widgets)[3]).toEqual("LightGoldenrodYellow");
|
||||
|
||||
//Check lch value
|
||||
expect(extractColorsFromString(widgets)[4]).toEqual(
|
||||
"lch(54.292% 106.839 40.853)",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import type { ContainerWidgetProps } from "widgets/ContainerWidget/widget";
|
|||
import type { WidgetProps } from "widgets/BaseWidget";
|
||||
import { getContainerIdForCanvas } from "sagas/WidgetOperationUtils";
|
||||
import scrollIntoView from "scroll-into-view-if-needed";
|
||||
import validateColor from "validate-color";
|
||||
|
||||
export const snapToGrid = (
|
||||
columnWidth: number,
|
||||
|
|
@ -757,28 +758,36 @@ export function getLogToSentryFromResponse(response?: ApiResponse) {
|
|||
return response && response?.responseMeta?.status >= 500;
|
||||
}
|
||||
|
||||
const BLACKLIST_COLORS = ["#ffffff"];
|
||||
const HEX_REGEX = /#[0-9a-fA-F]{6}/gi;
|
||||
const RGB_REGEX = /rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)/gi;
|
||||
|
||||
/**
|
||||
* extract colors from string
|
||||
*
|
||||
* @param text
|
||||
* @returns
|
||||
* @param widgets
|
||||
*/
|
||||
export function extractColorsFromString(text: string) {
|
||||
export function extractColorsFromString(widgets: CanvasWidgetsReduxState) {
|
||||
const colors = new Set();
|
||||
|
||||
[...(text.match(RGB_REGEX) || []), ...(text.match(HEX_REGEX) || [])]
|
||||
.filter((d) => BLACKLIST_COLORS.indexOf(d.toLowerCase()) === -1)
|
||||
.forEach((color) => {
|
||||
colors.add(color.toLowerCase());
|
||||
Object.values(widgets).forEach((widget) => {
|
||||
Object.values(widget).forEach((widgetProp) => {
|
||||
if (isString(widgetProp) && validateColor(widgetProp)) {
|
||||
colors.add(widgetProp);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return Array.from(colors) as Array<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate color string
|
||||
*
|
||||
* @returns {boolean} true if string is valid color or includes url
|
||||
* @param color
|
||||
*/
|
||||
export function isValidColor(color: string) {
|
||||
return color?.includes("url") || validateColor(color);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to merge property pane config of a widget
|
||||
*
|
||||
|
|
|
|||
|
|
@ -9589,6 +9589,7 @@ __metadata:
|
|||
unescape-js: ^1.1.4
|
||||
url-search-params-polyfill: ^8.0.0
|
||||
uuid: ^9.0.0
|
||||
validate-color: ^2.2.4
|
||||
webfontloader: ^1.6.28
|
||||
webpack-merge: ^5.8.0
|
||||
webpack-retry-chunk-load-plugin: ^3.1.1
|
||||
|
|
@ -28934,6 +28935,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"validate-color@npm:^2.2.4":
|
||||
version: 2.2.4
|
||||
resolution: "validate-color@npm:2.2.4"
|
||||
checksum: ac9109e6347797300fd0a0b08d623acaf3cc295cc2077b9041119582c632eb56dc78e94b8f7f929754508974a8a0b63d296995106a20b237b3be5e89ff2c80f1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"validate-npm-package-license@npm:^3.0.1":
|
||||
version: 3.0.4
|
||||
resolution: "validate-npm-package-license@npm:3.0.4"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user