KMDesignToken.swift 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. //
  2. // KMDesignToken.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by wanjun on 2022/12/21.
  6. //
  7. import Cocoa
  8. @objcMembers class KMDesignToken: NSObject {
  9. private static let sharedInstance = KMDesignToken()
  10. @objc class var shared: KMDesignToken {
  11. return sharedInstance
  12. }
  13. var jsonPaser: KMJSONParser?
  14. var finalDict: [String : Any] = [:]
  15. func parserExcel(withPath path: String) -> Void {
  16. let data = try? Data(contentsOf: URL(fileURLWithPath: Bundle.main.path(forResource: "$metadata", ofType: "json")!))
  17. let jsonData = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers)
  18. let jsonDict = jsonData as! [String : [String]]
  19. jsonPaser = KMJSONParser.defaultJSONParser_JSONParser
  20. jsonPaser?.parseFilePaths = jsonDict["tokenSetOrder"]
  21. jsonPaser?.parseOutType = .ArrayObj
  22. jsonPaser?.delete = self
  23. jsonPaser?.parse()
  24. }
  25. func tokenUsesAction(withToken token: String) -> [String : Any] {
  26. return finalDict[token] as! [String : Any]
  27. }
  28. // MARK: Design Token Uses
  29. /**
  30. 在仅知道Token值,或其余快捷接口不满足当前类型时,使用此方法。当其余接口处理失败后,自动调用此方法返回数据
  31. - parameter token: 传入获取的Design Token
  32. - returns: 返回 KMDesignTokenValue 数据模型
  33. */
  34. func tokenUsesModel(withToken token: String) -> KMDesignTokenValue {
  35. let tokenDict = tokenUsesAction(withToken: token)
  36. var model = KMDesignTokenValue.init()
  37. let allKey = tokenDict.keys
  38. if allKey.contains("sizing") {
  39. model.sizing = tokenDict["sizing"] as Any
  40. }
  41. if allKey.contains("height") {
  42. model.height = tokenDict["height"] as Any
  43. }
  44. if allKey.contains("width") {
  45. model.width = tokenDict["width"] as Any
  46. }
  47. if allKey.contains("spacing") {
  48. model.spacing = tokenDict["spacing"] as Any
  49. }
  50. if allKey.contains("verticalPadding") {
  51. model.verticalPadding = tokenDict["verticalPadding"] as Any
  52. }
  53. if allKey.contains("horizontalPadding") {
  54. model.horizontalPadding = tokenDict["horizontalPadding"] as Any
  55. }
  56. if allKey.contains("paddingTop") {
  57. model.paddingTop = tokenDict["paddingTop"] as Any
  58. }
  59. if allKey.contains("paddingRight") {
  60. model.paddingRight = tokenDict["paddingRight"] as Any
  61. }
  62. if allKey.contains("paddingBottom") {
  63. model.paddingBottom = tokenDict["paddingBottom"] as Any
  64. }
  65. if allKey.contains("paddingLeft") {
  66. model.paddingLeft = tokenDict["paddingLeft"] as Any
  67. }
  68. if allKey.contains("itemSpacing") {
  69. model.itemSpacing = tokenDict["itemSpacing"] as Any
  70. }
  71. if allKey.contains("fill") {
  72. model.fill = tokenDict["fill"] as Any
  73. }
  74. if allKey.contains("border") {
  75. model.border = tokenDict["border"] as Any
  76. }
  77. if allKey.contains("borderColor") {
  78. model.borderColor = tokenDict["borderColor"] as Any
  79. }
  80. if allKey.contains("borderTop") {
  81. model.borderTop = tokenDict["borderTop"] as Any
  82. }
  83. if allKey.contains("borderRight") {
  84. model.borderRight = tokenDict["borderRight"] as Any
  85. }
  86. if allKey.contains("borderBottom") {
  87. model.borderBottom = tokenDict["borderBottom"] as Any
  88. }
  89. if allKey.contains("borderLeft") {
  90. model.borderLeft = tokenDict["borderLeft"] as Any
  91. }
  92. if allKey.contains("borderRadius") {
  93. model.borderRadius = tokenDict["borderRadius"] as Any
  94. }
  95. if allKey.contains("borderRadiusTopLeft") {
  96. model.borderRadiusTopLeft = tokenDict["borderRadiusTopLeft"] as Any
  97. }
  98. if allKey.contains("borderRadiusTopRight") {
  99. model.borderRadiusTopRight = tokenDict["borderRadiusTopRight"] as Any
  100. }
  101. if allKey.contains("borderRadiusBottomRight") {
  102. model.borderRadiusBottomRight = tokenDict["borderRadiusBottomRight"] as Any
  103. }
  104. if allKey.contains("borderRadiusBottomLeft") {
  105. model.borderRadiusBottomLeft = tokenDict["borderRadiusBottomLeft"] as Any
  106. }
  107. if allKey.contains("borderWidth") {
  108. model.borderWidth = tokenDict["borderWidth"] as Any
  109. }
  110. if allKey.contains("borderWidthTop") {
  111. model.borderWidthTop = tokenDict["borderWidthTop"] as Any
  112. }
  113. if allKey.contains("borderWidthRight") {
  114. model.borderWidthRight = tokenDict["borderWidthRight"] as Any
  115. }
  116. if allKey.contains("borderWidthBottom") {
  117. model.borderWidthBottom = tokenDict["borderWidthBottom"] as Any
  118. }
  119. if allKey.contains("borderWidthLeft") {
  120. model.borderWidthLeft = tokenDict["borderWidthLeft"] as Any
  121. }
  122. if allKey.contains("boxShadow") {
  123. model.boxShadow = tokenDict["boxShadow"] as Any
  124. }
  125. if allKey.contains("typography") {
  126. model.typography = tokenDict["typography"] as Any
  127. }
  128. return model
  129. }
  130. /**
  131. 当使用者希望传入控件/约束后绑定值时调用此方法。
  132. 仅支持系统控件默认属性/自定义控件的属性绑定,所以不支持设置以下属性 【borderTop】、【borderRight】、【borderBottom】、【borderLeft】、【borderRadiusTopLeft】、【borderRadiusTopRight】、【borderRadiusBottomRight】、【borderRadiusBottomLeft】、【borderWidthTop】、【borderWidthRight】、【borderWidthBottom】、【borderWidthLeft】
  133. - parameter token: 传入Design Token
  134. - parameter sizing: 包含 sizing 属性的控件;支持控件【NSTextField】、
  135. - parameter height: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【高度】赋值
  136. - parameter width: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【宽度】赋值
  137. - parameter spacing: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 上下左右 距离】赋值
  138. - parameter verticalPadding: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 垂直(上下)距离】赋值
  139. - parameter horizontalPadding: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 水平(左右)距离】赋值
  140. - parameter paddingTop: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 上 边距】赋值
  141. - parameter paddingRight: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 右 边距】赋值
  142. - parameter paddingBottom: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 下 边距】赋值
  143. - parameter paddingLeft: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 左 边距】赋值
  144. - parameter itemSpacing: 组件内多个控件间距,多个控件水平排列,属于水平间距;多个控件垂直排列,属于垂直间距;建议传入【NSLayoutConstraint】 类型
  145. - parameter fill: 传入需要调整【填充颜色】的控件;支持控件
  146. - parameter border: 传入需要调整【边框属性合集,包括边框颜色、边框宽度、边框样式(虚线/直线)】的控件;支持控件
  147. - parameter borderColor: 传入需要调整【边框颜色】的控件;支持控件
  148. - parameter borderRadius: 传入需要调整【边框圆角】的控件;支持控件
  149. - parameter borderWidth: 传入需要调整【边框宽度】的控件;支持控件
  150. - parameter boxShadow: 传入需要调整【包含x/y 倾斜度、blur(模糊间距)】的控件;支持控件
  151. - parameter typography: 传入需要调整【字体合集,包含字体/大小/字重/行高】的控件;支持控件
  152. - returns: 当处理成功时返回Bool值,若处理失败,则返回 KMDesignTokenValue 数据模型
  153. */
  154. func designTokenUsesAction(withToken token: String,
  155. sizing : Any = "",
  156. height : Any = "",
  157. width : Any = "",
  158. spacing : Any = "",
  159. verticalPadding : Any = "",
  160. horizontalPadding: Any = "",
  161. paddingTop : Any = "",
  162. paddingRight : Any = "",
  163. paddingBottom : Any = "",
  164. paddingLeft : Any = "",
  165. itemSpacing : Any = "",
  166. fill : Any = "",
  167. border : Any = "",
  168. borderColor : Any = "",
  169. borderRadius : Any = "",
  170. borderWidth : Any = "",
  171. boxShadow : Any = "",
  172. typography : Any = "") -> Any {
  173. if (sizing is String) &&
  174. (height is String) &&
  175. (width is String) &&
  176. (spacing is String) &&
  177. (verticalPadding is String) &&
  178. (horizontalPadding is String) &&
  179. (paddingTop is String) &&
  180. (paddingRight is String) &&
  181. (paddingBottom is String) &&
  182. (paddingLeft is String) &&
  183. (itemSpacing is String) &&
  184. (fill is String) &&
  185. (border is String) &&
  186. (borderColor is String) &&
  187. (borderRadius is String) &&
  188. (borderWidth is String) &&
  189. (boxShadow is String) &&
  190. (typography is String) {
  191. return tokenUsesModel(withToken: token)
  192. } else {
  193. let tokenDict = tokenUsesAction(withToken: token)
  194. let allKey = tokenDict.keys
  195. if allKey.contains("sizing") {
  196. let sizingNode = tokenDict["sizing"]
  197. if nodeIsEmpty(control: sizing, node: sizingNode as Any) {
  198. if sizingNodeUsesAction(control: sizing, node: sizingNode as Any) {
  199. KMPrint("sizing node user success")
  200. } else {
  201. return tokenUsesModel(withToken: token)
  202. }
  203. } else {
  204. return tokenUsesModel(withToken: token)
  205. }
  206. }
  207. if allKey.contains("height") ||
  208. allKey.contains("width") ||
  209. allKey.contains("spacing") ||
  210. allKey.contains("verticalPadding") ||
  211. allKey.contains("horizontalPadding") ||
  212. allKey.contains("paddingTop") ||
  213. allKey.contains("paddingRight") ||
  214. allKey.contains("paddingBottom") ||
  215. allKey.contains("paddingLeft") ||
  216. allKey.contains("itemSpacing") {
  217. var node: Any!
  218. var control: Any!
  219. if allKey.contains("height") {
  220. node = tokenDict["height"] as Any
  221. control = height
  222. } else if allKey.contains("width") {
  223. node = tokenDict["width"] as Any
  224. control = width
  225. } else if allKey.contains("spacing") {
  226. node = tokenDict["spacing"] as Any
  227. control = spacing
  228. } else if allKey.contains("verticalPadding") {
  229. node = tokenDict["verticalPadding"] as Any
  230. control = verticalPadding
  231. } else if allKey.contains("horizontalPadding") {
  232. node = tokenDict["horizontalPadding"] as Any
  233. control = horizontalPadding
  234. } else if allKey.contains("paddingTop") {
  235. node = tokenDict["paddingTop"] as Any
  236. control = paddingTop
  237. } else if allKey.contains("paddingRight") {
  238. node = tokenDict["paddingRight"] as Any
  239. control = paddingRight
  240. } else if allKey.contains("paddingBottom") {
  241. node = tokenDict["paddingBottom"] as Any
  242. control = paddingBottom
  243. } else if allKey.contains("paddingLeft") {
  244. node = tokenDict["paddingLeft"] as Any
  245. control = paddingLeft
  246. } else if allKey.contains("itemSpacing") {
  247. node = tokenDict["itemSpacing"] as Any
  248. control = itemSpacing
  249. }
  250. if nodeIsEmpty(control: control as Any, node: node as Any) {
  251. if layoutConstraintNodeUsesAction(control: control as Any, node: node as Any) {
  252. KMPrint("node user success")
  253. } else {
  254. return tokenUsesModel(withToken: token)
  255. }
  256. } else {
  257. return tokenUsesModel(withToken: token)
  258. }
  259. }
  260. if allKey.contains("fill") {
  261. let fillNode = tokenDict["fill"]
  262. if nodeIsEmpty(control: fill, node: fillNode as Any) {
  263. if fillNodeUsesAction(control: fill, node: fillNode as Any) {
  264. KMPrint("fill node user success")
  265. } else {
  266. return tokenUsesModel(withToken: token)
  267. }
  268. } else {
  269. return tokenUsesModel(withToken: token)
  270. }
  271. }
  272. if allKey.contains("border") {
  273. let borderNode = tokenDict["border"]
  274. if nodeIsEmpty(control: border, node: borderNode as Any) {
  275. if borderNodeUsesAction(control: border, node: borderNode as Any) {
  276. KMPrint("border node user success")
  277. } else {
  278. return tokenUsesModel(withToken: token)
  279. }
  280. } else {
  281. return tokenUsesModel(withToken: token)
  282. }
  283. }
  284. if allKey.contains("borderColor") {
  285. let borderColorNode = tokenDict["borderColor"]
  286. if nodeIsEmpty(control: borderColor, node: borderColorNode as Any) {
  287. if borderColorNodeUsesAction(control: borderColor, node: borderColorNode as Any) {
  288. KMPrint("borderColor node user success")
  289. } else {
  290. return tokenUsesModel(withToken: token)
  291. }
  292. } else {
  293. return tokenUsesModel(withToken: token)
  294. }
  295. }
  296. if allKey.contains("borderRadius") {
  297. let borderRadiusNode = tokenDict["borderRadius"]
  298. if nodeIsEmpty(control: borderRadius, node: borderRadiusNode as Any) {
  299. if borderRadiusNodeUsesAction(control: borderRadius, node: borderRadiusNode as Any) {
  300. KMPrint("borderRadius node user success")
  301. } else {
  302. return tokenUsesModel(withToken: token)
  303. }
  304. } else {
  305. return tokenUsesModel(withToken: token)
  306. }
  307. }
  308. if allKey.contains("borderWidth") {
  309. let borderWidthNode = tokenDict["borderWidth"]
  310. if nodeIsEmpty(control: borderWidth, node: borderWidthNode as Any) {
  311. if borderWidthNodeUsesAction(control: borderWidth, node: borderWidthNode as Any) {
  312. KMPrint("borderWidth node user success")
  313. } else {
  314. return tokenUsesModel(withToken: token)
  315. }
  316. } else {
  317. return tokenUsesModel(withToken: token)
  318. }
  319. }
  320. if allKey.contains("boxShadow") {
  321. let boxShadowNode = tokenDict["boxShadow"]
  322. if nodeIsEmpty(control: boxShadow, node: boxShadowNode as Any) {
  323. if boxShadowNodeUsesAction(control: boxShadow, node: boxShadowNode as Any) {
  324. KMPrint("boxShadow node user success")
  325. } else {
  326. return tokenUsesModel(withToken: token)
  327. }
  328. } else {
  329. return tokenUsesModel(withToken: token)
  330. }
  331. }
  332. if allKey.contains("typography") {
  333. let typographyNode = tokenDict["typography"]
  334. if nodeIsEmpty(control: typography, node: typographyNode as Any) {
  335. if typographyNodeUsesAction(control: typography, node: typographyNode as Any) {
  336. KMPrint("typography node user success")
  337. } else {
  338. return tokenUsesModel(withToken: token)
  339. }
  340. } else {
  341. return tokenUsesModel(withToken: token)
  342. }
  343. }
  344. }
  345. return tokenUsesModel(withToken: token)
  346. }
  347. // MARK: height、width、spacing、verticalPaddin、horizontalPadding、paddingTop、paddingRight、paddingBottom、paddingLeft、itemSpacing
  348. func layoutConstraintNodeUsesAction(control: Any, node: Any) -> Bool {
  349. if control is NSLayoutConstraint {
  350. (control as! NSLayoutConstraint).constant = (node as! String).stringToCGFloat()
  351. return true
  352. }
  353. return false
  354. }
  355. // MARK: Private Methods
  356. func nodeIsEmpty(control: Any, node: Any) -> Bool {
  357. if (control is String) {
  358. return false
  359. } else {
  360. if (node is String) {
  361. if (node as! String == "") {
  362. return false
  363. } else {
  364. return true
  365. }
  366. } else if (node is [String : Any]) {
  367. return true
  368. }
  369. }
  370. return false
  371. }
  372. }
  373. extension KMDesignToken: KMJSONParserDelegate {
  374. func parser(_ parser: KMJSONParser, success responseObj: Any) {
  375. finalDict = responseObj as! [String : Any]
  376. }
  377. }