mirror of
https://github.com/phranck/TUIkit.git
synced 2026-06-20 09:54:37 +00:00
Merge pull request #4 from phranck/feature/docc-documentation
Feature/docc documentation
This commit is contained in:
+24
-33
@@ -1,57 +1,48 @@
|
||||
name: Build and Deploy DocC Documentation
|
||||
name: Build and Deploy DocC
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
branches: [main]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-and-deploy-docs:
|
||||
runs-on: macos-latest
|
||||
build:
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- name: Checkout code
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check Swift version
|
||||
run: swift --version
|
||||
|
||||
- name: Build documentation
|
||||
- name: Build DocC documentation
|
||||
run: |
|
||||
xcrun docc convert TUIKit.docc \
|
||||
--output-path ./docs
|
||||
swift package --allow-writing-to-directory docs-output \
|
||||
generate-documentation \
|
||||
--target TUIKit \
|
||||
--output-path docs-output \
|
||||
--transform-for-static-hosting
|
||||
|
||||
- name: Commit and push documentation
|
||||
run: |
|
||||
git config --local user.email "action@github.com"
|
||||
git config --local user.name "GitHub Action"
|
||||
git add docs/
|
||||
git commit -m "docs: Generate DocC documentation" || echo "No changes to commit"
|
||||
git push
|
||||
- name: Add CNAME for custom domain
|
||||
run: echo "tuikit.layered.work" > docs-output/CNAME
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: docs-output
|
||||
|
||||
deploy:
|
||||
needs: build-and-deploy-docs
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v4
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: './docs'
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
name: Build and Deploy MkDocs Documentation
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- 'mkdocs.yml'
|
||||
- '.github/workflows/docs.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pip install --upgrade pip
|
||||
pip install mkdocs mkdocs-material
|
||||
|
||||
- name: Build documentation
|
||||
run: mkdocs build
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: 'site'
|
||||
|
||||
deploy:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
+2
-4
@@ -7,10 +7,8 @@ DerivedData/
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
||||
|
||||
# MkDocs generated files
|
||||
/site/
|
||||
|
||||
# Keep docs/ for documentation source files
|
||||
# DocC generated output
|
||||
/docs-output/
|
||||
|
||||
# Claude Code
|
||||
.claude/
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"originHash" : "d7399fa1b3074f6a5debef722dbf8a5621cd2171116ce5f4a91b6c3170b14ece",
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "swift-docc-plugin",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/swiftlang/swift-docc-plugin",
|
||||
"state" : {
|
||||
"revision" : "3e4f133a77e644a5812911a0513aeb7288b07d06",
|
||||
"version" : "1.4.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-docc-symbolkit",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/swiftlang/swift-docc-symbolkit",
|
||||
"state" : {
|
||||
"revision" : "b45d1f2ed151d057b54504d653e0da5552844e34",
|
||||
"version" : "1.0.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 3
|
||||
}
|
||||
@@ -20,6 +20,9 @@ let package = Package(
|
||||
targets: ["TUIKitExample"]
|
||||
),
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.4.3"),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "TUIKit"
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
# Architecture
|
||||
|
||||
Understand the layer model and rendering pipeline of TUIKit.
|
||||
|
||||
## Overview
|
||||
|
||||
TUIKit is structured in five layers, each building on the one below. This clean separation makes the framework easy to extend and maintain.
|
||||
|
||||
## Layer Model
|
||||
|
||||
### 1. App Layer
|
||||
|
||||
The ``App`` protocol is the entry point. It defines one or more scenes that make up your application. The internal `AppRunner` manages the main run loop, terminal setup, signal handling, and event dispatching.
|
||||
|
||||
```
|
||||
@main → App → AppRunner → Main Loop
|
||||
```
|
||||
|
||||
### 2. View Layer
|
||||
|
||||
Every UI component conforms to the ``View`` protocol. Views are composed declaratively using ``ViewBuilder``, which supports:
|
||||
|
||||
- Single and multiple child views (up to 10)
|
||||
- Conditionals (`if`, `if-else`, `if let`)
|
||||
- Loops (`for-in` via ``ForEach``)
|
||||
|
||||
Built-in views include ``Text``, ``Button``, ``Menu``, ``Alert``, ``Dialog``, ``Box``, ``Card``, ``Panel``, and layout primitives like ``VStack``, ``HStack``, ``ZStack``, and ``Spacer``.
|
||||
|
||||
### 3. Modifier Layer
|
||||
|
||||
View modifiers implement the ``ViewModifier`` protocol and operate at the ``FrameBuffer`` level. They transform rendered output — adding padding, borders, frames, backgrounds, or overlays.
|
||||
|
||||
```swift
|
||||
Text("Hello")
|
||||
.padding(1)
|
||||
.border(.rounded)
|
||||
.frame(width: 40)
|
||||
```
|
||||
|
||||
### 4. State & Environment Layer
|
||||
|
||||
- **``State``** — Mutable per-view state that triggers re-renders
|
||||
- **``Binding``** — Two-way connection to a value owned elsewhere
|
||||
- **``Environment``** — Values propagated down the view tree
|
||||
- **``AppStorage``** — Persistent key-value storage via `UserDefaults`
|
||||
|
||||
### 5. Rendering Layer
|
||||
|
||||
The rendering pipeline converts the view tree into terminal output:
|
||||
|
||||
1. **View tree traversal** — Each view produces a ``FrameBuffer``
|
||||
2. **Modifier application** — Modifiers transform buffers
|
||||
3. **ANSI rendering** — The `ANSIRenderer` converts colors and styles to escape codes
|
||||
4. **Terminal output** — The ``FrameBuffer`` lines are written to the terminal
|
||||
|
||||
## Event Loop
|
||||
|
||||
TUIKit runs a synchronous event loop:
|
||||
|
||||
```
|
||||
┌─────────────────────────┐
|
||||
│ Check resize/state │
|
||||
│ ↓ │
|
||||
│ Render view tree │
|
||||
│ ↓ │
|
||||
│ Read key event │
|
||||
│ ↓ │
|
||||
│ Dispatch to handlers │
|
||||
│ ↓ │
|
||||
│ Loop │
|
||||
└─────────────────────────┘
|
||||
```
|
||||
|
||||
Key events are dispatched in order:
|
||||
1. Status bar items (system and user)
|
||||
2. Registered key event handlers (from `onKeyPress`)
|
||||
3. Default handlers (quit, theme cycling, appearance cycling)
|
||||
|
||||
## Focus System
|
||||
|
||||
The ``FocusManager`` manages keyboard navigation between interactive elements. Views register as focusable, and the user navigates with Tab/Shift+Tab or arrow keys.
|
||||
@@ -0,0 +1,107 @@
|
||||
# Getting Started
|
||||
|
||||
Build your first terminal application with TUIKit.
|
||||
|
||||
## Overview
|
||||
|
||||
TUIKit is a Swift package that lets you create terminal user interfaces with a declarative, SwiftUI-like syntax. This guide walks you through setting up a project and building a simple app.
|
||||
|
||||
## Adding TUIKit to Your Project
|
||||
|
||||
Add TUIKit as a dependency in your `Package.swift`:
|
||||
|
||||
```swift
|
||||
// swift-tools-version: 6.0
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "MyTUIApp",
|
||||
platforms: [.macOS(.v10_15)],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/phranck/TUIKit.git", from: "0.1.0"),
|
||||
],
|
||||
targets: [
|
||||
.executableTarget(
|
||||
name: "MyTUIApp",
|
||||
dependencies: ["TUIKit"]
|
||||
),
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
## Creating Your First App
|
||||
|
||||
Create a `main.swift` file with the ``App`` protocol as your entry point:
|
||||
|
||||
```swift
|
||||
import TUIKit
|
||||
|
||||
@main
|
||||
struct MyApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("Welcome to TUIKit!")
|
||||
.bold()
|
||||
.foregroundColor(.cyan)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("Press 'q' to quit")
|
||||
.dim()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Using State
|
||||
|
||||
Add interactivity with the ``State`` property wrapper:
|
||||
|
||||
```swift
|
||||
struct CounterView: View {
|
||||
@State var count = 0
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("Count: \(count)")
|
||||
.bold()
|
||||
Button("Increment") {
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## One-Shot Rendering
|
||||
|
||||
For simple scripts that don't need a full app lifecycle, use ``renderOnce(content:)``:
|
||||
|
||||
```swift
|
||||
import TUIKit
|
||||
|
||||
renderOnce {
|
||||
VStack {
|
||||
Text("Hello, TUIKit!")
|
||||
.bold()
|
||||
.foregroundColor(.green)
|
||||
Divider()
|
||||
Text("Version \(tuiKitVersion)")
|
||||
.dim()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Learn about the framework's <doc:Architecture>
|
||||
- Explore <doc:StateManagement> for reactive UIs
|
||||
- Customize your app's look with <doc:ThemingGuide>
|
||||
@@ -0,0 +1,109 @@
|
||||
# State Management
|
||||
|
||||
Manage reactive state in your TUIKit application.
|
||||
|
||||
## Overview
|
||||
|
||||
TUIKit provides a state management system modeled after SwiftUI. When state changes, the view tree is automatically re-rendered.
|
||||
|
||||
## @State
|
||||
|
||||
Use ``State`` for simple values owned by a single view:
|
||||
|
||||
```swift
|
||||
struct CounterView: View {
|
||||
@State var count = 0
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("Count: \(count)")
|
||||
Button("Increment") {
|
||||
count += 1 // Triggers re-render
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Binding
|
||||
|
||||
``Binding`` provides a two-way connection to a value owned elsewhere. Use the `$` prefix on a `@State` property to get its binding:
|
||||
|
||||
```swift
|
||||
struct ParentView: View {
|
||||
@State var selectedIndex = 0
|
||||
|
||||
var body: some View {
|
||||
Menu(items: menuItems, selection: $selectedIndex)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Create constant bindings for previews or static values:
|
||||
|
||||
```swift
|
||||
let binding = Binding.constant(42)
|
||||
```
|
||||
|
||||
## @Environment
|
||||
|
||||
``Environment`` reads values propagated down the view hierarchy:
|
||||
|
||||
```swift
|
||||
struct MyView: View {
|
||||
@Environment(\.theme) var theme
|
||||
@Environment(\.statusBar) var statusBar
|
||||
|
||||
var body: some View {
|
||||
Text("Themed text")
|
||||
.foregroundColor(theme.foreground)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Defining Custom Environment Keys
|
||||
|
||||
```swift
|
||||
struct MyCustomKey: EnvironmentKey {
|
||||
static var defaultValue: String = "default"
|
||||
}
|
||||
|
||||
extension EnvironmentValues {
|
||||
var myCustomValue: String {
|
||||
get { self[MyCustomKey.self] }
|
||||
set { self[MyCustomKey.self] = newValue }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Inject values with the `.environment()` modifier:
|
||||
|
||||
```swift
|
||||
ContentView()
|
||||
.environment(\.myCustomValue, "custom")
|
||||
```
|
||||
|
||||
## @AppStorage
|
||||
|
||||
``AppStorage`` persists values across app launches using `UserDefaults`:
|
||||
|
||||
```swift
|
||||
struct SettingsView: View {
|
||||
@AppStorage("username") var username = "Guest"
|
||||
|
||||
var body: some View {
|
||||
Text("Hello, \(username)!")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## How Re-Rendering Works
|
||||
|
||||
TUIKit uses a single-threaded event loop. When a ``State`` value changes:
|
||||
|
||||
1. ``AppState/setNeedsRender()`` is called
|
||||
2. The main loop detects the change
|
||||
3. The entire view tree is re-rendered
|
||||
4. The new ``FrameBuffer`` output is written to the terminal
|
||||
|
||||
This is simple and predictable — no diffing, no virtual DOM, just full re-renders on every state change.
|
||||
@@ -0,0 +1,97 @@
|
||||
# Theming Guide
|
||||
|
||||
Customize the visual appearance of your TUIKit application with themes.
|
||||
|
||||
## Overview
|
||||
|
||||
TUIKit includes a full theming system with five built-in themes inspired by classic CRT terminals. Themes define semantic colors for backgrounds, foregrounds, accents, and UI elements.
|
||||
|
||||
## Built-in Themes
|
||||
|
||||
| Theme | Struct | Inspiration |
|
||||
|-------|--------|-------------|
|
||||
| Green Phosphor | ``GreenPhosphorTheme`` | IBM 5151, Apple II |
|
||||
| Amber Phosphor | ``AmberPhosphorTheme`` | IBM 3278, Wyse 50 |
|
||||
| White Phosphor | ``WhitePhosphorTheme`` | DEC VT100, VT220 |
|
||||
| Red Phosphor | ``RedPhosphorTheme`` | Military terminals |
|
||||
| ncurses | ``NCursesTheme`` | Classic ncurses apps |
|
||||
|
||||
## Using Themes
|
||||
|
||||
### Via ThemeManager
|
||||
|
||||
Access the ``ThemeManager`` through the environment to cycle or set themes:
|
||||
|
||||
```swift
|
||||
struct MyView: View {
|
||||
@Environment(\.themeManager) var themeManager
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("Current: \(themeManager.currentThemeName)")
|
||||
Button("Next Theme") {
|
||||
themeManager.cycleTheme()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Via Environment
|
||||
|
||||
Set a theme for a view and all its descendants:
|
||||
|
||||
```swift
|
||||
ContentView()
|
||||
.theme(AmberPhosphorTheme())
|
||||
```
|
||||
|
||||
### Theme Colors in Views
|
||||
|
||||
Use ``Color/theme`` to access the current theme's colors:
|
||||
|
||||
```swift
|
||||
Text("Styled text")
|
||||
.foregroundColor(.theme.foreground)
|
||||
.backgroundColor(.theme.backgroundSecondary)
|
||||
```
|
||||
|
||||
Or read the theme directly from the environment:
|
||||
|
||||
```swift
|
||||
@Environment(\.theme) var theme
|
||||
|
||||
Text("Hello").foregroundColor(theme.accent)
|
||||
```
|
||||
|
||||
## Creating Custom Themes
|
||||
|
||||
Implement the ``Theme`` protocol:
|
||||
|
||||
```swift
|
||||
struct MyCustomTheme: Theme {
|
||||
let id = "custom"
|
||||
let name = "Custom"
|
||||
|
||||
let background = Color.hex(0x1A1A2E)
|
||||
let foreground = Color.hex(0xE0E0E0)
|
||||
let accent = Color.hex(0x00D4FF)
|
||||
|
||||
// ... implement remaining required properties
|
||||
// Many have default implementations via Theme extension
|
||||
}
|
||||
```
|
||||
|
||||
## Theme Color Properties
|
||||
|
||||
The ``Theme`` protocol defines these semantic color categories:
|
||||
|
||||
- **Backgrounds**: `background`, `backgroundSecondary`, `backgroundTertiary`
|
||||
- **Foregrounds**: `foreground`, `foregroundSecondary`, `foregroundTertiary`
|
||||
- **Accents**: `accent`, `accentSecondary`
|
||||
- **Semantic**: `success`, `warning`, `error`, `info`
|
||||
- **UI Elements**: `border`, `borderFocused`, `separator`, `selection`, `disabled`
|
||||
- **Status Bar**: `statusBarBackground`, `statusBarForeground`, `statusBarHighlight`
|
||||
- **Containers**: `containerBackground`, `containerHeaderBackground`, `buttonBackground`
|
||||
|
||||
Many of these have default implementations that derive from the primary colors, so a minimal theme only needs to define a handful of values.
|
||||
@@ -0,0 +1,148 @@
|
||||
# ``TUIKit``
|
||||
|
||||
A declarative, SwiftUI-like framework for building Terminal User Interfaces in Swift.
|
||||
|
||||
@Metadata {
|
||||
@DisplayName("TUIKit")
|
||||
}
|
||||
|
||||
## Overview
|
||||
|
||||
TUIKit lets you build terminal applications using a familiar, declarative syntax inspired by SwiftUI. No ncurses, no C dependencies — pure Swift.
|
||||
|
||||
```swift
|
||||
@main
|
||||
struct MyApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
VStack {
|
||||
Text("Hello, TUIKit!")
|
||||
.bold()
|
||||
.foregroundColor(.cyan)
|
||||
Button("Press me") {
|
||||
// handle action
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Declarative syntax** — Build UIs with `VStack`, `HStack`, `Text`, `Button`, and more
|
||||
- **SwiftUI-like API** — `@State`, `@Environment`, `@ViewBuilder`, modifiers
|
||||
- **Theming system** — 5 built-in phosphor themes with full RGB color support
|
||||
- **Focus management** — Keyboard-driven navigation between interactive elements
|
||||
- **Status bar** — Configurable shortcut bar with context stack
|
||||
- **No dependencies** — Pure Swift, no ncurses or other C libraries
|
||||
- **Cross-platform** — macOS and Linux
|
||||
|
||||
## Topics
|
||||
|
||||
### Essentials
|
||||
|
||||
- <doc:GettingStarted>
|
||||
- <doc:Architecture>
|
||||
|
||||
### App Structure
|
||||
|
||||
- ``App``
|
||||
- ``Scene``
|
||||
- ``WindowGroup``
|
||||
|
||||
### Views
|
||||
|
||||
- ``View``
|
||||
- ``Text``
|
||||
- ``Button``
|
||||
- ``Menu``
|
||||
- ``Alert``
|
||||
- ``Dialog``
|
||||
|
||||
### Layout
|
||||
|
||||
- ``VStack``
|
||||
- ``HStack``
|
||||
- ``ZStack``
|
||||
- ``Spacer``
|
||||
- ``ForEach``
|
||||
|
||||
### Containers
|
||||
|
||||
- ``Box``
|
||||
- ``Card``
|
||||
- ``Panel``
|
||||
- ``ContainerView``
|
||||
|
||||
### State Management
|
||||
|
||||
- <doc:StateManagement>
|
||||
- ``State``
|
||||
- ``Binding``
|
||||
- ``AppState``
|
||||
|
||||
### Environment
|
||||
|
||||
- ``Environment``
|
||||
- ``EnvironmentKey``
|
||||
- ``EnvironmentValues``
|
||||
- ``EnvironmentStorage``
|
||||
|
||||
### Theming
|
||||
|
||||
- <doc:ThemingGuide>
|
||||
- ``Theme``
|
||||
- ``ThemeManager``
|
||||
- ``ThemeRegistry``
|
||||
- ``ThemeColors``
|
||||
- ``GreenPhosphorTheme``
|
||||
- ``AmberPhosphorTheme``
|
||||
- ``WhitePhosphorTheme``
|
||||
- ``RedPhosphorTheme``
|
||||
- ``NCursesTheme``
|
||||
|
||||
### Colors
|
||||
|
||||
- ``Color``
|
||||
- ``ANSIColor``
|
||||
|
||||
### View Composition
|
||||
|
||||
- ``ViewBuilder``
|
||||
- ``ViewModifier``
|
||||
- ``ModifiedView``
|
||||
|
||||
### Appearance
|
||||
|
||||
- ``Appearance``
|
||||
- ``AppearanceManager``
|
||||
- ``BorderStyle``
|
||||
|
||||
### Focus System
|
||||
|
||||
- ``FocusManager``
|
||||
|
||||
### Status Bar
|
||||
|
||||
- ``StatusBar``
|
||||
- ``StatusBarState``
|
||||
- ``StatusBarItem``
|
||||
- ``StatusBarItemProtocol``
|
||||
- ``StatusBarStyle``
|
||||
- ``StatusBarAlignment``
|
||||
|
||||
### Input Handling
|
||||
|
||||
- ``KeyEvent``
|
||||
- ``QuitBehavior``
|
||||
|
||||
### Rendering
|
||||
|
||||
- ``Renderable``
|
||||
- ``FrameBuffer``
|
||||
- ``RenderContext``
|
||||
|
||||
### Persistence
|
||||
|
||||
- ``AppStorage``
|
||||
@@ -1,256 +0,0 @@
|
||||
# Appearance System
|
||||
|
||||
Learn about the 5 structural appearance styles for rendering borders and containers.
|
||||
|
||||
## Overview
|
||||
|
||||
TUIKit provides 5 appearance styles that control how borders and containers are rendered:
|
||||
|
||||
- **Line**: Simple ASCII lines
|
||||
- **Rounded**: Rounded corners (default)
|
||||
- **DoubleLine**: Double-line borders
|
||||
- **Heavy**: Heavy/bold borders
|
||||
- **Block**: Half-block Unicode characters for solid appearance
|
||||
|
||||
## Appearance Styles
|
||||
|
||||
### Line Appearance
|
||||
|
||||
Simple single-line ASCII borders:
|
||||
|
||||
```swift
|
||||
VStack {
|
||||
Text("Content")
|
||||
}
|
||||
.border(.line)
|
||||
```
|
||||
|
||||
Characters used:
|
||||
- Horizontal: `-`
|
||||
- Vertical: `|`
|
||||
- Corners: `+`
|
||||
|
||||
### Rounded Appearance
|
||||
|
||||
Rounded corners (default appearance):
|
||||
|
||||
```swift
|
||||
VStack {
|
||||
Text("Content")
|
||||
}
|
||||
.border(.rounded)
|
||||
```
|
||||
|
||||
Characters used:
|
||||
- Top-left: `╭`
|
||||
- Top-right: `╮`
|
||||
- Bottom-left: `╰`
|
||||
- Bottom-right: `╯`
|
||||
- Horizontal: `─`
|
||||
- Vertical: `│`
|
||||
|
||||
### DoubleLine Appearance
|
||||
|
||||
Double-line borders for emphasis:
|
||||
|
||||
```swift
|
||||
VStack {
|
||||
Text("Content")
|
||||
}
|
||||
.border(.doubleLine)
|
||||
```
|
||||
|
||||
Characters used:
|
||||
- Top-left: `╔`
|
||||
- Top-right: `╗`
|
||||
- Bottom-left: `╚`
|
||||
- Bottom-right: `╝`
|
||||
- Horizontal: `═`
|
||||
- Vertical: `║`
|
||||
|
||||
### Heavy Appearance
|
||||
|
||||
Bold/heavy borders:
|
||||
|
||||
```swift
|
||||
VStack {
|
||||
Text("Content")
|
||||
}
|
||||
.border(.heavy)
|
||||
```
|
||||
|
||||
Characters used:
|
||||
- Top-left: `┏`
|
||||
- Top-right: `┓`
|
||||
- Bottom-left: `┗`
|
||||
- Bottom-right: `┛`
|
||||
- Horizontal: `━`
|
||||
- Vertical: `┃`
|
||||
|
||||
### Block Appearance
|
||||
|
||||
Modern half-block Unicode characters for a solid, integrated look:
|
||||
|
||||
```swift
|
||||
VStack {
|
||||
Text("Content")
|
||||
}
|
||||
.border(.block)
|
||||
```
|
||||
|
||||
Special rendering:
|
||||
- **Top border**: `▄` (lower half-block) with foreground = container background
|
||||
- **Side borders**: `█` (full block) with foreground = container background
|
||||
- **Bottom border**: `▀` (upper half-block) with foreground = container background
|
||||
- **Content**: Filled with container background color
|
||||
- Uses full-block characters to create solid visual edges
|
||||
|
||||
The block appearance creates a seamless, filled container that appears integrated with the terminal background.
|
||||
|
||||
## Setting Global Appearance
|
||||
|
||||
Use the appearance environment to set the default for all components:
|
||||
|
||||
```swift
|
||||
@main
|
||||
struct MyApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
.environment(\.appearance, .block)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Cycling Appearances
|
||||
|
||||
The example app supports appearance cycling with the `a` key:
|
||||
|
||||
```swift
|
||||
@main
|
||||
struct ExampleApp: App {
|
||||
@State private var currentAppearance: Appearance = .rounded
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
.environment(\.appearance, currentAppearance)
|
||||
.statusBarItems {
|
||||
StatusBarItem(
|
||||
label: "Appearance",
|
||||
shortcut: Shortcut.letter("a"),
|
||||
action: {
|
||||
currentAppearance = currentAppearance.next()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Using Appearance with Containers
|
||||
|
||||
All container views respect the appearance setting:
|
||||
|
||||
```swift
|
||||
// Using Panel with different appearances
|
||||
VStack {
|
||||
Panel(title: "Settings") {
|
||||
Text("Configure options here")
|
||||
}
|
||||
.border(.rounded)
|
||||
|
||||
Panel(title: "Status") {
|
||||
Text("System information")
|
||||
}
|
||||
.border(.block)
|
||||
|
||||
Card {
|
||||
Text("Card content")
|
||||
}
|
||||
.border(.heavy)
|
||||
}
|
||||
```
|
||||
|
||||
## BorderStyle
|
||||
|
||||
Use the ``BorderStyle`` type to customize individual borders:
|
||||
|
||||
```swift
|
||||
extension View {
|
||||
func border(
|
||||
_ style: BorderStyle = .default,
|
||||
width: Int = 1,
|
||||
color: Color = .theme.border,
|
||||
appearance: Appearance = .rounded
|
||||
) -> some View {
|
||||
// Returns bordered view
|
||||
}
|
||||
}
|
||||
|
||||
// Custom border
|
||||
Text("Custom border")
|
||||
.border(.custom, width: 2, color: .theme.accent)
|
||||
```
|
||||
|
||||
## Appearance in Components
|
||||
|
||||
Different components use appearance differently:
|
||||
|
||||
### Text with Border
|
||||
|
||||
```swift
|
||||
Text("Bordered text")
|
||||
.border(.block)
|
||||
```
|
||||
|
||||
### Card with Appearance
|
||||
|
||||
```swift
|
||||
Card {
|
||||
Text("Content")
|
||||
}
|
||||
.border(.rounded)
|
||||
```
|
||||
|
||||
### Panel with Title
|
||||
|
||||
```swift
|
||||
Panel(title: "Title") {
|
||||
Text("Content")
|
||||
}
|
||||
.border(.block)
|
||||
```
|
||||
|
||||
### Alerts and Dialogs
|
||||
|
||||
Alerts automatically use the current appearance:
|
||||
|
||||
```swift
|
||||
Alert(
|
||||
title: "Confirm",
|
||||
message: "Are you sure?",
|
||||
borderColor: .theme.border,
|
||||
titleColor: .theme.accent
|
||||
)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Consistency**: Choose one appearance and stick with it
|
||||
2. **Theme integration**: Use theme colors for borders
|
||||
3. **Readability**: Ensure sufficient contrast for borders
|
||||
4. **Performance**: Complex borders render efficiently
|
||||
5. **Testing**: Test appearance on various terminal sizes
|
||||
|
||||
## Related Topics
|
||||
|
||||
- ``Appearance``
|
||||
- ``BorderStyle``
|
||||
- ``View/border(_:style:)-4xzvw``
|
||||
- <doc:Theming>
|
||||
- ``Panel``
|
||||
- ``Card``
|
||||
- ``ContainerView``
|
||||
@@ -1,258 +0,0 @@
|
||||
# Architecture Overview
|
||||
|
||||
Understand the architecture and design patterns that power TUIKit.
|
||||
|
||||
## Core Design Principles
|
||||
|
||||
TUIKit follows these key principles:
|
||||
|
||||
1. **Declarative UI**: Describe what you want, not how to build it
|
||||
2. **Composability**: Build complex UIs from simple, reusable components
|
||||
3. **Value Semantics**: Views are lightweight value types, not stateful objects
|
||||
4. **Data Flow**: Clear, unidirectional data flow through Environment and State
|
||||
5. **Pure Swift**: No external dependencies or C bindings
|
||||
|
||||
## The View System
|
||||
|
||||
### View Protocol
|
||||
|
||||
The `View` protocol is the foundation of TUIKit:
|
||||
|
||||
```swift
|
||||
public protocol View {
|
||||
associatedtype Body: View
|
||||
@ViewBuilder var body: Body { get }
|
||||
}
|
||||
```
|
||||
|
||||
Views are **not** UI elements—they're descriptions of UI that get rendered when needed. This enables:
|
||||
- Lightweight composition
|
||||
- Efficient updates
|
||||
- Declarative syntax
|
||||
|
||||
### Primitive vs Composite Views
|
||||
|
||||
**Primitive Views** directly render content:
|
||||
- Conform to `Renderable`
|
||||
- Have `body: Never`
|
||||
- Examples: `Text`, `Button`, `Menu`
|
||||
|
||||
**Composite Views** combine other views:
|
||||
- Define a `body` property
|
||||
- Renderer walks the tree recursively
|
||||
- Examples: `VStack`, `HStack`, `Card`
|
||||
|
||||
### Rendering Pipeline
|
||||
|
||||
1. **View Tree**: User creates view hierarchy
|
||||
2. **Traversal**: Renderer walks tree depth-first
|
||||
3. **Rendering**: Primitive views produce `FrameBuffer` character data
|
||||
4. **Compositing**: Overlays blend on top with character-level precision
|
||||
5. **Output**: Terminal renders the final buffer
|
||||
|
||||
## State Management Architecture
|
||||
|
||||
### Local State (@State)
|
||||
|
||||
Stored in the view itself:
|
||||
```swift
|
||||
@State var count: Int = 0
|
||||
```
|
||||
|
||||
When `@State` changes, the view re-renders automatically.
|
||||
|
||||
### Environment (Top-Down)
|
||||
|
||||
Parent views pass data to children:
|
||||
|
||||
```swift
|
||||
@Environment(\.theme) var theme
|
||||
|
||||
// Theme flows from App → all children
|
||||
```
|
||||
|
||||
### Preferences (Bottom-Up)
|
||||
|
||||
Children can propagate values to parents (rarely used in TUIKit).
|
||||
|
||||
### Storage (@AppStorage, @SceneStorage)
|
||||
|
||||
Persistent storage via:
|
||||
- **@AppStorage**: UserDefaults (macOS) or JSON file (Linux)
|
||||
- **@SceneStorage**: Per-scene state restoration
|
||||
|
||||
## Data Flow Pattern
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ App or Scene │
|
||||
│ @AppStorage, @State, Environment │
|
||||
└────────┬────────────────────────────┘
|
||||
│ passes theme, data
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ Composite Views (VStack, etc) │
|
||||
│ pass Environment to children │
|
||||
└────────┬────────────────────────────┘
|
||||
│ may use @State locally
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ Primitive Views (Text, Button) │
|
||||
│ render to FrameBuffer │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Theme and Appearance System
|
||||
|
||||
### Theme Protocol
|
||||
|
||||
Defines semantic colors:
|
||||
|
||||
```swift
|
||||
public protocol Theme {
|
||||
var background: Color { get }
|
||||
var accent: Color { get }
|
||||
// ... other colors
|
||||
}
|
||||
```
|
||||
|
||||
### Appearance Protocol
|
||||
|
||||
Defines structural styles:
|
||||
|
||||
```swift
|
||||
public enum Appearance {
|
||||
case line, rounded, doubleLine, heavy, block
|
||||
}
|
||||
```
|
||||
|
||||
Both are passed through Environment, enabling:
|
||||
- Global theme switching
|
||||
- Dynamic appearance changes
|
||||
- Consistent styling across app
|
||||
|
||||
## Focus Management System
|
||||
|
||||
``FocusManager`` tracks which element has keyboard focus:
|
||||
|
||||
1. **Focus ID**: Each interactive element has a unique ID
|
||||
2. **Navigation**: Tab/Shift+Tab moves focus
|
||||
3. **Rendering**: Focused element shows visual indicator
|
||||
4. **Events**: Keyboard events route to focused element
|
||||
|
||||
```swift
|
||||
@Environment(\.focusManager) var focusManager
|
||||
|
||||
// Navigation automatically updates focusManager
|
||||
// onKeyPress receives keyboard events
|
||||
```
|
||||
|
||||
## Modifier System
|
||||
|
||||
Modifiers wrap views to add behavior:
|
||||
|
||||
```swift
|
||||
extension View {
|
||||
func padding(_ amount: Int) -> some View {
|
||||
ModifiedView(content: self, modifier: PaddingModifier(amount))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Modifiers compose:
|
||||
```swift
|
||||
Text("Hello")
|
||||
.bold() // Text → BoldView
|
||||
.padding(1) // BoldView → PaddedView
|
||||
.border(.rounded) // PaddedView → BorderedView
|
||||
```
|
||||
|
||||
## Component Library
|
||||
|
||||
### Container Views
|
||||
- `VStack`, `HStack`, `ZStack`: Layout primitives
|
||||
- `Card`, `Box`, `Panel`: Styled containers
|
||||
- `ContainerView`: Header/body/footer structure
|
||||
|
||||
### Interactive Views
|
||||
- `Button`: Clickable button with focus
|
||||
- `Menu`: Selection menu with keyboard
|
||||
- `Alert`, `Dialog`: Modal overlays
|
||||
|
||||
### Structural Views
|
||||
- `ForEach`: Render collections
|
||||
- `Text`: Display text
|
||||
- `Spacer`, `Divider`: Layout helpers
|
||||
|
||||
### Status Bar
|
||||
- `StatusBar`: Application status bar
|
||||
- `StatusBarItem`: Individual item
|
||||
- `Shortcut`: Keyboard shortcut display
|
||||
|
||||
## Rendering Engine
|
||||
|
||||
### FrameBuffer
|
||||
|
||||
Character-level buffer for compositing:
|
||||
- 2D array of characters and attributes
|
||||
- Supports color, styling (bold, italic, etc.)
|
||||
- Compositing for overlays
|
||||
|
||||
### ANSI Renderer
|
||||
|
||||
Converts buffer to ANSI escape codes:
|
||||
- Color codes (foreground/background)
|
||||
- Styling (bold, italic, underline)
|
||||
- Terminal state management
|
||||
|
||||
### Terminal Abstraction
|
||||
|
||||
Platform-specific terminal handling:
|
||||
- macOS: termios
|
||||
- Linux: termios via libc
|
||||
- Raw mode, alternate screen, signal handling
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
1. **Lazy Rendering**: Only visible areas render
|
||||
2. **Diff Optimization**: Only changed areas redraw
|
||||
3. **Buffer Reuse**: FrameBuffer recycled across frames
|
||||
4. **View Value Semantics**: Lightweight copying and discarding
|
||||
|
||||
## Error Handling
|
||||
|
||||
TUIKit uses Swift's error handling:
|
||||
- Fatal errors for programmer mistakes
|
||||
- Non-fatal errors for recovery scenarios
|
||||
- Storage backend errors are silenced (fallback to defaults)
|
||||
|
||||
## Platform Support
|
||||
|
||||
### macOS
|
||||
- Native UserDefaults for @AppStorage
|
||||
- Full terminal support
|
||||
- Modern Swift runtime
|
||||
|
||||
### Linux
|
||||
- JSON file storage for @AppStorage
|
||||
- glibc-based terminal support
|
||||
- XDG paths for configuration
|
||||
|
||||
## Future Extensibility
|
||||
|
||||
The architecture supports:
|
||||
- Custom storage backends
|
||||
- Custom themes
|
||||
- Custom appearances
|
||||
- Custom view components
|
||||
- Animation system (planned)
|
||||
|
||||
## Related Topics
|
||||
|
||||
- ``View``
|
||||
- ``Theme``
|
||||
- ``Appearance``
|
||||
- ``FocusManager``
|
||||
- ``FrameBuffer``
|
||||
- <doc:Rendering>
|
||||
- <doc:StateManagement>
|
||||
@@ -1,252 +0,0 @@
|
||||
# Focus Management
|
||||
|
||||
Understand how keyboard navigation and focus works in TUIKit.
|
||||
|
||||
## Overview
|
||||
|
||||
TUIKit provides a sophisticated focus management system that enables Tab/Shift+Tab navigation, keyboard shortcuts, and custom focus logic.
|
||||
|
||||
## The Focus Manager
|
||||
|
||||
``FocusManager`` manages which component currently has keyboard focus:
|
||||
|
||||
```swift
|
||||
@Environment(\.focusManager) var focusManager
|
||||
|
||||
Button("Click me") {
|
||||
// Handle click
|
||||
}
|
||||
.focused(focusID: "myButton")
|
||||
```
|
||||
|
||||
## Tab Navigation
|
||||
|
||||
By default, all focusable elements can be navigated with Tab and Shift+Tab:
|
||||
|
||||
- **Tab**: Move focus to the next element
|
||||
- **Shift+Tab**: Move focus to the previous element
|
||||
- **Enter/Space**: Activate focused button
|
||||
|
||||
```swift
|
||||
VStack(spacing: 1) {
|
||||
Text("Navigation")
|
||||
|
||||
Button("First") { }
|
||||
Button("Second") { }
|
||||
Button("Third") { }
|
||||
}
|
||||
```
|
||||
|
||||
Users can Tab between the buttons in order.
|
||||
|
||||
## Focus Indicators
|
||||
|
||||
Focusable elements show a focus indicator when active:
|
||||
|
||||
```swift
|
||||
Button("Focusable") {
|
||||
print("Activated")
|
||||
}
|
||||
```
|
||||
|
||||
The button displays:
|
||||
- A border around the element
|
||||
- Visual highlight (usually arrow prefix: `▸`)
|
||||
- Theme accent color
|
||||
|
||||
## Programmatic Focus
|
||||
|
||||
Set focus programmatically:
|
||||
|
||||
```swift
|
||||
struct Settings: View {
|
||||
@State private var focusedField: String?
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 1) {
|
||||
Button("First") { focusedField = "first" }
|
||||
.focused(focusID: "first", focused: focusedField == "first")
|
||||
|
||||
Button("Second") { focusedField = "second" }
|
||||
.focused(focusID: "second", focused: focusedField == "second")
|
||||
|
||||
Button("Reset") { focusedField = nil }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Keyboard Events
|
||||
|
||||
Handle keyboard events with `onKeyPress`:
|
||||
|
||||
```swift
|
||||
struct App: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
ContentView()
|
||||
.onKeyPress { event in
|
||||
if event.key == .character("h") && event.modifiers.contains(.ctrl) {
|
||||
print("Help requested")
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Key Event Structure
|
||||
|
||||
``KeyEvent`` contains:
|
||||
|
||||
- **key**: The key pressed (character, arrow, enter, etc.)
|
||||
- **modifiers**: Ctrl, Shift, Alt flags
|
||||
- **raw**: Raw terminal escape sequence
|
||||
|
||||
### Special Keys
|
||||
|
||||
Handle special keys like arrows and function keys:
|
||||
|
||||
```swift
|
||||
.onKeyPress { event in
|
||||
switch event.key {
|
||||
case .up:
|
||||
print("Arrow up")
|
||||
case .down:
|
||||
print("Arrow down")
|
||||
case .left:
|
||||
print("Arrow left")
|
||||
case .right:
|
||||
print("Arrow right")
|
||||
case .enter:
|
||||
print("Enter pressed")
|
||||
case .escape:
|
||||
print("Escape pressed")
|
||||
case .tab:
|
||||
print("Tab pressed")
|
||||
case .character(let char):
|
||||
print("Character: \(char)")
|
||||
default:
|
||||
break
|
||||
}
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
## Focusable Protocol
|
||||
|
||||
Components conform to ``Focusable`` to support focus:
|
||||
|
||||
```swift
|
||||
public protocol Focusable {
|
||||
var focusID: String? { get }
|
||||
var isFocused: Bool { get }
|
||||
}
|
||||
```
|
||||
|
||||
Button, Menu, and other interactive components automatically implement this.
|
||||
|
||||
## Custom Focus Logic
|
||||
|
||||
Create custom focus behavior:
|
||||
|
||||
```swift
|
||||
struct CustomMenu: View {
|
||||
@State private var selectedIndex: Int = 0
|
||||
let items: [String]
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
ForEach(Array(items.enumerated()), id: \.offset) { index, item in
|
||||
Text(item)
|
||||
.padding(1)
|
||||
.background(selectedIndex == index ? .theme.accent : .clear)
|
||||
}
|
||||
}
|
||||
.onKeyPress { event in
|
||||
switch event.key {
|
||||
case .up:
|
||||
selectedIndex = max(0, selectedIndex - 1)
|
||||
return true
|
||||
case .down:
|
||||
selectedIndex = min(items.count - 1, selectedIndex + 1)
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Focus in Modals
|
||||
|
||||
Focus works correctly with modals and overlays:
|
||||
|
||||
```swift
|
||||
@State var showDialog: Bool = false
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
if showDialog {
|
||||
Alert(
|
||||
title: "Confirm",
|
||||
message: "Continue?"
|
||||
) {
|
||||
VStack(spacing: 1) {
|
||||
Button("Yes") { showDialog = false }
|
||||
Button("No") { showDialog = false }
|
||||
}
|
||||
}
|
||||
.modal()
|
||||
}
|
||||
|
||||
Button("Show Dialog") { showDialog = true }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When a modal appears, focus automatically moves to the first focusable element in the modal.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Tab order**: Arrange elements logically for Tab navigation
|
||||
2. **Feedback**: Always provide visual feedback for focused elements
|
||||
3. **Shortcuts**: Implement keyboard shortcuts for common actions
|
||||
4. **Testing**: Test focus behavior with keyboard navigation
|
||||
5. **Accessibility**: Consider users with motor impairments who rely on keyboard
|
||||
|
||||
## Status Bar Integration
|
||||
|
||||
Status bar items show keyboard shortcuts:
|
||||
|
||||
```swift
|
||||
.statusBarItems {
|
||||
StatusBarItem(
|
||||
label: "Help",
|
||||
shortcut: Shortcut.letter("?"),
|
||||
action: {
|
||||
print("Show help")
|
||||
}
|
||||
)
|
||||
|
||||
StatusBarItem(
|
||||
label: "Quit",
|
||||
shortcut: Shortcut.letter("q"),
|
||||
action: {
|
||||
print("Exit app")
|
||||
}
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Related Topics
|
||||
|
||||
- ``FocusManager``
|
||||
- ``KeyEvent``
|
||||
- ``Focusable``
|
||||
- ``View/onKeyPress(_:)``
|
||||
- ``StatusBar``
|
||||
- ``StatusBarItem``
|
||||
@@ -1,180 +0,0 @@
|
||||
# Getting Started with TUIKit
|
||||
|
||||
Create your first terminal user interface in minutes.
|
||||
|
||||
## Installation
|
||||
|
||||
### Using Swift Package Manager
|
||||
|
||||
Add TUIKit to your `Package.swift`:
|
||||
|
||||
```swift
|
||||
.package(url: "https://github.com/anthropics/SwiftTUI.git", from: "0.1.0")
|
||||
```
|
||||
|
||||
Or via Xcode: File > Add Packages > Enter repository URL
|
||||
|
||||
## Creating Your First App
|
||||
|
||||
### 1. Define Your App
|
||||
|
||||
Every TUIKit app needs an `@main` entry point that conforms to the `App` protocol:
|
||||
|
||||
```swift
|
||||
import TUIKit
|
||||
|
||||
@main
|
||||
struct HelloApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
Text("Hello, TUIKit!")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Add Some Layout
|
||||
|
||||
Use `VStack` and `HStack` to organize your content:
|
||||
|
||||
```swift
|
||||
@main
|
||||
struct LayoutApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
VStack(spacing: 1) {
|
||||
Text("Welcome")
|
||||
.bold()
|
||||
|
||||
Text("Build terminal UIs in Swift")
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("Press 'q' to quit")
|
||||
.foregroundColor(.theme.foregroundSecondary)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Make It Interactive
|
||||
|
||||
Add buttons and state to create interactive interfaces:
|
||||
|
||||
```swift
|
||||
import TUIKit
|
||||
|
||||
@main
|
||||
struct InteractiveApp: App {
|
||||
@State var count: Int = 0
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
VStack(spacing: 1) {
|
||||
Text("Counter: \(count)")
|
||||
.bold()
|
||||
|
||||
HStack(spacing: 2) {
|
||||
Button("Increment") { count += 1 }
|
||||
Button("Decrement") { count = max(0, count - 1) }
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Running Your App
|
||||
|
||||
### From Command Line
|
||||
|
||||
```bash
|
||||
swift run
|
||||
```
|
||||
|
||||
### With a Custom Executable Name
|
||||
|
||||
Add to `Package.swift`:
|
||||
|
||||
```swift
|
||||
.executableTarget(
|
||||
name: "MyApp",
|
||||
dependencies: [.product(name: "TUIKit", package: "SwiftTUI")]
|
||||
)
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```bash
|
||||
swift run MyApp
|
||||
```
|
||||
|
||||
## Understanding the Basics
|
||||
|
||||
### Views
|
||||
|
||||
Everything in TUIKit is a `View`. Views are lightweight, composable units that render content to the terminal.
|
||||
|
||||
Common views:
|
||||
- **`Text`**: Display text with optional styling
|
||||
- **`Button`**: Interactive button with action handler
|
||||
- **`VStack`**: Arrange views vertically
|
||||
- **`HStack`**: Arrange views horizontally
|
||||
- **`Spacer`**: Fill available space
|
||||
|
||||
### State Management
|
||||
|
||||
Use `@State` to make your views interactive:
|
||||
|
||||
```swift
|
||||
@State var isVisible: Bool = true
|
||||
|
||||
VStack {
|
||||
if isVisible {
|
||||
Text("Visible")
|
||||
}
|
||||
Button("Toggle") { isVisible.toggle() }
|
||||
}
|
||||
```
|
||||
|
||||
### Modifiers
|
||||
|
||||
Customize views with modifiers:
|
||||
|
||||
```swift
|
||||
Text("Hello")
|
||||
.bold()
|
||||
.foregroundColor(.theme.accent)
|
||||
.padding(1)
|
||||
.border(.rounded)
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Explore the <doc:ViewHierarchy> to understand component organization
|
||||
- Learn <doc:StateManagement> for complex state scenarios
|
||||
- Discover <doc:Theming> to customize colors and appearance
|
||||
- Check out <doc:Modifiers> for all available styling options
|
||||
- Try <doc:BuildYourFirstApp> tutorial for step-by-step guidance
|
||||
|
||||
## Key Bindings
|
||||
|
||||
By default, TUIKit apps support:
|
||||
- **`q`**: Quit the application
|
||||
- **`t`**: Cycle through themes
|
||||
- **`a`**: Cycle through appearance styles
|
||||
- **`?`**: Show help
|
||||
|
||||
See ``KeyEvent`` for custom keyboard handling.
|
||||
|
||||
## Terminal Requirements
|
||||
|
||||
- Minimum 80x24 character terminal
|
||||
- ANSI color support (256 colors recommended)
|
||||
- UTF-8 encoding
|
||||
- Supports: macOS Terminal, iTerm2, Kitty, and Linux terminals (gnome-terminal, konsole, etc.)
|
||||
@@ -1,340 +0,0 @@
|
||||
# View Modifiers
|
||||
|
||||
Learn how to use modifiers to customize the appearance and behavior of views.
|
||||
|
||||
## Overview
|
||||
|
||||
Modifiers are methods that return a modified copy of a view. Chain them together to build complex layouts and styling:
|
||||
|
||||
```swift
|
||||
Text("Hello")
|
||||
.bold()
|
||||
.foregroundColor(.theme.accent)
|
||||
.padding(1)
|
||||
.border(.rounded)
|
||||
```
|
||||
|
||||
## Layout Modifiers
|
||||
|
||||
### padding(_:)
|
||||
|
||||
Add padding around content:
|
||||
|
||||
```swift
|
||||
Text("Content")
|
||||
.padding() // Default 1 unit
|
||||
.padding(2) // 2 units all sides
|
||||
.padding(.top, 1) // 1 unit top
|
||||
.padding(.horizontal, 2) // 2 units left/right
|
||||
```
|
||||
|
||||
### frame(width:height:alignment:)
|
||||
|
||||
Set fixed size:
|
||||
|
||||
```swift
|
||||
Text("Fixed")
|
||||
.frame(width: 20, height: 5)
|
||||
|
||||
Button("Button")
|
||||
.frame(width: 15)
|
||||
```
|
||||
|
||||
### frame(minWidth:maxWidth:minHeight:maxHeight:)
|
||||
|
||||
Set flexible size constraints:
|
||||
|
||||
```swift
|
||||
Text("Flexible")
|
||||
.frame(minWidth: 10, maxWidth: 50)
|
||||
.frame(minHeight: 3, maxHeight: 10)
|
||||
|
||||
Text("Fill available space")
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
```
|
||||
|
||||
## Color Modifiers
|
||||
|
||||
### foregroundColor(_:)
|
||||
|
||||
Set text color:
|
||||
|
||||
```swift
|
||||
Text("Colored")
|
||||
.foregroundColor(.theme.accent)
|
||||
|
||||
Text("Green")
|
||||
.foregroundColor(.ansi(.brightGreen))
|
||||
|
||||
Text("Custom")
|
||||
.foregroundColor(.hex("FF5500"))
|
||||
```
|
||||
|
||||
### background(_:)
|
||||
|
||||
Add background color:
|
||||
|
||||
```swift
|
||||
Text("Background")
|
||||
.background(.theme.accent)
|
||||
.foregroundColor(.theme.background)
|
||||
```
|
||||
|
||||
## Text Styling
|
||||
|
||||
### Bold, Italic, Underline
|
||||
|
||||
```swift
|
||||
Text("Bold").bold()
|
||||
Text("Italic").italic()
|
||||
Text("Underline").underlined()
|
||||
Text("Strikethrough").strikethrough()
|
||||
Text("Dim").dimmed()
|
||||
Text("Blinking").blinking()
|
||||
Text("Inverted").inverted()
|
||||
```
|
||||
|
||||
Combine multiple modifiers:
|
||||
|
||||
```swift
|
||||
Text("Complex")
|
||||
.bold()
|
||||
.italic()
|
||||
.foregroundColor(.theme.accent)
|
||||
```
|
||||
|
||||
## Border and Structure
|
||||
|
||||
### border(_:)
|
||||
|
||||
Add borders with different styles:
|
||||
|
||||
```swift
|
||||
Text("Bordered")
|
||||
.border(.rounded)
|
||||
|
||||
Text("Heavy border")
|
||||
.border(.heavy, width: 2)
|
||||
|
||||
VStack {
|
||||
Text("Content")
|
||||
}
|
||||
.border(.block, color: .theme.accent)
|
||||
```
|
||||
|
||||
## Overlay and Compositing
|
||||
|
||||
### overlay(_:)
|
||||
|
||||
Layer content on top:
|
||||
|
||||
```swift
|
||||
Text("Background")
|
||||
.overlay {
|
||||
Text("Foreground")
|
||||
}
|
||||
```
|
||||
|
||||
### dimmed()
|
||||
|
||||
Reduce visual emphasis:
|
||||
|
||||
```swift
|
||||
VStack {
|
||||
Text("Normal")
|
||||
Text("Dimmed")
|
||||
.dimmed()
|
||||
}
|
||||
```
|
||||
|
||||
### modal()
|
||||
|
||||
Combine dimmed + centered overlay:
|
||||
|
||||
```swift
|
||||
showAlert {
|
||||
Alert(title: "Alert", message: "Message")
|
||||
.modal()
|
||||
}
|
||||
```
|
||||
|
||||
## Event Modifiers
|
||||
|
||||
### onKeyPress(_:)
|
||||
|
||||
Handle keyboard input:
|
||||
|
||||
```swift
|
||||
VStack {
|
||||
ContentView()
|
||||
}
|
||||
.onKeyPress { event in
|
||||
if event.key == .character("q") {
|
||||
// Quit
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
```
|
||||
|
||||
### onAppear(_:)
|
||||
|
||||
Run code when view appears:
|
||||
|
||||
```swift
|
||||
Text("Content")
|
||||
.onAppear {
|
||||
print("View appeared")
|
||||
}
|
||||
```
|
||||
|
||||
### onDisappear(_:)
|
||||
|
||||
Run code when view disappears:
|
||||
|
||||
```swift
|
||||
Text("Content")
|
||||
.onDisappear {
|
||||
print("View disappearing")
|
||||
}
|
||||
```
|
||||
|
||||
### task(_:)
|
||||
|
||||
Run async code:
|
||||
|
||||
```swift
|
||||
VStack {
|
||||
ContentView()
|
||||
}
|
||||
.task {
|
||||
// Fetch data
|
||||
let data = try await fetchData()
|
||||
}
|
||||
```
|
||||
|
||||
## Data Flow Modifiers
|
||||
|
||||
### environment(_:_:)
|
||||
|
||||
Pass environment values to children:
|
||||
|
||||
```swift
|
||||
VStack {
|
||||
ContentView()
|
||||
}
|
||||
.environment(\.theme, customTheme)
|
||||
```
|
||||
|
||||
### statusBarItems(_:)
|
||||
|
||||
Define status bar items:
|
||||
|
||||
```swift
|
||||
VStack {
|
||||
ContentView()
|
||||
}
|
||||
.statusBarItems {
|
||||
StatusBarItem(
|
||||
label: "Help",
|
||||
shortcut: Shortcut.letter("?"),
|
||||
action: { print("Help") }
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Combining Modifiers
|
||||
|
||||
Modifiers are applied in order—the order matters:
|
||||
|
||||
```swift
|
||||
// This looks different...
|
||||
Text("Order matters")
|
||||
.foregroundColor(.theme.accent)
|
||||
.padding(1)
|
||||
.border(.rounded)
|
||||
|
||||
// ...than this
|
||||
Text("Order matters")
|
||||
.border(.rounded)
|
||||
.padding(1)
|
||||
.foregroundColor(.theme.accent)
|
||||
```
|
||||
|
||||
### Creating Custom Modifiers
|
||||
|
||||
Create reusable modifiers:
|
||||
|
||||
```swift
|
||||
struct PrimaryButtonStyle: ViewModifier {
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.bold()
|
||||
.foregroundColor(.theme.background)
|
||||
.background(.theme.accent)
|
||||
.padding(1)
|
||||
.border(.rounded)
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
func primaryButton() -> some View {
|
||||
modifier(PrimaryButtonStyle())
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
Button("Click") { }
|
||||
.primaryButton()
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Centered Text
|
||||
|
||||
```swift
|
||||
Text("Centered")
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
```
|
||||
|
||||
### Full-Size Container
|
||||
|
||||
```swift
|
||||
VStack {
|
||||
ContentView()
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
```
|
||||
|
||||
### Bordered Section
|
||||
|
||||
```swift
|
||||
VStack(spacing: 1) {
|
||||
Text("Title").bold()
|
||||
ContentView()
|
||||
}
|
||||
.padding(1)
|
||||
.border(.rounded)
|
||||
```
|
||||
|
||||
### Button Row
|
||||
|
||||
```swift
|
||||
HStack(spacing: 2) {
|
||||
Button("OK") { }
|
||||
Button("Cancel") { }
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
||||
```
|
||||
|
||||
## Related Topics
|
||||
|
||||
- ``View``
|
||||
- ``ViewModifier``
|
||||
- ``View/padding(_:)-19gu9``
|
||||
- ``View/frame(width:height:alignment:)``
|
||||
- ``View/border(_:style:)-4xzvw``
|
||||
- ``View/background(_:)``
|
||||
- ``View/foregroundColor(_:)``
|
||||
- ``View/overlay(alignment:content:)``
|
||||
- ``View/onKeyPress(_:)``
|
||||
@@ -1,259 +0,0 @@
|
||||
# State Management
|
||||
|
||||
Learn how to manage application state and data flow in TUIKit.
|
||||
|
||||
## Overview
|
||||
|
||||
TUIKit provides several mechanisms for managing state:
|
||||
|
||||
- **`@State`**: Local view state
|
||||
- **`@Environment`**: Top-down data flow
|
||||
- **`Binding`**: Two-way data binding
|
||||
- **`@AppStorage`**: Persistent application settings
|
||||
- **`@SceneStorage`**: Scene-specific state restoration
|
||||
|
||||
## @State Property Wrapper
|
||||
|
||||
`@State` stores local state within a view and automatically triggers re-renders when the value changes:
|
||||
|
||||
```swift
|
||||
struct Counter: View {
|
||||
@State var count: Int = 0
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 1) {
|
||||
Text("Count: \(count)")
|
||||
.bold()
|
||||
|
||||
HStack(spacing: 2) {
|
||||
Button("Decrement") { count -= 1 }
|
||||
Button("Increment") { count += 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Rules for @State
|
||||
|
||||
- Declare as `private` to prevent external modification
|
||||
- Initialize with a default value
|
||||
- Use only in views, not in view models
|
||||
- State is destroyed when view is removed from hierarchy
|
||||
|
||||
```swift
|
||||
struct InputForm: View {
|
||||
@State private var name: String = ""
|
||||
@State private var age: Int = 0
|
||||
@State private var agreed: Bool = false
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 1) {
|
||||
// View content
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Binding
|
||||
|
||||
A `Binding` creates a two-way connection between a view and a state variable:
|
||||
|
||||
```swift
|
||||
struct Parent: View {
|
||||
@State var isExpanded: Bool = false
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Child(isExpanded: $isExpanded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Child: View {
|
||||
@Binding var isExpanded: Bool
|
||||
|
||||
var body: some View {
|
||||
Button(isExpanded ? "Collapse" : "Expand") {
|
||||
isExpanded.toggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use `$` to create a binding to a state property.
|
||||
|
||||
### Creating Custom Bindings
|
||||
|
||||
Create computed bindings for complex logic:
|
||||
|
||||
```swift
|
||||
struct FilteredList: View {
|
||||
@State private var showDetails: Bool = false
|
||||
|
||||
var detailsBinding: Binding<Bool> {
|
||||
Binding(
|
||||
get: { showDetails },
|
||||
set: { newValue in
|
||||
if newValue {
|
||||
print("Details opened")
|
||||
}
|
||||
showDetails = newValue
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Button("Toggle") {
|
||||
detailsBinding.wrappedValue.toggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## @Environment and Environment Keys
|
||||
|
||||
Environment provides top-down data flow to all child views:
|
||||
|
||||
```swift
|
||||
struct App: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
ContentView()
|
||||
.environment(\.theme, customTheme)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView: View {
|
||||
@Environment(\.theme) var theme
|
||||
|
||||
var body: some View {
|
||||
Text("Using current theme")
|
||||
.foregroundColor(theme.foreground)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Environment Keys
|
||||
|
||||
Define custom environment values:
|
||||
|
||||
```swift
|
||||
struct UserPreferencesKey: EnvironmentKey {
|
||||
static let defaultValue = UserPreferences()
|
||||
}
|
||||
|
||||
extension EnvironmentValues {
|
||||
var userPreferences: UserPreferences {
|
||||
get { self[UserPreferencesKey.self] }
|
||||
set { self[UserPreferencesKey.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
struct App: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
ContentView()
|
||||
.environment(\.userPreferences, UserPreferences(language: "de"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView: View {
|
||||
@Environment(\.userPreferences) var prefs
|
||||
|
||||
var body: some View {
|
||||
Text("Language: \(prefs.language)")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## @AppStorage
|
||||
|
||||
`@AppStorage` persists values to storage (UserDefaults on macOS, JSON file on Linux):
|
||||
|
||||
```swift
|
||||
struct App: View {
|
||||
@AppStorage("theme") var selectedTheme: String = "green"
|
||||
@AppStorage("fontSize") var fontSize: Int = 12
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("Current theme: \(selectedTheme)")
|
||||
// Settings UI
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Changes to `@AppStorage` variables are automatically saved and restored across app launches.
|
||||
|
||||
## @SceneStorage
|
||||
|
||||
`@SceneStorage` preserves state for the current scene:
|
||||
|
||||
```swift
|
||||
struct MyScene: Scene {
|
||||
@SceneStorage("selectedTab") var selectedTab: String = "home"
|
||||
@SceneStorage("scrollPosition") var scrollPosition: Int = 0
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
VStack {
|
||||
if selectedTab == "home" {
|
||||
HomeView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Data Flow Pattern
|
||||
|
||||
### Recommended Pattern
|
||||
|
||||
1. **Local state**: Use `@State` for temporary UI state
|
||||
2. **Shared state**: Use `@Environment` to pass to child views
|
||||
3. **Persistent state**: Use `@AppStorage` for settings
|
||||
4. **Child updates**: Use `@Binding` to let children modify parent state
|
||||
|
||||
```swift
|
||||
@main
|
||||
struct MyApp: App {
|
||||
// Persistent settings
|
||||
@AppStorage("theme") var theme: String = "green"
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
.environment(\.theme, themeForString(theme))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView: View {
|
||||
@Environment(\.theme) var theme
|
||||
@State private var showMenu: Bool = false
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
if showMenu {
|
||||
MenuView(showing: $showMenu)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Related Topics
|
||||
|
||||
- ``State``
|
||||
- ``Binding``
|
||||
- ``@Environment``
|
||||
- ``@AppStorage``
|
||||
- ``@SceneStorage``
|
||||
- ``EnvironmentKey``
|
||||
- ``EnvironmentValues``
|
||||
@@ -1,261 +0,0 @@
|
||||
# Theming System
|
||||
|
||||
Customize the appearance of your application with TUIKit's flexible theming system.
|
||||
|
||||
## Built-in Themes
|
||||
|
||||
TUIKit includes 4 beautiful phosphor-style themes:
|
||||
|
||||
### Green Theme
|
||||
|
||||
Classic green phosphor aesthetic for a retro terminal feel:
|
||||
|
||||
```swift
|
||||
.environment(\.themeManager.currentTheme, .green)
|
||||
```
|
||||
|
||||
- **Accent**: Bright green
|
||||
- **Background**: Deep dark green
|
||||
- **Foreground**: Light green text
|
||||
|
||||
### Amber Theme
|
||||
|
||||
Warm amber/orange phosphor theme:
|
||||
|
||||
```swift
|
||||
.environment(\.themeManager.currentTheme, .amber)
|
||||
```
|
||||
|
||||
- **Accent**: Bright amber
|
||||
- **Background**: Dark brown-orange
|
||||
- **Foreground**: Light amber text
|
||||
|
||||
### White Theme
|
||||
|
||||
Cool white/blue-tinted theme for modern appearance:
|
||||
|
||||
```swift
|
||||
.environment(\.themeManager.currentTheme, .white)
|
||||
```
|
||||
|
||||
- **Accent**: Bright white
|
||||
- **Background**: Deep blue-black
|
||||
- **Foreground**: Light white text
|
||||
|
||||
### Red Theme
|
||||
|
||||
Bold red phosphor theme:
|
||||
|
||||
```swift
|
||||
.environment(\.themeManager.currentTheme, .red)
|
||||
```
|
||||
|
||||
- **Accent**: Bright red
|
||||
- **Background**: Dark red-black
|
||||
- **Foreground**: Light red text
|
||||
|
||||
## Using Themes
|
||||
|
||||
### Default Theme
|
||||
|
||||
By default, the Green theme is active:
|
||||
|
||||
```swift
|
||||
@main
|
||||
struct MyApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Switching Themes
|
||||
|
||||
Use the theme manager to switch themes at runtime:
|
||||
|
||||
```swift
|
||||
struct App: View {
|
||||
@Environment(\.themeManager) var themeManager
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Button("Switch to Amber") {
|
||||
themeManager.currentTheme = .amber
|
||||
}
|
||||
Button("Switch to White") {
|
||||
themeManager.currentTheme = .white
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Accessing Theme Colors
|
||||
|
||||
Use `Color.theme` shorthand to access current theme colors:
|
||||
|
||||
```swift
|
||||
VStack {
|
||||
Text("This uses the theme accent color")
|
||||
.foregroundColor(.theme.accent)
|
||||
|
||||
Text("This uses the theme foreground")
|
||||
.foregroundColor(.theme.foreground)
|
||||
|
||||
Text("This uses secondary text color")
|
||||
.foregroundColor(.theme.foregroundSecondary)
|
||||
}
|
||||
```
|
||||
|
||||
## Theme Protocol
|
||||
|
||||
Themes conform to the ``Theme`` protocol:
|
||||
|
||||
```swift
|
||||
public protocol Theme {
|
||||
var background: Color { get }
|
||||
var containerBackground: Color { get }
|
||||
var containerHeaderBackground: Color { get }
|
||||
var buttonBackground: Color { get }
|
||||
var statusBarBackground: Color { get }
|
||||
var foreground: Color { get }
|
||||
var foregroundSecondary: Color { get }
|
||||
var foregroundTertiary: Color { get }
|
||||
var accent: Color { get }
|
||||
var border: Color { get }
|
||||
var statusBarForeground: Color { get }
|
||||
}
|
||||
```
|
||||
|
||||
## Creating Custom Themes
|
||||
|
||||
Implement the `Theme` protocol to create custom themes:
|
||||
|
||||
```swift
|
||||
struct CompanyTheme: Theme {
|
||||
let background = Color.hex("0a0a0a")
|
||||
let containerBackground = Color.hex("1a1a2e")
|
||||
let containerHeaderBackground = Color.hex("16213e")
|
||||
let buttonBackground = Color.hex("0f3460")
|
||||
let statusBarBackground = Color.hex("0f3460")
|
||||
let foreground = Color.hex("eaeaea")
|
||||
let foregroundSecondary = Color.hex("999999")
|
||||
let foregroundTertiary = Color.hex("666666")
|
||||
let accent = Color.hex("00d4ff")
|
||||
let border = Color.hex("00d4ff")
|
||||
let statusBarForeground = Color.hex("666666")
|
||||
}
|
||||
|
||||
// Use it
|
||||
@main
|
||||
struct MyApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
.environment(\.themeManager.currentTheme, CompanyTheme())
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Color System
|
||||
|
||||
TUIKit supports multiple color spaces:
|
||||
|
||||
### ANSI Colors
|
||||
|
||||
Use standard terminal colors:
|
||||
|
||||
```swift
|
||||
Color.ansi(.brightGreen)
|
||||
Color.ansi(.red)
|
||||
```
|
||||
|
||||
### Hex Colors
|
||||
|
||||
Specify colors as hex strings or integers:
|
||||
|
||||
```swift
|
||||
Color.hex("FF5500")
|
||||
Color.hex("#FF5500")
|
||||
Color.hex(0xFF5500)
|
||||
```
|
||||
|
||||
### RGB Colors
|
||||
|
||||
Define colors by RGB values:
|
||||
|
||||
```swift
|
||||
Color.rgb(red: 255, green: 85, blue: 0)
|
||||
Color.rgb(red: 1.0, green: 0.33, blue: 0.0)
|
||||
```
|
||||
|
||||
### 256-Color Palette
|
||||
|
||||
Use 256-color terminal palette (0-255):
|
||||
|
||||
```swift
|
||||
Color.palette256(196)
|
||||
```
|
||||
|
||||
### HSL Colors
|
||||
|
||||
Create colors using HSL (Hue, Saturation, Lightness):
|
||||
|
||||
```swift
|
||||
Color.hsl(hue: 25, saturation: 100, lightness: 50)
|
||||
```
|
||||
|
||||
## Color Modifiers
|
||||
|
||||
Adjust colors programmatically:
|
||||
|
||||
```swift
|
||||
let baseColor = Color.hex("#FF5500")
|
||||
|
||||
let lighter = baseColor.lighter(by: 0.2)
|
||||
let darker = baseColor.darker(by: 0.3)
|
||||
let transparent = baseColor.opacity(0.5)
|
||||
```
|
||||
|
||||
## Theme Cycling
|
||||
|
||||
The example app supports theme cycling with the `t` key:
|
||||
|
||||
```swift
|
||||
@main
|
||||
struct ExampleApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
.statusBarItems {
|
||||
StatusBarItem(
|
||||
label: "Theme",
|
||||
shortcut: Shortcut.letter("t"),
|
||||
action: {
|
||||
// Cycle themes
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use semantic colors**: Reference `Color.theme.accent` instead of hardcoding colors
|
||||
2. **Test readability**: Ensure sufficient contrast in custom themes
|
||||
3. **Support all modes**: Create both dark and light themed colors if needed
|
||||
4. **Store preferences**: Use `@AppStorage` to remember user theme choice
|
||||
5. **Provide visual feedback**: Show current theme in settings
|
||||
|
||||
## Related Topics
|
||||
|
||||
- ``Color``
|
||||
- ``Theme``
|
||||
- ``ThemeManager``
|
||||
- <doc:Appearance>
|
||||
- <doc:StateManagement>
|
||||
@@ -1,239 +0,0 @@
|
||||
# Understanding the View Hierarchy
|
||||
|
||||
Learn how TUIKit's declarative view model works and how to compose views effectively.
|
||||
|
||||
## The View Protocol
|
||||
|
||||
Everything in TUIKit conforms to the `View` protocol. A view is a lightweight value type that describes a piece of UI:
|
||||
|
||||
```swift
|
||||
public protocol View {
|
||||
associatedtype Body: View
|
||||
@ViewBuilder var body: Body { get }
|
||||
}
|
||||
```
|
||||
|
||||
Views are **not** the rendered output—they're descriptions of UI that get rendered when needed.
|
||||
|
||||
### Primitive Views
|
||||
|
||||
Some views have `body: Never` and directly conform to `Renderable`. These render their own content:
|
||||
|
||||
- **`Text`**: Display text with styling
|
||||
- **`Button`**: Interactive clickable element
|
||||
- **`Menu`**: Selection menu with keyboard navigation
|
||||
- **`Spacer`**: Occupy available space
|
||||
- **`Divider`**: Horizontal or vertical separator
|
||||
- **`EmptyView`**: Invisible placeholder view
|
||||
|
||||
### Composite Views
|
||||
|
||||
Most views define a `body` that combines other views:
|
||||
|
||||
```swift
|
||||
struct MyCard: View {
|
||||
var body: some View {
|
||||
VStack(spacing: 1) {
|
||||
Text("Title").bold()
|
||||
Text("Content")
|
||||
}
|
||||
.border(.rounded)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Composite views don't render directly—the renderer walks the view tree and renders primitives.
|
||||
|
||||
## Container Views
|
||||
|
||||
### VStack (Vertical Stack)
|
||||
|
||||
Stack views vertically with optional spacing:
|
||||
|
||||
```swift
|
||||
VStack(spacing: 1) {
|
||||
Text("First")
|
||||
Text("Second")
|
||||
Text("Third")
|
||||
}
|
||||
```
|
||||
|
||||
### HStack (Horizontal Stack)
|
||||
|
||||
Stack views horizontally:
|
||||
|
||||
```swift
|
||||
HStack(spacing: 2) {
|
||||
Button("OK") { }
|
||||
Button("Cancel") { }
|
||||
}
|
||||
```
|
||||
|
||||
### ZStack (Depth Stack)
|
||||
|
||||
Layer views on top of each other:
|
||||
|
||||
```swift
|
||||
ZStack {
|
||||
Text("Background")
|
||||
Text("Foreground")
|
||||
}
|
||||
```
|
||||
|
||||
### ForEach
|
||||
|
||||
Render a collection of items:
|
||||
|
||||
```swift
|
||||
ForEach(items) { item in
|
||||
Text(item.name)
|
||||
}
|
||||
```
|
||||
|
||||
## Control Flow
|
||||
|
||||
### Conditionals
|
||||
|
||||
Use standard Swift `if` statements:
|
||||
|
||||
```swift
|
||||
if isLoading {
|
||||
Text("Loading...")
|
||||
} else {
|
||||
Text("Loaded!")
|
||||
}
|
||||
```
|
||||
|
||||
### Optional Values
|
||||
|
||||
Handle optional views:
|
||||
|
||||
```swift
|
||||
if let name = userName {
|
||||
Text("Hello, \(name)")
|
||||
} else {
|
||||
Text("Not logged in")
|
||||
}
|
||||
```
|
||||
|
||||
## The ViewBuilder Result Builder
|
||||
|
||||
`@ViewBuilder` is a result builder that enables the declarative syntax:
|
||||
|
||||
```swift
|
||||
@ViewBuilder
|
||||
var content: some View {
|
||||
if condition {
|
||||
Text("A")
|
||||
} else {
|
||||
Text("B")
|
||||
}
|
||||
Text("C")
|
||||
}
|
||||
```
|
||||
|
||||
It supports:
|
||||
- Up to 10 children without nesting
|
||||
- `if/else if/else` conditionals
|
||||
- `if let` optional unwrapping
|
||||
- Arrays and `ForEach`
|
||||
- Nested result builders
|
||||
|
||||
## Type Erasure with AnyView
|
||||
|
||||
When you need to return different view types, use `AnyView`:
|
||||
|
||||
```swift
|
||||
func makeView(condition: Bool) -> AnyView {
|
||||
if condition {
|
||||
return AnyView(Text("A"))
|
||||
} else {
|
||||
return AnyView(VStack { Text("B") })
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> Note: Use `AnyView` sparingly—prefer `@ViewBuilder` when possible.
|
||||
|
||||
## Custom Views
|
||||
|
||||
Create your own reusable components:
|
||||
|
||||
```swift
|
||||
struct CustomButton: View {
|
||||
let label: String
|
||||
let action: () -> Void
|
||||
|
||||
var body: some View {
|
||||
Button(label, action: action)
|
||||
.padding(1)
|
||||
.border(.rounded)
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
CustomButton(label: "Click me", action: {
|
||||
print("Clicked")
|
||||
})
|
||||
```
|
||||
|
||||
## View Composition Pattern
|
||||
|
||||
Build complex UIs by composing smaller views:
|
||||
|
||||
```swift
|
||||
struct ContentView: View {
|
||||
var body: some View {
|
||||
VStack(spacing: 1) {
|
||||
HeaderView()
|
||||
BodyView()
|
||||
FooterView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct HeaderView: View {
|
||||
var body: some View {
|
||||
Text("Header").bold()
|
||||
}
|
||||
}
|
||||
|
||||
struct BodyView: View {
|
||||
var body: some View {
|
||||
Text("Content").padding(1)
|
||||
}
|
||||
}
|
||||
|
||||
struct FooterView: View {
|
||||
var body: some View {
|
||||
Text("Footer")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## View Lifetime
|
||||
|
||||
Views are value types—they're created, rendered, and discarded. They don't have persistent storage. Use `@State` for state that persists across renders:
|
||||
|
||||
```swift
|
||||
struct Counter: View {
|
||||
@State var count: Int = 0
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("Count: \(count)")
|
||||
Button("Increment") { count += 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Related Topics
|
||||
|
||||
- ``View``
|
||||
- ``@ViewBuilder``
|
||||
- ``VStack``
|
||||
- ``HStack``
|
||||
- ``ZStack``
|
||||
- <doc:StateManagement>
|
||||
- <doc:Modifiers>
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleName</key>
|
||||
<string>TUIKit</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.anthropic.tuikit.documentation</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.1.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>dext</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2026 Anthropic. All rights reserved.</string>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.documentation.extension</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,124 +0,0 @@
|
||||
# ``TUIKit``
|
||||
|
||||
Build beautiful, interactive terminal user interfaces in Swift.
|
||||
|
||||
## Overview
|
||||
|
||||
TUIKit is a modern Swift framework for creating sophisticated terminal user interfaces (TUIs) on macOS and Linux. It provides a declarative, SwiftUI-like API with support for themes, styling, focus management, and interactive components.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Declarative UI**: Build interfaces using Swift's result builders and view composition
|
||||
- **5 Appearance Styles**: line, rounded, doubleLine, heavy, and block rendering modes
|
||||
- **4 Phosphor Themes**: Green, Amber, White, and Red with customizable colors
|
||||
- **Rich Components**: Text, Button, Menu, Alert, Dialog, Card, Panel, and more
|
||||
- **Focus Management**: Tab/Shift+Tab navigation with keyboard shortcuts
|
||||
- **State Management**: `@State`, `@Environment`, `@AppStorage`, `@SceneStorage` property wrappers
|
||||
- **No Dependencies**: Pure Swift implementation for macOS 10.15+ and Linux
|
||||
|
||||
## Getting Started
|
||||
|
||||
Create your first TUIKit app in minutes:
|
||||
|
||||
```swift
|
||||
import TUIKit
|
||||
|
||||
@main
|
||||
struct MyApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
VStack(spacing: 1) {
|
||||
Text("Welcome to TUIKit!")
|
||||
.bold()
|
||||
.foregroundColor(.theme.accent)
|
||||
|
||||
Spacer()
|
||||
|
||||
Button("Press me") {
|
||||
print("Button pressed!")
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Run with: `swift run`
|
||||
|
||||
## Topics
|
||||
|
||||
### Essentials
|
||||
|
||||
- ``View``
|
||||
- ``App``
|
||||
- ``Scene``
|
||||
- ``@main``
|
||||
|
||||
### Building Views
|
||||
|
||||
- <doc:ViewHierarchy>
|
||||
- <doc:GettingStarted>
|
||||
- ``VStack``
|
||||
- ``HStack``
|
||||
- ``ZStack``
|
||||
- ``ForEach``
|
||||
|
||||
### Interactive Components
|
||||
|
||||
- ``Button``
|
||||
- ``Menu``
|
||||
- ``Alert``
|
||||
- ``Dialog``
|
||||
- ``Text``
|
||||
|
||||
### Styling & Appearance
|
||||
|
||||
- <doc:Theming>
|
||||
- <doc:Appearance>
|
||||
- ``Color``
|
||||
- ``Theme``
|
||||
- ``Appearance``
|
||||
|
||||
### Layout & Modifiers
|
||||
|
||||
- <doc:Modifiers>
|
||||
- ``View/padding(_:)-19gu9``
|
||||
- ``View/frame(width:height:alignment:)``
|
||||
- ``View/border(_:style:)-4xzvw``
|
||||
|
||||
### State Management
|
||||
|
||||
- <doc:StateManagement>
|
||||
- ``State``
|
||||
- ``Binding``
|
||||
- ``@Environment``
|
||||
- ``@AppStorage``
|
||||
|
||||
### Advanced Topics
|
||||
|
||||
- <doc:Focus>
|
||||
- <doc:Architecture>
|
||||
- <doc:Rendering>
|
||||
- ``FocusManager``
|
||||
- ``KeyEvent``
|
||||
|
||||
### Examples
|
||||
|
||||
- <doc:BuildYourFirstApp>
|
||||
- <doc:BuildInteractiveMenu>
|
||||
- <doc:BuildThemableUI>
|
||||
|
||||
## Resources
|
||||
|
||||
- [GitHub Repository](https://github.com/anthropics/SwiftTUI)
|
||||
- [Example Application](https://github.com/anthropics/SwiftTUI/tree/main/Sources/TUIKitExample)
|
||||
- [Issue Tracker](https://github.com/anthropics/SwiftTUI/issues)
|
||||
|
||||
## Minimum Requirements
|
||||
|
||||
- Swift 6.0 or later
|
||||
- macOS 10.15+ or Linux (glibc)
|
||||
- Terminal with ANSI color support (256 colors or better)
|
||||
@@ -1,375 +0,0 @@
|
||||
# Building an Interactive Menu
|
||||
|
||||
Create a navigation menu with keyboard shortcuts and status bar hints.
|
||||
|
||||
@Intro(title: "Build an Interactive Menu App") {
|
||||
Learn how to create a functional menu system with keyboard navigation,
|
||||
selection handling, and status bar integration.
|
||||
|
||||
You'll build a simple settings menu that demonstrates focus management,
|
||||
keyboard events, and status bar items.
|
||||
}
|
||||
|
||||
## Overview
|
||||
|
||||
In this tutorial, you'll create a menu-driven application featuring:
|
||||
|
||||
- `Menu` component for selection
|
||||
- Keyboard shortcut handling
|
||||
- Status bar with hints
|
||||
- Page navigation patterns
|
||||
|
||||
@Section(title: "Create the Menu Component") {
|
||||
@ContentAndMedia {
|
||||
Start with a basic menu that displays options and tracks selection.
|
||||
}
|
||||
|
||||
@Steps {
|
||||
@Step {
|
||||
Create your app with a `Menu`:
|
||||
|
||||
```swift
|
||||
import TUIKit
|
||||
|
||||
@main
|
||||
struct MenuApp: App {
|
||||
@State private var selectedOption: String = "home"
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
VStack(spacing: 2) {
|
||||
Text("Main Menu")
|
||||
.bold()
|
||||
.foregroundColor(.theme.accent)
|
||||
|
||||
Spacer()
|
||||
|
||||
Menu(
|
||||
items: [
|
||||
MenuItem("📄 View Profile", id: "profile"),
|
||||
MenuItem("⚙️ Settings", id: "settings"),
|
||||
MenuItem("💾 Save Data", id: "save"),
|
||||
MenuItem("❌ Exit", id: "exit")
|
||||
],
|
||||
selection: $selectedOption
|
||||
)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("Selected: \(selectedOption)")
|
||||
.foregroundColor(.theme.foregroundSecondary)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `Menu` creates an interactive selectable list
|
||||
- `$selectedOption` creates a two-way binding
|
||||
- Use Tab/Arrow keys to navigate
|
||||
- Press Enter to confirm selection
|
||||
}
|
||||
|
||||
@Step {
|
||||
Run the app:
|
||||
|
||||
```bash
|
||||
swift run
|
||||
```
|
||||
|
||||
Test navigating with Tab, arrow keys, and Enter.
|
||||
The "Selected" text updates as you navigate.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Section(title: "Add Page Navigation") {
|
||||
@ContentAndMedia {
|
||||
Create different pages that show based on menu selection.
|
||||
}
|
||||
|
||||
@Steps {
|
||||
@Step {
|
||||
Add conditional pages:
|
||||
|
||||
```swift
|
||||
@main
|
||||
struct MenuApp: App {
|
||||
@State private var selectedOption: String = "home"
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
if selectedOption == "exit" {
|
||||
VStack {
|
||||
Text("Exiting...")
|
||||
}
|
||||
} else {
|
||||
VStack(spacing: 2) {
|
||||
Text("Main Menu")
|
||||
.bold()
|
||||
.foregroundColor(.theme.accent)
|
||||
|
||||
Spacer()
|
||||
|
||||
Menu(
|
||||
items: [
|
||||
MenuItem("📄 View Profile", id: "profile"),
|
||||
MenuItem("⚙️ Settings", id: "settings"),
|
||||
MenuItem("💾 Save Data", id: "save"),
|
||||
MenuItem("❌ Exit", id: "exit")
|
||||
],
|
||||
selection: $selectedOption
|
||||
)
|
||||
|
||||
Spacer()
|
||||
|
||||
currentPageContent
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
var currentPageContent: some View {
|
||||
switch selectedOption {
|
||||
case "profile":
|
||||
VStack(spacing: 1) {
|
||||
Text("📄 Profile Information").bold()
|
||||
Text("Name: John Doe")
|
||||
Text("Role: Developer")
|
||||
}
|
||||
case "settings":
|
||||
VStack(spacing: 1) {
|
||||
Text("⚙️ Application Settings").bold()
|
||||
Text("Theme: Green")
|
||||
Text("Language: English")
|
||||
}
|
||||
case "save":
|
||||
Text("✓ Data saved successfully!")
|
||||
.foregroundColor(.theme.success)
|
||||
default:
|
||||
Text("Select an option above")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `currentPageContent` computed property shows different content
|
||||
based on the selected menu item.
|
||||
}
|
||||
|
||||
@Step {
|
||||
Run and test navigation:
|
||||
|
||||
```bash
|
||||
swift run
|
||||
```
|
||||
|
||||
Navigate to each menu item and see the page content change.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Section(title: "Add Status Bar Hints") {
|
||||
@ContentAndMedia {
|
||||
Add a status bar at the bottom with helpful keyboard hints.
|
||||
}
|
||||
|
||||
@Steps {
|
||||
@Step {
|
||||
Add status bar items:
|
||||
|
||||
```swift
|
||||
@main
|
||||
struct MenuApp: App {
|
||||
@State private var selectedOption: String = "home"
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
if selectedOption == "exit" {
|
||||
VStack {
|
||||
Text("Exiting...")
|
||||
}
|
||||
} else {
|
||||
VStack(spacing: 2) {
|
||||
Text("Main Menu")
|
||||
.bold()
|
||||
.foregroundColor(.theme.accent)
|
||||
|
||||
Spacer()
|
||||
|
||||
Menu(
|
||||
items: [
|
||||
MenuItem("📄 View Profile", id: "profile"),
|
||||
MenuItem("⚙️ Settings", id: "settings"),
|
||||
MenuItem("💾 Save Data", id: "save"),
|
||||
MenuItem("❌ Exit", id: "exit")
|
||||
],
|
||||
selection: $selectedOption
|
||||
)
|
||||
|
||||
Spacer()
|
||||
|
||||
currentPageContent
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.statusBarItems {
|
||||
StatusBarItem(
|
||||
label: "Select",
|
||||
shortcut: Shortcut.enter,
|
||||
action: { }
|
||||
)
|
||||
|
||||
StatusBarItem(
|
||||
label: "Theme",
|
||||
shortcut: Shortcut.letter("t"),
|
||||
action: { }
|
||||
)
|
||||
|
||||
StatusBarItem(
|
||||
label: "Help",
|
||||
shortcut: Shortcut.letter("?"),
|
||||
action: { }
|
||||
)
|
||||
|
||||
StatusBarItem(
|
||||
label: "Quit",
|
||||
shortcut: Shortcut.letter("q"),
|
||||
action: { }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
var currentPageContent: some View {
|
||||
switch selectedOption {
|
||||
case "profile":
|
||||
VStack(spacing: 1) {
|
||||
Text("📄 Profile Information").bold()
|
||||
Text("Name: John Doe")
|
||||
Text("Role: Developer")
|
||||
}
|
||||
case "settings":
|
||||
VStack(spacing: 1) {
|
||||
Text("⚙️ Application Settings").bold()
|
||||
Text("Theme: Green")
|
||||
Text("Language: English")
|
||||
}
|
||||
case "save":
|
||||
Text("✓ Data saved successfully!")
|
||||
.foregroundColor(.theme.success)
|
||||
default:
|
||||
Text("Select an option above")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`statusBarItems` adds a bottom status bar with keyboard shortcuts.
|
||||
}
|
||||
|
||||
@Step {
|
||||
Run the app:
|
||||
|
||||
```bash
|
||||
swift run
|
||||
```
|
||||
|
||||
The status bar appears at the bottom showing available shortcuts.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Section(title: "Add Keyboard Shortcuts") {
|
||||
@ContentAndMedia {
|
||||
Handle custom keyboard shortcuts to navigate directly to menu items.
|
||||
}
|
||||
|
||||
@Steps {
|
||||
@Step {
|
||||
Add keyboard event handling:
|
||||
|
||||
```swift
|
||||
.onKeyPress { event in
|
||||
switch event.key {
|
||||
case .character("1"):
|
||||
selectedOption = "profile"
|
||||
return true
|
||||
case .character("2"):
|
||||
selectedOption = "settings"
|
||||
return true
|
||||
case .character("3"):
|
||||
selectedOption = "save"
|
||||
return true
|
||||
case .character("e"):
|
||||
selectedOption = "exit"
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Add this modifier to your main `VStack`. Now users can:
|
||||
- Press `1` to go to Profile
|
||||
- Press `2` to go to Settings
|
||||
- Press `3` to Save
|
||||
- Press `e` to Exit
|
||||
}
|
||||
|
||||
@Step {
|
||||
Update the status bar to show these shortcuts:
|
||||
|
||||
```swift
|
||||
.statusBarItems {
|
||||
StatusBarItem(
|
||||
label: "Profile",
|
||||
shortcut: Shortcut.digit("1"),
|
||||
action: { }
|
||||
)
|
||||
|
||||
StatusBarItem(
|
||||
label: "Settings",
|
||||
shortcut: Shortcut.digit("2"),
|
||||
action: { }
|
||||
)
|
||||
|
||||
StatusBarItem(
|
||||
label: "Save",
|
||||
shortcut: Shortcut.digit("3"),
|
||||
action: { }
|
||||
)
|
||||
|
||||
StatusBarItem(
|
||||
label: "Exit",
|
||||
shortcut: Shortcut.letter("e"),
|
||||
action: { }
|
||||
)
|
||||
}
|
||||
```
|
||||
}
|
||||
|
||||
@Step {
|
||||
Test your shortcuts:
|
||||
|
||||
```bash
|
||||
swift run
|
||||
```
|
||||
|
||||
Press number keys to jump directly to menu items.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## Next Steps
|
||||
|
||||
You've created an interactive menu-driven application!
|
||||
|
||||
- Learn about <doc:Focus> for advanced focus management
|
||||
- Explore <doc:StateManagement> for more complex state patterns
|
||||
- Try building a <doc:BuildThemableUI> with theme switching
|
||||
- Check out <doc:Appearance> for custom styling
|
||||
@@ -1,421 +0,0 @@
|
||||
# Building a Themable UI
|
||||
|
||||
Create an application with dynamic theme switching and persistence.
|
||||
|
||||
@Intro(title: "Build a Themable App") {
|
||||
Learn how to integrate TUIKit's theming system into your application,
|
||||
allowing users to switch between themes and persist their preference.
|
||||
|
||||
You'll work with the theme environment, theme manager, and storage to
|
||||
create a professional themable application.
|
||||
}
|
||||
|
||||
## Overview
|
||||
|
||||
In this tutorial, you'll create an app that features:
|
||||
|
||||
- Theme environment integration
|
||||
- Dynamic theme switching
|
||||
- Persisted theme preference
|
||||
- Visual theme selection UI
|
||||
|
||||
@Section(title: "Set Up Theme Storage") {
|
||||
@ContentAndMedia {
|
||||
Use `@AppStorage` to remember the user's theme choice across sessions.
|
||||
}
|
||||
|
||||
@Steps {
|
||||
@Step {
|
||||
Create an app that stores the selected theme:
|
||||
|
||||
```swift
|
||||
import TUIKit
|
||||
|
||||
@main
|
||||
struct ThemableApp: App {
|
||||
@AppStorage("selectedTheme") var selectedThemeName: String = "green"
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
.environment(\.theme, themeForName(selectedThemeName))
|
||||
}
|
||||
}
|
||||
|
||||
func themeForName(_ name: String) -> Theme {
|
||||
switch name {
|
||||
case "amber":
|
||||
return AmberPhosphorTheme()
|
||||
case "white":
|
||||
return WhitePhosphorTheme()
|
||||
case "red":
|
||||
return RedPhosphorTheme()
|
||||
default:
|
||||
return GreenPhosphorTheme()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView: View {
|
||||
var body: some View {
|
||||
VStack(spacing: 2) {
|
||||
Text("Themable Application")
|
||||
.bold()
|
||||
.foregroundColor(.theme.accent)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("Select a theme to customize the appearance")
|
||||
.foregroundColor(.theme.foregroundSecondary)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`@AppStorage("selectedTheme")` automatically persists the theme choice.
|
||||
When the app restarts, it loads the saved theme.
|
||||
}
|
||||
|
||||
@Step {
|
||||
Run your app:
|
||||
|
||||
```bash
|
||||
swift run
|
||||
```
|
||||
|
||||
The app launches with the default Green theme.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Section(title: "Create Theme Selection UI") {
|
||||
@ContentAndMedia {
|
||||
Display the 4 available themes and let users select one.
|
||||
}
|
||||
|
||||
@Steps {
|
||||
@Step {
|
||||
Add a theme menu:
|
||||
|
||||
```swift
|
||||
@main
|
||||
struct ThemableApp: App {
|
||||
@AppStorage("selectedTheme") var selectedThemeName: String = "green"
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView(selectedThemeName: $selectedThemeName)
|
||||
.environment(\.theme, themeForName(selectedThemeName))
|
||||
}
|
||||
}
|
||||
|
||||
func themeForName(_ name: String) -> Theme {
|
||||
// ... same as before
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView: View {
|
||||
@Binding var selectedThemeName: String
|
||||
|
||||
let themes = [
|
||||
("green", "🟢 Green (Default)"),
|
||||
("amber", "🟡 Amber"),
|
||||
("white", "⚪ White"),
|
||||
("red", "🔴 Red")
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 2) {
|
||||
Text("Themable Application")
|
||||
.bold()
|
||||
.foregroundColor(.theme.accent)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("Select a theme:")
|
||||
.bold()
|
||||
|
||||
Menu(
|
||||
items: themes.map { id, label in
|
||||
MenuItem(label, id: id)
|
||||
},
|
||||
selection: $selectedThemeName
|
||||
)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("Current: \(themeName(selectedThemeName))")
|
||||
.foregroundColor(.theme.foregroundSecondary)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
|
||||
func themeName(_ id: String) -> String {
|
||||
themes.first(where: { $0.0 == id })?.1 ?? id
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Pass `$selectedThemeName` as a binding to allow the menu to change it.
|
||||
The environment automatically updates because it depends on this value.
|
||||
}
|
||||
|
||||
@Step {
|
||||
Test theme switching:
|
||||
|
||||
```bash
|
||||
swift run
|
||||
```
|
||||
|
||||
Use Tab/Arrow keys to select different themes.
|
||||
Notice the colors change immediately!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Section(title: "Display Theme Colors") {
|
||||
@ContentAndMedia {
|
||||
Show a visual preview of the current theme's colors.
|
||||
}
|
||||
|
||||
@Steps {
|
||||
@Step {
|
||||
Add a color preview:
|
||||
|
||||
```swift
|
||||
struct ContentView: View {
|
||||
@Binding var selectedThemeName: String
|
||||
@Environment(\.theme) var theme
|
||||
|
||||
let themes = [
|
||||
("green", "🟢 Green (Default)"),
|
||||
("amber", "🟡 Amber"),
|
||||
("white", "⚪ White"),
|
||||
("red", "🔴 Red")
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 2) {
|
||||
Text("Themable Application")
|
||||
.bold()
|
||||
.foregroundColor(.theme.accent)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("Select a theme:").bold()
|
||||
|
||||
Menu(
|
||||
items: themes.map { id, label in
|
||||
MenuItem(label, id: id)
|
||||
},
|
||||
selection: $selectedThemeName
|
||||
)
|
||||
|
||||
Spacer()
|
||||
|
||||
// Color preview box
|
||||
VStack(spacing: 1) {
|
||||
Text("Theme Colors")
|
||||
.bold()
|
||||
|
||||
HStack(spacing: 1) {
|
||||
Text(" ").background(theme.foreground)
|
||||
Text(" ").background(theme.accent)
|
||||
Text(" ").background(theme.border)
|
||||
Text(" ").background(theme.warning)
|
||||
}
|
||||
|
||||
Text("Foreground | Accent | Border | Warning")
|
||||
.foregroundColor(.theme.foregroundSecondary)
|
||||
}
|
||||
.padding(1)
|
||||
.border(.rounded)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
|
||||
func themeName(_ id: String) -> String {
|
||||
themes.first(where: { $0.0 == id })?.1 ?? id
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`@Environment(\.theme)` gives access to the current theme.
|
||||
Use `theme.foreground`, `theme.accent`, etc. to access colors.
|
||||
}
|
||||
|
||||
@Step {
|
||||
Run the app:
|
||||
|
||||
```bash
|
||||
swift run
|
||||
```
|
||||
|
||||
Switch themes and see the color preview update.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Section(title: "Add Theme Shortcuts and Status Bar") {
|
||||
@ContentAndMedia {
|
||||
Let users cycle themes quickly with keyboard shortcuts.
|
||||
}
|
||||
|
||||
@Steps {
|
||||
@Step {
|
||||
Add quick theme cycling:
|
||||
|
||||
```swift
|
||||
struct ContentView: View {
|
||||
@Binding var selectedThemeName: String
|
||||
@Environment(\.theme) var theme
|
||||
|
||||
let themes = [
|
||||
("green", "🟢 Green (Default)"),
|
||||
("amber", "🟡 Amber"),
|
||||
("white", "⚪ White"),
|
||||
("red", "🔴 Red")
|
||||
]
|
||||
|
||||
let themeIds = ["green", "amber", "white", "red"]
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 2) {
|
||||
// ... menu UI as before ...
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
.onKeyPress { event in
|
||||
if event.key == .character("t") {
|
||||
// Cycle to next theme
|
||||
if let currentIndex = themeIds.firstIndex(of: selectedThemeName) {
|
||||
let nextIndex = (currentIndex + 1) % themeIds.count
|
||||
selectedThemeName = themeIds[nextIndex]
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
.statusBarItems {
|
||||
StatusBarItem(
|
||||
label: "Cycle Theme",
|
||||
shortcut: Shortcut.letter("t"),
|
||||
action: { }
|
||||
)
|
||||
|
||||
StatusBarItem(
|
||||
label: "Help",
|
||||
shortcut: Shortcut.letter("?"),
|
||||
action: { }
|
||||
)
|
||||
|
||||
StatusBarItem(
|
||||
label: "Quit",
|
||||
shortcut: Shortcut.letter("q"),
|
||||
action: { }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func themeName(_ id: String) -> String {
|
||||
themes.first(where: { $0.0 == id })?.1 ?? id
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now users can press `t` to quickly cycle through themes.
|
||||
}
|
||||
|
||||
@Step {
|
||||
Test theme cycling:
|
||||
|
||||
```bash
|
||||
swift run
|
||||
```
|
||||
|
||||
Press `t` repeatedly to cycle through all 4 themes.
|
||||
The selection updates and the preview colors change.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Section(title: "Enhance with Appearance Switching") {
|
||||
@ContentAndMedia {
|
||||
Add appearance style switching alongside theme switching.
|
||||
}
|
||||
|
||||
@Steps {
|
||||
@Step {
|
||||
Add appearance cycling:
|
||||
|
||||
```swift
|
||||
@main
|
||||
struct ThemableApp: App {
|
||||
@AppStorage("selectedTheme") var selectedThemeName: String = "green"
|
||||
@AppStorage("selectedAppearance") var selectedAppearance: String = "rounded"
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView(
|
||||
selectedThemeName: $selectedThemeName,
|
||||
selectedAppearance: $selectedAppearance
|
||||
)
|
||||
.environment(\.theme, themeForName(selectedThemeName))
|
||||
.environment(\.appearance, appearanceForName(selectedAppearance))
|
||||
}
|
||||
}
|
||||
|
||||
func themeForName(_ name: String) -> Theme {
|
||||
// ... existing code ...
|
||||
}
|
||||
|
||||
func appearanceForName(_ name: String) -> Appearance {
|
||||
switch name {
|
||||
case "line":
|
||||
return .line
|
||||
case "doubled":
|
||||
return .doubleLine
|
||||
case "heavy":
|
||||
return .heavy
|
||||
case "block":
|
||||
return .block
|
||||
default:
|
||||
return .rounded
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now users can customize both theme AND appearance style!
|
||||
}
|
||||
|
||||
@Step {
|
||||
The changes are automatically persisted with `@AppStorage`.
|
||||
Run the app:
|
||||
|
||||
```bash
|
||||
swift run
|
||||
```
|
||||
|
||||
Select a theme and appearance, exit with `q`, and run again.
|
||||
Your selection is remembered!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## Next Steps
|
||||
|
||||
Congratulations! You've built a fully themed, customizable application.
|
||||
|
||||
- Learn more about <doc:Theming> for creating custom themes
|
||||
- Explore <doc:Appearance> for structural styles
|
||||
- See <doc:StateManagement> for advanced state patterns
|
||||
- Check the <doc:Architecture> overview for deeper understanding
|
||||
@@ -1,270 +0,0 @@
|
||||
# Building Your First App
|
||||
|
||||
Create a simple counter application to learn TUIKit basics.
|
||||
|
||||
@Intro(title: "Create Your First TUIKit App") {
|
||||
Learn the fundamentals of building a terminal user interface with TUIKit
|
||||
by creating a simple counter application.
|
||||
|
||||
You'll learn how to set up an `@main` app, use `@State` for local state,
|
||||
add interactive buttons, and use basic layout with `VStack` and `HStack`.
|
||||
}
|
||||
|
||||
## Overview
|
||||
|
||||
In this tutorial, you'll build a working counter app with increment/decrement buttons.
|
||||
This will teach you:
|
||||
|
||||
- Creating an app with the `@main` attribute
|
||||
- Using `VStack` and `HStack` for layout
|
||||
- Handling button taps with `@State`
|
||||
- Running and testing your app
|
||||
|
||||
@Section(title: "Create the App Entry Point") {
|
||||
@ContentAndMedia {
|
||||
Every TUIKit app needs an entry point decorated with `@main`.
|
||||
This tells Swift to use your app as the entry point for the program.
|
||||
}
|
||||
|
||||
@Steps {
|
||||
@Step {
|
||||
Create a new file called `main.swift` in your project:
|
||||
|
||||
```swift
|
||||
import TUIKit
|
||||
|
||||
@main
|
||||
struct CounterApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
Text("Hello, TUIKit!")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `@main` attribute marks this as the app entry point.
|
||||
`WindowGroup` represents the main window of your terminal app.
|
||||
}
|
||||
|
||||
@Step {
|
||||
Run your app with:
|
||||
|
||||
```bash
|
||||
swift run
|
||||
```
|
||||
|
||||
You should see "Hello, TUIKit!" displayed in the terminal.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Section(title: "Add Layout and Text") {
|
||||
@ContentAndMedia {
|
||||
Now let's organize content with `VStack` (vertical layout).
|
||||
We'll add a title and multiple text lines.
|
||||
}
|
||||
|
||||
@Steps {
|
||||
@Step {
|
||||
Modify the `body` to use `VStack`:
|
||||
|
||||
```swift
|
||||
@main
|
||||
struct CounterApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
VStack(spacing: 1) {
|
||||
Text("Counter App")
|
||||
.bold()
|
||||
|
||||
Text("Simple counter to learn TUIKit")
|
||||
.foregroundColor(.theme.foregroundSecondary)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("Current count: 0")
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `VStack(spacing: 1)` arranges content vertically with 1-unit spacing
|
||||
- `.bold()` makes the title bold
|
||||
- `.foregroundColor()` colors text
|
||||
- `Spacer()` creates flexible vertical space
|
||||
- `.padding()` adds space around all edges
|
||||
}
|
||||
|
||||
@Step {
|
||||
Run the app again:
|
||||
|
||||
```bash
|
||||
swift run
|
||||
```
|
||||
|
||||
Now you should see a nicely formatted display with title,
|
||||
description, and spacing.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Section(title: "Add Interactive State") {
|
||||
@ContentAndMedia {
|
||||
Use `@State` to track the counter value and re-render when it changes.
|
||||
This makes your app interactive!
|
||||
}
|
||||
|
||||
@Steps {
|
||||
@Step {
|
||||
Add a `@State` property for the counter:
|
||||
|
||||
```swift
|
||||
@main
|
||||
struct CounterApp: App {
|
||||
@State private var count: Int = 0
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
VStack(spacing: 1) {
|
||||
Text("Counter App")
|
||||
.bold()
|
||||
|
||||
Text("Simple counter to learn TUIKit")
|
||||
.foregroundColor(.theme.foregroundSecondary)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("Current count: \(count)")
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `@State` property wrapper stores local state. When `count` changes,
|
||||
the view automatically re-renders.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Section(title: "Add Buttons") {
|
||||
@ContentAndMedia {
|
||||
Now add buttons to increment and decrement the counter.
|
||||
Use `HStack` to arrange them horizontally.
|
||||
}
|
||||
|
||||
@Steps {
|
||||
@Step {
|
||||
Add buttons using `HStack`:
|
||||
|
||||
```swift
|
||||
@main
|
||||
struct CounterApp: App {
|
||||
@State private var count: Int = 0
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
VStack(spacing: 1) {
|
||||
Text("Counter App")
|
||||
.bold()
|
||||
|
||||
Text("Simple counter to learn TUIKit")
|
||||
.foregroundColor(.theme.foregroundSecondary)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("Current count: \(count)")
|
||||
|
||||
HStack(spacing: 2) {
|
||||
Button("Decrement") { count -= 1 }
|
||||
Button("Increment") { count += 1 }
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("Press 'q' to quit")
|
||||
.foregroundColor(.theme.foregroundTertiary)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `HStack(spacing: 2)` arranges buttons horizontally
|
||||
- `Button(label) { action }` creates a clickable button
|
||||
- The closure after the label runs when the button is pressed
|
||||
}
|
||||
|
||||
@Step {
|
||||
Run your app:
|
||||
|
||||
```bash
|
||||
swift run
|
||||
```
|
||||
|
||||
Now use Tab to navigate to the buttons and press Enter to increment/decrement.
|
||||
The counter value updates in real-time!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Section(title: "Test and Iterate") {
|
||||
@ContentAndMedia {
|
||||
Test your counter app and try making improvements.
|
||||
}
|
||||
|
||||
@Steps {
|
||||
@Step {
|
||||
Test the following interactions:
|
||||
|
||||
- Press `Tab` to move focus to the next button
|
||||
- Press `Shift+Tab` to move focus backward
|
||||
- Press `Enter` when a button is focused to activate it
|
||||
- Watch the counter update
|
||||
- Press `q` to quit the app
|
||||
- Press `t` to cycle through themes
|
||||
- Press `a` to cycle through appearance styles
|
||||
}
|
||||
|
||||
@Step {
|
||||
Try these enhancements:
|
||||
|
||||
Add a reset button:
|
||||
|
||||
```swift
|
||||
HStack(spacing: 2) {
|
||||
Button("Decrement") { count = max(0, count - 1) }
|
||||
Button("Reset") { count = 0 }
|
||||
Button("Increment") { count += 1 }
|
||||
}
|
||||
```
|
||||
|
||||
Or add a border around the counter:
|
||||
|
||||
```swift
|
||||
Text("Current count: \(count)")
|
||||
.bold()
|
||||
.padding(1)
|
||||
.border(.rounded)
|
||||
```
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## Next Steps
|
||||
|
||||
Congratulations! You've built your first TUIKit app.
|
||||
|
||||
- Learn more about <doc:StateManagement> for complex state scenarios
|
||||
- Explore <doc:Theming> to customize colors
|
||||
- Try building an interactive <doc:BuildInteractiveMenu>
|
||||
- Check out <doc:Modifiers> for more styling options
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
{"hierarchy":{"paths":[["doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit"]]},"identifier":{"url":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/BuildInteractiveMenu","interfaceLanguage":"swift"},"metadata":{"role":"article","roleHeading":"Article","title":"Building an Interactive Menu"},"schemaVersion":{"minor":3,"patch":0,"major":0},"kind":"article","primaryContentSections":[{"kind":"content","content":[{"anchor":"Overview","text":"Overview","level":2,"type":"heading"},{"inlineContent":[{"type":"text","text":"In this tutorial, you’ll create a menu-driven application featuring:"}],"type":"paragraph"},{"items":[{"content":[{"type":"paragraph","inlineContent":[{"type":"codeVoice","code":"Menu"},{"text":" component for selection","type":"text"}]}]},{"content":[{"inlineContent":[{"text":"Keyboard shortcut handling","type":"text"}],"type":"paragraph"}]},{"content":[{"type":"paragraph","inlineContent":[{"text":"Status bar with hints","type":"text"}]}]},{"content":[{"type":"paragraph","inlineContent":[{"type":"text","text":"Page navigation patterns"}]}]}],"type":"unorderedList"},{"anchor":"Next-Steps","text":"Next Steps","level":2,"type":"heading"},{"inlineContent":[{"type":"text","text":"You’ve created an interactive menu-driven application!"}],"type":"paragraph"},{"items":[{"content":[{"inlineContent":[{"text":"Learn about ","type":"text"},{"type":"reference","isActive":true,"identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/Focus"},{"text":" for advanced focus management","type":"text"}],"type":"paragraph"}]},{"content":[{"type":"paragraph","inlineContent":[{"text":"Explore ","type":"text"},{"identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/StateManagement","isActive":true,"type":"reference"},{"text":" for more complex state patterns","type":"text"}]}]},{"content":[{"type":"paragraph","inlineContent":[{"type":"text","text":"Try building a "},{"identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/BuildThemableUI","type":"reference","isActive":true},{"type":"text","text":" with theme switching"}]}]},{"content":[{"type":"paragraph","inlineContent":[{"type":"text","text":"Check out "},{"identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/Appearance","type":"reference","isActive":true},{"type":"text","text":" for custom styling"}]}]}],"type":"unorderedList"}]}],"sections":[],"abstract":[{"type":"text","text":"Create a navigation menu with keyboard shortcuts and status bar hints."}],"references":{"doc://com.anthropic.tuikit.documentation/documentation/TUIKit":{"role":"collection","type":"topic","kind":"article","abstract":[],"title":"TUIKit","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit","url":"\/documentation\/tuikit"},"doc://com.anthropic.tuikit.documentation/documentation/TUIKit/BuildThemableUI":{"abstract":[{"type":"text","text":"Create an application with dynamic theme switching and persistence."}],"type":"topic","title":"Building a Themable UI","role":"article","url":"\/documentation\/tuikit\/buildthemableui","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/BuildThemableUI","kind":"article"},"doc://com.anthropic.tuikit.documentation/documentation/TUIKit/Appearance":{"url":"\/documentation\/tuikit\/appearance","title":"Appearance System","kind":"article","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/Appearance","type":"topic","abstract":[{"text":"Learn about the 5 structural appearance styles for rendering borders and containers.","type":"text"}],"role":"article"},"doc://com.anthropic.tuikit.documentation/documentation/TUIKit/Focus":{"abstract":[{"text":"Understand how keyboard navigation and focus works in TUIKit.","type":"text"}],"type":"topic","role":"article","title":"Focus Management","url":"\/documentation\/tuikit\/focus","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/Focus","kind":"article"},"doc://com.anthropic.tuikit.documentation/documentation/TUIKit/StateManagement":{"identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/StateManagement","kind":"article","url":"\/documentation\/tuikit\/statemanagement","abstract":[{"type":"text","text":"Learn how to manage application state and data flow in TUIKit."}],"title":"State Management","role":"article","type":"topic"}}}
|
||||
@@ -1 +0,0 @@
|
||||
{"hierarchy":{"paths":[["doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit"]]},"schemaVersion":{"minor":3,"major":0,"patch":0},"sections":[],"identifier":{"url":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/BuildThemableUI","interfaceLanguage":"swift"},"kind":"article","abstract":[{"type":"text","text":"Create an application with dynamic theme switching and persistence."}],"metadata":{"title":"Building a Themable UI","roleHeading":"Article","role":"article"},"primaryContentSections":[{"content":[{"type":"heading","text":"Overview","anchor":"Overview","level":2},{"type":"paragraph","inlineContent":[{"type":"text","text":"In this tutorial, you’ll create an app that features:"}]},{"type":"unorderedList","items":[{"content":[{"type":"paragraph","inlineContent":[{"text":"Theme environment integration","type":"text"}]}]},{"content":[{"type":"paragraph","inlineContent":[{"text":"Dynamic theme switching","type":"text"}]}]},{"content":[{"type":"paragraph","inlineContent":[{"type":"text","text":"Persisted theme preference"}]}]},{"content":[{"inlineContent":[{"text":"Visual theme selection UI","type":"text"}],"type":"paragraph"}]}]},{"type":"heading","text":"Next Steps","anchor":"Next-Steps","level":2},{"type":"paragraph","inlineContent":[{"type":"text","text":"Congratulations! You’ve built a fully themed, customizable application."}]},{"type":"unorderedList","items":[{"content":[{"inlineContent":[{"type":"text","text":"Learn more about "},{"identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/Theming","type":"reference","isActive":true},{"type":"text","text":" for creating custom themes"}],"type":"paragraph"}]},{"content":[{"inlineContent":[{"text":"Explore ","type":"text"},{"isActive":true,"type":"reference","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/Appearance"},{"text":" for structural styles","type":"text"}],"type":"paragraph"}]},{"content":[{"type":"paragraph","inlineContent":[{"type":"text","text":"See "},{"type":"reference","isActive":true,"identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/StateManagement"},{"type":"text","text":" for advanced state patterns"}]}]},{"content":[{"type":"paragraph","inlineContent":[{"type":"text","text":"Check the "},{"type":"reference","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/Architecture","isActive":true},{"type":"text","text":" overview for deeper understanding"}]}]}]}],"kind":"content"}],"references":{"doc://com.anthropic.tuikit.documentation/documentation/TUIKit/Architecture":{"type":"topic","kind":"article","abstract":[{"type":"text","text":"Understand the architecture and design patterns that power TUIKit."}],"url":"\/documentation\/tuikit\/architecture","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/Architecture","title":"Architecture Overview","role":"article"},"doc://com.anthropic.tuikit.documentation/documentation/TUIKit":{"role":"collection","type":"topic","kind":"article","abstract":[],"title":"TUIKit","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit","url":"\/documentation\/tuikit"},"doc://com.anthropic.tuikit.documentation/documentation/TUIKit/Theming":{"title":"Theming System","type":"topic","role":"article","abstract":[{"type":"text","text":"Customize the appearance of your application with TUIKit’s flexible theming system."}],"kind":"article","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/Theming","url":"\/documentation\/tuikit\/theming"},"doc://com.anthropic.tuikit.documentation/documentation/TUIKit/Appearance":{"url":"\/documentation\/tuikit\/appearance","title":"Appearance System","kind":"article","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/Appearance","type":"topic","abstract":[{"text":"Learn about the 5 structural appearance styles for rendering borders and containers.","type":"text"}],"role":"article"},"doc://com.anthropic.tuikit.documentation/documentation/TUIKit/StateManagement":{"identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/StateManagement","kind":"article","url":"\/documentation\/tuikit\/statemanagement","abstract":[{"type":"text","text":"Learn how to manage application state and data flow in TUIKit."}],"title":"State Management","role":"article","type":"topic"}}}
|
||||
@@ -1 +0,0 @@
|
||||
{"hierarchy":{"paths":[["doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit"]]},"kind":"article","metadata":{"title":"Building Your First App","role":"article","roleHeading":"Article"},"primaryContentSections":[{"content":[{"anchor":"Overview","type":"heading","text":"Overview","level":2},{"inlineContent":[{"type":"text","text":"In this tutorial, you’ll build a working counter app with increment\/decrement buttons."},{"type":"text","text":" "},{"type":"text","text":"This will teach you:"}],"type":"paragraph"},{"type":"unorderedList","items":[{"content":[{"type":"paragraph","inlineContent":[{"type":"text","text":"Creating an app with the "},{"type":"codeVoice","code":"@main"},{"type":"text","text":" attribute"}]}]},{"content":[{"inlineContent":[{"text":"Using ","type":"text"},{"type":"codeVoice","code":"VStack"},{"text":" and ","type":"text"},{"type":"codeVoice","code":"HStack"},{"text":" for layout","type":"text"}],"type":"paragraph"}]},{"content":[{"type":"paragraph","inlineContent":[{"text":"Handling button taps with ","type":"text"},{"code":"@State","type":"codeVoice"}]}]},{"content":[{"inlineContent":[{"type":"text","text":"Running and testing your app"}],"type":"paragraph"}]}]},{"anchor":"Next-Steps","type":"heading","text":"Next Steps","level":2},{"inlineContent":[{"type":"text","text":"Congratulations! You’ve built your first TUIKit app."}],"type":"paragraph"},{"type":"unorderedList","items":[{"content":[{"type":"paragraph","inlineContent":[{"text":"Learn more about ","type":"text"},{"identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/StateManagement","type":"reference","isActive":true},{"text":" for complex state scenarios","type":"text"}]}]},{"content":[{"type":"paragraph","inlineContent":[{"text":"Explore ","type":"text"},{"identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/Theming","type":"reference","isActive":true},{"text":" to customize colors","type":"text"}]}]},{"content":[{"type":"paragraph","inlineContent":[{"type":"text","text":"Try building an interactive "},{"type":"reference","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/BuildInteractiveMenu","isActive":true}]}]},{"content":[{"type":"paragraph","inlineContent":[{"text":"Check out ","type":"text"},{"isActive":true,"identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/Modifiers","type":"reference"},{"text":" for more styling options","type":"text"}]}]}]}],"kind":"content"}],"schemaVersion":{"major":0,"minor":3,"patch":0},"abstract":[{"type":"text","text":"Create a simple counter application to learn TUIKit basics."}],"identifier":{"interfaceLanguage":"swift","url":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/BuildYourFirstApp"},"sections":[],"references":{"doc://com.anthropic.tuikit.documentation/documentation/TUIKit/StateManagement":{"identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/StateManagement","kind":"article","url":"\/documentation\/tuikit\/statemanagement","abstract":[{"type":"text","text":"Learn how to manage application state and data flow in TUIKit."}],"title":"State Management","role":"article","type":"topic"},"doc://com.anthropic.tuikit.documentation/documentation/TUIKit/Modifiers":{"title":"View Modifiers","type":"topic","role":"article","abstract":[{"type":"text","text":"Learn how to use modifiers to customize the appearance and behavior of views."}],"kind":"article","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/Modifiers","url":"\/documentation\/tuikit\/modifiers"},"doc://com.anthropic.tuikit.documentation/documentation/TUIKit/Theming":{"title":"Theming System","type":"topic","role":"article","abstract":[{"type":"text","text":"Customize the appearance of your application with TUIKit’s flexible theming system."}],"kind":"article","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/Theming","url":"\/documentation\/tuikit\/theming"},"doc://com.anthropic.tuikit.documentation/documentation/TUIKit":{"role":"collection","type":"topic","kind":"article","abstract":[],"title":"TUIKit","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit","url":"\/documentation\/tuikit"},"doc://com.anthropic.tuikit.documentation/documentation/TUIKit/BuildInteractiveMenu":{"title":"Building an Interactive Menu","abstract":[{"type":"text","text":"Create a navigation menu with keyboard shortcuts and status bar hints."}],"role":"article","kind":"article","url":"\/documentation\/tuikit\/buildinteractivemenu","identifier":"doc:\/\/com.anthropic.tuikit.documentation\/documentation\/TUIKit\/BuildInteractiveMenu","type":"topic"}}}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="en-US" class="no-js"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><link rel="icon" href="/favicon.ico"><link rel="mask-icon" href="/favicon.svg" color="#333333"><title>Documentation</title><script>var baseUrl = "/"</script><script defer="defer" src="/js/chunk-vendors.bdb7cbba.js"></script><script defer="defer" src="/js/index.d2f6f6a9.js"></script><link href="/css/index.3a335429.css" rel="stylesheet"></head><body data-color-scheme="auto"><noscript><style>.noscript{font-family:"SF Pro Display","SF Pro Icons","Helvetica Neue",Helvetica,Arial,sans-serif;margin:92px auto 140px auto;text-align:center;width:980px}.noscript-title{color:#111;font-size:48px;font-weight:600;letter-spacing:-.003em;line-height:1.08365;margin:0 auto 54px auto;width:502px}@media only screen and (max-width:1068px){.noscript{margin:90px auto 120px auto;width:692px}.noscript-title{font-size:40px;letter-spacing:0;line-height:1.1;margin:0 auto 45px auto;width:420px}}@media only screen and (max-width:735px){.noscript{margin:45px auto 60px auto;width:87.5%}.noscript-title{font-size:32px;letter-spacing:.004em;line-height:1.125;margin:0 auto 35px auto;max-width:330px;width:auto}}#loading-placeholder{display:none}</style><div class="noscript"><h1 class="noscript-title">This page requires JavaScript.</h1><p>Please turn on JavaScript in your browser and refresh the page to view its content.</p></div></noscript><div id="app"></div></body></html>
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="en-US" class="no-js"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><link rel="icon" href="/favicon.ico"><link rel="mask-icon" href="/favicon.svg" color="#333333"><title>Documentation</title><script>var baseUrl = "/"</script><script defer="defer" src="/js/chunk-vendors.bdb7cbba.js"></script><script defer="defer" src="/js/index.d2f6f6a9.js"></script><link href="/css/index.3a335429.css" rel="stylesheet"></head><body data-color-scheme="auto"><noscript><style>.noscript{font-family:"SF Pro Display","SF Pro Icons","Helvetica Neue",Helvetica,Arial,sans-serif;margin:92px auto 140px auto;text-align:center;width:980px}.noscript-title{color:#111;font-size:48px;font-weight:600;letter-spacing:-.003em;line-height:1.08365;margin:0 auto 54px auto;width:502px}@media only screen and (max-width:1068px){.noscript{margin:90px auto 120px auto;width:692px}.noscript-title{font-size:40px;letter-spacing:0;line-height:1.1;margin:0 auto 45px auto;width:420px}}@media only screen and (max-width:735px){.noscript{margin:45px auto 60px auto;width:87.5%}.noscript-title{font-size:32px;letter-spacing:.004em;line-height:1.125;margin:0 auto 35px auto;max-width:330px;width:auto}}#loading-placeholder{display:none}</style><div class="noscript"><h1 class="noscript-title">This page requires JavaScript.</h1><p>Please turn on JavaScript in your browser and refresh the page to view its content.</p></div></noscript><div id="app"></div></body></html>
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="en-US" class="no-js"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><link rel="icon" href="/favicon.ico"><link rel="mask-icon" href="/favicon.svg" color="#333333"><title>Documentation</title><script>var baseUrl = "/"</script><script defer="defer" src="/js/chunk-vendors.bdb7cbba.js"></script><script defer="defer" src="/js/index.d2f6f6a9.js"></script><link href="/css/index.3a335429.css" rel="stylesheet"></head><body data-color-scheme="auto"><noscript><style>.noscript{font-family:"SF Pro Display","SF Pro Icons","Helvetica Neue",Helvetica,Arial,sans-serif;margin:92px auto 140px auto;text-align:center;width:980px}.noscript-title{color:#111;font-size:48px;font-weight:600;letter-spacing:-.003em;line-height:1.08365;margin:0 auto 54px auto;width:502px}@media only screen and (max-width:1068px){.noscript{margin:90px auto 120px auto;width:692px}.noscript-title{font-size:40px;letter-spacing:0;line-height:1.1;margin:0 auto 45px auto;width:420px}}@media only screen and (max-width:735px){.noscript{margin:45px auto 60px auto;width:87.5%}.noscript-title{font-size:32px;letter-spacing:.004em;line-height:1.125;margin:0 auto 35px auto;max-width:330px;width:auto}}#loading-placeholder{display:none}</style><div class="noscript"><h1 class="noscript-title">This page requires JavaScript.</h1><p>Please turn on JavaScript in your browser and refresh the page to view its content.</p></div></noscript><div id="app"></div></body></html>
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="en-US" class="no-js"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><link rel="icon" href="/favicon.ico"><link rel="mask-icon" href="/favicon.svg" color="#333333"><title>Documentation</title><script>var baseUrl = "/"</script><script defer="defer" src="/js/chunk-vendors.bdb7cbba.js"></script><script defer="defer" src="/js/index.d2f6f6a9.js"></script><link href="/css/index.3a335429.css" rel="stylesheet"></head><body data-color-scheme="auto"><noscript><style>.noscript{font-family:"SF Pro Display","SF Pro Icons","Helvetica Neue",Helvetica,Arial,sans-serif;margin:92px auto 140px auto;text-align:center;width:980px}.noscript-title{color:#111;font-size:48px;font-weight:600;letter-spacing:-.003em;line-height:1.08365;margin:0 auto 54px auto;width:502px}@media only screen and (max-width:1068px){.noscript{margin:90px auto 120px auto;width:692px}.noscript-title{font-size:40px;letter-spacing:0;line-height:1.1;margin:0 auto 45px auto;width:420px}}@media only screen and (max-width:735px){.noscript{margin:45px auto 60px auto;width:87.5%}.noscript-title{font-size:32px;letter-spacing:.004em;line-height:1.125;margin:0 auto 35px auto;max-width:330px;width:auto}}#loading-placeholder{display:none}</style><div class="noscript"><h1 class="noscript-title">This page requires JavaScript.</h1><p>Please turn on JavaScript in your browser and refresh the page to view its content.</p></div></noscript><div id="app"></div></body></html>
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="en-US" class="no-js"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><link rel="icon" href="/favicon.ico"><link rel="mask-icon" href="/favicon.svg" color="#333333"><title>Documentation</title><script>var baseUrl = "/"</script><script defer="defer" src="/js/chunk-vendors.bdb7cbba.js"></script><script defer="defer" src="/js/index.d2f6f6a9.js"></script><link href="/css/index.3a335429.css" rel="stylesheet"></head><body data-color-scheme="auto"><noscript><style>.noscript{font-family:"SF Pro Display","SF Pro Icons","Helvetica Neue",Helvetica,Arial,sans-serif;margin:92px auto 140px auto;text-align:center;width:980px}.noscript-title{color:#111;font-size:48px;font-weight:600;letter-spacing:-.003em;line-height:1.08365;margin:0 auto 54px auto;width:502px}@media only screen and (max-width:1068px){.noscript{margin:90px auto 120px auto;width:692px}.noscript-title{font-size:40px;letter-spacing:0;line-height:1.1;margin:0 auto 45px auto;width:420px}}@media only screen and (max-width:735px){.noscript{margin:45px auto 60px auto;width:87.5%}.noscript-title{font-size:32px;letter-spacing:.004em;line-height:1.125;margin:0 auto 35px auto;max-width:330px;width:auto}}#loading-placeholder{display:none}</style><div class="noscript"><h1 class="noscript-title">This page requires JavaScript.</h1><p>Please turn on JavaScript in your browser and refresh the page to view its content.</p></div></noscript><div id="app"></div></body></html>
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="en-US" class="no-js"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><link rel="icon" href="/favicon.ico"><link rel="mask-icon" href="/favicon.svg" color="#333333"><title>Documentation</title><script>var baseUrl = "/"</script><script defer="defer" src="/js/chunk-vendors.bdb7cbba.js"></script><script defer="defer" src="/js/index.d2f6f6a9.js"></script><link href="/css/index.3a335429.css" rel="stylesheet"></head><body data-color-scheme="auto"><noscript><style>.noscript{font-family:"SF Pro Display","SF Pro Icons","Helvetica Neue",Helvetica,Arial,sans-serif;margin:92px auto 140px auto;text-align:center;width:980px}.noscript-title{color:#111;font-size:48px;font-weight:600;letter-spacing:-.003em;line-height:1.08365;margin:0 auto 54px auto;width:502px}@media only screen and (max-width:1068px){.noscript{margin:90px auto 120px auto;width:692px}.noscript-title{font-size:40px;letter-spacing:0;line-height:1.1;margin:0 auto 45px auto;width:420px}}@media only screen and (max-width:735px){.noscript{margin:45px auto 60px auto;width:87.5%}.noscript-title{font-size:32px;letter-spacing:.004em;line-height:1.125;margin:0 auto 35px auto;max-width:330px;width:auto}}#loading-placeholder{display:none}</style><div class="noscript"><h1 class="noscript-title">This page requires JavaScript.</h1><p>Please turn on JavaScript in your browser and refresh the page to view its content.</p></div></noscript><div id="app"></div></body></html>
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="en-US" class="no-js"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><link rel="icon" href="/favicon.ico"><link rel="mask-icon" href="/favicon.svg" color="#333333"><title>Documentation</title><script>var baseUrl = "/"</script><script defer="defer" src="/js/chunk-vendors.bdb7cbba.js"></script><script defer="defer" src="/js/index.d2f6f6a9.js"></script><link href="/css/index.3a335429.css" rel="stylesheet"></head><body data-color-scheme="auto"><noscript><style>.noscript{font-family:"SF Pro Display","SF Pro Icons","Helvetica Neue",Helvetica,Arial,sans-serif;margin:92px auto 140px auto;text-align:center;width:980px}.noscript-title{color:#111;font-size:48px;font-weight:600;letter-spacing:-.003em;line-height:1.08365;margin:0 auto 54px auto;width:502px}@media only screen and (max-width:1068px){.noscript{margin:90px auto 120px auto;width:692px}.noscript-title{font-size:40px;letter-spacing:0;line-height:1.1;margin:0 auto 45px auto;width:420px}}@media only screen and (max-width:735px){.noscript{margin:45px auto 60px auto;width:87.5%}.noscript-title{font-size:32px;letter-spacing:.004em;line-height:1.125;margin:0 auto 35px auto;max-width:330px;width:auto}}#loading-placeholder{display:none}</style><div class="noscript"><h1 class="noscript-title">This page requires JavaScript.</h1><p>Please turn on JavaScript in your browser and refresh the page to view its content.</p></div></noscript><div id="app"></div></body></html>
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="en-US" class="no-js"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><link rel="icon" href="/favicon.ico"><link rel="mask-icon" href="/favicon.svg" color="#333333"><title>Documentation</title><script>var baseUrl = "/"</script><script defer="defer" src="/js/chunk-vendors.bdb7cbba.js"></script><script defer="defer" src="/js/index.d2f6f6a9.js"></script><link href="/css/index.3a335429.css" rel="stylesheet"></head><body data-color-scheme="auto"><noscript><style>.noscript{font-family:"SF Pro Display","SF Pro Icons","Helvetica Neue",Helvetica,Arial,sans-serif;margin:92px auto 140px auto;text-align:center;width:980px}.noscript-title{color:#111;font-size:48px;font-weight:600;letter-spacing:-.003em;line-height:1.08365;margin:0 auto 54px auto;width:502px}@media only screen and (max-width:1068px){.noscript{margin:90px auto 120px auto;width:692px}.noscript-title{font-size:40px;letter-spacing:0;line-height:1.1;margin:0 auto 45px auto;width:420px}}@media only screen and (max-width:735px){.noscript{margin:45px auto 60px auto;width:87.5%}.noscript-title{font-size:32px;letter-spacing:.004em;line-height:1.125;margin:0 auto 35px auto;max-width:330px;width:auto}}#loading-placeholder{display:none}</style><div class="noscript"><h1 class="noscript-title">This page requires JavaScript.</h1><p>Please turn on JavaScript in your browser and refresh the page to view its content.</p></div></noscript><div id="app"></div></body></html>
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="en-US" class="no-js"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><link rel="icon" href="/favicon.ico"><link rel="mask-icon" href="/favicon.svg" color="#333333"><title>Documentation</title><script>var baseUrl = "/"</script><script defer="defer" src="/js/chunk-vendors.bdb7cbba.js"></script><script defer="defer" src="/js/index.d2f6f6a9.js"></script><link href="/css/index.3a335429.css" rel="stylesheet"></head><body data-color-scheme="auto"><noscript><style>.noscript{font-family:"SF Pro Display","SF Pro Icons","Helvetica Neue",Helvetica,Arial,sans-serif;margin:92px auto 140px auto;text-align:center;width:980px}.noscript-title{color:#111;font-size:48px;font-weight:600;letter-spacing:-.003em;line-height:1.08365;margin:0 auto 54px auto;width:502px}@media only screen and (max-width:1068px){.noscript{margin:90px auto 120px auto;width:692px}.noscript-title{font-size:40px;letter-spacing:0;line-height:1.1;margin:0 auto 45px auto;width:420px}}@media only screen and (max-width:735px){.noscript{margin:45px auto 60px auto;width:87.5%}.noscript-title{font-size:32px;letter-spacing:.004em;line-height:1.125;margin:0 auto 35px auto;max-width:330px;width:auto}}#loading-placeholder{display:none}</style><div class="noscript"><h1 class="noscript-title">This page requires JavaScript.</h1><p>Please turn on JavaScript in your browser and refresh the page to view its content.</p></div></noscript><div id="app"></div></body></html>
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="en-US" class="no-js"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><link rel="icon" href="/favicon.ico"><link rel="mask-icon" href="/favicon.svg" color="#333333"><title>Documentation</title><script>var baseUrl = "/"</script><script defer="defer" src="/js/chunk-vendors.bdb7cbba.js"></script><script defer="defer" src="/js/index.d2f6f6a9.js"></script><link href="/css/index.3a335429.css" rel="stylesheet"></head><body data-color-scheme="auto"><noscript><style>.noscript{font-family:"SF Pro Display","SF Pro Icons","Helvetica Neue",Helvetica,Arial,sans-serif;margin:92px auto 140px auto;text-align:center;width:980px}.noscript-title{color:#111;font-size:48px;font-weight:600;letter-spacing:-.003em;line-height:1.08365;margin:0 auto 54px auto;width:502px}@media only screen and (max-width:1068px){.noscript{margin:90px auto 120px auto;width:692px}.noscript-title{font-size:40px;letter-spacing:0;line-height:1.1;margin:0 auto 45px auto;width:420px}}@media only screen and (max-width:735px){.noscript{margin:45px auto 60px auto;width:87.5%}.noscript-title{font-size:32px;letter-spacing:.004em;line-height:1.125;margin:0 auto 35px auto;max-width:330px;width:auto}}#loading-placeholder{display:none}</style><div class="noscript"><h1 class="noscript-title">This page requires JavaScript.</h1><p>Please turn on JavaScript in your browser and refresh the page to view its content.</p></div></noscript><div id="app"></div></body></html>
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="en-US" class="no-js"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><link rel="icon" href="/favicon.ico"><link rel="mask-icon" href="/favicon.svg" color="#333333"><title>Documentation</title><script>var baseUrl = "/"</script><script defer="defer" src="/js/chunk-vendors.bdb7cbba.js"></script><script defer="defer" src="/js/index.d2f6f6a9.js"></script><link href="/css/index.3a335429.css" rel="stylesheet"></head><body data-color-scheme="auto"><noscript><style>.noscript{font-family:"SF Pro Display","SF Pro Icons","Helvetica Neue",Helvetica,Arial,sans-serif;margin:92px auto 140px auto;text-align:center;width:980px}.noscript-title{color:#111;font-size:48px;font-weight:600;letter-spacing:-.003em;line-height:1.08365;margin:0 auto 54px auto;width:502px}@media only screen and (max-width:1068px){.noscript{margin:90px auto 120px auto;width:692px}.noscript-title{font-size:40px;letter-spacing:0;line-height:1.1;margin:0 auto 45px auto;width:420px}}@media only screen and (max-width:735px){.noscript{margin:45px auto 60px auto;width:87.5%}.noscript-title{font-size:32px;letter-spacing:.004em;line-height:1.125;margin:0 auto 35px auto;max-width:330px;width:auto}}#loading-placeholder{display:none}</style><div class="noscript"><h1 class="noscript-title">This page requires JavaScript.</h1><p>Please turn on JavaScript in your browser and refresh the page to view its content.</p></div></noscript><div id="app"></div></body></html>
|
||||
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="en-US" class="no-js"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><link rel="icon" href="/favicon.ico"><link rel="mask-icon" href="/favicon.svg" color="#333333"><title>Documentation</title><script>var baseUrl = "/"</script><script defer="defer" src="/js/chunk-vendors.bdb7cbba.js"></script><script defer="defer" src="/js/index.d2f6f6a9.js"></script><link href="/css/index.3a335429.css" rel="stylesheet"></head><body data-color-scheme="auto"><noscript><style>.noscript{font-family:"SF Pro Display","SF Pro Icons","Helvetica Neue",Helvetica,Arial,sans-serif;margin:92px auto 140px auto;text-align:center;width:980px}.noscript-title{color:#111;font-size:48px;font-weight:600;letter-spacing:-.003em;line-height:1.08365;margin:0 auto 54px auto;width:502px}@media only screen and (max-width:1068px){.noscript{margin:90px auto 120px auto;width:692px}.noscript-title{font-size:40px;letter-spacing:0;line-height:1.1;margin:0 auto 45px auto;width:420px}}@media only screen and (max-width:735px){.noscript{margin:45px auto 60px auto;width:87.5%}.noscript-title{font-size:32px;letter-spacing:.004em;line-height:1.125;margin:0 auto 35px auto;max-width:330px;width:auto}}#loading-placeholder{display:none}</style><div class="noscript"><h1 class="noscript-title">This page requires JavaScript.</h1><p>Please turn on JavaScript in your browser and refresh the page to view its content.</p></div></noscript><div id="app"></div></body></html>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,11 +0,0 @@
|
||||
<!--
|
||||
This source file is part of the Swift.org open source project
|
||||
|
||||
Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
|
||||
See https://swift.org/LICENSE.txt for license information
|
||||
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
-->
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 25"><path d="M12.5.5a12,12,0,1,0,12,12A12,12,0,0,0,12.5.5ZM1.525,13H6.014a20.83,20.83,0,0,0,.469,4.031h-4A10.924,10.924,0,0,1,1.525,13ZM13,6.969V1.552c1.734.339,3.32,2.417,4.222,5.417Zm4.49,1a19.808,19.808,0,0,1,.5,4.031H13V7.969ZM12,1.552V6.969H7.778C8.68,3.969,10.266,1.891,12,1.552Zm0,6.417V12H7.013a19.808,19.808,0,0,1,.5-4.031ZM6.014,12H1.525a10.924,10.924,0,0,1,.96-4.031h4A20.83,20.83,0,0,0,6.014,12Zm1,1H12v4.031H7.51A19.808,19.808,0,0,1,7.013,13ZM12,18.031v5.417c-1.734-.339-3.32-2.417-4.222-5.417Zm1,5.417V18.031h4.222C16.32,21.031,14.734,23.109,13,23.448Zm0-6.417V13h4.987a19.808,19.808,0,0,1-.5,4.031ZM18.986,13h4.489a10.924,10.924,0,0,1-.96,4.031h-4A20.83,20.83,0,0,0,18.986,13Zm0-1a20.83,20.83,0,0,0-.469-4.031h4A10.924,10.924,0,0,1,23.475,12ZM22,6.969H18.265A11.6,11.6,0,0,0,15.6,1.951,11.007,11.007,0,0,1,22,6.969ZM9.4,1.951A11.6,11.6,0,0,0,6.735,6.969H3A11.007,11.007,0,0,1,9.4,1.951ZM3,18.031H6.735A11.6,11.6,0,0,0,9.4,23.049,11.007,11.007,0,0,1,3,18.031Zm12.6,5.018a11.6,11.6,0,0,0,2.665-5.018H22A11.007,11.007,0,0,1,15.6,23.049Z" fill-rule="evenodd"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1 +0,0 @@
|
||||
<!doctype html><html lang="en-US" class="no-js"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><link rel="icon" href="/favicon.ico"><link rel="mask-icon" href="/favicon.svg" color="#333333"><title>Documentation</title><script>var baseUrl = "/"</script><script defer="defer" src="/js/chunk-vendors.bdb7cbba.js"></script><script defer="defer" src="/js/index.d2f6f6a9.js"></script><link href="/css/index.3a335429.css" rel="stylesheet"></head><body data-color-scheme="auto"><noscript><style>.noscript{font-family:"SF Pro Display","SF Pro Icons","Helvetica Neue",Helvetica,Arial,sans-serif;margin:92px auto 140px auto;text-align:center;width:980px}.noscript-title{color:#111;font-size:48px;font-weight:600;letter-spacing:-.003em;line-height:1.08365;margin:0 auto 54px auto;width:502px}@media only screen and (max-width:1068px){.noscript{margin:90px auto 120px auto;width:692px}.noscript-title{font-size:40px;letter-spacing:0;line-height:1.1;margin:0 auto 45px auto;width:420px}}@media only screen and (max-width:735px){.noscript{margin:45px auto 60px auto;width:87.5%}.noscript-title{font-size:32px;letter-spacing:.004em;line-height:1.125;margin:0 auto 35px auto;max-width:330px;width:auto}}#loading-placeholder{display:none}</style><div class="noscript"><h1 class="noscript-title">This page requires JavaScript.</h1><p>Please turn on JavaScript in your browser and refresh the page to view its content.</p></div></noscript><div id="app"></div></body></html>
|
||||
@@ -1 +0,0 @@
|
||||
{"includedArchiveIdentifiers":["com.anthropic.tuikit.documentation"],"interfaceLanguages":{"swift":[{"children":[{"title":"Articles","type":"groupMarker"},{"path":"\/documentation\/tuikit\/appearance","title":"Appearance System","type":"article"},{"path":"\/documentation\/tuikit\/architecture","title":"Architecture Overview","type":"article"},{"path":"\/documentation\/tuikit\/focus","title":"Focus Management","type":"article"},{"path":"\/documentation\/tuikit\/gettingstarted","title":"Getting Started with TUIKit","type":"article"},{"path":"\/documentation\/tuikit\/modifiers","title":"View Modifiers","type":"article"},{"path":"\/documentation\/tuikit\/statemanagement","title":"State Management","type":"article"},{"path":"\/documentation\/tuikit\/theming","title":"Theming System","type":"article"},{"path":"\/documentation\/tuikit\/viewhierarchy","title":"Understanding the View Hierarchy","type":"article"},{"path":"\/documentation\/tuikit\/buildinteractivemenu","title":"Building an Interactive Menu","type":"article"},{"path":"\/documentation\/tuikit\/buildthemableui","title":"Building a Themable UI","type":"article"},{"path":"\/documentation\/tuikit\/buildyourfirstapp","title":"Building Your First App","type":"article"}],"path":"\/documentation\/tuikit","title":"TUIKit","type":"module"}]},"schemaVersion":{"major":0,"minor":1,"patch":2}}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[393],{8780:function(e){function s(e){const s=e.regex,t={},n={begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]};Object.assign(t,{className:"variable",variants:[{begin:s.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},n]});const a={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},i={begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,className:"string"})]}},c={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,t,a]};a.contains.push(c);const o={className:"",begin:/\\"/},r={className:"string",begin:/'/,end:/'/},l={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t]},d=["fish","bash","zsh","sh","csh","ksh","tcsh","dash","scsh"],p=e.SHEBANG({binary:`(${d.join("|")})`,relevance:10}),m={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0},u=["if","then","else","elif","fi","for","while","in","do","done","case","esac","function"],h=["true","false"],b={match:/(\/[a-z._-]+)+/},f=["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset"],g=["alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","type","typeset","ulimit","unalias"],w=["autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp"],k=["chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"];return{name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z._-]+\b/,keyword:u,literal:h,built_in:[...f,...g,"set","shopt",...w,...k]},contains:[p,e.SHEBANG(),m,l,e.HASH_COMMENT_MODE,i,b,c,o,r,t]}}e.exports=s}}]);
|
||||
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[546],{612:function(e){function n(e){const n=e.regex,s=e.COMMENT("//","$",{contains:[{begin:/\\\n/}]}),t="decltype\\(auto\\)",a="[a-zA-Z_]\\w*::",r="<[^<>]+>",i="("+t+"|"+n.optional(a)+"[a-zA-Z_]\\w*"+n.optional(r)+")",l={className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{match:/\batomic_[a-z]{3,6}\b/}]},c="\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)",o={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'("+c+"|.)",end:"'",illegal:"."},e.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},d={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},u={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{className:"string",begin:/<.*?>/},s,e.C_BLOCK_COMMENT_MODE]},_={className:"title",begin:n.optional(a)+e.IDENT_RE,relevance:0},g=n.optional(a)+e.IDENT_RE+"\\s*\\(",p=["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"],m=["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","const","static","complex","bool","imaginary"],f={keyword:p,type:m,literal:"true false NULL",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr"},b=[u,l,s,e.C_BLOCK_COMMENT_MODE,d,o],w={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:f,contains:b.concat([{begin:/\(/,end:/\)/,keywords:f,contains:b.concat(["self"]),relevance:0}]),relevance:0},y={begin:"("+i+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:f,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:t,keywords:f,relevance:0},{begin:g,returnBegin:!0,contains:[e.inherit(_,{className:"title.function"})],relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,keywords:f,relevance:0,contains:[s,e.C_BLOCK_COMMENT_MODE,o,d,l,{begin:/\(/,end:/\)/,keywords:f,relevance:0,contains:["self",s,e.C_BLOCK_COMMENT_MODE,o,d,l]}]},l,s,e.C_BLOCK_COMMENT_MODE,u]};return{name:"C",aliases:["h"],keywords:f,disableAutodetect:!0,illegal:"</",contains:[].concat(w,y,b,[u,{begin:e.IDENT_RE+"::",keywords:f},{className:"class",beginKeywords:"enum class struct union",end:/[{;:<>=]/,contains:[{beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:u,strings:o,keywords:f}}}e.exports=n}}]);
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
"use strict";(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[642],{2003:function(e,n,a){function i(e){const n=e.regex,a={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},i={begin:"^[-\\*]{3,}",end:"$"},s={className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},c={className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},t={begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]},d=/[A-Za-z][A-Za-z0-9+.-]*/,l={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,relevance:2},{begin:n.concat(/\[.+?\]\(/,d,/:\/\/.*?\)/),relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}]},g={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},r={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};g.contains.push(r),r.contains.push(g);let o=[a,l];g.contains=g.contains.concat(o),r.contains=r.contains.concat(o),o=o.concat(g,r);const b={className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:o},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:o}]}]},u={className:"quote",begin:"^>\\s+",contains:o,end:"$"};return{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[b,a,c,g,r,u,s,i,l,t]}}a.r(n),a.d(n,{default:function(){return l}});const s={begin:"<doc:",end:">",returnBegin:!0,contains:[{className:"link",begin:"doc:",end:">",excludeEnd:!0}]},c={className:"link",begin:/`{2}(?!`)/,end:/`{2}(?!`)/,excludeBegin:!0,excludeEnd:!0},t={begin:"^>\\s+[Note:|Tip:|Important:|Experiment:|Warning:]",end:"$",returnBegin:!0,contains:[{className:"quote",begin:"^>",end:"\\s+"},{className:"type",begin:"Note|Tip|Important|Experiment|Warning",end:":"},{className:"quote",begin:".*",end:"$",endsParent:!0}]},d={begin:"@",end:"[{\\)\\s]",returnBegin:!0,contains:[{className:"title",begin:"@",end:"[\\s+(]",excludeEnd:!0},{begin:":",end:"[,\\)\n\t]",excludeBegin:!0,keywords:{literal:"true false null undefined"},contains:[{className:"number",begin:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",endsWithParent:!0,excludeEnd:!0},{className:"string",variants:[{begin:/"""/,end:/"""/},{begin:/"/,end:/"/}],endsParent:!0},{className:"link",begin:"http|https",endsWithParent:!0,excludeEnd:!0}]}]};function l(e){const n=i(e),a=n.contains.find((({className:e})=>"code"===e));a.variants=a.variants.filter((({begin:e})=>!e.includes("( {4}|\\t)")));const l=[...n.contains.filter((({className:e})=>"code"!==e)),a];return{...n,contains:[c,s,t,d,...l]}}}}]);
|
||||
File diff suppressed because one or more lines are too long
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[213],{7731:function(e){function n(e){const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/)},{className:"comment",variants:[{begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/),end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,end:/$/}]}}e.exports=n}}]);
|
||||
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[878],{8937:function(e){function n(e){const n=e.regex,a="HTTP/(2|1\\.[01])",s=/[A-Za-z][A-Za-z0-9-]*/,t={className:"attribute",begin:n.concat("^",s,"(?=\\:\\s)"),starts:{contains:[{className:"punctuation",begin:/: /,relevance:0,starts:{end:"$",relevance:0}}]}},i=[t,{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0}}];return{name:"HTTP",aliases:["https"],illegal:/\S/,contains:[{begin:"^(?="+a+" \\d{3})",end:/$/,contains:[{className:"meta",begin:a},{className:"number",begin:"\\b\\d{3}\\b"}],starts:{end:/\b\B/,illegal:/\S/,contains:i}},{begin:"(?=^[A-Z]+ (.*?) "+a+"$)",end:/$/,contains:[{className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{className:"meta",begin:a},{className:"keyword",begin:"[A-Z]+"}],starts:{end:/\b\B/,illegal:/\S/,contains:i}},e.inherit(t,{relevance:0})]}}e.exports=n}}]);
|
||||
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[788],{8257:function(e){var n="[0-9](_*[0-9])*",a=`\\.(${n})`,s="[0-9a-fA-F](_*[0-9a-fA-F])*",t={className:"number",variants:[{begin:`(\\b(${n})((${a})|\\.)?|(${a}))[eE][+-]?(${n})[fFdD]?\\b`},{begin:`\\b(${n})((${a})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${a})[fFdD]?\\b`},{begin:`\\b(${n})[fFdD]\\b`},{begin:`\\b0[xX]((${s})\\.?|(${s})?\\.(${s}))[pP][+-]?(${n})[fFdD]?\\b`},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${s})[lL]?\\b`},{begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],relevance:0};function i(e,n,a){return-1===a?"":e.replace(n,(s=>i(e,n,a-1)))}function r(e){e.regex;const n="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",a=n+i("(?:<"+n+"~~~(?:\\s*,\\s*"+n+"~~~)*>)?",/~~~/g,2),s=["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do"],r=["super","this"],c=["false","true","null"],l=["char","boolean","long","float","int","byte","short","double"],b={keyword:s,literal:c,type:l,built_in:r},o={className:"meta",begin:"@"+n,contains:[{begin:/\(/,end:/\)/,contains:["self"]}]},_={className:"params",begin:/\(/,end:/\)/,keywords:b,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0};return{name:"Java",aliases:["jsp"],keywords:b,illegal:/<\/|#/,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{begin:/import java\.[a-z]+\./,keywords:"import",relevance:2},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/,className:"string",contains:[e.BACKSLASH_ESCAPE]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,n],className:{1:"keyword",3:"title.class"}},{begin:[n,/\s+/,n,/\s+/,/=/],className:{1:"type",3:"variable",5:"operator"}},{begin:[/record/,/\s+/,n],className:{1:"keyword",3:"title.class"},contains:[_,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"new throw return else",relevance:0},{begin:["(?:"+a+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{2:"title.function"},keywords:b,contains:[{className:"params",begin:/\(/,end:/\)/,keywords:b,relevance:0,contains:[o,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,t,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},t,o]}}e.exports=r}}]);
|
||||
File diff suppressed because one or more lines are too long
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[82],{14:function(e){function n(e){const n={className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},c={match:/[{}[\],:]/,className:"punctuation",relevance:0},a={beginKeywords:["true","false","null"].join(" ")};return{name:"JSON",contains:[n,c,e.QUOTE_STRING_MODE,a,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE],illegal:"\\S"}}e.exports=n}}]);
|
||||
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[133],{4972:function(e){function n(e){const n=e.regex,a=/([-a-zA-Z$._][\w$.-]*)/,t={className:"type",begin:/\bi\d+(?=\s|\b)/},i={className:"operator",relevance:0,begin:/=/},c={className:"punctuation",relevance:0,begin:/,/},l={className:"number",variants:[{begin:/0[xX][a-fA-F0-9]+/},{begin:/-?\d+(?:[.]\d+)?(?:[eE][-+]?\d+(?:[.]\d+)?)?/}],relevance:0},r={className:"symbol",variants:[{begin:/^\s*[a-z]+:/}],relevance:0},s={className:"variable",variants:[{begin:n.concat(/%/,a)},{begin:/%\d+/},{begin:/#\d+/}]},o={className:"title",variants:[{begin:n.concat(/@/,a)},{begin:/@\d+/},{begin:n.concat(/!/,a)},{begin:n.concat(/!\d+/,a)},{begin:/!\d+/}]};return{name:"LLVM IR",keywords:"begin end true false declare define global constant private linker_private internal available_externally linkonce linkonce_odr weak weak_odr appending dllimport dllexport common default hidden protected extern_weak external thread_local zeroinitializer undef null to tail target triple datalayout volatile nuw nsw nnan ninf nsz arcp fast exact inbounds align addrspace section alias module asm sideeffect gc dbg linker_private_weak attributes blockaddress initialexec localdynamic localexec prefix unnamed_addr ccc fastcc coldcc x86_stdcallcc x86_fastcallcc arm_apcscc arm_aapcscc arm_aapcs_vfpcc ptx_device ptx_kernel intel_ocl_bicc msp430_intrcc spir_func spir_kernel x86_64_sysvcc x86_64_win64cc x86_thiscallcc cc c signext zeroext inreg sret nounwind noreturn noalias nocapture byval nest readnone readonly inlinehint noinline alwaysinline optsize ssp sspreq noredzone noimplicitfloat naked builtin cold nobuiltin noduplicate nonlazybind optnone returns_twice sanitize_address sanitize_memory sanitize_thread sspstrong uwtable returned type opaque eq ne slt sgt sle sge ult ugt ule uge oeq one olt ogt ole oge ord uno ueq une x acq_rel acquire alignstack atomic catch cleanup filter inteldialect max min monotonic nand personality release seq_cst singlethread umax umin unordered xchg add fadd sub fsub mul fmul udiv sdiv fdiv urem srem frem shl lshr ashr and or xor icmp fcmp phi call trunc zext sext fptrunc fpext uitofp sitofp fptoui fptosi inttoptr ptrtoint bitcast addrspacecast select va_arg ret br switch invoke unwind unreachable indirectbr landingpad resume malloc alloca free load store getelementptr extractelement insertelement shufflevector getresult extractvalue insertvalue atomicrmw cmpxchg fence argmemonly double",contains:[t,e.COMMENT(/;\s*$/,null,{relevance:0}),e.COMMENT(/;/,/$/),e.QUOTE_STRING_MODE,{className:"string",variants:[{begin:/"/,end:/[^\\]"/}]},o,c,i,s,r,l]}}e.exports=n}}]);
|
||||
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[113],{1312:function(e){function n(e){const n=e.regex,a={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},i={begin:"^[-\\*]{3,}",end:"$"},c={className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},s={className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},t={begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]},d=/[A-Za-z][A-Za-z0-9+.-]*/,l={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,relevance:2},{begin:n.concat(/\[.+?\]\(/,d,/:\/\/.*?\)/),relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}]},g={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},b={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};g.contains.push(b),b.contains.push(g);let o=[a,l];g.contains=g.contains.concat(o),b.contains=b.contains.concat(o),o=o.concat(g,b);const r={className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:o},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:o}]}]},u={className:"quote",begin:"^>\\s+",contains:o,end:"$"};return{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[r,a,s,g,b,u,c,i,l,t]}}e.exports=n}}]);
|
||||
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[637],{2446:function(e){function n(e){const n={className:"built_in",begin:"\\b(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)\\w+"},_=/[a-zA-Z@][a-zA-Z0-9_]*/,i=["int","float","while","char","export","sizeof","typedef","const","struct","for","union","unsigned","long","volatile","static","bool","mutable","if","do","return","goto","void","enum","else","break","extern","asm","case","short","default","double","register","explicit","signed","typename","this","switch","continue","wchar_t","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","super","unichar","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"],t=["false","true","FALSE","TRUE","nil","YES","NO","NULL"],a=["BOOL","dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"],r={$pattern:_,keyword:i,literal:t,built_in:a},s={$pattern:_,keyword:["@interface","@class","@protocol","@implementation"]};return{name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"],keywords:r,illegal:"</",contains:[n,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.C_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{className:"string",variants:[{begin:'@"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]}]},{className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{keyword:"if else elif endif define undef warning error line pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),{className:"string",begin:/<.*?>/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",begin:"("+s.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:s,contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,relevance:0}]}}e.exports=n}}]);
|
||||
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[645],{2482:function(e){function n(e){const n=e.regex,t=["abs","accept","alarm","and","atan2","bind","binmode","bless","break","caller","chdir","chmod","chomp","chop","chown","chr","chroot","close","closedir","connect","continue","cos","crypt","dbmclose","dbmopen","defined","delete","die","do","dump","each","else","elsif","endgrent","endhostent","endnetent","endprotoent","endpwent","endservent","eof","eval","exec","exists","exit","exp","fcntl","fileno","flock","for","foreach","fork","format","formline","getc","getgrent","getgrgid","getgrnam","gethostbyaddr","gethostbyname","gethostent","getlogin","getnetbyaddr","getnetbyname","getnetent","getpeername","getpgrp","getpriority","getprotobyname","getprotobynumber","getprotoent","getpwent","getpwnam","getpwuid","getservbyname","getservbyport","getservent","getsockname","getsockopt","given","glob","gmtime","goto","grep","gt","hex","if","index","int","ioctl","join","keys","kill","last","lc","lcfirst","length","link","listen","local","localtime","log","lstat","lt","ma","map","mkdir","msgctl","msgget","msgrcv","msgsnd","my","ne","next","no","not","oct","open","opendir","or","ord","our","pack","package","pipe","pop","pos","print","printf","prototype","push","q|0","qq","quotemeta","qw","qx","rand","read","readdir","readline","readlink","readpipe","recv","redo","ref","rename","require","reset","return","reverse","rewinddir","rindex","rmdir","say","scalar","seek","seekdir","select","semctl","semget","semop","send","setgrent","sethostent","setnetent","setpgrp","setpriority","setprotoent","setpwent","setservent","setsockopt","shift","shmctl","shmget","shmread","shmwrite","shutdown","sin","sleep","socket","socketpair","sort","splice","split","sprintf","sqrt","srand","stat","state","study","sub","substr","symlink","syscall","sysopen","sysread","sysseek","system","syswrite","tell","telldir","tie","tied","time","times","tr","truncate","uc","ucfirst","umask","undef","unless","unlink","unpack","unshift","untie","until","use","utime","values","vec","wait","waitpid","wantarray","warn","when","while","write","x|0","xor","y|0"],r=/[dualxmsipngr]{0,12}/,s={$pattern:/[\w.]+/,keyword:t.join(" ")},i={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:s},a={begin:/->\{/,end:/\}/},c={variants:[{begin:/\$\d/},{begin:n.concat(/[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])")},{begin:/[$%@][^\s\w{]/,relevance:0}]},o=[e.BACKSLASH_ESCAPE,i,c],g=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],l=(e,t,s="\\1")=>{const i="\\1"===s?s:n.concat(s,t);return n.concat(n.concat("(?:",e,")"),t,/(?:\\.|[^\\\/])*?/,i,/(?:\\.|[^\\\/])*?/,s,r)},d=(e,t,s)=>n.concat(n.concat("(?:",e,")"),t,/(?:\\.|[^\\\/])*?/,s,r),p=[c,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{endsWithParent:!0}),a,{className:"string",contains:o,variants:[{begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">",relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{begin:"-?\\w+\\s*=>",relevance:0}]},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",keywords:"split return print reverse grep",relevance:0,contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{begin:l("s|tr|y",n.either(...g,{capture:!0}))},{begin:l("s|tr|y","\\(","\\)")},{begin:l("s|tr|y","\\[","\\]")},{begin:l("s|tr|y","\\{","\\}")}],relevance:2},{className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{begin:d("(?:m|qr)?",/\//,/\//)},{begin:d("m|qr",n.either(...g,{capture:!0}),/\1/)},{begin:d("m|qr",/\(/,/\)/)},{begin:d("m|qr",/\[/,/\]/)},{begin:d("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub",end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]}];return i.contains=p,a.contains=p,{name:"Perl",aliases:["pl","pm"],keywords:s,contains:p}}e.exports=n}}]);
|
||||
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[596],{2656:function(e){function r(e){const r={className:"variable",begin:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*(?![A-Za-z0-9])(?![$])"},t={className:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?[=]?/},{begin:/\?>/}]},a={className:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}]},n=e.inherit(e.APOS_STRING_MODE,{illegal:null}),i=e.inherit(e.QUOTE_STRING_MODE,{illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(a)}),o=e.END_SAME_AS_BEGIN({begin:/<<<[ \t]*(\w+)\n/,end:/[ \t]*(\w+)\b/,contains:e.QUOTE_STRING_MODE.contains.concat(a)}),l={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[e.inherit(n,{begin:"b'",end:"'"}),e.inherit(i,{begin:'b"',end:'"'}),i,n,o]},c={className:"number",variants:[{begin:"\\b0b[01]+(?:_[01]+)*\\b"},{begin:"\\b0o[0-7]+(?:_[0-7]+)*\\b"},{begin:"\\b0x[\\da-f]+(?:_[\\da-f]+)*\\b"},{begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:e[+-]?\\d+)?"}],relevance:0},s={keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile enum eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list match|0 mixed new object or private protected public real return string switch throw trait try unset use var void while xor yield",literal:"false null true",built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException UnhandledMatchError ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Stringable Throwable Traversable WeakReference WeakMap Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass"};return{case_insensitive:!0,keywords:s,contains:[e.HASH_COMMENT_MODE,e.COMMENT("//","$",{contains:[t]}),e.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0,keywords:"__halt_compiler"}),t,{className:"keyword",begin:/\$this\b/},r,{begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use"},e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{className:"params",begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:s,contains:["self",r,e.C_BLOCK_COMMENT_MODE,l,c]}]},{className:"class",variants:[{beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait",illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/,contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",relevance:0,end:";",contains:[e.UNDERSCORE_TITLE_MODE]},l,c]}}e.exports=r}}]);
|
||||
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[435],{8245:function(e){function n(e){const n=e.regex,a=/[\p{XID_Start}_]\p{XID_Continue}*/u,i=["and","as","assert","async","await","break","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],s=["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"],t=["__debug__","Ellipsis","False","None","NotImplemented","True"],r=["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"],l={$pattern:/[A-Za-z]\w+|__\w+__/,keyword:i,built_in:s,literal:t,type:r},b={className:"meta",begin:/^(>>>|\.\.\.) /},o={className:"subst",begin:/\{/,end:/\}/,keywords:l,illegal:/#/},c={begin:/\{\{/,relevance:0},d={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,b],relevance:10},{begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,b],relevance:10},{begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,b,c,o]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,b,c,o]},{begin:/([uU]|[rR])'/,end:/'/,relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/,end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/,contains:[e.BACKSLASH_ESCAPE,c,o]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,c,o]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},p="[0-9](_?[0-9])*",_=`(\\b(${p}))?\\.(${p})|\\b(${p})\\.`,g={className:"number",relevance:0,variants:[{begin:`(\\b(${p})|(${_}))[eE][+-]?(${p})[jJ]?\\b`},{begin:`(${_})[jJ]?`},{begin:"\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?\\b"},{begin:"\\b0[bB](_?[01])+[lL]?\\b"},{begin:"\\b0[oO](_?[0-7])+[lL]?\\b"},{begin:"\\b0[xX](_?[0-9a-fA-F])+[lL]?\\b"},{begin:`\\b(${p})[jJ]\\b`}]},m={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:l,contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},f={className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:l,contains:["self",b,g,d,e.HASH_COMMENT_MODE]}]};return o.contains=[d,g,b],{name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:l,illegal:/(<\/|->|\?)|=>/,contains:[b,g,{begin:/\bself\b/},{beginKeywords:"if",relevance:0},d,m,e.HASH_COMMENT_MODE,{match:[/def/,/\s+/,a],scope:{1:"keyword",3:"title.function"},contains:[f]},{variants:[{match:[/class/,/\s+/,a,/\s*/,/\(\s*/,a,/\s*\)/]},{match:[/class/,/\s+/,a]}],scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[g,f,d]}]}}e.exports=n}}]);
|
||||
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[623],{7905:function(e){function n(e){const n=e.regex,a="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",i={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor __FILE__",built_in:"proc lambda",literal:"true false nil"},s={className:"doctag",begin:"@[A-Za-z]+"},c={begin:"#<",end:">"},b=[e.COMMENT("#","$",{contains:[s]}),e.COMMENT("^=begin","^=end",{contains:[s],relevance:10}),e.COMMENT("^__END__","\\n$")],r={className:"subst",begin:/#\{/,end:/\}/,keywords:i},d={className:"string",contains:[e.BACKSLASH_ESCAPE,r],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?</,end:/>/},{begin:/%[qQwWx]?\//,end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)),contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,r]})]}]},t="[1-9](_?[0-9])*|0",l="[0-9](_?[0-9])*",o={className:"number",relevance:0,variants:[{begin:`\\b(${t})(\\.(${l}))?([eE][+-]?(${l})|r)?i?\\b`},{begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{begin:"\\b0(_?[0-7])+r?i?\\b"}]},g={className:"params",begin:"\\(",end:"\\)",endsParent:!0,keywords:i},_=[d,{className:"class",beginKeywords:"class module",end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|!)?"}),{begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE,relevance:0}]}].concat(b)},{className:"function",begin:n.concat(/def\s+/,n.lookahead(a+"\\s*(\\(|;|$)")),relevance:0,keywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:a}),g].concat(b)},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[d,{begin:a}],relevance:0},o,{className:"variable",begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{className:"params",begin:/\|/,end:/\|/,relevance:0,keywords:i},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,r],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(c,b),relevance:0}].concat(c,b);r.contains=_,g.contains=_;const E="[>?]>",w="[\\w#]+\\(\\w+\\):\\d+:\\d+>",u="(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>",N=[{begin:/^\s*=>/,starts:{end:"$",contains:_}},{className:"meta",begin:"^("+E+"|"+w+"|"+u+")(?=[ ])",starts:{end:"$",contains:_}}];return b.unshift(c),{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:i,illegal:/\/\*/,contains:[e.SHEBANG({binary:"ruby"})].concat(N).concat(b).concat(_)}}e.exports=n}}]);
|
||||
File diff suppressed because one or more lines are too long
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[176],{7874:function(s){function e(s){return{name:"Shell Session",aliases:["console","shellsession"],contains:[{className:"meta",begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/,subLanguage:"bash"}}]}}s.exports=e}}]);
|
||||
File diff suppressed because one or more lines are too long
@@ -1,10 +0,0 @@
|
||||
/*!
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2021 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See https://swift.org/LICENSE.txt for license information
|
||||
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||
*/
|
||||
(self["webpackChunkswift_docc_render"]=self["webpackChunkswift_docc_render"]||[]).push([[490],{4610:function(e){function n(e){const n=e.regex,a=n.concat(/[A-Z_]/,n.optional(/[A-Z0-9_.-]*:/),/[A-Z0-9_.-]*/),s=/[A-Za-z0-9._:-]+/,t={className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},c={begin:/\s/,contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]},i=e.inherit(c,{begin:/\(/,end:/\)/}),l=e.inherit(e.APOS_STRING_MODE,{className:"string"}),r=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),g={endsWithParent:!0,illegal:/</,relevance:0,contains:[{className:"attr",begin:s,relevance:0},{begin:/=\s*/,relevance:0,contains:[{className:"string",endsParent:!0,variants:[{begin:/"/,end:/"/,contains:[t]},{begin:/'/,end:/'/,contains:[t]},{begin:/[^\s"'=<>`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin:/<![a-z]/,end:/>/,relevance:10,contains:[c,r,l,i,{begin:/\[/,end:/\]/,contains:[{className:"meta",begin:/<![a-z]/,end:/>/,contains:[c,i,r,l]}]}]},e.COMMENT(/<!--/,/-->/,{relevance:10}),{begin:/<!\[CDATA\[/,end:/\]\]>/,relevance:10},t,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:/<style(?=\s|>)/,end:/>/,keywords:{name:"style"},contains:[g],starts:{end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:/<script(?=\s|>)/,end:/>/,keywords:{name:"script"},contains:[g],starts:{end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:/<>|<\/>/},{className:"tag",begin:n.concat(/</,n.lookahead(n.concat(a,n.either(/\/>/,/>/,/\s/)))),end:/\/?>/,contains:[{className:"name",begin:a,relevance:0,starts:g}]},{className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(a,/>/))),contains:[{className:"name",begin:a,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]}}e.exports=n}}]);
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
{"schemaVersion":{"major":0,"patch":0,"minor":1},"bundleDisplayName":"TUIKit","bundleID":"com.anthropic.tuikit.documentation"}
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
site_name: TUIKit Documentation
|
||||
site_description: A declarative, SwiftUI-like framework for building Terminal User Interfaces in Swift
|
||||
site_url: https://docs-tuikit.layered.work/
|
||||
|
||||
theme:
|
||||
name: material
|
||||
language: en
|
||||
palette:
|
||||
- media: "(prefers-color-scheme: light)"
|
||||
scheme: default
|
||||
primary: emerald
|
||||
accent: indigo
|
||||
toggle:
|
||||
icon: material/lightbulb-outline
|
||||
name: Switch to dark mode
|
||||
- media: "(prefers-color-scheme: dark)"
|
||||
scheme: slate
|
||||
primary: green
|
||||
accent: indigo
|
||||
toggle:
|
||||
icon: material/lightbulb
|
||||
name: Switch to light mode
|
||||
features:
|
||||
- navigation.instant
|
||||
- navigation.tracking
|
||||
- navigation.tabs
|
||||
- navigation.top
|
||||
- search.suggest
|
||||
- search.highlight
|
||||
- content.code.copy
|
||||
- toc.follow
|
||||
|
||||
plugins:
|
||||
- search
|
||||
|
||||
nav:
|
||||
- Home: index.md
|
||||
- Getting Started: getting-started.md
|
||||
- API Reference:
|
||||
- TUIKit: api/tuikit.md
|
||||
- Contributing: contributing.md
|
||||
|
||||
markdown_extensions:
|
||||
- pymdownx.highlight:
|
||||
use_pygments: true
|
||||
- pymdownx.superfences
|
||||
- pymdownx.snippets
|
||||
- pymdownx.tabbed:
|
||||
alternate_style: true
|
||||
- admonition
|
||||
- attr_list
|
||||
- md_in_html
|
||||
Reference in New Issue
Block a user