@c9up/nebula 0.1.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/LICENSE +21 -0
- package/README.md +256 -0
- package/dist/adapters/css.d.ts +33 -0
- package/dist/adapters/css.js +67 -0
- package/dist/adapters/index.d.ts +16 -0
- package/dist/adapters/index.js +27 -0
- package/dist/adapters/tailwind.d.ts +25 -0
- package/dist/adapters/tailwind.js +122 -0
- package/dist/adapters/types.d.ts +49 -0
- package/dist/adapters/types.js +21 -0
- package/dist/adapters/unocss.d.ts +17 -0
- package/dist/adapters/unocss.js +107 -0
- package/dist/atoms/AspectRatio.d.ts +17 -0
- package/dist/atoms/AspectRatio.js +19 -0
- package/dist/atoms/Avatar.d.ts +23 -0
- package/dist/atoms/Avatar.js +46 -0
- package/dist/atoms/Badge.d.ts +25 -0
- package/dist/atoms/Badge.js +28 -0
- package/dist/atoms/Button.d.ts +58 -0
- package/dist/atoms/Button.js +67 -0
- package/dist/atoms/Checkbox.d.ts +41 -0
- package/dist/atoms/Checkbox.js +47 -0
- package/dist/atoms/Input.d.ts +36 -0
- package/dist/atoms/Input.js +50 -0
- package/dist/atoms/Kbd.d.ts +14 -0
- package/dist/atoms/Kbd.js +17 -0
- package/dist/atoms/Label.d.ts +24 -0
- package/dist/atoms/Label.js +26 -0
- package/dist/atoms/Marker.d.ts +42 -0
- package/dist/atoms/Marker.js +55 -0
- package/dist/atoms/NativeSelect.d.ts +43 -0
- package/dist/atoms/NativeSelect.js +81 -0
- package/dist/atoms/Progress.d.ts +21 -0
- package/dist/atoms/Progress.js +48 -0
- package/dist/atoms/ScrollArea.d.ts +28 -0
- package/dist/atoms/ScrollArea.js +37 -0
- package/dist/atoms/Separator.d.ts +16 -0
- package/dist/atoms/Separator.js +21 -0
- package/dist/atoms/Skeleton.d.ts +13 -0
- package/dist/atoms/Skeleton.js +18 -0
- package/dist/atoms/Slider.d.ts +30 -0
- package/dist/atoms/Slider.js +40 -0
- package/dist/atoms/Spinner.d.ts +17 -0
- package/dist/atoms/Spinner.js +20 -0
- package/dist/atoms/Switch.d.ts +24 -0
- package/dist/atoms/Switch.js +41 -0
- package/dist/atoms/Textarea.d.ts +28 -0
- package/dist/atoms/Textarea.js +36 -0
- package/dist/atoms/Toggle.d.ts +38 -0
- package/dist/atoms/Toggle.js +45 -0
- package/dist/atoms/index.d.ts +32 -0
- package/dist/atoms/index.js +32 -0
- package/dist/cli/add.d.ts +44 -0
- package/dist/cli/add.js +99 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.js +10 -0
- package/dist/cli/registry.d.ts +31 -0
- package/dist/cli/registry.js +83 -0
- package/dist/config.d.ts +81 -0
- package/dist/config.js +43 -0
- package/dist/configure.d.ts +34 -0
- package/dist/configure.js +85 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +41 -0
- package/dist/lib/children.d.ts +28 -0
- package/dist/lib/children.js +27 -0
- package/dist/lib/cn.d.ts +13 -0
- package/dist/lib/cn.js +13 -0
- package/dist/lib/cva.d.ts +83 -0
- package/dist/lib/cva.js +178 -0
- package/dist/lib/icons.d.ts +44 -0
- package/dist/lib/icons.js +79 -0
- package/dist/lib/id.d.ts +31 -0
- package/dist/lib/id.js +41 -0
- package/dist/lib/index.d.ts +12 -0
- package/dist/lib/index.js +12 -0
- package/dist/lib/motion.d.ts +31 -0
- package/dist/lib/motion.js +39 -0
- package/dist/lib/props.d.ts +48 -0
- package/dist/lib/props.js +59 -0
- package/dist/lib/styled.d.ts +31 -0
- package/dist/lib/styled.js +39 -0
- package/dist/molecules/Accordion.d.ts +35 -0
- package/dist/molecules/Accordion.js +117 -0
- package/dist/molecules/Alert.d.ts +30 -0
- package/dist/molecules/Alert.js +35 -0
- package/dist/molecules/Attachment.d.ts +39 -0
- package/dist/molecules/Attachment.js +103 -0
- package/dist/molecules/Breadcrumb.d.ts +29 -0
- package/dist/molecules/Breadcrumb.js +73 -0
- package/dist/molecules/Bubble.d.ts +56 -0
- package/dist/molecules/Bubble.js +92 -0
- package/dist/molecules/ButtonGroup.d.ts +23 -0
- package/dist/molecules/ButtonGroup.js +30 -0
- package/dist/molecules/Card.d.ts +17 -0
- package/dist/molecules/Card.js +17 -0
- package/dist/molecules/Collapsible.d.ts +40 -0
- package/dist/molecules/Collapsible.js +71 -0
- package/dist/molecules/Empty.d.ts +16 -0
- package/dist/molecules/Empty.js +16 -0
- package/dist/molecules/Field.d.ts +54 -0
- package/dist/molecules/Field.js +82 -0
- package/dist/molecules/InputGroup.d.ts +33 -0
- package/dist/molecules/InputGroup.js +35 -0
- package/dist/molecules/InputOTP.d.ts +33 -0
- package/dist/molecules/InputOTP.js +140 -0
- package/dist/molecules/Item.d.ts +41 -0
- package/dist/molecules/Item.js +48 -0
- package/dist/molecules/Message.d.ts +43 -0
- package/dist/molecules/Message.js +82 -0
- package/dist/molecules/Pagination.d.ts +41 -0
- package/dist/molecules/Pagination.js +144 -0
- package/dist/molecules/RadioGroup.d.ts +32 -0
- package/dist/molecules/RadioGroup.js +65 -0
- package/dist/molecules/Resizable.d.ts +37 -0
- package/dist/molecules/Resizable.js +136 -0
- package/dist/molecules/Table.d.ts +37 -0
- package/dist/molecules/Table.js +78 -0
- package/dist/molecules/Tabs.d.ts +37 -0
- package/dist/molecules/Tabs.js +109 -0
- package/dist/molecules/ToggleGroup.d.ts +37 -0
- package/dist/molecules/ToggleGroup.js +68 -0
- package/dist/molecules/Typography.d.ts +26 -0
- package/dist/molecules/Typography.js +67 -0
- package/dist/molecules/index.d.ts +37 -0
- package/dist/molecules/index.js +37 -0
- package/dist/organisms/AlertDialog.d.ts +40 -0
- package/dist/organisms/AlertDialog.js +104 -0
- package/dist/organisms/Calendar.d.ts +96 -0
- package/dist/organisms/Calendar.js +353 -0
- package/dist/organisms/Carousel.d.ts +29 -0
- package/dist/organisms/Carousel.js +128 -0
- package/dist/organisms/Chart.d.ts +55 -0
- package/dist/organisms/Chart.js +189 -0
- package/dist/organisms/Combobox.d.ts +41 -0
- package/dist/organisms/Combobox.js +102 -0
- package/dist/organisms/Command.d.ts +46 -0
- package/dist/organisms/Command.js +171 -0
- package/dist/organisms/CommandDialog.d.ts +42 -0
- package/dist/organisms/CommandDialog.js +116 -0
- package/dist/organisms/ContextMenu.d.ts +29 -0
- package/dist/organisms/ContextMenu.js +102 -0
- package/dist/organisms/DataTable.d.ts +50 -0
- package/dist/organisms/DataTable.js +257 -0
- package/dist/organisms/DatePicker.d.ts +34 -0
- package/dist/organisms/DatePicker.js +115 -0
- package/dist/organisms/DateRangePicker.d.ts +34 -0
- package/dist/organisms/DateRangePicker.js +122 -0
- package/dist/organisms/Dialog.d.ts +50 -0
- package/dist/organisms/Dialog.js +116 -0
- package/dist/organisms/Drawer.d.ts +40 -0
- package/dist/organisms/Drawer.js +131 -0
- package/dist/organisms/DropdownMenu.d.ts +30 -0
- package/dist/organisms/DropdownMenu.js +91 -0
- package/dist/organisms/Form.d.ts +114 -0
- package/dist/organisms/Form.js +151 -0
- package/dist/organisms/HoverCard.d.ts +30 -0
- package/dist/organisms/HoverCard.js +68 -0
- package/dist/organisms/Menubar.d.ts +28 -0
- package/dist/organisms/Menubar.js +147 -0
- package/dist/organisms/MessageScroller.d.ts +36 -0
- package/dist/organisms/MessageScroller.js +124 -0
- package/dist/organisms/NavigationMenu.d.ts +41 -0
- package/dist/organisms/NavigationMenu.js +139 -0
- package/dist/organisms/Popover.d.ts +33 -0
- package/dist/organisms/Popover.js +58 -0
- package/dist/organisms/Questionnaire.d.ts +74 -0
- package/dist/organisms/Questionnaire.js +235 -0
- package/dist/organisms/Select.d.ts +47 -0
- package/dist/organisms/Select.js +250 -0
- package/dist/organisms/Sheet.d.ts +34 -0
- package/dist/organisms/Sheet.js +107 -0
- package/dist/organisms/Sidebar.d.ts +100 -0
- package/dist/organisms/Sidebar.js +228 -0
- package/dist/organisms/Toaster.d.ts +67 -0
- package/dist/organisms/Toaster.js +189 -0
- package/dist/organisms/Tooltip.d.ts +39 -0
- package/dist/organisms/Tooltip.js +94 -0
- package/dist/organisms/index.d.ts +40 -0
- package/dist/organisms/index.js +40 -0
- package/dist/primitives/controllable.d.ts +38 -0
- package/dist/primitives/controllable.js +43 -0
- package/dist/primitives/dismissable.d.ts +53 -0
- package/dist/primitives/dismissable.js +158 -0
- package/dist/primitives/floating.d.ts +116 -0
- package/dist/primitives/floating.js +289 -0
- package/dist/primitives/floatingSurface.d.ts +56 -0
- package/dist/primitives/floatingSurface.js +142 -0
- package/dist/primitives/focusTrap.d.ts +47 -0
- package/dist/primitives/focusTrap.js +101 -0
- package/dist/primitives/focusable.d.ts +53 -0
- package/dist/primitives/focusable.js +109 -0
- package/dist/primitives/index.d.ts +27 -0
- package/dist/primitives/index.js +27 -0
- package/dist/primitives/menu.d.ts +102 -0
- package/dist/primitives/menu.js +356 -0
- package/dist/primitives/modalSurface.d.ts +54 -0
- package/dist/primitives/modalSurface.js +146 -0
- package/dist/primitives/portal.d.ts +34 -0
- package/dist/primitives/portal.js +42 -0
- package/dist/primitives/presence.d.ts +45 -0
- package/dist/primitives/presence.js +152 -0
- package/dist/primitives/rovingFocus.d.ts +47 -0
- package/dist/primitives/rovingFocus.js +176 -0
- package/dist/primitives/scrollLock.d.ts +21 -0
- package/dist/primitives/scrollLock.js +75 -0
- package/dist/primitives/typeahead.d.ts +39 -0
- package/dist/primitives/typeahead.js +123 -0
- package/dist/templates/AppShell.d.ts +30 -0
- package/dist/templates/AppShell.js +42 -0
- package/dist/templates/AuthLayout.d.ts +23 -0
- package/dist/templates/AuthLayout.js +42 -0
- package/dist/templates/SettingsLayout.d.ts +27 -0
- package/dist/templates/SettingsLayout.js +42 -0
- package/dist/templates/index.d.ts +16 -0
- package/dist/templates/index.js +16 -0
- package/nebula.css +2 -0
- package/package.json +92 -0
- package/registry.json +1107 -0
- package/src/adapters/css.ts +75 -0
- package/src/adapters/index.ts +40 -0
- package/src/adapters/tailwind.ts +134 -0
- package/src/adapters/types.ts +53 -0
- package/src/adapters/unocss.ts +116 -0
- package/src/atoms/AspectRatio.ts +28 -0
- package/src/atoms/Avatar.ts +67 -0
- package/src/atoms/Badge.ts +46 -0
- package/src/atoms/Button.ts +96 -0
- package/src/atoms/Checkbox.ts +76 -0
- package/src/atoms/Input.ts +76 -0
- package/src/atoms/Kbd.ts +28 -0
- package/src/atoms/Label.ts +38 -0
- package/src/atoms/Marker.ts +79 -0
- package/src/atoms/NativeSelect.ts +115 -0
- package/src/atoms/Progress.ts +64 -0
- package/src/atoms/ScrollArea.ts +53 -0
- package/src/atoms/Separator.ts +36 -0
- package/src/atoms/Skeleton.ts +24 -0
- package/src/atoms/Slider.ts +65 -0
- package/src/atoms/Spinner.ts +28 -0
- package/src/atoms/Switch.ts +56 -0
- package/src/atoms/Textarea.ts +58 -0
- package/src/atoms/Toggle.ts +67 -0
- package/src/atoms/index.ts +62 -0
- package/src/cli/add.ts +126 -0
- package/src/cli/index.ts +22 -0
- package/src/cli/registry.ts +116 -0
- package/src/config.ts +102 -0
- package/src/configure.ts +127 -0
- package/src/index.ts +53 -0
- package/src/lib/children.ts +43 -0
- package/src/lib/cn.ts +14 -0
- package/src/lib/cva.ts +249 -0
- package/src/lib/icons.ts +138 -0
- package/src/lib/id.ts +44 -0
- package/src/lib/index.ts +21 -0
- package/src/lib/motion.ts +48 -0
- package/src/lib/props.ts +83 -0
- package/src/lib/styled.ts +60 -0
- package/src/molecules/Accordion.ts +161 -0
- package/src/molecules/Alert.ts +58 -0
- package/src/molecules/Attachment.ts +132 -0
- package/src/molecules/Breadcrumb.ts +107 -0
- package/src/molecules/Bubble.ts +134 -0
- package/src/molecules/ButtonGroup.ts +55 -0
- package/src/molecules/Card.ts +42 -0
- package/src/molecules/Collapsible.ts +89 -0
- package/src/molecules/Empty.ts +43 -0
- package/src/molecules/Field.ts +131 -0
- package/src/molecules/InputGroup.ts +62 -0
- package/src/molecules/InputOTP.ts +166 -0
- package/src/molecules/Item.ts +89 -0
- package/src/molecules/Message.ts +127 -0
- package/src/molecules/Pagination.ts +197 -0
- package/src/molecules/RadioGroup.ts +104 -0
- package/src/molecules/Resizable.ts +166 -0
- package/src/molecules/Table.ts +118 -0
- package/src/molecules/Tabs.ts +148 -0
- package/src/molecules/ToggleGroup.ts +109 -0
- package/src/molecules/Typography.ts +94 -0
- package/src/molecules/index.ts +144 -0
- package/src/organisms/AlertDialog.ts +133 -0
- package/src/organisms/Calendar.ts +470 -0
- package/src/organisms/Carousel.ts +161 -0
- package/src/organisms/Chart.ts +257 -0
- package/src/organisms/Combobox.ts +140 -0
- package/src/organisms/Command.ts +211 -0
- package/src/organisms/CommandDialog.ts +149 -0
- package/src/organisms/ContextMenu.ts +125 -0
- package/src/organisms/DataTable.ts +328 -0
- package/src/organisms/DatePicker.ts +141 -0
- package/src/organisms/DateRangePicker.ts +149 -0
- package/src/organisms/Dialog.ts +162 -0
- package/src/organisms/Drawer.ts +167 -0
- package/src/organisms/DropdownMenu.ts +112 -0
- package/src/organisms/Form.ts +217 -0
- package/src/organisms/HoverCard.ts +92 -0
- package/src/organisms/Menubar.ts +167 -0
- package/src/organisms/MessageScroller.ts +145 -0
- package/src/organisms/NavigationMenu.ts +184 -0
- package/src/organisms/Popover.ts +84 -0
- package/src/organisms/Questionnaire.ts +322 -0
- package/src/organisms/Select.ts +286 -0
- package/src/organisms/Sheet.ts +144 -0
- package/src/organisms/Sidebar.ts +336 -0
- package/src/organisms/Toaster.ts +246 -0
- package/src/organisms/Tooltip.ts +124 -0
- package/src/organisms/index.ts +134 -0
- package/src/primitives/controllable.ts +64 -0
- package/src/primitives/dismissable.ts +195 -0
- package/src/primitives/floating.ts +453 -0
- package/src/primitives/floatingSurface.ts +209 -0
- package/src/primitives/focusTrap.ts +132 -0
- package/src/primitives/focusable.ts +108 -0
- package/src/primitives/index.ts +88 -0
- package/src/primitives/menu.ts +491 -0
- package/src/primitives/modalSurface.ts +199 -0
- package/src/primitives/portal.ts +61 -0
- package/src/primitives/presence.ts +185 -0
- package/src/primitives/rovingFocus.ts +212 -0
- package/src/primitives/scrollLock.ts +79 -0
- package/src/primitives/typeahead.ts +156 -0
- package/src/templates/AppShell.ts +56 -0
- package/src/templates/AuthLayout.ts +66 -0
- package/src/templates/SettingsLayout.ts +63 -0
- package/src/templates/index.ts +21 -0
- package/theme.css +151 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UnoCSS adapter.
|
|
3
|
+
*
|
|
4
|
+
* `presetWind4` implements Tailwind v4's utility syntax, so nebula's component
|
|
5
|
+
* sources are unchanged between this adapter and the Tailwind one — the whole
|
|
6
|
+
* reason both can be offered without a second set of components.
|
|
7
|
+
*
|
|
8
|
+
* What differs is the config format. UnoCSS is configured in JavaScript rather
|
|
9
|
+
* than CSS, so the theme mapping that `@theme inline` expresses for Tailwind
|
|
10
|
+
* is a `theme` object here, and the token definitions come in through
|
|
11
|
+
* `preflights` since UnoCSS has no `@import` of its own.
|
|
12
|
+
*
|
|
13
|
+
* The tokens still come from `theme.css`. One file remains the source of truth
|
|
14
|
+
* for the palette; only the plumbing around it changes.
|
|
15
|
+
*/
|
|
16
|
+
const CONFIG_PATH = "uno.config.ts";
|
|
17
|
+
function unoConfig(config) {
|
|
18
|
+
return `import { defineConfig, presetWind4 } from 'unocss'
|
|
19
|
+
import { readFileSync } from 'node:fs'
|
|
20
|
+
import { createRequire } from 'node:module'
|
|
21
|
+
|
|
22
|
+
const require = createRequire(import.meta.url)
|
|
23
|
+
|
|
24
|
+
/*
|
|
25
|
+
* nebula's tokens, read from the package rather than copied.
|
|
26
|
+
*
|
|
27
|
+
* UnoCSS has no \`@import\`, so the custom properties are injected as a
|
|
28
|
+
* preflight. Reading the file keeps one source of truth for the palette —
|
|
29
|
+
* copying it here would drift the moment nebula retunes a colour.
|
|
30
|
+
*/
|
|
31
|
+
const tokens = readFileSync(require.resolve('@c9up/nebula/theme.css'), 'utf8')
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Map a token to a colour the utilities can reach.
|
|
35
|
+
*
|
|
36
|
+
* The indirection through \`var()\` is what makes dark mode work: the utility
|
|
37
|
+
* resolves the variable at paint time, so a \`.dark\` ancestor redefining it
|
|
38
|
+
* changes the rendered colour without a second stylesheet.
|
|
39
|
+
*/
|
|
40
|
+
const color = (name: string) => \`var(--\${name})\`
|
|
41
|
+
|
|
42
|
+
export default defineConfig({
|
|
43
|
+
presets: [presetWind4()],
|
|
44
|
+
content: {
|
|
45
|
+
filesystem: ['${config.paths.components}/**/*.{ts,js}'],
|
|
46
|
+
},
|
|
47
|
+
preflights: [{ getCSS: () => tokens }],
|
|
48
|
+
// \`dark:\` follows a \`.dark\` class, so a theme toggle can override the OS.
|
|
49
|
+
darkMode: 'class',
|
|
50
|
+
theme: {
|
|
51
|
+
colors: {
|
|
52
|
+
background: color('background'),
|
|
53
|
+
foreground: color('foreground'),
|
|
54
|
+
card: { DEFAULT: color('card'), foreground: color('card-foreground') },
|
|
55
|
+
popover: { DEFAULT: color('popover'), foreground: color('popover-foreground') },
|
|
56
|
+
primary: { DEFAULT: color('primary'), foreground: color('primary-foreground') },
|
|
57
|
+
secondary: { DEFAULT: color('secondary'), foreground: color('secondary-foreground') },
|
|
58
|
+
muted: { DEFAULT: color('muted'), foreground: color('muted-foreground') },
|
|
59
|
+
accent: { DEFAULT: color('accent'), foreground: color('accent-foreground') },
|
|
60
|
+
destructive: { DEFAULT: color('destructive'), foreground: color('destructive-foreground') },
|
|
61
|
+
border: color('border'),
|
|
62
|
+
input: color('input'),
|
|
63
|
+
ring: color('ring'),
|
|
64
|
+
chart: {
|
|
65
|
+
1: color('chart-1'),
|
|
66
|
+
2: color('chart-2'),
|
|
67
|
+
3: color('chart-3'),
|
|
68
|
+
4: color('chart-4'),
|
|
69
|
+
5: color('chart-5'),
|
|
70
|
+
},
|
|
71
|
+
sidebar: {
|
|
72
|
+
DEFAULT: color('sidebar'),
|
|
73
|
+
foreground: color('sidebar-foreground'),
|
|
74
|
+
primary: color('sidebar-primary'),
|
|
75
|
+
accent: color('sidebar-accent'),
|
|
76
|
+
border: color('sidebar-border'),
|
|
77
|
+
ring: color('sidebar-ring'),
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
radius: {
|
|
81
|
+
sm: 'calc(var(--radius) - 4px)',
|
|
82
|
+
md: 'calc(var(--radius) - 2px)',
|
|
83
|
+
lg: 'var(--radius)',
|
|
84
|
+
xl: 'calc(var(--radius) + 4px)',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
})
|
|
88
|
+
`;
|
|
89
|
+
}
|
|
90
|
+
export const unocssAdapter = {
|
|
91
|
+
name: "unocss",
|
|
92
|
+
summary: "UnoCSS with presetWind4 — same class syntax, no PostCSS, faster builds.",
|
|
93
|
+
packages: ["unocss", "@unocss/cli"],
|
|
94
|
+
files(config) {
|
|
95
|
+
return [
|
|
96
|
+
{ path: CONFIG_PATH, contents: unoConfig(config), skipIfExists: true },
|
|
97
|
+
];
|
|
98
|
+
},
|
|
99
|
+
commands(config) {
|
|
100
|
+
const patterns = `${config.paths.components}/**/*.{ts,js}`;
|
|
101
|
+
const base = [patterns, "-o", config.paths.output];
|
|
102
|
+
return {
|
|
103
|
+
build: { command: "unocss", args: base },
|
|
104
|
+
dev: { command: "unocss", args: [...base, "--watch"] },
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AspectRatio — hold a box at a fixed width-to-height ratio.
|
|
3
|
+
*
|
|
4
|
+
* Radix's version predates the CSS `aspect-ratio` property and reproduces it
|
|
5
|
+
* with a padding-top percentage trick. That is no longer needed anywhere
|
|
6
|
+
* nebula runs, so this is the property, set inline because the value is
|
|
7
|
+
* arbitrary and cannot be a utility class.
|
|
8
|
+
*/
|
|
9
|
+
import { type Slot } from "../lib/children.js";
|
|
10
|
+
import { type Reactive } from "../lib/props.js";
|
|
11
|
+
export interface AspectRatioProps {
|
|
12
|
+
children?: Slot;
|
|
13
|
+
/** Width divided by height. `16 / 9` for widescreen, `1` for a square. */
|
|
14
|
+
ratio?: Reactive<number>;
|
|
15
|
+
class?: Reactive<string>;
|
|
16
|
+
}
|
|
17
|
+
export declare const AspectRatio: (props?: AspectRatioProps | undefined) => import("@c9up/aurora").TemplateResult;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AspectRatio — hold a box at a fixed width-to-height ratio.
|
|
3
|
+
*
|
|
4
|
+
* Radix's version predates the CSS `aspect-ratio` property and reproduces it
|
|
5
|
+
* with a padding-top percentage trick. That is no longer needed anywhere
|
|
6
|
+
* nebula runs, so this is the property, set inline because the value is
|
|
7
|
+
* arbitrary and cannot be a utility class.
|
|
8
|
+
*/
|
|
9
|
+
import { component, html } from "@c9up/aurora";
|
|
10
|
+
import { slot } from "../lib/children.js";
|
|
11
|
+
import { cn } from "../lib/cn.js";
|
|
12
|
+
import { read, readOr } from "../lib/props.js";
|
|
13
|
+
export const AspectRatio = component((props) => {
|
|
14
|
+
return html `<div
|
|
15
|
+
data-slot="aspect-ratio"
|
|
16
|
+
style="${() => `aspect-ratio: ${readOr(props.ratio, 1)}`}"
|
|
17
|
+
class="${() => cn("relative w-full", read(props.class))}"
|
|
18
|
+
>${slot(props.children)}</div>`;
|
|
19
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Avatar — a user's picture, with a fallback when there is none.
|
|
3
|
+
*
|
|
4
|
+
* shadcn splits this into `Avatar` / `AvatarImage` / `AvatarFallback` because
|
|
5
|
+
* Radix needs three components to track the image's load state across them.
|
|
6
|
+
* nebula tracks it in one signal inside one component, so the API is a `src`
|
|
7
|
+
* and a `fallback`.
|
|
8
|
+
*
|
|
9
|
+
* Three states, not two. An image that has not loaded *yet* must not show the
|
|
10
|
+
* fallback — swapping initials in and a photo over them a moment later is the
|
|
11
|
+
* flicker this component exists to avoid. So the fallback appears only once
|
|
12
|
+
* the image has actually failed, or when there was no `src` to begin with.
|
|
13
|
+
*/
|
|
14
|
+
import { type Slot } from "../lib/children.js";
|
|
15
|
+
import { type Reactive } from "../lib/props.js";
|
|
16
|
+
export interface AvatarProps {
|
|
17
|
+
src?: Reactive<string | undefined>;
|
|
18
|
+
alt?: Reactive<string>;
|
|
19
|
+
/** Shown when there is no image, or it failed. Usually initials. */
|
|
20
|
+
fallback?: Slot;
|
|
21
|
+
class?: Reactive<string>;
|
|
22
|
+
}
|
|
23
|
+
export declare const Avatar: (props?: AvatarProps | undefined) => import("@c9up/aurora").TemplateResult;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Avatar — a user's picture, with a fallback when there is none.
|
|
3
|
+
*
|
|
4
|
+
* shadcn splits this into `Avatar` / `AvatarImage` / `AvatarFallback` because
|
|
5
|
+
* Radix needs three components to track the image's load state across them.
|
|
6
|
+
* nebula tracks it in one signal inside one component, so the API is a `src`
|
|
7
|
+
* and a `fallback`.
|
|
8
|
+
*
|
|
9
|
+
* Three states, not two. An image that has not loaded *yet* must not show the
|
|
10
|
+
* fallback — swapping initials in and a photo over them a moment later is the
|
|
11
|
+
* flicker this component exists to avoid. So the fallback appears only once
|
|
12
|
+
* the image has actually failed, or when there was no `src` to begin with.
|
|
13
|
+
*/
|
|
14
|
+
import { component, html, signal } from "@c9up/aurora";
|
|
15
|
+
import { slot } from "../lib/children.js";
|
|
16
|
+
import { cn } from "../lib/cn.js";
|
|
17
|
+
import { read, readOr } from "../lib/props.js";
|
|
18
|
+
export const Avatar = component((props) => {
|
|
19
|
+
const state = signal("pending");
|
|
20
|
+
const hasSrc = () => {
|
|
21
|
+
const src = read(props.src);
|
|
22
|
+
return src !== undefined && src !== "";
|
|
23
|
+
};
|
|
24
|
+
const showFallback = () => !hasSrc() || state() === "failed";
|
|
25
|
+
return html `<span
|
|
26
|
+
data-slot="avatar"
|
|
27
|
+
class="${() => cn("relative flex size-8 shrink-0 overflow-hidden rounded-full", read(props.class))}"
|
|
28
|
+
>
|
|
29
|
+
${() => hasSrc() && state() !== "failed"
|
|
30
|
+
? html `<img
|
|
31
|
+
data-slot="avatar-image"
|
|
32
|
+
src="${() => read(props.src)}"
|
|
33
|
+
alt="${() => readOr(props.alt, "")}"
|
|
34
|
+
class="aspect-square size-full object-cover"
|
|
35
|
+
@load="${() => state("loaded")}"
|
|
36
|
+
@error="${() => state("failed")}"
|
|
37
|
+
/>`
|
|
38
|
+
: null}
|
|
39
|
+
${() => showFallback()
|
|
40
|
+
? html `<span
|
|
41
|
+
data-slot="avatar-fallback"
|
|
42
|
+
class="bg-muted flex size-full items-center justify-center rounded-full text-xs font-medium"
|
|
43
|
+
>${slot(props.fallback)}</span>`
|
|
44
|
+
: null}
|
|
45
|
+
</span>`;
|
|
46
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Badge — a small status or count marker.
|
|
3
|
+
*
|
|
4
|
+
* Exported variants as well as the component, for the same reason as Button:
|
|
5
|
+
* a badge is often a link to the thing it counts, and an anchor needs the
|
|
6
|
+
* classes without the element.
|
|
7
|
+
*/
|
|
8
|
+
import { type Slot } from "../lib/children.js";
|
|
9
|
+
import { type VariantProps } from "../lib/cva.js";
|
|
10
|
+
import { type Reactive } from "../lib/props.js";
|
|
11
|
+
export declare const badgeVariants: (props?: (import("../index.js").VariantSelection<{
|
|
12
|
+
variant: {
|
|
13
|
+
default: string;
|
|
14
|
+
secondary: string;
|
|
15
|
+
destructive: string;
|
|
16
|
+
outline: string;
|
|
17
|
+
};
|
|
18
|
+
}> & import("../index.js").ClassOverrides) | undefined) => string;
|
|
19
|
+
export type BadgeVariants = VariantProps<typeof badgeVariants>;
|
|
20
|
+
export interface BadgeProps {
|
|
21
|
+
children?: Slot;
|
|
22
|
+
variant?: Reactive<BadgeVariants["variant"]>;
|
|
23
|
+
class?: Reactive<string>;
|
|
24
|
+
}
|
|
25
|
+
export declare const Badge: (props?: BadgeProps | undefined) => import("@c9up/aurora").TemplateResult;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Badge — a small status or count marker.
|
|
3
|
+
*
|
|
4
|
+
* Exported variants as well as the component, for the same reason as Button:
|
|
5
|
+
* a badge is often a link to the thing it counts, and an anchor needs the
|
|
6
|
+
* classes without the element.
|
|
7
|
+
*/
|
|
8
|
+
import { component, html } from "@c9up/aurora";
|
|
9
|
+
import { slot } from "../lib/children.js";
|
|
10
|
+
import { cva } from "../lib/cva.js";
|
|
11
|
+
import { read } from "../lib/props.js";
|
|
12
|
+
export const badgeVariants = cva("inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", {
|
|
13
|
+
variants: {
|
|
14
|
+
variant: {
|
|
15
|
+
default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
|
16
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
|
17
|
+
destructive: "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20",
|
|
18
|
+
outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
defaultVariants: { variant: "default" },
|
|
22
|
+
});
|
|
23
|
+
export const Badge = component((props) => {
|
|
24
|
+
return html `<span
|
|
25
|
+
data-slot="badge"
|
|
26
|
+
class="${() => badgeVariants({ variant: read(props.variant), class: read(props.class) })}"
|
|
27
|
+
>${slot(props.children)}</span>`;
|
|
28
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Button — the reference component for the whole library.
|
|
3
|
+
*
|
|
4
|
+
* Every other nebula component follows the shape set here, so it is worth
|
|
5
|
+
* reading once:
|
|
6
|
+
*
|
|
7
|
+
* - Variants come from `cva`, exported separately as `buttonVariants` so a
|
|
8
|
+
* link or a menu item can borrow the button's look without being a button.
|
|
9
|
+
* shadcn does the same, and half its examples depend on it.
|
|
10
|
+
* - Every prop that can change is `Reactive<T>` and is bound through
|
|
11
|
+
* `accessor()`. Aurora does not re-render; a value read once at setup is
|
|
12
|
+
* frozen, so `disabled: form.pending` would be a bug that only shows up
|
|
13
|
+
* after the first submit.
|
|
14
|
+
* - `data-slot` mirrors shadcn v4, which stamps one on every part. It gives
|
|
15
|
+
* host CSS and tests a stable hook that does not depend on the utility
|
|
16
|
+
* classes, which are the part a user is expected to edit.
|
|
17
|
+
*
|
|
18
|
+
* No `asChild`. React's Slot pattern clones an element and merges props into
|
|
19
|
+
* it; Aurora templates are compiled markup with no element to clone. Where
|
|
20
|
+
* shadcn would write `<Button asChild><a/></Button>`, nebula exports the
|
|
21
|
+
* variants and you put them on the anchor yourself — which is what the Slot
|
|
22
|
+
* was doing anyway, with a runtime in between.
|
|
23
|
+
*/
|
|
24
|
+
import { type Slot } from "../lib/children.js";
|
|
25
|
+
import { type VariantProps } from "../lib/cva.js";
|
|
26
|
+
import { type Reactive } from "../lib/props.js";
|
|
27
|
+
export declare const buttonVariants: (props?: (import("../index.js").VariantSelection<{
|
|
28
|
+
variant: {
|
|
29
|
+
default: string;
|
|
30
|
+
destructive: string;
|
|
31
|
+
outline: string;
|
|
32
|
+
secondary: string;
|
|
33
|
+
ghost: string;
|
|
34
|
+
link: string;
|
|
35
|
+
};
|
|
36
|
+
size: {
|
|
37
|
+
default: string;
|
|
38
|
+
sm: string;
|
|
39
|
+
lg: string;
|
|
40
|
+
icon: string;
|
|
41
|
+
};
|
|
42
|
+
}> & import("../index.js").ClassOverrides) | undefined) => string;
|
|
43
|
+
export type ButtonVariants = VariantProps<typeof buttonVariants>;
|
|
44
|
+
export interface ButtonProps {
|
|
45
|
+
children?: Slot;
|
|
46
|
+
variant?: Reactive<ButtonVariants["variant"]>;
|
|
47
|
+
size?: Reactive<ButtonVariants["size"]>;
|
|
48
|
+
/** Defaults to `"button"` — never `"submit"`, which is HTML's default and
|
|
49
|
+
* the cause of most accidental form submissions. */
|
|
50
|
+
type?: Reactive<"button" | "submit" | "reset">;
|
|
51
|
+
disabled?: Reactive<boolean>;
|
|
52
|
+
class?: Reactive<string>;
|
|
53
|
+
id?: string;
|
|
54
|
+
/** Sets `aria-label`. Required in practice for `size: "icon"`. */
|
|
55
|
+
label?: Reactive<string | undefined>;
|
|
56
|
+
onClick?: (event: MouseEvent) => void;
|
|
57
|
+
}
|
|
58
|
+
export declare const Button: (props?: ButtonProps | undefined) => import("@c9up/aurora").TemplateResult;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Button — the reference component for the whole library.
|
|
3
|
+
*
|
|
4
|
+
* Every other nebula component follows the shape set here, so it is worth
|
|
5
|
+
* reading once:
|
|
6
|
+
*
|
|
7
|
+
* - Variants come from `cva`, exported separately as `buttonVariants` so a
|
|
8
|
+
* link or a menu item can borrow the button's look without being a button.
|
|
9
|
+
* shadcn does the same, and half its examples depend on it.
|
|
10
|
+
* - Every prop that can change is `Reactive<T>` and is bound through
|
|
11
|
+
* `accessor()`. Aurora does not re-render; a value read once at setup is
|
|
12
|
+
* frozen, so `disabled: form.pending` would be a bug that only shows up
|
|
13
|
+
* after the first submit.
|
|
14
|
+
* - `data-slot` mirrors shadcn v4, which stamps one on every part. It gives
|
|
15
|
+
* host CSS and tests a stable hook that does not depend on the utility
|
|
16
|
+
* classes, which are the part a user is expected to edit.
|
|
17
|
+
*
|
|
18
|
+
* No `asChild`. React's Slot pattern clones an element and merges props into
|
|
19
|
+
* it; Aurora templates are compiled markup with no element to clone. Where
|
|
20
|
+
* shadcn would write `<Button asChild><a/></Button>`, nebula exports the
|
|
21
|
+
* variants and you put them on the anchor yourself — which is what the Slot
|
|
22
|
+
* was doing anyway, with a runtime in between.
|
|
23
|
+
*/
|
|
24
|
+
import { component, html } from "@c9up/aurora";
|
|
25
|
+
import { slot } from "../lib/children.js";
|
|
26
|
+
import { cva } from "../lib/cva.js";
|
|
27
|
+
import { accessor, read } from "../lib/props.js";
|
|
28
|
+
export const buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 aria-invalid:border-destructive", {
|
|
29
|
+
variants: {
|
|
30
|
+
variant: {
|
|
31
|
+
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
32
|
+
destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20",
|
|
33
|
+
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
|
|
34
|
+
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
35
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
36
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
37
|
+
},
|
|
38
|
+
size: {
|
|
39
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
40
|
+
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
41
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
42
|
+
icon: "size-9",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
defaultVariants: {
|
|
46
|
+
variant: "default",
|
|
47
|
+
size: "default",
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
export const Button = component((props) => {
|
|
51
|
+
// An accessor, not a string: the renderer wraps it in an effect, so the
|
|
52
|
+
// class list tracks whichever of these props were given as signals.
|
|
53
|
+
const classes = () => buttonVariants({
|
|
54
|
+
variant: read(props.variant),
|
|
55
|
+
size: read(props.size),
|
|
56
|
+
class: read(props.class),
|
|
57
|
+
});
|
|
58
|
+
return html `<button
|
|
59
|
+
data-slot="button"
|
|
60
|
+
id="${props.id}"
|
|
61
|
+
type="${accessor(props.type, "button")}"
|
|
62
|
+
class="${classes}"
|
|
63
|
+
aria-label="${accessor(props.label, undefined)}"
|
|
64
|
+
?disabled="${accessor(props.disabled, false)}"
|
|
65
|
+
@click="${props.onClick}"
|
|
66
|
+
>${slot(props.children)}</button>`;
|
|
67
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkbox.
|
|
3
|
+
*
|
|
4
|
+
* Radix renders a `<button role="checkbox">` plus a hidden input, because it
|
|
5
|
+
* needs a element it can put arbitrary children in. nebula keeps the native
|
|
6
|
+
* `<input type="checkbox">` and styles it with `appearance-none`.
|
|
7
|
+
*
|
|
8
|
+
* That is not just simpler, it is better behaved: the control participates in
|
|
9
|
+
* form submission and reset on its own, `:checked` and `:indeterminate` drive
|
|
10
|
+
* the visuals with no state to synchronise, and the label association through
|
|
11
|
+
* `for` works without a click forwarder. The tick and dash are siblings shown
|
|
12
|
+
* by `peer-checked:` / `peer-indeterminate:`, so the whole component is
|
|
13
|
+
* declarative — no JavaScript runs when the box is toggled.
|
|
14
|
+
*
|
|
15
|
+
* `indeterminate` is bound as a property because there is no attribute for it;
|
|
16
|
+
* it exists only in the DOM.
|
|
17
|
+
*/
|
|
18
|
+
import { type Reactive } from "../lib/props.js";
|
|
19
|
+
export declare const checkboxClasses = "peer size-4 shrink-0 appearance-none rounded-[4px] border border-input bg-transparent shadow-xs outline-none transition-shadow dark:bg-input/30 checked:border-primary checked:bg-primary indeterminate:border-primary indeterminate:bg-primary focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20";
|
|
20
|
+
export interface CheckboxProps {
|
|
21
|
+
id?: string;
|
|
22
|
+
name?: string;
|
|
23
|
+
value?: string;
|
|
24
|
+
checked?: Reactive<boolean>;
|
|
25
|
+
/** The mixed state — a parent box over partially selected children. */
|
|
26
|
+
indeterminate?: Reactive<boolean>;
|
|
27
|
+
disabled?: Reactive<boolean>;
|
|
28
|
+
required?: Reactive<boolean>;
|
|
29
|
+
invalid?: Reactive<boolean>;
|
|
30
|
+
/**
|
|
31
|
+
* Accessible name, for a checkbox with no visible `<label>`.
|
|
32
|
+
*
|
|
33
|
+
* A checkbox in a table row or a toolbar has its meaning from what is beside
|
|
34
|
+
* it, which a screen reader does not see — it announces "checkbox, unchecked"
|
|
35
|
+
* and nothing else. Every such use needs this.
|
|
36
|
+
*/
|
|
37
|
+
label?: Reactive<string | undefined>;
|
|
38
|
+
class?: Reactive<string>;
|
|
39
|
+
onCheckedChange?: (checked: boolean, event: Event) => void;
|
|
40
|
+
}
|
|
41
|
+
export declare const Checkbox: (props?: CheckboxProps | undefined) => import("@c9up/aurora").TemplateResult;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkbox.
|
|
3
|
+
*
|
|
4
|
+
* Radix renders a `<button role="checkbox">` plus a hidden input, because it
|
|
5
|
+
* needs a element it can put arbitrary children in. nebula keeps the native
|
|
6
|
+
* `<input type="checkbox">` and styles it with `appearance-none`.
|
|
7
|
+
*
|
|
8
|
+
* That is not just simpler, it is better behaved: the control participates in
|
|
9
|
+
* form submission and reset on its own, `:checked` and `:indeterminate` drive
|
|
10
|
+
* the visuals with no state to synchronise, and the label association through
|
|
11
|
+
* `for` works without a click forwarder. The tick and dash are siblings shown
|
|
12
|
+
* by `peer-checked:` / `peer-indeterminate:`, so the whole component is
|
|
13
|
+
* declarative — no JavaScript runs when the box is toggled.
|
|
14
|
+
*
|
|
15
|
+
* `indeterminate` is bound as a property because there is no attribute for it;
|
|
16
|
+
* it exists only in the DOM.
|
|
17
|
+
*/
|
|
18
|
+
import { component, html } from "@c9up/aurora";
|
|
19
|
+
import { cn } from "../lib/cn.js";
|
|
20
|
+
import { CheckIcon, MinusIcon } from "../lib/icons.js";
|
|
21
|
+
import { accessor, read } from "../lib/props.js";
|
|
22
|
+
export const checkboxClasses = "peer size-4 shrink-0 appearance-none rounded-[4px] border border-input bg-transparent shadow-xs outline-none transition-shadow dark:bg-input/30 checked:border-primary checked:bg-primary indeterminate:border-primary indeterminate:bg-primary focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20";
|
|
23
|
+
function inputChecked(event) {
|
|
24
|
+
const target = event.target;
|
|
25
|
+
return target instanceof HTMLInputElement ? target.checked : false;
|
|
26
|
+
}
|
|
27
|
+
export const Checkbox = component((props) => {
|
|
28
|
+
const marker = "pointer-events-none absolute inset-0 size-4 p-px text-primary-foreground opacity-0 transition-opacity";
|
|
29
|
+
return html `<span data-slot="checkbox" class="relative inline-flex size-4 shrink-0">
|
|
30
|
+
<input
|
|
31
|
+
type="checkbox"
|
|
32
|
+
id="${props.id}"
|
|
33
|
+
name="${props.name}"
|
|
34
|
+
value="${props.value}"
|
|
35
|
+
aria-invalid="${() => (read(props.invalid) === true ? "true" : undefined)}"
|
|
36
|
+
aria-label="${accessor(props.label, undefined)}"
|
|
37
|
+
?disabled="${accessor(props.disabled, false)}"
|
|
38
|
+
?required="${accessor(props.required, false)}"
|
|
39
|
+
.checked="${accessor(props.checked, false)}"
|
|
40
|
+
.indeterminate="${accessor(props.indeterminate, false)}"
|
|
41
|
+
class="${() => cn(checkboxClasses, read(props.class))}"
|
|
42
|
+
@change="${(event) => props.onCheckedChange?.(inputChecked(event), event)}"
|
|
43
|
+
/>
|
|
44
|
+
${CheckIcon({ class: cn(marker, "peer-checked:opacity-100 peer-indeterminate:opacity-0") })}
|
|
45
|
+
${MinusIcon({ class: cn(marker, "peer-indeterminate:opacity-100") })}
|
|
46
|
+
</span>`;
|
|
47
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input — a single-line text field.
|
|
3
|
+
*
|
|
4
|
+
* The value binding is the part that differs from React and is worth calling
|
|
5
|
+
* out. `.value` is a *property* slot, not an attribute: setting the `value`
|
|
6
|
+
* attribute only seeds the initial value, and after the user types once the
|
|
7
|
+
* attribute and the property diverge. Binding the property is what keeps a
|
|
8
|
+
* signal and the field in step in both directions.
|
|
9
|
+
*
|
|
10
|
+
* There is no controlled/uncontrolled split. Pass a signal and the field is
|
|
11
|
+
* controlled; pass nothing and the DOM owns the value, which is the right
|
|
12
|
+
* default for a form posted the classic way — the shape aurora apps use.
|
|
13
|
+
*/
|
|
14
|
+
import { type Reactive } from "../lib/props.js";
|
|
15
|
+
export declare const inputClasses = "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive";
|
|
16
|
+
export interface InputProps {
|
|
17
|
+
id?: string;
|
|
18
|
+
name?: string;
|
|
19
|
+
type?: Reactive<string>;
|
|
20
|
+
value?: Reactive<string>;
|
|
21
|
+
placeholder?: Reactive<string>;
|
|
22
|
+
autocomplete?: string;
|
|
23
|
+
disabled?: Reactive<boolean>;
|
|
24
|
+
readonly?: Reactive<boolean>;
|
|
25
|
+
required?: Reactive<boolean>;
|
|
26
|
+
/** Renders `aria-invalid`, which the focus ring and border both key off. */
|
|
27
|
+
invalid?: Reactive<boolean>;
|
|
28
|
+
/** Names the element describing the error, for screen readers. */
|
|
29
|
+
describedBy?: Reactive<string | undefined>;
|
|
30
|
+
class?: Reactive<string>;
|
|
31
|
+
onInput?: (value: string, event: Event) => void;
|
|
32
|
+
onChange?: (value: string, event: Event) => void;
|
|
33
|
+
onBlur?: (event: FocusEvent) => void;
|
|
34
|
+
onKeyDown?: (event: KeyboardEvent) => void;
|
|
35
|
+
}
|
|
36
|
+
export declare const Input: (props?: InputProps | undefined) => import("@c9up/aurora").TemplateResult;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input — a single-line text field.
|
|
3
|
+
*
|
|
4
|
+
* The value binding is the part that differs from React and is worth calling
|
|
5
|
+
* out. `.value` is a *property* slot, not an attribute: setting the `value`
|
|
6
|
+
* attribute only seeds the initial value, and after the user types once the
|
|
7
|
+
* attribute and the property diverge. Binding the property is what keeps a
|
|
8
|
+
* signal and the field in step in both directions.
|
|
9
|
+
*
|
|
10
|
+
* There is no controlled/uncontrolled split. Pass a signal and the field is
|
|
11
|
+
* controlled; pass nothing and the DOM owns the value, which is the right
|
|
12
|
+
* default for a form posted the classic way — the shape aurora apps use.
|
|
13
|
+
*/
|
|
14
|
+
import { component, html } from "@c9up/aurora";
|
|
15
|
+
import { cn } from "../lib/cn.js";
|
|
16
|
+
import { accessor, read } from "../lib/props.js";
|
|
17
|
+
export const inputClasses = "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive";
|
|
18
|
+
/**
|
|
19
|
+
* Pull the current text out of an input event.
|
|
20
|
+
*
|
|
21
|
+
* Reads the target rather than trusting the caller to, so a handler receives a
|
|
22
|
+
* plain string. The guard is not defensive padding: `event.target` is typed as
|
|
23
|
+
* the general `EventTarget`, and narrowing it here is what keeps the callback
|
|
24
|
+
* signature honest without a cast at every call site.
|
|
25
|
+
*/
|
|
26
|
+
function inputValue(event) {
|
|
27
|
+
const target = event.target;
|
|
28
|
+
return target instanceof HTMLInputElement ? target.value : "";
|
|
29
|
+
}
|
|
30
|
+
export const Input = component((props) => {
|
|
31
|
+
return html `<input
|
|
32
|
+
data-slot="input"
|
|
33
|
+
id="${props.id}"
|
|
34
|
+
name="${props.name}"
|
|
35
|
+
type="${accessor(props.type, "text")}"
|
|
36
|
+
placeholder="${accessor(props.placeholder, undefined)}"
|
|
37
|
+
autocomplete="${props.autocomplete}"
|
|
38
|
+
aria-invalid="${() => (read(props.invalid) === true ? "true" : undefined)}"
|
|
39
|
+
aria-describedby="${accessor(props.describedBy, undefined)}"
|
|
40
|
+
?disabled="${accessor(props.disabled, false)}"
|
|
41
|
+
?readonly="${accessor(props.readonly, false)}"
|
|
42
|
+
?required="${accessor(props.required, false)}"
|
|
43
|
+
.value="${accessor(props.value, "")}"
|
|
44
|
+
class="${() => cn(inputClasses, read(props.class))}"
|
|
45
|
+
@input="${(event) => props.onInput?.(inputValue(event), event)}"
|
|
46
|
+
@change="${(event) => props.onChange?.(inputValue(event), event)}"
|
|
47
|
+
@blur="${props.onBlur}"
|
|
48
|
+
@keydown="${props.onKeyDown}"
|
|
49
|
+
/>`;
|
|
50
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kbd — a keyboard key rendered inline.
|
|
3
|
+
*
|
|
4
|
+
* Used by Command and by menu items showing their shortcut. Kept as an atom
|
|
5
|
+
* rather than baked into those two, because shortcut hints show up in tooltips
|
|
6
|
+
* and documentation prose as well.
|
|
7
|
+
*/
|
|
8
|
+
import { type Slot } from "../lib/children.js";
|
|
9
|
+
import { type Reactive } from "../lib/props.js";
|
|
10
|
+
export interface KbdProps {
|
|
11
|
+
children?: Slot;
|
|
12
|
+
class?: Reactive<string>;
|
|
13
|
+
}
|
|
14
|
+
export declare const Kbd: (props?: KbdProps | undefined) => import("@c9up/aurora").TemplateResult;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kbd — a keyboard key rendered inline.
|
|
3
|
+
*
|
|
4
|
+
* Used by Command and by menu items showing their shortcut. Kept as an atom
|
|
5
|
+
* rather than baked into those two, because shortcut hints show up in tooltips
|
|
6
|
+
* and documentation prose as well.
|
|
7
|
+
*/
|
|
8
|
+
import { component, html } from "@c9up/aurora";
|
|
9
|
+
import { slot } from "../lib/children.js";
|
|
10
|
+
import { cn } from "../lib/cn.js";
|
|
11
|
+
import { read } from "../lib/props.js";
|
|
12
|
+
export const Kbd = component((props) => {
|
|
13
|
+
return html `<kbd
|
|
14
|
+
data-slot="kbd"
|
|
15
|
+
class="${() => cn("bg-muted text-muted-foreground pointer-events-none inline-flex h-5 w-fit min-w-5 select-none items-center justify-center gap-1 rounded-sm px-1 font-sans text-xs font-medium", read(props.class))}"
|
|
16
|
+
>${slot(props.children)}</kbd>`;
|
|
17
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Label — the caption for a form control.
|
|
3
|
+
*
|
|
4
|
+
* Radix's Label exists mostly to stop a click on the label from selecting its
|
|
5
|
+
* text on double-click, and to forward clicks to the control. The browser
|
|
6
|
+
* already does the forwarding through `for`, so nebula keeps the native
|
|
7
|
+
* element and only adds `select-none`.
|
|
8
|
+
*
|
|
9
|
+
* The disabled styling is driven from outside: `peer-disabled:` picks up a
|
|
10
|
+
* sibling control marked disabled, `group-data-[disabled=true]:` picks up a
|
|
11
|
+
* wrapping `Field`. Both are why the label dims without being told anything
|
|
12
|
+
* about the control it captions.
|
|
13
|
+
*/
|
|
14
|
+
import { type Slot } from "../lib/children.js";
|
|
15
|
+
import { type Reactive } from "../lib/props.js";
|
|
16
|
+
export declare const labelClasses = "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50";
|
|
17
|
+
export interface LabelProps {
|
|
18
|
+
children?: Slot;
|
|
19
|
+
/** The `id` of the control this labels. */
|
|
20
|
+
for?: string;
|
|
21
|
+
id?: string;
|
|
22
|
+
class?: Reactive<string>;
|
|
23
|
+
}
|
|
24
|
+
export declare const Label: (props?: LabelProps | undefined) => import("@c9up/aurora").TemplateResult;
|