jui-tools-mcp-server 2.12.1 → 2.12.3

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.
@@ -1,6 +1,32 @@
1
1
  {
2
2
  "_comment": "Unified attribute definitions for JsonUI (Swift/Kotlin/React). Binding format: @{propertyName}. When `type` includes \"binding\", an optional `binding_direction` field declares how the MCP should label the binding: \"two-way\" means the component writes back to the binding (e.g. TextField.text); omit the field (or set \"read-only\") for values that only flow view ← model. Optional extended fields per attribute: `aliases` (array of alternate names treated as synonyms for this canonical attribute; validator expands these at load time), `deprecated` (boolean; validator emits a warning when the attribute is used), `deprecation_note` (string appended to the warning to explain the replacement or limitation).",
3
3
  "common": {
4
+ "glass": {
5
+ "type": ["boolean", "object"],
6
+ "platform": "swift",
7
+ "mode": ["uikit", "swiftui"],
8
+ "description": "Liquid Glass. true for the default treatment, or an object {style: regular|clear|identity, tint: color, interactive: bool, shape: capsule|rect|circle|rounded(N)}. Declared on common rather than per component because ios.md names View, Button, TextField and Label followed by 'etc' - an open list, and a per-component declaration would make the set of components the acceptance population, so every reading of 'etc' becomes a gap. mode carries BOTH uikit and swiftui because the attribute has two implementations, .glassEffect() on SwiftUI and UIGlassEffect on UIKit; this is the first declaration in the file to pair those two, though five declarations already use an array for mode and both readers accept one (kjui Array(attr_def['mode']), jui isinstance(raw, list)). Leaving mode off would not have meant 'both' - an absent mode means NO restriction at all (kjui attribute_validator_core.rb mode_compatible? returns true when the key is missing), which would let the attribute read as available in modes it has no implementation for.",
9
+ "properties": {
10
+ "style": {
11
+ "type": "string",
12
+ "enum": ["regular", "clear", "identity"],
13
+ "description": "Glass appearance. SwiftUI has all three (SwiftUICore.Glass.regular / .clear / .identity). UIKit has only two: UIGlassEffectStyle is Regular and Clear, so `identity` is SwiftUI-only and the UIKit path applies no effect for it rather than resolving a member that does not exist."
14
+ },
15
+ "tint": {
16
+ "type": "string",
17
+ "description": "Tint colour applied to the glass. SwiftUI Glass.tint(_ color: Color?), UIKit UIGlassEffect.tintColor."
18
+ },
19
+ "interactive": {
20
+ "type": "boolean",
21
+ "description": "Whether the glass reacts to touch. SwiftUI Glass.interactive(_:), UIKit UIGlassEffect.interactive. An explicit false is a value the author wrote and is distinct from the key being absent - the SwiftUI Glass type does not preserve that distinction (measured: Glass.regular == Glass.regular.interactive(false)), so the implementation records the author's choice before calling the SDK."
22
+ },
23
+ "shape": {
24
+ "type": "string",
25
+ "enum": ["capsule", "circle", "rect"],
26
+ "description": "Shape the glass is clipped to. The enum is the complete set of FIXED spellings; `rounded(N)` is additionally accepted and cannot be an enum member because N varies, so a validator checks the enum first and the `rounded(` prefix second. SwiftUI takes a shape argument (.glassEffect(_:in:)); UIKit does not - UIGlassEffect is a UIVisualEffect subclass with no shape parameter, so there the shape comes from the host view. Transcribed from the implementation that resolves them (SJUIGlass.swift knownShapeSpellings), not from this file's own prose - the two disagreed once already (`rectangle` was accepted by the implementation and named by nobody)."
27
+ }
28
+ }
29
+ },
4
30
  "_comment": "Common attributes shared across all components",
5
31
  "$jui": {
6
32
  "type": "object",
@@ -1669,9 +1695,13 @@
1669
1695
  "phone",
1670
1696
  "url",
1671
1697
  "password",
1672
- "decimal"
1698
+ "decimal",
1699
+ "signedDecimal",
1700
+ "date",
1701
+ "time",
1702
+ "datetime"
1673
1703
  ],
1674
- "description": "Input type (includes 'allphabet' typo for backward compatibility)"
1704
+ "description": "Input type (includes 'allphabet' typo for backward compatibility). Not every face can express every value, and the degradations are declared here so that an implementer does not rediscover them one at a time. Android, codegen: all four of the values added in 1.8.8x land natively (Compose 1.12 KeyboardType.Date / Time / DateTime / DecimalSigned - note the order: Signed is a suffix in Compose, so the member is DecimalSigned, modifier last, while the value declared here is signedDecimal, modifier first. Each reads as a typo of the other. The plan for this work named the member SignedDecimal, which does not exist, and this description repeated it until 2026-09-14. Both spellings therefore appear in this text on purpose, here and in the four vendored tables that copy it, so grepping for SignedDecimal finds hits that are the correction rather than the defect - the hit count is not a measure of whether this was fixed). Android, dynamic: the runtime renderer has no case for any of the four - DynamicTextFieldComponent and DynamicTextViewComponent both fall to `else -> KeyboardType.Text` - so they degrade to plain text there. The two Android faces differ, and 'Android supports it' is true only of the generated one. The floor is codegen's alone: the generated Kotlin NAMES the member, so Compose below 1.12 would be a COMPILE error there rather than a degradation - ui-text 1.11 has ten KeyboardType members and none of these four, and 1.12.0 is the first with Date, Time, DateTime and DecimalSigned. Dynamic needs nothing new, because it never names them: it falls to KeyboardType.Text, which 1.11 already has. As of 1.8.80 the Compose emitter carries that floor, and it is DECLARED rather than detected: a project that declares nothing keeps the real members, and a project that sets compose_version below 1.12.0 in kjui.config.json gets these four - and only these four - degraded to KeyboardType.Text, on TextView as well as TextField because both read one table. Nothing is detected, because this generator never sees the consumer's dependency graph; a project on an older Compose that declares nothing therefore still gets a build failure rather than a silent keyboard change, which is the failure a reader can act on. The comparison is Gem::Version and never String, because '1.9.0' sorts ABOVE '1.12.0' as text and that is the direction that ships the build failure. web, TextField: date, time and datetime are not inputmode values; they change the element type to date, time and datetime-local, which is the path SelectBox's datepicker already takes. web, TextView: a textarea has no type attribute at all, so those three degrade to plain text there and the declared value cannot be honoured. web, inputmode: signedDecimal has no inputmode of its own and must share decimal with the decimal value above, so on web the two are INDISTINGUISHABLE. web, type: number and decimal already collapse to type=number, and signedDecimal joins them. iOS: UIKeyboardType has no member for the date family, so they fall back to .default, and signedDecimal to .numbersAndPunctuation."
1675
1705
  },
1676
1706
  "inputType": {
1677
1707
  "type": "string",
@@ -1782,7 +1812,7 @@
1782
1812
  },
1783
1813
  "applyLiquidGlass": {
1784
1814
  "type": "boolean",
1785
- "description": "Apply liquid glass effect",
1815
+ "description": "Apply liquid glass effect. SUPERSEDED by the common attribute 'glass' as of 2026-09-14. The fold from this spelling to glass belongs to the normalizer and IS NOT IMPLEMENTED YET, so both spellings are live: this one stays TextField-only, UIKit-only and backed by UIBlurEffect, while glass is declared on common for SwiftUI and UIKit. Nothing breaks while both exist - they do not overlap in platform, mode or component - but a layout should be written against glass.",
1786
1816
  "platform": "swift",
1787
1817
  "mode": "uikit"
1788
1818
  },
@@ -1794,7 +1824,7 @@
1794
1824
  },
1795
1825
  "glassEffectStyle": {
1796
1826
  "type": "string",
1797
- "description": "Glass effect style",
1827
+ "description": "Glass effect style. SUPERSEDED by glass.style as of 2026-09-14. As with applyLiquidGlass, the normalizer fold is NOT IMPLEMENTED YET and both spellings are live.",
1798
1828
  "platform": "swift",
1799
1829
  "mode": "uikit"
1800
1830
  },
@@ -2117,9 +2147,13 @@
2117
2147
  "phone",
2118
2148
  "url",
2119
2149
  "password",
2120
- "decimal"
2150
+ "decimal",
2151
+ "signedDecimal",
2152
+ "date",
2153
+ "time",
2154
+ "datetime"
2121
2155
  ],
2122
- "description": "Input type (includes 'allphabet' typo for backward compatibility)"
2156
+ "description": "Input type (includes 'allphabet' typo for backward compatibility). Not every face can express every value, and the degradations are declared here so that an implementer does not rediscover them one at a time. Android, codegen: all four of the values added in 1.8.8x land natively (Compose 1.12 KeyboardType.Date / Time / DateTime / DecimalSigned - note the order: Signed is a suffix in Compose, so the member is DecimalSigned, modifier last, while the value declared here is signedDecimal, modifier first. Each reads as a typo of the other. The plan for this work named the member SignedDecimal, which does not exist, and this description repeated it until 2026-09-14. Both spellings therefore appear in this text on purpose, here and in the four vendored tables that copy it, so grepping for SignedDecimal finds hits that are the correction rather than the defect - the hit count is not a measure of whether this was fixed). Android, dynamic: the runtime renderer has no case for any of the four - DynamicTextFieldComponent and DynamicTextViewComponent both fall to `else -> KeyboardType.Text` - so they degrade to plain text there. The two Android faces differ, and 'Android supports it' is true only of the generated one. The floor is codegen's alone: the generated Kotlin NAMES the member, so Compose below 1.12 would be a COMPILE error there rather than a degradation - ui-text 1.11 has ten KeyboardType members and none of these four, and 1.12.0 is the first with Date, Time, DateTime and DecimalSigned. Dynamic needs nothing new, because it never names them: it falls to KeyboardType.Text, which 1.11 already has. As of 1.8.80 the Compose emitter carries that floor, and it is DECLARED rather than detected: a project that declares nothing keeps the real members, and a project that sets compose_version below 1.12.0 in kjui.config.json gets these four - and only these four - degraded to KeyboardType.Text, on TextView as well as TextField because both read one table. Nothing is detected, because this generator never sees the consumer's dependency graph; a project on an older Compose that declares nothing therefore still gets a build failure rather than a silent keyboard change, which is the failure a reader can act on. The comparison is Gem::Version and never String, because '1.9.0' sorts ABOVE '1.12.0' as text and that is the direction that ships the build failure. web, TextField: date, time and datetime are not inputmode values; they change the element type to date, time and datetime-local, which is the path SelectBox's datepicker already takes. web, TextView: a textarea has no type attribute at all, so those three degrade to plain text there and the declared value cannot be honoured. web, inputmode: signedDecimal has no inputmode of its own and must share decimal with the decimal value above, so on web the two are INDISTINGUISHABLE. web, type: number and decimal already collapse to type=number, and signedDecimal joins them. iOS: UIKeyboardType has no member for the date family, so they fall back to .default, and signedDecimal to .numbersAndPunctuation."
2123
2157
  },
2124
2158
  "returnKeyType": {
2125
2159
  "type": "string",
@@ -4724,7 +4758,7 @@
4724
4758
  "string",
4725
4759
  "binding"
4726
4760
  ],
4727
- "description": "Unselected tab color - hex string or color name from colors.json (binding supported)"
4761
+ "description": "Unselected tab color - hex string or color name from colors.json (binding supported). SCOPE: this is the colour of an unselected TAB ITEM, so it only concerns TabView used as a tab bar. A TabView carrying .tabViewStyle(.page) is a PAGER and has no tab items at all, so nothing here applies to it - measured 2026-09-15 across two consumer faces, where all four TabView uses were .page pagers and the exposure to this key was zero. iOS 26 AND LATER DO NOT HONOUR THIS, on either iOS face, and there is no replacement: SwiftUI exposes no per-item tint for a tab bar (the whole tab/toolbar modifier surface was enumerated from the iOS 27 SDK swiftinterface - tabBarMinimizeBehavior, tabViewCustomization, tabViewSearchActivation and eleven toolbar* modifiers, none of which reaches an item), so both faces route through the UIKit appearance proxy UITabBar.appearance().unselectedItemTintColor. Measured 2026-09-15 on iPhone 16 Pro / iOS 26.5: the fixture renders 0 differing pixels from its control while tabBarBackground renders 223110 and tintColor 4553 on the same capture. The proxy is not being cleared - reading it back immediately after the set and again one runloop later both return the assigned colour - iOS 26 simply ignores it for item tints, having replaced the tab bar. Three replacement routes were rendered and each measured 0: the legacy property, UITabBarAppearance item colours (stackedLayoutAppearance / inlineLayoutAppearance / compactInlineLayoutAppearance, assigned to standardAppearance and scrollEdgeAppearance) in onAppear, and the same set before the view is constructed; a build control injecting a red backgroundColor on that same path moved 223110 pixels, so the code demonstrably ran. NOT a v10.22.0 regression: conformance run 34849471695 shows it on iOS 26 before that tag existed, and the iOS 18 runs before it do not. The sibling keys are unaffected - tintColor, tabBarBackground (which also has a SwiftUI route) and the Slider / Switch / Segment appearance proxies are all still active on iOS 26, so this is one key, not the proxy as a whole. android and web are unaffected and still honour it."
4728
4762
  },
4729
4763
  "tabBarBackground": {
4730
4764
  "type": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jui-tools-mcp-server",
3
- "version": "2.12.1",
3
+ "version": "2.12.3",
4
4
  "description": "MCP server for JsonUI project management - wraps jui and jsonui-doc CLIs plus component spec lookup",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -44,7 +44,7 @@ const DATA_DIR = join(PROJECT_ROOT, "data");
44
44
  // 3. `npm run fetch-definitions` and commit the data/ diff together with
45
45
  // this pin in one commit
46
46
  // JSONUI_CLI_RAW_BASE still overrides the whole base URL for manual testing.
47
- const JSONUI_CLI_TAG = "v1.8.67";
47
+ const JSONUI_CLI_TAG = "v1.8.85";
48
48
  const BASE_URL =
49
49
  process.env.JSONUI_CLI_RAW_BASE ||
50
50
  `https://raw.githubusercontent.com/Tai-Kimura/jsonui-cli/${JSONUI_CLI_TAG}`;