@pienter/ui 0.3.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +258 -0
- package/CONVENTIONS.md +342 -385
- package/README.md +33 -18
- package/components/display/record-details/RecordDetails.vue +61 -0
- package/components/display/record-details/record-details.css +37 -0
- package/components/display/record-details/types.ts +8 -0
- package/components/feedback/toast/toast.css +1 -1
- package/components/form/block-editor/BlockEditor.vue +454 -0
- package/components/form/block-editor/block-editor.css +149 -0
- package/components/form/block-editor/types.ts +15 -0
- package/components/form/combobox/Combobox.vue +42 -72
- package/components/form/combobox/combobox.css +1 -1
- package/components/form/form/Form.vue +1 -2
- package/components/form/label/label.css +1 -1
- package/components/form/number-field/NumberField.vue +1 -2
- package/components/form/number-field/number-field.css +1 -1
- package/components/form/radio-group/RadioGroup.vue +2 -5
- package/components/form/record-form/RecordFields.vue +128 -0
- package/components/form/record-form/RecordForm.vue +116 -0
- package/components/form/record-form/fields.ts +20 -0
- package/components/form/record-form/record-form.css +15 -0
- package/components/form/record-form/types.ts +28 -0
- package/components/form/slider/slider.css +2 -3
- package/components/form/tags-input/tags-input.css +1 -2
- package/components/form/text-input/text-input.css +2 -0
- package/components/form/textarea/textarea.css +1 -1
- package/components/layout/accordion/Accordion.vue +6 -27
- package/components/layout/collapsible/Collapsible.vue +9 -19
- package/components/layout/index/Index.vue +353 -0
- package/components/layout/index/index.css +114 -0
- package/components/layout/index/useIndex.ts +390 -0
- package/components/layout/table/table.css +5 -4
- package/components/navigation/breadcrumb/Breadcrumb.vue +24 -5
- package/components/navigation/breadcrumb/breadcrumb.css +15 -0
- package/components/navigation/sidebar/Sidebar.vue +329 -84
- package/components/navigation/sidebar/SidebarMenuItem.vue +199 -0
- package/components/navigation/sidebar/context.ts +21 -0
- package/components/navigation/sidebar/sidebar.css +346 -78
- package/components/navigation/sidebar/types.ts +13 -1
- package/components/navigation/tabs/Tabs.vue +6 -0
- package/components/overlay/alert-dialog/AlertDialog.vue +10 -31
- package/components/overlay/command/Command.vue +10 -38
- package/components/overlay/command/command.css +1 -1
- package/components/overlay/dropdown-menu/DropdownMenu.vue +37 -62
- package/components/overlay/modal/Modal.vue +7 -28
- package/components/overlay/popover/Popover.vue +9 -31
- package/components/overlay/sheet/Sheet.vue +7 -28
- package/components/overlay/tooltip/Tooltip.vue +14 -19
- package/{utils/controllers/dialog.ts → composables/useDialog.ts} +90 -78
- package/composables/useDisclosure.ts +113 -0
- package/composables/useEventListener.ts +16 -0
- package/composables/useMenu.ts +212 -0
- package/{utils/controllers/popover.ts → composables/usePopover.ts} +107 -120
- package/package.json +16 -40
- package/styles/0-settings/colors.css +10 -0
- package/styles/0-settings/layout.css +18 -0
- package/styles/0-settings/motion.css +2 -2
- package/styles/0-settings/spacing.css +3 -1
- package/utils/a11y/focus.ts +9 -3
- package/utils/cms/index.ts +283 -0
- package/utils/cms/schema.json +126 -0
- package/utils/navigation/sidebar.ts +97 -0
- package/utils/validation/form.ts +6 -9
- package/components/action/button/Button.astro +0 -95
- package/components/action/button/IconButton.astro +0 -86
- package/components/display/avatar/Avatar.astro +0 -17
- package/components/display/avatar/AvatarStack.astro +0 -9
- package/components/display/badge/Badge.astro +0 -15
- package/components/display/empty/Empty.astro +0 -9
- package/components/display/icon/Icon.astro +0 -52
- package/components/feedback/alert/Alert.astro +0 -52
- package/components/feedback/progress/Progress.astro +0 -68
- package/components/feedback/skeleton/Skeleton.astro +0 -32
- package/components/feedback/spinner/Spinner.astro +0 -25
- package/components/feedback/toast/Toast.astro +0 -50
- package/components/form/checkbox/Checkbox.astro +0 -79
- package/components/form/date-input/DateInput.astro +0 -105
- package/components/form/form/Form.astro +0 -106
- package/components/form/input-otp/InputOTP.astro +0 -147
- package/components/form/label/Label.astro +0 -13
- package/components/form/number-field/NumberField.astro +0 -142
- package/components/form/radio-group/RadioGroup.astro +0 -105
- package/components/form/select/Select.astro +0 -105
- package/components/form/slider/Slider.astro +0 -205
- package/components/form/switch/Switch.astro +0 -75
- package/components/form/tags-input/TagsInput.astro +0 -153
- package/components/form/text-input/TextInput.astro +0 -84
- package/components/form/textarea/Textarea.astro +0 -86
- package/components/layout/card/Card.astro +0 -13
- package/components/layout/separator/Separator.astro +0 -31
- package/components/layout/table/Table.astro +0 -116
- package/components/navigation/breadcrumb/Breadcrumb.astro +0 -36
- package/components/navigation/navbar/Navbar.astro +0 -62
- package/components/navigation/pagination/PaginationFooter.astro +0 -24
- package/components/navigation/sidebar/Sidebar.astro +0 -132
- package/components/navigation/sidebar/SidebarItemRender.astro +0 -83
- package/components/navigation/sidebar/SidebarItemRender.vue +0 -98
- package/components/overlay/alert-dialog/AlertDialog.astro +0 -112
- package/components/overlay/modal/Modal.astro +0 -66
- package/utils/controllers/disclosure.ts +0 -117
- package/utils/controllers/form.ts +0 -524
- package/utils/controllers/index.ts +0 -39
- package/utils/controllers/menu.ts +0 -255
- package/utils/controllers/number-field.ts +0 -103
- package/utils/controllers/otp.ts +0 -252
- package/utils/controllers/sidebar.ts +0 -610
- package/utils/controllers/slider.ts +0 -336
- package/utils/controllers/tags-input.ts +0 -255
- package/utils/controllers/toast.ts +0 -426
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import './button.css';
|
|
3
|
-
import Icon from '../../display/icon/Icon.astro';
|
|
4
|
-
import Spinner from '../../feedback/spinner/Spinner.astro';
|
|
5
|
-
import type { IconName } from '../../../icons/index.js';
|
|
6
|
-
|
|
7
|
-
interface Props {
|
|
8
|
-
/** Accessible name for the icon-only control (required — there is no visible label). */
|
|
9
|
-
label: string;
|
|
10
|
-
/** Shipped icon to render. Omit and pass your own SVG via the default slot instead. */
|
|
11
|
-
name?: IconName;
|
|
12
|
-
variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
|
|
13
|
-
size?: 'sm' | 'md';
|
|
14
|
-
disabled?: boolean;
|
|
15
|
-
loading?: boolean;
|
|
16
|
-
type?: 'button' | 'submit' | 'reset';
|
|
17
|
-
href?: string;
|
|
18
|
-
/** Anchor target, only applied when `href` is set (renders an <a>). */
|
|
19
|
-
target?: string;
|
|
20
|
-
/** Anchor rel; defaults to a safe value for `target="_blank"`. */
|
|
21
|
-
rel?: string;
|
|
22
|
-
id?: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const {
|
|
26
|
-
label,
|
|
27
|
-
name,
|
|
28
|
-
variant = 'secondary',
|
|
29
|
-
size = 'md',
|
|
30
|
-
disabled = false,
|
|
31
|
-
loading = false,
|
|
32
|
-
type = 'button',
|
|
33
|
-
href,
|
|
34
|
-
target,
|
|
35
|
-
rel,
|
|
36
|
-
id,
|
|
37
|
-
...rest
|
|
38
|
-
} = Astro.props;
|
|
39
|
-
|
|
40
|
-
const Tag = href ? 'a' : 'button';
|
|
41
|
-
const isInert = disabled || loading;
|
|
42
|
-
const iconSize = size === 'sm' ? 'sm' : 'md';
|
|
43
|
-
const hasSlot = Astro.slots.has('default');
|
|
44
|
-
const resolvedRel = href
|
|
45
|
-
? (rel ?? (target === '_blank' ? 'noopener noreferrer' : undefined))
|
|
46
|
-
: undefined;
|
|
47
|
-
|
|
48
|
-
// the slot wins over the `name`; flag the redundant combination in dev
|
|
49
|
-
if (import.meta.env.DEV && name && hasSlot) {
|
|
50
|
-
console.warn(
|
|
51
|
-
'[pienter-ui] IconButton received both a `name` and slot content; the slot is used and `name` is ignored.',
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
---
|
|
55
|
-
|
|
56
|
-
<Tag
|
|
57
|
-
id={id}
|
|
58
|
-
class="pui-icon-btn"
|
|
59
|
-
type={href ? undefined : type}
|
|
60
|
-
href={href}
|
|
61
|
-
target={href ? target : undefined}
|
|
62
|
-
rel={resolvedRel}
|
|
63
|
-
disabled={href ? undefined : isInert}
|
|
64
|
-
aria-disabled={href && isInert ? 'true' : undefined}
|
|
65
|
-
tabindex={href && isInert ? '-1' : undefined}
|
|
66
|
-
aria-busy={loading ? 'true' : undefined}
|
|
67
|
-
aria-label={label}
|
|
68
|
-
data-variant={variant}
|
|
69
|
-
data-size={size}
|
|
70
|
-
data-state={loading ? 'loading' : undefined}
|
|
71
|
-
{...rest}
|
|
72
|
-
>
|
|
73
|
-
{
|
|
74
|
-
loading ? (
|
|
75
|
-
<span class="pui-btn__spinner" aria-hidden="true">
|
|
76
|
-
<Spinner />
|
|
77
|
-
</span>
|
|
78
|
-
) : hasSlot ? (
|
|
79
|
-
<Icon size={iconSize}>
|
|
80
|
-
<slot />
|
|
81
|
-
</Icon>
|
|
82
|
-
) : (
|
|
83
|
-
<Icon name={name} size={iconSize} />
|
|
84
|
-
)
|
|
85
|
-
}
|
|
86
|
-
</Tag>
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import './avatar.css';
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
size?: 'sm' | 'lg';
|
|
6
|
-
tone?: 'brand' | 'solid';
|
|
7
|
-
src?: string;
|
|
8
|
-
alt?: string;
|
|
9
|
-
initials?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const { size, tone, src, alt = '', initials, ...rest } = Astro.props;
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
<span class="pui-avatar" data-size={size} data-tone={tone} {...rest}>
|
|
16
|
-
{src ? <img src={src} alt={alt} /> : initials ? initials : <slot />}
|
|
17
|
-
</span>
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import './badge.css';
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
tone?: 'brand' | 'success' | 'warning' | 'danger' | 'solid';
|
|
6
|
-
dot?: boolean;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const { tone, dot = false, ...rest } = Astro.props;
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
<span class="pui-badge" data-tone={tone} {...rest}>
|
|
13
|
-
{dot && <span class="pui-badge__dot" />}
|
|
14
|
-
<slot />
|
|
15
|
-
</span>
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import './icon.css';
|
|
3
|
-
import { icons, type IconName } from '../../../icons/index.js';
|
|
4
|
-
|
|
5
|
-
interface Props {
|
|
6
|
-
/** Shipped icon to render. Omit and pass a custom <svg> via the default slot. */
|
|
7
|
-
name?: IconName;
|
|
8
|
-
size?: 'sm' | 'md' | 'lg';
|
|
9
|
-
/** Continuous animation applied to the glyph (e.g. a loading spinner). */
|
|
10
|
-
animation?: 'spin';
|
|
11
|
-
label?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const { name, size = 'md', animation, label, ...rest } = Astro.props;
|
|
15
|
-
const hasSlot = Astro.slots.has('default');
|
|
16
|
-
|
|
17
|
-
// slot wins over name; flag the redundant combination in development
|
|
18
|
-
if (import.meta.env.DEV && name && hasSlot) {
|
|
19
|
-
console.warn(
|
|
20
|
-
'[pienter-ui] Icon received both a `name` and slot content; the slot is used and `name` is ignored.',
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const svg = name ? icons[name] : '';
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
{
|
|
28
|
-
hasSlot ? (
|
|
29
|
-
<span
|
|
30
|
-
class="pui-icon"
|
|
31
|
-
data-size={size}
|
|
32
|
-
data-animation={animation}
|
|
33
|
-
aria-hidden={!label}
|
|
34
|
-
aria-label={label}
|
|
35
|
-
role={label ? 'img' : undefined}
|
|
36
|
-
{...rest}
|
|
37
|
-
>
|
|
38
|
-
<slot />
|
|
39
|
-
</span>
|
|
40
|
-
) : (
|
|
41
|
-
<span
|
|
42
|
-
class="pui-icon"
|
|
43
|
-
data-size={size}
|
|
44
|
-
data-animation={animation}
|
|
45
|
-
aria-hidden={!label}
|
|
46
|
-
aria-label={label}
|
|
47
|
-
role={label ? 'img' : undefined}
|
|
48
|
-
{...rest}
|
|
49
|
-
set:html={svg}
|
|
50
|
-
/>
|
|
51
|
-
)
|
|
52
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import './alert.css';
|
|
3
|
-
import Icon from '../../display/icon/Icon.astro';
|
|
4
|
-
import type { IconName } from '../../../icons/index.js';
|
|
5
|
-
|
|
6
|
-
type Tone = 'brand' | 'success' | 'warning' | 'danger';
|
|
7
|
-
|
|
8
|
-
interface Props {
|
|
9
|
-
tone?: Tone;
|
|
10
|
-
title?: string;
|
|
11
|
-
/** Override the tone's default icon with a shipped one. Use the `icon` slot for a custom <svg>. */
|
|
12
|
-
icon?: IconName;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const toneIconMap: Record<Tone, IconName> = {
|
|
16
|
-
brand: 'info',
|
|
17
|
-
success: 'circle-check',
|
|
18
|
-
warning: 'alert-triangle',
|
|
19
|
-
danger: 'circle-alert',
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const { tone, title, icon, ...rest } = Astro.props;
|
|
23
|
-
const resolvedIcon: IconName = icon ?? (tone ? toneIconMap[tone] : 'info');
|
|
24
|
-
const hasIconSlot = Astro.slots.has('icon');
|
|
25
|
-
|
|
26
|
-
// the icon slot wins over the `icon` name; flag the redundant combination in dev
|
|
27
|
-
if (import.meta.env.DEV && icon && hasIconSlot) {
|
|
28
|
-
console.warn(
|
|
29
|
-
'[pienter-ui] Alert received both an `icon` name and an `icon` slot; the slot is used and `icon` is ignored.',
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
<div class="pui-alert" data-tone={tone} role="alert" {...rest}>
|
|
35
|
-
<span class="pui-alert__icon">
|
|
36
|
-
{
|
|
37
|
-
hasIconSlot ? (
|
|
38
|
-
<Icon size="md">
|
|
39
|
-
<slot name="icon" />
|
|
40
|
-
</Icon>
|
|
41
|
-
) : (
|
|
42
|
-
<Icon name={resolvedIcon} size="md" />
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
</span>
|
|
46
|
-
<div class="pui-alert__content">
|
|
47
|
-
{title && <p class="pui-alert__title">{title}</p>}
|
|
48
|
-
<div class="pui-alert__body">
|
|
49
|
-
<slot />
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import './progress.css';
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
/**
|
|
6
|
-
* Current value of the progress bar. When `null` or `undefined`, the
|
|
7
|
-
* component renders the indeterminate ("loading") state per WAI-ARIA
|
|
8
|
-
* convention — `aria-valuenow` is OMITTED from the wrapper so assistive
|
|
9
|
-
* technology announces an indeterminate progressbar.
|
|
10
|
-
*/
|
|
11
|
-
value?: number | null;
|
|
12
|
-
/** Maximum value of the range. */
|
|
13
|
-
max?: number;
|
|
14
|
-
/** Minimum value of the range. */
|
|
15
|
-
min?: number;
|
|
16
|
-
/**
|
|
17
|
-
* Accessible name for the progressbar — emitted as `aria-label`. Omit
|
|
18
|
-
* when an external `aria-labelledby` is supplied via `...rest`.
|
|
19
|
-
*/
|
|
20
|
-
label?: string;
|
|
21
|
-
/** Tone variant — drives indicator color via `data-tone`. */
|
|
22
|
-
tone?: 'brand' | 'success' | 'warning' | 'danger';
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const {
|
|
26
|
-
value = null,
|
|
27
|
-
max = 100,
|
|
28
|
-
min = 0,
|
|
29
|
-
label,
|
|
30
|
-
tone = 'brand',
|
|
31
|
-
...rest
|
|
32
|
-
} = Astro.props;
|
|
33
|
-
|
|
34
|
-
const isIndeterminate = value === null || value === undefined;
|
|
35
|
-
|
|
36
|
-
const clampedValue = isIndeterminate
|
|
37
|
-
? min
|
|
38
|
-
: Math.min(Math.max(value as number, min), max);
|
|
39
|
-
|
|
40
|
-
const span = max - min;
|
|
41
|
-
const percent =
|
|
42
|
-
isIndeterminate || span <= 0 ? 0 : ((clampedValue - min) / span) * 100;
|
|
43
|
-
|
|
44
|
-
const state: 'loading' | 'in-progress' | 'complete' = isIndeterminate
|
|
45
|
-
? 'loading'
|
|
46
|
-
: clampedValue === max
|
|
47
|
-
? 'complete'
|
|
48
|
-
: 'in-progress';
|
|
49
|
-
|
|
50
|
-
const indicatorStyle: Record<string, string> = {};
|
|
51
|
-
if (!isIndeterminate) {
|
|
52
|
-
indicatorStyle.width = `${percent}%`;
|
|
53
|
-
}
|
|
54
|
-
---
|
|
55
|
-
|
|
56
|
-
<div
|
|
57
|
-
class="pui-progress"
|
|
58
|
-
role="progressbar"
|
|
59
|
-
aria-valuenow={isIndeterminate ? undefined : clampedValue}
|
|
60
|
-
aria-valuemin={min}
|
|
61
|
-
aria-valuemax={max}
|
|
62
|
-
aria-label={label}
|
|
63
|
-
data-state={state}
|
|
64
|
-
data-tone={tone}
|
|
65
|
-
{...rest}
|
|
66
|
-
>
|
|
67
|
-
<div class="pui-progress__indicator" style={indicatorStyle}></div>
|
|
68
|
-
</div>
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import './skeleton.css';
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
variant?: 'text' | 'rect' | 'circle';
|
|
6
|
-
width?: string;
|
|
7
|
-
height?: string;
|
|
8
|
-
rounded?: boolean;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const {
|
|
12
|
-
variant = 'rect',
|
|
13
|
-
width,
|
|
14
|
-
height,
|
|
15
|
-
rounded = false,
|
|
16
|
-
...rest
|
|
17
|
-
} = Astro.props;
|
|
18
|
-
|
|
19
|
-
const inlineStyle: Record<string, string> = {};
|
|
20
|
-
if (width) inlineStyle.width = width;
|
|
21
|
-
if (height) inlineStyle.height = height;
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
<div
|
|
25
|
-
class="pui-skeleton"
|
|
26
|
-
data-variant={variant}
|
|
27
|
-
data-rounded={rounded ? '' : undefined}
|
|
28
|
-
style={inlineStyle}
|
|
29
|
-
aria-hidden="true"
|
|
30
|
-
{...rest}
|
|
31
|
-
>
|
|
32
|
-
</div>
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// Spinner (Astro) — same contract as Spinner.vue; composes Icon so the spin stays in icon.css.
|
|
3
|
-
import './spinner.css';
|
|
4
|
-
import Icon from '../../display/icon/Icon.astro';
|
|
5
|
-
|
|
6
|
-
interface Props {
|
|
7
|
-
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
8
|
-
/** Accessible name; supply it when the spinner is the only signal. See Spinner.vue. */
|
|
9
|
-
label?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const { size = 'md', label, ...rest } = Astro.props;
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
<span
|
|
16
|
-
class="pui-spinner"
|
|
17
|
-
data-size={size}
|
|
18
|
-
role={label ? 'status' : undefined}
|
|
19
|
-
aria-hidden={label ? undefined : 'true'}
|
|
20
|
-
{...rest}
|
|
21
|
-
>
|
|
22
|
-
<Icon name="loader" animation="spin" />
|
|
23
|
-
{/* Real text, not an aria-label — see Spinner.vue. */}
|
|
24
|
-
{label && <span class="pui-spinner__label">{label}</span>}
|
|
25
|
-
</span>
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import './toast.css';
|
|
3
|
-
import Icon from '../../display/icon/Icon.astro';
|
|
4
|
-
import type { IconName } from '../../../icons/index.js';
|
|
5
|
-
|
|
6
|
-
type Tone = 'brand' | 'success' | 'warning' | 'danger';
|
|
7
|
-
|
|
8
|
-
interface Props {
|
|
9
|
-
tone?: Tone;
|
|
10
|
-
title: string;
|
|
11
|
-
message?: string;
|
|
12
|
-
dismissible?: boolean;
|
|
13
|
-
icon?: IconName;
|
|
14
|
-
action?: { label: string };
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const toneIconMap: Record<Tone, IconName> = {
|
|
18
|
-
brand: 'info',
|
|
19
|
-
success: 'circle-check',
|
|
20
|
-
warning: 'alert-triangle',
|
|
21
|
-
danger: 'circle-alert',
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const { tone, title, message, dismissible = true, icon, action } = Astro.props;
|
|
25
|
-
const resolvedIcon: IconName = icon ?? (tone ? toneIconMap[tone] : 'info');
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
<div class="pui-toast" data-tone={tone}>
|
|
29
|
-
<span class="pui-toast__icon" aria-hidden="true">
|
|
30
|
-
<Icon name={resolvedIcon} size="sm" />
|
|
31
|
-
</span>
|
|
32
|
-
<div class="pui-toast__body">
|
|
33
|
-
<p class="pui-toast__title">{title}</p>
|
|
34
|
-
{message && <p class="pui-toast__msg">{message}</p>}
|
|
35
|
-
</div>
|
|
36
|
-
{
|
|
37
|
-
action && (
|
|
38
|
-
<button class="pui-toast__action" type="button">
|
|
39
|
-
{action.label}
|
|
40
|
-
</button>
|
|
41
|
-
)
|
|
42
|
-
}
|
|
43
|
-
{
|
|
44
|
-
dismissible && (
|
|
45
|
-
<button class="pui-toast__close" type="button" aria-label="Close">
|
|
46
|
-
<Icon name="x" size="sm" />
|
|
47
|
-
</button>
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
</div>
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import './checkbox.css';
|
|
3
|
-
import { generateId } from '../../../utils/a11y/id.js';
|
|
4
|
-
|
|
5
|
-
interface Props {
|
|
6
|
-
id?: string;
|
|
7
|
-
label: string;
|
|
8
|
-
name?: string;
|
|
9
|
-
checked?: boolean;
|
|
10
|
-
required?: boolean;
|
|
11
|
-
disabled?: boolean;
|
|
12
|
-
hint?: string;
|
|
13
|
-
errors?: string[];
|
|
14
|
-
status?: 'error' | 'success';
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const {
|
|
18
|
-
id,
|
|
19
|
-
label,
|
|
20
|
-
name,
|
|
21
|
-
checked = false,
|
|
22
|
-
required = false,
|
|
23
|
-
disabled = false,
|
|
24
|
-
hint,
|
|
25
|
-
errors = [],
|
|
26
|
-
status,
|
|
27
|
-
...rest
|
|
28
|
-
} = Astro.props;
|
|
29
|
-
|
|
30
|
-
const inputId = id ?? generateId('checkbox');
|
|
31
|
-
const hintId = `${inputId}-hint`;
|
|
32
|
-
const errorsId = `${inputId}-errors`;
|
|
33
|
-
|
|
34
|
-
const hasErrors = errors.length > 0;
|
|
35
|
-
const computedStatus = status ?? (hasErrors ? 'error' : undefined);
|
|
36
|
-
|
|
37
|
-
const describedByIds: string[] = [];
|
|
38
|
-
if (hint) describedByIds.push(hintId);
|
|
39
|
-
if (hasErrors) describedByIds.push(errorsId);
|
|
40
|
-
const describedBy =
|
|
41
|
-
describedByIds.length > 0 ? describedByIds.join(' ') : undefined;
|
|
42
|
-
|
|
43
|
-
const ariaChecked = checked ? 'true' : 'false';
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
<div class="pui-field" data-layout="inline" data-status={computedStatus}>
|
|
47
|
-
<input
|
|
48
|
-
class="pui-checkbox"
|
|
49
|
-
type="checkbox"
|
|
50
|
-
id={inputId}
|
|
51
|
-
name={name}
|
|
52
|
-
checked={checked}
|
|
53
|
-
required={required}
|
|
54
|
-
disabled={disabled}
|
|
55
|
-
aria-checked={ariaChecked}
|
|
56
|
-
aria-invalid={hasErrors ? 'true' : undefined}
|
|
57
|
-
aria-describedby={describedBy}
|
|
58
|
-
{...rest}
|
|
59
|
-
/>
|
|
60
|
-
<label class="pui-field__label" for={inputId}>
|
|
61
|
-
{label}
|
|
62
|
-
</label>
|
|
63
|
-
{
|
|
64
|
-
hint && (
|
|
65
|
-
<p id={hintId} class="pui-field__hint">
|
|
66
|
-
{hint}
|
|
67
|
-
</p>
|
|
68
|
-
)
|
|
69
|
-
}
|
|
70
|
-
{
|
|
71
|
-
hasErrors && (
|
|
72
|
-
<ul id={errorsId} class="pui-field__hint" role="alert">
|
|
73
|
-
{errors.map((error) => (
|
|
74
|
-
<li>{error}</li>
|
|
75
|
-
))}
|
|
76
|
-
</ul>
|
|
77
|
-
)
|
|
78
|
-
}
|
|
79
|
-
</div>
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import './date-input.css';
|
|
3
|
-
import { generateId } from '../../../utils/a11y/id.js';
|
|
4
|
-
|
|
5
|
-
interface Props {
|
|
6
|
-
id?: string;
|
|
7
|
-
label: string;
|
|
8
|
-
name?: string;
|
|
9
|
-
/**
|
|
10
|
-
* Native input type. `month` and `week` are intentionally out of
|
|
11
|
-
* scope for v1 because their browser support is uneven (notably
|
|
12
|
-
* Safari) — see CONVENTIONS DateInput audit entry.
|
|
13
|
-
*/
|
|
14
|
-
type?: 'date' | 'time' | 'datetime-local';
|
|
15
|
-
/**
|
|
16
|
-
* Current ISO-formatted value. The exact shape depends on `type`:
|
|
17
|
-
* - `date` → `YYYY-MM-DD`
|
|
18
|
-
* - `time` → `HH:MM` (or `HH:MM:SS` when `step` enables seconds)
|
|
19
|
-
* - `datetime-local` → `YYYY-MM-DDTHH:MM`
|
|
20
|
-
*/
|
|
21
|
-
value?: string;
|
|
22
|
-
/** Lower bound, in the same ISO shape as `value`. Forwarded to native `min`. */
|
|
23
|
-
min?: string;
|
|
24
|
-
/** Upper bound, in the same ISO shape as `value`. Forwarded to native `max`. */
|
|
25
|
-
max?: string;
|
|
26
|
-
/**
|
|
27
|
-
* Native step granularity. Useful for `type="time"`:
|
|
28
|
-
* `step="60"` (default) gives minute precision; `step="1"`
|
|
29
|
-
* exposes seconds in the picker.
|
|
30
|
-
*/
|
|
31
|
-
step?: number | string;
|
|
32
|
-
required?: boolean;
|
|
33
|
-
disabled?: boolean;
|
|
34
|
-
hint?: string;
|
|
35
|
-
errors?: string[];
|
|
36
|
-
status?: 'error' | 'success';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const {
|
|
40
|
-
id,
|
|
41
|
-
label,
|
|
42
|
-
name,
|
|
43
|
-
type = 'date',
|
|
44
|
-
value = '',
|
|
45
|
-
min,
|
|
46
|
-
max,
|
|
47
|
-
step,
|
|
48
|
-
required = false,
|
|
49
|
-
disabled = false,
|
|
50
|
-
hint,
|
|
51
|
-
errors = [],
|
|
52
|
-
status,
|
|
53
|
-
...rest
|
|
54
|
-
} = Astro.props;
|
|
55
|
-
|
|
56
|
-
const inputId = id ?? generateId('input');
|
|
57
|
-
const hintId = `${inputId}-hint`;
|
|
58
|
-
const errorsId = `${inputId}-errors`;
|
|
59
|
-
|
|
60
|
-
const hasErrors = errors.length > 0;
|
|
61
|
-
const computedStatus = status ?? (hasErrors ? 'error' : undefined);
|
|
62
|
-
|
|
63
|
-
const describedByIds: string[] = [];
|
|
64
|
-
if (hint) describedByIds.push(hintId);
|
|
65
|
-
if (hasErrors) describedByIds.push(errorsId);
|
|
66
|
-
const describedBy =
|
|
67
|
-
describedByIds.length > 0 ? describedByIds.join(' ') : undefined;
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
<div class="pui-field" data-status={computedStatus}>
|
|
71
|
-
<label class="pui-field__label" for={inputId}>
|
|
72
|
-
{label}
|
|
73
|
-
</label>
|
|
74
|
-
<input
|
|
75
|
-
class="pui-input"
|
|
76
|
-
id={inputId}
|
|
77
|
-
type={type}
|
|
78
|
-
name={name}
|
|
79
|
-
value={value}
|
|
80
|
-
min={min}
|
|
81
|
-
max={max}
|
|
82
|
-
step={step}
|
|
83
|
-
required={required}
|
|
84
|
-
disabled={disabled}
|
|
85
|
-
aria-invalid={hasErrors ? 'true' : undefined}
|
|
86
|
-
aria-describedby={describedBy}
|
|
87
|
-
{...rest}
|
|
88
|
-
/>
|
|
89
|
-
{
|
|
90
|
-
hint && (
|
|
91
|
-
<p id={hintId} class="pui-field__hint">
|
|
92
|
-
{hint}
|
|
93
|
-
</p>
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
{
|
|
97
|
-
hasErrors && (
|
|
98
|
-
<ul id={errorsId} class="pui-field__hint" role="alert">
|
|
99
|
-
{errors.map((error) => (
|
|
100
|
-
<li>{error}</li>
|
|
101
|
-
))}
|
|
102
|
-
</ul>
|
|
103
|
-
)
|
|
104
|
-
}
|
|
105
|
-
</div>
|