@microbit/ui 0.1.0-alpha.21 → 0.1.0-alpha.23

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 (97) hide show
  1. package/LICENSE.md +5 -5
  2. package/README.md +29 -13
  3. package/lang/ui.ca.json +12 -12
  4. package/lang/ui.cy.json +4 -4
  5. package/lang/ui.de.json +6 -6
  6. package/lang/ui.es-es.json +5 -5
  7. package/lang/ui.fr.json +6 -6
  8. package/lang/ui.ga-ie.json +6 -6
  9. package/lang/ui.it.json +4 -4
  10. package/lang/ui.ja.json +7 -7
  11. package/lang/ui.ko.json +6 -6
  12. package/lang/ui.lo.json +58 -0
  13. package/lang/ui.nl.json +9 -9
  14. package/lang/ui.pl.json +8 -8
  15. package/lang/ui.pt-br.json +7 -7
  16. package/lang/ui.vi.json +58 -0
  17. package/lang/ui.zh-cn.json +6 -6
  18. package/lang/ui.zh-tw.json +7 -7
  19. package/package.json +1 -1
  20. package/src/Avatar.recipe.ts +16 -20
  21. package/src/Avatar.tsx +31 -29
  22. package/src/Breadcrumb.recipe.ts +3 -7
  23. package/src/Breadcrumb.tsx +6 -8
  24. package/src/Button.recipe.ts +22 -33
  25. package/src/Button.tsx +10 -12
  26. package/src/ButtonGroup.tsx +10 -9
  27. package/src/Card.recipe.ts +1 -2
  28. package/src/Card.tsx +2 -1
  29. package/src/Checkbox.recipe.ts +7 -9
  30. package/src/Checkbox.tsx +2 -3
  31. package/src/CheckboxGroup.tsx +5 -7
  32. package/src/CloseButton.tsx +2 -2
  33. package/src/CloseIcon.tsx +6 -4
  34. package/src/Code.tsx +1 -1
  35. package/src/Collapse.tsx +13 -14
  36. package/src/Divider.tsx +3 -3
  37. package/src/Drawer.recipe.ts +4 -5
  38. package/src/Drawer.tsx +3 -4
  39. package/src/Fade.tsx +6 -10
  40. package/src/Field.recipe.ts +9 -12
  41. package/src/Field.tsx +16 -18
  42. package/src/GridList.recipe.ts +1 -2
  43. package/src/Heading.recipe.ts +5 -5
  44. package/src/Heading.tsx +3 -3
  45. package/src/Icon.tsx +7 -11
  46. package/src/IconButton.tsx +1 -1
  47. package/src/Image.tsx +1 -1
  48. package/src/Input.recipe.ts +5 -6
  49. package/src/Input.tsx +4 -4
  50. package/src/InputGroup.tsx +4 -5
  51. package/src/Kbd.tsx +1 -1
  52. package/src/Link.tsx +2 -2
  53. package/src/LinkBox.tsx +2 -3
  54. package/src/LinkButton.tsx +4 -4
  55. package/src/List.tsx +5 -7
  56. package/src/Menu.recipe.ts +15 -16
  57. package/src/Menu.tsx +9 -13
  58. package/src/Modal.recipe.ts +7 -8
  59. package/src/Modal.tsx +19 -24
  60. package/src/NativeSelect.tsx +16 -16
  61. package/src/NumberField.recipe.ts +25 -11
  62. package/src/NumberField.tsx +4 -4
  63. package/src/PopoverArrow.tsx +1 -2
  64. package/src/ProgressBar.tsx +2 -4
  65. package/src/Radio.recipe.ts +8 -9
  66. package/src/Radio.tsx +2 -2
  67. package/src/RadioGroup.tsx +4 -5
  68. package/src/Select.recipe.ts +9 -9
  69. package/src/Select.tsx +8 -9
  70. package/src/Skeleton.tsx +13 -15
  71. package/src/Slide.tsx +2 -2
  72. package/src/Slider.recipe.ts +11 -14
  73. package/src/Slider.tsx +3 -7
  74. package/src/Spinner.tsx +6 -9
  75. package/src/Svg.tsx +2 -3
  76. package/src/Switch.recipe.ts +4 -5
  77. package/src/Switch.tsx +3 -4
  78. package/src/Text.recipe.ts +4 -7
  79. package/src/Text.tsx +2 -2
  80. package/src/TextField.tsx +3 -4
  81. package/src/Toast.recipe.ts +43 -11
  82. package/src/Toast.tsx +69 -40
  83. package/src/Tooltip.recipe.ts +4 -9
  84. package/src/Tooltip.tsx +48 -10
  85. package/src/TooltipButton.tsx +229 -0
  86. package/src/UnmountCallback.tsx +2 -2
  87. package/src/VisuallyHidden.tsx +1 -1
  88. package/src/base-preset.ts +38 -43
  89. package/src/button-icon.ts +2 -3
  90. package/src/dense-preset.ts +6 -7
  91. package/src/hooks/useBreakpointValue.ts +4 -4
  92. package/src/hooks/useClipboard.ts +5 -6
  93. package/src/hooks/useDisclosure.ts +4 -5
  94. package/src/hooks/useMediaQuery.ts +3 -4
  95. package/src/hooks/usePrevious.ts +1 -4
  96. package/src/index.ts +4 -3
  97. package/src/system.ts +2 -2
@@ -5,15 +5,14 @@
5
5
  */
6
6
  import { defineRecipe } from "@pandacss/dev";
7
7
 
8
- // Chakra's transition.property.common, inlined (Panda has no transitionProperty
9
- // token category).
8
+ // The common transition-property list, inlined (Panda has no
9
+ // transitionProperty token category).
10
10
  const transitionCommon =
11
11
  "background-color, border-color, color, fill, stroke, opacity, box-shadow, transform";
12
12
 
13
13
  /**
14
- * Input recipe — Chakra's outline Input field (light mode) with its size
15
- * scale. Used by the shared-ui Input and NativeSelect, and by TextField's
16
- * input slot.
14
+ * Input recipe — the outline text field with an sm/md/lg size scale. Used by
15
+ * the shared-ui Input and NativeSelect, and by TextField's input slot.
17
16
  *
18
17
  * Focus matches both native `:focus-visible` (plain inputs; browsers treat any
19
18
  * focus in a text field as focus-visible) and react-aria's `data-focused`
@@ -70,7 +69,7 @@ export const input = defineRecipe({
70
69
  },
71
70
  },
72
71
  variants: {
73
- // Chakra's Input size scale, minus the unused xs.
72
+ // The sm/md/lg size scale.
74
73
  size: {
75
74
  lg: { fontSize: "lg", px: "4", h: "12", borderRadius: "md" },
76
75
  md: { fontSize: "md", px: "4", h: "10", borderRadius: "md" },
package/src/Input.tsx CHANGED
@@ -9,8 +9,8 @@ import { input, InputVariantProps } from "styled-system/recipes";
9
9
  import { SystemStyleObject } from "styled-system/types";
10
10
 
11
11
  export interface InputProps
12
- // `size` is the recipe's size scale, as in Chakra; the native character-count
13
- // attribute it shadows was unused.
12
+ // `size` is the recipe's size scale; the native character-count attribute
13
+ // it shadows was unused.
14
14
  extends Omit<InputHTMLAttributes<HTMLInputElement>, "className" | "size">,
15
15
  InputVariantProps {
16
16
  /** Per-instance style overrides, merged after the recipe. */
@@ -19,8 +19,8 @@ export interface InputProps
19
19
  }
20
20
 
21
21
  /**
22
- * Input — a native input styled like Chakra's outline Input. For a
23
- * labelled field with help/error text use TextField instead.
22
+ * Input — a native input in the outline field style. For a labelled field
23
+ * with help/error text use TextField instead.
24
24
  */
25
25
  export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
26
26
  { css: cssProp, className, ...props },
@@ -7,8 +7,7 @@ import { styled } from "styled-system/jsx";
7
7
 
8
8
  /**
9
9
  * InputGroup — relative wrapper for an Input with addon elements. Pad the
10
- * input (`pl`/`pr`) to make room for the elements. Replaces Chakra's
11
- * InputGroup.
10
+ * input (`pl`/`pr`) to make room for the elements.
12
11
  */
13
12
  export const InputGroup = styled("div", {
14
13
  base: { position: "relative", width: "100%", display: "flex" },
@@ -17,9 +16,9 @@ export const InputGroup = styled("div", {
17
16
  // The element styles are written out twice rather than shared via a spread:
18
17
  // Panda's extractor only reliably evaluates inline literals.
19
18
  // The size variants are square boxes matching the input recipe's height per
20
- // size, as in Chakra; pass the same `size` as the grouped Input.
19
+ // size; pass the same `size` as the grouped Input.
21
20
 
22
- /** Element overlaying the start of an InputGroup (Chakra InputLeftElement). */
21
+ /** Element overlaying the start of an InputGroup. */
23
22
  export const InputLeftElement = styled("div", {
24
23
  base: {
25
24
  position: "absolute",
@@ -40,7 +39,7 @@ export const InputLeftElement = styled("div", {
40
39
  defaultVariants: { size: "md" },
41
40
  });
42
41
 
43
- /** Element overlaying the end of an InputGroup (Chakra InputRightElement). */
42
+ /** Element overlaying the end of an InputGroup. */
44
43
  export const InputRightElement = styled("div", {
45
44
  base: {
46
45
  position: "absolute",
package/src/Kbd.tsx CHANGED
@@ -6,7 +6,7 @@
6
6
  import { styled } from "styled-system/jsx";
7
7
 
8
8
  /**
9
- * Kbd — keyboard-key chip matching Chakra's <Kbd> (light mode).
9
+ * Kbd — a keyboard-key chip (light mode).
10
10
  */
11
11
  export const Kbd = styled("kbd", {
12
12
  base: {
package/src/Link.tsx CHANGED
@@ -6,8 +6,8 @@
6
6
  import { styled } from "styled-system/jsx";
7
7
 
8
8
  /**
9
- * Link — anchor styled to match Chakra's <Link> base (no underline until hover,
10
- * focus ring on keyboard focus). Accepts Panda style props for colour etc.
9
+ * Link — a styled anchor (no underline until hover, focus ring on keyboard
10
+ * focus). Accepts Panda style props for colour etc.
11
11
  */
12
12
  export const Link = styled("a", {
13
13
  base: {
package/src/LinkBox.tsx CHANGED
@@ -12,7 +12,7 @@ import { SystemStyleObject } from "styled-system/types";
12
12
  /**
13
13
  * LinkBox — makes a whole box clickable via a nested LinkOverlay (or any
14
14
  * element with an inset `_before` overlay). Other interactive children must
15
- * be raised with `zIndex: 1`. Replaces Chakra's <LinkBox>.
15
+ * be raised with `zIndex: 1`.
16
16
  */
17
17
  export const LinkBox = styled("div", {
18
18
  base: { position: "relative" },
@@ -54,8 +54,7 @@ export interface LinkOverlayButtonProps
54
54
  * Deliberately a plain button, not a react-aria one: react-aria's usePress
55
55
  * cancels presses that land outside the button's bounding rect, which defeats
56
56
  * the overlay. `position: static` overrides the button recipe's base so the
57
- * overlay anchors to the LinkBox (Chakra's LinkOverlay did the same over its
58
- * Button).
57
+ * overlay anchors to the LinkBox.
59
58
  */
60
59
  export const LinkOverlayButton = forwardRef<
61
60
  HTMLButtonElement,
@@ -19,9 +19,9 @@ export interface LinkButtonProps
19
19
  /** Per-instance style overrides, merged after the recipe. */
20
20
  css?: SystemStyleObject;
21
21
  className?: string;
22
- /** Icon rendered before the label, matching Chakra's `leftIcon`. */
22
+ /** Icon rendered before the label. */
23
23
  leftIcon?: ReactNode;
24
- /** Icon rendered after the label, matching Chakra's `rightIcon`. */
24
+ /** Icon rendered after the label. */
25
25
  rightIcon?: ReactNode;
26
26
  children?: ReactNode;
27
27
  }
@@ -33,8 +33,8 @@ const linkReset = css.raw({
33
33
  });
34
34
 
35
35
  /**
36
- * LinkButton — a navigation link that looks like a Button (Chakra's
37
- * `Button as="a"`). react-aria-components <Link> renders a real anchor
36
+ * LinkButton — a navigation link that looks like a Button.
37
+ * react-aria-components <Link> renders a real anchor
38
38
  * (`href`, `target`, new-tab/middle-click semantics preserved) with the same
39
39
  * interaction data attributes as Button, so the `button` recipe's
40
40
  * hover/press/focus/disabled states apply unchanged.
package/src/List.tsx CHANGED
@@ -6,26 +6,24 @@
6
6
  import { styled } from "styled-system/jsx";
7
7
 
8
8
  /**
9
- * Unstyled list, matching Chakra's <List>. The marker removal is explicit
10
- * Chakra's List set listStyleType itself, and coexisting apps run without
11
- * Panda's preflight (margins/padding are zeroed by whichever reset is
12
- * active).
9
+ * Unstyled list. The marker removal is explicit rather than relying on a
10
+ * reset.
13
11
  */
14
12
  export const List = styled("ul", {
15
13
  base: { listStyleType: "none" },
16
14
  });
17
15
 
18
- /** List item, matching Chakra's <ListItem>. */
16
+ /** List item. */
19
17
  export const ListItem = styled("li", {
20
18
  base: {},
21
19
  });
22
20
 
23
- /** Bulleted list matching Chakra's <UnorderedList>. */
21
+ /** Bulleted list. */
24
22
  export const UnorderedList = styled("ul", {
25
23
  base: { listStyleType: "disc", marginStart: "1em" },
26
24
  });
27
25
 
28
- /** Numbered list matching Chakra's <OrderedList>. */
26
+ /** Numbered list. */
29
27
  export const OrderedList = styled("ol", {
30
28
  base: { listStyleType: "decimal", marginStart: "1em" },
31
29
  });
@@ -6,9 +6,9 @@
6
6
  import { defineSlotRecipe } from "@pandacss/dev";
7
7
 
8
8
  /**
9
- * Menu slot recipe — Chakra's default Menu parts (light mode). `content` is the
10
- * dropdown card (react-aria-components' Popover), `list` the RAC Menu, `item` a
11
- * MenuItem, `icon` the leading-icon wrapper.
9
+ * Menu slot recipe. `content` is the dropdown card (react-aria-components'
10
+ * Popover), `list` the RAC Menu, `item` a MenuItem, `icon` the leading-icon
11
+ * wrapper.
12
12
  *
13
13
  * A config slot recipe (rather than an atomic `sva`) for consistency with
14
14
  * `dialog` and so presets can override it later if brands diverge.
@@ -38,15 +38,14 @@ export const menu = defineSlotRecipe({
38
38
  // `popover` (1500), not `dropdown` (1000): a RAC Popover always portals
39
39
  // to the body, so a menu opened from inside a Modal (zIndex `modal`,
40
40
  // 1400) escapes the modal's stacking context and would paint behind it.
41
- // Chakra never hit this its MenuList rendered inline unless explicitly
42
- // portalled. Nothing else lives between 1400 and the toast/tooltip layer.
41
+ // Nothing else lives between 1400 and the toast/tooltip layer.
43
42
  zIndex: "popover",
44
43
  borderRadius: "md",
45
44
  borderWidth: "1px",
46
45
  borderColor: "gray.200",
47
46
  boxShadow: "sm",
48
- // Approximate Chakra's menu fade/scale. RAC toggles data-entering/
49
- // data-exiting on the Popover and waits for the transition before unmount.
47
+ // Fade/scale enter/exit. RAC toggles data-entering/data-exiting on the
48
+ // Popover and waits for the transition before unmount.
50
49
  transformOrigin: "top",
51
50
  opacity: 1,
52
51
  transform: "scale(1)",
@@ -71,15 +70,15 @@ export const menu = defineSlotRecipe({
71
70
  transitionDuration: "ultra-fast",
72
71
  transitionTimingFunction: "ease-in",
73
72
  // RAC highlights the active item (keyboard or pointer) with data-focused;
74
- // data-pressed is the pressed state — mirrors Chakra's _focus/_active.
73
+ // data-pressed is the pressed state.
75
74
  "&[data-focused]": { bg: "gray.100" },
76
75
  "&[data-pressed]": { bg: "gray.200" },
77
76
  "&[data-disabled]": { opacity: 0.4, cursor: "not-allowed" },
78
77
  },
79
78
  label: {
80
- // Chakra wraps an icon-item's children in a flex:1 span, so block
81
- // children (e.g. two stacked <Text>s) lay out vertically rather than as
82
- // flex-row siblings of the icon.
79
+ // A flex:1 wrapper around an icon-item's children, so block children
80
+ // (e.g. two stacked <Text>s) lay out vertically rather than as flex-row
81
+ // siblings of the icon.
83
82
  flex: "1",
84
83
  },
85
84
  icon: {
@@ -88,8 +87,8 @@ export const menu = defineSlotRecipe({
88
87
  justifyContent: "center",
89
88
  flexShrink: 0,
90
89
  marginEnd: "0.75rem",
91
- // Chakra's MenuIcon shrinks glyphs to 0.8em; items passing an explicitly
92
- // sized icon (e.g. h/w) override this.
90
+ // Glyphs shrink to 0.8em; items passing an explicitly sized icon
91
+ // (e.g. h/w) override this.
93
92
  fontSize: "0.8em",
94
93
  },
95
94
  divider: {
@@ -100,7 +99,7 @@ export const menu = defineSlotRecipe({
100
99
  opacity: 0.6,
101
100
  },
102
101
  group: {},
103
- // Chakra's MenuGroup/MenuOptionGroup title.
102
+ // Title for a menu group or option group.
104
103
  groupTitle: {
105
104
  display: "block",
106
105
  mx: "4",
@@ -108,8 +107,8 @@ export const menu = defineSlotRecipe({
108
107
  fontWeight: "semibold",
109
108
  fontSize: "sm",
110
109
  },
111
- // Check glyph slot for MenuItemOption: space always reserved (as Chakra
112
- // does), visible only on the selected item (RAC sets data-selected on it).
110
+ // Check glyph slot for MenuItemOption: space always reserved, visible
111
+ // only on the selected item (RAC sets data-selected on it).
113
112
  itemIndicator: {
114
113
  display: "inline-flex",
115
114
  alignItems: "center",
package/src/Menu.tsx CHANGED
@@ -97,7 +97,6 @@ export interface MenuListProps {
97
97
  */
98
98
  export const MenuList = ({
99
99
  children,
100
- // Matches Chakra Menu's default "bottom-start".
101
100
  placement = "bottom start",
102
101
  css: cssProp,
103
102
  className,
@@ -119,7 +118,7 @@ export const MenuList = ({
119
118
 
120
119
  export interface MenuItemProps
121
120
  extends Omit<RACMenuItemProps, "className" | "children"> {
122
- /** Icon rendered before the label, matching Chakra's MenuItem `icon`. */
121
+ /** Icon rendered before the label. */
123
122
  icon?: ReactNode;
124
123
  /** Per-instance style overrides, merged after the recipe. */
125
124
  css?: SystemStyleObject;
@@ -157,7 +156,7 @@ export const MenuItem = ({
157
156
  };
158
157
 
159
158
  interface MenuOptionGroupBaseProps {
160
- /** Group heading shown above the options (Chakra's `title`). */
159
+ /** Group heading shown above the options. */
161
160
  title?: ReactNode;
162
161
  /** `MenuItemOption` children. */
163
162
  children: ReactNode;
@@ -186,19 +185,17 @@ export type MenuOptionGroupProps =
186
185
  | MenuOptionGroupCheckboxProps;
187
186
 
188
187
  /**
189
- * MenuOptionGroup — a group of checkable `MenuItemOption`s within a menu,
190
- * replacing Chakra's `MenuOptionGroup`. `type="radio"` (the default) is
191
- * single-select and renders `menuitemradio`; `type="checkbox"` is multi-select
192
- * and renders `menuitemcheckbox`, each option toggling independently.
188
+ * MenuOptionGroup — a group of checkable `MenuItemOption`s within a menu.
189
+ * `type="radio"` (the default) is single-select and renders `menuitemradio`;
190
+ * `type="checkbox"` is multi-select and renders `menuitemcheckbox`, each
191
+ * option toggling independently.
193
192
  *
194
193
  * Selection is section-scoped (RAC MenuSection), so a menu can mix action items
195
194
  * and option groups. An option's own `onAction` still fires on every press,
196
195
  * including the press that deselects it — so a lone toggle can be driven either
197
196
  * by the group's `onChange` or by the item's `onAction`.
198
197
  *
199
- * Choosing an option leaves the menu open (a plain `MenuItem` closes it), which
200
- * is what Chakra's checkbox groups did. Chakra's *radio* groups closed on
201
- * select, so a ported radio group is a deliberate behaviour change.
198
+ * Choosing an option leaves the menu open (a plain `MenuItem` closes it).
202
199
  */
203
200
  export const MenuOptionGroup = (props: MenuOptionGroupProps) => {
204
201
  const { title, children, css: cssProp, className } = props;
@@ -222,8 +219,7 @@ export const MenuOptionGroup = (props: MenuOptionGroupProps) => {
222
219
  if (props.type === "checkbox") {
223
220
  props.onChange?.(values);
224
221
  } else if (values.length > 0) {
225
- // Radio: a press that clears the selection reports nothing, matching
226
- // Chakra, which had no way to express an empty radio group.
222
+ // Radio: a press that clears the selection reports nothing.
227
223
  props.onChange?.(values[0]);
228
224
  }
229
225
  }}
@@ -247,7 +243,7 @@ export interface MenuItemOptionProps
247
243
 
248
244
  /**
249
245
  * MenuItemOption — a selectable option inside a `MenuOptionGroup`, with a
250
- * check indicator on the selected item (Chakra's MenuItemOption).
246
+ * check indicator on the selected item.
251
247
  */
252
248
  export const MenuItemOption = ({
253
249
  value,
@@ -6,9 +6,9 @@
6
6
  import { defineSlotRecipe } from "@pandacss/dev";
7
7
 
8
8
  /**
9
- * Dialog slot recipe Chakra's default Modal parts (light mode), plus this
10
- * app's overrides: a full-viewport overlay (the iOS WKWebView 100% fix) and a
11
- * `full` size with safe-area insets and the brand status-bar gradient.
9
+ * Dialog slot recipe. The overlay spans the full viewport (the iOS WKWebView
10
+ * 100% fix) and the `full` size adds safe-area insets and the brand
11
+ * status-bar gradient.
12
12
  *
13
13
  * A config recipe (rather than an atomic `sva`) so the `size` variant accepts
14
14
  * responsive values, e.g. `{ base: "full", md: "4xl" }`. Consumed by the
@@ -85,7 +85,7 @@ export const dialog = defineSlotRecipe({
85
85
  display: "flex",
86
86
  flexDirection: "column",
87
87
  outline: "none",
88
- // Approximate Chakra's fade + scale enter/exit.
88
+ // Fade + scale enter/exit.
89
89
  opacity: 1,
90
90
  transform: "scale(1)",
91
91
  transition: "opacity 0.2s ease-out, transform 0.2s ease-out",
@@ -114,16 +114,15 @@ export const dialog = defineSlotRecipe({
114
114
  display: "flex",
115
115
  alignItems: "center",
116
116
  justifyContent: "flex-end",
117
- // Chakra had no footer gap (call sites wrapped buttons in HStacks);
118
- // baked in as the house style. Override via css for tighter layouts.
117
+ // The gap is house style; override via css for tighter layouts.
119
118
  gap: "5",
120
119
  flexShrink: 0,
121
120
  },
122
121
  closeTrigger: { position: "absolute", top: "2", insetEnd: "3" },
123
122
  },
124
123
  variants: {
125
- // Chakra's `isCentered`: vertically centre the dialog in the viewport
126
- // rather than the default top alignment.
124
+ // Vertically centre the dialog in the viewport rather than the default
125
+ // top alignment.
127
126
  centered: {
128
127
  true: {
129
128
  overlay: { alignItems: "center" },
package/src/Modal.tsx CHANGED
@@ -55,11 +55,11 @@ export interface ModalOwnProps {
55
55
  size?: ModalSize;
56
56
  /** Allow closing by clicking the backdrop (default true; Escape always closes). */
57
57
  isDismissable?: boolean;
58
- /** Disable the enter/exit transitions (Chakra's motionPreset="none"). */
58
+ /** Disable the enter/exit transitions. */
59
59
  motionless?: boolean;
60
- /** Prevent Escape closing the dialog (Chakra's closeOnEsc={false}). */
60
+ /** Prevent Escape closing the dialog. */
61
61
  isKeyboardDismissDisabled?: boolean;
62
- /** Style overrides for the dialog box (Chakra's ModalContent props). */
62
+ /** Style overrides for the dialog box. */
63
63
  contentCss?: SystemStyleObject;
64
64
  /**
65
65
  * Inline styles for the dialog box, for runtime-computed positioning that
@@ -68,25 +68,22 @@ export interface ModalOwnProps {
68
68
  */
69
69
  contentStyle?: CSSProperties;
70
70
  /**
71
- * Style overrides for the backdrop (Chakra's ModalOverlay props), e.g. a
72
- * transparent backdrop when something else provides the dimming.
71
+ * Style overrides for the backdrop, e.g. a transparent backdrop when
72
+ * something else provides the dimming.
73
73
  */
74
74
  overlayCss?: SystemStyleObject;
75
- /**
76
- * Use "alertdialog" for confirmations that interrupt the user (Chakra's
77
- * AlertDialog).
78
- */
75
+ /** Use "alertdialog" for confirmations that interrupt the user. */
79
76
  role?: "dialog" | "alertdialog";
80
- /** Vertically centre the dialog (Chakra's `isCentered`). */
77
+ /** Vertically centre the dialog. */
81
78
  isCentered?: boolean;
82
79
  /**
83
80
  * Called after the dialog has fully closed (exit transition done and the
84
- * dialog removed). Matches Chakra's `onCloseComplete`.
81
+ * dialog removed).
85
82
  */
86
83
  onCloseComplete?: () => void;
87
84
  /**
88
85
  * Element to focus when the dialog closes, instead of the element that was
89
- * focused when it opened. Matches Chakra's `finalFocusRef`.
86
+ * focused when it opened.
90
87
  */
91
88
  finalFocusRef?: RefObject<HTMLElement>;
92
89
  /**
@@ -98,9 +95,9 @@ export interface ModalOwnProps {
98
95
  "aria-label"?: string;
99
96
  children: ReactNode;
100
97
  /**
101
- * `data-*` attributes land on the dialog box (where Chakra's went, on
102
- * ModalContent), so end-to-end tests can address a dialog. Shells that
103
- * forward their caller's data attributes can spread them straight in.
98
+ * `data-*` attributes land on the dialog box, so end-to-end tests can
99
+ * address a dialog. Shells that forward their caller's data attributes can
100
+ * spread them straight in.
104
101
  */
105
102
  [key: `data-${string}`]: unknown;
106
103
  }
@@ -129,16 +126,14 @@ export type ModalProps =
129
126
  | (ModalOwnProps & { isOpen?: never; onClose?: never });
130
127
 
131
128
  /**
132
- * Modal — a focus-trapping dialog. Collapses Chakra's
133
- * Modal/ModalOverlay/ModalContent into a single shell; place ModalHeader,
129
+ * Modal — a focus-trapping dialog in a single shell; place ModalHeader,
134
130
  * ModalBody and ModalFooter inside.
135
131
  *
136
132
  * Two ways to drive it:
137
133
  *
138
- * - **Controlled** (`isOpen` + `onClose`), which is what a Chakra app ports
139
- * to, and what any dialog with more than one opener needs — a menu item and
140
- * a toolbar button opening the same dialog, or one opened from a handler
141
- * after an async result.
134
+ * - **Controlled** (`isOpen` + `onClose`), which is what any dialog with more
135
+ * than one opener needs — a menu item and a toolbar button opening the same
136
+ * dialog, or one opened from a handler after an async result.
142
137
  * - **Inside a `DialogTrigger`**, with neither prop: react-aria holds the
143
138
  * open state, the trigger opens it, and `ModalCloseButton` and the footer's
144
139
  * `useDialogClose()` still close it. Prefer this where a dialog has exactly
@@ -259,7 +254,7 @@ interface SlotProps {
259
254
  children?: ReactNode;
260
255
  css?: SystemStyleObject;
261
256
  className?: string;
262
- /** `data-*` attributes land on the slot element, as they did on Chakra's. */
257
+ /** `data-*` attributes land on the slot element. */
263
258
  [key: `data-${string}`]: unknown;
264
259
  }
265
260
 
@@ -340,8 +335,8 @@ export interface ModalCloseButtonProps {
340
335
  }
341
336
 
342
337
  /**
343
- * ModalCloseButton — the X in the dialog's top corner (Chakra's
344
- * ModalCloseButton at its default md size). Closes via the Modal's onClose.
338
+ * ModalCloseButton — the X in the dialog's top corner. Closes via the Modal's
339
+ * onClose.
345
340
  */
346
341
  export const ModalCloseButton = ({
347
342
  "aria-label": ariaLabel,
@@ -9,8 +9,8 @@ import { input, InputVariantProps } from "styled-system/recipes";
9
9
  import { SystemStyleObject } from "styled-system/types";
10
10
 
11
11
  export interface NativeSelectProps
12
- // `size` is the recipe's size scale, as in Chakra; the native visible-rows
13
- // attribute it shadows was unused.
12
+ // `size` is the recipe's size scale; the native visible-rows attribute it
13
+ // shadows was unused.
14
14
  extends Omit<SelectHTMLAttributes<HTMLSelectElement>, "className" | "size">,
15
15
  InputVariantProps {
16
16
  /**
@@ -23,18 +23,17 @@ export interface NativeSelectProps
23
23
  css?: SystemStyleObject;
24
24
  /**
25
25
  * Style overrides for the chevron wrapper, which is where width constraints
26
- * belong (the select fills it). Chakra's Select worked the same way: layout
27
- * props were split onto `.chakra-select__wrapper`, `width: 100%` otherwise.
28
- * No wrapper is rendered with `hideChevron`; constrain the select directly.
26
+ * belong (the select fills it). No wrapper is rendered with `hideChevron`;
27
+ * constrain the select directly.
29
28
  */
30
29
  wrapperCss?: SystemStyleObject;
31
30
  className?: string;
32
31
  }
33
32
 
34
33
  /**
35
- * NativeSelect — a native select styled like Chakra's Select field (outline).
36
- * The recipe's `appearance: none` removes the platform chevron, so one is
37
- * drawn back in by default (Chakra Select's glyph, `currentColor`).
34
+ * NativeSelect — a native select styled like the outline Input. The recipe's
35
+ * `appearance: none` removes the platform chevron, so one is drawn back in by
36
+ * default (`currentColor`).
38
37
  */
39
38
  export const NativeSelect = forwardRef<HTMLSelectElement, NativeSelectProps>(
40
39
  function NativeSelect(
@@ -47,15 +46,14 @@ export const NativeSelect = forwardRef<HTMLSelectElement, NativeSelectProps>(
47
46
  className={cx(
48
47
  input({ size }),
49
48
  css(
50
- // Chakra's Select field carried a 1px bottom padding its Input
51
- // didn't (its option text sits a hair higher than input text).
49
+ // Option text sits a hair higher than input text; the 1px bottom
50
+ // padding compensates.
52
51
  {
53
52
  cursor: "pointer",
54
53
  paddingBottom: "1px",
55
54
  _disabled: { cursor: "not-allowed" },
56
55
  },
57
- // Room for the chevron overlay (Chakra Select's icon spacing,
58
- // constant across sizes).
56
+ // Room for the chevron overlay (constant across sizes).
59
57
  hideChevron ? undefined : { paddingRight: "8" },
60
58
  cssProp,
61
59
  ),
@@ -70,14 +68,16 @@ export const NativeSelect = forwardRef<HTMLSelectElement, NativeSelectProps>(
70
68
  return (
71
69
  <span
72
70
  className={css(
73
- // Full-width like every other field (and Chakra's select wrapper);
74
- // the select's own recipe width fills it. Constrain via wrapperCss.
71
+ // Full-width like every other field; the select's own recipe width
72
+ // fills it. Constrain via wrapperCss.
75
73
  { position: "relative", display: "inline-flex", width: "100%" },
76
74
  wrapperCss,
77
75
  )}
78
76
  >
79
77
  {select}
80
- {/* Chakra Select's chevron, fixed-size across field sizes. */}
78
+ {/* The chevron, fixed-size across field sizes. The path is Chakra
79
+ UI's Select chevron, inlined for visual parity with the apps'
80
+ original look (see the notice in LICENSE.md). */}
81
81
  <svg
82
82
  viewBox="0 0 24 24"
83
83
  aria-hidden
@@ -91,7 +91,7 @@ export const NativeSelect = forwardRef<HTMLSelectElement, NativeSelectProps>(
91
91
  pointerEvents: "none",
92
92
  fill: "currentColor",
93
93
  // The chevron sits outside the select so it doesn't inherit its
94
- // disabled dimming; Chakra's Select icon dimmed to 0.5.
94
+ // disabled dimming; dim it explicitly to match.
95
95
  "select:disabled + &": { opacity: 0.5 },
96
96
  })}
97
97
  >
@@ -6,10 +6,9 @@
6
6
  import { defineSlotRecipe } from "@pandacss/dev";
7
7
 
8
8
  /**
9
- * NumberField slot recipe — Chakra's NumberInput look: an outline input (the
10
- * `input` recipe styles the input itself) with a right-hand stepper column of
11
- * two stacked buttons. Consumed by the shared-ui NumberField
12
- * (react-aria-components NumberField).
9
+ * NumberField slot recipe — an outline input (the `input` recipe styles the
10
+ * input itself) with a right-hand stepper column of two stacked buttons.
11
+ * Consumed by the shared-ui NumberField (react-aria-components NumberField).
13
12
  *
14
13
  * Registered in the base preset (base-preset.ts), which also has the
15
14
  * `staticCss` entry that keeps the runtime-prop size variants generated.
@@ -27,8 +26,7 @@ export const numberField = defineSlotRecipe({
27
26
  position: "relative",
28
27
  zIndex: 0,
29
28
  },
30
- // Chakra's NumberInputStepper: a column overlaying the input's right
31
- // edge, inset by the input border.
29
+ // A column overlaying the input's right edge, inset by the input border.
32
30
  stepper: {
33
31
  display: "flex",
34
32
  flexDirection: "column",
@@ -54,10 +52,18 @@ export const numberField = defineSlotRecipe({
54
52
  borderColor: "gray.200",
55
53
  transitionProperty: "background",
56
54
  transitionDuration: "ultra-fast",
55
+ // Follow the input's corners, less the 1px border the stepper is inset
56
+ // by, so the hover and pressed fills curve away with the border instead
57
+ // of squaring off over its arc. Radii track the input recipe's size
58
+ // scale, so the `sm` variant restates them.
59
+ "&:first-child": {
60
+ borderStartEndRadius: "calc(token(radii.md) - 1px)",
61
+ },
57
62
  "&:last-child": {
58
63
  borderTop: "1px solid",
59
64
  borderTopColor: "gray.200",
60
65
  marginTop: "-1px",
66
+ borderEndEndRadius: "calc(token(radii.md) - 1px)",
61
67
  },
62
68
  "&[data-hovered]": { bg: "gray.100" },
63
69
  "&[data-pressed]": { bg: "gray.200" },
@@ -65,17 +71,25 @@ export const numberField = defineSlotRecipe({
65
71
  },
66
72
  },
67
73
  variants: {
68
- // Chakra's NumberInput: the stepper column stays 24px wide at every size
69
- // (as does the input padding paired with it in NumberField.tsx); only the
70
- // arrow glyphs scale, at 0.75 × the field's font size. The base's `xs` is
71
- // exactly md × 0.75, so md adds nothing.
74
+ // The stepper column stays 24px wide at every size (as does the input
75
+ // padding paired with it in NumberField.tsx); only the arrow glyphs
76
+ // scale, at 0.75 × the field's font size. The base's `xs` is exactly
77
+ // md × 0.75, so md adds nothing.
72
78
  size: {
73
79
  lg: {
74
80
  stepperButton: { fontSize: "calc(token(fontSizes.lg) * 0.75)" },
75
81
  },
76
82
  md: {},
77
83
  sm: {
78
- stepperButton: { fontSize: "calc(token(fontSizes.sm) * 0.75)" },
84
+ stepperButton: {
85
+ fontSize: "calc(token(fontSizes.sm) * 0.75)",
86
+ "&:first-child": {
87
+ borderStartEndRadius: "calc(token(radii.sm) - 1px)",
88
+ },
89
+ "&:last-child": {
90
+ borderEndEndRadius: "calc(token(radii.sm) - 1px)",
91
+ },
92
+ },
79
93
  },
80
94
  },
81
95
  },
@@ -49,10 +49,10 @@ export interface NumberFieldProps
49
49
  }
50
50
 
51
51
  /**
52
- * NumberField — react-aria-components <NumberField> styled like Chakra's
53
- * NumberInput (outline input + right-hand stepper column). The ref is
54
- * forwarded to the input element. Value clamping to min/maxValue is
55
- * handled by react-aria; onChange receives NaN when the field is emptied.
52
+ * NumberField — react-aria-components <NumberField>: an outline input with a
53
+ * right-hand stepper column. The ref is forwarded to the input element. Value
54
+ * clamping to min/maxValue is handled by react-aria; onChange receives NaN
55
+ * when the field is emptied.
56
56
  */
57
57
  export const NumberField = forwardRef<HTMLInputElement, NumberFieldProps>(
58
58
  function NumberField(