@cookieinformation/react-native-sdk 0.5.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CookieInformationRNSDKModule.js","sourceRoot":"","sources":["../src/CookieInformationRNSDKModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AA6KzD,MAAM,MAAM,GAAG,mBAAmB,CAChC,wBAAwB,CACzB,CAAC;AAEF,eAAe;IACb,UAAU,EAAE,CAAC,OAA0B,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC;IACtE,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC;IACtD,wBAAwB,EAAE,CACxB,OAAoE,EACpE,EAAE,CAAC,MAAM,CAAC,wBAAwB,CAAC,OAAO,IAAI,EAAE,CAAC;IACnD,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC;IACxD,oBAAoB,EAAE,CAAC,MAAsB,EAAE,EAAE,CAC/C,MAAM,CAAC,oBAAoB,CAAC,MAAM,IAAI,IAAI,CAAC;IAC7C,oBAAoB,EAAE,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC;IAC9D,mBAAmB,EAAE,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC;IAC5D,gBAAgB,EAAE,CAAC,MAAsB,EAAE,EAAE,CAC3C,MAAM,CAAC,gBAAgB,CAAC,MAAM,IAAI,IAAI,CAAC;IACzC,YAAY,EAAE,CACZ,YAA2B,EAC3B,UAA0C,EAC1C,MAAsB,EACtB,wBAAwC,EACxC,EAAE,CACF,MAAM,CAAC,YAAY,CACjB,YAAY,EACZ,UAAU,IAAI,IAAI,EAClB,MAAM,IAAI,IAAI,EACd,wBAAwB,IAAI,IAAI,CACjC;CACJ,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\n\n/**\n * Consent choices keyed by purpose/category.\n * iOS uses ConsentItemType raw values: \"necessary\", \"marketing\", \"statistical\", \"functional\", \"custom\".\n * Android uses consent item titles (localized). Custom purposes and other keys may appear.\n */\ninterface TrackingConsents {\n necessary?: boolean;\n marketing?: boolean;\n statistical?: boolean;\n functional?: boolean;\n custom?: boolean;\n [key: string]: boolean | undefined;\n}\n\n/** Consent item shape (id, universalId, title, description, required, type, accepted). Returned by getSavedConsents/cacheConsentSolution; pass to saveConsents. */\nexport interface ConsentItem {\n id: number;\n universalId: string;\n title: string;\n description: string;\n required: boolean;\n type: string;\n accepted: boolean;\n}\n\ninterface AcceptAllConsentsResponse {\n success: boolean;\n message: string;\n consents: ConsentItem[];\n count: number;\n}\n\nexport interface InitializeOptions {\n clientId: string;\n clientSecret: string;\n solutionId: string;\n /** The SDK uses languageCode if provided; otherwise it uses the device locale. */\n languageCode?: string | null;\n /** iOS only. Ignored on Android. */\n enableNetworkLogger?: boolean | null;\n ui?: UiOptions | null;\n}\n\nexport interface UiOptions {\n ios?: IosUiOptions | null;\n android?: AndroidUiOptions | null;\n}\n\nexport interface IosUiOptions {\n /** Hex color like \"#RRGGBB\" or \"#AARRGGBB\". */\n accentColor?: string | null;\n fontSet?: FontSet | null;\n}\n\nexport interface FontSet {\n largeTitle?: FontSpec | null;\n body?: FontSpec | null;\n bold?: FontSpec | null;\n}\n\nexport interface FontSpec {\n /** iOS font name. If omitted, system font is used. */\n name?: string | null;\n size?: number | null;\n weight?: 'regular' | 'medium' | 'semibold' | 'bold' | null;\n}\n\nexport interface AndroidUiOptions {\n lightColorScheme?: ColorScheme | null;\n darkColorScheme?: ColorScheme | null;\n typography?: Typography | null;\n}\n\nexport interface ColorScheme {\n primary?: string | null;\n secondary?: string | null;\n tertiary?: string | null;\n}\n\nexport interface Typography {\n bodyMedium?: TextStyle | null;\n}\n\nexport interface TextStyle {\n /** Android font resource name in res/font (e.g. \"inter_bold\"). */\n font?: string | null;\n size?: number | null;\n}\n\ninterface CacheConsentSolutionResponse {\n consentItems: ConsentItem[];\n /** Consent solution version ID (iOS only). */\n consentSolutionVersionId?: string;\n}\n\n/**\n * Confirmation returned when consent was successfully saved to the server.\n */\nexport interface SaveConsentsResponse {\n success: true;\n /** Number of consent items that were saved. */\n savedCount: number;\n}\n\ndeclare class CookieInformationRNSDKModule extends NativeModule {\n /**\n * Initialize the native SDKs.\n * This must be called before any other SDK method.\n */\n initialize(options: InitializeOptions): Promise<void>;\n /**\n * Show the privacy pop-up so the user can view and change consent choices.\n * Typically used from settings or a \"Privacy preferences\" entry point.\n * Resolves with the user's consent choices after they close the dialog.\n */\n showPrivacyPopUp(): Promise<TrackingConsents>;\n /**\n * Show the privacy pop-up only if the user has not yet consented or the consent\n * solution version has changed. Use at app start or when re-checking is needed.\n * @param options - Optional: ignoreVersionChanges (iOS), userId (Android).\n */\n showPrivacyPopUpIfNeeded(\n options?: { ignoreVersionChanges?: boolean; userId?: string | null }\n ): Promise<TrackingConsents>;\n acceptAllConsents(userId?: string): Promise<AcceptAllConsentsResponse>;\n /**\n * Remove all stored consents from the device. Data on Cookie Information servers is not deleted.\n * @param userId - (Android) Optional user id; omit for anonymous user.\n */\n removeStoredConsents(userId?: string | null): Promise<void>;\n /**\n * Fetch the consent solution from the server. On Android, also saves it to the local database.\n * Returns the consent items (from the fetched solution on iOS, from local DB after cache on Android).\n * iOS also returns the consent solution version ID.\n * Note: On iOS the SDK does not persist the fetched solution to local storage; only the returned\n * items are available in memory. Use getSavedConsents after the user has submitted choices (e.g. via\n * the consent dialog) to read persisted data on iOS.\n */\n cacheConsentSolution(): Promise<CacheConsentSolutionResponse>;\n /**\n * Retry sending any failed consent uploads.\n */\n synchronizeIfNeeded(): Promise<void>;\n /**\n * Read consent items from local storage.\n * - Android: Returns items from the local DB (cached solution + user choices). May have items\n * after cacheConsentSolution even before the user selects anything.\n * - iOS: Returns only consents that were saved when the user submitted choices (e.g. via the\n * consent dialog or saveConsents). Empty until the user has completed the flow at least once.\n * @param userId - (Android) Optional user id; omit for anonymous user. Ignored on iOS.\n */\n getSavedConsents(userId?: string | null): Promise<CacheConsentSolutionResponse>;\n /**\n * Send consent to the server manually. Pass the list of consent items (e.g. from getSavedConsents).\n * Solution id is taken from native config; mapping into SDK structures is done in native code.\n * On iOS, the consent solution version is normally taken from cacheConsentSolution.\n * You may pass consentSolutionVersionId to override that value (iOS only).\n * Saves consent items to the local database and sends them to the server on both platforms.\n * @param consentItems - List of consent items to save (id, universalId, accepted, etc.).\n * @param customData - Optional custom data (e.g. email, device_id).\n * @param userId - (Android) Optional user id; omit for anonymous user. Ignored on iOS.\n * @param consentSolutionVersionId - (iOS) Optional version id override when already known.\n */\n saveConsents(\n consentItems: ConsentItem[],\n customData?: Record<string, string> | null,\n userId?: string | null,\n consentSolutionVersionId?: string | null\n ): Promise<SaveConsentsResponse>;\n}\n\nconst native = requireNativeModule<CookieInformationRNSDKModule>(\n 'CookieInformationRNSDK',\n);\n\nexport default {\n initialize: (options: InitializeOptions) => native.initialize(options),\n showPrivacyPopUp: native.showPrivacyPopUp.bind(native),\n showPrivacyPopUpIfNeeded: (\n options?: { ignoreVersionChanges?: boolean; userId?: string | null }\n ) => native.showPrivacyPopUpIfNeeded(options ?? {}),\n acceptAllConsents: native.acceptAllConsents.bind(native),\n removeStoredConsents: (userId?: string | null) =>\n native.removeStoredConsents(userId ?? null),\n cacheConsentSolution: native.cacheConsentSolution.bind(native),\n synchronizeIfNeeded: native.synchronizeIfNeeded.bind(native),\n getSavedConsents: (userId?: string | null) =>\n native.getSavedConsents(userId ?? null),\n saveConsents: (\n consentItems: ConsentItem[],\n customData?: Record<string, string> | null,\n userId?: string | null,\n consentSolutionVersionId?: string | null\n ) =>\n native.saveConsents(\n consentItems,\n customData ?? null,\n userId ?? null,\n consentSolutionVersionId ?? null\n ),\n};"]}
@@ -0,0 +1,3 @@
1
+ export { default } from './CookieInformationRNSDKModule';
2
+ export * from './CookieInformationRNSDKModule';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAEzD,cAAc,gCAAgC,CAAC"}
package/build/index.js ADDED
@@ -0,0 +1,6 @@
1
+ // Reexport the native module. On web, it will be resolved to CookieInformationRNSDKModule.web.ts
2
+ // and on native platforms to CookieInformationRNSDKModule.ts
3
+ export { default } from './CookieInformationRNSDKModule';
4
+ // eslint-disable-next-line import/export
5
+ export * from './CookieInformationRNSDKModule';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,6DAA6D;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AACzD,yCAAyC;AACzC,cAAc,gCAAgC,CAAC","sourcesContent":["// Reexport the native module. On web, it will be resolved to CookieInformationRNSDKModule.web.ts\n// and on native platforms to CookieInformationRNSDKModule.ts\nexport { default } from './CookieInformationRNSDKModule';\n// eslint-disable-next-line import/export\nexport * from './CookieInformationRNSDKModule';\n"]}
@@ -0,0 +1,17 @@
1
+ {
2
+ "platforms": [
3
+ "apple",
4
+ "android",
5
+ "web"
6
+ ],
7
+ "apple": {
8
+ "modules": [
9
+ "CookieInformationRNSDKModule"
10
+ ]
11
+ },
12
+ "android": {
13
+ "modules": [
14
+ "expo.modules.mobileconsentssdk.CookieInformationRNSDKModule"
15
+ ]
16
+ }
17
+ }
@@ -0,0 +1,30 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'CookieInformationRNSDK'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.description = package['description']
10
+ s.license = package['license']
11
+ s.author = package['author']
12
+ s.homepage = package['homepage']
13
+ s.platforms = {
14
+ :ios => '15.1',
15
+ :tvos => '15.1'
16
+ }
17
+ s.swift_version = '5.4'
18
+ s.source = { git: 'https://github.com/cookie-information/react-native-sdk' }
19
+ s.static_framework = true
20
+
21
+ s.dependency 'ExpoModulesCore'
22
+ s.dependency 'MobileConsentsSDK'
23
+
24
+ # Swift/Objective-C compatibility
25
+ s.pod_target_xcconfig = {
26
+ 'DEFINES_MODULE' => 'YES',
27
+ }
28
+
29
+ s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
30
+ end
@@ -0,0 +1,235 @@
1
+ import ExpoModulesCore
2
+ import Foundation
3
+ import MobileConsentsSDK
4
+
5
+ public class CookieInformationRNSDKModule: Module {
6
+ private var cookieInformationSDK: MobileConsents?
7
+ private var consentSolutionId: String?
8
+ private var consentSolutionVersionId: String?
9
+ private var sdkConfig: SDKConfig?
10
+
11
+ private struct SDKConfig {
12
+ let clientID: String
13
+ let clientSecret: String
14
+ let solutionID: String
15
+ let languageCode: String?
16
+ let logNetwork: Bool
17
+ let accentColor: UIColor?
18
+ let fontSet: FontSet?
19
+ }
20
+
21
+ private func withSDK(promise: Promise, action: @escaping (MobileConsents) -> Void) {
22
+ guard let sdk = cookieInformationSDK else {
23
+ promise.reject("INIT_ERROR", "SDK not ready")
24
+ return
25
+ }
26
+ action(sdk)
27
+ }
28
+
29
+
30
+ private func configureSDK() {
31
+ guard let config = sdkConfig else { return }
32
+
33
+ consentSolutionId = config.solutionID
34
+ let fontSet = config.fontSet ?? .standard
35
+ cookieInformationSDK = MobileConsents(
36
+ uiLanguageCode: config.languageCode,
37
+ clientID: config.clientID,
38
+ clientSecret: config.clientSecret,
39
+ solutionId: config.solutionID,
40
+ accentColor: config.accentColor,
41
+ fontSet: fontSet,
42
+ enableNetworkLogger: config.logNetwork
43
+ )
44
+
45
+ NSLog("CookieInformationRNSDK: SDK initialized")
46
+ }
47
+
48
+ private func buildApprovalList(from solution: ConsentSolution) -> [UserConsent] {
49
+ solution.consentItems
50
+ .filter { $0.type != .privacyPolicy }
51
+ .map { UserConsent(consentItem: $0, isSelected: true) }
52
+ }
53
+
54
+ private func mapSelections(_ approvals: [UserConsent]) -> [String: Bool] {
55
+ approvals.reduce(into: [:]) { dict, consent in
56
+ dict[consent.consentItem.type.rawValue] = consent.isSelected
57
+ }
58
+ }
59
+
60
+ private func mapSavedConsents(_ consents: [UserConsent]) -> [[String: Any]] {
61
+ consents.map { consent in
62
+ let item = consent.consentItem
63
+ return [
64
+ "id": 0,
65
+ "universalId": item.id,
66
+ "title": item.translations.primaryTranslation().shortText,
67
+ "description": item.translations.primaryTranslation().longText,
68
+ "required": item.required,
69
+ "type": item.type.rawValue,
70
+ "accepted": consent.isSelected,
71
+ ] as [String: Any]
72
+ }
73
+ }
74
+
75
+ public func definition() -> ModuleDefinition {
76
+ Name("CookieInformationRNSDK")
77
+
78
+ AsyncFunction("initialize") { (options: [String: Any], promise: Promise) in
79
+ guard let clientID = options["clientId"] as? String,
80
+ let clientSecret = options["clientSecret"] as? String,
81
+ let solutionID = options["solutionId"] as? String else {
82
+ promise.reject("INVALID_INIT", "clientId, clientSecret, and solutionId are required")
83
+ return
84
+ }
85
+ let languageCode = options["languageCode"] as? String
86
+ let logNetwork = (options["enableNetworkLogger"] as? NSNumber)?.boolValue ?? false
87
+ let ui = options["ui"] as? [String: Any]
88
+ let iosUi = ui?["ios"] as? [String: Any]
89
+ let accentColor = UiParsing.parseHexColor(iosUi?["accentColor"] as? String)
90
+ let fontSet = UiParsing.parseFontSet(iosUi?["fontSet"] as? [String: Any])
91
+ sdkConfig = SDKConfig(
92
+ clientID: clientID,
93
+ clientSecret: clientSecret,
94
+ solutionID: solutionID,
95
+ languageCode: languageCode,
96
+ logNetwork: logNetwork,
97
+ accentColor: accentColor,
98
+ fontSet: fontSet
99
+ )
100
+ configureSDK()
101
+ promise.resolve(())
102
+ }
103
+
104
+ AsyncFunction("showPrivacyPopUp") { (promise: Promise) in
105
+ withSDK(promise: promise) { sdk in
106
+ sdk.showPrivacyPopUp { [weak self] selections in
107
+ promise.resolve(self?.mapSelections(selections) ?? [:])
108
+ } errorHandler: { error in
109
+ promise.reject("UI_ERROR", error.localizedDescription)
110
+ }
111
+ }
112
+ }
113
+
114
+ AsyncFunction("showPrivacyPopUpIfNeeded") { (options: [String: Any]?, promise: Promise) in
115
+ let ignoreVersionChanges = (options?["ignoreVersionChanges"] as? NSNumber)?.boolValue ?? false
116
+ withSDK(promise: promise) { sdk in
117
+ sdk.showPrivacyPopUpIfNeeded(ignoreVersionChanges: ignoreVersionChanges) { [weak self] selections in
118
+ promise.resolve(self?.mapSelections(selections) ?? [:])
119
+ } errorHandler: { error in
120
+ promise.reject("UI_ERROR", error.localizedDescription)
121
+ }
122
+ }
123
+ }
124
+
125
+ AsyncFunction("acceptAllConsents") { (promise: Promise) in
126
+ withSDK(promise: promise) { sdk in
127
+ sdk.fetchConsentSolution { [weak self] result in
128
+ switch result {
129
+ case .success(let solution):
130
+ let approvals = self?.buildApprovalList(from: solution) ?? []
131
+ let payload = Consent(
132
+ consentSolutionId: solution.id,
133
+ consentSolutionVersionId: solution.versionId,
134
+ userConsents: approvals
135
+ )
136
+
137
+ sdk.postConsent(payload) { [weak self] error in
138
+ if let error = error {
139
+ promise.reject("SAVE_ERROR", error.localizedDescription)
140
+ return
141
+ }
142
+ promise.resolve(self?.mapSelections(approvals) ?? [:])
143
+ }
144
+ case .failure:
145
+ promise.reject("FETCH_ERROR", "Unable to load consent configuration")
146
+ }
147
+ }
148
+ }
149
+ }
150
+
151
+ AsyncFunction("removeStoredConsents") { (_: String?, promise: Promise) in
152
+ withSDK(promise: promise) { sdk in
153
+ sdk.removeStoredConsents()
154
+ promise.resolve(())
155
+ }
156
+ }
157
+
158
+ AsyncFunction("cacheConsentSolution") { (promise: Promise) in
159
+ withSDK(promise: promise) { [weak self] sdk in
160
+ guard let self = self else {
161
+ promise.reject("MODULE_ERROR", "SDK module unavailable")
162
+ return
163
+ }
164
+ sdk.fetchConsentSolution { result in
165
+ switch result {
166
+ case .success(let solution):
167
+ self.consentSolutionVersionId = solution.versionId
168
+ let userConsents = solution.consentItems.map { UserConsent(consentItem: $0, isSelected: false) }
169
+ let items = self.mapSavedConsents(userConsents)
170
+ promise.resolve([
171
+ "consentItems": items,
172
+ "consentSolutionVersionId": solution.versionId
173
+ ])
174
+ case .failure(let error):
175
+ promise.reject("FETCH_ERROR", error.localizedDescription)
176
+ }
177
+ }
178
+ }
179
+ }
180
+
181
+ AsyncFunction("synchronizeIfNeeded") { (promise: Promise) in
182
+ withSDK(promise: promise) { sdk in
183
+ sdk.synchronizeIfNeeded()
184
+ promise.resolve(())
185
+ }
186
+ }
187
+
188
+ AsyncFunction("getSavedConsents") { (_: String?, promise: Promise) in
189
+ withSDK(promise: promise) { [weak self] sdk in
190
+ guard let self = self else {
191
+ promise.reject("MODULE_ERROR", "SDK module unavailable")
192
+ return
193
+ }
194
+ let consents = sdk.getSavedConsents()
195
+ let items = self.mapSavedConsents(consents)
196
+ promise.resolve(["consentItems": items])
197
+ }
198
+ }
199
+
200
+ AsyncFunction("saveConsents") { (consentItemsRaw: [[String: Any]], customDataRaw: [String: String]?, _: String?, consentSolutionVersionId: String?, promise: Promise) in
201
+ withSDK(promise: promise) { sdk in
202
+ guard let solutionId = self.consentSolutionId, !solutionId.isEmpty else {
203
+ promise.reject("NO_CONFIG", "CookieInformation.plist missing or solutionID not set")
204
+ return
205
+ }
206
+ let versionId = consentSolutionVersionId ?? self.consentSolutionVersionId
207
+ guard let versionId = versionId else {
208
+ promise.reject("NO_VERSION", "Call cacheConsentSolution first or provide consentSolutionVersionId")
209
+ return
210
+ }
211
+ var consent = Consent(
212
+ consentSolutionId: solutionId,
213
+ consentSolutionVersionId: versionId,
214
+ customData: customDataRaw,
215
+ userConsents: []
216
+ )
217
+ let language = "EN"
218
+ for itemDict in consentItemsRaw {
219
+ guard let universalId = itemDict["universalId"] as? String,
220
+ let accepted = itemDict["accepted"] as? Bool else { continue }
221
+ let purpose = ProcessingPurpose(consentItemId: universalId, consentGiven: accepted, language: language)
222
+ consent.addProcessingPurpose(purpose)
223
+ }
224
+ sdk.postConsent(consent) { error in
225
+ if let error = error {
226
+ promise.reject("SAVE_CONSENTS_ERROR", error.localizedDescription)
227
+ return
228
+ }
229
+ let count = consent.processingPurposes.count
230
+ promise.resolve(["success": true, "savedCount": count] as [String: Any])
231
+ }
232
+ }
233
+ }
234
+ }
235
+ }
@@ -0,0 +1,58 @@
1
+ import Foundation
2
+ import MobileConsentsSDK
3
+ import UIKit
4
+
5
+ enum UiParsing {
6
+ static func parseHexColor(_ value: String?) -> UIColor? {
7
+ guard let value = value?.trimmingCharacters(in: .whitespacesAndNewlines),
8
+ value.hasPrefix("#") else {
9
+ return nil
10
+ }
11
+ let hex = String(value.dropFirst())
12
+ var rgba: UInt64 = 0
13
+ let scanner = Scanner(string: hex)
14
+ guard scanner.scanHexInt64(&rgba) else { return nil }
15
+ if hex.count == 6 {
16
+ let r = CGFloat((rgba & 0xFF0000) >> 16) / 255.0
17
+ let g = CGFloat((rgba & 0x00FF00) >> 8) / 255.0
18
+ let b = CGFloat(rgba & 0x0000FF) / 255.0
19
+ return UIColor(red: r, green: g, blue: b, alpha: 1.0)
20
+ }
21
+ if hex.count == 8 {
22
+ let a = CGFloat((rgba & 0xFF000000) >> 24) / 255.0
23
+ let r = CGFloat((rgba & 0x00FF0000) >> 16) / 255.0
24
+ let g = CGFloat((rgba & 0x0000FF00) >> 8) / 255.0
25
+ let b = CGFloat(rgba & 0x000000FF) / 255.0
26
+ return UIColor(red: r, green: g, blue: b, alpha: a)
27
+ }
28
+ return nil
29
+ }
30
+
31
+ static func parseFontSet(_ value: [String: Any]?) -> FontSet? {
32
+ guard let value = value else { return nil }
33
+ let largeTitle = parseFontSpec(value["largeTitle"] as? [String: Any], defaultSize: 34, defaultWeight: .bold)
34
+ let body = parseFontSpec(value["body"] as? [String: Any], defaultSize: 14, defaultWeight: .regular)
35
+ let bold = parseFontSpec(value["bold"] as? [String: Any], defaultSize: 14, defaultWeight: .bold)
36
+ return FontSet(largeTitle: largeTitle, body: body, bold: bold)
37
+ }
38
+
39
+ private static func parseFontSpec(_ value: [String: Any]?, defaultSize: CGFloat, defaultWeight: UIFont.Weight) -> UIFont {
40
+ let size = (value?["size"] as? NSNumber)?.doubleValue ?? Double(defaultSize)
41
+ let weight = parseWeight(value?["weight"] as? String) ?? defaultWeight
42
+ if let name = value?["name"] as? String, let font = UIFont(name: name, size: size) {
43
+ return font
44
+ }
45
+ return UIFont.systemFont(ofSize: size, weight: weight)
46
+ }
47
+
48
+ private static func parseWeight(_ value: String?) -> UIFont.Weight? {
49
+ guard let value = value?.lowercased() else { return nil }
50
+ switch value {
51
+ case "regular": return .regular
52
+ case "medium": return .medium
53
+ case "semibold": return .semibold
54
+ case "bold": return .bold
55
+ default: return nil
56
+ }
57
+ }
58
+ }
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@cookieinformation/react-native-sdk",
3
+ "version": "0.5.0",
4
+ "description": "Cookie Information consent management SDK for React Native",
5
+ "private": false,
6
+ "main": "build/index.js",
7
+ "types": "build/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./build/index.d.ts",
11
+ "default": "./build/index.js"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
15
+ "files": [
16
+ "build/",
17
+ "android/build.gradle",
18
+ "android/src/",
19
+ "ios/",
20
+ "expo-module.config.json",
21
+ "README.md",
22
+ "LICENSE"
23
+ ],
24
+ "scripts": {
25
+ "build": "expo-module build",
26
+ "clean": "expo-module clean",
27
+ "lint": "expo-module lint",
28
+ "test": "expo-module test",
29
+ "prepare": "expo-module prepare",
30
+ "prepublishOnly": "expo-module prepublishOnly",
31
+ "expo-module": "expo-module",
32
+ "open:ios": "xed example/ios",
33
+ "open:android": "open -a \"Android Studio\" example/android",
34
+ "android": "expo run:android",
35
+ "ios": "expo run:ios"
36
+ },
37
+ "keywords": [
38
+ "react-native",
39
+ "expo",
40
+ "react-native-cookie-information-consents-sdk",
41
+ "CookieInformationRNSDK"
42
+ ],
43
+ "repository": "https://github.com/cookie-information/react-native-sdk",
44
+ "bugs": {
45
+ "url": "https://github.com/cookie-information/react-native-sdk/issues"
46
+ },
47
+ "author": "CookieInformation",
48
+ "license": "MIT",
49
+ "homepage": "https://github.com/cookie-information/react-native-sdk#readme",
50
+ "publishConfig": {
51
+ "access": "public"
52
+ },
53
+ "engines": {
54
+ "node": ">=20"
55
+ },
56
+ "devDependencies": {
57
+ "@types/jest": "^30.0.0",
58
+ "expo-module-scripts": "~4.1.10",
59
+ "jest": "^29.7.0",
60
+ "ts-jest": "^29.4.6",
61
+ "typescript": "~5.8.3"
62
+ },
63
+ "dependencies": {
64
+ "expo": "^54.0.33",
65
+ "react": "^19.2.4",
66
+ "react-native": "^0.83.1"
67
+ },
68
+ "peerDependencies": {
69
+ "expo": "^54.0.33",
70
+ "react": "^19.2.4",
71
+ "react-native": "^0.83.1"
72
+ }
73
+ }