@dreamtree-org/twreact-ui 2.1.0 → 2.1.1
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/dist/components/core/Accordion.d.ts.map +1 -1
- package/dist/components/core/menu/MenuPopover.d.ts.map +1 -1
- package/dist/esm/components/core/Accordion.js +3 -1
- package/dist/esm/components/core/menu/MenuPopover.js +4 -2
- package/dist/esm/components/navigation/Navbar.js +1 -1
- package/dist/index.esm.js +13 -9
- package/dist/index.js +13 -9
- package/mcp/catalog.snapshot.json +1 -1
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Accordion.d.ts","sourceRoot":"","sources":["../../../src/components/core/Accordion.jsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"Accordion.d.ts","sourceRoot":"","sources":["../../../src/components/core/Accordion.jsx"],"names":[],"mappings":";AAQA;;;;GAIG;AAEH,mFA+QG;kBA7RqF,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MenuPopover.d.ts","sourceRoot":"","sources":["../../../../src/components/core/menu/MenuPopover.jsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MenuPopover.d.ts","sourceRoot":"","sources":["../../../../src/components/core/menu/MenuPopover.jsx"],"names":[],"mappings":"AAwBA,8MAIC;AAED;;;;;;;;;GASG;AACH,0LARG;IAAgC,QAAQ,EAAhC,WAAW,GAAC,IAAI;IACH,KAAK;IACY,YAAY,EAA1C,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI;IACU,cAAc,EAA9C,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI;IACT,SAAS;IACD,YAAY;IACnB,aAAa;CACvC,2CAsHA"}
|
|
@@ -7,6 +7,8 @@ import { useLatestRef } from '../../hooks/useLatestRef.js';
|
|
|
7
7
|
import { useReducedMotion } from '../../hooks/useReducedMotion.js';
|
|
8
8
|
|
|
9
9
|
var _excluded = ["items", "allowMultiple", "defaultOpenIndexes", "onChange", "className", "headerClassName", "contentClassName", "chevronPosition", "chevronIcon", "bordered", "rounded", "size", "transitionDuration"];
|
|
10
|
+
// useLayoutEffect warns during SSR; fall back to useEffect on the server.
|
|
11
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
10
12
|
/**
|
|
11
13
|
* item.leftIcon may be:
|
|
12
14
|
* - ReactNode (e.g. <svg/>)
|
|
@@ -76,7 +78,7 @@ var Accordion = /*#__PURE__*/forwardRef(function Accordion(_ref, ref) {
|
|
|
76
78
|
// refs / the DOM. An open panel settles on `max-height: none` so content
|
|
77
79
|
// that grows after opening is never clipped; closed panels are `inert` so
|
|
78
80
|
// Tab cannot land inside collapsed content.
|
|
79
|
-
|
|
81
|
+
useIsomorphicLayoutEffect(function () {
|
|
80
82
|
var prevOpen = prevOpenRef.current;
|
|
81
83
|
var timers = [];
|
|
82
84
|
panelRefs.current.forEach(function (panelEl, idx) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
-
import { useRef, useState,
|
|
4
|
+
import { useRef, useState, useCallback, useMemo, useEffect, useLayoutEffect } from 'react';
|
|
5
5
|
import { cn } from '../../../utils/cn.js';
|
|
6
6
|
import { setRefs } from '../../../utils/position.js';
|
|
7
7
|
import Portal from '../../utility/Portal.js';
|
|
@@ -12,6 +12,8 @@ import { useLatestRef } from '../../../hooks/useLatestRef.js';
|
|
|
12
12
|
import { getMenuItems, handleMenuKeyDown } from './menuKeyboard.js';
|
|
13
13
|
import { isDestructive } from './menuItems.js';
|
|
14
14
|
|
|
15
|
+
// useLayoutEffect warns during SSR; fall back to useEffect on the server.
|
|
16
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
15
17
|
// Internal (not exported). Desktop presentation of the action menu: a
|
|
16
18
|
// portaled, floating `role="menu"` anchored to its trigger (flip + shift via
|
|
17
19
|
// useFloatingPosition), with roving focus and Escape/outside-press dismissal.
|
|
@@ -64,7 +66,7 @@ function MenuPopover(_ref) {
|
|
|
64
66
|
menuEl = _useState2[0],
|
|
65
67
|
setMenuEl = _useState2[1];
|
|
66
68
|
var closeRef = useLatestRef(onRequestClose);
|
|
67
|
-
|
|
69
|
+
useIsomorphicLayoutEffect(function () {
|
|
68
70
|
refs.setReference(anchorEl !== null && anchorEl !== void 0 ? anchorEl : null);
|
|
69
71
|
}, [refs, anchorEl]);
|
|
70
72
|
var setMenuNode = useCallback(function (node) {
|
|
@@ -577,7 +577,7 @@ Navbar.propTypes = {
|
|
|
577
577
|
emitter: PropTypes.object.isRequired,
|
|
578
578
|
logo: PropTypes.node,
|
|
579
579
|
center: PropTypes.node,
|
|
580
|
-
items: PropTypes.array
|
|
580
|
+
items: PropTypes.array,
|
|
581
581
|
user: PropTypes.object,
|
|
582
582
|
notifications: PropTypes.array,
|
|
583
583
|
searchable: PropTypes.bool,
|
package/dist/index.esm.js
CHANGED
|
@@ -3836,7 +3836,7 @@ function setRefs$1(node) {
|
|
|
3836
3836
|
}
|
|
3837
3837
|
|
|
3838
3838
|
// useLayoutEffect warns during SSR; fall back to useEffect on the server.
|
|
3839
|
-
var useIsomorphicLayoutEffect$
|
|
3839
|
+
var useIsomorphicLayoutEffect$c = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
3840
3840
|
/**
|
|
3841
3841
|
* Internal (not exported from the package): a ref that always holds the latest
|
|
3842
3842
|
* `value`. Lets an effect call the newest consumer callback (e.g. `onChange`)
|
|
@@ -3845,7 +3845,7 @@ var useIsomorphicLayoutEffect$a = typeof window !== "undefined" ? useLayoutEffec
|
|
|
3845
3845
|
*/
|
|
3846
3846
|
function useLatestRef$1(value) {
|
|
3847
3847
|
var ref = useRef(value);
|
|
3848
|
-
useIsomorphicLayoutEffect$
|
|
3848
|
+
useIsomorphicLayoutEffect$c(function () {
|
|
3849
3849
|
ref.current = value;
|
|
3850
3850
|
});
|
|
3851
3851
|
return ref;
|
|
@@ -9116,6 +9116,8 @@ function normalizeAction(action, idx) {
|
|
|
9116
9116
|
|
|
9117
9117
|
function ownKeys$1a(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
9118
9118
|
function _objectSpread$1a(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$1a(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$1a(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
9119
|
+
// useLayoutEffect warns during SSR; fall back to useEffect on the server.
|
|
9120
|
+
var useIsomorphicLayoutEffect$b = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
9119
9121
|
// Internal (not exported). Desktop presentation of the action menu: a
|
|
9120
9122
|
// portaled, floating `role="menu"` anchored to its trigger (flip + shift via
|
|
9121
9123
|
// useFloatingPosition), with roving focus and Escape/outside-press dismissal.
|
|
@@ -9168,7 +9170,7 @@ function MenuPopover(_ref) {
|
|
|
9168
9170
|
menuEl = _useState2[0],
|
|
9169
9171
|
setMenuEl = _useState2[1];
|
|
9170
9172
|
var closeRef = useLatestRef$1(onRequestClose);
|
|
9171
|
-
|
|
9173
|
+
useIsomorphicLayoutEffect$b(function () {
|
|
9172
9174
|
refs.setReference(anchorEl !== null && anchorEl !== void 0 ? anchorEl : null);
|
|
9173
9175
|
}, [refs, anchorEl]);
|
|
9174
9176
|
var setMenuNode = useCallback(function (node) {
|
|
@@ -12446,7 +12448,7 @@ var getProxyFormState = (formState, control, localProxyFormState, isRoot = true)
|
|
|
12446
12448
|
return result;
|
|
12447
12449
|
};
|
|
12448
12450
|
|
|
12449
|
-
const useIsomorphicLayoutEffect$
|
|
12451
|
+
const useIsomorphicLayoutEffect$a = typeof window !== 'undefined' ? React__default.useLayoutEffect : React__default.useEffect;
|
|
12450
12452
|
|
|
12451
12453
|
/**
|
|
12452
12454
|
* This custom hook allows you to subscribe to each form state, and isolate the re-render at the custom hook level. It has its scope in terms of form state subscription, so it would not affect other useFormState and useForm. Using this hook can reduce the re-render impact on large and complex form application.
|
|
@@ -12492,7 +12494,7 @@ function useFormState(props) {
|
|
|
12492
12494
|
isValid: false,
|
|
12493
12495
|
errors: false,
|
|
12494
12496
|
});
|
|
12495
|
-
useIsomorphicLayoutEffect$
|
|
12497
|
+
useIsomorphicLayoutEffect$a(() => control._subscribe({
|
|
12496
12498
|
name,
|
|
12497
12499
|
formState: _localProxyFormState.current,
|
|
12498
12500
|
exact,
|
|
@@ -12611,7 +12613,7 @@ function useWatch(props) {
|
|
|
12611
12613
|
}
|
|
12612
12614
|
}
|
|
12613
12615
|
}, [control._formValues, control._names, disabled, name]);
|
|
12614
|
-
useIsomorphicLayoutEffect$
|
|
12616
|
+
useIsomorphicLayoutEffect$a(() => {
|
|
12615
12617
|
if (_prevControl.current !== control ||
|
|
12616
12618
|
!deepEqual(_prevName.current, name)) {
|
|
12617
12619
|
_prevControl.current = control;
|
|
@@ -14692,7 +14694,7 @@ function useForm(props = {}) {
|
|
|
14692
14694
|
}
|
|
14693
14695
|
const control = _formControl.current.control;
|
|
14694
14696
|
control._options = props;
|
|
14695
|
-
useIsomorphicLayoutEffect$
|
|
14697
|
+
useIsomorphicLayoutEffect$a(() => {
|
|
14696
14698
|
const sub = control._subscribe({
|
|
14697
14699
|
formState: control._proxyFormState,
|
|
14698
14700
|
callback: () => updateFormState({ ...control._formState }),
|
|
@@ -19790,6 +19792,8 @@ Form.displayName = "Form";
|
|
|
19790
19792
|
var _excluded$T = ["items", "allowMultiple", "defaultOpenIndexes", "onChange", "className", "headerClassName", "contentClassName", "chevronPosition", "chevronIcon", "bordered", "rounded", "size", "transitionDuration"];
|
|
19791
19793
|
function ownKeys$$(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
19792
19794
|
function _objectSpread$$(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$$(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$$(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
19795
|
+
// useLayoutEffect warns during SSR; fall back to useEffect on the server.
|
|
19796
|
+
var useIsomorphicLayoutEffect$9 = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
19793
19797
|
/**
|
|
19794
19798
|
* item.leftIcon may be:
|
|
19795
19799
|
* - ReactNode (e.g. <svg/>)
|
|
@@ -19859,7 +19863,7 @@ var Accordion = /*#__PURE__*/forwardRef(function Accordion(_ref, ref) {
|
|
|
19859
19863
|
// refs / the DOM. An open panel settles on `max-height: none` so content
|
|
19860
19864
|
// that grows after opening is never clipped; closed panels are `inert` so
|
|
19861
19865
|
// Tab cannot land inside collapsed content.
|
|
19862
|
-
|
|
19866
|
+
useIsomorphicLayoutEffect$9(function () {
|
|
19863
19867
|
var prevOpen = prevOpenRef.current;
|
|
19864
19868
|
var timers = [];
|
|
19865
19869
|
panelRefs.current.forEach(function (panelEl, idx) {
|
|
@@ -27440,7 +27444,7 @@ Navbar.propTypes = {
|
|
|
27440
27444
|
emitter: PropTypes.object.isRequired,
|
|
27441
27445
|
logo: PropTypes.node,
|
|
27442
27446
|
center: PropTypes.node,
|
|
27443
|
-
items: PropTypes.array
|
|
27447
|
+
items: PropTypes.array,
|
|
27444
27448
|
user: PropTypes.object,
|
|
27445
27449
|
notifications: PropTypes.array,
|
|
27446
27450
|
searchable: PropTypes.bool,
|
package/dist/index.js
CHANGED
|
@@ -3856,7 +3856,7 @@ function setRefs$1(node) {
|
|
|
3856
3856
|
}
|
|
3857
3857
|
|
|
3858
3858
|
// useLayoutEffect warns during SSR; fall back to useEffect on the server.
|
|
3859
|
-
var useIsomorphicLayoutEffect$
|
|
3859
|
+
var useIsomorphicLayoutEffect$c = typeof window !== "undefined" ? React.useLayoutEffect : React.useEffect;
|
|
3860
3860
|
/**
|
|
3861
3861
|
* Internal (not exported from the package): a ref that always holds the latest
|
|
3862
3862
|
* `value`. Lets an effect call the newest consumer callback (e.g. `onChange`)
|
|
@@ -3865,7 +3865,7 @@ var useIsomorphicLayoutEffect$a = typeof window !== "undefined" ? React.useLayou
|
|
|
3865
3865
|
*/
|
|
3866
3866
|
function useLatestRef$1(value) {
|
|
3867
3867
|
var ref = React.useRef(value);
|
|
3868
|
-
useIsomorphicLayoutEffect$
|
|
3868
|
+
useIsomorphicLayoutEffect$c(function () {
|
|
3869
3869
|
ref.current = value;
|
|
3870
3870
|
});
|
|
3871
3871
|
return ref;
|
|
@@ -9136,6 +9136,8 @@ function normalizeAction(action, idx) {
|
|
|
9136
9136
|
|
|
9137
9137
|
function ownKeys$1a(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
9138
9138
|
function _objectSpread$1a(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$1a(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$1a(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
9139
|
+
// useLayoutEffect warns during SSR; fall back to useEffect on the server.
|
|
9140
|
+
var useIsomorphicLayoutEffect$b = typeof window !== "undefined" ? React.useLayoutEffect : React.useEffect;
|
|
9139
9141
|
// Internal (not exported). Desktop presentation of the action menu: a
|
|
9140
9142
|
// portaled, floating `role="menu"` anchored to its trigger (flip + shift via
|
|
9141
9143
|
// useFloatingPosition), with roving focus and Escape/outside-press dismissal.
|
|
@@ -9188,7 +9190,7 @@ function MenuPopover(_ref) {
|
|
|
9188
9190
|
menuEl = _useState2[0],
|
|
9189
9191
|
setMenuEl = _useState2[1];
|
|
9190
9192
|
var closeRef = useLatestRef$1(onRequestClose);
|
|
9191
|
-
|
|
9193
|
+
useIsomorphicLayoutEffect$b(function () {
|
|
9192
9194
|
refs.setReference(anchorEl !== null && anchorEl !== void 0 ? anchorEl : null);
|
|
9193
9195
|
}, [refs, anchorEl]);
|
|
9194
9196
|
var setMenuNode = React.useCallback(function (node) {
|
|
@@ -12466,7 +12468,7 @@ var getProxyFormState = (formState, control, localProxyFormState, isRoot = true)
|
|
|
12466
12468
|
return result;
|
|
12467
12469
|
};
|
|
12468
12470
|
|
|
12469
|
-
const useIsomorphicLayoutEffect$
|
|
12471
|
+
const useIsomorphicLayoutEffect$a = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
|
|
12470
12472
|
|
|
12471
12473
|
/**
|
|
12472
12474
|
* This custom hook allows you to subscribe to each form state, and isolate the re-render at the custom hook level. It has its scope in terms of form state subscription, so it would not affect other useFormState and useForm. Using this hook can reduce the re-render impact on large and complex form application.
|
|
@@ -12512,7 +12514,7 @@ function useFormState(props) {
|
|
|
12512
12514
|
isValid: false,
|
|
12513
12515
|
errors: false,
|
|
12514
12516
|
});
|
|
12515
|
-
useIsomorphicLayoutEffect$
|
|
12517
|
+
useIsomorphicLayoutEffect$a(() => control._subscribe({
|
|
12516
12518
|
name,
|
|
12517
12519
|
formState: _localProxyFormState.current,
|
|
12518
12520
|
exact,
|
|
@@ -12631,7 +12633,7 @@ function useWatch(props) {
|
|
|
12631
12633
|
}
|
|
12632
12634
|
}
|
|
12633
12635
|
}, [control._formValues, control._names, disabled, name]);
|
|
12634
|
-
useIsomorphicLayoutEffect$
|
|
12636
|
+
useIsomorphicLayoutEffect$a(() => {
|
|
12635
12637
|
if (_prevControl.current !== control ||
|
|
12636
12638
|
!deepEqual(_prevName.current, name)) {
|
|
12637
12639
|
_prevControl.current = control;
|
|
@@ -14712,7 +14714,7 @@ function useForm(props = {}) {
|
|
|
14712
14714
|
}
|
|
14713
14715
|
const control = _formControl.current.control;
|
|
14714
14716
|
control._options = props;
|
|
14715
|
-
useIsomorphicLayoutEffect$
|
|
14717
|
+
useIsomorphicLayoutEffect$a(() => {
|
|
14716
14718
|
const sub = control._subscribe({
|
|
14717
14719
|
formState: control._proxyFormState,
|
|
14718
14720
|
callback: () => updateFormState({ ...control._formState }),
|
|
@@ -19810,6 +19812,8 @@ Form.displayName = "Form";
|
|
|
19810
19812
|
var _excluded$T = ["items", "allowMultiple", "defaultOpenIndexes", "onChange", "className", "headerClassName", "contentClassName", "chevronPosition", "chevronIcon", "bordered", "rounded", "size", "transitionDuration"];
|
|
19811
19813
|
function ownKeys$$(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
19812
19814
|
function _objectSpread$$(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$$(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$$(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
19815
|
+
// useLayoutEffect warns during SSR; fall back to useEffect on the server.
|
|
19816
|
+
var useIsomorphicLayoutEffect$9 = typeof window !== "undefined" ? React.useLayoutEffect : React.useEffect;
|
|
19813
19817
|
/**
|
|
19814
19818
|
* item.leftIcon may be:
|
|
19815
19819
|
* - ReactNode (e.g. <svg/>)
|
|
@@ -19879,7 +19883,7 @@ var Accordion = /*#__PURE__*/React.forwardRef(function Accordion(_ref, ref) {
|
|
|
19879
19883
|
// refs / the DOM. An open panel settles on `max-height: none` so content
|
|
19880
19884
|
// that grows after opening is never clipped; closed panels are `inert` so
|
|
19881
19885
|
// Tab cannot land inside collapsed content.
|
|
19882
|
-
|
|
19886
|
+
useIsomorphicLayoutEffect$9(function () {
|
|
19883
19887
|
var prevOpen = prevOpenRef.current;
|
|
19884
19888
|
var timers = [];
|
|
19885
19889
|
panelRefs.current.forEach(function (panelEl, idx) {
|
|
@@ -27460,7 +27464,7 @@ Navbar.propTypes = {
|
|
|
27460
27464
|
emitter: PropTypes.object.isRequired,
|
|
27461
27465
|
logo: PropTypes.node,
|
|
27462
27466
|
center: PropTypes.node,
|
|
27463
|
-
items: PropTypes.array
|
|
27467
|
+
items: PropTypes.array,
|
|
27464
27468
|
user: PropTypes.object,
|
|
27465
27469
|
notifications: PropTypes.array,
|
|
27466
27470
|
searchable: PropTypes.bool,
|
|
@@ -7182,7 +7182,7 @@
|
|
|
7182
7182
|
}
|
|
7183
7183
|
},
|
|
7184
7184
|
"docs": {
|
|
7185
|
-
"Accordion": "# Accordion\n\nExpandable/collapsible content panels. Only one panel open at a time by default, or multiple when `allowMultiple` is true. Supports keyboard navigation (Arrow keys, Home, End, Enter, Space). The bordered wrapper and each item use the semantic `bg-surface` / `divide-line` / `text-foreground` tokens, so the panels follow dark mode.\n\n## Import\n\n```jsx\nimport { Accordion } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `items` | `Array` | `[]` | Array of `{ id?, title, subtitle?, content, disabled?, leftIcon? }`. `leftIcon` can be ReactNode or `(index, item) => ReactNode`. |\n| `allowMultiple` | `boolean` | `false` | If true, multiple panels can be open at once. |\n| `defaultOpenIndexes` | `number[]` | `[]` | Initial open panel index(es). |\n| `onChange` | `(openIndexes: number[]) => void` | — | Called when open panels change. |\n| `className` | `string` | `\"\"` | Wrapper CSS classes. |\n| `headerClassName` | `string` | `\"\"` | Header button CSS classes. |\n| `contentClassName` | `string` | `\"\"` | Panel content CSS classes. |\n| `chevronPosition` | `\"left\"` \\| `\"right\"` | `\"right\"` | Position of chevron icon. |\n| `chevronIcon` | `ReactNode` | default SVG | Custom chevron icon. |\n| `bordered` | `boolean` | `true` | Whether to show border/background. |\n| `rounded` | `\"none\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` | `\"md\"` | Border radius of wrapper. |\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` | `\"md\"` | Header and content padding/text size. |\n| `transitionDuration` | `number` | `220` | Max-height transition duration in ms. Ignored (no animation) when the user prefers reduced motion. |\n\n## Accessibility & behavior\n\n- Header/panel ids are prefixed with a per-instance `useId()`, so several accordions on one page never collide.\n- Collapsed panels carry the `inert` attribute, so Tab never lands on focusable content inside a closed panel.\n- Header focus ring uses `focus-visible:ring-primary-500` (keyboard focus only).\n- Once an open transition finishes, the panel's `max-height` is released to `none`, so content that grows after opening is never clipped.\n- The height transition is disabled under `prefers-reduced-motion: reduce`.\n\n## Example\n\n```jsx\n<Accordion\n items={[\n { id: '1', title: 'Section 1', content: <p>Content for section 1</p> },\n { id: '2', title: 'Section 2', subtitle: 'Optional', content: <p>Content 2</p> },\n { title: 'Disabled', content: <p>Content</p>, disabled: true },\n ]}\n allowMultiple={false}\n defaultOpenIndexes={[0]}\n onChange={(indexes) => console.log('Open:', indexes)}\n size=\"md\"\n chevronPosition=\"right\"\n/>\n```\n\n[← Component overview](README.md)\n",
|
|
7185
|
+
"Accordion": "# Accordion\n\nExpandable/collapsible content panels. Only one panel open at a time by default, or multiple when `allowMultiple` is true. Supports keyboard navigation (Arrow keys, Home, End, Enter, Space). The bordered wrapper and each item use the semantic `bg-surface` / `divide-line` / `text-foreground` tokens, so the panels follow dark mode.\n\n## Import\n\n```jsx\nimport { Accordion } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `items` | `Array` | `[]` | Array of `{ id?, title, subtitle?, content, disabled?, leftIcon? }`. `leftIcon` can be ReactNode or `(index, item) => ReactNode`. |\n| `allowMultiple` | `boolean` | `false` | If true, multiple panels can be open at once. |\n| `defaultOpenIndexes` | `number[]` | `[]` | Initial open panel index(es). |\n| `onChange` | `(openIndexes: number[]) => void` | — | Called when open panels change. |\n| `className` | `string` | `\"\"` | Wrapper CSS classes. |\n| `headerClassName` | `string` | `\"\"` | Header button CSS classes. |\n| `contentClassName` | `string` | `\"\"` | Panel content CSS classes. |\n| `chevronPosition` | `\"left\"` \\| `\"right\"` | `\"right\"` | Position of chevron icon. |\n| `chevronIcon` | `ReactNode` | default SVG | Custom chevron icon. |\n| `bordered` | `boolean` | `true` | Whether to show border/background. |\n| `rounded` | `\"none\"` \\| `\"sm\"` \\| `\"md\"` \\| `\"lg\"` \\| `\"xl\"` | `\"md\"` | Border radius of wrapper. |\n| `size` | `\"sm\"` \\| `\"md\"` \\| `\"lg\"` | `\"md\"` | Header and content padding/text size. |\n| `transitionDuration` | `number` | `220` | Max-height transition duration in ms. Ignored (no animation) when the user prefers reduced motion. |\n\n## Accessibility & behavior\n\n- Header/panel ids are prefixed with a per-instance `useId()`, so several accordions on one page never collide.\n- Collapsed panels carry the `inert` attribute, so Tab never lands on focusable content inside a closed panel.\n- Header focus ring uses `focus-visible:ring-primary-500` (keyboard focus only).\n- Once an open transition finishes, the panel's `max-height` is released to `none`, so content that grows after opening is never clipped.\n- The height transition is disabled under `prefers-reduced-motion: reduce`.\n- Server rendering (Next.js) is warning-free: panels are sized in a layout effect on the client and a plain effect on the server.\n\n## Example\n\n```jsx\n<Accordion\n items={[\n { id: '1', title: 'Section 1', content: <p>Content for section 1</p> },\n { id: '2', title: 'Section 2', subtitle: 'Optional', content: <p>Content 2</p> },\n { title: 'Disabled', content: <p>Content</p>, disabled: true },\n ]}\n allowMultiple={false}\n defaultOpenIndexes={[0]}\n onChange={(indexes) => console.log('Open:', indexes)}\n size=\"md\"\n chevronPosition=\"right\"\n/>\n```\n\n[← Component overview](README.md)\n",
|
|
7186
7186
|
"ActionSheet": "# ActionSheet\n\niOS-style action sheet (the `UIAlertController` action-sheet pattern) on the bottom `Sheet`: an optional title and message, a card of actions — destructive ones in the error tone — and a separate Cancel button. Use it for \"what do you want to do with this?\" choices on phones; it is the same implementation `ThreeDotPopover` and `Table`'s row menu use for their phone presentation.\n\n## Import\n\n```jsx\nimport { ActionSheet } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `open` | `boolean` | — | Controls visibility |\n| `isOpen` | `boolean` | — | Alias of `open` |\n| `onClose` | `(reason) => void` | — | Called when the sheet should close; `reason` is `'select'` (after an action's `onSelect`), `'cancel'`, `'escape'`, `'backdrop'` or `'drag'` |\n| `title` | `ReactNode` | — | Small heading above the actions; names the sheet (`aria-labelledby`) unless `aria-label` is set |\n| `message` | `ReactNode` | — | Muted text under the title; wired to `aria-describedby` |\n| `actions` | `Array` | `[]` | `[{ key?, label, icon?, tone?: 'default' or 'destructive', onSelect, disabled? }]`. `icon` is a node (`<Trash2 />`) or a component (`Trash2`) |\n| `cancelLabel` | `ReactNode` | `\"Cancel\"` | Text of the separate Cancel button (always shown) |\n| `dismissible` | `boolean` | `true` | `false` disables Escape, backdrop click and drag dismissal |\n| `className` | `string` | — | Classes merged onto the sheet panel |\n\nOther props (`aria-label`, `data-*`, …) are forwarded to the sheet panel (`role=\"dialog\"`), and the ref points at it.\n\n### Behavior\n\n- Selecting an enabled action calls its `onSelect`, then `onClose('select')`. Disabled actions do nothing.\n- Cancel, Escape, a backdrop tap and a downward drag all call `onClose` with their reason; none of them calls an action.\n- You own the open state: set `open` to `false` in `onClose`.\n- With no `title` and no `aria-label`, the sheet is named \"Actions\".\n\n## Accessibility\n\n- The panel is a modal `role=\"dialog\"`; focus moves to the first action on open, Tab stays inside, and Escape closes.\n- Focus returns to the element that was focused before the sheet opened (usually the button that opened it).\n- Rows are at least 48px tall with a focus-visible ring; destructive rows pair the error colour with their label text.\n- The slide-in and slide-out animations are off under `prefers-reduced-motion`.\n\n## Examples\n\n```jsx\nfunction PhotoMenu({ photo }) {\n const [open, setOpen] = useState(false);\n return (\n <>\n <Button onClick={() => setOpen(true)}>Options</Button>\n <ActionSheet\n open={open}\n onClose={() => setOpen(false)}\n title=\"Photo options\"\n message=\"Choose what to do with this photo.\"\n actions={[\n { key: 'share', label: 'Share', icon: Share2, onSelect: () => share(photo) },\n { key: 'archive', label: 'Archive', onSelect: () => archive(photo), disabled: photo.archived },\n { key: 'delete', label: 'Delete', icon: Trash2, tone: 'destructive', onSelect: () => remove(photo) },\n ]}\n />\n </>\n );\n}\n```\n\n```jsx\n// Custom cancel text, no title (named by aria-label)\n<ActionSheet\n open={open}\n onClose={() => setOpen(false)}\n aria-label=\"Sort by\"\n cancelLabel=\"Never mind\"\n actions={[\n { label: 'Newest first', onSelect: () => setSort('new') },\n { label: 'Oldest first', onSelect: () => setSort('old') },\n ]}\n/>\n```\n\n[← Component overview](README.md)\n",
|
|
7187
7187
|
"Alert": "# Alert\n\nInline alert box for success, error, warning, info or neutral messages. Optional title, an actions slot after the description, and a dismiss button. Every variant has a dark tone, and the alert fades in (off under `prefers-reduced-motion`).\n\n## Import\n\n```jsx\nimport { Alert } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `variant` | `string` | `\"info\"` | `success`, `error`, `warning`, `info`, `neutral` (role tokens: surface, line, muted). Unknown values fall back to `info` |\n| `title` | `string` | — | Optional title |\n| `children` | `ReactNode` | — | Alert body content (the description) |\n| `actions` | `ReactNode` | — | Rendered after the description in a wrapping row (buttons, links) |\n| `dismissible` | `boolean` | `false` | Show close button |\n| `onDismiss` | `function` | — | Called when dismissed |\n| `dismissLabel` | `string` | `\"Dismiss\"` | Accessible name of the dismiss button |\n| `className` | `string` | — | Extra CSS classes |\n\nOther props are forwarded to the root `div`; the ref points at it.\n\n## Accessibility\n\n- `error` and `warning` render with `role=\"alert\"` (announced immediately); `info`, `success` and `neutral` use `role=\"status\"` (polite), so routine messages don't interrupt a screen reader. Pass `role` to override.\n- The dismiss button is labelled \"Dismiss\" (`dismissLabel`), has a focus-visible ring and a 44px hit area on touch screens.\n- The enter animation (`animate-fade-in`) is off under `prefers-reduced-motion`.\n\n## Examples\n\n```jsx\n<Alert variant=\"info\" title=\"Note\">Your session will expire in 5 minutes.</Alert>\n<Alert variant=\"success\">Saved successfully.</Alert>\n<Alert variant=\"error\" title=\"Error\">Something went wrong.</Alert>\n<Alert variant=\"warning\" dismissible onDismiss={() => {}}>\n Please review your input.\n</Alert>\n<Alert variant=\"neutral\" title=\"Heads up\">Billing moves to the 1st of each month.</Alert>\n\n<Alert\n variant=\"error\"\n title=\"Upload failed\"\n actions={\n <>\n <Button size=\"sm\" onClick={retry}>Retry</Button>\n <Button size=\"sm\" variant=\"ghost\" onClick={openHelp}>Get help</Button>\n </>\n }\n>\n The file is larger than 10 MB.\n</Alert>\n```\n\n[← Component overview](README.md)\n",
|
|
7188
7188
|
"AppShell": "# AppShell\n\nPage-level block: the product app shell — a sidebar on large screens, a top bar with a navigation drawer below `lg`, and an optional bottom nav on phones. Replaces the shell 12 of 13 products hand-rolled (extracted from procurementpro `components/app-shell.tsx`). Colours come from the `shell` and role tokens (`bg-background`, `bg-surface`, `text-foreground`, `text-muted`, `border-line`), so a brand file restyles it and dark mode needs no extra classes.\n\nThe shell fills the dynamic viewport (`min-h-dvh`; the sidebar is `h-dvh`), so mobile browser toolbars don't cut it off. It pads the safe areas: the top bar has `pt-safe` and `px-safe`, the sidebar `pt-safe pb-safe pl-safe`, the content column `px-safe`. Add `viewport-fit=cover` to your viewport meta.\n\n## Import\n\n```jsx\nimport { AppShell } from '@dreamtree-org/twreact-ui';\n```\n\n## Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `brand` | `ReactNode` | — | Product mark at the top of the sidebar |\n| `nav` | `AppShellNavItem[]` | — | `{ id, label, href?, icon?, active?, count?, group?, onClick? }`. Items with `href` render as links; `active` sets `aria-current=\"page\"` |\n| `sidebarFooter` | `ReactNode` | — | Pinned to the bottom of the sidebar (user menu, workspace switcher) |\n| `topbar` | `ReactNode` | — | Right side of the top bar (search, notifications, avatar) |\n| `pageTitle` | `string` | — | Title shown in the mobile top bar |\n| `bottomNav` | `ReactNode` | — | Bottom navigation for phones, usually a [`FootNav`](FootNav.md). Rendered below `md` only (hidden from `md` up, where the sidebar / drawer take over). When set, a `FootNav.Spacer` is added after `<main>` so content doesn't scroll under the bar |\n| `linkAs` | `ElementType` | `\"a\"` | Link element for nav items, e.g. Next.js `Link` |\n| `navOpen` | `boolean` | — | Controls the mobile navigation drawer, e.g. so a `FootNav` \"More\" tab can open it. Unset, the shell's menu button owns it |\n| `onNavOpenChange` | `(open: boolean) => void` | — | Called when the drawer should open or close (menu button, close button, Escape, backdrop, choosing a nav item). Called in uncontrolled mode too |\n| `topbarFrom` | `\"always\"` \\| `\"below-lg\"` | `\"always\"` | `\"below-lg\"` hides the top bar from `lg` up, where the sidebar carries the brand and nav, so a desktop page has no empty strip |\n| `className` | `string` | — | Extra CSS classes for the root (merged with `cn`) |\n| `children` | `ReactNode` | — | Page content, rendered in `<main id=\"main\">` |\n| ...rest | `HTMLAttributes<HTMLDivElement>` | — | Forwarded to the root `<div>`; the ref is forwarded to it |\n\n## Example\n\n```jsx\n<AppShell\n brand={<span className=\"text-lg font-bold\">PracticePro</span>}\n nav={[\n { id: 'overview', label: 'Overview', href: '/overview', icon: <Home className=\"h-5 w-5\" /> },\n { id: 'compliance', label: 'Compliance', href: '/compliance', active: true },\n { id: 'approvals', label: 'Approvals', href: '/approvals', count: 4 },\n ]}\n topbar={<Avatar name=\"Ananya Rao\" size=\"sm\" />}\n linkAs={Link}\n>\n <PageHeader title=\"Compliance calendar\" />\n</AppShell>\n```\n\n### Bottom nav on phones\n\n```jsx\n<AppShell\n brand={<Logo />}\n nav={nav}\n linkAs={Link}\n bottomNav={\n <FootNav\n linkAs={Link}\n items={[\n { id: 'home', label: 'Home', icon: <Home />, href: '/', active: true },\n { id: 'tasks', label: 'Tasks', icon: <CheckSquare />, href: '/tasks', badge: 3 },\n { id: 'inbox', label: 'Inbox', icon: <Inbox />, href: '/inbox' },\n ]}\n />\n }\n>\n {page}\n</AppShell>\n```\n\nKeep the bottom nav to the 3–5 most used destinations; the full `nav` stays in the drawer (menu button) below `lg` and in the sidebar on desktop.\n\n### Opening the drawer from a \"More\" tab\n\nPass `navOpen` / `onNavOpenChange` to control the drawer, and `topbarFrom=\"below-lg\"` when the desktop page has no top bar:\n\n```jsx\nconst [navOpen, setNavOpen] = useState(false);\n\n<AppShell\n brand={<Logo />}\n nav={nav}\n navOpen={navOpen}\n onNavOpenChange={setNavOpen}\n topbarFrom=\"below-lg\"\n bottomNav={\n <FootNav\n items={[\n { id: 'today', label: 'Today', icon: <Home />, href: '/', active: true },\n { id: 'more', label: 'More', icon: <Menu />, onClick: () => setNavOpen(true) },\n ]}\n />\n }\n>\n {page}\n</AppShell>\n```\n\n## Mobile drawer accessibility\n\nBelow `lg`, the \"Open navigation\" button (`aria-haspopup=\"dialog\"`, `aria-expanded`) opens the sidebar in a left [`Sheet`](Sheet.md) (`role=\"dialog\"`, `aria-modal=\"true\"`, `aria-label=\"Navigation\"`), coloured with the shell tokens. While it is open, focus moves into the drawer, Tab / Shift+Tab stay inside it, **Escape** closes it and returns focus to the menu button, and body scroll is locked. The lock is ref-counted and shared with `Dialog`, `Drawer`, `Sheet` and `Sidebar`, so stacked overlays release the page only when the last one closes. Clicking the backdrop, the close button or a nav item, or dragging the drawer to the left, also closes it. It slides in and out (instant under `prefers-reduced-motion`), so it stays mounted for its short exit transition. The menu, close and nav controls grow to 44px on coarse pointers and show a `focus-visible` ring.\n\n[← Component overview](README.md)\n",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dreamtree-org/twreact-ui",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "A comprehensive React + Tailwind components library for building modern web apps",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Partha Preetham Krishna",
|
|
@@ -166,8 +166,9 @@
|
|
|
166
166
|
"@storybook/blocks": "8.6.15",
|
|
167
167
|
"@storybook/react": "8.6.15",
|
|
168
168
|
"@storybook/react-vite": "8.6.15",
|
|
169
|
+
"@testing-library/dom": "^10.4.2",
|
|
169
170
|
"@testing-library/jest-dom": "^6.9.1",
|
|
170
|
-
"@testing-library/react": "^
|
|
171
|
+
"@testing-library/react": "^16.3.3",
|
|
171
172
|
"@tiptap/core": "^3.32.0",
|
|
172
173
|
"@tiptap/pm": "^3.32.0",
|
|
173
174
|
"@tiptap/react": "^3.32.0",
|