termcast 1.3.33 → 1.3.35
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.
- package/dist/apis/cache.d.ts +1 -2
- package/dist/apis/cache.d.ts.map +1 -1
- package/dist/apis/cache.js +134 -52
- package/dist/apis/cache.js.map +1 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +25 -0
- package/dist/build.js.map +1 -1
- package/dist/cli.js +6 -8
- package/dist/cli.js.map +1 -1
- package/dist/components/dropdown.js +3 -3
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/footer.d.ts.map +1 -1
- package/dist/components/footer.js +1 -1
- package/dist/components/footer.js.map +1 -1
- package/dist/components/icon.d.ts.map +1 -1
- package/dist/components/icon.js +386 -23
- package/dist/components/icon.js.map +1 -1
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +90 -22
- package/dist/components/list.js.map +1 -1
- package/dist/examples/list-controlled-search.d.ts +2 -0
- package/dist/examples/list-controlled-search.d.ts.map +1 -0
- package/dist/examples/list-controlled-search.js +12 -0
- package/dist/examples/list-controlled-search.js.map +1 -0
- package/dist/extensions/home.js +1 -1
- package/dist/extensions/home.js.map +1 -1
- package/dist/extensions/react-refresh-init.d.ts.map +1 -1
- package/dist/extensions/react-refresh-init.js +4 -3
- package/dist/extensions/react-refresh-init.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/dialog.d.ts.map +1 -1
- package/dist/internal/dialog.js +4 -5
- package/dist/internal/dialog.js.map +1 -1
- package/dist/internal/providers.d.ts.map +1 -1
- package/dist/internal/providers.js +18 -5
- package/dist/internal/providers.js.map +1 -1
- package/dist/state.d.ts +1 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js.map +1 -1
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +6 -2
- package/dist/theme.js.map +1 -1
- package/dist/utils/run-command.js +3 -3
- package/dist/utils/run-command.js.map +1 -1
- package/dist/utils.d.ts +16 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +28 -1
- package/dist/utils.js.map +1 -1
- package/dist/watcher.d.ts.map +1 -1
- package/dist/watcher.js +24 -4
- package/dist/watcher.js.map +1 -1
- package/package.json +10 -9
- package/src/apis/cache.test.ts +35 -3
- package/src/apis/cache.tsx +180 -57
- package/src/build.tsx +28 -0
- package/src/cli.tsx +8 -10
- package/src/compile.vitest.tsx +42 -24
- package/src/components/dropdown.tsx +3 -3
- package/src/components/footer.tsx +4 -2
- package/src/components/icon.tsx +385 -23
- package/src/components/list.tsx +104 -28
- package/src/examples/github.vitest.tsx +37 -37
- package/src/examples/list-controlled-search.tsx +28 -0
- package/src/examples/list-controlled-search.vitest.tsx +49 -0
- package/src/examples/list-detail-metadata.vitest.tsx +1 -1
- package/src/examples/list-dropdown-default.vitest.tsx +9 -9
- package/src/examples/list-scrollbox.vitest.tsx +55 -41
- package/src/examples/list-with-detail.vitest.tsx +35 -36
- package/src/examples/list-with-dropdown.vitest.tsx +2 -2
- package/src/examples/list-with-sections.vitest.tsx +153 -118
- package/src/examples/simple-file-picker.vitest.tsx +1 -1
- package/src/examples/simple-grid.vitest.tsx +44 -44
- package/src/examples/simple-navigation.vitest.tsx +43 -12
- package/src/examples/store.vitest.tsx +1 -1
- package/src/examples/swift-extension.vitest.tsx +3 -3
- package/src/extensions/dev.vitest.tsx +69 -34
- package/src/extensions/home.tsx +1 -1
- package/src/extensions/react-refresh-init.tsx +4 -3
- package/src/index.tsx +1 -0
- package/src/internal/dialog.tsx +21 -23
- package/src/internal/providers.tsx +18 -5
- package/src/state.tsx +1 -0
- package/src/theme.tsx +6 -2
- package/src/utils/run-command.tsx +3 -3
- package/src/utils.tsx +41 -1
- package/src/watcher.tsx +26 -6
package/src/components/icon.tsx
CHANGED
|
@@ -1,32 +1,394 @@
|
|
|
1
1
|
import { pascalCase } from 'change-case'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
// Semantic unicode mapping for Raycast icon IDs.
|
|
4
|
+
// Uses ONLY characters from emoji-safe unicode ranges for consistent terminal text rendering.
|
|
5
|
+
// Safe ranges used: Arrows (U+2190), Math Operators (U+2200), Geometric Shapes (U+25A0,
|
|
6
|
+
// excluding U+25B6/U+25C0), Block Elements (U+2580), Misc Technical non-emoji subset,
|
|
7
|
+
// Box Drawing (U+2500), Letterlike Symbols, General Punctuation, Latin/ASCII.
|
|
8
|
+
const ICON_MAP: Record<string, string> = {
|
|
9
|
+
'add-person-16': '⊕',
|
|
10
|
+
'airplane-16': '↗',
|
|
11
|
+
'airplane-filled-16': '↗',
|
|
12
|
+
'airplane-landing-16': '↘',
|
|
13
|
+
'airplane-takeoff-16': '↗',
|
|
14
|
+
'airpods-16': '⊚',
|
|
15
|
+
'alarm-16': '⌀',
|
|
16
|
+
'alarm-ringing-16': '⌀',
|
|
17
|
+
'align-centre-16': '≡',
|
|
18
|
+
'align-left-16': '≡',
|
|
19
|
+
'align-right-16': '≡',
|
|
20
|
+
'american-football-16': '◇',
|
|
21
|
+
'anchor-16': '⊥',
|
|
22
|
+
'app-window-16': '⊞',
|
|
23
|
+
'app-window-grid-2x2-16': '⊞',
|
|
24
|
+
'app-window-grid-3x3-16': '⊞',
|
|
25
|
+
'app-window-list-16': '≡',
|
|
26
|
+
'app-window-sidebar-left-16': '◧',
|
|
27
|
+
'app-window-sidebar-right-16': '◨',
|
|
28
|
+
'arrow-clockwise-16': '↻',
|
|
29
|
+
'arrow-counter-clockwise-16': '↺',
|
|
30
|
+
'arrow-down-16': '↓',
|
|
31
|
+
'arrow-down-circle-16': '⇩',
|
|
32
|
+
'arrow-down-circle-filled-16': '⇩',
|
|
33
|
+
'arrow-left-16': '←',
|
|
34
|
+
'arrow-left-circle-16': '⇦',
|
|
35
|
+
'arrow-left-circle-filled-16': '⇦',
|
|
36
|
+
'arrow-ne-16': '↗',
|
|
37
|
+
'arrow-right-16': '→',
|
|
38
|
+
'arrow-right-circle-16': '⇨',
|
|
39
|
+
'arrow-right-circle-filled-16': '⇨',
|
|
40
|
+
'arrow-up-16': '↑',
|
|
41
|
+
'arrow-up-circle-16': '⇧',
|
|
42
|
+
'arrow-up-circle-filled-16': '⇧',
|
|
43
|
+
'arrows-contract-16': '⇤',
|
|
44
|
+
'arrows-expand-16': '⇥',
|
|
45
|
+
'at-symbol-16': '@',
|
|
46
|
+
'band-aid-16': '╋',
|
|
47
|
+
'bank-note-16': '¤',
|
|
48
|
+
'bar-chart-16': '▊',
|
|
49
|
+
'bar-code-16': '▐',
|
|
50
|
+
'bath-tub-16': '▬',
|
|
51
|
+
'battery-16': '▮',
|
|
52
|
+
'battery-charging-16': '▮',
|
|
53
|
+
'battery-disabled-16': '▯',
|
|
54
|
+
'bell-16': '⍾',
|
|
55
|
+
'bell-disabled-16': '⍻',
|
|
56
|
+
'bike-16': '⎌',
|
|
57
|
+
'binoculars-16': '⌕',
|
|
58
|
+
'bird-16': '∿',
|
|
59
|
+
'blank-document-16': '▯',
|
|
60
|
+
'bluetooth-16': 'ᛒ',
|
|
61
|
+
'boat-16': '≈',
|
|
62
|
+
'bold-16': '𝐁',
|
|
63
|
+
'bolt-16': '↯',
|
|
64
|
+
'bolt-disabled-16': '↯',
|
|
65
|
+
'book-16': '⊞',
|
|
66
|
+
'bookmark-16': '▷',
|
|
67
|
+
'box-16': '□',
|
|
68
|
+
'brush-16': '⊘',
|
|
69
|
+
'bug-16': '⊗',
|
|
70
|
+
'building-16': '⌂',
|
|
71
|
+
'bullet-points-16': '•',
|
|
72
|
+
'bulls-eye-16': '◎',
|
|
73
|
+
'bulls-eye-missed-16': '◌',
|
|
74
|
+
'buoy-16': '◉',
|
|
75
|
+
'calculator-16': '⊞',
|
|
76
|
+
'calendar-16': '▦',
|
|
77
|
+
'camera-16': '⌬',
|
|
78
|
+
'car-16': '⊳',
|
|
79
|
+
'cart-16': '⊲',
|
|
80
|
+
'cd-16': '◎',
|
|
81
|
+
'center-16': '⊡',
|
|
82
|
+
'check-16': '✓',
|
|
83
|
+
'check-circle-16': '✓',
|
|
84
|
+
'check-list-16': '✓',
|
|
85
|
+
'check-rosette-16': '✓',
|
|
86
|
+
'checkmark-16': '✓',
|
|
87
|
+
'chess-piece-16': '⊠',
|
|
88
|
+
'chevron-down-16': '⌄',
|
|
89
|
+
'chevron-down-small-16': '⌄',
|
|
90
|
+
'chevron-left-16': '‹',
|
|
91
|
+
'chevron-left-small-16': '‹',
|
|
92
|
+
'chevron-right-16': '›',
|
|
93
|
+
'chevron-right-small-16': '›',
|
|
94
|
+
'chevron-up-16': '⌃',
|
|
95
|
+
'chevron-up-down-16': '⇕',
|
|
96
|
+
'chevron-up-small-16': '⌃',
|
|
97
|
+
'circle-16': '○',
|
|
98
|
+
'circle-disabled-16': '⊘',
|
|
99
|
+
'circle-ellipsis-16': '◯',
|
|
100
|
+
'circle-filled-16': '●',
|
|
101
|
+
'circle-progress-16': '◔',
|
|
102
|
+
'circle-progress-100-16': '●',
|
|
103
|
+
'circle-progress-25-16': '◔',
|
|
104
|
+
'circle-progress-50-16': '◑',
|
|
105
|
+
'circle-progress-75-16': '◕',
|
|
106
|
+
'clear-formatting-16': '⌧',
|
|
107
|
+
'clipboard-16': '⎘',
|
|
108
|
+
'clock-16': '◴',
|
|
109
|
+
'cloud-16': '◠',
|
|
110
|
+
'cloud-lightning-16': '◠',
|
|
111
|
+
'cloud-rain-16': '◠',
|
|
112
|
+
'cloud-snow-16': '◠',
|
|
113
|
+
'cloud-sun-16': '◠',
|
|
114
|
+
'code-16': '⟨⟩',
|
|
115
|
+
'code-block-16': '▤',
|
|
116
|
+
'cog-16': '⊛',
|
|
117
|
+
'coin-16': '¤',
|
|
118
|
+
'coins-16': '¤',
|
|
119
|
+
'command-symbol-16': '⌘',
|
|
120
|
+
'compass-16': '◎',
|
|
121
|
+
'computer-chip-16': '⎔',
|
|
122
|
+
'contrast-16': '◑',
|
|
123
|
+
'copy-clipboard-16': '⎘',
|
|
124
|
+
'credit-card-16': '▬',
|
|
125
|
+
'cricket-ball-16': '◉',
|
|
126
|
+
'crop-16': '⌌',
|
|
127
|
+
'crown-16': '△',
|
|
128
|
+
'crypto-16': '₿',
|
|
129
|
+
'delete-document-16': '⌧',
|
|
130
|
+
'desktop-16': '⎚',
|
|
131
|
+
'devices-16': '⎚',
|
|
132
|
+
'dna-16': '⧖',
|
|
133
|
+
'document-16': '▯',
|
|
134
|
+
'dot-16': '·',
|
|
135
|
+
'download-16': '⤓',
|
|
136
|
+
'droplets-16': '≋',
|
|
137
|
+
'duplicate-16': '⧉',
|
|
138
|
+
'edit-shape-16': '⌑',
|
|
139
|
+
'eject-16': '△',
|
|
140
|
+
'ellipsis-16': '…',
|
|
141
|
+
'ellipsis-vertical-16': '⋮',
|
|
142
|
+
'emoji-16': '◠',
|
|
143
|
+
'emoji-sad-16': '◡',
|
|
144
|
+
'envelope-16': '▷',
|
|
145
|
+
'eraser-16': '⌫',
|
|
146
|
+
'exclamationmark-16': '!',
|
|
147
|
+
'exclamationmark-2-16': '‼',
|
|
148
|
+
'exclamationmark-3-16': '‼',
|
|
149
|
+
'eye-16': '◉',
|
|
150
|
+
'eye-disabled-16': '⊘',
|
|
151
|
+
'eye-dropper-16': '⊙',
|
|
152
|
+
'female-16': '⊕',
|
|
153
|
+
'film-strip-16': '▥',
|
|
154
|
+
'filter-16': '⧩',
|
|
155
|
+
'finder-16': '⌕',
|
|
156
|
+
'fingerprint-16': '◉',
|
|
157
|
+
'flag-16': '⊳',
|
|
158
|
+
'folder-16': '▤',
|
|
159
|
+
'footprints-16': '⊹',
|
|
160
|
+
'forward-16': '▸',
|
|
161
|
+
'forward-filled-16': '▸',
|
|
162
|
+
'fountain-tip-16': '⌑',
|
|
163
|
+
'full-signal-16': '▊',
|
|
164
|
+
'game-controller-16': '⊞',
|
|
165
|
+
'gauge-16': '◔',
|
|
166
|
+
'geopin-16': '⊙',
|
|
167
|
+
'germ-16': '※',
|
|
168
|
+
'gift-16': '⊠',
|
|
169
|
+
'glasses-16': '∞',
|
|
170
|
+
'globe-01-16': '⊕',
|
|
171
|
+
'goal-16': '⊡',
|
|
172
|
+
'hammer-16': '⊤',
|
|
173
|
+
'hard-drive-16': '▬',
|
|
174
|
+
'hashtag-16': '#',
|
|
175
|
+
'heading-16': '𝐇',
|
|
176
|
+
'headphones-16': '⊚',
|
|
177
|
+
'heart-16': '◆',
|
|
178
|
+
'heart-disabled-16': '◇',
|
|
179
|
+
'heartbeat-16': '◆',
|
|
180
|
+
'highlight-16': '▮',
|
|
181
|
+
'hourglass-16': '⧖',
|
|
182
|
+
'house-16': '⌂',
|
|
183
|
+
'humidity-16': '≋',
|
|
184
|
+
'image-16': '⊞',
|
|
185
|
+
'important-01-16': '‼',
|
|
186
|
+
'info-01-16': 'ℹ',
|
|
187
|
+
'italics-16': '𝐼',
|
|
188
|
+
'key-16': '⊢',
|
|
189
|
+
'keyboard-16': '⌗',
|
|
190
|
+
'layers-16': '◫',
|
|
191
|
+
'leaderboard-16': '▊',
|
|
192
|
+
'leaf-16': '∿',
|
|
193
|
+
'light-bulb-16': '※',
|
|
194
|
+
'light-bulb-off-16': '※',
|
|
195
|
+
'line-chart-16': '⌒',
|
|
196
|
+
'link-16': '∞',
|
|
197
|
+
'livestream-01-16': '◉',
|
|
198
|
+
'livestream-disabled-01-16': '◌',
|
|
199
|
+
'lock-16': '⊟',
|
|
200
|
+
'lock-disabled-16': '⊠',
|
|
201
|
+
'lock-unlocked-16': '⊠',
|
|
202
|
+
'logout-16': '⎋',
|
|
203
|
+
'lorry-16': '⊳',
|
|
204
|
+
'lowercase-16': 'aᵃ',
|
|
205
|
+
'magnifying-glass-16': '⌕',
|
|
206
|
+
'male-16': '⊕',
|
|
207
|
+
'map-16': '▦',
|
|
208
|
+
'mask-16': '◑',
|
|
209
|
+
'maximize-16': '⤢',
|
|
210
|
+
'medical-support-16': '╋',
|
|
211
|
+
'megaphone-16': '⊳',
|
|
212
|
+
'memory-stick-16': '▬',
|
|
213
|
+
'microphone-16': '⊙',
|
|
214
|
+
'microphone-disabled-16': '⊘',
|
|
215
|
+
'minimize-16': '⤡',
|
|
216
|
+
'minus-16': '−',
|
|
217
|
+
'minus-circle-16': '⊖',
|
|
218
|
+
'minus-circle-filled-16': '⊖',
|
|
219
|
+
'mobile-16': '▯',
|
|
220
|
+
'monitor-16': '⎚',
|
|
221
|
+
'moon-16': '◐',
|
|
222
|
+
'moon-down-16': '◐',
|
|
223
|
+
'moon-up-16': '◐',
|
|
224
|
+
'moonrise-16': '◐',
|
|
225
|
+
'mountain-16': '△',
|
|
226
|
+
'mouse-16': '⊙',
|
|
227
|
+
'move-16': '⊹',
|
|
228
|
+
'mug-16': '⊔',
|
|
229
|
+
'mug-steam-16': '⊔',
|
|
230
|
+
'multiply-16': '×',
|
|
231
|
+
'music-16': '∿',
|
|
232
|
+
'network-16': '⊕',
|
|
233
|
+
'new-document-16': '▯',
|
|
234
|
+
'new-folder-16': '▤',
|
|
235
|
+
'number-list-16': '⑴',
|
|
236
|
+
'paperclip-16': '⊶',
|
|
237
|
+
'paragraph-16': '¶',
|
|
238
|
+
'patch-16': '╋',
|
|
239
|
+
'pause-16': '‖',
|
|
240
|
+
'pause-filled-16': '‖',
|
|
241
|
+
'pencil-16': '⌑',
|
|
242
|
+
'person-16': '⊙',
|
|
243
|
+
'person-circle-16': '⊙',
|
|
244
|
+
'person-lines-16': '⊙',
|
|
245
|
+
'phone-16': '⌕',
|
|
246
|
+
'phone-ringing-16': '⌕',
|
|
247
|
+
'pie-chart-16': '◔',
|
|
248
|
+
'pill-16': '⊝',
|
|
249
|
+
'pin-16': '⊙',
|
|
250
|
+
'pin-disabled-16': '⊘',
|
|
251
|
+
'play-16': '▸',
|
|
252
|
+
'play-filled-16': '▸',
|
|
253
|
+
'plug-16': '⊢',
|
|
254
|
+
'plus-16': '+',
|
|
255
|
+
'plus-circle-16': '⊕',
|
|
256
|
+
'plus-circle-filled-16': '⊕',
|
|
257
|
+
'plus-minus-divide-multiply-16': '±',
|
|
258
|
+
'plus-square-16': '⊞',
|
|
259
|
+
'plus-top-right-square-16': '⊞',
|
|
260
|
+
'power-16': '⊙',
|
|
261
|
+
'print-16': '⎙',
|
|
262
|
+
'question-mark-circle-16': '?',
|
|
263
|
+
'quicklink-16': '∞',
|
|
264
|
+
'quotation-marks-16': '❝',
|
|
265
|
+
'quote-block-16': '❝',
|
|
266
|
+
'racket-16': '⊙',
|
|
267
|
+
'raindrop-16': '≋',
|
|
268
|
+
'raycast-logo-neg-16': '◆',
|
|
269
|
+
'raycast-logo-pos-16': '◆',
|
|
270
|
+
'receipt-16': '▯',
|
|
271
|
+
'redo-16': '↻',
|
|
272
|
+
'remove-person-16': '⊖',
|
|
273
|
+
'repeat-16': '↻',
|
|
274
|
+
'replace-16': '⇄',
|
|
275
|
+
'replace-one-16': '⇄',
|
|
276
|
+
'reply-16': '↩',
|
|
277
|
+
'rewind-16': '◂',
|
|
278
|
+
'rewind-filled-16': '◂',
|
|
279
|
+
'rocket-16': '⁕',
|
|
280
|
+
'rosette-16': '✦',
|
|
281
|
+
'rotate-anti-clockwise-16': '↺',
|
|
282
|
+
'rotate-clockwise-16': '↻',
|
|
283
|
+
'rss-16': '◉',
|
|
284
|
+
'ruler-16': '⊢',
|
|
285
|
+
'save-document-16': '⊞',
|
|
286
|
+
'shield-01-16': '⊛',
|
|
287
|
+
'short-paragraph-16': '¶',
|
|
288
|
+
'shuffle-16': '⇝',
|
|
289
|
+
'signal-0-16': '▁',
|
|
290
|
+
'signal-1-16': '▂',
|
|
291
|
+
'signal-2-16': '▄',
|
|
292
|
+
'signal-3-16': '█',
|
|
293
|
+
'snippets-16': '⊠',
|
|
294
|
+
'snowflake-16': '※',
|
|
295
|
+
'soccer-ball-16': '◎',
|
|
296
|
+
'speaker-16': '◁',
|
|
297
|
+
'speaker-down-16': '◁',
|
|
298
|
+
'speaker-high-16': '◂',
|
|
299
|
+
'speaker-low-16': '◁',
|
|
300
|
+
'speaker-off-16': '◃',
|
|
301
|
+
'speaker-on-16': '◂',
|
|
302
|
+
'speaker-up-16': '◂',
|
|
303
|
+
'speech-bubble-16': '⊐',
|
|
304
|
+
'speech-bubble-active-16': '⊐',
|
|
305
|
+
'speech-bubble-important-16': '⊐',
|
|
306
|
+
'square-ellipsis-16': '□',
|
|
307
|
+
'stacked-bars-1-16': '▁',
|
|
308
|
+
'stacked-bars-2-16': '▃',
|
|
309
|
+
'stacked-bars-3-16': '▅',
|
|
310
|
+
'stacked-bars-4-16': '▇',
|
|
311
|
+
'star-16': '★',
|
|
312
|
+
'star-circle-16': '★',
|
|
313
|
+
'star-disabled-16': '☆',
|
|
314
|
+
'stars-16': '✦',
|
|
315
|
+
'stop-16': '■',
|
|
316
|
+
'stop-filled-16': '■',
|
|
317
|
+
'stopwatch-16': '◴',
|
|
318
|
+
'store-16': '⊞',
|
|
319
|
+
'strike-through-16': 'S̶',
|
|
320
|
+
'sun-16': '※',
|
|
321
|
+
'sunrise-16': '※',
|
|
322
|
+
'swatch-16': '◧',
|
|
323
|
+
'switch-16': '⇋',
|
|
324
|
+
'syringe-16': '⊸',
|
|
325
|
+
'tack-16': '⊙',
|
|
326
|
+
'tack-disabled-16': '⊘',
|
|
327
|
+
'tag-16': '⊢',
|
|
328
|
+
'temperature-16': '⊥',
|
|
329
|
+
'tennis-ball-16': '◎',
|
|
330
|
+
'terminal-16': '>_',
|
|
331
|
+
'text-16': '𝐓',
|
|
332
|
+
'text-cursor-16': '⌶',
|
|
333
|
+
'text-input-16': '⌗',
|
|
334
|
+
'text-selection-16': '▮',
|
|
335
|
+
'thumbs-down-16': '⊘',
|
|
336
|
+
'thumbs-down-filled-16': '⊘',
|
|
337
|
+
'thumbs-up-16': '✓',
|
|
338
|
+
'thumbs-up-filled-16': '✓',
|
|
339
|
+
'ticket-16': '▬',
|
|
340
|
+
'torch-16': '※',
|
|
341
|
+
'train-16': '⊳',
|
|
342
|
+
'trash-16': '⌧',
|
|
343
|
+
'tray-16': '⊔',
|
|
344
|
+
'tree-16': '⊥',
|
|
345
|
+
'trophy-16': '⊛',
|
|
346
|
+
'two-people-16': '⊙',
|
|
347
|
+
'umbrella-16': '△',
|
|
348
|
+
'underline-16': 'U̲',
|
|
349
|
+
'undo-16': '↺',
|
|
350
|
+
'upload-16': '⤒',
|
|
351
|
+
'uppercase-16': 'Aᴬ',
|
|
352
|
+
'video-16': '▸',
|
|
353
|
+
'video-disabled-16': '⊘',
|
|
354
|
+
'wallet-16': '▬',
|
|
355
|
+
'wand-16': '✧',
|
|
356
|
+
'warning-16': '△',
|
|
357
|
+
'waveform-16': '∿',
|
|
358
|
+
'weights-16': '⊥',
|
|
359
|
+
'wifi-16': '⊛',
|
|
360
|
+
'wifi-disabled-16': '⊘',
|
|
361
|
+
'wind-16': '≋',
|
|
362
|
+
'windsock-16': '⊳',
|
|
363
|
+
'wrench-screwdriver-16': '⊤',
|
|
364
|
+
'wrist-watch-16': '◴',
|
|
365
|
+
'x-mark-circle-16': '×',
|
|
366
|
+
'x-mark-circle-filled-16': '×',
|
|
367
|
+
'x-mark-circle-half-dash-16': '×',
|
|
368
|
+
'x-mark-top-right-square-16': '×',
|
|
369
|
+
'xmark-16': '×',
|
|
370
|
+
}
|
|
15
371
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
372
|
+
// Number icons (number-00-16 through number-99-16) use circled numbers where available,
|
|
373
|
+
// falling back to the plain digit string for values without unicode circled forms.
|
|
374
|
+
for (let i = 0; i <= 99; i++) {
|
|
375
|
+
const id = `number-${String(i).padStart(2, '0')}-16`
|
|
376
|
+
if (i >= 0 && i <= 20) {
|
|
377
|
+
// Unicode circled numbers: ⓪①②…⑳
|
|
378
|
+
ICON_MAP[id] = String.fromCodePoint(i === 0 ? 0x24EA : 0x2460 + i - 1)
|
|
379
|
+
} else if (i <= 50) {
|
|
380
|
+
// Unicode circled numbers 21-50: ㉑㉒…㊿
|
|
381
|
+
ICON_MAP[id] = String.fromCodePoint(0x3251 + i - 21)
|
|
382
|
+
} else {
|
|
383
|
+
// No standard circled unicode above 50, use plain digits
|
|
384
|
+
ICON_MAP[id] = String(i)
|
|
22
385
|
}
|
|
23
|
-
return Math.abs(hash)
|
|
24
386
|
}
|
|
25
387
|
|
|
388
|
+
const FALLBACK_ICON = '●'
|
|
389
|
+
|
|
26
390
|
export function getIconShape(iconId: string): string {
|
|
27
|
-
|
|
28
|
-
const index = hash % ICON_SHAPES.length
|
|
29
|
-
return ICON_SHAPES[index]
|
|
391
|
+
return ICON_MAP[iconId] || FALLBACK_ICON
|
|
30
392
|
}
|
|
31
393
|
|
|
32
394
|
export const iconIds = [
|
|
@@ -591,7 +953,7 @@ export function getIconValue(icon: unknown): string {
|
|
|
591
953
|
|
|
592
954
|
// Handle { fileIcon: string }
|
|
593
955
|
if ('fileIcon' in obj && typeof obj.fileIcon === 'string') {
|
|
594
|
-
return '
|
|
956
|
+
return '▤'
|
|
595
957
|
}
|
|
596
958
|
|
|
597
959
|
// Unknown format - return empty string instead of [object Object]
|
package/src/components/list.tsx
CHANGED
|
@@ -81,30 +81,30 @@ function ListFooter(): any {
|
|
|
81
81
|
const hasDropdown = listContext?.hasDropdown ?? false
|
|
82
82
|
|
|
83
83
|
const content = hasToast ? null : (
|
|
84
|
-
<box style={{ flexDirection: 'row', gap: 3 }}>
|
|
84
|
+
<box style={{ flexDirection: 'row', gap: 3, flexShrink: 0 }}>
|
|
85
85
|
{firstActionTitle && (
|
|
86
|
-
<box style={{ flexDirection: 'row', gap: 1 }}>
|
|
86
|
+
<box style={{ flexDirection: 'row', gap: 1, flexShrink: 0 }}>
|
|
87
87
|
<text flexShrink={0} fg={theme.text} attributes={TextAttributes.BOLD}>
|
|
88
88
|
↵
|
|
89
89
|
</text>
|
|
90
90
|
<text flexShrink={0} fg={theme.textMuted}>{firstActionTitle.toLowerCase()}</text>
|
|
91
91
|
</box>
|
|
92
92
|
)}
|
|
93
|
-
<box style={{ flexDirection: 'row', gap: 1 }}>
|
|
93
|
+
<box style={{ flexDirection: 'row', gap: 1, flexShrink: 0 }}>
|
|
94
94
|
<text flexShrink={0} fg={theme.text} attributes={TextAttributes.BOLD}>
|
|
95
95
|
↑↓
|
|
96
96
|
</text>
|
|
97
97
|
<text flexShrink={0} fg={theme.textMuted}>navigate</text>
|
|
98
98
|
</box>
|
|
99
99
|
{hasDropdown && (
|
|
100
|
-
<box style={{ flexDirection: 'row', gap: 1 }}>
|
|
100
|
+
<box style={{ flexDirection: 'row', gap: 1, flexShrink: 0 }}>
|
|
101
101
|
<text flexShrink={0} fg={theme.text} attributes={TextAttributes.BOLD}>
|
|
102
102
|
^p
|
|
103
103
|
</text>
|
|
104
104
|
<text flexShrink={0} fg={theme.textMuted}>dropdown</text>
|
|
105
105
|
</box>
|
|
106
106
|
)}
|
|
107
|
-
<box style={{ flexDirection: 'row', gap: 1 }}>
|
|
107
|
+
<box style={{ flexDirection: 'row', gap: 1, flexShrink: 0 }}>
|
|
108
108
|
<text flexShrink={0} fg={theme.text} attributes={TextAttributes.BOLD}>
|
|
109
109
|
^k
|
|
110
110
|
</text>
|
|
@@ -774,8 +774,15 @@ export const List: ListType = (props) => {
|
|
|
774
774
|
} = props
|
|
775
775
|
|
|
776
776
|
const theme = useTheme()
|
|
777
|
-
const
|
|
778
|
-
|
|
777
|
+
const currentStackSelectedListIndex = useStore((state) => {
|
|
778
|
+
const stack = state.navigationStack
|
|
779
|
+
const currentItem = stack[stack.length - 1]
|
|
780
|
+
return currentItem?.selectedListIndex
|
|
781
|
+
})
|
|
782
|
+
const [internalSearchText, setInternalSearchText] = useState('')
|
|
783
|
+
const [selectedIndex, setSelectedIndex] = useState<number>(() => {
|
|
784
|
+
return currentStackSelectedListIndex ?? 0
|
|
785
|
+
})
|
|
779
786
|
const [isDropdownOpen, setIsDropdownOpen] = useState(false)
|
|
780
787
|
const [currentDetail, setCurrentDetail] = useState<ReactNode>(null)
|
|
781
788
|
|
|
@@ -845,20 +852,55 @@ export const List: ListType = (props) => {
|
|
|
845
852
|
setIsDropdownOpen(true)
|
|
846
853
|
}
|
|
847
854
|
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
855
|
+
const persistSelectedIndexInCurrentNavigationItem = (index: number) => {
|
|
856
|
+
useStore.setState((state) => {
|
|
857
|
+
const stack = state.navigationStack
|
|
858
|
+
const currentIndex = stack.length - 1
|
|
859
|
+
const currentItem = stack[currentIndex]
|
|
860
|
+
if (!currentItem) {
|
|
861
|
+
return {}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
if (currentItem.selectedListIndex === index) {
|
|
865
|
+
return {}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
const nextStack = [...stack]
|
|
869
|
+
nextStack[currentIndex] = {
|
|
870
|
+
...currentItem,
|
|
871
|
+
selectedListIndex: index,
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
return {
|
|
875
|
+
navigationStack: nextStack,
|
|
876
|
+
}
|
|
853
877
|
})
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
const setSelectedIndexWithPersistence = (index: number) => {
|
|
881
|
+
setSelectedIndex(index)
|
|
882
|
+
persistSelectedIndexInCurrentNavigationItem(index)
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// Sync selection to the first visible item whenever searchText changes.
|
|
886
|
+
// Runs after children's useLayoutEffects (descendants registered) but before paint,
|
|
887
|
+
// so there is no intermediate frame with stale selection.
|
|
888
|
+
// Works for both controlled and uncontrolled searchText.
|
|
889
|
+
const prevSearchTextRef = useRef(searchText)
|
|
890
|
+
useLayoutEffect(() => {
|
|
891
|
+
if (prevSearchTextRef.current === searchText) return
|
|
892
|
+
prevSearchTextRef.current = searchText
|
|
893
|
+
|
|
894
|
+
if (!isFilteringEnabled) return
|
|
895
|
+
|
|
854
896
|
const items = Object.values(descendantsContext.map.current)
|
|
855
897
|
.filter((item) => item.index !== -1 && item.props?.visible !== false)
|
|
856
898
|
.sort((a, b) => a.index - b.index)
|
|
857
899
|
|
|
858
900
|
if (items.length > 0 && items[0]) {
|
|
859
|
-
|
|
901
|
+
setSelectedIndexWithPersistence(items[0].index)
|
|
860
902
|
}
|
|
861
|
-
}
|
|
903
|
+
})
|
|
862
904
|
|
|
863
905
|
const listContextValue = useMemo<ListContextValue>(
|
|
864
906
|
() => ({
|
|
@@ -866,7 +908,7 @@ export const List: ListType = (props) => {
|
|
|
866
908
|
setIsDropdownOpen,
|
|
867
909
|
openDropdown,
|
|
868
910
|
selectedIndex,
|
|
869
|
-
setSelectedIndex,
|
|
911
|
+
setSelectedIndex: setSelectedIndexWithPersistence,
|
|
870
912
|
searchText,
|
|
871
913
|
isFiltering: isFilteringEnabled,
|
|
872
914
|
setCurrentDetail,
|
|
@@ -878,15 +920,15 @@ export const List: ListType = (props) => {
|
|
|
878
920
|
[isDropdownOpen, selectedIndex, searchText, isFilteringEnabled, isShowingDetail, isLoading, searchBarAccessory],
|
|
879
921
|
)
|
|
880
922
|
|
|
881
|
-
// Clear detail when detail view is hidden
|
|
882
|
-
|
|
923
|
+
// Clear detail when detail view is hidden (before paint to avoid flash)
|
|
924
|
+
useLayoutEffect(() => {
|
|
883
925
|
if (!isShowingDetail) {
|
|
884
926
|
setCurrentDetail(null)
|
|
885
927
|
}
|
|
886
928
|
}, [isShowingDetail])
|
|
887
929
|
|
|
888
|
-
// Handle selectedItemId prop changes
|
|
889
|
-
|
|
930
|
+
// Handle selectedItemId prop changes (before paint to avoid flash)
|
|
931
|
+
useLayoutEffect(() => {
|
|
890
932
|
// Only update selection if selectedItemId is explicitly provided
|
|
891
933
|
if (selectedItemId !== undefined) {
|
|
892
934
|
const items = Object.values(descendantsContext.map.current)
|
|
@@ -894,7 +936,7 @@ export const List: ListType = (props) => {
|
|
|
894
936
|
|
|
895
937
|
const foundItem = items.find((item) => item.props?.id === selectedItemId)
|
|
896
938
|
if (foundItem) {
|
|
897
|
-
|
|
939
|
+
setSelectedIndexWithPersistence(foundItem.index)
|
|
898
940
|
}
|
|
899
941
|
}
|
|
900
942
|
}, [selectedItemId])
|
|
@@ -930,6 +972,21 @@ export const List: ListType = (props) => {
|
|
|
930
972
|
scrollBox.scrollTo(Math.max(0, targetScrollTop))
|
|
931
973
|
}
|
|
932
974
|
|
|
975
|
+
// Track whether onLoadMore has been called and we're waiting for new items.
|
|
976
|
+
// Reset when item count changes (new items arrived) so we can trigger again.
|
|
977
|
+
const paginationCalledRef = useRef(false)
|
|
978
|
+
const prevItemCountRef = useRef(0)
|
|
979
|
+
|
|
980
|
+
const triggerPaginationIfNeeded = (currentVisibleIndex: number, totalItems: number) => {
|
|
981
|
+
if (!props.pagination?.hasMore || paginationCalledRef.current) return
|
|
982
|
+
// Trigger when within 5 items of the end, matching Raycast's behavior
|
|
983
|
+
const threshold = Math.min(5, Math.max(1, Math.floor(totalItems * 0.2)))
|
|
984
|
+
if (totalItems - currentVisibleIndex <= threshold) {
|
|
985
|
+
paginationCalledRef.current = true
|
|
986
|
+
props.pagination.onLoadMore()
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
933
990
|
const move = (direction: -1 | 1) => {
|
|
934
991
|
// Get all visible items
|
|
935
992
|
const items = Object.values(descendantsContext.map.current)
|
|
@@ -938,6 +995,12 @@ export const List: ListType = (props) => {
|
|
|
938
995
|
|
|
939
996
|
if (items.length === 0) return
|
|
940
997
|
|
|
998
|
+
// Reset pagination lock when new items arrive
|
|
999
|
+
if (items.length !== prevItemCountRef.current) {
|
|
1000
|
+
prevItemCountRef.current = items.length
|
|
1001
|
+
paginationCalledRef.current = false
|
|
1002
|
+
}
|
|
1003
|
+
|
|
941
1004
|
// Find currently selected item's position in visible items
|
|
942
1005
|
let currentVisibleIndex = items.findIndex(
|
|
943
1006
|
(item) => item.index === selectedIndex,
|
|
@@ -945,13 +1008,21 @@ export const List: ListType = (props) => {
|
|
|
945
1008
|
if (currentVisibleIndex === -1) {
|
|
946
1009
|
// If current selection is not visible, select first visible item
|
|
947
1010
|
if (items[0]) {
|
|
948
|
-
|
|
1011
|
+
setSelectedIndexWithPersistence(items[0].index)
|
|
949
1012
|
}
|
|
950
1013
|
return
|
|
951
1014
|
}
|
|
952
1015
|
|
|
953
1016
|
// Calculate next visible index
|
|
954
1017
|
let nextVisibleIndex = currentVisibleIndex + direction
|
|
1018
|
+
|
|
1019
|
+
// When navigating past the end and pagination has more, don't wrap
|
|
1020
|
+
if (direction === 1 && nextVisibleIndex >= items.length && props.pagination?.hasMore) {
|
|
1021
|
+
triggerPaginationIfNeeded(currentVisibleIndex, items.length)
|
|
1022
|
+
// Stay on the last item instead of wrapping
|
|
1023
|
+
return
|
|
1024
|
+
}
|
|
1025
|
+
|
|
955
1026
|
if (nextVisibleIndex < 0) nextVisibleIndex = items.length - 1
|
|
956
1027
|
if (nextVisibleIndex >= items.length) nextVisibleIndex = 0
|
|
957
1028
|
|
|
@@ -960,7 +1031,11 @@ export const List: ListType = (props) => {
|
|
|
960
1031
|
flushSync(() => {
|
|
961
1032
|
setSelectedIndex(nextItem.index)
|
|
962
1033
|
})
|
|
1034
|
+
persistSelectedIndexInCurrentNavigationItem(nextItem.index)
|
|
963
1035
|
scrollToItem(nextItem)
|
|
1036
|
+
|
|
1037
|
+
// Check if we're approaching the end and should trigger pagination
|
|
1038
|
+
triggerPaginationIfNeeded(nextVisibleIndex, items.length)
|
|
964
1039
|
}
|
|
965
1040
|
}
|
|
966
1041
|
|
|
@@ -1102,10 +1177,11 @@ export const List: ListType = (props) => {
|
|
|
1102
1177
|
rootOptions: {
|
|
1103
1178
|
backgroundColor: undefined,
|
|
1104
1179
|
},
|
|
1180
|
+
viewportOptions: {
|
|
1181
|
+
paddingRight: 0,
|
|
1182
|
+
},
|
|
1105
1183
|
scrollbarOptions: {
|
|
1106
|
-
|
|
1107
|
-
showArrows: true,
|
|
1108
|
-
|
|
1184
|
+
visible: false,
|
|
1109
1185
|
},
|
|
1110
1186
|
}}
|
|
1111
1187
|
>
|
|
@@ -1269,8 +1345,8 @@ const ListItem: ListItemType = (props) => {
|
|
|
1269
1345
|
const selectedIndex = listContext?.selectedIndex ?? 0
|
|
1270
1346
|
const isActive = index === selectedIndex
|
|
1271
1347
|
|
|
1272
|
-
// Update detail when this item becomes active or detail prop changes
|
|
1273
|
-
|
|
1348
|
+
// Update detail when this item becomes active or detail prop changes (before paint)
|
|
1349
|
+
useLayoutEffect(() => {
|
|
1274
1350
|
if (isActive && listContext?.isShowingDetail && listContext?.setCurrentDetail) {
|
|
1275
1351
|
listContext.setCurrentDetail(props.detail || null)
|
|
1276
1352
|
}
|
|
@@ -1486,8 +1562,8 @@ const ListDropdown: ListDropdownType = (props) => {
|
|
|
1486
1562
|
[],
|
|
1487
1563
|
)
|
|
1488
1564
|
|
|
1489
|
-
// Open dropdown dialog when triggered
|
|
1490
|
-
|
|
1565
|
+
// Open dropdown dialog when triggered (before paint to avoid flash)
|
|
1566
|
+
useLayoutEffect(() => {
|
|
1491
1567
|
if (isDropdownOpen && !dialog.stack.length) {
|
|
1492
1568
|
// Pass the children to the dialog to render them there
|
|
1493
1569
|
dialog.push({
|