@crisp-ui-kit/crisp 0.54.1 → 0.54.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chip.css +7 -1
- package/dist/chip.d.ts +2 -1
- package/dist/chip.layered.css +7 -1
- package/dist/cjs/components/chip/chip.js +3 -2
- package/dist/cjs/components/chip/chip.recipe.js +37 -1
- package/dist/cjs/components/datatable/datatable.js +490 -111
- package/dist/cjs/components/datatable/datatable.recipe.js +4 -0
- package/dist/cjs/components/emptystate/emptystate.js +3 -2
- package/dist/cjs/components/emptystate/emptystate.recipe.js +26 -1
- package/dist/cjs/components/mentionchip/index.js +7 -0
- package/dist/cjs/components/mentionchip/mentionchip.js +57 -0
- package/dist/cjs/components/mentionchip/mentionchip.recipe.js +38 -0
- package/dist/cjs/components/personchip/index.js +17 -0
- package/dist/cjs/components/personchip/personchip.js +50 -0
- package/dist/cjs/components/table/table.js +2 -2
- package/dist/cjs/components/table/table.recipe.js +15 -3
- package/dist/cjs/components/tabs/tabs.js +2 -2
- package/dist/cjs/components/tabs/tabs.recipe.js +30 -3
- package/dist/cjs/components/text/index.js +7 -0
- package/dist/cjs/components/text/text.js +55 -0
- package/dist/cjs/components/text/text.recipe.js +34 -0
- package/dist/cjs/core/floating-stack.js +18 -0
- package/dist/cjs/core/index.js +2 -1
- package/dist/cjs/index.js +8 -0
- package/dist/cjs/product/formdialog/formdialog.js +171 -0
- package/dist/cjs/product/formdialog/formdialog.recipe.js +26 -0
- package/dist/cjs/product/formdialog/index.js +8 -0
- package/dist/cjs/product/headerbar/headerbar.recipe.js +9 -1
- package/dist/cjs/product/importdialog/importdialog.js +134 -0
- package/dist/cjs/product/importdialog/importdialog.recipe.js +92 -0
- package/dist/cjs/product/importdialog/index.js +18 -0
- package/dist/cjs/product/recordpage/recordpage.recipe.js +10 -1
- package/dist/cjs/product/recordstable/recordstable.js +89 -6
- package/dist/cjs/product/richtext/richtext.recipe.js +26 -1
- package/dist/cjs/product/savedviews/index.js +7 -0
- package/dist/cjs/product/savedviews/savedviews.js +207 -0
- package/dist/cjs/product/savedviews/savedviews.recipe.js +103 -0
- package/dist/cjs/product/taskstable/index.js +7 -0
- package/dist/cjs/product/taskstable/taskstable.js +27 -0
- package/dist/cjs/product/taskstable/taskstable.recipe.js +47 -0
- package/dist/cjs/product/themepicker/index.js +17 -0
- package/dist/cjs/product/themepicker/themepicker.js +32 -0
- package/dist/cjs/product/themepicker/themepicker.recipe.js +98 -0
- package/dist/cjs/tokens/palette.js +30 -13
- package/dist/cjs/tokens/semantic.js +6 -0
- package/dist/datatable.css +20 -21
- package/dist/datatable.layered.css +20 -21
- package/dist/emptystate.css +15 -1
- package/dist/emptystate.d.ts +2 -2
- package/dist/emptystate.layered.css +15 -1
- package/dist/esm/components/chip/chip.js +3 -2
- package/dist/esm/components/chip/chip.recipe.js +37 -1
- package/dist/esm/components/datatable/datatable.js +489 -111
- package/dist/esm/components/datatable/datatable.recipe.js +4 -0
- package/dist/esm/components/emptystate/emptystate.js +4 -3
- package/dist/esm/components/emptystate/emptystate.recipe.js +26 -1
- package/dist/esm/components/emptystate/index.js +1 -1
- package/dist/esm/components/mentionchip/index.js +2 -0
- package/dist/esm/components/mentionchip/mentionchip.js +21 -0
- package/dist/esm/components/mentionchip/mentionchip.recipe.js +35 -0
- package/dist/esm/components/personchip/index.js +1 -0
- package/dist/esm/components/personchip/personchip.js +47 -0
- package/dist/esm/components/table/table.js +2 -2
- package/dist/esm/components/table/table.recipe.js +15 -3
- package/dist/esm/components/tabs/tabs.js +2 -2
- package/dist/esm/components/tabs/tabs.recipe.js +30 -3
- package/dist/esm/components/text/index.js +2 -0
- package/dist/esm/components/text/text.js +19 -0
- package/dist/esm/components/text/text.recipe.js +31 -0
- package/dist/esm/core/floating-stack.js +17 -0
- package/dist/esm/core/index.js +1 -1
- package/dist/esm/index.js +8 -0
- package/dist/esm/product/formdialog/formdialog.js +134 -0
- package/dist/esm/product/formdialog/formdialog.recipe.js +23 -0
- package/dist/esm/product/formdialog/index.js +2 -0
- package/dist/esm/product/headerbar/headerbar.recipe.js +9 -1
- package/dist/esm/product/importdialog/importdialog.js +97 -0
- package/dist/esm/product/importdialog/importdialog.recipe.js +89 -0
- package/dist/esm/product/importdialog/index.js +2 -0
- package/dist/esm/product/recordpage/recordpage.recipe.js +10 -1
- package/dist/esm/product/recordstable/recordstable.js +90 -8
- package/dist/esm/product/richtext/richtext.recipe.js +26 -1
- package/dist/esm/product/savedviews/index.js +2 -0
- package/dist/esm/product/savedviews/savedviews.js +171 -0
- package/dist/esm/product/savedviews/savedviews.recipe.js +100 -0
- package/dist/esm/product/taskstable/index.js +2 -0
- package/dist/esm/product/taskstable/taskstable.js +24 -0
- package/dist/esm/product/taskstable/taskstable.recipe.js +44 -0
- package/dist/esm/product/themepicker/index.js +1 -0
- package/dist/esm/product/themepicker/themepicker.js +29 -0
- package/dist/esm/product/themepicker/themepicker.recipe.js +95 -0
- package/dist/esm/tokens/palette.js +30 -13
- package/dist/esm/tokens/semantic.js +6 -0
- package/dist/formdialog.css +6 -0
- package/dist/formdialog.d.ts +7 -0
- package/dist/formdialog.layered.css +8 -0
- package/dist/headerbar.css +1 -1
- package/dist/headerbar.layered.css +1 -1
- package/dist/importdialog.css +38 -0
- package/dist/importdialog.d.ts +7 -0
- package/dist/importdialog.layered.css +40 -0
- package/dist/mentionchip.css +3 -0
- package/dist/mentionchip.d.ts +7 -0
- package/dist/mentionchip.layered.css +5 -0
- package/dist/native/tokens.d.ts +1 -1
- package/dist/native/tokens.js +14 -6
- package/dist/recordpage.css +13 -2
- package/dist/recordpage.layered.css +13 -2
- package/dist/richtext.css +11 -1
- package/dist/richtext.layered.css +11 -1
- package/dist/savedviews.css +78 -0
- package/dist/savedviews.d.ts +7 -0
- package/dist/savedviews.layered.css +80 -0
- package/dist/styles.css +287 -37
- package/dist/styles.layered.css +287 -37
- package/dist/table.css +15 -6
- package/dist/table.layered.css +15 -6
- package/dist/tabs.css +7 -1
- package/dist/tabs.d.ts +2 -2
- package/dist/tabs.layered.css +7 -1
- package/dist/taskstable.css +23 -0
- package/dist/taskstable.d.ts +7 -0
- package/dist/taskstable.layered.css +25 -0
- package/dist/text.css +9 -0
- package/dist/text.d.ts +7 -0
- package/dist/text.layered.css +11 -0
- package/dist/themepicker.css +27 -0
- package/dist/themepicker.d.ts +7 -0
- package/dist/themepicker.layered.css +29 -0
- package/dist/tokens.css +7 -3
- package/dist/tokens.json +14 -6
- package/dist/types/components/chip/chip.d.ts +32 -0
- package/dist/types/components/chip/chip.recipe.d.ts +31 -0
- package/dist/types/components/datatable/datatable.d.ts +39 -4
- package/dist/types/components/emptystate/emptystate.d.ts +29 -4
- package/dist/types/components/emptystate/emptystate.recipe.d.ts +2 -0
- package/dist/types/components/emptystate/index.d.ts +1 -1
- package/dist/types/components/mentionchip/index.d.ts +2 -0
- package/dist/types/components/mentionchip/mentionchip.d.ts +20 -0
- package/dist/types/components/mentionchip/mentionchip.recipe.d.ts +18 -0
- package/dist/types/components/personchip/index.d.ts +1 -0
- package/dist/types/components/personchip/personchip.d.ts +37 -0
- package/dist/types/components/table/table.d.ts +36 -0
- package/dist/types/components/tabs/tabs.d.ts +4 -2
- package/dist/types/components/tabs/tabs.recipe.d.ts +18 -3
- package/dist/types/components/text/index.d.ts +2 -0
- package/dist/types/components/text/text.d.ts +32 -0
- package/dist/types/components/text/text.recipe.d.ts +40 -0
- package/dist/types/core/floating-stack.d.ts +14 -0
- package/dist/types/core/index.d.ts +1 -1
- package/dist/types/index.d.ts +8 -0
- package/dist/types/product/formdialog/formdialog.d.ts +57 -0
- package/dist/types/product/formdialog/formdialog.recipe.d.ts +3 -0
- package/dist/types/product/formdialog/index.d.ts +2 -0
- package/dist/types/product/importdialog/importdialog.d.ts +86 -0
- package/dist/types/product/importdialog/importdialog.recipe.d.ts +3 -0
- package/dist/types/product/importdialog/index.d.ts +2 -0
- package/dist/types/product/recordstable/recordstable.d.ts +24 -2
- package/dist/types/product/savedviews/index.d.ts +2 -0
- package/dist/types/product/savedviews/savedviews.d.ts +55 -0
- package/dist/types/product/savedviews/savedviews.recipe.d.ts +3 -0
- package/dist/types/product/taskstable/index.d.ts +2 -0
- package/dist/types/product/taskstable/taskstable.d.ts +54 -0
- package/dist/types/product/taskstable/taskstable.recipe.d.ts +3 -0
- package/dist/types/product/themepicker/index.d.ts +1 -0
- package/dist/types/product/themepicker/themepicker.d.ts +21 -0
- package/dist/types/product/themepicker/themepicker.recipe.d.ts +3 -0
- package/dist/types/tokens/contract.d.ts +2 -0
- package/dist/types/tokens/palette.d.ts +11 -3
- package/dist/types/tokens/semantic.d.ts +6 -0
- package/package.json +41 -1
|
@@ -3,6 +3,7 @@ declare const config: import("../..").RecipeConfig<{
|
|
|
3
3
|
default: string;
|
|
4
4
|
illustrated: string;
|
|
5
5
|
page: string;
|
|
6
|
+
records: string;
|
|
6
7
|
};
|
|
7
8
|
}>;
|
|
8
9
|
export declare const emptystateRecipe: import("../..").RecipeFn<{
|
|
@@ -10,6 +11,7 @@ export declare const emptystateRecipe: import("../..").RecipeFn<{
|
|
|
10
11
|
default: string;
|
|
11
12
|
illustrated: string;
|
|
12
13
|
page: string;
|
|
14
|
+
records: string;
|
|
13
15
|
};
|
|
14
16
|
}>;
|
|
15
17
|
export default config;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { EmptyState, type EmptyStateProps } from "./emptystate";
|
|
1
|
+
export { EmptyState, type EmptyStateLearnMore, type EmptyStateProps, } from "./emptystate";
|
|
2
2
|
export { emptystateRecipe } from "./emptystate.recipe";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type MentionChipProps = React.ComponentPropsWithoutRef<"span"> & {
|
|
3
|
+
asChild?: boolean;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* A standalone "@mention" chip — the same look `RichTextEditor` draws
|
|
7
|
+
* inline while an editor is live (`.crisp-rte-mention`), exported on its
|
|
8
|
+
* own for a consumer rendering a mention OUTSIDE a mounted editor: a
|
|
9
|
+
* comment thread, a note's collapsed preview, anywhere a stored
|
|
10
|
+
* `@[Name](actor:id)`-shaped token needs to read as a person, not literal
|
|
11
|
+
* markup. Renders whatever `children` is given (the trigger character
|
|
12
|
+
* included, if the caller wants one, matching how `RichTextEditor`'s own
|
|
13
|
+
* chip includes it) rather than assuming an `@` prefix itself — plain text,
|
|
14
|
+
* no built-in click/remove behaviour (none was asked for; add one once a
|
|
15
|
+
* real interaction is measured, the same reasoning `Chip`'s own doc gives
|
|
16
|
+
* for not guessing a remove affordance).
|
|
17
|
+
*/
|
|
18
|
+
export declare const MentionChip: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & {
|
|
19
|
+
asChild?: boolean;
|
|
20
|
+
} & React.RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
declare const spec: {
|
|
2
|
+
readonly name: "mention-chip";
|
|
3
|
+
readonly base: {
|
|
4
|
+
readonly display: "inline";
|
|
5
|
+
readonly borderRadius: `var(--${string})`;
|
|
6
|
+
readonly paddingInline: `var(--${string})`;
|
|
7
|
+
readonly background: `color-mix(in srgb, var(--${string}) 14%, transparent)`;
|
|
8
|
+
readonly color: `color-mix(in srgb, var(--${string}) 82%, var(--${string}))`;
|
|
9
|
+
readonly fontWeight: `var(--${string})`;
|
|
10
|
+
readonly cursor: "default";
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
declare const config: import("../..").RecipeConfig<Record<string, Record<string, string>>>;
|
|
14
|
+
export declare const mentionChipRecipe: import("../..").RecipeFn<Record<string, Record<string, string>>> & {
|
|
15
|
+
config: import("../..").RecipeConfig<Record<string, Record<string, string>>>;
|
|
16
|
+
};
|
|
17
|
+
export { spec };
|
|
18
|
+
export default config;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./personchip";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
export type PersonChipProps = Omit<React.ComponentPropsWithoutRef<"span">, "children"> & {
|
|
3
|
+
/** The person's display name — also the avatar's initials fallback. */
|
|
4
|
+
name: string;
|
|
5
|
+
/** A photo URL. Omitted (no populated photo field was reachable to
|
|
6
|
+
* measure this round), the avatar falls back to a per-name hashed-colour
|
|
7
|
+
* initials tile. */
|
|
8
|
+
avatar?: string;
|
|
9
|
+
/** De-emphasises the name (e.g. a departed person, a system actor) —
|
|
10
|
+
* `fgNeutralMuted`, the same token `Text`'s own `tone="muted"` uses.
|
|
11
|
+
* Applied to the name only; the avatar keeps its full-strength tone so
|
|
12
|
+
* the chip still reads as a distinct person, not a disabled control. */
|
|
13
|
+
muted?: boolean;
|
|
14
|
+
className?: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* A person, as a chip: a small avatar (a photo, or hashed-colour initials)
|
|
18
|
+
* plus their name, truncating with an ellipsis when it doesn't fit — Attio's
|
|
19
|
+
* own actor chip (measured live on `techpartners`, Tasks page, "Assigned to"
|
|
20
|
+
* column): a 16px circular avatar in a neutral `Chip`, `gap: 3px` between
|
|
21
|
+
* avatar and name (now `Chip`'s own base — every multi-child `Chip` gets
|
|
22
|
+
* it). Every other value — the pill's height, padding, radius, ring and text
|
|
23
|
+
* — is already `Chip`'s, unchanged; `PersonChip` adds no recipe of its own.
|
|
24
|
+
*
|
|
25
|
+
* Ellipsis only, no `Tooltip` on hover (#623 — no Attio reference for one;
|
|
26
|
+
* a truncated cell there is revealed by its own click-to-expand, #579, a
|
|
27
|
+
* different, DataTable-specific interaction).
|
|
28
|
+
*
|
|
29
|
+
* Composes `Chip`'s `truncate` CSS directly rather than its string-only
|
|
30
|
+
* auto-wrap (children here is an avatar plus a name, not a single string),
|
|
31
|
+
* so the name gets its own `.crisp-chip-label` span while the avatar stays
|
|
32
|
+
* fixed-size.
|
|
33
|
+
*/
|
|
34
|
+
export declare function PersonChip({ name, avatar, muted, className, ...props }: PersonChipProps): React.JSX.Element;
|
|
35
|
+
export declare namespace PersonChip {
|
|
36
|
+
var displayName: string;
|
|
37
|
+
}
|
|
@@ -8,6 +8,24 @@ export type TableProps = React.ComponentPropsWithoutRef<"table"> & VariantProps<
|
|
|
8
8
|
scrollProps?: React.ComponentPropsWithoutRef<"div"> & {
|
|
9
9
|
ref?: React.Ref<HTMLDivElement>;
|
|
10
10
|
};
|
|
11
|
+
/**
|
|
12
|
+
* Style applied to the `<table>` element itself, as opposed to `style`
|
|
13
|
+
* (below), which sizes the OUTER bordered wrapper -- crisp/#581.
|
|
14
|
+
* `DataTable` uses this for its `min-width: <sum of column widths>`,
|
|
15
|
+
* which forces `<table>` to its true content width and lets
|
|
16
|
+
* `.crisp-table-scroll`'s existing `overflow-x: auto` scroll it
|
|
17
|
+
* internally. Putting that same min-width on the outer wrapper
|
|
18
|
+
* (`style`) instead, as this component used to require, forces the
|
|
19
|
+
* WRAPPER itself that wide -- a plain block box's width is normally set
|
|
20
|
+
* by its own container regardless of a child's min-width, so the only
|
|
21
|
+
* element that should ever be forced wider than its container is the
|
|
22
|
+
* scrollable one, never an ancestor of it. Getting this backwards is
|
|
23
|
+
* exactly what made a `DataTable` widen its own page instead of
|
|
24
|
+
* scrolling in place (internal/grc#117), forcing GRC to hand-build its
|
|
25
|
+
* own `overflow: hidden` clipping wrapper around it -- which the
|
|
26
|
+
* crisp-only rule forbids and which this makes unnecessary.
|
|
27
|
+
*/
|
|
28
|
+
tableStyle?: React.CSSProperties;
|
|
11
29
|
};
|
|
12
30
|
/**
|
|
13
31
|
* A composable data table. Wraps `<table>` in a horizontally scrollable
|
|
@@ -32,6 +50,24 @@ export declare const Table: React.ForwardRefExoticComponent<Omit<React.DetailedH
|
|
|
32
50
|
scrollProps?: React.ComponentPropsWithoutRef<"div"> & {
|
|
33
51
|
ref?: React.Ref<HTMLDivElement>;
|
|
34
52
|
};
|
|
53
|
+
/**
|
|
54
|
+
* Style applied to the `<table>` element itself, as opposed to `style`
|
|
55
|
+
* (below), which sizes the OUTER bordered wrapper -- crisp/#581.
|
|
56
|
+
* `DataTable` uses this for its `min-width: <sum of column widths>`,
|
|
57
|
+
* which forces `<table>` to its true content width and lets
|
|
58
|
+
* `.crisp-table-scroll`'s existing `overflow-x: auto` scroll it
|
|
59
|
+
* internally. Putting that same min-width on the outer wrapper
|
|
60
|
+
* (`style`) instead, as this component used to require, forces the
|
|
61
|
+
* WRAPPER itself that wide -- a plain block box's width is normally set
|
|
62
|
+
* by its own container regardless of a child's min-width, so the only
|
|
63
|
+
* element that should ever be forced wider than its container is the
|
|
64
|
+
* scrollable one, never an ancestor of it. Getting this backwards is
|
|
65
|
+
* exactly what made a `DataTable` widen its own page instead of
|
|
66
|
+
* scrolling in place (internal/grc#117), forcing GRC to hand-build its
|
|
67
|
+
* own `overflow: hidden` clipping wrapper around it -- which the
|
|
68
|
+
* crisp-only rule forbids and which this makes unnecessary.
|
|
69
|
+
*/
|
|
70
|
+
tableStyle?: React.CSSProperties;
|
|
35
71
|
} & React.RefAttributes<HTMLTableElement>>;
|
|
36
72
|
export declare const TableHeader: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>, "ref"> & React.RefAttributes<HTMLTableSectionElement>>;
|
|
37
73
|
export declare const TableBody: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>, "ref"> & React.RefAttributes<HTMLTableSectionElement>>;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import type { VariantProps } from "../../core";
|
|
3
|
+
import { tabsRecipe } from "./tabs.recipe";
|
|
2
4
|
export type TabItem = {
|
|
3
5
|
value: string;
|
|
4
6
|
label: React.ReactNode;
|
|
@@ -8,7 +10,7 @@ export type TabItem = {
|
|
|
8
10
|
badge?: React.ReactNode;
|
|
9
11
|
disabled?: boolean;
|
|
10
12
|
};
|
|
11
|
-
export type TabsProps = Omit<React.ComponentPropsWithoutRef<"div">, "value" | "defaultValue" | "children"> & {
|
|
13
|
+
export type TabsProps = Omit<React.ComponentPropsWithoutRef<"div">, "value" | "defaultValue" | "children"> & VariantProps<typeof tabsRecipe> & {
|
|
12
14
|
tabs: TabItem[];
|
|
13
15
|
/** Controlled active value. Omit to let Tabs manage it (see defaultValue). */
|
|
14
16
|
value?: string;
|
|
@@ -27,7 +29,7 @@ export type TabsProps = Omit<React.ComponentPropsWithoutRef<"div">, "value" | "d
|
|
|
27
29
|
* Home/End jump); activation follows focus. Controlled via
|
|
28
30
|
* `value`/`onValueChange`, or uncontrolled from `defaultValue`.
|
|
29
31
|
*/
|
|
30
|
-
export declare function Tabs({ tabs, value, defaultValue, onValueChange, leading, children, className, "aria-label": ariaLabel, ...rest }: TabsProps): React.JSX.Element;
|
|
32
|
+
export declare function Tabs({ tabs, value, defaultValue, onValueChange, leading, children, className, fill, "aria-label": ariaLabel, ...rest }: TabsProps): React.JSX.Element;
|
|
31
33
|
export declare namespace Tabs {
|
|
32
34
|
var displayName: string;
|
|
33
35
|
}
|
|
@@ -1,5 +1,20 @@
|
|
|
1
|
-
declare const config: import("../..").RecipeConfig<{
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
declare const config: import("../..").RecipeConfig<{
|
|
2
|
+
fill: {
|
|
3
|
+
true: string;
|
|
4
|
+
false: string;
|
|
5
|
+
};
|
|
6
|
+
}>;
|
|
7
|
+
export declare const tabsRecipe: import("../..").RecipeFn<{
|
|
8
|
+
fill: {
|
|
9
|
+
true: string;
|
|
10
|
+
false: string;
|
|
11
|
+
};
|
|
12
|
+
}> & {
|
|
13
|
+
config: import("../..").RecipeConfig<{
|
|
14
|
+
fill: {
|
|
15
|
+
true: string;
|
|
16
|
+
false: string;
|
|
17
|
+
};
|
|
18
|
+
}>;
|
|
4
19
|
};
|
|
5
20
|
export default config;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { VariantProps } from "../../core";
|
|
3
|
+
import { textRecipe } from "./text.recipe";
|
|
4
|
+
export type TextProps = React.ComponentPropsWithoutRef<"span"> & VariantProps<typeof textRecipe> & {
|
|
5
|
+
asChild?: boolean;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Plain coloured text — `tone="default"` (the app's primary text colour) or
|
|
9
|
+
* `"muted"` — for the runs of text that aren't a Badge, a Chip, a link, or
|
|
10
|
+
* any of crisp's other typed things: a cell's own yes/no, an empty-state
|
|
11
|
+
* caption, a secondary line under a heading. One component so every such
|
|
12
|
+
* spot reaches for crisp's own tokens instead of each hand-writing its own
|
|
13
|
+
* colour utility for the same two values.
|
|
14
|
+
*
|
|
15
|
+
* Renders a `<span>` (inherits its size/weight/line-height from context —
|
|
16
|
+
* see `text.recipe.ts`'s doc for why `Text` sets none of those itself).
|
|
17
|
+
*/
|
|
18
|
+
export declare const Text: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & VariantProps<import("../..").RecipeFn<{
|
|
19
|
+
readonly tone: {
|
|
20
|
+
readonly default: string;
|
|
21
|
+
readonly muted: string;
|
|
22
|
+
};
|
|
23
|
+
}> & {
|
|
24
|
+
config: import("../..").RecipeConfig<{
|
|
25
|
+
readonly tone: {
|
|
26
|
+
readonly default: string;
|
|
27
|
+
readonly muted: string;
|
|
28
|
+
};
|
|
29
|
+
}>;
|
|
30
|
+
}> & {
|
|
31
|
+
asChild?: boolean;
|
|
32
|
+
} & React.RefAttributes<HTMLSpanElement>>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
declare const spec: {
|
|
2
|
+
readonly name: "text";
|
|
3
|
+
readonly base: {
|
|
4
|
+
readonly display: "inline";
|
|
5
|
+
};
|
|
6
|
+
readonly variants: {
|
|
7
|
+
tone: {
|
|
8
|
+
default: {
|
|
9
|
+
color: `var(--${string})`;
|
|
10
|
+
};
|
|
11
|
+
muted: {
|
|
12
|
+
color: `var(--${string})`;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
readonly defaultVariants: {
|
|
17
|
+
readonly tone: "default";
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
declare const config: import("../..").RecipeConfig<{
|
|
21
|
+
readonly tone: {
|
|
22
|
+
readonly default: string;
|
|
23
|
+
readonly muted: string;
|
|
24
|
+
};
|
|
25
|
+
}>;
|
|
26
|
+
export declare const textRecipe: import("../..").RecipeFn<{
|
|
27
|
+
readonly tone: {
|
|
28
|
+
readonly default: string;
|
|
29
|
+
readonly muted: string;
|
|
30
|
+
};
|
|
31
|
+
}> & {
|
|
32
|
+
config: import("../..").RecipeConfig<{
|
|
33
|
+
readonly tone: {
|
|
34
|
+
readonly default: string;
|
|
35
|
+
readonly muted: string;
|
|
36
|
+
};
|
|
37
|
+
}>;
|
|
38
|
+
};
|
|
39
|
+
export { spec };
|
|
40
|
+
export default config;
|
|
@@ -11,6 +11,20 @@ export declare function registerFloatingLayer(el: HTMLElement): () => void;
|
|
|
11
11
|
* right query for "was this click inside some floating child I opened".
|
|
12
12
|
*/
|
|
13
13
|
export declare function isInsideLaterFloatingLayer(target: Node, self: HTMLElement | null): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* True when a layer is registered strictly after `self` — i.e. `self` has
|
|
16
|
+
* spawned a still-open nested layer of its own (a row's kebab `Menu` inside
|
|
17
|
+
* `SavedViews`' own panel, e.g.).
|
|
18
|
+
*
|
|
19
|
+
* This is `hasOpenFloatingLayer`'s sibling for a caller that DOES register
|
|
20
|
+
* itself on this stack: `hasOpenFloatingLayer` reads "is the stack
|
|
21
|
+
* non-empty", which is always true for such a caller once its own layer is
|
|
22
|
+
* open — checking that before closing on Escape would defer to itself
|
|
23
|
+
* forever and Escape would never close it. `self`'s own position on the
|
|
24
|
+
* stack has to be excluded from the count, which `hasOpenFloatingLayer`
|
|
25
|
+
* cannot do since it takes no argument.
|
|
26
|
+
*/
|
|
27
|
+
export declare function hasNestedFloatingLayer(self: HTMLElement | null): boolean;
|
|
14
28
|
/**
|
|
15
29
|
* True when at least one `Select`/`MultiSelect`/`Menu`/`Popover`/
|
|
16
30
|
* `ContextMenu` is currently open, anywhere (#361).
|
|
@@ -5,7 +5,7 @@ export { defineRecipe } from "./define";
|
|
|
5
5
|
export { withDescribedBy } from "./dialog-description";
|
|
6
6
|
export { isRtlElement } from "./direction";
|
|
7
7
|
export { FloatingPortal } from "./floating-portal";
|
|
8
|
-
export { hasOpenFloatingLayer, isInsideLaterFloatingLayer, registerFloatingLayer, } from "./floating-stack";
|
|
8
|
+
export { hasNestedFloatingLayer, hasOpenFloatingLayer, isInsideLaterFloatingLayer, registerFloatingLayer, } from "./floating-stack";
|
|
9
9
|
export { formValueStyle } from "./form-value";
|
|
10
10
|
export { type CrispComponentDefaults, type CrispMessages, CrispMessagesProvider, useCrispComponentDefaults, useCrispMessage, useCrispMessages, } from "./i18n";
|
|
11
11
|
export { type MentionAnchor, type MentionMatch, matchMentionTrigger, } from "./mention";
|
package/dist/types/index.d.ts
CHANGED
|
@@ -29,9 +29,11 @@ export * from "./components/heatmapchart";
|
|
|
29
29
|
export * from "./components/input";
|
|
30
30
|
export * from "./components/kbd";
|
|
31
31
|
export * from "./components/linechart";
|
|
32
|
+
export * from "./components/mentionchip";
|
|
32
33
|
export * from "./components/menu";
|
|
33
34
|
export * from "./components/middletruncate";
|
|
34
35
|
export * from "./components/multiselect";
|
|
36
|
+
export * from "./components/personchip";
|
|
35
37
|
export * from "./components/popover";
|
|
36
38
|
export * from "./components/progress";
|
|
37
39
|
export * from "./components/quantitypicker";
|
|
@@ -49,6 +51,7 @@ export * from "./components/switch";
|
|
|
49
51
|
export * from "./components/table";
|
|
50
52
|
export * from "./components/tabletoolbar";
|
|
51
53
|
export * from "./components/tabs";
|
|
54
|
+
export * from "./components/text";
|
|
52
55
|
export * from "./components/textarea";
|
|
53
56
|
export * from "./components/textlink";
|
|
54
57
|
export * from "./components/timepicker";
|
|
@@ -64,7 +67,9 @@ export * from "./product/board";
|
|
|
64
67
|
export * from "./product/command";
|
|
65
68
|
export * from "./product/entitycard";
|
|
66
69
|
export * from "./product/flowcanvas";
|
|
70
|
+
export * from "./product/formdialog";
|
|
67
71
|
export * from "./product/headerbar";
|
|
72
|
+
export * from "./product/importdialog";
|
|
68
73
|
export * from "./product/inbox";
|
|
69
74
|
export * from "./product/listpage";
|
|
70
75
|
export * from "./product/navitem";
|
|
@@ -73,11 +78,14 @@ export * from "./product/recordpage";
|
|
|
73
78
|
export * from "./product/recordpanel";
|
|
74
79
|
export * from "./product/recordstable";
|
|
75
80
|
export * from "./product/richtext";
|
|
81
|
+
export * from "./product/savedviews";
|
|
76
82
|
export * from "./product/settingssection";
|
|
77
83
|
export * from "./product/settingsshell";
|
|
78
84
|
export * from "./product/sidebar";
|
|
79
85
|
export * from "./product/statlist";
|
|
80
86
|
export * from "./product/tasklist";
|
|
87
|
+
export * from "./product/taskstable";
|
|
88
|
+
export * from "./product/themepicker";
|
|
81
89
|
export * from "./product/trialbanner";
|
|
82
90
|
export * from "./product/viewtoggle";
|
|
83
91
|
export * from "./tokens";
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/** See `OptionalLabelsContext`. Call from a field wrapper as
|
|
3
|
+
* `optional={useFormDialogOptional(required)}`. */
|
|
4
|
+
export declare function useFormDialogOptional(required: boolean): boolean;
|
|
5
|
+
export type FormDialogProps = Omit<React.ComponentPropsWithoutRef<"div">, "title" | "children" | "onSubmit" | "onClose"> & {
|
|
6
|
+
title: React.ReactNode;
|
|
7
|
+
/** The primary button's label on an edit dialog ("Save"). Ignored when
|
|
8
|
+
* `createMode` is set — Attio's own button always reads "Create record",
|
|
9
|
+
* never the object's name (measured live: "New Company"'s dialog still
|
|
10
|
+
* says "Create record", not "Create company"). */
|
|
11
|
+
submitLabel: React.ReactNode;
|
|
12
|
+
/** Called on submit — click, Enter in a field, or (in `createMode`)
|
|
13
|
+
* Cmd/Ctrl+Enter — with whether the "Create more" switch was on at that
|
|
14
|
+
* moment. An edit dialog (no switch, always `false`) can ignore it. */
|
|
15
|
+
onSubmit: (createMore: boolean) => void;
|
|
16
|
+
onClose: () => void;
|
|
17
|
+
busy?: boolean;
|
|
18
|
+
/** Anything the server rejected that belongs to no one field. */
|
|
19
|
+
error?: React.ReactNode;
|
|
20
|
+
children: React.ReactNode;
|
|
21
|
+
/** Widens the dialog for a form with more columns to hold. */
|
|
22
|
+
wide?: boolean;
|
|
23
|
+
/** Dialog content width in px, overrides `wide`. */
|
|
24
|
+
size?: number;
|
|
25
|
+
/** Bundles Attio's whole "New Company" create-dialog chrome (crisp#548,
|
|
26
|
+
* measured live): "(optional)" on every non-required field (via
|
|
27
|
+
* `useFormDialogOptional`); a footer of a "Create more" switch and a
|
|
28
|
+
* single "Create record ⌘↵" button with NO Cancel — Attio's dialog
|
|
29
|
+
* closes only from the header's ×; and Cmd/Ctrl+Enter submitting from
|
|
30
|
+
* anywhere inside the dialog, including a portaled Select/DatePicker
|
|
31
|
+
* popover. Only ever set by a create dialog — an edit dialog keeps
|
|
32
|
+
* Cancel + `submitLabel`, unmeasured territory the audit never touched. */
|
|
33
|
+
createMode?: boolean;
|
|
34
|
+
createMoreLabel?: string;
|
|
35
|
+
cancelLabel?: string;
|
|
36
|
+
discardTitle?: string;
|
|
37
|
+
discardConfirmLabel?: string;
|
|
38
|
+
discardCancelLabel?: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* A modal for a create or edit form — crisp's own `Dialog`/`DialogBody`/
|
|
42
|
+
* `DialogFooter`, plus everything a record-creating form needs beyond plain
|
|
43
|
+
* chrome (crisp#548, moved out of internal/grc's own `forms.tsx`, called
|
|
44
|
+
* from nine places there): dirty tracking with a discard-changes confirm
|
|
45
|
+
* (any click/change/input inside the form marks it dirty; Escape/backdrop/
|
|
46
|
+
* header-×/Cancel all route through one `requestClose`, which only asks
|
|
47
|
+
* when something actually changed — a stacked crisp `Dialog`), a
|
|
48
|
+
* `beforeunload` guard for a reload or external navigation, and
|
|
49
|
+
* scroll-to-first-invalid-field once a submit attempt finishes (crisp's own
|
|
50
|
+
* `FormField` already marks every control `aria-invalid`, so this needs no
|
|
51
|
+
* per-field wiring). A record needs several fields at once to be valid,
|
|
52
|
+
* which is why records are not created by inline editing.
|
|
53
|
+
*/
|
|
54
|
+
export declare function FormDialog({ title, submitLabel, onSubmit, onClose, busy, error, children, wide, size, createMode, createMoreLabel: createMoreLabelProp, cancelLabel: cancelLabelProp, discardTitle: discardTitleProp, discardConfirmLabel: discardConfirmLabelProp, discardCancelLabel: discardCancelLabelProp, className, ...rest }: FormDialogProps): React.JSX.Element;
|
|
55
|
+
export declare namespace FormDialog {
|
|
56
|
+
var displayName: string;
|
|
57
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { FileRejection, UseFileUploadProps } from "@seed-design/react-file-upload";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
export type { FileRejection };
|
|
4
|
+
export type ImportDialogStep = {
|
|
5
|
+
/** Stable id, compared against `activeStep`. */
|
|
6
|
+
id: string;
|
|
7
|
+
label: React.ReactNode;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Root props land on the DIALOG SURFACE — same convention as `Dialog`/
|
|
11
|
+
* `Drawer` (#223): the element a consumer actually wants to reach (for
|
|
12
|
+
* `aria-describedby`, a `data-testid`, a `style`) is the panel, not the
|
|
13
|
+
* portal wrapper.
|
|
14
|
+
*/
|
|
15
|
+
export type ImportDialogProps = Omit<React.ComponentPropsWithoutRef<"div">, "title" | "children"> & {
|
|
16
|
+
open: boolean;
|
|
17
|
+
onOpenChange: (open: boolean) => void;
|
|
18
|
+
/** Header title (default "Import"). */
|
|
19
|
+
title?: React.ReactNode;
|
|
20
|
+
/** The fixed step header — id + label pairs, in order. */
|
|
21
|
+
steps: ImportDialogStep[];
|
|
22
|
+
/** Which step's id is current — drives both the header pill and, when a
|
|
23
|
+
* consumer wires `onStepClick`, which row gets `aria-current`. */
|
|
24
|
+
activeStep: string;
|
|
25
|
+
/** Fired when an earlier step's pill is clicked. Omit to make the header
|
|
26
|
+
* display-only (Attio's own back-navigation between steps wasn't part of
|
|
27
|
+
* this measurement pass). */
|
|
28
|
+
onStepClick?: (id: string) => void;
|
|
29
|
+
/** The active step's body. */
|
|
30
|
+
children?: React.ReactNode;
|
|
31
|
+
/** Primary action label (e.g. "Next", "Import 40 rows"). Default "Next". */
|
|
32
|
+
primaryLabel?: React.ReactNode;
|
|
33
|
+
onPrimary?: () => void;
|
|
34
|
+
primaryDisabled?: boolean;
|
|
35
|
+
"aria-label"?: string;
|
|
36
|
+
/** aria-label on the close button (default "Close"). */
|
|
37
|
+
closeLabel?: string;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* A full-viewport step wizard — Attio's own CSV import flow (measured live:
|
|
41
|
+
* `1584x871` filling a ~1600x900 viewport, `border-radius: 0`, no shadow,
|
|
42
|
+
* opaque white). Composes Zag's dialog machine for focus-trap/scroll-lock/
|
|
43
|
+
* Escape exactly like `Dialog`/`Drawer`, with its own recipe for the
|
|
44
|
+
* full-bleed chrome neither of those two share (see importdialog.recipe.ts).
|
|
45
|
+
*
|
|
46
|
+
* The step header and footer are generic — the wizard doesn't know about
|
|
47
|
+
* CSV. Step 1's body is typically `ImportDialogDropzone`; steps 2-4
|
|
48
|
+
* (map columns / review values / preview import) are consumer-supplied
|
|
49
|
+
* `children`, since Attio's own column-mapping UI wasn't part of this
|
|
50
|
+
* measurement pass.
|
|
51
|
+
*/
|
|
52
|
+
export declare function ImportDialog({ open, onOpenChange, title, steps, activeStep, onStepClick, children, primaryLabel, onPrimary, primaryDisabled, "aria-label": ariaLabel, closeLabel: closeLabelProp, className, style, "aria-describedby": describedBy, ...rest }: ImportDialogProps): React.JSX.Element | null;
|
|
53
|
+
export declare namespace ImportDialog {
|
|
54
|
+
var displayName: string;
|
|
55
|
+
}
|
|
56
|
+
export type ImportDialogDropzoneProps = Omit<React.ComponentPropsWithoutRef<"div">, "children" | "onDrop"> & {
|
|
57
|
+
/** Accepted file type(s), e.g. ".csv" (the default) or "text/csv". */
|
|
58
|
+
accept?: UseFileUploadProps["accept"];
|
|
59
|
+
disabled?: boolean;
|
|
60
|
+
maxFileSize?: number;
|
|
61
|
+
/** Fired with the accepted file. One file per drop/pick — a CSV import
|
|
62
|
+
* has exactly one source file, unlike the generic `FileUpload` list. */
|
|
63
|
+
onFileAccept?: (file: File) => void;
|
|
64
|
+
onFileReject?: (rejections: FileRejection[]) => void;
|
|
65
|
+
dropLabel?: React.ReactNode;
|
|
66
|
+
orLabel?: React.ReactNode;
|
|
67
|
+
chooseLabel?: React.ReactNode;
|
|
68
|
+
learnMoreHref?: string;
|
|
69
|
+
learnMoreLabel?: React.ReactNode;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* The step-1 drop target — measured chrome (`border: 1px dashed
|
|
73
|
+
* rgb(230,231,234)`, `border-radius: 20px`, `background: rgb(251,251,251)`)
|
|
74
|
+
* over the SAME headless drag/drop + file-picker engine `FileUpload` uses
|
|
75
|
+
* (`@seed-design/react-file-upload`'s `useFileUpload`), rather than a fork
|
|
76
|
+
* of it. `FileUpload`'s own rendered markup (a single button carrying one
|
|
77
|
+
* title + one hint) can't host this dropzone's four separate pieces of copy
|
|
78
|
+
* — a title, an "or" divider, a "Choose a .CSV file" trigger, and a "Learn
|
|
79
|
+
* more" link that needs its own `<a href>` — so this composes the hook
|
|
80
|
+
* directly instead of wrapping `<FileUpload>`, and the engine (not this
|
|
81
|
+
* file) still owns every bit of drag-state/accept/reject behaviour.
|
|
82
|
+
*/
|
|
83
|
+
export declare function ImportDialogDropzone({ accept, disabled, maxFileSize, onFileAccept, onFileReject, dropLabel, orLabel, chooseLabel, learnMoreHref, learnMoreLabel, className, id, ...rest }: ImportDialogDropzoneProps): React.JSX.Element;
|
|
84
|
+
export declare namespace ImportDialogDropzone {
|
|
85
|
+
var displayName: string;
|
|
86
|
+
}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { type EmptyStateLearnMore } from "../../components/emptystate";
|
|
2
3
|
import type { EditableOption } from "./editable-field";
|
|
3
4
|
type IconType = React.ComponentType<{
|
|
4
5
|
size?: number;
|
|
5
6
|
strokeWidth?: number;
|
|
6
7
|
}>;
|
|
8
|
+
export declare function isLabelTruncated(el: {
|
|
9
|
+
scrollWidth: number;
|
|
10
|
+
clientWidth: number;
|
|
11
|
+
}): boolean;
|
|
7
12
|
export type ColumnType = "entity" | "text" | "tags" | "number" | "url" | "date" | "currency" | "status" | "reference";
|
|
8
13
|
export type StatusOption = {
|
|
9
14
|
value: string;
|
|
@@ -123,6 +128,20 @@ export type RecordsTableProps = Omit<React.ComponentPropsWithoutRef<"div">, "chi
|
|
|
123
128
|
* stable colour per name, matching what `DataTable`'s `avatarTone` offers).
|
|
124
129
|
* Entity avatars only — `TAG_TONES`/tag/status tone logic is untouched. */
|
|
125
130
|
avatarTone?: "brand" | "hashed";
|
|
131
|
+
/**
|
|
132
|
+
* #603: Attio's zero-*records* state (nothing imported yet, no active
|
|
133
|
+
* filter) adds an "Import CSV" / "Connect data source" pair and a
|
|
134
|
+
* "Learn more" card next to the usual "New record" action -- measured
|
|
135
|
+
* on Users/Workspaces, which show nothing else. Omit any of these and
|
|
136
|
+
* that piece is left out; omit the whole prop and the empty state is
|
|
137
|
+
* unchanged (just "New record"), since this hasn't been confirmed for
|
|
138
|
+
* every object type.
|
|
139
|
+
*/
|
|
140
|
+
emptyStateExtra?: {
|
|
141
|
+
onImportCsv?: () => void;
|
|
142
|
+
onConnectDataSource?: () => void;
|
|
143
|
+
learnMore?: EmptyStateLearnMore;
|
|
144
|
+
};
|
|
126
145
|
className?: string;
|
|
127
146
|
};
|
|
128
147
|
export declare function tagTone(t: string): string;
|
|
@@ -204,6 +223,9 @@ export type RecordsTableLabels = {
|
|
|
204
223
|
setRecordPlaceholder: string;
|
|
205
224
|
noRecords: string;
|
|
206
225
|
untitled: string;
|
|
226
|
+
/** #603: the zero-records state's optional extra CTAs. */
|
|
227
|
+
importCsv: string;
|
|
228
|
+
connectDataSource: string;
|
|
207
229
|
/** Aggregation names, keyed by the aggregation. */
|
|
208
230
|
agg: Record<Agg, string>;
|
|
209
231
|
/** Filter operator names, keyed by the operator. */
|
|
@@ -229,7 +251,7 @@ export type RecordsTableLabelsInput = Partial<Omit<RecordsTableLabels, "agg" | "
|
|
|
229
251
|
agg?: Partial<Record<Agg, string>>;
|
|
230
252
|
op?: Partial<Record<FilterOp, string>>;
|
|
231
253
|
};
|
|
232
|
-
type FilterOp = "contains" | "is" | "isnot" | "empty" | "notempty";
|
|
254
|
+
type FilterOp = "contains" | "doesnotcontain" | "startswith" | "endswith" | "is" | "isnot" | "empty" | "notempty";
|
|
233
255
|
/**
|
|
234
256
|
* A date-only cell is a CALENDAR DATE, not an instant. ECMA-262 parses the
|
|
235
257
|
* date-only ISO forms — `1998`, `1998-09`, `1998-09-04` — as UTC midnight, and
|
|
@@ -251,6 +273,6 @@ export { formatCellDate, parseCellDate };
|
|
|
251
273
|
* and a floating bulk-action bar (delete / deselect) when rows are selected.
|
|
252
274
|
* Selection can be controlled via `selectedIds`/`onSelectionChange`.
|
|
253
275
|
*/
|
|
254
|
-
export declare function RecordsTable({ labels, columns: columnsProp, rows: rowsProp, selectedIds, onSelectionChange, showNew, allowAddColumn, onOpenRecord, onOpenRecordPage, avatarTone, className, ...rest }: RecordsTableProps): React.JSX.Element;
|
|
276
|
+
export declare function RecordsTable({ labels, columns: columnsProp, rows: rowsProp, selectedIds, onSelectionChange, showNew, allowAddColumn, onOpenRecord, onOpenRecordPage, avatarTone, emptyStateExtra, className, ...rest }: RecordsTableProps): React.JSX.Element;
|
|
255
277
|
export declare const defaultColumns: Column[];
|
|
256
278
|
export declare const defaultRows: Row[];
|