@mystravil/hardpoint 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +51 -38
  2. package/LICENSE +25 -25
  3. package/README.md +67 -64
  4. package/dist/base.css +625 -625
  5. package/dist/components/AppShell.svelte +698 -698
  6. package/dist/components/Button.svelte +221 -174
  7. package/dist/components/Button.svelte.d.ts +18 -2
  8. package/dist/components/Checkbox.svelte +235 -235
  9. package/dist/components/CheckboxGroup.svelte +207 -207
  10. package/dist/components/Combobox.svelte +901 -901
  11. package/dist/components/Dialog.svelte +359 -359
  12. package/dist/components/Disclosure.svelte +201 -201
  13. package/dist/components/EmptyState.svelte +88 -88
  14. package/dist/components/ErrorState.svelte +135 -135
  15. package/dist/components/ImageViewer.svelte +764 -764
  16. package/dist/components/KeyValueList.svelte +114 -114
  17. package/dist/components/ListDetail.svelte +218 -218
  18. package/dist/components/LoadRegion.svelte +219 -219
  19. package/dist/components/MediaFrame.svelte +110 -110
  20. package/dist/components/MediaImage.svelte +256 -256
  21. package/dist/components/Menu.svelte +275 -258
  22. package/dist/components/MenuCheckboxItem.svelte +119 -119
  23. package/dist/components/MenuGroup.svelte +50 -50
  24. package/dist/components/MenuItem.svelte +94 -94
  25. package/dist/components/MenuRadioGroup.svelte +62 -62
  26. package/dist/components/MenuRadioItem.svelte +110 -110
  27. package/dist/components/MenuSeparator.svelte +28 -28
  28. package/dist/components/Meter.svelte +283 -283
  29. package/dist/components/NativeSelect.svelte +135 -135
  30. package/dist/components/Notice.svelte +262 -262
  31. package/dist/components/Popover.svelte +222 -222
  32. package/dist/components/Progress.svelte +157 -157
  33. package/dist/components/RadioGroup.svelte +440 -440
  34. package/dist/components/Select.svelte +471 -471
  35. package/dist/components/Skeleton.svelte +149 -149
  36. package/dist/components/Spinner.svelte +118 -118
  37. package/dist/components/Stat.svelte +253 -253
  38. package/dist/components/Steps.svelte +189 -189
  39. package/dist/components/Switch.svelte +222 -222
  40. package/dist/components/Table.svelte +504 -504
  41. package/dist/components/Tabs.svelte +246 -246
  42. package/dist/components/Tag.svelte +40 -40
  43. package/dist/components/TextArea.svelte +272 -272
  44. package/dist/components/TextField.svelte +396 -256
  45. package/dist/components/TextField.svelte.d.ts +16 -1
  46. package/dist/components/Timeline.svelte +156 -156
  47. package/dist/components/Toaster.svelte +411 -411
  48. package/dist/components/Tooltip.svelte +200 -200
  49. package/dist/components/TooltipGroup.svelte +46 -46
  50. package/dist/components/internal/Scrim.svelte +52 -52
  51. package/dist/components/internal/Sheet.svelte +263 -263
  52. package/dist/fonts.css +71 -71
  53. package/dist/tokens.css +283 -283
  54. package/package.json +81 -76
@@ -1,174 +1,221 @@
1
- <script lang="ts" module>
2
- import { Button as BitsButton } from 'bits-ui';
3
-
4
- export type ButtonVariant = 'primary' | 'secondary' | 'tertiary';
5
-
6
- export type ButtonProps = BitsButton.RootProps & {
7
- /**
8
- * `primary`: solid titanium block, for the view's one group of solid
9
- * blocks. `secondary` (default): outlined. `tertiary`: caps label only.
10
- */
11
- variant?: ButtonVariant;
12
- /** Ends the label in a small ▸: the button opens another view. */
13
- opens?: boolean;
14
- /**
15
- * A square, icon-only button (height and width are `--control-height`).
16
- * It has no visible label, so it needs an accessible name: pass
17
- * `aria-label`.
18
- */
19
- icon?: boolean;
20
- };
21
- </script>
22
-
23
- <script lang="ts">
24
- let {
25
- variant = 'secondary',
26
- opens = false,
27
- icon = false,
28
- class: className,
29
- ref = $bindable(null),
30
- children,
31
- ...rest
32
- }: ButtonProps = $props();
33
- </script>
34
-
35
- <!--
36
- An <a> when `href` is set, a <button> otherwise (Bits UI Button.Root). A
37
- disabled link renders without href, with aria-disabled="true" and
38
- tabindex -1; a disabled <button> is not focusable.
39
- -->
40
- <BitsButton.Root
41
- bind:ref
42
- class={['hp-button', 'hp-label', className]}
43
- data-variant={variant}
44
- data-opens={opens || undefined}
45
- data-icon={icon || undefined}
46
- {...rest}
47
- >
48
- {@render children?.()}
49
- </BitsButton.Root>
50
-
51
- <style>
52
- /* Bits UI renders the element, so the root class reaches it from the
53
- outside: the rules are :global, keyed on .hp-button and its data-*. */
54
- :global(.hp-button) {
55
- display: inline-flex;
56
- align-items: center;
57
- justify-content: space-between;
58
- gap: var(--space-4);
59
- box-sizing: border-box;
60
- height: var(--control-height);
61
- /* The visible box is the hit area: 36px fine, 44px coarse, and never
62
- narrower than --hit-target for a short label. */
63
- min-width: var(--hit-target);
64
- padding: 0 var(--space-3);
65
- border: 0;
66
- background: transparent;
67
- color: var(--text);
68
- font-family: var(--sans);
69
- text-decoration: none;
70
- white-space: nowrap;
71
- cursor: pointer;
72
- -webkit-tap-highlight-color: transparent;
73
- }
74
-
75
- /* ---- Variants ---------------------------------------------------- */
76
-
77
- /* Solid titanium block with a black label. */
78
- :global(.hp-button[data-variant='primary']) {
79
- background: var(--accent);
80
- color: var(--canvas);
81
- }
82
- /* Outlined: a 3:1 boundary, titanium label, black fill. */
83
- :global(.hp-button[data-variant='secondary']) {
84
- border: 1px solid var(--border-control);
85
- background: var(--canvas);
86
- }
87
- /* The label alone. */
88
- :global(.hp-button[data-variant='tertiary']) {
89
- background: transparent;
90
- }
91
-
92
- /* ---- Opens another view: a small ▸ drawn in CSS ------------------ */
93
-
94
- :global(.hp-button[data-opens]::after) {
95
- content: '';
96
- flex: none;
97
- width: 6px;
98
- height: 8px;
99
- background: currentColor;
100
- clip-path: polygon(0 0, 100% 50%, 0 100%);
101
- }
102
-
103
- /* ---- Icon only: a square ----------------------------------------- */
104
-
105
- :global(.hp-button[data-icon]) {
106
- justify-content: center;
107
- width: var(--control-height);
108
- padding: 0;
109
- }
110
- /* The icon is the consumer's inline <svg>; it draws in currentColor. */
111
- :global(.hp-button svg) {
112
- flex: none;
113
- }
114
- :global(.hp-button[data-icon] svg) {
115
- width: var(--space-4);
116
- height: var(--space-4);
117
- }
118
-
119
- /* ---- Hover: fine pointers only ----------------------------------- */
120
-
121
- @media (hover: hover) and (pointer: fine) {
122
- :global(.hp-button) {
123
- transition:
124
- background-color var(--dur-hover) var(--settle),
125
- color var(--dur-hover) var(--settle);
126
- }
127
- :global(.hp-button:active:not(:disabled):not([aria-disabled='true'])) {
128
- transition-duration: var(--dur-press);
129
- }
130
- :global(.hp-button[data-variant='primary']:hover:not(:disabled):not([aria-disabled='true'])) {
131
- background: var(--muted);
132
- }
133
- :global(.hp-button[data-variant='secondary']:hover:not(:disabled):not([aria-disabled='true'])),
134
- :global(.hp-button[data-variant='tertiary']:hover:not(:disabled):not([aria-disabled='true'])) {
135
- background: var(--surface-hover);
136
- }
137
- /* The tint alone barely shows (1.03:1), so the label also underlines. */
138
- :global(.hp-button[data-variant='tertiary']:hover:not(:disabled):not([aria-disabled='true'])) {
139
- text-decoration: underline;
140
- text-decoration-thickness: 1px;
141
- text-underline-offset: 0.3em;
142
- }
143
- }
144
-
145
- /* ---- Press: after hover, so it wins while the pointer is down ----- */
146
-
147
- :global(.hp-button[data-variant='primary']:active:not(:disabled):not([aria-disabled='true'])) {
148
- background: var(--muted);
149
- }
150
- /* One step past the hover tint, so a press reads on a phone too. */
151
- :global(.hp-button[data-variant='secondary']:active:not(:disabled):not([aria-disabled='true'])),
152
- :global(.hp-button[data-variant='tertiary']:active:not(:disabled):not([aria-disabled='true'])) {
153
- background: var(--surface-raised);
154
- }
155
-
156
- /* ---- Disabled: muted ink. A <button> is not focusable; a link has
157
- no href. -------------------------------------------------------- */
158
-
159
- :global(.hp-button:disabled),
160
- :global(.hp-button[aria-disabled='true']) {
161
- color: var(--muted);
162
- cursor: not-allowed;
163
- }
164
- :global(.hp-button[data-variant='primary']:disabled),
165
- :global(.hp-button[data-variant='primary'][aria-disabled='true']) {
166
- /* --muted is 4.9:1 on the band. */
167
- background: var(--surface-band);
168
- }
169
- :global(.hp-button[data-variant='secondary']:disabled),
170
- :global(.hp-button[data-variant='secondary'][aria-disabled='true']) {
171
- /* An off control needs no 3:1 boundary. */
172
- border-color: var(--border);
173
- }
174
- </style>
1
+ <script lang="ts" module>
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
4
+
5
+ export type ButtonVariant = 'primary' | 'secondary' | 'tertiary';
6
+
7
+ type ButtonOwnProps = {
8
+ /**
9
+ * `primary`: solid titanium block, for the view's one group of solid
10
+ * blocks. `secondary` (default): outlined. `tertiary`: caps label only.
11
+ */
12
+ variant?: ButtonVariant;
13
+ /** Ends the label in a small ▸: the button opens another view. */
14
+ opens?: boolean;
15
+ /**
16
+ * A square, icon-only button (height and width are `--control-height`).
17
+ * It has no visible label, so it needs an accessible name: pass
18
+ * `aria-label`.
19
+ */
20
+ icon?: boolean;
21
+ /** The `<button>`, or the `<a>` when `href` is set. */
22
+ ref?: HTMLElement | null;
23
+ children?: Snippet;
24
+ };
25
+
26
+ /**
27
+ * An `<a>` when `href` is set, a `<button>` otherwise. Attributes and
28
+ * handlers not listed here go to the element.
29
+ */
30
+ export type ButtonProps =
31
+ | (ButtonOwnProps &
32
+ Omit<HTMLButtonAttributes, 'children' | 'type' | 'href'> & {
33
+ type?: HTMLButtonAttributes['type'];
34
+ href?: never;
35
+ })
36
+ | (ButtonOwnProps &
37
+ Omit<HTMLAnchorAttributes, 'children' | 'type' | 'href'> & {
38
+ href: HTMLAnchorAttributes['href'];
39
+ type?: never;
40
+ disabled?: HTMLButtonAttributes['disabled'];
41
+ });
42
+ </script>
43
+
44
+ <script lang="ts">
45
+ let {
46
+ variant = 'secondary',
47
+ opens = false,
48
+ icon = false,
49
+ class: className,
50
+ ref = $bindable(null),
51
+ href,
52
+ disabled,
53
+ children,
54
+ ...rest
55
+ }: ButtonProps = $props();
56
+
57
+ // `rest` holds one element's attributes; each branch reads it as its own.
58
+ const asButton = (attributes: typeof rest) => attributes as HTMLButtonAttributes;
59
+ const asLink = (attributes: typeof rest) => attributes as HTMLAnchorAttributes;
60
+ </script>
61
+
62
+ <!--
63
+ A plain <button> without `href`, an <a> with it, with no component layer
64
+ between: a transcript may draw hundreds. A disabled link renders without
65
+ href, with role="link", aria-disabled="true" and tabindex -1; a disabled
66
+ <button> is not focusable.
67
+ -->
68
+ {#if !href}
69
+ <button
70
+ bind:this={ref}
71
+ class={['hp-button', 'hp-label', className]}
72
+ data-variant={variant}
73
+ data-opens={opens || undefined}
74
+ data-icon={icon || undefined}
75
+ {disabled}
76
+ {...asButton(rest)}
77
+ >
78
+ {@render children?.()}
79
+ </button>
80
+ {:else}
81
+ <a
82
+ bind:this={ref}
83
+ class={['hp-button', 'hp-label', className]}
84
+ data-variant={variant}
85
+ data-opens={opens || undefined}
86
+ data-icon={icon || undefined}
87
+ href={disabled ? undefined : href}
88
+ role={disabled ? 'link' : undefined}
89
+ aria-disabled={disabled ? 'true' : undefined}
90
+ tabindex={disabled ? -1 : undefined}
91
+ {...asLink(rest)}
92
+ >
93
+ {@render children?.()}
94
+ </a>
95
+ {/if}
96
+
97
+ <style>
98
+ /* Global rules keyed on .hp-button and its data-*, at one class of
99
+ specificity as when Bits UI rendered the element, so an app's rules
100
+ that override them still apply. */
101
+ :global(.hp-button) {
102
+ display: inline-flex;
103
+ align-items: center;
104
+ justify-content: space-between;
105
+ gap: var(--space-4);
106
+ box-sizing: border-box;
107
+ height: var(--control-height);
108
+ /* The visible box is the hit area: 36px fine, 44px coarse, and never
109
+ narrower than --hit-target for a short label. */
110
+ min-width: var(--hit-target);
111
+ padding: 0 var(--space-3);
112
+ border: 0;
113
+ background: transparent;
114
+ color: var(--text);
115
+ font-family: var(--sans);
116
+ text-decoration: none;
117
+ white-space: nowrap;
118
+ cursor: pointer;
119
+ -webkit-tap-highlight-color: transparent;
120
+ }
121
+
122
+ /* ---- Variants ---------------------------------------------------- */
123
+
124
+ /* Solid titanium block with a black label. */
125
+ :global(.hp-button[data-variant='primary']) {
126
+ background: var(--accent);
127
+ color: var(--canvas);
128
+ }
129
+ /* Outlined: a 3:1 boundary, titanium label, black fill. */
130
+ :global(.hp-button[data-variant='secondary']) {
131
+ border: 1px solid var(--border-control);
132
+ background: var(--canvas);
133
+ }
134
+ /* The label alone. */
135
+ :global(.hp-button[data-variant='tertiary']) {
136
+ background: transparent;
137
+ }
138
+
139
+ /* ---- Opens another view: a small ▸ drawn in CSS ------------------ */
140
+
141
+ :global(.hp-button[data-opens]::after) {
142
+ content: '';
143
+ flex: none;
144
+ width: 6px;
145
+ height: 8px;
146
+ background: currentColor;
147
+ clip-path: polygon(0 0, 100% 50%, 0 100%);
148
+ }
149
+
150
+ /* ---- Icon only: a square ----------------------------------------- */
151
+
152
+ :global(.hp-button[data-icon]) {
153
+ justify-content: center;
154
+ width: var(--control-height);
155
+ padding: 0;
156
+ }
157
+ /* The icon is the consumer's inline <svg>; it draws in currentColor. */
158
+ :global(.hp-button svg) {
159
+ flex: none;
160
+ }
161
+ :global(.hp-button[data-icon] svg) {
162
+ width: var(--space-4);
163
+ height: var(--space-4);
164
+ }
165
+
166
+ /* ---- Hover: fine pointers only ----------------------------------- */
167
+
168
+ @media (hover: hover) and (pointer: fine) {
169
+ :global(.hp-button) {
170
+ transition:
171
+ background-color var(--dur-hover) var(--settle),
172
+ color var(--dur-hover) var(--settle);
173
+ }
174
+ :global(.hp-button:active:not(:disabled):not([aria-disabled='true'])) {
175
+ transition-duration: var(--dur-press);
176
+ }
177
+ :global(.hp-button[data-variant='primary']:hover:not(:disabled):not([aria-disabled='true'])) {
178
+ background: var(--muted);
179
+ }
180
+ :global(.hp-button[data-variant='secondary']:hover:not(:disabled):not([aria-disabled='true'])),
181
+ :global(.hp-button[data-variant='tertiary']:hover:not(:disabled):not([aria-disabled='true'])) {
182
+ background: var(--surface-hover);
183
+ }
184
+ /* The tint alone barely shows (1.03:1), so the label also underlines. */
185
+ :global(.hp-button[data-variant='tertiary']:hover:not(:disabled):not([aria-disabled='true'])) {
186
+ text-decoration: underline;
187
+ text-decoration-thickness: 1px;
188
+ text-underline-offset: 0.3em;
189
+ }
190
+ }
191
+
192
+ /* ---- Press: after hover, so it wins while the pointer is down ----- */
193
+
194
+ :global(.hp-button[data-variant='primary']:active:not(:disabled):not([aria-disabled='true'])) {
195
+ background: var(--muted);
196
+ }
197
+ /* One step past the hover tint, so a press reads on a phone too. */
198
+ :global(.hp-button[data-variant='secondary']:active:not(:disabled):not([aria-disabled='true'])),
199
+ :global(.hp-button[data-variant='tertiary']:active:not(:disabled):not([aria-disabled='true'])) {
200
+ background: var(--surface-raised);
201
+ }
202
+
203
+ /* ---- Disabled: muted ink. A <button> is not focusable; a link has
204
+ no href. -------------------------------------------------------- */
205
+
206
+ :global(.hp-button:disabled),
207
+ :global(.hp-button[aria-disabled='true']) {
208
+ color: var(--muted);
209
+ cursor: not-allowed;
210
+ }
211
+ :global(.hp-button[data-variant='primary']:disabled),
212
+ :global(.hp-button[data-variant='primary'][aria-disabled='true']) {
213
+ /* --muted is 4.9:1 on the band. */
214
+ background: var(--surface-band);
215
+ }
216
+ :global(.hp-button[data-variant='secondary']:disabled),
217
+ :global(.hp-button[data-variant='secondary'][aria-disabled='true']) {
218
+ /* An off control needs no 3:1 boundary. */
219
+ border-color: var(--border);
220
+ }
221
+ </style>
@@ -1,6 +1,7 @@
1
- import { Button as BitsButton } from 'bits-ui';
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
2
3
  export type ButtonVariant = 'primary' | 'secondary' | 'tertiary';
3
- export type ButtonProps = BitsButton.RootProps & {
4
+ type ButtonOwnProps = {
4
5
  /**
5
6
  * `primary`: solid titanium block, for the view's one group of solid
6
7
  * blocks. `secondary` (default): outlined. `tertiary`: caps label only.
@@ -14,7 +15,22 @@ export type ButtonProps = BitsButton.RootProps & {
14
15
  * `aria-label`.
15
16
  */
16
17
  icon?: boolean;
18
+ /** The `<button>`, or the `<a>` when `href` is set. */
19
+ ref?: HTMLElement | null;
20
+ children?: Snippet;
17
21
  };
22
+ /**
23
+ * An `<a>` when `href` is set, a `<button>` otherwise. Attributes and
24
+ * handlers not listed here go to the element.
25
+ */
26
+ export type ButtonProps = (ButtonOwnProps & Omit<HTMLButtonAttributes, 'children' | 'type' | 'href'> & {
27
+ type?: HTMLButtonAttributes['type'];
28
+ href?: never;
29
+ }) | (ButtonOwnProps & Omit<HTMLAnchorAttributes, 'children' | 'type' | 'href'> & {
30
+ href: HTMLAnchorAttributes['href'];
31
+ type?: never;
32
+ disabled?: HTMLButtonAttributes['disabled'];
33
+ });
18
34
  declare const Button: import("svelte").Component<ButtonProps, {}, "ref">;
19
35
  type Button = ReturnType<typeof Button>;
20
36
  export default Button;