@swiftbrowser/web 0.1.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 (84) hide show
  1. package/README.md +600 -0
  2. package/app/index.html +125 -0
  3. package/index.html +56 -0
  4. package/node/dist/node/apps.d.ts +58 -0
  5. package/node/dist/node/apps.d.ts.map +1 -0
  6. package/node/dist/node/apps.js +60 -0
  7. package/node/dist/node/apps.js.map +1 -0
  8. package/node/dist/node/config.d.ts +42 -0
  9. package/node/dist/node/config.d.ts.map +1 -0
  10. package/node/dist/node/config.js +99 -0
  11. package/node/dist/node/config.js.map +1 -0
  12. package/node/dist/node/examples.d.ts +39 -0
  13. package/node/dist/node/examples.d.ts.map +1 -0
  14. package/node/dist/node/examples.js +116 -0
  15. package/node/dist/node/examples.js.map +1 -0
  16. package/node/dist/node/index.d.ts +47 -0
  17. package/node/dist/node/index.d.ts.map +1 -0
  18. package/node/dist/node/index.js +52 -0
  19. package/node/dist/node/index.js.map +1 -0
  20. package/node/dist/plugins/app-manifests.d.ts +61 -0
  21. package/node/dist/plugins/app-manifests.d.ts.map +1 -0
  22. package/node/dist/plugins/app-manifests.js +168 -0
  23. package/node/dist/plugins/app-manifests.js.map +1 -0
  24. package/node/dist/plugins/asset-catalogs.d.ts +119 -0
  25. package/node/dist/plugins/asset-catalogs.d.ts.map +1 -0
  26. package/node/dist/plugins/asset-catalogs.js +488 -0
  27. package/node/dist/plugins/asset-catalogs.js.map +1 -0
  28. package/node/dist/plugins/bundle-resources.d.ts +49 -0
  29. package/node/dist/plugins/bundle-resources.d.ts.map +1 -0
  30. package/node/dist/plugins/bundle-resources.js +172 -0
  31. package/node/dist/plugins/bundle-resources.js.map +1 -0
  32. package/node/dist/plugins/swift-wasm.d.ts +33 -0
  33. package/node/dist/plugins/swift-wasm.d.ts.map +1 -0
  34. package/node/dist/plugins/swift-wasm.js +241 -0
  35. package/node/dist/plugins/swift-wasm.js.map +1 -0
  36. package/node/dist/src/assets.d.ts +60 -0
  37. package/node/dist/src/assets.d.ts.map +1 -0
  38. package/node/dist/src/assets.js +54 -0
  39. package/node/dist/src/assets.js.map +1 -0
  40. package/node/dist/src/devEvents.d.ts +31 -0
  41. package/node/dist/src/devEvents.d.ts.map +1 -0
  42. package/node/dist/src/devEvents.js +9 -0
  43. package/node/dist/src/devEvents.js.map +1 -0
  44. package/package.json +56 -0
  45. package/plugins/app-manifests.ts +192 -0
  46. package/plugins/asset-catalogs.ts +558 -0
  47. package/plugins/bundle-resources.ts +195 -0
  48. package/plugins/swift-wasm.ts +259 -0
  49. package/public/_headers +23 -0
  50. package/public/apple-touch-icon.png +0 -0
  51. package/public/icon.svg +14 -0
  52. package/public/manifest.webmanifest +14 -0
  53. package/src/animation.ts +521 -0
  54. package/src/assets.ts +86 -0
  55. package/src/chartDom.ts +481 -0
  56. package/src/devEvents.ts +35 -0
  57. package/src/deviceMode.ts +80 -0
  58. package/src/ghost.ts +25 -0
  59. package/src/interaction.ts +1113 -0
  60. package/src/landing.css +261 -0
  61. package/src/landing.ts +141 -0
  62. package/src/layout/chart.ts +477 -0
  63. package/src/layout/controls.ts +116 -0
  64. package/src/layout/engine.ts +3581 -0
  65. package/src/layout/index.ts +91 -0
  66. package/src/layout/measure.ts +86 -0
  67. package/src/layout/text.ts +124 -0
  68. package/src/layout/types.ts +153 -0
  69. package/src/layout/typography.ts +188 -0
  70. package/src/layoutDom.ts +549 -0
  71. package/src/layoutEvents.ts +110 -0
  72. package/src/locale.ts +64 -0
  73. package/src/main.ts +554 -0
  74. package/src/mock.ts +752 -0
  75. package/src/nodeQueries.ts +60 -0
  76. package/src/protocol.ts +1421 -0
  77. package/src/renderer.ts +2882 -0
  78. package/src/styles.css +2834 -0
  79. package/src/styles.ts +373 -0
  80. package/src/swipe.ts +110 -0
  81. package/src/symbols.ts +595 -0
  82. package/src/typography.ts +76 -0
  83. package/src/vite-env.d.ts +26 -0
  84. package/src/wasm.ts +400 -0
package/src/symbols.ts ADDED
@@ -0,0 +1,595 @@
1
+ /**
2
+ * SF Symbol names → lucide glyphs for the `image` element kind.
3
+ *
4
+ * The Swift side sends `Image(systemName:)` names unchanged; SF Symbols are
5
+ * not redistributable, so the renderer draws the closest glyph from lucide
6
+ * (ISC). Icons are inline SVG at `1em`, stroked with `currentColor`, so they
7
+ * follow the surrounding font size and foreground color like SF Symbols do.
8
+ *
9
+ * `.fill` variants: lucide only ships outlines, so a filled variant is drawn
10
+ * by filling the glyph's outer shape with `currentColor` and stroking the
11
+ * inner marks with the background color (`knockout`), or by filling every
12
+ * path (`solid`) when the glyph is a single silhouette.
13
+ */
14
+
15
+ import {
16
+ Accessibility,
17
+ AlarmClock,
18
+ Archive,
19
+ ArrowDown,
20
+ ArrowDownToLine,
21
+ ArrowLeft,
22
+ ArrowLeftRight,
23
+ ArrowRight,
24
+ ArrowUp,
25
+ ArrowUpDown,
26
+ ArrowUpFromLine,
27
+ ArrowUpRight,
28
+ AtSign,
29
+ Battery,
30
+ Bell,
31
+ Bike,
32
+ Bluetooth,
33
+ Book,
34
+ BookOpen,
35
+ Bookmark,
36
+ Briefcase,
37
+ Bug,
38
+ Building,
39
+ Bus,
40
+ Calendar,
41
+ Camera,
42
+ Car,
43
+ ChartBar,
44
+ ChartLine,
45
+ ChartPie,
46
+ Check,
47
+ ChevronDown,
48
+ ChevronLeft,
49
+ ChevronRight,
50
+ ChevronUp,
51
+ ChevronsDown,
52
+ ChevronsLeft,
53
+ ChevronsRight,
54
+ ChevronsUp,
55
+ ChevronsUpDown,
56
+ Circle,
57
+ CircleAlert,
58
+ CircleArrowDown,
59
+ CircleArrowLeft,
60
+ CircleArrowRight,
61
+ CircleArrowUp,
62
+ CircleCheck,
63
+ CircleDot,
64
+ CircleEllipsis,
65
+ CircleMinus,
66
+ CirclePause,
67
+ CirclePlay,
68
+ CirclePlus,
69
+ CircleStop,
70
+ CircleQuestionMark,
71
+ CircleUser,
72
+ CircleX,
73
+ Clipboard,
74
+ Clock,
75
+ Cloud,
76
+ CloudLightning,
77
+ CloudMoon,
78
+ CloudRain,
79
+ CloudSnow,
80
+ CloudSun,
81
+ Code,
82
+ Cog,
83
+ Compass,
84
+ Copy,
85
+ CreditCard,
86
+ Crown,
87
+ Download,
88
+ Droplet,
89
+ Ellipsis,
90
+ Eye,
91
+ EyeOff,
92
+ FaceSlightlySmiling,
93
+ File,
94
+ FileText,
95
+ Flag,
96
+ Flame,
97
+ Folder,
98
+ Funnel,
99
+ Gamepad2,
100
+ Gift,
101
+ Globe,
102
+ GraduationCap,
103
+ Hand,
104
+ Hourglass,
105
+ Headphones,
106
+ Heart,
107
+ House,
108
+ Image,
109
+ Inbox,
110
+ Info,
111
+ Key,
112
+ Keyboard,
113
+ Laptop,
114
+ Leaf,
115
+ Lightbulb,
116
+ Link,
117
+ List,
118
+ ListChecks,
119
+ ListOrdered,
120
+ LoaderCircle,
121
+ Lock,
122
+ LockOpen,
123
+ LogIn,
124
+ LogOut,
125
+ Mail,
126
+ Map,
127
+ MapPin,
128
+ Menu,
129
+ MessageCircle,
130
+ MessageSquare,
131
+ Mic,
132
+ MicOff,
133
+ Minus,
134
+ Monitor,
135
+ Moon,
136
+ Music,
137
+ Package,
138
+ Paperclip,
139
+ Pause,
140
+ Pencil,
141
+ Phone,
142
+ Pin,
143
+ Plane,
144
+ Play,
145
+ Plus,
146
+ Power,
147
+ Printer,
148
+ QrCode,
149
+ RefreshCw,
150
+ Repeat,
151
+ RotateCcw,
152
+ RotateCw,
153
+ Search,
154
+ Send,
155
+ Settings,
156
+ Share,
157
+ Shield,
158
+ ShieldCheck,
159
+ ShoppingBag,
160
+ ShoppingCart,
161
+ Shuffle,
162
+ SkipBack,
163
+ SkipForward,
164
+ SlidersHorizontal,
165
+ Smartphone,
166
+ Sparkles,
167
+ Speaker,
168
+ Square,
169
+ SquareCheck,
170
+ SquarePen,
171
+ Star,
172
+ Sun,
173
+ Tag,
174
+ Target,
175
+ Terminal,
176
+ Timer,
177
+ ThumbsUp,
178
+ Trash,
179
+ TriangleAlert,
180
+ TrendingUp,
181
+ Trophy,
182
+ Tv,
183
+ Type,
184
+ Upload,
185
+ User,
186
+ Users,
187
+ Volume,
188
+ Volume1,
189
+ Volume2,
190
+ VolumeX,
191
+ Wallet,
192
+ Watch,
193
+ Wifi,
194
+ Wind,
195
+ Wrench,
196
+ X,
197
+ Zap,
198
+ ZoomIn,
199
+ ZoomOut,
200
+ createElement,
201
+ type IconNode,
202
+ Grid3x3,
203
+ LayoutGrid,
204
+ LayoutList,
205
+ MessageSquarePlus,
206
+ MessageSquareText,
207
+ Truck,
208
+ Utensils,
209
+ } from 'lucide';
210
+
211
+ /** How a glyph is painted; see the file comment. */
212
+ export type GlyphFill = 'outline' | 'knockout' | 'solid';
213
+
214
+ export interface SymbolGlyph {
215
+ icon: IconNode;
216
+ fill: GlyphFill;
217
+ }
218
+
219
+ const outline = (icon: IconNode): SymbolGlyph => ({ icon, fill: 'outline' });
220
+ const knockout = (icon: IconNode): SymbolGlyph => ({ icon, fill: 'knockout' });
221
+ const solid = (icon: IconNode): SymbolGlyph => ({ icon, fill: 'solid' });
222
+
223
+ /** SF Symbol name → glyph. Keys are the exact `systemName` strings. */
224
+ export const SF_SYMBOLS: Readonly<Record<string, SymbolGlyph>> = {
225
+ // Marks
226
+ plus: outline(Plus),
227
+ minus: outline(Minus),
228
+ checkmark: outline(Check),
229
+ 'checkmark.circle': outline(CircleCheck),
230
+ 'checkmark.circle.fill': knockout(CircleCheck),
231
+ 'checkmark.square': outline(SquareCheck),
232
+ 'checkmark.square.fill': knockout(SquareCheck),
233
+ checklist: outline(ListChecks),
234
+ xmark: outline(X),
235
+ 'xmark.circle': outline(CircleX),
236
+ 'xmark.circle.fill': knockout(CircleX),
237
+ 'plus.circle': outline(CirclePlus),
238
+ 'plus.circle.fill': knockout(CirclePlus),
239
+ 'minus.circle': outline(CircleMinus),
240
+ 'minus.circle.fill': knockout(CircleMinus),
241
+ 'info.circle': outline(Info),
242
+ 'info.circle.fill': knockout(Info),
243
+ 'questionmark.circle': outline(CircleQuestionMark),
244
+ 'questionmark.circle.fill': knockout(CircleQuestionMark),
245
+ 'exclamationmark.circle': outline(CircleAlert),
246
+ 'exclamationmark.circle.fill': knockout(CircleAlert),
247
+ 'exclamationmark.triangle': outline(TriangleAlert),
248
+ 'exclamationmark.triangle.fill': knockout(TriangleAlert),
249
+ ellipsis: outline(Ellipsis),
250
+ 'ellipsis.circle': outline(CircleEllipsis),
251
+ 'ellipsis.circle.fill': knockout(CircleEllipsis),
252
+
253
+ // Shapes
254
+ circle: outline(Circle),
255
+ 'circle.fill': solid(Circle),
256
+ 'circle.inset.filled': outline(CircleDot),
257
+ 'largecircle.fill.circle': outline(CircleDot),
258
+ square: outline(Square),
259
+ 'square.fill': solid(Square),
260
+ star: outline(Star),
261
+ 'star.fill': solid(Star),
262
+ heart: outline(Heart),
263
+ 'heart.fill': solid(Heart),
264
+ bolt: outline(Zap),
265
+ 'bolt.fill': solid(Zap),
266
+ sparkles: outline(Sparkles),
267
+
268
+ // Chevrons and arrows
269
+ 'chevron.left': outline(ChevronLeft),
270
+ 'chevron.right': outline(ChevronRight),
271
+ 'chevron.up': outline(ChevronUp),
272
+ 'chevron.down': outline(ChevronDown),
273
+ 'chevron.left.2': outline(ChevronsLeft),
274
+ 'chevron.right.2': outline(ChevronsRight),
275
+ 'chevron.up.2': outline(ChevronsUp),
276
+ 'chevron.up.chevron.down': outline(ChevronsUpDown),
277
+ 'chevron.down.2': outline(ChevronsDown),
278
+ 'chevron.backward': outline(ChevronLeft),
279
+ 'chevron.forward': outline(ChevronRight),
280
+ 'arrow.left': outline(ArrowLeft),
281
+ 'arrow.right': outline(ArrowRight),
282
+ 'arrow.up': outline(ArrowUp),
283
+ 'arrow.down': outline(ArrowDown),
284
+ 'arrow.backward': outline(ArrowLeft),
285
+ 'arrow.forward': outline(ArrowRight),
286
+ 'arrow.up.right': outline(ArrowUpRight),
287
+ 'arrow.left.arrow.right': outline(ArrowLeftRight),
288
+ 'arrow.up.arrow.down': outline(ArrowUpDown),
289
+ 'arrow.left.circle': outline(CircleArrowLeft),
290
+ 'arrow.right.circle': outline(CircleArrowRight),
291
+ 'arrow.up.circle': outline(CircleArrowUp),
292
+ 'arrow.down.circle': outline(CircleArrowDown),
293
+ 'arrow.down.to.line': outline(ArrowDownToLine),
294
+ 'arrow.up.to.line': outline(ArrowUpFromLine),
295
+ 'arrow.clockwise': outline(RotateCw),
296
+ 'arrow.counterclockwise': outline(RotateCcw),
297
+ 'arrow.triangle.2.circlepath': outline(RefreshCw),
298
+ 'arrow.2.squarepath': outline(RefreshCw),
299
+ repeat: outline(Repeat),
300
+ shuffle: outline(Shuffle),
301
+ 'square.and.arrow.up': outline(Share),
302
+ 'square.and.arrow.down': outline(Download),
303
+ 'arrow.down.doc': outline(Download),
304
+ 'arrow.up.doc': outline(Upload),
305
+ 'rectangle.portrait.and.arrow.right': outline(LogOut),
306
+ 'rectangle.portrait.and.arrow.forward': outline(LogOut),
307
+ 'arrow.right.to.line': outline(LogIn),
308
+
309
+ // Editing
310
+ trash: outline(Trash),
311
+ 'trash.fill': outline(Trash),
312
+ pencil: outline(Pencil),
313
+ 'square.and.pencil': outline(SquarePen),
314
+ 'doc.on.doc': outline(Copy),
315
+ 'doc.on.clipboard': outline(Clipboard),
316
+ paperclip: outline(Paperclip),
317
+ pin: outline(Pin),
318
+ 'pin.fill': solid(Pin),
319
+ bookmark: outline(Bookmark),
320
+ 'bookmark.fill': solid(Bookmark),
321
+ flag: outline(Flag),
322
+ 'flag.fill': solid(Flag),
323
+ tag: outline(Tag),
324
+ 'tag.fill': solid(Tag),
325
+ textformat: outline(Type),
326
+ 'line.3.horizontal': outline(Menu),
327
+ 'line.3.horizontal.decrease': outline(Funnel),
328
+ 'line.3.horizontal.decrease.circle': outline(Funnel),
329
+ 'slider.horizontal.3': outline(SlidersHorizontal),
330
+ 'list.bullet': outline(List),
331
+ 'list.number': outline(ListOrdered),
332
+ 'chart.bar': outline(ChartBar),
333
+ 'chart.xyaxis.line': outline(ChartLine),
334
+ 'chart.pie': outline(ChartPie),
335
+ magnifyingglass: outline(Search),
336
+ 'plus.magnifyingglass': outline(ZoomIn),
337
+ 'minus.magnifyingglass': outline(ZoomOut),
338
+
339
+ // People and places
340
+ person: outline(User),
341
+ 'person.fill': outline(User),
342
+ 'person.2': outline(Users),
343
+ 'person.circle': outline(CircleUser),
344
+ 'person.circle.fill': knockout(CircleUser),
345
+ 'person.crop.circle': outline(CircleUser),
346
+ 'person.crop.circle.fill': knockout(CircleUser),
347
+ 'figure.walk': outline(Accessibility),
348
+ 'face.smiling': outline(FaceSlightlySmiling),
349
+ 'hand.thumbsup': outline(ThumbsUp),
350
+ 'hand.thumbsup.fill': solid(ThumbsUp),
351
+ 'hand.raised': outline(Hand),
352
+ house: outline(House),
353
+ 'house.fill': solid(House),
354
+ building: outline(Building),
355
+ 'building.2': outline(Building),
356
+ graduationcap: outline(GraduationCap),
357
+ briefcase: outline(Briefcase),
358
+ 'briefcase.fill': solid(Briefcase),
359
+ map: outline(Map),
360
+ location: outline(MapPin),
361
+ 'location.fill': knockout(MapPin),
362
+ 'mappin': outline(MapPin),
363
+ 'mappin.and.ellipse': outline(MapPin),
364
+ globe: outline(Globe),
365
+ safari: outline(Compass),
366
+ scope: outline(Target),
367
+
368
+ // Communication
369
+ bell: outline(Bell),
370
+ 'bell.fill': solid(Bell),
371
+ envelope: outline(Mail),
372
+ 'envelope.fill': outline(Mail),
373
+ 'envelope.open': outline(Inbox),
374
+ tray: outline(Inbox),
375
+ phone: outline(Phone),
376
+ 'phone.fill': solid(Phone),
377
+ message: outline(MessageCircle),
378
+ 'message.fill': solid(MessageCircle),
379
+ bubble: outline(MessageSquare),
380
+ 'bubble.left': outline(MessageSquare),
381
+ at: outline(AtSign),
382
+ paperplane: outline(Send),
383
+ 'paperplane.fill': outline(Send),
384
+ link: outline(Link),
385
+ 'link.circle': outline(Link),
386
+
387
+ // Time
388
+ calendar: outline(Calendar),
389
+ clock: outline(Clock),
390
+ 'clock.fill': knockout(Clock),
391
+ alarm: outline(AlarmClock),
392
+ 'applewatch': outline(Watch),
393
+ stopwatch: outline(Timer),
394
+ timer: outline(Timer),
395
+ hourglass: outline(Hourglass),
396
+
397
+ // Media and devices
398
+ camera: outline(Camera),
399
+ 'camera.fill': outline(Camera),
400
+ photo: outline(Image),
401
+ 'photo.fill': outline(Image),
402
+ 'photo.on.rectangle': outline(Image),
403
+ play: outline(Play),
404
+ 'play.fill': solid(Play),
405
+ 'play.circle': outline(CirclePlay),
406
+ 'play.circle.fill': knockout(CirclePlay),
407
+ 'pause.circle': outline(CirclePause),
408
+ 'pause.circle.fill': knockout(CirclePause),
409
+ 'stop.circle': outline(CircleStop),
410
+ pause: outline(Pause),
411
+ 'pause.fill': solid(Pause),
412
+ stop: outline(Square),
413
+ 'stop.fill': solid(Square),
414
+ 'backward.end': outline(SkipBack),
415
+ 'forward.end': outline(SkipForward),
416
+ 'backward.end.fill': solid(SkipBack),
417
+ 'forward.end.fill': solid(SkipForward),
418
+ 'speaker': outline(Volume),
419
+ 'speaker.wave.1': outline(Volume1),
420
+ 'speaker.wave.2': outline(Volume2),
421
+ 'speaker.wave.3': outline(Volume2),
422
+ 'speaker.slash': outline(VolumeX),
423
+ 'hifispeaker': outline(Speaker),
424
+ headphones: outline(Headphones),
425
+ mic: outline(Mic),
426
+ 'mic.fill': outline(Mic),
427
+ 'mic.slash': outline(MicOff),
428
+ 'music.note': outline(Music),
429
+ tv: outline(Tv),
430
+ desktopcomputer: outline(Monitor),
431
+ laptopcomputer: outline(Laptop),
432
+ iphone: outline(Smartphone),
433
+ keyboard: outline(Keyboard),
434
+ printer: outline(Printer),
435
+ 'qrcode': outline(QrCode),
436
+ gamecontroller: outline(Gamepad2),
437
+ 'gamecontroller.fill': outline(Gamepad2),
438
+ wifi: outline(Wifi),
439
+ 'antenna.radiowaves.left.and.right': outline(Wifi),
440
+ bluetooth: outline(Bluetooth),
441
+ 'battery.100': outline(Battery),
442
+ power: outline(Power),
443
+ 'cpu': outline(Terminal),
444
+ 'chevron.left.forwardslash.chevron.right': outline(Code),
445
+ terminal: outline(Terminal),
446
+ 'ant': outline(Bug),
447
+ 'ladybug': outline(Bug),
448
+ wrench: outline(Wrench),
449
+ 'wrench.and.screwdriver': outline(Wrench),
450
+ 'wrench.fill': outline(Wrench),
451
+
452
+ // Documents
453
+ folder: outline(Folder),
454
+ 'folder.fill': solid(Folder),
455
+ doc: outline(File),
456
+ 'doc.fill': outline(File),
457
+ 'doc.text': outline(FileText),
458
+ 'doc.text.fill': outline(FileText),
459
+ archivebox: outline(Archive),
460
+ 'shippingbox': outline(Package),
461
+ 'shippingbox.fill': outline(Package),
462
+
463
+ // Settings and security
464
+ gear: outline(Settings),
465
+ gearshape: outline(Settings),
466
+ 'gearshape.fill': outline(Settings),
467
+ 'gearshape.2': outline(Cog),
468
+ lock: outline(Lock),
469
+ 'lock.fill': solid(Lock),
470
+ 'lock.open': outline(LockOpen),
471
+ 'lock.open.fill': solid(LockOpen),
472
+ key: outline(Key),
473
+ 'key.fill': solid(Key),
474
+ shield: outline(Shield),
475
+ 'shield.fill': solid(Shield),
476
+ 'checkmark.shield': outline(ShieldCheck),
477
+ 'checkmark.shield.fill': knockout(ShieldCheck),
478
+ eye: outline(Eye),
479
+ 'eye.fill': knockout(Eye),
480
+ 'eye.slash': outline(EyeOff),
481
+ 'eye.slash.fill': outline(EyeOff),
482
+
483
+ // Commerce
484
+ cart: outline(ShoppingCart),
485
+ 'cart.fill': outline(ShoppingCart),
486
+ bag: outline(ShoppingBag),
487
+ 'bag.fill': outline(ShoppingBag),
488
+ creditcard: outline(CreditCard),
489
+ 'creditcard.fill': knockout(CreditCard),
490
+ wallet: outline(Wallet),
491
+ 'wallet.pass': outline(Wallet),
492
+ gift: outline(Gift),
493
+ 'gift.fill': outline(Gift),
494
+ crown: outline(Crown),
495
+ 'crown.fill': solid(Crown),
496
+ trophy: outline(Trophy),
497
+ 'trophy.fill': outline(Trophy),
498
+
499
+ // Nature and weather
500
+ 'sun.max': outline(Sun),
501
+ 'sun.max.fill': solid(Sun),
502
+ moon: outline(Moon),
503
+ 'moon.fill': solid(Moon),
504
+ 'moon.stars': outline(Moon),
505
+ cloud: outline(Cloud),
506
+ 'cloud.fill': solid(Cloud),
507
+ 'cloud.rain': outline(CloudRain),
508
+ 'cloud.snow': outline(CloudSnow),
509
+ 'cloud.sun': outline(CloudSun),
510
+ 'cloud.sun.fill': solid(CloudSun),
511
+ 'moon.circle.fill': solid(Moon),
512
+ 'sun.max.circle.fill': solid(Sun),
513
+ 'person.3': outline(Users),
514
+ 'person.3.fill': solid(Users),
515
+ 'chart.line.uptrend.xyaxis': outline(TrendingUp),
516
+ 'square.grid.2x2': outline(LayoutGrid),
517
+ 'circle.grid.3x3': outline(Grid3x3),
518
+ 'fork.knife': outline(Utensils),
519
+ 'text.bubble': outline(MessageSquareText),
520
+ 'plus.bubble': outline(MessageSquarePlus),
521
+ 'box.truck': outline(Truck),
522
+ 'list.bullet.below.rectangle': outline(LayoutList),
523
+ 'cloud.moon': outline(CloudMoon),
524
+ 'cloud.bolt': outline(CloudLightning),
525
+ wind: outline(Wind),
526
+ leaf: outline(Leaf),
527
+ 'leaf.fill': solid(Leaf),
528
+ flame: outline(Flame),
529
+ 'flame.fill': solid(Flame),
530
+ drop: outline(Droplet),
531
+ 'drop.fill': solid(Droplet),
532
+ lightbulb: outline(Lightbulb),
533
+ 'lightbulb.fill': outline(Lightbulb),
534
+
535
+ // Transport
536
+ car: outline(Car),
537
+ 'car.fill': outline(Car),
538
+ airplane: outline(Plane),
539
+ bus: outline(Bus),
540
+ 'bus.fill': outline(Bus),
541
+ bicycle: outline(Bike),
542
+
543
+ // Reading
544
+ book: outline(Book),
545
+ 'book.fill': solid(Book),
546
+ 'book.closed': outline(Book),
547
+ 'text.book.closed': outline(BookOpen),
548
+
549
+ // Activity
550
+ 'rays': outline(LoaderCircle),
551
+ 'circle.dotted': outline(LoaderCircle),
552
+ };
553
+
554
+ /** Number of SF Symbol names the renderer can draw. */
555
+ export const SF_SYMBOL_COUNT = Object.keys(SF_SYMBOLS).length;
556
+
557
+ export function lookupSymbol(systemName: string): SymbolGlyph | undefined {
558
+ return SF_SYMBOLS[systemName];
559
+ }
560
+
561
+ const SVG_NS = 'http://www.w3.org/2000/svg';
562
+
563
+ /** Color used for inner marks of `knockout` glyphs; styles.css sets the variable. */
564
+ const KNOCKOUT_COLOR = 'var(--sb-icon-knockout, var(--sb-color-system-background, #fff))';
565
+
566
+ /**
567
+ * Build the `<svg>` for a symbol. Returns `null` for unknown names; the
568
+ * caller draws a placeholder in that case.
569
+ */
570
+ export function renderSymbol(systemName: string): SVGElement | null {
571
+ const glyph = lookupSymbol(systemName);
572
+ if (!glyph) return null;
573
+ const svg = createElement(glyph.icon, {
574
+ width: '1em',
575
+ height: '1em',
576
+ 'aria-hidden': 'true',
577
+ focusable: 'false',
578
+ });
579
+ if (svg.namespaceURI !== SVG_NS) return null;
580
+ svg.setAttribute('data-sb-symbol', systemName);
581
+ svg.setAttribute('data-sb-glyph-fill', glyph.fill);
582
+ if (glyph.fill === 'solid') {
583
+ for (const shape of Array.from(svg.children)) {
584
+ shape.setAttribute('fill', 'currentColor');
585
+ }
586
+ } else if (glyph.fill === 'knockout') {
587
+ const [outer, ...inner] = Array.from(svg.children);
588
+ outer?.setAttribute('fill', 'currentColor');
589
+ for (const mark of inner) {
590
+ mark.setAttribute('stroke', KNOCKOUT_COLOR);
591
+ mark.setAttribute('fill', 'none');
592
+ }
593
+ }
594
+ return svg;
595
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Dynamic Type for the page: a thin layer over the layout engine's font
3
+ * resolution (`src/layout/typography.ts`), which is the single source of
4
+ * truth for Apple's Dynamic Type table (point sizes per text style and size
5
+ * category) and iOS line heights.
6
+ *
7
+ * The page writes one CSS custom property pair per text style on the device
8
+ * frame (`--sb-ts-<style>-size` / `-lh`) plus a `-scale` factor relative to
9
+ * Large, so styled text that is not laid out by the engine (chrome, the mock
10
+ * page before the first layout) still follows the selected size.
11
+ */
12
+
13
+ import {
14
+ TEXT_STYLE_SIZES,
15
+ lineHeightFor,
16
+ textStyleSize,
17
+ type TextStyle,
18
+ } from './layout/typography';
19
+ import type { DynamicTypeSize } from './protocol';
20
+
21
+ export {
22
+ DYNAMIC_TYPE_SIZES,
23
+ FONT_FAMILIES,
24
+ FONT_WEIGHTS,
25
+ LINE_HEIGHTS,
26
+ TEXT_STYLE_SIZES,
27
+ defaultFont,
28
+ lineHeightFor,
29
+ makeFont,
30
+ resolveFont,
31
+ textStyleSize,
32
+ } from './layout/typography';
33
+ export type { TextStyle } from './layout/typography';
34
+
35
+ export const DEFAULT_TYPE_SIZE: DynamicTypeSize = 'large';
36
+
37
+ export const TEXT_STYLES: readonly TextStyle[] = Object.keys(TEXT_STYLE_SIZES) as TextStyle[];
38
+
39
+ /** Default weight of a text style (only `headline` differs from regular). */
40
+ export const TEXT_STYLE_WEIGHT: Partial<Record<TextStyle, 'semibold'>> = {
41
+ headline: 'semibold',
42
+ };
43
+
44
+ export interface ResolvedTextStyle {
45
+ fontSize: number;
46
+ lineHeight: number;
47
+ }
48
+
49
+ /** Point size and line height of `style` at `size`. */
50
+ export function resolveTextStyle(style: TextStyle, size: DynamicTypeSize): ResolvedTextStyle {
51
+ const fontSize = textStyleSize(style, size);
52
+ return { fontSize, lineHeight: lineHeightFor(fontSize) };
53
+ }
54
+
55
+ /** Scale factor of `style` at `size` relative to Large (`Font.system(size:relativeTo:)`). */
56
+ export function relativeScale(style: TextStyle, size: DynamicTypeSize): number {
57
+ return textStyleSize(style, size) / textStyleSize(style, DEFAULT_TYPE_SIZE);
58
+ }
59
+
60
+ /** CSS custom property names the renderer reads for a text style. */
61
+ export function textStyleVar(style: TextStyle, metric: 'size' | 'lh'): string {
62
+ return `--sb-ts-${style}-${metric}`;
63
+ }
64
+
65
+ /**
66
+ * Write every text style's size and line height for `size` as CSS custom
67
+ * properties on `target` (the device frame).
68
+ */
69
+ export function applyTypeSizeVariables(target: HTMLElement, size: DynamicTypeSize): void {
70
+ for (const style of TEXT_STYLES) {
71
+ const { fontSize, lineHeight } = resolveTextStyle(style, size);
72
+ target.style.setProperty(textStyleVar(style, 'size'), `${fontSize}px`);
73
+ target.style.setProperty(textStyleVar(style, 'lh'), `${lineHeight}px`);
74
+ target.style.setProperty(`--sb-ts-${style}-scale`, String(relativeScale(style, size)));
75
+ }
76
+ }
@@ -0,0 +1,26 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ // Injected by `define` in node/config.ts (every page; the landing page lists the apps, the app page reads its own entry).
4
+
5
+ /** One registered app, as the landing page sees it (`LandingApp` in node/config.ts). */
6
+ interface SBLandingApp {
7
+ /** URL-safe name (`?app=<name>`). */
8
+ name: string;
9
+ /** Card title; the spec's `displayName`, else `name`. */
10
+ displayName: string;
11
+ /** Card subtitle, when the spec has one. */
12
+ description?: string;
13
+ /** URL of the app's own icon (`/manifests/<name>-icon.png`), when the spec has one. */
14
+ icon?: string;
15
+ /** Languages the module carries locale data for; the page runs it in the viewer's when among them. */
16
+ locales?: string[];
17
+ }
18
+
19
+ /** The registered apps, in registry order. */
20
+ declare const __SB_APPS__: readonly SBLandingApp[];
21
+ /** Commit sha the site was built from (`GITHUB_SHA`, else `git rev-parse --short HEAD`, else "dev"). */
22
+ declare const __SB_COMMIT__: string;
23
+ /** Branch the site was built from (`GITHUB_REF_NAME`, else `git rev-parse --abbrev-ref HEAD`, else ""). */
24
+ declare const __SB_BRANCH__: string;
25
+ /** ISO 8601 timestamp of the build. */
26
+ declare const __SB_BUILT_AT__: string;