diff --git a/src/components/color_picker/color_picker.css b/src/components/color_picker/color_picker.css index 5637ab2786..2e55e0f8f5 100644 --- a/src/components/color_picker/color_picker.css +++ b/src/components/color_picker/color_picker.css @@ -31,9 +31,12 @@ } } } + + --color-picker-item-size: calc(var(--os-item-edge-length) + (2 * var(--os-item-border-width))); + .o-color-picker-line-item { - width: calc(var(--os-item-edge-length) + (2 * var(--os-item-border-width))); - height: calc(var(--os-item-edge-length) + (2 * var(--os-item-border-width))); + width: var(--color-picker-item-size); + height: var(--color-picker-item-size); margin: 0px; border-radius: 50px; border: var(--os-item-border-width) solid light-dark(var(--os-gray-600), #c0c0c0); @@ -45,6 +48,18 @@ cursor: pointer; } } + .eyedropper { + width: var(--color-picker-item-size); + height: var(--color-picker-item-size); + &:hover { + background-color: var(--os-hovered-menu-item-color); + color: var(--os-button-active-text-color); + cursor: pointer; + } + .fa { + font-size: 13px; + } + } .o-buttons { padding: var(--os-picker-padding); display: flex; diff --git a/src/components/color_picker/color_picker.ts b/src/components/color_picker/color_picker.ts index 1aa06081b9..f1cd78fc9b 100644 --- a/src/components/color_picker/color_picker.ts +++ b/src/components/color_picker/color_picker.ts @@ -212,4 +212,25 @@ export class ColorPicker extends ComponentCustom
-
-
- -
-
+
+
+ +
+
+
+ +
; } + +interface EyeDropperConstructor { + new (): EyeDropper; +} + +declare var EyeDropper: EyeDropperConstructor | undefined; diff --git a/src/helpers/figures/charts/runtime/chartjs_scales.ts b/src/helpers/figures/charts/runtime/chartjs_scales.ts index ab30d72452..94d50480c0 100644 --- a/src/helpers/figures/charts/runtime/chartjs_scales.ts +++ b/src/helpers/figures/charts/runtime/chartjs_scales.ts @@ -464,7 +464,7 @@ export function getFunnelChartScales( } function getGeoChartProjection(projection: GeoChartProjection) { - if (projection === "conicConformal") { + if (globalThis.ChartGeo && projection === "conicConformal") { return globalThis.ChartGeo.geoConicConformal().rotate([100, 0]); // Centered on the US } return projection; diff --git a/src/plugins/ui_feature/geo_features.ts b/src/plugins/ui_feature/geo_features.ts index 2d2293bbbb..c7c2db0172 100644 --- a/src/plugins/ui_feature/geo_features.ts +++ b/src/plugins/ui_feature/geo_features.ts @@ -132,10 +132,10 @@ export class GeoFeaturePlugin extends UIPlugin { } // TopoJSON if (json.type === "Topology") { - const features = (globalThis as any).ChartGeo.topojson.feature( - json, - Object.values(json.objects)[0] - ); + if (!globalThis.ChartGeo) { + return null; + } + const features = globalThis.ChartGeo.topojson.feature(json, Object.values(json.objects)[0]); return features.type === "FeatureCollection" ? features.features : [features]; } // GeoJSON diff --git a/src/types/chart/chartjs_global_augmentation.d.ts b/src/types/chart/chartjs_global_augmentation.d.ts deleted file mode 100644 index bdf0c7568f..0000000000 --- a/src/types/chart/chartjs_global_augmentation.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -// This file is a script-mode ambient declaration (no imports/exports). -// It augments the global scope for TypeScript type checking without being -// included in the rollup-plugin-dts bundle (unreachable from module graph). -declare var Chart: import("./chartjs").GlobalChart | undefined; diff --git a/tests/colors/__snapshots__/color_picker_component.test.ts.snap b/tests/colors/__snapshots__/color_picker_component.test.ts.snap index b3ba35ea36..308aef3928 100644 --- a/tests/colors/__snapshots__/color_picker_component.test.ts.snap +++ b/tests/colors/__snapshots__/color_picker_component.test.ts.snap @@ -435,6 +435,8 @@ exports[`Color Picker buttons Full component rendering 1`] = `
+ +
@@ -453,7 +455,13 @@ exports[`Color Picker buttons Full component rendering 1`] = `
- +
+ +
delete globalThis.EyeDropper); +} + async function mountColorPicker(partialProps: Partial = {}, model = new Model()) { const props = { onColorPicked: partialProps.onColorPicked || (() => {}), @@ -20,6 +30,7 @@ async function mountColorPicker(partialProps: Partial = {}, mo disableNoColor: partialProps.disableNoColor || false, }; ({ fixture } = await mountComponentWithPortalTarget(ColorPicker, { model, props })); + return model; } test("Color picker is correctly positioned", async () => { @@ -48,6 +59,7 @@ describe("Color Picker buttons", () => { }); test("Full component rendering", async () => { + addMockEyeDropperSupport("#123456"); await mountColorPicker(); await simulateClick(".o-color-picker-toggler-sign"); expect(fixture.querySelector(".o-color-picker")).toMatchSnapshot(); @@ -203,4 +215,29 @@ describe("Color Picker buttons", () => { const addButton = fixture.querySelector(".o-add-button")!; expect(addButton.classList).toContain("o-disabled"); }); + + test("Eye dropper button is not there if the EyeDropper API is not present", async () => { + await mountColorPicker(); + expect(".eyedropper").toHaveCount(0); + }); + + test("Eye dropper button is not there in dark mode", async () => { + // In dark mode we'd have to do the opposite color inversion than then dark mode color inversion to get the correct color. + // But this mathematically cannot always be done, because our color inversion lose information with clipping and rounding. + addMockEyeDropperSupport("#abc123"); + const model = await mountColorPicker({}); + expect(".eyedropper").toHaveCount(1); + + model.dispatch("UPDATE_COLOR_SCHEME", { colorScheme: "dark" }); + await nextTick(); + expect(".eyedropper").toHaveCount(0); + }); + + test("Can pick a custom color with the eye dropper", async () => { + addMockEyeDropperSupport("#abc123"); + const onColorPicked = jest.fn(); + await mountColorPicker({ onColorPicked }); + await simulateClick(".eyedropper"); + expect(onColorPicked).toHaveBeenCalledWith("#ABC123"); + }); });