copy_tuner_client 2.2.1 → 2.4.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.
data/src/main.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable no-console */
2
2
  import { CopyrayOverlay } from './copyray-overlay'
3
3
  import { CopytunerBar } from './copytuner-bar'
4
+ import { CopytunerRoot } from './copytuner-root'
4
5
  import { isMac } from './util'
5
6
 
6
7
  declare global {
@@ -18,38 +19,47 @@ declare global {
18
19
 
19
20
  customElements.define('copytuner-bar', CopytunerBar)
20
21
  customElements.define('copyray-overlay', CopyrayOverlay)
22
+ customElements.define('copytuner-root', CopytunerRoot)
21
23
 
22
24
  const start = () => {
23
25
  const { url, data, keysSkipped } = window.CopyTuner
24
26
  const onOpen = (key: string) => window.open(`${url}/blurbs/${key}/edit`)
25
27
 
26
- const bar = document.createElement('copytuner-bar') as CopytunerBar
27
- document.body.append(bar)
28
- bar.init({ url, data, keysSkipped: Boolean(keysSkipped), onOpen })
28
+ const root = document.createElement('copytuner-root') as CopytunerRoot
29
+ document.body.append(root)
29
30
 
31
+ const bar = document.createElement('copytuner-bar') as CopytunerBar
30
32
  const overlay = document.createElement('copyray-overlay') as CopyrayOverlay
31
33
  overlay.onOpen = onOpen
32
- document.body.append(overlay)
34
+ root.dialog.append(overlay, bar)
35
+ bar.init({ url, data, keysSkipped: Boolean(keysSkipped), onOpen })
33
36
 
34
37
  const show = () => {
38
+ // display: none のままでは searchBox にフォーカスが当たらないので dialog を先に開く
39
+ root.dialog.showModal()
35
40
  overlay.show()
36
41
  bar.show()
37
42
  }
38
43
  const hide = () => {
44
+ root.dialog.close()
45
+ // close イベントを待たず同期で後始末する。イベントは queued task 発火で、
46
+ // 自動テスト環境など発火が遅れる/落ちる状況があるため、ここを唯一の頼りにしない
39
47
  overlay.hide()
40
- bar.hide()
41
48
  }
42
- const toggle = () => (overlay.isShowing ? hide() : show())
49
+ const toggle = () => (root.dialog.open ? hide() : show())
43
50
 
44
- overlay.onToggle = toggle
51
+ root.onToggle = toggle
52
+ overlay.onClose = hide
45
53
  window.CopyTuner.toggle = toggle
46
54
 
47
- document.addEventListener('keydown', (event) => {
48
- if (overlay.isShowing && ['Escape', 'Esc'].includes(event.key)) {
49
- hide()
50
- return
51
- }
55
+ // Escape のようにこちらの hide() を経由しない閉じ方の受け皿。overlay.hide() は冪等なので二重でも問題ない
56
+ root.dialog.addEventListener('close', () => {
57
+ // 閉じた直後に開き直された場合、遅れて届いたこのイベントで後始末してはいけない
58
+ if (root.dialog.open) return
59
+ overlay.hide()
60
+ })
52
61
 
62
+ document.addEventListener('keydown', (event) => {
53
63
  if (((isMac && event.metaKey) || (!isMac && event.ctrlKey)) && event.shiftKey && event.key.toLowerCase() === 'k') {
54
64
  toggle()
55
65
  }
data/src/styles.ts CHANGED
@@ -1,6 +1,57 @@
1
1
  // 各 custom element の Shadow root に <style> として注入する CSS。
2
2
  // Shadow DOM のスタイル隔離が効くため、旧 copyray.css にあった #copyray-overlay * のグローバルリセットは不要。
3
3
 
4
+ // コンテナ(<copytuner-root>)のスタイル。
5
+ // dialog の UA デフォルト(中央寄せ・白背景・枠線・padding・暗転)を全て打ち消し、
6
+ // viewport 全面を覆う透明なコンテナにする。暗転は overlay 側の .backdrop が担う。
7
+ export const ROOT_STYLES = `
8
+ /* transform / filter / perspective / contain は置かない(理由は OVERLAY_STYLES のコメント参照) */
9
+ dialog {
10
+ position: fixed;
11
+ inset: 0;
12
+ width: 100%;
13
+ height: 100%;
14
+ max-width: none;
15
+ max-height: none;
16
+ margin: 0;
17
+ border: none;
18
+ padding: 0;
19
+ background: transparent;
20
+ color: inherit;
21
+ }
22
+
23
+ dialog::backdrop {
24
+ background: transparent;
25
+ }
26
+
27
+ .toggle-button {
28
+ display: block;
29
+ position: fixed;
30
+ left: 0;
31
+ bottom: 0;
32
+ color: white;
33
+ background: black;
34
+ padding: 12px 16px;
35
+ border-radius: 0 10px 0 0;
36
+ opacity: 0;
37
+ transition: opacity 0.6s ease-in-out;
38
+ z-index: 10000;
39
+ font-size: 12px;
40
+ cursor: pointer;
41
+ text-decoration: none;
42
+ }
43
+
44
+ .toggle-button:hover {
45
+ opacity: 1;
46
+ }
47
+
48
+ @media screen and (max-width: 480px) {
49
+ .toggle-button {
50
+ display: none;
51
+ }
52
+ }
53
+ `
54
+
4
55
  // ツールバー(<copytuner-bar>)のスタイル。:host にバー本体のレイアウトを定義する。
5
56
  export const BAR_STYLES = `
6
57
  :host {
@@ -20,10 +71,6 @@ export const BAR_STYLES = `
20
71
  box-sizing: border-box;
21
72
  }
22
73
 
23
- :host([hidden]) {
24
- display: none;
25
- }
26
-
27
74
  .log-menu {
28
75
  position: fixed;
29
76
  left: 0;
@@ -109,22 +156,19 @@ export const BAR_STYLES = `
109
156
  `
110
157
 
111
158
  // オーバーレイ(<copyray-overlay>)のスタイル。
112
- // :host はドキュメント原点基準(position: absolute; top/left: 0)にして、
113
- // 子の specimen を computeBoundingBox のページ座標で absolute 配置できるようにする。
114
- // 背景の暗転(.backdrop)だけは viewport 固定(fixed)にする。
159
+ // specimen は getBoundingClientRect() の viewport 座標をそのまま使うため、
160
+ // dialog / :host / specimen のコンテナ div のいずれにも
161
+ // transform / filter / perspective / contain を置かない。
162
+ // 置くとそれが containing block になり、fixed な specimen が viewport 基準から外れる。
163
+ // :host の position: absolute と width/height: 0 は、インラインの custom element が
164
+ // dialog のフローに line box を作らないようにするため(fixed の containing block は作らない)。
115
165
  export const OVERLAY_STYLES = `
116
166
  :host {
117
167
  position: absolute;
118
- top: 0;
119
- left: 0;
120
168
  width: 0;
121
169
  height: 0;
122
170
  }
123
171
 
124
- :host([hidden]) {
125
- display: none;
126
- }
127
-
128
172
  .backdrop {
129
173
  position: fixed;
130
174
  inset: 0;
@@ -137,7 +181,7 @@ export const OVERLAY_STYLES = `
137
181
  }
138
182
 
139
183
  .specimen {
140
- position: absolute;
184
+ position: fixed;
141
185
  background: rgba(255, 50, 50, 0.1);
142
186
  outline: 1px solid rgba(255, 50, 50, 0.8);
143
187
  outline-offset: -1px;
@@ -153,6 +197,10 @@ export const OVERLAY_STYLES = `
153
197
  background: rgba(255, 50, 50, 0.4);
154
198
  }
155
199
 
200
+ .specimen[hidden] {
201
+ display: none;
202
+ }
203
+
156
204
  .specimen-handle {
157
205
  float: left;
158
206
  margin: 0 2px 2px 0;
@@ -162,31 +210,4 @@ export const OVERLAY_STYLES = `
162
210
  font-size: 10px;
163
211
  cursor: pointer;
164
212
  }
165
-
166
- .toggle-button {
167
- display: block;
168
- position: fixed;
169
- left: 0;
170
- bottom: 0;
171
- color: white;
172
- background: black;
173
- padding: 12px 16px;
174
- border-radius: 0 10px 0 0;
175
- opacity: 0;
176
- transition: opacity 0.6s ease-in-out;
177
- z-index: 10000;
178
- font-size: 12px;
179
- cursor: pointer;
180
- text-decoration: none;
181
- }
182
-
183
- .toggle-button:hover {
184
- opacity: 1;
185
- }
186
-
187
- @media screen and (max-width: 480px) {
188
- .toggle-button {
189
- display: none;
190
- }
191
- }
192
213
  `
data/src/util.ts CHANGED
@@ -1,40 +1,5 @@
1
1
  const isMac = navigator.platform.toUpperCase().includes('MAC')
2
2
 
3
- // @ts-expect-error TS7006
4
- const isVisible = (element) => !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length > 0)
5
-
6
- // @ts-expect-error TS7006
7
- const getOffset = (elment) => {
8
- const box = elment.getBoundingClientRect()
9
-
10
- return {
11
- top: box.top + (window.pageYOffset - document.documentElement.clientTop),
12
- left: box.left + (window.pageXOffset - document.documentElement.clientLeft),
13
- }
14
- }
15
-
16
- // @ts-expect-error TS7006
17
- const computeBoundingBox = (element) => {
18
- if (!isVisible(element)) {
19
- return null
20
- }
21
-
22
- const boxFrame = getOffset(element)
23
- // @ts-expect-error TS2339
24
- boxFrame.right = boxFrame.left + element.offsetWidth
25
- // @ts-expect-error TS2339
26
- boxFrame.bottom = boxFrame.top + element.offsetHeight
27
-
28
- return {
29
- left: boxFrame.left,
30
- top: boxFrame.top,
31
- // @ts-expect-error TS2339
32
- width: boxFrame.right - boxFrame.left,
33
- // @ts-expect-error TS2339
34
- height: boxFrame.bottom - boxFrame.top,
35
- }
36
- }
37
-
38
3
  const debounce = <A extends unknown[]>(fn: (...args: A) => void, wait: number) => {
39
4
  let timer: ReturnType<typeof setTimeout> | undefined
40
5
  return (...args: A) => {
@@ -43,4 +8,4 @@ const debounce = <A extends unknown[]>(fn: (...args: A) => void, wait: number) =
43
8
  }
44
9
  }
45
10
 
46
- export { computeBoundingBox, debounce, getOffset, isMac, isVisible }
11
+ export { debounce, isMac }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: copy_tuner_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SonicGarden
@@ -200,6 +200,7 @@ files:
200
200
  - app/assets/javascripts/copytuner.js
201
201
  - biome.json
202
202
  - copy_tuner_client.gemspec
203
+ - docs/poller-startup.md
203
204
  - gemfiles/8.0.gemfile
204
205
  - gemfiles/8.1.gemfile
205
206
  - gemfiles/main.gemfile
@@ -215,6 +216,7 @@ files:
215
216
  - lib/copy_tuner_client/dotted_hash.rb
216
217
  - lib/copy_tuner_client/engine.rb
217
218
  - lib/copy_tuner_client/errors.rb
219
+ - lib/copy_tuner_client/fork_hook.rb
218
220
  - lib/copy_tuner_client/helper_extension.rb
219
221
  - lib/copy_tuner_client/i18n_backend.rb
220
222
  - lib/copy_tuner_client/i18n_compat.rb
@@ -251,11 +253,13 @@ files:
251
253
  - spec/copy_tuner_client/copyray_middleware_spec.rb
252
254
  - spec/copy_tuner_client/copyray_spec.rb
253
255
  - spec/copy_tuner_client/dotted_hash_spec.rb
256
+ - spec/copy_tuner_client/fork_hook_spec.rb
254
257
  - spec/copy_tuner_client/helper_extension_spec.rb
255
258
  - spec/copy_tuner_client/i18n_backend_spec.rb
256
259
  - spec/copy_tuner_client/poller_spec.rb
257
260
  - spec/copy_tuner_client/prefixed_logger_spec.rb
258
261
  - spec/copy_tuner_client/process_guard_spec.rb
262
+ - spec/copy_tuner_client/queue_with_timeout_spec.rb
259
263
  - spec/copy_tuner_client/request_sync_spec.rb
260
264
  - spec/copy_tuner_client/translation_log_spec.rb
261
265
  - spec/copy_tuner_client/warden_integration_spec.rb
@@ -273,6 +277,7 @@ files:
273
277
  - spec/support/writing_cache.rb
274
278
  - src/copyray-overlay.ts
275
279
  - src/copytuner-bar.ts
280
+ - src/copytuner-root.ts
276
281
  - src/main.ts
277
282
  - src/styles.ts
278
283
  - src/util.ts
@@ -302,7 +307,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
302
307
  - !ruby/object:Gem::Version
303
308
  version: '0'
304
309
  requirements: []
305
- rubygems_version: 4.0.15
310
+ rubygems_version: 4.0.10
306
311
  specification_version: 4
307
312
  summary: Client for the CopyTuner copy management service
308
313
  test_files: []