@seekalfred/primitives 0.5.0 → 0.6.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 +664 -9
- package/dist/accordion/accordion.d.ts +5 -5
- package/dist/accordion/accordion.js +22 -11
- package/dist/accordion/accordion.js.map +1 -1
- package/dist/action-button/action-button.d.ts +50 -0
- package/dist/action-button/action-button.js +159 -0
- package/dist/action-button/action-button.js.map +1 -0
- package/dist/action-button/index.d.ts +2 -0
- package/dist/action-button/index.js +2 -0
- package/dist/alert/alert.d.ts +16 -2
- package/dist/alert/alert.js +118 -20
- package/dist/alert/alert.js.map +1 -1
- package/dist/alert-dialog/alert-dialog.d.ts +1 -1
- package/dist/alert-dialog/alert-dialog.js +4 -2
- package/dist/alert-dialog/alert-dialog.js.map +1 -1
- package/dist/avatar/avatar.d.ts +7 -1
- package/dist/avatar/avatar.js +51 -18
- package/dist/avatar/avatar.js.map +1 -1
- package/dist/badge/badge.d.ts +10 -3
- package/dist/badge/badge.js +37 -5
- package/dist/badge/badge.js.map +1 -1
- package/dist/breadcrumb/breadcrumb.d.ts +3 -30
- package/dist/breadcrumb/breadcrumb.js +25 -8
- package/dist/breadcrumb/breadcrumb.js.map +1 -1
- package/dist/button/button.d.ts +36 -23
- package/dist/button/button.js +178 -33
- package/dist/button/button.js.map +1 -1
- package/dist/button-group/button-group.d.ts +76 -0
- package/dist/button-group/button-group.js +403 -0
- package/dist/button-group/button-group.js.map +1 -0
- package/dist/button-group/index.d.ts +2 -0
- package/dist/button-group/index.js +2 -0
- package/dist/calendar/calendar.d.ts +3 -3
- package/dist/calendar/calendar.js +263 -34
- package/dist/calendar/calendar.js.map +1 -1
- package/dist/card/card.d.ts +14 -7
- package/dist/card/card.js +32 -14
- package/dist/card/card.js.map +1 -1
- package/dist/checkbox/checkbox.d.ts +2 -9
- package/dist/checkbox/checkbox.js +28 -29
- package/dist/checkbox/checkbox.js.map +1 -1
- package/dist/confirm-morph/confirm-morph.d.ts +85 -0
- package/dist/confirm-morph/confirm-morph.js +652 -0
- package/dist/confirm-morph/confirm-morph.js.map +1 -0
- package/dist/confirm-morph/index.d.ts +2 -0
- package/dist/confirm-morph/index.js +2 -0
- package/dist/copy-button/copy-button.d.ts +32 -0
- package/dist/copy-button/copy-button.js +134 -0
- package/dist/copy-button/copy-button.js.map +1 -0
- package/dist/copy-button/index.d.ts +2 -0
- package/dist/copy-button/index.js +2 -0
- package/dist/date-picker/date-picker.d.ts +51 -0
- package/dist/date-picker/date-picker.js +241 -0
- package/dist/date-picker/date-picker.js.map +1 -0
- package/dist/date-picker/date-range-picker.d.ts +78 -0
- package/dist/date-picker/date-range-picker.js +1015 -0
- package/dist/date-picker/date-range-picker.js.map +1 -0
- package/dist/date-picker/index.d.ts +4 -0
- package/dist/date-picker/index.js +4 -0
- package/dist/date-picker/picker-parts.d.ts +46 -0
- package/dist/date-picker/picker-parts.js +135 -0
- package/dist/date-picker/picker-parts.js.map +1 -0
- package/dist/dialog/dialog.d.ts +12 -16
- package/dist/dialog/dialog.js +45 -14
- package/dist/dialog/dialog.js.map +1 -1
- package/dist/empty-state/empty-state.d.ts +44 -0
- package/dist/empty-state/empty-state.js +83 -0
- package/dist/empty-state/empty-state.js.map +1 -0
- package/dist/empty-state/index.d.ts +2 -0
- package/dist/empty-state/index.js +2 -0
- package/dist/expanding-button-group/expanding-button-group.d.ts +54 -0
- package/dist/expanding-button-group/expanding-button-group.js +350 -0
- package/dist/expanding-button-group/expanding-button-group.js.map +1 -0
- package/dist/expanding-button-group/index.d.ts +2 -0
- package/dist/expanding-button-group/index.js +2 -0
- package/dist/file-drop-zone/file-drop-zone.d.ts +71 -0
- package/dist/file-drop-zone/file-drop-zone.js +116 -0
- package/dist/file-drop-zone/file-drop-zone.js.map +1 -0
- package/dist/file-drop-zone/index.d.ts +2 -0
- package/dist/file-drop-zone/index.js +2 -0
- package/dist/filter-bar/filter-bar.d.ts +121 -0
- package/dist/filter-bar/filter-bar.js +300 -0
- package/dist/filter-bar/filter-bar.js.map +1 -0
- package/dist/filter-bar/index.d.ts +2 -0
- package/dist/filter-bar/index.js +2 -0
- package/dist/floating-button-group/floating-button-group.d.ts +61 -0
- package/dist/floating-button-group/floating-button-group.js +340 -0
- package/dist/floating-button-group/floating-button-group.js.map +1 -0
- package/dist/floating-button-group/index.d.ts +2 -0
- package/dist/floating-button-group/index.js +2 -0
- package/dist/icon-morph/icon-morph.d.ts +55 -0
- package/dist/icon-morph/icon-morph.js +331 -0
- package/dist/icon-morph/icon-morph.js.map +1 -0
- package/dist/icon-morph/index.d.ts +2 -0
- package/dist/icon-morph/index.js +2 -0
- package/dist/index.d.ts +24 -2
- package/dist/index.js +29 -7
- package/dist/input/input.d.ts +23 -1
- package/dist/input/input.js +37 -13
- package/dist/input/input.js.map +1 -1
- package/dist/label/label.d.ts +1 -1
- package/dist/label/label.js +4 -2
- package/dist/label/label.js.map +1 -1
- package/dist/lib/count-to.js +113 -0
- package/dist/lib/count-to.js.map +1 -0
- package/dist/lib/eye-morph.js +62 -0
- package/dist/lib/eye-morph.js.map +1 -0
- package/dist/lib/field-message.js +336 -0
- package/dist/lib/field-message.js.map +1 -0
- package/dist/lib/field-shell.js +81 -0
- package/dist/lib/field-shell.js.map +1 -0
- package/dist/lib/field-surface.js +4 -2
- package/dist/lib/field-surface.js.map +1 -1
- package/dist/lib/flip.js +80 -0
- package/dist/lib/flip.js.map +1 -0
- package/dist/lib/height-follow.js +59 -0
- package/dist/lib/height-follow.js.map +1 -0
- package/dist/lib/icon-swap.js +47 -0
- package/dist/lib/icon-swap.js.map +1 -0
- package/dist/lib/leaving-list.js +57 -0
- package/dist/lib/leaving-list.js.map +1 -0
- package/dist/lib/merge-refs.js +22 -0
- package/dist/lib/merge-refs.js.map +1 -0
- package/dist/lib/morph-text.js +128 -0
- package/dist/lib/morph-text.js.map +1 -0
- package/dist/lib/motion.js +162 -0
- package/dist/lib/motion.js.map +1 -0
- package/dist/lib/pausable-timeout.js +67 -0
- package/dist/lib/pausable-timeout.js.map +1 -0
- package/dist/lib/rolling-value.js +31 -0
- package/dist/lib/rolling-value.js.map +1 -0
- package/dist/lib/spring-progress.js +114 -0
- package/dist/lib/spring-progress.js.map +1 -0
- package/dist/lib/svg-id.js +10 -0
- package/dist/lib/svg-id.js.map +1 -0
- package/dist/lib/swap-text.js +77 -0
- package/dist/lib/swap-text.js.map +1 -0
- package/dist/lib/use-copy-feedback.js +36 -0
- package/dist/lib/use-copy-feedback.js.map +1 -0
- package/dist/menu/menu.d.ts +5 -5
- package/dist/menu/menu.js +10 -6
- package/dist/menu/menu.js.map +1 -1
- package/dist/page-header/index.d.ts +2 -0
- package/dist/page-header/index.js +2 -0
- package/dist/page-header/page-header.d.ts +75 -0
- package/dist/page-header/page-header.js +83 -0
- package/dist/page-header/page-header.js.map +1 -0
- package/dist/password-field/index.d.ts +2 -0
- package/dist/password-field/index.js +2 -0
- package/dist/password-field/password-field.d.ts +37 -0
- package/dist/password-field/password-field.js +101 -0
- package/dist/password-field/password-field.js.map +1 -0
- package/dist/password-strength/index.d.ts +2 -0
- package/dist/password-strength/index.js +2 -0
- package/dist/password-strength/password-strength.d.ts +127 -0
- package/dist/password-strength/password-strength.js +455 -0
- package/dist/password-strength/password-strength.js.map +1 -0
- package/dist/popover/popover.d.ts +10 -2
- package/dist/popover/popover.js +6 -4
- package/dist/popover/popover.js.map +1 -1
- package/dist/progress/progress.d.ts +2 -2
- package/dist/progress/progress.js +50 -7
- package/dist/progress/progress.js.map +1 -1
- package/dist/radio-group/radio-group.d.ts +3 -3
- package/dist/radio-group/radio-group.js +14 -10
- package/dist/radio-group/radio-group.js.map +1 -1
- package/dist/scroll-area/scroll-area.d.ts +17 -6
- package/dist/scroll-area/scroll-area.js +30 -6
- package/dist/scroll-area/scroll-area.js.map +1 -1
- package/dist/search-field/index.d.ts +2 -0
- package/dist/search-field/index.js +2 -0
- package/dist/search-field/search-field.d.ts +26 -0
- package/dist/search-field/search-field.js +155 -0
- package/dist/search-field/search-field.js.map +1 -0
- package/dist/select/select.d.ts +3 -3
- package/dist/select/select.js +85 -24
- package/dist/select/select.js.map +1 -1
- package/dist/separator/separator.d.ts +1 -1
- package/dist/separator/separator.js +4 -2
- package/dist/separator/separator.js.map +1 -1
- package/dist/sheet/sheet.d.ts +1 -1
- package/dist/sheet/sheet.js +6 -3
- package/dist/sheet/sheet.js.map +1 -1
- package/dist/side-nav/index.d.ts +2 -0
- package/dist/side-nav/index.js +2 -0
- package/dist/side-nav/side-nav.d.ts +72 -0
- package/dist/side-nav/side-nav.js +142 -0
- package/dist/side-nav/side-nav.js.map +1 -0
- package/dist/skeleton/skeleton.d.ts +8 -2
- package/dist/skeleton/skeleton.js +9 -3
- package/dist/skeleton/skeleton.js.map +1 -1
- package/dist/slider/slider.d.ts +2 -2
- package/dist/slider/slider.js +64 -8
- package/dist/slider/slider.js.map +1 -1
- package/dist/spinner/spinner.d.ts +1 -1
- package/dist/spinner/spinner.js +4 -2
- package/dist/spinner/spinner.js.map +1 -1
- package/dist/split-button/index.d.ts +2 -0
- package/dist/split-button/index.js +2 -0
- package/dist/split-button/split-button.d.ts +46 -0
- package/dist/split-button/split-button.js +122 -0
- package/dist/split-button/split-button.js.map +1 -0
- package/dist/stat-card/index.d.ts +2 -0
- package/dist/stat-card/index.js +2 -0
- package/dist/stat-card/stat-card.d.ts +81 -0
- package/dist/stat-card/stat-card.js +152 -0
- package/dist/stat-card/stat-card.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/switch/switch.d.ts +2 -2
- package/dist/switch/switch.js +11 -8
- package/dist/switch/switch.js.map +1 -1
- package/dist/table/index.d.ts +2 -2
- package/dist/table/index.js +2 -2
- package/dist/table/table.d.ts +38 -7
- package/dist/table/table.js +114 -12
- package/dist/table/table.js.map +1 -1
- package/dist/tabs/tabs.d.ts +4 -4
- package/dist/tabs/tabs.js +153 -12
- package/dist/tabs/tabs.js.map +1 -1
- package/dist/textarea/textarea.d.ts +24 -1
- package/dist/textarea/textarea.js +27 -3
- package/dist/textarea/textarea.js.map +1 -1
- package/dist/theme-switch/index.d.ts +2 -0
- package/dist/theme-switch/index.js +2 -0
- package/dist/theme-switch/theme-switch.d.ts +37 -0
- package/dist/theme-switch/theme-switch.js +123 -0
- package/dist/theme-switch/theme-switch.js.map +1 -0
- package/dist/time-picker/index.d.ts +2 -0
- package/dist/time-picker/index.js +2 -0
- package/dist/time-picker/time-picker.d.ts +54 -0
- package/dist/time-picker/time-picker.js +201 -0
- package/dist/time-picker/time-picker.js.map +1 -0
- package/dist/toast/toast.d.ts +2 -2
- package/dist/toast/toast.js +61 -39
- package/dist/toast/toast.js.map +1 -1
- package/dist/tooltip/tooltip.d.ts +3 -3
- package/dist/tooltip/tooltip.js +66 -15
- package/dist/tooltip/tooltip.js.map +1 -1
- package/package.json +83 -3
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { InputProps } from "react-aria-components";
|
|
2
|
+
//#region src/password-field/password-field.d.ts
|
|
3
|
+
/** The toggle's accessible names. Both have English defaults; pass the ones you translate. */
|
|
4
|
+
export interface PasswordFieldMessages {
|
|
5
|
+
showPassword: string;
|
|
6
|
+
hidePassword: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const defaultPasswordFieldMessages: PasswordFieldMessages;
|
|
9
|
+
export interface PasswordFieldProps extends Omit<InputProps, "className" | "style" | "size" | "type"> {
|
|
10
|
+
/** Extra classes for the input. Merged last, so they win conflicts with ours. */
|
|
11
|
+
className?: string;
|
|
12
|
+
/** The visible label, tied to the input with `htmlFor`. */
|
|
13
|
+
label: string;
|
|
14
|
+
/**
|
|
15
|
+
* Helper text under the field, named by `aria-describedby`. A string, because
|
|
16
|
+
* the copy is animated word by word: it opens on a spring when it appears
|
|
17
|
+
* after mount and changed words rise in. Nothing animates on first render.
|
|
18
|
+
*/
|
|
19
|
+
description?: string;
|
|
20
|
+
/** Translated or reworded toggle names. */
|
|
21
|
+
messages?: Partial<PasswordFieldMessages>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A password input with a show and hide toggle. Switching resolves the text in
|
|
25
|
+
* place from a soft blur, and the eye is one outline that a slash draws across.
|
|
26
|
+
* Native input props apply to the input; `disabled` also disables the toggle,
|
|
27
|
+
* and `aria-invalid` gives the box its invalid border.
|
|
28
|
+
*
|
|
29
|
+
* The toggle's name changes with the state and it is also `aria-pressed`, so a
|
|
30
|
+
* screen reader may announce both ("Hide password, pressed").
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* <PasswordField label="Password" description="At least eight characters." />
|
|
34
|
+
*/
|
|
35
|
+
export declare const PasswordField: import("react").ForwardRefExoticComponent<PasswordFieldProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
36
|
+
//#endregion
|
|
37
|
+
//# sourceMappingURL=password-field.d.ts.map
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { fieldSurfaceVariants } from "../lib/field-surface.js";
|
|
4
|
+
import { FieldShell, useFieldWiring } from "../lib/field-shell.js";
|
|
5
|
+
import { EyeMorph } from "../lib/eye-morph.js";
|
|
6
|
+
import { forwardRef, useState } from "react";
|
|
7
|
+
import { Button, Group, Input } from "react-aria-components";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
//#region src/password-field/password-field.tsx
|
|
10
|
+
const defaultPasswordFieldMessages = {
|
|
11
|
+
showPassword: "Show password",
|
|
12
|
+
hidePassword: "Hide password"
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* The field's box. A React Aria `Group` rather than the input, because the
|
|
16
|
+
* toggle sits inside the same border: it carries the shared field surface (the
|
|
17
|
+
* 160ms border transition, the darker border on hover and focus, the muted
|
|
18
|
+
* disabled look, the invalid border) and the input inside is borderless.
|
|
19
|
+
*
|
|
20
|
+
* `data-focus-within` darkens the border too. A Group reports focus-visible
|
|
21
|
+
* from the input modality, so a mouse click into the input, or onto the toggle,
|
|
22
|
+
* would otherwise leave the border pale; a plain Input is different because
|
|
23
|
+
* React Aria treats a text input as always keyboard-focused.
|
|
24
|
+
*/
|
|
25
|
+
const shellClass = cn(fieldSurfaceVariants(), "flex items-center h-(--density-control-h-md) ps-(--density-control-pad-md) field-toggle-shell [&:where([data-focus-within])]:border-foreground");
|
|
26
|
+
/** The input inside the box: no border, no fill, no outline of its own. */
|
|
27
|
+
const inputClass = "min-w-0 flex-1 border-0 bg-transparent p-0 font-sans text-base text-foreground outline-none placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground data-[disabled]:cursor-not-allowed motion-safe:data-[reveal=shown]:animate-field-reveal-shown motion-safe:data-[reveal=hidden]:animate-field-reveal-hidden";
|
|
28
|
+
const toggleClass = "field-toggle-button grid size-7.5 flex-none cursor-pointer place-items-center rounded-md border-0 bg-transparent p-0 text-muted-foreground outline-none data-[hovered]:bg-muted data-[hovered]:text-foreground aria-pressed:text-foreground data-[focus-visible]:outline-solid data-[focus-visible]:outline-(length:--focus-ring-width) data-[focus-visible]:outline-offset-(--focus-ring-offset) data-[focus-visible]:outline-(--color-ring) data-[disabled]:cursor-not-allowed";
|
|
29
|
+
/**
|
|
30
|
+
* A password input with a show and hide toggle. Switching resolves the text in
|
|
31
|
+
* place from a soft blur, and the eye is one outline that a slash draws across.
|
|
32
|
+
* Native input props apply to the input; `disabled` also disables the toggle,
|
|
33
|
+
* and `aria-invalid` gives the box its invalid border.
|
|
34
|
+
*
|
|
35
|
+
* The toggle's name changes with the state and it is also `aria-pressed`, so a
|
|
36
|
+
* screen reader may announce both ("Hide password, pressed").
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* <PasswordField label="Password" description="At least eight characters." />
|
|
40
|
+
*/
|
|
41
|
+
const PasswordField = forwardRef(function PasswordField({ label, description, messages: messagesProp, className, ...props }, ref) {
|
|
42
|
+
const messages = {
|
|
43
|
+
...defaultPasswordFieldMessages,
|
|
44
|
+
...messagesProp
|
|
45
|
+
};
|
|
46
|
+
const [visible, setVisible] = useState(false);
|
|
47
|
+
const [toggled, setToggled] = useState(false);
|
|
48
|
+
const field = useFieldWiring({
|
|
49
|
+
enabled: true,
|
|
50
|
+
id: props.id,
|
|
51
|
+
describedBy: props["aria-describedby"],
|
|
52
|
+
invalid: props["aria-invalid"],
|
|
53
|
+
description,
|
|
54
|
+
error: void 0
|
|
55
|
+
});
|
|
56
|
+
const disabled = Boolean(props.disabled);
|
|
57
|
+
const ariaInvalid = props["aria-invalid"];
|
|
58
|
+
const control = /* @__PURE__ */ jsxs(Group, {
|
|
59
|
+
role: "presentation",
|
|
60
|
+
isDisabled: disabled,
|
|
61
|
+
isInvalid: ariaInvalid !== void 0 && ariaInvalid !== false && ariaInvalid !== "false",
|
|
62
|
+
"data-slot": "password-field-shell",
|
|
63
|
+
className: shellClass,
|
|
64
|
+
children: [/* @__PURE__ */ jsx(Input, {
|
|
65
|
+
ref,
|
|
66
|
+
...props,
|
|
67
|
+
...field.controlProps,
|
|
68
|
+
type: visible ? "text" : "password",
|
|
69
|
+
"data-slot": "password-field",
|
|
70
|
+
"data-reveal": toggled ? visible ? "shown" : "hidden" : void 0,
|
|
71
|
+
className: cn(inputClass, className)
|
|
72
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
73
|
+
type: "button",
|
|
74
|
+
isDisabled: disabled,
|
|
75
|
+
"aria-label": visible ? messages.hidePassword : messages.showPassword,
|
|
76
|
+
"aria-pressed": visible,
|
|
77
|
+
onPress: () => {
|
|
78
|
+
setVisible((current) => !current);
|
|
79
|
+
setToggled(true);
|
|
80
|
+
},
|
|
81
|
+
className: toggleClass,
|
|
82
|
+
children: /* @__PURE__ */ jsx(EyeMorph, { slashed: visible })
|
|
83
|
+
})]
|
|
84
|
+
});
|
|
85
|
+
if (!field.active) return control;
|
|
86
|
+
return /* @__PURE__ */ jsx(FieldShell, {
|
|
87
|
+
label,
|
|
88
|
+
controlId: field.controlId,
|
|
89
|
+
description,
|
|
90
|
+
hintId: field.hintId,
|
|
91
|
+
error: void 0,
|
|
92
|
+
errorId: void 0,
|
|
93
|
+
wordExit: "sharp",
|
|
94
|
+
numbers: false,
|
|
95
|
+
children: control
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
//#endregion
|
|
99
|
+
export { PasswordField, defaultPasswordFieldMessages };
|
|
100
|
+
|
|
101
|
+
//# sourceMappingURL=password-field.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-field.js","names":["AriaGroup","AriaInput","AriaButton"],"sources":["../../src/password-field/password-field.tsx"],"sourcesContent":["\"use client\";\n\nimport { forwardRef, useState } from \"react\";\nimport {\n Button as AriaButton,\n Group as AriaGroup,\n Input as AriaInput,\n type InputProps as AriaInputProps,\n} from \"react-aria-components\";\n\nimport { cn } from \"../lib/cn.js\";\nimport { EyeMorph } from \"../lib/eye-morph.js\";\nimport { FieldShell, useFieldWiring } from \"../lib/field-shell.js\";\nimport { fieldSurfaceVariants } from \"../lib/field-surface.js\";\n\n/** The toggle's accessible names. Both have English defaults; pass the ones you translate. */\nexport interface PasswordFieldMessages {\n showPassword: string;\n hidePassword: string;\n}\n\nexport const defaultPasswordFieldMessages: PasswordFieldMessages = {\n showPassword: \"Show password\",\n hidePassword: \"Hide password\",\n};\n\n/**\n * The field's box. A React Aria `Group` rather than the input, because the\n * toggle sits inside the same border: it carries the shared field surface (the\n * 160ms border transition, the darker border on hover and focus, the muted\n * disabled look, the invalid border) and the input inside is borderless.\n *\n * `data-focus-within` darkens the border too. A Group reports focus-visible\n * from the input modality, so a mouse click into the input, or onto the toggle,\n * would otherwise leave the border pale; a plain Input is different because\n * React Aria treats a text input as always keyboard-focused.\n */\nconst shellClass = cn(\n fieldSurfaceVariants(),\n \"flex items-center h-(--density-control-h-md) ps-(--density-control-pad-md) field-toggle-shell [&:where([data-focus-within])]:border-foreground\",\n);\n\n/** The input inside the box: no border, no fill, no outline of its own. */\nconst inputClass =\n \"min-w-0 flex-1 border-0 bg-transparent p-0 font-sans text-base text-foreground outline-none placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground data-[disabled]:cursor-not-allowed motion-safe:data-[reveal=shown]:animate-field-reveal-shown motion-safe:data-[reveal=hidden]:animate-field-reveal-hidden\";\n\nconst toggleClass =\n \"field-toggle-button grid size-7.5 flex-none cursor-pointer place-items-center rounded-md border-0 bg-transparent p-0 text-muted-foreground outline-none data-[hovered]:bg-muted data-[hovered]:text-foreground aria-pressed:text-foreground data-[focus-visible]:outline-solid data-[focus-visible]:outline-(length:--focus-ring-width) data-[focus-visible]:outline-offset-(--focus-ring-offset) data-[focus-visible]:outline-(--color-ring) data-[disabled]:cursor-not-allowed\";\n\nexport interface PasswordFieldProps extends Omit<\n AriaInputProps,\n \"className\" | \"style\" | \"size\" | \"type\"\n> {\n /** Extra classes for the input. Merged last, so they win conflicts with ours. */\n className?: string;\n /** The visible label, tied to the input with `htmlFor`. */\n label: string;\n /**\n * Helper text under the field, named by `aria-describedby`. A string, because\n * the copy is animated word by word: it opens on a spring when it appears\n * after mount and changed words rise in. Nothing animates on first render.\n */\n description?: string;\n /** Translated or reworded toggle names. */\n messages?: Partial<PasswordFieldMessages>;\n}\n\n/**\n * A password input with a show and hide toggle. Switching resolves the text in\n * place from a soft blur, and the eye is one outline that a slash draws across.\n * Native input props apply to the input; `disabled` also disables the toggle,\n * and `aria-invalid` gives the box its invalid border.\n *\n * The toggle's name changes with the state and it is also `aria-pressed`, so a\n * screen reader may announce both (\"Hide password, pressed\").\n *\n * @example\n * <PasswordField label=\"Password\" description=\"At least eight characters.\" />\n */\nexport const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(\n function PasswordField({ label, description, messages: messagesProp, className, ...props }, ref) {\n const messages = { ...defaultPasswordFieldMessages, ...messagesProp };\n const [visible, setVisible] = useState(false);\n // data-reveal only appears after the first toggle, so the animation runs on each change but never on mount.\n const [toggled, setToggled] = useState(false);\n const field = useFieldWiring({\n enabled: true,\n id: props.id,\n describedBy: props[\"aria-describedby\"],\n invalid: props[\"aria-invalid\"],\n description,\n error: undefined,\n });\n const disabled = Boolean(props.disabled);\n const ariaInvalid = props[\"aria-invalid\"];\n const invalid = ariaInvalid !== undefined && ariaInvalid !== false && ariaInvalid !== \"false\";\n\n const control = (\n <AriaGroup\n role=\"presentation\"\n isDisabled={disabled}\n isInvalid={invalid}\n data-slot=\"password-field-shell\"\n className={shellClass}\n >\n <AriaInput\n ref={ref}\n {...props}\n {...field.controlProps}\n type={visible ? \"text\" : \"password\"}\n data-slot=\"password-field\"\n data-reveal={toggled ? (visible ? \"shown\" : \"hidden\") : undefined}\n className={cn(inputClass, className)}\n />\n <AriaButton\n type=\"button\"\n isDisabled={disabled}\n aria-label={visible ? messages.hidePassword : messages.showPassword}\n aria-pressed={visible}\n onPress={() => {\n setVisible((current) => !current);\n setToggled(true);\n }}\n className={toggleClass}\n >\n <EyeMorph slashed={visible} />\n </AriaButton>\n </AriaGroup>\n );\n\n if (!field.active) return control;\n return (\n <FieldShell\n label={label}\n controlId={field.controlId}\n description={description}\n hintId={field.hintId}\n error={undefined}\n errorId={undefined}\n wordExit=\"sharp\"\n numbers={false}\n >\n {control}\n </FieldShell>\n );\n },\n);\n"],"mappings":";;;;;;;;;AAqBA,MAAa,+BAAsD;CACjE,cAAc;CACd,cAAc;AAChB;;;;;;;;;;;;AAaA,MAAM,aAAa,GACjB,qBAAqB,GACrB,gJACF;;AAGA,MAAM,aACJ;AAEF,MAAM,cACJ;;;;;;;;;;;;;AAgCF,MAAa,gBAAgB,WAC3B,SAAS,cAAc,EAAE,OAAO,aAAa,UAAU,cAAc,WAAW,GAAG,SAAS,KAAK;CAC/F,MAAM,WAAW;EAAE,GAAG;EAA8B,GAAG;CAAa;CACpE,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAE5C,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,QAAQ,eAAe;EAC3B,SAAS;EACT,IAAI,MAAM;EACV,aAAa,MAAM;EACnB,SAAS,MAAM;EACf;EACA,OAAO,KAAA;CACT,CAAC;CACD,MAAM,WAAW,QAAQ,MAAM,QAAQ;CACvC,MAAM,cAAc,MAAM;CAG1B,MAAM,UACJ,qBAACA,OAAD;EACE,MAAK;EACL,YAAY;EACZ,WANY,gBAAgB,KAAA,KAAa,gBAAgB,SAAS,gBAAgB;EAOlF,aAAU;EACV,WAAW;EALb,UAAA,CAOE,oBAACC,OAAD;GACO;GACL,GAAI;GACJ,GAAI,MAAM;GACV,MAAM,UAAU,SAAS;GACzB,aAAU;GACV,eAAa,UAAW,UAAU,UAAU,WAAY,KAAA;GACxD,WAAW,GAAG,YAAY,SAAS;EACpC,CAAA,GACD,oBAACC,QAAD;GACE,MAAK;GACL,YAAY;GACZ,cAAY,UAAU,SAAS,eAAe,SAAS;GACvD,gBAAc;GACd,eAAe;IACb,YAAY,YAAY,CAAC,OAAO;IAChC,WAAW,IAAI;GACjB;GACA,WAAW;GAEX,UAAA,oBAAC,UAAD,EAAU,SAAS,QAAU,CAAA;EACnB,CAAA,CACH;;CAGb,IAAI,CAAC,MAAM,QAAQ,OAAO;CAC1B,OACE,oBAAC,YAAD;EACS;EACP,WAAW,MAAM;EACJ;EACb,QAAQ,MAAM;EACd,OAAO,KAAA;EACP,SAAS,KAAA;EACT,UAAS;EACT,SAAS;EAER,UAAA;CACS,CAAA;AAEhB,CACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { EstimateStrengthOptions, PasswordRule, PasswordRuleLabels, PasswordRuleOptions, PasswordStrength, PasswordStrengthLevels, PasswordStrengthMessages, PasswordStrengthMessagesInput, PasswordStrengthProps, PasswordStrengthResult, countCodePoints, createPasswordRules, defaultPasswordRules, defaultPasswordStrengthMessages, estimateStrength } from "./password-strength.js";
|
|
2
|
+
export { type EstimateStrengthOptions, type PasswordRule, type PasswordRuleLabels, type PasswordRuleOptions, PasswordStrength, type PasswordStrengthLevels, type PasswordStrengthMessages, type PasswordStrengthMessagesInput, type PasswordStrengthProps, type PasswordStrengthResult, countCodePoints, createPasswordRules, defaultPasswordRules, defaultPasswordStrengthMessages, estimateStrength };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { PasswordStrength, countCodePoints, createPasswordRules, defaultPasswordRules, defaultPasswordStrengthMessages, estimateStrength } from "./password-strength.js";
|
|
2
|
+
export { PasswordStrength, countCodePoints, createPasswordRules, defaultPasswordRules, defaultPasswordStrengthMessages, estimateStrength };
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { InputProps } from "react-aria-components";
|
|
2
|
+
//#region src/password-strength/password-strength.d.ts
|
|
3
|
+
export interface PasswordRule {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
test: (password: string) => boolean;
|
|
7
|
+
/** Characters still missing. Shown as a rolling count beside the rule while it is unmet. */
|
|
8
|
+
remaining?: (password: string) => number;
|
|
9
|
+
}
|
|
10
|
+
export interface PasswordStrengthResult {
|
|
11
|
+
level: 0 | 1 | 2 | 3 | 4;
|
|
12
|
+
label: string;
|
|
13
|
+
met: string[];
|
|
14
|
+
/** True while the password is shorter than the short length, so the meter holds at its first step. */
|
|
15
|
+
short?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** The strength words, one per meter step. Override them to translate the meter. */
|
|
18
|
+
export interface PasswordStrengthLevels {
|
|
19
|
+
tooShort: string;
|
|
20
|
+
weak: string;
|
|
21
|
+
fair: string;
|
|
22
|
+
good: string;
|
|
23
|
+
strong: string;
|
|
24
|
+
}
|
|
25
|
+
/** Every user-facing string in PasswordStrength. All have English defaults; pass only the ones you change. */
|
|
26
|
+
export interface PasswordStrengthMessages {
|
|
27
|
+
levels: PasswordStrengthLevels;
|
|
28
|
+
/** Name of the show password toggle. It is a pressed toggle (aria-pressed), so the name stays the same in both states. */
|
|
29
|
+
showPassword: string;
|
|
30
|
+
/** Accessible name of the strength meter. */
|
|
31
|
+
meterLabel: string;
|
|
32
|
+
/** Meter value text while the field is empty. */
|
|
33
|
+
noPassword: string;
|
|
34
|
+
/** Accessible name of the requirements list. */
|
|
35
|
+
rulesLabel: string;
|
|
36
|
+
/** Read after a rule's label for screen readers, including any leading punctuation. */
|
|
37
|
+
ruleMet: string;
|
|
38
|
+
ruleNotMet: string;
|
|
39
|
+
/** Words around the rolling count beside an unmet rule, as in "4 more". */
|
|
40
|
+
remainingPrefix: string;
|
|
41
|
+
remainingSuffix: string;
|
|
42
|
+
/** The polite live-region summary read after each change. */
|
|
43
|
+
summary: (result: {
|
|
44
|
+
label: string;
|
|
45
|
+
met: number;
|
|
46
|
+
total: number;
|
|
47
|
+
}) => string;
|
|
48
|
+
}
|
|
49
|
+
export declare const defaultPasswordStrengthMessages: PasswordStrengthMessages;
|
|
50
|
+
/** Partial messages, with partial strength words, for the `messages` prop. */
|
|
51
|
+
export type PasswordStrengthMessagesInput = Partial<Omit<PasswordStrengthMessages, "levels">> & {
|
|
52
|
+
levels?: Partial<PasswordStrengthLevels>;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* A new-password field that shows how strong the password is while it is typed:
|
|
56
|
+
* four segments fill and change tone, each rule checks off with a drawn tick, and
|
|
57
|
+
* the strength word swaps in place. Use it when creating or changing a password;
|
|
58
|
+
* use `PasswordField` for sign in. Scoring happens on the device, nothing is sent
|
|
59
|
+
* anywhere.
|
|
60
|
+
*
|
|
61
|
+
* Native input props apply to the input (`className` too); `disabled` also
|
|
62
|
+
* disables the toggle, and `aria-invalid` gives the box its invalid border.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* <PasswordStrength label="New password" onValueChange={(value, strength) => save(value, strength.level)} />
|
|
66
|
+
*/
|
|
67
|
+
export interface PasswordStrengthProps extends Omit<InputProps, "className" | "style" | "size" | "type" | "value" | "defaultValue" | "children"> {
|
|
68
|
+
/** Extra classes for the input. Merged last, so they win conflicts with ours. */
|
|
69
|
+
className?: string;
|
|
70
|
+
/** The visible label, tied to the input with `htmlFor`. */
|
|
71
|
+
label: string;
|
|
72
|
+
value?: string;
|
|
73
|
+
defaultValue?: string;
|
|
74
|
+
onValueChange?: (value: string, strength: PasswordStrengthResult) => void;
|
|
75
|
+
/** Rules to check. Strength is the share of rules met, spread over four steps. */
|
|
76
|
+
rules?: PasswordRule[];
|
|
77
|
+
/**
|
|
78
|
+
* Error copy tied to the field. It is an alert, opens on a spring and swaps as a
|
|
79
|
+
* whole when it changes; the field shakes once each time a new error appears.
|
|
80
|
+
*/
|
|
81
|
+
error?: string;
|
|
82
|
+
revealed?: boolean;
|
|
83
|
+
onRevealedChange?: (revealed: boolean) => void;
|
|
84
|
+
/** Translated or reworded copy. Every string has an English default; see PasswordStrengthMessages. */
|
|
85
|
+
messages?: PasswordStrengthMessagesInput;
|
|
86
|
+
/** Below this many characters the meter holds at its first step and reads "Too short". Defaults to 8. */
|
|
87
|
+
shortLength?: number;
|
|
88
|
+
/** How characters are counted for shortLength. Defaults to code points, so an emoji counts once; pass `password => password.length` to count UTF-16 units like a server might. */
|
|
89
|
+
countCharacters?: (password: string) => number;
|
|
90
|
+
}
|
|
91
|
+
/** Counts code points, so an emoji or other astral character counts as one. */
|
|
92
|
+
export declare const countCodePoints: (password: string) => number;
|
|
93
|
+
/** Labels for the built-in rules. `length` receives the minimum length. */
|
|
94
|
+
export interface PasswordRuleLabels {
|
|
95
|
+
length: (minLength: number) => string;
|
|
96
|
+
case: string;
|
|
97
|
+
number: string;
|
|
98
|
+
symbol: string;
|
|
99
|
+
}
|
|
100
|
+
export interface PasswordRuleOptions {
|
|
101
|
+
/** Characters the length rule asks for. Defaults to 12. */
|
|
102
|
+
minLength?: number;
|
|
103
|
+
/** Translated or reworded rule labels. */
|
|
104
|
+
labels?: Partial<PasswordRuleLabels>;
|
|
105
|
+
/** How the length rule counts characters. Defaults to code points. */
|
|
106
|
+
countCharacters?: (password: string) => number;
|
|
107
|
+
}
|
|
108
|
+
/** The built-in rules (length, mixed case, number, symbol) with your own minimum length, labels and character count. */
|
|
109
|
+
export declare function createPasswordRules({ minLength, labels, countCharacters }?: PasswordRuleOptions): PasswordRule[];
|
|
110
|
+
export declare const defaultPasswordRules: PasswordRule[];
|
|
111
|
+
export interface EstimateStrengthOptions {
|
|
112
|
+
/** Below this many characters a password stays at the first step, however varied it is. Defaults to 8. */
|
|
113
|
+
shortLength?: number;
|
|
114
|
+
/** Strength words for the result's label. */
|
|
115
|
+
levels?: Partial<PasswordStrengthLevels>;
|
|
116
|
+
/** How characters are counted for shortLength. Defaults to code points. */
|
|
117
|
+
countCharacters?: (password: string) => number;
|
|
118
|
+
}
|
|
119
|
+
/** Scores a password on the device: one step per share of rules met, capped at the first step while it is shorter than the short length (8 by default). */
|
|
120
|
+
export declare function estimateStrength(password: string, rules?: PasswordRule[], { shortLength, levels, countCharacters }?: EstimateStrengthOptions): PasswordStrengthResult;
|
|
121
|
+
/**
|
|
122
|
+
* A new-password input with a strength meter and a checklist (see
|
|
123
|
+
* {@link PasswordStrengthProps}).
|
|
124
|
+
*/
|
|
125
|
+
export declare const PasswordStrength: import("react").ForwardRefExoticComponent<PasswordStrengthProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
126
|
+
//#endregion
|
|
127
|
+
//# sourceMappingURL=password-strength.d.ts.map
|