From 4eee3ac386914729ffa57f6d8b8a626f73c13a7f Mon Sep 17 00:00:00 2001 From: Tom Hicks Date: Thu, 2 Oct 2025 15:44:26 +0200 Subject: [PATCH 1/2] Add basemaps API --- docs/Basemaps/Basemap.md | 3 + docs/Basemaps/BasemapsController.md | 193 +++++++++ docs/Basemaps/ColorBasemap.md | 51 +++ docs/Basemaps/ColorBasemapInput.md | 3 + docs/Basemaps/CustomTileBasemap.md | 51 +++ docs/Basemaps/CustomTileBasemapInput.md | 3 + docs/Basemaps/FeltBasemap.md | 51 +++ docs/Basemaps/README.md | 21 + docs/Elements/NoteElementCreate.md | 2 +- docs/Elements/NoteElementRead.md | 2 +- docs/Elements/NoteElementUpdate.md | 2 +- docs/Elements/TextElementCreate.md | 2 +- docs/Elements/TextElementRead.md | 2 +- docs/Elements/TextElementUpdate.md | 2 +- docs/Layers/AggregatedGridConfig.md | 2 +- docs/Layers/AggregationConfig.md | 2 +- docs/Layers/AggregationMethod.md | 2 +- docs/Layers/GetLayerHistogramParams.md | 6 +- docs/Layers/LayersController.md | 2 +- docs/Layers/PrecomputedAggregationMethod.md | 2 +- docs/Main/FeltController.md | 187 ++++++++- docs/README.md | 1 + docs/Tools/NoteToolSettings.md | 2 +- docs/Tools/TextToolSettings.md | 2 +- etc/js-sdk.api.md | 431 ++++++++++---------- src/client.ts | 1 + src/modules/basemaps/controller.ts | 153 +++++++ src/modules/basemaps/index.ts | 16 + src/modules/basemaps/schema.ts | 59 +++ src/modules/basemaps/type-tests.ts | 56 +++ src/modules/basemaps/types.ts | 55 +++ src/modules/main/controller.ts | 8 +- src/modules/main/schema.ts | 5 +- 33 files changed, 1155 insertions(+), 225 deletions(-) create mode 100644 docs/Basemaps/Basemap.md create mode 100644 docs/Basemaps/BasemapsController.md create mode 100644 docs/Basemaps/ColorBasemap.md create mode 100644 docs/Basemaps/ColorBasemapInput.md create mode 100644 docs/Basemaps/CustomTileBasemap.md create mode 100644 docs/Basemaps/CustomTileBasemapInput.md create mode 100644 docs/Basemaps/FeltBasemap.md create mode 100644 docs/Basemaps/README.md create mode 100644 src/modules/basemaps/controller.ts create mode 100644 src/modules/basemaps/index.ts create mode 100644 src/modules/basemaps/schema.ts create mode 100644 src/modules/basemaps/type-tests.ts create mode 100644 src/modules/basemaps/types.ts diff --git a/docs/Basemaps/Basemap.md b/docs/Basemaps/Basemap.md new file mode 100644 index 00000000..f6b5809b --- /dev/null +++ b/docs/Basemaps/Basemap.md @@ -0,0 +1,3 @@ +*** + +> **Basemap**: [`FeltBasemap`](FeltBasemap.md) | [`ColorBasemap`](ColorBasemap.md) | [`CustomTileBasemap`](CustomTileBasemap.md) diff --git a/docs/Basemaps/BasemapsController.md b/docs/Basemaps/BasemapsController.md new file mode 100644 index 00000000..71d4559f --- /dev/null +++ b/docs/Basemaps/BasemapsController.md @@ -0,0 +1,193 @@ +*** + +The basemaps controller allows you to manage the map's basemap layer. + +You can get the current basemap, list available basemaps, change the basemap, +and be notified when the basemap changes. + +# Extended by + +* [`FeltController`](../Main/FeltController.md) + +# Methods + +## getCurrentBasemap() + +> **getCurrentBasemap**(): `Promise`\<[`Basemap`](Basemap.md)> + +Gets the currently active basemap. + +Use this method to retrieve information about the current basemap, including +its type (Felt, color, or custom tile), name, color scheme, and attribution. + +### Returns + +`Promise`\<[`Basemap`](Basemap.md)> + +A promise that resolves to the current basemap configuration. + +### Example + +```typescript +// Get current basemap +const basemap = await felt.getCurrentBasemap(); +console.log({ + name: basemap.name, + type: basemap.type, + uiColorScheme: basemap.uiColorScheme, +}); +``` + +*** + +## getBasemaps() + +> **getBasemaps**(): `Promise`\<[`Basemap`](Basemap.md)\[]> + +Gets all basemaps available on the map. + +Use this method to retrieve a list of all available basemaps that can be +applied to the map. + +### Returns + +`Promise`\<[`Basemap`](Basemap.md)\[]> + +A promise that resolves to all basemaps available on the map. + +### Example + +```typescript +// Get all available basemaps +const basemaps = await felt.getBasemaps(); +const lightBasemaps = basemaps.filter(b => b.uiColorScheme === "light"); +``` + +*** + +## chooseBasemap() + +> **chooseBasemap**(`id`: `string`): `void` + +Chooses the basemap to use for the map. + +Use this method to change the current basemap. The basemap ID can be obtained +from getBasemaps(). + +### Parameters + +| Parameter | Type | +| --------- | -------- | +| `id` | `string` | + +### Returns + +`void` + +A promise that resolves when the basemap has been set. + +### Example + +```typescript +// Switch to a specific basemap +const basemaps = await felt.getBasemaps(); +const darkBasemap = basemaps.find(b => b.uiColorScheme === "dark"); +if (darkBasemap) { + await felt.chooseBasemap(darkBasemap.id); +} +``` + +*** + +## addCustomBasemap() + +> **addCustomBasemap**(`args`: \{ `basemap`: [`ColorBasemapInput`](ColorBasemapInput.md) | [`CustomTileBasemapInput`](CustomTileBasemapInput.md); `select`: `boolean`; }): `Promise`\<[`Basemap`](Basemap.md)> + +Adds a custom basemap to the map. This can be either a solid color or a basemap +from a custom tile URL. + +### Parameters + +| Parameter | Type | Description | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------- | +| `args` | \{ `basemap`: [`ColorBasemapInput`](ColorBasemapInput.md) \| [`CustomTileBasemapInput`](CustomTileBasemapInput.md); `select`: `boolean`; } | - | +| `args.basemap` | [`ColorBasemapInput`](ColorBasemapInput.md) \| [`CustomTileBasemapInput`](CustomTileBasemapInput.md) | The basemap to add. | +| `args.select`? | `boolean` | Whether to select the basemap after adding it. | + +### Returns + +`Promise`\<[`Basemap`](Basemap.md)> + +A promise for the added basemap. + +### Example + +```typescript +// Add a custom basemap and select it +await felt.addCustomBasemap({ + basemap: { + type: "xyz_tile", + tileUrl: "https://example.com/tile.png" + }, + select: true, +}); +``` + +*** + +## removeBasemap() + +> **removeBasemap**(`id`: `string`): `Promise`\<`void`> + +Removes a basemap from the list of available basemaps. + +### Parameters + +| Parameter | Type | +| --------- | -------- | +| `id` | `string` | + +### Returns + +`Promise`\<`void`> + +A promise that resolves when the basemap has been removed. + +# Events + +## onBasemapChange() + +> **onBasemapChange**(`args`: \{ `handler`: (`basemap`: [`Basemap`](Basemap.md)) => `void`; }): `VoidFunction` + +Adds a listener for when the basemap changes. + +Use this to react to basemap changes, such as updating your UI or +adjusting other map elements to match the new basemap's color scheme. + +### Parameters + +| Parameter | Type | +| -------------- | --------------------------------------------------------------- | +| `args` | \{ `handler`: (`basemap`: [`Basemap`](Basemap.md)) => `void`; } | +| `args.handler` | (`basemap`: [`Basemap`](Basemap.md)) => `void` | + +### Returns + +`VoidFunction` + +A function to unsubscribe from the listener. + +### Example + +```typescript +// Listen for basemap changes +const unsubscribe = felt.onBasemapChange({ + handler: basemap => { + console.log(`Switched to ${basemap.name}`); + updateUIColors(basemap.uiColorScheme); + }, +}); + +// later on... +unsubscribe(); +``` diff --git a/docs/Basemaps/ColorBasemap.md b/docs/Basemaps/ColorBasemap.md new file mode 100644 index 00000000..a14f0127 --- /dev/null +++ b/docs/Basemaps/ColorBasemap.md @@ -0,0 +1,51 @@ +*** + +# Properties + +## id + +> **id**: `string` + +A unique identifier for the basemap. + +### Remarks + +Do not rely on the stability of this ID for Felt basemaps, as they are +subject to change. + +*** + +## name + +> **name**: `string` + +The name of the basemap. + +*** + +## uiColorScheme + +> **uiColorScheme**: `"light"` | `"dark"` + +The color scheme of the UI that goes with the basemap. It is best to set this to +"light" if your basemap is broadly light, and "dark" if your basemap is broadly dark. + +*** + +## type + +> **type**: `"color"` + +*** + +## color + +> **color**: `string` + +*** + +## attribution? + +> `optional` **attribution**: `string` + +The attribution of the basemap, which is shown in the map's UI. diff --git a/docs/Basemaps/ColorBasemapInput.md b/docs/Basemaps/ColorBasemapInput.md new file mode 100644 index 00000000..30accc1c --- /dev/null +++ b/docs/Basemaps/ColorBasemapInput.md @@ -0,0 +1,3 @@ +*** + +> **ColorBasemapInput**: `Omit`\<[`ColorBasemap`](ColorBasemap.md), `"id"`> diff --git a/docs/Basemaps/CustomTileBasemap.md b/docs/Basemaps/CustomTileBasemap.md new file mode 100644 index 00000000..51a1ddb5 --- /dev/null +++ b/docs/Basemaps/CustomTileBasemap.md @@ -0,0 +1,51 @@ +*** + +# Properties + +## id + +> **id**: `string` + +A unique identifier for the basemap. + +### Remarks + +Do not rely on the stability of this ID for Felt basemaps, as they are +subject to change. + +*** + +## name + +> **name**: `string` + +The name of the basemap. + +*** + +## uiColorScheme + +> **uiColorScheme**: `"light"` | `"dark"` + +The color scheme of the UI that goes with the basemap. It is best to set this to +"light" if your basemap is broadly light, and "dark" if your basemap is broadly dark. + +*** + +## type + +> **type**: `"xyz_tile"` + +*** + +## tileUrl + +> **tileUrl**: `string` + +*** + +## attribution? + +> `optional` **attribution**: `string` + +The attribution of the basemap, which is shown in the map's UI. diff --git a/docs/Basemaps/CustomTileBasemapInput.md b/docs/Basemaps/CustomTileBasemapInput.md new file mode 100644 index 00000000..1837175d --- /dev/null +++ b/docs/Basemaps/CustomTileBasemapInput.md @@ -0,0 +1,3 @@ +*** + +> **CustomTileBasemapInput**: `Omit`\<[`CustomTileBasemap`](CustomTileBasemap.md), `"id"`> diff --git a/docs/Basemaps/FeltBasemap.md b/docs/Basemaps/FeltBasemap.md new file mode 100644 index 00000000..d130e584 --- /dev/null +++ b/docs/Basemaps/FeltBasemap.md @@ -0,0 +1,51 @@ +*** + +# Properties + +## id + +> **id**: `string` + +A unique identifier for the basemap. + +### Remarks + +Do not rely on the stability of this ID for Felt basemaps, as they are +subject to change. + +*** + +## name + +> **name**: `string` + +The name of the basemap. + +*** + +## uiColorScheme + +> **uiColorScheme**: `"light"` | `"dark"` + +The color scheme of the UI that goes with the basemap. It is best to set this to +"light" if your basemap is broadly light, and "dark" if your basemap is broadly dark. + +*** + +## type + +> **type**: `"felt"` + +*** + +## theme + +> **theme**: `"color_light"` | `"monochrome_dark"` | `"monochrome_light"` | `"satellite"` + +*** + +## attribution? + +> `optional` **attribution**: `string` + +The attribution of the basemap, which is shown in the map's UI. diff --git a/docs/Basemaps/README.md b/docs/Basemaps/README.md new file mode 100644 index 00000000..be015597 --- /dev/null +++ b/docs/Basemaps/README.md @@ -0,0 +1,21 @@ +*** + +The Basemaps module allows you to control the map's basemap layer, such as getting +the current basemap, listing available basemaps, changing the basemap, and being +notified when the basemap changes. + +# Controller + +* [BasemapsController](BasemapsController.md) + +# Interfaces + +* [FeltBasemap](FeltBasemap.md) +* [ColorBasemap](ColorBasemap.md) +* [CustomTileBasemap](CustomTileBasemap.md) + +# Type Aliases + +* [ColorBasemapInput](ColorBasemapInput.md) +* [CustomTileBasemapInput](CustomTileBasemapInput.md) +* [Basemap](Basemap.md) diff --git a/docs/Elements/NoteElementCreate.md b/docs/Elements/NoteElementCreate.md index 00206cca..b9cb0c62 100644 --- a/docs/Elements/NoteElementCreate.md +++ b/docs/Elements/NoteElementCreate.md @@ -151,7 +151,7 @@ The alignment of the text, either `left`, `center` or `right`. ## style? -> `optional` **style**: `"italic"` | `"light"` | `"regular"` | `"caps"` +> `optional` **style**: `"light"` | `"italic"` | `"regular"` | `"caps"` The style of the text, either `italic`, `light`, `regular` or `caps`. diff --git a/docs/Elements/NoteElementRead.md b/docs/Elements/NoteElementRead.md index ee013eed..ccbc529a 100644 --- a/docs/Elements/NoteElementRead.md +++ b/docs/Elements/NoteElementRead.md @@ -130,7 +130,7 @@ The alignment of the text, either `left`, `center` or `right`. ## style -> **style**: `"italic"` | `"light"` | `"regular"` | `"caps"` +> **style**: `"light"` | `"italic"` | `"regular"` | `"caps"` The style of the text, either `italic`, `light`, `regular` or `caps`. diff --git a/docs/Elements/NoteElementUpdate.md b/docs/Elements/NoteElementUpdate.md index 799079dc..5afd60a7 100644 --- a/docs/Elements/NoteElementUpdate.md +++ b/docs/Elements/NoteElementUpdate.md @@ -161,7 +161,7 @@ The alignment of the text, either `left`, `center` or `right`. ## style? -> `optional` **style**: `"italic"` | `"light"` | `"regular"` | `"caps"` +> `optional` **style**: `"light"` | `"italic"` | `"regular"` | `"caps"` The style of the text, either `italic`, `light`, `regular` or `caps`. diff --git a/docs/Elements/TextElementCreate.md b/docs/Elements/TextElementCreate.md index 5cf5f0f4..1975f782 100644 --- a/docs/Elements/TextElementCreate.md +++ b/docs/Elements/TextElementCreate.md @@ -151,7 +151,7 @@ The alignment of the text, either `left`, `center` or `right`. ## style? -> `optional` **style**: `"italic"` | `"light"` | `"regular"` | `"caps"` +> `optional` **style**: `"light"` | `"italic"` | `"regular"` | `"caps"` The style of the text, either `italic`, `light`, `regular` or `caps`. diff --git a/docs/Elements/TextElementRead.md b/docs/Elements/TextElementRead.md index d09200e0..231576db 100644 --- a/docs/Elements/TextElementRead.md +++ b/docs/Elements/TextElementRead.md @@ -130,7 +130,7 @@ The alignment of the text, either `left`, `center` or `right`. ## style -> **style**: `"italic"` | `"light"` | `"regular"` | `"caps"` +> **style**: `"light"` | `"italic"` | `"regular"` | `"caps"` The style of the text, either `italic`, `light`, `regular` or `caps`. diff --git a/docs/Elements/TextElementUpdate.md b/docs/Elements/TextElementUpdate.md index 5050cca0..5d59c05a 100644 --- a/docs/Elements/TextElementUpdate.md +++ b/docs/Elements/TextElementUpdate.md @@ -161,7 +161,7 @@ The alignment of the text, either `left`, `center` or `right`. ## style? -> `optional` **style**: `"italic"` | `"light"` | `"regular"` | `"caps"` +> `optional` **style**: `"light"` | `"italic"` | `"regular"` | `"caps"` The style of the text, either `italic`, `light`, `regular` or `caps`. diff --git a/docs/Layers/AggregatedGridConfig.md b/docs/Layers/AggregatedGridConfig.md index 2924da71..e28ab427 100644 --- a/docs/Layers/AggregatedGridConfig.md +++ b/docs/Layers/AggregatedGridConfig.md @@ -38,6 +38,6 @@ The type of grid to use for the precomputed calculation. ## method -> **method**: `"avg"` | `"max"` | `"min"` | `"sum"` +> **method**: `"min"` | `"max"` | `"avg"` | `"sum"` The method to use for the precomputed calculation. diff --git a/docs/Layers/AggregationConfig.md b/docs/Layers/AggregationConfig.md index 8e79ad16..db711f41 100644 --- a/docs/Layers/AggregationConfig.md +++ b/docs/Layers/AggregationConfig.md @@ -14,6 +14,6 @@ The attribute to use for the aggregation. This must be a numeric attribute. ## method -> **method**: `"avg"` | `"max"` | `"min"` | `"sum"` | `"median"` +> **method**: `"min"` | `"max"` | `"avg"` | `"sum"` | `"median"` The method to use for the aggregation. diff --git a/docs/Layers/AggregationMethod.md b/docs/Layers/AggregationMethod.md index 09ba1e61..7b956ce0 100644 --- a/docs/Layers/AggregationMethod.md +++ b/docs/Layers/AggregationMethod.md @@ -1,5 +1,5 @@ *** -> **AggregationMethod**: `"avg"` | `"max"` | `"min"` | `"sum"` | `"median"` +> **AggregationMethod**: `"min"` | `"max"` | `"avg"` | `"sum"` | `"median"` The method to use for the aggregation. diff --git a/docs/Layers/GetLayerHistogramParams.md b/docs/Layers/GetLayerHistogramParams.md index 06906c50..b92c0063 100644 --- a/docs/Layers/GetLayerHistogramParams.md +++ b/docs/Layers/GetLayerHistogramParams.md @@ -25,7 +25,7 @@ the [LayersController.getHistogramData](LayersController.md#gethistogramdata) me ## values? -> `optional` **values**: \{ `boundary`: \[`number`, `number`]\[] | \[`number`, `number`, `number`, `number`] | \{ `type`: `"Polygon"`; `coordinates`: \[`number`, `number`]\[]\[]; } | \{ `type`: `"MultiPolygon"`; `coordinates`: \[`number`, `number`]\[]\[]\[]; }; `filters`: `null` | `boolean` | \[`null` | `string`, `"in"` | `"ni"`, `null` | (`null` | `string` | `number` | `boolean`)\[]] | \[`null` | `string`, `"lt"` | `"gt"` | `"le"` | `"ge"` | `"eq"` | `"ne"` | `"cn"` | `"nc"` | `"is"` | `"isnt"`, `null` | `string` | `number` | `boolean`] | [`FilterTernary`](FilterTernary.md); `aggregation`: \{ `method`: `"avg"` | `"max"` | `"min"` | `"sum"` | `"median"`; `attribute`: `string`; }; } +> `optional` **values**: \{ `boundary`: \[`number`, `number`]\[] | \[`number`, `number`, `number`, `number`] | \{ `type`: `"Polygon"`; `coordinates`: \[`number`, `number`]\[]\[]; } | \{ `type`: `"MultiPolygon"`; `coordinates`: \[`number`, `number`]\[]\[]\[]; }; `filters`: `null` | `boolean` | \[`null` | `string`, `"in"` | `"ni"`, `null` | (`null` | `string` | `number` | `boolean`)\[]] | \[`null` | `string`, `"lt"` | `"gt"` | `"le"` | `"ge"` | `"eq"` | `"ne"` | `"cn"` | `"nc"` | `"is"` | `"isnt"`, `null` | `string` | `number` | `boolean`] | [`FilterTernary`](FilterTernary.md); `aggregation`: \{ `method`: `"min"` | `"max"` | `"avg"` | `"sum"` | `"median"`; `attribute`: `string`; }; } Configuration for filtering and aggregating values while preserving the full set of bin ranges in the results. @@ -43,8 +43,8 @@ ranges in the results. | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | --------------------------------------------------------------------------- | | `boundary`? | \[`number`, `number`]\[] \| \[`number`, `number`, `number`, `number`] \| \{ `type`: `"Polygon"`; `coordinates`: \[`number`, `number`]\[]\[]; } \| \{ `type`: `"MultiPolygon"`; `coordinates`: \[`number`, `number`]\[]\[]\[]; } | - | - | | `filters`? | `null` \| `boolean` \| \[`null` \| `string`, `"in"` \| `"ni"`, `null` \| (`null` \| `string` \| `number` \| `boolean`)\[]] \| \[`null` \| `string`, `"lt"` \| `"gt"` \| `"le"` \| `"ge"` \| `"eq"` \| `"ne"` \| `"cn"` \| `"nc"` \| `"is"` \| `"isnt"`, `null` \| `string` \| `number` \| `boolean`] \| [`FilterTernary`](FilterTernary.md) | - | - | -| `aggregation`? | \{ `method`: `"avg"` \| `"max"` \| `"min"` \| `"sum"` \| `"median"`; `attribute`: `string`; } | - | - | -| `aggregation.method` | `"avg"` \| `"max"` \| `"min"` \| `"sum"` \| `"median"` | AggregateMethodSchema | The operation to use on the values from the features in the layer | +| `aggregation`? | \{ `method`: `"min"` \| `"max"` \| `"avg"` \| `"sum"` \| `"median"`; `attribute`: `string`; } | - | - | +| `aggregation.method` | `"min"` \| `"max"` \| `"avg"` \| `"sum"` \| `"median"` | AggregateMethodSchema | The operation to use on the values from the features in the layer | | `aggregation.attribute` | `string` | - | The attribute to use for the aggregation. This must be a numeric attribute. | *** diff --git a/docs/Layers/LayersController.md b/docs/Layers/LayersController.md index bf6b7d4a..afb7fe04 100644 --- a/docs/Layers/LayersController.md +++ b/docs/Layers/LayersController.md @@ -912,7 +912,7 @@ Calculates a single aggregate value for a layer based on the provided configurat | Type Parameter | | --------------------------------------------------------------------------------- | -| `T` *extends* `"avg"` \| `"max"` \| `"min"` \| `"sum"` \| `"median"` \| `"count"` | +| `T` *extends* `"min"` \| `"max"` \| `"avg"` \| `"sum"` \| `"median"` \| `"count"` | ### Parameters diff --git a/docs/Layers/PrecomputedAggregationMethod.md b/docs/Layers/PrecomputedAggregationMethod.md index d20c7282..c409b725 100644 --- a/docs/Layers/PrecomputedAggregationMethod.md +++ b/docs/Layers/PrecomputedAggregationMethod.md @@ -1,5 +1,5 @@ *** -> **PrecomputedAggregationMethod**: `"avg"` | `"max"` | `"min"` | `"sum"` | `"count"` +> **PrecomputedAggregationMethod**: `"min"` | `"max"` | `"avg"` | `"sum"` | `"count"` The method to use for the precomputed aggregation. diff --git a/docs/Main/FeltController.md b/docs/Main/FeltController.md index 73d967c2..fa851a90 100644 --- a/docs/Main/FeltController.md +++ b/docs/Main/FeltController.md @@ -10,10 +10,154 @@ own to make it easier to find related methods and events. # Extends -* [`ViewportController`](../Viewport/ViewportController.md).[`UiController`](../UI/UiController.md).[`LayersController`](../Layers/LayersController.md).[`ElementsController`](../Elements/ElementsController.md).[`SelectionController`](../Selection/SelectionController.md).[`InteractionsController`](../Interactions/InteractionsController.md).[`ToolsController`](../Tools/ToolsController.md).[`MiscController`](../Misc/MiscController.md) +* [`ViewportController`](../Viewport/ViewportController.md).[`UiController`](../UI/UiController.md).[`LayersController`](../Layers/LayersController.md).[`ElementsController`](../Elements/ElementsController.md).[`SelectionController`](../Selection/SelectionController.md).[`InteractionsController`](../Interactions/InteractionsController.md).[`ToolsController`](../Tools/ToolsController.md).[`MiscController`](../Misc/MiscController.md).[`BasemapsController`](../Basemaps/BasemapsController.md) # Methods +## getCurrentBasemap() + +> **getCurrentBasemap**(): `Promise`\<[`Basemap`](../Basemaps/Basemap.md)> + +Gets the currently active basemap. + +Use this method to retrieve information about the current basemap, including +its type (Felt, color, or custom tile), name, color scheme, and attribution. + +### Returns + +`Promise`\<[`Basemap`](../Basemaps/Basemap.md)> + +A promise that resolves to the current basemap configuration. + +### Example + +```typescript +// Get current basemap +const basemap = await felt.getCurrentBasemap(); +console.log({ + name: basemap.name, + type: basemap.type, + uiColorScheme: basemap.uiColorScheme, +}); +``` + +*** + +## getBasemaps() + +> **getBasemaps**(): `Promise`\<[`Basemap`](../Basemaps/Basemap.md)\[]> + +Gets all basemaps available on the map. + +Use this method to retrieve a list of all available basemaps that can be +applied to the map. + +### Returns + +`Promise`\<[`Basemap`](../Basemaps/Basemap.md)\[]> + +A promise that resolves to all basemaps available on the map. + +### Example + +```typescript +// Get all available basemaps +const basemaps = await felt.getBasemaps(); +const lightBasemaps = basemaps.filter(b => b.uiColorScheme === "light"); +``` + +*** + +## chooseBasemap() + +> **chooseBasemap**(`id`: `string`): `void` + +Chooses the basemap to use for the map. + +Use this method to change the current basemap. The basemap ID can be obtained +from getBasemaps(). + +### Parameters + +| Parameter | Type | +| --------- | -------- | +| `id` | `string` | + +### Returns + +`void` + +A promise that resolves when the basemap has been set. + +### Example + +```typescript +// Switch to a specific basemap +const basemaps = await felt.getBasemaps(); +const darkBasemap = basemaps.find(b => b.uiColorScheme === "dark"); +if (darkBasemap) { + await felt.chooseBasemap(darkBasemap.id); +} +``` + +*** + +## addCustomBasemap() + +> **addCustomBasemap**(`args`: \{ `basemap`: [`ColorBasemapInput`](../Basemaps/ColorBasemapInput.md) | [`CustomTileBasemapInput`](../Basemaps/CustomTileBasemapInput.md); `select`: `boolean`; }): `Promise`\<[`Basemap`](../Basemaps/Basemap.md)> + +Adds a custom basemap to the map. This can be either a solid color or a basemap +from a custom tile URL. + +### Parameters + +| Parameter | Type | Description | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------- | +| `args` | \{ `basemap`: [`ColorBasemapInput`](../Basemaps/ColorBasemapInput.md) \| [`CustomTileBasemapInput`](../Basemaps/CustomTileBasemapInput.md); `select`: `boolean`; } | - | +| `args.basemap` | [`ColorBasemapInput`](../Basemaps/ColorBasemapInput.md) \| [`CustomTileBasemapInput`](../Basemaps/CustomTileBasemapInput.md) | The basemap to add. | +| `args.select`? | `boolean` | Whether to select the basemap after adding it. | + +### Returns + +`Promise`\<[`Basemap`](../Basemaps/Basemap.md)> + +A promise for the added basemap. + +### Example + +```typescript +// Add a custom basemap and select it +await felt.addCustomBasemap({ + basemap: { + type: "xyz_tile", + tileUrl: "https://example.com/tile.png" + }, + select: true, +}); +``` + +*** + +## removeBasemap() + +> **removeBasemap**(`id`: `string`): `Promise`\<`void`> + +Removes a basemap from the list of available basemaps. + +### Parameters + +| Parameter | Type | +| --------- | -------- | +| `id` | `string` | + +### Returns + +`Promise`\<`void`> + +A promise that resolves when the basemap has been removed. + +*** + ## getElement() > **getElement**(`id`: `string`): `Promise`\<`null` | [`Element`](../Elements/Element.md)> @@ -1211,7 +1355,7 @@ Calculates a single aggregate value for a layer based on the provided configurat | Type Parameter | | --------------------------------------------------------------------------------- | -| `T` *extends* `"avg"` \| `"max"` \| `"min"` \| `"sum"` \| `"median"` \| `"count"` | +| `T` *extends* `"min"` \| `"max"` \| `"avg"` \| `"sum"` \| `"median"` \| `"count"` | ### Parameters @@ -2394,6 +2538,45 @@ felt.fitViewportToBounds({ bounds: [west, south, east, north] }); # Events +## onBasemapChange() + +> **onBasemapChange**(`args`: \{ `handler`: (`basemap`: [`Basemap`](../Basemaps/Basemap.md)) => `void`; }): `VoidFunction` + +Adds a listener for when the basemap changes. + +Use this to react to basemap changes, such as updating your UI or +adjusting other map elements to match the new basemap's color scheme. + +### Parameters + +| Parameter | Type | +| -------------- | --------------------------------------------------------------------------- | +| `args` | \{ `handler`: (`basemap`: [`Basemap`](../Basemaps/Basemap.md)) => `void`; } | +| `args.handler` | (`basemap`: [`Basemap`](../Basemaps/Basemap.md)) => `void` | + +### Returns + +`VoidFunction` + +A function to unsubscribe from the listener. + +### Example + +```typescript +// Listen for basemap changes +const unsubscribe = felt.onBasemapChange({ + handler: basemap => { + console.log(`Switched to ${basemap.name}`); + updateUIColors(basemap.uiColorScheme); + }, +}); + +// later on... +unsubscribe(); +``` + +*** + ## onElementCreate() > **onElementCreate**(`args`: \{ `handler`: (`change`: [`ElementChangeCallbackParams`](../Elements/ElementChangeCallbackParams.md)) => `void`; }): `VoidFunction` diff --git a/docs/README.md b/docs/README.md index a614acd4..ff9c9446 100644 --- a/docs/README.md +++ b/docs/README.md @@ -27,6 +27,7 @@ const layers = await map.getLayers(); ## Modules +* [Basemaps](Basemaps/README.md) * [Elements](Elements/README.md) * [Interactions](Interactions/README.md) * [Layers](Layers/README.md) diff --git a/docs/Tools/NoteToolSettings.md b/docs/Tools/NoteToolSettings.md index e3862752..10c34f7f 100644 --- a/docs/Tools/NoteToolSettings.md +++ b/docs/Tools/NoteToolSettings.md @@ -40,7 +40,7 @@ The alignment of the text, either `left`, `center` or `right`. ## style -> **style**: `"italic"` | `"light"` | `"regular"` | `"caps"` +> **style**: `"light"` | `"italic"` | `"regular"` | `"caps"` The style of the text, either `italic`, `light`, `regular` or `caps`. diff --git a/docs/Tools/TextToolSettings.md b/docs/Tools/TextToolSettings.md index e3862752..10c34f7f 100644 --- a/docs/Tools/TextToolSettings.md +++ b/docs/Tools/TextToolSettings.md @@ -40,7 +40,7 @@ The alignment of the text, either `left`, `center` or `right`. ## style -> **style**: `"italic"` | `"light"` | `"regular"` | `"caps"` +> **style**: `"light"` | `"italic"` | `"regular"` | `"caps"` The style of the text, either `italic`, `light`, `regular` or `caps`. diff --git a/etc/js-sdk.api.md b/etc/js-sdk.api.md index cb0ff312..dc7b8f46 100644 --- a/etc/js-sdk.api.md +++ b/etc/js-sdk.api.md @@ -4,211 +4,218 @@ ```ts -import { av as AggregatedGridConfig } from './controller-Bo9c_mT4.js'; -import { aw as AggregationConfig } from './controller-Bo9c_mT4.js'; -import { ax as AggregationMethod } from './controller-Bo9c_mT4.js'; -import { C as CircleElementCreate } from './controller-Bo9c_mT4.js'; -import { a as CircleElementRead } from './controller-Bo9c_mT4.js'; -import { b as CircleElementUpdate } from './controller-Bo9c_mT4.js'; -import { b9 as CircleToolSettings } from './controller-Bo9c_mT4.js'; -import { ba as ConfigurableToolType } from './controller-Bo9c_mT4.js'; -import { ay as CountGridConfig } from './controller-Bo9c_mT4.js'; -import { bq as CreateActionTriggerParams } from './controller-Bo9c_mT4.js'; -import { br as CreateFeatureActionParams } from './controller-Bo9c_mT4.js'; -import { K as CreateLayersFromGeoJsonParams } from './controller-Bo9c_mT4.js'; -import { bs as CreateOrUpdatePanelParams } from './controller-Bo9c_mT4.js'; -import { bt as CreatePanelElementsParams } from './controller-Bo9c_mT4.js'; -import { O as DataOnlyLayer } from './controller-Bo9c_mT4.js'; -import { bu as DeletePanelElementsParams } from './controller-Bo9c_mT4.js'; -import { E as Element_2 } from './controller-Bo9c_mT4.js'; -import { c as ElementChangeCallbackParams } from './controller-Bo9c_mT4.js'; -import { d as ElementCreate } from './controller-Bo9c_mT4.js'; -import { e as ElementGroup } from './controller-Bo9c_mT4.js'; -import { f as ElementGroupChangeCallbackParams } from './controller-Bo9c_mT4.js'; -import { aN as ElementGroupNode } from './controller-Bo9c_mT4.js'; -import { aO as ElementNode } from './controller-Bo9c_mT4.js'; -import { B as ElementsController } from './controller-Bo9c_mT4.js'; -import { g as ElementUpdate } from './controller-Bo9c_mT4.js'; -import { aP as EntityNode } from './controller-Bo9c_mT4.js'; -import { aQ as FeatureNode } from './controller-Bo9c_mT4.js'; -import { aR as FeatureSelection } from './controller-Bo9c_mT4.js'; -import { aV as FeltBoundary } from './controller-Bo9c_mT4.js'; -import { F as FeltController } from './controller-Bo9c_mT4.js'; -import { Q as FeltTiledVectorSource } from './controller-Bo9c_mT4.js'; -import { aW as FeltZoom } from './controller-Bo9c_mT4.js'; -import { ao as FilterExpression } from './controller-Bo9c_mT4.js'; -import { ap as FilterLogicGate } from './controller-Bo9c_mT4.js'; -import { ar as Filters } from './controller-Bo9c_mT4.js'; -import { aq as FilterTernary } from './controller-Bo9c_mT4.js'; -import { R as GeoJsonDataVectorSource } from './controller-Bo9c_mT4.js'; -import { aX as GeoJsonFeature } from './controller-Bo9c_mT4.js'; -import { S as GeoJsonFileVectorSource } from './controller-Bo9c_mT4.js'; -import { aY as GeoJsonGeometry } from './controller-Bo9c_mT4.js'; -import { aZ as GeoJsonProperties } from './controller-Bo9c_mT4.js'; -import { W as GeoJsonUrlVectorSource } from './controller-Bo9c_mT4.js'; -import { as as GeometryFilter } from './controller-Bo9c_mT4.js'; -import { G as GetElementGroupsConstraint } from './controller-Bo9c_mT4.js'; -import { h as GetElementsConstraint } from './controller-Bo9c_mT4.js'; -import { az as GetLayerCalculationParams } from './controller-Bo9c_mT4.js'; -import { aA as GetLayerCategoriesGroup } from './controller-Bo9c_mT4.js'; -import { aB as GetLayerCategoriesParams } from './controller-Bo9c_mT4.js'; -import { X as GetLayerGroupsConstraint } from './controller-Bo9c_mT4.js'; -import { aC as GetLayerHistogramBin } from './controller-Bo9c_mT4.js'; -import { aD as GetLayerHistogramParams } from './controller-Bo9c_mT4.js'; -import { aE as GetLayerPrecomputedCalculationParams } from './controller-Bo9c_mT4.js'; -import { Y as GetLayersConstraint } from './controller-Bo9c_mT4.js'; -import { Z as GetRenderedFeaturesConstraint } from './controller-Bo9c_mT4.js'; -import { aF as GridConfig } from './controller-Bo9c_mT4.js'; -import { aG as GridType } from './controller-Bo9c_mT4.js'; -import { H as HighlighterElementCreate } from './controller-Bo9c_mT4.js'; -import { i as HighlighterElementRead } from './controller-Bo9c_mT4.js'; -import { j as HighlighterElementUpdate } from './controller-Bo9c_mT4.js'; -import { bb as HighlighterToolSettings } from './controller-Bo9c_mT4.js'; -import { I as ImageElementCreate } from './controller-Bo9c_mT4.js'; -import { k as ImageElementRead } from './controller-Bo9c_mT4.js'; -import { l as ImageElementUpdate } from './controller-Bo9c_mT4.js'; -import { bc as InputToolSettings } from './controller-Bo9c_mT4.js'; -import { J as InteractionsController } from './controller-Bo9c_mT4.js'; -import { a_ as LatLng } from './controller-Bo9c_mT4.js'; -import { _ as Layer } from './controller-Bo9c_mT4.js'; -import { at as LayerBoundaries } from './controller-Bo9c_mT4.js'; -import { $ as LayerChangeCallbackParams } from './controller-Bo9c_mT4.js'; -import { a0 as LayerCommon } from './controller-Bo9c_mT4.js'; -import { ae as LayerFeature } from './controller-Bo9c_mT4.js'; -import { au as LayerFilters } from './controller-Bo9c_mT4.js'; -import { a1 as LayerGroup } from './controller-Bo9c_mT4.js'; -import { a2 as LayerGroupChangeCallbackParams } from './controller-Bo9c_mT4.js'; -import { aS as LayerGroupNode } from './controller-Bo9c_mT4.js'; -import { aT as LayerNode } from './controller-Bo9c_mT4.js'; -import { a3 as LayerProcessingStatus } from './controller-Bo9c_mT4.js'; -import { ag as LayerSchema } from './controller-Bo9c_mT4.js'; -import { ah as LayerSchemaAttribute } from './controller-Bo9c_mT4.js'; -import { ai as LayerSchemaBooleanAttribute } from './controller-Bo9c_mT4.js'; -import { aj as LayerSchemaCommonAttribute } from './controller-Bo9c_mT4.js'; -import { ak as LayerSchemaDateAttribute } from './controller-Bo9c_mT4.js'; -import { al as LayerSchemaDateTimeAttribute } from './controller-Bo9c_mT4.js'; -import { am as LayerSchemaNumericAttribute } from './controller-Bo9c_mT4.js'; -import { an as LayerSchemaTextAttribute } from './controller-Bo9c_mT4.js'; -import { aK as LayersController } from './controller-Bo9c_mT4.js'; -import { a4 as LegendDisplay } from './controller-Bo9c_mT4.js'; -import { a5 as LegendItem } from './controller-Bo9c_mT4.js'; -import { a6 as LegendItemChangeCallbackParams } from './controller-Bo9c_mT4.js'; -import { a7 as LegendItemIdentifier } from './controller-Bo9c_mT4.js'; -import { a8 as LegendItemsConstraint } from './controller-Bo9c_mT4.js'; -import { a$ as LineStringGeometry } from './controller-Bo9c_mT4.js'; -import { bd as LineToolSettings } from './controller-Bo9c_mT4.js'; -import { L as LinkElementRead } from './controller-Bo9c_mT4.js'; -import { b0 as LngLatTuple } from './controller-Bo9c_mT4.js'; -import { aL as MapDetails } from './controller-Bo9c_mT4.js'; -import { D as MapInteractionEvent } from './controller-Bo9c_mT4.js'; -import { M as MarkerElementCreate } from './controller-Bo9c_mT4.js'; -import { m as MarkerElementRead } from './controller-Bo9c_mT4.js'; -import { n as MarkerElementUpdate } from './controller-Bo9c_mT4.js'; -import { be as MarkerToolSettings } from './controller-Bo9c_mT4.js'; -import { aM as MiscController } from './controller-Bo9c_mT4.js'; -import { aH as MultiAggregationConfig } from './controller-Bo9c_mT4.js'; -import { b1 as MultiLineStringGeometry } from './controller-Bo9c_mT4.js'; -import { b2 as MultiPointGeometry } from './controller-Bo9c_mT4.js'; -import { b3 as MultiPolygonGeometry } from './controller-Bo9c_mT4.js'; -import { N as NoteElementCreate } from './controller-Bo9c_mT4.js'; -import { o as NoteElementRead } from './controller-Bo9c_mT4.js'; -import { p as NoteElementUpdate } from './controller-Bo9c_mT4.js'; -import { bf as NoteToolSettings } from './controller-Bo9c_mT4.js'; -import { bv as OnMapInteractionsOptions } from './controller-Bo9c_mT4.js'; -import { P as PathElementCreate } from './controller-Bo9c_mT4.js'; -import { q as PathElementRead } from './controller-Bo9c_mT4.js'; -import { r as PathElementUpdate } from './controller-Bo9c_mT4.js'; -import { bg as PinToolSettings } from './controller-Bo9c_mT4.js'; -import { s as PlaceElementCreate } from './controller-Bo9c_mT4.js'; -import { t as PlaceElementRead } from './controller-Bo9c_mT4.js'; -import { u as PlaceElementUpdate } from './controller-Bo9c_mT4.js'; -import { bh as PlaceFrame } from './controller-Bo9c_mT4.js'; -import { bz as PlacementForUIElement } from './controller-Bo9c_mT4.js'; -import { bi as PlaceSymbol } from './controller-Bo9c_mT4.js'; -import { b4 as PointGeometry } from './controller-Bo9c_mT4.js'; -import { v as PolygonElementCreate } from './controller-Bo9c_mT4.js'; -import { w as PolygonElementRead } from './controller-Bo9c_mT4.js'; -import { x as PolygonElementUpdate } from './controller-Bo9c_mT4.js'; -import { b5 as PolygonGeometry } from './controller-Bo9c_mT4.js'; -import { bj as PolygonToolSettings } from './controller-Bo9c_mT4.js'; -import { aI as PrecomputedAggregationMethod } from './controller-Bo9c_mT4.js'; -import { a9 as RasterBand } from './controller-Bo9c_mT4.js'; -import { aa as RasterLayer } from './controller-Bo9c_mT4.js'; -import { ab as RasterLayerSource } from './controller-Bo9c_mT4.js'; -import { af as RasterValue } from './controller-Bo9c_mT4.js'; -import { bk as RouteToolSettings } from './controller-Bo9c_mT4.js'; -import { aU as SelectionController } from './controller-Bo9c_mT4.js'; -import { ci as SetViewportCenterZoomParams } from './controller-Bo9c_mT4.js'; -import { b6 as SetVisibilityRequest } from './controller-Bo9c_mT4.js'; -import { b7 as SortConfig } from './controller-Bo9c_mT4.js'; -import { b8 as SortDirection } from './controller-Bo9c_mT4.js'; -import { T as TextElementCreate } from './controller-Bo9c_mT4.js'; -import { y as TextElementRead } from './controller-Bo9c_mT4.js'; -import { A as TextElementUpdate } from './controller-Bo9c_mT4.js'; -import { bl as TextToolSettings } from './controller-Bo9c_mT4.js'; -import { bp as ToolsController } from './controller-Bo9c_mT4.js'; -import { bm as ToolSettingsChangeEvent } from './controller-Bo9c_mT4.js'; -import { bn as ToolSettingsMap } from './controller-Bo9c_mT4.js'; -import { bo as ToolType } from './controller-Bo9c_mT4.js'; -import { ce as UIActionTriggerCreate } from './controller-Bo9c_mT4.js'; -import { bC as UIButtonElement } from './controller-Bo9c_mT4.js'; -import { bD as UIButtonElementCreate } from './controller-Bo9c_mT4.js'; -import { bE as UIButtonElementUpdate } from './controller-Bo9c_mT4.js'; -import { b_ as UIButtonRowElement } from './controller-Bo9c_mT4.js'; -import { b$ as UIButtonRowElementCreate } from './controller-Bo9c_mT4.js'; -import { c0 as UIButtonRowElementUpdate } from './controller-Bo9c_mT4.js'; -import { c1 as UICheckboxGroupElement } from './controller-Bo9c_mT4.js'; -import { c2 as UICheckboxGroupElementCreate } from './controller-Bo9c_mT4.js'; -import { c3 as UICheckboxGroupElementUpdate } from './controller-Bo9c_mT4.js'; -import { cd as UIControlElementOption } from './controller-Bo9c_mT4.js'; -import { ch as UiController } from './controller-Bo9c_mT4.js'; -import { U as UiControlsOptions } from './controller-Bo9c_mT4.js'; -import { bL as UIDividerElement } from './controller-Bo9c_mT4.js'; -import { bM as UIDividerElementCreate } from './controller-Bo9c_mT4.js'; -import { bN as UIDividerElementUpdate } from './controller-Bo9c_mT4.js'; -import { cf as uiFeatureAction } from './controller-Bo9c_mT4.js'; -import { cg as uiFeatureActionCreate } from './controller-Bo9c_mT4.js'; -import { bI as UIFlexibleSpaceElement } from './controller-Bo9c_mT4.js'; -import { bJ as UIFlexibleSpaceElementCreate } from './controller-Bo9c_mT4.js'; -import { bK as UIFlexibleSpaceElementUpdate } from './controller-Bo9c_mT4.js'; -import { bX as UIGridContainerElement } from './controller-Bo9c_mT4.js'; -import { bY as UIGridContainerElementCreate } from './controller-Bo9c_mT4.js'; -import { bZ as UIGridContainerElementUpdate } from './controller-Bo9c_mT4.js'; -import { ca as UIIframeElement } from './controller-Bo9c_mT4.js'; -import { cb as UIIframeElementCreate } from './controller-Bo9c_mT4.js'; -import { cc as UIIframeElementUpdate } from './controller-Bo9c_mT4.js'; -import { bA as UIPanel } from './controller-Bo9c_mT4.js'; -import { bB as UIPanelCreateOrUpdate } from './controller-Bo9c_mT4.js'; -import { bU as UIPanelElement } from './controller-Bo9c_mT4.js'; -import { bV as UIPanelElementCreate } from './controller-Bo9c_mT4.js'; -import { bW as UIPanelElementUpdate } from './controller-Bo9c_mT4.js'; -import { c4 as UIRadioGroupElement } from './controller-Bo9c_mT4.js'; -import { c5 as UIRadioGroupElementCreate } from './controller-Bo9c_mT4.js'; -import { c6 as UIRadioGroupElementUpdate } from './controller-Bo9c_mT4.js'; -import { bR as UISelectElement } from './controller-Bo9c_mT4.js'; -import { bS as UISelectElementCreate } from './controller-Bo9c_mT4.js'; -import { bT as UISelectElementUpdate } from './controller-Bo9c_mT4.js'; -import { bF as UITextElement } from './controller-Bo9c_mT4.js'; -import { bG as UITextElementCreate } from './controller-Bo9c_mT4.js'; -import { bH as UITextElementUpdate } from './controller-Bo9c_mT4.js'; -import { bO as UITextInputElement } from './controller-Bo9c_mT4.js'; -import { bP as UITextInputElementCreate } from './controller-Bo9c_mT4.js'; -import { bQ as UITextInputElementUpdate } from './controller-Bo9c_mT4.js'; -import { c7 as UIToggleGroupElement } from './controller-Bo9c_mT4.js'; -import { c8 as UIToggleGroupElementCreate } from './controller-Bo9c_mT4.js'; -import { c9 as UIToggleGroupElementUpdate } from './controller-Bo9c_mT4.js'; -import { bw as UpdateActionTriggerParams } from './controller-Bo9c_mT4.js'; -import { bx as UpdateFeatureActionParams } from './controller-Bo9c_mT4.js'; -import { ac as UpdateLayerParams } from './controller-Bo9c_mT4.js'; -import { by as UpdatePanelElementsParams } from './controller-Bo9c_mT4.js'; -import { aJ as ValueConfiguration } from './controller-Bo9c_mT4.js'; -import { ad as VectorLayer } from './controller-Bo9c_mT4.js'; -import { V as ViewportCenterZoom } from './controller-Bo9c_mT4.js'; -import { cj as ViewportConstraints } from './controller-Bo9c_mT4.js'; -import { cm as ViewportController } from './controller-Bo9c_mT4.js'; -import { ck as ViewportFitBoundsParams } from './controller-Bo9c_mT4.js'; -import { cl as ViewportState } from './controller-Bo9c_mT4.js'; -import { z } from './controller-Bo9c_mT4.js'; +import { aC as AggregatedGridConfig } from './controller-BD8DKro2.js'; +import { aD as AggregationConfig } from './controller-BD8DKro2.js'; +import { aE as AggregationMethod } from './controller-BD8DKro2.js'; +import { a as Basemap } from './controller-BD8DKro2.js'; +import { B as BasemapsController } from './controller-BD8DKro2.js'; +import { f as CircleElementCreate } from './controller-BD8DKro2.js'; +import { g as CircleElementRead } from './controller-BD8DKro2.js'; +import { h as CircleElementUpdate } from './controller-BD8DKro2.js'; +import { bg as CircleToolSettings } from './controller-BD8DKro2.js'; +import { C as ColorBasemap } from './controller-BD8DKro2.js'; +import { b as ColorBasemapInput } from './controller-BD8DKro2.js'; +import { bh as ConfigurableToolType } from './controller-BD8DKro2.js'; +import { aF as CountGridConfig } from './controller-BD8DKro2.js'; +import { bx as CreateActionTriggerParams } from './controller-BD8DKro2.js'; +import { by as CreateFeatureActionParams } from './controller-BD8DKro2.js'; +import { Y as CreateLayersFromGeoJsonParams } from './controller-BD8DKro2.js'; +import { bz as CreateOrUpdatePanelParams } from './controller-BD8DKro2.js'; +import { bA as CreatePanelElementsParams } from './controller-BD8DKro2.js'; +import { c as CustomTileBasemap } from './controller-BD8DKro2.js'; +import { d as CustomTileBasemapInput } from './controller-BD8DKro2.js'; +import { Z as DataOnlyLayer } from './controller-BD8DKro2.js'; +import { bB as DeletePanelElementsParams } from './controller-BD8DKro2.js'; +import { E as Element_2 } from './controller-BD8DKro2.js'; +import { i as ElementChangeCallbackParams } from './controller-BD8DKro2.js'; +import { j as ElementCreate } from './controller-BD8DKro2.js'; +import { k as ElementGroup } from './controller-BD8DKro2.js'; +import { l as ElementGroupChangeCallbackParams } from './controller-BD8DKro2.js'; +import { aU as ElementGroupNode } from './controller-BD8DKro2.js'; +import { aV as ElementNode } from './controller-BD8DKro2.js'; +import { S as ElementsController } from './controller-BD8DKro2.js'; +import { m as ElementUpdate } from './controller-BD8DKro2.js'; +import { aW as EntityNode } from './controller-BD8DKro2.js'; +import { aX as FeatureNode } from './controller-BD8DKro2.js'; +import { aY as FeatureSelection } from './controller-BD8DKro2.js'; +import { e as FeltBasemap } from './controller-BD8DKro2.js'; +import { b0 as FeltBoundary } from './controller-BD8DKro2.js'; +import { F as FeltController } from './controller-BD8DKro2.js'; +import { _ as FeltTiledVectorSource } from './controller-BD8DKro2.js'; +import { b1 as FeltZoom } from './controller-BD8DKro2.js'; +import { av as FilterExpression } from './controller-BD8DKro2.js'; +import { aw as FilterLogicGate } from './controller-BD8DKro2.js'; +import { ay as Filters } from './controller-BD8DKro2.js'; +import { ax as FilterTernary } from './controller-BD8DKro2.js'; +import { $ as GeoJsonDataVectorSource } from './controller-BD8DKro2.js'; +import { b2 as GeoJsonFeature } from './controller-BD8DKro2.js'; +import { a0 as GeoJsonFileVectorSource } from './controller-BD8DKro2.js'; +import { b3 as GeoJsonGeometry } from './controller-BD8DKro2.js'; +import { b4 as GeoJsonProperties } from './controller-BD8DKro2.js'; +import { a1 as GeoJsonUrlVectorSource } from './controller-BD8DKro2.js'; +import { az as GeometryFilter } from './controller-BD8DKro2.js'; +import { G as GetElementGroupsConstraint } from './controller-BD8DKro2.js'; +import { n as GetElementsConstraint } from './controller-BD8DKro2.js'; +import { aG as GetLayerCalculationParams } from './controller-BD8DKro2.js'; +import { aH as GetLayerCategoriesGroup } from './controller-BD8DKro2.js'; +import { aI as GetLayerCategoriesParams } from './controller-BD8DKro2.js'; +import { a2 as GetLayerGroupsConstraint } from './controller-BD8DKro2.js'; +import { aJ as GetLayerHistogramBin } from './controller-BD8DKro2.js'; +import { aK as GetLayerHistogramParams } from './controller-BD8DKro2.js'; +import { aL as GetLayerPrecomputedCalculationParams } from './controller-BD8DKro2.js'; +import { a3 as GetLayersConstraint } from './controller-BD8DKro2.js'; +import { a4 as GetRenderedFeaturesConstraint } from './controller-BD8DKro2.js'; +import { aM as GridConfig } from './controller-BD8DKro2.js'; +import { aN as GridType } from './controller-BD8DKro2.js'; +import { H as HighlighterElementCreate } from './controller-BD8DKro2.js'; +import { o as HighlighterElementRead } from './controller-BD8DKro2.js'; +import { p as HighlighterElementUpdate } from './controller-BD8DKro2.js'; +import { bi as HighlighterToolSettings } from './controller-BD8DKro2.js'; +import { I as ImageElementCreate } from './controller-BD8DKro2.js'; +import { q as ImageElementRead } from './controller-BD8DKro2.js'; +import { r as ImageElementUpdate } from './controller-BD8DKro2.js'; +import { bj as InputToolSettings } from './controller-BD8DKro2.js'; +import { X as InteractionsController } from './controller-BD8DKro2.js'; +import { b5 as LatLng } from './controller-BD8DKro2.js'; +import { a5 as Layer } from './controller-BD8DKro2.js'; +import { aA as LayerBoundaries } from './controller-BD8DKro2.js'; +import { a6 as LayerChangeCallbackParams } from './controller-BD8DKro2.js'; +import { a7 as LayerCommon } from './controller-BD8DKro2.js'; +import { al as LayerFeature } from './controller-BD8DKro2.js'; +import { aB as LayerFilters } from './controller-BD8DKro2.js'; +import { a8 as LayerGroup } from './controller-BD8DKro2.js'; +import { a9 as LayerGroupChangeCallbackParams } from './controller-BD8DKro2.js'; +import { aZ as LayerGroupNode } from './controller-BD8DKro2.js'; +import { a_ as LayerNode } from './controller-BD8DKro2.js'; +import { aa as LayerProcessingStatus } from './controller-BD8DKro2.js'; +import { an as LayerSchema } from './controller-BD8DKro2.js'; +import { ao as LayerSchemaAttribute } from './controller-BD8DKro2.js'; +import { ap as LayerSchemaBooleanAttribute } from './controller-BD8DKro2.js'; +import { aq as LayerSchemaCommonAttribute } from './controller-BD8DKro2.js'; +import { ar as LayerSchemaDateAttribute } from './controller-BD8DKro2.js'; +import { as as LayerSchemaDateTimeAttribute } from './controller-BD8DKro2.js'; +import { at as LayerSchemaNumericAttribute } from './controller-BD8DKro2.js'; +import { au as LayerSchemaTextAttribute } from './controller-BD8DKro2.js'; +import { aR as LayersController } from './controller-BD8DKro2.js'; +import { ab as LegendDisplay } from './controller-BD8DKro2.js'; +import { ac as LegendItem } from './controller-BD8DKro2.js'; +import { ad as LegendItemChangeCallbackParams } from './controller-BD8DKro2.js'; +import { ae as LegendItemIdentifier } from './controller-BD8DKro2.js'; +import { af as LegendItemsConstraint } from './controller-BD8DKro2.js'; +import { b6 as LineStringGeometry } from './controller-BD8DKro2.js'; +import { bk as LineToolSettings } from './controller-BD8DKro2.js'; +import { L as LinkElementRead } from './controller-BD8DKro2.js'; +import { b7 as LngLatTuple } from './controller-BD8DKro2.js'; +import { aS as MapDetails } from './controller-BD8DKro2.js'; +import { W as MapInteractionEvent } from './controller-BD8DKro2.js'; +import { M as MarkerElementCreate } from './controller-BD8DKro2.js'; +import { s as MarkerElementRead } from './controller-BD8DKro2.js'; +import { t as MarkerElementUpdate } from './controller-BD8DKro2.js'; +import { bl as MarkerToolSettings } from './controller-BD8DKro2.js'; +import { aT as MiscController } from './controller-BD8DKro2.js'; +import { aO as MultiAggregationConfig } from './controller-BD8DKro2.js'; +import { b8 as MultiLineStringGeometry } from './controller-BD8DKro2.js'; +import { b9 as MultiPointGeometry } from './controller-BD8DKro2.js'; +import { ba as MultiPolygonGeometry } from './controller-BD8DKro2.js'; +import { N as NoteElementCreate } from './controller-BD8DKro2.js'; +import { u as NoteElementRead } from './controller-BD8DKro2.js'; +import { v as NoteElementUpdate } from './controller-BD8DKro2.js'; +import { bm as NoteToolSettings } from './controller-BD8DKro2.js'; +import { bC as OnMapInteractionsOptions } from './controller-BD8DKro2.js'; +import { P as PathElementCreate } from './controller-BD8DKro2.js'; +import { w as PathElementRead } from './controller-BD8DKro2.js'; +import { x as PathElementUpdate } from './controller-BD8DKro2.js'; +import { bn as PinToolSettings } from './controller-BD8DKro2.js'; +import { y as PlaceElementCreate } from './controller-BD8DKro2.js'; +import { A as PlaceElementRead } from './controller-BD8DKro2.js'; +import { D as PlaceElementUpdate } from './controller-BD8DKro2.js'; +import { bo as PlaceFrame } from './controller-BD8DKro2.js'; +import { bG as PlacementForUIElement } from './controller-BD8DKro2.js'; +import { bp as PlaceSymbol } from './controller-BD8DKro2.js'; +import { bb as PointGeometry } from './controller-BD8DKro2.js'; +import { J as PolygonElementCreate } from './controller-BD8DKro2.js'; +import { K as PolygonElementRead } from './controller-BD8DKro2.js'; +import { O as PolygonElementUpdate } from './controller-BD8DKro2.js'; +import { bc as PolygonGeometry } from './controller-BD8DKro2.js'; +import { bq as PolygonToolSettings } from './controller-BD8DKro2.js'; +import { aP as PrecomputedAggregationMethod } from './controller-BD8DKro2.js'; +import { ag as RasterBand } from './controller-BD8DKro2.js'; +import { ah as RasterLayer } from './controller-BD8DKro2.js'; +import { ai as RasterLayerSource } from './controller-BD8DKro2.js'; +import { am as RasterValue } from './controller-BD8DKro2.js'; +import { br as RouteToolSettings } from './controller-BD8DKro2.js'; +import { a$ as SelectionController } from './controller-BD8DKro2.js'; +import { cp as SetViewportCenterZoomParams } from './controller-BD8DKro2.js'; +import { bd as SetVisibilityRequest } from './controller-BD8DKro2.js'; +import { be as SortConfig } from './controller-BD8DKro2.js'; +import { bf as SortDirection } from './controller-BD8DKro2.js'; +import { T as TextElementCreate } from './controller-BD8DKro2.js'; +import { Q as TextElementRead } from './controller-BD8DKro2.js'; +import { R as TextElementUpdate } from './controller-BD8DKro2.js'; +import { bs as TextToolSettings } from './controller-BD8DKro2.js'; +import { bw as ToolsController } from './controller-BD8DKro2.js'; +import { bt as ToolSettingsChangeEvent } from './controller-BD8DKro2.js'; +import { bu as ToolSettingsMap } from './controller-BD8DKro2.js'; +import { bv as ToolType } from './controller-BD8DKro2.js'; +import { cl as UIActionTriggerCreate } from './controller-BD8DKro2.js'; +import { bJ as UIButtonElement } from './controller-BD8DKro2.js'; +import { bK as UIButtonElementCreate } from './controller-BD8DKro2.js'; +import { bL as UIButtonElementUpdate } from './controller-BD8DKro2.js'; +import { c5 as UIButtonRowElement } from './controller-BD8DKro2.js'; +import { c6 as UIButtonRowElementCreate } from './controller-BD8DKro2.js'; +import { c7 as UIButtonRowElementUpdate } from './controller-BD8DKro2.js'; +import { c8 as UICheckboxGroupElement } from './controller-BD8DKro2.js'; +import { c9 as UICheckboxGroupElementCreate } from './controller-BD8DKro2.js'; +import { ca as UICheckboxGroupElementUpdate } from './controller-BD8DKro2.js'; +import { ck as UIControlElementOption } from './controller-BD8DKro2.js'; +import { co as UiController } from './controller-BD8DKro2.js'; +import { U as UiControlsOptions } from './controller-BD8DKro2.js'; +import { bS as UIDividerElement } from './controller-BD8DKro2.js'; +import { bT as UIDividerElementCreate } from './controller-BD8DKro2.js'; +import { bU as UIDividerElementUpdate } from './controller-BD8DKro2.js'; +import { cm as uiFeatureAction } from './controller-BD8DKro2.js'; +import { cn as uiFeatureActionCreate } from './controller-BD8DKro2.js'; +import { bP as UIFlexibleSpaceElement } from './controller-BD8DKro2.js'; +import { bQ as UIFlexibleSpaceElementCreate } from './controller-BD8DKro2.js'; +import { bR as UIFlexibleSpaceElementUpdate } from './controller-BD8DKro2.js'; +import { c2 as UIGridContainerElement } from './controller-BD8DKro2.js'; +import { c3 as UIGridContainerElementCreate } from './controller-BD8DKro2.js'; +import { c4 as UIGridContainerElementUpdate } from './controller-BD8DKro2.js'; +import { ch as UIIframeElement } from './controller-BD8DKro2.js'; +import { ci as UIIframeElementCreate } from './controller-BD8DKro2.js'; +import { cj as UIIframeElementUpdate } from './controller-BD8DKro2.js'; +import { bH as UIPanel } from './controller-BD8DKro2.js'; +import { bI as UIPanelCreateOrUpdate } from './controller-BD8DKro2.js'; +import { b$ as UIPanelElement } from './controller-BD8DKro2.js'; +import { c0 as UIPanelElementCreate } from './controller-BD8DKro2.js'; +import { c1 as UIPanelElementUpdate } from './controller-BD8DKro2.js'; +import { cb as UIRadioGroupElement } from './controller-BD8DKro2.js'; +import { cc as UIRadioGroupElementCreate } from './controller-BD8DKro2.js'; +import { cd as UIRadioGroupElementUpdate } from './controller-BD8DKro2.js'; +import { bY as UISelectElement } from './controller-BD8DKro2.js'; +import { bZ as UISelectElementCreate } from './controller-BD8DKro2.js'; +import { b_ as UISelectElementUpdate } from './controller-BD8DKro2.js'; +import { bM as UITextElement } from './controller-BD8DKro2.js'; +import { bN as UITextElementCreate } from './controller-BD8DKro2.js'; +import { bO as UITextElementUpdate } from './controller-BD8DKro2.js'; +import { bV as UITextInputElement } from './controller-BD8DKro2.js'; +import { bW as UITextInputElementCreate } from './controller-BD8DKro2.js'; +import { bX as UITextInputElementUpdate } from './controller-BD8DKro2.js'; +import { ce as UIToggleGroupElement } from './controller-BD8DKro2.js'; +import { cf as UIToggleGroupElementCreate } from './controller-BD8DKro2.js'; +import { cg as UIToggleGroupElementUpdate } from './controller-BD8DKro2.js'; +import { bD as UpdateActionTriggerParams } from './controller-BD8DKro2.js'; +import { bE as UpdateFeatureActionParams } from './controller-BD8DKro2.js'; +import { aj as UpdateLayerParams } from './controller-BD8DKro2.js'; +import { bF as UpdatePanelElementsParams } from './controller-BD8DKro2.js'; +import { aQ as ValueConfiguration } from './controller-BD8DKro2.js'; +import { ak as VectorLayer } from './controller-BD8DKro2.js'; +import { V as ViewportCenterZoom } from './controller-BD8DKro2.js'; +import { cq as ViewportConstraints } from './controller-BD8DKro2.js'; +import { ct as ViewportController } from './controller-BD8DKro2.js'; +import { cr as ViewportFitBoundsParams } from './controller-BD8DKro2.js'; +import { cs as ViewportState } from './controller-BD8DKro2.js'; +import { z } from './controller-BD8DKro2.js'; import { z as z_2 } from 'zod'; export { AggregatedGridConfig } @@ -217,6 +224,10 @@ export { AggregationConfig } export { AggregationMethod } +export { Basemap } + +export { BasemapsController } + export { CircleElementCreate } export { CircleElementRead } @@ -225,6 +236,10 @@ export { CircleElementUpdate } export { CircleToolSettings } +export { ColorBasemap } + +export { ColorBasemapInput } + export { ConfigurableToolType } export { CountGridConfig } @@ -239,6 +254,10 @@ export { CreateOrUpdatePanelParams } export { CreatePanelElementsParams } +export { CustomTileBasemap } + +export { CustomTileBasemapInput } + export { DataOnlyLayer } export { DeletePanelElementsParams } @@ -273,6 +292,8 @@ export const Felt: { connect(feltWindow: Pick): Promise; }; +export { FeltBasemap } + export { FeltBoundary } export { FeltController } diff --git a/src/client.ts b/src/client.ts index 824a8a94..61d8d65e 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,3 +1,4 @@ +export * from "./modules/basemaps"; export * from "./modules/elements"; export * from "./modules/interactions"; export * from "./modules/layers"; diff --git a/src/modules/basemaps/controller.ts b/src/modules/basemaps/controller.ts new file mode 100644 index 00000000..75ddbc73 --- /dev/null +++ b/src/modules/basemaps/controller.ts @@ -0,0 +1,153 @@ +import { listener, method } from "~/lib/interface"; +import type { + Basemap, + ColorBasemapInput, + CustomTileBasemapInput, +} from "./types"; + +/** + * @ignore + */ +export const basemapsController = ( + feltWindow: Pick, +): BasemapsController => ({ + getCurrentBasemap: method(feltWindow, "getCurrentBasemap"), + getBasemaps: method(feltWindow, "getBasemaps"), + chooseBasemap: method(feltWindow, "chooseBasemap"), + + addCustomBasemap: method(feltWindow, "addCustomBasemap"), + removeBasemap: method(feltWindow, "removeBasemap"), + + onBasemapChange: listener(feltWindow, "onBasemapChange"), +}); + +/** + * The basemaps controller allows you to manage the map's basemap layer. + * + * You can get the current basemap, list available basemaps, change the basemap, + * and be notified when the basemap changes. + * + * @group Controller + * @public + */ +export interface BasemapsController { + /** + * Gets the currently active basemap. + * + * Use this method to retrieve information about the current basemap, including + * its type (Felt, color, or custom tile), name, color scheme, and attribution. + * + * @returns A promise that resolves to the current basemap configuration. + * + * @example + * ```typescript + * // Get current basemap + * const basemap = await felt.getCurrentBasemap(); + * console.log({ + * name: basemap.name, + * type: basemap.type, + * uiColorScheme: basemap.uiColorScheme, + * }); + * ``` + */ + getCurrentBasemap(): Promise; + + /** + * Gets all basemaps available on the map. + * + * Use this method to retrieve a list of all available basemaps that can be + * applied to the map. + * + * @returns A promise that resolves to all basemaps available on the map. + * + * @example + * ```typescript + * // Get all available basemaps + * const basemaps = await felt.getBasemaps(); + * const lightBasemaps = basemaps.filter(b => b.uiColorScheme === "light"); + * ``` + */ + getBasemaps(): Promise; + + /** + * Chooses the basemap to use for the map. + * + * Use this method to change the current basemap. The basemap ID can be obtained + * from getBasemaps(). + * + * @returns A promise that resolves when the basemap has been set. + * + * @example + * ```typescript + * // Switch to a specific basemap + * const basemaps = await felt.getBasemaps(); + * const darkBasemap = basemaps.find(b => b.uiColorScheme === "dark"); + * if (darkBasemap) { + * await felt.chooseBasemap(darkBasemap.id); + * } + * ``` + */ + chooseBasemap(id: string): void; + + /** + * Adds a custom basemap to the map. This can be either a solid color or a basemap + * from a custom tile URL. + * + * @returns A promise for the added basemap. + * + * @example + * ```typescript + * // Add a custom basemap and select it + * await felt.addCustomBasemap({ + * basemap: { + * type: "xyz_tile", + * tileUrl: "https://example.com/tile.png" + * }, + * select: true, + * }); + * ``` + */ + addCustomBasemap(args: { + /** + * The basemap to add. + */ + basemap: ColorBasemapInput | CustomTileBasemapInput; + + /** + * Whether to select the basemap after adding it. + */ + select?: boolean; + }): Promise; + + /** + * Removes a basemap from the list of available basemaps. + * + * @returns A promise that resolves when the basemap has been removed. + */ + removeBasemap(id: string): Promise; + + /** + * Adds a listener for when the basemap changes. + * + * Use this to react to basemap changes, such as updating your UI or + * adjusting other map elements to match the new basemap's color scheme. + * + * @returns A function to unsubscribe from the listener. + * + * @event + * @example + * ```typescript + * // Listen for basemap changes + * const unsubscribe = felt.onBasemapChange({ + * handler: basemap => { + * console.log(`Switched to ${basemap.name}`); + * updateUIColors(basemap.uiColorScheme); + * }, + * }); + * + * // later on... + * unsubscribe(); + * ``` + */ + onBasemapChange(args: { handler: (basemap: Basemap) => void }): VoidFunction; +} diff --git a/src/modules/basemaps/index.ts b/src/modules/basemaps/index.ts new file mode 100644 index 00000000..2b7b97ca --- /dev/null +++ b/src/modules/basemaps/index.ts @@ -0,0 +1,16 @@ +/** + * The Basemaps module allows you to control the map's basemap layer, such as getting + * the current basemap, listing available basemaps, changing the basemap, and being + * notified when the basemap changes. + * + * @module Basemaps + */ +export type { BasemapsController } from "./controller"; +export type { + Basemap, + ColorBasemap, + ColorBasemapInput, + CustomTileBasemap, + CustomTileBasemapInput, + FeltBasemap, +} from "./types"; diff --git a/src/modules/basemaps/schema.ts b/src/modules/basemaps/schema.ts new file mode 100644 index 00000000..5255756e --- /dev/null +++ b/src/modules/basemaps/schema.ts @@ -0,0 +1,59 @@ +import { z } from "zod"; +import { + listenerMessageNoParams, + methodMessage, + type ListenerNoOptions, + type Method, +} from "~/lib/builders"; +import type { ModuleSchema } from "~/lib/ModuleSchema"; +import type { zInfer } from "~/lib/utils"; +import { + ColorBaseBasemapSchema, + CustomTileBasemapSchema, + type Basemap, +} from "./types"; + +const GetCurrentBasemapMessage = methodMessage("getCurrentBasemap", z.void()); +const GetBasemapsMessage = methodMessage("getBasemaps", z.void()); + +const ChooseBasemapMessage = methodMessage("chooseBasemap", z.string()); +const RemoveBasemapMessage = methodMessage("removeBasemap", z.string()); + +const AddBasemapMessage = methodMessage( + "addCustomBasemap", + z.object({ + basemap: z.discriminatedUnion("type", [ + ColorBaseBasemapSchema.omit({ id: true, uiColorScheme: true }), + CustomTileBasemapSchema.omit({ id: true }), + ]), + select: z.boolean().optional(), + }), +); + +const OnBasemapChangeMessage = listenerMessageNoParams("onBasemapChange"); + +export const basemapsSchema = { + methods: [ + GetCurrentBasemapMessage, + GetBasemapsMessage, + ChooseBasemapMessage, + AddBasemapMessage, + RemoveBasemapMessage, + ], + listeners: [OnBasemapChangeMessage], +} satisfies ModuleSchema; + +export type BasemapsSchema = { + methods: { + getCurrentBasemap: Method, Basemap>; + getBasemaps: Method, Basemap[]>; + chooseBasemap: Method>; + + addCustomBasemap: Method>; + removeBasemap: Method>; + }; + + listeners: { + onBasemapChange: ListenerNoOptions; + }; +}; diff --git a/src/modules/basemaps/type-tests.ts b/src/modules/basemaps/type-tests.ts new file mode 100644 index 00000000..581d9894 --- /dev/null +++ b/src/modules/basemaps/type-tests.ts @@ -0,0 +1,56 @@ +import type { BasemapsController } from "./controller"; + +const controller: BasemapsController = {} as BasemapsController; + +const basemaps = await controller.getBasemaps(); +const first = basemaps[0]; +if (first) { + first.id; + first.name; + first.uiColorScheme; + first.attribution; + + if (first?.type === "xyz_tile") { + first.tileUrl; + } else if (first?.type === "color") { + first.color; + } else if (first?.type === "felt") { + first.theme; + } +} + +controller.addCustomBasemap({ + basemap: { + type: "xyz_tile", + tileUrl: "https://example.com/tile.png", + uiColorScheme: "light", + name: "Example Basemap", + }, +}); + +// check discriminated union input +controller.addCustomBasemap({ + basemap: { + type: "color", + uiColorScheme: "light", + + // @ts-expect-error - tileUrl not allowed for color basemaps + tileUrl: "https://example.com/tile.png", + }, +}); + +controller.removeBasemap("example-basemap"); + +const basemap = await controller.getCurrentBasemap(); +// @ts-expect-error - whatever isn't a property of the basemap +basemap.whatever; + +controller.chooseBasemap("example-basemap"); +controller.onBasemapChange({ + handler: (basemap) => { + basemap.id; + basemap.name; + basemap.uiColorScheme; + basemap.attribution; + }, +}); diff --git a/src/modules/basemaps/types.ts b/src/modules/basemaps/types.ts new file mode 100644 index 00000000..5104dc8a --- /dev/null +++ b/src/modules/basemaps/types.ts @@ -0,0 +1,55 @@ +import { z } from "zod"; +import type { zInfer } from "~/lib/utils"; + +const BaseBasemapSchema = z.object({ + /** + * A unique identifier for the basemap. + * + * @remarks Do not rely on the stability of this ID for Felt basemaps, as they are + * subject to change. + */ + id: z.string(), + + /** + * The name of the basemap. + */ + name: z.string(), + + /** + * The color scheme of the UI that goes with the basemap. It is best to set this to + * "light" if your basemap is broadly light, and "dark" if your basemap is broadly dark. + */ + uiColorScheme: z.enum(["light", "dark"]), + + /** + * The attribution of the basemap, which is shown in the map's UI. + */ + attribution: z.string().optional(), +}); + +interface BaseBasemap extends zInfer {} + +export interface FeltBasemap extends BaseBasemap { + type: "felt"; + theme: "color_light" | "monochrome_dark" | "monochrome_light" | "satellite"; +} + +export const ColorBaseBasemapSchema = BaseBasemapSchema.extend({ + type: z.literal("color"), + color: z.string(), +}); + +export interface ColorBasemap extends zInfer {} + +export const CustomTileBasemapSchema = BaseBasemapSchema.extend({ + type: z.literal("xyz_tile"), + tileUrl: z.string(), +}); + +export interface CustomTileBasemap + extends zInfer {} + +export type ColorBasemapInput = Omit; +export type CustomTileBasemapInput = Omit; + +export type Basemap = FeltBasemap | ColorBasemap | CustomTileBasemap; diff --git a/src/modules/main/controller.ts b/src/modules/main/controller.ts index 6cecdd0d..85563a0a 100644 --- a/src/modules/main/controller.ts +++ b/src/modules/main/controller.ts @@ -1,3 +1,7 @@ +import { + basemapsController, + type BasemapsController, +} from "../basemaps/controller"; import { elementsController, type ElementsController, @@ -37,6 +41,7 @@ export function makeController( ...interactionsController(feltWindow), ...toolsController(feltWindow), ...miscController(feltWindow), + ...basemapsController(feltWindow), }; } @@ -65,7 +70,8 @@ export interface FeltController InteractionsController, ToolsController, InteractionsController, - MiscController { + MiscController, + BasemapsController { /** * The iframe element containing the Felt map, if it is an embedded map. * diff --git a/src/modules/main/schema.ts b/src/modules/main/schema.ts index 8e1bbd58..d7a1040d 100644 --- a/src/modules/main/schema.ts +++ b/src/modules/main/schema.ts @@ -1,3 +1,4 @@ +import { basemapsSchema, type BasemapsSchema } from "../basemaps/schema"; import { elementsSchema, type ElementsSchema } from "../elements/schema"; import { interactionsSchema, @@ -19,6 +20,7 @@ export const allModules = [ interactionsSchema, toolsSchema, miscSchema, + basemapsSchema, ]; export type AllModules = @@ -30,4 +32,5 @@ export type AllModules = | InteractionsSchema | ToolsSchema | InteractionsSchema - | MiscSchema; + | MiscSchema + | BasemapsSchema; From e29597ba6d9614f7e6bd6cb71fc1e517b40cdbf2 Mon Sep 17 00:00:00 2001 From: Tom Hicks Date: Thu, 2 Oct 2025 15:44:43 +0200 Subject: [PATCH 2/2] docs(changeset): Add basemaps API --- .changeset/cuddly-pumpkins-fetch.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/cuddly-pumpkins-fetch.md diff --git a/.changeset/cuddly-pumpkins-fetch.md b/.changeset/cuddly-pumpkins-fetch.md new file mode 100644 index 00000000..1009fabc --- /dev/null +++ b/.changeset/cuddly-pumpkins-fetch.md @@ -0,0 +1,5 @@ +--- +"@feltmaps/js-sdk": minor +--- + +Add basemaps API