@antscorp/ui 0.1.2 → 0.1.4
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 +26 -2
- package/dist/atoms/AddButton.d.ts +3 -6
- package/dist/atoms/Chip.d.ts +2 -5
- package/dist/atoms/Chip.js +1 -1
- package/dist/atoms/InfoTip.js +2 -0
- package/dist/atoms/LabeledDivider.d.ts +1 -1
- package/dist/atoms/PanelSearchInput.d.ts +1 -1
- package/dist/atoms/RemoveButton.d.ts +2 -5
- package/dist/atoms/TextAction.d.ts +5 -6
- package/dist/atoms/TruncatedOption.d.ts +1 -1
- package/dist/cli.js +248 -0
- package/dist/doc/schema.d.ts +34 -0
- package/dist/doc/schema.js +33 -0
- package/dist/docs.json +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +53 -51
- package/dist/lib/iso.d.ts +2 -2
- package/dist/lib/iso.js +16 -8
- package/dist/lib/tokenEditorExtensions.js +1 -1
- package/dist/lib/useLoadingShown.d.ts +1 -1
- package/dist/molecules/AccentCard.d.ts +2 -3
- package/dist/molecules/AccentCard.js +2 -2
- package/dist/molecules/CheckRow.d.ts +3 -8
- package/dist/molecules/ChoiceTiles.d.ts +1 -1
- package/dist/molecules/ChoiceTiles.js +1 -1
- package/dist/molecules/CommitTextField.d.ts +1 -19
- package/dist/molecules/CommitTextField.js +21 -18
- package/dist/molecules/ConfirmDialog.d.ts +2 -7
- package/dist/molecules/DateTimeInput.d.ts +6 -3
- package/dist/molecules/DateTimeInput.js +82 -73
- package/dist/molecules/FieldGroup.d.ts +1 -1
- package/dist/molecules/FieldRow.d.ts +1 -1
- package/dist/molecules/MetaTable.d.ts +1 -1
- package/dist/molecules/PhoneFrame.d.ts +1 -1
- package/dist/molecules/RemovableRow.d.ts +1 -1
- package/dist/molecules/RemovableRow.js +32 -32
- package/dist/molecules/RevealRadioGroup.d.ts +2 -9
- package/dist/molecules/RevealSwitch.d.ts +2 -7
- package/dist/molecules/Select.d.ts +8 -24
- package/dist/molecules/Select.js +50 -44
- package/dist/molecules/SideLabelRow.d.ts +1 -1
- package/dist/molecules/SplitButton.d.ts +1 -1
- package/dist/molecules/StatusButton.d.ts +2 -7
- package/dist/molecules/TagSelect.d.ts +2 -2
- package/dist/molecules/TransferLayout.d.ts +1 -1
- package/dist/molecules/TreeOptions.d.ts +4 -3
- package/dist/molecules/TreeOptions.js +67 -44
- package/dist/organisms/HourOfDayRow.js +2 -2
- package/dist/organisms/HourOfWeekGrid.js +2 -2
- package/dist/organisms/RuleGroups.d.ts +3 -3
- package/dist/organisms/SearchableGroupedList.d.ts +1 -1
- package/dist/organisms/TransferPicker.d.ts +1 -1
- package/dist/organisms/TreeSearchPanel.js +50 -47
- package/dist/organisms/TreeSelect.d.ts +3 -3
- package/dist/ui.css +1 -1
- package/package.json +36 -19
- package/src/atoms/AddButton.tsx +3 -7
- package/src/atoms/Chip.tsx +7 -9
- package/src/atoms/InfoTip.tsx +2 -2
- package/src/atoms/LabeledDivider.tsx +1 -1
- package/src/atoms/PanelSearchInput.tsx +1 -1
- package/src/atoms/RemoveButton.tsx +2 -6
- package/src/atoms/TextAction.tsx +6 -8
- package/src/atoms/TruncatedOption.tsx +1 -1
- package/src/doc/schema.ts +67 -0
- package/src/index.ts +2 -0
- package/src/lib/iso.ts +15 -3
- package/src/lib/tokenEditorExtensions.ts +1 -1
- package/src/lib/useLoadMore.ts +1 -2
- package/src/lib/useLoadingShown.ts +1 -1
- package/src/molecules/AccentCard.tsx +11 -10
- package/src/molecules/CheckRow.tsx +3 -9
- package/src/molecules/ChoiceTiles.tsx +6 -4
- package/src/molecules/CommitTextField.tsx +15 -20
- package/src/molecules/ConfirmDialog.tsx +2 -8
- package/src/molecules/DateTimeInput.tsx +86 -68
- package/src/molecules/DurationInput.tsx +2 -2
- package/src/molecules/FieldGroup.tsx +1 -1
- package/src/molecules/FieldRow.tsx +1 -1
- package/src/molecules/FrequencyLimitRow.tsx +1 -1
- package/src/molecules/MetaTable.tsx +1 -1
- package/src/molecules/PhoneFrame.tsx +2 -2
- package/src/molecules/RemovableRow.tsx +3 -3
- package/src/molecules/RevealRadioGroup.tsx +5 -10
- package/src/molecules/RevealSwitch.tsx +2 -8
- package/src/molecules/Select.tsx +23 -23
- package/src/molecules/SideLabelRow.tsx +2 -2
- package/src/molecules/SplitButton.tsx +1 -1
- package/src/molecules/StatusButton.tsx +2 -8
- package/src/molecules/TagSelect.tsx +5 -5
- package/src/molecules/TransferLayout.tsx +2 -3
- package/src/molecules/TreeOptions.tsx +89 -65
- package/src/organisms/HourOfDayRow.tsx +5 -3
- package/src/organisms/HourOfWeekGrid.tsx +5 -3
- package/src/organisms/RuleGroups.tsx +3 -3
- package/src/organisms/SearchableGroupedList.tsx +2 -2
- package/src/organisms/TransferPicker.tsx +3 -3
- package/src/organisms/TreeSearchPanel.tsx +2 -2
- package/src/organisms/TreeSelect.tsx +4 -4
package/package.json
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antscorp/ui",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Generic UI kit: atoms, molecules and organisms over Astryx
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "Generic UI kit: atoms, molecules and organisms over Astryx.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://bitbucket.org/git-vn/at.antsomi-ui.git",
|
|
9
9
|
"directory": "packages/ui"
|
|
10
10
|
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"antscorp-ui": "./dist/cli.js"
|
|
13
|
+
},
|
|
11
14
|
"files": [
|
|
12
15
|
"dist",
|
|
13
16
|
"src",
|
|
17
|
+
"!src/cli/**",
|
|
14
18
|
"!src/**/*.test.*",
|
|
15
19
|
"!src/**/*.stories.*",
|
|
20
|
+
"!src/**/*.doc.ts",
|
|
21
|
+
"!dist/**/*.doc.*",
|
|
16
22
|
"!src/**/__snapshots__/**",
|
|
17
23
|
"!src/testing.tsx",
|
|
18
24
|
"!src/story.tsx"
|
|
@@ -37,6 +43,11 @@
|
|
|
37
43
|
"types": "./dist/astryx/*.d.ts",
|
|
38
44
|
"default": "./dist/astryx/*.js"
|
|
39
45
|
},
|
|
46
|
+
"./doc": {
|
|
47
|
+
"antscorp-source": "./src/doc/schema.ts",
|
|
48
|
+
"types": "./dist/doc/schema.d.ts",
|
|
49
|
+
"default": "./dist/doc/schema.js"
|
|
50
|
+
},
|
|
40
51
|
"./stylex": {
|
|
41
52
|
"antscorp-source": "./src/stylex.ts",
|
|
42
53
|
"types": "./dist/stylex.d.ts",
|
|
@@ -88,38 +99,44 @@
|
|
|
88
99
|
"scripts": {
|
|
89
100
|
"astryx:reexports": "bun scripts/astryx-reexports.ts",
|
|
90
101
|
"test": "bun scripts/astryx-reexports.ts --check && vitest run && AUI_REACT_COMPILER=off vitest run --coverage",
|
|
102
|
+
"test:perf": "PERF=1 vitest run",
|
|
91
103
|
"typecheck": "tsc -p .",
|
|
92
|
-
"build": "vite build --config vite.build.ts && tsc -p tsconfig.build.json && bun scripts/build-declarations.ts"
|
|
104
|
+
"build": "vite build --config vite.build.ts && tsc -p tsconfig.build.json && bun scripts/build-declarations.ts && node ../../tools/component-catalog/src/main.ts . && bun build src/cli/main.ts --target=node --outfile=dist/cli.js"
|
|
93
105
|
},
|
|
94
106
|
"dependencies": {
|
|
95
|
-
"@antscorp/astryx-theme-antsomi": "0.1.
|
|
96
|
-
"@antscorp/immutable": "0.1.
|
|
107
|
+
"@antscorp/astryx-theme-antsomi": "0.1.4",
|
|
108
|
+
"@antscorp/immutable": "0.1.1",
|
|
97
109
|
"@astryxdesign/core": "0.7.4",
|
|
98
110
|
"@codemirror/state": "6.7.6",
|
|
99
|
-
"@codemirror/view": "6.43.
|
|
111
|
+
"@codemirror/view": "6.43.15",
|
|
100
112
|
"@stylexjs/stylex": "0.19.1",
|
|
101
|
-
"spin-delay": "2.0.1"
|
|
113
|
+
"spin-delay": "2.0.1",
|
|
114
|
+
"zod": "4.6.7"
|
|
102
115
|
},
|
|
103
116
|
"devDependencies": {
|
|
104
|
-
"@antscorp/
|
|
105
|
-
"@
|
|
117
|
+
"@antscorp/component-catalog": "0.1.0",
|
|
118
|
+
"@antscorp/vite-stylex": "0.1.4",
|
|
119
|
+
"@storybook/react-vite": "10.6.5",
|
|
106
120
|
"@testing-library/dom": "10.4.2",
|
|
107
121
|
"@testing-library/react": "16.3.3",
|
|
108
|
-
"@testing-library/user-event": "14.6.
|
|
122
|
+
"@testing-library/user-event": "14.6.8",
|
|
109
123
|
"@types/bun": "1.4.4",
|
|
110
|
-
"@types/node": "24.19.
|
|
124
|
+
"@types/node": "24.19.2",
|
|
111
125
|
"@types/react": "19.3.0",
|
|
112
126
|
"@types/react-dom": "19.3.0",
|
|
113
|
-
"@vitest/coverage-v8": "5.0.
|
|
127
|
+
"@vitest/coverage-v8": "5.0.5",
|
|
114
128
|
"happy-dom": "20.14.5",
|
|
115
|
-
"react": "19.3.
|
|
116
|
-
"react-dom": "19.3.
|
|
117
|
-
"storybook": "10.6.
|
|
118
|
-
"vite": "8.3.
|
|
119
|
-
"vitest": "5.0.
|
|
129
|
+
"react": "19.3.1",
|
|
130
|
+
"react-dom": "19.3.1",
|
|
131
|
+
"storybook": "10.6.5",
|
|
132
|
+
"vite": "8.3.5",
|
|
133
|
+
"vitest": "5.0.5"
|
|
120
134
|
},
|
|
121
135
|
"peerDependencies": {
|
|
122
|
-
"react": ">=19",
|
|
123
|
-
"react-dom": ">=19"
|
|
136
|
+
"react": ">=19.2",
|
|
137
|
+
"react-dom": ">=19.2"
|
|
138
|
+
},
|
|
139
|
+
"engines": {
|
|
140
|
+
"node": ">=24"
|
|
124
141
|
}
|
|
125
142
|
}
|
package/src/atoms/AddButton.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Button } from "@astryxdesign/core/Button";
|
|
1
|
+
import { Button, type ButtonProps } from "@astryxdesign/core/Button";
|
|
2
2
|
import { radiusVars } from "@astryxdesign/core/theme/tokens.stylex";
|
|
3
3
|
import * as stylex from "@stylexjs/stylex";
|
|
4
4
|
import type { ReactNode } from "react";
|
|
@@ -6,19 +6,15 @@ import type { ReactNode } from "react";
|
|
|
6
6
|
import { AddGlyph } from "./AddGlyph";
|
|
7
7
|
|
|
8
8
|
/** What `AddButton` takes. */
|
|
9
|
-
export type AddButtonProps = {
|
|
10
|
-
/** What it adds, such as "Add row"; the host translates it. */
|
|
11
|
-
readonly label: string;
|
|
9
|
+
export type AddButtonProps = Pick<ButtonProps, "label" | "isDisabled"> & {
|
|
12
10
|
/** `ghost` by default; `secondary` for an add that needs more weight. */
|
|
13
11
|
readonly variant?: "ghost" | "secondary" | undefined;
|
|
14
12
|
/** The button's height, `md` by default; its plus follows it. */
|
|
15
13
|
readonly size?: "sm" | "md" | undefined;
|
|
16
14
|
/** `default` keeps the button's own corners; `pill` rounds them fully; the theme colours its outline. */
|
|
17
15
|
readonly shape?: "default" | "pill" | undefined;
|
|
18
|
-
/** `sentence` (default) shows the label as given; `upper` in capitals, as
|
|
16
|
+
/** `sentence` (default) shows the label as given; `upper` in capitals, such as "+ AND". */
|
|
19
17
|
readonly case?: "sentence" | "upper" | undefined;
|
|
20
|
-
/** Dimmed and not pressable, e.g. when a limit is reached. */
|
|
21
|
-
readonly isDisabled?: boolean | undefined;
|
|
22
18
|
/** Read-only: an add is an editing affordance, so nothing is drawn. */
|
|
23
19
|
readonly isReadOnly?: boolean | undefined;
|
|
24
20
|
/** Called when the button is pressed. */
|
package/src/atoms/Chip.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AccentRole } from "@antscorp/astryx-theme-antsomi/palette";
|
|
1
2
|
import { HStack } from "@astryxdesign/core/HStack";
|
|
2
3
|
import { Icon } from "@astryxdesign/core/Icon";
|
|
3
4
|
import { IconButton } from "@astryxdesign/core/IconButton";
|
|
@@ -9,7 +10,7 @@ import {
|
|
|
9
10
|
spacingVars,
|
|
10
11
|
typeScaleVars,
|
|
11
12
|
} from "@astryxdesign/core/theme/tokens.stylex";
|
|
12
|
-
import { Token } from "@astryxdesign/core/Token";
|
|
13
|
+
import { Token, type TokenProps } from "@astryxdesign/core/Token";
|
|
13
14
|
import { Tooltip } from "@astryxdesign/core/Tooltip";
|
|
14
15
|
import * as stylex from "@stylexjs/stylex";
|
|
15
16
|
import type { ReactNode } from "react";
|
|
@@ -17,9 +18,7 @@ import type { ReactNode } from "react";
|
|
|
17
18
|
import { RemoveButton } from "./RemoveButton";
|
|
18
19
|
|
|
19
20
|
/** What `Chip` takes. */
|
|
20
|
-
export type ChipProps = {
|
|
21
|
-
/** The chip's text; cut short with an ellipsis past `maxWidth`, and shown whole in a tooltip. */
|
|
22
|
-
readonly label: string;
|
|
21
|
+
export type ChipProps = Pick<TokenProps, "label" | "isDisabled"> & {
|
|
23
22
|
/** `neutral` (default) is the plain grey chip; `accent` the pale accent one; `danger` a value no longer valid. */
|
|
24
23
|
readonly tone?: "neutral" | "accent" | "danger" | undefined;
|
|
25
24
|
/** The chip's height, `sm` or `md` (default), as the controls beside it. */
|
|
@@ -40,8 +39,6 @@ export type ChipProps = {
|
|
|
40
39
|
* button over its end; it stays in the tab order. Without it the button always shows after the text.
|
|
41
40
|
*/
|
|
42
41
|
readonly isRemoveOnHover?: boolean | undefined;
|
|
43
|
-
/** Dims the chip and blocks its remove button. */
|
|
44
|
-
readonly isDisabled?: boolean | undefined;
|
|
45
42
|
/** Read-only: no remove button. */
|
|
46
43
|
readonly isReadOnly?: boolean | undefined;
|
|
47
44
|
};
|
|
@@ -102,8 +99,9 @@ export function Chip(props: ChipProps): ReactNode {
|
|
|
102
99
|
// The remove button shows while the chip is hovered or has focus inside it.
|
|
103
100
|
const marker = stylex.defaultMarker();
|
|
104
101
|
|
|
102
|
+
const accentFill: AccentRole = "var(--ants-accent-fill)";
|
|
105
103
|
const styles = stylex.create({
|
|
106
|
-
//
|
|
104
|
+
// A pill as high as the controls, 10px either side (no
|
|
107
105
|
// spacing step is 10px), in 12px body text of the normal weight. An xstyle, not a `token` theme entry: Token is also
|
|
108
106
|
// drawn by ChipListAddPopover's unframed list in Astryx's own look, which a theme entry would change.
|
|
109
107
|
chip: {
|
|
@@ -117,10 +115,10 @@ const styles = stylex.create({
|
|
|
117
115
|
md: { height: sizeVars["--size-element-md"] },
|
|
118
116
|
// Not `color="blue"` with a theme entry, for the same reason.
|
|
119
117
|
accent: {
|
|
120
|
-
backgroundColor:
|
|
118
|
+
backgroundColor: accentFill,
|
|
121
119
|
color: colorVars["--color-text-primary"],
|
|
122
120
|
},
|
|
123
|
-
//
|
|
121
|
+
// A 16px white circle over the chip's end (Token's own remove button is 16px too).
|
|
124
122
|
hoverRemove: {
|
|
125
123
|
position: "absolute",
|
|
126
124
|
insetInlineEnd: spacingVars["--spacing-1"],
|
package/src/atoms/InfoTip.tsx
CHANGED
|
@@ -16,8 +16,8 @@ export type InfoTipProps = {
|
|
|
16
16
|
export function InfoTip({ label, tone = "info" }: InfoTipProps): ReactNode {
|
|
17
17
|
const isError = tone === "error";
|
|
18
18
|
return (
|
|
19
|
-
<Tooltip content={label}>
|
|
20
|
-
<Text as="span" color="accent" aria-label={label} xstyle={styles.info}>
|
|
19
|
+
<Tooltip content={label} focusTrigger="always">
|
|
20
|
+
<Text as="span" tabIndex={0} color="accent" aria-label={label} xstyle={styles.info}>
|
|
21
21
|
<Icon icon={isError ? "warning" : "info"} size="xsm" {...(isError && { color: "error" })} />
|
|
22
22
|
</Text>
|
|
23
23
|
</Tooltip>
|
|
@@ -7,7 +7,7 @@ import type { ReactNode } from "react";
|
|
|
7
7
|
export type LabeledDividerProps = {
|
|
8
8
|
/** The short word on the rule, such as "or"; it also names the separator. */
|
|
9
9
|
readonly label: string;
|
|
10
|
-
/** `sentence` (default) shows the word as given; `upper` in capitals, as
|
|
10
|
+
/** `sentence` (default) shows the word as given; `upper` in capitals, such as "OR". */
|
|
11
11
|
readonly case?: "sentence" | "upper" | undefined;
|
|
12
12
|
};
|
|
13
13
|
|
|
@@ -28,7 +28,7 @@ export type PanelSearchInputProps = {
|
|
|
28
28
|
/** The clear button's name, such as "Clear search"; it shows only an icon. */
|
|
29
29
|
readonly clear: string;
|
|
30
30
|
};
|
|
31
|
-
/** Where the magnifier sits: `start` (default) or `end`, after the clear button
|
|
31
|
+
/** Where the magnifier sits: `start` (default) or `end`, after the clear button. */
|
|
32
32
|
readonly iconPosition?: "start" | "end" | undefined;
|
|
33
33
|
/** The input element, to focus it (with `useFocusLater` in a pop-over, say). */
|
|
34
34
|
readonly ref?: Ref<HTMLInputElement> | undefined;
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import { Icon } from "@astryxdesign/core/Icon";
|
|
2
|
-
import { IconButton } from "@astryxdesign/core/IconButton";
|
|
2
|
+
import { IconButton, type IconButtonProps } from "@astryxdesign/core/IconButton";
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
4
|
|
|
5
5
|
/** What `RemoveButton` takes. */
|
|
6
|
-
export type RemoveButtonProps = {
|
|
7
|
-
/** What goes, such as "Remove row"; the button shows only an icon, so this is its name. */
|
|
8
|
-
readonly label: string;
|
|
6
|
+
export type RemoveButtonProps = Pick<IconButtonProps, "label" | "isDisabled"> & {
|
|
9
7
|
/** The button's height, `md` by default. */
|
|
10
8
|
readonly size?: "sm" | "md" | undefined;
|
|
11
|
-
/** Dimmed and not pressable. */
|
|
12
|
-
readonly isDisabled?: boolean | undefined;
|
|
13
9
|
/** Read-only: a remove is an editing affordance, so nothing is drawn. */
|
|
14
10
|
readonly isReadOnly?: boolean | undefined;
|
|
15
11
|
/** Called when the button is pressed. */
|
package/src/atoms/TextAction.tsx
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { Icon } from "@astryxdesign/core/Icon";
|
|
2
|
-
import { Link } from "@astryxdesign/core/Link";
|
|
2
|
+
import { Link, type LinkProps } from "@astryxdesign/core/Link";
|
|
3
3
|
import { spacingVars } from "@astryxdesign/core/theme/tokens.stylex";
|
|
4
4
|
import * as stylex from "@stylexjs/stylex";
|
|
5
5
|
import type { ReactNode } from "react";
|
|
6
6
|
|
|
7
7
|
/** What `TextAction` takes. */
|
|
8
|
-
export type TextActionProps = {
|
|
8
|
+
export type TextActionProps = Pick<LinkProps, "isDisabled"> & {
|
|
9
9
|
/** What it does, such as "Remove all"; shown in capitals by default, so pass it in normal case. */
|
|
10
10
|
readonly label: string;
|
|
11
11
|
/** A glyph before the text, in the text's colour, such as an Astryx `Icon` of a bin for a removal. */
|
|
12
12
|
readonly icon?: ReactNode;
|
|
13
|
-
/** `upper` (default) shows the label in capitals, as
|
|
13
|
+
/** `upper` (default) shows the label in capitals, such as "REMOVE ALL"; `sentence` as given. */
|
|
14
14
|
readonly case?: "upper" | "sentence" | undefined;
|
|
15
15
|
/**
|
|
16
16
|
* Called when it is pressed. Leave it out when a wrapper handles the presses, such as an Astryx
|
|
@@ -19,13 +19,11 @@ export type TextActionProps = {
|
|
|
19
19
|
readonly onClick?: (() => void) | undefined;
|
|
20
20
|
/** A down chevron after the text, for an action that opens a menu. */
|
|
21
21
|
readonly hasChevron?: boolean | undefined;
|
|
22
|
-
/** Dimmed and not pressable. */
|
|
23
|
-
readonly isDisabled?: boolean | undefined;
|
|
24
22
|
};
|
|
25
23
|
|
|
26
24
|
/**
|
|
27
|
-
* An action drawn as text alone: bold capitals in the accent, no frame, as
|
|
28
|
-
* and "CREATE NEW … ▾", or in sentence case with a glyph before it
|
|
25
|
+
* An action drawn as text alone: bold capitals in the accent, no frame, such as "REMOVE ALL"
|
|
26
|
+
* and "CREATE NEW … ▾", or in sentence case with a glyph before it
|
|
29
27
|
* (a bin, then "Remove"). An Astryx `Link` without an `href`, so a `<button>` in a link's look, with
|
|
30
28
|
* a down chevron after the text when it opens a menu; still a button without `onClick`, so it can
|
|
31
29
|
* be a `Popover`'s trigger. It holds no state.
|
|
@@ -54,7 +52,7 @@ export function TextAction({
|
|
|
54
52
|
}
|
|
55
53
|
|
|
56
54
|
const styles = stylex.create({
|
|
57
|
-
// Capitals are a look, not text, so translations stay in normal case.
|
|
55
|
+
// Capitals are a look, not text, so translations stay in normal case. Text actions have
|
|
58
56
|
// no underline, not even on hover (Astryx's Link adds one). The theme styles no link, so this
|
|
59
57
|
// sets what nothing else does.
|
|
60
58
|
action: { whiteSpace: "nowrap", textDecoration: "none" },
|
|
@@ -11,7 +11,7 @@ export type TruncatedOptionProps = {
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* A Selector option whose label ends in an ellipsis when it is wider than the pop-up, with the
|
|
14
|
-
* whole label in a tooltip on hover
|
|
14
|
+
* whole label in a tooltip on hover. Its icon and description show as the
|
|
15
15
|
* Selector's own option's. It holds no state.
|
|
16
16
|
*/
|
|
17
17
|
export function TruncatedOption({ option }: TruncatedOptionProps): ReactNode {
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
const text = z.string().trim().min(1);
|
|
4
|
+
|
|
5
|
+
/** Structured guidance beside a view; its props and examples come from TypeScript and stories. */
|
|
6
|
+
export const componentDocSchema = z.object({
|
|
7
|
+
category: z
|
|
8
|
+
.enum(["Inputs", "Selection", "Feedback", "Layout", "Data display", "Overlays", "Theme"])
|
|
9
|
+
.describe(
|
|
10
|
+
"The view's purpose: Inputs edits values; Selection chooses options; Feedback communicates status; Layout arranges content; Data display presents values; Overlays shows dialogs or panels; Theme provides visual tokens and icons.",
|
|
11
|
+
),
|
|
12
|
+
keywords: z.array(text).min(3).describe("At least three search terms for the view."),
|
|
13
|
+
related: z
|
|
14
|
+
.array(
|
|
15
|
+
z.object({
|
|
16
|
+
name: text.describe("A kit view or Astryx facade module, such as astryx/Badge."),
|
|
17
|
+
when: text.describe("When to choose this alternative."),
|
|
18
|
+
}),
|
|
19
|
+
)
|
|
20
|
+
.min(1)
|
|
21
|
+
.optional()
|
|
22
|
+
.describe(
|
|
23
|
+
"Alternatives, validated against public views and facade modules during docs generation.",
|
|
24
|
+
),
|
|
25
|
+
example: text
|
|
26
|
+
.optional()
|
|
27
|
+
.describe("The existing story export shown first, validated during docs generation."),
|
|
28
|
+
usage: z
|
|
29
|
+
.object({
|
|
30
|
+
description: text.describe("When and how to use the view."),
|
|
31
|
+
bestPractices: z
|
|
32
|
+
.array(
|
|
33
|
+
z.object({
|
|
34
|
+
guidance: z
|
|
35
|
+
.boolean()
|
|
36
|
+
.describe("True for a recommended practice; false for a practice to avoid."),
|
|
37
|
+
description: text.describe("The practice and its reason."),
|
|
38
|
+
}),
|
|
39
|
+
)
|
|
40
|
+
.min(2)
|
|
41
|
+
.refine(
|
|
42
|
+
(items) => items.some((item) => item.guidance) && items.some((item) => !item.guidance),
|
|
43
|
+
"Include a recommended practice and a practice to avoid.",
|
|
44
|
+
)
|
|
45
|
+
.describe("Recommended practices and practices to avoid."),
|
|
46
|
+
anatomy: z
|
|
47
|
+
.array(
|
|
48
|
+
z.object({
|
|
49
|
+
name: text.describe("The part's name."),
|
|
50
|
+
required: z.boolean().describe("Whether this part is always present."),
|
|
51
|
+
description: text.describe("The part's purpose and the condition when it appears."),
|
|
52
|
+
}),
|
|
53
|
+
)
|
|
54
|
+
.min(1)
|
|
55
|
+
.optional()
|
|
56
|
+
.describe("The view's visible and interactive parts."),
|
|
57
|
+
})
|
|
58
|
+
.describe("Usage, best practices and optional anatomy."),
|
|
59
|
+
accessibility: z
|
|
60
|
+
.array(text)
|
|
61
|
+
.min(1)
|
|
62
|
+
.optional()
|
|
63
|
+
.describe("Accessible naming and interaction guidance."),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
/** Authoring contract for a view's `<View>.doc.ts` export. */
|
|
67
|
+
export type ComponentDoc = z.input<typeof componentDocSchema>;
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export { PathMark, type PathMarkProps, useEnclosingPath } from "./atoms/PathMark
|
|
|
15
15
|
export { RowSkeletons, type RowSkeletonsProps } from "./atoms/RowSkeletons";
|
|
16
16
|
export { TextAction, type TextActionProps } from "./atoms/TextAction";
|
|
17
17
|
export { TruncatedText, type TruncatedTextProps } from "./atoms/TruncatedText";
|
|
18
|
+
export { TruncatedOption, type TruncatedOptionProps } from "./atoms/TruncatedOption";
|
|
18
19
|
export { AccentCard, type AccentCardProps } from "./molecules/AccentCard";
|
|
19
20
|
export { ChoiceDialog, type ChoiceDialogProps } from "./molecules/ChoiceDialog";
|
|
20
21
|
export { type ChoiceTile, ChoiceTiles, type ChoiceTilesProps } from "./molecules/ChoiceTiles";
|
|
@@ -117,3 +118,4 @@ export { HourOfDayRow, type HourOfDayRowProps } from "./organisms/HourOfDayRow";
|
|
|
117
118
|
export { HourOfWeekGrid, type HourOfWeekGridProps } from "./organisms/HourOfWeekGrid";
|
|
118
119
|
export { ResizableDrawer, type ResizableDrawerProps } from "./organisms/ResizableDrawer";
|
|
119
120
|
export { TreeSelect, type TreeSelectItem, type TreeSelectProps } from "./organisms/TreeSelect";
|
|
121
|
+
export { TreeSearchPanel, type TreeSearchPanelProps } from "./organisms/TreeSearchPanel";
|
package/src/lib/iso.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
createISOTimeString,
|
|
3
3
|
type ISODateString,
|
|
4
4
|
type ISOTimeString,
|
|
5
|
+
parseISO,
|
|
5
6
|
} from "@astryxdesign/core/utils";
|
|
6
7
|
|
|
7
8
|
// Astryx date and time inputs take a value only when it is a valid one; a draft's empty or broken
|
|
@@ -13,14 +14,25 @@ export function timeValue(time: string): { readonly value?: ISOTimeString } {
|
|
|
13
14
|
return value === null ? {} : { value };
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
const
|
|
17
|
+
const hasISODateShape = (value: string): value is ISODateString =>
|
|
18
|
+
/^\d{4}-\d{2}-\d{2}$/u.test(value);
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
function isISODate(value: string): value is ISODateString {
|
|
21
|
+
if (!hasISODateShape(value)) return false;
|
|
22
|
+
try {
|
|
23
|
+
parseISO(value);
|
|
24
|
+
return true;
|
|
25
|
+
} catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Spread into a date input: `{ value }` for a valid calendar date in `YYYY-MM-DD`, `{}` otherwise. */
|
|
19
31
|
export function dateValue(date: string): { readonly value?: ISODateString } {
|
|
20
32
|
return isISODate(date) ? { value: date } : {};
|
|
21
33
|
}
|
|
22
34
|
|
|
23
|
-
/** Spread into a date input: `{ min }`
|
|
35
|
+
/** Spread into a date input: `{ min }` for a valid calendar date in `YYYY-MM-DD`, `{}` otherwise. */
|
|
24
36
|
export function minDate(min: string | undefined): { readonly min?: ISODateString } {
|
|
25
37
|
return min !== undefined && isISODate(min) ? { min } : {};
|
|
26
38
|
}
|
|
@@ -255,7 +255,7 @@ const theme = EditorView.theme({
|
|
|
255
255
|
font: "inherit",
|
|
256
256
|
fontSize: "12px",
|
|
257
257
|
borderRadius: "50%",
|
|
258
|
-
color: "var(--
|
|
258
|
+
color: "var(--color-icon-accent)",
|
|
259
259
|
cursor: "pointer",
|
|
260
260
|
},
|
|
261
261
|
".cm-token:hover .cm-token-remove, .cm-token:focus-within .cm-token-remove": { opacity: "1" },
|
package/src/lib/useLoadMore.ts
CHANGED
|
@@ -14,8 +14,7 @@ export type LoadMoreOptions = {
|
|
|
14
14
|
readonly itemCount: number;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
//
|
|
18
|
-
// (UITargetUpdateSegment `index.jsx:719-728`).
|
|
17
|
+
// Load the next page 20px before the list's end so scrolling can continue without a pause.
|
|
19
18
|
const NEAR_END = "0px 0px 20px 0px";
|
|
20
19
|
|
|
21
20
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useSpinDelay } from "spin-delay";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* When a loading state shows, for every view of the kit
|
|
4
|
+
* When a loading state shows, for every view of the kit: only after the load has
|
|
5
5
|
* lasted `delay` ms, then for at least `minDuration` ms, so a fast load shows nothing and a slow
|
|
6
6
|
* one never flashes. `delay` matches the antsomi theme's skeleton `animationDelay`.
|
|
7
7
|
*/
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AccentRole } from "@antscorp/astryx-theme-antsomi/palette";
|
|
1
2
|
import { Card } from "@astryxdesign/core/Card";
|
|
2
3
|
import { HStack } from "@astryxdesign/core/HStack";
|
|
3
4
|
import { Icon } from "@astryxdesign/core/Icon";
|
|
@@ -39,9 +40,8 @@ export type AccentCardProps = {
|
|
|
39
40
|
readonly isDisabled?: boolean | undefined;
|
|
40
41
|
/**
|
|
41
42
|
* `stripe` (default): a grey border with an accent stripe down the start edge and a light
|
|
42
|
-
* header bar
|
|
43
|
-
* under a dark blue header bar with the title in white capitals and a white close cross
|
|
44
|
-
* fe-app's audience picker.
|
|
43
|
+
* header bar. `banner`: no border nor stripe but a soft shadow,
|
|
44
|
+
* under a dark blue header bar with the title in white capitals and a white close cross.
|
|
45
45
|
*/
|
|
46
46
|
readonly variant?: "stripe" | "banner" | undefined;
|
|
47
47
|
};
|
|
@@ -87,7 +87,7 @@ export function AccentCard(props: AccentCardProps): ReactNode {
|
|
|
87
87
|
<RemoveButton
|
|
88
88
|
label={close}
|
|
89
89
|
size="sm"
|
|
90
|
-
isDisabled={props.isDisabled}
|
|
90
|
+
isDisabled={props.isDisabled ?? false}
|
|
91
91
|
onClick={props.onClose}
|
|
92
92
|
/>
|
|
93
93
|
))}
|
|
@@ -102,8 +102,9 @@ export function AccentCard(props: AccentCardProps): ReactNode {
|
|
|
102
102
|
);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
const accentBanner: AccentRole = "var(--ants-accent-banner)";
|
|
105
106
|
const styles = stylex.create({
|
|
106
|
-
//
|
|
107
|
+
// A grey border and a
|
|
107
108
|
// 4px accent stripe at the start (no border token is 4px). A look of this card only, which no
|
|
108
109
|
// Card prop nor theme entry (it would paint every card) can express; `padding={0}` clears the rest.
|
|
109
110
|
card: {
|
|
@@ -111,19 +112,19 @@ const styles = stylex.create({
|
|
|
111
112
|
borderInlineStartWidth: 4,
|
|
112
113
|
borderInlineStartColor: colorVars["--color-accent"],
|
|
113
114
|
},
|
|
114
|
-
//
|
|
115
|
+
// The header bar: 10px above and below, between the spacing steps of 8px and 12px, and as
|
|
115
116
|
// high with the close button (sm) as without it.
|
|
116
117
|
header: {
|
|
117
118
|
paddingBlock: 10,
|
|
118
119
|
minHeight: `calc(${sizeVars["--size-element-sm"]} + ${spacingVars["--spacing-5"]})`,
|
|
119
120
|
backgroundColor: "var(--ants-mh-gray-75)",
|
|
120
121
|
},
|
|
121
|
-
//
|
|
122
|
-
// corners and a soft shadow (Astryx's low elevation, near
|
|
122
|
+
// The banner card: no border, square
|
|
123
|
+
// corners and a soft shadow (Astryx's low elevation, near a 0 1px 4px grey shadow).
|
|
123
124
|
bannerCard: { borderStyle: "none", borderRadius: 0 },
|
|
124
|
-
//
|
|
125
|
+
// White semibold capitals on the header blue, 10px 20px around.
|
|
125
126
|
banner: {
|
|
126
|
-
backgroundColor:
|
|
127
|
+
backgroundColor: accentBanner,
|
|
127
128
|
color: colorVars["--color-on-accent"],
|
|
128
129
|
textTransform: "uppercase",
|
|
129
130
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CheckboxInput } from "@astryxdesign/core/CheckboxInput";
|
|
1
|
+
import { CheckboxInput, type CheckboxInputProps } from "@astryxdesign/core/CheckboxInput";
|
|
2
2
|
import { HStack } from "@astryxdesign/core/HStack";
|
|
3
3
|
import { Text } from "@astryxdesign/core/Text";
|
|
4
4
|
import { sizeVars } from "@astryxdesign/core/theme/tokens.stylex";
|
|
@@ -10,9 +10,7 @@ import { HoverSwap } from "../atoms/HoverSwap";
|
|
|
10
10
|
import { TruncatedText } from "../atoms/TruncatedText";
|
|
11
11
|
|
|
12
12
|
/** What `CheckRow` takes. */
|
|
13
|
-
export type CheckRowProps = {
|
|
14
|
-
/** The row's text and the checkbox's name; one line, the whole text in a tooltip when cut. */
|
|
15
|
-
readonly label: string;
|
|
13
|
+
export type CheckRowProps = Pick<CheckboxInputProps, "label" | "isDisabled" | "isReadOnly"> & {
|
|
16
14
|
/** A second line under the text, such as an id under a name; one line too. */
|
|
17
15
|
readonly description?: string | undefined;
|
|
18
16
|
/** Whether the box is ticked. */
|
|
@@ -26,17 +24,13 @@ export type CheckRowProps = {
|
|
|
26
24
|
* link to the item; the two share one place, so nothing moves. None without it.
|
|
27
25
|
*/
|
|
28
26
|
readonly hoverContent?: ReactNode;
|
|
29
|
-
/** Dims the box and blocks it; nothing is hidden. */
|
|
30
|
-
readonly isDisabled?: boolean | undefined;
|
|
31
|
-
/** Shows the box's state, not dimmed, and blocks it. */
|
|
32
|
-
readonly isReadOnly?: boolean | undefined;
|
|
33
27
|
};
|
|
34
28
|
|
|
35
29
|
/**
|
|
36
30
|
* One row of a list to tick: a checkbox (md, as every checkbox), the row's text on one line (and
|
|
37
31
|
* an optional second line), and content at its end that `hoverContent` replaces while the row is
|
|
38
32
|
* hovered or focused. The box is the control and is named by the text; the text itself is not a
|
|
39
|
-
* click target
|
|
33
|
+
* click target. As high as a small control, so `RowSkeletons variant="check"`
|
|
40
34
|
* stands in for it without a shift. It holds no state.
|
|
41
35
|
*/
|
|
42
36
|
export function CheckRow(props: CheckRowProps): ReactNode {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AccentRole } from "@antscorp/astryx-theme-antsomi/palette";
|
|
1
2
|
import { Center } from "@astryxdesign/core/Center";
|
|
2
3
|
import { ClickableCard } from "@astryxdesign/core/ClickableCard";
|
|
3
4
|
import { HStack } from "@astryxdesign/core/HStack";
|
|
@@ -32,7 +33,7 @@ export type ChoiceTilesProps<V extends string> = {
|
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
|
-
* A choice among a few ways to go on
|
|
36
|
+
* A choice among a few ways to go on: a wrapping row of 180×170 cards, each
|
|
36
37
|
* a button with its glyph in a soft accent circle, a bold title and a description under it. A pick
|
|
37
38
|
* is an action, not a selected state: the host shows what follows instead. It holds no state.
|
|
38
39
|
*/
|
|
@@ -64,19 +65,20 @@ export function ChoiceTiles<V extends string>(props: ChoiceTilesProps<V>): React
|
|
|
64
65
|
);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
//
|
|
68
|
+
// A 150×130 tile at 12px text is too tight; 180×170 leaves room for a two-line description.
|
|
68
69
|
const TILE = { width: 180, height: 170 } as const;
|
|
69
70
|
|
|
71
|
+
const accentHover: AccentRole = "var(--ants-accent-hover)";
|
|
70
72
|
const styles = stylex.create({
|
|
71
73
|
// Text has no alignment prop: its lines centre under the glyph from here.
|
|
72
74
|
fill: { height: "100%", textAlign: "center" },
|
|
73
|
-
//
|
|
75
|
+
// A 50px circle in the accent's lightest tint, the glyph in the accent.
|
|
74
76
|
circle: {
|
|
75
77
|
flexShrink: 0,
|
|
76
78
|
width: 50,
|
|
77
79
|
height: 50,
|
|
78
80
|
borderRadius: "50%",
|
|
79
|
-
backgroundColor:
|
|
81
|
+
backgroundColor: accentHover,
|
|
80
82
|
color: colorVars["--color-accent"],
|
|
81
83
|
},
|
|
82
84
|
});
|