@pearpages/pulp-react 0.2.2 → 0.3.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 +14 -0
- package/dist/accordion.js +1 -1
- package/dist/alert.css +18 -0
- package/dist/alert.css.map +1 -1
- package/dist/alert.js +4 -4
- package/dist/avatar.css +46 -0
- package/dist/avatar.css.map +1 -0
- package/dist/avatar.d.ts +41 -0
- package/dist/avatar.js +5 -0
- package/dist/avatar.js.map +1 -0
- package/dist/badge.css +37 -0
- package/dist/badge.css.map +1 -1
- package/dist/badge.d.ts +22 -5
- package/dist/badge.js +2 -1
- package/dist/button.css +18 -0
- package/dist/button.css.map +1 -1
- package/dist/button.d.ts +11 -2
- package/dist/button.js +2 -2
- package/dist/calendar.js +1 -1
- package/dist/card.js +2 -2
- package/dist/checkbox.js +4 -4
- package/dist/chip.css +95 -0
- package/dist/chip.css.map +1 -0
- package/dist/chip.d.ts +43 -0
- package/dist/chip.js +4 -0
- package/dist/chip.js.map +1 -0
- package/dist/{chunk-N6E2E2OY.js → chunk-2NVC3C7K.js} +3 -3
- package/dist/{chunk-N6E2E2OY.js.map → chunk-2NVC3C7K.js.map} +1 -1
- package/dist/{chunk-MF66ICX6.js → chunk-56RSH7GQ.js} +3 -3
- package/dist/{chunk-MF66ICX6.js.map → chunk-56RSH7GQ.js.map} +1 -1
- package/dist/chunk-5TYCIBLW.js +27 -0
- package/dist/chunk-5TYCIBLW.js.map +1 -0
- package/dist/chunk-7O6FTCZL.js +101 -0
- package/dist/chunk-7O6FTCZL.js.map +1 -0
- package/dist/{chunk-N4C3NQIN.js → chunk-A7TMFEQ2.js} +3 -3
- package/dist/{chunk-N4C3NQIN.js.map → chunk-A7TMFEQ2.js.map} +1 -1
- package/dist/{chunk-2NSQPN7S.js → chunk-AZAI4OVR.js} +3 -3
- package/dist/{chunk-2NSQPN7S.js.map → chunk-AZAI4OVR.js.map} +1 -1
- package/dist/{chunk-DVZ46GQN.js → chunk-CLE2QGCU.js} +3 -3
- package/dist/{chunk-DVZ46GQN.js.map → chunk-CLE2QGCU.js.map} +1 -1
- package/dist/{chunk-5TTYVQ6Q.js → chunk-DE67ECD7.js} +5 -3
- package/dist/chunk-DE67ECD7.js.map +1 -0
- package/dist/{chunk-BAPNIZDV.js → chunk-F2YI5N4L.js} +3 -3
- package/dist/chunk-F2YI5N4L.js.map +1 -0
- package/dist/{chunk-U3N3G2UA.js → chunk-FFCEY76B.js} +10 -5
- package/dist/chunk-FFCEY76B.js.map +1 -0
- package/dist/{chunk-XWPXW46D.js → chunk-GWTHITZO.js} +3 -3
- package/dist/{chunk-XWPXW46D.js.map → chunk-GWTHITZO.js.map} +1 -1
- package/dist/chunk-HDC2IQV2.js +34 -0
- package/dist/chunk-HDC2IQV2.js.map +1 -0
- package/dist/{chunk-VQN5DQP6.js → chunk-HKNIEQ2V.js} +4 -4
- package/dist/{chunk-VQN5DQP6.js.map → chunk-HKNIEQ2V.js.map} +1 -1
- package/dist/{chunk-LA3YBXCR.js → chunk-HPQ462R5.js} +3 -3
- package/dist/{chunk-LA3YBXCR.js.map → chunk-HPQ462R5.js.map} +1 -1
- package/dist/chunk-KSLKNWWM.js +28 -0
- package/dist/chunk-KSLKNWWM.js.map +1 -0
- package/dist/chunk-OKA2PLDV.js +85 -0
- package/dist/chunk-OKA2PLDV.js.map +1 -0
- package/dist/{chunk-6BIEW4WJ.js → chunk-Q6SYKNZ5.js} +3 -3
- package/dist/{chunk-6BIEW4WJ.js.map → chunk-Q6SYKNZ5.js.map} +1 -1
- package/dist/chunk-QID6YYFF.js +33 -0
- package/dist/chunk-QID6YYFF.js.map +1 -0
- package/dist/{chunk-ZVDN3GRI.js → chunk-QJG5ILK5.js} +3 -3
- package/dist/{chunk-ZVDN3GRI.js.map → chunk-QJG5ILK5.js.map} +1 -1
- package/dist/chunk-QXHSA4QD.js +43 -0
- package/dist/chunk-QXHSA4QD.js.map +1 -0
- package/dist/chunk-S632WN4W.js +106 -0
- package/dist/chunk-S632WN4W.js.map +1 -0
- package/dist/{chunk-OFFFRIJG.js → chunk-SDIK6VSC.js} +3 -3
- package/dist/{chunk-OFFFRIJG.js.map → chunk-SDIK6VSC.js.map} +1 -1
- package/dist/{chunk-M5VL22MY.js → chunk-SXMORGSG.js} +3 -3
- package/dist/{chunk-M5VL22MY.js.map → chunk-SXMORGSG.js.map} +1 -1
- package/dist/{chunk-Z6SS4G4V.js → chunk-UMK4D234.js} +3 -3
- package/dist/{chunk-Z6SS4G4V.js.map → chunk-UMK4D234.js.map} +1 -1
- package/dist/{chunk-5PYLJQJX.js → chunk-VS2HPJIX.js} +3 -3
- package/dist/{chunk-5PYLJQJX.js.map → chunk-VS2HPJIX.js.map} +1 -1
- package/dist/{chunk-NOUUOH4R.js → chunk-WDIFWMKE.js} +3 -3
- package/dist/chunk-WDIFWMKE.js.map +1 -0
- package/dist/chunk-Y7KC2FDU.js +88 -0
- package/dist/chunk-Y7KC2FDU.js.map +1 -0
- package/dist/{chunk-OFKSU77Y.js → chunk-ZEVQQQOA.js} +3 -3
- package/dist/{chunk-OFKSU77Y.js.map → chunk-ZEVQQQOA.js.map} +1 -1
- package/dist/combobox.css +3 -0
- package/dist/combobox.css.map +1 -1
- package/dist/combobox.js +2 -2
- package/dist/component-manifest.json +679 -8
- package/dist/date-picker.js +1 -1
- package/dist/dialog.js +1 -1
- package/dist/divider.css +37 -0
- package/dist/divider.css.map +1 -0
- package/dist/divider.d.ts +35 -0
- package/dist/divider.js +4 -0
- package/dist/divider.js.map +1 -0
- package/dist/empty-state.css +175 -0
- package/dist/empty-state.css.map +1 -0
- package/dist/empty-state.d.ts +40 -0
- package/dist/empty-state.js +7 -0
- package/dist/empty-state.js.map +1 -0
- package/dist/field.js +2 -2
- package/dist/icon-button.css +18 -0
- package/dist/icon-button.css.map +1 -1
- package/dist/icon-button.js +3 -3
- package/dist/index.css +489 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.js +38 -32
- package/dist/link.css +35 -0
- package/dist/link.css.map +1 -0
- package/dist/link.d.ts +37 -0
- package/dist/link.js +5 -0
- package/dist/link.js.map +1 -0
- package/dist/listbox.js +1 -1
- package/dist/menu.js +2 -2
- package/dist/pagination.css +18 -0
- package/dist/pagination.css.map +1 -1
- package/dist/pagination.js +4 -4
- package/dist/picker.css +3 -0
- package/dist/picker.css.map +1 -1
- package/dist/picker.js +2 -2
- package/dist/popover.js +2 -2
- package/dist/radio.js +3 -3
- package/dist/segmented-control.css +111 -0
- package/dist/segmented-control.css.map +1 -0
- package/dist/segmented-control.d.ts +90 -0
- package/dist/segmented-control.js +5 -0
- package/dist/segmented-control.js.map +1 -0
- package/dist/select.js +3 -3
- package/dist/sheet.css +28 -0
- package/dist/sheet.css.map +1 -1
- package/dist/sheet.d.ts +9 -2
- package/dist/sheet.js +1 -1
- package/dist/slider.js +1 -1
- package/dist/switch.js +4 -4
- package/dist/table.js +1 -1
- package/dist/tabs.js +1 -1
- package/dist/text-field.css +63 -0
- package/dist/text-field.css.map +1 -1
- package/dist/text-field.d.ts +15 -2
- package/dist/text-field.js +3 -3
- package/dist/textarea.js +3 -3
- package/dist/toast.css +18 -0
- package/dist/toast.css.map +1 -1
- package/dist/toast.d.ts +21 -3
- package/dist/toast.js +5 -5
- package/dist/tooltip.js +2 -2
- package/package.json +36 -6
- package/dist/chunk-5TTYVQ6Q.js.map +0 -1
- package/dist/chunk-737GQSOB.js +0 -19
- package/dist/chunk-737GQSOB.js.map +0 -1
- package/dist/chunk-BAPNIZDV.js.map +0 -1
- package/dist/chunk-IFIQLIA3.js +0 -48
- package/dist/chunk-IFIQLIA3.js.map +0 -1
- package/dist/chunk-NOUUOH4R.js.map +0 -1
- package/dist/chunk-TJJBCS3N.js +0 -28
- package/dist/chunk-TJJBCS3N.js.map +0 -1
- package/dist/chunk-U3N3G2UA.js.map +0 -1
package/dist/chip.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ButtonHTMLAttributes, Ref, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type ChipSize = 'sm' | 'md' | 'lg';
|
|
5
|
+
type ChipTone = 'neutral' | 'action';
|
|
6
|
+
interface ChipProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'value'> {
|
|
7
|
+
/** Controlled pressed state. Passing it (or `defaultSelected`, or `onSelectedChange`) makes the chip a toggle. */
|
|
8
|
+
selected?: boolean;
|
|
9
|
+
/** Uncontrolled initial pressed state. */
|
|
10
|
+
defaultSelected?: boolean;
|
|
11
|
+
/** Called with the next state when the chip is pressed. */
|
|
12
|
+
onSelectedChange?: (selected: boolean) => void;
|
|
13
|
+
/** Adds a remove button after the label: a second button beside the chip, never inside it. */
|
|
14
|
+
onRemove?: () => void;
|
|
15
|
+
/** The remove button is named "`removeLabel` + the chip's label" ("Remove Vegan"). @default 'Remove' */
|
|
16
|
+
removeLabel?: string;
|
|
17
|
+
/** `sm` is 24px high, the minimum target size. @default 'md' */
|
|
18
|
+
size?: ChipSize;
|
|
19
|
+
/** `action` takes the brand's colour; a selected chip is filled in either tone. @default 'neutral' */
|
|
20
|
+
tone?: ChipTone;
|
|
21
|
+
/** The `button` that carries the label, or the `span` when the chip neither toggles nor has an `onClick`. */
|
|
22
|
+
ref?: Ref<HTMLButtonElement>;
|
|
23
|
+
children: ReactNode;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A small pill for a choice or a value the user controls: a filter that
|
|
27
|
+
* toggles (`selected`), a tag that can be removed (`onRemove`), or both. The
|
|
28
|
+
* label is a button only when pressing it does something.
|
|
29
|
+
*
|
|
30
|
+
* @status experimental
|
|
31
|
+
* @category Actions
|
|
32
|
+
* @accessibility A toggle chip is a native `button` with `aria-pressed`, so Space and Enter work and the state is announced. The remove control is a second `button`, a sibling of the first (a button inside a button is invalid HTML and unreachable by keyboard), named by `removeLabel` plus the chip's own label through `aria-labelledby`: "Remove Vegan", not "Remove" six times. The pair is wrapped in a `role="group"` named by the label only when there are two controls. `disabled` disables both. After removing a chip, move focus yourself (to the next chip or the input): the button that had it is gone.
|
|
33
|
+
* @do Use a group of toggle chips for filters where several can be on at once.
|
|
34
|
+
* @do Keep the label to a word or two; a chip does not wrap.
|
|
35
|
+
* @dont Use a chip that does nothing as a label or a status: that is a Badge.
|
|
36
|
+
* @dont Use chips for one choice out of several; that is a SegmentedControl or a RadioGroup.
|
|
37
|
+
*/
|
|
38
|
+
declare function Chip({ selected, defaultSelected, onSelectedChange, onRemove, removeLabel, size, tone, disabled, className, onClick, ref, children, ...rest }: ChipProps): react.JSX.Element;
|
|
39
|
+
declare namespace Chip {
|
|
40
|
+
var displayName: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export { Chip, type ChipProps };
|
package/dist/chip.js
ADDED
package/dist/chip.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chip.js"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Field, useField } from './chunk-
|
|
1
|
+
import { Field, useField } from './chunk-SXMORGSG.js';
|
|
2
2
|
import { classes } from './chunk-MI4QUKQS.js';
|
|
3
3
|
import { createContext, useId, useState, useCallback, useContext } from 'react';
|
|
4
4
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
@@ -96,5 +96,5 @@ RadioGroup.displayName = "RadioGroup";
|
|
|
96
96
|
Radio.displayName = "Radio";
|
|
97
97
|
|
|
98
98
|
export { Radio, RadioGroup };
|
|
99
|
-
//# sourceMappingURL=chunk-
|
|
100
|
-
//# sourceMappingURL=chunk-
|
|
99
|
+
//# sourceMappingURL=chunk-2NVC3C7K.js.map
|
|
100
|
+
//# sourceMappingURL=chunk-2NVC3C7K.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/radio/Radio.module.css","../src/radio/Radio.tsx"],"names":["group","items","radio","label","input"],"mappings":"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","file":"chunk-N6E2E2OY.js","sourcesContent":["/* Every value is a token (--radio-*). The input draws itself; the dot is its ::after. */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .group {\n --_size: var(--radio-size-md);\n --_border: var(--radio-border);\n\n font-family: var(--font-family-body);\n\n &[data-size=\"sm\"] { --_size: var(--radio-size-sm); }\n &[data-size=\"lg\"] { --_size: var(--radio-size-lg); }\n &[data-invalid] { --_border: var(--radio-border-invalid); }\n }\n\n .items {\n display: flex;\n flex-direction: column;\n gap: var(--radio-group-gap);\n\n &[data-orientation=\"horizontal\"] {\n flex-flow: row wrap;\n gap: var(--radio-group-gap) var(--space-4);\n }\n }\n\n .radio {\n display: inline-flex;\n align-items: center;\n gap: var(--radio-gap);\n cursor: pointer;\n\n &[data-disabled] {\n cursor: not-allowed;\n }\n }\n\n .label {\n font-size: var(--field-label-font-size);\n color: var(--field-label-fg);\n }\n\n .input {\n display: grid;\n flex: none;\n place-content: center;\n inline-size: var(--_size);\n block-size: var(--_size);\n margin: 0;\n border: var(--size-hairline) solid var(--_border);\n border-radius: var(--radio-radius);\n background-color: var(--radio-bg);\n appearance: none;\n cursor: inherit;\n transition: border-color var(--radio-motion-duration) var(--motion-easing-standard);\n\n /* Sized from the box, not in percent: a grid item's percentage resolves against an auto area and collapses. */\n &::after {\n content: \"\";\n inline-size: calc(var(--_size) / 2);\n block-size: calc(var(--_size) / 2);\n border-radius: var(--radio-radius);\n background-color: var(--radio-dot);\n scale: 0;\n transition: scale var(--radio-motion-duration) var(--motion-easing-standard);\n }\n\n &:checked {\n border-color: var(--radio-border-checked);\n\n &::after {\n scale: 1;\n }\n }\n\n &:focus-visible {\n outline: var(--radio-focus-ring-width) solid var(--radio-focus-ring);\n outline-offset: var(--radio-focus-ring-offset);\n }\n\n &:disabled {\n opacity: 0.55;\n }\n\n &:hover:not(:disabled, :checked) {\n border-color: var(--radio-border-hover);\n }\n }\n}\n","import {\n createContext,\n useCallback,\n useContext,\n useId,\n useState,\n type HTMLAttributes,\n type InputHTMLAttributes,\n type ReactNode,\n type Ref,\n} from 'react';\nimport { Field, useField } from '../field';\nimport { classes } from '../internal/classes';\nimport styles from './Radio.module.css';\n\nexport type RadioSize = 'sm' | 'md' | 'lg';\nexport type RadioGroupOrientation = 'vertical' | 'horizontal';\n\ninterface RadioGroupContextValue {\n name: string;\n value: string | undefined;\n setValue: (value: string) => void;\n size: RadioSize;\n}\n\nconst RadioGroupContext = createContext<RadioGroupContextValue | null>(null);\n\nexport interface RadioGroupProps extends Omit<HTMLAttributes<HTMLDivElement>, 'defaultValue' | 'onChange'> {\n /** Visible group label. */\n label: ReactNode;\n description?: ReactNode;\n error?: ReactNode;\n /** Form field name shared by the radios. Generated when omitted. */\n name?: string;\n /** Controlled selected value. */\n value?: string;\n /** Initially selected value when uncontrolled. */\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n /** @default 'vertical' */\n orientation?: RadioGroupOrientation;\n /** @default 'md' */\n size?: RadioSize;\n disabled?: boolean;\n required?: boolean;\n ref?: Ref<HTMLDivElement>;\n children: ReactNode;\n}\n\n/**\n * A set of native radios under one label. The group is labelled by\n * reference (`aria-labelledby`) and described through Field, so description\n * and error apply to the whole set. Keyboard is the browser's own: arrows\n * move and select within the group. Controlled or uncontrolled by `value`.\n *\n * @status stable\n * @category Forms\n * @accessibility A `radiogroup` labelled by reference through Field and described by its description and error. Native radios: arrows move and select within the group, Tab leaves it.\n * @do Use it for two to five exclusive options that should all be visible.\n * @dont Preselect a consequential choice; leave the group empty and mark it required.\n */\nexport function RadioGroup({\n label,\n description,\n error,\n name,\n value,\n defaultValue,\n onValueChange,\n orientation = 'vertical',\n size = 'md',\n disabled = false,\n required = false,\n id,\n className,\n ref,\n children,\n ...rest\n}: RadioGroupProps) {\n const autoName = useId();\n const [uncontrolled, setUncontrolled] = useState(defaultValue);\n const controlled = value !== undefined;\n const current = controlled ? value : uncontrolled;\n const setValue = useCallback(\n (next: string) => {\n if (!controlled) setUncontrolled(next);\n onValueChange?.(next);\n },\n [controlled, onValueChange],\n );\n const invalid = error !== undefined && error !== null && error !== false && error !== '';\n\n return (\n <RadioGroupContext.Provider value={{ name: name ?? autoName, value: current, setValue, size }}>\n <Field id={id} invalid={invalid} disabled={disabled} required={required} className={classes(styles.group, className)} data-size={size}>\n <Field.Label as=\"span\">{label}</Field.Label>\n <RadioGroupItems {...rest} ref={ref} orientation={orientation}>\n {children}\n </RadioGroupItems>\n {description && <Field.Description>{description}</Field.Description>}\n {invalid && <Field.Error>{error}</Field.Error>}\n </Field>\n </RadioGroupContext.Provider>\n );\n}\n\ninterface RadioGroupItemsProps extends HTMLAttributes<HTMLDivElement> {\n orientation: RadioGroupOrientation;\n ref?: Ref<HTMLDivElement>;\n children: ReactNode;\n}\n\nfunction RadioGroupItems({ orientation, className, ref, children, ...rest }: RadioGroupItemsProps) {\n const field = useField();\n return (\n <div\n {...rest}\n ref={ref}\n id={field.id}\n role=\"radiogroup\"\n aria-labelledby={field.labelId}\n aria-describedby={field.describedBy}\n aria-invalid={field.invalid || undefined}\n aria-required={field.required || undefined}\n className={classes(styles.items, className)}\n data-orientation={orientation}\n >\n {children}\n </div>\n );\n}\n\nexport interface RadioProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'type' | 'value' | 'name' | 'checked' | 'defaultChecked' | 'onChange'> {\n /** The value this radio contributes to the group. */\n value: string;\n /** Visible label beside the radio. */\n label: ReactNode;\n /** The `<input>` element. */\n ref?: Ref<HTMLInputElement>;\n /** Applied to the wrapping label, not the input. */\n className?: string;\n}\n\n/** One option of a RadioGroup. Must be rendered inside `RadioGroup`. */\n/**\n * One option of a RadioGroup: a native radio with its own visible label.\n *\n * @status stable\n * @category Forms\n * @accessibility A native `input type=\"radio\"` labelled by its visible text; the group semantics, description and error come from RadioGroup.\n * @do Render it only inside RadioGroup.\n * @dont Disable a single radio without saying why in its label or the group description.\n */\nexport function Radio({ value, label, disabled, className, ref, ...rest }: RadioProps) {\n const group = useContext(RadioGroupContext);\n const field = useField();\n if (!group) throw new Error('Radio must be rendered inside <RadioGroup>');\n const checked = group.value === value;\n return (\n <label className={classes(styles.radio, className)} data-checked={checked ? '' : undefined} data-disabled={disabled || field.disabled ? '' : undefined}>\n <input\n {...rest}\n ref={ref}\n type=\"radio\"\n className={styles.input}\n name={group.name}\n value={value}\n checked={checked}\n onChange={() => group.setValue(value)}\n disabled={disabled || field.disabled}\n required={field.required}\n />\n <span className={styles.label}>{label}</span>\n </label>\n );\n}\n\nRadioGroup.displayName = 'RadioGroup';\nRadio.displayName = 'Radio';\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/radio/Radio.module.css","../src/radio/Radio.tsx"],"names":["group","items","radio","label","input"],"mappings":"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","file":"chunk-2NVC3C7K.js","sourcesContent":["/* Every value is a token (--radio-*). The input draws itself; the dot is its ::after. */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .group {\n --_size: var(--radio-size-md);\n --_border: var(--radio-border);\n\n font-family: var(--font-family-body);\n\n &[data-size=\"sm\"] { --_size: var(--radio-size-sm); }\n &[data-size=\"lg\"] { --_size: var(--radio-size-lg); }\n &[data-invalid] { --_border: var(--radio-border-invalid); }\n }\n\n .items {\n display: flex;\n flex-direction: column;\n gap: var(--radio-group-gap);\n\n &[data-orientation=\"horizontal\"] {\n flex-flow: row wrap;\n gap: var(--radio-group-gap) var(--space-4);\n }\n }\n\n .radio {\n display: inline-flex;\n align-items: center;\n gap: var(--radio-gap);\n cursor: pointer;\n\n &[data-disabled] {\n cursor: not-allowed;\n }\n }\n\n .label {\n font-size: var(--field-label-font-size);\n color: var(--field-label-fg);\n }\n\n .input {\n display: grid;\n flex: none;\n place-content: center;\n inline-size: var(--_size);\n block-size: var(--_size);\n margin: 0;\n border: var(--size-hairline) solid var(--_border);\n border-radius: var(--radio-radius);\n background-color: var(--radio-bg);\n appearance: none;\n cursor: inherit;\n transition: border-color var(--radio-motion-duration) var(--motion-easing-standard);\n\n /* Sized from the box, not in percent: a grid item's percentage resolves against an auto area and collapses. */\n &::after {\n content: \"\";\n inline-size: calc(var(--_size) / 2);\n block-size: calc(var(--_size) / 2);\n border-radius: var(--radio-radius);\n background-color: var(--radio-dot);\n scale: 0;\n transition: scale var(--radio-motion-duration) var(--motion-easing-standard);\n }\n\n &:checked {\n border-color: var(--radio-border-checked);\n\n &::after {\n scale: 1;\n }\n }\n\n &:focus-visible {\n outline: var(--radio-focus-ring-width) solid var(--radio-focus-ring);\n outline-offset: var(--radio-focus-ring-offset);\n }\n\n &:disabled {\n opacity: 0.55;\n }\n\n &:hover:not(:disabled, :checked) {\n border-color: var(--radio-border-hover);\n }\n }\n}\n","import {\n createContext,\n useCallback,\n useContext,\n useId,\n useState,\n type HTMLAttributes,\n type InputHTMLAttributes,\n type ReactNode,\n type Ref,\n} from 'react';\nimport { Field, useField } from '../field';\nimport { classes } from '../internal/classes';\nimport styles from './Radio.module.css';\n\nexport type RadioSize = 'sm' | 'md' | 'lg';\nexport type RadioGroupOrientation = 'vertical' | 'horizontal';\n\ninterface RadioGroupContextValue {\n name: string;\n value: string | undefined;\n setValue: (value: string) => void;\n size: RadioSize;\n}\n\nconst RadioGroupContext = createContext<RadioGroupContextValue | null>(null);\n\nexport interface RadioGroupProps extends Omit<HTMLAttributes<HTMLDivElement>, 'defaultValue' | 'onChange'> {\n /** Visible group label. */\n label: ReactNode;\n description?: ReactNode;\n error?: ReactNode;\n /** Form field name shared by the radios. Generated when omitted. */\n name?: string;\n /** Controlled selected value. */\n value?: string;\n /** Initially selected value when uncontrolled. */\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n /** @default 'vertical' */\n orientation?: RadioGroupOrientation;\n /** @default 'md' */\n size?: RadioSize;\n disabled?: boolean;\n required?: boolean;\n ref?: Ref<HTMLDivElement>;\n children: ReactNode;\n}\n\n/**\n * A set of native radios under one label. The group is labelled by\n * reference (`aria-labelledby`) and described through Field, so description\n * and error apply to the whole set. Keyboard is the browser's own: arrows\n * move and select within the group. Controlled or uncontrolled by `value`.\n *\n * @status stable\n * @category Forms\n * @accessibility A `radiogroup` labelled by reference through Field and described by its description and error. Native radios: arrows move and select within the group, Tab leaves it.\n * @do Use it for two to five exclusive options that should all be visible.\n * @dont Preselect a consequential choice; leave the group empty and mark it required.\n */\nexport function RadioGroup({\n label,\n description,\n error,\n name,\n value,\n defaultValue,\n onValueChange,\n orientation = 'vertical',\n size = 'md',\n disabled = false,\n required = false,\n id,\n className,\n ref,\n children,\n ...rest\n}: RadioGroupProps) {\n const autoName = useId();\n const [uncontrolled, setUncontrolled] = useState(defaultValue);\n const controlled = value !== undefined;\n const current = controlled ? value : uncontrolled;\n const setValue = useCallback(\n (next: string) => {\n if (!controlled) setUncontrolled(next);\n onValueChange?.(next);\n },\n [controlled, onValueChange],\n );\n const invalid = error !== undefined && error !== null && error !== false && error !== '';\n\n return (\n <RadioGroupContext.Provider value={{ name: name ?? autoName, value: current, setValue, size }}>\n <Field id={id} invalid={invalid} disabled={disabled} required={required} className={classes(styles.group, className)} data-size={size}>\n <Field.Label as=\"span\">{label}</Field.Label>\n <RadioGroupItems {...rest} ref={ref} orientation={orientation}>\n {children}\n </RadioGroupItems>\n {description && <Field.Description>{description}</Field.Description>}\n {invalid && <Field.Error>{error}</Field.Error>}\n </Field>\n </RadioGroupContext.Provider>\n );\n}\n\ninterface RadioGroupItemsProps extends HTMLAttributes<HTMLDivElement> {\n orientation: RadioGroupOrientation;\n ref?: Ref<HTMLDivElement>;\n children: ReactNode;\n}\n\nfunction RadioGroupItems({ orientation, className, ref, children, ...rest }: RadioGroupItemsProps) {\n const field = useField();\n return (\n <div\n {...rest}\n ref={ref}\n id={field.id}\n role=\"radiogroup\"\n aria-labelledby={field.labelId}\n aria-describedby={field.describedBy}\n aria-invalid={field.invalid || undefined}\n aria-required={field.required || undefined}\n className={classes(styles.items, className)}\n data-orientation={orientation}\n >\n {children}\n </div>\n );\n}\n\nexport interface RadioProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'type' | 'value' | 'name' | 'checked' | 'defaultChecked' | 'onChange'> {\n /** The value this radio contributes to the group. */\n value: string;\n /** Visible label beside the radio. */\n label: ReactNode;\n /** The `<input>` element. */\n ref?: Ref<HTMLInputElement>;\n /** Applied to the wrapping label, not the input. */\n className?: string;\n}\n\n/** One option of a RadioGroup. Must be rendered inside `RadioGroup`. */\n/**\n * One option of a RadioGroup: a native radio with its own visible label.\n *\n * @status stable\n * @category Forms\n * @accessibility A native `input type=\"radio\"` labelled by its visible text; the group semantics, description and error come from RadioGroup.\n * @do Render it only inside RadioGroup.\n * @dont Disable a single radio without saying why in its label or the group description.\n */\nexport function Radio({ value, label, disabled, className, ref, ...rest }: RadioProps) {\n const group = useContext(RadioGroupContext);\n const field = useField();\n if (!group) throw new Error('Radio must be rendered inside <RadioGroup>');\n const checked = group.value === value;\n return (\n <label className={classes(styles.radio, className)} data-checked={checked ? '' : undefined} data-disabled={disabled || field.disabled ? '' : undefined}>\n <input\n {...rest}\n ref={ref}\n type=\"radio\"\n className={styles.input}\n name={group.name}\n value={value}\n checked={checked}\n onChange={() => group.setValue(value)}\n disabled={disabled || field.disabled}\n required={field.required}\n />\n <span className={styles.label}>{label}</span>\n </label>\n );\n}\n\nRadioGroup.displayName = 'RadioGroup';\nRadio.displayName = 'Radio';\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Button } from './chunk-
|
|
1
|
+
import { Button } from './chunk-DE67ECD7.js';
|
|
2
2
|
import { Icon } from './chunk-O5LII5XP.js';
|
|
3
3
|
import { classes } from './chunk-MI4QUKQS.js';
|
|
4
4
|
import { isValidElement, cloneElement } from 'react';
|
|
@@ -34,5 +34,5 @@ function IconButton({
|
|
|
34
34
|
IconButton.displayName = "IconButton";
|
|
35
35
|
|
|
36
36
|
export { IconButton };
|
|
37
|
-
//# sourceMappingURL=chunk-
|
|
38
|
-
//# sourceMappingURL=chunk-
|
|
37
|
+
//# sourceMappingURL=chunk-56RSH7GQ.js.map
|
|
38
|
+
//# sourceMappingURL=chunk-56RSH7GQ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/icon-button/IconButton.module.css","../src/icon-button/IconButton.tsx"],"names":["iconButton"],"mappings":";;;;;;;AAAA,IAAA,kBAAA,GAAA;AAAA,EAKG,UAAA,EAAAA;AAAA,CAAA;ACsBI,SAAS,UAAA,CAAsD;AAAA,EACpE,KAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA,GAAU,KAAA;AAAA,EACV,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAuB;AACrB,EAAA,MAAM,KAAA,mBAAQ,GAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAK,WAAW,QAAA,EAAA,IAAA,EAAK,CAAA;AACzC,EAAA,uBACE,GAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACE,GAAG,IAAA;AAAA,MACJ,OAAA;AAAA,MACA,YAAA,EAAY,KAAA;AAAA,MACZ,OAAO,KAAA,IAAS,KAAA;AAAA,MAChB,gBAAA,EAAe,EAAA;AAAA,MACf,SAAA,EAAW,OAAA,CAAQ,kBAAA,CAAO,UAAA,EAAY,SAAS,CAAA;AAAA,MAE9C,QAAA,EAAA,OAAA,IAAW,eAAe,QAAQ,CAAA,GAAI,aAAa,QAAA,EAAU,MAAA,EAAW,KAAK,CAAA,GAAI;AAAA;AAAA,GACpF;AAEJ;AAEA,UAAA,CAAW,WAAA,GAAc,YAAA","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/icon-button/IconButton.module.css","../src/icon-button/IconButton.tsx"],"names":["iconButton"],"mappings":";;;;;;;AAAA,IAAA,kBAAA,GAAA;AAAA,EAKG,UAAA,EAAAA;AAAA,CAAA;ACsBI,SAAS,UAAA,CAAsD;AAAA,EACpE,KAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA,GAAU,KAAA;AAAA,EACV,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAuB;AACrB,EAAA,MAAM,KAAA,mBAAQ,GAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAK,WAAW,QAAA,EAAA,IAAA,EAAK,CAAA;AACzC,EAAA,uBACE,GAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACE,GAAG,IAAA;AAAA,MACJ,OAAA;AAAA,MACA,YAAA,EAAY,KAAA;AAAA,MACZ,OAAO,KAAA,IAAS,KAAA;AAAA,MAChB,gBAAA,EAAe,EAAA;AAAA,MACf,SAAA,EAAW,OAAA,CAAQ,kBAAA,CAAO,UAAA,EAAY,SAAS,CAAA;AAAA,MAE9C,QAAA,EAAA,OAAA,IAAW,eAAe,QAAQ,CAAA,GAAI,aAAa,QAAA,EAAU,MAAA,EAAW,KAAK,CAAA,GAAI;AAAA;AAAA,GACpF;AAEJ;AAEA,UAAA,CAAW,WAAA,GAAc,YAAA","file":"chunk-56RSH7GQ.js","sourcesContent":["/* Squares a Button. Selectors carry the data attribute so they outrank Button's own size rules. */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .iconButton[data-icon-only] {\n gap: 0;\n inline-size: var(--icon-button-size-md);\n padding-inline: 0;\n\n &[data-size=\"sm\"] { inline-size: var(--icon-button-size-sm); }\n &[data-size=\"lg\"] { inline-size: var(--icon-button-size-lg); }\n }\n}\n","import { cloneElement, isValidElement, type ReactElement, type ReactNode } from 'react';\nimport { Button, type ButtonProps } from '../button';\nimport { Icon } from '../icon';\nimport { classes } from '../internal/classes';\nimport styles from './IconButton.module.css';\n\nexport interface IconButtonProps<E extends HTMLElement = HTMLButtonElement>\n extends Omit<ButtonProps<E>, 'children' | 'iconStart' | 'iconEnd'> {\n /** The accessible name. Required: an icon alone is not a name. Also used as the tooltip unless `title` is given. */\n label: string;\n /** The glyph, for instance from `@pearpages/pulp-icons`. */\n icon: ReactNode;\n /** With `asChild`: the element to render (a link, for instance). Its own children are replaced by the icon. */\n children?: ReactElement;\n}\n\n/**\n * A square Button that shows only an icon and therefore *requires* a name.\n * Everything else (variants, sizes, loading, asChild) is Button's; the\n * `--icon-button-size-*` tokens make it square.\n *\n * @status stable\n * @category Actions\n * @accessibility A Button with `aria-label` from the required `label`; `title` shows it as a tooltip. Everything else is Button's.\n * @do Write the label as the action (\"Close\", \"Add item\").\n * @dont Use the icon's name as the label.\n */\nexport function IconButton<E extends HTMLElement = HTMLButtonElement>({\n label,\n icon,\n title,\n className,\n asChild = false,\n children,\n ...rest\n}: IconButtonProps<E>) {\n const glyph = <Icon size=\"inherit\">{icon}</Icon>;\n return (\n <Button\n {...rest}\n asChild={asChild}\n aria-label={label}\n title={title ?? label}\n data-icon-only=\"\"\n className={classes(styles.iconButton, className)}\n >\n {asChild && isValidElement(children) ? cloneElement(children, undefined, glyph) : glyph}\n </Button>\n );\n}\n\nIconButton.displayName = 'IconButton';\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Stack } from './chunk-2E2ESMS2.js';
|
|
2
|
+
import { Heading } from './chunk-F3S5BHX2.js';
|
|
3
|
+
import { Text } from './chunk-LKWZZIRZ.js';
|
|
4
|
+
import { classes } from './chunk-MI4QUKQS.js';
|
|
5
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
// src/empty-state/EmptyState.module.css
|
|
8
|
+
var EmptyState_default = {
|
|
9
|
+
root: "EmptyState_root",
|
|
10
|
+
text: "EmptyState_text",
|
|
11
|
+
icon: "EmptyState_icon"
|
|
12
|
+
};
|
|
13
|
+
function EmptyState({ title, description, icon, action, tone = "neutral", headingLevel = 3, className, ref, ...rest }) {
|
|
14
|
+
return /* @__PURE__ */ jsx("div", { ...rest, ref, className: classes(EmptyState_default.root, className), "data-tone": tone, children: /* @__PURE__ */ jsxs(Stack, { gap: 4, align: "center", children: [
|
|
15
|
+
icon != null && /* @__PURE__ */ jsx("span", { className: EmptyState_default.icon, "aria-hidden": "true", children: icon }),
|
|
16
|
+
/* @__PURE__ */ jsxs(Stack, { gap: 1, align: "center", children: [
|
|
17
|
+
/* @__PURE__ */ jsx(Heading, { level: headingLevel, size: "md", className: EmptyState_default.text, children: title }),
|
|
18
|
+
description != null && /* @__PURE__ */ jsx(Text, { tone: "muted", align: "center", className: EmptyState_default.text, children: description })
|
|
19
|
+
] }),
|
|
20
|
+
action
|
|
21
|
+
] }) });
|
|
22
|
+
}
|
|
23
|
+
EmptyState.displayName = "EmptyState";
|
|
24
|
+
|
|
25
|
+
export { EmptyState };
|
|
26
|
+
//# sourceMappingURL=chunk-5TYCIBLW.js.map
|
|
27
|
+
//# sourceMappingURL=chunk-5TYCIBLW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/empty-state/EmptyState.module.css","../src/empty-state/EmptyState.tsx"],"names":["root","text","icon"],"mappings":";;;;;;;AAAA,IAAA,kBAAA,GAAA;AAAA,EAKG,IAAA,EAAAA,iBAAAA;AAAA,EAKA,IAAA,EAAAC,iBAAAA;AAAA,EAKA,IAAA,EAAAC;AAAA,CAAA;ACwBI,SAAS,UAAA,CAAW,EAAE,KAAA,EAAO,WAAA,EAAa,MAAM,MAAA,EAAQ,IAAA,GAAO,SAAA,EAAW,YAAA,GAAe,CAAA,EAAG,SAAA,EAAW,GAAA,EAAK,GAAG,MAAK,EAAoB;AAC7I,EAAA,2BACG,KAAA,EAAA,EAAK,GAAG,MAAM,GAAA,EAAU,SAAA,EAAW,QAAQ,kBAAA,CAAO,IAAA,EAAM,SAAS,CAAA,EAAG,aAAW,IAAA,EAC9E,QAAA,kBAAA,IAAA,CAAC,SAAM,GAAA,EAAK,CAAA,EAAG,OAAM,QAAA,EAClB,QAAA,EAAA;AAAA,IAAA,IAAA,IAAQ,IAAA,wBACN,MAAA,EAAA,EAAK,SAAA,EAAW,mBAAO,IAAA,EAAM,aAAA,EAAY,QACvC,QAAA,EAAA,IAAA,EACH,CAAA;AAAA,oBAEF,IAAA,CAAC,KAAA,EAAA,EAAM,GAAA,EAAK,CAAA,EAAG,OAAM,QAAA,EACnB,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,OAAA,EAAA,EAAQ,OAAO,YAAA,EAAc,IAAA,EAAK,MAAK,SAAA,EAAW,kBAAA,CAAO,MACvD,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,MACC,WAAA,IAAe,IAAA,oBACd,GAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAK,OAAA,EAAQ,KAAA,EAAM,QAAA,EAAS,SAAA,EAAW,kBAAA,CAAO,IAAA,EACjD,QAAA,EAAA,WAAA,EACH;AAAA,KAAA,EAEJ,CAAA;AAAA,IACC;AAAA,GAAA,EACH,CAAA,EACF,CAAA;AAEJ;AAEA,UAAA,CAAW,WAAA,GAAc,YAAA","file":"chunk-5TYCIBLW.js","sourcesContent":["/* Every value is a token: --empty-state-* in packages/tokens/tokens/component/empty-state.json */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .root {\n box-sizing: border-box;\n padding: var(--empty-state-padding);\n }\n\n .text {\n text-align: center;\n text-wrap: balance;\n }\n\n .icon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n inline-size: var(--empty-state-icon-size);\n block-size: var(--empty-state-icon-size);\n border-radius: var(--empty-state-icon-radius);\n background: var(--empty-state-icon-neutral-bg);\n color: var(--empty-state-icon-neutral-fg);\n font-size: var(--empty-state-icon-glyph-size);\n\n .root[data-tone='error'] & {\n background: var(--empty-state-icon-error-bg);\n color: var(--empty-state-icon-error-fg);\n }\n }\n}\n","import type { HTMLAttributes, ReactNode, Ref } from 'react';\nimport { Heading, type HeadingLevel } from '../heading';\nimport { classes } from '../internal/classes';\nimport { Stack } from '../stack';\nimport { Text } from '../text';\nimport styles from './EmptyState.module.css';\n\nexport type EmptyStateTone = 'neutral' | 'error';\n\nexport interface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** What is missing, or what went wrong, in a few words. Rendered as a heading. */\n title: ReactNode;\n /** One or two sentences: why it is empty and what to do about it. */\n description?: ReactNode;\n /** A glyph, shown in a tinted disc. Decorative: the title carries the meaning. */\n icon?: ReactNode;\n /** One control: a Button, or a Link. For an error, the retry. */\n action?: ReactNode;\n /** `error` tints the icon with the error colours. It does not announce anything: see the accessibility notes. @default 'neutral' */\n tone?: EmptyStateTone;\n /** The heading's outline level, from where the empty state sits in the page. @default 3 */\n headingLevel?: HeadingLevel;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * What a list, a search or a page shows instead of its content: nothing yet,\n * nothing found, or it failed to load. An icon, a title, a sentence and one\n * action, centred. Composes Heading, Text and Stack, so the type follows the\n * brand without tokens of its own.\n *\n * @status experimental\n * @category Feedback\n * @accessibility The title is a real heading at `headingLevel`, so the empty region shows up in the outline; pick the level from the page, as with Heading. The icon is `aria-hidden`. Nothing is announced on its own: an empty state that is there when the page loads is just content. When it **replaces** content after the user did something (a search with no results, a failed reload), pass `role=\"status\"` (or `role=\"alert\"` for an error that needs attention) so it is read out; do not put `role=\"alert\"` on one that renders with the page. The action is whatever you pass, with its own semantics.\n * @do Say what to do next in the description, and make the action that next step.\n * @do Use `tone=\"error\"` with a retry action when loading failed.\n * @dont Use it for a validation error or a transient message; that is a Field error, an Alert or a Toast.\n * @dont Offer several actions; an empty state has one way forward.\n */\nexport function EmptyState({ title, description, icon, action, tone = 'neutral', headingLevel = 3, className, ref, ...rest }: EmptyStateProps) {\n return (\n <div {...rest} ref={ref} className={classes(styles.root, className)} data-tone={tone}>\n <Stack gap={4} align=\"center\">\n {icon != null && (\n <span className={styles.icon} aria-hidden=\"true\">\n {icon}\n </span>\n )}\n <Stack gap={1} align=\"center\">\n <Heading level={headingLevel} size=\"md\" className={styles.text}>\n {title}\n </Heading>\n {description != null && (\n <Text tone=\"muted\" align=\"center\" className={styles.text}>\n {description}\n </Text>\n )}\n </Stack>\n {action}\n </Stack>\n </div>\n );\n}\n\nEmptyState.displayName = 'EmptyState';\n"]}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Dialog } from './chunk-55QUKGK2.js';
|
|
2
|
+
import { classes } from './chunk-MI4QUKQS.js';
|
|
3
|
+
import { useRef } from 'react';
|
|
4
|
+
import { useModalId, useModalStack } from '@pearpages/modals';
|
|
5
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
// src/sheet/drag.ts
|
|
8
|
+
var DISMISS_DISTANCE_RATIO = 0.25;
|
|
9
|
+
var DISMISS_DISTANCE_FALLBACK_PX = 120;
|
|
10
|
+
var DISMISS_VELOCITY_PX_PER_S = 500;
|
|
11
|
+
function shouldDismiss({
|
|
12
|
+
offsetY,
|
|
13
|
+
velocityY,
|
|
14
|
+
panelHeight,
|
|
15
|
+
distanceRatio = DISMISS_DISTANCE_RATIO,
|
|
16
|
+
distanceFallbackPx = DISMISS_DISTANCE_FALLBACK_PX,
|
|
17
|
+
velocityThreshold = DISMISS_VELOCITY_PX_PER_S
|
|
18
|
+
}) {
|
|
19
|
+
if (offsetY <= 0) return false;
|
|
20
|
+
const distanceThreshold = panelHeight > 0 ? panelHeight * distanceRatio : distanceFallbackPx;
|
|
21
|
+
return offsetY > distanceThreshold || velocityY > velocityThreshold;
|
|
22
|
+
}
|
|
23
|
+
function releaseVelocity(samples, windowMs = 100) {
|
|
24
|
+
const last = samples[samples.length - 1];
|
|
25
|
+
if (!last) return 0;
|
|
26
|
+
const first = samples.find((sample) => last.time - sample.time <= windowMs) ?? last;
|
|
27
|
+
const elapsed = last.time - first.time;
|
|
28
|
+
return elapsed > 0 ? (last.y - first.y) / elapsed * 1e3 : 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/sheet/Sheet.module.css
|
|
32
|
+
var Sheet_default = {
|
|
33
|
+
content: "Sheet_content",
|
|
34
|
+
handle: "Sheet_handle"
|
|
35
|
+
};
|
|
36
|
+
function Sheet(props) {
|
|
37
|
+
return /* @__PURE__ */ jsx(Dialog, { ...props });
|
|
38
|
+
}
|
|
39
|
+
function SheetContent({ placement = "end", dragToDismiss = true, className, children, ...rest }) {
|
|
40
|
+
const draggable = placement === "bottom" && dragToDismiss;
|
|
41
|
+
return /* @__PURE__ */ jsxs(Dialog.Content, { ...rest, placement, className: classes(Sheet_default.content, className), "data-draggable": draggable ? "" : void 0, children: [
|
|
42
|
+
draggable && /* @__PURE__ */ jsx(SheetHandle, {}),
|
|
43
|
+
children
|
|
44
|
+
] });
|
|
45
|
+
}
|
|
46
|
+
function SheetHandle() {
|
|
47
|
+
const id = useModalId();
|
|
48
|
+
const { close } = useModalStack();
|
|
49
|
+
const drag = useRef(null);
|
|
50
|
+
const onPointerDown = (event) => {
|
|
51
|
+
const panel = event.currentTarget.closest('[role="dialog"]');
|
|
52
|
+
if (!panel || event.button !== 0) return;
|
|
53
|
+
if (typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
54
|
+
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
55
|
+
drag.current = { startY: event.clientY, panel, samples: [{ time: performance.now(), y: event.clientY }] };
|
|
56
|
+
panel.dataset.dragging = "";
|
|
57
|
+
};
|
|
58
|
+
const onPointerMove = (event) => {
|
|
59
|
+
if (!drag.current) return;
|
|
60
|
+
drag.current.samples.push({ time: performance.now(), y: event.clientY });
|
|
61
|
+
drag.current.panel.style.setProperty("--_drag", `${Math.max(0, event.clientY - drag.current.startY)}px`);
|
|
62
|
+
};
|
|
63
|
+
const end = (event, cancelled) => {
|
|
64
|
+
const current = drag.current;
|
|
65
|
+
if (!current) return;
|
|
66
|
+
drag.current = null;
|
|
67
|
+
current.samples.push({ time: performance.now(), y: event.clientY });
|
|
68
|
+
delete current.panel.dataset.dragging;
|
|
69
|
+
const dismiss = !cancelled && shouldDismiss({ offsetY: event.clientY - current.startY, velocityY: releaseVelocity(current.samples), panelHeight: current.panel.offsetHeight });
|
|
70
|
+
if (dismiss) {
|
|
71
|
+
close(id);
|
|
72
|
+
} else {
|
|
73
|
+
current.panel.style.removeProperty("--_drag");
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
return /* @__PURE__ */ jsx(
|
|
77
|
+
"div",
|
|
78
|
+
{
|
|
79
|
+
className: Sheet_default.handle,
|
|
80
|
+
"aria-hidden": "true",
|
|
81
|
+
onPointerDown,
|
|
82
|
+
onPointerMove,
|
|
83
|
+
onPointerUp: (event) => end(event, false),
|
|
84
|
+
onPointerCancel: (event) => end(event, true)
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
Sheet.displayName = "Sheet";
|
|
89
|
+
SheetContent.displayName = "Sheet.Content";
|
|
90
|
+
Sheet.Trigger = Dialog.Trigger;
|
|
91
|
+
Sheet.Content = SheetContent;
|
|
92
|
+
Sheet.Header = Dialog.Header;
|
|
93
|
+
Sheet.Title = Dialog.Title;
|
|
94
|
+
Sheet.Description = Dialog.Description;
|
|
95
|
+
Sheet.Close = Dialog.Close;
|
|
96
|
+
Sheet.Body = Dialog.Body;
|
|
97
|
+
Sheet.Footer = Dialog.Footer;
|
|
98
|
+
|
|
99
|
+
export { Sheet };
|
|
100
|
+
//# sourceMappingURL=chunk-7O6FTCZL.js.map
|
|
101
|
+
//# sourceMappingURL=chunk-7O6FTCZL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sheet/drag.ts","../src/sheet/Sheet.module.css","../src/sheet/Sheet.tsx"],"names":["content","handle"],"mappings":"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","file":"chunk-7O6FTCZL.js","sourcesContent":["/**\n * When a dragged bottom sheet should close on release. Ported from bitepals'\n * `shouldDismiss()` with its thresholds and its test cases: past a quarter of\n * the sheet's height, or a flick faster than 500 px/s, downwards only.\n */\nconst DISMISS_DISTANCE_RATIO = 0.25;\nconst DISMISS_DISTANCE_FALLBACK_PX = 120;\nconst DISMISS_VELOCITY_PX_PER_S = 500;\n\nexport interface DismissInput {\n /** How far the sheet has been dragged down, in px. Zero or negative never dismisses. */\n offsetY: number;\n /** Downward speed at release, in px/s. */\n velocityY: number;\n /** The sheet's height in px; 0 when it cannot be measured, which falls back to a fixed distance. */\n panelHeight: number;\n distanceRatio?: number;\n distanceFallbackPx?: number;\n velocityThreshold?: number;\n}\n\nexport function shouldDismiss({\n offsetY,\n velocityY,\n panelHeight,\n distanceRatio = DISMISS_DISTANCE_RATIO,\n distanceFallbackPx = DISMISS_DISTANCE_FALLBACK_PX,\n velocityThreshold = DISMISS_VELOCITY_PX_PER_S,\n}: DismissInput): boolean {\n if (offsetY <= 0) return false;\n const distanceThreshold = panelHeight > 0 ? panelHeight * distanceRatio : distanceFallbackPx;\n return offsetY > distanceThreshold || velocityY > velocityThreshold;\n}\n\n/** Speed over the last ~100 ms of samples, in px/s: the release flick, not the average of the whole drag. */\nexport function releaseVelocity(samples: ReadonlyArray<{ time: number; y: number }>, windowMs = 100): number {\n const last = samples[samples.length - 1];\n if (!last) return 0;\n const first = samples.find((sample) => last.time - sample.time <= windowMs) ?? last;\n const elapsed = last.time - first.time;\n return elapsed > 0 ? ((last.y - first.y) / elapsed) * 1000 : 0;\n}\n","/*\n * The vendor (@pearpages/modals) docks the dialog and sizes it from three variables it declares on\n * :root. This class sits on the dialog element itself, so its own declarations beat the inherited\n * :root defaults whatever the cascade layer or import order: no specificity fight with the\n * vendor's unlayered rules, which only *read* these. Colour, type and motion timing come from\n * Dialog's mapping on the portal root.\n */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .content {\n --modal-width-sheet: var(--sheet-width);\n --modal-height-sheet: var(--sheet-height);\n --modal-animation-translate-sheet: var(--sheet-motion-translate);\n }\n\n /*\n * Drag to dismiss (bottom sheets). The vendor moves the sheet with `transform`; the drag uses\n * the separate `translate` property, so the two never fight. --_drag is set by the handle while\n * the pointer is down: the one per-instance value, like Progress's --_value.\n */\n .content[data-draggable] {\n translate: 0 var(--_drag, 0);\n transition: translate var(--sheet-handle-snap-duration) var(--motion-easing-standard);\n\n &[data-dragging] {\n transition: none;\n }\n }\n\n .handle {\n display: grid;\n flex: none;\n place-items: center;\n block-size: var(--sheet-handle-hit-height);\n cursor: grab;\n touch-action: none;\n\n &::before {\n inline-size: var(--sheet-handle-width);\n block-size: var(--sheet-handle-height);\n border-radius: var(--sheet-handle-radius);\n background: var(--sheet-handle-bg);\n content: \"\";\n }\n\n [data-dragging] > & {\n cursor: grabbing;\n }\n\n /* Following the finger is motion: without it there is no handle to offer. */\n @media (prefers-reduced-motion: reduce) {\n display: none;\n }\n }\n}\n","import { useRef, type ComponentProps, type PointerEvent } from 'react';\nimport { useModalId, useModalStack } from '@pearpages/modals';\nimport { Dialog, type DialogProps } from '../dialog';\nimport { classes } from '../internal/classes';\nimport { releaseVelocity, shouldDismiss } from './drag';\nimport styles from './Sheet.module.css';\n\nexport type SheetProps = DialogProps;\n\n/** The edge a sheet docks to. `start` and `end` follow the writing direction. */\nexport type SheetPlacement = 'start' | 'end' | 'top' | 'bottom';\n\nexport interface SheetContentProps extends Omit<ComponentProps<typeof Dialog.Content>, 'placement'> {\n /**\n * The edge the sheet docks to. `start` and `end` take `--sheet-width` and the full height;\n * `top` and `bottom` take the full width and `--sheet-height`. There is no `center`: a centred\n * sheet is a Dialog.\n * @default 'end'\n */\n placement?: SheetPlacement;\n /**\n * `placement=\"bottom\"` only: a grab handle at the top of the sheet that can be dragged down to\n * close it (past a quarter of the sheet's height, or with a flick). Pointer and touch only, and\n * off under `prefers-reduced-motion`; Escape, the backdrop and `Sheet.Close` are unchanged.\n * @default true\n */\n dragToDismiss?: boolean;\n}\n\n/**\n * A dialog docked to an edge of the viewport: a side panel for detail or settings that keeps the\n * page in view, or a bottom sheet on a phone. It is Dialog with a `placement`: the same parts\n * (`Sheet.Trigger`, `Sheet.Content`, `Sheet.Header`, `Sheet.Title`, `Sheet.Description`,\n * `Sheet.Close`, `Sheet.Body`, `Sheet.Footer`), the same focus trap, stacking and dismissal, and\n * the same colours and type, from Dialog's tokens. Only the size is Sheet's: `--sheet-width`,\n * `--sheet-height` and `--sheet-motion-translate`, the distance it slides in from its edge.\n *\n * It needs what Dialog needs: `DialogSystem` mounted once near the app root, and\n * `@pearpages/modals/styles.css` imported into the `vendor` layer.\n *\n * @status experimental\n * @category Overlays\n * @accessibility The drag handle of a bottom sheet is a pointer and touch shortcut, hidden from assistive technology and not focusable: it adds no keyboard stop, and closing by keyboard stays Escape or `Sheet.Close`, so always render a `Sheet.Close` in a sheet that can be dragged. Otherwise Dialog's: `role=\"dialog\"` with `aria-modal`, named by `Sheet.Title` and described by `Sheet.Description`; focus moves in on open, is trapped, and returns to the trigger on close; Escape and the backdrop dismiss it; the page behind is inert. Docking changes the layout only, never the semantics.\n * @do Always render a `Sheet.Title`.\n * @do Dock to `end` for detail and settings beside the page, and to `bottom` for choices on a narrow screen.\n * @dont Use it for a short confirmation; a centred Dialog reads as more urgent and takes less room.\n * @dont Put the page's primary content in a sheet: it is modal, so everything behind it is out of reach.\n */\nexport function Sheet(props: SheetProps) {\n return <Dialog {...props} />;\n}\n\n/**\n * The docked dialog element. Dialog's `Content`, with `placement` and the class that maps pulp's\n * `--sheet-*` tokens onto the vendor's sheet variables.\n */\nfunction SheetContent({ placement = 'end', dragToDismiss = true, className, children, ...rest }: SheetContentProps) {\n const draggable = placement === 'bottom' && dragToDismiss;\n return (\n <Dialog.Content {...rest} placement={placement} className={classes(styles.content, className)} data-draggable={draggable ? '' : undefined}>\n {draggable && <SheetHandle />}\n {children}\n </Dialog.Content>\n );\n}\n\n/** The grab handle. Internal: rendered by `Sheet.Content`, never on its own. */\nfunction SheetHandle() {\n const id = useModalId();\n const { close } = useModalStack();\n const drag = useRef<{ startY: number; panel: HTMLElement; samples: Array<{ time: number; y: number }> } | null>(null);\n\n const onPointerDown = (event: PointerEvent<HTMLDivElement>) => {\n const panel = event.currentTarget.closest<HTMLElement>('[role=\"dialog\"]');\n if (!panel || event.button !== 0) return;\n // The sheet following the finger is motion; without it the handle is not offered at all (see the stylesheet).\n if (typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;\n event.currentTarget.setPointerCapture?.(event.pointerId);\n drag.current = { startY: event.clientY, panel, samples: [{ time: performance.now(), y: event.clientY }] };\n panel.dataset.dragging = '';\n };\n\n const onPointerMove = (event: PointerEvent<HTMLDivElement>) => {\n if (!drag.current) return;\n drag.current.samples.push({ time: performance.now(), y: event.clientY });\n // The one per-instance value: how far this sheet has been pulled. A custom property, read by the stylesheet.\n drag.current.panel.style.setProperty('--_drag', `${Math.max(0, event.clientY - drag.current.startY)}px`);\n };\n\n const end = (event: PointerEvent<HTMLDivElement>, cancelled: boolean) => {\n const current = drag.current;\n if (!current) return;\n drag.current = null;\n current.samples.push({ time: performance.now(), y: event.clientY });\n delete current.panel.dataset.dragging;\n const dismiss =\n !cancelled &&\n shouldDismiss({ offsetY: event.clientY - current.startY, velocityY: releaseVelocity(current.samples), panelHeight: current.panel.offsetHeight });\n if (dismiss) {\n // The offset stays, so the sheet leaves from where it was let go instead of snapping back first.\n close(id);\n } else {\n current.panel.style.removeProperty('--_drag');\n }\n };\n\n return (\n <div\n className={styles.handle}\n aria-hidden=\"true\"\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={(event) => end(event, false)}\n onPointerCancel={(event) => end(event, true)}\n />\n );\n}\n\nSheet.displayName = 'Sheet';\nSheetContent.displayName = 'Sheet.Content';\nSheet.Trigger = Dialog.Trigger;\nSheet.Content = SheetContent;\nSheet.Header = Dialog.Header;\nSheet.Title = Dialog.Title;\nSheet.Description = Dialog.Description;\nSheet.Close = Dialog.Close;\nSheet.Body = Dialog.Body;\nSheet.Footer = Dialog.Footer;\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IconButton } from './chunk-
|
|
1
|
+
import { IconButton } from './chunk-56RSH7GQ.js';
|
|
2
2
|
import { Icon } from './chunk-O5LII5XP.js';
|
|
3
3
|
import { classes } from './chunk-MI4QUKQS.js';
|
|
4
4
|
import { Close, Warning, Check, Info } from '@pearpages/pulp-icons';
|
|
@@ -49,5 +49,5 @@ function Alert({
|
|
|
49
49
|
Alert.displayName = "Alert";
|
|
50
50
|
|
|
51
51
|
export { Alert };
|
|
52
|
-
//# sourceMappingURL=chunk-
|
|
53
|
-
//# sourceMappingURL=chunk-
|
|
52
|
+
//# sourceMappingURL=chunk-A7TMFEQ2.js.map
|
|
53
|
+
//# sourceMappingURL=chunk-A7TMFEQ2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/alert/Alert.module.css","../src/alert/Alert.tsx"],"names":["alert","icon","body","title","content","action","dismiss"],"mappings":";;;;;;;AAAA,IAAA,aAAA,GAAA;AAAA,EAKG,KAAA,EAAAA,aAAAA;AAAA,EAyCA,IAAA,EAAAC,YAAAA;AAAA,EAKA,IAAA,EAAAC,YAAAA;AAAA,EAQA,KAAA,EAAAC,aAAAA;AAAA,EAMA,OAAA,EAAAC,eAAAA;AAAA,EAIA,MAAA,EAAAC,cAAAA;AAAA,EAOA,OAAA,EAAAC;AAAA,CAAA;AC3CH,IAAM,YAAA,GAA6C;AAAA,EACjD,IAAA,sBAAO,IAAA,EAAA,EAAK,CAAA;AAAA,EACZ,OAAA,sBAAU,KAAA,EAAA,EAAM,CAAA;AAAA,EAChB,OAAA,sBAAU,OAAA,EAAA,EAAQ,CAAA;AAAA,EAClB,KAAA,sBAAQ,OAAA,EAAA,EAAQ;AAClB,CAAA;AAeO,SAAS,KAAA,CAAM;AAAA,EACpB,IAAA,GAAO,MAAA;AAAA,EACP,KAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA,GAAe,SAAA;AAAA,EACf,IAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAe;AACb,EAAA,MAAM,IAAA,GAAO,IAAA,KAAS,IAAA,KAAS,OAAA,GAAU,WAAA,GAAc,QAAA,CAAA;AACvD,EAAA,MAAM,OAAO,IAAA,KAAS,KAAA,GAAQ,MAAA,GAAY,IAAA,KAAS,cAAc,OAAA,GAAU,QAAA;AAC3E,EAAA,MAAM,KAAA,GAAQ,IAAA,KAAS,MAAA,GAAY,YAAA,CAAa,IAAI,CAAA,GAAI,IAAA;AAExD,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAK,GAAG,IAAA,EAAM,GAAA,EAAU,IAAA,EAAY,SAAA,EAAW,OAAA,CAAQ,aAAA,CAAO,KAAA,EAAO,SAAS,CAAA,EAAG,aAAW,IAAA,EAC1F,QAAA,EAAA;AAAA,IAAA,KAAA,wBACE,IAAA,EAAA,EAAK,IAAA,EAAK,MAAK,SAAA,EAAW,aAAA,CAAO,MAC/B,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,oBAEF,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAA,CAAO,IAAA,EACpB,QAAA,EAAA;AAAA,MAAA,KAAA,oBAAS,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAW,aAAA,CAAO,OAAQ,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,MAC5C,4BAAY,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAA,CAAO,SAAU,QAAA,EAAS,CAAA;AAAA,MACtD,0BAAU,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAA,CAAO,QAAS,QAAA,EAAA,MAAA,EAAO;AAAA,KAAA,EACpD,CAAA;AAAA,IACC,6BACC,GAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAAQ,OAAA,EAAQ,MAAK,IAAA,EAAK,KAAA,EAAO,YAAA,EAAc,IAAA,sBAAO,KAAA,EAAA,EAAM,CAAA,EAAI,SAAS,SAAA,EAAW,SAAA,EAAW,cAAO,OAAA,EAAS;AAAA,GAAA,EAE/H,CAAA;AAEJ;AAEA,KAAA,CAAM,WAAA,GAAc,OAAA","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/alert/Alert.module.css","../src/alert/Alert.tsx"],"names":["alert","icon","body","title","content","action","dismiss"],"mappings":";;;;;;;AAAA,IAAA,aAAA,GAAA;AAAA,EAKG,KAAA,EAAAA,aAAAA;AAAA,EAyCA,IAAA,EAAAC,YAAAA;AAAA,EAKA,IAAA,EAAAC,YAAAA;AAAA,EAQA,KAAA,EAAAC,aAAAA;AAAA,EAMA,OAAA,EAAAC,eAAAA;AAAA,EAIA,MAAA,EAAAC,cAAAA;AAAA,EAOA,OAAA,EAAAC;AAAA,CAAA;AC3CH,IAAM,YAAA,GAA6C;AAAA,EACjD,IAAA,sBAAO,IAAA,EAAA,EAAK,CAAA;AAAA,EACZ,OAAA,sBAAU,KAAA,EAAA,EAAM,CAAA;AAAA,EAChB,OAAA,sBAAU,OAAA,EAAA,EAAQ,CAAA;AAAA,EAClB,KAAA,sBAAQ,OAAA,EAAA,EAAQ;AAClB,CAAA;AAeO,SAAS,KAAA,CAAM;AAAA,EACpB,IAAA,GAAO,MAAA;AAAA,EACP,KAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA,GAAe,SAAA;AAAA,EACf,IAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAe;AACb,EAAA,MAAM,IAAA,GAAO,IAAA,KAAS,IAAA,KAAS,OAAA,GAAU,WAAA,GAAc,QAAA,CAAA;AACvD,EAAA,MAAM,OAAO,IAAA,KAAS,KAAA,GAAQ,MAAA,GAAY,IAAA,KAAS,cAAc,OAAA,GAAU,QAAA;AAC3E,EAAA,MAAM,KAAA,GAAQ,IAAA,KAAS,MAAA,GAAY,YAAA,CAAa,IAAI,CAAA,GAAI,IAAA;AAExD,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAK,GAAG,IAAA,EAAM,GAAA,EAAU,IAAA,EAAY,SAAA,EAAW,OAAA,CAAQ,aAAA,CAAO,KAAA,EAAO,SAAS,CAAA,EAAG,aAAW,IAAA,EAC1F,QAAA,EAAA;AAAA,IAAA,KAAA,wBACE,IAAA,EAAA,EAAK,IAAA,EAAK,MAAK,SAAA,EAAW,aAAA,CAAO,MAC/B,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,oBAEF,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAA,CAAO,IAAA,EACpB,QAAA,EAAA;AAAA,MAAA,KAAA,oBAAS,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAW,aAAA,CAAO,OAAQ,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,MAC5C,4BAAY,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAA,CAAO,SAAU,QAAA,EAAS,CAAA;AAAA,MACtD,0BAAU,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAA,CAAO,QAAS,QAAA,EAAA,MAAA,EAAO;AAAA,KAAA,EACpD,CAAA;AAAA,IACC,6BACC,GAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAAQ,OAAA,EAAQ,MAAK,IAAA,EAAK,KAAA,EAAO,YAAA,EAAc,IAAA,sBAAO,KAAA,EAAA,EAAM,CAAA,EAAI,SAAS,SAAA,EAAW,SAAA,EAAW,cAAO,OAAA,EAAS;AAAA,GAAA,EAE/H,CAAA;AAEJ;AAEA,KAAA,CAAM,WAAA,GAAc,OAAA","file":"chunk-A7TMFEQ2.js","sourcesContent":["/* Every value is a token (--alert-*). Tone resolves into private custom properties. */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .alert {\n --_bg: var(--alert-info-bg);\n --_accent: var(--alert-info-accent);\n --_title: var(--alert-info-title);\n\n display: flex;\n align-items: flex-start;\n gap: var(--alert-gap);\n padding: var(--alert-padding);\n border: var(--alert-border-width) solid var(--_accent);\n border-inline-start-width: var(--alert-accent-width);\n border-radius: var(--alert-radius);\n background-color: var(--_bg);\n color: var(--alert-fg);\n font-size: var(--alert-font-size);\n\n &[data-tone=\"info\"] {\n --_bg: var(--alert-info-bg);\n --_accent: var(--alert-info-accent);\n --_title: var(--alert-info-title);\n }\n\n &[data-tone=\"success\"] {\n --_bg: var(--alert-success-bg);\n --_accent: var(--alert-success-accent);\n --_title: var(--alert-success-title);\n }\n\n &[data-tone=\"warning\"] {\n --_bg: var(--alert-warning-bg);\n --_accent: var(--alert-warning-accent);\n --_title: var(--alert-warning-title);\n }\n\n &[data-tone=\"error\"] {\n --_bg: var(--alert-error-bg);\n --_accent: var(--alert-error-accent);\n --_title: var(--alert-error-title);\n }\n }\n\n .icon {\n flex: none;\n color: var(--_accent);\n }\n\n .body {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: var(--space-1);\n min-inline-size: 0;\n }\n\n .title {\n margin: 0;\n color: var(--_title);\n font-weight: var(--alert-title-font-weight);\n }\n\n .content {\n overflow-wrap: anywhere;\n }\n\n .action {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-2);\n margin-block-start: var(--space-1);\n }\n\n .dismiss {\n flex: none;\n margin-block: calc(-1 * var(--space-1));\n margin-inline-end: calc(-1 * var(--space-2));\n }\n}\n","import type { HTMLAttributes, ReactNode, Ref } from 'react';\nimport { Check, Close, Info, Warning } from '@pearpages/pulp-icons';\nimport { Icon } from '../icon';\nimport { IconButton } from '../icon-button';\nimport { classes } from '../internal/classes';\nimport styles from './Alert.module.css';\n\nexport type AlertTone = 'info' | 'success' | 'warning' | 'error';\nexport type AlertLive = 'polite' | 'assertive' | 'off';\n\nexport interface AlertProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** @default 'info' */\n tone?: AlertTone;\n title?: ReactNode;\n /** Replaces the tone's default glyph; `null` shows none. */\n icon?: ReactNode | null;\n /** Buttons or links placed under the body. */\n action?: ReactNode;\n /** Renders a dismiss button that calls this. */\n onDismiss?: () => void;\n /** @default 'Dismiss' */\n dismissLabel?: string;\n /**\n * How assistive technology announces it: `assertive` (`role=\"alert\"`),\n * `polite` (`role=\"status\"`) or `off` (no live role, for content present at\n * page load or inside another live region). Defaults to assertive for\n * `error`, polite otherwise.\n */\n live?: AlertLive;\n ref?: Ref<HTMLDivElement>;\n children?: ReactNode;\n}\n\nconst DEFAULT_ICON: Record<AlertTone, ReactNode> = {\n info: <Info />,\n success: <Check />,\n warning: <Warning />,\n error: <Warning />,\n};\n\n/**\n * An inline message with a tone. Tint, accent and title colour come from\n * the status tokens; the body keeps the default text colour so long\n * messages stay readable. Toast renders one Alert per notification.\n *\n * @status stable\n * @category Feedback\n * @accessibility `role=\"alert\"` for `tone=\"error\"` (assertive), `role=\"status\"` otherwise (polite); `live=\"off\"` opts out. The glyph is decorative; the tone is carried by the title and text, never by colour alone.\n * @do Give it a `title` when the body is more than one sentence.\n * Use `onDismiss` for messages the user can act on and clear.\n * @dont Announce errors through both an Alert and a Toast.\n * Use it as a page-level banner for marketing copy.\n */\nexport function Alert({\n tone = 'info',\n title,\n icon,\n action,\n onDismiss,\n dismissLabel = 'Dismiss',\n live,\n className,\n ref,\n children,\n ...rest\n}: AlertProps) {\n const mode = live ?? (tone === 'error' ? 'assertive' : 'polite');\n const role = mode === 'off' ? undefined : mode === 'assertive' ? 'alert' : 'status';\n const glyph = icon === undefined ? DEFAULT_ICON[tone] : icon;\n\n return (\n <div {...rest} ref={ref} role={role} className={classes(styles.alert, className)} data-tone={tone}>\n {glyph && (\n <Icon size=\"md\" className={styles.icon}>\n {glyph}\n </Icon>\n )}\n <div className={styles.body}>\n {title && <p className={styles.title}>{title}</p>}\n {children && <div className={styles.content}>{children}</div>}\n {action && <div className={styles.action}>{action}</div>}\n </div>\n {onDismiss && (\n <IconButton variant=\"ghost\" size=\"sm\" label={dismissLabel} icon={<Close />} onClick={onDismiss} className={styles.dismiss} />\n )}\n </div>\n );\n}\n\nAlert.displayName = 'Alert';\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useRovingFocus } from './chunk-I5OZ63W7.js';
|
|
2
2
|
import { useDismiss } from './chunk-NAYFLTK6.js';
|
|
3
3
|
import { useFloatingPosition } from './chunk-U6QRAD73.js';
|
|
4
|
-
import { renderAsChild } from './chunk-ZVDN3GRI.js';
|
|
5
4
|
import { Icon } from './chunk-O5LII5XP.js';
|
|
5
|
+
import { renderAsChild } from './chunk-QJG5ILK5.js';
|
|
6
6
|
import { classes } from './chunk-MI4QUKQS.js';
|
|
7
7
|
import { createContext, useState, useCallback, useId, useRef, useEffect, useContext } from 'react';
|
|
8
8
|
import { createPortal } from 'react-dom';
|
|
@@ -177,5 +177,5 @@ Menu.Item = MenuItem;
|
|
|
177
177
|
Menu.Separator = MenuSeparator;
|
|
178
178
|
|
|
179
179
|
export { Menu };
|
|
180
|
-
//# sourceMappingURL=chunk-
|
|
181
|
-
//# sourceMappingURL=chunk-
|
|
180
|
+
//# sourceMappingURL=chunk-AZAI4OVR.js.map
|
|
181
|
+
//# sourceMappingURL=chunk-AZAI4OVR.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/menu/Menu.module.css","../src/menu/Menu.tsx"],"names":["content","item","label","separator"],"mappings":"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","file":"chunk-2NSQPN7S.js","sourcesContent":["/* Every value is a token (--menu-*). Position comes in as --_x/--_y from the floating hook. */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .content {\n --_gap: var(--menu-gap);\n\n position: fixed;\n z-index: var(--menu-layer);\n inset-block-start: var(--_y);\n inset-inline-start: var(--_x);\n display: flex;\n flex-direction: column;\n min-inline-size: var(--menu-min-width);\n max-inline-size: calc(100vw - 2 * var(--space-4));\n padding: var(--menu-padding);\n border: var(--size-hairline) solid var(--menu-border);\n border-radius: var(--menu-radius);\n background-color: var(--menu-bg);\n color: var(--menu-fg);\n font-family: var(--font-family-body);\n box-shadow: var(--menu-shadow);\n animation: fade var(--menu-duration) var(--motion-easing-standard);\n\n &:focus-visible {\n outline: var(--menu-focus-ring-width) solid var(--menu-focus-ring);\n outline-offset: var(--menu-focus-ring-offset);\n }\n }\n\n .item {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n inline-size: 100%;\n padding-block: var(--menu-item-padding-block);\n padding-inline: var(--menu-item-padding-inline);\n border: none;\n border-radius: var(--menu-item-radius);\n background-color: transparent;\n color: var(--menu-item-fg);\n font-size: var(--menu-item-font-size);\n text-align: start;\n cursor: pointer;\n\n &[data-tone=\"danger\"] {\n color: var(--menu-item-fg-danger);\n }\n\n &[data-disabled] {\n color: var(--menu-item-fg-muted);\n cursor: not-allowed;\n }\n\n &:focus-visible {\n outline: none;\n background-color: var(--menu-item-bg-active);\n }\n\n &:hover:not([data-disabled]) {\n background-color: var(--menu-item-bg-active);\n }\n }\n\n .label {\n flex: 1;\n }\n\n .separator {\n block-size: var(--size-hairline);\n margin-block: var(--menu-padding);\n background-color: var(--menu-separator);\n }\n\n @keyframes fade {\n from {\n opacity: 0;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .content {\n animation: none;\n }\n }\n}\n","import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useId,\n useRef,\n useState,\n type ButtonHTMLAttributes,\n type HTMLAttributes,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n type Ref,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { Icon } from '../icon';\nimport { renderAsChild } from '../internal/asChild';\nimport { classes } from '../internal/classes';\nimport { useFloatingPosition, type FloatingPlacement } from '../internal/floating';\nimport { useDismiss } from '../internal/useDismiss';\nimport { useRovingFocus } from '../internal/useRovingFocus';\nimport styles from './Menu.module.css';\n\nexport type MenuPlacement = FloatingPlacement;\ntype FocusTarget = 'first' | 'last' | null;\n\ninterface MenuContextValue {\n open: boolean;\n setOpen: (open: boolean, focus?: FocusTarget) => void;\n focusTarget: FocusTarget;\n triggerId: string;\n contentId: string;\n floating: ReturnType<typeof useFloatingPosition>;\n}\n\nconst MenuContext = createContext<MenuContextValue | null>(null);\n\nfunction useMenu(part: string): MenuContextValue {\n const context = useContext(MenuContext);\n if (!context) throw new Error(`${part} must be rendered inside <Menu>`);\n return context;\n}\n\nexport interface MenuProps {\n open?: boolean;\n /** @default false */\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** @default 'bottom-start' */\n placement?: MenuPlacement;\n children: ReactNode;\n}\n\n/**\n * A list of actions opened from a button, following the WAI-ARIA menu\n * button pattern: Down/Up arrow on the trigger opens and focuses the first\n * or last item, arrows move with wraparound, Home and End jump, typing\n * jumps to the next item starting with that letter, Enter, Space or click\n * selects and closes, Escape and Tab close and return focus. Compose with\n * `Menu.Trigger`, `Menu.Content`, `Menu.Item` and `Menu.Separator`.\n *\n * @status stable\n * @category Overlays\n * @accessibility The WAI-ARIA menu button pattern: the trigger has `aria-haspopup=\"menu\"` and `aria-expanded`; the popup is `role=\"menu\"` named by the trigger with `menuitem` children. Down/Up opens to the first/last item, arrows wrap, Home/End jump, typing jumps, Enter/Space/click select and close, Escape and Tab close and return focus.\n * @do Use `tone=\"danger\"` for destructive items and put them after a separator.\n * @dont Put form controls or links that navigate inside a menu; those want Popover or a navigation list.\n * Use it for navigation between pages.\n */\nexport function Menu({ open, defaultOpen = false, onOpenChange, placement = 'bottom-start', children }: MenuProps) {\n const [uncontrolled, setUncontrolled] = useState(defaultOpen);\n const [focusTarget, setFocusTarget] = useState<FocusTarget>(null);\n const controlled = open !== undefined;\n const isOpen = controlled ? open : uncontrolled;\n const setOpen = useCallback(\n (next: boolean, focus: FocusTarget = null) => {\n setFocusTarget(next ? focus : null);\n if (!controlled) setUncontrolled(next);\n onOpenChange?.(next);\n },\n [controlled, onOpenChange],\n );\n const id = useId();\n const floating = useFloatingPosition({ open: isOpen, placement });\n\n return (\n <MenuContext.Provider value={{ open: isOpen, setOpen, focusTarget, triggerId: `${id}-trigger`, contentId: `${id}-menu`, floating }}>\n {children}\n </MenuContext.Provider>\n );\n}\n\nfunction mergeRefs<T>(a: Ref<T> | undefined, b: (node: T | null) => void) {\n return (node: T | null) => {\n b(node);\n if (typeof a === 'function') a(node);\n else if (a) a.current = node;\n };\n}\n\ninterface MenuTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n asChild?: boolean;\n ref?: Ref<HTMLButtonElement>;\n children: ReactNode;\n}\n\nfunction MenuTrigger({ asChild = false, onClick, onKeyDown, ref, children, ...rest }: MenuTriggerProps) {\n const menu = useMenu('Menu.Trigger');\n const props = {\n ...rest,\n id: menu.triggerId,\n 'aria-haspopup': 'menu' as const,\n 'aria-expanded': menu.open,\n 'aria-controls': menu.open ? menu.contentId : undefined,\n onClick: (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n if (!event.defaultPrevented) menu.setOpen(!menu.open, 'first');\n },\n onKeyDown: (event: KeyboardEvent<HTMLButtonElement>) => {\n onKeyDown?.(event);\n if (event.defaultPrevented) return;\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n menu.setOpen(true, event.key === 'ArrowDown' ? 'first' : 'last');\n }\n },\n };\n const setRef = mergeRefs(ref, menu.floating.refs.setReference);\n // eslint-disable-next-line react-hooks/refs -- forwarded to the reference element, not read\n if (asChild) return renderAsChild('Menu.Trigger', children, { ...props, ref: setRef });\n return (\n <button type=\"button\" {...props} ref={setRef}>\n {children}\n </button>\n );\n}\n\ninterface MenuContentProps extends HTMLAttributes<HTMLDivElement> {\n ref?: Ref<HTMLDivElement>;\n children: ReactNode;\n}\n\nfunction MenuContent({ className, onKeyDown, ref, children, ...rest }: MenuContentProps) {\n const menu = useMenu('Menu.Content');\n const { refs, positionStyle, placement } = menu.floating;\n const contentRef = useRef<HTMLDivElement | null>(null);\n const rove = useRovingFocus({ orientation: 'vertical', selector: '[role=\"menuitem\"]' });\n\n useDismiss({\n open: menu.open,\n onDismiss: () => menu.setOpen(false),\n inside: () => [refs.reference.current as Element | null, refs.floating.current],\n });\n\n useEffect(() => {\n if (!menu.open) return;\n const content = contentRef.current;\n if (!content) return;\n const items = Array.from(content.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])'));\n const target = menu.focusTarget === 'last' ? items.at(-1) : items[0];\n (target ?? content).focus();\n return () => {\n const reference = refs.reference.current as HTMLElement | null;\n if (content.contains(document.activeElement) || document.activeElement === document.body) reference?.focus();\n };\n }, [menu.open, menu.focusTarget, refs.reference]);\n\n const typeahead = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key.length !== 1 || event.altKey || event.ctrlKey || event.metaKey) return false;\n const items = Array.from(event.currentTarget.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])'));\n const current = items.indexOf(document.activeElement as HTMLElement);\n const ordered = [...items.slice(current + 1), ...items.slice(0, current + 1)];\n const match = ordered.find((item) => item.textContent?.trim().toLowerCase().startsWith(event.key.toLowerCase()));\n if (!match) return false;\n event.preventDefault();\n match.focus();\n return true;\n };\n\n if (!menu.open) return null;\n return createPortal(\n <div\n {...rest}\n ref={mergeRefs(ref, (node) => {\n contentRef.current = node;\n refs.setFloating(node);\n })}\n id={menu.contentId}\n role=\"menu\"\n aria-labelledby={menu.triggerId}\n tabIndex={-1}\n className={classes(styles.content, className)}\n data-placement={placement}\n // eslint-disable-next-line react/forbid-dom-props -- per-instance position (--_x/--_y), see internal/floating.ts\n style={positionStyle}\n onKeyDown={(event) => {\n onKeyDown?.(event);\n if (event.defaultPrevented) return;\n if (event.key === 'Tab') {\n menu.setOpen(false);\n return;\n }\n if (typeahead(event)) return;\n rove(event);\n }}\n >\n {children}\n </div>,\n document.body,\n );\n}\n\nexport type MenuItemTone = 'default' | 'danger';\n\ninterface MenuItemProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onSelect'> {\n /** Called when the item is chosen; the menu closes afterwards. */\n onSelect?: () => void;\n /** @default 'default' */\n tone?: MenuItemTone;\n /** Leading glyph, decorative. */\n icon?: ReactNode;\n ref?: Ref<HTMLButtonElement>;\n children: ReactNode;\n}\n\nfunction MenuItem({ onSelect, tone = 'default', icon, disabled, className, onClick, ref, children, ...rest }: MenuItemProps) {\n const menu = useMenu('Menu.Item');\n return (\n <button\n {...rest}\n ref={ref}\n type=\"button\"\n role=\"menuitem\"\n tabIndex={-1}\n aria-disabled={disabled || undefined}\n className={classes(styles.item, className)}\n data-tone={tone}\n data-disabled={disabled ? '' : undefined}\n onClick={(event) => {\n onClick?.(event);\n if (event.defaultPrevented || disabled) return;\n onSelect?.();\n menu.setOpen(false);\n }}\n >\n {icon && <Icon size=\"inherit\">{icon}</Icon>}\n <span className={styles.label}>{children}</span>\n </button>\n );\n}\n\nfunction MenuSeparator({ className, ...rest }: HTMLAttributes<HTMLDivElement>) {\n return <div {...rest} role=\"separator\" className={classes(styles.separator, className)} />;\n}\n\nMenu.displayName = 'Menu';\nMenuTrigger.displayName = 'Menu.Trigger';\nMenuContent.displayName = 'Menu.Content';\nMenuItem.displayName = 'Menu.Item';\nMenuSeparator.displayName = 'Menu.Separator';\n\nMenu.Trigger = MenuTrigger;\nMenu.Content = MenuContent;\nMenu.Item = MenuItem;\nMenu.Separator = MenuSeparator;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/menu/Menu.module.css","../src/menu/Menu.tsx"],"names":["content","item","label","separator"],"mappings":"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","file":"chunk-AZAI4OVR.js","sourcesContent":["/* Every value is a token (--menu-*). Position comes in as --_x/--_y from the floating hook. */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .content {\n --_gap: var(--menu-gap);\n\n position: fixed;\n z-index: var(--menu-layer);\n inset-block-start: var(--_y);\n inset-inline-start: var(--_x);\n display: flex;\n flex-direction: column;\n min-inline-size: var(--menu-min-width);\n max-inline-size: calc(100vw - 2 * var(--space-4));\n padding: var(--menu-padding);\n border: var(--size-hairline) solid var(--menu-border);\n border-radius: var(--menu-radius);\n background-color: var(--menu-bg);\n color: var(--menu-fg);\n font-family: var(--font-family-body);\n box-shadow: var(--menu-shadow);\n animation: fade var(--menu-duration) var(--motion-easing-standard);\n\n &:focus-visible {\n outline: var(--menu-focus-ring-width) solid var(--menu-focus-ring);\n outline-offset: var(--menu-focus-ring-offset);\n }\n }\n\n .item {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n inline-size: 100%;\n padding-block: var(--menu-item-padding-block);\n padding-inline: var(--menu-item-padding-inline);\n border: none;\n border-radius: var(--menu-item-radius);\n background-color: transparent;\n color: var(--menu-item-fg);\n font-size: var(--menu-item-font-size);\n text-align: start;\n cursor: pointer;\n\n &[data-tone=\"danger\"] {\n color: var(--menu-item-fg-danger);\n }\n\n &[data-disabled] {\n color: var(--menu-item-fg-muted);\n cursor: not-allowed;\n }\n\n &:focus-visible {\n outline: none;\n background-color: var(--menu-item-bg-active);\n }\n\n &:hover:not([data-disabled]) {\n background-color: var(--menu-item-bg-active);\n }\n }\n\n .label {\n flex: 1;\n }\n\n .separator {\n block-size: var(--size-hairline);\n margin-block: var(--menu-padding);\n background-color: var(--menu-separator);\n }\n\n @keyframes fade {\n from {\n opacity: 0;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .content {\n animation: none;\n }\n }\n}\n","import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useId,\n useRef,\n useState,\n type ButtonHTMLAttributes,\n type HTMLAttributes,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n type Ref,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { Icon } from '../icon';\nimport { renderAsChild } from '../internal/asChild';\nimport { classes } from '../internal/classes';\nimport { useFloatingPosition, type FloatingPlacement } from '../internal/floating';\nimport { useDismiss } from '../internal/useDismiss';\nimport { useRovingFocus } from '../internal/useRovingFocus';\nimport styles from './Menu.module.css';\n\nexport type MenuPlacement = FloatingPlacement;\ntype FocusTarget = 'first' | 'last' | null;\n\ninterface MenuContextValue {\n open: boolean;\n setOpen: (open: boolean, focus?: FocusTarget) => void;\n focusTarget: FocusTarget;\n triggerId: string;\n contentId: string;\n floating: ReturnType<typeof useFloatingPosition>;\n}\n\nconst MenuContext = createContext<MenuContextValue | null>(null);\n\nfunction useMenu(part: string): MenuContextValue {\n const context = useContext(MenuContext);\n if (!context) throw new Error(`${part} must be rendered inside <Menu>`);\n return context;\n}\n\nexport interface MenuProps {\n open?: boolean;\n /** @default false */\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** @default 'bottom-start' */\n placement?: MenuPlacement;\n children: ReactNode;\n}\n\n/**\n * A list of actions opened from a button, following the WAI-ARIA menu\n * button pattern: Down/Up arrow on the trigger opens and focuses the first\n * or last item, arrows move with wraparound, Home and End jump, typing\n * jumps to the next item starting with that letter, Enter, Space or click\n * selects and closes, Escape and Tab close and return focus. Compose with\n * `Menu.Trigger`, `Menu.Content`, `Menu.Item` and `Menu.Separator`.\n *\n * @status stable\n * @category Overlays\n * @accessibility The WAI-ARIA menu button pattern: the trigger has `aria-haspopup=\"menu\"` and `aria-expanded`; the popup is `role=\"menu\"` named by the trigger with `menuitem` children. Down/Up opens to the first/last item, arrows wrap, Home/End jump, typing jumps, Enter/Space/click select and close, Escape and Tab close and return focus.\n * @do Use `tone=\"danger\"` for destructive items and put them after a separator.\n * @dont Put form controls or links that navigate inside a menu; those want Popover or a navigation list.\n * Use it for navigation between pages.\n */\nexport function Menu({ open, defaultOpen = false, onOpenChange, placement = 'bottom-start', children }: MenuProps) {\n const [uncontrolled, setUncontrolled] = useState(defaultOpen);\n const [focusTarget, setFocusTarget] = useState<FocusTarget>(null);\n const controlled = open !== undefined;\n const isOpen = controlled ? open : uncontrolled;\n const setOpen = useCallback(\n (next: boolean, focus: FocusTarget = null) => {\n setFocusTarget(next ? focus : null);\n if (!controlled) setUncontrolled(next);\n onOpenChange?.(next);\n },\n [controlled, onOpenChange],\n );\n const id = useId();\n const floating = useFloatingPosition({ open: isOpen, placement });\n\n return (\n <MenuContext.Provider value={{ open: isOpen, setOpen, focusTarget, triggerId: `${id}-trigger`, contentId: `${id}-menu`, floating }}>\n {children}\n </MenuContext.Provider>\n );\n}\n\nfunction mergeRefs<T>(a: Ref<T> | undefined, b: (node: T | null) => void) {\n return (node: T | null) => {\n b(node);\n if (typeof a === 'function') a(node);\n else if (a) a.current = node;\n };\n}\n\ninterface MenuTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n asChild?: boolean;\n ref?: Ref<HTMLButtonElement>;\n children: ReactNode;\n}\n\nfunction MenuTrigger({ asChild = false, onClick, onKeyDown, ref, children, ...rest }: MenuTriggerProps) {\n const menu = useMenu('Menu.Trigger');\n const props = {\n ...rest,\n id: menu.triggerId,\n 'aria-haspopup': 'menu' as const,\n 'aria-expanded': menu.open,\n 'aria-controls': menu.open ? menu.contentId : undefined,\n onClick: (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n if (!event.defaultPrevented) menu.setOpen(!menu.open, 'first');\n },\n onKeyDown: (event: KeyboardEvent<HTMLButtonElement>) => {\n onKeyDown?.(event);\n if (event.defaultPrevented) return;\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n menu.setOpen(true, event.key === 'ArrowDown' ? 'first' : 'last');\n }\n },\n };\n const setRef = mergeRefs(ref, menu.floating.refs.setReference);\n // eslint-disable-next-line react-hooks/refs -- forwarded to the reference element, not read\n if (asChild) return renderAsChild('Menu.Trigger', children, { ...props, ref: setRef });\n return (\n <button type=\"button\" {...props} ref={setRef}>\n {children}\n </button>\n );\n}\n\ninterface MenuContentProps extends HTMLAttributes<HTMLDivElement> {\n ref?: Ref<HTMLDivElement>;\n children: ReactNode;\n}\n\nfunction MenuContent({ className, onKeyDown, ref, children, ...rest }: MenuContentProps) {\n const menu = useMenu('Menu.Content');\n const { refs, positionStyle, placement } = menu.floating;\n const contentRef = useRef<HTMLDivElement | null>(null);\n const rove = useRovingFocus({ orientation: 'vertical', selector: '[role=\"menuitem\"]' });\n\n useDismiss({\n open: menu.open,\n onDismiss: () => menu.setOpen(false),\n inside: () => [refs.reference.current as Element | null, refs.floating.current],\n });\n\n useEffect(() => {\n if (!menu.open) return;\n const content = contentRef.current;\n if (!content) return;\n const items = Array.from(content.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])'));\n const target = menu.focusTarget === 'last' ? items.at(-1) : items[0];\n (target ?? content).focus();\n return () => {\n const reference = refs.reference.current as HTMLElement | null;\n if (content.contains(document.activeElement) || document.activeElement === document.body) reference?.focus();\n };\n }, [menu.open, menu.focusTarget, refs.reference]);\n\n const typeahead = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key.length !== 1 || event.altKey || event.ctrlKey || event.metaKey) return false;\n const items = Array.from(event.currentTarget.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])'));\n const current = items.indexOf(document.activeElement as HTMLElement);\n const ordered = [...items.slice(current + 1), ...items.slice(0, current + 1)];\n const match = ordered.find((item) => item.textContent?.trim().toLowerCase().startsWith(event.key.toLowerCase()));\n if (!match) return false;\n event.preventDefault();\n match.focus();\n return true;\n };\n\n if (!menu.open) return null;\n return createPortal(\n <div\n {...rest}\n ref={mergeRefs(ref, (node) => {\n contentRef.current = node;\n refs.setFloating(node);\n })}\n id={menu.contentId}\n role=\"menu\"\n aria-labelledby={menu.triggerId}\n tabIndex={-1}\n className={classes(styles.content, className)}\n data-placement={placement}\n // eslint-disable-next-line react/forbid-dom-props -- per-instance position (--_x/--_y), see internal/floating.ts\n style={positionStyle}\n onKeyDown={(event) => {\n onKeyDown?.(event);\n if (event.defaultPrevented) return;\n if (event.key === 'Tab') {\n menu.setOpen(false);\n return;\n }\n if (typeahead(event)) return;\n rove(event);\n }}\n >\n {children}\n </div>,\n document.body,\n );\n}\n\nexport type MenuItemTone = 'default' | 'danger';\n\ninterface MenuItemProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onSelect'> {\n /** Called when the item is chosen; the menu closes afterwards. */\n onSelect?: () => void;\n /** @default 'default' */\n tone?: MenuItemTone;\n /** Leading glyph, decorative. */\n icon?: ReactNode;\n ref?: Ref<HTMLButtonElement>;\n children: ReactNode;\n}\n\nfunction MenuItem({ onSelect, tone = 'default', icon, disabled, className, onClick, ref, children, ...rest }: MenuItemProps) {\n const menu = useMenu('Menu.Item');\n return (\n <button\n {...rest}\n ref={ref}\n type=\"button\"\n role=\"menuitem\"\n tabIndex={-1}\n aria-disabled={disabled || undefined}\n className={classes(styles.item, className)}\n data-tone={tone}\n data-disabled={disabled ? '' : undefined}\n onClick={(event) => {\n onClick?.(event);\n if (event.defaultPrevented || disabled) return;\n onSelect?.();\n menu.setOpen(false);\n }}\n >\n {icon && <Icon size=\"inherit\">{icon}</Icon>}\n <span className={styles.label}>{children}</span>\n </button>\n );\n}\n\nfunction MenuSeparator({ className, ...rest }: HTMLAttributes<HTMLDivElement>) {\n return <div {...rest} role=\"separator\" className={classes(styles.separator, className)} />;\n}\n\nMenu.displayName = 'Menu';\nMenuTrigger.displayName = 'Menu.Trigger';\nMenuContent.displayName = 'Menu.Content';\nMenuItem.displayName = 'Menu.Item';\nMenuSeparator.displayName = 'Menu.Separator';\n\nMenu.Trigger = MenuTrigger;\nMenu.Content = MenuContent;\nMenu.Item = MenuItem;\nMenu.Separator = MenuSeparator;\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ToggleField } from './chunk-
|
|
1
|
+
import { ToggleField } from './chunk-Q6SYKNZ5.js';
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
3
|
|
|
4
4
|
// src/switch/Switch.module.css
|
|
@@ -41,5 +41,5 @@ function Switch({
|
|
|
41
41
|
Switch.displayName = "Switch";
|
|
42
42
|
|
|
43
43
|
export { Switch };
|
|
44
|
-
//# sourceMappingURL=chunk-
|
|
45
|
-
//# sourceMappingURL=chunk-
|
|
44
|
+
//# sourceMappingURL=chunk-CLE2QGCU.js.map
|
|
45
|
+
//# sourceMappingURL=chunk-CLE2QGCU.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/switch/Switch.module.css","../src/switch/Switch.tsx"],"names":["switch","row","input"],"mappings":";;;;AAAA,IAAA,cAAA,GAAA;AAAA,EASG,MAAA,EAAAA,eAAAA;AAAA,EAWA,GAAA,EAAAC,YAAAA;AAAA,EAMA,KAAA,EAAAC;AAAA,CAAA;ACKI,SAAS,MAAA,CAAO;AAAA,EACrB,KAAA;AAAA,EACA,WAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA,GAAO,IAAA;AAAA,EACP,QAAA;AAAA,EACA,QAAA;AAAA,EACA,EAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAA;AAAA,EACA,kBAAA,EAAoB,WAAA;AAAA,EACpB,GAAG;AACL,CAAA,EAAgB;AACd,EAAA,uBACE,GAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,KAAA;AAAA,MACA,WAAA;AAAA,MACA,KAAA;AAAA,MACA,IAAA;AAAA,MACA,QAAA;AAAA,MACA,QAAA;AAAA,MACA,EAAA;AAAA,MACA,SAAA;AAAA,MACA,eAAe,cAAA,CAAO,MAAA;AAAA,MACtB,cAAc,cAAA,CAAO,GAAA;AAAA,MACrB,kBAAA,EAAkB,WAAA;AAAA,MAClB,OAAA,kBAAS,GAAA,CAAC,OAAA,EAAA,EAAO,GAAG,IAAA,EAAM,GAAA,EAAU,IAAA,EAAK,UAAA,EAAW,IAAA,EAAK,QAAA,EAAS,SAAA,EAAW,cAAA,CAAO,KAAA,EAAO;AAAA;AAAA,GAC7F;AAEJ;AAEA,MAAA,CAAO,WAAA,GAAc,QAAA","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/switch/Switch.module.css","../src/switch/Switch.tsx"],"names":["switch","row","input"],"mappings":";;;;AAAA,IAAA,cAAA,GAAA;AAAA,EASG,MAAA,EAAAA,eAAAA;AAAA,EAWA,GAAA,EAAAC,YAAAA;AAAA,EAMA,KAAA,EAAAC;AAAA,CAAA;ACKI,SAAS,MAAA,CAAO;AAAA,EACrB,KAAA;AAAA,EACA,WAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA,GAAO,IAAA;AAAA,EACP,QAAA;AAAA,EACA,QAAA;AAAA,EACA,EAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAA;AAAA,EACA,kBAAA,EAAoB,WAAA;AAAA,EACpB,GAAG;AACL,CAAA,EAAgB;AACd,EAAA,uBACE,GAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,KAAA;AAAA,MACA,WAAA;AAAA,MACA,KAAA;AAAA,MACA,IAAA;AAAA,MACA,QAAA;AAAA,MACA,QAAA;AAAA,MACA,EAAA;AAAA,MACA,SAAA;AAAA,MACA,eAAe,cAAA,CAAO,MAAA;AAAA,MACtB,cAAc,cAAA,CAAO,GAAA;AAAA,MACrB,kBAAA,EAAkB,WAAA;AAAA,MAClB,OAAA,kBAAS,GAAA,CAAC,OAAA,EAAA,EAAO,GAAG,IAAA,EAAM,GAAA,EAAU,IAAA,EAAK,UAAA,EAAW,IAAA,EAAK,QAAA,EAAS,SAAA,EAAW,cAAA,CAAO,KAAA,EAAO;AAAA;AAAA,GAC7F;AAEJ;AAEA,MAAA,CAAO,WAAA,GAAc,QAAA","file":"chunk-CLE2QGCU.js","sourcesContent":["/*\n * Every value is a token (--switch-*). The input is the track; its ::before\n * is the thumb. Size and invalid state resolve into private custom\n * properties on the root.\n */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .switch {\n --_size: var(--switch-size-md);\n --_track: var(--switch-track-bg);\n\n font-family: var(--font-family-body);\n\n &[data-size=\"sm\"] { --_size: var(--switch-size-sm); }\n &[data-size=\"lg\"] { --_size: var(--switch-size-lg); }\n &[data-invalid] { --_track: var(--switch-track-invalid); }\n }\n\n .row {\n display: flex;\n align-items: center;\n gap: var(--switch-gap);\n }\n\n .input {\n --_inset: calc(2 * var(--switch-thumb-inset));\n\n position: relative;\n flex: none;\n inline-size: calc(2 * var(--_size));\n block-size: var(--_size);\n margin: 0;\n border: none;\n border-radius: var(--switch-radius);\n background-color: var(--_track);\n appearance: none;\n cursor: pointer;\n transition: background-color var(--switch-motion-duration) var(--motion-easing-standard);\n\n &::before {\n content: \"\";\n position: absolute;\n inset-block-start: var(--_inset);\n inset-inline-start: var(--_inset);\n inline-size: calc(var(--_size) - 2 * var(--_inset));\n block-size: calc(var(--_size) - 2 * var(--_inset));\n border-radius: var(--switch-radius);\n background-color: var(--switch-thumb);\n transition: translate var(--switch-motion-duration) var(--motion-easing-standard);\n }\n\n &:checked {\n background-color: var(--switch-track-bg-checked);\n\n &::before {\n translate: var(--_size) 0;\n background-color: var(--switch-thumb-checked);\n }\n }\n\n &:focus-visible {\n outline: var(--switch-focus-ring-width) solid var(--switch-focus-ring);\n outline-offset: var(--switch-focus-ring-offset);\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.55;\n }\n\n &:hover:not(:disabled, :checked) {\n background-color: var(--switch-track-bg-hover);\n }\n\n &:hover:not(:disabled):checked {\n background-color: var(--switch-track-bg-checked-hover);\n }\n }\n}\n","import type { InputHTMLAttributes, ReactNode, Ref } from 'react';\nimport { ToggleField, type ToggleSize } from '../internal/ToggleField';\nimport styles from './Switch.module.css';\n\nexport type SwitchSize = ToggleSize;\n\nexport interface SwitchProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'type'> {\n /** Visible label beside the switch. */\n label: ReactNode;\n description?: ReactNode;\n error?: ReactNode;\n /** @default 'md' */\n size?: SwitchSize;\n /** The `<input>` element. */\n ref?: Ref<HTMLInputElement>;\n /** Applied to the wrapper, not the input. */\n className?: string;\n}\n\n/**\n * An on/off control: a native checkbox with `role=\"switch\"`, so assistive\n * technology announces on and off, and the browser handles keyboard, forms\n * and state. Use it for settings that take effect immediately; use Checkbox\n * for choices submitted with a form. Drawn with `--switch-*` tokens.\n *\n * @status stable\n * @category Forms\n * @accessibility A native checkbox with `role=\"switch\"`, so on and off are announced; Space toggles; label, description and error wire through Field.\n * @do Use it for settings that apply immediately.\n * @dont Use it inside a form that needs a submit; use Checkbox.\n */\nexport function Switch({\n label,\n description,\n error,\n size = 'md',\n required,\n disabled,\n id,\n className,\n ref,\n 'aria-describedby': describedBy,\n ...rest\n}: SwitchProps) {\n return (\n <ToggleField\n label={label}\n description={description}\n error={error}\n size={size}\n required={required}\n disabled={disabled}\n id={id}\n className={className}\n rootClassName={styles.switch}\n rowClassName={styles.row}\n aria-describedby={describedBy}\n control={<input {...rest} ref={ref} type=\"checkbox\" role=\"switch\" className={styles.input} />}\n />\n );\n}\n\nSwitch.displayName = 'Switch';\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Spinner } from './chunk-ZL5MMRLG.js';
|
|
2
|
-
import { renderAsChild } from './chunk-ZVDN3GRI.js';
|
|
3
2
|
import { Icon } from './chunk-O5LII5XP.js';
|
|
3
|
+
import { renderAsChild } from './chunk-QJG5ILK5.js';
|
|
4
4
|
import { classes } from './chunk-MI4QUKQS.js';
|
|
5
5
|
import { Children, isValidElement } from 'react';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -22,6 +22,7 @@ function hasText(node) {
|
|
|
22
22
|
}
|
|
23
23
|
function Button({
|
|
24
24
|
variant = "primary",
|
|
25
|
+
tone = "default",
|
|
25
26
|
size = "md",
|
|
26
27
|
loading = false,
|
|
27
28
|
iconStart,
|
|
@@ -47,6 +48,7 @@ function Button({
|
|
|
47
48
|
ref,
|
|
48
49
|
className: classes(Button_default.button, className),
|
|
49
50
|
"data-variant": variant,
|
|
51
|
+
"data-tone": tone === "danger" ? tone : void 0,
|
|
50
52
|
"data-size": size,
|
|
51
53
|
"data-loading": loading ? "" : void 0,
|
|
52
54
|
"aria-busy": loading || void 0,
|
|
@@ -73,5 +75,5 @@ function Button({
|
|
|
73
75
|
Button.displayName = "Button";
|
|
74
76
|
|
|
75
77
|
export { Button };
|
|
76
|
-
//# sourceMappingURL=chunk-
|
|
77
|
-
//# sourceMappingURL=chunk-
|
|
78
|
+
//# sourceMappingURL=chunk-DE67ECD7.js.map
|
|
79
|
+
//# sourceMappingURL=chunk-DE67ECD7.js.map
|