@atlaskit/link-picker 0.0.2 → 0.7.0

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 (66) hide show
  1. package/CHANGELOG.md +140 -0
  2. package/README.md +27 -5
  3. package/dist/cjs/browser.js +39 -0
  4. package/dist/cjs/index.js +2 -2
  5. package/dist/cjs/messages.js +102 -0
  6. package/dist/cjs/styles.js +90 -0
  7. package/dist/cjs/transformTimeStamp.js +55 -0
  8. package/dist/cjs/types.js +5 -0
  9. package/dist/cjs/ui/LinkSearchList.js +112 -0
  10. package/dist/cjs/ui/LinkSearchListItem.js +101 -0
  11. package/dist/cjs/ui/PanelTextInput.js +119 -0
  12. package/dist/cjs/ui/announcer.js +64 -0
  13. package/dist/cjs/ui/link-picker.js +584 -0
  14. package/dist/cjs/url.js +104 -0
  15. package/dist/cjs/utils.js +40 -0
  16. package/dist/cjs/version.json +1 -1
  17. package/dist/es2019/browser.js +34 -0
  18. package/dist/es2019/index.js +1 -1
  19. package/dist/es2019/messages.js +93 -0
  20. package/dist/es2019/styles.js +94 -0
  21. package/dist/es2019/transformTimeStamp.js +41 -0
  22. package/dist/es2019/types.js +1 -0
  23. package/dist/es2019/ui/LinkSearchList.js +65 -0
  24. package/dist/es2019/ui/LinkSearchListItem.js +88 -0
  25. package/dist/es2019/ui/PanelTextInput.js +93 -0
  26. package/dist/es2019/ui/announcer.js +38 -0
  27. package/dist/es2019/ui/link-picker.js +480 -0
  28. package/dist/es2019/url.js +88 -0
  29. package/dist/es2019/utils.js +24 -0
  30. package/dist/es2019/version.json +1 -1
  31. package/dist/esm/browser.js +34 -0
  32. package/dist/esm/index.js +1 -1
  33. package/dist/esm/messages.js +93 -0
  34. package/dist/esm/styles.js +46 -0
  35. package/dist/esm/transformTimeStamp.js +41 -0
  36. package/dist/esm/types.js +1 -0
  37. package/dist/esm/ui/LinkSearchList.js +87 -0
  38. package/dist/esm/ui/LinkSearchListItem.js +88 -0
  39. package/dist/esm/ui/PanelTextInput.js +93 -0
  40. package/dist/esm/ui/announcer.js +51 -0
  41. package/dist/esm/ui/link-picker.js +559 -0
  42. package/dist/esm/url.js +90 -0
  43. package/dist/esm/utils.js +24 -0
  44. package/dist/esm/version.json +1 -1
  45. package/dist/types/browser.d.ts +15 -0
  46. package/dist/types/index.d.ts +3 -1
  47. package/dist/types/messages.d.ts +92 -0
  48. package/dist/types/styles.d.ts +18 -0
  49. package/dist/types/transformTimeStamp.d.ts +3 -0
  50. package/dist/types/types.d.ts +37 -0
  51. package/dist/types/ui/LinkSearchList.d.ts +20 -0
  52. package/dist/types/ui/LinkSearchListItem.d.ts +17 -0
  53. package/dist/types/ui/PanelTextInput.d.ts +17 -0
  54. package/dist/types/ui/announcer.d.ts +22 -0
  55. package/dist/types/ui/link-picker.d.ts +79 -0
  56. package/dist/types/url.d.ts +5 -0
  57. package/dist/types/utils.d.ts +4 -0
  58. package/example-helpers/flight-deck/_manifest.json +9 -0
  59. package/example-helpers/flight-deck/mockFDResponse.json +133 -0
  60. package/example-helpers/mock-data.ts +316 -0
  61. package/example-helpers/providers.ts +39 -0
  62. package/package.json +35 -6
  63. package/dist/cjs/link-picker.js +0 -12
  64. package/dist/es2019/link-picker.js +0 -3
  65. package/dist/esm/link-picker.js +0 -3
  66. package/dist/types/link-picker.d.ts +0 -1
@@ -0,0 +1,480 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+
3
+ /** @jsx jsx */
4
+ import React, { PureComponent } from 'react';
5
+ import { jsx } from '@emotion/core';
6
+ import { injectIntl } from 'react-intl-next';
7
+ import { messages } from '../messages';
8
+ import PanelTextInput from './PanelTextInput';
9
+ import LinkSearchList from './LinkSearchList';
10
+ import { normalizeUrl, isSafeUrl } from '../url';
11
+ import { recentListStyles, Container, SearchIconWrapper, ListTitleStyles } from '../styles';
12
+ import { browser } from '../browser';
13
+ import { transformTimeStamp } from '../transformTimeStamp';
14
+ import Announcer from './announcer';
15
+ import Button, { ButtonGroup } from '@atlaskit/button';
16
+ import { FormFooter } from '@atlaskit/form';
17
+ import EditorSearchIcon from '@atlaskit/icon/glyph/editor/search';
18
+ import VisuallyHidden from '@atlaskit/visually-hidden';
19
+ export const RECENT_SEARCH_LIST_SIZE = 5;
20
+ export class LinkPicker extends PureComponent {
21
+ constructor(props) {
22
+ super(props);
23
+
24
+ _defineProperty(this, "wrapperRef", /*#__PURE__*/React.createRef());
25
+
26
+ _defineProperty(this, "queryVersion", 0);
27
+
28
+ _defineProperty(this, "updateInput", async input => {
29
+ // If input is a valid URL, do not search or display link suggestions
30
+ if (input.length && isSafeUrl(input)) {
31
+ return this.setState({
32
+ url: input,
33
+ selectedIndex: -1,
34
+ items: [],
35
+ isLoading: false,
36
+ invalidUrl: null
37
+ });
38
+ }
39
+
40
+ return this.setState({
41
+ url: input,
42
+ // Unset selection on any input change
43
+ selectedIndex: -1,
44
+ invalidUrl: null
45
+ }, () => {
46
+ this.updateResults();
47
+ });
48
+ });
49
+
50
+ _defineProperty(this, "createClearHandler", field => {
51
+ return () => {
52
+ switch (field) {
53
+ case 'url':
54
+ {
55
+ this.updateInput('');
56
+ break;
57
+ }
58
+
59
+ case 'displayText':
60
+ {
61
+ this.setState({
62
+ [field]: ''
63
+ });
64
+ }
65
+ }
66
+ };
67
+ });
68
+
69
+ _defineProperty(this, "getScreenReaderText", () => {
70
+ const {
71
+ intl
72
+ } = this.props;
73
+ const {
74
+ items,
75
+ selectedIndex
76
+ } = this.state;
77
+
78
+ if (items.length && selectedIndex > -1) {
79
+ const {
80
+ name,
81
+ container,
82
+ lastUpdatedDate,
83
+ lastViewedDate
84
+ } = items[selectedIndex];
85
+ const date = transformTimeStamp(intl, lastViewedDate, lastUpdatedDate);
86
+ return `${name}, ${container}, ${date === null || date === void 0 ? void 0 : date.pageAction} ${date === null || date === void 0 ? void 0 : date.dateString} ${(date === null || date === void 0 ? void 0 : date.timeSince) || ''}`;
87
+ }
88
+ });
89
+
90
+ _defineProperty(this, "isUrlPopulatedWithSelectedItem", () => {
91
+ /**
92
+ * When we use ArrowKey to navigate through result items,
93
+ * the URL field will be populated with the content of
94
+ * selected item.
95
+ * This function will check if the URL field is populated
96
+ * with selected item.
97
+ * It can be useful to detect whether we want to insert a
98
+ * smartlink or a hyperlink with customized title
99
+ */
100
+ const {
101
+ items,
102
+ selectedIndex,
103
+ url
104
+ } = this.state;
105
+ const selectedItem = items[selectedIndex];
106
+
107
+ if (selectedItem && selectedItem.url === url) {
108
+ return true;
109
+ }
110
+
111
+ return false;
112
+ });
113
+
114
+ _defineProperty(this, "handleSelected", objectId => {
115
+ const {
116
+ items
117
+ } = this.state;
118
+ const selectedItem = items.find(item => item.objectId === objectId);
119
+
120
+ if (selectedItem) {
121
+ const {
122
+ url,
123
+ name
124
+ } = selectedItem;
125
+ this.handleInsert(url, name, 'typeAhead');
126
+ }
127
+ });
128
+
129
+ _defineProperty(this, "handleInsert", (url, title, inputType) => {
130
+ const {
131
+ onSubmit
132
+ } = this.props;
133
+ const {
134
+ url: rawUrl,
135
+ displayText
136
+ } = this.state;
137
+
138
+ if (onSubmit) {
139
+ onSubmit({
140
+ url,
141
+ displayText: displayText || null,
142
+ title: title || null,
143
+ meta: {
144
+ inputMethod: inputType
145
+ },
146
+ ...(inputType === 'manual' ? {
147
+ rawUrl
148
+ } : {})
149
+ });
150
+ }
151
+ });
152
+
153
+ _defineProperty(this, "handleMouseEnterResultItem", objectId => {
154
+ const {
155
+ items
156
+ } = this.state;
157
+ const index = findIndex(items, item => item.objectId === objectId);
158
+ this.setState({
159
+ activeIndex: index
160
+ });
161
+ });
162
+
163
+ _defineProperty(this, "handleMouseLeaveResultItem", objectId => {
164
+ const {
165
+ items,
166
+ activeIndex
167
+ } = this.state;
168
+ const index = findIndex(items, item => item.objectId === objectId); // This is to avoid updating index that was set by other mouseenter event
169
+
170
+ if (activeIndex === index) {
171
+ this.setState({
172
+ activeIndex: -1
173
+ });
174
+ }
175
+ });
176
+
177
+ _defineProperty(this, "handleSubmit", () => {
178
+ const {
179
+ url,
180
+ selectedIndex,
181
+ items
182
+ } = this.state;
183
+ const selectedItem = items[selectedIndex];
184
+
185
+ if (this.isUrlPopulatedWithSelectedItem()) {
186
+ this.handleInsert(selectedItem.url, selectedItem.name, 'typeAhead');
187
+ } else if (url.length > 0) {
188
+ const normalized = normalizeUrl(url);
189
+
190
+ if (normalized) {
191
+ this.handleInsert(normalized, null, 'manual');
192
+ } else {
193
+ const {
194
+ intl
195
+ } = this.props;
196
+ const linkInvalid = intl.formatMessage(messages.linkInvalid);
197
+ this.setState({
198
+ invalidUrl: linkInvalid
199
+ });
200
+ }
201
+ }
202
+ });
203
+
204
+ _defineProperty(this, "handleKeyDown", event => {
205
+ const {
206
+ items,
207
+ activeIndex
208
+ } = this.state;
209
+ const {
210
+ keyCode
211
+ } = event;
212
+ const KEY_CODE_ARROW_DOWN = 40;
213
+ const KEY_CODE_ARROW_UP = 38;
214
+
215
+ if (!items || !items.length) {
216
+ return;
217
+ }
218
+
219
+ let updatedIndex = activeIndex;
220
+
221
+ switch (keyCode) {
222
+ case KEY_CODE_ARROW_DOWN:
223
+ // down
224
+ event.preventDefault();
225
+ updatedIndex = (activeIndex + 1) % items.length;
226
+ break;
227
+
228
+ case KEY_CODE_ARROW_UP:
229
+ // up
230
+ event.preventDefault();
231
+ updatedIndex = activeIndex > 0 ? activeIndex - 1 : items.length - 1;
232
+ break;
233
+ }
234
+
235
+ if ([KEY_CODE_ARROW_DOWN, KEY_CODE_ARROW_UP].includes(keyCode) && items[updatedIndex]) {
236
+ this.setState({
237
+ activeIndex: updatedIndex,
238
+ selectedIndex: updatedIndex,
239
+ url: items[updatedIndex].url,
240
+ invalidUrl: null
241
+ });
242
+ }
243
+ });
244
+
245
+ _defineProperty(this, "handleCancel", () => {
246
+ const {
247
+ onCancel
248
+ } = this.props;
249
+
250
+ if (onCancel) {
251
+ onCancel();
252
+ }
253
+ });
254
+
255
+ _defineProperty(this, "updateTextInput", displayText => {
256
+ this.setState({
257
+ displayText: displayText
258
+ });
259
+ });
260
+
261
+ this.state = {
262
+ selectedIndex: -1,
263
+ activeIndex: -1,
264
+ isLoading: false,
265
+ url: normalizeUrl(props.url) || '',
266
+ displayText: props.displayText || '',
267
+ items: [],
268
+ invalidUrl: null
269
+ };
270
+ /* Cache functions */
271
+
272
+ this.handleClearUrl = this.createClearHandler('url');
273
+ this.handleClearDisplayText = this.createClearHandler('displayText');
274
+ }
275
+
276
+ componentDidMount() {
277
+ this.loadInitialLinkSearchResult();
278
+ }
279
+
280
+ loadInitialLinkSearchResult() {
281
+ const {
282
+ url
283
+ } = this.state;
284
+
285
+ if (!url) {
286
+ this.updateResults();
287
+ }
288
+ }
289
+
290
+ getActivePlugin() {
291
+ if (!this.props.plugins) {
292
+ return null;
293
+ }
294
+
295
+ return this.props.plugins[0];
296
+ }
297
+ /**
298
+ * Interface between link picker and plugins to update results
299
+ */
300
+
301
+
302
+ async updateResults() {
303
+ const queryVersion = ++this.queryVersion;
304
+ const activePlugin = this.getActivePlugin();
305
+
306
+ if (!activePlugin) {
307
+ return;
308
+ }
309
+
310
+ const updates = activePlugin.resolve({
311
+ query: this.state.url
312
+ });
313
+ this.setState({
314
+ isLoading: true,
315
+ items: []
316
+ });
317
+
318
+ try {
319
+ while (queryVersion === this.queryVersion) {
320
+ const {
321
+ done,
322
+ value
323
+ } = await updates.next();
324
+
325
+ if (queryVersion !== this.queryVersion) {
326
+ return;
327
+ }
328
+
329
+ this.setState({
330
+ items: limit(value),
331
+ isLoading: !done
332
+ });
333
+
334
+ if (done) {
335
+ return;
336
+ }
337
+ }
338
+ } catch {
339
+ this.setState({
340
+ isLoading: false
341
+ });
342
+ }
343
+ }
344
+
345
+ render() {
346
+ const {
347
+ items,
348
+ isLoading,
349
+ activeIndex,
350
+ selectedIndex,
351
+ url,
352
+ displayText
353
+ } = this.state;
354
+ const {
355
+ intl: {
356
+ formatMessage
357
+ }
358
+ } = this.props;
359
+ const activePlugin = this.getActivePlugin();
360
+ const linkPlaceHolder = formatMessage(activePlugin ? messages.placeholder : messages.linkPlaceholder);
361
+ const linkLabel = formatMessage(messages.linkLabel);
362
+ const linkTextLabel = formatMessage(messages.linkTextLabel);
363
+ const linkTextPlaceHolder = formatMessage(messages.linkTextPlaceholder);
364
+ const screenReaderDescriptionId = 'search-recent-links-field-description';
365
+ const linkSearchListId = 'link-picker-search-list';
366
+ const ariaActiveDescendant = selectedIndex > -1 ? `link-search-list-item-${selectedIndex}` : ''; // Added workaround with a screen reader Announcer specifically for VoiceOver + Safari
367
+ // as the Aria design pattern for combobox does not work in this case
368
+ // for details: https://a11y-internal.atlassian.net/browse/AK-740
369
+
370
+ const screenReaderText = browser.safari && this.getScreenReaderText();
371
+ const searchIcon = activePlugin && jsx(SearchIconWrapper, {
372
+ "data-testid": "link-picker-search-icon"
373
+ }, jsx(EditorSearchIcon, {
374
+ size: "medium",
375
+ label: ''
376
+ }));
377
+ return jsx("div", {
378
+ "data-testid": "link-picker",
379
+ className: "recent-list",
380
+ css: recentListStyles
381
+ }, jsx(Container, {
382
+ innerRef: this.wrapperRef
383
+ }, screenReaderText && jsx(Announcer, {
384
+ ariaLive: "assertive",
385
+ text: screenReaderText,
386
+ ariaRelevant: "additions",
387
+ delay: 250
388
+ }), jsx(VisuallyHidden, null, jsx("span", {
389
+ "aria-hidden": "true",
390
+ id: screenReaderDescriptionId
391
+ }, formatMessage(messages.searchLinkAriaDescription))), jsx(PanelTextInput, {
392
+ name: "link",
393
+ testId: "link-url",
394
+ role: "combobox",
395
+ label: linkLabel,
396
+ placeholder: linkPlaceHolder,
397
+ value: url,
398
+ autoFocus: true,
399
+ autoComplete: "off",
400
+ elemBeforeInput: searchIcon,
401
+ onSubmit: this.handleSubmit,
402
+ onChange: this.updateInput,
403
+ onKeyDown: this.handleKeyDown,
404
+ onClear: this.handleClearUrl,
405
+ error: this.state.invalidUrl,
406
+ clearLabel: formatMessage(messages.clearLink),
407
+ "aria-controls": linkSearchListId,
408
+ "aria-autocomplete": "list",
409
+ "aria-activedescendant": ariaActiveDescendant,
410
+ "aria-describedby": screenReaderDescriptionId,
411
+ "aria-expanded": true
412
+ }), jsx(PanelTextInput, {
413
+ name: "link-text",
414
+ testId: "link-text",
415
+ autoComplete: "off",
416
+ label: linkTextLabel,
417
+ placeholder: linkTextPlaceHolder,
418
+ "aria-label": formatMessage(messages.linkAriaLabel),
419
+ value: displayText,
420
+ onSubmit: this.handleSubmit,
421
+ onKeyDown: this.handleKeyDown,
422
+ onChange: this.updateTextInput,
423
+ onClear: this.handleClearDisplayText,
424
+ clearLabel: formatMessage(messages.clearText)
425
+ }), !!items.length && jsx("div", {
426
+ css: ListTitleStyles,
427
+ id: "link-picker-list-title",
428
+ "data-testid": "link-picker-list-title"
429
+ }, formatMessage(this.state.url ? messages.titleResults : messages.titleRecentlyViewed)), jsx(VisuallyHidden, null, jsx("span", {
430
+ "aria-live": "polite",
431
+ "aria-atomic": "true",
432
+ id: "fabric.smartcard.linkpicker.suggested.results"
433
+ }, url && formatMessage(messages.searchLinkResults, {
434
+ count: items.length
435
+ }))), jsx(LinkSearchList, {
436
+ ariaLabelledBy: "link-picker-list-title",
437
+ ariaControls: "fabric.smartcard.linkpicker.suggested.results",
438
+ id: linkSearchListId,
439
+ role: "listbox",
440
+ items: items,
441
+ isLoading: isLoading,
442
+ selectedIndex: selectedIndex,
443
+ activeIndex: activeIndex,
444
+ onSelect: this.handleSelected,
445
+ onMouseEnter: this.handleMouseEnterResultItem,
446
+ onMouseLeave: this.handleMouseLeaveResultItem
447
+ }), jsx(FormFooter, {
448
+ align: "end"
449
+ }, jsx(ButtonGroup, null, jsx(Button, {
450
+ appearance: "default",
451
+ onClick: this.handleCancel,
452
+ testId: "link-picker-cancel-button"
453
+ }, formatMessage(messages.cancelButton)), jsx(Button, {
454
+ type: "submit",
455
+ appearance: "primary",
456
+ onClick: this.handleSubmit,
457
+ testId: "link-picker-insert-button"
458
+ }, formatMessage(messages.insertButton))))));
459
+ }
460
+
461
+ }
462
+
463
+ function findIndex(array, predicate) {
464
+ let index = -1;
465
+ array.some((item, i) => {
466
+ if (predicate(item)) {
467
+ index = i;
468
+ return true;
469
+ }
470
+
471
+ return false;
472
+ });
473
+ return index;
474
+ }
475
+
476
+ function limit(items) {
477
+ return items.slice(0, RECENT_SEARCH_LIST_SIZE);
478
+ }
479
+
480
+ export const LinkPickerWithIntl = injectIntl(LinkPicker);
@@ -0,0 +1,88 @@
1
+ import LinkifyIt from 'linkify-it';
2
+ const linkify = LinkifyIt();
3
+ linkify.add('sourcetree:', 'http:');
4
+ const tlds = 'biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф'.split('|');
5
+ const tlds2Char = 'a[cdefgilmnoqrtuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrtuvwxyz]|n[acefgilopruz]|om|p[aefghkmnrtw]|qa|r[eosuw]|s[abcdegijklmnrtuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]';
6
+ tlds.push(tlds2Char);
7
+ linkify.tlds(tlds, false);
8
+ const whitelistedURLPatterns = [/^https?:\/\/[^\s]*$/im, /^ftps?:\/\//im, /^\//im, /^mailto:/im, /^skype:/im, /^callto:[^\s]*$/im, /^facetime:[^\s]*$/im, /^git:/im, /^irc6?:/im, /^news:/im, /^nntp:/im, /^feed:/im, /^cvs:/im, /^svn:/im, /^mvn:/im, /^ssh:/im, /^scp:\/\//im, /^sftp:\/\//im, /^itms:/im, /^notes:/im, /^hipchat:\/\//im, /^sourcetree:/im, /^urn:/im, /^tel:/im, /^xmpp:/im, /^telnet:/im, /^vnc:/im, /^rdp:/im, /^whatsapp:/im, /^slack:/im, /^sips?:/im, /^magnet:/im, /^foo:/im, /^#/im];
9
+
10
+ const normaliseLinkHref = url => {
11
+ const match = getLinkMatch(url);
12
+ return match && match.url || null;
13
+ };
14
+
15
+ const getLinkMatch = str => {
16
+ if (!str) {
17
+ return null;
18
+ }
19
+
20
+ let match = linkifyMatch(str);
21
+
22
+ if (!match.length) {
23
+ match = linkify.match(str);
24
+ }
25
+
26
+ return match && match.length > 0 && match[0].index === 0 && match[0].lastIndex === str.trim().length ? match[0] : null;
27
+ };
28
+
29
+ const LINK_REGEXP = /(https?|ftp):\/\/[^\s]+/;
30
+
31
+ const linkifyMatch = text => {
32
+ const matches = [];
33
+
34
+ if (!LINK_REGEXP.test(text)) {
35
+ return matches;
36
+ }
37
+
38
+ let startpos = 0;
39
+ let substr;
40
+
41
+ while (substr = text.substr(startpos)) {
42
+ const link = (substr.match(LINK_REGEXP) || [''])[0];
43
+
44
+ if (link) {
45
+ const index = substr.search(LINK_REGEXP);
46
+ const start = index >= 0 ? index + startpos : index;
47
+ const end = start + link.length;
48
+ matches.push({
49
+ index: start,
50
+ lastIndex: end,
51
+ raw: link,
52
+ url: link,
53
+ text: link,
54
+ schema: ''
55
+ });
56
+ startpos += end;
57
+ } else {
58
+ break;
59
+ }
60
+ }
61
+
62
+ return matches;
63
+ };
64
+
65
+ export const isSafeUrl = url => {
66
+ const urlTrimmed = url.trim();
67
+
68
+ if (urlTrimmed.length === 0) {
69
+ return true;
70
+ }
71
+
72
+ return whitelistedURLPatterns.some(p => p.test(urlTrimmed));
73
+ };
74
+ /**
75
+ * Adds protocol to url if needed.
76
+ */
77
+
78
+ export function normalizeUrl(url) {
79
+ if (!url) {
80
+ return '';
81
+ }
82
+
83
+ if (isSafeUrl(url)) {
84
+ return url.trim();
85
+ }
86
+
87
+ return normaliseLinkHref(url);
88
+ }
@@ -0,0 +1,24 @@
1
+ import { browser } from './browser';
2
+ export const relativeFontSizeToBase16 = px => {
3
+ if (typeof px === 'string') {
4
+ px = parseInt(px);
5
+ }
6
+
7
+ if (isNaN(px)) {
8
+ throw new Error(`Invalid font size: '${px}'`);
9
+ }
10
+
11
+ return `${px / 16}rem`;
12
+ };
13
+ const KeyZCode = 90;
14
+ const KeyYCode = 89;
15
+ export const isUndoEvent = e => {
16
+ return e.keyCode === KeyZCode && ( // cmd + z for mac
17
+ browser.mac && e.metaKey && !e.shiftKey || // ctrl + z for non-mac
18
+ !browser.mac && e.ctrlKey);
19
+ };
20
+ export const isRedoEvent = e => {
21
+ return (// ctrl + y for non-mac
22
+ !browser.mac && e.ctrlKey && e.keyCode === KeyYCode || browser.mac && e.metaKey && e.shiftKey && e.keyCode === KeyZCode || e.ctrlKey && e.shiftKey && e.keyCode === KeyZCode
23
+ );
24
+ };
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/link-picker",
3
- "version": "0.0.2",
3
+ "version": "0.7.0",
4
4
  "sideEffects": false
5
5
  }
@@ -0,0 +1,34 @@
1
+ var result = {
2
+ mac: false,
3
+ ie: false,
4
+ ie_version: 0,
5
+ gecko: false,
6
+ chrome: false,
7
+ chrome_version: 0,
8
+ android: false,
9
+ ios: false,
10
+ webkit: false,
11
+ safari: false,
12
+ supportsIntersectionObserver: false,
13
+ supportsResizeObserver: false
14
+ };
15
+
16
+ if (typeof navigator !== 'undefined') {
17
+ var ieEdge = /Edge\/(\d+)/.exec(navigator.userAgent);
18
+ var ieUpTo10 = /MSIE \d/.test(navigator.userAgent);
19
+ var ie11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
20
+ result.mac = /Mac/.test(navigator.platform);
21
+ var ie = result.ie = !!(ieUpTo10 || ie11up || ieEdge);
22
+ result.ie_version = ieUpTo10 ? document.documentMode || 6 : ie11up ? +ie11up[1] : ieEdge ? +ieEdge[1] : null;
23
+ result.gecko = !ie && /gecko\/\d/i.test(navigator.userAgent);
24
+ result.chrome = !ie && /Chrome\//.test(navigator.userAgent);
25
+ result.chrome_version = parseInt((navigator.userAgent.match(/Chrome\/(\d+)/) || [])[1], 10);
26
+ result.android = /Android \d/.test(navigator.userAgent);
27
+ result.ios = !ie && /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
28
+ result.webkit = !ie && !!document.documentElement && 'WebkitAppearance' in document.documentElement.style;
29
+ result.safari = Boolean(navigator.vendor && navigator.vendor.indexOf('Apple') > -1 && navigator.userAgent && navigator.userAgent.indexOf('CriOS') === -1 && navigator.userAgent.indexOf('FxiOS') === -1);
30
+ result.supportsIntersectionObserver = typeof window !== 'undefined' && 'IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype;
31
+ result.supportsResizeObserver = typeof window !== 'undefined' && 'ResizeObserver' in window && 'ResizeObserverEntry' in window;
32
+ }
33
+
34
+ export { result as browser };
package/dist/esm/index.js CHANGED
@@ -1 +1 @@
1
- export { LinkPicker } from './link-picker';
1
+ export { LinkPickerWithIntl as LinkPicker } from './ui/link-picker';