first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
require 'json'
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
Pod::Spec.new do |s|
s.name = 'ExpoGlassEffect'
s.version = package['version']
s.summary = package['description']
s.description = package['description']
s.license = package['license']
s.author = package['author']
s.homepage = package['homepage']
s.platforms = {
:ios => '15.1',
:tvos => '15.1',
}
s.source = { git: 'https://github.com/expo/expo.git' }
s.static_framework = true
s.dependency 'ExpoModulesCore'
if !$ExpoUseSources&.include?(package['name']) && ENV['EXPO_USE_SOURCE'].to_i == 0 && File.exist?("#{s.name}.xcframework") && Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.10.0')
s.source_files = "**/*.h"
s.vendored_frameworks = "#{s.name}.xcframework"
else
s.source_files = "**/*.{h,m,swift}"
end
end

View File

@@ -0,0 +1,56 @@
// Copyright 2022-present 650 Industries. All rights reserved.
import ExpoModulesCore
public final class GlassContainer: ExpoView {
private var containerEffect: Any?
private var containerEffectView = UIVisualEffectView()
private var containerSpacing: CGFloat?
public required init(appContext: AppContext? = nil) {
super.init(appContext: appContext)
containerEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(containerEffectView)
}
// UIGlassEffect initialiser is failing for iOS 26 beta versions for some reason, so we need to check if it's available at runtime
// https://github.com/expo/expo/issues/40911
private func isGlassContainerEffectAvailable() -> Bool {
#if compiler(>=6.2)
if #available(iOS 26.0, tvOS 26.0, macOS 26.0, *) {
return NSClassFromString("UIGlassContainerEffect") != nil
}
#endif
return false
}
func setSpacing(_ spacing: CGFloat?) {
if containerSpacing != spacing {
containerSpacing = spacing
guard isGlassContainerEffectAvailable() else {
return
}
if #available(iOS 26.0, tvOS 26.0, macOS 26.0, *) {
#if compiler(>=6.2) // Xcode 26
let effect = UIGlassContainerEffect()
if let spacing = spacing {
effect.spacing = spacing
}
containerEffectView.effect = effect
containerEffect = effect
#endif
}
}
}
public override func mountChildComponentView(_ childComponentView: UIView, index: Int) {
containerEffectView.contentView.insertSubview(childComponentView, at: index)
}
public override func unmountChildComponentView(_ childComponentView: UIView, index: Int) {
childComponentView.removeFromSuperview()
}
}

View File

@@ -0,0 +1,106 @@
// Copyright 2022-present 650 Industries. All rights reserved.
import ExpoModulesCore
public final class GlassEffectModule: Module {
public func definition() -> ModuleDefinition {
Name("ExpoGlassEffect")
Constant("isLiquidGlassAvailable") {
#if compiler(>=6.2) // Xcode 26
if #available(iOS 26.0, tvOS 26.0, macOS 26.0, *) { // iOS 26
if let infoPlist = Bundle.main.infoDictionary,
let requiresCompatibility = infoPlist["UIDesignRequiresCompatibility"] as? Bool {
// TODO(@uabx): Add a check for maximum SDK version when apple disables this flag
return !requiresCompatibility // If the app requires compatibility then it will not use liquid glass
}
return true
}
#endif
return false
}
Constant("isGlassEffectAPIAvailable") {
#if compiler(>=6.2)
if #available(iOS 26.0, tvOS 26.0, macOS 26.0, *) {
guard let glassEffectClass = NSClassFromString("UIGlassEffect") as? NSObject.Type else {
return false
}
let respondsToSelector = glassEffectClass.responds(to: Selector(("effectWithStyle:")))
return respondsToSelector
}
#endif
return false
}
View(GlassView.self) {
Prop("glassEffectStyle") { (view, config: Either<GlassStyle, GlassEffectStyleConfig>?) in
if let styleConfig: GlassEffectStyleConfig = config?.get() {
view.setGlassStyle(styleConfig)
} else if let style: GlassStyle = config?.get() {
view.setGlassStyle(style)
} else {
view.setGlassStyle(.regular)
}
}
Prop("tintColor") { (view, tintColor: UIColor?) in
view.setTintColor(tintColor)
}
Prop("isInteractive") { (view, interactive: Bool) in
view.setInteractive(interactive)
}
Prop("colorScheme", .auto) { (view, colorScheme: GlassColorScheme) in
view.setColorScheme(colorScheme)
}
Prop("borderRadius") { (view, border: CGFloat?) in
view.setBorderRadius(border)
}
Prop("borderBottomLeftRadius") { (view, radius: CGFloat?) in
view.setBorderBottomLeftRadius(radius)
}
Prop("borderBottomRightRadius") { (view, radius: CGFloat?) in
view.setBorderBottomRightRadius(radius)
}
Prop("borderTopLeftRadius") { (view, radius: CGFloat?) in
view.setBorderTopLeftRadius(radius)
}
Prop("borderTopRightRadius") { (view, radius: CGFloat?) in
view.setBorderTopRightRadius(radius)
}
Prop("borderTopStartRadius") { (view, radius: CGFloat?) in
view.setBorderTopStartRadius(radius)
}
Prop("borderTopEndRadius") { (view, radius: CGFloat?) in
view.setBorderTopEndRadius(radius)
}
Prop("borderBottomStartRadius") { (view, radius: CGFloat?) in
view.setBorderBottomStartRadius(radius)
}
Prop("borderBottomEndRadius") { (view, radius: CGFloat?) in
view.setBorderBottomEndRadius(radius)
}
Prop("borderCurve") { (view, curve: String?) in
view.setBorderCurve(curve)
}
}
View(GlassContainer.self) {
Prop("spacing") { (view, spacing: CGFloat?) in
view.setSpacing(spacing)
}
}
}
}

50
node_modules/expo-glass-effect/ios/GlassStyle.swift generated vendored Normal file
View File

@@ -0,0 +1,50 @@
import ExpoModulesCore
import UIKit
public enum GlassStyle: String, Enumerable {
case clear
case regular
case none
#if compiler(>=6.2) // Xcode 26
@available(iOS 26.0, tvOS 26.0, macOS 26.0, *)
func toUIGlassEffectStyle() -> UIGlassEffect.Style? {
switch self {
case .clear:
return .clear
case .regular:
return .regular
case .none:
return nil
}
}
#endif
}
internal struct GlassEffectStyleConfig: Record {
@Field
var style: GlassStyle = .regular
@Field
var animate: Bool = false
@Field
var animationDuration: Double?
}
internal enum GlassColorScheme: String, Enumerable {
case auto
case light
case dark
func toUIUserInterfaceStyle() -> UIUserInterfaceStyle {
switch self {
case .auto:
return .unspecified
case .light:
return .light
case .dark:
return .dark
}
}
}

254
node_modules/expo-glass-effect/ios/GlassView.swift generated vendored Normal file
View File

@@ -0,0 +1,254 @@
// Copyright 2022-present 650 Industries. All rights reserved.
import ExpoModulesCore
import React
public final class GlassView: ExpoView {
private var glassEffect: Any?
private var glassEffectView = UIVisualEffectView()
// TODO: Find a better fix
// Glass effect does not work sometimes if view has not been laid out yet
// https://github.com/expo/expo/issues/41024#issuecomment-3867466289
private var isMounted = false
private var glassStyle: GlassStyle?
private var glassTintColor: UIColor?
private var glassIsInteractive: Bool?
private var radius: CGFloat?
private var bottomLeftRadius: CGFloat?
private var bottomRightRadius: CGFloat?
private var topLeftRadius: CGFloat?
private var topRightRadius: CGFloat?
private var bottomStartRadius: CGFloat?
private var bottomEndRadius: CGFloat?
private var topStartRadius: CGFloat?
private var topEndRadius: CGFloat?
public required init(appContext: AppContext? = nil) {
super.init(appContext: appContext)
glassEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(glassEffectView)
}
// UIGlassEffect initialiser is crashing for iOS 26 beta versions for some reason, so we need to check if it's available at runtime
// https://github.com/expo/expo/issues/40911
private func isGlassEffectAvailable() -> Bool {
#if compiler(>=6.2)
if #available(iOS 26.0, tvOS 26.0, macOS 26.0, *) {
guard let glassEffectClass = NSClassFromString("UIGlassEffect") as? NSObject.Type else {
return false
}
let respondsToSelector = glassEffectClass.responds(to: Selector(("effectWithStyle:")))
return respondsToSelector
}
#endif
return false
}
override public func layoutSubviews() {
super.layoutSubviews()
if !isMounted {
isMounted = true
updateEffect()
}
}
func updateBorderRadius() {
guard isGlassEffectAvailable() else {
return
}
if #available(iOS 26.0, tvOS 26.0, macOS 26.0, *) {
#if compiler(>=6.2) // Xcode 26
let isRTL = RCTI18nUtil.sharedInstance()?.isRTL() ?? false
let finalTopLeft: CGFloat
let finalTopRight: CGFloat
let finalBottomLeft: CGFloat
let finalBottomRight: CGFloat
if isRTL {
finalTopLeft = topLeftRadius ?? topEndRadius ?? radius ?? 0
finalTopRight = topRightRadius ?? topStartRadius ?? radius ?? 0
finalBottomLeft = bottomLeftRadius ?? bottomEndRadius ?? radius ?? 0
finalBottomRight = bottomRightRadius ?? bottomStartRadius ?? radius ?? 0
} else {
finalTopLeft = topLeftRadius ?? topStartRadius ?? radius ?? 0
finalTopRight = topRightRadius ?? topEndRadius ?? radius ?? 0
finalBottomLeft = bottomLeftRadius ?? bottomStartRadius ?? radius ?? 0
finalBottomRight = bottomRightRadius ?? bottomEndRadius ?? radius ?? 0
}
let topLeft = UICornerRadius(floatLiteral: finalTopLeft)
let topRight = UICornerRadius(floatLiteral: finalTopRight)
let bottomLeft = UICornerRadius(floatLiteral: finalBottomLeft)
let bottomRight = UICornerRadius(floatLiteral: finalBottomRight)
glassEffectView.cornerConfiguration = .corners(
topLeftRadius: topLeft,
topRightRadius: topRight,
bottomLeftRadius: bottomLeft,
bottomRightRadius: bottomRight
)
#endif
}
}
func setGlassStyle(_ config: GlassEffectStyleConfig) {
applyGlassStyle(config.style, animate: config.animate, animationDuration: config.animationDuration)
}
func setGlassStyle(_ style: GlassStyle) {
applyGlassStyle(style)
}
private func applyGlassStyle(_ newStyle: GlassStyle, animate: Bool = false, animationDuration: Double? = nil) {
if glassStyle != newStyle {
glassStyle = newStyle
guard isGlassEffectAvailable() else {
return
}
if #available(iOS 26.0, tvOS 26.0, macOS 26.0, *) {
#if compiler(>=6.2) // Xcode 26
let applyEffect = {
if let uiStyle = newStyle.toUIGlassEffectStyle() {
self.glassEffect = UIGlassEffect(style: uiStyle)
self.updateEffect()
} else {
// TODO: revisit this in newer versions of iOS
// setting `nil` does not work as expected, so we need to set a visual effect with no effect
self.glassEffectView.effect = UIVisualEffect()
self.glassEffect = self.glassEffectView.effect
}
}
if animate {
if let duration = animationDuration {
UIView.animate(withDuration: duration, animations: applyEffect)
} else {
UIView.animate(animations: applyEffect)
}
} else {
applyEffect()
}
#endif
}
}
}
// TODO: support UIVisualEffectView with ExpoFabricView?
func setBorderRadius(_ _radius: CGFloat?) {
if _radius != radius {
radius = _radius
updateBorderRadius()
}
}
func setBorderCurve(_: String?) {
glassEffectView.layer.cornerCurve = self.layer.cornerCurve
}
func setBorderBottomLeftRadius(_ radius: CGFloat?) {
if radius != bottomLeftRadius {
bottomLeftRadius = radius
updateBorderRadius()
}
}
func setBorderBottomRightRadius(_ radius: CGFloat?) {
if radius != bottomRightRadius {
bottomRightRadius = radius
updateBorderRadius()
}
}
func setBorderTopLeftRadius(_ radius: CGFloat?) {
if radius != topLeftRadius {
topLeftRadius = radius
updateBorderRadius()
}
}
func setBorderTopRightRadius(_ radius: CGFloat?) {
if radius != topRightRadius {
topRightRadius = radius
updateBorderRadius()
}
}
func setBorderBottomStartRadius(_ radius: CGFloat?) {
if radius != bottomStartRadius {
bottomStartRadius = radius
updateBorderRadius()
}
}
func setBorderBottomEndRadius(_ radius: CGFloat?) {
if radius != bottomEndRadius {
bottomEndRadius = radius
updateBorderRadius()
}
}
func setBorderTopStartRadius(_ radius: CGFloat?) {
if radius != topStartRadius {
topStartRadius = radius
updateBorderRadius()
}
}
func setBorderTopEndRadius(_ radius: CGFloat?) {
if radius != topEndRadius {
topEndRadius = radius
updateBorderRadius()
}
}
func setTintColor(_ color: UIColor?) {
if color != glassTintColor {
glassTintColor = color
updateEffect()
}
}
func setInteractive(_ interactive: Bool) {
if interactive != glassIsInteractive {
glassIsInteractive = interactive
updateEffect()
}
}
func setColorScheme(_ colorScheme: GlassColorScheme) {
overrideUserInterfaceStyle = colorScheme.toUIUserInterfaceStyle()
}
private func updateEffect() {
if !isMounted {
return
}
guard isGlassEffectAvailable() else {
return
}
if #available(iOS 26.0, tvOS 26.0, macOS 26.0, *) {
#if compiler(>=6.2) // Xcode 26
if let effect = glassEffect as? UIGlassEffect {
effect.tintColor = glassTintColor
effect.isInteractive = glassIsInteractive ?? false
// we need to set the effect again or it has no effect!
glassEffectView.effect = effect
updateBorderRadius()
setBorderCurve(nil)
}
#endif
}
}
public override func mountChildComponentView(_ childComponentView: UIView, index: Int) {
glassEffectView.contentView.insertSubview(childComponentView, at: index)
}
public override func unmountChildComponentView(_ childComponentView: UIView, index: Int) {
childComponentView.removeFromSuperview()
}
}