@edux-design/chips 0.1.0 → 0.2.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,19 @@
1
+ # @edux-design/chips
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add typed removeButtonProps for native remove-button descriptions, refs and composed handlers while preserving Chip removal, label and disabled semantics. Keep collection state and post-removal focus with the host.
8
+
9
+ ## 0.1.0
10
+
11
+ ### Minor Changes
12
+
13
+ - Moved react / dom to peer deps
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies
18
+ - @edux-design/icons@0.1.0
19
+ - @edux-design/utils@0.1.0
package/README.md CHANGED
@@ -14,6 +14,18 @@ npm install @edux-design/chips @edux-design/utils @edux-design/icons
14
14
 
15
15
  The package ships React components and depends on `react@^19.1.0` / `react-dom@^19.1.0`.
16
16
 
17
+ ## Token contract
18
+
19
+ Small chips use the shared `min-h-32` token and both chip sizes use the shared
20
+ `size-16` token for the remove control. The default chip remains `40px` tall
21
+ through an explicit component-owned `min-h-[40px]` value because the current
22
+ theme has no 40px spacing or control token; introducing a new semantic token
23
+ would be broader than this package change and is intentionally deferred.
24
+
25
+ Padding, gaps, borders, colours, and focus treatment use existing Edux numeric
26
+ and semantic tokens. Consumers should import `@edux-design/tokens/theme` so
27
+ those utilities resolve consistently.
28
+
17
29
  ---
18
30
 
19
31
  ## Usage
package/dist/index.d.mts CHANGED
@@ -1,5 +1,3 @@
1
- import * as react from 'react';
2
-
3
1
  /**
4
2
  * Token-driven chip that composes existing primitives (i.e. TagNumber) inside.
5
3
  *
@@ -9,8 +7,21 @@ import * as react from 'react';
9
7
  * onRemove?: (event: React.MouseEvent<HTMLButtonElement>) => void,
10
8
  * removeLabel?: string,
11
9
  * disabled?: boolean,
10
+ * removeButtonProps?: Omit<React.ComponentPropsWithRef<"button">, "type"|"disabled"|"aria-label"|"aria-labelledby"|"children">,
12
11
  * }} ChipProps
13
12
  */
14
- declare const Chip: react.ForwardRefExoticComponent<react.RefAttributes<any>>;
13
+ /** @type {React.ForwardRefExoticComponent<ChipProps & React.RefAttributes<HTMLDivElement>>} */
14
+ declare const Chip: React.ForwardRefExoticComponent<ChipProps & React.RefAttributes<HTMLDivElement>>;
15
+ /**
16
+ * Token-driven chip that composes existing primitives (i.e. TagNumber) inside.
17
+ */
18
+ type ChipProps = React.HTMLAttributes<HTMLDivElement> & {
19
+ label?: React.ReactNode;
20
+ size?: "default" | "small";
21
+ onRemove?: (event: React.MouseEvent<HTMLButtonElement>) => void;
22
+ removeLabel?: string;
23
+ disabled?: boolean;
24
+ removeButtonProps?: Omit<React.ComponentPropsWithRef<"button">, "type" | "disabled" | "aria-label" | "aria-labelledby" | "children">;
25
+ };
15
26
 
16
27
  export { Chip };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- import * as react from 'react';
2
-
3
1
  /**
4
2
  * Token-driven chip that composes existing primitives (i.e. TagNumber) inside.
5
3
  *
@@ -9,8 +7,21 @@ import * as react from 'react';
9
7
  * onRemove?: (event: React.MouseEvent<HTMLButtonElement>) => void,
10
8
  * removeLabel?: string,
11
9
  * disabled?: boolean,
10
+ * removeButtonProps?: Omit<React.ComponentPropsWithRef<"button">, "type"|"disabled"|"aria-label"|"aria-labelledby"|"children">,
12
11
  * }} ChipProps
13
12
  */
14
- declare const Chip: react.ForwardRefExoticComponent<react.RefAttributes<any>>;
13
+ /** @type {React.ForwardRefExoticComponent<ChipProps & React.RefAttributes<HTMLDivElement>>} */
14
+ declare const Chip: React.ForwardRefExoticComponent<ChipProps & React.RefAttributes<HTMLDivElement>>;
15
+ /**
16
+ * Token-driven chip that composes existing primitives (i.e. TagNumber) inside.
17
+ */
18
+ type ChipProps = React.HTMLAttributes<HTMLDivElement> & {
19
+ label?: React.ReactNode;
20
+ size?: "default" | "small";
21
+ onRemove?: (event: React.MouseEvent<HTMLButtonElement>) => void;
22
+ removeLabel?: string;
23
+ disabled?: boolean;
24
+ removeButtonProps?: Omit<React.ComponentPropsWithRef<"button">, "type" | "disabled" | "aria-label" | "aria-labelledby" | "children">;
25
+ };
15
26
 
16
27
  export { Chip };
package/dist/index.js CHANGED
@@ -41,11 +41,11 @@ var import_jsx_runtime = require("react/jsx-runtime");
41
41
  var SIZE_MAP = {
42
42
  default: {
43
43
  container: "text-sm min-h-[40px] px-8 py-6 gap-8",
44
- close: "h-[16px] w-[16px]"
44
+ close: "size-16"
45
45
  },
46
46
  small: {
47
- container: "text-xs min-h-[32px] px-8 py-4 gap-6",
48
- close: "h-[16px] w-[16px]"
47
+ container: "text-xs min-h-32 px-8 py-4 gap-6",
48
+ close: "size-16"
49
49
  }
50
50
  };
51
51
  var BASE_STYLES = (0, import_utils.cx)(
@@ -64,9 +64,15 @@ var Chip = (0, import_react.forwardRef)(function Chip2({
64
64
  onRemove,
65
65
  removeLabel = "Remove chip",
66
66
  disabled = false,
67
+ removeButtonProps = {},
67
68
  className,
68
69
  ...rest
69
70
  }, ref) {
71
+ const {
72
+ className: removeClassName,
73
+ onClick: onRemoveClick,
74
+ ...buttonProps
75
+ } = removeButtonProps;
70
76
  const sizeStyles = SIZE_MAP[size] ?? SIZE_MAP.default;
71
77
  const containerClass = (0, import_utils.cx)(
72
78
  BASE_STYLES,
@@ -86,6 +92,7 @@ var Chip = (0, import_react.forwardRef)(function Chip2({
86
92
  className: containerClass,
87
93
  "data-disabled": disabled ? "true" : void 0,
88
94
  ...rest,
95
+ "aria-disabled": disabled ? true : rest["aria-disabled"],
89
96
  children: [
90
97
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "flex min-w-0 flex-1 items-center gap-6", children: [
91
98
  shouldRenderChildren && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex items-center gap-4 shrink-0 [&>*]:shrink-0", children: normalizedChildren.map(
@@ -96,12 +103,16 @@ var Chip = (0, import_react.forwardRef)(function Chip2({
96
103
  onRemove && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
97
104
  "button",
98
105
  {
106
+ ...buttonProps,
99
107
  type: "button",
100
108
  disabled,
101
109
  "aria-label": removeLabel,
110
+ "aria-labelledby": void 0,
102
111
  onClick: (event) => {
103
112
  event.stopPropagation();
104
- onRemove(event);
113
+ if (disabled) return;
114
+ onRemoveClick == null ? void 0 : onRemoveClick(event);
115
+ if (!event.defaultPrevented) onRemove(event);
105
116
  },
106
117
  className: (0, import_utils.cx)(
107
118
  "ml-4 inline-flex items-center justify-center rounded-full text-fg-subtle",
@@ -110,7 +121,8 @@ var Chip = (0, import_react.forwardRef)(function Chip2({
110
121
  "focus-visible:shadow-focus focus-visible:outline-none",
111
122
  "active:bg-bg-primary-subtle-90",
112
123
  disabled && "opacity-60 pointer-events-none bg-transparent text-fg-inactive",
113
- sizeStyles.close
124
+ sizeStyles.close,
125
+ removeClassName
114
126
  ),
115
127
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.Close, {})
116
128
  }
package/dist/index.mjs CHANGED
@@ -6,11 +6,11 @@ import { jsx, jsxs } from "react/jsx-runtime";
6
6
  var SIZE_MAP = {
7
7
  default: {
8
8
  container: "text-sm min-h-[40px] px-8 py-6 gap-8",
9
- close: "h-[16px] w-[16px]"
9
+ close: "size-16"
10
10
  },
11
11
  small: {
12
- container: "text-xs min-h-[32px] px-8 py-4 gap-6",
13
- close: "h-[16px] w-[16px]"
12
+ container: "text-xs min-h-32 px-8 py-4 gap-6",
13
+ close: "size-16"
14
14
  }
15
15
  };
16
16
  var BASE_STYLES = cx(
@@ -29,9 +29,15 @@ var Chip = forwardRef(function Chip2({
29
29
  onRemove,
30
30
  removeLabel = "Remove chip",
31
31
  disabled = false,
32
+ removeButtonProps = {},
32
33
  className,
33
34
  ...rest
34
35
  }, ref) {
36
+ const {
37
+ className: removeClassName,
38
+ onClick: onRemoveClick,
39
+ ...buttonProps
40
+ } = removeButtonProps;
35
41
  const sizeStyles = SIZE_MAP[size] ?? SIZE_MAP.default;
36
42
  const containerClass = cx(
37
43
  BASE_STYLES,
@@ -51,6 +57,7 @@ var Chip = forwardRef(function Chip2({
51
57
  className: containerClass,
52
58
  "data-disabled": disabled ? "true" : void 0,
53
59
  ...rest,
60
+ "aria-disabled": disabled ? true : rest["aria-disabled"],
54
61
  children: [
55
62
  /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-6", children: [
56
63
  shouldRenderChildren && /* @__PURE__ */ jsx("span", { className: "flex items-center gap-4 shrink-0 [&>*]:shrink-0", children: normalizedChildren.map(
@@ -61,12 +68,16 @@ var Chip = forwardRef(function Chip2({
61
68
  onRemove && /* @__PURE__ */ jsx(
62
69
  "button",
63
70
  {
71
+ ...buttonProps,
64
72
  type: "button",
65
73
  disabled,
66
74
  "aria-label": removeLabel,
75
+ "aria-labelledby": void 0,
67
76
  onClick: (event) => {
68
77
  event.stopPropagation();
69
- onRemove(event);
78
+ if (disabled) return;
79
+ onRemoveClick == null ? void 0 : onRemoveClick(event);
80
+ if (!event.defaultPrevented) onRemove(event);
70
81
  },
71
82
  className: cx(
72
83
  "ml-4 inline-flex items-center justify-center rounded-full text-fg-subtle",
@@ -75,7 +86,8 @@ var Chip = forwardRef(function Chip2({
75
86
  "focus-visible:shadow-focus focus-visible:outline-none",
76
87
  "active:bg-bg-primary-subtle-90",
77
88
  disabled && "opacity-60 pointer-events-none bg-transparent text-fg-inactive",
78
- sizeStyles.close
89
+ sizeStyles.close,
90
+ removeClassName
79
91
  ),
80
92
  children: /* @__PURE__ */ jsx(Close, {})
81
93
  }
@@ -0,0 +1,26 @@
1
+ # Removal, descriptions and focus
2
+
3
+ `Chip` remains a static native div with a forwarded `HTMLDivElement` ref. Passing
4
+ `onRemove` renders its existing native button. Set a specific `removeLabel`, such
5
+ as `Remove AC9M3N01`.
6
+
7
+ `removeButtonProps` forwards attributes, native handlers, style, className and an
8
+ `HTMLButtonElement` ref to that same button. It adds no wrapper or tab stop. Use
9
+ `aria-describedby` to associate host-owned context with the actual remove action;
10
+ descriptions on an ancestor are not inherited. A visual tooltip can still use
11
+ `TooltipTrigger asChild` around the Chip root.
12
+
13
+ Chip owns the remove button's `type="button"`, `disabled`, accessible name and
14
+ icon children. `type`, `disabled`, `aria-label`, `aria-labelledby` and `children`
15
+ are excluded from the public slot props and cannot override those core semantics.
16
+ The slot's click handler runs before `onRemove`; `event.preventDefault()` cancels
17
+ removal. Click propagation is stopped, including when cancelled, so an ancestor
18
+ does not also toggle the selection. A disabled Chip invokes neither click
19
+ callback. Other native events, including keyboard and focus handlers, forward
20
+ normally. Class names merge with the existing button presentation.
21
+
22
+ Collection state and focus after removal belong to the host. Use the public
23
+ button refs to focus the next enabled remove action, then the previous action,
24
+ then a stable host control when the last chip disappears. Do not query private
25
+ button markup or focus the noninteractive root. The Selection adoption story
26
+ demonstrates this recipe with descriptions and keyboard/pointer removal.
package/package.json CHANGED
@@ -1,36 +1,24 @@
1
1
  {
2
2
  "name": "@edux-design/chips",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css"
7
7
  ],
8
8
  "files": [
9
- "dist"
9
+ "dist",
10
+ "docs",
11
+ "README.md",
12
+ "CHANGELOG.md"
10
13
  ],
11
14
  "types": "./dist/index.d.ts",
12
15
  "exports": {
13
16
  ".": {
17
+ "types": "./dist/index.d.ts",
14
18
  "import": "./dist/index.mjs",
15
- "require": "./dist/index.js",
16
- "types": "./dist/index.d.ts"
19
+ "require": "./dist/index.js"
17
20
  }
18
21
  },
19
- "scripts": {
20
- "lint": "eslint . --max-warnings 0",
21
- "build": "tsup src/index.js --format esm,cjs --dts",
22
- "dev": "tsup src/index.js --watch --format esm,cjs --dts",
23
- "generate:component": "turbo gen react-component",
24
- "check-types": "tsc --noEmit"
25
- },
26
- "devDependencies": {
27
- "typescript": "^5.9.2",
28
- "tailwindcss": "^4.1.12",
29
- "postcss": "^8.5.6",
30
- "tsup": "^8.5.0",
31
- "@tailwindcss/cli": "^4.1.12",
32
- "@tailwindcss/postcss": "^4.1.12"
33
- },
34
22
  "dependencies": {
35
23
  "@edux-design/utils": "*",
36
24
  "@edux-design/icons": "*"