@stack-spot/citric-react 0.45.0 → 0.46.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.
@@ -66,5 +66,5 @@ export type StepperProps<Key extends string> = Omit<React.JSX.IntrinsicElements[
66
66
  * return <Stepper tabs={steps} />
67
67
  * ```
68
68
  */
69
- export declare const Stepper: <Key extends string>({ tabs: initialTabs, controller: ctrl, value, onChange, buttons, className, ...props }: StepperProps<Key>) => import("react/jsx-runtime").JSX.Element;
69
+ export declare const Stepper: <Key extends string>({ tabs: initialTabs, value, onChange, buttons, className, ...props }: StepperProps<Key>) => import("react/jsx-runtime").JSX.Element;
70
70
  //# sourceMappingURL=Stepper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Stepper.d.ts","sourceRoot":"","sources":["../../src/components/Stepper.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAO,MAAM,cAAc,CAAA;AAGjD,MAAM,WAAW,gBAAgB,CAAC,GAAG,SAAS,MAAM,CAAE,SAAQ,aAAa,CAAC,GAAG,CAAC;IAC9E;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG;QAClB;;WAEG;QACH,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB;;WAEG;QACH,IAAI,CAAC,EAAE,MAAM,CAAC;QACd;;WAEG;QACH,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB;;WAEG;QACH,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB;;;WAGG;QACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;QACtB;;;WAGG;QACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC;QAC1C;;;WAGG;QACH,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC;QACtC;;;WAGG;QACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;KACvB,CAAC;CACH;AAED,MAAM,MAAM,YAAY,CAAC,GAAG,SAAS,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAA;AAQxI;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,OAAO,GACD,GAAG,SAAS,MAAM,0FAC8D,YAAY,CAAC,GAAG,CAAC,4CA2DnH,CAAA"}
1
+ {"version":3,"file":"Stepper.d.ts","sourceRoot":"","sources":["../../src/components/Stepper.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,aAAa,EAAO,MAAM,cAAc,CAAA;AAGjD,MAAM,WAAW,gBAAgB,CAAC,GAAG,SAAS,MAAM,CAAE,SAAQ,aAAa,CAAC,GAAG,CAAC;IAC9E;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG;QAClB;;WAEG;QACH,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB;;WAEG;QACH,IAAI,CAAC,EAAE,MAAM,CAAC;QACd;;WAEG;QACH,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB;;WAEG;QACH,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB;;;WAGG;QACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;QACtB;;;WAGG;QACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC;QAC1C;;;WAGG;QACH,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC;QACtC;;;WAGG;QACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;KACvB,CAAC;CACH;AAED,MAAM,MAAM,YAAY,CAAC,GAAG,SAAS,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAA;AAoDxI;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,OAAO,GACD,GAAG,SAAS,MAAM,wEAC4C,YAAY,CAAC,GAAG,CAAC,4CAyBjG,CAAA"}
@@ -1,12 +1,11 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { listToClass } from '@stack-spot/portal-theme';
3
3
  import { useTranslate } from '@stack-spot/portal-translate';
4
- import { useCallback, useEffect, useMemo, useState } from 'react';
4
+ import { useCallback, useEffect, useRef, useState } from 'react';
5
5
  import { withRef } from '../utils/react.js';
6
6
  import { Button } from './Button.js';
7
- import { Column, Row } from './layout.js';
8
- import { Tabs } from './Tabs/index.js';
9
- import { TabController } from './Tabs/TabController.js';
7
+ import { Row } from './layout.js';
8
+ import { Tabs, useTabController } from './Tabs/index.js';
10
9
  import { findSelectedIndex } from './Tabs/utils.js';
11
10
  function getTabsWithDisabled(tabs, value) {
12
11
  let index = findSelectedIndex(tabs, value ?? '');
@@ -14,6 +13,27 @@ function getTabsWithDisabled(tabs, value) {
14
13
  index = 0;
15
14
  return tabs.map((t, i) => ({ ...t, disabled: i > index }));
16
15
  }
16
+ const StepperButtons = ({ buttons, tabs }) => {
17
+ const controller = useTabController();
18
+ const [selectedIndex, setSelectedIndex] = useState(findSelectedIndex(tabs, controller.getValue()));
19
+ const t = useTranslate(dictionary);
20
+ const tabsRef = useRef(tabs);
21
+ tabsRef.current = tabs;
22
+ useEffect(() => controller.onChange((value) => {
23
+ setSelectedIndex(findSelectedIndex(tabsRef.current, value));
24
+ }), [controller]);
25
+ const onPrevious = useCallback(() => {
26
+ controller.previous();
27
+ if (typeof buttons === 'object')
28
+ buttons.onPrevious?.(controller.getValue());
29
+ }, [controller]);
30
+ const onNext = useCallback(() => {
31
+ controller.next();
32
+ if (typeof buttons === 'object')
33
+ buttons.onNext?.(controller.getValue());
34
+ }, [controller]);
35
+ return _jsxs(Row, { mt: "20px", justifyContent: (typeof buttons !== 'object' || !buttons.onCancel) && selectedIndex === 0 ? 'end' : 'space-between', children: [selectedIndex === 0 && typeof buttons === 'object' && buttons.onCancel && (_jsx(Button, { onClick: buttons.onCancel, colorScheme: "inverse", appearance: "outlined", children: buttons.cancel || t.cancel })), selectedIndex > 0 && buttons && (_jsx(Button, { onClick: onPrevious, colorScheme: "inverse", appearance: "outlined", children: (typeof buttons === 'object' && buttons.previous) || t.previous })), selectedIndex < tabs.length - 1 && buttons && (_jsx(Button, { onClick: onNext, children: (typeof buttons === 'object' && buttons.next) || t.next })), selectedIndex === tabs.length - 1 && typeof buttons === 'object' && buttons.onFinish && (_jsx(Button, { onClick: buttons.onFinish, children: buttons.finish || t.finish }))] });
36
+ };
17
37
  /**
18
38
  * A Stepper is a tab view with a different appearance. To control the current tab (step), retrieve the controller by calling
19
39
  * `useTabsController()` from within a tab (step) content.
@@ -33,28 +53,12 @@ function getTabsWithDisabled(tabs, value) {
33
53
  * return <Stepper tabs={steps} />
34
54
  * ```
35
55
  */
36
- export const Stepper = withRef(function Stepper({ tabs: initialTabs, controller: ctrl, value, onChange, buttons = true, className, ...props }) {
37
- const controller = useMemo(() => ctrl ?? new TabController(initialTabs.map(t => t.key), value || initialTabs[0]?.key), []);
56
+ export const Stepper = withRef(function Stepper({ tabs: initialTabs, value, onChange, buttons = true, className, ...props }) {
38
57
  const [tabs, setTabs] = useState(getTabsWithDisabled(initialTabs, value));
39
- const [selectedIndex, setSelectedIndex] = useState(findSelectedIndex(tabs, controller.getValue()));
40
- const t = useTranslate(dictionary);
41
- useEffect(() => controller.onChange((v) => {
42
- setSelectedIndex(findSelectedIndex(tabs, v));
43
- }), [tabs]);
44
- useEffect(() => controller.onChange((value) => {
45
- setTabs(getTabsWithDisabled(initialTabs, value));
46
- }), []);
47
- const onPrevious = useCallback(() => {
48
- controller.previous();
49
- if (typeof buttons === 'object')
50
- buttons.onPrevious?.(controller.getValue());
51
- }, []);
52
- const onNext = useCallback(() => {
53
- controller.next();
54
- if (typeof buttons === 'object')
55
- buttons.onNext?.(controller.getValue());
56
- }, []);
57
- return buttons ? (_jsxs(Column, { ...props, className: className, gap: "20px", children: [_jsx(Tabs, { tabs: tabs, controller: controller, value: value, onChange: onChange, className: "stepper" }), _jsxs(Row, { justifyContent: (typeof buttons !== 'object' || !buttons.onCancel) && selectedIndex === 0 ? 'end' : 'space-between', children: [selectedIndex === 0 && typeof buttons === 'object' && buttons.onCancel && (_jsx(Button, { onClick: buttons.onCancel, colorScheme: "inverse", appearance: "outlined", children: buttons.cancel || t.cancel })), selectedIndex > 0 && buttons && (_jsx(Button, { onClick: onPrevious, colorScheme: "inverse", appearance: "outlined", children: (typeof buttons === 'object' && buttons.previous) || t.previous })), selectedIndex < tabs.length - 1 && buttons && (_jsx(Button, { onClick: onNext, children: (typeof buttons === 'object' && buttons.next) || t.next })), selectedIndex === tabs.length - 1 && typeof buttons === 'object' && buttons.onFinish && (_jsx(Button, { onClick: buttons.onFinish, children: buttons.finish || t.finish }))] })] })) : _jsx(Tabs, { tabs: tabs, controller: controller, value: value, onChange: onChange, className: listToClass([className, 'stepper']), ...props });
58
+ return buttons ? (_jsx(Tabs, { tabs: tabs, className: listToClass([className, 'stepper']), value: value, onChange: (value) => {
59
+ setTabs(getTabsWithDisabled(initialTabs, value));
60
+ onChange?.(value);
61
+ }, customRenderer: (selector, content) => _jsxs(_Fragment, { children: [selector, content, _jsx(StepperButtons, { buttons: buttons, tabs: initialTabs })] }) })) : _jsx(Tabs, { tabs: tabs, className: listToClass([className, 'stepper']), ...props });
58
62
  });
59
63
  const dictionary = {
60
64
  en: {
@@ -1 +1 @@
1
- {"version":3,"file":"Stepper.js","sourceRoot":"","sources":["../../src/components/Stepper.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Stepper.js","sourceRoot":"","sources":["../../src/components/Stepper.tsx"],"names":[],"mappings":"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"}
@@ -3,6 +3,10 @@ export declare class TabController<Key extends string> extends ValueController<K
3
3
  private tabOrder;
4
4
  constructor(tabOrder: Key[], value: Key);
5
5
  private getCurrentIndex;
6
+ /**
7
+ * Replaces the current set of tabs.
8
+ */
9
+ setTabOrder(tabOrder: Key[]): void;
6
10
  /**
7
11
  * @returns true if there's another tab after the one currently selected. False otherwise.
8
12
  */
@@ -1 +1 @@
1
- {"version":3,"file":"TabController.d.ts","sourceRoot":"","sources":["../../../src/components/Tabs/TabController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAE7D,qBAAa,aAAa,CAAC,GAAG,SAAS,MAAM,CAAE,SAAQ,eAAe,CAAC,GAAG,CAAC;IACzE,OAAO,CAAC,QAAQ,CAAO;gBAEX,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,GAAG;IAKvC,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACH,OAAO,IAAI,OAAO;IAKlB;;OAEG;IACH,WAAW,IAAI,OAAO;IAKtB;;;OAGG;IACH,IAAI,IAAI,OAAO;IAQf;;;OAGG;IACH,QAAQ,IAAI,OAAO;CAOpB"}
1
+ {"version":3,"file":"TabController.d.ts","sourceRoot":"","sources":["../../../src/components/Tabs/TabController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAE7D,qBAAa,aAAa,CAAC,GAAG,SAAS,MAAM,CAAE,SAAQ,eAAe,CAAC,GAAG,CAAC;IACzE,OAAO,CAAC,QAAQ,CAAO;gBAEX,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,GAAG;IAKvC,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,GAAG,EAAE;IAe3B;;OAEG;IACH,OAAO,IAAI,OAAO;IAKlB;;OAEG;IACH,WAAW,IAAI,OAAO;IAKtB;;;OAGG;IACH,IAAI,IAAI,OAAO;IAQf;;;OAGG;IACH,QAAQ,IAAI,OAAO;CAOpB"}
@@ -13,6 +13,24 @@ export class TabController extends ValueController {
13
13
  getCurrentIndex() {
14
14
  return this.tabOrder.findIndex(t => t === this.value);
15
15
  }
16
+ /**
17
+ * Replaces the current set of tabs.
18
+ */
19
+ setTabOrder(tabOrder) {
20
+ let newValue = this.value;
21
+ if (!tabOrder.includes(this.value)) {
22
+ const prev = this.getCurrentIndex() - 1;
23
+ const key = this.tabOrder[prev];
24
+ if (key && tabOrder.includes(key)) {
25
+ newValue = key;
26
+ }
27
+ else {
28
+ newValue = tabOrder[0];
29
+ }
30
+ }
31
+ this.tabOrder = tabOrder;
32
+ this.setValue(newValue);
33
+ }
16
34
  /**
17
35
  * @returns true if there's another tab after the one currently selected. False otherwise.
18
36
  */
@@ -1 +1 @@
1
- {"version":3,"file":"TabController.js","sourceRoot":"","sources":["../../../src/components/Tabs/TabController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAE7D,MAAM,OAAO,aAAkC,SAAQ,eAAoB;IAGzE,YAAY,QAAe,EAAE,KAAU;QACrC,KAAK,CAAC,KAAK,CAAC,CAAA;QAHN;;;;;WAAe;QAIrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC1B,CAAC;IAEO,eAAe;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,CAAA;IACvD,CAAC;IAED;;OAEG;IACH,OAAO;QACL,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAA;QACtC,OAAO,OAAO,GAAG,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAA;IAC3D,CAAC;IAED;;OAEG;IACH,WAAW;QACT,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAA;QACtC,OAAO,OAAO,GAAG,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,CAAC,CAAA;IACzC,CAAC;IAED;;;OAGG;IACH,IAAI;QACF,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACnB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;YACxD,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAED;;;OAGG;IACH,QAAQ;QACN,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;YACxD,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;CACF"}
1
+ {"version":3,"file":"TabController.js","sourceRoot":"","sources":["../../../src/components/Tabs/TabController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAE7D,MAAM,OAAO,aAAkC,SAAQ,eAAoB;IAGzE,YAAY,QAAe,EAAE,KAAU;QACrC,KAAK,CAAC,KAAK,CAAC,CAAA;QAHN;;;;;WAAe;QAIrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC1B,CAAC;IAEO,eAAe;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,CAAA;IACvD,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,QAAe;QACzB,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAA;QACzB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,EAAE,GAAG,CAAC,CAAA;YACvC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;YAC/B,IAAI,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClC,QAAQ,GAAG,GAAG,CAAA;YAChB,CAAC;iBAAM,CAAC;gBACN,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;YACxB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACxB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;IACzB,CAAC;IAED;;OAEG;IACH,OAAO;QACL,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAA;QACtC,OAAO,OAAO,GAAG,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAA;IAC3D,CAAC;IAED;;OAEG;IACH,WAAW;QACT,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAA;QACtC,OAAO,OAAO,GAAG,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,CAAC,CAAA;IACzC,CAAC;IAED;;;OAGG;IACH,IAAI;QACF,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACnB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;YACxD,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAED;;;OAGG;IACH,QAAQ;QACN,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;YACxD,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;CACF"}
@@ -15,7 +15,7 @@ import { TabsProps } from './types.js';
15
15
  * return <Tabs tabs={tabs} />
16
16
  * ```
17
17
  */
18
- export declare const Tabs: <Key extends string>({ tabs, value, equallySized, onChange, controller: ctrl, appearance, customRenderer, className, ...props }: TabsProps<Key>) => import("react/jsx-runtime").JSX.Element;
18
+ export declare const Tabs: <Key extends string>({ tabs, value, equallySized, onChange, appearance, customRenderer, className, ...props }: TabsProps<Key>) => import("react/jsx-runtime").JSX.Element;
19
19
  /**
20
20
  * Request the tab controller of the current context. Use this to control the tabs in the parent components. This returns undefined when
21
21
  * no tab context is found.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Tabs/index.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAKnC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,IAAI,GACD,GAAG,SAAS,MAAM,8GAC8E,SAAS,CAAC,GAAG,CAAC,4CA0D7H,CAAA;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,KAAK,aAAa,CAAC,GAAG,CAAC,GAAG,SAAS,CAE9F"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Tabs/index.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAKnC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,IAAI,GACD,GAAG,SAAS,MAAM,4FAC4D,SAAS,CAAC,GAAG,CAAC,4CAkE3G,CAAA;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,KAAK,aAAa,CAAC,GAAG,CAAC,GAAG,SAAS,CAE9F"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { listToClass } from '@stack-spot/portal-theme';
3
3
  import { useTranslate } from '@stack-spot/portal-translate';
4
- import { createContext, Suspense, useContext, useEffect, useMemo, useState } from 'react';
4
+ import { createContext, Suspense, useContext, useEffect, useMemo, useRef, useState } from 'react';
5
5
  import { withRef } from '../../utils/react.js';
6
6
  import { CitricComponent } from '../CitricComponent.js';
7
7
  import { ErrorBoundary } from '../ErrorBoundary.js';
@@ -25,20 +25,26 @@ const ctx = createContext(undefined);
25
25
  * return <Tabs tabs={tabs} />
26
26
  * ```
27
27
  */
28
- export const Tabs = withRef(function Tabs({ tabs, value, equallySized, onChange, controller: ctrl, appearance, customRenderer, className, ...props }) {
29
- const controller = useMemo(() => ctrl ?? new TabController(tabs.map(t => t.key), value || tabs[0]?.key), []);
28
+ export const Tabs = withRef(function Tabs({ tabs, value, equallySized, onChange, appearance, customRenderer, className, ...props }) {
29
+ const tabKeys = tabs.map(t => t.key);
30
+ const controller = useMemo(() => new TabController(tabKeys, value || tabs[0]?.key), []);
30
31
  const t = useTranslate(dictionary);
31
32
  const [selectedIndex, setSelectedIndex] = useState(findSelectedIndex(tabs, controller.getValue()));
33
+ const tabsRef = useRef(tabs);
34
+ tabsRef.current = tabs;
32
35
  useEffect(() => {
33
36
  if (value)
34
37
  controller.setValue(value);
35
38
  }, [value]);
36
39
  useEffect(() => controller.onChange((v) => {
37
- setSelectedIndex(findSelectedIndex(tabs, v));
40
+ setSelectedIndex(findSelectedIndex(tabsRef.current, v));
38
41
  onChange?.(v);
39
- }), [tabs]);
40
- const tabSelector = useMemo(() => (_jsx("nav", { className: "tab-selector", children: tabs.map(({ key, label, icon, disabled }, index) => (_jsxs("label", { children: [_jsx("input", { type: "radio", role: "tab", checked: index === selectedIndex, onChange: () => controller.setValue(key), disabled: disabled }), icon, label || key] }, key))) })), [tabs, selectedIndex]);
41
- const content = useMemo(() => (_jsx("section", { className: "tab-content", children: _jsx(ErrorBoundary, { message: t.error, children: _jsx(Suspense, { fallback: _jsx(Center, { style: { padding: '20px' }, children: _jsx(ProgressCircular, {}) }), children: selectedIndex === -1 ? null : tabs[selectedIndex]?.content }) }, selectedIndex) })), [selectedIndex, t]);
42
+ }), [controller]);
43
+ useEffect(() => {
44
+ controller.setTabOrder(tabKeys);
45
+ }, [tabKeys.join(','), controller]);
46
+ const tabSelector = useMemo(() => (_jsx("nav", { className: "tab-selector", children: tabs.map(({ key, label, icon, after, disabled }, index) => (_jsxs("label", { children: [_jsx("input", { type: "radio", role: "tab", checked: index === selectedIndex, onChange: () => controller.setValue(key), disabled: disabled }), icon, label || key, after] }, key))) })), [tabs, selectedIndex]);
47
+ const content = useMemo(() => (_jsx("section", { className: "tab-content", children: _jsx(ErrorBoundary, { message: t.error, children: _jsx(Suspense, { fallback: _jsx(Center, { style: { padding: '20px' }, children: _jsx(ProgressCircular, {}) }), children: selectedIndex === -1 ? null : tabs[selectedIndex]?.content }) }, selectedIndex) })), [selectedIndex, value, t]);
42
48
  return (_jsx(ctx.Provider, { value: controller, children: _jsx(CitricComponent, { tag: "div", component: "tabs", className: listToClass([className, equallySized && 'equally-sized', appearance]), ...props, children: customRenderer ? customRenderer(tabSelector, content) : _jsxs(_Fragment, { children: [tabSelector, content] }) }) }));
43
49
  });
44
50
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/Tabs/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/Tabs/index.tsx"],"names":[],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  import { WithColorPalette, WithColorScheme } from '../../types.js';
2
- import { TabController } from './TabController.js';
3
2
  export interface Tab<Key extends string = string> {
4
3
  /**
5
4
  * A unique identifier for the tab.
@@ -13,6 +12,10 @@ export interface Tab<Key extends string = string> {
13
12
  * An icon for the tab.
14
13
  */
15
14
  icon?: React.ReactElement;
15
+ /**
16
+ * Content to place after the tab's name.
17
+ */
18
+ after?: React.ReactElement;
16
19
  /**
17
20
  * The tab's content. This can be a suspended component.
18
21
  *
@@ -41,10 +44,6 @@ export interface BaseTabsProps<Key extends string> extends WithColorScheme, With
41
44
  * @param key the key of the selected tab.
42
45
  */
43
46
  onChange?: (key: Key) => void;
44
- /**
45
- * A tab-controller, useful if you want to control the tabs outside the component context.
46
- */
47
- controller?: TabController<Key>;
48
47
  /**
49
48
  * Instead of each tab occupying only the space it needs, all tabs will have their sizes equally distributed.
50
49
  *
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/Tabs/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE/C,MAAM,WAAW,GAAG,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM;IAC9C;;OAEG;IACH,GAAG,EAAE,GAAG,CAAC;IACT;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,IAAI,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;IAC1B;;;;OAIG;IACH,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,aAAa,CAAC,GAAG,SAAS,MAAM,CAAE,SAAQ,eAAe,EAAE,gBAAgB;IAC1F;;OAEG;IACH,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;IACjB;;OAEG;IACH,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;IAC9B;;OAEG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAChC;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC,YAAY,KAAK,KAAK,CAAC,SAAS,CAAC;CACpG;AAED,MAAM,MAAM,SAAS,CAAC,GAAG,SAAS,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/Tabs/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE/D,MAAM,WAAW,GAAG,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM;IAC9C;;OAEG;IACH,GAAG,EAAE,GAAG,CAAC;IACT;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,IAAI,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;IAC1B;;OAEG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;IAC3B;;;;OAIG;IACH,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,aAAa,CAAC,GAAG,SAAS,MAAM,CAAE,SAAQ,eAAe,EAAE,gBAAgB;IAC1F;;OAEG;IACH,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;IACjB;;OAEG;IACH,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;IAC9B;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC,YAAY,KAAK,KAAK,CAAC,SAAS,CAAC;CACpG;AAED,MAAM,MAAM,SAAS,CAAC,GAAG,SAAS,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stack-spot/citric-react",
3
- "version": "0.45.0",
3
+ "version": "0.46.0",
4
4
  "author": "StackSpot",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -1,11 +1,10 @@
1
1
  import { listToClass } from '@stack-spot/portal-theme'
2
2
  import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
3
- import { useCallback, useEffect, useMemo, useState } from 'react'
3
+ import { useCallback, useEffect, useRef, useState } from 'react'
4
4
  import { withRef } from '../utils/react'
5
5
  import { Button } from './Button'
6
- import { Column, Row } from './layout'
7
- import { Tabs } from './Tabs'
8
- import { TabController } from './Tabs/TabController'
6
+ import { Row } from './layout'
7
+ import { Tabs, useTabController } from './Tabs'
9
8
  import { BaseTabsProps, Tab } from './Tabs/types'
10
9
  import { findSelectedIndex } from './Tabs/utils'
11
10
 
@@ -65,6 +64,50 @@ function getTabsWithDisabled<Key extends string>(tabs: Tab<Key>[], value: Key |
65
64
  return tabs.map((t, i) => ({ ...t, disabled: i > index }))
66
65
  }
67
66
 
67
+ const StepperButtons = ({ buttons, tabs }: { buttons: StepperProps<any>['buttons'], tabs: Tab[] }) => {
68
+ const controller = useTabController()!
69
+ const [selectedIndex, setSelectedIndex] = useState(findSelectedIndex(tabs, controller.getValue()))
70
+ const t = useTranslate(dictionary)
71
+ const tabsRef = useRef(tabs)
72
+ tabsRef.current = tabs
73
+
74
+ useEffect(() => controller.onChange((value) => {
75
+ setSelectedIndex(findSelectedIndex(tabsRef.current, value))
76
+ }), [controller])
77
+
78
+ const onPrevious = useCallback(() => {
79
+ controller.previous()
80
+ if (typeof buttons === 'object') buttons.onPrevious?.(controller.getValue())
81
+ }, [controller])
82
+
83
+ const onNext = useCallback(() => {
84
+ controller.next()
85
+ if (typeof buttons === 'object') buttons.onNext?.(controller.getValue())
86
+ }, [controller])
87
+
88
+ return <Row
89
+ mt="20px"
90
+ justifyContent={(typeof buttons !== 'object' || !buttons.onCancel) && selectedIndex === 0 ? 'end' : 'space-between'}
91
+ >
92
+ {selectedIndex === 0 && typeof buttons === 'object' && buttons.onCancel && (
93
+ <Button onClick={buttons.onCancel} colorScheme="inverse" appearance="outlined">{buttons.cancel || t.cancel}</Button>
94
+ )}
95
+ {selectedIndex > 0 && buttons && (
96
+ <Button onClick={onPrevious} colorScheme="inverse" appearance="outlined">
97
+ {(typeof buttons === 'object' && buttons.previous) || t.previous}
98
+ </Button>
99
+ )}
100
+ {selectedIndex < tabs.length - 1 && buttons && (
101
+ <Button onClick={onNext}>
102
+ {(typeof buttons === 'object' && buttons.next) || t.next}
103
+ </Button>
104
+ )}
105
+ {selectedIndex === tabs.length - 1 && typeof buttons === 'object' && buttons.onFinish && (
106
+ <Button onClick={buttons.onFinish}>{buttons.finish || t.finish}</Button>
107
+ )}
108
+ </Row>
109
+ }
110
+
68
111
  /**
69
112
  * A Stepper is a tab view with a different appearance. To control the current tab (step), retrieve the controller by calling
70
113
  * `useTabsController()` from within a tab (step) content.
@@ -86,61 +129,27 @@ function getTabsWithDisabled<Key extends string>(tabs: Tab<Key>[], value: Key |
86
129
  */
87
130
  export const Stepper = withRef(
88
131
  function Stepper<Key extends string>(
89
- { tabs: initialTabs, controller: ctrl, value, onChange, buttons = true, className, ...props }: StepperProps<Key>,
132
+ { tabs: initialTabs, value, onChange, buttons = true, className, ...props }: StepperProps<Key>,
90
133
  ) {
91
- const controller = useMemo(
92
- () => ctrl ?? new TabController<Key>(initialTabs.map(t => t.key), value || initialTabs[0]?.key),
93
- [],
94
- )
95
134
  const [tabs, setTabs] = useState(getTabsWithDisabled(initialTabs, value))
96
- const [selectedIndex, setSelectedIndex] = useState(findSelectedIndex(tabs, controller.getValue()))
97
- const t = useTranslate(dictionary)
98
-
99
- useEffect(() => controller.onChange((v) => {
100
- setSelectedIndex(findSelectedIndex(tabs, v))
101
- }), [tabs])
102
-
103
- useEffect(() => controller.onChange((value) => {
104
- setTabs(getTabsWithDisabled(initialTabs, value))
105
- }), [])
106
-
107
- const onPrevious = useCallback(() => {
108
- controller.previous()
109
- if (typeof buttons === 'object') buttons.onPrevious?.(controller.getValue())
110
- }, [])
111
-
112
- const onNext = useCallback(() => {
113
- controller.next()
114
- if (typeof buttons === 'object') buttons.onNext?.(controller.getValue())
115
- }, [])
116
-
135
+
117
136
  return buttons ? (
118
- <Column {...props} className={className} gap="20px">
119
- <Tabs tabs={tabs} controller={controller} value={value} onChange={onChange} className="stepper" />
120
- <Row justifyContent={(typeof buttons !== 'object' || !buttons.onCancel) && selectedIndex === 0 ? 'end' : 'space-between'}>
121
- {selectedIndex === 0 && typeof buttons === 'object' && buttons.onCancel && (
122
- <Button onClick={buttons.onCancel} colorScheme="inverse" appearance="outlined">{buttons.cancel || t.cancel}</Button>
123
- )}
124
- {selectedIndex > 0 && buttons && (
125
- <Button onClick={onPrevious} colorScheme="inverse" appearance="outlined">
126
- {(typeof buttons === 'object' && buttons.previous) || t.previous}
127
- </Button>
128
- )}
129
- {selectedIndex < tabs.length - 1 && buttons && (
130
- <Button onClick={onNext}>
131
- {(typeof buttons === 'object' && buttons.next) || t.next}
132
- </Button>
133
- )}
134
- {selectedIndex === tabs.length - 1 && typeof buttons === 'object' && buttons.onFinish && (
135
- <Button onClick={buttons.onFinish}>{buttons.finish || t.finish}</Button>
136
- )}
137
- </Row>
138
- </Column>
137
+ <Tabs
138
+ tabs={tabs}
139
+ className={listToClass([className, 'stepper'])}
140
+ value={value}
141
+ onChange={(value) => {
142
+ setTabs(getTabsWithDisabled(initialTabs, value))
143
+ onChange?.(value)
144
+ }}
145
+ customRenderer={(selector, content) => <>
146
+ {selector}
147
+ {content}
148
+ <StepperButtons buttons={buttons} tabs={initialTabs} />
149
+ </>}
150
+ />
139
151
  ) : <Tabs
140
152
  tabs={tabs}
141
- controller={controller}
142
- value={value}
143
- onChange={onChange}
144
153
  className={listToClass([className, 'stepper'])}
145
154
  {...props}
146
155
  />
@@ -12,6 +12,24 @@ export class TabController<Key extends string> extends ValueController<Key> {
12
12
  return this.tabOrder.findIndex(t => t === this.value)
13
13
  }
14
14
 
15
+ /**
16
+ * Replaces the current set of tabs.
17
+ */
18
+ setTabOrder(tabOrder: Key[]) {
19
+ let newValue = this.value
20
+ if (!tabOrder.includes(this.value)) {
21
+ const prev = this.getCurrentIndex() - 1
22
+ const key = this.tabOrder[prev]
23
+ if (key && tabOrder.includes(key)) {
24
+ newValue = key
25
+ } else {
26
+ newValue = tabOrder[0]
27
+ }
28
+ }
29
+ this.tabOrder = tabOrder
30
+ this.setValue(newValue)
31
+ }
32
+
15
33
  /**
16
34
  * @returns true if there's another tab after the one currently selected. False otherwise.
17
35
  */
@@ -1,6 +1,6 @@
1
1
  import { listToClass } from '@stack-spot/portal-theme'
2
2
  import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
3
- import { createContext, Suspense, useContext, useEffect, useMemo, useState } from 'react'
3
+ import { createContext, Suspense, useContext, useEffect, useMemo, useRef, useState } from 'react'
4
4
  import { withRef } from '../../utils/react'
5
5
  import { CitricComponent } from '../CitricComponent'
6
6
  import { ErrorBoundary } from '../ErrorBoundary'
@@ -29,25 +29,32 @@ const ctx = createContext<TabController<any> | undefined>(undefined)
29
29
  */
30
30
  export const Tabs = withRef(
31
31
  function Tabs<Key extends string>(
32
- { tabs, value, equallySized, onChange, controller: ctrl, appearance, customRenderer, className, ...props }: TabsProps<Key>,
32
+ { tabs, value, equallySized, onChange, appearance, customRenderer, className, ...props }: TabsProps<Key>,
33
33
  ) {
34
- const controller = useMemo(() => ctrl ?? new TabController<Key>(tabs.map(t => t.key), value || tabs[0]?.key), [])
34
+ const tabKeys = tabs.map(t => t.key)
35
+ const controller = useMemo(() => new TabController<Key>(tabKeys, value || tabs[0]?.key), [])
35
36
  const t = useTranslate(dictionary)
36
37
  const [selectedIndex, setSelectedIndex] = useState(findSelectedIndex(tabs, controller.getValue()))
38
+ const tabsRef = useRef(tabs)
39
+ tabsRef.current = tabs
37
40
 
38
41
  useEffect(() => {
39
42
  if (value) controller.setValue(value)
40
43
  }, [value])
41
44
 
42
45
  useEffect(() => controller.onChange((v) => {
43
- setSelectedIndex(findSelectedIndex(tabs, v))
46
+ setSelectedIndex(findSelectedIndex(tabsRef.current, v))
44
47
  onChange?.(v)
45
- }), [tabs])
48
+ }), [controller])
49
+
50
+ useEffect(() => {
51
+ controller.setTabOrder(tabKeys)
52
+ }, [tabKeys.join(','), controller])
46
53
 
47
54
  const tabSelector = useMemo(
48
55
  () => (
49
56
  <nav className="tab-selector">
50
- {tabs.map(({ key, label, icon, disabled }, index) => (
57
+ {tabs.map(({ key, label, icon, after, disabled }, index) => (
51
58
  <label key={key}>
52
59
  <input
53
60
  type="radio"
@@ -57,6 +64,7 @@ export const Tabs = withRef(
57
64
  />
58
65
  {icon}
59
66
  {label || key}
67
+ {after}
60
68
  </label>
61
69
  ))}
62
70
  </nav>
@@ -72,7 +80,7 @@ export const Tabs = withRef(
72
80
  </Suspense>
73
81
  </ErrorBoundary>
74
82
  </section>
75
- ), [selectedIndex, t])
83
+ ), [selectedIndex, value, t])
76
84
 
77
85
  return (
78
86
  <ctx.Provider value={controller}>
@@ -1,5 +1,4 @@
1
1
  import { WithColorPalette, WithColorScheme } from '../../types'
2
- import { TabController } from './TabController'
3
2
 
4
3
  export interface Tab<Key extends string = string> {
5
4
  /**
@@ -14,6 +13,10 @@ export interface Tab<Key extends string = string> {
14
13
  * An icon for the tab.
15
14
  */
16
15
  icon?: React.ReactElement,
16
+ /**
17
+ * Content to place after the tab's name.
18
+ */
19
+ after?: React.ReactElement,
17
20
  /**
18
21
  * The tab's content. This can be a suspended component.
19
22
  *
@@ -43,10 +46,6 @@ export interface BaseTabsProps<Key extends string> extends WithColorScheme, With
43
46
  * @param key the key of the selected tab.
44
47
  */
45
48
  onChange?: (key: Key) => void,
46
- /**
47
- * A tab-controller, useful if you want to control the tabs outside the component context.
48
- */
49
- controller?: TabController<Key>,
50
49
  /**
51
50
  * Instead of each tab occupying only the space it needs, all tabs will have their sizes equally distributed.
52
51
  *