better-ship 0.34.0 → 0.35.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.
@@ -0,0 +1,142 @@
1
+ /** Set on `documentElement` when the update screen is showing. Hydration checks this name. */
2
+ export const unsupportedBrowserAttribute = 'data-unsupported-browser'
3
+
4
+ const updateTitleAttribute = 'data-update-title' as const
5
+ const updateBodyAttribute = 'data-update-body' as const
6
+ const fallbackFont = 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif'
7
+
8
+ /** Copy and public URLs for the update screen tags in the document head. */
9
+ export type UpdateScreenHead = {
10
+ readonly title: string
11
+ readonly body: string
12
+ /** Public URL of `updateScreenStyle`. */
13
+ readonly styleHref: string
14
+ /** Public URL of `updateScreenScript`. */
15
+ readonly scriptSrc: string
16
+ }
17
+
18
+ /** Stylesheet link a root route places in `head().links`. */
19
+ export type UpdateScreenLink = {
20
+ readonly rel: 'stylesheet'
21
+ readonly href: string
22
+ }
23
+
24
+ /** Deferred script a root route places in `head().scripts`. */
25
+ export type UpdateScreenScript = {
26
+ readonly src: string
27
+ readonly defer: true
28
+ readonly 'data-update-title': string
29
+ readonly 'data-update-body': string
30
+ }
31
+
32
+ /**
33
+ * `links` and `scripts` a root route spreads into `head()`.
34
+ * The arrays are mutable so they match the `head()` return type.
35
+ */
36
+ export type UpdateScreenHeadEntries = {
37
+ links: UpdateScreenLink[]
38
+ scripts: UpdateScreenScript[]
39
+ }
40
+
41
+ /**
42
+ * Stylesheet and deferred script entries for a root route `head()`.
43
+ * Spread `links` and `scripts` into `head()`. The router escapes the attribute values.
44
+ * `defer` keeps parsing unblocked. The script is classic ES5, so a browser below the floor can show the screen.
45
+ */
46
+ export function updateScreenHeadScript(head: UpdateScreenHead): UpdateScreenHeadEntries {
47
+ return {
48
+ links: [{ rel: 'stylesheet', href: head.styleHref }],
49
+ scripts: [
50
+ {
51
+ src: head.scriptSrc,
52
+ defer: true,
53
+ [updateTitleAttribute]: head.title,
54
+ [updateBodyAttribute]: head.body,
55
+ },
56
+ ],
57
+ }
58
+ }
59
+
60
+ /** True when the update screen script marked this element. Skip hydration when it is true. */
61
+ export function isUnsupportedBrowser(root: {
62
+ readonly hasAttribute: (name: string) => boolean
63
+ }): boolean {
64
+ return root.hasAttribute(unsupportedBrowserAttribute)
65
+ }
66
+
67
+ /**
68
+ * Classic ES5 script. Serve it at `scriptSrc`.
69
+ * It shows the screen when `CSS.registerProperty` or `color-mix()` is missing, and does nothing at the floor.
70
+ */
71
+ export const updateScreenScript = `(function () {
72
+ var cssApi = typeof CSS === 'undefined' ? null : CSS;
73
+ var hasProperty = cssApi !== null && typeof cssApi.registerProperty === 'function';
74
+ var hasMix = cssApi !== null && typeof cssApi.supports === 'function' && cssApi.supports('color', 'color-mix(in srgb, red, blue)');
75
+ if (hasProperty && hasMix) return;
76
+ document.documentElement.setAttribute('${unsupportedBrowserAttribute}', '');
77
+ var scripts = document.getElementsByTagName('script');
78
+ var title = 'Update your browser';
79
+ var body = '';
80
+ for (var index = 0; index < scripts.length; index = index + 1) {
81
+ var marker = scripts[index].getAttribute('${updateTitleAttribute}');
82
+ if (marker === null) continue;
83
+ title = marker;
84
+ var text = scripts[index].getAttribute('${updateBodyAttribute}');
85
+ body = text === null ? '' : text;
86
+ break;
87
+ }
88
+ var screen = document.createElement('div');
89
+ screen.id = 'unsupported-browser';
90
+ var heading = document.createElement('h1');
91
+ heading.className = 'unsupported-browser-title';
92
+ heading.textContent = title;
93
+ var paragraph = document.createElement('p');
94
+ paragraph.className = 'unsupported-browser-body';
95
+ paragraph.textContent = body;
96
+ screen.appendChild(heading);
97
+ screen.appendChild(paragraph);
98
+ document.body.appendChild(screen);
99
+ })();
100
+ `
101
+
102
+ // `!important` keeps application styles from painting over the update screen.
103
+ /** Classic CSS for the update screen. Serve it at `styleHref`. Tokens fall back to neutral grey and a system sans-serif. */
104
+ export const updateScreenStyle = `html[${unsupportedBrowserAttribute}],
105
+ html[${unsupportedBrowserAttribute}] body {
106
+ margin: 0;
107
+ min-height: 100%;
108
+ background: var(--band, #f5f5f5);
109
+ }
110
+ html[${unsupportedBrowserAttribute}] body > :not(#unsupported-browser) {
111
+ display: none !important;
112
+ }
113
+ #unsupported-browser {
114
+ box-sizing: border-box;
115
+ min-height: 100vh;
116
+ margin: 0;
117
+ padding: 48px 24px;
118
+ display: flex;
119
+ flex-direction: column;
120
+ justify-content: center;
121
+ align-items: center;
122
+ text-align: center;
123
+ background: var(--band, #f5f5f5);
124
+ color: var(--foreground, #171717);
125
+ font-family: var(--font-text, ${fallbackFont});
126
+ }
127
+ .unsupported-browser-title {
128
+ margin: 0 0 12px;
129
+ max-width: 28rem;
130
+ font-family: var(--font-brand, ${fallbackFont});
131
+ font-size: 2rem;
132
+ font-weight: 500;
133
+ line-height: 1.2;
134
+ }
135
+ .unsupported-browser-body {
136
+ margin: 0;
137
+ max-width: 32rem;
138
+ color: var(--muted-foreground, #525252);
139
+ font-size: 1.0625rem;
140
+ line-height: 1.5;
141
+ }
142
+ `