@ttoss/components 2.15.0 → 2.16.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/README.md CHANGED
@@ -14,6 +14,52 @@ pnpm add @ttoss/components @ttoss/ui @emotion/react @ttoss/react-hooks
14
14
 
15
15
  All components are theme-aware and integrate seamlessly with `@ttoss/ui`.
16
16
 
17
+ ### OAuthConsent
18
+
19
+ OAuth consent screen with flat and GitHub-style hierarchical scopes. Granting a parent scope automatically locks all descendants. All visible copy is injected via the `labels` prop — no hardcoded strings. [Docs](https://storybook.ttoss.dev/?path=/docs/components-oauthconsent--docs)
20
+
21
+ ```tsx
22
+ import { OAuthConsent } from '@ttoss/components';
23
+
24
+ <OAuthConsent
25
+ clientName="My App"
26
+ scopes={[
27
+ {
28
+ key: 'openid',
29
+ label: 'OpenID Connect',
30
+ description: 'Verify your identity',
31
+ required: true,
32
+ },
33
+ {
34
+ key: 'profile',
35
+ label: 'Profile',
36
+ description: 'Read your public profile information',
37
+ },
38
+ ]}
39
+ onAuthorize={async (grantedScopes) => {
40
+ const res = await authorize({ scopes: grantedScopes });
41
+ return { ok: res.ok };
42
+ }}
43
+ onAuthorized={() => {
44
+ window.location.href = resumeUrl;
45
+ }}
46
+ onDeny={() => navigate('/')}
47
+ labels={{
48
+ title: 'Authorize access',
49
+ requestedBy: (name) => (
50
+ <>
51
+ <strong>{name}</strong> is requesting access.
52
+ </>
53
+ ),
54
+ permissionsHeading: 'Requested permissions',
55
+ approve: 'Authorize',
56
+ deny: 'Deny',
57
+ invalidRequestTitle: 'Invalid request',
58
+ invalidRequestBody: 'Missing required OAuth parameters. Please try again.',
59
+ }}
60
+ />;
61
+ ```
62
+
17
63
  ### Accordion
18
64
 
19
65
  Accessible accordion component with collapsible content sections. [Docs](https://storybook.ttoss.dev/?path=/docs/components-accordion--docs)
package/dist/index.d.mts CHANGED
@@ -854,6 +854,119 @@ declare const NotificationsMenu: ({
854
854
  onClearAll
855
855
  }: Props) => import("react/jsx-runtime").JSX.Element;
856
856
  //#endregion
857
+ //#region src/components/OAuthConsent/OAuthConsent.d.ts
858
+ /**
859
+ * A single OAuth scope, optionally with implied child scopes.
860
+ */
861
+ type ConsentScope = {
862
+ /** OAuth scope token, e.g. 'repo', 'write:packages', 'read'. */key: string; /** Bold display name shown on the left. Pre-translated by the consumer. */
863
+ label: string; /** Scope description shown below the label. Pre-translated by the consumer. */
864
+ description: string;
865
+ /**
866
+ * Child scopes implied by this one. When this scope is granted, every
867
+ * descendant is granted and locked (checked + disabled).
868
+ */
869
+ children?: ConsentScope[];
870
+ /**
871
+ * Pre-checked on mount.
872
+ * @default false
873
+ */
874
+ defaultGranted?: boolean;
875
+ /**
876
+ * Always granted; cannot be unchecked. Renders checked + disabled.
877
+ * @default false
878
+ */
879
+ required?: boolean;
880
+ };
881
+ /**
882
+ * All visible copy for the consent screen. Pre-translated by the consumer.
883
+ */
884
+ type OAuthConsentLabels = {
885
+ /** Page heading, e.g. "Authorize access". */title: string; /** Client request line. Receives the client identifier for interpolation. */
886
+ requestedBy: (clientName: string) => React.ReactNode; /** Section heading above the scope list, e.g. "Requested permissions". */
887
+ permissionsHeading: string; /** Approve button label, e.g. "Authorize". */
888
+ approve: string; /** Deny button label, e.g. "Deny". */
889
+ deny: string; /** Heading shown when required OAuth params are missing. */
890
+ invalidRequestTitle: string; /** Body text shown when required OAuth params are missing. */
891
+ invalidRequestBody: string;
892
+ };
893
+ /**
894
+ * Props for the OAuthConsent component.
895
+ */
896
+ type OAuthConsentProps = {
897
+ /** Display name or identifier of the requesting OAuth client. */clientName: string; /** Scope tree to render. */
898
+ scopes: ConsentScope[];
899
+ /**
900
+ * Called when the user approves. Receives the minimal granted scope set
901
+ * (top-most selected keys; implied descendants omitted). Return `{ ok: true }`
902
+ * to signal success; the component then calls `onAuthorized`.
903
+ */
904
+ onAuthorize: (grantedScopes: string[]) => Promise<{
905
+ ok: boolean;
906
+ }>;
907
+ /**
908
+ * Called after a successful `onAuthorize`. Use this to redirect to the OAuth
909
+ * server's resumed /authorize URL. The component does not navigate itself.
910
+ */
911
+ onAuthorized: () => void; /** Called when the user clicks Deny. Use this to navigate away. */
912
+ onDeny: () => void;
913
+ /**
914
+ * True while the authorize call is in flight (disables both buttons).
915
+ * The component also tracks its own internal loading state.
916
+ */
917
+ isAuthorizing?: boolean;
918
+ /**
919
+ * When false, renders the invalid-request error state instead of the form.
920
+ * @default true
921
+ */
922
+ isValidRequest?: boolean; /** All visible copy. Pre-translated by the consumer. */
923
+ labels: OAuthConsentLabels;
924
+ };
925
+ /**
926
+ * Walk the scope tree and return the minimal set of granted scope keys.
927
+ * When a node is selected, its key is emitted and its subtree is skipped
928
+ * (the server expands parent scopes to their children). Nodes not in
929
+ * `selected` are recursed into so that individually-selected children
930
+ * are still captured.
931
+ */
932
+ declare const collectGrantedScopes: (scopes: ConsentScope[], selected: Set<string>) => string[];
933
+ /**
934
+ * Accessible, framework-agnostic OAuth consent screen component.
935
+ *
936
+ * Renders a standards-compliant "authorize this client" page with support for
937
+ * flat and GitHub-style grouped/hierarchical scopes. Granting a parent scope
938
+ * automatically locks all descendant scopes (checked + disabled). All visible
939
+ * copy is injected via `labels`; no strings are hardcoded inside this component.
940
+ *
941
+ * @example
942
+ * ```tsx
943
+ * <OAuthConsent
944
+ * clientName="My App"
945
+ * scopes={[
946
+ * { key: 'read', label: 'Read', description: 'Read access', required: true },
947
+ * { key: 'write', label: 'Write', description: 'Write access' },
948
+ * ]}
949
+ * onAuthorize={async (scopes) => {
950
+ * const res = await authorize({ variables: { scopes } });
951
+ * return { ok: !!res.ok };
952
+ * }}
953
+ * onAuthorized={() => { window.location.href = resumeUrl; }}
954
+ * onDeny={() => navigate('/')}
955
+ * labels={labels}
956
+ * />
957
+ * ```
958
+ */
959
+ declare const OAuthConsent: ({
960
+ clientName,
961
+ scopes,
962
+ onAuthorize,
963
+ onAuthorized,
964
+ onDeny,
965
+ isAuthorizing,
966
+ isValidRequest,
967
+ labels
968
+ }: OAuthConsentProps) => import("react/jsx-runtime").JSX.Element;
969
+ //#endregion
857
970
  //#region src/components/Search/Search.d.ts
858
971
  type SearchProps = Omit<InputProps, 'onChange'> & {
859
972
  loading?: boolean;
@@ -926,4 +1039,4 @@ declare const Tabs: {
926
1039
  declare const ToastContainer: (props: ToastContainerProps) => import("react/jsx-runtime").JSX.Element;
927
1040
  declare const toast: typeof toast$1;
928
1041
  //#endregion
929
- export { Accordion, AccordionItem, AccordionProps, AccordionRenderItemProps, BaseMetric, DateMetric, DatePicker, DateRange, Drawer, DrawerProps, EnhancedTitle, EnhancedTitleBadge, EnhancedTitleProps, EnhancedTitleVariant, FileUploadState, FileUploader, FileUploaderProps, InstallPwa, InstallPwaUi, InstallPwaUiProps, JsonEditor, JsonView, type LinkComponentProps, List, ListItem, ListItemProps, ListProps, LockedOverlay, Markdown, MarkdownProps, Menu, MenuProps, Metric, MetricCard, MetricCardProps, Modal, ModalProps, NavList, type NavListGroup, type NavListItem, type NavListProps, Notification, NotificationAction, NotificationButton, NotificationButtonProps, NotificationCard, NotificationCardProps, NotificationsMenu, NumberMetric, OnFilesChange, OnRemove, OnUpload, OnUploadComplete, OnUploadError, OnUploadProgress, OnUploadStart, PercentageMetric, Search, SearchProps, SpotlightCard, SpotlightCardProps, type TabListProps, type TabPanelProps, type TabProps, Table, Tabs, type TabsProps, ToastContainer, type ToastContainerProps, type ToastOptions, UploadResult, UploadedFile, createCell, createColumnHelper, flexRender, getCoreRowModel, toast, useReactTable };
1042
+ export { Accordion, AccordionItem, AccordionProps, AccordionRenderItemProps, BaseMetric, ConsentScope, DateMetric, DatePicker, DateRange, Drawer, DrawerProps, EnhancedTitle, EnhancedTitleBadge, EnhancedTitleProps, EnhancedTitleVariant, FileUploadState, FileUploader, FileUploaderProps, InstallPwa, InstallPwaUi, InstallPwaUiProps, JsonEditor, JsonView, type LinkComponentProps, List, ListItem, ListItemProps, ListProps, LockedOverlay, Markdown, MarkdownProps, Menu, MenuProps, Metric, MetricCard, MetricCardProps, Modal, ModalProps, NavList, type NavListGroup, type NavListItem, type NavListProps, Notification, NotificationAction, NotificationButton, NotificationButtonProps, NotificationCard, NotificationCardProps, NotificationsMenu, NumberMetric, OAuthConsent, OAuthConsentLabels, OAuthConsentProps, OnFilesChange, OnRemove, OnUpload, OnUploadComplete, OnUploadError, OnUploadProgress, OnUploadStart, PercentageMetric, Search, SearchProps, SpotlightCard, SpotlightCardProps, type TabListProps, type TabPanelProps, type TabProps, Table, Tabs, type TabsProps, ToastContainer, type ToastContainerProps, type ToastOptions, UploadResult, UploadedFile, collectGrantedScopes, createCell, createColumnHelper, flexRender, getCoreRowModel, toast, useReactTable };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { Badge, BaseStyles, Box, Button, Card, CloseButton, Divider, Flex, Heading, IconButton, Input, Label, Link, Stack, Tag, Text, TooltipIcon, keyframes, useResponsiveValue, useTheme } from "@ttoss/ui";
2
+ import { Badge, BaseStyles, Box, Button, Card, Checkbox, CloseButton, Divider, Flex, Heading, IconButton, Input, Label, Link, Stack, Tag, Text, TooltipIcon, keyframes, useResponsiveValue, useTheme } from "@ttoss/ui";
3
3
  import * as React from "react";
4
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
5
  import { Icon } from "@ttoss/react-icons";
@@ -2980,6 +2980,331 @@ var NotificationsMenu = ({
2980
2980
  });
2981
2981
  };
2982
2982
 
2983
+ //#endregion
2984
+ //#region src/components/OAuthConsent/OAuthConsent.tsx
2985
+ /**
2986
+ * Walk the scope tree and return the minimal set of granted scope keys.
2987
+ * When a node is selected, its key is emitted and its subtree is skipped
2988
+ * (the server expands parent scopes to their children). Nodes not in
2989
+ * `selected` are recursed into so that individually-selected children
2990
+ * are still captured.
2991
+ */
2992
+ var collectGrantedScopes = (scopes, selected) => {
2993
+ const result = [];
2994
+ const walk = nodes => {
2995
+ for (const node of nodes) if (selected.has(node.key)) result.push(node.key);else if (node.children) walk(node.children);
2996
+ };
2997
+ walk(scopes);
2998
+ return result;
2999
+ };
3000
+ var initSelected = scopes => {
3001
+ const selected = /* @__PURE__ */new Set();
3002
+ const walk = nodes => {
3003
+ for (const node of nodes) {
3004
+ if (node.required || node.defaultGranted) selected.add(node.key);
3005
+ if (node.children) walk(node.children);
3006
+ }
3007
+ };
3008
+ walk(scopes);
3009
+ return selected;
3010
+ };
3011
+ var getScopeRowState = ({
3012
+ scope,
3013
+ ancestorSelected,
3014
+ selected,
3015
+ busy
3016
+ }) => {
3017
+ const isChecked = ancestorSelected || selected.has(scope.key);
3018
+ const isLocked = !!scope.required || ancestorSelected;
3019
+ return {
3020
+ isChecked,
3021
+ isDisabled: isLocked || busy,
3022
+ isInteractive: !isLocked && !busy
3023
+ };
3024
+ };
3025
+ var ScopeRow = ({
3026
+ scope,
3027
+ ancestorSelected,
3028
+ selected,
3029
+ busy,
3030
+ onToggle
3031
+ }) => {
3032
+ const {
3033
+ isChecked,
3034
+ isDisabled,
3035
+ isInteractive
3036
+ } = getScopeRowState({
3037
+ scope,
3038
+ ancestorSelected,
3039
+ selected,
3040
+ busy
3041
+ });
3042
+ const checkboxId = `consent-scope-${scope.key}`;
3043
+ const labelId = `consent-scope-label-${scope.key}`;
3044
+ const descId = `consent-scope-desc-${scope.key}`;
3045
+ return /* @__PURE__ */jsxs(Box, {
3046
+ as: "li",
3047
+ sx: {
3048
+ listStyle: "none"
3049
+ },
3050
+ children: [/* @__PURE__ */jsxs(Flex, {
3051
+ as: "label",
3052
+ sx: {
3053
+ gap: 3,
3054
+ alignItems: "flex-start",
3055
+ paddingX: 3,
3056
+ paddingY: 3,
3057
+ borderRadius: "md",
3058
+ opacity: ancestorSelected ? .55 : 1,
3059
+ transition: "background-color 0.15s ease",
3060
+ cursor: isInteractive ? "pointer" : "default",
3061
+ ...(isInteractive && {
3062
+ "&:hover": {
3063
+ backgroundColor: "display.background.muted.default"
3064
+ }
3065
+ })
3066
+ },
3067
+ children: [/* @__PURE__ */jsx(Box, {
3068
+ sx: {
3069
+ paddingTop: "3px",
3070
+ flexShrink: 0
3071
+ },
3072
+ children: /* @__PURE__ */jsx(Checkbox, {
3073
+ id: checkboxId,
3074
+ checked: isChecked,
3075
+ disabled: isDisabled,
3076
+ "aria-labelledby": labelId,
3077
+ "aria-describedby": descId,
3078
+ onChange: () => {
3079
+ onToggle(scope, ancestorSelected);
3080
+ }
3081
+ })
3082
+ }), /* @__PURE__ */jsxs(Box, {
3083
+ sx: {
3084
+ flex: 1,
3085
+ minWidth: 0
3086
+ },
3087
+ children: [/* @__PURE__ */jsx(Text, {
3088
+ as: "span",
3089
+ id: labelId,
3090
+ sx: {
3091
+ fontWeight: "semibold",
3092
+ fontSize: "md",
3093
+ lineHeight: "short",
3094
+ color: "display.text.primary.default",
3095
+ display: "block"
3096
+ },
3097
+ children: scope.label
3098
+ }), /* @__PURE__ */jsx(Text, {
3099
+ id: descId,
3100
+ sx: {
3101
+ fontSize: "sm",
3102
+ lineHeight: "short",
3103
+ color: "display.text.muted.default",
3104
+ display: "block",
3105
+ marginTop: "1"
3106
+ },
3107
+ children: scope.description
3108
+ })]
3109
+ })]
3110
+ }), scope.children?.length ? /* @__PURE__ */jsx(Box, {
3111
+ as: "ul",
3112
+ sx: {
3113
+ listStyle: "none",
3114
+ margin: 0,
3115
+ padding: 0,
3116
+ marginLeft: 5,
3117
+ paddingLeft: 2,
3118
+ borderLeft: "sm",
3119
+ borderColor: "display.border.muted.default"
3120
+ },
3121
+ children: scope.children?.map(child => {
3122
+ return /* @__PURE__ */jsx(ScopeRow, {
3123
+ scope: child,
3124
+ ancestorSelected: isChecked,
3125
+ selected,
3126
+ busy,
3127
+ onToggle
3128
+ }, child.key);
3129
+ })
3130
+ }) : null]
3131
+ });
3132
+ };
3133
+ /** Shared centered card shell for the consent and invalid-request views. */
3134
+ var ConsentCard = ({
3135
+ children
3136
+ }) => {
3137
+ return /* @__PURE__ */jsx(Flex, {
3138
+ sx: {
3139
+ justifyContent: "center",
3140
+ paddingX: 4,
3141
+ paddingY: 6
3142
+ },
3143
+ children: /* @__PURE__ */jsx(Card, {
3144
+ sx: {
3145
+ width: "100%",
3146
+ maxWidth: 480,
3147
+ alignItems: "stretch",
3148
+ padding: 6
3149
+ },
3150
+ children
3151
+ })
3152
+ });
3153
+ };
3154
+ /**
3155
+ * Accessible, framework-agnostic OAuth consent screen component.
3156
+ *
3157
+ * Renders a standards-compliant "authorize this client" page with support for
3158
+ * flat and GitHub-style grouped/hierarchical scopes. Granting a parent scope
3159
+ * automatically locks all descendant scopes (checked + disabled). All visible
3160
+ * copy is injected via `labels`; no strings are hardcoded inside this component.
3161
+ *
3162
+ * @example
3163
+ * ```tsx
3164
+ * <OAuthConsent
3165
+ * clientName="My App"
3166
+ * scopes={[
3167
+ * { key: 'read', label: 'Read', description: 'Read access', required: true },
3168
+ * { key: 'write', label: 'Write', description: 'Write access' },
3169
+ * ]}
3170
+ * onAuthorize={async (scopes) => {
3171
+ * const res = await authorize({ variables: { scopes } });
3172
+ * return { ok: !!res.ok };
3173
+ * }}
3174
+ * onAuthorized={() => { window.location.href = resumeUrl; }}
3175
+ * onDeny={() => navigate('/')}
3176
+ * labels={labels}
3177
+ * />
3178
+ * ```
3179
+ */
3180
+ var OAuthConsent = ({
3181
+ clientName,
3182
+ scopes,
3183
+ onAuthorize,
3184
+ onAuthorized,
3185
+ onDeny,
3186
+ isAuthorizing = false,
3187
+ isValidRequest = true,
3188
+ labels
3189
+ }) => {
3190
+ const [selected, setSelected] = React.useState(() => {
3191
+ return initSelected(scopes);
3192
+ });
3193
+ const [isLoading, setIsLoading] = React.useState(false);
3194
+ const busy = isAuthorizing || isLoading;
3195
+ const handleToggle = React.useCallback((scope, ancestorSelected) => {
3196
+ if (scope.required || ancestorSelected) return;
3197
+ setSelected(prev => {
3198
+ const next = new Set(prev);
3199
+ if (next.has(scope.key)) next.delete(scope.key);else next.add(scope.key);
3200
+ return next;
3201
+ });
3202
+ }, []);
3203
+ const handleApprove = React.useCallback(async () => {
3204
+ const grantedScopes = collectGrantedScopes(scopes, selected);
3205
+ setIsLoading(true);
3206
+ try {
3207
+ if ((await onAuthorize(grantedScopes)).ok) onAuthorized();
3208
+ } finally {
3209
+ setIsLoading(false);
3210
+ }
3211
+ }, [scopes, selected, onAuthorize, onAuthorized]);
3212
+ if (!isValidRequest) return /* @__PURE__ */jsxs(ConsentCard, {
3213
+ children: [/* @__PURE__ */jsx(Heading, {
3214
+ as: "h1",
3215
+ sx: {
3216
+ fontSize: "3xl",
3217
+ color: "display.text.primary.default",
3218
+ marginBottom: 3
3219
+ },
3220
+ children: labels.invalidRequestTitle
3221
+ }), /* @__PURE__ */jsx(Text, {
3222
+ sx: {
3223
+ fontSize: "md",
3224
+ lineHeight: "moderate",
3225
+ color: "display.text.secondary.default"
3226
+ },
3227
+ children: labels.invalidRequestBody
3228
+ })]
3229
+ });
3230
+ return /* @__PURE__ */jsxs(ConsentCard, {
3231
+ children: [/* @__PURE__ */jsx(Heading, {
3232
+ as: "h1",
3233
+ sx: {
3234
+ fontSize: "3xl",
3235
+ lineHeight: "shorter",
3236
+ color: "display.text.primary.default",
3237
+ marginBottom: 2
3238
+ },
3239
+ children: labels.title
3240
+ }), /* @__PURE__ */jsx(Text, {
3241
+ sx: {
3242
+ fontSize: "md",
3243
+ lineHeight: "moderate",
3244
+ color: "display.text.secondary.default"
3245
+ },
3246
+ children: labels.requestedBy(clientName)
3247
+ }), /* @__PURE__ */jsx(Divider, {
3248
+ sx: {
3249
+ marginY: 5,
3250
+ borderColor: "display.border.muted.default"
3251
+ }
3252
+ }), /* @__PURE__ */jsx(Heading, {
3253
+ as: "h3",
3254
+ sx: {
3255
+ fontSize: "xs",
3256
+ fontWeight: "semibold",
3257
+ letterSpacing: "wider",
3258
+ textTransform: "uppercase",
3259
+ color: "display.text.muted.default",
3260
+ marginBottom: 2
3261
+ },
3262
+ children: labels.permissionsHeading
3263
+ }), /* @__PURE__ */jsx(Box, {
3264
+ as: "ul",
3265
+ sx: {
3266
+ listStyle: "none",
3267
+ margin: 0,
3268
+ padding: 0
3269
+ },
3270
+ children: scopes.map(scope => {
3271
+ return /* @__PURE__ */jsx(ScopeRow, {
3272
+ scope,
3273
+ ancestorSelected: false,
3274
+ selected,
3275
+ busy,
3276
+ onToggle: handleToggle
3277
+ }, scope.key);
3278
+ })
3279
+ }), /* @__PURE__ */jsxs(Flex, {
3280
+ sx: {
3281
+ gap: 3,
3282
+ marginTop: 6
3283
+ },
3284
+ children: [/* @__PURE__ */jsx(Button, {
3285
+ variant: "secondary",
3286
+ onClick: onDeny,
3287
+ disabled: busy,
3288
+ sx: {
3289
+ flex: 1,
3290
+ justifyContent: "center"
3291
+ },
3292
+ children: labels.deny
3293
+ }), /* @__PURE__ */jsx(Button, {
3294
+ variant: "accent",
3295
+ onClick: handleApprove,
3296
+ disabled: busy,
3297
+ loading: isLoading || isAuthorizing,
3298
+ sx: {
3299
+ flex: 1,
3300
+ justifyContent: "center"
3301
+ },
3302
+ children: labels.approve
3303
+ })]
3304
+ })]
3305
+ });
3306
+ };
3307
+
2983
3308
  //#endregion
2984
3309
  //#region src/components/Search/Search.tsx
2985
3310
  var Search = ({
@@ -3178,4 +3503,4 @@ var ToastContainer = props => {
3178
3503
  var toast = toast$1;
3179
3504
 
3180
3505
  //#endregion
3181
- export { Accordion, DatePicker, Drawer, EnhancedTitle, FileUploader, InstallPwa, InstallPwaUi, JsonEditor, JsonView, List, ListItem, LockedOverlay, Markdown, Menu, MetricCard, Modal, NavList, NotificationButton, NotificationCard, NotificationsMenu, Search, SpotlightCard, Table, Tabs, ToastContainer, createCell, createColumnHelper, flexRender, getCoreRowModel, toast, useReactTable };
3506
+ export { Accordion, DatePicker, Drawer, EnhancedTitle, FileUploader, InstallPwa, InstallPwaUi, JsonEditor, JsonView, List, ListItem, LockedOverlay, Markdown, Menu, MetricCard, Modal, NavList, NotificationButton, NotificationCard, NotificationsMenu, OAuthConsent, Search, SpotlightCard, Table, Tabs, ToastContainer, collectGrantedScopes, createCell, createColumnHelper, flexRender, getCoreRowModel, toast, useReactTable };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/components",
3
- "version": "2.15.0",
3
+ "version": "2.16.1",
4
4
  "description": "React components for ttoss ecosystem.",
5
5
  "keywords": [
6
6
  "React",
@@ -55,11 +55,11 @@
55
55
  "tsx": "^4.21.0",
56
56
  "@ttoss/config": "^1.37.17",
57
57
  "@ttoss/i18n-cli": "^0.8.17",
58
- "@ttoss/react-hooks": "^2.3.20",
59
58
  "@ttoss/react-i18n": "^2.3.0",
60
59
  "@ttoss/react-icons": "^0.7.21",
61
- "@ttoss/ui": "^6.9.28",
62
- "@ttoss/test-utils": "^4.2.18"
60
+ "@ttoss/react-hooks": "^2.3.20",
61
+ "@ttoss/test-utils": "^4.2.18",
62
+ "@ttoss/ui": "^6.9.28"
63
63
  },
64
64
  "peerDependencies": {
65
65
  "react": ">=16.8.0",