@astryxdesign/native 0.7.5-canary.c60f571 → 0.7.5-canary.cd53c2d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,10 +21,11 @@ rests on evidence.
21
21
  | Icons | `NATIVE_ICON_DEFAULTS` | Astryx's built-in icon names mapped to SF Symbols on Apple platforms and Material Symbols on Android. |
22
22
  | Wire | `AstryxNode`, `AstryxAction` | Each component as JSON a TypeScript core sends a native host (arm C), and the action a host sends back when a view calls a callback. Swift decodes `<Name>Node` and turns it into `<Name>Props` with `viewProps(send:)`. |
23
23
  | Logic core | `@astryxdesign/native/logic` | `createLogicCore` holds a screen's state, builds its node tree, and reduces actions; `connectBridge` carries it to a native host as JSON. ECMAScript built-ins only, so it runs in Hermes. Shaped after EJ Campbell's astryx-swift spike. |
24
+ | Logic host | `AstryxLogicHost` (Swift) | Runs a logic core bundle in JavaScriptCore, decodes each tree into `AstryxNode`, and sends views' actions back. A Hermes host speaks the same bridge. |
24
25
 
25
- Contracts cover Button, Card, Divider, Heading, HStack, ProgressBar, Selector,
26
- Switch, Text, TextInput, and VStack. React Native and Android bindings are not built yet; see
27
- [the experiment matrix](#experiment-matrix).
26
+ Contracts cover Badge, Button, Card, Divider, Heading, HStack, ProgressBar,
27
+ Selector, Switch, Text, TextInput, and VStack. React Native and Android
28
+ bindings are not built yet; see [the experiment matrix](#experiment-matrix).
28
29
 
29
30
  ```ts
30
31
  // tsconfig.json for an iOS app: "customConditions": ["ios"]
@@ -90,14 +91,17 @@ const action: AstryxAction = {
90
91
  ```
91
92
 
92
93
  ```swift
93
- let node = try JSONDecoder().decode(AstryxNode.self, from: snapshot)
94
- if case .switch(let wifi) = node {
95
- let props = wifi.viewProps { action in core.dispatch(action.json) }
94
+ let host = AstryxLogicHost(bundle: bundleSource) // calls the bundle's global astryxStart(host)
95
+ if case .switch(let wifi) = host.root {
96
+ let props = wifi.viewProps(send: host.send)
96
97
  }
97
98
  ```
98
99
 
99
100
  ```ts
101
+ // tsconfig: "customConditions": ["ios"]
102
+ import type {AstryxAction, AstryxNode} from '@astryxdesign/native/components';
100
103
  import {connectBridge, createLogicCore} from '@astryxdesign/native/logic';
104
+ import type {Bridge, BridgeHost} from '@astryxdesign/native/logic';
101
105
 
102
106
  const core = createLogicCore<{wifi: boolean}, AstryxNode, AstryxAction>({
103
107
  initial: {wifi: true},
@@ -112,19 +116,18 @@ const core = createLogicCore<{wifi: boolean}, AstryxNode, AstryxAction>({
112
116
  ? {wifi: action.args[0]}
113
117
  : state,
114
118
  });
115
- // In the app's JavaScript engine: the host reads snapshots and dispatches actions.
116
- const bridge = connectBridge(core, {
117
- connected() {},
118
- changed(json) {
119
- /* to Swift */
120
- },
121
- });
119
+ // The bundle's entry: the native host calls it with its two calls in and
120
+ // gets back the bridge it reads snapshots from and dispatches actions to.
121
+ (globalThis as {astryxStart?: (host: BridgeHost) => Bridge}).astryxStart =
122
+ host => connectBridge(core, host);
122
123
  ```
123
124
 
124
125
  ## Working on it
125
126
 
126
127
  ```sh
128
+ pnpm -F @astryxdesign/native typecheck # source and tests
127
129
  pnpm -F @astryxdesign/native build # dist/, including platform types
130
+ pnpm -F @astryxdesign/native typecheck:types # every platform's types, after build
128
131
  pnpm -F @astryxdesign/native generate:apple # regenerate apple/Sources/.../Generated
129
132
  pnpm vitest run --project node packages/native
130
133
  ```
@@ -142,8 +145,23 @@ files are ignored on `main`.
142
145
  Boundaries, checked by `pnpm check:package-boundaries`:
143
146
 
144
147
  - `@astryxdesign/core` never imports this package.
145
- - This package's source never imports core. It reads core's documentation
146
- files as data at build time.
148
+ - No file in this package, in any folder, imports core, apart from the
149
+ build-time reads AST-082 FR16 lists until core's portable entry ships: the
150
+ theme generator in `scripts/` may import `@astryxdesign/core/theme` and
151
+ `@astryxdesign/core/theme/tokens`; `scripts/swift-ios-strings.mjs` may
152
+ read core's locale catalogs (`@astryxdesign/core/locales/*.json`); and
153
+ `scripts/core-docs.mjs` reads core's component documentation and built-in
154
+ icon names as data.
155
+ - The check reads source text in every folder except `node_modules`, `dist`,
156
+ `.build`, and `.swiftpm`. It flags any other module specifier that names
157
+ core (`import`, `require`, `require.resolve`, `import.meta.resolve`, or a
158
+ relative path into `packages/core`). It also flags a path to core's package,
159
+ written as adjacent string segments (`'@astryxdesign', 'core'`,
160
+ `'node_modules', '@astryxdesign/core'`, `'packages', 'core'`) or inside one
161
+ string (`node_modules/@astryxdesign/core`, `packages/core`). In
162
+ `scripts/core-docs.mjs` it allows exactly one such path, the `CORE_ROOT`
163
+ definition, and only the listed reads under `CORE_ROOT`. It does not follow
164
+ paths computed in other ways.
147
165
 
148
166
  ## Experiment matrix
149
167
 
@@ -7,6 +7,7 @@ import Foundation
7
7
  /// or a known one with a value its enums lack or a required prop missing. An older
8
8
  /// app then keeps drawing the rest of a newer core's tree.
9
9
  public enum AstryxNode: Decodable, Equatable, Sendable {
10
+ case badge(BadgeNode)
10
11
  case button(ButtonNode)
11
12
  case card(CardNode)
12
13
  case divider(DividerNode)
@@ -22,6 +23,7 @@ public enum AstryxNode: Decodable, Equatable, Sendable {
22
23
 
23
24
  public var key: String {
24
25
  switch self {
26
+ case .badge(let node): return node.key
25
27
  case .button(let node): return node.key
26
28
  case .card(let node): return node.key
27
29
  case .divider(let node): return node.key
@@ -45,6 +47,7 @@ public enum AstryxNode: Decodable, Equatable, Sendable {
45
47
  let key = try container.decode(String.self, forKey: .key)
46
48
  do {
47
49
  switch component {
50
+ case "Badge": self = .badge(try BadgeNode(from: decoder))
48
51
  case "Button": self = .button(try ButtonNode(from: decoder))
49
52
  case "Card": self = .card(try CardNode(from: decoder))
50
53
  case "Divider": self = .divider(try DividerNode(from: decoder))
@@ -0,0 +1,89 @@
1
+ // Generated by @astryxdesign/native. Do not edit.
2
+ public enum BadgeVariant: String, CaseIterable, Codable, Sendable {
3
+ case neutral = "neutral"
4
+ case info = "info"
5
+ case success = "success"
6
+ case warning = "warning"
7
+ case error = "error"
8
+ case blue = "blue"
9
+ case cyan = "cyan"
10
+ case green = "green"
11
+ case orange = "orange"
12
+ case pink = "pink"
13
+ case purple = "purple"
14
+ case red = "red"
15
+ case teal = "teal"
16
+ case yellow = "yellow"
17
+ }
18
+ #if os(iOS)
19
+ public struct BadgeProps {
20
+ /// Base props attach to this part on every platform.
21
+ public static let baseTarget: AstryxBaseTarget = .root
22
+ public var base: AstryxBaseProps
23
+ public var variant: BadgeVariant?
24
+ public var label: String
25
+ public init(variant: BadgeVariant? = nil, label: String, base: AstryxBaseProps = AstryxBaseProps()) {
26
+ self.variant = variant
27
+ self.label = label
28
+ self.base = base
29
+ }
30
+ }
31
+ public struct BadgeNode: Decodable, Equatable, Sendable {
32
+ public struct Props: Decodable, Equatable, Sendable {
33
+ public var variant: BadgeVariant?
34
+ public var label: String
35
+ }
36
+ public let key: String
37
+ public let base: AstryxBaseProps?
38
+ public let props: Props
39
+ /// The callbacks the core listens to, by prop name.
40
+ public let events: [String]?
41
+
42
+ public func listens(_ event: String) -> Bool { events?.contains(event) ?? false }
43
+
44
+ /// The contract a Badge view takes; its callbacks send actions to the core.
45
+ public func viewProps(send: @escaping @Sendable (AstryxAction) -> Void) -> BadgeProps {
46
+ return BadgeProps(
47
+ variant: props.variant,
48
+ label: props.label,
49
+ base: base ?? AstryxBaseProps()
50
+ )
51
+ }
52
+ }
53
+ #endif
54
+ #if os(macOS)
55
+ public struct BadgeProps {
56
+ /// Base props attach to this part on every platform.
57
+ public static let baseTarget: AstryxBaseTarget = .root
58
+ public var base: AstryxBaseProps
59
+ public var variant: BadgeVariant?
60
+ public var label: String
61
+ public init(variant: BadgeVariant? = nil, label: String, base: AstryxBaseProps = AstryxBaseProps()) {
62
+ self.variant = variant
63
+ self.label = label
64
+ self.base = base
65
+ }
66
+ }
67
+ public struct BadgeNode: Decodable, Equatable, Sendable {
68
+ public struct Props: Decodable, Equatable, Sendable {
69
+ public var variant: BadgeVariant?
70
+ public var label: String
71
+ }
72
+ public let key: String
73
+ public let base: AstryxBaseProps?
74
+ public let props: Props
75
+ /// The callbacks the core listens to, by prop name.
76
+ public let events: [String]?
77
+
78
+ public func listens(_ event: String) -> Bool { events?.contains(event) ?? false }
79
+
80
+ /// The contract a Badge view takes; its callbacks send actions to the core.
81
+ public func viewProps(send: @escaping @Sendable (AstryxAction) -> Void) -> BadgeProps {
82
+ return BadgeProps(
83
+ variant: props.variant,
84
+ label: props.label,
85
+ base: base ?? AstryxBaseProps()
86
+ )
87
+ }
88
+ }
89
+ #endif
@@ -0,0 +1,102 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ //
3
+ // The host side of arm C (AST-082 FR12): a TypeScript logic core runs in a
4
+ // JavaScript engine inside the app and native views draw its tree. Its shape
5
+ // follows the ClientHost of EJ Campbell's astryx-swift spike
6
+ // (github.com/ejc3/astryx-swift, MIT), which runs the core in Hermes. This host
7
+ // uses JavaScriptCore, part of the platform SDK, so the package needs nothing
8
+ // else; a Hermes host speaks the same bridge.
9
+
10
+ #if os(iOS) || os(macOS)
11
+ import Foundation
12
+ import JavaScriptCore
13
+ import Observation
14
+
15
+ /// Runs a logic core bundle and carries its tree to native views and their
16
+ /// actions back, as the JSON `@astryxdesign/native/logic`'s `connectBridge`
17
+ /// speaks.
18
+ ///
19
+ /// The bundle defines a global function, `astryxStart` by default, that takes
20
+ /// the host (`connected(version)` and `changed(json)`) and returns the bridge
21
+ /// (`getSnapshot()` and `dispatch(json)`).
22
+ @MainActor
23
+ @Observable
24
+ public final class AstryxLogicHost {
25
+ /// The bridge version this host speaks (`BRIDGE_VERSION` in TypeScript).
26
+ public static let bridgeVersion = 1
27
+
28
+ /// The current tree; nil before the first snapshot and once the host fails.
29
+ public private(set) var root: AstryxNode?
30
+ /// Why the core stopped or a snapshot could not be read.
31
+ public private(set) var failure: String?
32
+
33
+ @ObservationIgnored private let context: JSContext
34
+ @ObservationIgnored private var bridge: JSValue?
35
+
36
+ public init(bundle source: String, entry: String = "astryxStart") {
37
+ context = JSContext()
38
+ context.exceptionHandler = { [weak self] _, exception in
39
+ let message = exception?.toString() ?? "An unknown JavaScript error"
40
+ MainActor.assumeIsolated { self?.fail(message) }
41
+ }
42
+ context.evaluateScript(source)
43
+ guard failure == nil else { return }
44
+ guard let start = context.objectForKeyedSubscript(entry), start.isObject else {
45
+ fail("The bundle defines no \(entry) function")
46
+ return
47
+ }
48
+ let host = JSValue(newObjectIn: context)
49
+ let connected: @convention(block) (Int) -> Void = { [weak self] version in
50
+ MainActor.assumeIsolated {
51
+ if version != Self.bridgeVersion {
52
+ self?.fail("The core speaks bridge \(version); this host speaks \(Self.bridgeVersion)")
53
+ }
54
+ }
55
+ }
56
+ let changed: @convention(block) (String) -> Void = { [weak self] json in
57
+ MainActor.assumeIsolated { self?.receive(json) }
58
+ }
59
+ host?.setObject(connected, forKeyedSubscript: "connected" as NSString)
60
+ host?.setObject(changed, forKeyedSubscript: "changed" as NSString)
61
+ bridge = start.call(withArguments: [host as Any])
62
+ guard failure == nil, let snapshot = bridge?.invokeMethod("getSnapshot", withArguments: []),
63
+ snapshot.isString, let json = snapshot.toString() else {
64
+ if failure == nil { fail("The bridge returned no snapshot") }
65
+ return
66
+ }
67
+ receive(json)
68
+ }
69
+
70
+ /// Sends a view's action to the core: `node.viewProps(send: host.send)`.
71
+ /// Views call it on the main thread, where it dispatches at once; from any
72
+ /// other thread it dispatches on the main actor.
73
+ public nonisolated func send(_ action: AstryxAction) {
74
+ if Thread.isMainThread {
75
+ MainActor.assumeIsolated { dispatch(action) }
76
+ } else {
77
+ Task { @MainActor in self.dispatch(action) }
78
+ }
79
+ }
80
+
81
+ private func dispatch(_ action: AstryxAction) {
82
+ guard failure == nil, let bridge else { return }
83
+ bridge.invokeMethod("dispatch", withArguments: [action.json])
84
+ }
85
+
86
+ private func receive(_ json: String) {
87
+ // A failed host stays failed: a later tree does not bring it back.
88
+ guard failure == nil else { return }
89
+ do {
90
+ root = try JSONDecoder().decode(AstryxNode.self, from: Data(json.utf8))
91
+ } catch {
92
+ fail("The core sent a tree this binding cannot read: \(error)")
93
+ }
94
+ }
95
+
96
+ /// Stops the host: no tree to draw and no actions sent.
97
+ private func fail(_ message: String) {
98
+ failure = message
99
+ root = nil
100
+ }
101
+ }
102
+ #endif
@@ -15,6 +15,8 @@ import Testing
15
15
  let heading = HeadingProps(level: .v2, children: "Orders")
16
16
  #expect(heading.level.rawValue == 2)
17
17
  #expect(heading.children == "Orders")
18
+ let badge = BadgeProps(variant: .success, label: "Paid")
19
+ #expect(badge.label == "Paid")
18
20
  let divider = DividerProps(label: "Or")
19
21
  #expect(divider.label == "Or")
20
22
  }
@@ -0,0 +1,85 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import Testing
4
+ @testable import AstryxNative
5
+
6
+ /// A logic core with the bridge `@astryxdesign/native/logic` exposes, written
7
+ /// out by hand so the Swift tests need no build step.
8
+ private let settingsBundle = """
9
+ function astryxStart(host) {
10
+ var state = {wifi: true};
11
+ function view() {
12
+ return {component: 'VStack', key: 'root', props: {children: [
13
+ {component: 'Switch', key: 'wifi', props: {label: 'Wi-Fi', value: state.wifi}, events: ['onChange']},
14
+ {component: 'Text', key: 'status', props: {children: state.wifi ? 'Connected' : 'Off'}}
15
+ ]}};
16
+ }
17
+ host.connected(1);
18
+ return {
19
+ getSnapshot: function () { return JSON.stringify(view()); },
20
+ dispatch: function (json) {
21
+ var action = JSON.parse(json);
22
+ if (action.key === 'wifi' && action.event === 'onChange') {
23
+ state = {wifi: action.args[0]};
24
+ host.changed(JSON.stringify(view()));
25
+ }
26
+ }
27
+ };
28
+ }
29
+ """
30
+
31
+ @MainActor
32
+ @Test func aViewsActionReachesTheCoreAndTheNewTreeComesBack() throws {
33
+ let host = AstryxLogicHost(bundle: settingsBundle)
34
+ #expect(host.failure == nil)
35
+ guard case .vStack(let stack) = host.root, case .switch(let wifi) = stack.props.children?[0] else {
36
+ Issue.record("unexpected first tree")
37
+ return
38
+ }
39
+ #expect(wifi.props.value == true)
40
+
41
+ // The view calls its onChange; the action goes to the core.
42
+ let props = wifi.viewProps(send: host.send)
43
+ props.onChange?(false)
44
+
45
+ guard case .vStack(let next) = host.root, case .text(let status) = next.props.children?[1] else {
46
+ Issue.record("unexpected next tree")
47
+ return
48
+ }
49
+ #expect(status.props.children == "Off")
50
+ }
51
+
52
+ @MainActor
53
+ @Test func aLaterErrorClearsTheTreeAndStopsActions() throws {
54
+ let bundle = settingsBundle + "\nvar fragile = astryxStart; astryxStart = function (h) { var b = fragile(h); var d = b.dispatch; b.dispatch = function (j) { if (JSON.parse(j).args[0] === false) throw new Error('core broke'); d(j); }; return b; };"
55
+ let host = AstryxLogicHost(bundle: bundle)
56
+ guard case .vStack(let stack) = host.root, case .switch(let wifi) = stack.props.children?[0] else {
57
+ Issue.record("unexpected first tree")
58
+ return
59
+ }
60
+ wifi.viewProps(send: host.send).onChange?(false)
61
+ #expect(host.failure?.contains("core broke") == true)
62
+ #expect(host.root == nil)
63
+ }
64
+
65
+ @MainActor
66
+ @Test func aTreeAfterAFailureIsIgnored() {
67
+ let bundle = """
68
+ function astryxStart(h) {
69
+ h.connected(2);
70
+ h.changed(JSON.stringify({component: 'Text', key: 'late', props: {children: 'Too late'}}));
71
+ return {getSnapshot: function () { return '{}'; }, dispatch: function () {}};
72
+ }
73
+ """
74
+ let host = AstryxLogicHost(bundle: bundle)
75
+ #expect(host.failure?.contains("bridge 2") == true)
76
+ #expect(host.root == nil)
77
+ }
78
+
79
+ @MainActor
80
+ @Test func aBundleWithoutTheEntryOrWithAnErrorFails() {
81
+ #expect(AstryxLogicHost(bundle: "var x = 1;").failure == "The bundle defines no astryxStart function")
82
+ #expect(AstryxLogicHost(bundle: "throw new Error('boom');").failure?.contains("boom") == true)
83
+ let wrongVersion = AstryxLogicHost(bundle: "function astryxStart(h) { h.connected(2); return {getSnapshot: function () { return '{}'; }}; }")
84
+ #expect(wrongVersion.failure?.contains("bridge 2") == true)
85
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @file components/Badge.ts
3
+ * @input None
4
+ * @output What @astryxdesign/native adds to the core Badge contract
5
+ * @position Native additions read by fromComponentDoc together with core's
6
+ * Badge documentation
7
+ */
8
+ import type { NativeAdditions } from '../contract/fromComponentDoc.js';
9
+ export declare const badge: NativeAdditions;
10
+ //# sourceMappingURL=Badge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Badge.d.ts","sourceRoot":"","sources":["../../src/components/Badge.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,iCAAiC,CAAC;AAErE,eAAO,MAAM,KAAK,EAAE,eAKnB,CAAC"}
@@ -0,0 +1,7 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ export const badge = {
3
+ name: 'Badge',
4
+ baseTarget: 'root',
5
+ // `icon` stays web-only until the core has an icon slot.
6
+ slots: { label: 'text' },
7
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,iCAAiC,CAAC;AAarE,eAAO,MAAM,iBAAiB,EAAE,SAAS,eAAe,EAYvD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,iCAAiC,CAAC;AAcrE,eAAO,MAAM,iBAAiB,EAAE,SAAS,eAAe,EAavD,CAAC"}
@@ -1,4 +1,5 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ import { badge } from './Badge.js';
2
3
  import { button } from './Button.js';
3
4
  import { card } from './Card.js';
4
5
  import { divider } from './Divider.js';
@@ -11,6 +12,7 @@ import { text } from './Text.js';
11
12
  import { textInput } from './TextInput.js';
12
13
  import { vStack } from './VStack.js';
13
14
  export const NATIVE_COMPONENTS = [
15
+ badge,
14
16
  button,
15
17
  card,
16
18
  divider,
@@ -1,6 +1,9 @@
1
1
  // Generated by @astryxdesign/native. Do not edit.
2
- import type {AstryxSharedBaseProps, SelectorOption, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
3
- export type {AstryxSharedBaseProps, AstryxContentNode, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorOption, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
2
+ import type {AstryxSharedBaseProps, SelectorOption, BadgeCoreProps, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
3
+ export type {AstryxSharedBaseProps, AstryxContentNode, BadgeCoreProps, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorOption, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
4
+ /** Badge props: core contract plus the android contract. */
5
+ export interface BadgeProps extends BadgeCoreProps {}
6
+ export declare function Badge(props: BadgeProps): unknown;
4
7
  /** Button props: core contract plus the android contract. */
5
8
  export interface ButtonProps extends ButtonCoreProps {}
6
9
  export declare function Button(props: ButtonProps): unknown;
@@ -36,6 +39,13 @@ export declare function TextInput(props: TextInputProps): unknown;
36
39
  /** VStack props: core contract plus the android contract. */
37
40
  export interface VStackProps extends VStackCoreProps {}
38
41
  export declare function VStack(props: VStackProps): unknown;
42
+ /** Badge as JSON from a TypeScript core. */
43
+ export interface BadgeNode {
44
+ component: 'Badge';
45
+ key: string;
46
+ base?: AstryxSharedBaseProps;
47
+ props: {variant?: 'neutral' | 'info' | 'success' | 'warning' | 'error' | 'blue' | 'cyan' | 'green' | 'orange' | 'pink' | 'purple' | 'red' | 'teal' | 'yellow'; label: string;};
48
+ }
39
49
  /** Button as JSON from a TypeScript core. */
40
50
  export interface ButtonNode {
41
51
  component: 'Button';
@@ -122,7 +132,7 @@ export interface VStackNode {
122
132
  props: {gap?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; padding?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInline?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInlineStart?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInlineEnd?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlock?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlockStart?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlockEnd?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; isScrollable?: boolean; hAlign?: 'start' | 'center' | 'end' | 'stretch'; vAlign?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'; justify?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'; align?: 'start' | 'center' | 'end' | 'stretch'; wrap?: 'nowrap' | 'wrap' | 'wrap-reverse'; children?: ReadonlyArray<AstryxNode>;};
123
133
  }
124
134
  /** Any Astryx component a TypeScript core can send. */
125
- export type AstryxNode = ButtonNode | CardNode | DividerNode | HeadingNode | HStackNode | ProgressBarNode | SelectorNode | SwitchNode | TextNode | TextInputNode | VStackNode;
135
+ export type AstryxNode = BadgeNode | ButtonNode | CardNode | DividerNode | HeadingNode | HStackNode | ProgressBarNode | SelectorNode | SwitchNode | TextNode | TextInputNode | VStackNode;
126
136
  /** A callback a native view called, sent back to the core. */
127
137
  export type AstryxAction =
128
138
  | {key: string; component: 'Button'; event: 'onClick'; args: []}
@@ -15,6 +15,11 @@ export interface SelectorOption {
15
15
  disabled?: boolean;
16
16
  }
17
17
  /** Core contract. Base props attach to the root. */
18
+ export interface BadgeCoreProps extends AstryxSharedBaseProps {
19
+ variant?: 'neutral' | 'info' | 'success' | 'warning' | 'error' | 'blue' | 'cyan' | 'green' | 'orange' | 'pink' | 'purple' | 'red' | 'teal' | 'yellow';
20
+ label: string;
21
+ }
22
+ /** Core contract. Base props attach to the root. */
18
23
  export interface ButtonCoreProps extends AstryxSharedBaseProps {
19
24
  label: string;
20
25
  variant?: 'primary' | 'secondary' | 'ghost' | 'destructive';
@@ -1,6 +1,9 @@
1
1
  // Generated by @astryxdesign/native. Do not edit.
2
- import type {AstryxSharedBaseProps, SelectorOption, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
3
- export type {AstryxSharedBaseProps, AstryxContentNode, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorOption, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
2
+ import type {AstryxSharedBaseProps, SelectorOption, BadgeCoreProps, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
3
+ export type {AstryxSharedBaseProps, AstryxContentNode, BadgeCoreProps, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorOption, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
4
+ /** Badge props: core contract plus the ios contract. */
5
+ export interface BadgeProps extends BadgeCoreProps {}
6
+ export declare function Badge(props: BadgeProps): unknown;
4
7
  /** Button props: core contract plus the ios contract. */
5
8
  export interface ButtonProps extends ButtonCoreProps {}
6
9
  export declare function Button(props: ButtonProps): unknown;
@@ -36,6 +39,13 @@ export declare function TextInput(props: TextInputProps): unknown;
36
39
  /** VStack props: core contract plus the ios contract. */
37
40
  export interface VStackProps extends VStackCoreProps {}
38
41
  export declare function VStack(props: VStackProps): unknown;
42
+ /** Badge as JSON from a TypeScript core. */
43
+ export interface BadgeNode {
44
+ component: 'Badge';
45
+ key: string;
46
+ base?: AstryxSharedBaseProps;
47
+ props: {variant?: 'neutral' | 'info' | 'success' | 'warning' | 'error' | 'blue' | 'cyan' | 'green' | 'orange' | 'pink' | 'purple' | 'red' | 'teal' | 'yellow'; label: string;};
48
+ }
39
49
  /** Button as JSON from a TypeScript core. */
40
50
  export interface ButtonNode {
41
51
  component: 'Button';
@@ -122,7 +132,7 @@ export interface VStackNode {
122
132
  props: {gap?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; padding?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInline?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInlineStart?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInlineEnd?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlock?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlockStart?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlockEnd?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; isScrollable?: boolean; hAlign?: 'start' | 'center' | 'end' | 'stretch'; vAlign?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'; justify?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'; align?: 'start' | 'center' | 'end' | 'stretch'; wrap?: 'nowrap' | 'wrap' | 'wrap-reverse'; children?: ReadonlyArray<AstryxNode>;};
123
133
  }
124
134
  /** Any Astryx component a TypeScript core can send. */
125
- export type AstryxNode = ButtonNode | CardNode | DividerNode | HeadingNode | HStackNode | ProgressBarNode | SelectorNode | SwitchNode | TextNode | TextInputNode | VStackNode;
135
+ export type AstryxNode = BadgeNode | ButtonNode | CardNode | DividerNode | HeadingNode | HStackNode | ProgressBarNode | SelectorNode | SwitchNode | TextNode | TextInputNode | VStackNode;
126
136
  /** A callback a native view called, sent back to the core. */
127
137
  export type AstryxAction =
128
138
  | {key: string; component: 'Button'; event: 'onClick'; args: []}
@@ -1,6 +1,9 @@
1
1
  // Generated by @astryxdesign/native. Do not edit.
2
- import type {AstryxSharedBaseProps, SelectorOption, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
3
- export type {AstryxSharedBaseProps, AstryxContentNode, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorOption, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
2
+ import type {AstryxSharedBaseProps, SelectorOption, BadgeCoreProps, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
3
+ export type {AstryxSharedBaseProps, AstryxContentNode, BadgeCoreProps, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorOption, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
4
+ /** Badge props: core contract plus the macos contract. */
5
+ export interface BadgeProps extends BadgeCoreProps {}
6
+ export declare function Badge(props: BadgeProps): unknown;
4
7
  /** Button props: core contract plus the macos contract. */
5
8
  export interface ButtonProps extends ButtonCoreProps {}
6
9
  export declare function Button(props: ButtonProps): unknown;
@@ -36,6 +39,13 @@ export declare function TextInput(props: TextInputProps): unknown;
36
39
  /** VStack props: core contract plus the macos contract. */
37
40
  export interface VStackProps extends VStackCoreProps {}
38
41
  export declare function VStack(props: VStackProps): unknown;
42
+ /** Badge as JSON from a TypeScript core. */
43
+ export interface BadgeNode {
44
+ component: 'Badge';
45
+ key: string;
46
+ base?: AstryxSharedBaseProps;
47
+ props: {variant?: 'neutral' | 'info' | 'success' | 'warning' | 'error' | 'blue' | 'cyan' | 'green' | 'orange' | 'pink' | 'purple' | 'red' | 'teal' | 'yellow'; label: string;};
48
+ }
39
49
  /** Button as JSON from a TypeScript core. */
40
50
  export interface ButtonNode {
41
51
  component: 'Button';
@@ -122,7 +132,7 @@ export interface VStackNode {
122
132
  props: {gap?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; padding?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInline?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInlineStart?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInlineEnd?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlock?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlockStart?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlockEnd?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; isScrollable?: boolean; hAlign?: 'start' | 'center' | 'end' | 'stretch'; vAlign?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'; justify?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'; align?: 'start' | 'center' | 'end' | 'stretch'; wrap?: 'nowrap' | 'wrap' | 'wrap-reverse'; children?: ReadonlyArray<AstryxNode>;};
123
133
  }
124
134
  /** Any Astryx component a TypeScript core can send. */
125
- export type AstryxNode = ButtonNode | CardNode | DividerNode | HeadingNode | HStackNode | ProgressBarNode | SelectorNode | SwitchNode | TextNode | TextInputNode | VStackNode;
135
+ export type AstryxNode = BadgeNode | ButtonNode | CardNode | DividerNode | HeadingNode | HStackNode | ProgressBarNode | SelectorNode | SwitchNode | TextNode | TextInputNode | VStackNode;
126
136
  /** A callback a native view called, sent back to the core. */
127
137
  export type AstryxAction =
128
138
  | {key: string; component: 'Button'; event: 'onClick'; args: []}
@@ -1,6 +1,9 @@
1
1
  // Generated by @astryxdesign/native. Do not edit.
2
- import type {AstryxSharedBaseProps, SelectorOption, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
3
- export type {AstryxSharedBaseProps, AstryxContentNode, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorOption, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
2
+ import type {AstryxSharedBaseProps, SelectorOption, BadgeCoreProps, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
3
+ export type {AstryxSharedBaseProps, AstryxContentNode, BadgeCoreProps, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorOption, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
4
+ /** Badge props: core contract only. */
5
+ export interface BadgeProps extends BadgeCoreProps {}
6
+ export declare function Badge(props: BadgeProps): unknown;
4
7
  /** Button props: core contract only. */
5
8
  export interface ButtonProps extends ButtonCoreProps {}
6
9
  export declare function Button(props: ButtonProps): unknown;
@@ -34,6 +37,13 @@ export declare function TextInput(props: TextInputProps): unknown;
34
37
  /** VStack props: core contract only. */
35
38
  export interface VStackProps extends VStackCoreProps {}
36
39
  export declare function VStack(props: VStackProps): unknown;
40
+ /** Badge as JSON from a TypeScript core. */
41
+ export interface BadgeNode {
42
+ component: 'Badge';
43
+ key: string;
44
+ base?: AstryxSharedBaseProps;
45
+ props: {variant?: 'neutral' | 'info' | 'success' | 'warning' | 'error' | 'blue' | 'cyan' | 'green' | 'orange' | 'pink' | 'purple' | 'red' | 'teal' | 'yellow'; label: string;};
46
+ }
37
47
  /** Button as JSON from a TypeScript core. */
38
48
  export interface ButtonNode {
39
49
  component: 'Button';
@@ -120,7 +130,7 @@ export interface VStackNode {
120
130
  props: {gap?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; padding?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInline?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInlineStart?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInlineEnd?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlock?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlockStart?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlockEnd?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; isScrollable?: boolean; hAlign?: 'start' | 'center' | 'end' | 'stretch'; vAlign?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'; justify?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'; align?: 'start' | 'center' | 'end' | 'stretch'; wrap?: 'nowrap' | 'wrap' | 'wrap-reverse'; children?: ReadonlyArray<AstryxNode>;};
121
131
  }
122
132
  /** Any Astryx component a TypeScript core can send. */
123
- export type AstryxNode = ButtonNode | CardNode | DividerNode | HeadingNode | HStackNode | ProgressBarNode | SelectorNode | SwitchNode | TextNode | TextInputNode | VStackNode;
133
+ export type AstryxNode = BadgeNode | ButtonNode | CardNode | DividerNode | HeadingNode | HStackNode | ProgressBarNode | SelectorNode | SwitchNode | TextNode | TextInputNode | VStackNode;
124
134
  /** A callback a native view called, sent back to the core. */
125
135
  export type AstryxAction =
126
136
  | {key: string; component: 'Button'; event: 'onClick'; args: []}
@@ -1,6 +1,9 @@
1
1
  // Generated by @astryxdesign/native. Do not edit.
2
- import type {AstryxSharedBaseProps, SelectorOption, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
3
- export type {AstryxSharedBaseProps, AstryxContentNode, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorOption, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
2
+ import type {AstryxSharedBaseProps, SelectorOption, BadgeCoreProps, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
3
+ export type {AstryxSharedBaseProps, AstryxContentNode, BadgeCoreProps, ButtonCoreProps, CardCoreProps, DividerCoreProps, HeadingCoreProps, HStackCoreProps, ProgressBarCoreProps, SelectorOption, SelectorCoreProps, SwitchCoreProps, TextCoreProps, TextInputCoreProps, VStackCoreProps} from './core.js';
4
+ /** Badge props: core contract plus the windows contract. */
5
+ export interface BadgeProps extends BadgeCoreProps {}
6
+ export declare function Badge(props: BadgeProps): unknown;
4
7
  /** Button props: core contract plus the windows contract. */
5
8
  export interface ButtonProps extends ButtonCoreProps {}
6
9
  export declare function Button(props: ButtonProps): unknown;
@@ -34,6 +37,13 @@ export declare function TextInput(props: TextInputProps): unknown;
34
37
  /** VStack props: core contract plus the windows contract. */
35
38
  export interface VStackProps extends VStackCoreProps {}
36
39
  export declare function VStack(props: VStackProps): unknown;
40
+ /** Badge as JSON from a TypeScript core. */
41
+ export interface BadgeNode {
42
+ component: 'Badge';
43
+ key: string;
44
+ base?: AstryxSharedBaseProps;
45
+ props: {variant?: 'neutral' | 'info' | 'success' | 'warning' | 'error' | 'blue' | 'cyan' | 'green' | 'orange' | 'pink' | 'purple' | 'red' | 'teal' | 'yellow'; label: string;};
46
+ }
37
47
  /** Button as JSON from a TypeScript core. */
38
48
  export interface ButtonNode {
39
49
  component: 'Button';
@@ -120,7 +130,7 @@ export interface VStackNode {
120
130
  props: {gap?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; padding?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInline?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInlineStart?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingInlineEnd?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlock?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlockStart?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; paddingBlockEnd?: 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10; isScrollable?: boolean; hAlign?: 'start' | 'center' | 'end' | 'stretch'; vAlign?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'; justify?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'; align?: 'start' | 'center' | 'end' | 'stretch'; wrap?: 'nowrap' | 'wrap' | 'wrap-reverse'; children?: ReadonlyArray<AstryxNode>;};
121
131
  }
122
132
  /** Any Astryx component a TypeScript core can send. */
123
- export type AstryxNode = ButtonNode | CardNode | DividerNode | HeadingNode | HStackNode | ProgressBarNode | SelectorNode | SwitchNode | TextNode | TextInputNode | VStackNode;
133
+ export type AstryxNode = BadgeNode | ButtonNode | CardNode | DividerNode | HeadingNode | HStackNode | ProgressBarNode | SelectorNode | SwitchNode | TextNode | TextInputNode | VStackNode;
124
134
  /** A callback a native view called, sent back to the core. */
125
135
  export type AstryxAction =
126
136
  | {key: string; component: 'Button'; event: 'onClick'; args: []}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/native",
3
- "version": "0.7.5-canary.c60f571",
3
+ "version": "0.7.5-canary.cd53c2d",
4
4
  "description": "Experimental native platforms for Astryx (iOS, Android, macOS, Windows) — published to npm only under the @canary dist-tag; never released as a stable (latest) version.",
5
5
  "author": "Meta Open Source",
6
6
  "license": "MIT",
@@ -69,15 +69,16 @@
69
69
  }
70
70
  },
71
71
  "peerDependencies": {
72
- "@astryxdesign/core": "0.7.5-canary.c60f571"
72
+ "@astryxdesign/core": "0.7.5-canary.cd53c2d"
73
73
  },
74
74
  "devDependencies": {
75
- "@astryxdesign/core": "0.7.5-canary.c60f571"
75
+ "@astryxdesign/core": "0.7.5-canary.cd53c2d"
76
76
  },
77
77
  "scripts": {
78
78
  "build": "node ../../scripts/clean-dist.mjs && tsc --project tsconfig.build.json && node scripts/generate.mjs --types",
79
79
  "generate:apple": "pnpm build && node scripts/generate.mjs --apple",
80
80
  "test": "vitest run --root ../.. packages/native",
81
- "typecheck": "tsc --project tsconfig.json --noEmit"
81
+ "typecheck": "tsc --project tsconfig.json --noEmit",
82
+ "typecheck:types": "tsc --project tsconfig.types.json"
82
83
  }
83
84
  }
@@ -0,0 +1,18 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file components/Badge.ts
5
+ * @input None
6
+ * @output What @astryxdesign/native adds to the core Badge contract
7
+ * @position Native additions read by fromComponentDoc together with core's
8
+ * Badge documentation
9
+ */
10
+
11
+ import type {NativeAdditions} from '../contract/fromComponentDoc.js';
12
+
13
+ export const badge: NativeAdditions = {
14
+ name: 'Badge',
15
+ baseTarget: 'root',
16
+ // `icon` stays web-only until the core has an icon slot.
17
+ slots: {label: 'text'},
18
+ };
@@ -9,6 +9,7 @@
9
9
  */
10
10
 
11
11
  import type {NativeAdditions} from '../contract/fromComponentDoc.js';
12
+ import {badge} from './Badge.js';
12
13
  import {button} from './Button.js';
13
14
  import {card} from './Card.js';
14
15
  import {divider} from './Divider.js';
@@ -22,6 +23,7 @@ import {textInput} from './TextInput.js';
22
23
  import {vStack} from './VStack.js';
23
24
 
24
25
  export const NATIVE_COMPONENTS: readonly NativeAdditions[] = [
26
+ badge,
25
27
  button,
26
28
  card,
27
29
  divider,
@@ -76,6 +76,13 @@ describe('native contracts', () => {
76
76
  values: [1, 2, 3, 4, 5, 6],
77
77
  });
78
78
  expect(byName.get('Text')!.core).not.toHaveProperty('id');
79
+ expect(byName.get('Badge')!.core.label).toMatchObject({
80
+ type: {kind: 'string'},
81
+ optional: false,
82
+ });
83
+ expect(byName.get('Badge')!.webOnly.map(prop => prop.name)).toContain(
84
+ 'icon',
85
+ );
79
86
  });
80
87
 
81
88
  it('reports naming and portability errors', () => {