@texaryn/react-bootstrap 0.1.2 → 0.2.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # @texaryn/react-bootstrap
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3545378: Expose a titled nested object as a named group in React and Vue, closing the last gap the DOM accessibility contract declared.
8
+
9
+ A nested object rendered as a plain `div` gives no indication where one group of fields ends and the next begins. It is now a `fieldset` named by its `legend`, matching what `@texaryn/web-components` already did. The element is chosen once at mount and only the grouping semantics are re-derived, because a conditional subschema can add or drop a title on any recompile and swapping `div` for `fieldset` at that moment would remount the subtree and take the caret with it. An untitled nested object stays a `fieldset` but carries `role="none"`, since an unnamed group is noise in the accessibility tree.
10
+
11
+ The decision is shared through a new `useObjectGroup` hook, so the three React widget sets cannot drift apart on it. The root object is still a plain container: it is the form itself, not a group inside one.
12
+ - 3e53ca9: Keep each field's error container mounted as a live region instead of inserting it with the message already inside.
13
+
14
+ A region that appears together with its content is not reliably announced, which is what every binding did: React and Vue rendered nothing until an error existed, and Web Components kept the node but hid it, which takes it out of the accessibility tree just the same. The container now exists from mount, stays empty while the field is valid, and only its contents change.
15
+
16
+ It is `aria-live="polite" aria-atomic="true"` rather than `role="alert"`. This is a public semantic change: `ErrorProps` promised `role: 'alert'` and now carries the live-region attributes instead. Alert is assertive, and validation runs on change, blur and submit, so keeping it would have interrupted typing and spoken once per failing field on submit. `aria-describedby` stays conditional, pointing at the region only while it has something to say. `ErrorSummary` loses its `role="alert"` and keeps rendering conditionally, because the fields now announce their own errors and an aggregate region would repeat the same validation event.
17
+ - e7c00ce: Render a schema's `readOnly` as read-only rather than disabled, and enforce it in the runtime.
18
+
19
+ A disabled control is not focusable and is announced differently; a read-only one stays focusable and selectable, which is what `readOnly` means. Compiled nodes now carry a resolved `readOnly` that a read-only object or array passes to everything beneath it, because editing a descendant changes the ancestor's value. The runtime refuses `SetValue`, `InsertItem`, `RemoveItem` and `MoveItem` on a read-only node, so a custom widget set cannot write past the restriction; `Reset` stays allowed as the owning authority replacing state. Renderers use the native `readonly` attribute where HTML has one and `aria-readonly` plus refusing the change where it does not, which is select and checkbox. `disabled` remains part of the node API, but the compiler no longer derives it from `readOnly`, so compiled nodes currently resolve it to false.
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies [3545378]
24
+ - Updated dependencies [3e53ca9]
25
+ - Updated dependencies [4a161b2]
26
+ - Updated dependencies [e7c00ce]
27
+ - @texaryn/react@0.3.0
28
+ - @texaryn/core@0.6.0
29
+
30
+ ## 0.1.3
31
+
32
+ ### Patch Changes
33
+
34
+ - Updated dependencies [8b20b6e]
35
+ - @texaryn/core@0.5.0
36
+ - @texaryn/react@0.2.4
37
+
3
38
  ## 0.1.2
4
39
 
5
40
  ### Patch Changes
package/README.md CHANGED
@@ -42,7 +42,7 @@ The CSS import above assumes a bundler that resolves stylesheet imports. A page
42
42
 
43
43
  ## What this package renders
44
44
 
45
- `createBootstrapRegistry()` returns a `RendererRegistry<WidgetComponent>` with seven widgets. Each field widget sits in a `mb-3` wrapper, adds `is-invalid` to its control while the field shows errors, and renders the description as `form-text` and every visible error as `invalid-feedback d-block` inside the binding's `role="alert"` container.
45
+ `createBootstrapRegistry()` returns a `RendererRegistry<WidgetComponent>` with seven widgets. Each field widget sits in a `mb-3` wrapper, adds `is-invalid` to its control while the field shows errors, and renders the description as `form-text` and every visible error as `invalid-feedback d-block` inside the binding's live region, which stays mounted and empty while the field is valid.
46
46
 
47
47
  | Widget | Node it matches | Classes |
48
48
  | --- | --- | --- |
@@ -51,12 +51,12 @@ The CSS import above assumes a bundler that resolves stylesheet imports. A page
51
51
  | `BootstrapTextarea` | field with the `textarea` widget hint | `form-label`, `form-control` |
52
52
  | `BootstrapSelect` | field with enum values | `form-label`, `form-select` |
53
53
  | `BootstrapCheckbox` | boolean field | `form-check`, `form-check-input`, `form-check-label` |
54
- | `BootstrapObjectLayout` | object container | none, a plain `div` around the children |
54
+ | `BootstrapObjectLayout` | object container | a nested object is a `fieldset` named by its `legend`; the root is a plain `div` |
55
55
  | `BootstrapArrayControl` | array container | `btn btn-primary` to add, `btn btn-outline-danger btn-sm` to remove |
56
56
 
57
57
  Enum outranks the primitive type, so a string field with an `enum` renders as a select, and the `textarea` hint outranks both.
58
58
 
59
- `invalid-feedback` is hidden by Bootstrap unless it directly follows an `.is-invalid` sibling. The error lines sit inside the alert container rather than beside the control, so each one carries `d-block`.
59
+ `invalid-feedback` is hidden by Bootstrap unless it directly follows an `.is-invalid` sibling. The error lines sit inside the live region rather than beside the control, so each one carries `d-block`.
60
60
 
61
61
  ## Composing your own registry
62
62
 
@@ -1 +1 @@
1
- {"version":3,"file":"BootstrapFeedback.d.ts","sourceRoot":"","sources":["../../src/widgets/BootstrapFeedback.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAKlD,wBAAgB,iBAAiB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,YAAY,CAAA;CAAE,+BAenE"}
1
+ {"version":3,"file":"BootstrapFeedback.d.ts","sourceRoot":"","sources":["../../src/widgets/BootstrapFeedback.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAKlD,wBAAgB,iBAAiB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,YAAY,CAAA;CAAE,+BAiBnE"}
@@ -1,8 +1,10 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // .invalid-feedback is display: none unless it follows an .is-invalid sibling or
3
- // carries d-block. The lines sit inside the role="alert" container, not beside
4
- // the control, so each one needs d-block.
3
+ // carries d-block. The lines sit inside the live region, not beside the
4
+ // control, so each one needs d-block.
5
5
  export function BootstrapFeedback({ field }) {
6
- return (_jsxs(_Fragment, { children: [field.description ? (_jsx("div", { ...field.descriptionProps, className: "form-text", children: field.description })) : null, field.invalid ? (_jsx("div", { ...field.errorProps, children: field.errors.map((error, index) => (_jsx("div", { className: "invalid-feedback d-block", children: error.message ?? error.keyword }, index))) })) : null] }));
6
+ return (_jsxs(_Fragment, { children: [field.description ? (_jsx("div", { ...field.descriptionProps, className: "form-text", children: field.description })) : null, _jsx("div", { ...field.errorProps, children: field.invalid
7
+ ? field.errors.map((error, index) => (_jsx("div", { className: "invalid-feedback d-block", children: error.message ?? error.keyword }, index)))
8
+ : null })] }));
7
9
  }
8
10
  //# sourceMappingURL=BootstrapFeedback.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BootstrapFeedback.js","sourceRoot":"","sources":["../../src/widgets/BootstrapFeedback.tsx"],"names":[],"mappings":";AAEA,iFAAiF;AACjF,+EAA+E;AAC/E,0CAA0C;AAC1C,MAAM,UAAU,iBAAiB,CAAC,EAAE,KAAK,EAA2B;IAClE,OAAO,CACL,8BACG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CACnB,iBAAS,KAAK,CAAC,gBAAgB,EAAE,SAAS,EAAC,WAAW,YAAE,KAAK,CAAC,WAAW,GAAO,CACjF,CAAC,CAAC,CAAC,IAAI,EACP,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CACf,iBAAS,KAAK,CAAC,UAAU,YACtB,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAClC,cAAiB,SAAS,EAAC,0BAA0B,YAAE,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,IAA3E,KAAK,CAA6E,CAC7F,CAAC,GACE,CACP,CAAC,CAAC,CAAC,IAAI,IACP,CACJ,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"BootstrapFeedback.js","sourceRoot":"","sources":["../../src/widgets/BootstrapFeedback.tsx"],"names":[],"mappings":";AAEA,iFAAiF;AACjF,wEAAwE;AACxE,sCAAsC;AACtC,MAAM,UAAU,iBAAiB,CAAC,EAAE,KAAK,EAA2B;IAClE,OAAO,CACL,8BACG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CACnB,iBAAS,KAAK,CAAC,gBAAgB,EAAE,SAAS,EAAC,WAAW,YAAE,KAAK,CAAC,WAAW,GAAO,CACjF,CAAC,CAAC,CAAC,IAAI,EAGR,iBAAS,KAAK,CAAC,UAAU,YACtB,KAAK,CAAC,OAAO;oBACZ,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CACjC,cAAiB,SAAS,EAAC,0BAA0B,YAAE,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,IAA3E,KAAK,CAA6E,CAC7F,CAAC;oBACJ,CAAC,CAAC,IAAI,GACJ,IACL,CACJ,CAAA;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"BootstrapObjectLayout.d.ts","sourceRoot":"","sources":["../../src/widgets/BootstrapObjectLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,KAAK,EAAiB,MAAM,EAAE,MAAM,eAAe,CAAA;AAG1D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;CACb;AAED,iBAAS,yBAAyB,CAAC,EAAE,IAAI,EAAE,EAAE,WAAW,qBAevD;AAED,eAAO,MAAM,qBAAqB,6DAGjC,CAAA"}
1
+ {"version":3,"file":"BootstrapObjectLayout.d.ts","sourceRoot":"","sources":["../../src/widgets/BootstrapObjectLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAG3C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;CACb;AAED,iBAAS,yBAAyB,CAAC,EAAE,IAAI,EAAE,EAAE,WAAW,qBAkBvD;AAED,eAAO,MAAM,qBAAqB,6DAGjC,CAAA"}
@@ -1,16 +1,14 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
- import { NodeRenderer, useRendererContext } from '@texaryn/react';
3
+ import { NodeRenderer, useObjectGroup, useRendererContext } from '@texaryn/react';
4
4
  function BootstrapObjectLayoutImpl({ node }) {
5
- const containerNode = node;
6
5
  const { document, registry } = useRendererContext();
7
- return (_jsx("div", { children: containerNode.children.map((childId) => {
8
- const child = document.nodes[childId];
9
- if (!child) {
10
- return null;
11
- }
12
- return _jsx(NodeRenderer, { node: child, document: document, registry: registry }, childId);
13
- }) }));
6
+ const { nested, title, children } = useObjectGroup(node);
7
+ const rendered = children.map((child) => (_jsx(NodeRenderer, { node: child, document: document, registry: registry }, child.id)));
8
+ if (!nested) {
9
+ return _jsx("div", { children: rendered });
10
+ }
11
+ return (_jsxs("fieldset", { role: title === undefined ? 'none' : undefined, className: "mb-3", children: [title === undefined ? null : _jsx("legend", { className: "fs-6 fw-semibold", children: title }), _jsx("div", { children: rendered })] }));
14
12
  }
15
13
  export const BootstrapObjectLayout = React.memo(BootstrapObjectLayoutImpl, (prev, next) => prev.node.id === next.node.id);
16
14
  //# sourceMappingURL=BootstrapObjectLayout.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BootstrapObjectLayout.js","sourceRoot":"","sources":["../../src/widgets/BootstrapObjectLayout.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAMjE,SAAS,yBAAyB,CAAC,EAAE,IAAI,EAAe;IACtD,MAAM,aAAa,GAAG,IAAqB,CAAA;IAC3C,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,kBAAkB,EAAE,CAAA;IAEnD,OAAO,CACL,wBACG,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;YACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YACrC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,IAAI,CAAA;YACb,CAAC;YACD,OAAO,KAAC,YAAY,IAAe,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,IAA5D,OAAO,CAAyD,CAAA;QAC5F,CAAC,CAAC,GACE,CACP,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,CAAC,IAAI,CAC7C,yBAAyB,EACzB,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC,EAAE,CAC9C,CAAA"}
1
+ {"version":3,"file":"BootstrapObjectLayout.js","sourceRoot":"","sources":["../../src/widgets/BootstrapObjectLayout.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAMjF,SAAS,yBAAyB,CAAC,EAAE,IAAI,EAAe;IACtD,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,kBAAkB,EAAE,CAAA;IACnD,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;IAExD,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACvC,KAAC,YAAY,IAAgB,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,IAA7D,KAAK,CAAC,EAAE,CAAyD,CACrF,CAAC,CAAA;IAEF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,wBAAM,QAAQ,GAAO,CAAA;IAC9B,CAAC;IAED,OAAO,CACL,oBAAU,IAAI,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAAE,SAAS,EAAC,MAAM,aACvE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAQ,SAAS,EAAC,kBAAkB,YAAE,KAAK,GAAU,EACnF,wBAAM,QAAQ,GAAO,IACZ,CACZ,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,CAAC,IAAI,CAC7C,yBAAyB,EACzB,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC,EAAE,CAC9C,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@texaryn/react-bootstrap",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Bootstrap 5 widgets for Texaryn: native markup and Bootstrap classes on top of @texaryn/react",
5
5
  "keywords": [
6
6
  "react",
@@ -41,12 +41,12 @@
41
41
  "CHANGELOG.md"
42
42
  ],
43
43
  "dependencies": {
44
- "@texaryn/core": "^0.4.0"
44
+ "@texaryn/core": "^0.6.0"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "react": ">=18.0.0",
48
48
  "bootstrap": "^5.3",
49
- "@texaryn/react": "^0.2.3"
49
+ "@texaryn/react": "^0.3.0"
50
50
  },
51
51
  "peerDependenciesMeta": {
52
52
  "bootstrap": {
@@ -59,8 +59,8 @@
59
59
  "jsdom": "^25.0.0",
60
60
  "react": "^19.0.0",
61
61
  "react-dom": "^19.0.0",
62
- "@texaryn/react": "0.2.3",
63
- "@texaryn/schema-json": "0.2.3"
62
+ "@texaryn/schema-json": "0.2.5",
63
+ "@texaryn/react": "0.3.0"
64
64
  },
65
65
  "scripts": {
66
66
  "build": "tsc --build"