@nqmcreative/ui 0.1.1 → 0.2.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/README.md +89 -34
- package/cli/index.mjs +83 -33
- package/dist/core/calendar.d.ts +3 -0
- package/dist/core/calendar.js +36 -0
- package/dist/core/dialog.svelte.d.ts +14 -0
- package/dist/core/dialog.svelte.js +23 -0
- package/dist/core/files.d.ts +35 -0
- package/dist/core/files.js +62 -0
- package/dist/core/index.d.ts +37 -0
- package/dist/core/index.js +35 -0
- package/dist/core/list.svelte.d.ts +41 -0
- package/dist/core/list.svelte.js +77 -0
- package/dist/core/number.d.ts +7 -0
- package/dist/core/number.js +17 -0
- package/dist/core/pagination.d.ts +6 -0
- package/dist/core/pagination.js +21 -0
- package/dist/core/password.d.ts +8 -0
- package/dist/core/password.js +23 -0
- package/dist/core/table.d.ts +22 -0
- package/dist/core/table.js +41 -0
- package/dist/core/theme.svelte.d.ts +16 -0
- package/dist/core/theme.svelte.js +34 -0
- package/dist/core/trigger.d.ts +35 -0
- package/dist/core/trigger.js +77 -0
- package/dist/index.d.ts +11 -103
- package/dist/index.js +11 -75
- package/dist/{components → styles/matte}/AccordionItem.svelte +1 -1
- package/dist/{components → styles/matte}/AccordionItem.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Alert.svelte +8 -2
- package/dist/{components → styles/matte}/Alert.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Avatar.svelte +1 -1
- package/dist/{components → styles/matte}/Avatar.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Badge.svelte +8 -3
- package/dist/{components → styles/matte}/Badge.svelte.d.ts +1 -3
- package/dist/{components → styles/matte}/Breadcrumb.svelte +2 -2
- package/dist/{components → styles/matte}/Breadcrumb.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Button.svelte +1 -1
- package/dist/{components → styles/matte}/Button.svelte.d.ts +1 -1
- package/dist/styles/matte/CTASection.svelte +76 -0
- package/dist/styles/matte/CTASection.svelte.d.ts +18 -0
- package/dist/{components → styles/matte}/Calendar.svelte +7 -17
- package/dist/{components → styles/matte}/Calendar.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Card.svelte +1 -1
- package/dist/{components → styles/matte}/Card.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Checkbox.svelte +1 -1
- package/dist/{components → styles/matte}/Checkbox.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/CheckboxGroup.svelte +1 -1
- package/dist/{components → styles/matte}/CheckboxGroup.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Combobox.svelte +31 -42
- package/dist/{components → styles/matte}/Combobox.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/CommandPalette.svelte +26 -41
- package/dist/{components → styles/matte}/CommandPalette.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/ConfirmDialog.svelte +2 -2
- package/dist/{components → styles/matte}/ConfirmDialog.svelte.d.ts +2 -2
- package/dist/{components → styles/matte}/ContextMenu.svelte +5 -7
- package/dist/{components → styles/matte}/DatePicker.svelte +7 -11
- package/dist/{components → styles/matte}/DatePicker.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Drawer.svelte +4 -7
- package/dist/{components → styles/matte}/Dropdown.svelte +18 -36
- package/dist/{components → styles/matte}/Dropdown.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Dropzone.svelte +11 -43
- package/dist/{components → styles/matte}/Dropzone.svelte.d.ts +2 -5
- package/dist/{components → styles/matte}/EmptyState.svelte +1 -1
- package/dist/{components → styles/matte}/EmptyState.svelte.d.ts +1 -1
- package/dist/styles/matte/FeatureCard.svelte +58 -0
- package/dist/styles/matte/FeatureCard.svelte.d.ts +16 -0
- package/dist/styles/matte/FeatureGrid.svelte +62 -0
- package/dist/styles/matte/FeatureGrid.svelte.d.ts +16 -0
- package/dist/{components → styles/matte}/Footer.svelte +1 -1
- package/dist/{components → styles/matte}/Footer.svelte.d.ts +1 -1
- package/dist/styles/matte/HeroSection.svelte +80 -0
- package/dist/styles/matte/HeroSection.svelte.d.ts +21 -0
- package/dist/{components → styles/matte}/Input.svelte +1 -1
- package/dist/{components → styles/matte}/Input.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Link.svelte +1 -1
- package/dist/{components → styles/matte}/Link.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/LocaleProvider.svelte +1 -1
- package/dist/{components → styles/matte}/LocaleProvider.svelte.d.ts +1 -1
- package/dist/styles/matte/LogoCloud.svelte +61 -0
- package/dist/styles/matte/LogoCloud.svelte.d.ts +19 -0
- package/dist/{components → styles/matte}/MenuItem.svelte +1 -1
- package/dist/{components → styles/matte}/MenuItem.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Modal.svelte +4 -7
- package/dist/{components → styles/matte}/MultiSelect.svelte +18 -37
- package/dist/{components → styles/matte}/MultiSelect.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Navbar.svelte +2 -2
- package/dist/{components → styles/matte}/Navbar.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/NumberInput.svelte +4 -8
- package/dist/{components → styles/matte}/NumberInput.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Pagination.svelte +4 -15
- package/dist/{components → styles/matte}/Pagination.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/PasswordInput.svelte +4 -13
- package/dist/{components → styles/matte}/PasswordInput.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Popover.svelte +16 -41
- package/dist/{components → styles/matte}/Popover.svelte.d.ts +1 -1
- package/dist/styles/matte/PricingCard.svelte +107 -0
- package/dist/styles/matte/PricingCard.svelte.d.ts +25 -0
- package/dist/{components → styles/matte}/Progress.svelte +3 -2
- package/dist/{components → styles/matte}/Progress.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Radio.svelte +1 -1
- package/dist/{components → styles/matte}/Radio.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/RadioGroup.svelte +1 -1
- package/dist/{components → styles/matte}/RadioGroup.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/SegmentedControl.svelte +1 -1
- package/dist/{components → styles/matte}/SegmentedControl.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Select.svelte +1 -1
- package/dist/{components → styles/matte}/Select.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Sidebar.svelte +2 -2
- package/dist/{components → styles/matte}/Sidebar.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Slider.svelte +3 -2
- package/dist/{components → styles/matte}/Slider.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Spinner.svelte +2 -2
- package/dist/{components → styles/matte}/Spinner.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Stat.svelte +1 -1
- package/dist/{components → styles/matte}/Stat.svelte.d.ts +1 -1
- package/dist/styles/matte/StatsBand.svelte +57 -0
- package/dist/styles/matte/StatsBand.svelte.d.ts +20 -0
- package/dist/{components → styles/matte}/Steps.svelte +1 -1
- package/dist/{components → styles/matte}/Steps.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Switch.svelte +1 -1
- package/dist/{components → styles/matte}/Switch.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/Table.svelte +6 -28
- package/dist/{components → styles/matte}/Table.svelte.d.ts +2 -6
- package/dist/{components → styles/matte}/Tabs.svelte +8 -1
- package/dist/{components → styles/matte}/Tabs.svelte.d.ts +1 -1
- package/dist/styles/matte/Testimonial.svelte +67 -0
- package/dist/styles/matte/Testimonial.svelte.d.ts +19 -0
- package/dist/{components → styles/matte}/Textarea.svelte +1 -1
- package/dist/{components → styles/matte}/Textarea.svelte.d.ts +1 -1
- package/dist/{components → styles/matte}/ThemeToggle.svelte +14 -27
- package/dist/{components → styles/matte}/ThemeToggle.svelte.d.ts +2 -6
- package/dist/{components → styles/matte}/Toaster.svelte +4 -4
- package/dist/styles/matte/index.d.ts +109 -0
- package/dist/styles/matte/index.js +83 -0
- package/dist/styles/paper/Accordion.svelte +17 -0
- package/dist/styles/paper/Accordion.svelte.d.ts +8 -0
- package/dist/styles/paper/AccordionItem.svelte +46 -0
- package/dist/styles/paper/AccordionItem.svelte.d.ts +14 -0
- package/dist/styles/paper/Alert.svelte +99 -0
- package/dist/styles/paper/Alert.svelte.d.ts +18 -0
- package/dist/styles/paper/Avatar.svelte +60 -0
- package/dist/styles/paper/Avatar.svelte.d.ts +16 -0
- package/dist/styles/paper/AvatarGroup.svelte +17 -0
- package/dist/styles/paper/AvatarGroup.svelte.d.ts +8 -0
- package/dist/styles/paper/Badge.svelte +58 -0
- package/dist/styles/paper/Badge.svelte.d.ts +16 -0
- package/dist/styles/paper/Breadcrumb.svelte +49 -0
- package/dist/styles/paper/Breadcrumb.svelte.d.ts +14 -0
- package/dist/styles/paper/Button.svelte +96 -0
- package/dist/styles/paper/Button.svelte.d.ts +21 -0
- package/dist/styles/paper/CTASection.svelte +76 -0
- package/dist/styles/paper/CTASection.svelte.d.ts +18 -0
- package/dist/styles/paper/Calendar.svelte +202 -0
- package/dist/styles/paper/Calendar.svelte.d.ts +22 -0
- package/dist/styles/paper/Card.svelte +78 -0
- package/dist/styles/paper/Card.svelte.d.ts +21 -0
- package/dist/styles/paper/Checkbox.svelte +75 -0
- package/dist/styles/paper/Checkbox.svelte.d.ts +15 -0
- package/dist/styles/paper/CheckboxGroup.svelte +111 -0
- package/dist/styles/paper/CheckboxGroup.svelte.d.ts +30 -0
- package/dist/styles/paper/Combobox.svelte +266 -0
- package/dist/styles/paper/Combobox.svelte.d.ts +29 -0
- package/dist/styles/paper/CommandPalette.svelte +209 -0
- package/dist/styles/paper/CommandPalette.svelte.d.ts +32 -0
- package/dist/styles/paper/ConfirmDialog.svelte +97 -0
- package/dist/styles/paper/ConfirmDialog.svelte.d.ts +22 -0
- package/dist/styles/paper/ContextMenu.svelte +88 -0
- package/dist/styles/paper/ContextMenu.svelte.d.ts +15 -0
- package/dist/styles/paper/DatePicker.svelte +192 -0
- package/dist/styles/paper/DatePicker.svelte.d.ts +23 -0
- package/dist/styles/paper/Divider.svelte +30 -0
- package/dist/styles/paper/Divider.svelte.d.ts +10 -0
- package/dist/styles/paper/Drawer.svelte +165 -0
- package/dist/styles/paper/Drawer.svelte.d.ts +20 -0
- package/dist/styles/paper/Dropdown.svelte +94 -0
- package/dist/styles/paper/Dropdown.svelte.d.ts +23 -0
- package/dist/styles/paper/Dropzone.svelte +210 -0
- package/dist/styles/paper/Dropzone.svelte.d.ts +29 -0
- package/dist/styles/paper/EmptyState.svelte +71 -0
- package/dist/styles/paper/EmptyState.svelte.d.ts +18 -0
- package/dist/styles/paper/FeatureCard.svelte +58 -0
- package/dist/styles/paper/FeatureCard.svelte.d.ts +16 -0
- package/dist/styles/paper/FeatureGrid.svelte +62 -0
- package/dist/styles/paper/FeatureGrid.svelte.d.ts +16 -0
- package/dist/styles/paper/Field.svelte +42 -0
- package/dist/styles/paper/Field.svelte.d.ts +16 -0
- package/dist/styles/paper/Footer.svelte +91 -0
- package/dist/styles/paper/Footer.svelte.d.ts +25 -0
- package/dist/styles/paper/HeroSection.svelte +86 -0
- package/dist/styles/paper/HeroSection.svelte.d.ts +21 -0
- package/dist/styles/paper/Input.svelte +60 -0
- package/dist/styles/paper/Input.svelte.d.ts +18 -0
- package/dist/styles/paper/InputGroup.svelte +20 -0
- package/dist/styles/paper/InputGroup.svelte.d.ts +11 -0
- package/dist/styles/paper/Kbd.svelte +17 -0
- package/dist/styles/paper/Kbd.svelte.d.ts +8 -0
- package/dist/styles/paper/Label.svelte +16 -0
- package/dist/styles/paper/Label.svelte.d.ts +9 -0
- package/dist/styles/paper/Link.svelte +44 -0
- package/dist/styles/paper/Link.svelte.d.ts +16 -0
- package/dist/styles/paper/LocaleProvider.svelte +24 -0
- package/dist/styles/paper/LocaleProvider.svelte.d.ts +10 -0
- package/dist/styles/paper/LogoCloud.svelte +61 -0
- package/dist/styles/paper/LogoCloud.svelte.d.ts +19 -0
- package/dist/styles/paper/MenuItem.svelte +64 -0
- package/dist/styles/paper/MenuItem.svelte.d.ts +18 -0
- package/dist/styles/paper/MenuSeparator.svelte +22 -0
- package/dist/styles/paper/MenuSeparator.svelte.d.ts +8 -0
- package/dist/styles/paper/Modal.svelte +118 -0
- package/dist/styles/paper/Modal.svelte.d.ts +21 -0
- package/dist/styles/paper/MultiSelect.svelte +287 -0
- package/dist/styles/paper/MultiSelect.svelte.d.ts +31 -0
- package/dist/styles/paper/Navbar.svelte +201 -0
- package/dist/styles/paper/Navbar.svelte.d.ts +33 -0
- package/dist/styles/paper/NumberInput.svelte +96 -0
- package/dist/styles/paper/NumberInput.svelte.d.ts +15 -0
- package/dist/styles/paper/Pagination.svelte +83 -0
- package/dist/styles/paper/Pagination.svelte.d.ts +15 -0
- package/dist/styles/paper/PasswordInput.svelte +100 -0
- package/dist/styles/paper/PasswordInput.svelte.d.ts +12 -0
- package/dist/styles/paper/Popover.svelte +89 -0
- package/dist/styles/paper/Popover.svelte.d.ts +19 -0
- package/dist/styles/paper/PricingCard.svelte +108 -0
- package/dist/styles/paper/PricingCard.svelte.d.ts +25 -0
- package/dist/styles/paper/Progress.svelte +59 -0
- package/dist/styles/paper/Progress.svelte.d.ts +17 -0
- package/dist/styles/paper/Radio.svelte +55 -0
- package/dist/styles/paper/Radio.svelte.d.ts +15 -0
- package/dist/styles/paper/RadioGroup.svelte +95 -0
- package/dist/styles/paper/RadioGroup.svelte.d.ts +27 -0
- package/dist/styles/paper/SegmentedControl.svelte +88 -0
- package/dist/styles/paper/SegmentedControl.svelte.d.ts +25 -0
- package/dist/styles/paper/Select.svelte +61 -0
- package/dist/styles/paper/Select.svelte.d.ts +20 -0
- package/dist/styles/paper/Sidebar.svelte +206 -0
- package/dist/styles/paper/Sidebar.svelte.d.ts +36 -0
- package/dist/styles/paper/Skeleton.svelte +46 -0
- package/dist/styles/paper/Skeleton.svelte.d.ts +13 -0
- package/dist/styles/paper/Slider.svelte +80 -0
- package/dist/styles/paper/Slider.svelte.d.ts +19 -0
- package/dist/styles/paper/Spinner.svelte +34 -0
- package/dist/styles/paper/Spinner.svelte.d.ts +13 -0
- package/dist/styles/paper/Stat.svelte +51 -0
- package/dist/styles/paper/Stat.svelte.d.ts +16 -0
- package/dist/styles/paper/StatsBand.svelte +63 -0
- package/dist/styles/paper/StatsBand.svelte.d.ts +20 -0
- package/dist/styles/paper/Steps.svelte +141 -0
- package/dist/styles/paper/Steps.svelte.d.ts +24 -0
- package/dist/styles/paper/Switch.svelte +64 -0
- package/dist/styles/paper/Switch.svelte.d.ts +14 -0
- package/dist/styles/paper/Table.svelte +217 -0
- package/dist/styles/paper/Table.svelte.d.ts +66 -0
- package/dist/styles/paper/Tabs.svelte +102 -0
- package/dist/styles/paper/Tabs.svelte.d.ts +23 -0
- package/dist/styles/paper/Testimonial.svelte +64 -0
- package/dist/styles/paper/Testimonial.svelte.d.ts +19 -0
- package/dist/styles/paper/Textarea.svelte +54 -0
- package/dist/styles/paper/Textarea.svelte.d.ts +12 -0
- package/dist/styles/paper/ThemeToggle.svelte +130 -0
- package/dist/styles/paper/ThemeToggle.svelte.d.ts +16 -0
- package/dist/styles/paper/Toaster.svelte +132 -0
- package/dist/styles/paper/Toaster.svelte.d.ts +8 -0
- package/dist/styles/paper/Tooltip.svelte +33 -0
- package/dist/styles/paper/Tooltip.svelte.d.ts +12 -0
- package/dist/styles/paper/fonts.css +46 -0
- package/dist/styles/paper/index.d.ts +109 -0
- package/dist/styles/paper/index.js +83 -0
- package/dist/styles/paper/theme.css +222 -0
- package/package.json +531 -201
- package/registry.json +658 -339
- /package/dist/{actions → core/actions}/anchor.d.ts +0 -0
- /package/dist/{actions → core/actions}/anchor.js +0 -0
- /package/dist/{actions → core/actions}/dismissable.d.ts +0 -0
- /package/dist/{actions → core/actions}/dismissable.js +0 -0
- /package/dist/{date.d.ts → core/date.d.ts} +0 -0
- /package/dist/{date.js → core/date.js} +0 -0
- /package/dist/{locale.svelte.d.ts → core/locale.svelte.d.ts} +0 -0
- /package/dist/{locale.svelte.js → core/locale.svelte.js} +0 -0
- /package/dist/{toast.svelte.d.ts → core/toast.svelte.d.ts} +0 -0
- /package/dist/{toast.svelte.js → core/toast.svelte.js} +0 -0
- /package/dist/{tones.d.ts → core/tones.d.ts} +0 -0
- /package/dist/{tones.js → core/tones.js} +0 -0
- /package/dist/{components → styles/matte}/Accordion.svelte +0 -0
- /package/dist/{components → styles/matte}/Accordion.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/AvatarGroup.svelte +0 -0
- /package/dist/{components → styles/matte}/AvatarGroup.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/ContextMenu.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Divider.svelte +0 -0
- /package/dist/{components → styles/matte}/Divider.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Drawer.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Field.svelte +0 -0
- /package/dist/{components → styles/matte}/Field.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/InputGroup.svelte +0 -0
- /package/dist/{components → styles/matte}/InputGroup.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Kbd.svelte +0 -0
- /package/dist/{components → styles/matte}/Kbd.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Label.svelte +0 -0
- /package/dist/{components → styles/matte}/Label.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/MenuSeparator.svelte +0 -0
- /package/dist/{components → styles/matte}/MenuSeparator.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Modal.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Skeleton.svelte +0 -0
- /package/dist/{components → styles/matte}/Skeleton.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Toaster.svelte.d.ts +0 -0
- /package/dist/{components → styles/matte}/Tooltip.svelte +0 -0
- /package/dist/{components → styles/matte}/Tooltip.svelte.d.ts +0 -0
- /package/dist/{fonts.css → styles/matte/fonts.css} +0 -0
- /package/dist/{theme.css → styles/matte/theme.css} +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import { toneText, type Tone } from '../../core/tones.js';
|
|
5
|
+
|
|
6
|
+
interface Props extends HTMLAttributes<HTMLElement> {
|
|
7
|
+
/** Small line above the headline. */
|
|
8
|
+
eyebrow?: string;
|
|
9
|
+
title: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
tone?: Tone;
|
|
12
|
+
/** `center` also centres the actions. Ignored when `media` is set. */
|
|
13
|
+
align?: 'left' | 'center';
|
|
14
|
+
/** Buttons under the copy. */
|
|
15
|
+
actions?: Snippet;
|
|
16
|
+
/** Anything on the right — a screenshot, an illustration, a form. */
|
|
17
|
+
media?: Snippet;
|
|
18
|
+
/** Extra content between the description and the actions. */
|
|
19
|
+
children?: Snippet;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let {
|
|
23
|
+
eyebrow,
|
|
24
|
+
title,
|
|
25
|
+
description,
|
|
26
|
+
tone = 'brand',
|
|
27
|
+
align = 'left',
|
|
28
|
+
actions,
|
|
29
|
+
media,
|
|
30
|
+
class: className = '',
|
|
31
|
+
children,
|
|
32
|
+
...rest
|
|
33
|
+
}: Props = $props();
|
|
34
|
+
|
|
35
|
+
// A media column only makes sense next to left-aligned copy.
|
|
36
|
+
const centred = $derived(align === 'center' && !media);
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<section class="w-full px-6 py-20 sm:py-28 {className}" {...rest}>
|
|
40
|
+
<div
|
|
41
|
+
class="mx-auto flex w-full max-w-6xl gap-16
|
|
42
|
+
{media ? 'flex-col lg:flex-row lg:items-center' : 'flex-col'}"
|
|
43
|
+
>
|
|
44
|
+
<div
|
|
45
|
+
class="flex min-w-0 flex-1 flex-col gap-6 {centred
|
|
46
|
+
? 'items-center text-center'
|
|
47
|
+
: 'items-start'}"
|
|
48
|
+
>
|
|
49
|
+
{#if eyebrow}
|
|
50
|
+
<span class="font-mono text-xs tracking-wide uppercase {toneText[tone]}">{eyebrow}</span>
|
|
51
|
+
{/if}
|
|
52
|
+
|
|
53
|
+
<h1
|
|
54
|
+
class="max-w-2xl font-heading text-4xl leading-tight font-medium tracking-tight text-balance text-text sm:text-5xl"
|
|
55
|
+
>
|
|
56
|
+
{title}
|
|
57
|
+
</h1>
|
|
58
|
+
|
|
59
|
+
{#if description}
|
|
60
|
+
<p class="max-w-xl font-sans text-lg leading-relaxed text-pretty text-text-secondary">
|
|
61
|
+
{description}
|
|
62
|
+
</p>
|
|
63
|
+
{/if}
|
|
64
|
+
|
|
65
|
+
{#if children}
|
|
66
|
+
{@render children()}
|
|
67
|
+
{/if}
|
|
68
|
+
|
|
69
|
+
{#if actions}
|
|
70
|
+
<div class="flex flex-wrap items-center gap-3 pt-2 {centred ? 'justify-center' : ''}">
|
|
71
|
+
{@render actions()}
|
|
72
|
+
</div>
|
|
73
|
+
{/if}
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
{#if media}
|
|
77
|
+
<div class="min-w-0 flex-1">{@render media()}</div>
|
|
78
|
+
{/if}
|
|
79
|
+
</div>
|
|
80
|
+
</section>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import { type Tone } from '../../core/tones.js';
|
|
4
|
+
interface Props extends HTMLAttributes<HTMLElement> {
|
|
5
|
+
/** Small line above the headline. */
|
|
6
|
+
eyebrow?: string;
|
|
7
|
+
title: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
tone?: Tone;
|
|
10
|
+
/** `center` also centres the actions. Ignored when `media` is set. */
|
|
11
|
+
align?: 'left' | 'center';
|
|
12
|
+
/** Buttons under the copy. */
|
|
13
|
+
actions?: Snippet;
|
|
14
|
+
/** Anything on the right — a screenshot, an illustration, a form. */
|
|
15
|
+
media?: Snippet;
|
|
16
|
+
/** Extra content between the description and the actions. */
|
|
17
|
+
children?: Snippet;
|
|
18
|
+
}
|
|
19
|
+
declare const HeroSection: import("svelte").Component<Props, {}, "">;
|
|
20
|
+
type HeroSection = ReturnType<typeof HeroSection>;
|
|
21
|
+
export default HeroSection;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
4
|
-
import { toneFocusWithinBorder, type Tone } from '
|
|
4
|
+
import { toneFocusWithinBorder, type Tone } from '../../core/tones.js';
|
|
5
5
|
|
|
6
6
|
export type InputSize = 'sm' | 'md' | 'lg';
|
|
7
7
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
3
|
-
import { type Tone } from '
|
|
3
|
+
import { type Tone } from '../../core/tones.js';
|
|
4
4
|
export type InputSize = 'sm' | 'md' | 'lg';
|
|
5
5
|
interface Props extends Omit<HTMLInputAttributes, 'size' | 'prefix' | 'suffix'> {
|
|
6
6
|
value?: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAnchorAttributes } from 'svelte/elements';
|
|
4
|
-
import { focusRing, toneHoverText, toneRing, toneText, type Tone } from '
|
|
4
|
+
import { focusRing, toneHoverText, toneRing, toneText, type Tone } from '../../core/tones.js';
|
|
5
5
|
|
|
6
6
|
interface Props extends HTMLAnchorAttributes {
|
|
7
7
|
tone?: Tone;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { HTMLAnchorAttributes } from 'svelte/elements';
|
|
3
|
-
import { type Tone } from '
|
|
3
|
+
import { type Tone } from '../../core/tones.js';
|
|
4
4
|
interface Props extends HTMLAnchorAttributes {
|
|
5
5
|
tone?: Tone;
|
|
6
6
|
/** `'hover'` shows the rule only on hover. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
-
import { provideLocale, type Locale } from '
|
|
3
|
+
import { provideLocale, type Locale } from '../../core/locale.svelte.js';
|
|
4
4
|
|
|
5
5
|
interface Props {
|
|
6
6
|
/** Full locale or just the keys you want to change. */
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
|
|
5
|
+
export interface Logo {
|
|
6
|
+
name: string;
|
|
7
|
+
src?: string;
|
|
8
|
+
href?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface Props extends HTMLAttributes<HTMLElement> {
|
|
12
|
+
title?: string;
|
|
13
|
+
/** Without `src` the name is set in the heading face — fine for wordmarks. */
|
|
14
|
+
logos?: Logo[];
|
|
15
|
+
/** Dim until hovered, so the row does not compete with the headline. */
|
|
16
|
+
muted?: boolean;
|
|
17
|
+
/** Your own markup instead of `logos`. */
|
|
18
|
+
children?: Snippet;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let {
|
|
22
|
+
title,
|
|
23
|
+
logos = [],
|
|
24
|
+
muted = true,
|
|
25
|
+
class: className = '',
|
|
26
|
+
children,
|
|
27
|
+
...rest
|
|
28
|
+
}: Props = $props();
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<section class="w-full px-6 py-14 {className}" {...rest}>
|
|
32
|
+
<div class="mx-auto flex w-full max-w-6xl flex-col items-center gap-8">
|
|
33
|
+
{#if title}
|
|
34
|
+
<p class="text-center font-mono text-xs tracking-wide text-text-muted uppercase">{title}</p>
|
|
35
|
+
{/if}
|
|
36
|
+
|
|
37
|
+
<div class="flex flex-wrap items-center justify-center gap-x-12 gap-y-8">
|
|
38
|
+
{#if children}
|
|
39
|
+
{@render children()}
|
|
40
|
+
{:else}
|
|
41
|
+
{#each logos as logo (logo.name)}
|
|
42
|
+
<svelte:element
|
|
43
|
+
this={logo.href ? 'a' : 'div'}
|
|
44
|
+
href={logo.href}
|
|
45
|
+
class="flex items-center transition-all duration-200 ease-brand-out {muted
|
|
46
|
+
? 'opacity-60 grayscale hover:opacity-100 hover:grayscale-0'
|
|
47
|
+
: ''}"
|
|
48
|
+
>
|
|
49
|
+
{#if logo.src}
|
|
50
|
+
<img src={logo.src} alt={logo.name} class="h-7 w-auto object-contain" />
|
|
51
|
+
{:else}
|
|
52
|
+
<span class="font-heading text-lg font-medium tracking-tight text-text-secondary">
|
|
53
|
+
{logo.name}
|
|
54
|
+
</span>
|
|
55
|
+
{/if}
|
|
56
|
+
</svelte:element>
|
|
57
|
+
{/each}
|
|
58
|
+
{/if}
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</section>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
export interface Logo {
|
|
4
|
+
name: string;
|
|
5
|
+
src?: string;
|
|
6
|
+
href?: string;
|
|
7
|
+
}
|
|
8
|
+
interface Props extends HTMLAttributes<HTMLElement> {
|
|
9
|
+
title?: string;
|
|
10
|
+
/** Without `src` the name is set in the heading face — fine for wordmarks. */
|
|
11
|
+
logos?: Logo[];
|
|
12
|
+
/** Dim until hovered, so the row does not compete with the headline. */
|
|
13
|
+
muted?: boolean;
|
|
14
|
+
/** Your own markup instead of `logos`. */
|
|
15
|
+
children?: Snippet;
|
|
16
|
+
}
|
|
17
|
+
declare const LogoCloud: import("svelte").Component<Props, {}, "">;
|
|
18
|
+
type LogoCloud = ReturnType<typeof LogoCloud>;
|
|
19
|
+
export default LogoCloud;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
4
|
-
import { toneSoftHover, toneText, type Tone } from '
|
|
4
|
+
import { toneSoftHover, toneText, type Tone } from '../../core/tones.js';
|
|
5
5
|
|
|
6
6
|
interface Props extends HTMLButtonAttributes {
|
|
7
7
|
/** Renders an `<a>` instead of a `<button>`. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
3
|
-
import { type Tone } from '
|
|
3
|
+
import { type Tone } from '../../core/tones.js';
|
|
4
4
|
interface Props extends HTMLButtonAttributes {
|
|
5
5
|
/** Renders an `<a>` instead of a `<button>`. */
|
|
6
6
|
href?: string;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLDialogAttributes } from 'svelte/elements';
|
|
4
|
-
import { useLocale } from '
|
|
4
|
+
import { useLocale } from '../../core/locale.svelte.js';
|
|
5
|
+
import { isBackdropClick, syncDialog } from '../../core/dialog.svelte.js';
|
|
5
6
|
|
|
6
7
|
export type ModalSize = 'sm' | 'md' | 'lg';
|
|
7
8
|
|
|
@@ -46,11 +47,7 @@
|
|
|
46
47
|
lg: 'max-w-2xl'
|
|
47
48
|
};
|
|
48
49
|
|
|
49
|
-
$effect(() =>
|
|
50
|
-
if (!dialog) return;
|
|
51
|
-
if (open && !dialog.open) dialog.showModal();
|
|
52
|
-
else if (!open && dialog.open) dialog.close();
|
|
53
|
-
});
|
|
50
|
+
$effect(() => syncDialog(dialog, open));
|
|
54
51
|
|
|
55
52
|
function close() {
|
|
56
53
|
open = false;
|
|
@@ -59,7 +56,7 @@
|
|
|
59
56
|
|
|
60
57
|
function onBackdrop(event: MouseEvent) {
|
|
61
58
|
if (!dismissible) return;
|
|
62
|
-
if (event
|
|
59
|
+
if (isBackdropClick(event, dialog)) close();
|
|
63
60
|
}
|
|
64
61
|
</script>
|
|
65
62
|
|
|
@@ -9,10 +9,11 @@
|
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
11
|
<script lang="ts">
|
|
12
|
-
import { anchored } from '
|
|
13
|
-
import { clickOutside, portal } from '
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
12
|
+
import { anchored } from '../../core/actions/anchor.js';
|
|
13
|
+
import { clickOutside, portal } from '../../core/actions/dismissable.js';
|
|
14
|
+
import { ListCursor, groupItems, matchQuery, revealIndex } from '../../core/list.svelte.js';
|
|
15
|
+
import { useLocale } from '../../core/locale.svelte.js';
|
|
16
|
+
import { toneFocusWithinBorder, toneSoft, toneText, type Tone } from '../../core/tones.js';
|
|
16
17
|
|
|
17
18
|
interface Props {
|
|
18
19
|
/** Bindable — the `value` of every chosen option. */
|
|
@@ -56,7 +57,6 @@
|
|
|
56
57
|
|
|
57
58
|
let open = $state(false);
|
|
58
59
|
let query = $state('');
|
|
59
|
-
let active = $state(0);
|
|
60
60
|
let wrapper: HTMLElement | null = $state(null);
|
|
61
61
|
let inputEl: HTMLInputElement | null = $state(null);
|
|
62
62
|
let listEl: HTMLElement | null = $state(null);
|
|
@@ -67,29 +67,16 @@
|
|
|
67
67
|
const full = $derived(max > 0 && value.length >= max);
|
|
68
68
|
const collapsed = $derived(maxChips > 0 && chosen.length > maxChips);
|
|
69
69
|
|
|
70
|
-
const matches = $derived
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return options.filter(
|
|
74
|
-
(option) =>
|
|
75
|
-
option.label.toLowerCase().includes(needle) ||
|
|
76
|
-
option.description?.toLowerCase().includes(needle)
|
|
77
|
-
);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
const groups = $derived.by(() => {
|
|
81
|
-
const out: [string, MultiSelectOption[]][] = [];
|
|
82
|
-
for (const option of matches) {
|
|
83
|
-
const key = option.group ?? '';
|
|
84
|
-
const bucket = out.find(([n]) => n === key);
|
|
85
|
-
if (bucket) bucket[1].push(option);
|
|
86
|
-
else out.push([key, [option]]);
|
|
87
|
-
}
|
|
88
|
-
return out;
|
|
89
|
-
});
|
|
70
|
+
const matches = $derived(
|
|
71
|
+
matchQuery(options, query, (option) => `${option.label} ${option.description ?? ''}`)
|
|
72
|
+
);
|
|
90
73
|
|
|
74
|
+
const groups = $derived(groupItems(matches));
|
|
91
75
|
const flat = $derived(groups.flatMap(([, items]) => items));
|
|
92
76
|
|
|
77
|
+
const cursor = new ListCursor(() => flat);
|
|
78
|
+
const active = $derived(cursor.index);
|
|
79
|
+
|
|
93
80
|
function toggle(option: MultiSelectOption) {
|
|
94
81
|
const has = value.includes(option.value);
|
|
95
82
|
if (option.disabled || (!has && full)) return;
|
|
@@ -103,14 +90,8 @@
|
|
|
103
90
|
}
|
|
104
91
|
|
|
105
92
|
function move(step: number) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
for (let i = 0; i < flat.length; i++) {
|
|
109
|
-
next = (next + step + flat.length) % flat.length;
|
|
110
|
-
if (!flat[next].disabled) break;
|
|
111
|
-
}
|
|
112
|
-
active = next;
|
|
113
|
-
listEl?.querySelector(`[data-index="${next}"]`)?.scrollIntoView({ block: 'nearest' });
|
|
93
|
+
cursor.move(step);
|
|
94
|
+
revealIndex(listEl, cursor.index);
|
|
114
95
|
}
|
|
115
96
|
|
|
116
97
|
function onKeydown(event: KeyboardEvent) {
|
|
@@ -125,9 +106,9 @@
|
|
|
125
106
|
if (open) move(-1);
|
|
126
107
|
break;
|
|
127
108
|
case 'Enter':
|
|
128
|
-
if (open &&
|
|
109
|
+
if (open && cursor.current) {
|
|
129
110
|
event.preventDefault();
|
|
130
|
-
toggle(
|
|
111
|
+
toggle(cursor.current);
|
|
131
112
|
}
|
|
132
113
|
break;
|
|
133
114
|
case 'Backspace':
|
|
@@ -201,7 +182,7 @@
|
|
|
201
182
|
placeholder={chosen.length ? '' : (placeholder ?? t.current.comboboxPlaceholder)}
|
|
202
183
|
oninput={() => {
|
|
203
184
|
open = true;
|
|
204
|
-
|
|
185
|
+
cursor.index = 0;
|
|
205
186
|
}}
|
|
206
187
|
onfocus={() => (open = true)}
|
|
207
188
|
onkeydown={onKeydown}
|
|
@@ -263,7 +244,7 @@
|
|
|
263
244
|
aria-selected={checked}
|
|
264
245
|
aria-disabled={option.disabled || (full && !checked)}
|
|
265
246
|
onclick={() => toggle(option)}
|
|
266
|
-
onpointermove={() => (
|
|
247
|
+
onpointermove={() => (cursor.index = index)}
|
|
267
248
|
class="flex cursor-pointer items-start gap-2.5 px-3 py-2 text-[14px] transition-colors duration-100
|
|
268
249
|
{option.disabled || (full && !checked) ? 'pointer-events-none opacity-40' : ''}
|
|
269
250
|
{index === active ? toneSoft[tone] : 'text-text-secondary'}"
|
|
@@ -5,7 +5,7 @@ export interface MultiSelectOption {
|
|
|
5
5
|
disabled?: boolean;
|
|
6
6
|
group?: string;
|
|
7
7
|
}
|
|
8
|
-
import { type Tone } from '
|
|
8
|
+
import { type Tone } from '../../core/tones.js';
|
|
9
9
|
interface Props {
|
|
10
10
|
/** Bindable — the `value` of every chosen option. */
|
|
11
11
|
value?: string[];
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
<script lang="ts">
|
|
16
16
|
import type { Snippet } from 'svelte';
|
|
17
|
-
import { useLocale } from '
|
|
18
|
-
import { focusRing, toneRing, toneText, type Tone } from '
|
|
17
|
+
import { useLocale } from '../../core/locale.svelte.js';
|
|
18
|
+
import { focusRing, toneRing, toneText, type Tone } from '../../core/tones.js';
|
|
19
19
|
import Drawer from './Drawer.svelte';
|
|
20
20
|
import Dropdown from './Dropdown.svelte';
|
|
21
21
|
import MenuItem from './MenuItem.svelte';
|
|
@@ -10,7 +10,7 @@ export interface NavItem {
|
|
|
10
10
|
badge?: string | number;
|
|
11
11
|
}
|
|
12
12
|
import type { Snippet } from 'svelte';
|
|
13
|
-
import { type Tone } from '
|
|
13
|
+
import { type Tone } from '../../core/tones.js';
|
|
14
14
|
interface Props {
|
|
15
15
|
items?: NavItem[];
|
|
16
16
|
/** Logo or wordmark on the left. */
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
3
|
-
import { toneFocusWithinBorder, type Tone } from '
|
|
4
|
-
import { useLocale } from '
|
|
3
|
+
import { toneFocusWithinBorder, type Tone } from '../../core/tones.js';
|
|
4
|
+
import { useLocale } from '../../core/locale.svelte.js';
|
|
5
|
+
import { clampToStep } from '../../core/number.js';
|
|
5
6
|
|
|
6
7
|
interface Props extends Omit<HTMLInputAttributes, 'size' | 'type' | 'value' | 'min' | 'max'> {
|
|
7
8
|
value?: number;
|
|
@@ -29,12 +30,7 @@
|
|
|
29
30
|
|
|
30
31
|
const t = useLocale();
|
|
31
32
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
function clamp(next: number) {
|
|
35
|
-
if (Number.isNaN(next)) return min === -Infinity ? 0 : min;
|
|
36
|
-
return Number(Math.min(max, Math.max(min, next)).toFixed(decimals));
|
|
37
|
-
}
|
|
33
|
+
const clamp = (next: number) => clampToStep(next, min, max, step);
|
|
38
34
|
|
|
39
35
|
function nudge(direction: 1 | -1) {
|
|
40
36
|
value = clamp(value + direction * step);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
2
|
-
import { type Tone } from '
|
|
2
|
+
import { type Tone } from '../../core/tones.js';
|
|
3
3
|
interface Props extends Omit<HTMLInputAttributes, 'size' | 'type' | 'value' | 'min' | 'max'> {
|
|
4
4
|
value?: number;
|
|
5
5
|
min?: number;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
-
import { focusRing, toneRing, toneSolid, type Tone } from '
|
|
4
|
-
import { useLocale } from '
|
|
3
|
+
import { focusRing, toneRing, toneSolid, type Tone } from '../../core/tones.js';
|
|
4
|
+
import { useLocale } from '../../core/locale.svelte.js';
|
|
5
|
+
import { pageRange } from '../../core/pagination.js';
|
|
5
6
|
|
|
6
7
|
interface Props extends Omit<HTMLAttributes<HTMLElement>, 'onchange'> {
|
|
7
8
|
/** Bindable, 1-based. */
|
|
@@ -26,19 +27,7 @@
|
|
|
26
27
|
|
|
27
28
|
const t = useLocale();
|
|
28
29
|
|
|
29
|
-
const pages = $derived
|
|
30
|
-
if (total <= 5 + siblings * 2) {
|
|
31
|
-
return Array.from({ length: total }, (_, i) => i + 1);
|
|
32
|
-
}
|
|
33
|
-
const start = Math.max(2, page - siblings);
|
|
34
|
-
const end = Math.min(total - 1, page + siblings);
|
|
35
|
-
const out: (number | '…')[] = [1];
|
|
36
|
-
if (start > 2) out.push('…');
|
|
37
|
-
for (let i = start; i <= end; i++) out.push(i);
|
|
38
|
-
if (end < total - 1) out.push('…');
|
|
39
|
-
out.push(total);
|
|
40
|
-
return out;
|
|
41
|
-
});
|
|
30
|
+
const pages = $derived(pageRange(page, total, siblings));
|
|
42
31
|
|
|
43
32
|
function go(next: number) {
|
|
44
33
|
const clamped = Math.min(total, Math.max(1, next));
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
3
|
-
import { toneFocusWithinBorder, type Tone } from '
|
|
4
|
-
import { useLocale } from '
|
|
3
|
+
import { toneFocusWithinBorder, type Tone } from '../../core/tones.js';
|
|
4
|
+
import { useLocale } from '../../core/locale.svelte.js';
|
|
5
|
+
import { passwordScore } from '../../core/password.js';
|
|
5
6
|
|
|
6
7
|
interface Props extends Omit<HTMLInputAttributes, 'size' | 'type'> {
|
|
7
8
|
value?: string;
|
|
@@ -25,17 +26,7 @@
|
|
|
25
26
|
|
|
26
27
|
let visible = $state(false);
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
const score = $derived.by(() => {
|
|
30
|
-
if (!value) return 0;
|
|
31
|
-
let points = 0;
|
|
32
|
-
if (value.length >= 8) points++;
|
|
33
|
-
if (value.length >= 12) points++;
|
|
34
|
-
if (/[a-z]/.test(value) && /[A-Z]/.test(value)) points++;
|
|
35
|
-
if (/\d/.test(value)) points++;
|
|
36
|
-
if (/[^\w\s]/.test(value)) points++;
|
|
37
|
-
return Math.min(4, points);
|
|
38
|
-
});
|
|
29
|
+
const score = $derived(passwordScore(value));
|
|
39
30
|
|
|
40
31
|
const bars = ['bg-danger', 'bg-danger', 'bg-warning', 'bg-info', 'bg-success'];
|
|
41
32
|
const texts = ['text-danger', 'text-danger', 'text-warning', 'text-info', 'text-success'];
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
-
import { anchored, type Placement } from '
|
|
4
|
-
import { clickOutside, focusTrap, portal } from '
|
|
3
|
+
import { anchored, type Placement } from '../../core/actions/anchor.js';
|
|
4
|
+
import { clickOutside, focusTrap, portal } from '../../core/actions/dismissable.js';
|
|
5
|
+
import { HOVER_GRACE, describeTrigger, popupTrigger } from '../../core/trigger.js';
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
7
8
|
trigger: Snippet;
|
|
@@ -32,45 +33,10 @@
|
|
|
32
33
|
}: Props = $props();
|
|
33
34
|
|
|
34
35
|
let anchorEl: HTMLElement | null = $state(null);
|
|
36
|
+
/** Held so the panel itself can cancel the hover close it inherited. */
|
|
35
37
|
let closeTimer: ReturnType<typeof setTimeout> | undefined;
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
const toggle = () => (open = !open);
|
|
39
|
-
const show = () => {
|
|
40
|
-
clearTimeout(closeTimer);
|
|
41
|
-
open = true;
|
|
42
|
-
};
|
|
43
|
-
const hide = () => {
|
|
44
|
-
closeTimer = setTimeout(() => (open = false), 120);
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
if (on === 'click') {
|
|
48
|
-
node.addEventListener('click', toggle);
|
|
49
|
-
} else {
|
|
50
|
-
node.addEventListener('pointerenter', show);
|
|
51
|
-
node.addEventListener('pointerleave', hide);
|
|
52
|
-
node.addEventListener('focusin', show);
|
|
53
|
-
node.addEventListener('focusout', hide);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return {
|
|
57
|
-
destroy() {
|
|
58
|
-
clearTimeout(closeTimer);
|
|
59
|
-
node.removeEventListener('click', toggle);
|
|
60
|
-
node.removeEventListener('pointerenter', show);
|
|
61
|
-
node.removeEventListener('pointerleave', hide);
|
|
62
|
-
node.removeEventListener('focusin', show);
|
|
63
|
-
node.removeEventListener('focusout', hide);
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
$effect(() => {
|
|
69
|
-
const control = anchorEl?.querySelector('button, a, [role="button"]');
|
|
70
|
-
if (!control) return;
|
|
71
|
-
control.setAttribute('aria-haspopup', 'dialog');
|
|
72
|
-
control.setAttribute('aria-expanded', String(open));
|
|
73
|
-
});
|
|
39
|
+
$effect(() => describeTrigger(anchorEl, 'dialog', open));
|
|
74
40
|
|
|
75
41
|
function onKeydown(event: KeyboardEvent) {
|
|
76
42
|
if (event.key !== 'Escape') return;
|
|
@@ -80,7 +46,16 @@
|
|
|
80
46
|
}
|
|
81
47
|
</script>
|
|
82
48
|
|
|
83
|
-
<span
|
|
49
|
+
<span
|
|
50
|
+
bind:this={anchorEl}
|
|
51
|
+
use:popupTrigger={{
|
|
52
|
+
toggle: () => (open = !open),
|
|
53
|
+
open: () => (open = true),
|
|
54
|
+
close: () => (open = false),
|
|
55
|
+
on
|
|
56
|
+
}}
|
|
57
|
+
class="inline-flex {triggerClass}"
|
|
58
|
+
>
|
|
84
59
|
{@render trigger()}
|
|
85
60
|
</span>
|
|
86
61
|
|
|
@@ -97,7 +72,7 @@
|
|
|
97
72
|
onkeydown={onKeydown}
|
|
98
73
|
onpointerenter={() => clearTimeout(closeTimer)}
|
|
99
74
|
onpointerleave={() => {
|
|
100
|
-
if (on === 'hover') closeTimer = setTimeout(() => (open = false),
|
|
75
|
+
if (on === 'hover') closeTimer = setTimeout(() => (open = false), HOVER_GRACE);
|
|
101
76
|
}}
|
|
102
77
|
role="dialog"
|
|
103
78
|
aria-label={title}
|