{"id":20177614,"url":"https://github.com/artlasovsky/foundation-ui","last_synced_at":"2025-09-08T12:40:20.371Z","repository":{"id":162635611,"uuid":"611956242","full_name":"artlasovsky/foundation-ui","owner":"artlasovsky","description":"SwiftUI framework to speedup prototyping and development of user interfaces.","archived":false,"fork":false,"pushed_at":"2025-08-29T09:09:09.000Z","size":412,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-29T13:06:47.644Z","etag":null,"topics":["design-system","ios","macos","modifier","swiftui"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/artlasovsky.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["artlasovsky"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2023-03-09T22:24:06.000Z","updated_at":"2025-08-29T09:09:12.000Z","dependencies_parsed_at":"2023-12-20T15:32:05.232Z","dependency_job_id":"fa744f41-85c5-4390-9ab1-f433006daf45","html_url":"https://github.com/artlasovsky/foundation-ui","commit_stats":null,"previous_names":["artlasovsky/truss-ui","artlasovsky/foundation-ui"],"tags_count":85,"template":false,"template_full_name":null,"purl":"pkg:github/artlasovsky/foundation-ui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artlasovsky%2Ffoundation-ui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artlasovsky%2Ffoundation-ui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artlasovsky%2Ffoundation-ui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artlasovsky%2Ffoundation-ui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/artlasovsky","download_url":"https://codeload.github.com/artlasovsky/foundation-ui/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artlasovsky%2Ffoundation-ui/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274187506,"owners_count":25237811,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-08T02:00:09.813Z","response_time":121,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["design-system","ios","macos","modifier","swiftui"],"created_at":"2024-11-14T02:16:34.565Z","updated_at":"2025-09-08T12:40:20.358Z","avatar_url":"https://github.com/artlasovsky.png","language":"Swift","readme":"# FoundationUI\n\n\u003cp align=\"left\"\u003e\n\u003cimg src=\"https://img.shields.io/github/v/tag/artlasovsky/foundation-ui?label=Beta\u0026color=yellow\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/iOS-15+-orange.svg\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/macOS-12+-orange.svg\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/watchOS-Soon-lightgrey.svg\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/tvOS-WIP-lightgrey.svg\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/visionOS-WIP-lightgrey.svg\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/Licence-MIT-green\"\u003e\n\u003c/p\u003e\n\nA framework designed to streamline and accelerate the prototyping and development of user interfaces using SwiftUI.\n\n## Idea\nFoundationUI was created to simplify and accelerate the development of SwiftUI-based applications. \nBy abstracting repetitive tasks and offering intuitive, reusable components, it empowers developers to focus on delivering great user experiences.\n\n## Core Principles\n1.\t**Simplicity:** Easy-to-adopt APIs with minimal boilerplate.\n2.\t**Extensibility:** Modular design for seamless integration into any project.\n3.\t**Discoverability:** Rich documentation and intuitive structure to make it easy to explore and utilize the design system.\n4.\t**Consistency:** Centralized theming and dynamic colors ensure a unified design.\n\n## Mission\nTo bridge the gap between rapid prototyping and production-ready apps, empowering developers to swiftly create refined interfaces while maintaining best practice standards.\n\n# Quick Start Guide\n\n## Setup\n\n1. Add package using Swift Package Manager ([Adding Package Dependencies to Your App](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app))\n```\nhttps://github.com/artlasovsky/foundation-ui\n```\n\n2. Import FoundationUI in your Swift files:\n```swift\nimport FoundationUI\n```\n\n## Core Concepts\n\n### 1. Theme System\nFoundationUI uses an extensible theme system. Create your design tokens by extending the `Theme` namespace:\n\n```swift\n// Theme.swift\nimport FoundationUI\n\npublic extension Theme.Padding {\n    static let small = Theme.Padding(6)\n    static let regular = Theme.Padding(8)\n\tstatic let large = regular + regular * 0.5 // 12\n}\n\npublic extension Theme.Size {\n    static let standard = Theme.Size(width: 110, height: 30)\n}\n```\n\n### 2. Modifiers\nApply styling using `.foundation()` modifiers:\n\n```swift\nText(\"Hello World\")\n    .foundation(.size(.standard))\n    .foundation(.padding(.small, .horizontal))\n```\n\n### 3. Dynamic Colors\nCreate adaptive colors that respond to color scheme changes:\n\n\u003e Note: Use Swift's Access Control features to control scope of the theme extensions.\n\n```swift\nprivate extension Theme.Color {\n    static let regular = Theme.Color(\n        light: .init(grayscale: 0.8),\n        dark: .init(grayscale: 0.6)\n    )\n}\n\n// Usage\nmyView.foundation(.background(.regular))\n```\n\n### 4. Basic Component Example\nHere's a simple example combining these concepts:\n\n```swift\nstruct SimpleButton: View {\n    var body: some View {\n        Text(\"Click Me\")\n            .foundation(.size(.standard))\n            .foundation(.foreground(.white))\n            .foundation(.background(Theme.Color.from(color: .accentColor)))\n            .foundation(.concentricRoundedRectangle(.small))\n    }\n}\n```\n\n## Next Steps\n- Check out the [detailed example](#example-building-a-native-style-button) for a more comprehensive implementation\n- Explore the DocC documentation to explore advanced features\n\n\n# Example: Building a Native-Style Button\n\nThis example demonstrates FoundationUI's capabilities by creating a custom button style that matches native macOS design. \nWe'll build a button with two variants (prominent and regular) that:\n- Adapts to light and dark color schemes\n- Responds to pressed states\n- Includes highlighting effects in dark mode\n\n## Visual Progress\n| Unstyled (Step 1) | Basic Styling (Step 2) | Polished (Step 3) |\n|-|-|-|\n| ![Step 1][step01] | ![Step 2][step02] | ![Step 3][step03] |\n\n[step01]: Documentation.docc/Resources/ReadmeSample/Images/readme_sample_01.jpg\n[step02]: Documentation.docc/Resources/ReadmeSample/Images/readme_sample_02.jpg\n[step03]: Documentation.docc/Resources/ReadmeSample/Images/readme_sample_03.jpg\n[sample_files]: Documentation.docc/Resources/ReadmeSample\n\n## Code\n\nDownload the final example files here:\n[Documentation.docc/Resources/ReadmeSample][sample_files]\n\n## Step 1: Unstyled `CustomButtonStyle` and Preview\n\nFirst, we'll set up the basic button structure. This shows the minimal setup needed before applying FoundationUI's styling features.\n\n```swift\n// FILE: - CustomButtonStyle.swift\n\nstruct CustomButtonStyle: ButtonStyle {\n\tvar variant: CustomButtonStyleVariant = .regular\n\n\tfunc makeBody(configuration: Configuration) -\u003e some View {\n\t\tconfiguration.label\n\t}\n}\n\nenum CustomButtonStyleVariant {\n\tcase prominent\n\tcase regular\n}\n\nstruct CustomButtonStylePreview: View {\n\tvar body: some View {\n\t\tVStack {\n\t\t\tbuttonGroup(.light)\n\t\t\tbuttonGroup(.dark)\n\t\t}\n\t\t.padding()\n\t\t.background(.background)\n\t}\n\n\tfunc buttonGroup(_ colorScheme: ColorScheme) -\u003e some View {\n\t\tVStack {\n\t\t\tText(colorScheme == .light ? \"Light\" : \"Dark\")\n\t\t\t\t.monospaced()\n\t\t\t\t.font(.caption)\n\t\t\tHStack {\n\t\t\t\tButton(\"Cancel\") {}\n\t\t\t\t\t.buttonStyle(CustomButtonStyle())\n\t\t\t\tButton(\"Action\") {}\n\t\t\t\t\t.buttonStyle(CustomButtonStyle(variant: .prominent))\n\t\t\t}\n\t\t\t.padding(18)\n\t\t\t.background(.windowBackground, in: .rect(cornerRadius: 18))\n\t\t\t.environment(\\.colorScheme, colorScheme)\n\t\t}\n\t}\n}\n\n#Preview {\n\tCustomButtonStylePreview()\n}\n```\n\n\u003cdiv align=\"center\"\u003e\n\t\u003cimg \n\t\tsrc=\"Documentation.docc/Resources/ReadmeSample/Images/readme_sample_01.jpg\" \n\t\talt=\"Step 1: Unstyled `CustomButtonStyle`\"\n\t\twidth=400\n\t\u003e\n\u003c/div\u003e\n\n\n## Step 2 - Essentials\n\n### Theme\nFoundationUI doesn't include a default theme, as each team has its own naming conventions. \nIt can be effortlessly extended with your design system tokens using the `extension Theme.{Variable} {}`.\n\n#### Padding and Radius\nWe will create a `Theme.swift` file and add tokens to the `Radius` variable.\n\n```swift\n// FILE: - Theme.swift\n\nimport FoundationUI\n\npublic extension Theme.Radius {\n\tstatic let xxSmall = Theme.Radius(2)\n\tstatic let xSmall = Theme.Radius(4)\n\tstatic let small = Theme.Radius(6)\n\tstatic let regular = Theme.Radius(8)\n\tstatic let large = Theme.Radius(12)\n\tstatic let xLarge = Theme.Radius(18)\n\tstatic let xxLarge = Theme.Radius(24)\n}\n```\n\n#### FoundationUI Modifiers\n\nImport `FoundationUI` and create a token for the `Size` variable,\nthen use the `.foundation(.size())` view modifier to set the size. \n\n```swift\n// FILE: - CustomButtonStyle.swift\nimport FoundationUI\n\nprivate extension Theme.Size {\n\tstatic let button = Theme.Size(width: 110, height: 30)\n}\n\nstruct CustomButtonStyle: ButtonStyle {\n\tvar variant: CustomButtonStyleVariant = .regular\n\t\n\tfunc makeBody(configuration: Configuration) -\u003e some View {\n\t\tconfiguration.label\n\t\t\t.foundation(.size(.button))\n\t}\n}\n\n/// ...\n```\n\n#### DynamicColor\nNext, we'll create the `background` token. Currently, we have two button styles: `regular` and `prominent`. Additionally, we need to show the `isPressed` state.\n\nLet's extend `Theme.Color`. It based on FoundationUI's `DynamicColor` designed to be flexible: \n- It can be created with multiple `ColorComponents` across various color models (HSB, RGB, HEX, OKLCH) or through native colors (SwiftUI.Color, UIColor, NSColor).\n- You have the option to configure each component for various color schemes: `light`, `dark`, `lightAccessible`, and `darkAccessible`\n- It has built-in modifiers, such as brightness, hue, saturation, opacity, blendMode, and more.\n\n```swift\n// FILE: - CustomButtonStyle.swift\nprivate extension Theme.Color {\n\tstatic func background(_ variant: CustomButtonStyleVariant, isPressed: Bool) -\u003e Theme.Color {\n\t\tlet color: Theme.Color\n\t\tswitch variant {\n\t\tcase .prominent:\n\t\t\tcolor = .from(color: .accentColor)\n\t\tcase .regular:\n\t\t\tcolor = .init(\n\t\t\t\tlight: .init(grayscale: 0.8),\n\t\t\t\tdark: .init(grayscale: 0.6)\n\t\t\t)\n\t\t}\n\t\treturn color.brightness(isPressed ? 0.9 : 1)\n\t}\n}\n```\n\nthen create `foreground` token:\n```swift\n// FILE: - CustomButtonStyle.swift\nprivate extension Theme.Color {\n\t/// static func background(...){ ... }\n\tstatic func foreground(_ variant: CustomButtonStyleVariant) -\u003e Theme.Color {\n\t\tswitch variant {\n\t\tcase .prominent:\n\t\t\t.white\n\t\tcase .regular:\n\t\t\t.init(\n\t\t\t\tlight: .init(grayscale: 0.25),\n\t\t\t\tdark: .init(grayscale: 0.98)\n\t\t\t)\n\t\t}\n\t}\n}\n```\n\nand finally add FountationUI's view modifiers to the `makeBody()`:\n\n```swift\n// FILE: - CustomButtonStyle.swift\nstruct CustomButtonStyle: ButtonStyle {\n\t// ...\n\tfunc makeBody(configuration: Configuration) -\u003e some View {\n\t\t\tconfiguration.label\n\t\t\t\t.foundation(.size(.button))\n\t\t\t\t.foundation(.foreground(.foreground(variant)))\n\t\t\t\t.foundation(.background(.background(variant, isPressed: isPressed)))\n\t}\n\t// ...\n}\n```\n\n\nIt's time to use one of the `Theme.Radius` tokens we declared initially. \nWe'll apply it with the `.foundation(.concentricRoundedRectangle())` view modifier, which automatically adjusts the shape of `.foundation(.background())`. \n\n```swift\n// FILE: - CustomButtonStyle.swift\nstruct CustomButtonStyle: ButtonStyle {\n\t// ...\n\tfunc makeBody(configuration: Configuration) -\u003e some View {\n\t\t\tconfiguration.label\n\t\t\t\t.foundation(.size(.button))\n\t\t\t\t.foundation(.foreground(.foreground(variant)))\n\t\t\t\t.foundation(.background(.background(variant, isPressed: isPressed)))\n\t\t\t\t.foundation(.concentricRoundedRectangle(.small))\n\t}\n\t// ..\n}\n```\n\n\u003cdiv align=\"center\"\u003e\n\t\u003cimg \n\t\tsrc=\"Documentation.docc/Resources/ReadmeSample/Images/readme_sample_02.jpg\" \n\t\talt=\"Step 2 - Essentials\"\n\t\twidth=400\n\t\u003e\n\u003c/div\u003e\n\n## Step 3 - Details\n\nFor the final step, we will modify the highlight for the dark variant of the `CustomButtonStyle`. A vertical linear gradient will be applied over the background. \nFoundationUI provides `Theme.Gradient` with the custom `DynamicGradient` ShapeStyle, streamlining the creation and reuse of gradients.\n\n\u003e **Note:** The `.foundation(.backgroundGradient())` view modifier automatically inherits the cornerRadius value from the `.foundation(.concentricRoundedRectangle())` modifier, same way as the `.foundation(.background())`.\n\u003e\\\n\u003e This behavior is enabled by default but can be adjusted or disabled. \n\n```swift\n// FILE: - CustomButtonStyle.swift\nprivate extension Theme.Gradient {\n\tstatic let backgroundHighlight = Theme.Gradient(\n\t\tcolors: [\n\t\t\t.white, \n\t\t\t.white.opacity(0.5), \n\t\t\t.black.opacity(0.1)\n\t\t],\n\t\ttype: .linear(startPoint: .top, endPoint: .bottom)\n\t).opacity(0.2)\n}\n\nstruct CustomButtonStyle: ButtonStyle {\n\t// ...\n\tfunc makeBody(configuration: Configuration) -\u003e some View {\n\t\t\tconfiguration.label\n\t\t\t\t.foundation(.size(.button))\n\t\t\t\t.foundation(.foreground(.foreground(variant)))\n\t\t\t\t.foundation(.backgroundGradient(.backgroundHighlight), bypass: !isShowingBackgroundHighlight)\n\t\t\t\t.foundation(.background(.background(variant, isPressed: isPressed)))\n\t\t\t\t.foundation(.concentricRoundedRectangle(.small))\n\t}\n\n\t/// Conditionally showing background highlight\n\tprivate var isShowingBackgroundHighlight: Bool {\n\t\tswitch variant {\n\t\tcase .prominent: true\n\t\tcase .regular: false\n\t\t}\n\t}\n\t// ...\n}\n```\n\n\u003e **Hint:**\n\u003e If a token, such as `Theme.Color` in this example, is only used once and is not intended for use elsewhere, it can be stored anywhere and referenced directly rather than being placed within `Theme.Color`.\n\n```swift\n// FILE: - CustomButtonStyle.swift\nprivate extension Theme.Gradient {\n\t// static let backgroundHighlight = ...\n\n\tstatic let topEdgeHighlight = Theme.Gradient(\n\t\tstops: [\n\t\t\t.init(color: topEdgeHighlightColor, location: 0),\n\t\t\t.init(color: .clear, location: 0.15)\n\t\t],\n\t\ttype: .linear(startPoint: .top, endPoint: .bottom)\n\t)\n\t\n\tprivate static let topEdgeHighlightColor = Theme.Color(\n\t\tlight: .init(grayscale: 0, opacity: 0),\n\t\tdark: .init(grayscale: 1, opacity: 0.5)\n\t)\n\t.blendMode(.vibrant)\n}\n\nstruct CustomButtonStyle: ButtonStyle {\n\tprivate static let topEdgeHighlightWidth: CGFloat = 0.75\n\t\n\t// ...\n\t\n\tfunc makeBody(configuration: Configuration) -\u003e some View {\n\t\t\tconfiguration.label\n\t\t\t\t.foundation(.size(.button))\n\t\t\t\t.foundation(.foreground(.foreground(variant)))\n\t\t\t\t.foundation(.borderGradient(.topEdgeHighlight, width: Self.topEdgeHighlightWidth, placement: .inside))\n\t\t\t\t.foundation(.backgroundGradient(.backgroundHighlight), bypass: !isShowingBackgroundHighlight)\n\t\t\t\t.foundation(.background(.background(variant, isPressed: isPressed)))\n\t\t\t\t.foundation(.concentricRoundedRectangle(.small))\n\t}\n\t// ...\n}\n```\n\n\u003cdiv align=\"center\"\u003e\n\t\u003cimg \n\t\tsrc=\"Documentation.docc/Resources/ReadmeSample/Images/readme_sample_03.jpg\" \n\t\talt=\"Step 3 - Details\"\n\t\twidth=400\n\t\u003e\n\u003c/div\u003e\n\n## Done!\nYour button now features a polished, native-like appearance that:\n- Seamlessly adapts to both light and dark modes\n- Features subtle gradient highlights on the background and edges\n- Provides appropriate visual feedback for press states\n- Maintains consistent styling with FoundationUI's theme tokens\n\nThis example illustrates how FoundationUI's modifiers and theme system collaborate to create sophisticated, maintainable UI components. \nBy separating style tokens into Theme extensions and utilizing features like DynamicColor and DynamicGradient, you can craft reusable components that naturally integrate with the platform while keeping your code tidy and organized.\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n# Roadmap\n\n- [ ] Changelog\n- [ ] Tests\n\t- [ ] DynamicColor / ColorComponents\n\t- [ ] Modifiers\n\t- [ ] Variables\n- [ ] Code Documentation: DynamicColor / ColorComponent inits and methods\n- [ ] Code Documentation: Modifiers\n- [ ] Documentation: Basic Interactive Tutorials\n\t- [ ] How to extend theme (`Color`, `Padding`, `Size`, `Font`, `Radius`)\n\t- [ ] How to create tokens with state (`isPressed`, `isHovered`, etc.)\n\t- [ ] How to work with nested radii (`DynamicRoundedRectangle`)\n\t- [ ] Cross platform design system\n\t- [ ] How to use default theme\n- [ ] Documentation: Advanced Interactive Tutorials\n\t- [ ] Theme scope\n\t- [ ] Create sharable themes\n\t- [ ] Advanced features of the framework\n\t- [ ] Extending the features of the framework\n- [ ] watchOS support\n- [ ] Add OKLCH support\n","funding_links":["https://github.com/sponsors/artlasovsky"],"categories":["Swift"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartlasovsky%2Ffoundation-ui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fartlasovsky%2Ffoundation-ui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartlasovsky%2Ffoundation-ui/lists"}