@mortenbrudvik/waveui 0.8.0 → 0.9.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/README.md +231 -85
- package/dist/components/data-display/InfoButton.cjs +2 -0
- package/dist/components/data-display/InfoButton.cjs.map +1 -0
- package/dist/components/data-display/InfoButton.mjs +173 -0
- package/dist/components/data-display/InfoButton.mjs.map +1 -0
- package/dist/components/data-display/InfoLabel.cjs +1 -1
- package/dist/components/data-display/InfoLabel.cjs.map +1 -1
- package/dist/components/data-display/InfoLabel.mjs +39 -96
- package/dist/components/data-display/InfoLabel.mjs.map +1 -1
- package/dist/components/input/Checkbox.cjs +1 -1
- package/dist/components/input/Checkbox.cjs.map +1 -1
- package/dist/components/input/Checkbox.mjs +91 -75
- package/dist/components/input/Checkbox.mjs.map +1 -1
- package/dist/components/input/ColorPicker.parts.cjs +1 -1
- package/dist/components/input/ColorPicker.parts.cjs.map +1 -1
- package/dist/components/input/ColorPicker.parts.mjs +1 -1
- package/dist/components/input/ColorPicker.parts.mjs.map +1 -1
- package/dist/components/input/Combobox.cjs +1 -1
- package/dist/components/input/Combobox.cjs.map +1 -1
- package/dist/components/input/Combobox.expand.cjs +1 -1
- package/dist/components/input/Combobox.expand.cjs.map +1 -1
- package/dist/components/input/Combobox.expand.mjs +20 -20
- package/dist/components/input/Combobox.expand.mjs.map +1 -1
- package/dist/components/input/Combobox.mjs +143 -138
- package/dist/components/input/Combobox.mjs.map +1 -1
- package/dist/components/input/DatePicker.cjs +1 -1
- package/dist/components/input/DatePicker.cjs.map +1 -1
- package/dist/components/input/DatePicker.mjs +213 -209
- package/dist/components/input/DatePicker.mjs.map +1 -1
- package/dist/components/input/Dropdown.cjs +1 -1
- package/dist/components/input/Dropdown.cjs.map +1 -1
- package/dist/components/input/Dropdown.mjs +80 -74
- package/dist/components/input/Dropdown.mjs.map +1 -1
- package/dist/components/input/Field.cjs +1 -1
- package/dist/components/input/Field.cjs.map +1 -1
- package/dist/components/input/Field.mjs +99 -66
- package/dist/components/input/Field.mjs.map +1 -1
- package/dist/components/input/Input.cjs +1 -1
- package/dist/components/input/Input.cjs.map +1 -1
- package/dist/components/input/Input.mjs +79 -55
- package/dist/components/input/Input.mjs.map +1 -1
- package/dist/components/input/Label.cjs +1 -1
- package/dist/components/input/Label.cjs.map +1 -1
- package/dist/components/input/Label.mjs +19 -13
- package/dist/components/input/Label.mjs.map +1 -1
- package/dist/components/input/Rating.cjs +1 -1
- package/dist/components/input/Rating.cjs.map +1 -1
- package/dist/components/input/Rating.item.cjs +2 -0
- package/dist/components/input/Rating.item.cjs.map +1 -0
- package/dist/components/input/Rating.item.mjs +255 -0
- package/dist/components/input/Rating.item.mjs.map +1 -0
- package/dist/components/input/Rating.mjs +150 -151
- package/dist/components/input/Rating.mjs.map +1 -1
- package/dist/components/input/SearchBox.cjs +1 -1
- package/dist/components/input/SearchBox.cjs.map +1 -1
- package/dist/components/input/SearchBox.mjs +146 -115
- package/dist/components/input/SearchBox.mjs.map +1 -1
- package/dist/components/input/Select.cjs +1 -1
- package/dist/components/input/Select.cjs.map +1 -1
- package/dist/components/input/Select.mjs +34 -25
- package/dist/components/input/Select.mjs.map +1 -1
- package/dist/components/input/Slider.cjs +1 -1
- package/dist/components/input/Slider.cjs.map +1 -1
- package/dist/components/input/Slider.mjs +77 -54
- package/dist/components/input/Slider.mjs.map +1 -1
- package/dist/components/input/SpinButton.cjs +1 -1
- package/dist/components/input/SpinButton.cjs.map +1 -1
- package/dist/components/input/SpinButton.mjs +198 -96
- package/dist/components/input/SpinButton.mjs.map +1 -1
- package/dist/components/input/Switch.cjs +1 -1
- package/dist/components/input/Switch.cjs.map +1 -1
- package/dist/components/input/Switch.mjs +71 -55
- package/dist/components/input/Switch.mjs.map +1 -1
- package/dist/components/input/TagPicker.cjs +1 -1
- package/dist/components/input/TagPicker.cjs.map +1 -1
- package/dist/components/input/TagPicker.mjs +142 -116
- package/dist/components/input/TagPicker.mjs.map +1 -1
- package/dist/components/input/Textarea.cjs +1 -1
- package/dist/components/input/Textarea.cjs.map +1 -1
- package/dist/components/input/Textarea.mjs +28 -21
- package/dist/components/input/Textarea.mjs.map +1 -1
- package/dist/components/input/TimePicker.cjs +1 -1
- package/dist/components/input/TimePicker.cjs.map +1 -1
- package/dist/components/input/TimePicker.mjs +189 -184
- package/dist/components/input/TimePicker.mjs.map +1 -1
- package/dist/components/input/fieldLabel.cjs +2 -0
- package/dist/components/input/fieldLabel.cjs.map +1 -0
- package/dist/components/input/fieldLabel.mjs +17 -0
- package/dist/components/input/fieldLabel.mjs.map +1 -0
- package/dist/components/input/inputLook.cjs +2 -0
- package/dist/components/input/inputLook.cjs.map +1 -0
- package/dist/components/input/inputLook.mjs +28 -0
- package/dist/components/input/inputLook.mjs.map +1 -0
- package/dist/components/input/pickerStyles.cjs +1 -1
- package/dist/components/input/pickerStyles.cjs.map +1 -1
- package/dist/components/input/pickerStyles.mjs +42 -4
- package/dist/components/input/pickerStyles.mjs.map +1 -1
- package/dist/components/navigation/Menu.popover.cjs +1 -1
- package/dist/components/navigation/Menu.popover.cjs.map +1 -1
- package/dist/components/navigation/Menu.popover.mjs +10 -10
- package/dist/components/navigation/Menu.root.cjs +1 -1
- package/dist/components/navigation/Menu.root.cjs.map +1 -1
- package/dist/components/navigation/Menu.root.mjs +10 -10
- package/dist/components/overlays/Popover.cjs +1 -1
- package/dist/components/overlays/Popover.cjs.map +1 -1
- package/dist/components/overlays/Popover.mjs +203 -208
- package/dist/components/overlays/Popover.mjs.map +1 -1
- package/dist/components/overlays/Popover.shared.cjs +1 -1
- package/dist/components/overlays/Popover.shared.cjs.map +1 -1
- package/dist/components/overlays/Popover.shared.mjs +82 -77
- package/dist/components/overlays/Popover.shared.mjs.map +1 -1
- package/dist/components/provider/WaveProvider.cjs +1 -1
- package/dist/components/provider/WaveProvider.cjs.map +1 -1
- package/dist/components/provider/WaveProvider.mjs +25 -19
- package/dist/components/provider/WaveProvider.mjs.map +1 -1
- package/dist/hooks/useFieldControl.cjs.map +1 -1
- package/dist/hooks/useFieldControl.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +805 -99
- package/dist/index.d.ts +805 -99
- package/dist/index.mjs +101 -99
- package/dist/lib/classNames.cjs +1 -1
- package/dist/lib/classNames.cjs.map +1 -1
- package/dist/lib/classNames.mjs +74 -66
- package/dist/lib/classNames.mjs.map +1 -1
- package/dist/lib/styles.cjs +1 -1
- package/dist/lib/styles.cjs.map +1 -1
- package/dist/lib/styles.mjs +21 -4
- package/dist/lib/styles.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/styles/tokens.css +13 -0
|
@@ -1,82 +1,106 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn as e } from "../../lib/cn.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
3
|
+
import { resolveDeprecatedProp as t } from "../../lib/dev.mjs";
|
|
4
|
+
import { renderSlot as n, slotRendersContent as r } from "../../lib/slot.mjs";
|
|
5
|
+
import { inputClassNames as i } from "../../lib/classNames.mjs";
|
|
6
|
+
import { useId as a } from "../../hooks/useId.mjs";
|
|
7
|
+
import { joinIds as o } from "../../lib/aria.mjs";
|
|
8
|
+
import { useFieldContext as s, useFieldControl as c } from "../../hooks/useFieldControl.mjs";
|
|
9
|
+
import { inputAppearanceClasses as l, inputFocus as u, inputFocusWithin as d, inputHeightClasses as f, inputPaddingClasses as p, inputTextClasses as m } from "../../lib/styles.mjs";
|
|
10
|
+
import { legacyNativeSize as h, useInputLook as g } from "./inputLook.mjs";
|
|
9
11
|
import "react";
|
|
10
|
-
import { Fragment as
|
|
12
|
+
import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
11
13
|
//#region src/components/input/Input.tsx
|
|
12
|
-
function
|
|
14
|
+
function b(e) {
|
|
13
15
|
return e === !1 || e === "false";
|
|
14
16
|
}
|
|
15
|
-
function
|
|
16
|
-
let
|
|
17
|
-
if (!l || typeof t != "string" ||
|
|
17
|
+
function x(t, n, r, i) {
|
|
18
|
+
let o = s(), c = a("error"), l = !b(r) && (t === !0 || typeof t == "string" && t !== "");
|
|
19
|
+
if (!l || typeof t != "string" || o?.hasErrorMessage) return {
|
|
18
20
|
invalid: l,
|
|
19
21
|
messageId: void 0,
|
|
20
22
|
message: null
|
|
21
23
|
};
|
|
22
|
-
let { id: u, className:
|
|
24
|
+
let { id: u, className: d, ...f } = n ?? {}, p = u ?? c;
|
|
23
25
|
return {
|
|
24
26
|
invalid: l,
|
|
25
|
-
messageId:
|
|
26
|
-
message: /* @__PURE__ */
|
|
27
|
+
messageId: p,
|
|
28
|
+
message: /* @__PURE__ */ v("span", {
|
|
27
29
|
role: "alert",
|
|
28
|
-
...
|
|
29
|
-
id:
|
|
30
|
-
className: e(
|
|
30
|
+
...f,
|
|
31
|
+
id: p,
|
|
32
|
+
className: e(i, "mt-1 block text-caption-1 text-error", d),
|
|
31
33
|
children: t
|
|
32
34
|
})
|
|
33
35
|
};
|
|
34
36
|
}
|
|
35
|
-
function
|
|
36
|
-
return
|
|
37
|
+
function S(e, t) {
|
|
38
|
+
return b(t) ? !1 : e || t === !0 || t === "true";
|
|
37
39
|
}
|
|
38
|
-
var
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
40
|
+
var C = {
|
|
41
|
+
small: {
|
|
42
|
+
before: "ps-1.5",
|
|
43
|
+
after: "pe-1.5",
|
|
44
|
+
input: "px-1.5"
|
|
45
|
+
},
|
|
46
|
+
medium: {
|
|
47
|
+
before: "ps-2",
|
|
48
|
+
after: "pe-2",
|
|
49
|
+
input: "px-2"
|
|
50
|
+
},
|
|
51
|
+
large: {
|
|
52
|
+
before: "ps-3",
|
|
53
|
+
after: "pe-3",
|
|
54
|
+
input: "px-3"
|
|
55
|
+
}
|
|
56
|
+
}, w = ({ error: a, errorMessageProps: s, size: b, htmlSize: w, appearance: T, contentBefore: E, contentAfter: D, onChange: O, onValueChange: k, className: A, ref: j, id: M, "aria-label": ee, "aria-labelledby": N, "aria-describedby": P, "aria-invalid": F, "aria-required": I, "aria-errormessage": L, required: R, ...z }) => {
|
|
57
|
+
let { invalid: B, messageId: V, message: H } = x(a, s, F, i.errorMessage), U = c({
|
|
58
|
+
id: M,
|
|
59
|
+
"aria-label": ee,
|
|
60
|
+
"aria-labelledby": N,
|
|
61
|
+
"aria-describedby": o(P, V),
|
|
62
|
+
"aria-invalid": F ?? (B || void 0),
|
|
63
|
+
"aria-required": I,
|
|
64
|
+
required: R
|
|
65
|
+
}, { nativeRequired: !0 }), W = S(B, U["aria-invalid"]), G = h(b), K = t("Input", w, G, "size={number}", "htmlSize"), { size: q, appearance: J } = g(G === void 0 && typeof b != "number" ? b : void 0, T), Y = O || k ? (e) => {
|
|
66
|
+
O?.(e), k?.(e.currentTarget.value);
|
|
67
|
+
} : void 0, X = {
|
|
68
|
+
...z,
|
|
69
|
+
...U,
|
|
70
|
+
"aria-errormessage": o(L, V),
|
|
71
|
+
onChange: Y
|
|
72
|
+
}, Z = r(E), Q = r(D), $;
|
|
73
|
+
if (Z || Q) {
|
|
74
|
+
let { style: t, hidden: r, ...a } = X;
|
|
75
|
+
$ = /* @__PURE__ */ y("span", {
|
|
76
|
+
hidden: r,
|
|
77
|
+
style: t,
|
|
78
|
+
"data-size": q,
|
|
79
|
+
"data-appearance": J,
|
|
80
|
+
className: e(i.root, "inline-flex w-full items-center", f[q], m[q], l[J], "text-foreground", d, W && "border-destructive", z.disabled && "cursor-not-allowed opacity-50 has-focus-visible:opacity-100", A),
|
|
61
81
|
children: [
|
|
62
|
-
|
|
63
|
-
/* @__PURE__ */
|
|
64
|
-
ref:
|
|
65
|
-
className: e(
|
|
66
|
-
...a
|
|
82
|
+
Z && n(E, "span", e(i.contentBefore, "shrink-0", C[q].before)),
|
|
83
|
+
/* @__PURE__ */ v("input", {
|
|
84
|
+
ref: j,
|
|
85
|
+
className: e(i.input, "h-full w-full min-w-0 bg-transparent", C[q].input, m[q], "text-foreground", "placeholder:text-muted-foreground", "focus:outline-hidden", "disabled:cursor-not-allowed"),
|
|
86
|
+
...a,
|
|
87
|
+
size: K
|
|
67
88
|
}),
|
|
68
|
-
|
|
89
|
+
Q && n(D, "span", e(i.contentAfter, "shrink-0", C[q].after))
|
|
69
90
|
]
|
|
70
91
|
});
|
|
71
|
-
} else
|
|
72
|
-
ref:
|
|
73
|
-
|
|
74
|
-
|
|
92
|
+
} else $ = /* @__PURE__ */ v("input", {
|
|
93
|
+
ref: j,
|
|
94
|
+
"data-size": q,
|
|
95
|
+
"data-appearance": J,
|
|
96
|
+
className: e(i.root, i.input, f[q], "w-full", p[q], m[q], l[J], "text-foreground placeholder:text-muted-foreground", u, "disabled:cursor-not-allowed disabled:opacity-50", W && "border-destructive", A),
|
|
97
|
+
...X,
|
|
98
|
+
size: K
|
|
75
99
|
});
|
|
76
|
-
return
|
|
100
|
+
return H ? /* @__PURE__ */ y(_, { children: [$, H] }) : $;
|
|
77
101
|
};
|
|
78
|
-
|
|
102
|
+
w.displayName = "Input";
|
|
79
103
|
//#endregion
|
|
80
|
-
export {
|
|
104
|
+
export { w as Input, S as isInvalidLook, x as useControlErrorMessage };
|
|
81
105
|
|
|
82
106
|
//# sourceMappingURL=Input.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.mjs","names":["useId","_jsx","_Fragment","useId$1","isAriaValid","ariaInvalid","useControlErrorMessage","field","useFieldContext","generatedId","invalid","consumerAriaInvalid","error","ownId","messageClassName","messageRest","errorMessageProps","messageId","cn","partClassName","isInvalidLook","ownError","Input","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaRequired","ariaErrorMessage","props","inputClassNames","fieldProps","useFieldControl","joinIds","invalidLook","handleChange","onChange","onValueChange","event","controlProps","hasBefore","slotRendersContent","contentBefore","hasAfter","contentAfter","control","inputProps","inputFocusWithin","className","renderSlot","inputFocus","message","Fragment"],"sources":["../../../src/components/input/Input.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { joinIds } from '../../lib/aria';\nimport { inputClassNames } from '../../lib/classNames';\nimport { renderSlot, slotRendersContent } from '../../lib/slot';\nimport { inputFocus, inputFocusWithin, inputInvalid, inputInvalidWithin } from '../../lib/styles';\nimport type { Slot } from '../../lib/types';\nimport { useId } from '../../hooks/useId';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\n\n/**\n * Props of the error message element that {@link Input}, `Select` and `Textarea` render after the\n * control for a string `error` (`id`, `className`, `role`, data attributes, …).\n */\nexport interface InputErrorMessageProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Ref to the message `<span>`. */\n ref?: React.Ref<HTMLSpanElement>;\n /** Any `data-*` attribute. */\n [dataAttribute: `data-${string}`]: unknown;\n}\n\n/**\n * Result of {@link useControlErrorMessage}.\n *\n * @internal Not exported from the package.\n */\nexport interface ControlErrorMessage {\n /**\n * Whether `error` marks the control invalid (a non-empty string or `true`), unless the consumer\n * set `aria-invalid` to `false`/`\"false\"`.\n */\n invalid: boolean;\n /** The id of the rendered message, joined into `aria-describedby`/`aria-errormessage`. */\n messageId: string | undefined;\n /** The message element to render after the control, or `null`. */\n message: React.ReactElement | null;\n}\n\n/** Whether an `aria-invalid` value explicitly reports the control as valid. */\nfunction isAriaValid(ariaInvalid: React.AriaAttributes['aria-invalid']): boolean {\n return ariaInvalid === false || ariaInvalid === 'false';\n}\n\n/**\n * Shared by Input, Select and Textarea (internal): a non-empty string `error` renders a sibling\n * `<span role=\"alert\">` message, unless the surrounding `Field` already renders its own error\n * (`FieldContext.hasErrorMessage`); `true` only marks the control invalid. The consumer's\n * `aria-invalid` of `false`/`\"false\"` wins over `error`: the control is valid, so nothing is\n * marked invalid and no message is rendered or referenced (ARIA: an error message of a valid\n * control is hidden).\n *\n * `partClassName` is the host's stable `errorMessage` class, first in the message's classes\n * (Input, Select and Textarea each pass their own).\n *\n * @internal Not exported from the package.\n */\nexport function useControlErrorMessage(\n error: string | boolean | undefined,\n errorMessageProps: InputErrorMessageProps | undefined,\n consumerAriaInvalid?: React.AriaAttributes['aria-invalid'],\n partClassName?: string,\n): ControlErrorMessage {\n const field = useFieldContext();\n const generatedId = useId('error');\n const invalid =\n !isAriaValid(consumerAriaInvalid) &&\n (error === true || (typeof error === 'string' && error !== ''));\n const showMessage = invalid && typeof error === 'string' && !field?.hasErrorMessage;\n if (!showMessage) return { invalid, messageId: undefined, message: null };\n\n const { id: ownId, className: messageClassName, ...messageRest } = errorMessageProps ?? {};\n const messageId = ownId ?? generatedId;\n const message = (\n <span\n role=\"alert\"\n {...messageRest}\n id={messageId}\n className={cn(partClassName, 'mt-1 block text-caption-1 text-error', messageClassName)}\n >\n {error}\n </span>\n );\n return { invalid, messageId, message };\n}\n\n/**\n * Whether a text control shows the invalid look (error border), shared by Input, Select, Textarea\n * and SearchBox (internal): its own `error`, or a resolved `aria-invalid` of `true`/`\"true\"` —\n * from the consumer or from the surrounding `Field` (`useFieldControl`) — so the look always\n * matches the state assistive technology reports. A resolved `false`/`\"false\"` (the consumer's\n * override) never shows it, even with an own `error`. `\"grammar\"`/`\"spelling\"` alone do not\n * count; with an own `error` they keep the look (the control is reported invalid).\n *\n * @internal Not exported from the package.\n */\nexport function isInvalidLook(\n ownError: boolean,\n ariaInvalid: React.AriaAttributes['aria-invalid'],\n): boolean {\n if (isAriaValid(ariaInvalid)) return false;\n return ownError || ariaInvalid === true || ariaInvalid === 'true';\n}\n\n/** Properties for the Input component. */\nexport interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {\n /**\n * Validation error.\n * - A non-empty string renders the message in a `role=\"alert\"` element **after** the field (a\n * sibling, so it does not change which element receives `ref`, `className` or `style`) and\n * links it through `aria-describedby` and `aria-errormessage`. Inside a `Field` that renders\n * its own `error`, the message is not repeated.\n * - `true` only marks the input invalid (`aria-invalid` and the error border), as in 0.4.\n *\n * The error border also shows whenever the input ends up `aria-invalid=\"true\"` without this\n * prop (an `error` on the surrounding `Field`, or your own `aria-invalid`).\n * Your own `aria-invalid={false}` (or `\"false\"`) wins over this prop: the input is reported\n * valid and shows neither the error border nor the message.\n * Use `Field` (`label`, `hint`, `error`) for a complete field layout.\n */\n error?: string | boolean;\n /** Props of the error message element (`id`, `className`, …) rendered for a string `error`. */\n errorMessageProps?: InputErrorMessageProps;\n /**\n * Slot rendered before the input text (e.g., an icon). With content in either slot, a bordered\n * `<span>` around the input draws the field: it receives `className`, `style` and `hidden`,\n * while `ref`, `id`, `aria-*`, `data-*`, handlers and native attributes stay on the `<input>`.\n * A value that renders nothing (`false`, `''`, `[]`) is no slot.\n */\n contentBefore?: Slot<'span'>;\n /** Slot rendered after the input text (e.g., a suffix). Same wrapper as `contentBefore`. */\n contentAfter?: Slot<'span'>;\n /**\n * Called with the new string value on every change, next to the native `onChange` event\n * handler (`onValueChange={setName}` instead of `onChange={(e) => setName(e.target.value)}`).\n */\n onValueChange?: (value: string) => void;\n /** Ref to the `<input>` element (also with `contentBefore`/`contentAfter`). */\n ref?: React.Ref<HTMLInputElement>;\n}\n\n/**\n * A single-line text input with Fluent styling: a 1px border with an accessible bottom stroke, a\n * primary bottom border while focused, optional `contentBefore`/`contentAfter` slots and an\n * optional error message. Inside a `Field` it picks up the label, hint, error, `required` (native\n * attribute) and invalid state automatically.\n *\n * Every prop reaches the `<input>`, except with slot content: then a bordered `<span>` wrapper\n * draws the field and receives `className`, `style` and `hidden` (`ref` stays on the input).\n *\n * @example\n * <Field label=\"Email\" hint=\"We never share it\" required>\n * <Input type=\"email\" value={email} onValueChange={setEmail} />\n * </Field>\n */\nexport const Input = ({\n error,\n errorMessageProps,\n contentBefore,\n contentAfter,\n onChange,\n onValueChange,\n className,\n ref,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n required,\n ...props\n}: InputProps) => {\n const { invalid, messageId, message } = useControlErrorMessage(\n error,\n errorMessageProps,\n ariaInvalid,\n inputClassNames.errorMessage,\n );\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': joinIds(ariaDescribedBy, messageId),\n 'aria-invalid': ariaInvalid ?? (invalid || undefined),\n 'aria-required': ariaRequired,\n required,\n },\n { nativeRequired: true },\n );\n const invalidLook = isInvalidLook(invalid, fieldProps['aria-invalid']);\n\n const handleChange =\n onChange || onValueChange\n ? (event: React.ChangeEvent<HTMLInputElement>) => {\n onChange?.(event);\n onValueChange?.(event.currentTarget.value);\n }\n : undefined;\n\n const controlProps = {\n ...props,\n ...fieldProps,\n 'aria-errormessage': joinIds(ariaErrorMessage, messageId),\n onChange: handleChange,\n };\n\n const hasBefore = slotRendersContent(contentBefore);\n const hasAfter = slotRendersContent(contentAfter);\n\n let control: React.ReactElement;\n if (hasBefore || hasAfter) {\n // The bordered wrapper is the visible field: `className`, `style` and `hidden` size, style and\n // hide it; `ref`, `id`, `aria-*`, `data-*`, handlers and native attributes go to the input.\n const { style, hidden, ...inputProps } = controlProps;\n control = (\n <span\n hidden={hidden}\n style={style}\n className={cn(\n inputClassNames.root,\n 'inline-flex h-8 w-full items-center rounded border border-input border-b-stroke-accessible bg-background text-body-1 text-foreground',\n inputFocusWithin,\n invalidLook && inputInvalidWithin,\n // The dimmed look lifts while a focus ring shows inside the wrapper (focusable slot\n // content; the disabled input never takes focus): opacity would dim the ring below 3:1.\n props.disabled && 'cursor-not-allowed opacity-50 has-focus-visible:opacity-100',\n className,\n )}\n >\n {hasBefore &&\n renderSlot(contentBefore, 'span', cn(inputClassNames.contentBefore, 'shrink-0 ps-2'))}\n <input\n ref={ref}\n className={cn(\n inputClassNames.input,\n 'h-full w-full min-w-0 bg-transparent px-2 text-body-1 text-foreground',\n 'placeholder:text-muted-foreground',\n 'focus:outline-hidden',\n 'disabled:cursor-not-allowed',\n )}\n {...inputProps}\n />\n {hasAfter &&\n renderSlot(contentAfter, 'span', cn(inputClassNames.contentAfter, 'shrink-0 pe-2'))}\n </span>\n );\n } else {\n control = (\n <input\n ref={ref}\n className={cn(\n inputClassNames.root,\n inputClassNames.input,\n 'h-8 w-full rounded border border-input border-b-stroke-accessible bg-background px-3 text-body-1 text-foreground',\n 'placeholder:text-muted-foreground',\n inputFocus,\n 'disabled:cursor-not-allowed disabled:opacity-50',\n invalidLook && inputInvalid,\n className,\n )}\n {...controlProps}\n />\n );\n }\n\n if (!message) return control;\n return (\n <>\n {control}\n {message}\n </>\n );\n};\n\nInput.displayName = 'Input';\n"],"mappings":";;;;;;;;;;;AAuCA,SAASI,EAAY,GAA4D;CAC/E,OAAOC,MAAgB,MAASA,MAAgB;AAClD;AAeA,SAAgBC,EACd,GACA,GACA,GACA,GACqB;CACrB,IAAMC,IAAQC,EAAgB,GACxBC,IAAcT,EAAM,OAAO,GAC3BU,IACJ,CAACN,EAAYO,CAAmB,MAC/BC,MAAU,MAAS,OAAOA,KAAU,YAAYA,MAAU;CAE7D,IADoB,MAAW,OAAOA,KAAU,YAAaL,GAAO,iBAClD,OAAO;EAAE;EAAS,WAAW,KAAA;EAAW,SAAS;CAAK;CAExE,IAAM,EAAE,IAAIM,GAAO,WAAWC,GAAkB,GAAGC,MAAgBC,KAAqB,CAAC,GACnFC,IAAYJ,KAASJ;CAW3B,OAAO;EAAE;EAAS;EAAW,SAT3BR,kBAAC,QAAD;GACE,MAAK;GACL,GAAIc;GACJ,IAAIE;GACJ,WAAWC,EAAGC,GAAe,wCAAwCL,CAAgB;GAEpF,UAAAF;EACG,CAEqB;CAAQ;AACvC;AAYA,SAAgBQ,EACd,GACA,GACS;CAET,OADIhB,EAAYC,CAAW,IAAU,KAC9BgB,KAAYhB,MAAgB,MAAQA,MAAgB;AAC7D;AAqDA,IAAaiB,KAAS,EACpB,UACA,sBACA,kBACA,iBACA,aACA,kBACA,cACA,QACA,OACA,cAAcC,GACd,mBAAmBC,GACnB,oBAAoBC,GACpB,gBAAgBpB,GAChB,iBAAiBqB,GACjB,qBAAqBC,GACrB,aACA,GAAGC,QACa;CAChB,IAAM,EAAE,YAAS,cAAW,eAAYtB,EACtCM,GACAI,GACAX,GACAwB,EAAgB,YAClB,GACMC,IAAaC,EACjB;EACE;EACA,cAAcR;EACd,mBAAmBC;EACnB,oBAAoBQ,EAAQP,GAAiBR,CAAS;EACtD,gBAAgBZ,MAAgBK,KAAW,KAAA;EAC3C,iBAAiBgB;EACjB;CACF,GACA,EAAE,gBAAgB,GAAK,CACzB,GACMO,IAAcb,EAAcV,GAASoB,EAAW,eAAe,GAE/DI,IACJC,KAAYC,KACP,MAA+C;EAE9C,AADAD,IAAWE,CAAK,GAChBD,IAAgBC,EAAM,cAAc,KAAK;CAC3C,IACA,KAAA,GAEAC,IAAe;EACnB,GAAGV;EACH,GAAGE;EACH,qBAAqBE,EAAQL,GAAkBV,CAAS;EACxD,UAAUiB;CACZ,GAEMK,IAAYC,EAAmBC,CAAa,GAC5CC,IAAWF,EAAmBG,CAAY,GAE5CC;CACJ,IAAIL,KAAaG,GAAU;EAGzB,IAAM,EAAE,UAAO,WAAQ,GAAGG,MAAeP;EACzC,IACE,kBAAC,QAAD;GACU;GACD;GACP,WAAWpB,EACTW,EAAgB,MAChB,wIACAiB,GACAb,KAAA,wDAGAL,EAAM,YAAY,+DAClBmB,CACF;GAZF,UAAA;IAcGR,KACCS,EAAWP,GAAe,QAAQvB,EAAGW,EAAgB,eAAe,eAAe,CAAC;IACtF,kBAAC,SAAD;KACO;KACL,WAAWX,EACTW,EAAgB,OAChB,yEACA,qCACA,wBACA,6BACF;KACA,GAAIgB;IACL,CAAA;IACAH,KACCM,EAAWL,GAAc,QAAQzB,EAAGW,EAAgB,cAAc,eAAe,CAAC;GAChF;;CAEV,OACE,IACE,kBAAC,SAAD;EACO;EACL,WAAWX,EACTW,EAAgB,MAChBA,EAAgB,OAChB,oHACA,qCACAoB,GACA,mDACAhB,KAAA,iDACAc,CACF;EACA,GAAIT;CACL,CAAA;CAKL,OADKY,IAEH,kBAAAhD,GAAA,EAAA,UAAA,CACG0C,GACAM,CACD,EAAA,CAAA,IALiBN;AAOvB;AAEA,EAAM,cAAc"}
|
|
1
|
+
{"version":3,"file":"Input.mjs","names":["useId","_jsx","_Fragment","useId$1","isAriaValid","ariaInvalid","useControlErrorMessage","field","useFieldContext","generatedId","invalid","consumerAriaInvalid","error","ownId","messageClassName","messageRest","errorMessageProps","messageId","cn","partClassName","isInvalidLook","ownError","SLOT_PADDING","Input","sizeProp","appearanceProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaRequired","ariaErrorMessage","props","inputClassNames","fieldProps","useFieldControl","joinIds","invalidLook","numericSize","legacyNativeSize","nativeSize","resolveDeprecatedProp","htmlSize","useInputLook","handleChange","onChange","onValueChange","event","controlProps","hasBefore","slotRendersContent","contentBefore","hasAfter","contentAfter","control","inputProps","size","appearance","inputHeightClasses","inputTextClasses","inputAppearanceClasses","inputFocusWithin","className","renderSlot","inputPaddingClasses","inputFocus","message","Fragment"],"sources":["../../../src/components/input/Input.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { joinIds } from '../../lib/aria';\nimport { inputClassNames } from '../../lib/classNames';\nimport { resolveDeprecatedProp } from '../../lib/dev';\nimport { renderSlot, slotRendersContent } from '../../lib/slot';\nimport {\n inputAppearanceClasses,\n inputFocus,\n inputFocusWithin,\n inputHeightClasses,\n inputInvalid,\n inputInvalidWithin,\n inputPaddingClasses,\n inputTextClasses,\n} from '../../lib/styles';\nimport type { CoreSize, InputAppearance, Slot } from '../../lib/types';\nimport { useId } from '../../hooks/useId';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { legacyNativeSize, useInputLook } from './inputLook';\n\n/**\n * Props of the error message element that {@link Input}, `Select` and `Textarea` render after the\n * control for a string `error` (`id`, `className`, `role`, data attributes, …).\n */\nexport interface InputErrorMessageProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Ref to the message `<span>`. */\n ref?: React.Ref<HTMLSpanElement>;\n /** Any `data-*` attribute. */\n [dataAttribute: `data-${string}`]: unknown;\n}\n\n/**\n * Result of {@link useControlErrorMessage}.\n *\n * @internal Not exported from the package.\n */\nexport interface ControlErrorMessage {\n /**\n * Whether `error` marks the control invalid (a non-empty string or `true`), unless the consumer\n * set `aria-invalid` to `false`/`\"false\"`.\n */\n invalid: boolean;\n /** The id of the rendered message, joined into `aria-describedby`/`aria-errormessage`. */\n messageId: string | undefined;\n /** The message element to render after the control, or `null`. */\n message: React.ReactElement | null;\n}\n\n/** Whether an `aria-invalid` value explicitly reports the control as valid. */\nfunction isAriaValid(ariaInvalid: React.AriaAttributes['aria-invalid']): boolean {\n return ariaInvalid === false || ariaInvalid === 'false';\n}\n\n/**\n * Shared by Input, Select and Textarea (internal): a non-empty string `error` renders a sibling\n * `<span role=\"alert\">` message, unless the surrounding `Field` already renders its own error\n * (`FieldContext.hasErrorMessage`); `true` only marks the control invalid. The consumer's\n * `aria-invalid` of `false`/`\"false\"` wins over `error`: the control is valid, so nothing is\n * marked invalid and no message is rendered or referenced (ARIA: an error message of a valid\n * control is hidden).\n *\n * `partClassName` is the host's stable `errorMessage` class, first in the message's classes\n * (Input, Select and Textarea each pass their own).\n *\n * @internal Not exported from the package.\n */\nexport function useControlErrorMessage(\n error: string | boolean | undefined,\n errorMessageProps: InputErrorMessageProps | undefined,\n consumerAriaInvalid?: React.AriaAttributes['aria-invalid'],\n partClassName?: string,\n): ControlErrorMessage {\n const field = useFieldContext();\n const generatedId = useId('error');\n const invalid =\n !isAriaValid(consumerAriaInvalid) &&\n (error === true || (typeof error === 'string' && error !== ''));\n const showMessage = invalid && typeof error === 'string' && !field?.hasErrorMessage;\n if (!showMessage) return { invalid, messageId: undefined, message: null };\n\n const { id: ownId, className: messageClassName, ...messageRest } = errorMessageProps ?? {};\n const messageId = ownId ?? generatedId;\n const message = (\n <span\n role=\"alert\"\n {...messageRest}\n id={messageId}\n className={cn(partClassName, 'mt-1 block text-caption-1 text-error', messageClassName)}\n >\n {error}\n </span>\n );\n return { invalid, messageId, message };\n}\n\n/**\n * Whether a text control shows the invalid look (error border), shared by Input, Select, Textarea\n * and SearchBox (internal): its own `error`, or a resolved `aria-invalid` of `true`/`\"true\"` —\n * from the consumer or from the surrounding `Field` (`useFieldControl`) — so the look always\n * matches the state assistive technology reports. A resolved `false`/`\"false\"` (the consumer's\n * override) never shows it, even with an own `error`. `\"grammar\"`/`\"spelling\"` alone do not\n * count; with an own `error` they keep the look (the control is reported invalid).\n *\n * @internal Not exported from the package.\n */\nexport function isInvalidLook(\n ownError: boolean,\n ariaInvalid: React.AriaAttributes['aria-invalid'],\n): boolean {\n if (isAriaValid(ariaInvalid)) return false;\n return ownError || ariaInvalid === true || ariaInvalid === 'true';\n}\n\n/** Padding of the slot spans and the inner input of the slot wrapper, per size. */\nconst SLOT_PADDING: Readonly<Record<CoreSize, { before: string; after: string; input: string }>> = {\n small: { before: 'ps-1.5', after: 'pe-1.5', input: 'px-1.5' },\n medium: { before: 'ps-2', after: 'pe-2', input: 'px-2' },\n large: { before: 'ps-3', after: 'pe-3', input: 'px-3' },\n};\n\n/** Properties for the Input component. */\nexport interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {\n /**\n * Validation error.\n * - A non-empty string renders the message in a `role=\"alert\"` element **after** the field (a\n * sibling, so it does not change which element receives `ref`, `className` or `style`) and\n * links it through `aria-describedby` and `aria-errormessage`. Inside a `Field` that renders\n * its own `error`, the message is not repeated.\n * - `true` only marks the input invalid (`aria-invalid` and the error border), as in 0.4.\n *\n * The error border also shows whenever the input ends up `aria-invalid=\"true\"` without this\n * prop (an `error` on the surrounding `Field`, or your own `aria-invalid`).\n * Your own `aria-invalid={false}` (or `\"false\"`) wins over this prop: the input is reported\n * valid and shows neither the error border nor the message.\n * Use `Field` (`label`, `hint`, `error`) for a complete field layout.\n */\n error?: string | boolean;\n /** Props of the error message element (`id`, `className`, …) rendered for a string `error`. */\n errorMessageProps?: InputErrorMessageProps;\n /**\n * Size of the field: `small` (24px tall), `medium` (32px) or `large` (40px). Default: the\n * surrounding Field's `size`, else `WaveProvider inputDefaults.size`, else `'medium'`.\n *\n * A number is the native `size` attribute (the visible width in characters), as in 0.8: it\n * still renders, warns once in development and is removed in 1.0. Use `htmlSize` for it.\n * A string of digits only (`size=\"20\"` from untyped code) counts as that number. Any other value\n * outside the three sizes renders as if `size` were not set.\n */\n size?: CoreSize | number;\n /** The native `size` attribute: the visible width of the field in characters. */\n htmlSize?: number;\n /**\n * Look of the field: `outline` (a full border), `underline` (a bottom stroke only),\n * `filled-darker` or `filled-lighter` (a fill without a visible stroke: give the field a visible\n * label). Default: `WaveProvider inputDefaults.appearance`, else `'outline'`.\n */\n appearance?: InputAppearance;\n /**\n * Slot rendered before the input text (e.g., an icon). With content in either slot, a bordered\n * `<span>` around the input draws the field: it receives `className`, `style` and `hidden`,\n * while `ref`, `id`, `aria-*`, `data-*`, handlers and native attributes stay on the `<input>`.\n * A value that renders nothing (`false`, `''`, `[]`) is no slot.\n */\n contentBefore?: Slot<'span'>;\n /** Slot rendered after the input text (e.g., a suffix). Same wrapper as `contentBefore`. */\n contentAfter?: Slot<'span'>;\n /**\n * Called with the new string value on every change, next to the native `onChange` event\n * handler (`onValueChange={setName}` instead of `onChange={(e) => setName(e.target.value)}`).\n */\n onValueChange?: (value: string) => void;\n /** Ref to the `<input>` element (also with `contentBefore`/`contentAfter`). */\n ref?: React.Ref<HTMLInputElement>;\n}\n\n/**\n * A single-line text input with Fluent styling: a 1px border with an accessible bottom stroke, a\n * primary bottom border while focused, optional `contentBefore`/`contentAfter` slots and an\n * optional error message. Inside a `Field` it picks up the label, hint, error, `required` (native\n * attribute) and invalid state automatically.\n *\n * `size` resolves from its own prop, then the surrounding `Field`'s `size`, then\n * `WaveProvider inputDefaults.size`, else `'medium'`; `appearance` from its own prop, then\n * `WaveProvider inputDefaults.appearance`, else `'outline'`; both render as `data-size` and\n * `data-appearance` on the element that draws the field (the `<input>`, or the wrapper with slot\n * content).\n *\n * Every prop reaches the `<input>`, except with slot content: then a bordered `<span>` wrapper\n * draws the field and receives `className`, `style` and `hidden` (`ref` stays on the input).\n *\n * @example\n * <Field label=\"Email\" hint=\"We never share it\" required>\n * <Input type=\"email\" value={email} onValueChange={setEmail} />\n * </Field>\n */\nexport const Input = ({\n error,\n errorMessageProps,\n size: sizeProp,\n htmlSize,\n appearance: appearanceProp,\n contentBefore,\n contentAfter,\n onChange,\n onValueChange,\n className,\n ref,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n required,\n ...props\n}: InputProps) => {\n const { invalid, messageId, message } = useControlErrorMessage(\n error,\n errorMessageProps,\n ariaInvalid,\n inputClassNames.errorMessage,\n );\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': joinIds(ariaDescribedBy, messageId),\n 'aria-invalid': ariaInvalid ?? (invalid || undefined),\n 'aria-required': ariaRequired,\n required,\n },\n { nativeRequired: true },\n );\n const invalidLook = isInvalidLook(invalid, fieldProps['aria-invalid']);\n const numericSize = legacyNativeSize(sizeProp);\n const nativeSize = resolveDeprecatedProp(\n 'Input',\n htmlSize,\n numericSize,\n 'size={number}',\n 'htmlSize',\n );\n const { size, appearance } = useInputLook(\n numericSize === undefined && typeof sizeProp !== 'number' ? sizeProp : undefined,\n appearanceProp,\n );\n\n const handleChange =\n onChange || onValueChange\n ? (event: React.ChangeEvent<HTMLInputElement>) => {\n onChange?.(event);\n onValueChange?.(event.currentTarget.value);\n }\n : undefined;\n\n const controlProps = {\n ...props,\n ...fieldProps,\n 'aria-errormessage': joinIds(ariaErrorMessage, messageId),\n onChange: handleChange,\n };\n\n const hasBefore = slotRendersContent(contentBefore);\n const hasAfter = slotRendersContent(contentAfter);\n\n let control: React.ReactElement;\n if (hasBefore || hasAfter) {\n // The bordered wrapper is the visible field: `className`, `style` and `hidden` size, style and\n // hide it; `ref`, `id`, `aria-*`, `data-*`, handlers and native attributes go to the input.\n const { style, hidden, ...inputProps } = controlProps;\n control = (\n <span\n hidden={hidden}\n style={style}\n data-size={size}\n data-appearance={appearance}\n className={cn(\n inputClassNames.root,\n 'inline-flex w-full items-center',\n inputHeightClasses[size],\n inputTextClasses[size],\n inputAppearanceClasses[appearance],\n 'text-foreground',\n inputFocusWithin,\n invalidLook && inputInvalidWithin,\n // The dimmed look lifts while a focus ring shows inside the wrapper (focusable slot\n // content; the disabled input never takes focus): opacity would dim the ring below 3:1.\n props.disabled && 'cursor-not-allowed opacity-50 has-focus-visible:opacity-100',\n className,\n )}\n >\n {hasBefore &&\n renderSlot(\n contentBefore,\n 'span',\n cn(inputClassNames.contentBefore, 'shrink-0', SLOT_PADDING[size].before),\n )}\n <input\n ref={ref}\n className={cn(\n inputClassNames.input,\n 'h-full w-full min-w-0 bg-transparent',\n SLOT_PADDING[size].input,\n inputTextClasses[size],\n 'text-foreground',\n 'placeholder:text-muted-foreground',\n 'focus:outline-hidden',\n 'disabled:cursor-not-allowed',\n )}\n {...inputProps}\n size={nativeSize}\n />\n {hasAfter &&\n renderSlot(\n contentAfter,\n 'span',\n cn(inputClassNames.contentAfter, 'shrink-0', SLOT_PADDING[size].after),\n )}\n </span>\n );\n } else {\n control = (\n <input\n ref={ref}\n data-size={size}\n data-appearance={appearance}\n className={cn(\n inputClassNames.root,\n inputClassNames.input,\n inputHeightClasses[size],\n 'w-full',\n inputPaddingClasses[size],\n inputTextClasses[size],\n inputAppearanceClasses[appearance],\n 'text-foreground placeholder:text-muted-foreground',\n inputFocus,\n 'disabled:cursor-not-allowed disabled:opacity-50',\n invalidLook && inputInvalid,\n className,\n )}\n {...controlProps}\n size={nativeSize}\n />\n );\n }\n\n if (!message) return control;\n return (\n <>\n {control}\n {message}\n </>\n );\n};\n\nInput.displayName = 'Input';\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/classNames.cjs");let
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/slot.cjs"),r=require("../../lib/classNames.cjs"),i=require("./fieldLabel.cjs");let a=require("react");a=e.__toESM(a,1);let o=require("react/jsx-runtime");var s={small:`text-caption-1`,medium:`text-body-1`,large:`text-body-2`},c={regular:void 0,semibold:`font-semibold`,bold:`font-bold`},l=({required:e=!1,disabled:i=!1,size:a=`medium`,weight:l=`regular`,className:u,children:d,ref:f,...p})=>(0,o.jsxs)(`label`,{ref:f,className:t.cn(r.labelClassNames.root,i?`text-muted-foreground`:`text-foreground`,s[a],c[l],u),...p,children:[d,e===!0?(0,o.jsx)(`span`,{className:t.cn(r.labelClassNames.required,`ms-1 text-error`),"aria-hidden":`true`,children:`*`}):e!==!1&&n.slotRendersContent(e)?(0,o.jsx)(`span`,{className:t.cn(r.labelClassNames.required,`ms-1 text-error`),"aria-hidden":`true`,children:n.materialiseSlotContent(e)}):null]});l.displayName=`Label`,i.markFieldLabel(l),exports.Label=l;
|
|
2
2
|
//# sourceMappingURL=Label.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Label.cjs","names":["cn","labelClassNames","require_runtime","require_cn","require_classNames","react","react_jsx_runtime","sizeMap","weightMap","Label","rest","disabled","size","weight","className","children","required"],"sources":["../../../src/components/input/Label.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { labelClassNames } from '../../lib/classNames';\nimport type {
|
|
1
|
+
{"version":3,"file":"Label.cjs","names":["cn","labelClassNames","slotRendersContent","materialiseSlotContent","markFieldLabel","require_runtime","require_cn","require_slot","require_classNames","require_fieldLabel","react","react_jsx_runtime","sizeMap","weightMap","Label","rest","disabled","size","weight","className","children","required"],"sources":["../../../src/components/input/Label.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { labelClassNames } from '../../lib/classNames';\nimport { markFieldLabel } from './fieldLabel';\nimport { materialiseSlotContent, slotRendersContent } from '../../lib/slot';\nimport type { CoreSize, TextWeight } from '../../lib/types';\n\n/** Properties for the Label component. */\nexport interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {\n /** Whether to show a required indicator. `true` shows a decorative asterisk; other content\n * replaces it (for example a `(required)` text). Decorative (`aria-hidden`), so it must not be\n * focusable; mark the control itself `required`.\n * @default false\n */\n required?: boolean | React.ReactNode;\n /** Whether the label is visually dimmed.\n * @default false\n */\n disabled?: boolean;\n /** Text size of the label: `small` = caption-1, `medium` = body-1, `large` = body-2.\n * @default 'medium'\n */\n size?: CoreSize;\n /** Font weight of the label (the shared `TextWeight` vocabulary).\n * @default 'regular'\n */\n weight?: TextWeight;\n /** Ref to the `<label>` element. */\n ref?: React.Ref<HTMLLabelElement>;\n}\n\nconst sizeMap: Record<CoreSize, string> = {\n small: 'text-caption-1',\n medium: 'text-body-1',\n large: 'text-body-2',\n};\n\nconst weightMap: Record<TextWeight, string | undefined> = {\n regular: undefined,\n semibold: 'font-semibold',\n bold: 'font-bold',\n};\n\n/**\n * A text label for a form control (`htmlFor`), on the Fluent type ramp. The optional required\n * indicator is decorative (`aria-hidden`). `Field` renders its own label; use `Label` for custom\n * layouts.\n *\n * @example\n * <Label htmlFor=\"email\" required>Email</Label>\n * <Input id=\"email\" required />\n */\nexport const Label = ({\n required = false,\n disabled = false,\n size = 'medium',\n weight = 'regular',\n className,\n children,\n ref,\n ...rest\n}: LabelProps) => {\n return (\n <label\n ref={ref}\n className={cn(\n labelClassNames.root,\n disabled ? 'text-muted-foreground' : 'text-foreground',\n sizeMap[size],\n weightMap[weight],\n className,\n )}\n {...rest}\n >\n {children}\n {required === true ? (\n <span className={cn(labelClassNames.required, 'ms-1 text-error')} aria-hidden=\"true\">\n *\n </span>\n ) : required !== false && slotRendersContent(required) ? (\n <span className={cn(labelClassNames.required, 'ms-1 text-error')} aria-hidden=\"true\">\n {materialiseSlotContent(required)}\n </span>\n ) : null}\n </label>\n );\n};\n\nLabel.displayName = 'Label';\nmarkFieldLabel(Label);\n"],"mappings":"kRA+BA,IAAMY,EAAoC,CACxC,MAAO,iBACP,OAAQ,cACR,MAAO,aACT,EAEMC,EAAoD,CACxD,QAAS,IAAA,GACT,SAAU,gBACV,KAAM,WACR,EAWaC,GAAS,CACpB,WAAW,GACX,WAAW,GACX,OAAO,SACP,SAAS,UACT,YACA,WACA,MACA,GAAGC,MAGD,EAAAJ,EAAA,KAAA,CAAC,QAAD,CACO,MACL,UAAWX,EAAAA,GACTC,EAAAA,gBAAgB,KAChBe,EAAW,wBAA0B,kBACrCJ,EAAQK,GACRJ,EAAUK,GACVC,CACF,EACA,GAAIJ,EATN,SAAA,CAWGK,EACAC,IAAa,IACZ,EAAAV,EAAA,IAAA,CAAC,OAAD,CAAM,UAAWX,EAAAA,GAAGC,EAAAA,gBAAgB,SAAU,iBAAiB,EAAG,cAAY,OAAO,SAAA,GAE/E,CAAA,EACJoB,IAAa,IAASnB,EAAAA,mBAAmBmB,CAAQ,GACnD,EAAAV,EAAA,IAAA,CAAC,OAAD,CAAM,UAAWX,EAAAA,GAAGC,EAAAA,gBAAgB,SAAU,iBAAiB,EAAG,cAAY,OAC3E,SAAAE,EAAAA,uBAAuBkB,CAAQ,CAC5B,CAAA,EACJ,IACC,IAIX,EAAM,YAAc,QACpBjB,EAAAA,eAAeU,CAAK"}
|
|
@@ -1,29 +1,35 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn as e } from "../../lib/cn.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { materialiseSlotContent as t, slotRendersContent as n } from "../../lib/slot.mjs";
|
|
4
|
+
import { labelClassNames as r } from "../../lib/classNames.mjs";
|
|
5
|
+
import { markFieldLabel as i } from "./fieldLabel.mjs";
|
|
4
6
|
import "react";
|
|
5
|
-
import { jsx as
|
|
7
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
6
8
|
//#region src/components/input/Label.tsx
|
|
7
|
-
var
|
|
9
|
+
var s = {
|
|
8
10
|
small: "text-caption-1",
|
|
9
11
|
medium: "text-body-1",
|
|
10
12
|
large: "text-body-2"
|
|
11
|
-
},
|
|
13
|
+
}, c = {
|
|
12
14
|
regular: void 0,
|
|
13
15
|
semibold: "font-semibold",
|
|
14
16
|
bold: "font-bold"
|
|
15
|
-
},
|
|
16
|
-
ref:
|
|
17
|
-
className: e(
|
|
18
|
-
...
|
|
19
|
-
children: [
|
|
20
|
-
className: e(
|
|
17
|
+
}, l = ({ required: i = !1, disabled: l = !1, size: u = "medium", weight: d = "regular", className: f, children: p, ref: m, ...h }) => /* @__PURE__ */ o("label", {
|
|
18
|
+
ref: m,
|
|
19
|
+
className: e(r.root, l ? "text-muted-foreground" : "text-foreground", s[u], c[d], f),
|
|
20
|
+
...h,
|
|
21
|
+
children: [p, i === !0 ? /* @__PURE__ */ a("span", {
|
|
22
|
+
className: e(r.required, "ms-1 text-error"),
|
|
21
23
|
"aria-hidden": "true",
|
|
22
24
|
children: "*"
|
|
23
|
-
})
|
|
25
|
+
}) : i !== !1 && n(i) ? /* @__PURE__ */ a("span", {
|
|
26
|
+
className: e(r.required, "ms-1 text-error"),
|
|
27
|
+
"aria-hidden": "true",
|
|
28
|
+
children: t(i)
|
|
29
|
+
}) : null]
|
|
24
30
|
});
|
|
25
|
-
|
|
31
|
+
l.displayName = "Label", i(l);
|
|
26
32
|
//#endregion
|
|
27
|
-
export {
|
|
33
|
+
export { l as Label };
|
|
28
34
|
|
|
29
35
|
//# sourceMappingURL=Label.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Label.mjs","names":["sizeMap","weightMap","Label","rest","cn","labelClassNames","disabled","size","weight","className","children","required"],"sources":["../../../src/components/input/Label.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { labelClassNames } from '../../lib/classNames';\nimport type {
|
|
1
|
+
{"version":3,"file":"Label.mjs","names":["sizeMap","weightMap","Label","rest","cn","labelClassNames","disabled","size","weight","className","children","required","slotRendersContent","materialiseSlotContent","markFieldLabel"],"sources":["../../../src/components/input/Label.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { labelClassNames } from '../../lib/classNames';\nimport { markFieldLabel } from './fieldLabel';\nimport { materialiseSlotContent, slotRendersContent } from '../../lib/slot';\nimport type { CoreSize, TextWeight } from '../../lib/types';\n\n/** Properties for the Label component. */\nexport interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {\n /** Whether to show a required indicator. `true` shows a decorative asterisk; other content\n * replaces it (for example a `(required)` text). Decorative (`aria-hidden`), so it must not be\n * focusable; mark the control itself `required`.\n * @default false\n */\n required?: boolean | React.ReactNode;\n /** Whether the label is visually dimmed.\n * @default false\n */\n disabled?: boolean;\n /** Text size of the label: `small` = caption-1, `medium` = body-1, `large` = body-2.\n * @default 'medium'\n */\n size?: CoreSize;\n /** Font weight of the label (the shared `TextWeight` vocabulary).\n * @default 'regular'\n */\n weight?: TextWeight;\n /** Ref to the `<label>` element. */\n ref?: React.Ref<HTMLLabelElement>;\n}\n\nconst sizeMap: Record<CoreSize, string> = {\n small: 'text-caption-1',\n medium: 'text-body-1',\n large: 'text-body-2',\n};\n\nconst weightMap: Record<TextWeight, string | undefined> = {\n regular: undefined,\n semibold: 'font-semibold',\n bold: 'font-bold',\n};\n\n/**\n * A text label for a form control (`htmlFor`), on the Fluent type ramp. The optional required\n * indicator is decorative (`aria-hidden`). `Field` renders its own label; use `Label` for custom\n * layouts.\n *\n * @example\n * <Label htmlFor=\"email\" required>Email</Label>\n * <Input id=\"email\" required />\n */\nexport const Label = ({\n required = false,\n disabled = false,\n size = 'medium',\n weight = 'regular',\n className,\n children,\n ref,\n ...rest\n}: LabelProps) => {\n return (\n <label\n ref={ref}\n className={cn(\n labelClassNames.root,\n disabled ? 'text-muted-foreground' : 'text-foreground',\n sizeMap[size],\n weightMap[weight],\n className,\n )}\n {...rest}\n >\n {children}\n {required === true ? (\n <span className={cn(labelClassNames.required, 'ms-1 text-error')} aria-hidden=\"true\">\n *\n </span>\n ) : required !== false && slotRendersContent(required) ? (\n <span className={cn(labelClassNames.required, 'ms-1 text-error')} aria-hidden=\"true\">\n {materialiseSlotContent(required)}\n </span>\n ) : null}\n </label>\n );\n};\n\nLabel.displayName = 'Label';\nmarkFieldLabel(Label);\n"],"mappings":";;;;;;;;AA+BA,IAAMA,IAAoC;CACxC,OAAO;CACP,QAAQ;CACR,OAAO;AACT,GAEMC,IAAoD;CACxD,SAAS,KAAA;CACT,UAAU;CACV,MAAM;AACR,GAWaC,KAAS,EACpB,cAAW,IACX,cAAW,IACX,UAAO,UACP,YAAS,WACT,cACA,aACA,QACA,GAAGC,QAGD,kBAAC,SAAD;CACO;CACL,WAAWC,EACTC,EAAgB,MAChBC,IAAW,0BAA0B,mBACrCN,EAAQO,IACRN,EAAUO,IACVC,CACF;CACA,GAAIN;CATN,UAAA,CAWGO,GACAC,MAAa,KACZ,kBAAC,QAAD;EAAM,WAAWP,EAAGC,EAAgB,UAAU,iBAAiB;EAAG,eAAY;EAAO,UAAA;CAE/E,CAAA,IACJM,MAAa,MAASC,EAAmBD,CAAQ,IACnD,kBAAC,QAAD;EAAM,WAAWP,EAAGC,EAAgB,UAAU,iBAAiB;EAAG,eAAY;EAC3E,UAAAQ,EAAuBF,CAAQ;CAC5B,CAAA,IACJ,IACC;;AAIX,EAAM,cAAc,SACpBG,EAAeZ,CAAK"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/slot.cjs"),i=require("../../lib/composeEventHandlers.cjs"),a=require("../../lib/classNames.cjs"),o=require("../../hooks/useEventCallback.cjs"),s=require("../../hooks/useControllable.cjs"),c=require("../../lib/direction.cjs"),l=require("../../hooks/useRovingTabIndex.cjs"),u=require("../../hooks/useMergedRefs.cjs"),d=require("../../hooks/useFieldControl.cjs"),f=require("../../hooks/useFormReset.cjs"),p=require("../internal/HiddenInput.cjs"),m=require("../../lib/events.cjs"),h=require("./Rating.item.cjs");let g=require("react");g=e.__toESM(g,1);let _=require("react/jsx-runtime");var v=e=>`${e} star${e===1?``:`s`}`,y=({value:e,defaultValue:y,onValueChange:b,onChange:x,max:S=5,step:C,size:w=`medium`,color:T,iconFilled:E,iconOutline:D,disabled:O=!1,name:k,required:A,form:j,labels:M,className:N,children:P,id:F,"aria-label":I,"aria-labelledby":L,"aria-describedby":R,"aria-invalid":z,"aria-required":ee,onKeyDown:te,onFocus:ne,onMouseLeave:re,ref:ie,...ae})=>{x!==void 0&&n.warnDeprecated(`Rating`,`onChange`,`onValueChange`);let B=y??0,[V,H]=s.useControllable(e,B,e=>{b?.(e),x?.(e)}),U=C===.5?.5:1,[oe,W]=g.useState(0),[se,ce]=g.useState(O);se!==O&&(ce(O),O&&W(0));let G=O?V:oe||V,{containerProps:K,getTabIndex:q,focusValue:le}=l.useRovingTabIndex({activeValue:V>=U?String(Math.floor(V/U)*U):null}),J=e=>Math.floor(e/U)*U+U,Y=e=>Math.ceil(e/U)*U-U,ue=e=>{if(e.defaultPrevented||e.altKey||e.ctrlKey||e.metaKey||!m.isOwnEvent(e))return;let t;if(e.key===`Home`)t=U;else if(e.key===`End`)t=S;else if(e.key===`ArrowUp`)t=J(V);else if(e.key===`ArrowDown`)t=Y(V);else{let n=c.getArrowIntent(e.key,{orientation:`horizontal`,dir:c.getDirection(e.currentTarget)});if(!n)return;t=n===`next`?J(V):Y(V)}e.preventDefault(),t=Math.min(t,S),!(O||t<U||t===V)&&(le(String(t)),H(t))},X=g.useRef(null),de=u.useMergedRefs(ie,K.ref,X),fe=d.useFieldContext(),Z=d.useFieldControl({id:F,"aria-label":I,"aria-labelledby":L,"aria-describedby":R,"aria-invalid":z,"aria-required":ee??A},{labelable:!1}),pe=A??fe?.required??!1,me=Z[`aria-label`]===void 0&&Z[`aria-labelledby`]===void 0?`Rating`:void 0;f.useFormReset(X,()=>H(B),j);let he=()=>{X.current?.querySelector(`[data-roving-value][tabindex="0"]`)?.focus()},Q=o.useEventCallback(e=>{X.current?.querySelector(`[data-roving-value="${e}"]`)?.focus({preventScroll:!0})}),$=h.resolveRatingColor(T),ge=h.useStarGlyphs(`Rating`,E,D),_e=M?.star??v,{registerItem:ve,counts:ye}=h.useRatingItemRegistry(),be=r.slotRendersContent(P);h.useRatingItemChecks(ye,S,be);let xe=g.useMemo(()=>({kind:`input`,value:V,drawnValue:G,step:U,max:S,size:w,color:$,glyphs:ge,disabled:O,starLabel:_e,getTabIndex:q,choose:(e,t)=>{H(e),t&&Q(String(e))},preview:W,registerItem:ve}),[V,G,U,S,w,$,ge,O,_e,q,H,Q,ve]);return(0,_.jsxs)(`div`,{role:`radiogroup`,"aria-label":me,...Z,"aria-disabled":O||void 0,"data-color":$,className:t.cn(a.ratingClassNames.root,`relative inline-flex items-center gap-0.5`,O&&`pointer-events-none opacity-50`,N),...ae,ref:de,"data-roving-container":``,onKeyDown:i.composeEventHandlers(te,ue),onFocus:i.composeEventHandlers(ne,K.onFocus,{checkDefaultPrevented:!1}),onMouseLeave:i.composeEventHandlers(re,()=>W(0),{checkDefaultPrevented:!1}),children:[(0,_.jsx)(h.RatingContext.Provider,{value:xe,children:h.ratingItems(P,S)}),(0,_.jsx)(p.HiddenInput,{type:`radio`,name:k,form:j,disabled:O,value:V>0?String(V):``,required:pe,onInvalid:he})]})};y.displayName=`Rating`;var b={"extra-small":`text-caption-1`,small:`text-caption-1`,medium:`text-body-1`,large:`text-body-2`,"extra-large":`text-body-2`},x=(e,t,n)=>`Rating: ${n} out of ${t}`,S=(e,t)=>e===1?`1 rating`:`${t} ratings`;function C(e){if(e!==void 0)try{return Intl.getCanonicalLocales(e),e}catch{return}}var w=({value:e,max:i=5,size:o=`medium`,color:s,iconFilled:c,iconOutline:l,showValue:u=!1,count:d,compact:f=!1,locale:p,labels:m,className:v,children:y,ref:w,...T})=>{let E=C(p),D=p!==void 0&&E===void 0;g.useEffect(()=>{D&&n.warnOnce(`RatingDisplay:invalid-locale:${p}`,`RatingDisplay: \`locale\` "${p}" is not a valid BCP 47 language tag (use hyphens, as in "en-US"). The runtime default locale formats the value instead, so the server and the browser may render different text.`)},[D,p]);let O=new Intl.NumberFormat(E,{maximumFractionDigits:1}).format(e),k=d===void 0?void 0:new Intl.NumberFormat(E).format(d),A=(m?.rating??x)(e,i,O),j=d===void 0||k===void 0?A:`${A}, ${(m?.count??S)(d,k)}`,M=u||f||d!==void 0,N=b[o],P=h.resolveRatingColor(s),F=h.useStarGlyphs(`RatingDisplay`,c,l),{registerItem:I,counts:L}=h.useRatingItemRegistry(),R=!f&&r.slotRendersContent(y);h.useRatingItemChecks(L,i,R);let z=g.useMemo(()=>({...h.INERT_RATING_CONTEXT,kind:`display`,value:e,drawnValue:e,max:i,size:o,color:P,glyphs:F,registerItem:I}),[e,i,o,P,F,I]);return(0,_.jsxs)(`div`,{ref:w,role:`img`,"aria-label":j,"data-compact":f?``:void 0,"data-color":P,className:t.cn(a.ratingDisplayClassNames.root,`inline-flex items-center gap-0.5`,v),...T,children:[f?(0,_.jsx)(h.StarGlyph,{starClassName:a.ratingDisplayClassNames.star,iconClassName:a.ratingDisplayClassNames.icon,fraction:1,size:o,color:P,glyphs:F}):(0,_.jsx)(h.RatingContext.Provider,{value:z,children:h.ratingItems(y,i)}),M&&(0,_.jsx)(`span`,{className:t.cn(a.ratingDisplayClassNames.value,`ms-1 font-semibold text-foreground`,N),children:O}),k!==void 0&&(0,_.jsxs)(`span`,{className:t.cn(a.ratingDisplayClassNames.count,`ms-1 text-muted-foreground`,N),children:[`(`,k,`)`]})]})};w.displayName=`RatingDisplay`;var T=Object.assign(y,{Item:h.RatingItem}),E=Object.assign(w,{Item:h.RatingItem}),D=h.RatingItem;exports.Rating=T,exports.RatingDisplay=E,exports.RatingDisplayItem=D,exports.RatingItem=h.RatingItem;
|
|
2
2
|
//# sourceMappingURL=Rating.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Rating.cjs","names":["StarIcon","useControllable","React","useRovingTabIndex","getArrowIntent","getDirection","useMergedRefs","useFieldContext","useFieldControl","cn","ratingClassNames","composeEventHandlers","focusRing","HiddenInput","ratingDisplayClassNames","require_runtime","require_cn","require_dev","require_composeEventHandlers","require_classNames","require_useControllable","require_direction","require_useRovingTabIndex","require_useMergedRefs","require_useFieldControl","require_styles","require_icons","require_useFormReset","require_HiddenInput","react","react_jsx_runtime","defaultStarLabel","value","sizeMap","targetPaddingMap","Star","filled","Rating","valueProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","rest","onChange","initialValue","defaultValue","setValue","onValueChange","next","hovered","setHovered","prevDisabled","setPrevDisabled","disabled","displayValue","handleKeyDown","max","intent","focusValue","rootRef","mergedRef","ref","containerProps","field","fieldProps","required","isRequired","defaultName","form","focusTabStop","starSize","size","starLabel","labels","className","onKeyDown","onFocus","onMouseLeave","starValue","i","key","getTabIndex","textSizeMap","defaultRatingLabel","formattedValue","defaultCountLabel","count","formattedCount","supportedLocale","locale","RatingDisplay","formatLocale","invalidLocale","ratingName","name","showText","showValue","compact","textSize","percent"],"sources":["../../../src/components/input/Rating.tsx"],"sourcesContent":["import * as React from 'react';\nimport { ratingClassNames, ratingDisplayClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { warnDeprecated, warnOnce } from '../../lib/dev';\nimport { getArrowIntent, getDirection } from '../../lib/direction';\nimport { StarIcon } from '../../lib/icons';\nimport { focusRing } from '../../lib/styles';\nimport type { Size } from '../../lib/types';\nimport { useControllable } from '../../hooks/useControllable';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useRovingTabIndex } from '../../hooks/useRovingTabIndex';\nimport { HiddenInput } from '../internal/HiddenInput';\n\n/**\n * The Rating's built-in star names, for localization. Each member is optional and falls back to\n * its English default.\n */\nexport interface RatingLabels {\n /**\n * Accessible name of the star that chooses `value` (1 to `max`).\n * @default (value) => value === 1 ? '1 star' : `${value} stars`\n */\n star?: (value: number, max: number) => string;\n}\n\nconst defaultStarLabel = (value: number) => `${value} star${value !== 1 ? 's' : ''}`;\n\n/** Properties for the Rating component. */\nexport interface RatingProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue'\n> {\n /** Controlled rating value (`0` = no rating). */\n value?: number;\n /** Initial rating for uncontrolled usage (also the value a form reset restores).\n * @default 0\n */\n defaultValue?: number;\n /** Called with the new rating when it changes (not when the current star is chosen again). */\n onValueChange?: (value: number) => void;\n /**\n * Called with the new rating, exactly like `onValueChange`: only when the rating changes (0.4\n * also called it when the current star was clicked again, or a key was pressed at an end).\n * @deprecated Use `onValueChange`.\n */\n onChange?: (value: number) => void;\n /** Maximum number of stars.\n * @default 5\n */\n max?: number;\n /** Size of the star icons. Every size keeps a target of at least 24×24px.\n * @default 'medium'\n */\n size?: Size;\n /** Whether the rating is disabled and non-interactive.\n * @default false\n */\n disabled?: boolean;\n /**\n * Form field name. With a name, the chosen rating is submitted with the form (nothing while no\n * star is chosen).\n */\n name?: string;\n /** A star must be chosen before the form can be submitted (native validation). */\n required?: boolean;\n /** Id of the form the rating belongs to, when it is rendered outside that form. */\n form?: string;\n /**\n * Names of the stars (\"1 star\", \"2 stars\", …), for localization. The group's own name is\n * `aria-label` (default \"Rating\"). Unset members keep their English defaults.\n */\n labels?: RatingLabels;\n /** Ref to the `role=\"radiogroup\"` element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** Built-in texts of RatingDisplay, for localization. */\nexport interface RatingDisplayLabels {\n /**\n * Accessible name. `formattedValue` is `value` formatted with `locale` (as shown).\n * @default (value, max, formattedValue) => `Rating: ${formattedValue} out of ${max}`\n */\n rating?: (value: number, max: number, formattedValue: string) => string;\n /**\n * Count part of the name.\n * @default (count, formatted) => count === 1 ? '1 rating' : `${formatted} ratings`\n */\n count?: (count: number, formattedCount: string) => string;\n}\n\n/** Properties for the RatingDisplay (read-only) component. */\nexport interface RatingDisplayProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Rating value to display. A fraction is drawn as a partly filled star (`4.6` fills 60% of the\n * fifth star), so the stars show the value the accessible name reports.\n */\n value: number;\n /** Maximum number of stars.\n * @default 5\n */\n max?: number;\n /** Size of the star icons (and of the value and count text).\n * @default 'medium'\n */\n size?: Size;\n /**\n * Shows the value as text after the stars, formatted with `locale` (up to one decimal).\n * @default false\n */\n showValue?: boolean;\n /**\n * Number of ratings: shown as \"(1,160)\" after the value with the locale's digit grouping, and\n * added to the accessible name (\"…, 1,160 ratings\").\n */\n count?: number;\n /**\n * One filled star followed by the value (and the count) instead of `max` stars. Implies\n * `showValue`.\n * @default false\n */\n compact?: boolean;\n /**\n * BCP 47 locale of the value and count formatting (runtime default when omitted; pass it when\n * rendering on the server). A tag `Intl` rejects (the POSIX `de_DE`, a typo) falls back to the\n * runtime default locale (development warning).\n */\n locale?: string;\n /** Built-in texts, for localization. */\n labels?: RatingDisplayLabels;\n /** Ref to the root element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\nconst sizeMap: Record<Size, string> = {\n 'extra-small': 'h-3 w-3',\n small: 'h-4 w-4',\n medium: 'h-5 w-5',\n large: 'h-6 w-6',\n 'extra-large': 'h-8 w-8',\n};\n\n/** Padding that gives every interactive star a target of at least 24×24px (WCAG 2.5.8). */\nconst targetPaddingMap: Record<Size, string> = {\n 'extra-small': 'p-1.5', // 12px icon + 12px\n small: 'p-1', // 16px icon + 8px\n medium: 'p-0.5', // 20px icon + 4px\n large: 'p-0.5',\n 'extra-large': 'p-0.5',\n};\n\n/** A filled star, or an outlined one (the outline keeps a 3:1 non-text contrast). */\nfunction Star({ filled, className }: { filled: boolean; className: string }) {\n return filled ? (\n <StarIcon className={className} />\n ) : (\n <StarIcon className={className} fill=\"none\" stroke=\"currentColor\" strokeWidth={1.5} />\n );\n}\n\n/**\n * A star rating input (`role=\"radiogroup\"` of `role=\"radio\"` stars).\n *\n * - One tab stop (the chosen star, else the first). Keys choose relative to the current rating and\n * move focus to the chosen star, as in 0.4: Right/Up one star more, Left/Down one fewer\n * (Left/Right mirrored under `dir=\"rtl\"`), Home/End the first/last star. From an empty rating,\n * Right/Up/Home choose 1 star. Keys at the ends (and Left/Down while empty) emit nothing.\n * - The keyboard cannot clear a rating: Left/Down stop at 1 star (APG radio group; 0.4 went down\n * to 0). Only a controlled `value={0}` (or a form reset while `defaultValue` is 0) clears it.\n * - `onValueChange` (and the deprecated `onChange` alias) fire only when the rating changes, so\n * choosing the current star again calls neither.\n * - Hovering previews a value; the preview never outlives the hover or a disabled state.\n * - Inside a `Field` it is named by the Field label (instead of the default \"Rating\") and\n * described by its hint and error. The stars are named \"1 star\", \"2 stars\", …; `labels`\n * localizes these names.\n * - With `name` (or `required`) it takes part in native forms; a form reset restores\n * `defaultValue`.\n */\nexport const Rating = ({\n value: valueProp,\n defaultValue,\n onValueChange,\n onChange,\n max = 5,\n size = 'medium',\n disabled = false,\n name,\n required,\n form,\n labels,\n className,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n onKeyDown,\n onFocus,\n onMouseLeave,\n ref,\n ...rest\n}: RatingProps) => {\n if (onChange !== undefined) warnDeprecated('Rating', 'onChange', 'onValueChange');\n const initialValue = defaultValue ?? 0;\n const [value, setValue] = useControllable(valueProp, initialValue, (next: number) => {\n onValueChange?.(next);\n onChange?.(next);\n });\n\n const [hovered, setHovered] = React.useState(0);\n // A hover preview must not survive the rating becoming disabled (adjust state during render).\n const [prevDisabled, setPrevDisabled] = React.useState(disabled);\n if (prevDisabled !== disabled) {\n setPrevDisabled(disabled);\n if (disabled) setHovered(0);\n }\n const displayValue = disabled ? value : hovered || value;\n\n // Roving tab stop (the chosen star, else the first) and focus moves; the keys are handled below.\n const { containerProps, getTabIndex, focusValue } = useRovingTabIndex({\n activeValue: value > 0 ? String(value) : null,\n });\n\n // Keys count from the current rating, not from the focused star (0.4 semantics): from an empty\n // rating, Tab lands on the unchosen first star and Right/Up/Home choose it. Never wraps.\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey) return;\n let next: number;\n if (e.key === 'Home') next = 1;\n else if (e.key === 'End') next = max;\n else if (e.key === 'ArrowUp') next = value + 1;\n else if (e.key === 'ArrowDown') next = value - 1;\n else {\n const intent = getArrowIntent(e.key, {\n orientation: 'horizontal',\n dir: getDirection(e.currentTarget),\n });\n if (!intent) return;\n next = intent === 'next' ? value + 1 : value - 1;\n }\n e.preventDefault();\n next = Math.min(next, max);\n // The ends are no-ops (nothing is emitted, focus stays), and Left/Down never clear to 0.\n if (disabled || next < 1 || next === value) return;\n focusValue(String(next));\n setValue(next);\n };\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n const mergedRef = useMergedRefs<HTMLDivElement>(ref, containerProps.ref, rootRef);\n\n const field = useFieldContext();\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n // An explicit `required={false}` wins over a required Field, so aria-required always\n // matches the native validation below (`isRequired`).\n 'aria-required': ariaRequired ?? required,\n },\n { labelable: false },\n );\n const isRequired = required ?? field?.required ?? false;\n const defaultName =\n fieldProps['aria-label'] === undefined && fieldProps['aria-labelledby'] === undefined\n ? 'Rating'\n : undefined;\n\n useFormReset(rootRef, () => setValue(initialValue), form);\n\n const focusTabStop = () => {\n rootRef.current?.querySelector<HTMLElement>('[data-roving-value][tabindex=\"0\"]')?.focus();\n };\n\n const starSize = sizeMap[size];\n const starLabel = labels?.star ?? defaultStarLabel;\n\n return (\n <div\n role=\"radiogroup\"\n aria-label={defaultName}\n {...fieldProps}\n aria-disabled={disabled || undefined}\n className={cn(\n ratingClassNames.root,\n 'relative inline-flex items-center gap-0.5',\n disabled && 'pointer-events-none opacity-50',\n className,\n )}\n {...rest}\n ref={mergedRef}\n data-roving-container=\"\"\n onKeyDown={composeEventHandlers(onKeyDown, handleKeyDown)}\n onFocus={composeEventHandlers(onFocus, containerProps.onFocus, {\n checkDefaultPrevented: false,\n })}\n onMouseLeave={composeEventHandlers(onMouseLeave, () => setHovered(0), {\n checkDefaultPrevented: false,\n })}\n >\n {Array.from({ length: max }, (_, i) => {\n const starValue = i + 1;\n const key = String(starValue);\n const filled = displayValue >= starValue;\n return (\n <button\n key={key}\n type=\"button\"\n role=\"radio\"\n aria-checked={value === starValue}\n aria-label={starLabel(starValue, max)}\n data-roving-value={key}\n tabIndex={disabled ? -1 : getTabIndex(key)}\n disabled={disabled}\n className={cn(\n ratingClassNames.star,\n 'inline-flex cursor-pointer rounded border-0 bg-transparent transition-colors motion-reduce:transition-none disabled:cursor-not-allowed',\n targetPaddingMap[size],\n focusRing,\n filled ? 'text-rating' : 'text-stroke-accessible',\n )}\n onClick={() => {\n // Choosing the current star again is a no-op for both callbacks (useControllable).\n if (!disabled) setValue(starValue);\n }}\n onMouseEnter={() => {\n if (!disabled) setHovered(starValue);\n }}\n >\n <Star filled={filled} className={cn(ratingClassNames.icon, starSize)} />\n </button>\n );\n })}\n <HiddenInput\n type=\"radio\"\n name={name}\n form={form}\n disabled={disabled}\n value={value > 0 ? String(value) : ''}\n required={isRequired}\n onInvalid={focusTabStop}\n />\n </div>\n );\n};\nRating.displayName = 'Rating';\n\n/** Text size of the value and the count, following the star size. */\nconst textSizeMap: Record<Size, string> = {\n 'extra-small': 'text-caption-1',\n small: 'text-caption-1',\n medium: 'text-body-1',\n large: 'text-body-2',\n 'extra-large': 'text-body-2',\n};\n\nconst defaultRatingLabel = (_value: number, max: number, formattedValue: string) =>\n `Rating: ${formattedValue} out of ${max}`;\nconst defaultCountLabel = (count: number, formattedCount: string) =>\n count === 1 ? '1 rating' : `${formattedCount} ratings`;\n\n/** `locale` when `Intl` accepts it as a language tag, else `undefined` (the runtime default). */\nfunction supportedLocale(locale: string | undefined): string | undefined {\n if (locale === undefined) return undefined;\n try {\n Intl.getCanonicalLocales(locale);\n return locale;\n } catch {\n return undefined;\n }\n}\n\n/**\n * A read-only star rating (`role=\"img\"` named \"Rating: <value> out of <max>\"). A fractional value\n * is drawn with a partly filled star, so the stars and the name show the same value.\n *\n * - `showValue` adds the value as text after the stars, `count` the number of ratings (\"(1,160)\",\n * also added to the name), and `compact` shows one filled star with the value instead of `max`\n * stars (the root carries `data-compact`). Without them only the stars show.\n * - The value (up to one decimal) and the count are formatted with `locale`, in the text and in\n * the name; `labels` localizes the name. Pass `locale` when rendering on the server.\n */\nexport const RatingDisplay = ({\n value,\n max = 5,\n size = 'medium',\n showValue = false,\n count,\n compact = false,\n locale,\n labels,\n className,\n ref,\n ...rest\n}: RatingDisplayProps) => {\n const starSize = sizeMap[size];\n const formatLocale = supportedLocale(locale);\n const invalidLocale = locale !== undefined && formatLocale === undefined;\n React.useEffect(() => {\n if (invalidLocale) {\n warnOnce(\n `RatingDisplay:invalid-locale:${locale}`,\n `RatingDisplay: \\`locale\\` \"${locale}\" is not a valid BCP 47 language tag (use hyphens, as ` +\n 'in \"en-US\"). The runtime default locale formats the value instead, so the server and ' +\n 'the browser may render different text.',\n );\n }\n }, [invalidLocale, locale]);\n\n const formattedValue = new Intl.NumberFormat(formatLocale, { maximumFractionDigits: 1 }).format(\n value,\n );\n const formattedCount =\n count === undefined ? undefined : new Intl.NumberFormat(formatLocale).format(count);\n const ratingName = (labels?.rating ?? defaultRatingLabel)(value, max, formattedValue);\n const name =\n count === undefined || formattedCount === undefined\n ? ratingName\n : `${ratingName}, ${(labels?.count ?? defaultCountLabel)(count, formattedCount)}`;\n const showText = showValue || compact || count !== undefined;\n const textSize = textSizeMap[size];\n\n return (\n <div\n ref={ref}\n role=\"img\"\n aria-label={name}\n data-compact={compact ? '' : undefined}\n className={cn(ratingDisplayClassNames.root, 'inline-flex items-center gap-0.5', className)}\n {...rest}\n >\n {compact ? (\n <span className={cn(ratingDisplayClassNames.star, 'inline-flex text-rating')}>\n <Star filled className={cn(ratingDisplayClassNames.icon, starSize)} />\n </span>\n ) : (\n Array.from({ length: max }, (_, i) => {\n // The share of this star that the value covers, in whole percent.\n const percent = Math.round(Math.min(1, Math.max(0, value - i)) * 100);\n if (percent > 0 && percent < 100) {\n // The outline of an empty star, with the filled star clipped to the fraction over it\n // from the inline start (the reading direction of the stars, also under RTL).\n return (\n <span\n key={i}\n className={cn(\n ratingDisplayClassNames.star,\n 'relative inline-flex text-stroke-accessible',\n )}\n >\n <Star filled={false} className={cn(ratingDisplayClassNames.icon, starSize)} />\n <span\n className=\"absolute inset-y-0 start-0 flex overflow-hidden text-rating\"\n style={{ width: `${percent}%` }}\n >\n <Star filled className={cn(ratingDisplayClassNames.icon, starSize, 'shrink-0')} />\n </span>\n </span>\n );\n }\n const filled = percent === 100;\n return (\n <span\n key={i}\n className={cn(\n ratingDisplayClassNames.star,\n 'inline-flex',\n filled ? 'text-rating' : 'text-stroke-accessible',\n )}\n >\n <Star filled={filled} className={cn(ratingDisplayClassNames.icon, starSize)} />\n </span>\n );\n })\n )}\n {showText && (\n <span\n className={cn(\n ratingDisplayClassNames.value,\n 'ms-1 font-semibold text-foreground',\n textSize,\n )}\n >\n {formattedValue}\n </span>\n )}\n {formattedCount !== undefined && (\n <span className={cn(ratingDisplayClassNames.count, 'ms-1 text-muted-foreground', textSize)}>\n ({formattedCount})\n </span>\n )}\n </div>\n );\n};\nRatingDisplay.displayName = 'RatingDisplay';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Rating.cjs","names":["useControllable","React","useRovingTabIndex","isOwnEvent","getArrowIntent","getDirection","useMergedRefs","useFieldContext","useFieldControl","useEventCallback","resolveRatingColor","useStarGlyphs","useRatingItemRegistry","slotRendersContent","cn","ratingClassNames","composeEventHandlers","RatingContext","ratingItems","HiddenInput","INERT_RATING_CONTEXT","ratingDisplayClassNames","StarGlyph","RatingItem","require_runtime","require_cn","require_dev","require_slot","require_composeEventHandlers","require_classNames","require_useEventCallback","require_useControllable","require_direction","require_useRovingTabIndex","require_useMergedRefs","require_useFieldControl","require_useFormReset","require_HiddenInput","require_events","require_Rating_item","react","react_jsx_runtime","defaultStarLabel","value","RatingRoot","valueProp","stepProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","rest","onChange","initialValue","defaultValue","setValue","onValueChange","next","step","hovered","setHovered","prevDisabled","setPrevDisabled","disabled","drawnValue","up","v","down","handleKeyDown","max","intent","focusValue","rootRef","mergedRef","ref","containerProps","field","fieldProps","required","isRequired","defaultName","form","focusTabStop","focusChosen","key","resolvedColor","color","glyphs","iconFilled","iconOutline","starLabel","labels","hasItems","children","counts","context","focus","size","getTabIndex","registerItem","className","onKeyDown","onFocus","onMouseLeave","textSizeMap","defaultRatingLabel","formattedValue","defaultCountLabel","count","formattedCount","supportedLocale","locale","RatingDisplayRoot","formatLocale","invalidLocale","ratingName","name","showText","showValue","compact","textSize","Rating","RatingDisplay","RatingDisplayItem"],"sources":["../../../src/components/input/Rating.tsx"],"sourcesContent":["import * as React from 'react';\nimport { ratingClassNames, ratingDisplayClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { warnDeprecated, warnOnce } from '../../lib/dev';\nimport { getArrowIntent, getDirection } from '../../lib/direction';\nimport { isOwnEvent } from '../../lib/events';\nimport { slotRendersContent, type Slot } from '../../lib/slot';\nimport type { Size } from '../../lib/types';\nimport { useControllable } from '../../hooks/useControllable';\nimport { useEventCallback } from '../../hooks/useEventCallback';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useRovingTabIndex } from '../../hooks/useRovingTabIndex';\nimport { HiddenInput } from '../internal/HiddenInput';\nimport {\n INERT_RATING_CONTEXT,\n RatingContext,\n RatingItem,\n ratingItems,\n resolveRatingColor,\n StarGlyph,\n useRatingItemChecks,\n useRatingItemRegistry,\n useStarGlyphs,\n type RatingColor,\n type RatingContextValue,\n} from './Rating.item';\n\n/**\n * The Rating's built-in star names, for localization. Each member is optional and falls back to\n * its English default.\n */\nexport interface RatingLabels {\n /**\n * Accessible name of the radio that chooses `value`: a whole star (1 to `max`), and with\n * `step={0.5}` a half value too (\"2.5 stars\").\n * @default (value) => value === 1 ? '1 star' : `${value} stars`\n */\n star?: (value: number, max: number) => string;\n}\n\nconst defaultStarLabel = (value: number) => `${value} star${value !== 1 ? 's' : ''}`;\n\n/** Properties for the Rating component. */\nexport interface RatingProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue' | 'color'\n> {\n /**\n * Controlled rating value (`0` = no rating): a whole number of stars, or with `step={0.5}` a\n * multiple of 0.5. A value between two steps (2.7) checks no radio, is drawn as the step below\n * it (2.5) and holds the tab stop there; the keys move it to the next or previous step.\n */\n value?: number;\n /** Initial rating for uncontrolled usage (also the value a form reset restores).\n * @default 0\n */\n defaultValue?: number;\n /** Called with the new rating when it changes (not when the current star is chosen again). */\n onValueChange?: (value: number) => void;\n /**\n * Called with the new rating, exactly like `onValueChange`: only when the rating changes (0.4\n * also called it when the current star was clicked again, or a key was pressed at an end).\n * @deprecated Use `onValueChange`.\n */\n onChange?: (value: number) => void;\n /** Maximum number of stars.\n * @default 5\n */\n max?: number;\n /**\n * The grain of the rating: `1` (whole stars) or `0.5` (half stars). With `0.5`, each star stays\n * one pointer target of at least 24×24px (a larger `size` keeps a larger one): the half is\n * chosen by the pointer's position over it (the half at the inline start, which mirrors under\n * `dir=\"rtl\"`), and two transparent radios per star, the half value then the full value, serve\n * the keyboard and screen readers. The keys then move by half a star. A value other than `0.5`\n * (from untyped code) counts as `1`. RatingDisplay has no `step`: it draws any fraction.\n * @default 1\n */\n step?: 0.5 | 1;\n /** Size of the star icons. Every size keeps a target of at least 24×24px.\n * @default 'medium'\n */\n size?: Size;\n /**\n * Color of the filled stars: `marigold` (default), `brand` or `neutral`; unfilled stars keep a\n * 3:1 outline. Fluent's default is `neutral`. A value outside the three (from untyped code)\n * renders as `marigold`; the root carries `data-color` with the resolved value.\n * @default 'marigold'\n */\n color?: RatingColor;\n /**\n * The glyph of a filled star. `iconFilled` and `iconOutline` are the glyphs of a filled and an\n * unfilled star, as a pair; decorative. Fluent's RatingDisplay takes one `icon`; here a filled\n * and an unfilled star must differ by shape, not by color alone.\n *\n * - Each glyph is sized by `size` (an SVG child fills the star) and takes the star's color\n * (paint it with `currentColor`). A half-filled star (`step={0.5}`) clips the filled glyph\n * over the unfilled one from the inline start.\n * - `null`, `undefined` and a value that renders nothing draw the default star. A value that\n * renders nothing, and a pair with only one of the two set, log a development warning.\n * - A `<button>` or `Button` element (or a slot object whose `as` is one) is not nested in the\n * star: its children become the glyph (the default star when they render nothing), its props\n * are dropped, and a development warning says so (in place of the warning for a value that\n * renders nothing).\n * - A `Rating.Item` that sets its own pair draws that one instead.\n */\n iconFilled?: Slot<'span'>;\n /**\n * The glyph of an unfilled star, as a pair with `iconFilled` (its rules apply); decorative.\n * Fluent's RatingDisplay takes one `icon`; here a filled and an unfilled star must differ by\n * shape, not by color alone.\n */\n iconOutline?: Slot<'span'>;\n /** Whether the rating is disabled and non-interactive.\n * @default false\n */\n disabled?: boolean;\n /**\n * Form field name. With a name, the chosen rating is submitted with the form (nothing while no\n * star is chosen).\n */\n name?: string;\n /** A star must be chosen before the form can be submitted (native validation). */\n required?: boolean;\n /** Id of the form the rating belongs to, when it is rendered outside that form. */\n form?: string;\n /**\n * Names of the stars (\"1 star\", \"2 stars\", …, and \"2.5 stars\" for a half value), for\n * localization. The group's own name is `aria-label` (default \"Rating\"). Unset members keep\n * their English defaults.\n */\n labels?: RatingLabels;\n /**\n * Custom stars: one `Rating.Item` per value from 1 to `max`, in place of the generated stars\n * (when the children render content). `max` still sets the key range and the star names.\n */\n children?: React.ReactNode;\n /** Ref to the `role=\"radiogroup\"` element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** Built-in texts of RatingDisplay, for localization. */\nexport interface RatingDisplayLabels {\n /**\n * Accessible name. `formattedValue` is `value` formatted with `locale` (as shown).\n * @default (value, max, formattedValue) => `Rating: ${formattedValue} out of ${max}`\n */\n rating?: (value: number, max: number, formattedValue: string) => string;\n /**\n * Count part of the name.\n * @default (count, formatted) => count === 1 ? '1 rating' : `${formatted} ratings`\n */\n count?: (count: number, formattedCount: string) => string;\n}\n\n/** Properties for the RatingDisplay (read-only) component. */\nexport interface RatingDisplayProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'> {\n /**\n * Rating value to display. A fraction is drawn as a partly filled star (`4.6` fills 60% of the\n * fifth star), so the stars show the value the accessible name reports.\n */\n value: number;\n /** Maximum number of stars.\n * @default 5\n */\n max?: number;\n /** Size of the star icons (and of the value and count text).\n * @default 'medium'\n */\n size?: Size;\n /**\n * Color of the filled stars: `marigold` (default), `brand` or `neutral`; unfilled stars keep a\n * 3:1 outline. Fluent's default is `neutral`. A value outside the three (from untyped code)\n * renders as `marigold`; the root carries `data-color` with the resolved value.\n * @default 'marigold'\n */\n color?: RatingColor;\n /**\n * The glyph of a filled star. `iconFilled` and `iconOutline` are the glyphs of a filled and an\n * unfilled star, as a pair; decorative. Fluent's RatingDisplay takes one `icon`; here a filled\n * and an unfilled star must differ by shape, not by color alone.\n *\n * - Each glyph is sized by `size` (an SVG child fills the star) and takes the star's color\n * (paint it with `currentColor`). A partly filled star clips the filled glyph over the\n * unfilled one from the inline start, and the `compact` star is the filled glyph.\n * - `null`, `undefined` and a value that renders nothing draw the default star. A value that\n * renders nothing, and a pair with only one of the two set, log a development warning.\n * - A `<button>` or `Button` element (or a slot object whose `as` is one) is not nested in the\n * star: its children become the glyph (the default star when they render nothing), its props\n * are dropped, and a development warning says so (in place of the warning for a value that\n * renders nothing).\n * - A `RatingDisplay.Item` that sets its own pair draws that one instead.\n */\n iconFilled?: Slot<'span'>;\n /**\n * The glyph of an unfilled star, as a pair with `iconFilled` (its rules apply); decorative.\n * Fluent's RatingDisplay takes one `icon`; here a filled and an unfilled star must differ by\n * shape, not by color alone.\n */\n iconOutline?: Slot<'span'>;\n /**\n * Shows the value as text after the stars, formatted with `locale` (up to one decimal).\n * @default false\n */\n showValue?: boolean;\n /**\n * Number of ratings: shown as \"(1,160)\" after the value with the locale's digit grouping, and\n * added to the accessible name (\"…, 1,160 ratings\").\n */\n count?: number;\n /**\n * One filled star followed by the value (and the count) instead of `max` stars. Implies\n * `showValue`.\n * @default false\n */\n compact?: boolean;\n /**\n * BCP 47 locale of the value and count formatting (runtime default when omitted; pass it when\n * rendering on the server). A tag `Intl` rejects (the POSIX `de_DE`, a typo) falls back to the\n * runtime default locale (development warning).\n */\n locale?: string;\n /** Built-in texts, for localization. */\n labels?: RatingDisplayLabels;\n /**\n * Custom stars: one `RatingDisplay.Item` per value from 1 to `max`, in place of the generated\n * stars (when the children render content). A `compact` display ignores them.\n */\n children?: React.ReactNode;\n /** Ref to the root element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\nconst RatingRoot = ({\n value: valueProp,\n defaultValue,\n onValueChange,\n onChange,\n max = 5,\n step: stepProp,\n size = 'medium',\n color,\n iconFilled,\n iconOutline,\n disabled = false,\n name,\n required,\n form,\n labels,\n className,\n children,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n onKeyDown,\n onFocus,\n onMouseLeave,\n ref,\n ...rest\n}: RatingProps) => {\n if (onChange !== undefined) warnDeprecated('Rating', 'onChange', 'onValueChange');\n const initialValue = defaultValue ?? 0;\n const [value, setValue] = useControllable(valueProp, initialValue, (next: number) => {\n onValueChange?.(next);\n onChange?.(next);\n });\n // The items draw whole or half stars only, so the keys move by one of the two (untyped code\n // may pass another number).\n const step: 0.5 | 1 = stepProp === 0.5 ? 0.5 : 1;\n\n const [hovered, setHovered] = React.useState(0);\n // A hover preview must not survive the rating becoming disabled (adjust state during render).\n const [prevDisabled, setPrevDisabled] = React.useState(disabled);\n if (prevDisabled !== disabled) {\n setPrevDisabled(disabled);\n if (disabled) setHovered(0);\n }\n const drawnValue = disabled ? value : hovered || value;\n\n // Roving tab stop (the radio of the chosen value, else the first) and focus moves; the keys are\n // handled below. A value between two steps holds the tab stop on the radio below it (D23).\n const { containerProps, getTabIndex, focusValue } = useRovingTabIndex({\n activeValue: value >= step ? String(Math.floor(value / step) * step) : null,\n });\n\n // The next and previous multiples of `step`: a value between two steps (a controlled 2.7 at\n // step 0.5) moves to the step above or below it (3 or 2.5).\n const up = (v: number) => Math.floor(v / step) * step + step;\n const down = (v: number) => Math.ceil(v / step) * step - step;\n\n // Keys count from the current rating, not from the focused radio (0.4 semantics): from an empty\n // rating, Tab lands on the unchosen first radio and Right/Up/Home choose it. Never wraps.\n // Keys from a portal rendered among the children (a popup opened from one) are not the rating's.\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey || !isOwnEvent(e)) return;\n let next: number;\n if (e.key === 'Home') next = step;\n else if (e.key === 'End') next = max;\n else if (e.key === 'ArrowUp') next = up(value);\n else if (e.key === 'ArrowDown') next = down(value);\n else {\n const intent = getArrowIntent(e.key, {\n orientation: 'horizontal',\n dir: getDirection(e.currentTarget),\n });\n if (!intent) return;\n next = intent === 'next' ? up(value) : down(value);\n }\n e.preventDefault();\n next = Math.min(next, max);\n // The ends are no-ops (nothing is emitted, focus stays), and Left/Down never clear to 0.\n if (disabled || next < step || next === value) return;\n focusValue(String(next));\n setValue(next);\n };\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n const mergedRef = useMergedRefs<HTMLDivElement>(ref, containerProps.ref, rootRef);\n\n const field = useFieldContext();\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n // An explicit `required={false}` wins over a required Field, so aria-required always\n // matches the native validation below (`isRequired`).\n 'aria-required': ariaRequired ?? required,\n },\n { labelable: false },\n );\n const isRequired = required ?? field?.required ?? false;\n const defaultName =\n fieldProps['aria-label'] === undefined && fieldProps['aria-labelledby'] === undefined\n ? 'Rating'\n : undefined;\n\n useFormReset(rootRef, () => setValue(initialValue), form);\n\n const focusTabStop = () => {\n rootRef.current?.querySelector<HTMLElement>('[data-roving-value][tabindex=\"0\"]')?.focus();\n };\n\n // A pointer click on a half star focuses the radio it chose, so the keyboard continues from\n // there, without scrolling: the star is under the pointer already (D22).\n const focusChosen = useEventCallback((key: string) => {\n rootRef.current\n ?.querySelector<HTMLElement>(`[data-roving-value=\"${key}\"]`)\n ?.focus({ preventScroll: true });\n });\n\n const resolvedColor = resolveRatingColor(color);\n const glyphs = useStarGlyphs('Rating', iconFilled, iconOutline);\n const starLabel = labels?.star ?? defaultStarLabel;\n const { registerItem, counts } = useRatingItemRegistry();\n // Whether the root draws its own children instead of the `max` generated stars (D26): the\n // generated stars always cover every value on their own, so only a custom item set can leave\n // one missing.\n const hasItems = slotRendersContent(children);\n useRatingItemChecks(counts, max, hasItems);\n const context = React.useMemo<RatingContextValue>(\n () => ({\n kind: 'input',\n value,\n drawnValue,\n step,\n max,\n size,\n color: resolvedColor,\n glyphs,\n disabled,\n starLabel,\n getTabIndex,\n choose: (next, focus) => {\n setValue(next);\n if (focus) focusChosen(String(next));\n },\n preview: setHovered,\n registerItem,\n }),\n [\n value,\n drawnValue,\n step,\n max,\n size,\n resolvedColor,\n glyphs,\n disabled,\n starLabel,\n getTabIndex,\n setValue,\n focusChosen,\n registerItem,\n ],\n );\n\n return (\n <div\n role=\"radiogroup\"\n aria-label={defaultName}\n {...fieldProps}\n aria-disabled={disabled || undefined}\n data-color={resolvedColor}\n className={cn(\n ratingClassNames.root,\n 'relative inline-flex items-center gap-0.5',\n disabled && 'pointer-events-none opacity-50',\n className,\n )}\n {...rest}\n ref={mergedRef}\n data-roving-container=\"\"\n onKeyDown={composeEventHandlers(onKeyDown, handleKeyDown)}\n onFocus={composeEventHandlers(onFocus, containerProps.onFocus, {\n checkDefaultPrevented: false,\n })}\n onMouseLeave={composeEventHandlers(onMouseLeave, () => setHovered(0), {\n checkDefaultPrevented: false,\n })}\n >\n <RatingContext.Provider value={context}>{ratingItems(children, max)}</RatingContext.Provider>\n <HiddenInput\n type=\"radio\"\n name={name}\n form={form}\n disabled={disabled}\n value={value > 0 ? String(value) : ''}\n required={isRequired}\n onInvalid={focusTabStop}\n />\n </div>\n );\n};\nRatingRoot.displayName = 'Rating';\n\n/** Text size of the value and the count, following the star size. */\nconst textSizeMap: Record<Size, string> = {\n 'extra-small': 'text-caption-1',\n small: 'text-caption-1',\n medium: 'text-body-1',\n large: 'text-body-2',\n 'extra-large': 'text-body-2',\n};\n\nconst defaultRatingLabel = (_value: number, max: number, formattedValue: string) =>\n `Rating: ${formattedValue} out of ${max}`;\nconst defaultCountLabel = (count: number, formattedCount: string) =>\n count === 1 ? '1 rating' : `${formattedCount} ratings`;\n\n/** `locale` when `Intl` accepts it as a language tag, else `undefined` (the runtime default). */\nfunction supportedLocale(locale: string | undefined): string | undefined {\n if (locale === undefined) return undefined;\n try {\n Intl.getCanonicalLocales(locale);\n return locale;\n } catch {\n return undefined;\n }\n}\n\nconst RatingDisplayRoot = ({\n value,\n max = 5,\n size = 'medium',\n color,\n iconFilled,\n iconOutline,\n showValue = false,\n count,\n compact = false,\n locale,\n labels,\n className,\n children,\n ref,\n ...rest\n}: RatingDisplayProps) => {\n const formatLocale = supportedLocale(locale);\n const invalidLocale = locale !== undefined && formatLocale === undefined;\n React.useEffect(() => {\n if (invalidLocale) {\n warnOnce(\n `RatingDisplay:invalid-locale:${locale}`,\n `RatingDisplay: \\`locale\\` \"${locale}\" is not a valid BCP 47 language tag (use hyphens, as ` +\n 'in \"en-US\"). The runtime default locale formats the value instead, so the server and ' +\n 'the browser may render different text.',\n );\n }\n }, [invalidLocale, locale]);\n\n const formattedValue = new Intl.NumberFormat(formatLocale, { maximumFractionDigits: 1 }).format(\n value,\n );\n const formattedCount =\n count === undefined ? undefined : new Intl.NumberFormat(formatLocale).format(count);\n const ratingName = (labels?.rating ?? defaultRatingLabel)(value, max, formattedValue);\n const name =\n count === undefined || formattedCount === undefined\n ? ratingName\n : `${ratingName}, ${(labels?.count ?? defaultCountLabel)(count, formattedCount)}`;\n const showText = showValue || compact || count !== undefined;\n const textSize = textSizeMap[size];\n\n const resolvedColor = resolveRatingColor(color);\n const glyphs = useStarGlyphs('RatingDisplay', iconFilled, iconOutline);\n const { registerItem, counts } = useRatingItemRegistry();\n // A compact display ignores `children` (D26): it never renders items of its own, so a value\n // from 1 to `max` without an item is never \"missing\" on purpose.\n const hasItems = !compact && slotRendersContent(children);\n useRatingItemChecks(counts, max, hasItems);\n // Read-only: the stars take the inert actions (they choose, preview and rove nothing).\n const context = React.useMemo<RatingContextValue>(\n () => ({\n ...INERT_RATING_CONTEXT,\n kind: 'display',\n value,\n drawnValue: value,\n max,\n size,\n color: resolvedColor,\n glyphs,\n registerItem,\n }),\n [value, max, size, resolvedColor, glyphs, registerItem],\n );\n\n return (\n <div\n ref={ref}\n role=\"img\"\n aria-label={name}\n data-compact={compact ? '' : undefined}\n data-color={resolvedColor}\n className={cn(ratingDisplayClassNames.root, 'inline-flex items-center gap-0.5', className)}\n {...rest}\n >\n {compact ? (\n <StarGlyph\n starClassName={ratingDisplayClassNames.star}\n iconClassName={ratingDisplayClassNames.icon}\n fraction={1}\n size={size}\n color={resolvedColor}\n glyphs={glyphs}\n />\n ) : (\n <RatingContext.Provider value={context}>\n {ratingItems(children, max)}\n </RatingContext.Provider>\n )}\n {showText && (\n <span\n className={cn(\n ratingDisplayClassNames.value,\n 'ms-1 font-semibold text-foreground',\n textSize,\n )}\n >\n {formattedValue}\n </span>\n )}\n {formattedCount !== undefined && (\n <span className={cn(ratingDisplayClassNames.count, 'ms-1 text-muted-foreground', textSize)}>\n ({formattedCount})\n </span>\n )}\n </div>\n );\n};\nRatingDisplayRoot.displayName = 'RatingDisplay';\n\n/**\n * A star rating input (`role=\"radiogroup\"` of `role=\"radio\"` stars).\n *\n * - One tab stop (the radio of the chosen value, else the first). Keys choose relative to the\n * current rating and move focus to the chosen radio, as in 0.4: Right/Up one `step` more (a\n * star, or half a star), Left/Down one fewer (Left/Right mirrored under `dir=\"rtl\"`), Home the\n * smallest value (`step`) and End `max`. From an empty rating, Right/Up/Home choose `step`.\n * Keys at the ends (and Left/Down while empty) emit nothing.\n * - The keyboard cannot clear a rating: Left/Down stop at `step` (APG radio group; 0.4 went down\n * to 0). Only a controlled `value={0}` (or a form reset while `defaultValue` is 0) clears it.\n * - `step={0.5}` offers half stars. Each star stays one pointer target, which chooses by the\n * pointer's position (its half from the inline start, else its full value) and then focuses\n * the radio it chose; it holds two transparent radios (\"2.5 stars\", \"3 stars\") for the\n * keyboard and screen readers, and draws the focus ring of either. A controlled value between\n * two steps checks no radio and is drawn as the step below it; the keys move it to the next or\n * previous step.\n * - `onValueChange` (and the deprecated `onChange` alias) fire only when the rating changes, so\n * choosing the current star again calls neither.\n * - Hovering previews a value (half stars preview by the pointer's position); the preview never\n * outlives the hover or a disabled state.\n * - `color` colors the filled stars (`marigold`, the default, `brand` or `neutral`; the root\n * carries `data-color`); `iconFilled` and `iconOutline` replace the star glyphs, as a pair.\n * - Inside a `Field` it is named by the Field label (instead of the default \"Rating\") and\n * described by its hint and error. The stars are named \"1 star\", \"2 stars\", … (and a half value\n * \"2.5 stars\"); `labels` localizes these names.\n * - With `name` (or `required`) it takes part in native forms; a form reset restores\n * `defaultValue`.\n * - The stars are generated from `max`. Children that render content replace them: one\n * `Rating.Item` per value from 1 to `max`, chosen, previewed, roved and named as the generated\n * stars are (`max` still sets the key range and the star names).\n *\n * Sub-component: `Rating.Item` (the same component as `RatingDisplay.Item`). React Server\n * Components import its flat name `RatingItem` (dotted access needs a client file).\n */\nexport const Rating = /* @__PURE__ */ Object.assign(RatingRoot, { Item: RatingItem });\n\n/**\n * A read-only star rating (`role=\"img\"` named \"Rating: <value> out of <max>\"). A fractional value\n * is drawn with a partly filled star, so the stars and the name show the same value.\n *\n * - `showValue` adds the value as text after the stars, `count` the number of ratings (\"(1,160)\",\n * also added to the name), and `compact` shows one filled star with the value instead of `max`\n * stars (the root carries `data-compact`). Without them only the stars show.\n * - The value (up to one decimal) and the count are formatted with `locale`, in the text and in\n * the name; `labels` localizes the name. Pass `locale` when rendering on the server.\n * - `color` colors the filled stars (`marigold`, the default, `brand` or `neutral`; the root\n * carries `data-color`); `iconFilled` and `iconOutline` replace the star glyphs, as a pair.\n * - The stars are generated from `max`. Children that render content replace them: one\n * `RatingDisplay.Item` per value from 1 to `max`. A `compact` display ignores them.\n *\n * Sub-component: `RatingDisplay.Item` (the same component as `Rating.Item`). React Server\n * Components import its flat name `RatingDisplayItem`, or `RatingItem` (dotted access needs a\n * client file).\n */\nexport const RatingDisplay = /* @__PURE__ */ Object.assign(RatingDisplayRoot, {\n Item: RatingItem,\n});\n\n/**\n * Flat name of `RatingDisplay.Item` for React Server Components (the same component as\n * `RatingItem`).\n */\nexport const RatingDisplayItem = RatingItem;\n\nexport { RatingItem, type RatingItemProps, type RatingColor } from './Rating.item';\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/slot.cjs"),i=require("../../lib/composeEventHandlers.cjs"),a=require("../../lib/classNames.cjs"),o=require("../../lib/direction.cjs"),s=require("../../lib/styles.cjs"),c=require("../button/Button.slots.cjs"),l=require("../../lib/icons.cjs"),u=require("../../lib/events.cjs");let d=require("react");d=e.__toESM(d,1);let f=require("react/jsx-runtime");var p={marigold:`text-rating`,brand:`text-primary`,neutral:`text-foreground`},m=`text-stroke-accessible`;function h(e){return e===`brand`||e===`neutral`?e:`marigold`}var g={"extra-small":`h-3 w-3`,small:`h-4 w-4`,medium:`h-5 w-5`,large:`h-6 w-6`,"extra-large":`h-8 w-8`},_={"extra-small":`p-1.5`,small:`p-1`,medium:`p-0.5`,large:`p-0.5`,"extra-large":`p-0.5`},v={filled:null,outline:null};function y(e){let{glyph:t,button:n}=c.unwrapButtonGlyph(e),i=r.slotRendersContent(t);return{glyph:i?t:null,button:n,empty:e!=null&&n===null&&!i}}function b(e,t,{button:r,empty:i}){d.useEffect(()=>{i&&n.warnOnce(`${e}:${t}-empty`,`${e}: \`${t}\` renders nothing, so the default star is used.`),r&&n.warnOnce(`${e}:${t}-button`,`${e}: \`${t}\` received ${r}; its children render as the glyph of the star and its props were dropped (buttons cannot be nested). Pass icon content instead, e.g. \`${t}={<MyIcon />}\`.`)},[e,t,i,r])}function x(e,t,r){let i=y(t),a=y(r),o=t===void 0!=(r===void 0);d.useEffect(()=>{o&&n.warnOnce(`${e}:icon-pair`,`${e}: pass both \`iconFilled\` and \`iconOutline\`: with only one of them, the other is the default star.`)},[e,o]),b(e,`iconFilled`,i),b(e,`iconOutline`,a);let s=i.glyph,c=a.glyph;return d.useMemo(()=>({filled:s,outline:c}),[s,c])}function S(e,t,n){return e?{colorClass:p[t],glyph:n.filled}:{colorClass:m,glyph:n.outline}}function C({filled:e,glyph:n,className:i}){return n==null?e?(0,f.jsx)(l.StarIcon,{className:i}):(0,f.jsx)(l.StarIcon,{className:i,fill:`none`,stroke:`currentColor`,strokeWidth:1.5}):r.renderSlot(n,`span`,t.cn(`inline-flex shrink-0 [&>svg]:size-full`,i),{"aria-hidden":!0})}C.displayName=`GlyphLayer`;var w=({fraction:e,size:n,color:r,glyphs:i,starClassName:a,iconClassName:o,className:s,ref:c,...l})=>{let u=Math.round(Math.min(1,Math.max(0,e))*100),d=g[n];if(u>0&&u<100){let e=S(!1,r,i),n=S(!0,r,i);return(0,f.jsxs)(`span`,{...l,ref:c,className:t.cn(a,`relative inline-flex`,e.colorClass,s),children:[(0,f.jsx)(C,{filled:!1,glyph:e.glyph,className:t.cn(o,d)}),(0,f.jsx)(`span`,{className:t.cn(`absolute inset-y-0 start-0 flex overflow-hidden`,n.colorClass),style:{width:`${u}%`},children:(0,f.jsx)(C,{filled:!0,glyph:n.glyph,className:t.cn(o,d,`shrink-0`)})})]})}let p=u===100,m=S(p,r,i);return(0,f.jsx)(`span`,{...l,ref:c,className:t.cn(a,`inline-flex`,m.colorClass,s),children:(0,f.jsx)(C,{filled:p,glyph:m.glyph,className:t.cn(o,d)})})};w.displayName=`StarGlyph`;var T=()=>{},E={kind:`display`,value:0,drawnValue:0,step:1,max:5,size:`medium`,color:`marigold`,glyphs:v,disabled:!0,starLabel:()=>``,getTabIndex:()=>-1,choose:T,preview:T,registerItem:()=>T},D=d.createContext(null);D.displayName=`RatingContext`;function O(){return d.useContext(D)||(n.reportMissingContext(`Rating.Item`,`a rating (Rating or RatingDisplay)`),E)}function k(){let[e]=d.useState(()=>{let e=new Map;return{counts:e,registerItem:t=>(e.set(t,(e.get(t)??0)+1),()=>{let n=(e.get(t)??1)-1;n>0?e.set(t,n):e.delete(t)})}});return e}function A(e,t,r){d.useEffect(()=>{for(let[r,i]of e)i>1&&n.warnOnce(`Rating.Item:duplicate:${r}`,`Rating.Item: two items have the value ${r}; give each star a unique value from 1 to max.`),(!Number.isInteger(r)||r<1||r>t)&&n.warnOnce(`Rating.Item:value:${r}`,`Rating.Item: the value ${r} is not a whole number from 1 to ${t}.`);if(r){for(let r=1;r<=t;r++)if(!e.has(r)){n.warnOnce(`Rating.Item:missing`,`Rating.Item: no item has the value ${r}; pass one Rating.Item per value from 1 to max.`);return}}})}var j=({value:e,iconFilled:n,iconOutline:r,className:c,ref:l,...p})=>{let m=O(),{registerItem:h}=m;d.useLayoutEffect(()=>h(e),[h,e]);let v=x(`Rating.Item`,n,r),y=n!==void 0||r!==void 0?v:m.glyphs,b=m.kind===`display`?t.cn(a.ratingItemClassNames.root,a.ratingDisplayClassNames.star):t.cn(a.ratingItemClassNames.root,a.ratingClassNames.star),T=m.kind===`display`?t.cn(a.ratingItemClassNames.icon,a.ratingDisplayClassNames.icon):t.cn(a.ratingItemClassNames.icon,a.ratingClassNames.icon);if(m.kind===`display`)return(0,f.jsx)(w,{...p,ref:l,starClassName:b,iconClassName:T,className:c,fraction:m.drawnValue-(e-1),size:m.size,color:m.color,glyphs:y});if(m.step===.5){let{onClick:n,onPointerMove:r,...a}=p,s=e-.5,d=m.drawnValue,h=d>=e?1:d>=s?.5:0,g=t=>{let n=t.currentTarget.getBoundingClientRect();return(o.getDirection(t.currentTarget)===`rtl`?n.right-t.clientX:t.clientX-n.left)<n.width/2?s:e};return(0,f.jsxs)(`span`,{...a,ref:l,className:t.cn(b,`relative inline-flex cursor-pointer rounded`,_[m.size],`has-focus-visible:outline-2 has-focus-visible:outline-offset-2 has-focus-visible:outline-ring`,m.disabled&&`cursor-not-allowed`,c),onClick:i.composeEventHandlers(n,e=>{if(m.disabled||e.detail===0||!u.isOwnEvent(e))return;let t=e.target.closest(`[role="radio"]`);t&&e.currentTarget.contains(t)||m.choose(g(e),!0)}),onPointerMove:i.composeEventHandlers(r,e=>{!m.disabled&&e.pointerType===`mouse`&&u.isOwnEvent(e)&&m.preview(g(e))}),children:[(0,f.jsx)(w,{iconClassName:T,fraction:h,size:m.size,color:m.color,glyphs:y}),[s,e].map((e,n)=>{let r=String(e);return(0,f.jsx)(`button`,{type:`button`,role:`radio`,"aria-checked":m.value===e,"aria-label":m.starLabel(e,m.max),"data-roving-value":r,tabIndex:m.disabled?-1:m.getTabIndex(r),disabled:m.disabled,className:t.cn(`pointer-events-none absolute inset-y-0 w-1/2 border-0 bg-transparent p-0 opacity-0`,n===0?`start-0`:`end-0`),onClick:()=>{m.disabled||m.choose(e,!1)}},r)})]})}let{onClick:E,onMouseEnter:D,...k}=p,A=String(e),j=m.drawnValue>=e,M=S(j,m.color,y);return(0,f.jsx)(`button`,{type:`button`,...k,ref:l,role:`radio`,"aria-checked":m.value===e,"aria-label":m.starLabel(e,m.max),"data-roving-value":A,tabIndex:m.disabled?-1:m.getTabIndex(A),disabled:m.disabled,className:t.cn(b,`inline-flex cursor-pointer rounded border-0 bg-transparent transition-colors motion-reduce:transition-none disabled:cursor-not-allowed`,_[m.size],s.focusRing,M.colorClass,c),onClick:i.composeEventHandlers(E,t=>{!m.disabled&&u.isOwnEvent(t)&&m.choose(e,!1)}),onMouseEnter:i.composeEventHandlers(D,t=>{!m.disabled&&u.isOwnEvent(t)&&m.preview(e)}),children:(0,f.jsx)(C,{filled:j,glyph:M.glyph,className:t.cn(T,g[m.size])})})};j.displayName=`RatingItem`;function M(e,t){let n=r.materialiseSlotContent(e);return r.slotRendersContent(n)?n:Array.from({length:t},(e,t)=>(0,f.jsx)(j,{value:t+1},t+1))}exports.FILLED_COLOR=p,exports.INERT_RATING_CONTEXT=E,exports.RatingContext=D,exports.RatingItem=j,exports.StarGlyph=w,exports.ratingItems=M,exports.resolveRatingColor=h,exports.useRatingContext=O,exports.useRatingItemChecks=A,exports.useRatingItemRegistry=k,exports.useStarGlyphs=x;
|
|
2
|
+
//# sourceMappingURL=Rating.item.cjs.map
|