diff --git a/apps/inline-alert/components/Alerts.tsx b/apps/inline-alert/components/Alerts.tsx
new file mode 100644
index 0000000..94fe87c
--- /dev/null
+++ b/apps/inline-alert/components/Alerts.tsx
@@ -0,0 +1,103 @@
+import { Component } from '@geastack/core'
+import { InlineAlert } from '@geastack/elements'
+import { demo } from '../stores/DemoStore'
+
+// Each alert sits in its own class component that reads the store, the way
+// e-reader's OpeningModal does, with an element as the template's root. In
+// a native build, a component inside a conditional branch keeps the props it
+// was first built with, and so does a class whose template root is the
+// InlineAlert itself; this shape follows the store.
+// The language switch changes every text, including the severity labels, to
+// show localized content wrapping in the same layout. With the built-in
+// bitmap font, pixel targets draw the Turkish letters as `?`.
+
+class InfoAlert extends Component {
+ template() {
+ return (
+
+ demo.dismiss('info')}
+ />
+
+ )
+ }
+}
+
+class SuccessAlert extends Component {
+ template() {
+ return (
+
+ demo.dismiss('success')}
+ />
+
+ )
+ }
+}
+
+class WarningAlert extends Component {
+ template() {
+ return (
+
+ demo.dismiss('warning')}
+ />
+
+ )
+ }
+}
+
+class ErrorAlert extends Component {
+ template() {
+ return (
+
+ demo.retry()}
+ dismissible={true}
+ dismissLabel={demo.turkish ? 'Kapat' : undefined}
+ onDismiss={() => demo.dismiss('error')}
+ />
+
+ )
+ }
+}
+
+export function Alerts() {
+ return (
+
+ {demo.infoOpen ? : null}
+ {demo.successOpen ? : null}
+ {demo.warningOpen ? : null}
+ {demo.errorOpen ? : null}
+
+ )
+}
diff --git a/apps/inline-alert/components/App.tsx b/apps/inline-alert/components/App.tsx
new file mode 100644
index 0000000..222aea5
--- /dev/null
+++ b/apps/inline-alert/components/App.tsx
@@ -0,0 +1,22 @@
+import { Component } from '@geastack/core'
+import { demo } from '../stores/DemoStore'
+import { Alerts } from './Alerts'
+
+export class App extends Component {
+ template() {
+ return (
+
+
InlineAlert
+
+
+ demo.toggleLanguage()}>
+ {demo.turkish ? 'English' : 'Türkçe'}
+
+ demo.reset()}>
+ {demo.turkish ? 'Sıfırla' : 'Reset'}
+
+
+
+ )
+ }
+}
diff --git a/apps/inline-alert/env.d.ts b/apps/inline-alert/env.d.ts
new file mode 100644
index 0000000..dc50b2b
--- /dev/null
+++ b/apps/inline-alert/env.d.ts
@@ -0,0 +1,2 @@
+///
+declare module '*.css'
diff --git a/apps/inline-alert/index.tsx b/apps/inline-alert/index.tsx
new file mode 100644
index 0000000..46c9b1f
--- /dev/null
+++ b/apps/inline-alert/index.tsx
@@ -0,0 +1,5 @@
+import { mount } from '@geastack/core'
+import './styles.css'
+import { App } from './components/App'
+
+mount(App)
diff --git a/apps/inline-alert/package.json b/apps/inline-alert/package.json
new file mode 100644
index 0000000..18872a1
--- /dev/null
+++ b/apps/inline-alert/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "@geastack/example-inline-alert",
+ "type": "module",
+ "scripts": {
+ "check": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@geastack/core": "^0.1.41",
+ "@geastack/elements": "^0.1.6"
+ },
+ "gea": {
+ "id": "inline-alert",
+ "name": "Inline Alert",
+ "entry": "index.tsx",
+ "runtime": "gea",
+ "targets": {
+ "web": true,
+ "esp32": false
+ },
+ "launcher": {
+ "description": "inline alert variants",
+ "order": 999,
+ "hidden": true
+ }
+ },
+ "private": true,
+ "license": "MIT",
+ "version": "0.1.0"
+}
diff --git a/apps/inline-alert/stores/DemoStore.ts b/apps/inline-alert/stores/DemoStore.ts
new file mode 100644
index 0000000..7504dc0
--- /dev/null
+++ b/apps/inline-alert/stores/DemoStore.ts
@@ -0,0 +1,38 @@
+import { Store } from '@geastack/core'
+import type { InlineAlertVariant } from '@geastack/elements'
+
+// The app owns which alerts are shown. InlineAlert only reports onDismiss,
+// so dismissing one here removes it until Reset.
+class DemoStore extends Store {
+ infoOpen = true
+ successOpen = true
+ warningOpen = true
+ errorOpen = true
+ turkish = false
+ retries = 0
+
+ dismiss(variant: InlineAlertVariant): void {
+ if (variant === 'info') this.infoOpen = false
+ if (variant === 'success') this.successOpen = false
+ if (variant === 'warning') this.warningOpen = false
+ if (variant === 'error') this.errorOpen = false
+ }
+
+ retry(): void {
+ this.retries = this.retries + 1
+ }
+
+ toggleLanguage(): void {
+ this.turkish = !this.turkish
+ }
+
+ reset(): void {
+ this.infoOpen = true
+ this.successOpen = true
+ this.warningOpen = true
+ this.errorOpen = true
+ this.retries = 0
+ }
+}
+
+export const demo = new DemoStore()
diff --git a/apps/inline-alert/styles.css b/apps/inline-alert/styles.css
new file mode 100644
index 0000000..3dff5d4
--- /dev/null
+++ b/apps/inline-alert/styles.css
@@ -0,0 +1,46 @@
+body {
+ background-color: #f6f3ea;
+ color: #171713;
+ font-family: 'Inter';
+}
+
+.demo-app {
+ display: flex;
+ flex-direction: column;
+ padding: 24px;
+ gap: 12px;
+}
+
+.demo-title {
+ font-size: 28px;
+ font-weight: 700;
+}
+
+.demo-alerts {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.demo-alert {
+ width: 100%;
+}
+
+.demo-alert--narrow {
+ width: 220px;
+}
+
+.demo-buttons {
+ display: flex;
+ flex-direction: row;
+ gap: 8px;
+}
+
+.demo-button {
+ width: 96px;
+ height: 44px;
+ background-color: #171713;
+ color: #ffffff;
+ font-size: 14px;
+ border-radius: 8px;
+}
diff --git a/apps/inline-alert/tsconfig.json b/apps/inline-alert/tsconfig.json
new file mode 100644
index 0000000..2388422
--- /dev/null
+++ b/apps/inline-alert/tsconfig.json
@@ -0,0 +1,23 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "lib": [
+ "ES2022"
+ ],
+ "strict": true,
+ "noEmit": true,
+ "skipLibCheck": true,
+ "jsx": "preserve",
+ "types": []
+ },
+ "include": [
+ "**/*.tsx",
+ "**/*.d.ts",
+ "../../node_modules/@geajs/vite-plugin/gea-env.d.ts"
+ ],
+ "exclude": [
+ "vite.config.ts"
+ ]
+}
diff --git a/docs/EXAMPLE-CATALOG.md b/docs/EXAMPLE-CATALOG.md
index f0ee5d2..3263611 100644
--- a/docs/EXAMPLE-CATALOG.md
+++ b/docs/EXAMPLE-CATALOG.md
@@ -10,7 +10,7 @@ tests, and marketing proof.
| Watch and wearable UI | `watch`, `watch-analog`, `watch-date`, `watch-face` | Compact layouts, clock/date rendering, small-screen app surfaces. |
| Basic JSX apps | `counter-jsx`, `todo-jsx`, `static-card`, `stopwatch-jsx` | Component rendering, state updates, text/input, timers. |
| Canvas and animation | `bouncing-balls`, `bouncing-balls-jsx`, `canvas-3d`, `canvas-3d-cube`, `css-3d-cube`, `css-animation-showcase` | Canvas drawing, CSS animation, frame loop, transform behavior. |
-| UI components | `settings`, `dialer`, `virtual-list`, `typography`, `bubble-grid`, `bubble-grid-jsx` | Higher-level controls, scroll behavior, text layout, launchable apps. |
+| UI components | `settings`, `dialer`, `virtual-list`, `inline-alert`, `typography`, `bubble-grid`, `bubble-grid-jsx` | Higher-level controls, scroll behavior, text layout, launchable apps. |
| Games | `sky-hop`, `sky-hop-jsx`, `tic-tac-toe`, `tilt-breakout`, `button-tetris` | Interaction, simple game loops, collision/physics, deterministic logic. |
| Device features | `camera-showcase`, `camera-studio`, `voice-notes`, `hid-clicker`, `weather`, `maps` | Target capabilities such as camera, audio, HID, network, and map assets. |
| Apple/native experiments | `notes-jsx`, `notes-native`, `ios-device-showcase`, `ios-metal-*`, `ios-native-showcase`, `macos-native-showcase` | Apple target and native renderer experiments. |
diff --git a/package-lock.json b/package-lock.json
index d71e820..c5eddee 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1122,6 +1122,15 @@
"node": ">= 8.0.0"
}
},
+ "apps/inline-alert": {
+ "name": "@geastack/example-inline-alert",
+ "version": "0.1.0",
+ "license": "MIT",
+ "dependencies": {
+ "@geastack/core": "^0.1.41",
+ "@geastack/elements": "^0.1.6"
+ }
+ },
"apps/ios-device-showcase": {
"name": "@geastack/example-ios-device-showcase",
"version": "0.1.0",
@@ -2779,6 +2788,10 @@
"resolved": "apps/image-jsx",
"link": true
},
+ "node_modules/@geastack/example-inline-alert": {
+ "resolved": "apps/inline-alert",
+ "link": true
+ },
"node_modules/@geastack/example-ios-device-showcase": {
"resolved": "apps/ios-device-showcase",
"link": true