Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions scripts/check-mobile-ui-evidence.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const componentDocs = JSON.parse(
const components = tags(componentDirectory, '.png');
const gifs = tags(gifDirectory, '.gif');
const staticComponents = new Set(contract.staticComponents);
const candidateComponents = new Set(contract.candidateComponents ?? []);
const failures = [];
const documentedComponents = new Map(
componentDocs.components.map((component) => [component.tag, component]),
Expand All @@ -25,10 +26,18 @@ if (
|| contract.capture?.api !== 31
|| contract.capture?.densityDpi !== 420
|| contract.capture?.screenCount !== 90
|| contract.capture?.interactionComponentCount !== contract.expectedComponentCount
|| contract.capture?.interactionComponentCount !== contract.expectedComponentCount - candidateComponents.size
) {
failures.push('physical Android capture provenance is missing or incomplete');
}
if (
contract.candidateCapture?.api !== 36
|| contract.candidateCapture?.densityDpi !== 420
|| contract.candidateCapture?.componentCount !== candidateComponents.size
|| !/^[a-f0-9]{64}$/.test(contract.candidateCapture?.buildSha256 ?? '')
) {
failures.push('emulator candidate capture provenance is missing or incomplete');
}

if (components.size !== contract.expectedComponentCount) {
failures.push(
Expand All @@ -52,7 +61,7 @@ for (const tag of staticComponents) {
for (const tag of components) {
const image = readFileSync(join(componentDirectory, `${tag}.png`));
if (!isPng(image)) failures.push(`${tag}.png is not a valid PNG asset`);
if (!staticComponents.has(tag) && !gifs.has(tag)) {
if (!staticComponents.has(tag) && !candidateComponents.has(tag) && !gifs.has(tag)) {
failures.push(`${tag} is interactive but has no Android interaction GIF`);
}
const docs = documentedComponents.get(tag);
Expand All @@ -74,6 +83,10 @@ for (const tag of components) {
}
}

for (const tag of candidateComponents) {
if (!components.has(tag)) failures.push(`${tag} candidate has no screenshot`);
}

for (const tag of documentedComponents.keys()) {
if (!components.has(tag)) failures.push(`${tag} API record has no matching screenshot/page`);
}
Expand All @@ -90,8 +103,10 @@ if (failures.length > 0) {
}

console.log(
`PAM Native UI evidence complete: ${components.size}/${contract.expectedComponentCount} screenshots, ` +
`${components.size - staticComponents.size} interactive GIFs, ${staticComponents.size} static specimens, ` +
`PAM Native UI asset inventory validated (not release approval): ${components.size}/${contract.expectedComponentCount} screenshots, ` +
`${gifs.size} physical interaction GIFs, ` +
`${[...candidateComponents].filter((tag) => !staticComponents.has(tag)).length} emulator interactions awaiting physical GIFs, ` +
`${staticComponents.size} static specimens, ` +
`${documentedComponents.size} component API records.`,
);

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/mobile-ui/components/p-chart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/mobile-ui/components/p-data-grid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/mobile-ui/components/p-file-input.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/mobile-ui/components/p-filter-bar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/mobile-ui/components/p-pagination.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/mobile-ui/components/p-popover.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/mobile-ui/components/p-search-bar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/mobile-ui/components/p-tag-input.png
6 changes: 4 additions & 2 deletions src/components/PamNativeUiGallery.astro
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
---
import evidenceContract from '../data/mobile-ui-evidence.json';

const modules = import.meta.glob('../assets/mobile-ui/components/p-*.png', {
eager: true,
query: '?url',
Expand Down Expand Up @@ -35,9 +37,9 @@ const componentBase = `${siteBase}mobile-ui/components`;
<a href={`${componentBase}/${tag}/`} aria-label={`Open the ${tag} component documentation`}>
<img
src={url}
alt={`${tag} rendered by PAM Native UI on a physical Samsung Android device`}
alt={`${tag} rendered by PAM Native UI on ${evidenceContract.candidateComponents.includes(tag) ? 'an Android API 36 emulator; physical approval pending' : 'a physical Samsung Android device'}`}
width="1080"
height="2280"
height={evidenceContract.candidateComponents.includes(tag) ? 2400 : 2280}
loading="lazy"
decoding="async"
/>
Expand Down
8 changes: 7 additions & 1 deletion src/content/docs/packages/mobile-ui-architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ Compatibility means equivalent public intent and state—not pixel-identical
Android and iOS controls. Platform conventions are preserved when they produce
the more native result.

Registry entries and implementation coverage do not establish runtime approval.
A passing PHP rendering matrix is not a substitute for device interactions,
visual review, accessibility checks or platform-specific execution. Treat a
verification gate as complete only when its evidence covers the release candidate
and the required platform; Android evidence cannot establish iOS validation.

## Performance claims

Performance evidence belongs to reproducible benchmarks with device, OS,
Expand All @@ -68,4 +74,4 @@ Before shipping:

See [PAM Native UI](/packages/mobile-ui/) for installation and
authoring, and the [component catalog](/packages/mobile-ui-catalog/)
for the verified public surface.
for the documented public surface.
42 changes: 32 additions & 10 deletions src/content/docs/packages/mobile-ui-catalog.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: PAM Native UI component catalog
description: Complete verified catalog of PAM Native UI retained-native Material 3 tags for Android and iOS.
description: PAM Native UI component catalog with APIs, historical Android captures and separately identified candidate evidence.
---

import PamNativeUiGallery from '../../../components/PamNativeUiGallery.astro';
Expand All @@ -20,25 +20,35 @@ import calendarDayGif from '../../../assets/mobile-ui/gifs/p-calendar-day.gif?ur
import carouselGif from '../../../assets/mobile-ui/gifs/p-carousel.gif?url';

Every tag below creates or configures retained native UI. The release parity
manifest is the source of truth for this verified surface: **62 modules and 84
manifest is the source of truth for the current surface: **92 modules and 114
component parts**, on both Android and iOS.

The README, generated map, parity schema and executable release gate all use
this same 62-module/84-component contract.
this same 92-module/114-component contract.

## Android showcase application

The catalog below is also a real Android application. These images were
captured from the release renderer on a physical Samsung SM-G973F running
Android 12 (API 31) at 420 dpi—not from HTML, an emulator or a design mockup.
The publication gate verified **90/90 screens** and real interaction on
The media below records specific historical builds, not approval of the latest
source or every component state. Route execution, asset availability and package
compatibility checks are separate from complete visual, accessibility and
performance approval. New captures must identify their build and review scope;
do not treat an older screenshot as proof of a later correction.

The catalog below is also a real Android application. The original showcase
set was captured from the release renderer on a physical Samsung SM-G973F
running Android 12 (API 31) at 420 dpi—not from HTML or a design mockup. That
physical pass verified **90/90 screens** and real interaction on the original
**84/84 component routes**, including input, selection, drag, scroll and native
overlay flows. No blank render, invalid viewport or overlapping text is
accepted into this page.
overlay flows.

The 30 components added in the current expansion have separate Android 16
(API 36) emulator evidence and remain explicitly marked as candidates until
their physical Samsung interaction pass is recorded. Emulator evidence is
never presented as physical-device approval.

<div class="pam-showcase-strip">
<figure><a href={overviewUrl}><img src={overviewUrl} alt="PAM Native UI showcase home on a physical Samsung Android device" width="1080" height="2280" /></a><figcaption>Showcase home</figcaption></figure>
<figure><a href={workbenchUrl}><img src={workbenchUrl} alt="Complete PAM Native UI component workbench on a physical Samsung Android device" width="1080" height="2280" /></a><figcaption>84 components</figcaption></figure>
<figure><a href={workbenchUrl}><img src={workbenchUrl} alt="Original PAM Native UI component workbench on a physical Samsung Android device" width="1080" height="2280" /></a><figcaption>Original 84-component workbench</figcaption></figure>
<figure><a href={actionsUrl}><img src={actionsUrl} alt="PAM Native UI actions showcase on a physical Samsung Android device" width="1080" height="2280" /></a><figcaption>Actions</figcaption></figure>
<figure><a href={formsUrl}><img src={formsUrl} alt="PAM Native UI forms showcase on a physical Samsung Android device" width="1080" height="2280" /></a><figcaption>Forms</figcaption></figure>
<figure><a href={dataUrl}><img src={dataUrl} alt="PAM Native UI data showcase on a physical Samsung Android device" width="1080" height="2280" /></a><figcaption>Data</figcaption></figure>
Expand Down Expand Up @@ -91,6 +101,18 @@ reuse views rather than recreate them.
| Trees | `p-treeview`, `p-treeview-item` |
| Floating actions | `p-speed-dial` |

## Universal application components

| Area | Tags |
| --- | --- |
| Application shell | `p-app-scaffold`, `p-navigation-bar`, `p-navigation-rail`, `p-navigation-drawer`, `p-bottom-app-bar` |
| Search and commands | `p-search-bar`, `p-command-palette`, `p-filter-bar`, `p-pagination` |
| Advanced input | `p-password-field`, `p-masked-field`, `p-currency-field`, `p-tag-input`, `p-multi-select`, `p-file-input` |
| Date and selection | `p-date-range-picker`, `p-time-range-picker`, `p-segmented-button`, `p-tree-select` |
| Adaptive data | `p-responsive-grid`, `p-virtual-list`, `p-section-list`, `p-reorderable-list`, `p-data-grid` |
| Gestures and refresh | `p-swipe-actions`, `p-pull-to-refresh` |
| Feedback and visualization | `p-popover`, `p-progress-button`, `p-result-state`, `p-chart` |

## Product composition

Typed forms bind schema, values, errors, loading and submit behavior without
Expand Down
11 changes: 6 additions & 5 deletions src/content/docs/packages/mobile-ui.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,19 @@ Author with declarative `p-*` tags:
</p-screen-scroll>
```

Or compose the same native tree with typed PHP facades:
Or compose controls with typed PHP facades. Inside your component's render
method, bind the existing `shipOrder` method as a closure:

```php
use Pam\MobileUi\Component\Button;
use Pam\MobileUi\Component\Card;
use Pam\MobileUi\Enum\ColorToken;

$content = Card::make()
->class('p-4 gap-3')
$content = Card::make(['class' => 'p-4 gap-3'])
->child(
Button::make('Ship order')
->onPress('shipOrder')
->color('primary'),
->onPress($this->shipOrder(...))
->color(ColorToken::Primary),
);
```

Expand Down
Loading