// // KMDesignToken.swift // PDF Reader Pro // // Created by wanjun on 2022/12/21. // import Cocoa @objcMembers class KMDesignToken: NSObject { private static let sharedInstance = KMDesignToken() @objc class var shared: KMDesignToken { return sharedInstance } var jsonPaser: KMJSONParser? var finalDict: [String : Any] = [:] func parserExcel(withPath path: String) -> Void { let data = try? Data(contentsOf: URL(fileURLWithPath: Bundle.main.path(forResource: "$metadata", ofType: "json")!)) let jsonData = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) let jsonDict = jsonData as! [String : [String]] jsonPaser = KMJSONParser.defaultJSONParser_JSONParser jsonPaser?.parseFilePaths = jsonDict["tokenSetOrder"] jsonPaser?.parseOutType = .ArrayObj jsonPaser?.delete = self jsonPaser?.parse() } func tokenUsesAction(withToken token: String) -> [String : Any] { return finalDict[token] as! [String : Any] } // MARK: Design Token Uses /** 在仅知道Token值,或其余快捷接口不满足当前类型时,使用此方法。当其余接口处理失败后,自动调用此方法返回数据 - parameter token: 传入获取的Design Token - returns: 返回 KMDesignTokenValue 数据模型 */ func tokenUsesModel(withToken token: String) -> KMDesignTokenValue { let tokenDict = tokenUsesAction(withToken: token) var model = KMDesignTokenValue.init() let allKey = tokenDict.keys if allKey.contains("sizing") { model.sizing = tokenDict["sizing"] as Any } if allKey.contains("height") { model.height = tokenDict["height"] as Any } if allKey.contains("width") { model.width = tokenDict["width"] as Any } if allKey.contains("spacing") { model.spacing = tokenDict["spacing"] as Any } if allKey.contains("verticalPadding") { model.verticalPadding = tokenDict["verticalPadding"] as Any } if allKey.contains("horizontalPadding") { model.horizontalPadding = tokenDict["horizontalPadding"] as Any } if allKey.contains("paddingTop") { model.paddingTop = tokenDict["paddingTop"] as Any } if allKey.contains("paddingRight") { model.paddingRight = tokenDict["paddingRight"] as Any } if allKey.contains("paddingBottom") { model.paddingBottom = tokenDict["paddingBottom"] as Any } if allKey.contains("paddingLeft") { model.paddingLeft = tokenDict["paddingLeft"] as Any } if allKey.contains("itemSpacing") { model.itemSpacing = tokenDict["itemSpacing"] as Any } if allKey.contains("fill") { model.fill = tokenDict["fill"] as Any } if allKey.contains("border") { model.border = tokenDict["border"] as Any } if allKey.contains("borderColor") { model.borderColor = tokenDict["borderColor"] as Any } if allKey.contains("borderTop") { model.borderTop = tokenDict["borderTop"] as Any } if allKey.contains("borderRight") { model.borderRight = tokenDict["borderRight"] as Any } if allKey.contains("borderBottom") { model.borderBottom = tokenDict["borderBottom"] as Any } if allKey.contains("borderLeft") { model.borderLeft = tokenDict["borderLeft"] as Any } if allKey.contains("borderRadius") { model.borderRadius = tokenDict["borderRadius"] as Any } if allKey.contains("borderRadiusTopLeft") { model.borderRadiusTopLeft = tokenDict["borderRadiusTopLeft"] as Any } if allKey.contains("borderRadiusTopRight") { model.borderRadiusTopRight = tokenDict["borderRadiusTopRight"] as Any } if allKey.contains("borderRadiusBottomRight") { model.borderRadiusBottomRight = tokenDict["borderRadiusBottomRight"] as Any } if allKey.contains("borderRadiusBottomLeft") { model.borderRadiusBottomLeft = tokenDict["borderRadiusBottomLeft"] as Any } if allKey.contains("borderWidth") { model.borderWidth = tokenDict["borderWidth"] as Any } if allKey.contains("borderWidthTop") { model.borderWidthTop = tokenDict["borderWidthTop"] as Any } if allKey.contains("borderWidthRight") { model.borderWidthRight = tokenDict["borderWidthRight"] as Any } if allKey.contains("borderWidthBottom") { model.borderWidthBottom = tokenDict["borderWidthBottom"] as Any } if allKey.contains("borderWidthLeft") { model.borderWidthLeft = tokenDict["borderWidthLeft"] as Any } if allKey.contains("boxShadow") { model.boxShadow = tokenDict["boxShadow"] as Any } if allKey.contains("typography") { model.typography = tokenDict["typography"] as Any } return model } /** 当使用者希望传入控件/约束后绑定值时调用此方法。 仅支持系统控件默认属性/自定义控件的属性绑定,所以不支持设置以下属性 【borderTop】、【borderRight】、【borderBottom】、【borderLeft】、【borderRadiusTopLeft】、【borderRadiusTopRight】、【borderRadiusBottomRight】、【borderRadiusBottomLeft】、【borderWidthTop】、【borderWidthRight】、【borderWidthBottom】、【borderWidthLeft】 - parameter token: 传入Design Token - parameter sizing: 包含 sizing 属性的控件;支持控件【NSTextField】、 - parameter height: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【高度】赋值 - parameter width: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【宽度】赋值 - parameter spacing: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 上下左右 距离】赋值 - parameter verticalPadding: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 垂直(上下)距离】赋值 - parameter horizontalPadding: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 水平(左右)距离】赋值 - parameter paddingTop: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 上 边距】赋值 - parameter paddingRight: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 右 边距】赋值 - parameter paddingBottom: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 下 边距】赋值 - parameter paddingLeft: 考虑约束冲突的问题,指定传入【NSLayoutConstraint】 类型来进行【组件内控件与边框 左 边距】赋值 - parameter itemSpacing: 组件内多个控件间距,多个控件水平排列,属于水平间距;多个控件垂直排列,属于垂直间距;建议传入【NSLayoutConstraint】 类型 - parameter fill: 传入需要调整【填充颜色】的控件;支持控件 - parameter border: 传入需要调整【边框属性合集,包括边框颜色、边框宽度、边框样式(虚线/直线)】的控件;支持控件 - parameter borderColor: 传入需要调整【边框颜色】的控件;支持控件 - parameter borderRadius: 传入需要调整【边框圆角】的控件;支持控件 - parameter borderWidth: 传入需要调整【边框宽度】的控件;支持控件 - parameter boxShadow: 传入需要调整【包含x/y 倾斜度、blur(模糊间距)】的控件;支持控件 - parameter typography: 传入需要调整【字体合集,包含字体/大小/字重/行高】的控件;支持控件 - returns: 当处理成功时返回Bool值,若处理失败,则返回 KMDesignTokenValue 数据模型 */ func designTokenUsesAction(withToken token: String, sizing : Any = "", height : Any = "", width : Any = "", spacing : Any = "", verticalPadding : Any = "", horizontalPadding: Any = "", paddingTop : Any = "", paddingRight : Any = "", paddingBottom : Any = "", paddingLeft : Any = "", itemSpacing : Any = "", fill : Any = "", border : Any = "", borderColor : Any = "", borderRadius : Any = "", borderWidth : Any = "", boxShadow : Any = "", typography : Any = "") -> Any { if (sizing is String) && (height is String) && (width is String) && (spacing is String) && (verticalPadding is String) && (horizontalPadding is String) && (paddingTop is String) && (paddingRight is String) && (paddingBottom is String) && (paddingLeft is String) && (itemSpacing is String) && (fill is String) && (border is String) && (borderColor is String) && (borderRadius is String) && (borderWidth is String) && (boxShadow is String) && (typography is String) { return tokenUsesModel(withToken: token) } else { let tokenDict = tokenUsesAction(withToken: token) let allKey = tokenDict.keys if allKey.contains("sizing") { let sizingNode = tokenDict["sizing"] if nodeIsEmpty(control: sizing, node: sizingNode as Any) { if sizingNodeUsesAction(control: sizing, node: sizingNode as Any) { KMPrint("sizing node user success") } else { return tokenUsesModel(withToken: token) } } else { return tokenUsesModel(withToken: token) } } if allKey.contains("height") || allKey.contains("width") || allKey.contains("spacing") || allKey.contains("verticalPadding") || allKey.contains("horizontalPadding") || allKey.contains("paddingTop") || allKey.contains("paddingRight") || allKey.contains("paddingBottom") || allKey.contains("paddingLeft") || allKey.contains("itemSpacing") { var node: Any! var control: Any! if allKey.contains("height") { node = tokenDict["height"] as Any control = height } else if allKey.contains("width") { node = tokenDict["width"] as Any control = width } else if allKey.contains("spacing") { node = tokenDict["spacing"] as Any control = spacing } else if allKey.contains("verticalPadding") { node = tokenDict["verticalPadding"] as Any control = verticalPadding } else if allKey.contains("horizontalPadding") { node = tokenDict["horizontalPadding"] as Any control = horizontalPadding } else if allKey.contains("paddingTop") { node = tokenDict["paddingTop"] as Any control = paddingTop } else if allKey.contains("paddingRight") { node = tokenDict["paddingRight"] as Any control = paddingRight } else if allKey.contains("paddingBottom") { node = tokenDict["paddingBottom"] as Any control = paddingBottom } else if allKey.contains("paddingLeft") { node = tokenDict["paddingLeft"] as Any control = paddingLeft } else if allKey.contains("itemSpacing") { node = tokenDict["itemSpacing"] as Any control = itemSpacing } if nodeIsEmpty(control: control as Any, node: node as Any) { if layoutConstraintNodeUsesAction(control: control as Any, node: node as Any) { KMPrint("node user success") } else { return tokenUsesModel(withToken: token) } } else { return tokenUsesModel(withToken: token) } } if allKey.contains("fill") { let fillNode = tokenDict["fill"] if nodeIsEmpty(control: fill, node: fillNode as Any) { if fillNodeUsesAction(control: fill, node: fillNode as Any) { KMPrint("fill node user success") } else { return tokenUsesModel(withToken: token) } } else { return tokenUsesModel(withToken: token) } } if allKey.contains("border") { let borderNode = tokenDict["border"] if nodeIsEmpty(control: border, node: borderNode as Any) { if borderNodeUsesAction(control: border, node: borderNode as Any) { KMPrint("border node user success") } else { return tokenUsesModel(withToken: token) } } else { return tokenUsesModel(withToken: token) } } if allKey.contains("borderColor") { let borderColorNode = tokenDict["borderColor"] if nodeIsEmpty(control: borderColor, node: borderColorNode as Any) { if borderColorNodeUsesAction(control: borderColor, node: borderColorNode as Any) { KMPrint("borderColor node user success") } else { return tokenUsesModel(withToken: token) } } else { return tokenUsesModel(withToken: token) } } if allKey.contains("borderRadius") { let borderRadiusNode = tokenDict["borderRadius"] if nodeIsEmpty(control: borderRadius, node: borderRadiusNode as Any) { if borderRadiusNodeUsesAction(control: borderRadius, node: borderRadiusNode as Any) { KMPrint("borderRadius node user success") } else { return tokenUsesModel(withToken: token) } } else { return tokenUsesModel(withToken: token) } } if allKey.contains("borderWidth") { let borderWidthNode = tokenDict["borderWidth"] if nodeIsEmpty(control: borderWidth, node: borderWidthNode as Any) { if borderWidthNodeUsesAction(control: borderWidth, node: borderWidthNode as Any) { KMPrint("borderWidth node user success") } else { return tokenUsesModel(withToken: token) } } else { return tokenUsesModel(withToken: token) } } if allKey.contains("boxShadow") { let boxShadowNode = tokenDict["boxShadow"] if nodeIsEmpty(control: boxShadow, node: boxShadowNode as Any) { if boxShadowNodeUsesAction(control: boxShadow, node: boxShadowNode as Any) { KMPrint("boxShadow node user success") } else { return tokenUsesModel(withToken: token) } } else { return tokenUsesModel(withToken: token) } } if allKey.contains("typography") { let typographyNode = tokenDict["typography"] if nodeIsEmpty(control: typography, node: typographyNode as Any) { if typographyNodeUsesAction(control: typography, node: typographyNode as Any) { KMPrint("typography node user success") } else { return tokenUsesModel(withToken: token) } } else { return tokenUsesModel(withToken: token) } } } return tokenUsesModel(withToken: token) } // MARK: height、width、spacing、verticalPaddin、horizontalPadding、paddingTop、paddingRight、paddingBottom、paddingLeft、itemSpacing func layoutConstraintNodeUsesAction(control: Any, node: Any) -> Bool { if control is NSLayoutConstraint { (control as! NSLayoutConstraint).constant = (node as! String).stringToCGFloat() return true } return false } // MARK: Private Methods func nodeIsEmpty(control: Any, node: Any) -> Bool { if (control is String) { return false } else { if (node is String) { if (node as! String == "") { return false } else { return true } } else if (node is [String : Any]) { return true } } return false } } extension KMDesignToken: KMJSONParserDelegate { func parser(_ parser: KMJSONParser, success responseObj: Any) { finalDict = responseObj as! [String : Any] } }