@antscorp/ui 0.1.3 → 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.
Files changed (179) hide show
  1. package/README.md +25 -1
  2. package/dist/atoms/AddButton.d.ts +2 -5
  3. package/dist/atoms/Chip.d.ts +2 -5
  4. package/dist/atoms/Chip.js +1 -1
  5. package/dist/atoms/RemoveButton.d.ts +2 -5
  6. package/dist/atoms/TextAction.d.ts +2 -3
  7. package/dist/docs.json +1 -1
  8. package/dist/lib/iso.d.ts +2 -2
  9. package/dist/lib/iso.js +16 -8
  10. package/dist/lib/tokenEditorExtensions.js +1 -1
  11. package/dist/molecules/AccentCard.js +2 -2
  12. package/dist/molecules/CheckRow.d.ts +2 -7
  13. package/dist/molecules/ChoiceTiles.js +1 -1
  14. package/dist/molecules/CommitTextField.d.ts +1 -19
  15. package/dist/molecules/CommitTextField.js +21 -18
  16. package/dist/molecules/ConfirmDialog.d.ts +2 -7
  17. package/dist/molecules/DateTimeInput.d.ts +6 -3
  18. package/dist/molecules/DateTimeInput.js +82 -73
  19. package/dist/molecules/RemovableRow.js +32 -32
  20. package/dist/molecules/RevealRadioGroup.d.ts +2 -9
  21. package/dist/molecules/RevealSwitch.d.ts +2 -7
  22. package/dist/molecules/Select.d.ts +7 -23
  23. package/dist/molecules/Select.js +26 -20
  24. package/dist/molecules/StatusButton.d.ts +2 -7
  25. package/dist/molecules/TreeOptions.d.ts +3 -2
  26. package/dist/molecules/TreeOptions.js +67 -44
  27. package/dist/organisms/HourOfDayRow.js +2 -2
  28. package/dist/organisms/HourOfWeekGrid.js +2 -2
  29. package/dist/organisms/TreeSearchPanel.js +50 -47
  30. package/dist/ui.css +1 -1
  31. package/package.json +23 -17
  32. package/src/atoms/AddButton.tsx +2 -6
  33. package/src/atoms/Chip.tsx +5 -7
  34. package/src/atoms/RemoveButton.tsx +2 -6
  35. package/src/atoms/TextAction.tsx +2 -4
  36. package/src/lib/iso.ts +15 -3
  37. package/src/lib/tokenEditorExtensions.ts +1 -1
  38. package/src/molecules/AccentCard.tsx +4 -2
  39. package/src/molecules/CheckRow.tsx +2 -8
  40. package/src/molecules/ChoiceTiles.tsx +3 -1
  41. package/src/molecules/CommitTextField.tsx +15 -20
  42. package/src/molecules/ConfirmDialog.tsx +2 -8
  43. package/src/molecules/DateTimeInput.tsx +86 -68
  44. package/src/molecules/RemovableRow.tsx +1 -1
  45. package/src/molecules/RevealRadioGroup.tsx +5 -10
  46. package/src/molecules/RevealSwitch.tsx +2 -8
  47. package/src/molecules/Select.tsx +22 -22
  48. package/src/molecules/StatusButton.tsx +2 -8
  49. package/src/molecules/TreeOptions.tsx +86 -62
  50. package/src/organisms/HourOfDayRow.tsx +4 -2
  51. package/src/organisms/HourOfWeekGrid.tsx +4 -2
  52. package/src/organisms/TreeSearchPanel.tsx +1 -1
  53. package/dist/atoms/AddButton.doc.d.ts +0 -21
  54. package/dist/atoms/AddGlyph.doc.d.ts +0 -16
  55. package/dist/atoms/Chip.doc.d.ts +0 -29
  56. package/dist/atoms/ChipSkeletons.doc.d.ts +0 -21
  57. package/dist/atoms/FieldHeading.doc.d.ts +0 -15
  58. package/dist/atoms/HoverSwap.doc.d.ts +0 -25
  59. package/dist/atoms/InfoTip.doc.d.ts +0 -25
  60. package/dist/atoms/JointLabel.doc.d.ts +0 -15
  61. package/dist/atoms/LabeledDivider.doc.d.ts +0 -21
  62. package/dist/atoms/LogoImage.doc.d.ts +0 -21
  63. package/dist/atoms/PanelSearchInput.doc.d.ts +0 -25
  64. package/dist/atoms/PathMark.doc.d.ts +0 -16
  65. package/dist/atoms/RemoveButton.doc.d.ts +0 -16
  66. package/dist/atoms/RowSkeletons.doc.d.ts +0 -25
  67. package/dist/atoms/TextAction.doc.d.ts +0 -25
  68. package/dist/atoms/TruncatedOption.doc.d.ts +0 -24
  69. package/dist/atoms/TruncatedText.doc.d.ts +0 -15
  70. package/dist/molecules/AccentCard.doc.d.ts +0 -25
  71. package/dist/molecules/CheckGroup.doc.d.ts +0 -25
  72. package/dist/molecules/CheckRow.doc.d.ts +0 -25
  73. package/dist/molecules/ChoiceDialog.doc.d.ts +0 -21
  74. package/dist/molecules/ChoiceTiles.doc.d.ts +0 -21
  75. package/dist/molecules/CommitTextField.doc.d.ts +0 -29
  76. package/dist/molecules/ConfirmDialog.doc.d.ts +0 -21
  77. package/dist/molecules/DateTimeInput.doc.d.ts +0 -25
  78. package/dist/molecules/DurationInput.doc.d.ts +0 -25
  79. package/dist/molecules/FieldGroup.doc.d.ts +0 -25
  80. package/dist/molecules/FieldRow.doc.d.ts +0 -24
  81. package/dist/molecules/FieldSkeleton.doc.d.ts +0 -25
  82. package/dist/molecules/FrequencyLimitRow.doc.d.ts +0 -25
  83. package/dist/molecules/InlineEditableText.doc.d.ts +0 -25
  84. package/dist/molecules/LoadMoreRow.doc.d.ts +0 -21
  85. package/dist/molecules/LoadState.doc.d.ts +0 -21
  86. package/dist/molecules/MetaTable.doc.d.ts +0 -25
  87. package/dist/molecules/PercentRow.doc.d.ts +0 -25
  88. package/dist/molecules/PhoneFrame.doc.d.ts +0 -21
  89. package/dist/molecules/ProblemsButton.doc.d.ts +0 -25
  90. package/dist/molecules/RemovableRow.doc.d.ts +0 -25
  91. package/dist/molecules/RevealRadioGroup.doc.d.ts +0 -25
  92. package/dist/molecules/RevealSwitch.doc.d.ts +0 -25
  93. package/dist/molecules/RuleRow.doc.d.ts +0 -25
  94. package/dist/molecules/Select.doc.d.ts +0 -30
  95. package/dist/molecules/SideLabelRow.doc.d.ts +0 -20
  96. package/dist/molecules/SplitButton.doc.d.ts +0 -25
  97. package/dist/molecules/StatusButton.doc.d.ts +0 -25
  98. package/dist/molecules/TagSelect.doc.d.ts +0 -25
  99. package/dist/molecules/ToggleGrid.doc.d.ts +0 -25
  100. package/dist/molecules/TokenTextField.doc.d.ts +0 -29
  101. package/dist/molecules/TransferLayout.doc.d.ts +0 -25
  102. package/dist/molecules/TreeOptions.doc.d.ts +0 -25
  103. package/dist/organisms/ChipListAddPopover.doc.d.ts +0 -25
  104. package/dist/organisms/HourOfDayRow.doc.d.ts +0 -25
  105. package/dist/organisms/HourOfWeekGrid.doc.d.ts +0 -25
  106. package/dist/organisms/RepeatableList.doc.d.ts +0 -21
  107. package/dist/organisms/ResizableDrawer.doc.d.ts +0 -25
  108. package/dist/organisms/RuleGroups.doc.d.ts +0 -21
  109. package/dist/organisms/RuleList.doc.d.ts +0 -25
  110. package/dist/organisms/SearchableGroupedList.doc.d.ts +0 -25
  111. package/dist/organisms/TokenPickerDialog.doc.d.ts +0 -21
  112. package/dist/organisms/TransferPicker.doc.d.ts +0 -29
  113. package/dist/organisms/TreeSearchPanel.doc.d.ts +0 -25
  114. package/dist/organisms/TreeSelect.doc.d.ts +0 -29
  115. package/dist/theme/AntsomiTheme.doc.d.ts +0 -15
  116. package/dist/theme/AntsomiTheme.doc.js +0 -22
  117. package/src/atoms/AddButton.doc.ts +0 -36
  118. package/src/atoms/AddGlyph.doc.ts +0 -26
  119. package/src/atoms/Chip.doc.ts +0 -45
  120. package/src/atoms/ChipSkeletons.doc.ts +0 -31
  121. package/src/atoms/FieldHeading.doc.ts +0 -22
  122. package/src/atoms/HoverSwap.doc.ts +0 -39
  123. package/src/atoms/InfoTip.doc.ts +0 -37
  124. package/src/atoms/JointLabel.doc.ts +0 -23
  125. package/src/atoms/LabeledDivider.doc.ts +0 -35
  126. package/src/atoms/LogoImage.doc.ts +0 -42
  127. package/src/atoms/PanelSearchInput.doc.ts +0 -41
  128. package/src/atoms/PathMark.doc.ts +0 -25
  129. package/src/atoms/RemoveButton.doc.ts +0 -26
  130. package/src/atoms/RowSkeletons.doc.ts +0 -43
  131. package/src/atoms/TextAction.doc.ts +0 -40
  132. package/src/atoms/TruncatedOption.doc.ts +0 -39
  133. package/src/atoms/TruncatedText.doc.ts +0 -22
  134. package/src/molecules/AccentCard.doc.ts +0 -43
  135. package/src/molecules/CheckGroup.doc.ts +0 -40
  136. package/src/molecules/CheckRow.doc.ts +0 -43
  137. package/src/molecules/ChoiceDialog.doc.ts +0 -48
  138. package/src/molecules/ChoiceTiles.doc.ts +0 -42
  139. package/src/molecules/CommitTextField.doc.ts +0 -41
  140. package/src/molecules/ConfirmDialog.doc.ts +0 -43
  141. package/src/molecules/DateTimeInput.doc.ts +0 -48
  142. package/src/molecules/DurationInput.doc.ts +0 -36
  143. package/src/molecules/FieldGroup.doc.ts +0 -41
  144. package/src/molecules/FieldRow.doc.ts +0 -36
  145. package/src/molecules/FieldSkeleton.doc.ts +0 -38
  146. package/src/molecules/FrequencyLimitRow.doc.ts +0 -48
  147. package/src/molecules/InlineEditableText.doc.ts +0 -41
  148. package/src/molecules/LoadMoreRow.doc.ts +0 -36
  149. package/src/molecules/LoadState.doc.ts +0 -42
  150. package/src/molecules/MetaTable.doc.ts +0 -46
  151. package/src/molecules/PercentRow.doc.ts +0 -48
  152. package/src/molecules/PhoneFrame.doc.ts +0 -46
  153. package/src/molecules/ProblemsButton.doc.ts +0 -41
  154. package/src/molecules/RemovableRow.doc.ts +0 -48
  155. package/src/molecules/RevealRadioGroup.doc.ts +0 -41
  156. package/src/molecules/RevealSwitch.doc.ts +0 -38
  157. package/src/molecules/RuleRow.doc.ts +0 -43
  158. package/src/molecules/Select.doc.ts +0 -62
  159. package/src/molecules/SideLabelRow.doc.ts +0 -35
  160. package/src/molecules/SplitButton.doc.ts +0 -41
  161. package/src/molecules/StatusButton.doc.ts +0 -39
  162. package/src/molecules/TagSelect.doc.ts +0 -41
  163. package/src/molecules/ToggleGrid.doc.ts +0 -43
  164. package/src/molecules/TokenTextField.doc.ts +0 -41
  165. package/src/molecules/TransferLayout.doc.ts +0 -42
  166. package/src/molecules/TreeOptions.doc.ts +0 -38
  167. package/src/organisms/ChipListAddPopover.doc.ts +0 -54
  168. package/src/organisms/HourOfDayRow.doc.ts +0 -43
  169. package/src/organisms/HourOfWeekGrid.doc.ts +0 -48
  170. package/src/organisms/RepeatableList.doc.ts +0 -49
  171. package/src/organisms/ResizableDrawer.doc.ts +0 -48
  172. package/src/organisms/RuleGroups.doc.ts +0 -49
  173. package/src/organisms/RuleList.doc.ts +0 -43
  174. package/src/organisms/SearchableGroupedList.doc.ts +0 -49
  175. package/src/organisms/TokenPickerDialog.doc.ts +0 -54
  176. package/src/organisms/TransferPicker.doc.ts +0 -69
  177. package/src/organisms/TreeSearchPanel.doc.ts +0 -43
  178. package/src/organisms/TreeSelect.doc.ts +0 -56
  179. package/src/theme/AntsomiTheme.doc.ts +0 -23
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antscorp/ui",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Generic UI kit: atoms, molecules and organisms over Astryx.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -17,6 +17,8 @@
17
17
  "!src/cli/**",
18
18
  "!src/**/*.test.*",
19
19
  "!src/**/*.stories.*",
20
+ "!src/**/*.doc.ts",
21
+ "!dist/**/*.doc.*",
20
22
  "!src/**/__snapshots__/**",
21
23
  "!src/testing.tsx",
22
24
  "!src/story.tsx"
@@ -97,40 +99,44 @@
97
99
  "scripts": {
98
100
  "astryx:reexports": "bun scripts/astryx-reexports.ts",
99
101
  "test": "bun scripts/astryx-reexports.ts --check && vitest run && AUI_REACT_COMPILER=off vitest run --coverage",
102
+ "test:perf": "PERF=1 vitest run",
100
103
  "typecheck": "tsc -p .",
101
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"
102
105
  },
103
106
  "dependencies": {
104
- "@antscorp/astryx-theme-antsomi": "0.1.3",
105
- "@antscorp/immutable": "0.1.0",
107
+ "@antscorp/astryx-theme-antsomi": "0.1.4",
108
+ "@antscorp/immutable": "0.1.1",
106
109
  "@astryxdesign/core": "0.7.4",
107
110
  "@codemirror/state": "6.7.6",
108
- "@codemirror/view": "6.43.14",
111
+ "@codemirror/view": "6.43.15",
109
112
  "@stylexjs/stylex": "0.19.1",
110
113
  "spin-delay": "2.0.1",
111
- "zod": "4.6.5"
114
+ "zod": "4.6.7"
112
115
  },
113
116
  "devDependencies": {
114
117
  "@antscorp/component-catalog": "0.1.0",
115
- "@antscorp/vite-stylex": "0.1.3",
116
- "@storybook/react-vite": "10.6.1",
118
+ "@antscorp/vite-stylex": "0.1.4",
119
+ "@storybook/react-vite": "10.6.5",
117
120
  "@testing-library/dom": "10.4.2",
118
121
  "@testing-library/react": "16.3.3",
119
- "@testing-library/user-event": "14.6.7",
122
+ "@testing-library/user-event": "14.6.8",
120
123
  "@types/bun": "1.4.4",
121
- "@types/node": "24.19.1",
124
+ "@types/node": "24.19.2",
122
125
  "@types/react": "19.3.0",
123
126
  "@types/react-dom": "19.3.0",
124
- "@vitest/coverage-v8": "5.0.3",
127
+ "@vitest/coverage-v8": "5.0.5",
125
128
  "happy-dom": "20.14.5",
126
- "react": "19.3.0",
127
- "react-dom": "19.3.0",
128
- "storybook": "10.6.1",
129
- "vite": "8.3.3",
130
- "vitest": "5.0.3"
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"
131
134
  },
132
135
  "peerDependencies": {
133
- "react": ">=19",
134
- "react-dom": ">=19"
136
+ "react": ">=19.2",
137
+ "react-dom": ">=19.2"
138
+ },
139
+ "engines": {
140
+ "node": ">=24"
135
141
  }
136
142
  }
@@ -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,9 +6,7 @@ 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. */
@@ -17,8 +15,6 @@ export type AddButtonProps = {
17
15
  readonly shape?: "default" | "pill" | undefined;
18
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. */
@@ -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,6 +99,7 @@ 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
@@ -117,7 +115,7 @@ 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: "var(--ants-mh-blue-200)",
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).
@@ -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. */
@@ -1,11 +1,11 @@
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. */
@@ -19,8 +19,6 @@ 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
  /**
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 isISODate = (value: string): value is ISODateString => /^\d{4}-\d{2}-\d{2}$/u.test(value);
17
+ const hasISODateShape = (value: string): value is ISODateString =>
18
+ /^\d{4}-\d{2}-\d{2}$/u.test(value);
17
19
 
18
- /** Spread into a date input: `{ value }` when `date` is `YYYY-MM-DD`, `{}` otherwise. */
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 }` when `min` is `YYYY-MM-DD`, `{}` otherwise. */
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(--ants-mh-blue-700)",
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" },
@@ -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";
@@ -86,7 +87,7 @@ export function AccentCard(props: AccentCardProps): ReactNode {
86
87
  <RemoveButton
87
88
  label={close}
88
89
  size="sm"
89
- isDisabled={props.isDisabled}
90
+ isDisabled={props.isDisabled ?? false}
90
91
  onClick={props.onClose}
91
92
  />
92
93
  ))}
@@ -101,6 +102,7 @@ export function AccentCard(props: AccentCardProps): ReactNode {
101
102
  );
102
103
  }
103
104
 
105
+ const accentBanner: AccentRole = "var(--ants-accent-banner)";
104
106
  const styles = stylex.create({
105
107
  // A grey border and a
106
108
  // 4px accent stripe at the start (no border token is 4px). A look of this card only, which no
@@ -122,7 +124,7 @@ const styles = stylex.create({
122
124
  bannerCard: { borderStyle: "none", borderRadius: 0 },
123
125
  // White semibold capitals on the header blue, 10px 20px around.
124
126
  banner: {
125
- backgroundColor: "var(--ants-mh-blue-750)",
127
+ backgroundColor: accentBanner,
126
128
  color: colorVars["--color-on-accent"],
127
129
  textTransform: "uppercase",
128
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,10 +24,6 @@ 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
  /**
@@ -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";
@@ -67,6 +68,7 @@ export function ChoiceTiles<V extends string>(props: ChoiceTilesProps<V>): React
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" },
@@ -76,7 +78,7 @@ const styles = stylex.create({
76
78
  width: 50,
77
79
  height: 50,
78
80
  borderRadius: "50%",
79
- backgroundColor: "var(--ants-mh-blue-50)",
81
+ backgroundColor: accentHover,
80
82
  color: colorVars["--color-accent"],
81
83
  },
82
84
  });
@@ -7,33 +7,31 @@ import { fitToMaxLength } from "../lib/fitToMaxLength";
7
7
  import { useDraft } from "../lib/useDraft";
8
8
 
9
9
  /** What `CommitTextField` takes. */
10
- export type CommitTextFieldProps = {
11
- /** The field's label; also its accessible name when hidden. */
12
- readonly label: string;
10
+ export type CommitTextFieldProps = Pick<
11
+ TextInputProps,
12
+ | "label"
13
+ | "isDisabled"
14
+ | "isReadOnly"
15
+ | "isLabelHidden"
16
+ | "placeholder"
17
+ | "description"
18
+ | "isRequired"
19
+ | "width"
20
+ | "controlXstyle"
21
+ | "containerXstyle"
22
+ > & {
13
23
  /** The committed text. A new value from outside (an agent, undo) replaces the draft. */
14
24
  readonly value: string;
15
25
  /** Called with the draft on blur or Enter, only when it differs from `value`. */
16
26
  readonly onCommit: (value: string) => void;
17
27
  /** The input's height, `md` by default. */
18
28
  readonly size?: "sm" | "md";
19
- /** Dims the field and blocks typing. */
20
- readonly isDisabled?: boolean;
21
- /** Shows the text, not dimmed, and blocks typing. */
22
- readonly isReadOnly?: boolean;
23
- /** Keeps the label for screen readers only. */
24
- readonly isLabelHidden?: boolean;
25
- /** Shown while the field is empty. */
26
- readonly placeholder?: string;
27
- /** Help under the label. */
28
- readonly description?: string;
29
29
  /** A problem with the value, already in the user's language. */
30
30
  readonly error?: string | undefined;
31
31
  /** A text area instead of a single line; Enter then adds a line. */
32
32
  readonly isMultiline?: boolean;
33
33
  /** For `isMultiline`: how many rows the text area shows, `4` by default. */
34
34
  readonly rows?: number;
35
- /** Marks the field as required. */
36
- readonly isRequired?: boolean;
37
35
  /**
38
36
  * `false` (default): after a commit the draft goes back to `value`, so a refused text does not
39
37
  * stay in the field. `true` keeps the typed text until `value` changes from outside.
@@ -43,10 +41,6 @@ export type CommitTextFieldProps = {
43
41
  readonly maxLength?: number;
44
42
  /** Fresh global pattern for whole tokens, counted as one character even in plain text. */
45
43
  readonly pattern?: () => RegExp;
46
- /** For a single line: the field's width, in pixels or any CSS length such as `"100%"`. */
47
- readonly width?: number | string;
48
- /** For a single line: StyleX styles for the input's box, e.g. to make it read as plain text. */
49
- readonly controlXstyle?: TextInputProps["controlXstyle"];
50
44
  };
51
45
 
52
46
  /**
@@ -86,6 +80,8 @@ export function CommitTextField(props: CommitTextFieldProps): ReactNode {
86
80
  isRequired: props.isRequired ?? false,
87
81
  ...(props.placeholder === undefined ? {} : { placeholder: props.placeholder }),
88
82
  ...(props.description === undefined ? {} : { description: props.description }),
83
+ ...(props.controlXstyle === undefined ? {} : { controlXstyle: props.controlXstyle }),
84
+ ...(props.containerXstyle === undefined ? {} : { containerXstyle: props.containerXstyle }),
89
85
  ...errorStatus(error),
90
86
  };
91
87
  if (isMultiline) return <TextArea {...common} rows={props.rows ?? 4} />;
@@ -94,7 +90,6 @@ export function CommitTextField(props: CommitTextFieldProps): ReactNode {
94
90
  {...common}
95
91
  onEnter={commitAndReset}
96
92
  {...(props.width === undefined ? {} : { width: props.width })}
97
- {...(props.controlXstyle === undefined ? {} : { controlXstyle: props.controlXstyle })}
98
93
  />
99
94
  );
100
95
  }
@@ -1,14 +1,8 @@
1
- import { AlertDialog } from "@astryxdesign/core/AlertDialog";
1
+ import { AlertDialog, type AlertDialogProps } from "@astryxdesign/core/AlertDialog";
2
2
  import type { ReactNode } from "react";
3
3
 
4
4
  /** What `ConfirmDialog` takes. */
5
- export type ConfirmDialogProps = {
6
- /** Open while a change waits for an answer. */
7
- readonly isOpen: boolean;
8
- /** The question, e.g. "Remove these rows?". */
9
- readonly title: string;
10
- /** What the change does. */
11
- readonly description: string;
5
+ export type ConfirmDialogProps = Pick<AlertDialogProps, "isOpen" | "title" | "description"> & {
12
6
  /** The texts of the two buttons; the host translates them. */
13
7
  readonly labels: {
14
8
  /** The confirming button, e.g. "Remove". */
@@ -1,7 +1,8 @@
1
1
  import { DateInput } from "@astryxdesign/core/DateInput";
2
2
  import { HStack } from "@astryxdesign/core/HStack";
3
3
  import { Text } from "@astryxdesign/core/Text";
4
- import { TimeInput } from "@astryxdesign/core/TimeInput";
4
+ import { TextInput } from "@astryxdesign/core/TextInput";
5
+ import { TimeInput, type TimeInputProps } from "@astryxdesign/core/TimeInput";
5
6
  import type { ReactNode } from "react";
6
7
 
7
8
  import { errorStatus } from "../lib/errorStatus";
@@ -9,93 +10,105 @@ import { dateValue, minDate, timeValue } from "../lib/iso";
9
10
  import { FieldGroup, type FieldGroupProps } from "./FieldGroup";
10
11
 
11
12
  /** What `DateTimeInput` takes. */
12
- export type DateTimeInputProps = Pick<FieldGroupProps, "isDisabled"> & {
13
- /** The group's label, e.g. "Start date"; it names the group and is not shown. */
14
- readonly label: string;
15
- /** The texts the inputs show; the host translates them. */
16
- readonly labels: {
17
- /** The date input's label: its accessible name in a group, shown with `frame="none"`. */
18
- readonly date: string;
19
- /** The time input's label: its accessible name in a group, shown with `frame="none"`. */
20
- readonly time: string;
21
- /** A time zone, or any note, shown beside the time. */
22
- readonly timezone?: string | undefined;
13
+ export type DateTimeInputProps = Pick<FieldGroupProps, "isDisabled"> &
14
+ Pick<TimeInputProps, "hourFormat"> & {
15
+ /** The group's label, e.g. "Start date"; it names the group and is not shown. */
16
+ readonly label: string;
17
+ /** The texts the inputs show; the host translates them. */
18
+ readonly labels: {
19
+ /** The date input's label: its accessible name in a group, shown with `frame="none"`. */
20
+ readonly date: string;
21
+ /** The time input's label: its accessible name in a group, shown with `frame="none"`. */
22
+ readonly time: string;
23
+ /** A time zone, or any note, shown beside the time. */
24
+ readonly timezone?: string | undefined;
25
+ };
26
+ /** The local date-time (`YYYY-MM-DD HH:mm:ss`); empty or partial while it is being filled in. */
27
+ readonly value: string;
28
+ /** The inputs' size, `md` by default. */
29
+ readonly size?: "sm" | "md" | undefined;
30
+ /** Shows readable date and time fields at full opacity, without clear or picker actions. */
31
+ readonly isReadOnly?: boolean | undefined;
32
+ /** A problem with the date-time, already in the user's language. */
33
+ readonly error?: string | undefined;
34
+ /** `false` picks a date only: the time input is left out and `onChange` gets `YYYY-MM-DD`, or empty. */
35
+ readonly hasTime?: boolean;
36
+ /**
37
+ * `bare` (default) puts both inputs, with hidden labels, in an unframed group that `label` names
38
+ * for assistive tech, for a host that shows the label itself. `none` draws no group: it shows
39
+ * `labels.date` and `labels.time` above the inputs and hangs `description` and `error` on the
40
+ * date input.
41
+ */
42
+ readonly frame?: "bare" | "none";
43
+ /** Help above the inputs, or under the date input with `frame="none"`. */
44
+ readonly description?: string | undefined;
45
+ /** Marks the date as required. */
46
+ readonly isRequired?: boolean;
47
+ /** The time input stays disabled until a date is picked. */
48
+ readonly isTimeLockedWithoutDate?: boolean;
49
+ /** The earliest valid calendar date (`YYYY-MM-DD`); an absent or invalid minimum leaves dates unconstrained. */
50
+ readonly min?: string | undefined;
51
+ /** Called with the new date-time; a part not picked yet is empty, a new date starts at 00:00:00. */
52
+ readonly onChange: (value: string) => void;
23
53
  };
24
- /** The local date-time (`YYYY-MM-DD HH:mm:ss`); empty or partial while it is being filled in. */
25
- readonly value: string;
26
- /** The inputs' size, `md` by default. */
27
- readonly size?: "sm" | "md" | undefined;
28
- /** Shows the date-time, not dimmed, and ignores changes. */
29
- readonly isReadOnly?: boolean | undefined;
30
- /** A problem with the date-time, already in the user's language. */
31
- readonly error?: string | undefined;
32
- /** `false` picks a date only: the time input is left out and `onChange` gets `YYYY-MM-DD`, or empty. */
33
- readonly hasTime?: boolean;
34
- /**
35
- * `bare` (default) puts both inputs, with hidden labels, in an unframed group that `label` names
36
- * for assistive tech, for a host that shows the label itself. `none` draws no group: it shows
37
- * `labels.date` and `labels.time` above the inputs and hangs `description` and `error` on the
38
- * date input.
39
- */
40
- readonly frame?: "bare" | "none";
41
- /** Help above the inputs, or under the date input with `frame="none"`. */
42
- readonly description?: string | undefined;
43
- /** Marks the date as required. */
44
- readonly isRequired?: boolean;
45
- /** The time input stays disabled until a date is picked. */
46
- readonly isTimeLockedWithoutDate?: boolean;
47
- /** The earliest date the calendar offers (`YYYY-MM-DD`), such as an end's start; any without it or with another text. */
48
- readonly min?: string | undefined;
49
- /** Called with the new date-time; a part not picked yet is empty, a new date starts at 00:00:00. */
50
- readonly onChange: (value: string) => void;
51
- };
52
54
 
53
55
  /**
54
56
  * A date and a time of day under one label. It composes `DateInput` and `TimeInput` rather than
55
57
  * using Astryx's `DateTimeInput`, which holds only a complete value: here a date or a time may be
56
58
  * set alone while the other is still empty.
59
+ * `hourFormat` defaults to `12h`; choose `24h` for a 24-hour clock. Calendar and clear text use
60
+ * the facade's `InternationalizationProvider`, alongside host-translated `label` and `labels`.
57
61
  */
58
62
  export function DateTimeInput(props: DateTimeInputProps): ReactNode {
59
63
  const { label, isDisabled = false, isReadOnly = false, error, hasTime = true, frame } = props;
60
64
  const size = props.size ?? "md";
61
- const onChange = (next: string): void => {
62
- if (!isReadOnly) props.onChange(next);
63
- };
64
65
  const isInline = frame === "none";
65
66
  const [date = "", time = ""] = props.value.split(" ");
66
- const dateInput = (
67
+ const dateProps = {
68
+ label: props.labels.date,
69
+ size,
70
+ isLabelHidden: !isInline,
71
+ isRequired: props.isRequired ?? false,
72
+ ...(isInline && props.description !== undefined ? { description: props.description } : {}),
73
+ ...(isInline ? errorStatus(error) : {}),
74
+ };
75
+ const dateInput = isReadOnly ? (
76
+ <TextInput {...dateProps} value={date} isReadOnly />
77
+ ) : (
67
78
  <DateInput
68
- label={props.labels.date}
69
- size={size}
70
- isLabelHidden={!isInline}
79
+ {...dateProps}
71
80
  isDisabled={isDisabled}
72
- isRequired={props.isRequired ?? false}
73
81
  {...dateValue(date)}
74
82
  {...minDate(props.min)}
75
83
  onChange={(next) => {
76
84
  // join turns a cleared date (undefined) into an empty one.
77
- onChange(hasTime ? [next, time === "" ? "00:00:00" : time].join(" ") : (next ?? ""));
78
- }}
79
- {...(isInline && props.description !== undefined ? { description: props.description } : {})}
80
- {...(isInline ? errorStatus(error) : {})}
81
- />
82
- );
83
- const timeInput = hasTime && (
84
- <TimeInput
85
- label={props.labels.time}
86
- size={size}
87
- isLabelHidden={!isInline}
88
- hourFormat="12h"
89
- hasSeconds
90
- width={size === "sm" ? 150 : 168}
91
- isDisabled={isDisabled || (props.isTimeLockedWithoutDate === true && date === "")}
92
- {...timeValue(time)}
93
- onChange={(next) => {
94
- // Astryx may hand back HH:mm; the stored time always has seconds.
95
- onChange([date, next?.length === 5 ? `${next}:00` : next].join(" "));
85
+ props.onChange(hasTime ? [next, time === "" ? "00:00:00" : time].join(" ") : (next ?? ""));
96
86
  }}
97
87
  />
98
88
  );
89
+ const timeProps = {
90
+ label: props.labels.time,
91
+ size,
92
+ isLabelHidden: !isInline,
93
+ width: size === "sm" ? 150 : 168,
94
+ };
95
+ const timeInput =
96
+ hasTime &&
97
+ (isReadOnly ? (
98
+ <TextInput {...timeProps} value={time} isReadOnly />
99
+ ) : (
100
+ <TimeInput
101
+ {...timeProps}
102
+ hourFormat={props.hourFormat ?? "12h"}
103
+ hasSeconds
104
+ isDisabled={isDisabled || (props.isTimeLockedWithoutDate === true && date === "")}
105
+ {...timeValue(time)}
106
+ onChange={(next) => {
107
+ // Astryx may hand back HH:mm; the stored time always has seconds.
108
+ props.onChange([date, next?.length === 5 ? `${next}:00` : next].join(" "));
109
+ }}
110
+ />
111
+ ));
99
112
  const zone = props.labels.timezone !== undefined && (
100
113
  <Text type="supporting">{props.labels.timezone}</Text>
101
114
  );
@@ -110,7 +123,12 @@ export function DateTimeInput(props: DateTimeInputProps): ReactNode {
110
123
  );
111
124
  }
112
125
  return (
113
- <FieldGroup label={label} description={props.description} isDisabled={isDisabled} error={error}>
126
+ <FieldGroup
127
+ label={label}
128
+ description={props.description}
129
+ isDisabled={isDisabled && !isReadOnly}
130
+ error={error}
131
+ >
114
132
  <HStack gap={2} wrap="wrap" align="center">
115
133
  {dateInput}
116
134
  {timeInput}
@@ -67,7 +67,7 @@ export function RemovableRow(props: RemovableRowProps): ReactNode {
67
67
  <RemoveButton
68
68
  label={props.labels.remove}
69
69
  size={props.size}
70
- isDisabled={props.isDisabled}
70
+ isDisabled={props.isDisabled ?? false}
71
71
  isReadOnly={props.isReadOnly}
72
72
  onClick={props.onRemove}
73
73
  />
@@ -1,4 +1,4 @@
1
- import { RadioList, RadioListItem } from "@astryxdesign/core/RadioList";
1
+ import { RadioList, RadioListItem, type RadioListProps } from "@astryxdesign/core/RadioList";
2
2
  import { spacingVars } from "@astryxdesign/core/theme/tokens.stylex";
3
3
  import { VStack } from "@astryxdesign/core/VStack";
4
4
  import * as stylex from "@stylexjs/stylex";
@@ -21,13 +21,10 @@ export type RevealRadioOption<V extends string> = {
21
21
  };
22
22
 
23
23
  /** What `RevealRadioGroup` takes. */
24
- export type RevealRadioGroupProps<V extends string> = {
25
- /** Names the group; also its accessible name when hidden. */
26
- readonly label: string;
27
- /** Keeps the label for screen readers only. */
28
- readonly isLabelHidden?: boolean | undefined;
29
- /** Lays the options out in a row instead of a column. */
30
- readonly orientation?: "vertical" | "horizontal" | undefined;
24
+ export type RevealRadioGroupProps<V extends string> = Pick<
25
+ RadioListProps,
26
+ "label" | "isLabelHidden" | "orientation" | "isDisabled"
27
+ > & {
31
28
  /** The choices, in order. */
32
29
  readonly options: readonly RevealRadioOption<V>[];
33
30
  /** The chosen option's value. */
@@ -36,8 +33,6 @@ export type RevealRadioGroupProps<V extends string> = {
36
33
  readonly onChange: (value: V) => void;
37
34
  /** The radios' size, `md` by default (Astryx's default; the theme draws it at 18px). */
38
35
  readonly size?: "sm" | "md" | undefined;
39
- /** Dims the radios and blocks them. */
40
- readonly isDisabled?: boolean | undefined;
41
36
  /** Shows the value, not dimmed, and ignores changes. */
42
37
  readonly isReadOnly?: boolean | undefined;
43
38
  /** The space between the list and the revealed content, `2` by default. */