@blotch/dolan 22.2.4 → 22.2.5

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 (124) hide show
  1. package/dist/commands/add.test.js +2 -0
  2. package/dist/commands/add.test.js.map +1 -1
  3. package/dist/commands/doctor.js +78 -21
  4. package/dist/commands/doctor.js.map +1 -1
  5. package/dist/commands/doctor.test.js +167 -26
  6. package/dist/commands/doctor.test.js.map +1 -1
  7. package/dist/commands/init.test.js +4 -7
  8. package/dist/commands/init.test.js.map +1 -1
  9. package/dist/commands/update.d.ts +3 -1
  10. package/dist/commands/update.js +78 -15
  11. package/dist/commands/update.js.map +1 -1
  12. package/dist/commands/update.test.js +257 -2
  13. package/dist/commands/update.test.js.map +1 -1
  14. package/dist/lockfile.d.ts +10 -0
  15. package/dist/lockfile.js +20 -1
  16. package/dist/lockfile.js.map +1 -1
  17. package/dist/lockfile.test.js +43 -3
  18. package/dist/lockfile.test.js.map +1 -1
  19. package/dist/registry.js +73 -11
  20. package/dist/registry.js.map +1 -1
  21. package/dist/registry.test.js +16 -3
  22. package/dist/registry.test.js.map +1 -1
  23. package/dist/test-utils.d.ts +24 -2
  24. package/dist/test-utils.js +41 -2
  25. package/dist/test-utils.js.map +1 -1
  26. package/dist/ui/boolean-inputs.test.ts +76 -0
  27. package/dist/ui/components/action-sheet/action-sheet.test.ts +370 -1
  28. package/dist/ui/components/action-sheet/action-sheet.ts +306 -28
  29. package/dist/ui/components/action-sheet/index.ts +1 -0
  30. package/dist/ui/components/alert-dialog/alert-dialog.test.ts +552 -8
  31. package/dist/ui/components/alert-dialog/alert-dialog.ts +644 -36
  32. package/dist/ui/components/alert-dialog/index.ts +5 -0
  33. package/dist/ui/components/area-chart/area-chart.ts +3 -2
  34. package/dist/ui/components/badge/badge.ts +2 -1
  35. package/dist/ui/components/bottom-sheet/bottom-sheet.test.ts +968 -3
  36. package/dist/ui/components/bottom-sheet/bottom-sheet.ts +1021 -95
  37. package/dist/ui/components/bottom-sheet/index.ts +7 -1
  38. package/dist/ui/components/button/button.test.ts +36 -1
  39. package/dist/ui/components/button/button.ts +17 -7
  40. package/dist/ui/components/button-group/button-group.test.ts +53 -9
  41. package/dist/ui/components/button-group/button-group.ts +67 -21
  42. package/dist/ui/components/card/card.test.ts +16 -0
  43. package/dist/ui/components/card/card.ts +2 -1
  44. package/dist/ui/components/chart/chart-presets.ts +6 -6
  45. package/dist/ui/components/chart/chart.test.ts +14 -0
  46. package/dist/ui/components/chart/chart.ts +10 -3
  47. package/dist/ui/components/checkbox/checkbox.ts +2 -1
  48. package/dist/ui/components/collapsible/collapsible.ts +2 -1
  49. package/dist/ui/components/dialog/dialog.ts +6 -6
  50. package/dist/ui/components/dock/dock-scroll.ts +9 -0
  51. package/dist/ui/components/dock/dock-search.test.ts +594 -0
  52. package/dist/ui/components/dock/dock.test.ts +4 -1
  53. package/dist/ui/components/dock/dock.ts +529 -51
  54. package/dist/ui/components/dynamic-color/dynamic-color.test.ts +144 -0
  55. package/dist/ui/components/dynamic-color/dynamic-color.ts +146 -0
  56. package/dist/ui/components/dynamic-color/index.ts +5 -0
  57. package/dist/ui/components/glass/glass.test.ts +39 -1
  58. package/dist/ui/components/glass/glass.ts +87 -17
  59. package/dist/ui/components/glass/index.ts +1 -0
  60. package/dist/ui/components/icon/icon-theme.test.ts +28 -0
  61. package/dist/ui/components/icon/icon-theme.ts +38 -7
  62. package/dist/ui/components/input/input.ts +2 -1
  63. package/dist/ui/components/label/label.ts +8 -2
  64. package/dist/ui/components/line-chart/line-chart.ts +3 -2
  65. package/dist/ui/components/list/list.ts +5 -4
  66. package/dist/ui/components/menu/menu-popup.test.ts +18 -14
  67. package/dist/ui/components/menu/menu-popup.ts +24 -3
  68. package/dist/ui/components/menu/menu.test.ts +99 -5
  69. package/dist/ui/components/menu/menu.ts +74 -34
  70. package/dist/ui/components/nav-drawer/nav-drawer.ts +3 -2
  71. package/dist/ui/components/navigation-bar/index.ts +1 -0
  72. package/dist/ui/components/navigation-bar/navigation-bar.test.ts +425 -0
  73. package/dist/ui/components/navigation-bar/navigation-bar.ts +411 -0
  74. package/dist/ui/components/popover/index.ts +9 -0
  75. package/dist/ui/components/popover/popover-panel.test.ts +735 -0
  76. package/dist/ui/components/popover/popover-panel.ts +603 -0
  77. package/dist/ui/components/popover/popover.test.ts +286 -0
  78. package/dist/ui/components/popover/popover.ts +207 -0
  79. package/dist/ui/components/progress/progress.ts +2 -1
  80. package/dist/ui/components/radio-group/radio-group.ts +2 -1
  81. package/dist/ui/components/scroll-area/scroll-area.ts +4 -3
  82. package/dist/ui/components/search-field/index.ts +15 -0
  83. package/dist/ui/components/search-field/keyboard.test.ts +147 -0
  84. package/dist/ui/components/search-field/keyboard.ts +123 -0
  85. package/dist/ui/components/search-field/search-field.test.ts +549 -0
  86. package/dist/ui/components/search-field/search-field.ts +628 -0
  87. package/dist/ui/components/segmented-control/index.ts +8 -0
  88. package/dist/ui/components/segmented-control/segmented-control.test.ts +861 -0
  89. package/dist/ui/components/segmented-control/segmented-control.ts +884 -0
  90. package/dist/ui/components/select/select.ts +2 -1
  91. package/dist/ui/components/sheet/sheet.test.ts +90 -3
  92. package/dist/ui/components/sheet/sheet.ts +59 -4
  93. package/dist/ui/components/slider/index.ts +1 -0
  94. package/dist/ui/components/slider/slider.test.ts +695 -0
  95. package/dist/ui/components/slider/slider.ts +901 -0
  96. package/dist/ui/components/switch/index.ts +1 -1
  97. package/dist/ui/components/switch/switch.test.ts +464 -48
  98. package/dist/ui/components/switch/switch.ts +613 -43
  99. package/dist/ui/components/tabs/index.ts +7 -1
  100. package/dist/ui/components/tabs/tabs.test.ts +278 -2
  101. package/dist/ui/components/tabs/tabs.ts +233 -30
  102. package/dist/ui/components/textarea/textarea.ts +2 -1
  103. package/dist/ui/components/toggle/index.ts +1 -0
  104. package/dist/ui/components/toggle/toggle.test.ts +310 -4
  105. package/dist/ui/components/toggle/toggle.ts +241 -26
  106. package/dist/ui/components/toolbar/bar-scroll.test.ts +310 -0
  107. package/dist/ui/components/toolbar/bar-scroll.ts +372 -0
  108. package/dist/ui/components/toolbar/index.ts +12 -0
  109. package/dist/ui/components/toolbar/toolbar.test.ts +438 -0
  110. package/dist/ui/components/toolbar/toolbar.ts +535 -0
  111. package/dist/utils/analyze.d.ts +10 -5
  112. package/dist/utils/analyze.js +3 -2
  113. package/dist/utils/analyze.js.map +1 -1
  114. package/dist/utils/installed.d.ts +13 -1
  115. package/dist/utils/installed.js +17 -0
  116. package/dist/utils/installed.js.map +1 -1
  117. package/dist/utils/installed.test.js +39 -1
  118. package/dist/utils/installed.test.js.map +1 -1
  119. package/dist/utils/tailwind.d.ts +25 -5
  120. package/dist/utils/tailwind.js +53 -14
  121. package/dist/utils/tailwind.js.map +1 -1
  122. package/dist/utils/tailwind.test.js +85 -22
  123. package/dist/utils/tailwind.test.js.map +1 -1
  124. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  Component,
3
3
  ViewEncapsulation,
4
+ booleanAttribute,
4
5
  computed,
5
6
  contentChildren,
6
7
  inject,
@@ -50,7 +51,7 @@ const selectItem = () => UiSelectItem;
50
51
  export class UiSelect {
51
52
  readonly value = model<string>('');
52
53
  readonly placeholder = input('Select...');
53
- readonly disabled = input(false);
54
+ readonly disabled = input(false, { transform: booleanAttribute });
54
55
  readonly userClass = input<string>('', { alias: 'class' });
55
56
 
56
57
  readonly changed = output<string>();
@@ -1,11 +1,13 @@
1
- import { Component, signal } from '@angular/core';
1
+ import { Component, type WritableSignal, signal } from '@angular/core';
2
2
  import {
3
3
  fireEvent,
4
4
  render,
5
5
  waitForUpdate,
6
6
  } from '@blotch/angular-lynx-testing-library';
7
7
  import { LYNX_ELEMENTS } from '@blotch/angular-lynx';
8
- import { describe, expect, it, vi } from 'vitest';
8
+ import { afterEach, describe, expect, it, vi } from 'vitest';
9
+ import { type SheetDetent, UiSheetSource } from '../bottom-sheet/bottom-sheet';
10
+ import { UiGlass } from '../glass/glass';
9
11
  import {
10
12
  UiSheet,
11
13
  UiSheetDescription,
@@ -38,6 +40,25 @@ class SheetHost {
38
40
  readonly closed = vi.fn();
39
41
  }
40
42
 
43
+ /**
44
+ * A glass sheet presented by a glass button, which comes first, as a button
45
+ * above the sheet does.
46
+ */
47
+ @Component({
48
+ imports: [UiSheet, UiSheetSource, UiGlass, LYNX_ELEMENTS],
49
+ template: `
50
+ <blur-view ui-glass class="source" [uiSheetSource]="sheet">
51
+ <text>Add</text>
52
+ </blur-view>
53
+ <ui-sheet #sheet variant="glass" [(open)]="open">
54
+ <text>Body</text>
55
+ </ui-sheet>
56
+ `,
57
+ })
58
+ class SourceHost {
59
+ readonly open = signal(false);
60
+ }
61
+
41
62
  const renderSheet = async () => {
42
63
  const result = await render(SheetHost);
43
64
  return {
@@ -52,7 +73,7 @@ const renderSheet = async () => {
52
73
  * Opens the sheet and waits out its open sequence: the overlay shows on one
53
74
  * tick, and the panel slides in on the next.
54
75
  */
55
- const openSheet = async (host: SheetHost) => {
76
+ const openSheet = async (host: { readonly open: WritableSignal<boolean> }) => {
56
77
  host.open.set(true);
57
78
  for (let i = 0; i < 3; i++) await waitForUpdate();
58
79
  };
@@ -95,3 +116,69 @@ describe('UiSheet', () => {
95
116
  expect(host.closed).toHaveBeenCalledOnce();
96
117
  });
97
118
  });
119
+
120
+ @Component({
121
+ imports: [UiSheet, LYNX_ELEMENTS],
122
+ template: `
123
+ <ui-sheet
124
+ [(open)]="open"
125
+ variant="glass"
126
+ [detents]="['medium', 'large']"
127
+ [(detent)]="detent"
128
+ >
129
+ <text>Body</text>
130
+ </ui-sheet>
131
+ `,
132
+ })
133
+ class GlassSheetHost {
134
+ readonly open = signal(false);
135
+ readonly detent = signal<SheetDetent | undefined>(undefined);
136
+ }
137
+
138
+ describe('UiSheet glass variant', () => {
139
+ afterEach(() => vi.unstubAllGlobals());
140
+
141
+ it('passes the variant and the detents to its bottom sheet', async () => {
142
+ vi.stubGlobal('SystemInfo', { platform: 'iOS', osVersion: '26.0' });
143
+ const { componentRef, container, getByText } = await render(GlassSheetHost);
144
+ const host = componentRef.instance as GlassSheetHost;
145
+ // A sheet with heights of its own lets its content fill it.
146
+ expect(getByText('Body').parentElement?.classList).toContain('flex-1');
147
+
148
+ // Laid out as on a phone, which the medium and large detents need.
149
+ const backdrop = container.querySelector('overlay > view')!;
150
+ fireEvent.layoutchange(backdrop, { detail: { height: 874 } });
151
+ fireEvent.layoutchange(backdrop.firstElementChild!, {
152
+ detail: { height: 812 },
153
+ });
154
+ await openSheet(host);
155
+ expect(
156
+ container.querySelector('blur-view')?.getAttribute('blur-effect'),
157
+ ).toBe('glass');
158
+ expect(host.detent()).toBe('medium');
159
+
160
+ // The grabber moves it to the next detent, and the host hears of it.
161
+ const grabber = container.querySelector('overlay .rounded-full')!;
162
+ fireEvent.tap(grabber.parentElement!, { eventType: 'catchEvent' });
163
+ await waitForUpdate();
164
+ expect(host.detent()).toBe('large');
165
+ });
166
+ });
167
+
168
+ describe('UiSheet grown out of its control', () => {
169
+ afterEach(() => vi.unstubAllGlobals());
170
+
171
+ it('hands the control on to its bottom sheet, which pairs their glass', async () => {
172
+ vi.stubGlobal('SystemInfo', { platform: 'iOS', osVersion: '26.0' });
173
+ const { container } = await render(SourceHost);
174
+ const source = container.querySelector('.source')!;
175
+ const glass = container.querySelector('overlay blur-view[ui-glass]')!;
176
+
177
+ expect(source.getAttribute('glass-effect-id')).toMatch(/^ui-sheet-\d+$/);
178
+ expect(glass.getAttribute('glass-effect-id')).toBe(
179
+ source.getAttribute('glass-effect-id'),
180
+ );
181
+ // Shown until the sheet covers it.
182
+ expect((source as HTMLElement).style.visibility).toBe('');
183
+ });
184
+ });
@@ -5,21 +5,38 @@ import {
5
5
  input,
6
6
  model,
7
7
  output,
8
+ viewChild,
8
9
  } from '@angular/core';
9
10
  import { LYNX_ELEMENTS } from '@blotch/angular-lynx';
10
11
 
11
- import { UiBottomSheet } from '../bottom-sheet/bottom-sheet';
12
+ import {
13
+ type BottomSheetVariant,
14
+ type SheetDetent,
15
+ type SheetSourceTarget,
16
+ UiBottomSheet,
17
+ } from '../bottom-sheet/bottom-sheet';
12
18
  import { cn } from '../../utils/cn';
13
19
 
20
+ /**
21
+ * `UiBottomSheet`, for the sheet's view query. A call rather than the class
22
+ * itself: for a class, Angular's test build keeps an arrow function that
23
+ * nothing calls, which an app's coverage report would show as uncovered.
24
+ */
25
+ const bottomSheetType = () => UiBottomSheet;
26
+
14
27
  /**
15
28
  * Styled bottom sheet: a thin wrapper over the shared `ui-bottom-sheet`
16
29
  * primitive that adds content padding and pairs with the header/title/
17
30
  * description/footer layout helpers below. All the overlay, animation, and
18
- * drag-to-dismiss behavior lives in `ui-bottom-sheet`.
31
+ * drag-to-dismiss behavior lives in `ui-bottom-sheet`, and so do the glass
32
+ * variant and the detents, which pass straight through.
19
33
  *
20
34
  * The consumer's `class` and the built-in padding are applied to an inner
21
35
  * content wrapper (not the panel) — the panel chrome (rounded corners, border,
22
36
  * background) comes from the primitive.
37
+ *
38
+ * Mark the control that presents it with `[uiSheetSource]="sheet"`, and the
39
+ * glass sheet grows out of it (see UiSheetSource).
23
40
  */
24
41
  @Component({
25
42
  selector: 'ui-sheet',
@@ -34,6 +51,10 @@ import { cn } from '../../utils/cn';
34
51
  <ui-bottom-sheet
35
52
  [open]="open()"
36
53
  (openChange)="open.set($event)"
54
+ [variant]="variant()"
55
+ [detents]="detents()"
56
+ [detent]="detent()"
57
+ (detentChange)="detent.set($event)"
37
58
  (closed)="closed.emit()"
38
59
  >
39
60
  <view [class]="contentClass()">
@@ -42,14 +63,48 @@ import { cn } from '../../utils/cn';
42
63
  </ui-bottom-sheet>
43
64
  `,
44
65
  })
45
- export class UiSheet {
66
+ export class UiSheet implements SheetSourceTarget {
46
67
  readonly open = model(false);
47
68
  readonly userClass = input<string>('', { alias: 'class' });
69
+ /** `'default'` or `'glass'`; see BottomSheetVariant. */
70
+ readonly variant = input<BottomSheetVariant>('default');
71
+ /** The heights the sheet rests at; see UiBottomSheet's `detents`. */
72
+ readonly detents = input<readonly SheetDetent[]>(['fit']);
73
+ /** The detent the sheet rests at; see UiBottomSheet's `detent`. */
74
+ readonly detent = model<SheetDetent>();
48
75
 
49
76
  readonly closed = output<void>();
50
77
 
78
+ // Required: always in the template.
79
+ readonly bottomSheet = viewChild.required(bottomSheetType());
80
+
81
+ /**
82
+ * Whether the sheet covers the control that presents it; see
83
+ * UiSheetSource.
84
+ */
85
+ coversSource(): boolean {
86
+ return this.bottomSheet().coversSource();
87
+ }
88
+
89
+ /**
90
+ * @internal Called by the `uiSheetSource` directive, for the sheet this
91
+ * one draws on.
92
+ */
93
+ setSource(...source: Parameters<SheetSourceTarget['setSource']>): void {
94
+ this.bottomSheet().setSource(...source);
95
+ }
96
+
97
+ /**
98
+ * At a detent with a height of its own, the content fills the sheet as a
99
+ * column, so a `flex-1` scroll view in it gets the height that's left.
100
+ */
51
101
  protected readonly contentClass = computed(() =>
52
- cn('px-6 pb-6', this.userClass()),
102
+ cn(
103
+ 'px-6 pb-6',
104
+ this.detents().some((detent) => detent !== 'fit') &&
105
+ 'flex-1 flex-col flex',
106
+ this.userClass(),
107
+ ),
53
108
  );
54
109
  }
55
110
 
@@ -0,0 +1 @@
1
+ export { UiSlider, type SliderVariant } from './slider';