@octane-xplat/macos-renderer 0.13.0 → 0.15.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.
- package/README.md +95 -20
- package/package.json +15 -2
- package/src/appearance.ts +2 -0
- package/src/fonts.ts +2 -0
- package/src/formatted-text.ts +147 -0
- package/src/gestures.ts +196 -0
- package/src/host-globals.d.ts +55 -0
- package/src/html-text.ts +88 -0
- package/src/image.ts +91 -16
- package/src/index.d.ts +9 -0
- package/src/index.ts +5030 -678
- package/src/layer.ts +11 -9
- package/src/list-template.ts +266 -0
- package/src/list-view.ts +445 -0
- package/src/portal-components.macos.tsx +86 -0
- package/src/presentation.ts +48 -15
- package/src/scroll-view.ts +124 -0
- package/src/tab-view.ts +512 -0
- package/src/template-props.ts +402 -0
- package/src/vendor/listview/LICENSE +19 -0
- package/src/vendor/listview/README.md +1 -0
- package/src/vendor/listview/binding-options.ts +189 -0
- package/src/vendor/listview/expressions.ts +285 -0
- package/src/webview.ts +36 -7
- package/types/ARKitCore.d.ts +199 -0
- package/types/AVFAudio.d.ts +2304 -0
- package/types/AVFoundation.d.ts +6974 -0
- package/types/AVKit.d.ts +215 -0
- package/types/AVRouting.d.ts +7 -0
- package/types/Accelerate.d.ts +4776 -0
- package/types/Accessibility.d.ts +69 -0
- package/types/Accounts.d.ts +134 -0
- package/types/AdSupport.d.ts +12 -0
- package/types/AddressBook.d.ts +1012 -0
- package/types/AppKit.d.ts +34247 -0
- package/types/AppTrackingTransparency.d.ts +23 -0
- package/types/AppleScriptKit.d.ts +6 -0
- package/types/ApplicationServices.d.ts +6346 -0
- package/types/AudioToolbox.d.ts +7129 -0
- package/types/AudioVideoBridging.d.ts +613 -0
- package/types/AuthenticationServices.d.ts +982 -0
- package/types/AutomaticAssessmentConfiguration.d.ts +46 -0
- package/types/Automator.d.ts +248 -0
- package/types/BackgroundAssets.d.ts +9 -0
- package/types/BrowserEngineKit.d.ts +166 -0
- package/types/BusinessChat.d.ts +29 -0
- package/types/CFNetwork.d.ts +931 -0
- package/types/CalendarStore.d.ts +354 -0
- package/types/CallKit.d.ts +30 -0
- package/types/Carbon.d.ts +16207 -0
- package/types/ClassKit.d.ts +281 -0
- package/types/CloudKit.d.ts +1565 -0
- package/types/Collaboration.d.ts +123 -0
- package/types/ColorSync.d.ts +562 -0
- package/types/CompositorServices.d.ts +60 -0
- package/types/ComputeGraph.d.ts +16 -0
- package/types/Contacts.d.ts +1558 -0
- package/types/ContactsUI.d.ts +39 -0
- package/types/CoreAudio.d.ts +1376 -0
- package/types/CoreAudioKit.d.ts +122 -0
- package/types/CoreAudioTypes.d.ts +1003 -0
- package/types/CoreBluetooth.d.ts +657 -0
- package/types/CoreData.d.ts +2479 -0
- package/types/CoreFoundation.d.ts +5546 -0
- package/types/CoreGraphics.d.ts +3676 -0
- package/types/CoreHaptics.d.ts +361 -0
- package/types/CoreImage.d.ts +4781 -0
- package/types/CoreLocation.d.ts +564 -0
- package/types/CoreMIDI.d.ts +1538 -0
- package/types/CoreML.d.ts +905 -0
- package/types/CoreMedia.d.ts +2615 -0
- package/types/CoreMediaIO.d.ts +1046 -0
- package/types/CoreMotion.d.ts +316 -0
- package/types/CoreServices.d.ts +24810 -0
- package/types/CoreSpotlight.d.ts +789 -0
- package/types/CoreTelephony.d.ts +31 -0
- package/types/CoreText.d.ts +3973 -0
- package/types/CoreTransferable.d.ts +3 -0
- package/types/CoreVideo.d.ts +1162 -0
- package/types/CoreWLAN.d.ts +556 -0
- package/types/CryptoTokenKit.d.ts +548 -0
- package/types/DVDPlayback.d.ts +931 -0
- package/types/DataDetection.d.ts +66 -0
- package/types/DeviceCheck.d.ts +46 -0
- package/types/DeviceDiscoveryExtension.d.ts +142 -0
- package/types/DirectoryService.d.ts +966 -0
- package/types/DiscRecording.d.ts +2345 -0
- package/types/DiscRecordingUI.d.ts +288 -0
- package/types/DiskArbitration.d.ts +366 -0
- package/types/DriverKit.d.ts +639 -0
- package/types/EventKit.d.ts +640 -0
- package/types/ExceptionHandling.d.ts +56 -0
- package/types/ExecutionPolicy.d.ts +30 -0
- package/types/ExternalAccessory.d.ts +98 -0
- package/types/FSKit.d.ts +237 -0
- package/types/FileProvider.d.ts +495 -0
- package/types/FileProviderUI.d.ts +31 -0
- package/types/FinderSync.d.ts +165 -0
- package/types/FocusEngine.d.ts +133 -0
- package/types/ForceFeedback.d.ts +399 -0
- package/types/Foundation.d.ts +18216 -0
- package/types/GLKit.d.ts +937 -0
- package/types/GLUT.d.ts +1018 -0
- package/types/GSS.d.ts +855 -0
- package/types/GameController.d.ts +1394 -0
- package/types/GameKit.d.ts +1958 -0
- package/types/GameSave.d.ts +54 -0
- package/types/GameplayKit.d.ts +1645 -0
- package/types/HealthKit.d.ts +278 -0
- package/types/Hypervisor.d.ts +2079 -0
- package/types/ICADevices.d.ts +1400 -0
- package/types/IOBluetooth.d.ts +6094 -0
- package/types/IOBluetoothUI.d.ts +250 -0
- package/types/IOKit.d.ts +25804 -0
- package/types/IOSurface.d.ts +435 -0
- package/types/IOUSBHost.d.ts +809 -0
- package/types/ImageCaptureCore.d.ts +1104 -0
- package/types/ImageIO.d.ts +1697 -0
- package/types/InputMethodKit.d.ts +264 -0
- package/types/InstallerPlugins.d.ts +102 -0
- package/types/InstantMessage.d.ts +229 -0
- package/types/Intents.d.ts +1833 -0
- package/types/IntentsUI.d.ts +5 -0
- package/types/JavaRuntimeSupport.d.ts +520 -0
- package/types/JavaScriptCore.d.ts +934 -0
- package/types/Kerberos.d.ts +3754 -0
- package/types/Kernel.d.ts +33698 -0
- package/types/KernelManagement.d.ts +5 -0
- package/types/LatentSemanticMapping.d.ts +152 -0
- package/types/LinkPresentation.d.ts +57 -0
- package/types/LocalAuthentication.d.ts +94 -0
- package/types/MLCompute.d.ts +2343 -0
- package/types/MapKit.d.ts +2125 -0
- package/types/Matter.d.ts +151 -0
- package/types/MediaAccessibility.d.ts +137 -0
- package/types/MediaLibrary.d.ts +394 -0
- package/types/MediaPlayer.d.ts +475 -0
- package/types/MediaToolbox.d.ts +70 -0
- package/types/Metal.d.ts +4542 -0
- package/types/MetalFX.d.ts +107 -0
- package/types/MetalKit.d.ts +524 -0
- package/types/MetalPerformanceShaders.d.ts +9306 -0
- package/types/MetalPerformanceShadersGraph.d.ts +1394 -0
- package/types/MetricKit.d.ts +231 -0
- package/types/ModelIO.d.ts +2908 -0
- package/types/MultipeerConnectivity.d.ts +348 -0
- package/types/NaturalLanguage.d.ts +556 -0
- package/types/NearbyInteraction.d.ts +51 -0
- package/types/NetFS.d.ts +99 -0
- package/types/Network.d.ts +1622 -0
- package/types/NetworkExtension.d.ts +1574 -0
- package/types/NotificationCenter.d.ts +103 -0
- package/types/OSAKit.d.ts +260 -0
- package/types/OSLog.d.ts +208 -0
- package/types/OpenAL.d.ts +314 -0
- package/types/OpenCL.d.ts +2489 -0
- package/types/OpenDirectory.d.ts +1919 -0
- package/types/OpenGL.d.ts +11322 -0
- package/types/PCSC.d.ts +534 -0
- package/types/PDFKit.d.ts +1575 -0
- package/types/PHASE.d.ts +166 -0
- package/types/ParavirtualizedGraphics.d.ts +153 -0
- package/types/PassKit.d.ts +1287 -0
- package/types/PencilKit.d.ts +201 -0
- package/types/Photos.d.ts +1125 -0
- package/types/PhotosUI.d.ts +397 -0
- package/types/PreferencePanes.d.ts +68 -0
- package/types/ProximityReaderStub.d.ts +5 -0
- package/types/PushKit.d.ts +45 -0
- package/types/Quartz.d.ts +1642 -0
- package/types/QuartzCore.d.ts +1398 -0
- package/types/QuickLook.d.ts +212 -0
- package/types/QuickLookThumbnailing.d.ts +131 -0
- package/types/QuickLookUI.d.ts +117 -0
- package/types/REVISION.json +5 -0
- package/types/ReplayKit.d.ts +294 -0
- package/types/Runtime.d.ts +51605 -0
- package/types/SafariServices.d.ts +430 -0
- package/types/SafetyKit.d.ts +7 -0
- package/types/SceneKit.d.ts +4996 -0
- package/types/ScreenCaptureKit.d.ts +16 -0
- package/types/ScreenSaver.d.ts +41 -0
- package/types/ScreenTime.d.ts +41 -0
- package/types/ScriptingBridge.d.ts +96 -0
- package/types/Security.d.ts +14336 -0
- package/types/SecurityFoundation.d.ts +53 -0
- package/types/SecurityInterface.d.ts +297 -0
- package/types/SensorKit.d.ts +7 -0
- package/types/ServiceManagement.d.ts +71 -0
- package/types/SharedWithYou.d.ts +9 -0
- package/types/SharedWithYouCore.d.ts +5 -0
- package/types/ShazamKit.d.ts +12 -0
- package/types/Social.d.ts +306 -0
- package/types/SoundAnalysis.d.ts +177 -0
- package/types/Speech.d.ts +246 -0
- package/types/SpriteKit.d.ts +2766 -0
- package/types/StoreKit.d.ts +509 -0
- package/types/SyncServices.d.ts +551 -0
- package/types/SystemConfiguration.d.ts +1415 -0
- package/types/SystemExtensions.d.ts +89 -0
- package/types/TWAIN.d.ts +380 -0
- package/types/Tcl.d.ts +4013 -0
- package/types/ThreadNetwork.d.ts +77 -0
- package/types/Tk.d.ts +3750 -0
- package/types/UIUtilities.d.ts +31 -0
- package/types/UniformTypeIdentifiers.d.ts +358 -0
- package/types/UserNotifications.d.ts +538 -0
- package/types/UserNotificationsUI.d.ts +38 -0
- package/types/VideoDecodeAcceleration.d.ts +50 -0
- package/types/VideoSubscriberAccount.d.ts +139 -0
- package/types/VideoToolbox.d.ts +907 -0
- package/types/Virtualization.d.ts +302 -0
- package/types/Vision.d.ts +1723 -0
- package/types/WebKit.d.ts +5195 -0
- package/types/WidgetKit.d.ts +9 -0
- package/types/_LocationEssentials.d.ts +159 -0
- package/types/_ScreenCaptureKit_SwiftUI.d.ts +5 -0
- package/types/iTunesLibrary.d.ts +528 -0
- package/types/index.d.ts +9 -0
- package/types/vecLib.d.ts +33586 -0
- package/types/vmnet.d.ts +178 -0
- package/src/appkit.d.ts +0 -472
package/src/layer.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
/** Top-left viewport-relative rectangle, in window content points. */
|
|
2
|
+
|
|
3
|
+
import { NSView } from '@octane-xplat/platform/macos'
|
|
4
|
+
import type { NSClass, NSEvent, NSNotificationCenter, NSSize } from '@octane-xplat/platform/macos'
|
|
2
5
|
export interface WindowLayerBounds {
|
|
3
6
|
left: number
|
|
4
7
|
top: number
|
|
@@ -16,11 +19,7 @@ export interface WindowLayerOptions {
|
|
|
16
19
|
anchor: NSView
|
|
17
20
|
component?: any
|
|
18
21
|
props?: Record<string, any>
|
|
19
|
-
position(
|
|
20
|
-
anchor: WindowLayerBounds,
|
|
21
|
-
size: NSSize,
|
|
22
|
-
viewport: WindowLayerBounds,
|
|
23
|
-
): WindowLayerPoint
|
|
22
|
+
position(anchor: WindowLayerBounds, size: NSSize, viewport: WindowLayerBounds): WindowLayerPoint
|
|
24
23
|
lightDismiss?: boolean
|
|
25
24
|
onClose?: () => void
|
|
26
25
|
[key: string]: any
|
|
@@ -34,14 +33,17 @@ export interface WindowLayer {
|
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
export interface WindowLayerDeps {
|
|
37
|
-
createRoot(
|
|
36
|
+
createRoot(
|
|
37
|
+
contentView: NSView,
|
|
38
|
+
anchor: NSView,
|
|
39
|
+
): {
|
|
38
40
|
render(component: any, props: Record<string, any>): unknown
|
|
39
41
|
unmount(): void
|
|
40
42
|
}
|
|
41
43
|
fittingSize(view: NSView): NSSize | null | undefined
|
|
42
44
|
View?: NSClass<NSView>
|
|
43
|
-
Event?:
|
|
44
|
-
Center?:
|
|
45
|
+
Event?: typeof NSEvent
|
|
46
|
+
Center?: typeof NSNotificationCenter
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
interface NotificationRecord {
|
|
@@ -244,7 +246,7 @@ export function showWindowLayer(
|
|
|
244
246
|
if (Event?.addLocalMonitorForEventsMatchingMaskHandler) {
|
|
245
247
|
monitor = Event.addLocalMonitorForEventsMatchingMaskHandler(
|
|
246
248
|
(1 << 1) | (1 << 3) | (1 << 25),
|
|
247
|
-
(event) => {
|
|
249
|
+
(event: NSEvent) => {
|
|
248
250
|
if (layer.closed || !positioning.lightDismiss || event.window !== anchor.window) {
|
|
249
251
|
return event
|
|
250
252
|
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { SaxesParser } from 'saxes'
|
|
2
|
+
import {
|
|
3
|
+
universalPlan,
|
|
4
|
+
universalValue,
|
|
5
|
+
type UniversalHostPlan,
|
|
6
|
+
type UniversalRenderable,
|
|
7
|
+
} from 'octane/universal/native'
|
|
8
|
+
|
|
9
|
+
import { templateProps } from './template-props.ts'
|
|
10
|
+
import { getBindingOptions } from './vendor/listview/binding-options.ts'
|
|
11
|
+
import { parseExpression, convertExpressionToValue } from './vendor/listview/expressions.ts'
|
|
12
|
+
|
|
13
|
+
type Reader = (item: any) => unknown
|
|
14
|
+
export interface ListTemplate {
|
|
15
|
+
render(item: unknown): UniversalRenderable
|
|
16
|
+
validate(
|
|
17
|
+
validateProps: (tag: string, props: Record<string, any>) => void,
|
|
18
|
+
validateChildren: (parent: string | undefined, child: string) => void,
|
|
19
|
+
): void
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const cache = new Map<string, ListTemplate>()
|
|
23
|
+
const error = (message: string) => new TypeError('[macos-host] listview itemTemplate: ' + message)
|
|
24
|
+
|
|
25
|
+
function reader(name: string, raw: string, kind: string): Reader {
|
|
26
|
+
const value = raw.trim()
|
|
27
|
+
if (value.startsWith('{{') && value.endsWith('}}')) {
|
|
28
|
+
const options = getBindingOptions(name, value.slice(2, -2).trim())
|
|
29
|
+
if (options.source) {
|
|
30
|
+
throw error('explicit binding sources are outside item bindingContext')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (options.expression) {
|
|
34
|
+
let expression: any
|
|
35
|
+
try {
|
|
36
|
+
expression = parseExpression(options.expression)
|
|
37
|
+
} catch {
|
|
38
|
+
throw error('invalid binding expression for ' + name)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!expression) {
|
|
42
|
+
throw error('empty binding expression for ' + name)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return (item) => {
|
|
46
|
+
const model = Object(item ?? {})
|
|
47
|
+
return convertExpressionToValue(expression, model, false, { $value: item })
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const path = String(options.sourceProperty ?? '').split('.')
|
|
52
|
+
return (item) => path.reduce((value, key) => (key === '$value' ? item : value?.[key]), item)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (name === 'style') {
|
|
56
|
+
const style: Record<string, unknown> = {}
|
|
57
|
+
for (const declaration of value.split(';').filter((entry) => entry.trim())) {
|
|
58
|
+
const colon = declaration.indexOf(':')
|
|
59
|
+
if (colon < 1) {
|
|
60
|
+
throw error('invalid style declaration')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const key = declaration
|
|
64
|
+
.slice(0, colon)
|
|
65
|
+
.trim()
|
|
66
|
+
.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase())
|
|
67
|
+
|
|
68
|
+
const text = declaration.slice(colon + 1).trim()
|
|
69
|
+
style[key] = /^-?\d+(\.\d+)?$/.test(text) ? Number(text) : text
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return () => style
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (kind === 'boolean') {
|
|
76
|
+
return () => value.toLowerCase() === 'true'
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (kind === 'number') {
|
|
80
|
+
const number = Number(value)
|
|
81
|
+
if (!Number.isFinite(number)) {
|
|
82
|
+
throw error(name + ' must be numeric')
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return () => number
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return () => raw
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Parse once at the prop boundary, evaluate bindings each time a cell binds.
|
|
92
|
+
* The shared declaration map closes the vocabulary; AppKit's registry owns
|
|
93
|
+
* actual host creation. No DOM parser or NativeScript startup is involved. */
|
|
94
|
+
export function parseListTemplate(markup: string): ListTemplate {
|
|
95
|
+
const previous = cache.get(markup)
|
|
96
|
+
if (previous) {
|
|
97
|
+
return previous
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const slots: {
|
|
101
|
+
tag: string
|
|
102
|
+
readers: Record<string, Reader>
|
|
103
|
+
staticProps: Record<string, any>
|
|
104
|
+
}[] = []
|
|
105
|
+
|
|
106
|
+
const stack: UniversalHostPlan[] = []
|
|
107
|
+
let root: UniversalHostPlan | undefined
|
|
108
|
+
const parser = new SaxesParser({ xmlns: true })
|
|
109
|
+
parser.on('error', (failure) => {
|
|
110
|
+
throw error('invalid XML (' + failure.message + ')')
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
parser.on('doctype', () => {
|
|
114
|
+
throw error('DOCTYPE is unsupported')
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
parser.on('opentag', (element) => {
|
|
118
|
+
const tag = element.local.toLowerCase()
|
|
119
|
+
const declared = templateProps[tag]
|
|
120
|
+
if (!declared) {
|
|
121
|
+
throw error('unknown intrinsic <' + element.local + '>')
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const readers: Record<string, Reader> = {},
|
|
125
|
+
staticProps: Record<string, any> = {}
|
|
126
|
+
|
|
127
|
+
for (const attr of Object.values(element.attributes)) {
|
|
128
|
+
if (attr.prefix === 'xmlns' || attr.name === 'xmlns') {
|
|
129
|
+
continue
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const name = attr.name === 'class' ? 'className' : attr.name
|
|
133
|
+
if (!Object.hasOwn(declared, name)) {
|
|
134
|
+
throw error('undeclared prop ' + attr.name + ' on <' + tag + '>')
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
readers[name] = reader(name, attr.value, declared[name])
|
|
138
|
+
if (!(attr.value.trim().startsWith('{{') && attr.value.trim().endsWith('}}'))) {
|
|
139
|
+
staticProps[name] = readers[name](undefined)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const node: UniversalHostPlan = {
|
|
144
|
+
kind: 'host',
|
|
145
|
+
type: tag,
|
|
146
|
+
propsSlot: slots.length,
|
|
147
|
+
children: [],
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
slots.push({ tag, readers, staticProps })
|
|
151
|
+
if (stack.length) {
|
|
152
|
+
;(stack.at(-1)!.children as UniversalHostPlan[]).push(node)
|
|
153
|
+
} else if (root) {
|
|
154
|
+
throw error('exactly one root element is required')
|
|
155
|
+
} else {
|
|
156
|
+
root = node
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
stack.push(node)
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
parser.on('closetag', () => {
|
|
163
|
+
stack.pop()
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
// Builder ignores XML whitespace/text nodes; TextBase content uses text=.
|
|
167
|
+
parser.write(markup).close()
|
|
168
|
+
if (!root) {
|
|
169
|
+
throw error('one root element is required')
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const plan = universalPlan('macos', root)
|
|
173
|
+
const template: ListTemplate = {
|
|
174
|
+
render(item) {
|
|
175
|
+
try {
|
|
176
|
+
return universalValue(
|
|
177
|
+
plan,
|
|
178
|
+
slots.map(({ readers }) =>
|
|
179
|
+
Object.fromEntries(Object.entries(readers).map(([key, read]) => [key, read(item)])),
|
|
180
|
+
),
|
|
181
|
+
)
|
|
182
|
+
} catch (failure) {
|
|
183
|
+
throw error('binding evaluation failed: ' + String(failure))
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
validate(validateProps, validateChildren) {
|
|
187
|
+
for (const { tag, staticProps } of slots) {
|
|
188
|
+
validateProps(tag, staticProps)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const walk = (node: UniversalHostPlan, parent?: string) => {
|
|
192
|
+
validateChildren(parent, node.type)
|
|
193
|
+
for (const child of node.children as UniversalHostPlan[]) {
|
|
194
|
+
walk(child, node.type)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
walk(root!)
|
|
199
|
+
},
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (cache.size >= 256) {
|
|
203
|
+
cache.delete(cache.keys().next().value!)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
cache.set(markup, template)
|
|
207
|
+
return template
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function listFactory(props: Record<string, any>): (() => any) | undefined {
|
|
211
|
+
if (typeof props.itemTemplate === 'function') {
|
|
212
|
+
return props.itemTemplate
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return props.itemTemplates?.find((entry: any) => entry.key === 'default')?.createView
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function validateListProps(
|
|
219
|
+
props: Record<string, any>,
|
|
220
|
+
validateTemplate?: (template: ListTemplate) => void,
|
|
221
|
+
) {
|
|
222
|
+
if (
|
|
223
|
+
props.items != null &&
|
|
224
|
+
!Array.isArray(props.items) &&
|
|
225
|
+
(typeof props.items.getItem !== 'function' ||
|
|
226
|
+
!Number.isInteger(props.items.length) ||
|
|
227
|
+
props.items.length < 0)
|
|
228
|
+
) {
|
|
229
|
+
throw error('items must be an array or an ItemsSource with length and getItem(index)')
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (props.renderItem != null && typeof props.renderItem !== 'function') {
|
|
233
|
+
throw error('renderItem must be a function')
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (
|
|
237
|
+
props.itemTemplate != null &&
|
|
238
|
+
typeof props.itemTemplate !== 'function' &&
|
|
239
|
+
typeof props.itemTemplate !== 'string'
|
|
240
|
+
) {
|
|
241
|
+
throw error('itemTemplate must be a string or zero-argument factory')
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (props.itemTemplates != null) {
|
|
245
|
+
if (!Array.isArray(props.itemTemplates)) {
|
|
246
|
+
throw error('itemTemplates must be an array of keyed factories')
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
for (const entry of props.itemTemplates) {
|
|
250
|
+
if (entry?.key !== 'default') {
|
|
251
|
+
throw error(
|
|
252
|
+
'only the "default" itemTemplates key is reachable without itemTemplateSelector',
|
|
253
|
+
)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (typeof entry.createView !== 'function') {
|
|
257
|
+
throw error('itemTemplates entries need createView()')
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (typeof props.itemTemplate === 'string') {
|
|
263
|
+
const template = parseListTemplate(props.itemTemplate)
|
|
264
|
+
validateTemplate?.(template)
|
|
265
|
+
}
|
|
266
|
+
}
|