@cosmicds/vue-toolkit 0.3.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +20 -1
  2. package/dist/index.common.js +741 -628
  3. package/dist/index.umd.js +741 -628
  4. package/dist/index.umd.min.js +4 -4
  5. package/dist/src/background.d.ts +4 -0
  6. package/dist/src/components/CreditLogos.vue.d.ts +14 -9
  7. package/dist/src/components/FundingAcknowledgement.vue.d.ts +1 -1
  8. package/dist/src/components/Gallery.vue.d.ts +2 -2
  9. package/dist/src/components/GeolocationButton.vue.d.ts +0 -16
  10. package/dist/src/components/IconButton.vue.d.ts +10 -12
  11. package/dist/src/components/LocationSelector.vue.d.ts +4 -4
  12. package/dist/src/components/WwtHud.vue.d.ts +3 -3
  13. package/dist/src/composables.d.ts +15 -7
  14. package/dist/src/geolocation.d.ts +6 -0
  15. package/dist/src/index.d.ts +2 -2
  16. package/dist/src/keyboard.d.ts +35 -2
  17. package/dist/src/mapbox.d.ts +55 -3
  18. package/dist/src/stories/CreditLogos.stories.d.ts +6 -0
  19. package/dist/src/stories/FundingAcknowledgement.stories.d.ts +6 -0
  20. package/dist/src/stories/Gallery.stories.d.ts +6 -0
  21. package/dist/src/stories/IconButton.stories.d.ts +6 -0
  22. package/dist/src/stories/LocationSelector.stories.d.ts +6 -0
  23. package/dist/src/stories/WwtHud.stories.d.ts +6 -0
  24. package/dist/src/types.d.ts +123 -4
  25. package/dist/src/utils.d.ts +24 -2
  26. package/dist/src/wwt-utils.d.ts +6 -0
  27. package/dist/tsconfig.tsbuildinfo +1 -1
  28. package/package.json +29 -3
  29. package/src/background.ts +4 -0
  30. package/src/composables.ts +14 -1
  31. package/src/geolocation.ts +12 -0
  32. package/src/index.ts +2 -1
  33. package/src/keyboard.ts +36 -2
  34. package/src/mapbox.ts +74 -8
  35. package/src/types.ts +127 -5
  36. package/src/utils.ts +24 -4
  37. package/src/wwt-utils.ts +6 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicds/vue-toolkit",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "browser": "dist/index.umd.js",
5
5
  "dependencies": {
6
6
  "@capacitor/core": "^5.7.4",
@@ -17,21 +17,44 @@
17
17
  "vuetify": "^3.3.3"
18
18
  },
19
19
  "devDependencies": {
20
+ "@chromatic-com/storybook": "^1.3.3",
21
+ "@storybook/addon-essentials": "^8.0.9",
22
+ "@storybook/addon-interactions": "^8.0.9",
23
+ "@storybook/addon-links": "^8.0.9",
24
+ "@storybook/addon-webpack5-compiler-swc": "^1.0.2",
25
+ "@storybook/blocks": "^8.0.9",
26
+ "@storybook/test": "^8.0.9",
27
+ "@storybook/vue3": "^8.0.9",
28
+ "@storybook/vue3-webpack5": "^8.0.9",
20
29
  "@types/leaflet": "^1.9.11",
21
30
  "@typescript-eslint/eslint-plugin": "^6.19.0",
22
31
  "@typescript-eslint/parser": "^6.19.0",
23
32
  "@vue/cli-plugin-eslint": "^5.0.8",
24
33
  "@vue/cli-plugin-typescript": "^5.0.8",
25
34
  "@vue/cli-service": "^5.0.8",
35
+ "@vue/compiler-sfc": "^3.4.25",
26
36
  "@vue/eslint-config-typescript": "^12.0.0",
27
37
  "copy-webpack-plugin": "^12.0.2",
38
+ "css-loader": "^7.1.1",
28
39
  "eslint": "^8.31.0",
40
+ "eslint-plugin-storybook": "^0.8.0",
29
41
  "eslint-plugin-vue": "^9.8.0",
30
42
  "less": "^4.2.0",
31
43
  "less-loader": "^12.1.0",
44
+ "markdown-loader": "^8.0.0",
45
+ "pug": "^3.0.3",
46
+ "storybook": "^8.0.9",
47
+ "storybook-css-modules-preset": "^1.1.1",
48
+ "storybook-dark-mode": "^4.0.1",
49
+ "style-loader": "^4.0.0",
50
+ "typedoc": "^0.25.13",
51
+ "typedoc-plugin-markdown": "^3.17.1",
52
+ "typedoc-plugin-vue": "^1.1.0",
32
53
  "typescript": "^4.9.4",
54
+ "vue-loader": "^17.4.2",
33
55
  "vue-template-compiler": "^2.7.14",
34
- "webpack": "^5.75.0"
56
+ "webpack": "^5.75.0",
57
+ "webpack-dev-middleware": "^5.3.4"
35
58
  },
36
59
  "files": [
37
60
  "dist/*",
@@ -46,7 +69,10 @@
46
69
  "scripts": {
47
70
  "build": "vue-cli-service build --target lib --name index src/index.ts",
48
71
  "clean": "rimraf dist",
49
- "lint": "vue-cli-service lint src --no-fix"
72
+ "docs": "typedoc --plugin typedoc-plugin-markdown",
73
+ "lint": "vue-cli-service lint src --no-fix",
74
+ "storybook": "storybook dev -p 6006 --debug",
75
+ "build-storybook": "storybook build -o docs"
50
76
  },
51
77
  "types": "./dist/src/index.d.ts"
52
78
  }
package/src/background.ts CHANGED
@@ -1,5 +1,8 @@
1
+ /** Class representing a background imageset for WorldWide Telescope */
1
2
  export class BackgroundImageset {
3
+ /** The outward-facing name to use for the imageset in a story */
2
4
  public imagesetName: string;
5
+ /** The name of the imageset object inside WorldWide Telescope */
3
6
  public displayName: string;
4
7
 
5
8
  constructor(displayName: string, imagesetName: string) {
@@ -8,6 +11,7 @@ export class BackgroundImageset {
8
11
  }
9
12
  }
10
13
 
14
+ /** A default list of `BackgroundImagset` objects to use within data stories */
11
15
  export const skyBackgroundImagesets: BackgroundImageset[] = [
12
16
  new BackgroundImageset(
13
17
  "Optical (Terapixel DSS)",
@@ -1,6 +1,10 @@
1
1
  import { ref, onMounted, onUnmounted, Ref } from "vue";
2
2
  import screenfull from "screenfull";
3
3
 
4
+ /**
5
+ * A composable that encapsulates fullscreen behavior.
6
+ * @returns A reactive variable indicating whether or not fullscreen mode is active
7
+ */
4
8
  export function useFullscreen(): Ref<boolean> {
5
9
  const fullscreenModeActive = ref(false);
6
10
  function update(_event: Event) {
@@ -22,11 +26,20 @@ export function useFullscreen(): Ref<boolean> {
22
26
  return fullscreenModeActive;
23
27
  }
24
28
 
29
+ /** Interface describing the shape of a browser window */
25
30
  export interface WindowShape {
26
31
  width: number;
27
32
  height: number;
28
33
  }
34
+
35
+ /** A default `WindowShape` to use */
29
36
  export const defaultWindowShape = { width: 1200, height: 900 };
37
+
38
+ /**
39
+ * A composable that encapsulates a changing window shape.
40
+ *
41
+ * @returns A reactive variable describing the current window shape.
42
+ */
30
43
  export function useWindowShape() {
31
44
  const windowShape = ref<WindowShape>(defaultWindowShape);
32
45
  const resizeObserver = new ResizeObserver(_entries => update());
@@ -51,6 +64,6 @@ export function useWindowShape() {
51
64
  resizeObserver.unobserve(document.body);
52
65
  });
53
66
 
54
- return { windowShape, resizeObserver };
67
+ return windowShape;
55
68
  }
56
69
 
@@ -2,6 +2,11 @@ import { ref, onMounted } from "vue";
2
2
  import { Capacitor, PermissionState as CapacitorPermissionState } from '@capacitor/core';
3
3
  import { Geolocation, PermissionStatus as CapacitorPermissionStatus, Position, PositionOptions } from "@capacitor/geolocation";
4
4
 
5
+ /**
6
+ * Determine which of two capacitor permission states is 'better'.
7
+ * This implementation takes "prompt-with-rationale" to be better than "prompt".
8
+ * @returns The 'better' of the two input permission states
9
+ */
5
10
  function betterPermissionState(firstState: CapacitorPermissionState, secondState: CapacitorPermissionState): CapacitorPermissionState {
6
11
  const states: CapacitorPermissionState[] = ["granted", "prompt-with-rationale", "prompt", "denied"];
7
12
  for (const state of states) {
@@ -13,6 +18,13 @@ function betterPermissionState(firstState: CapacitorPermissionState, secondState
13
18
  }
14
19
 
15
20
  export type PositionCoords = Position['coords'];
21
+
22
+ /**
23
+ * A composable that encapsulates the current state of the browser
24
+ * geolocation position and permission status.
25
+ * @param onStartup - Whether or not to query the user's geolocation on startup.
26
+ * @returns Reactive state describing the geolocation
27
+ */
16
28
  export function useGeolocation(onStartup=true) {
17
29
 
18
30
  const geolocation = ref<PositionCoords | null>(null);
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { BackgroundImageset, skyBackgroundImagesets } from "./background";
2
2
  import { useFullscreen, useWindowShape, WindowShape } from "./composables";
3
3
  import { PositionCoords, useGeolocation } from "./geolocation";
4
- import { KeyboardControlSettings } from "./keyboard";
4
+ import { KeyPressInfo, KeyboardControlSettings } from "./keyboard";
5
5
  import { useWWTKeyboardControls } from "./wwt-utils";
6
6
 
7
7
  import IconButton from "./components/IconButton.vue";
@@ -15,6 +15,7 @@ import Gallery from "./components/Gallery.vue";
15
15
 
16
16
  export {
17
17
  BackgroundImageset,
18
+ KeyPressInfo,
18
19
  KeyboardControlSettings,
19
20
  Gallery,
20
21
  IconButton,
package/src/keyboard.ts CHANGED
@@ -1,10 +1,21 @@
1
- class KeyPressInfo {
1
+ /** Class representing a key press */
2
+ export class KeyPressInfo {
3
+ /** The code of the key that was pressed */
2
4
  code: string;
5
+ /** Whether the control modifier was pressed */
3
6
  ctrl: boolean;
7
+ /** Whether the alt modifier was pressed */
4
8
  alt: boolean;
9
+ /** Whether the shift modifier was pressed */
5
10
  shift: boolean;
11
+ /** Whether the meta modifier was pressed */
6
12
  meta: boolean;
7
13
 
14
+ /**
15
+ * Create an instance of key press information
16
+ * @param code The key code describing the keypress
17
+ * @param modifiers An object of boolean values describing which modifier keys were pressed down
18
+ */
8
19
  constructor(
9
20
  code: string,
10
21
  modifiers?: {
@@ -21,6 +32,11 @@ class KeyPressInfo {
21
32
  this.meta = modifiers?.meta ?? false;
22
33
  }
23
34
 
35
+ /**
36
+ * Determine whether a keyboard event matches this key press information
37
+ * @param event - The keyboard event to test
38
+ * @returns Whether or not the given event matches
39
+ */
24
40
  matches(event: KeyboardEvent): boolean {
25
41
  return (
26
42
  event.code === this.code &&
@@ -32,13 +48,26 @@ class KeyPressInfo {
32
48
  }
33
49
  }
34
50
 
51
+ /** Type describing the possible WWT actions */
52
+ type ActionType = KeyboardControlSettings["actionTypes"][number];
53
+
54
+ /**
55
+ * Class describing keyboard control settings for WorldWide Telescope actions
56
+ */
35
57
  export class KeyboardControlSettings {
58
+ /** A list of key presses that should result in zooming in */
36
59
  zoomIn: KeyPressInfo[];
60
+ /** A list of key presses that should result in zooming out */
37
61
  zoomOut: KeyPressInfo[];
62
+ /** A list of key presses that should result in moving the view up */
38
63
  moveUp: KeyPressInfo[];
64
+ /** A list of key presses that should result in moving the view down */
39
65
  moveDown: KeyPressInfo[];
66
+ /** A list of key presses that should result in moving the view left */
40
67
  moveLeft: KeyPressInfo[];
68
+ /** A list of key presses that should result in moving the view right */
41
69
  moveRight: KeyPressInfo[];
70
+ /** A value describing how much to move on a movement press. Larger means more movement. */
42
71
  moveAmount: number;
43
72
 
44
73
  constructor({
@@ -69,8 +98,13 @@ export class KeyboardControlSettings {
69
98
  "moveRight",
70
99
  ] as const;
71
100
 
101
+ /** Make a listener for a given WWT action
102
+ * @param actionName - The WWT action to make a listener for
103
+ * @param action - Function to execute when the given WWT action occurs
104
+ * @returns The key event listener for the desired behavior
105
+ */
72
106
  makeListener(
73
- actionName: KeyboardControlSettings["actionTypes"][number],
107
+ actionName: ActionType,
74
108
  action: () => void
75
109
  ): (event: KeyboardEvent) => void {
76
110
  return (event) => {
package/src/mapbox.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /** Interface describing a MapBox content item */
1
2
  export interface MapBoxContextItem {
2
3
  id: string;
3
4
  // eslint-disable-next-line @typescript-eslint/naming-convention
@@ -21,44 +22,65 @@ export interface MapBoxFeature {
21
22
  context: MapBoxContextItem[];
22
23
  }
23
24
 
25
+ /** Interface describing a MapBox feature collection, which is a GeoJSON object */
24
26
  export interface MapBoxFeatureCollection {
27
+ /* The type of the collection */
25
28
  type: "FeatureCollection";
29
+ /** The list of features in the collection */
26
30
  features: MapBoxFeature[];
27
31
  }
28
32
 
33
+ /** Union type describing the feature types available in MapBox */
29
34
  export type MapBoxFeatureType = "country" | "region" | "postcode" | "district" | "place" | "locality" | "neighborhood" | "street" | "address";
35
+
36
+ /** Union type describing the worldviews available in MapBox */
30
37
  export type MapBoxWorldviewType = "ar" | "cn" | "in" | "jp" | "ma" | "ru" | "tr" | "us";
31
38
 
32
- // For countries, use the ISO 3166-1 alpha-2 country codes:
33
- // https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
39
+ /** Interface describing options common to both forward and reverse MapBox geocoding */
34
40
  interface BaseMapBoxGeocodingOptions {
35
- permanent?: boolean;
41
+ /** The language to use for the results, as an IEFT language tag */
36
42
  language?: string;
43
+ /** The number of results to return. Default is 5 */
37
44
  limit?: number;
45
+ /** Countries to include in the results. If a list is given, any result outside of these countries is omitted
46
+ * Specify countries using ISO 3166-1 alpha-2 country codes: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
47
+ */
38
48
  countries?: string[];
49
+ /** The result types to include */
39
50
  types?: MapBoxFeatureType[];
40
51
 
41
- // MapBox API access token
52
+ /** The access token for MapBox. Required */
42
53
  // eslint-disable-next-line @typescript-eslint/naming-convention
43
54
  access_token: string;
44
55
  }
45
56
 
57
+ /** Interface describing options for forward geocoding */
46
58
  interface MapBoxForwardGeocodingOptions extends BaseMapBoxGeocodingOptions {
59
+ /** Whether to return autocomplete results. MapBox default is true */
47
60
  autocomplete?: boolean;
48
- bbox?: number;
49
- format?: "geojson" | "v5";
61
+ /** A bounding box for results. Should be a string of the form "minLon,minLat,maxLon,maxLat" */
62
+ bbox?: string;
63
+ /** Whether MapBox should try approximate, as well as exact, matching. MapBox default is true */
64
+ fuzzyMatch?: boolean;
65
+ /** If specified, results are biased to favor results closer to this location. Should be a string of the form "longitude, latitude" */
50
66
  proximity?: string;
51
67
  }
52
68
 
69
+ /** Interface describing options for reverse geocoding */
53
70
  interface MapBoxReverseGeocodingOptions extends BaseMapBoxGeocodingOptions {
71
+ /** The worldview to use for search results. MapBox default is "us" */
54
72
  worldview?: MapBoxWorldviewType[];
55
73
  }
56
74
 
75
+ /** Interface describing geocoding query parameters that are adjusted from the options exposed by our methods */
57
76
  interface MapBoxAdjustedGeocodingParams {
58
- countries?: string;
77
+ /** We take in a string of country codes, but MapBox wants a comma-separated list */
78
+ country?: string;
79
+ /** We take in a list of types, but MapBox wants a comma-separated list */
59
80
  types?: string;
60
81
  }
61
82
 
83
+ /** A type describing the query parameter type corresponding to one of our option types */
62
84
  type MapBoxQueryOptions<T extends BaseMapBoxGeocodingOptions> = {
63
85
  [K in keyof Omit<T, "countries" | "types">]: T[K];
64
86
  } & MapBoxAdjustedGeocodingParams;
@@ -67,6 +89,12 @@ const DEFAULT_RELEVANT_FEATURE_TYPES = ["postcode", "place", "region", "country"
67
89
  const NA_COUNTRIES = ["United States", "Canada", "Mexico"];
68
90
  const NA_ABBREVIATIONS = ["US-", "CA-", "MX-"];
69
91
 
92
+ /** Find the best feature from a collection of MapBox features.
93
+ * We look for feature place types in the order: 'place', 'postcode', 'region', 'country'
94
+ * @param collection The collection of items to search
95
+ * @param relevantTypes The set of feature place types to consider. If not specified, we use the four types mentioned above
96
+ * @returns The "best" feature, as described above
97
+ */
70
98
  export function findBestFeature(collection: MapBoxFeatureCollection, relevantTypes?: MapBoxFeatureType[]): MapBoxFeature | null {
71
99
  const types = relevantTypes ?? DEFAULT_RELEVANT_FEATURE_TYPES;
72
100
  const relevantFeatures = collection.features.filter(feature => types.some(type => feature.place_type.includes(type)));
@@ -85,6 +113,12 @@ export function findBestFeature(collection: MapBoxFeatureCollection, relevantTyp
85
113
  return null;
86
114
  }
87
115
 
116
+ /**
117
+ * Create text describing a MapBox feature, based on the MapBox items inside of the feature's context
118
+ * @param feature The MapBox feature
119
+ * @param relevantTypes The item types inside the feature's context that we want to consider when creating the string. If not specified, we use 'place', 'postcode', 'region', and 'country'
120
+ * @returns A string describing the feature
121
+ */
88
122
  export function textForMapboxFeature(feature: MapBoxFeature, relevantTypes?: MapBoxFeatureType[]): string {
89
123
  const types = relevantTypes ?? DEFAULT_RELEVANT_FEATURE_TYPES;
90
124
  const pieces: string[] = [];
@@ -115,21 +149,38 @@ export function textForMapboxFeature(feature: MapBoxFeature, relevantTypes?: Map
115
149
  return pieces.join(", ");
116
150
  }
117
151
 
152
+ /**
153
+ * Return text describing the "best" feature in a MapBox collection.
154
+ * See @link{findBestFeature} for a description of how a feature is chosen
155
+ * @param results The feature collection to use
156
+ * @param relevantTypes The item types inside the best feature's context that we want to consider when creating the string. If not specified, we use 'place', 'postcode', 'region', and 'country'
157
+ */
118
158
  export function textForMapboxResults(results: MapBoxFeatureCollection, relevantTypes?: MapBoxFeatureType[]): string {
119
159
  const feature = findBestFeature(results, relevantTypes);
120
160
  return feature !== null ? textForMapboxFeature(feature) : "";
121
161
  }
122
162
 
163
+ /**
164
+ * Convert our MapBox options to options suitable for a query to the MapBox API
165
+ * @param options The toolkit MapBox options
166
+ * @returns The options converted into a suitable object to use for a MapBox API query
167
+ * @template T extends @link{BaseMapBoxGeocodingOptions}
168
+ */
123
169
  function convertOptionsToQueryParams<T extends BaseMapBoxGeocodingOptions>(options: T): MapBoxQueryOptions<T> {
124
170
  const { types, countries, ...params } = options;
125
171
  const queryParams = params as MapBoxQueryOptions<T>;
126
172
  queryParams.types = (types ?? ["place", "postcode"]).join(",");
127
173
  if (countries) {
128
- queryParams.countries = countries.join(",");
174
+ queryParams.country = countries.join(",");
129
175
  }
130
176
  return queryParams;
131
177
  }
132
178
 
179
+ /**
180
+ * Convert a set of MapBox geocoding options to URL search parameters
181
+ * @param options The MapBox geocoding options
182
+ * @returns A `URLSearchParams` object that can be used for a MapBox query
183
+ */
133
184
  function searchParams(options: MapBoxForwardGeocodingOptions | MapBoxReverseGeocodingOptions): URLSearchParams {
134
185
  const search = new URLSearchParams();
135
186
  const queryParams = convertOptionsToQueryParams(options);
@@ -137,6 +188,13 @@ function searchParams(options: MapBoxForwardGeocodingOptions | MapBoxReverseGeoc
137
188
  return search;
138
189
  }
139
190
 
191
+ /**
192
+ * Obtain text describing a given longitude and latitude based on a MapBox reverse geocoding query
193
+ * @param longitudeDeg The longitude of the location, in degrees
194
+ * @param latitudeDeg The latitude of the location, in degrees
195
+ * @param options Options for the MapBox reverse geocoding
196
+ * @returns A promise that resolves to the string describing the given coordinates
197
+ */
140
198
  export async function textForLocation(longitudeDeg: number, latitudeDeg: number, options: MapBoxReverseGeocodingOptions): Promise<string> {
141
199
  const search = searchParams(options);
142
200
  const url = `https://api.mapbox.com/geocoding/v5/mapbox.places/${longitudeDeg},${latitudeDeg}.json?${search.toString()}`;
@@ -154,6 +212,14 @@ export async function textForLocation(longitudeDeg: number, latitudeDeg: number,
154
212
  });
155
213
  }
156
214
 
215
+ /**
216
+ * Obtain a collection of MapBox items obtained from performing a forward geocoding query for a particular search string.
217
+ * Note that the number of items returned is set by the `limit` field in your options.
218
+ * If `limit` is not specified, the MapBox default is 5
219
+ * @param searchText The search string
220
+ * @param options Options for the MapBox forward geocoding
221
+ * @returns A promise that resolves to the found collection of MapBox items
222
+ */
157
223
  export async function geocodingInfoForSearch(searchText: string, options: MapBoxForwardGeocodingOptions): Promise<MapBoxFeatureCollection> {
158
224
  const search = searchParams(options);
159
225
  const url = `https://api.mapbox.com/geocoding/v5/mapbox.places/${searchText}.json?${search.toString()}`;