accessibility and formatting update

This commit is contained in:
Kevin G Christiano 2020-09-04 15:00:55 -04:00
parent bfb604faae
commit 42929810a1
14 changed files with 277 additions and 116 deletions

View File

@ -34,7 +34,7 @@ import Foundation
public var baseValue: AnyHashable?
public var wasInitiallySelected: Bool = false
public var isValid: Bool? {
public var isValid: Bool? = true {
didSet { updateUI?() }
}

View File

@ -6,82 +6,136 @@
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
@objcMembers public class BGImageHeadlineBodyButton: Container {
let headlineBody = HeadlineBody(frame: .zero)
let button = PillButton(frame: .zero)
//--------------------------------------------------
// MARK: - Outlets
//--------------------------------------------------
let headlineBody = HeadlineBody()
let button = PillButton()
let backgroundImageView = LoadImageView(pinnedEdges: .all)
let maxWidth: CGFloat = 350.0
static let heightConstant: CGFloat = 320.0
//--------------------------------------------------
// MARK: - Property
//--------------------------------------------------
let maxWidth: CGFloat = 350
static let heightConstant: CGFloat = 320
//--------------------------------------------------
// MARK: - Constraints
//--------------------------------------------------
var heightConstraint: NSLayoutConstraint?
// MARK: - MVMCoreViewProtocol
open override func updateView(_ size: CGFloat) {
super.updateView(size)
headlineBody.updateView(size)
button.updateView(size)
backgroundImageView.updateView(size)
backgroundImageView.pinEdges(.all)
}
//--------------------------------------------------
// MARK: - Setup
//--------------------------------------------------
open override func setupView() {
super.setupView()
heightConstraint = heightAnchor.constraint(equalToConstant: Self.heightConstant)
heightConstraint?.isActive = true
backgroundImageView.addSizeConstraintsForAspectRatio = true
let container = MVMCoreUICommonViewsUtility.commonView()
addAndContain(container)
container.addSubview(headlineBody)
container.addSubview(button)
//Headline view
headlineBody.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true
headlineBody.topAnchor.constraint(equalTo: container.topAnchor, constant: 0).isActive = true
headlineBody.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
headlineBody.topAnchor.constraint(equalTo: container.topAnchor).isActive = true
let headLineBodyWidth = headlineBody.widthAnchor.constraint(equalTo: container.widthAnchor, multiplier: 0.67)
headLineBodyWidth.priority = UILayoutPriority(rawValue: 999)
headLineBodyWidth.isActive = true
headlineBody.widthAnchor.constraint(lessThanOrEqualToConstant: maxWidth).isActive = true
//Caret view
button.translatesAutoresizingMaskIntoConstraints = false
button.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true
container.bottomAnchor.constraint(greaterThanOrEqualTo: button.bottomAnchor, constant: 0).isActive = true
button.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
container.bottomAnchor.constraint(greaterThanOrEqualTo: button.bottomAnchor).isActive = true
button.topAnchor.constraint(equalTo: headlineBody.bottomAnchor, constant: PaddingDefault).isActive = true
//Background image view
backgroundImageView.translatesAutoresizingMaskIntoConstraints = false
backgroundImageView.imageView.contentMode = .scaleAspectFill
backgroundImageView.pinEdges(.all)
addSubview(backgroundImageView)
NSLayoutConstraint.constraintPinSubview(toSuperview: backgroundImageView)
sendSubviewToBack(backgroundImageView)
}
isAccessibilityElement = true
accessibilityHint = button.accessibilityHint
accessibilityTraits = button.accessibilityTraits
}
//--------------------------------------------------
// MARK: - MoleculeViewProtocol
//--------------------------------------------------
open override func updateView(_ size: CGFloat) {
super.updateView(size)
headlineBody.updateView(size)
button.updateView(size)
backgroundImageView.updateView(size)
backgroundImageView.pinEdges(.all)
}
open override func reset() {
super.reset()
headlineBody.reset()
backgroundImageView.reset()
}
// MARK:- MoleculeViewProtocol
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
return 320
}
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? BGImageHeadlineBodyButtonModel else { return }
headlineBody.set(with: model.headlineBody, delegateObject, additionalData)
button.setOptional(with: model.button, delegateObject, additionalData)
button.isHidden = model.button == nil
backgroundImageView.set(with: model.image, delegateObject, additionalData)
backgroundImageView.pinEdges(.all)
updateAccessibilityLabel()
}
//----------------------------------------------------
// MARK: - Accessibility
//----------------------------------------------------
func updateAccessibilityLabel() {
var message = ""
if let headline = headlineBody.headlineLabel.text, !headline.isEmpty {
message += headline + ", "
}
if let body = headlineBody.messageLabel.text, !body.isEmpty {
message += body + ", "
}
if let backgroundImageText = backgroundImageView.accessibilityLabel, !backgroundImageText.isEmpty {
message += backgroundImageText + ", "
}
if let buttonLabel = button.accessibilityLabel, !buttonLabel.isEmpty {
message += buttonLabel
}
accessibilityLabel = message
}
open override func accessibilityActivate() -> Bool {
return button.accessibilityActivate()
}
}

View File

@ -6,42 +6,62 @@
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import UIKit
public class BGImageHeadlineBodyButtonModel: ContainerModel, MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "bgImageHeadlineBodyButton"
public var backgroundColor: Color?
public var button: ButtonModel?
public var headlineBody: HeadlineBodyModel
public var image: ImageViewModel
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
init(headlineBody: HeadlineBodyModel, image: ImageViewModel) {
self.headlineBody = headlineBody
self.image = image
super.init()
}
/// Defaults to set
//--------------------------------------------------
// MARK: - Defaults
//--------------------------------------------------
public override func setDefaults() {
if useHorizontalMargins == nil {
useHorizontalMargins = true
}
if useVerticalMargins == nil {
useVerticalMargins = true
}
if topPadding == nil {
topPadding = PaddingDefault
}
if bottomPadding == nil {
bottomPadding = PaddingDefault
}
if image.height == nil {
image.height = BGImageHeadlineBodyButton.heightConstant
}
button?.size = .tiny
button?.style = .secondary
}
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case moleculeName
case backgroundColor
@ -49,7 +69,11 @@ public class BGImageHeadlineBodyButtonModel: ContainerModel, MoleculeModelProtoc
case image
case button
}
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
@ -58,7 +82,7 @@ public class BGImageHeadlineBodyButtonModel: ContainerModel, MoleculeModelProtoc
button = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .button)
try super.init(from: decoder)
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
@ -69,4 +93,3 @@ public class BGImageHeadlineBodyButtonModel: ContainerModel, MoleculeModelProtoc
try container.encodeIfPresent(button, forKey: .button)
}
}

View File

@ -6,7 +6,6 @@
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class EyebrowHeadlineBodyLink: View {
//--------------------------------------------------
@ -76,8 +75,9 @@ import UIKit
/// Returns the labels text in one message.
func getAccessibilityMessage() -> String? {
var message = ""
if let eyebrowLabel = eyebrow.text {
message += eyebrowLabel + ", "
}
@ -89,24 +89,31 @@ import UIKit
if let bodyLabel = body.text {
message += bodyLabel
}
return message.count > 0 ? message : nil
}
/// Returns an array of the appropriate accessibility elements.
func getAccessibilityElements() -> [Any]? {
var elements: [UIView] = []
if eyebrow.hasText {
elements.append(eyebrow)
}
if headline.hasText {
elements.append(headline)
}
if body.hasText {
elements.append(body)
}
if link.titleLabel?.text?.count ?? 0 > 0 {
elements.append(link)
}
return elements.count > 0 ? elements : nil
}
}

View File

@ -6,7 +6,6 @@
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public class EyebrowHeadlineBodyLinkModel: MoleculeModelProtocol {
//--------------------------------------------------

View File

@ -6,77 +6,88 @@
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
@objcMembers public class HeadLineBodyCaretLinkImage: Container {
let headlineBody = HeadlineBody(frame: .zero)
let caretButton = CaretLink(frame: .zero)
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
let headlineBody = HeadlineBody()
let caretButton = CaretLink()
let backgroundImageView = LoadImageView(pinnedEdges: .all)
let maxWidth: CGFloat = 350.0
static let heightConstant: CGFloat = 320.0
//--------------------------------------------------
// MARK: - Constraints
//--------------------------------------------------
let maxWidth: CGFloat = 350
static let heightConstant: CGFloat = 320
var heightConstraint: NSLayoutConstraint?
// MARK: - MVMCoreViewProtocol
open override func updateView(_ size: CGFloat) {
super.updateView(size)
headlineBody.updateView(size)
caretButton.updateView(size)
backgroundImageView.updateView(size)
backgroundImageView.pinEdges(.all)
}
//--------------------------------------------------
// MARK: - Setup
//--------------------------------------------------
open override func setupView() {
super.setupView()
heightConstraint = heightAnchor.constraint(equalToConstant: Self.heightConstant)
heightConstraint?.isActive = true
backgroundImageView.addSizeConstraintsForAspectRatio = true
let container = MVMCoreUICommonViewsUtility.commonView()
addAndContain(container)
container.addSubview(headlineBody)
container.addSubview(caretButton)
//Headline view
headlineBody.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true
headlineBody.topAnchor.constraint(equalTo: container.topAnchor, constant: 0).isActive = true
headlineBody.widthAnchor.constraint(equalTo: container.widthAnchor, multiplier: 0.67).isActive = true
let headLineBodyWidth = headlineBody.widthAnchor.constraint(lessThanOrEqualToConstant: maxWidth)
headLineBodyWidth.priority = UILayoutPriority(250)
headLineBodyWidth.isActive = true
//Caret view
caretButton.translatesAutoresizingMaskIntoConstraints = false
caretButton.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true
container.bottomAnchor.constraint(equalTo: caretButton.bottomAnchor, constant: 0).isActive = true
caretButton.topAnchor.constraint(greaterThanOrEqualTo: headlineBody.bottomAnchor, constant: PaddingTwo).isActive = true
//Background image view
backgroundImageView.translatesAutoresizingMaskIntoConstraints = false
backgroundImageView.imageView.contentMode = .scaleAspectFill
backgroundImageView.pinEdges(.all)
addSubview(backgroundImageView)
NSLayoutConstraint.constraintPinSubview(toSuperview: backgroundImageView)
sendSubviewToBack(backgroundImageView)
}
//--------------------------------------------------
// MARK: - MoleculeViewProtocol
//--------------------------------------------------
open override func updateView(_ size: CGFloat) {
super.updateView(size)
headlineBody.updateView(size)
caretButton.updateView(size)
backgroundImageView.updateView(size)
backgroundImageView.pinEdges(.all)
}
open override func reset() {
super.reset()
headlineBody.reset()
backgroundImageView.reset()
}
// MARK:- MoleculeViewProtocol
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
return 320
}
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? HeadlineBodyCaretLinkImageModel else { return }
headlineBody.set(with: model.headlineBody, delegateObject, additionalData)
caretButton.setOptional(with: model.caretLink, delegateObject, additionalData)
caretButton.isHidden = model.caretLink == nil

View File

@ -6,12 +6,19 @@
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
open class HeadlineBody: View {
//--------------------------------------------------
// MARK: - Outlets
//--------------------------------------------------
let headlineLabel = Label(fontStyle: .BoldTitleLarge)
let messageLabel = Label(fontStyle: .RegularBodySmall)
//--------------------------------------------------
// MARK: - Constraints
//--------------------------------------------------
var spaceBetweenLabelsConstant = PaddingOne
var spaceBetweenLabels: NSLayoutConstraint?
var leftConstraintTitle: NSLayoutConstraint?
@ -19,21 +26,30 @@ open class HeadlineBody: View {
var leftConstraintMessage: NSLayoutConstraint?
var rightConstraintMessage: NSLayoutConstraint?
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
func hasText() -> Bool {
return headlineLabel.hasText || messageLabel.hasText
}
// MARK: - Styling
func style(with style: HeadlineBodyModel.Style?) {
switch style {
case .landingHeader:
styleLandingPageHeader()
case .header:
stylePageHeader()
case .item:
styleListItem()
case .itemHeader:
styleListItemDivider()
default: break
}
}
@ -61,18 +77,14 @@ open class HeadlineBody: View {
messageLabel.setFontStyle(.RegularBodySmall)
spaceBetweenLabelsConstant = 0
}
// MARK: - MVMCoreViewProtocol
open override func updateView(_ size: CGFloat) {
super.updateView(size)
headlineLabel.updateView(size)
messageLabel.updateView(size)
setSpacing()
}
//--------------------------------------------------
// MARK: - Setup
//--------------------------------------------------
open override func setupView() {
super.setupView()
backgroundColor = .clear
clipsToBounds = true
@ -86,35 +98,35 @@ open class HeadlineBody: View {
view.addSubview(headlineLabel)
view.addSubview(messageLabel)
headlineLabel.setContentHuggingPriority(.required, for: .vertical)
messageLabel.setContentHuggingPriority(.required, for: .vertical)
view.setContentHuggingPriority(.required, for: .vertical)
headlineLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
headlineLabel.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
spaceBetweenLabels = messageLabel.topAnchor.constraint(equalTo: headlineLabel.bottomAnchor, constant: spaceBetweenLabelsConstant)
spaceBetweenLabels?.isActive = true
leftConstraintTitle = headlineLabel.leftAnchor.constraint(equalTo: view.leftAnchor)
leftConstraintTitle?.isActive = true
rightConstraintTitle = view.rightAnchor.constraint(equalTo: headlineLabel.rightAnchor)
rightConstraintTitle?.isActive = true
leftConstraintMessage = messageLabel.leftAnchor.constraint(equalTo: view.leftAnchor)
leftConstraintMessage?.isActive = true
rightConstraintMessage = view.rightAnchor.constraint(equalTo: messageLabel.rightAnchor)
rightConstraintMessage?.isActive = true
view.bottomAnchor.constraint(equalTo: messageLabel.bottomAnchor, constant: 0).isActive = true
view.bottomAnchor.constraint(equalTo: messageLabel.bottomAnchor).isActive = true
}
//--------------------------------------------------
// MARK: - Constraining
//--------------------------------------------------
public func setSpacing() {
if headlineLabel.hasText && messageLabel.hasText {
spaceBetweenLabels?.constant = spaceBetweenLabelsConstant
@ -122,11 +134,18 @@ open class HeadlineBody: View {
spaceBetweenLabels?.constant = 0
}
}
//--------------------------------------------------
// MARK: - MoleculeViewProtocol
//--------------------------------------------------
open override func updateView(_ size: CGFloat) {
super.updateView(size)
headlineLabel.updateView(size)
messageLabel.updateView(size)
setSpacing()
}
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
return 58
}
@ -135,7 +154,7 @@ open class HeadlineBody: View {
super.set(with: model, delegateObject, additionalData)
guard let headlineBodyModel = model as? HeadlineBodyModel else { return }
style(with: headlineBodyModel.style)
headlineLabel.setOptional(with: headlineBodyModel.headline, delegateObject, additionalData)

View File

@ -6,8 +6,6 @@
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class HeadlineBodyButton: View {
//------------------------------------------------------

View File

@ -6,8 +6,6 @@
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public class HeadlineBodyButtonModel: MoleculeModelProtocol {
//--------------------------------------------------
@ -17,7 +15,7 @@ public class HeadlineBodyButtonModel: MoleculeModelProtocol {
public static var identifier: String = "headlineBodyButton"
public var moleculeName: String = HeadlineBodyButtonModel.identifier
public var backgroundColor: Color?
public var headlineBody: HeadlineBodyModel
public var button: ButtonModel
public var buttonHeadlinePadding: CGFloat

View File

@ -6,40 +6,60 @@
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import UIKit
public class HeadlineBodyCaretLinkImageModel: ContainerModel, MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "headlineBodyCaretLinkImage"
public var backgroundColor: Color?
public var caretLink: CaretLinkModel?
public var headlineBody: HeadlineBodyModel
public var image: ImageViewModel
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
init(headlineBody: HeadlineBodyModel, image: ImageViewModel) {
self.headlineBody = headlineBody
self.image = image
super.init()
}
//--------------------------------------------------
// MARK: - Defaults
//--------------------------------------------------
/// Defaults to set
public override func setDefaults() {
if useHorizontalMargins == nil {
useHorizontalMargins = true
}
if useVerticalMargins == nil {
useVerticalMargins = true
}
if topPadding == nil {
topPadding = PaddingDefault
}
if bottomPadding == nil {
bottomPadding = PaddingDefault
}
if image.height == nil {
image.height = HeadLineBodyCaretLinkImage.heightConstant
}
}
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case moleculeName
case backgroundColor
@ -47,7 +67,11 @@ public class HeadlineBodyCaretLinkImageModel: ContainerModel, MoleculeModelProto
case image
case caretLink
}
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
@ -56,7 +80,7 @@ public class HeadlineBodyCaretLinkImageModel: ContainerModel, MoleculeModelProto
caretLink = try typeContainer.decodeIfPresent(CaretLinkModel.self, forKey: .caretLink)
try super.init(from: decoder)
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)

View File

@ -6,33 +6,41 @@
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers public class HeadlineBodyLink: View {
let headlineBody = HeadlineBody(frame: .zero)
//--------------------------------------------------
// MARK: - Outlets
//--------------------------------------------------
let headlineBody = HeadlineBody()
let link = Link()
var spaceBetweenConstant: CGFloat = 0.0
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
var spaceBetweenConstant: CGFloat = 0
//--------------------------------------------------
// MARK: - Constraints
//--------------------------------------------------
var spaceBetween: NSLayoutConstraint?
// MARK: - MVMCoreViewProtocol
open override func updateView(_ size: CGFloat) {
super.updateView(size)
headlineBody.updateView(size)
link.updateView(size)
setSpacing()
}
//--------------------------------------------------
// MARK: - Setup
//--------------------------------------------------
open override func setupView() {
super.setupView()
guard subviews.count == 0 else {
return
}
guard subviews.isEmpty else { return }
addSubview(headlineBody)
addSubview(link)
headlineBody.styleListItem()
headlineBody.topAnchor.constraint(equalTo: topAnchor, constant: 0).isActive = true
headlineBody.topAnchor.constraint(equalTo: topAnchor).isActive = true
headlineBody.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
var constraint = rightAnchor.constraint(equalTo: headlineBody.rightAnchor)
constraint.priority = .defaultHigh
@ -49,7 +57,10 @@ import UIKit
constraint.isActive = true
}
// MARK: - Constraining
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
public func setSpacing() {
if headlineBody.hasText() && (link.titleLabel?.text?.count ?? 0) > 0 {
spaceBetween?.constant = spaceBetweenConstant
@ -58,7 +69,17 @@ import UIKit
}
}
// MARK: - MoleculeViewProtocol
//--------------------------------------------------
// MARK: - MVMCoreViewProtocol
//--------------------------------------------------
open override func updateView(_ size: CGFloat) {
super.updateView(size)
headlineBody.updateView(size)
link.updateView(size)
setSpacing()
}
open override func reset() {
super.reset()
headlineBody.reset()
@ -66,7 +87,6 @@ import UIKit
link.reset()
}
// MARK:- MoleculeViewProtocol
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? HeadlineBodyLinkModel else { return }

View File

@ -8,13 +8,22 @@
import Foundation
public struct HeadlineBodyLinkModel: MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "headlineBodyLink"
public var moleculeName: String = HeadlineBodyLinkModel.identifier
public var headlineBody: HeadlineBodyModel
public var link: LinkModel
public var backgroundColor: Color?
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(headlineBody: HeadlineBodyModel, link: LinkModel) {
self.headlineBody = headlineBody
self.link = link

View File

@ -6,8 +6,6 @@
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import UIKit
open class ThreeHeadlineBodyLink: View {
//-------------------------------------------------------

View File

@ -66,11 +66,12 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
open func updateContainedMolecules(with models: [MoleculeModelProtocol?], _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
guard var stackModel = stackModel else { return }
var needsRestack = false
for (index, item) in stackItems.enumerated() {
guard let container = item as? UIView & ContainerProtocol,
let contained = container.view as? MoleculeViewProtocol else {
continue
}
let contained = container.view as? MoleculeViewProtocol
else { continue }
if let model = models[index] {
contained.set(with: model, delegateObject, additionalData)
if stackModel.molecules[index].gone {