tosijs-ui 1.0.0 → 1.0.2

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 (94) hide show
  1. package/README.md +4 -2
  2. package/dist/iife.js +70 -60
  3. package/dist/iife.js.map +42 -42
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.js +15 -37
  6. package/dist/index.js.map +39 -39
  7. package/dist/version.d.ts +1 -1
  8. package/package.json +2 -2
  9. package/dist/ab-test.js +0 -116
  10. package/dist/babylon-3d.js +0 -292
  11. package/dist/bodymovin-player.js +0 -172
  12. package/dist/bp-loader.js +0 -26
  13. package/dist/carousel.js +0 -308
  14. package/dist/code-editor.js +0 -102
  15. package/dist/color-input.js +0 -112
  16. package/dist/data-table.js +0 -774
  17. package/dist/drag-and-drop.js +0 -386
  18. package/dist/editable-rect.js +0 -450
  19. package/dist/filter-builder.js +0 -468
  20. package/dist/float.js +0 -170
  21. package/dist/form.js +0 -466
  22. package/dist/gamepad.js +0 -115
  23. package/dist/icon-data.js +0 -308
  24. package/dist/icon-types.js +0 -1
  25. package/dist/icons.js +0 -374
  26. package/dist/index-iife.js +0 -4
  27. package/dist/live-example.js +0 -611
  28. package/dist/localize.js +0 -381
  29. package/dist/make-sorter.js +0 -119
  30. package/dist/make-sorter.test.d.ts +0 -1
  31. package/dist/make-sorter.test.js +0 -48
  32. package/dist/mapbox.js +0 -161
  33. package/dist/markdown-viewer.js +0 -173
  34. package/dist/match-shortcut.js +0 -13
  35. package/dist/match-shortcut.test.d.ts +0 -1
  36. package/dist/match-shortcut.test.js +0 -194
  37. package/dist/menu.js +0 -614
  38. package/dist/notifications.js +0 -308
  39. package/dist/password-strength.js +0 -302
  40. package/dist/playwright.config.d.ts +0 -9
  41. package/dist/playwright.config.js +0 -73
  42. package/dist/pop-float.js +0 -231
  43. package/dist/rating.js +0 -192
  44. package/dist/rich-text.js +0 -296
  45. package/dist/segmented.js +0 -298
  46. package/dist/select.js +0 -427
  47. package/dist/side-nav.js +0 -106
  48. package/dist/size-break.js +0 -118
  49. package/dist/sizer.js +0 -92
  50. package/dist/src/ab-test.d.ts +0 -14
  51. package/dist/src/babylon-3d.d.ts +0 -53
  52. package/dist/src/bodymovin-player.d.ts +0 -32
  53. package/dist/src/bp-loader.d.ts +0 -0
  54. package/dist/src/carousel.d.ts +0 -113
  55. package/dist/src/code-editor.d.ts +0 -27
  56. package/dist/src/color-input.d.ts +0 -41
  57. package/dist/src/data-table.d.ts +0 -79
  58. package/dist/src/drag-and-drop.d.ts +0 -2
  59. package/dist/src/editable-rect.d.ts +0 -97
  60. package/dist/src/filter-builder.d.ts +0 -64
  61. package/dist/src/float.d.ts +0 -18
  62. package/dist/src/form.d.ts +0 -68
  63. package/dist/src/gamepad.d.ts +0 -34
  64. package/dist/src/icon-data.d.ts +0 -309
  65. package/dist/src/icon-types.d.ts +0 -7
  66. package/dist/src/icons.d.ts +0 -17
  67. package/dist/src/index.d.ts +0 -37
  68. package/dist/src/live-example.d.ts +0 -51
  69. package/dist/src/localize.d.ts +0 -30
  70. package/dist/src/make-sorter.d.ts +0 -3
  71. package/dist/src/mapbox.d.ts +0 -24
  72. package/dist/src/markdown-viewer.d.ts +0 -15
  73. package/dist/src/match-shortcut.d.ts +0 -9
  74. package/dist/src/menu.d.ts +0 -60
  75. package/dist/src/notifications.d.ts +0 -106
  76. package/dist/src/password-strength.d.ts +0 -35
  77. package/dist/src/pop-float.d.ts +0 -10
  78. package/dist/src/rating.d.ts +0 -62
  79. package/dist/src/rich-text.d.ts +0 -28
  80. package/dist/src/segmented.d.ts +0 -80
  81. package/dist/src/select.d.ts +0 -43
  82. package/dist/src/side-nav.d.ts +0 -36
  83. package/dist/src/size-break.d.ts +0 -18
  84. package/dist/src/sizer.d.ts +0 -34
  85. package/dist/src/tab-selector.d.ts +0 -91
  86. package/dist/src/tag-list.d.ts +0 -37
  87. package/dist/src/track-drag.d.ts +0 -5
  88. package/dist/src/version.d.ts +0 -1
  89. package/dist/src/via-tag.d.ts +0 -2
  90. package/dist/tab-selector.js +0 -326
  91. package/dist/tag-list.js +0 -375
  92. package/dist/track-drag.js +0 -143
  93. package/dist/version.js +0 -1
  94. package/dist/via-tag.js +0 -102
package/dist/localize.js DELETED
@@ -1,381 +0,0 @@
1
- /*#
2
- # localize
3
-
4
- `xinjs-ui` provides support for localization via the `localize` method and the `<xin-locale-picker>`
5
- and `<xin-localized>` custom-elements.
6
-
7
- > ### Important Note
8
- > This module deals with the **language** used in the user interface. "locale" is
9
- > *not the same thing*. The (usually) two-letter codes used designate **language**
10
- > and **not locale**.
11
- >
12
- > E.g. the US *locale* includes things like measurement systems
13
- > and date format. Most European locales use commas where we use decimal points in the US.
14
- >
15
- > Similarly, `ja` is the code for the Japanese **language** while `jp` is the **locale**.
16
-
17
- ## `initLocalization(localizationData: string)`
18
-
19
- Enables localization from TSV string data.
20
-
21
- ## XinLocalePicker
22
-
23
- A selector that lets the user pick from among supported languages.
24
-
25
- ```html
26
- <h3>Locale Picker</h3>
27
- <xin-locale-picker></xin-locale-picker>
28
-
29
- <h3>Locale Picker with <code>hide-captions</code></h3>
30
- <xin-locale-picker hide-caption></xin-locale-picker>
31
- ```
32
-
33
- ## `localize()`
34
-
35
- If you just want to localize a string with code, use `localize(s: string): string`.
36
-
37
- If the reference string only matches when both are converted to
38
- lowercase, the output string will also be lowercase.
39
-
40
- E.g. if you have localized `Cancel` as `Annuler`, then `localize("cancel")
41
- will output `annuler`.
42
-
43
- ### ellipses
44
-
45
- If you end a string with an ellipsis, `localize` will ignore the ellipsis,
46
- localize the string, and then append the ellipsis.
47
-
48
- ## `setLocale(language: string)`
49
-
50
- ```js
51
- const { button, p } = xinjs.elements
52
- const { setLocale } = xinjsui
53
-
54
- preview.append(
55
- p(
56
- button(
57
- {
58
- onClick() {
59
- setLocale('en-US')
60
- }
61
- },
62
- 'setLocale("en-US")'
63
- )
64
- ),
65
- p(
66
- button(
67
- {
68
- onClick() {
69
- setLocale('fr')
70
- }
71
- },
72
- 'setLocale("fr")'
73
- )
74
- ),
75
- p(
76
- button(
77
- {
78
- onClick() {
79
- setLocale('qq')
80
- }
81
- },
82
- 'setLocale("qq") (see console for error message)'
83
- )
84
- ),
85
- )
86
- ```
87
-
88
- If you want to directly set locale, just use `setLocale()`.
89
-
90
- ## XinLocalized
91
-
92
- A span-replacement that automatically localizes its text content.
93
- By default the case in the localized data is preserved unless the
94
- reference text is all lowercase, in which case the localized text
95
- is also lowercased.
96
-
97
- While viewing this documentation, all `<xin-localized>` elements should display a **red
98
- underline**.
99
-
100
- ```html
101
- <h3>Localized Widgets</h3>
102
- <button><xin-localized>Yes</xin-localized></button>
103
- <button><xin-localized>No</xin-localized></button>
104
- <button><xin-localized>Open…</xin-localized></button> <i>note the ellipsis</i>
105
-
106
- <h3>Lowercase is preserved</h3>
107
- <button><xin-localized>yes</xin-localized></button>
108
- <button><xin-localized>no</xin-localized></button>
109
- <button><xin-localized>open…</xin-localized></button>
110
-
111
- <h3>Localized Attribute</h3>
112
- <input>
113
- ```
114
- ```css
115
- xin-localized {
116
- border-bottom: 2px solid red;
117
- }
118
- ```
119
- ```js
120
- const { xinLocalized, localize } = xinjsui
121
-
122
- preview.append(xinLocalized({
123
- refString: 'localized placeholder',
124
- localeChanged() {
125
- this.previousElementSibling.setAttribute('placeholder', localize(this.refString))
126
- }
127
- }))
128
- ```
129
-
130
- `<xin-localized>` has a `refString` attribute (which defaults to its initial `textContent`)
131
- which is the text that it localizes. You can set it directly.
132
-
133
- It also has an `localeChanged` method which defaults to setting the content of the element
134
- to the localized reference string, but which you can override, to (for example) set a property
135
- or attribute of the parent element.
136
-
137
- > `<xin-localized>` *can* be used inside the shadowDOM of other custom-elements.
138
-
139
- ## `i18n`
140
-
141
- All of the data can be bound in the `i18n` proxy (`xin.i18n`), including the currently selected
142
- locale (which will default to `navigator.language`).
143
-
144
- You can take a look at `xin.i18n` in the console. `i18n` can be used to access localization
145
- data directly, and also to determine which locales are available `i18n.locales` and set the
146
- locale programmatically (e.g. `i18n.locale = 'en'`).
147
-
148
- ```
149
- if (i18n.locales.includes('fr')) {
150
- i18n.locale = 'fr'
151
- }
152
- ```
153
-
154
- ## Creating Localized String Data
155
-
156
- You can create your own localization data using any spreadsheet and exporting TSV.
157
-
158
- E.g. you can automatically create localization data
159
- using something like my [localized](https://docs.google.com/spreadsheets/d/1L0_4g_dDhVCwVVxLzYbMj_H86xSp9lsRCKj7IS9psso/edit?usp=sharing)
160
- Google Sheet which leverages `googletranslate` to automatically translate reference strings
161
- (and which you can manually override as you like).
162
-
163
- E.g. in this demo I've replaced the incorrect translation of "Finnish"
164
- (`googletranslate` used the word for Finnish nationality rather than the language).
165
-
166
- The format of the input data is a table in TSV format, that looks like this:
167
-
168
- en-US | fr | fi | sv | zh
169
- ------|----|----|----|----
170
- English (US) | French | Finnish | Swedish | Chinese (Mandarin)
171
- English (US) | Français | suomi | svenska | 中文(普通话)
172
- 🇺🇸 | 🇫🇷 | 🇫🇮 | 🇸🇪 | 🇨🇳
173
- Icon | Icône | Kuvake | Ikon | 图标
174
- Ok | D'accord | Ok | Ok | 好的
175
- Cancel | Annuler | Peruuttaa | Avboka | 取消
176
-
177
- - Column 1 is your reference language.
178
- - Row 1 is [language code](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes).
179
- - Row 2 is the name of the language in your reference language.
180
- - Row 3 is the name of the language in itself (because it's silly to expect people
181
- to know the name of their language in a language they don't know)
182
- - Row 4 is the flag emoji for that language (yes, that's problematic, but languages
183
- do not have flags, per se)
184
- - Rows 5 and on are user interface strings you want to localize
185
-
186
- In the spreadsheet provided, each cell contains a formula that translates the term
187
- in the left-most column from the language in that column to the language in the
188
- destination column. Once you have an automatic translation, you can hand off the
189
- sheet to language experts to vet the translations.
190
-
191
- Finally, create a `tsv` file and then turn that into a Typescript file by wrapping
192
- the content thus:
193
-
194
- ```
195
- export default `( content of tsv file )`
196
- ```
197
-
198
- You use this data using `initLocalization()`.
199
-
200
- ## Leveraging XinLocalized Automatic Updates
201
-
202
- If you want to leverage XinLocalized's automatic updates you simply need to
203
- implement `updateLocale` and register yourself with `XinLocalized.allInstances`
204
- (which is a `Set<AbstractLocalized>).
205
-
206
- Typically, this would look like something like:
207
-
208
- ```
209
- class MyLocalizedComponent extends Component {
210
- ...
211
-
212
- // register yourself as a localized component
213
- connectecCallback() {
214
- super.connectedCallback()
215
-
216
- XinLocalized.allInstances.add(this)
217
- }
218
-
219
- // avoid leaking!
220
- disconnectecCallback() {
221
- super.connectedCallback()
222
-
223
- XinLocalized.allInstances.delete(this)
224
- }
225
-
226
- // presumably your render method does the right things
227
- updateLocale = () => {
228
- this.queueRender()
229
- }
230
- }
231
- ```
232
- */
233
- import { Component, boxedProxy, elements, bindings, observe } from 'xinjs';
234
- import { makeSorter } from './make-sorter';
235
- import { xinSelect, XinSelect } from './select';
236
- const { span } = elements;
237
- export const { i18n } = boxedProxy({
238
- i18n: {
239
- locale: window.navigator.language,
240
- locales: [window.navigator.language],
241
- languages: [window.navigator.language],
242
- emoji: [''],
243
- stringMap: {},
244
- localeOptions: [
245
- {
246
- icon: span(),
247
- caption: window.navigator.language,
248
- value: window.navigator.language,
249
- },
250
- ],
251
- },
252
- });
253
- bindings.localeOptions = {
254
- toDOM(select, options) {
255
- if (select instanceof XinSelect) {
256
- select.options = options;
257
- }
258
- },
259
- };
260
- export const setLocale = (language) => {
261
- if (i18n.locales.includes(language)) {
262
- i18n.locale = language;
263
- }
264
- else {
265
- console.error(`language ${language} is not available`);
266
- }
267
- };
268
- export const updateLocalized = () => {
269
- const localizeds = Array.from(XinLocalized.allInstances);
270
- for (const localized of localizeds) {
271
- localized.localeChanged();
272
- }
273
- };
274
- observe(i18n.locale.xinPath, updateLocalized);
275
- const captionSort = makeSorter((locale) => [
276
- locale.caption.toLocaleLowerCase(),
277
- ]);
278
- export function initLocalization(localizedStrings) {
279
- const [locales, , languages, emoji, ...strings] = localizedStrings
280
- .split('\n')
281
- .map((line) => line.split('\t'));
282
- if (locales && languages && emoji && strings) {
283
- i18n.locales = locales;
284
- i18n.languages = languages;
285
- i18n.emoji = emoji;
286
- i18n.stringMap = strings.reduce((map, strings) => {
287
- map[strings[0].toLocaleLowerCase()] = strings;
288
- return map;
289
- }, {});
290
- i18n.localeOptions = locales
291
- .map((locale, index) => ({
292
- icon: span({ title: locales[index] }, emoji[index]),
293
- caption: languages[index],
294
- value: locale,
295
- }))
296
- .sort(captionSort);
297
- // if user locale isn't available, find the best match
298
- if (!i18n.locales.includes(i18n.locale.valueOf())) {
299
- const language = i18n.locale.substring(0, 2);
300
- i18n.locale =
301
- i18n.locales.find((locale) => locale.substring(0, 2) === language) ||
302
- i18n.locales[0];
303
- }
304
- updateLocalized();
305
- }
306
- }
307
- export function localize(ref) {
308
- if (ref.endsWith('…')) {
309
- return localize(ref.substring(0, ref.length - 1)) + '…';
310
- }
311
- const index = i18n.locales.indexOf(i18n.locale.valueOf());
312
- if (index > -1) {
313
- const map = i18n.stringMap[ref.toLocaleLowerCase()];
314
- const localized = map && map[index];
315
- if (localized) {
316
- ref =
317
- ref.toLocaleLowerCase() === ref
318
- ? localized.toLocaleLowerCase()
319
- : localized.valueOf();
320
- }
321
- }
322
- return ref;
323
- }
324
- export class LocalePicker extends Component {
325
- hideCaption = false;
326
- content = () => {
327
- return xinSelect({
328
- part: 'select',
329
- showIcon: true,
330
- title: localize('Language'),
331
- bindValue: i18n.locale,
332
- bindLocaleOptions: i18n.localeOptions,
333
- });
334
- };
335
- constructor() {
336
- super();
337
- this.initAttributes('hideCaption');
338
- }
339
- render() {
340
- super.render();
341
- this.parts.select.toggleAttribute('hide-caption', this.hideCaption);
342
- }
343
- }
344
- export const localePicker = LocalePicker.elementCreator({
345
- tag: 'xin-locale-picker',
346
- });
347
- export class XinLocalized extends Component {
348
- static allInstances = new Set();
349
- contents = () => elements.xinSlot();
350
- refString = '';
351
- constructor() {
352
- super();
353
- this.initAttributes('refString');
354
- }
355
- connectedCallback() {
356
- super.connectedCallback();
357
- XinLocalized.allInstances.add(this);
358
- }
359
- disconnectedCallback() {
360
- super.disconnectedCallback();
361
- XinLocalized.allInstances.delete(this);
362
- }
363
- localeChanged() {
364
- if (!this.refString) {
365
- this.refString = this.textContent || '';
366
- }
367
- this.textContent = this.refString ? localize(this.refString) : '';
368
- }
369
- render() {
370
- super.render();
371
- this.localeChanged();
372
- }
373
- }
374
- export const xinLocalized = XinLocalized.elementCreator({
375
- tag: 'xin-localized',
376
- styleSpec: {
377
- ':host': {
378
- pointerEvents: 'none',
379
- },
380
- },
381
- });
@@ -1,119 +0,0 @@
1
- /*#
2
- # makeSorter
3
-
4
- I'm always confusing myself when writing sort functions, so I wrote `makeSorter()`. It's
5
- insanely simple and just works™. It makes writing an array sort callback for anything
6
- other than an array of numbers or strings easier.
7
-
8
- ```js
9
- const { select, option, div, span, ul, li } = xinjs.elements
10
- const { icons, makeSorter } = xinjsui
11
-
12
- const people = [
13
- { first: 'Frasier', last: 'Crane', age: 38 },
14
- { first: 'Lilith', last: 'Crane', age: 37 },
15
- { first: 'Rebecca', last: 'Howe', age: 35 },
16
- { first: 'Woody', last: 'Boyd', age: 25 },
17
- { first: 'Sam', last: 'Malone', age: 40 },
18
- { first: 'Norm', last: 'Peterson', age: 38 },
19
- ]
20
-
21
- const sorters = {
22
- firstSort: makeSorter(person => [person.first]),
23
- firstDescSort: makeSorter(person => [person.first], false),
24
- nameSort: makeSorter(person => [person.last, person.first]),
25
- ageFirst: makeSorter(person => [-person.age, person.last]),
26
- ageLast: makeSorter(person => [person.age, person.first], [true, false]),
27
- }
28
-
29
- function person({first, last, age}) {
30
- return li(`${first} ${last}, ${age}`)
31
- }
32
-
33
- const list = ul()
34
- sortPicker = select(
35
- option('Sort by first', {value: 'firstSort'}),
36
- option('Sort by first (desc)', {value: 'firstDescSort'}),
37
- option('Sort by last, first', {value: 'nameSort'}),
38
- option('Sort by age (desc), first', {value: 'ageFirst'}),
39
- option('Sort by age, last (desc)', {value: 'ageLast'}),
40
- {
41
- onChange: render,
42
- value: 'nameSort'
43
- },
44
- )
45
-
46
- function render () {
47
- list.textContent = ''
48
- list.append(...people.sort(sorters[sortPicker.value]).map(person))
49
- }
50
-
51
- preview.append(
52
- div(
53
- sortPicker,
54
- icons.chevronDown()
55
- ),
56
- list
57
- )
58
-
59
- render()
60
- ```
61
- ```css
62
- .preview {
63
- padding: var(--spacing);
64
- }
65
-
66
- .preview div {
67
- position: absolute;
68
- top: var(--spacing);
69
- right: var(--spacing);
70
- }
71
- ```
72
-
73
- ## Details
74
-
75
- To create a sort callback that sorts by propA then propB (if propA is tied):
76
-
77
- ```
78
- const sorter = makeSorter(
79
- obj => [obj.propA, obj.propB]
80
- )
81
- ```
82
-
83
- As above, but sort descending:
84
- ```
85
- const sorter = makeSorter(
86
- obj => [obj.propA, obj.propB],
87
- false
88
- )
89
- ```
90
-
91
- As above but propA is sorted ascending, propB descending
92
- ```
93
- const sorter = makeSorter(
94
- obj => [obj.propA, obj.propB],
95
- [true, false]
96
- )
97
- ```
98
- */
99
- export function makeSorter(sortValuator, ascending = true) {
100
- return (p, q) => {
101
- const pSort = sortValuator(p);
102
- const qSort = sortValuator(q);
103
- for (const i in pSort) {
104
- if (pSort[i] !== qSort[i]) {
105
- const isAscending = Array.isArray(ascending)
106
- ? ascending[i] !== false
107
- : ascending;
108
- return isAscending
109
- ? pSort[i] > qSort[i]
110
- ? 1
111
- : -1
112
- : pSort[i] > qSort[i]
113
- ? -1
114
- : 1;
115
- }
116
- }
117
- return 0;
118
- };
119
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,48 +0,0 @@
1
- /* eslint-disable */
2
- import { test, expect } from 'bun:test';
3
- import { makeSorter } from './make-sorter';
4
- test('sorts simple values', () => {
5
- const simpleSort = makeSorter((a) => [a]);
6
- const array = [5, -1, 3];
7
- expect([...array].sort(simpleSort)[0]).toBe(-1);
8
- expect([...array].sort(simpleSort)[1]).toBe(3);
9
- const strings = ['oh', 'be', 'a', 'fine'];
10
- expect([...strings].sort(simpleSort)[0]).toBe('a');
11
- expect([...strings].sort(simpleSort)[1]).toBe('be');
12
- });
13
- test('sorts simple values descending', () => {
14
- const simpleSort = makeSorter((a) => [a], false);
15
- const array = [5, -1, 3];
16
- expect([...array].sort(simpleSort)[0]).toBe(5);
17
- expect([...array].sort(simpleSort)[1]).toBe(3);
18
- const strings = ['oh', 'be', 'a', 'fine'];
19
- expect([...strings].sort(simpleSort)[0]).toBe('oh');
20
- expect([...strings].sort(simpleSort)[1]).toBe('fine');
21
- });
22
- test('sorts compound objects', () => {
23
- const sortNameThenId = makeSorter((a) => [
24
- a.name,
25
- a.id,
26
- ]);
27
- const sortLowercaseNameThenId = makeSorter((a) => [a.name.toLocaleLowerCase(), a.id]);
28
- const idThenName = makeSorter((a) => [
29
- a.id,
30
- a.name,
31
- ]);
32
- const array = [
33
- { name: 'alice', id: 100 },
34
- { name: 'bob', id: 1 },
35
- { name: 'alice', id: 10 },
36
- { name: 'Zed', id: 5 },
37
- { name: 'smaug', id: -7 },
38
- ];
39
- expect([...array].sort(sortNameThenId)[0].id).toBe(5);
40
- expect([...array].sort(sortNameThenId)[2].id).toBe(100);
41
- expect([...array].sort(sortNameThenId)[4].id).toBe(-7);
42
- expect([...array].sort(sortLowercaseNameThenId)[0].id).toBe(10);
43
- expect([...array].sort(sortLowercaseNameThenId)[2].id).toBe(1);
44
- expect([...array].sort(sortLowercaseNameThenId)[4].id).toBe(5);
45
- expect([...array].sort(idThenName)[0].id).toBe(-7);
46
- expect([...array].sort(idThenName)[2].id).toBe(5);
47
- expect([...array].sort(idThenName)[4].id).toBe(100);
48
- });
package/dist/mapbox.js DELETED
@@ -1,161 +0,0 @@
1
- /*#
2
- # map
3
-
4
- A [mapboxgl](https://docs.mapbox.com/mapbox-gl-js/api/) wrapper.
5
-
6
- ```js
7
- const pickStyle = preview.querySelector('select')
8
- const mapbox = preview.querySelector('xin-map')
9
- const here = preview.querySelector('button')
10
-
11
- pickStyle.addEventListener('change', () => {
12
- mapbox.mapStyle = pickStyle.value
13
- })
14
-
15
- function getUserGPSCoordinates() {
16
- return new Promise((resolve) => {
17
- // Check if geolocation is supported
18
- if (!navigator.geolocation) {
19
- console.log("Geolocation is not supported by this browser.");
20
- resolve(null);
21
- return;
22
- }
23
-
24
- // Request position with options
25
- navigator.geolocation.getCurrentPosition(
26
- // Success callback
27
- (position) => {
28
- resolve({
29
- latitude: position.coords.latitude,
30
- longitude: position.coords.longitude
31
- });
32
- },
33
- // Error callback
34
- (error) => {
35
- console.log(`Error getting location: ${error.message}`);
36
- resolve(null);
37
- },
38
- // Options
39
- {
40
- enableHighAccuracy: true, // Request high accuracy if available
41
- timeout: 10000, // Time to wait for position (10 seconds)
42
- maximumAge: 0 // Don't use cached position
43
- }
44
- );
45
- });
46
- }
47
-
48
- here.addEventListener('click', async () => {
49
- const location = await getUserGPSCoordinates()
50
- if (location) {
51
- mapbox.coords = `${location.latitude},${location.longitude},12`
52
- }
53
- })
54
- ```
55
- ```html
56
- <!-- please don't abuse my mapbox token -->
57
- <xin-map
58
- style="width: 100%; height: 100%"
59
- coords="14.0093606,120.995083,17"
60
- token="pk.eyJ1IjoicG9kcGVyc29uIiwiYSI6ImNqc2JlbWU0bjA1ZmY0YW5ycHZod3VhbWcifQ.arvqfpOqMgFYkKgQ35UScA"
61
- map-style="mapbox://styles/mapbox/streets-v12"
62
- ></xin-map>
63
- <select>
64
- <option selected value="mapbox://styles/mapbox/streets-v12">Streets</option>
65
- <option value="mapbox://styles/mapbox/satellite-v9">Satellite</option>
66
- <option value="mapbox://styles/mapbox/light-v11">Light</option>
67
- <option value="mapbox://styles/mapbox/dark-v11">Dark</option>
68
- <option value="mapbox://styles/mapbox/outdoors-v12">Outdoors</option>
69
- </select>
70
- <button>
71
- <xin-icon icon="mapPin"></xin-icon>
72
- <span>Your Location</span>
73
- </button>
74
- ```
75
- ```css
76
- .preview button {
77
- position: absolute;
78
- right: 10px;
79
- top: 10px;
80
- display: flex;
81
- align-items: center;
82
- gap: 5px;
83
- }
84
-
85
- .preview select {
86
- position: absolute;
87
- bottom: 10px;
88
- right: 10px;
89
- }
90
- ```
91
-
92
- There's no need to learn new APIs or write wrappers, just access the element's `map` property
93
- and [use the standard mapbox APIs directly](https://docs.mapbox.com/api/maps/styles/).
94
- */
95
- import { Component as WebComponent, elements } from 'xinjs';
96
- import { styleSheet, scriptTag } from './via-tag';
97
- const { div } = elements;
98
- export class MapBox extends WebComponent {
99
- coords = '65.01715565258993,25.48081004203459,12';
100
- content = div({ style: { width: '100%', height: '100%' } });
101
- get map() {
102
- return this._map;
103
- }
104
- mapStyle = 'mapbox://styles/mapbox/streets-v12';
105
- token = '';
106
- static mapboxCSSAvailable;
107
- static mapboxAvailable;
108
- _map;
109
- static styleSpec = {
110
- ':host': {
111
- display: 'inline-block',
112
- position: 'relative',
113
- width: '400px',
114
- height: '400px',
115
- textAlign: 'left',
116
- },
117
- };
118
- constructor() {
119
- super();
120
- this.initAttributes('coords', 'token', 'mapStyle');
121
- if (MapBox.mapboxCSSAvailable === undefined) {
122
- MapBox.mapboxCSSAvailable = styleSheet('https://api.mapbox.com/mapbox-gl-js/v1.4.1/mapbox-gl.css').catch((e) => {
123
- console.error('failed to load mapbox-gl.css', e);
124
- });
125
- MapBox.mapboxAvailable = scriptTag('https://api.mapbox.com/mapbox-gl-js/v1.4.1/mapbox-gl.js').catch((e) => {
126
- console.error('failed to load mapbox-gl.js', e);
127
- });
128
- }
129
- }
130
- connectedCallback() {
131
- super.connectedCallback();
132
- if (!this.token) {
133
- console.error('mapbox requires an access token which you can provide via the token attribute');
134
- }
135
- }
136
- render() {
137
- super.render();
138
- if (!this.token) {
139
- return;
140
- }
141
- const { div } = this.parts;
142
- const [long, lat, zoom] = this.coords.split(',').map((x) => Number(x));
143
- if (this.map) {
144
- this.map.remove();
145
- }
146
- MapBox.mapboxAvailable.then(({ mapboxgl }) => {
147
- console.log("%cmapbox may complain about missing css -- don't panic!", 'background: orange; color: black; padding: 0 5px;');
148
- mapboxgl.accessToken = this.token;
149
- this._map = new mapboxgl.Map({
150
- container: div,
151
- style: this.mapStyle,
152
- zoom,
153
- center: [lat, long],
154
- });
155
- this._map.on('render', () => this._map.resize());
156
- });
157
- }
158
- }
159
- export const mapBox = MapBox.elementCreator({
160
- tag: 'xin-map',
161
- });