@nqmcreative/ui 0.1.1 → 0.2.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 +89 -34
- package/cli/index.mjs +67 -30
- 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
package/README.md
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
# @nqmcreative/ui
|
|
2
2
|
|
|
3
|
-
Svelte 5 (runes) + Tailwind CSS v4 component library.
|
|
4
|
-
|
|
5
|
-
dark, no runtime dependencies.
|
|
3
|
+
Svelte 5 (runes) + Tailwind CSS v4 component library. One package, **two
|
|
4
|
+
styles**, 65 components each — the same props, the same behaviour, a different
|
|
5
|
+
look. Eight tones, light and dark, no runtime dependencies.
|
|
6
|
+
|
|
7
|
+
| style | import | character |
|
|
8
|
+
| ------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
9
|
+
| `matte` | `@nqmcreative/ui/matte` | Flat and sharp-cornered — no radius, no shadow, no gloss. Hairline rules and mono micro-labels do the work borders usually do. |
|
|
10
|
+
| `paper` | `@nqmcreative/ui/paper` | The neutral one. Start here if unsure: soft corners, light shadows, generous spacing, and nothing that fights the content. |
|
|
6
11
|
|
|
7
12
|
The docs site lives in this repo — every component with a live demo, plus
|
|
8
13
|
theming, locale and contributing guides. `bun run dev` to read it.
|
|
@@ -14,7 +19,7 @@ bun add @nqmcreative/ui
|
|
|
14
19
|
```
|
|
15
20
|
|
|
16
21
|
```bash
|
|
17
|
-
bunx nqm-ui init
|
|
22
|
+
bunx nqm-ui init --style matte
|
|
18
23
|
```
|
|
19
24
|
|
|
20
25
|
`init` writes `src/app.css`, patches `src/app.html`, and adds the CSS import to
|
|
@@ -33,14 +38,18 @@ Your project brings its own `svelte` ^5 and Tailwind CSS v4.
|
|
|
33
38
|
```css
|
|
34
39
|
/* src/app.css */
|
|
35
40
|
@import 'tailwindcss';
|
|
36
|
-
@import '@nqmcreative/ui/theme.css';
|
|
37
|
-
@import '@nqmcreative/ui/fonts.css';
|
|
41
|
+
@import '@nqmcreative/ui/matte/theme.css';
|
|
42
|
+
@import '@nqmcreative/ui/matte/fonts.css';
|
|
38
43
|
|
|
39
44
|
/* Tailwind v4 skips node_modules. Without this every component renders
|
|
40
|
-
unstyled, with no error anywhere. */
|
|
41
|
-
@source '../node_modules/@nqmcreative/ui/dist';
|
|
45
|
+
unstyled, with no error anywhere. Point it at the style you import. */
|
|
46
|
+
@source '../node_modules/@nqmcreative/ui/dist/styles/matte';
|
|
42
47
|
```
|
|
43
48
|
|
|
49
|
+
Import exactly one style's `theme.css` — they all define the same token names,
|
|
50
|
+
so two would fight over every colour. Each style ships its own `fonts.css`
|
|
51
|
+
alongside it; skip it and the type falls back to the system stack.
|
|
52
|
+
|
|
44
53
|
Import that CSS once in `src/routes/+layout.svelte`, and put the font
|
|
45
54
|
preconnect plus the no-flash theme script in `src/app.html`, above
|
|
46
55
|
`%sveltekit.head%`:
|
|
@@ -57,13 +66,11 @@ preconnect plus the no-flash theme script in `src/app.html`, above
|
|
|
57
66
|
|
|
58
67
|
## Use
|
|
59
68
|
|
|
60
|
-
|
|
69
|
+
The import names the style:
|
|
61
70
|
|
|
62
71
|
```svelte
|
|
63
72
|
<script lang="ts">
|
|
64
|
-
import Button from '@nqmcreative/ui/
|
|
65
|
-
import Field from '@nqmcreative/ui/field';
|
|
66
|
-
import Input from '@nqmcreative/ui/input';
|
|
73
|
+
import { Button, Field, Input } from '@nqmcreative/ui/matte';
|
|
67
74
|
|
|
68
75
|
let email = $state('');
|
|
69
76
|
</script>
|
|
@@ -75,7 +82,13 @@ Each component has its own subpath — the file name in kebab-case:
|
|
|
75
82
|
<Button tone="accent">Get started</Button>
|
|
76
83
|
```
|
|
77
84
|
|
|
78
|
-
|
|
85
|
+
Per-component subpaths work too — the style, then the file name in kebab-case:
|
|
86
|
+
`@nqmcreative/ui/matte/avatar-group`.
|
|
87
|
+
|
|
88
|
+
**There is no root export.** `import { Button } from '@nqmcreative/ui'` resolves
|
|
89
|
+
to nothing, on purpose: a style is a choice, and picking one by accident is the
|
|
90
|
+
mistake this layout exists to prevent. Switching later is a find-and-replace of
|
|
91
|
+
the word after `@nqmcreative/ui/`.
|
|
79
92
|
|
|
80
93
|
### Tones
|
|
81
94
|
|
|
@@ -89,22 +102,23 @@ Eight of them — `brand`, `accent`, `violet`, `info`, `success`, `warning`,
|
|
|
89
102
|
```
|
|
90
103
|
|
|
91
104
|
Each ships four steps: `bg-accent`, `hover:bg-accent-hover`, `bg-accent-light`,
|
|
92
|
-
`border-accent-border`.
|
|
93
|
-
|
|
105
|
+
`border-accent-border`. The token _names_ are a contract every style fills in,
|
|
106
|
+
so only the values differ between them. Redeclare any of them in your own
|
|
107
|
+
`@theme` block to rebrand everything at once.
|
|
94
108
|
|
|
95
109
|
### Dark mode
|
|
96
110
|
|
|
97
|
-
`theme.css` ships both palettes; nothing in a component says
|
|
98
|
-
`<html class="dark">` or `class="light"` forces one, bare `<html>`
|
|
99
|
-
OS. `ThemeToggle` handles all three.
|
|
111
|
+
Each style's `theme.css` ships both palettes; nothing in a component says
|
|
112
|
+
`dark:`. `<html class="dark">` or `class="light"` forces one, bare `<html>`
|
|
113
|
+
follows the OS. `ThemeToggle` handles all three.
|
|
100
114
|
|
|
101
115
|
### Locale
|
|
102
116
|
|
|
103
117
|
Every built-in string — ARIA names, `No data`, the calendar's month names —
|
|
104
|
-
comes from one object:
|
|
118
|
+
comes from one object, shared by every style:
|
|
105
119
|
|
|
106
120
|
```js
|
|
107
|
-
import { setLocale, idID } from '@nqmcreative/ui/
|
|
121
|
+
import { setLocale, idID } from '@nqmcreative/ui/core';
|
|
108
122
|
|
|
109
123
|
setLocale(idID);
|
|
110
124
|
```
|
|
@@ -112,6 +126,26 @@ setLocale(idID);
|
|
|
112
126
|
`enUS` and `idID` ship with the package; pass a partial to change a few keys.
|
|
113
127
|
Under SSR use `<LocaleProvider>` instead, so the locale is scoped to a request.
|
|
114
128
|
|
|
129
|
+
## Layout
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
src/lib/core/ behaviour, a11y, types — no markup, no classes
|
|
133
|
+
src/lib/styles/matte/ 65 components
|
|
134
|
+
src/lib/styles/paper/ 65 components
|
|
135
|
+
scripts/catalogue.mjs the list every style must implement
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`core` holds what has no opinion about looks: focus traps, roving keyboard
|
|
139
|
+
navigation, viewport-aware anchoring, date maths, file validation, table
|
|
140
|
+
sorting, the toast queue, the locale strings. There is no `matte` version of a
|
|
141
|
+
focus trap, so no style writes one.
|
|
142
|
+
|
|
143
|
+
A style holds only markup and classes. It may differ from another completely —
|
|
144
|
+
different DOM, different animation — as long as the props and the behaviour
|
|
145
|
+
match. `bun run lint` fails if a style is missing a component from the
|
|
146
|
+
catalogue, and the parity suite mounts every style to assert they behave the
|
|
147
|
+
same.
|
|
148
|
+
|
|
115
149
|
## Components
|
|
116
150
|
|
|
117
151
|
| group | components |
|
|
@@ -123,6 +157,7 @@ Under SSR use `<LocaleProvider>` instead, so the locale is scoped to a request.
|
|
|
123
157
|
| Layout & nav | `Divider`, `Tabs`, `Accordion`, `AccordionItem`, `Breadcrumb`, `Pagination`, `Steps` |
|
|
124
158
|
| App shell | `Navbar`, `Sidebar`, `Footer` |
|
|
125
159
|
| Overlay | `Modal`, `ConfirmDialog`, `Drawer`, `Dropdown` + `MenuItem` + `MenuSeparator`, `ContextMenu`, `CommandPalette`, `Popover`, `Tooltip` |
|
|
160
|
+
| Marketing | `HeroSection`, `FeatureGrid`, `FeatureCard`, `PricingCard`, `Testimonial`, `LogoCloud`, `CTASection`, `StatsBand` |
|
|
126
161
|
| System | `ThemeToggle`, `LocaleProvider` |
|
|
127
162
|
|
|
128
163
|
Overlays are built on the native top layer and three in-house actions
|
|
@@ -131,33 +166,53 @@ Overlays are built on the native top layer and three in-house actions
|
|
|
131
166
|
## CLI
|
|
132
167
|
|
|
133
168
|
```bash
|
|
134
|
-
bunx nqm-ui list forms
|
|
135
|
-
bunx nqm-ui info date-picker
|
|
136
|
-
bunx nqm-ui add button badge
|
|
137
|
-
bunx nqm-ui add button --to src/routes/+page.svelte
|
|
169
|
+
bunx nqm-ui list forms # components in a category
|
|
170
|
+
bunx nqm-ui info date-picker # its import line in every style
|
|
171
|
+
bunx nqm-ui add button badge --style matte # print the import lines
|
|
172
|
+
bunx nqm-ui add button --style paper --to src/routes/+page.svelte
|
|
138
173
|
```
|
|
139
174
|
|
|
175
|
+
`--style` has no default: the CLI lists the styles and asks, rather than
|
|
176
|
+
guessing.
|
|
177
|
+
|
|
140
178
|
## Developing
|
|
141
179
|
|
|
142
180
|
```bash
|
|
143
181
|
bun install
|
|
144
182
|
bun run dev # the docs site at localhost:5173
|
|
145
183
|
bun run check # type-check
|
|
146
|
-
bun run test # vitest
|
|
184
|
+
bun run test # vitest, including the cross-style parity suite
|
|
147
185
|
bun run build # site + package
|
|
148
186
|
```
|
|
149
187
|
|
|
150
188
|
`src/lib` is the package, `src/site` and `src/routes` are the docs site.
|
|
151
189
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
`
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
190
|
+
**The style is the first segment of the URL**, not a toggle:
|
|
191
|
+
`/matte/components/button` and `/paper/components/button` are two prerendered
|
|
192
|
+
pages. Each renders entirely in its own style — navbar, sidebar, footer and
|
|
193
|
+
search box included — because every page takes its components from
|
|
194
|
+
`UI[data.style]` rather than importing one style directly. The static HTML for
|
|
195
|
+
the two differs: `h-11 px-7` in one, `h-10 px-4 rounded-md` in the other.
|
|
196
|
+
|
|
197
|
+
Two pieces make that work. `src/hooks.server.ts` stamps `data-style` onto
|
|
198
|
+
`<html>` before the first paint — on `<html>` rather than a wrapper, so
|
|
199
|
+
portalled overlays reach the tokens too and dark mode's class lands on the same
|
|
200
|
+
element. `src/routes/styles.css` re-declares each style's tokens under
|
|
201
|
+
`[data-style]`, generated by `bun run scoped`.
|
|
202
|
+
|
|
203
|
+
Both are docs-only. The package still ships one global `theme.css` per style,
|
|
204
|
+
because `--color-brand` cannot hold two values on one element.
|
|
205
|
+
|
|
206
|
+
**`dist/` is committed — rebuild and commit it with your change**, so what is
|
|
207
|
+
in the repo always matches the source beside it.
|
|
208
|
+
|
|
209
|
+
Adding a component: add a line to `scripts/catalogue.mjs`, put any behaviour in
|
|
210
|
+
`src/lib/core`, write the file in **every** style folder, add **one** demo in
|
|
211
|
+
`src/site/demos`, then `bun run build`. Barrels, exports map, registry, scoped
|
|
212
|
+
tokens and the per-style demo copies are all generated — a demo is authored once
|
|
213
|
+
against `matte` and copied into every other style with its import path
|
|
214
|
+
rewritten. `bun run lint` fails if any is stale or a style is missing
|
|
215
|
+
the component. Full conventions are on the site under `/docs/adding-components`.
|
|
161
216
|
|
|
162
217
|
## License
|
|
163
218
|
|
package/cli/index.mjs
CHANGED
|
@@ -23,7 +23,7 @@ const argv = process.argv.slice(2);
|
|
|
23
23
|
const flags = new Set(argv.filter((a) => a.startsWith('--')));
|
|
24
24
|
|
|
25
25
|
/** Flags that take a value, so the value is not mistaken for a positional. */
|
|
26
|
-
const valueFlags = new Set(['--to']);
|
|
26
|
+
const valueFlags = new Set(['--to', '--style']);
|
|
27
27
|
const args = [];
|
|
28
28
|
for (let i = 0; i < argv.length; i++) {
|
|
29
29
|
if (argv[i].startsWith('--')) {
|
|
@@ -66,15 +66,37 @@ async function registry() {
|
|
|
66
66
|
fail('registry.json not found — is the package installed correctly?');
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
/** Accepts `Button`, `button`, `date-picker` or
|
|
69
|
+
/** Accepts `Button`, `button`, `date-picker` or any style's full subpath. */
|
|
70
70
|
function findComponent(list, query) {
|
|
71
|
-
const needle = query.toLowerCase().replace(/^@nqmcreative\/ui
|
|
72
|
-
return list.find(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
const needle = query.toLowerCase().replace(/^@nqmcreative\/ui\/[a-z-]+\//, '');
|
|
72
|
+
return list.find((item) => item.name.toLowerCase() === needle || item.slug === needle);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The style to work in. There is no default on purpose: a component belongs to
|
|
77
|
+
* a style, and picking one by accident is the mistake this package exists to
|
|
78
|
+
* prevent. Asking once beats shipping the wrong look.
|
|
79
|
+
*/
|
|
80
|
+
function pickStyle(styles) {
|
|
81
|
+
const index = argv.indexOf('--style');
|
|
82
|
+
const wanted = index !== -1 ? argv[index + 1] : null;
|
|
83
|
+
|
|
84
|
+
if (!wanted) {
|
|
85
|
+
log();
|
|
86
|
+
log(' which style?');
|
|
87
|
+
log();
|
|
88
|
+
for (const style of styles) {
|
|
89
|
+
log(` ${c.cyan(style.name.padEnd(8))} ${c.dim(style.description)}`);
|
|
90
|
+
}
|
|
91
|
+
log();
|
|
92
|
+
log(` ${c.dim(`e.g. ${command} --style ${styles[0].name}`)}`);
|
|
93
|
+
log();
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const style = styles.find((s) => s.name === wanted);
|
|
98
|
+
if (!style) fail(`unknown style "${wanted}" — try ${styles.map((s) => s.name).join(' or ')}`);
|
|
99
|
+
return style;
|
|
78
100
|
}
|
|
79
101
|
|
|
80
102
|
/* ------------------------------------------------------------ file edits -- */
|
|
@@ -128,10 +150,12 @@ function sourcePath(cssRel) {
|
|
|
128
150
|
/* ------------------------------------------------------------------ init -- */
|
|
129
151
|
|
|
130
152
|
async function init() {
|
|
153
|
+
const { styles } = await registry();
|
|
154
|
+
const style = pickStyle(styles);
|
|
131
155
|
const project = await detectProject();
|
|
132
156
|
|
|
133
157
|
log();
|
|
134
|
-
log(c.bold(
|
|
158
|
+
log(c.bold(` @nqmcreative/ui — ${style.title}`));
|
|
135
159
|
log(c.dim(` ${project.isKit ? 'SvelteKit' : 'Svelte + Vite'} project detected`));
|
|
136
160
|
log();
|
|
137
161
|
|
|
@@ -151,16 +175,20 @@ async function init() {
|
|
|
151
175
|
const source = sourcePath(project.cssRel);
|
|
152
176
|
const lines = [
|
|
153
177
|
`@import 'tailwindcss';`,
|
|
154
|
-
`@import '@nqmcreative/ui/theme.css';`,
|
|
155
|
-
`@import '@nqmcreative/ui/fonts.css'
|
|
178
|
+
`@import '@nqmcreative/ui/${style.name}/theme.css';`,
|
|
179
|
+
...(style.fonts ? [`@import '@nqmcreative/ui/${style.name}/fonts.css';`] : []),
|
|
156
180
|
``,
|
|
157
|
-
`/* Tailwind v4 skips node_modules — point it at
|
|
158
|
-
` the class names used inside
|
|
159
|
-
`@source '${source}';`
|
|
181
|
+
`/* Tailwind v4 skips node_modules — point it at this style's folder so`,
|
|
182
|
+
` the class names used inside its components are generated. */`,
|
|
183
|
+
`@source '${source}/styles/${style.name}';`
|
|
160
184
|
];
|
|
161
185
|
|
|
162
186
|
const css = await readOr(project.css);
|
|
163
|
-
|
|
187
|
+
|
|
188
|
+
// Matched against *this* style's theme, not any of them. A file left over
|
|
189
|
+
// from an older layout — or wired to a different style — has to be reported,
|
|
190
|
+
// not skipped as already done.
|
|
191
|
+
if (css.includes(`@nqmcreative/ui/${style.name}/theme.css`)) {
|
|
164
192
|
skip(`${project.cssRel} already imports the theme`);
|
|
165
193
|
} else {
|
|
166
194
|
const body = css.trim()
|
|
@@ -197,7 +225,7 @@ async function init() {
|
|
|
197
225
|
// Unindented — `%sveltekit.head%` already sits at its own indentation,
|
|
198
226
|
// so the join below supplies it and the first line does not double up.
|
|
199
227
|
const additions = [];
|
|
200
|
-
if (!html.includes('fonts.gstatic.com')) {
|
|
228
|
+
if (style.fonts && !html.includes('fonts.gstatic.com')) {
|
|
201
229
|
additions.push(`<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />`);
|
|
202
230
|
}
|
|
203
231
|
if (!html.includes('nqm-theme')) {
|
|
@@ -272,14 +300,15 @@ async function init() {
|
|
|
272
300
|
}
|
|
273
301
|
|
|
274
302
|
log();
|
|
275
|
-
log(` Next: ${c.cyan(
|
|
303
|
+
log(` Next: ${c.cyan(`bunx @nqmcreative/ui add button --style ${style.name}`)}`);
|
|
276
304
|
log();
|
|
277
305
|
}
|
|
278
306
|
|
|
279
307
|
/* ------------------------------------------------------------------- add -- */
|
|
280
308
|
|
|
281
309
|
async function add() {
|
|
282
|
-
const { components } = await registry();
|
|
310
|
+
const { components, styles } = await registry();
|
|
311
|
+
const style = pickStyle(styles);
|
|
283
312
|
const names = args.slice(1);
|
|
284
313
|
if (names.length === 0) fail('which component? e.g. `nqm-ui add button dialog`');
|
|
285
314
|
|
|
@@ -290,7 +319,7 @@ async function add() {
|
|
|
290
319
|
const close = components
|
|
291
320
|
.filter((c) => c.name.toLowerCase().startsWith(name.slice(0, 3).toLowerCase()))
|
|
292
321
|
.slice(0, 3)
|
|
293
|
-
.map((c) => c.
|
|
322
|
+
.map((c) => c.slug);
|
|
294
323
|
fail(
|
|
295
324
|
`unknown component "${name}"${close.length ? ` — did you mean ${close.join(', ')}?` : ''}`
|
|
296
325
|
);
|
|
@@ -298,7 +327,7 @@ async function add() {
|
|
|
298
327
|
found.push(item);
|
|
299
328
|
}
|
|
300
329
|
|
|
301
|
-
const imports = found.map((item) => `import ${item.name} from '${item.
|
|
330
|
+
const imports = found.map((item) => `import ${item.name} from '${item.subpaths[style.name]}';`);
|
|
302
331
|
|
|
303
332
|
// `--to <file>` inserts the imports into an existing Svelte file.
|
|
304
333
|
const toIndex = argv.indexOf('--to');
|
|
@@ -339,7 +368,7 @@ async function add() {
|
|
|
339
368
|
/* ------------------------------------------------------------------ list -- */
|
|
340
369
|
|
|
341
370
|
async function list() {
|
|
342
|
-
const { components, count } = await registry();
|
|
371
|
+
const { components, count, styles } = await registry();
|
|
343
372
|
const filter = args[1]?.toLowerCase();
|
|
344
373
|
|
|
345
374
|
const groups = {};
|
|
@@ -355,11 +384,15 @@ async function list() {
|
|
|
355
384
|
for (const [category, items] of Object.entries(groups)) {
|
|
356
385
|
log(` ${c.bold(category)}`);
|
|
357
386
|
for (const item of items) {
|
|
358
|
-
log(` ${item.
|
|
387
|
+
log(` ${item.slug.padEnd(20)} ${c.dim(item.description)}`);
|
|
359
388
|
}
|
|
360
389
|
log();
|
|
361
390
|
}
|
|
362
|
-
log(
|
|
391
|
+
log(
|
|
392
|
+
c.dim(
|
|
393
|
+
` ${shown} of ${count} components, in every style: ${styles.map((s) => s.name).join(', ')}`
|
|
394
|
+
)
|
|
395
|
+
);
|
|
363
396
|
log();
|
|
364
397
|
}
|
|
365
398
|
|
|
@@ -374,11 +407,12 @@ async function info() {
|
|
|
374
407
|
log(` ${c.bold(item.name)} ${c.dim(item.category)}`);
|
|
375
408
|
if (item.description) log(` ${item.description}`);
|
|
376
409
|
log();
|
|
377
|
-
|
|
410
|
+
for (const [style, subpath] of Object.entries(item.subpaths)) {
|
|
411
|
+
log(` ${c.dim(style.padEnd(8))} ${c.cyan(`import ${item.name} from '${subpath}';`)}`);
|
|
412
|
+
}
|
|
378
413
|
log();
|
|
379
414
|
if (item.uses.length) log(` renders ${item.uses.join(', ')}`);
|
|
380
|
-
if (item.modules.length) log(`
|
|
381
|
-
log(` source ${item.file}`);
|
|
415
|
+
if (item.modules.length) log(` core ${item.modules.join(', ')}`);
|
|
382
416
|
log();
|
|
383
417
|
}
|
|
384
418
|
|
|
@@ -388,13 +422,16 @@ function help() {
|
|
|
388
422
|
log(`
|
|
389
423
|
${c.bold('@nqmcreative/ui')}
|
|
390
424
|
|
|
391
|
-
${c.cyan('init')}
|
|
425
|
+
${c.cyan('init --style <s>')} wire one style into this project
|
|
392
426
|
${c.cyan('add <name...>')} print the import for a component
|
|
427
|
+
${c.dim('--style <s>')} which style to import from (required)
|
|
393
428
|
${c.dim('--to <file>')} …and insert it into that file instead
|
|
394
|
-
${c.cyan('list [category]')} every component
|
|
395
|
-
${c.cyan('info <name>')} what one component pulls in
|
|
429
|
+
${c.cyan('list [category]')} every component in the catalogue
|
|
430
|
+
${c.cyan('info <name>')} what one component pulls in, in every style
|
|
396
431
|
|
|
397
432
|
${c.dim('--dry-run')} show the writes without making them
|
|
433
|
+
|
|
434
|
+
${c.dim('Every style implements every component. Run init once per project.')}
|
|
398
435
|
`);
|
|
399
436
|
}
|
|
400
437
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyboard movement inside a month grid.
|
|
3
|
+
*
|
|
4
|
+
* The arrow keys are obvious; Home/End are not — they go to the start and end
|
|
5
|
+
* of the *displayed* week, which depends on whether the grid starts on Monday
|
|
6
|
+
* or Sunday. Returns the day focus should move to, or `null` for a key the
|
|
7
|
+
* grid does not handle.
|
|
8
|
+
*/
|
|
9
|
+
import { addDays, addMonths } from './date.js';
|
|
10
|
+
export function calendarKeyMove(key, focused, weekStart, shiftKey = false) {
|
|
11
|
+
const intoWeek = (focused.getDay() - weekStart + 7) % 7;
|
|
12
|
+
switch (key) {
|
|
13
|
+
case 'ArrowLeft':
|
|
14
|
+
return addDays(focused, -1);
|
|
15
|
+
case 'ArrowRight':
|
|
16
|
+
return addDays(focused, 1);
|
|
17
|
+
case 'ArrowUp':
|
|
18
|
+
return addDays(focused, -7);
|
|
19
|
+
case 'ArrowDown':
|
|
20
|
+
return addDays(focused, 7);
|
|
21
|
+
case 'Home':
|
|
22
|
+
return addDays(focused, -intoWeek);
|
|
23
|
+
case 'End':
|
|
24
|
+
return addDays(focused, 6 - intoWeek);
|
|
25
|
+
case 'PageUp':
|
|
26
|
+
return addMonths(focused, shiftKey ? -12 : -1);
|
|
27
|
+
case 'PageDown':
|
|
28
|
+
return addMonths(focused, shiftKey ? 12 : 1);
|
|
29
|
+
default:
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** The placeholder a text date field shows for a locale's part order. */
|
|
34
|
+
export function dateHint(format) {
|
|
35
|
+
return { dmy: 'DD/MM/YYYY', mdy: 'MM/DD/YYYY', ymd: 'YYYY/MM/DD' }[format];
|
|
36
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeps a bound `open` prop and a native `<dialog>` in step.
|
|
3
|
+
*
|
|
4
|
+
* `showModal()` throws if the dialog is already open and `close()` fires an
|
|
5
|
+
* event of its own, so both directions need the guard below. Every overlay
|
|
6
|
+
* built on `<dialog>` — Modal, Drawer, CommandPalette — calls this from an
|
|
7
|
+
* effect rather than repeating the two `if`s.
|
|
8
|
+
*/
|
|
9
|
+
export declare function syncDialog(dialog: HTMLDialogElement | null, open: boolean): void;
|
|
10
|
+
/**
|
|
11
|
+
* True when a click landed on the backdrop rather than inside the panel.
|
|
12
|
+
* The backdrop is not a separate element — it is the dialog's own box.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isBackdropClick(event: MouseEvent, dialog: HTMLDialogElement | null): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeps a bound `open` prop and a native `<dialog>` in step.
|
|
3
|
+
*
|
|
4
|
+
* `showModal()` throws if the dialog is already open and `close()` fires an
|
|
5
|
+
* event of its own, so both directions need the guard below. Every overlay
|
|
6
|
+
* built on `<dialog>` — Modal, Drawer, CommandPalette — calls this from an
|
|
7
|
+
* effect rather than repeating the two `if`s.
|
|
8
|
+
*/
|
|
9
|
+
export function syncDialog(dialog, open) {
|
|
10
|
+
if (!dialog)
|
|
11
|
+
return;
|
|
12
|
+
if (open && !dialog.open)
|
|
13
|
+
dialog.showModal();
|
|
14
|
+
else if (!open && dialog.open)
|
|
15
|
+
dialog.close();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* True when a click landed on the backdrop rather than inside the panel.
|
|
19
|
+
* The backdrop is not a separate element — it is the dialog's own box.
|
|
20
|
+
*/
|
|
21
|
+
export function isBackdropClick(event, dialog) {
|
|
22
|
+
return !!dialog && event.target === dialog;
|
|
23
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File validation for the drop zone: which files a set of rules lets through,
|
|
3
|
+
* why the rest were turned away, and how to print a byte count.
|
|
4
|
+
*/
|
|
5
|
+
export interface RejectedFile {
|
|
6
|
+
file: File;
|
|
7
|
+
reason: 'type' | 'size' | 'count';
|
|
8
|
+
}
|
|
9
|
+
export interface FileRules {
|
|
10
|
+
/** Same syntax as the input's `accept` — `'image/*,.pdf'`. */
|
|
11
|
+
accept?: string;
|
|
12
|
+
/** Per-file ceiling in bytes. `0` means no limit. */
|
|
13
|
+
maxSize?: number;
|
|
14
|
+
/** Cap on how many files may be held at once. `0` means no limit. */
|
|
15
|
+
maxFiles?: number;
|
|
16
|
+
multiple?: boolean;
|
|
17
|
+
/** How many are already held, counted against `maxFiles`. */
|
|
18
|
+
held?: number;
|
|
19
|
+
}
|
|
20
|
+
/** `image/*`, `.pdf` and `application/pdf` all mean what you would expect. */
|
|
21
|
+
export declare function matchesAccept(file: File, accept?: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Sorts one drop into keepers and rejects. Order matters: a file is judged on
|
|
24
|
+
* type first, then size, then whether there is room left — so the reason a
|
|
25
|
+
* user sees is the first rule it actually broke.
|
|
26
|
+
*/
|
|
27
|
+
export declare function sortFiles(incoming: FileList | File[] | null, rules?: FileRules): {
|
|
28
|
+
accepted: File[];
|
|
29
|
+
rejected: RejectedFile[];
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* `900 B`, `2 MB`, `1.5 GB`. Units come from the locale so the number and its
|
|
33
|
+
* suffix can be translated together.
|
|
34
|
+
*/
|
|
35
|
+
export declare function formatSize(bytes: number, units: readonly string[]): string;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File validation for the drop zone: which files a set of rules lets through,
|
|
3
|
+
* why the rest were turned away, and how to print a byte count.
|
|
4
|
+
*/
|
|
5
|
+
/** `image/*`, `.pdf` and `application/pdf` all mean what you would expect. */
|
|
6
|
+
export function matchesAccept(file, accept) {
|
|
7
|
+
if (!accept)
|
|
8
|
+
return true;
|
|
9
|
+
return accept.split(',').some((raw) => {
|
|
10
|
+
const rule = raw.trim().toLowerCase();
|
|
11
|
+
if (!rule)
|
|
12
|
+
return true;
|
|
13
|
+
if (rule.startsWith('.'))
|
|
14
|
+
return file.name.toLowerCase().endsWith(rule);
|
|
15
|
+
if (rule.endsWith('/*'))
|
|
16
|
+
return file.type.startsWith(rule.slice(0, -1));
|
|
17
|
+
return file.type.toLowerCase() === rule;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Sorts one drop into keepers and rejects. Order matters: a file is judged on
|
|
22
|
+
* type first, then size, then whether there is room left — so the reason a
|
|
23
|
+
* user sees is the first rule it actually broke.
|
|
24
|
+
*/
|
|
25
|
+
export function sortFiles(incoming, rules = {}) {
|
|
26
|
+
const accepted = [];
|
|
27
|
+
const rejected = [];
|
|
28
|
+
if (!incoming)
|
|
29
|
+
return { accepted, rejected };
|
|
30
|
+
const { accept, maxSize = 0, maxFiles = 0, multiple = true, held = 0 } = rules;
|
|
31
|
+
let room = maxFiles ? maxFiles - (multiple ? held : 0) : Infinity;
|
|
32
|
+
for (const file of Array.from(incoming)) {
|
|
33
|
+
if (!matchesAccept(file, accept))
|
|
34
|
+
rejected.push({ file, reason: 'type' });
|
|
35
|
+
else if (maxSize && file.size > maxSize)
|
|
36
|
+
rejected.push({ file, reason: 'size' });
|
|
37
|
+
else if (room <= 0)
|
|
38
|
+
rejected.push({ file, reason: 'count' });
|
|
39
|
+
else {
|
|
40
|
+
accepted.push(file);
|
|
41
|
+
room--;
|
|
42
|
+
}
|
|
43
|
+
if (!multiple && accepted.length === 1)
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
return { accepted, rejected };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* `900 B`, `2 MB`, `1.5 GB`. Units come from the locale so the number and its
|
|
50
|
+
* suffix can be translated together.
|
|
51
|
+
*/
|
|
52
|
+
export function formatSize(bytes, units) {
|
|
53
|
+
if (bytes < 1024)
|
|
54
|
+
return `${bytes} ${units[0]}`;
|
|
55
|
+
let value = bytes / 1024;
|
|
56
|
+
let i = 1;
|
|
57
|
+
while (value >= 1024 && i < units.length - 1) {
|
|
58
|
+
value /= 1024;
|
|
59
|
+
i++;
|
|
60
|
+
}
|
|
61
|
+
return `${value.toFixed(Number.isInteger(value) || value >= 10 ? 0 : 1)} ${units[i]}`;
|
|
62
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nqmcreative/ui/core — everything the styles share.
|
|
3
|
+
*
|
|
4
|
+
* Behaviour, not looks: focus containment, keyboard navigation, date maths,
|
|
5
|
+
* file validation, the toast queue, the locale strings. Nothing in here
|
|
6
|
+
* renders anything, and nothing in here knows which style is being used.
|
|
7
|
+
*
|
|
8
|
+
* Styles are free to ignore any of it — but there is no `matte` version of a
|
|
9
|
+
* focus trap, so none of them should have to write one.
|
|
10
|
+
*/
|
|
11
|
+
export { TONES, focusRing, peerFocusRing, toneBorder, toneBorderLeft, toneBorderSoft, toneFill, toneFocusBorder, toneFocusWithinBorder, toneHoverBorder, toneHoverText, tonePeerChecked, tonePeerFocus, toneRing, toneSoft, toneSoftHover, toneSolid, toneSolidHover, toneSurface, toneText } from './tones.js';
|
|
12
|
+
export type { Tone } from './tones.js';
|
|
13
|
+
export { anchored } from './actions/anchor.js';
|
|
14
|
+
export type { Placement, AnchorOptions } from './actions/anchor.js';
|
|
15
|
+
export { clickOutside, focusTrap, focusable, navigateList, portal } from './actions/dismissable.js';
|
|
16
|
+
export type { ClickOutsideOptions, FocusTrapOptions } from './actions/dismissable.js';
|
|
17
|
+
export { syncDialog, isBackdropClick } from './dialog.svelte.js';
|
|
18
|
+
export { popupTrigger, describeTrigger, menuItems, HOVER_GRACE } from './trigger.js';
|
|
19
|
+
export type { PopupTriggerOptions } from './trigger.js';
|
|
20
|
+
export { ListCursor, groupItems, matchQuery, revealIndex } from './list.svelte.js';
|
|
21
|
+
export type { ListItem } from './list.svelte.js';
|
|
22
|
+
export { nextSort, sortRows, toggleKey } from './table.js';
|
|
23
|
+
export type { TableSort, SortDirection } from './table.js';
|
|
24
|
+
export { pageRange } from './pagination.js';
|
|
25
|
+
export { sortFiles, matchesAccept, formatSize } from './files.js';
|
|
26
|
+
export type { RejectedFile, FileRules } from './files.js';
|
|
27
|
+
export { passwordScore } from './password.js';
|
|
28
|
+
export { clampToStep, percentOf, stepDecimals } from './number.js';
|
|
29
|
+
export { toISO, fromISO, today, isSameDay, addDays, addMonths, monthGrid, weekdayNames, monthLabel, isOutOfRange, formatISO, parseFormatted } from './date.js';
|
|
30
|
+
export type { DateFormat } from './date.js';
|
|
31
|
+
export { calendarKeyMove, dateHint } from './calendar.js';
|
|
32
|
+
export { toast } from './toast.svelte.js';
|
|
33
|
+
export type { Toast, ToastOptions, ToastAction } from './toast.svelte.js';
|
|
34
|
+
export { applyTheme, storedTheme, persistTheme, nextTheme } from './theme.svelte.js';
|
|
35
|
+
export type { Theme } from './theme.svelte.js';
|
|
36
|
+
export { locale, setLocale, provideLocale, useLocale, enUS, idID, LocaleStore } from './locale.svelte.js';
|
|
37
|
+
export type { Locale } from './locale.svelte.js';
|