@radix-ng/primitives 0.1.0 → 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 +2 -4
- package/checkbox/src/checkbox-indicator.directive.d.ts +6 -0
- package/checkbox/src/checkbox.directive.d.ts +71 -0
- package/checkbox/src/checkbox.token.d.ts +4 -0
- package/esm2022/checkbox/index.mjs +4 -0
- package/esm2022/checkbox/radix-ng-primitives-checkbox.mjs +5 -0
- package/esm2022/checkbox/src/checkbox-indicator.directive.mjs +23 -0
- package/esm2022/checkbox/src/checkbox.directive.mjs +135 -0
- package/esm2022/checkbox/src/checkbox.token.mjs +6 -0
- package/esm2022/index.mjs +2 -0
- package/esm2022/label/index.mjs +2 -0
- package/esm2022/label/radix-ng-primitives-label.mjs +5 -0
- package/esm2022/label/src/label.directive.mjs +46 -0
- package/esm2022/progress/index.mjs +3 -0
- package/esm2022/progress/radix-ng-primitives-progress.mjs +5 -0
- package/esm2022/progress/src/progress-indicator.directive.mjs +23 -0
- package/esm2022/progress/src/progress.directive.mjs +62 -0
- package/esm2022/progress/src/progress.token.mjs +6 -0
- package/esm2022/radio/index.mjs +6 -0
- package/esm2022/radio/radix-ng-primitives-radio.mjs +5 -0
- package/esm2022/radio/src/radio-group.directive.mjs +108 -0
- package/esm2022/radio/src/radio-group.token.mjs +6 -0
- package/esm2022/radio/src/radio-indicator.directive.mjs +30 -0
- package/esm2022/radio/src/radio-item.directive.mjs +79 -0
- package/esm2022/radio/src/radio-item.token.mjs +6 -0
- package/esm2022/radix-ng-primitives.mjs +5 -0
- package/esm2022/roving-focus/index.mjs +5 -0
- package/esm2022/roving-focus/radix-ng-primitives-roving-focus.mjs +5 -0
- package/esm2022/roving-focus/src/roving-focus-group.directive.mjs +115 -0
- package/esm2022/roving-focus/src/roving-focus-group.token.mjs +9 -0
- package/esm2022/roving-focus/src/roving-focus-item.directive.mjs +91 -0
- package/esm2022/roving-focus/src/roving-focus-item.token.mjs +6 -0
- package/esm2022/separator/index.mjs +2 -0
- package/esm2022/separator/radix-ng-primitives-separator.mjs +5 -0
- package/esm2022/separator/src/separator.directive.mjs +37 -0
- package/esm2022/switch/index.mjs +4 -0
- package/esm2022/switch/radix-ng-primitives-switch.mjs +5 -0
- package/esm2022/switch/src/switch-thumb.directive.mjs +25 -0
- package/esm2022/switch/src/switch.directive.mjs +125 -0
- package/esm2022/switch/src/switch.token.mjs +6 -0
- package/esm2022/visually-hidden/index.mjs +2 -0
- package/esm2022/visually-hidden/radix-ng-primitives-visually-hidden.mjs +5 -0
- package/esm2022/visually-hidden/src/visually-hidden.directive.mjs +42 -0
- package/fesm2022/radix-ng-primitives-checkbox.mjs +166 -0
- package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-label.mjs +53 -0
- package/fesm2022/radix-ng-primitives-label.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-progress.mjs +93 -0
- package/fesm2022/radix-ng-primitives-progress.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-radio.mjs +221 -0
- package/fesm2022/radix-ng-primitives-radio.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-roving-focus.mjs +220 -0
- package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-separator.mjs +44 -0
- package/fesm2022/radix-ng-primitives-separator.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-switch.mjs +158 -0
- package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-visually-hidden.mjs +49 -0
- package/fesm2022/radix-ng-primitives-visually-hidden.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives.mjs +4 -0
- package/fesm2022/radix-ng-primitives.mjs.map +1 -0
- package/label/src/label.directive.d.ts +14 -0
- package/package.json +88 -24
- package/progress/src/progress-indicator.directive.d.ts +6 -0
- package/progress/src/progress.directive.d.ts +26 -0
- package/progress/src/progress.token.d.ts +4 -0
- package/radio/README.md +1 -0
- package/radio/index.d.ts +5 -0
- package/radio/src/radio-group.directive.d.ts +65 -0
- package/radio/src/radio-group.token.d.ts +4 -0
- package/radio/src/radio-indicator.directive.d.ts +13 -0
- package/radio/src/radio-item.directive.d.ts +36 -0
- package/radio/src/radio-item.token.d.ts +4 -0
- package/roving-focus/src/roving-focus-group.directive.d.ts +55 -0
- package/roving-focus/src/roving-focus-group.token.d.ts +7 -0
- package/roving-focus/src/roving-focus-item.directive.d.ts +52 -0
- package/roving-focus/src/roving-focus-item.token.d.ts +4 -0
- package/separator/src/separator.directive.d.ts +16 -0
- package/switch/src/switch-thumb.directive.d.ts +9 -0
- package/switch/src/switch.directive.d.ts +73 -0
- package/switch/src/switch.token.d.ts +4 -0
- package/visually-hidden/src/visually-hidden.directive.d.ts +11 -0
- package/.docs/overview/accessibility.docs.mdx +0 -45
- package/.docs/overview/installation.docs.mdx +0 -15
- package/.docs/overview/introduction.docs.mdx +0 -59
- package/.docs/utils/storybook.ts +0 -30
- package/.eslintrc.json +0 -56
- package/.storybook/helpers/bages-config.ts +0 -43
- package/.storybook/main.ts +0 -24
- package/.storybook/manager-head.html +0 -76
- package/.storybook/manager.ts +0 -6
- package/.storybook/preview.ts +0 -58
- package/.storybook/rdxTheme.ts +0 -8
- package/.storybook/tsconfig.json +0 -20
- package/CHANGELOG.md +0 -6
- package/checkbox/ng-package.json +0 -5
- package/checkbox/src/checkbox-indicator.directive.ts +0 -15
- package/checkbox/src/checkbox.directive.ts +0 -138
- package/checkbox/src/checkbox.token.ts +0 -8
- package/checkbox/stories/checkbox.component.ts +0 -50
- package/checkbox/stories/checkbox.stories.ts +0 -29
- package/checkbox/stories/style.css +0 -265
- package/jest.config.ts +0 -22
- package/label/ng-package.json +0 -5
- package/label/src/label.directive.ts +0 -36
- package/label/stories/label.docs.mdx +0 -40
- package/label/stories/label.stories.ts +0 -63
- package/ng-package.json +0 -7
- package/progress/ng-package.json +0 -5
- package/progress/src/progress-indicator.directive.ts +0 -15
- package/progress/src/progress.directive.ts +0 -51
- package/progress/src/progress.token.ts +0 -8
- package/progress/stories/progress.docs.mdx +0 -66
- package/progress/stories/progress.stories.ts +0 -61
- package/project.json +0 -90
- package/roving-focus/ng-package.json +0 -5
- package/roving-focus/src/roving-focus-group.directive.ts +0 -135
- package/roving-focus/src/roving-focus-group.token.ts +0 -13
- package/roving-focus/src/roving-focus-item.directive.ts +0 -98
- package/roving-focus/src/roving-focus-item.token.ts +0 -10
- package/separator/ng-package.json +0 -5
- package/separator/src/separator.directive.spec.ts +0 -59
- package/separator/src/separator.directive.ts +0 -24
- package/separator/stories/separator.docs.mdx +0 -38
- package/separator/stories/separator.stories.ts +0 -91
- package/switch/ng-package.json +0 -5
- package/switch/src/switch-thumb.directive.ts +0 -17
- package/switch/src/switch.directive.ts +0 -132
- package/switch/src/switch.token.ts +0 -8
- package/switch/stories/switch.docs.mdx +0 -74
- package/switch/stories/switch.stories.ts +0 -76
- package/test-setup.ts +0 -8
- package/tsconfig.json +0 -32
- package/tsconfig.lib.json +0 -19
- package/tsconfig.lib.prod.json +0 -9
- package/tsconfig.spec.json +0 -21
- package/visually-hidden/ng-package.json +0 -5
- package/visually-hidden/src/visually-hidden.directive.spec.ts +0 -48
- package/visually-hidden/src/visually-hidden.directive.ts +0 -35
- package/visually-hidden/stories/visually-hidden.docs.mdx +0 -35
- /package/checkbox/{index.ts → index.d.ts} +0 -0
- /package/{index.ts → index.d.ts} +0 -0
- /package/label/{index.ts → index.d.ts} +0 -0
- /package/progress/{index.ts → index.d.ts} +0 -0
- /package/roving-focus/{index.ts → index.d.ts} +0 -0
- /package/separator/{index.ts → index.d.ts} +0 -0
- /package/switch/{index.ts → index.d.ts} +0 -0
- /package/visually-hidden/{index.ts → index.d.ts} +0 -0
@@ -1,51 +0,0 @@
|
|
1
|
-
import { Directive, Input, numberAttribute } from '@angular/core';
|
2
|
-
import { ProgressToken } from './progress.token';
|
3
|
-
|
4
|
-
@Directive({
|
5
|
-
selector: '[rdxProgress]',
|
6
|
-
standalone: true,
|
7
|
-
providers: [{ provide: ProgressToken, useExisting: ProgressDirective }],
|
8
|
-
host: {
|
9
|
-
role: 'progressbar',
|
10
|
-
'[attr.aria-valuemax]': 'max',
|
11
|
-
'[attr.aria-valuemin]': '0',
|
12
|
-
'[attr.aria-valuenow]': 'value',
|
13
|
-
'[attr.aria-valuetext]': 'valueLabel(value, max)',
|
14
|
-
'[attr.data-state]': 'state',
|
15
|
-
'[attr.data-value]': 'value',
|
16
|
-
'[attr.data-max]': 'max'
|
17
|
-
}
|
18
|
-
})
|
19
|
-
export class ProgressDirective {
|
20
|
-
/**
|
21
|
-
* Define the progress value.
|
22
|
-
*/
|
23
|
-
@Input({ alias: 'rdxProgressValue', transform: numberAttribute }) value = 0;
|
24
|
-
|
25
|
-
/**
|
26
|
-
* Define the progress max value.
|
27
|
-
* @default 100
|
28
|
-
*/
|
29
|
-
@Input({ alias: 'rdxProgressMax', transform: numberAttribute }) max = 100;
|
30
|
-
|
31
|
-
/**
|
32
|
-
* Define a function that returns the progress value label.
|
33
|
-
*/
|
34
|
-
@Input('rdxProgressValueLabel') valueLabel: (value: number, max: number) => string = (
|
35
|
-
value,
|
36
|
-
max
|
37
|
-
) => `${Math.round((value / max) * 100)}%`;
|
38
|
-
|
39
|
-
/**
|
40
|
-
* Get the state of the progress bar.
|
41
|
-
* @returns 'indeterminate' | 'loading' | 'complete'
|
42
|
-
* @internal
|
43
|
-
*/
|
44
|
-
get state(): 'indeterminate' | 'loading' | 'complete' {
|
45
|
-
return this.value == null
|
46
|
-
? 'indeterminate'
|
47
|
-
: this.value === this.max
|
48
|
-
? 'complete'
|
49
|
-
: 'loading';
|
50
|
-
}
|
51
|
-
}
|
@@ -1,8 +0,0 @@
|
|
1
|
-
import { InjectionToken, inject } from '@angular/core';
|
2
|
-
import type { ProgressDirective } from './progress.directive';
|
3
|
-
|
4
|
-
export const ProgressToken = new InjectionToken<ProgressDirective>('ProgressDirective');
|
5
|
-
|
6
|
-
export function injectProgress(): ProgressDirective {
|
7
|
-
return inject(ProgressToken);
|
8
|
-
}
|
@@ -1,66 +0,0 @@
|
|
1
|
-
import { ArgTypes, Canvas, Markdown, Meta } from '@storybook/addon-docs';
|
2
|
-
import { ProgressDirective } from '../src/progress.directive';
|
3
|
-
import { ProgressIndicatorDirective } from '../src/progress-indicator.directive';
|
4
|
-
import * as ProgressDirectiveStories from "./progress.stories";
|
5
|
-
|
6
|
-
<Meta
|
7
|
-
title="Primitives/Progress"
|
8
|
-
/>
|
9
|
-
|
10
|
-
# Progress
|
11
|
-
#### Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.
|
12
|
-
|
13
|
-
<Canvas sourceState='hidden' of={ProgressDirectiveStories.Default}></Canvas>
|
14
|
-
|
15
|
-
## Features
|
16
|
-
- ✅ Provides context for assistive technology to read the progress of a task.
|
17
|
-
|
18
|
-
## Usage
|
19
|
-
|
20
|
-
Get started with importing the directive:
|
21
|
-
|
22
|
-
```typescript
|
23
|
-
import { ProgressDirective, ProgressIndicatorDirective } from '@radix-ng/primitives/progress';
|
24
|
-
```
|
25
|
-
|
26
|
-
## Example
|
27
|
-
|
28
|
-
```html
|
29
|
-
<div rdxProgress [rdxProgressValue]="progress" class="ProgressRoot">
|
30
|
-
<div rdxProgressIndicator
|
31
|
-
[style.transform]="'translateX(-' + (100 - progress) +'%)'"
|
32
|
-
class="ProgressIndicator"
|
33
|
-
></div>
|
34
|
-
</div>
|
35
|
-
```
|
36
|
-
## API Reference
|
37
|
-
|
38
|
-
### ProgressDirective
|
39
|
-
<ArgTypes of={ProgressDirective} />
|
40
|
-
|
41
|
-
<Markdown>
|
42
|
-
{`
|
43
|
-
| Data Attribute | Value |
|
44
|
-
| ----------- | --------- |
|
45
|
-
| [data-state] | "complete" or "indeterminate" or "loading" |
|
46
|
-
| [data-value] | The current value |
|
47
|
-
| [data-max] | The max value |
|
48
|
-
`}
|
49
|
-
</Markdown>
|
50
|
-
|
51
|
-
### ProgressIndicatorDirective
|
52
|
-
Used to show the progress visually. It also makes progress accessible to assistive technologies.
|
53
|
-
|
54
|
-
<Markdown>
|
55
|
-
{`
|
56
|
-
| Data Attribute | Value |
|
57
|
-
| ----------- | --------- |
|
58
|
-
| [data-state] | "complete" or "indeterminate" or "loading" |
|
59
|
-
| [data-value] | The current value |
|
60
|
-
| [data-max] | The max value |
|
61
|
-
`}
|
62
|
-
</Markdown>
|
63
|
-
|
64
|
-
## Accessibility
|
65
|
-
|
66
|
-
Adheres to the [`progressbar` role requirements](https://www.w3.org/WAI/ARIA/apg/patterns/meter).
|
@@ -1,61 +0,0 @@
|
|
1
|
-
import { Meta, moduleMetadata, StoryObj } from '@storybook/angular';
|
2
|
-
import { ProgressDirective } from '../src/progress.directive';
|
3
|
-
import { ProgressIndicatorDirective } from '../src/progress-indicator.directive';
|
4
|
-
|
5
|
-
export default {
|
6
|
-
title: 'Primitives/Progress',
|
7
|
-
decorators: [
|
8
|
-
moduleMetadata({
|
9
|
-
imports: [ProgressDirective, ProgressIndicatorDirective]
|
10
|
-
})
|
11
|
-
],
|
12
|
-
argTypes: {
|
13
|
-
progress: {
|
14
|
-
options: ['10', '30', '70', '95'],
|
15
|
-
control: { type: 'select' }
|
16
|
-
}
|
17
|
-
}
|
18
|
-
} as Meta;
|
19
|
-
|
20
|
-
type Story = StoryObj;
|
21
|
-
|
22
|
-
export const Default: Story = {
|
23
|
-
args: {
|
24
|
-
progress: 70
|
25
|
-
},
|
26
|
-
render: (args) => ({
|
27
|
-
props: args,
|
28
|
-
template: `
|
29
|
-
<style>
|
30
|
-
.ProgressRoot {
|
31
|
-
position: relative;
|
32
|
-
overflow: hidden;
|
33
|
-
background: color(display-p3 0 0 0 / 0.7);;
|
34
|
-
border-radius: 99999px;
|
35
|
-
width: 300px;
|
36
|
-
height: 25px;
|
37
|
-
|
38
|
-
/* Fix overflow clipping in Safari */
|
39
|
-
/* https://gist.github.com/domske/b66047671c780a238b51c51ffde8d3a0 */
|
40
|
-
transform: translateZ(0);
|
41
|
-
}
|
42
|
-
|
43
|
-
.ProgressIndicator {
|
44
|
-
background-color: white;
|
45
|
-
width: 100%;
|
46
|
-
height: 100%;
|
47
|
-
transition: transform 660ms cubic-bezier(0.65, 0, 0.35, 1);
|
48
|
-
}
|
49
|
-
</style>
|
50
|
-
|
51
|
-
<div rdxProgress [rdxProgressValue]="progress" class="ProgressRoot">
|
52
|
-
<div rdxProgressIndicator
|
53
|
-
[style.transform]="'translateX(-' + (100 - progress) +'%)'"
|
54
|
-
class="ProgressIndicator"
|
55
|
-
></div>
|
56
|
-
</div>
|
57
|
-
`
|
58
|
-
})
|
59
|
-
};
|
60
|
-
|
61
|
-
//style(transform: \`translateX(-${100 - progress}%)\`)
|
package/project.json
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"name": "primitives",
|
3
|
-
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
4
|
-
"sourceRoot": "packages/primitives",
|
5
|
-
"prefix": "rdx",
|
6
|
-
"tags": [],
|
7
|
-
"projectType": "library",
|
8
|
-
"targets": {
|
9
|
-
"build": {
|
10
|
-
"executor": "@nx/angular:package",
|
11
|
-
"outputs": [
|
12
|
-
"{workspaceRoot}/dist/{projectRoot}"
|
13
|
-
],
|
14
|
-
"options": {
|
15
|
-
"project": "packages/primitives/ng-package.json"
|
16
|
-
},
|
17
|
-
"configurations": {
|
18
|
-
"production": {
|
19
|
-
"tsConfig": "packages/primitives/tsconfig.lib.prod.json"
|
20
|
-
},
|
21
|
-
"development": {
|
22
|
-
"tsConfig": "packages/primitives/tsconfig.lib.json"
|
23
|
-
}
|
24
|
-
},
|
25
|
-
"defaultConfiguration": "production"
|
26
|
-
},
|
27
|
-
"test": {
|
28
|
-
"executor": "@nx/jest:jest",
|
29
|
-
"outputs": [
|
30
|
-
"{workspaceRoot}/coverage/{projectRoot}"
|
31
|
-
],
|
32
|
-
"options": {
|
33
|
-
"jestConfig": "packages/primitives/jest.config.ts"
|
34
|
-
}
|
35
|
-
},
|
36
|
-
"lint": {
|
37
|
-
"executor": "@nx/eslint:lint",
|
38
|
-
"outputs": [
|
39
|
-
"{options.outputFile}"
|
40
|
-
]
|
41
|
-
},
|
42
|
-
"storybook": {
|
43
|
-
"executor": "@storybook/angular:start-storybook",
|
44
|
-
"options": {
|
45
|
-
"port": 4400,
|
46
|
-
"configDir": "packages/primitives/.storybook",
|
47
|
-
"browserTarget": "primitives:build-storybook",
|
48
|
-
"compodoc": false
|
49
|
-
},
|
50
|
-
"configurations": {
|
51
|
-
"ci": {
|
52
|
-
"quiet": true
|
53
|
-
}
|
54
|
-
}
|
55
|
-
},
|
56
|
-
"build-storybook": {
|
57
|
-
"executor": "@storybook/angular:build-storybook",
|
58
|
-
"outputs": ["{options.outputDir}"],
|
59
|
-
"options": {
|
60
|
-
"outputDir": "dist/storybook/primitives",
|
61
|
-
"configDir": "packages/primitives/.storybook",
|
62
|
-
"browserTarget": "primitives:build-storybook",
|
63
|
-
"compodoc": false
|
64
|
-
},
|
65
|
-
"configurations": {
|
66
|
-
"ci": {
|
67
|
-
"quiet": true
|
68
|
-
}
|
69
|
-
}
|
70
|
-
},
|
71
|
-
"test-storybook": {
|
72
|
-
"executor": "nx:run-commands",
|
73
|
-
"options": {
|
74
|
-
"command": "test-storybook -c packages/primitives/.storybook --url=http://localhost:4400"
|
75
|
-
}
|
76
|
-
},
|
77
|
-
"static-storybook": {
|
78
|
-
"executor": "@nx/web:file-server",
|
79
|
-
"options": {
|
80
|
-
"buildTarget": "primitives:build-storybook",
|
81
|
-
"staticFilePath": "dist/storybook/primitives"
|
82
|
-
},
|
83
|
-
"configurations": {
|
84
|
-
"ci": {
|
85
|
-
"buildTarget": "primitives:build-storybook:ci"
|
86
|
-
}
|
87
|
-
}
|
88
|
-
}
|
89
|
-
}
|
90
|
-
}
|
@@ -1,135 +0,0 @@
|
|
1
|
-
import { FocusKeyManager } from '@angular/cdk/a11y';
|
2
|
-
import { Directionality } from '@angular/cdk/bidi';
|
3
|
-
import {
|
4
|
-
DestroyRef,
|
5
|
-
Directive,
|
6
|
-
Input,
|
7
|
-
OnChanges,
|
8
|
-
OnDestroy,
|
9
|
-
OnInit,
|
10
|
-
QueryList,
|
11
|
-
SimpleChanges,
|
12
|
-
booleanAttribute,
|
13
|
-
inject
|
14
|
-
} from '@angular/core';
|
15
|
-
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
16
|
-
import { filter } from 'rxjs';
|
17
|
-
import type { RovingFocusItemDirective } from './roving-focus-item.directive';
|
18
|
-
import { RovingFocusGroupToken } from './roving-focus-group.token';
|
19
|
-
|
20
|
-
@Directive({
|
21
|
-
selector: '[rdxRovingFocusGroup]',
|
22
|
-
standalone: true,
|
23
|
-
providers: [{ provide: RovingFocusGroupToken, useExisting: RovingFocusGroupDirective }]
|
24
|
-
})
|
25
|
-
export class RovingFocusGroupDirective implements OnInit, OnChanges, OnDestroy {
|
26
|
-
private readonly directionality = inject(Directionality);
|
27
|
-
|
28
|
-
private readonly destroyRef = inject(DestroyRef);
|
29
|
-
|
30
|
-
/**
|
31
|
-
* Create a query list of all the roving focus items.
|
32
|
-
* We don't use ContentChildren as dynamically added items may not be in the correct order.
|
33
|
-
*/
|
34
|
-
private readonly items = new QueryList<RovingFocusItemDirective>();
|
35
|
-
|
36
|
-
/**
|
37
|
-
* Create the focus key manager instance.
|
38
|
-
* @internal
|
39
|
-
*/
|
40
|
-
readonly keyManager = new FocusKeyManager<RovingFocusItemDirective>(this.items);
|
41
|
-
|
42
|
-
/**
|
43
|
-
* Determine the orientation of the roving focus group.
|
44
|
-
* @default vertical
|
45
|
-
*/
|
46
|
-
@Input() orientation: 'horizontal' | 'vertical' = 'vertical';
|
47
|
-
|
48
|
-
/**
|
49
|
-
* Determine if focus should wrap when the end or beginning is reached.
|
50
|
-
* @default true
|
51
|
-
*/
|
52
|
-
@Input({ transform: booleanAttribute }) wrap = true;
|
53
|
-
|
54
|
-
ngOnInit(): void {
|
55
|
-
this.keyManager.withWrap(this.wrap);
|
56
|
-
|
57
|
-
this.setOrientation(this.orientation);
|
58
|
-
|
59
|
-
// update the key manager orientation if the document direction changes
|
60
|
-
this.directionality.change
|
61
|
-
.pipe(
|
62
|
-
filter(() => this.orientation === 'horizontal'),
|
63
|
-
takeUntilDestroyed(this.destroyRef)
|
64
|
-
)
|
65
|
-
.subscribe((direction) => this.keyManager.withHorizontalOrientation(direction));
|
66
|
-
}
|
67
|
-
|
68
|
-
ngOnChanges(changes: SimpleChanges): void {
|
69
|
-
if ('orientation' in changes) {
|
70
|
-
this.setOrientation(this.orientation);
|
71
|
-
}
|
72
|
-
|
73
|
-
if ('wrap' in changes) {
|
74
|
-
this.keyManager.withWrap(this.wrap);
|
75
|
-
}
|
76
|
-
}
|
77
|
-
|
78
|
-
ngOnDestroy(): void {
|
79
|
-
this.keyManager.destroy();
|
80
|
-
}
|
81
|
-
|
82
|
-
/**
|
83
|
-
* Register a roving focus item.
|
84
|
-
* @param item The roving focus item to register.
|
85
|
-
*/
|
86
|
-
register(item: RovingFocusItemDirective): void {
|
87
|
-
// add the item to the query list by sort the items based on their order
|
88
|
-
this.items.reset([...this.items.toArray(), item].sort((a, b) => a.order - b.order));
|
89
|
-
|
90
|
-
// if this is the first item, make it the active item
|
91
|
-
if (this.items.length === 1) {
|
92
|
-
this.keyManager.updateActiveItem(item);
|
93
|
-
}
|
94
|
-
}
|
95
|
-
|
96
|
-
/**
|
97
|
-
* Unregister a roving focus item.
|
98
|
-
* @param item The roving focus item to unregister.
|
99
|
-
*/
|
100
|
-
unregister(item: RovingFocusItemDirective): void {
|
101
|
-
// determine if the item being removed is the active item
|
102
|
-
const isActive = this.keyManager.activeItem === item;
|
103
|
-
|
104
|
-
// remove the item from the query list
|
105
|
-
this.items.reset(this.items.toArray().filter((i) => i !== item));
|
106
|
-
|
107
|
-
// if the item being removed is the active item, make the first item the active item
|
108
|
-
if (isActive) {
|
109
|
-
this.keyManager.updateActiveItem(0);
|
110
|
-
}
|
111
|
-
}
|
112
|
-
|
113
|
-
/**
|
114
|
-
* Handle key events on the roving focus items.
|
115
|
-
* @param event The key event.
|
116
|
-
* @internal
|
117
|
-
*/
|
118
|
-
onKeydown(event: KeyboardEvent): void {
|
119
|
-
this.keyManager.onKeydown(event);
|
120
|
-
}
|
121
|
-
|
122
|
-
/**
|
123
|
-
* Set the orientation of the roving focus group.
|
124
|
-
* @param orientation The orientation of the roving focus group.
|
125
|
-
*/
|
126
|
-
setOrientation(orientation: 'horizontal' | 'vertical'): void {
|
127
|
-
this.orientation = orientation;
|
128
|
-
|
129
|
-
if (orientation === 'horizontal') {
|
130
|
-
this.keyManager.withHorizontalOrientation(this.directionality.value);
|
131
|
-
} else {
|
132
|
-
this.keyManager.withVerticalOrientation();
|
133
|
-
}
|
134
|
-
}
|
135
|
-
}
|
@@ -1,13 +0,0 @@
|
|
1
|
-
import { InjectionToken, inject } from '@angular/core';
|
2
|
-
import type { RovingFocusGroupDirective } from './roving-focus-group.directive';
|
3
|
-
|
4
|
-
export const RovingFocusGroupToken = new InjectionToken<RovingFocusGroupDirective>(
|
5
|
-
'RovingFocusToken'
|
6
|
-
);
|
7
|
-
|
8
|
-
/**
|
9
|
-
* Inject the roving focus directive instance.
|
10
|
-
*/
|
11
|
-
export function injectRovingFocusGroup(): RovingFocusGroupDirective {
|
12
|
-
return inject(RovingFocusGroupToken);
|
13
|
-
}
|
@@ -1,98 +0,0 @@
|
|
1
|
-
import { FocusableOption } from '@angular/cdk/a11y';
|
2
|
-
import {
|
3
|
-
ChangeDetectorRef,
|
4
|
-
DestroyRef,
|
5
|
-
Directive,
|
6
|
-
ElementRef,
|
7
|
-
HostBinding,
|
8
|
-
HostListener,
|
9
|
-
Input,
|
10
|
-
OnDestroy,
|
11
|
-
OnInit,
|
12
|
-
booleanAttribute,
|
13
|
-
inject,
|
14
|
-
numberAttribute
|
15
|
-
} from '@angular/core';
|
16
|
-
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
17
|
-
import { injectRovingFocusGroup } from './roving-focus-group.token';
|
18
|
-
import { RovingFocusItemToken } from './roving-focus-item.token';
|
19
|
-
|
20
|
-
@Directive({
|
21
|
-
selector: '[rdxRovingFocusItem]',
|
22
|
-
standalone: true,
|
23
|
-
providers: [{ provide: RovingFocusItemToken, useExisting: RovingFocusItemDirective }]
|
24
|
-
})
|
25
|
-
export class RovingFocusItemDirective implements OnInit, OnDestroy, FocusableOption {
|
26
|
-
/**
|
27
|
-
* Access the group the roving focus item belongs to.
|
28
|
-
*/
|
29
|
-
private readonly group = injectRovingFocusGroup();
|
30
|
-
|
31
|
-
/**
|
32
|
-
* Access the element reference of the roving focus item.
|
33
|
-
*/
|
34
|
-
private readonly elementRef = inject(ElementRef<HTMLElement>);
|
35
|
-
|
36
|
-
/**
|
37
|
-
* Access the destroyRef
|
38
|
-
*/
|
39
|
-
private readonly destroyRef = inject(DestroyRef);
|
40
|
-
|
41
|
-
/**
|
42
|
-
* Access the change detector ref
|
43
|
-
*/
|
44
|
-
private readonly changeDetectorRef = inject(ChangeDetectorRef);
|
45
|
-
|
46
|
-
/**
|
47
|
-
* Define the order of the roving focus item in the group.
|
48
|
-
*/
|
49
|
-
@Input({ transform: numberAttribute }) order = 0;
|
50
|
-
|
51
|
-
/**
|
52
|
-
* Define if the item is disabled.
|
53
|
-
*/
|
54
|
-
@Input({ transform: booleanAttribute }) disabled = false;
|
55
|
-
|
56
|
-
/**
|
57
|
-
* Derive the tabindex of the roving focus item.
|
58
|
-
* @internal
|
59
|
-
*/
|
60
|
-
@HostBinding('attr.tabindex')
|
61
|
-
get tabindex(): number {
|
62
|
-
return this.group.keyManager.activeItem === this ? 0 : -1;
|
63
|
-
}
|
64
|
-
|
65
|
-
ngOnInit(): void {
|
66
|
-
// register the roving focus item with the group
|
67
|
-
this.group.register(this);
|
68
|
-
|
69
|
-
// listen for changes to the active item and run change detection
|
70
|
-
this.group.keyManager.change
|
71
|
-
.pipe(takeUntilDestroyed(this.destroyRef))
|
72
|
-
.subscribe(() => this.changeDetectorRef.markForCheck());
|
73
|
-
}
|
74
|
-
|
75
|
-
ngOnDestroy(): void {
|
76
|
-
// unregister the roving focus item with the group
|
77
|
-
this.group.unregister(this);
|
78
|
-
}
|
79
|
-
|
80
|
-
/**
|
81
|
-
* Handle key events on the roving focus item.
|
82
|
-
* @param event The key event.
|
83
|
-
* @internal
|
84
|
-
*/
|
85
|
-
@HostListener('keydown', ['$event'])
|
86
|
-
onKeydown(event: KeyboardEvent): void {
|
87
|
-
this.group.onKeydown(event);
|
88
|
-
}
|
89
|
-
|
90
|
-
/**
|
91
|
-
* Focus the roving focus item.
|
92
|
-
* @param origin The origin of the focus request.
|
93
|
-
* @internal
|
94
|
-
*/
|
95
|
-
focus(): void {
|
96
|
-
this.elementRef?.nativeElement.focus();
|
97
|
-
}
|
98
|
-
}
|
@@ -1,10 +0,0 @@
|
|
1
|
-
import { InjectionToken, inject } from '@angular/core';
|
2
|
-
import type { RovingFocusItemDirective } from './roving-focus-item.directive';
|
3
|
-
|
4
|
-
export const RovingFocusItemToken = new InjectionToken<RovingFocusItemDirective>(
|
5
|
-
'RovingFocusItemToken'
|
6
|
-
);
|
7
|
-
|
8
|
-
export function injectRovingFocusItem(): RovingFocusItemDirective {
|
9
|
-
return inject(RovingFocusItemToken);
|
10
|
-
}
|
@@ -1,59 +0,0 @@
|
|
1
|
-
import { SeparatorDirective } from './separator.directive';
|
2
|
-
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
3
|
-
import { Component, DebugElement } from '@angular/core';
|
4
|
-
import { By } from '@angular/platform-browser';
|
5
|
-
|
6
|
-
@Component({
|
7
|
-
template:
|
8
|
-
'<div rdxSeparator [rdxSeparatorOrientation]="orientation" [rdxSeparatorDecorative]="decorative"></div>'
|
9
|
-
})
|
10
|
-
class TestComponent {
|
11
|
-
orientation: 'horizontal' | 'vertical' = 'horizontal';
|
12
|
-
decorative = false;
|
13
|
-
}
|
14
|
-
|
15
|
-
describe('SeparatorDirective', () => {
|
16
|
-
let component: TestComponent;
|
17
|
-
let fixture: ComponentFixture<TestComponent>;
|
18
|
-
let div: DebugElement;
|
19
|
-
|
20
|
-
beforeEach(async () => {
|
21
|
-
await TestBed.configureTestingModule({
|
22
|
-
declarations: [TestComponent],
|
23
|
-
imports: [SeparatorDirective]
|
24
|
-
}).compileComponents();
|
25
|
-
});
|
26
|
-
|
27
|
-
beforeEach(() => {
|
28
|
-
fixture = TestBed.createComponent(TestComponent);
|
29
|
-
component = fixture.componentInstance;
|
30
|
-
div = fixture.debugElement.query(By.css('div'));
|
31
|
-
fixture.detectChanges();
|
32
|
-
});
|
33
|
-
|
34
|
-
it('should create an instance', () => {
|
35
|
-
const directive = new SeparatorDirective();
|
36
|
-
expect(directive).toBeTruthy();
|
37
|
-
});
|
38
|
-
|
39
|
-
it('should apply the correct role attribute based on decorative input', () => {
|
40
|
-
expect(div.nativeElement.getAttribute('role')).toBe('separator');
|
41
|
-
component.decorative = true;
|
42
|
-
fixture.detectChanges();
|
43
|
-
expect(div.nativeElement.getAttribute('role')).toBe('none');
|
44
|
-
});
|
45
|
-
|
46
|
-
it('should apply the correct aria-orientation attribute based on orientation input', () => {
|
47
|
-
expect(div.nativeElement.getAttribute('aria-orientation')).toBe(null);
|
48
|
-
component.orientation = 'vertical';
|
49
|
-
fixture.detectChanges();
|
50
|
-
expect(div.nativeElement.getAttribute('aria-orientation')).toBe('vertical');
|
51
|
-
});
|
52
|
-
|
53
|
-
it('should apply the correct data-orientation attribute based on orientation input', () => {
|
54
|
-
expect(div.nativeElement.getAttribute('data-orientation')).toBe('horizontal');
|
55
|
-
component.orientation = 'vertical';
|
56
|
-
fixture.detectChanges();
|
57
|
-
expect(div.nativeElement.getAttribute('data-orientation')).toBe('vertical');
|
58
|
-
});
|
59
|
-
});
|
@@ -1,24 +0,0 @@
|
|
1
|
-
import { Directive, Input, booleanAttribute } from '@angular/core';
|
2
|
-
|
3
|
-
@Directive({
|
4
|
-
selector: '[rdxSeparator]',
|
5
|
-
standalone: true,
|
6
|
-
host: {
|
7
|
-
'[attr.role]': 'decorative ? "none" : "separator"',
|
8
|
-
'[attr.aria-orientation]': '!decorative && orientation === "vertical" ? "vertical" : null',
|
9
|
-
'[attr.data-orientation]': 'orientation'
|
10
|
-
}
|
11
|
-
})
|
12
|
-
export class SeparatorDirective {
|
13
|
-
/**
|
14
|
-
* The orientation of the separator.
|
15
|
-
* @default 'horizontal'
|
16
|
-
*/
|
17
|
-
@Input('rdxSeparatorOrientation') orientation: 'horizontal' | 'vertical' = 'horizontal';
|
18
|
-
|
19
|
-
/**
|
20
|
-
* Whether the separator is for decoration purposes. If true, the separator will not be included in the accessibility tree.
|
21
|
-
* @default false
|
22
|
-
*/
|
23
|
-
@Input({ alias: 'rdxSeparatorDecorative', transform: booleanAttribute }) decorative = false;
|
24
|
-
}
|
@@ -1,38 +0,0 @@
|
|
1
|
-
import { ArgTypes, Canvas, Meta } from '@storybook/addon-docs';
|
2
|
-
import { SeparatorDirective } from '../src/separator.directive';
|
3
|
-
import * as SeparatorDirectiveStories from "./separator.stories";
|
4
|
-
|
5
|
-
<Meta
|
6
|
-
title="Primitives/Separator"
|
7
|
-
/>
|
8
|
-
|
9
|
-
# Separator
|
10
|
-
#### Visually or semantically separates content.
|
11
|
-
|
12
|
-
<Canvas sourceState='hidden' of={SeparatorDirectiveStories.Default}></Canvas>
|
13
|
-
|
14
|
-
## Features
|
15
|
-
- ✅ Supports horizontal and vertical orientations.
|
16
|
-
|
17
|
-
## Usage
|
18
|
-
|
19
|
-
Get started with importing the directive:
|
20
|
-
|
21
|
-
```typescript
|
22
|
-
import { SeparatorDirective } from '@radix-ng/primitives/separator';
|
23
|
-
```
|
24
|
-
|
25
|
-
## Examples
|
26
|
-
|
27
|
-
```html
|
28
|
-
<div rdxSeparator
|
29
|
-
rdxSeparatorDecorative="decorative"
|
30
|
-
rdxSeparatorOrientation="vertical"></div>
|
31
|
-
```
|
32
|
-
## API Reference
|
33
|
-
|
34
|
-
<ArgTypes of={SeparatorDirective} />
|
35
|
-
|
36
|
-
## Accessibility
|
37
|
-
|
38
|
-
Adheres to the [`separator` role requirements](https://www.w3.org/TR/wai-aria-1.2/#separator).
|