@raqm/ui 0.1.2 → 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.
Files changed (96) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +87 -126
  3. package/fesm2022/raqm-ui-badge.mjs +3 -1
  4. package/fesm2022/raqm-ui-badge.mjs.map +1 -1
  5. package/fesm2022/raqm-ui-calendar.mjs +79 -12
  6. package/fesm2022/raqm-ui-calendar.mjs.map +1 -1
  7. package/fesm2022/raqm-ui-combobox.mjs +47 -23
  8. package/fesm2022/raqm-ui-combobox.mjs.map +1 -1
  9. package/fesm2022/raqm-ui-command.mjs +60 -12
  10. package/fesm2022/raqm-ui-command.mjs.map +1 -1
  11. package/fesm2022/raqm-ui-dialog.mjs +1 -3
  12. package/fesm2022/raqm-ui-dialog.mjs.map +1 -1
  13. package/fesm2022/raqm-ui-icon.mjs +160 -0
  14. package/fesm2022/raqm-ui-icon.mjs.map +1 -0
  15. package/fesm2022/raqm-ui-input-otp.mjs +7 -4
  16. package/fesm2022/raqm-ui-input-otp.mjs.map +1 -1
  17. package/fesm2022/raqm-ui-overlay-internal.mjs +15 -5
  18. package/fesm2022/raqm-ui-overlay-internal.mjs.map +1 -1
  19. package/fesm2022/raqm-ui-popover.mjs +51 -19
  20. package/fesm2022/raqm-ui-popover.mjs.map +1 -1
  21. package/fesm2022/raqm-ui-resizable.mjs +14 -4
  22. package/fesm2022/raqm-ui-resizable.mjs.map +1 -1
  23. package/fesm2022/raqm-ui-scroll-area.mjs +85 -29
  24. package/fesm2022/raqm-ui-scroll-area.mjs.map +1 -1
  25. package/fesm2022/raqm-ui-select.mjs +46 -19
  26. package/fesm2022/raqm-ui-select.mjs.map +1 -1
  27. package/fesm2022/raqm-ui-sidebar.mjs +13 -3
  28. package/fesm2022/raqm-ui-sidebar.mjs.map +1 -1
  29. package/fesm2022/raqm-ui-slider.mjs +59 -12
  30. package/fesm2022/raqm-ui-slider.mjs.map +1 -1
  31. package/fesm2022/raqm-ui-toast.mjs +60 -20
  32. package/fesm2022/raqm-ui-toast.mjs.map +1 -1
  33. package/fesm2022/raqm-ui-tooltip.mjs +28 -3
  34. package/fesm2022/raqm-ui-tooltip.mjs.map +1 -1
  35. package/fesm2022/raqm-ui.mjs +1 -0
  36. package/package.json +52 -18
  37. package/styles/accordion.css +1 -0
  38. package/styles/alert-dialog.css +1 -0
  39. package/styles/alert.css +1 -0
  40. package/styles/attachment.css +1 -0
  41. package/styles/avatar.css +1 -0
  42. package/styles/badge.css +1 -0
  43. package/styles/base.css +1 -0
  44. package/styles/button-group.css +1 -0
  45. package/styles/button.css +1 -0
  46. package/styles/checkbox.css +1 -0
  47. package/styles/combobox.css +1 -0
  48. package/styles/command.css +1 -0
  49. package/styles/common.css +17 -0
  50. package/styles/context-menu.css +1 -0
  51. package/styles/dialog.css +1 -0
  52. package/styles/drawer.css +1 -0
  53. package/styles/dropdown-menu.css +1 -0
  54. package/styles/empty.css +1 -0
  55. package/styles/field-parts.css +1 -0
  56. package/styles/field-relationships.css +1 -0
  57. package/styles/input-group-button.css +1 -0
  58. package/styles/input-group-relationships.css +1 -0
  59. package/styles/input-otp.css +1 -0
  60. package/styles/input.css +1 -0
  61. package/styles/item.css +1 -0
  62. package/styles/kbd.css +1 -0
  63. package/styles/menubar.css +1 -0
  64. package/styles/native-select.css +1 -0
  65. package/styles/navigation-menu.css +1 -0
  66. package/styles/overlay.css +1 -0
  67. package/styles/pagination.css +1 -0
  68. package/styles/popover.css +1 -0
  69. package/styles/questionnaire.css +1 -0
  70. package/styles/radio-group.css +1 -0
  71. package/styles/resizable.css +1 -0
  72. package/styles/sheet.css +1 -0
  73. package/styles/sidebar.css +1 -0
  74. package/styles/spinner.css +1 -0
  75. package/styles/switch.css +1 -0
  76. package/styles/table.css +1 -0
  77. package/styles/tabs.css +1 -0
  78. package/styles/textarea.css +1 -0
  79. package/styles/theme.css +50 -4324
  80. package/styles/toggle-group.css +1 -0
  81. package/styles/toggle.css +1 -0
  82. package/styles/tooltip.css +1 -0
  83. package/types/raqm-ui-calendar.d.ts +1 -0
  84. package/types/raqm-ui-combobox.d.ts +8 -4
  85. package/types/raqm-ui-command.d.ts +4 -0
  86. package/types/raqm-ui-dialog.d.ts +7 -1
  87. package/types/raqm-ui-icon.d.ts +65 -0
  88. package/types/raqm-ui-input-otp.d.ts +1 -0
  89. package/types/raqm-ui-resizable.d.ts +4 -0
  90. package/types/raqm-ui-scroll-area.d.ts +11 -0
  91. package/types/raqm-ui-slider.d.ts +1 -1
  92. package/types/raqm-ui-toast.d.ts +6 -0
  93. package/types/raqm-ui.d.ts +1 -0
  94. package/fesm2022/raqm-ui-carousel.mjs +0 -410
  95. package/fesm2022/raqm-ui-carousel.mjs.map +0 -1
  96. package/types/raqm-ui-carousel.d.ts +0 -81
package/CHANGELOG.md CHANGED
@@ -5,6 +5,25 @@ All notable changes to `@raqm/ui` are recorded here. The format follows
5
5
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Before `1.0.0`, minor
6
6
  releases may include breaking changes.
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.0] - 2026-11-13
11
+
12
+ ### Changed
13
+
14
+ - Point the package homepage and README guides to the public documentation site;
15
+ remove private repository and issue links from package metadata.
16
+ - Shorten the package README to installation, setup, usage, and public documentation.
17
+ - Optimize component update paths, overlay lifecycles, and theme synchronization.
18
+ Reuse OTP validation patterns and create sidebar tooltips only when eligible.
19
+
20
+ ### Removed
21
+
22
+ - **Breaking:** remove the unused `@raqm/ui/carousel` entrypoint and
23
+ `@raqm/ui/styles/carousel.css`, along with the Embla runtime dependency.
24
+ Carousel components, directives, options, and plugin/API integration are no
25
+ longer provided. The demo carousel page and autoplay dependency are removed too.
26
+
8
27
  ## [0.1.2] - 2026-11-13
9
28
 
10
29
  ### Removed
package/README.md CHANGED
@@ -1,126 +1,87 @@
1
- # Raqm UI
2
-
3
- UI components with Raqm's own design and APIs,
4
- implemented natively for Angular with the Angular CDK. Standalone components and
5
- directives, signal inputs and outputs, light/dark themes and first-class RTL.
6
-
7
- - **Status:** pre-1.0 — the component API may still change in minor releases.
8
- - **Angular:** 22.2 (peer dependency), Angular CDK 22.2, `@angular/forms` for the
9
- form controls.
10
- - **Styles:** plain CSS custom properties and SCSS. No Tailwind, no React, no runtime
11
- copy of shadcn/ui.
12
-
13
- ## Install
14
-
15
- ```sh
16
- npm install @raqm/ui @angular/cdk
17
- ```
18
-
19
- `@angular/core`, `@angular/common` and `@angular/forms` are peer dependencies and
20
- are expected to come from your application.
21
-
22
- ## Load the theme
23
-
24
- Load the CDK overlay stylesheet first, then the package theme, then your own styles:
25
-
26
- ```jsonc
27
- // angular.json -> projects.<app>.architect.build.options.styles
28
- "styles": [
29
- "@angular/cdk/overlay-prebuilt.css",
30
- "@raqm/ui/theme.css",
31
- "src/styles.scss"
32
- ]
33
- ```
34
-
35
- Import the components you use from their own entrypoint. Focused subpaths keep each
36
- lazy route from pulling the whole library into its bundle:
37
-
38
- ```ts
39
- import { Component } from '@angular/core';
40
- import { RaqmButton } from '@raqm/ui/button';
41
- import { RaqmCard } from '@raqm/ui/card';
42
-
43
- @Component({
44
- selector: 'app-example',
45
- imports: [RaqmButton, RaqmCard],
46
- template: `
47
- <raqm-card>
48
- <raqm-card-header>
49
- <h3 raqm-card-title>Monthly report</h3>
50
- </raqm-card-header>
51
- <raqm-card-content>
52
- <button raqm-button="outline" type="button">Download</button>
53
- </raqm-card-content>
54
- </raqm-card>
55
- `,
56
- })
57
- export class ExampleComponent {}
58
- ```
59
-
60
- The root import (`from '@raqm/ui'`) aggregates the historically root-exported
61
- families. Attachment, Calendar, Carousel, Resizable, and Questionnaire remain
62
- subpath-only. Prefer focused subpaths in application code.
63
-
64
- ## Themes
65
-
66
- The theme ships light and dark scopes and follows `prefers-reduced-motion`:
67
-
68
- | Scope | Effect |
69
- | --------------------------- | ------------------------------------------ |
70
- | `:root` | light theme (default) |
71
- | `[data-raqm-theme="light"]` | explicit light island inside a dark app |
72
- | `[data-raqm-theme="dark"]` | dark theme for the element and its subtree |
73
-
74
- All design tokens are `--raqm-*` custom properties, so an application can override
75
- them in its own stylesheet after the package theme loads. Components use logical CSS
76
- properties, so `dir="rtl"` mirrors layouts without extra overrides.
77
-
78
- ## Entrypoints
79
-
80
- | Area | Subpaths |
81
- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
82
- | Form controls | `button`, `button-group`, `input`, `checkbox`, `switch`, `textarea`, `label`, `radio-group`, `native-select`, `field`, `input-group`, `input-otp`, `select`, `combobox`, `slider`, `calendar`, `toggle`, `toggle-group` |
83
- | Layout and content | `card`, `item`, `table`, `sidebar`, `pagination`, `breadcrumb`, `empty`, `attachment`, `resizable`, `scroll-area` |
84
- | Overlays | `dialog`, `alert-dialog`, `drawer`, `sheet`, `popover`, `hover-card`, `tooltip`, `toast`, `command` |
85
- | Menus and disclosure | `dropdown-menu`, `context-menu`, `menubar`, `navigation-menu`, `accordion`, `collapsible`, `tabs` |
86
- | Display | `badge`, `avatar`, `spinner`, `kbd`, `separator`, `skeleton`, `aspect-ratio` |
87
- | Feedback | `alert`, `progress`, `questionnaire` |
88
- | Media | `carousel` (bundles `embla-carousel`) |
89
-
90
- Multipart families provide one readonly Angular template dependency array:
91
-
92
- ```ts
93
- import { RaqmCard } from '@raqm/ui/card';
94
- // Use imports: [RaqmCard] to enable the Card template parts.
95
- ```
96
-
97
- Single-piece controls export their class directly, for example `RaqmInput` from
98
- `@raqm/ui/input`. Use actual `Component`/`Directive` suffixed declarations for
99
- instance queries, injection, and inheritance—not a family array. Services and
100
- data types remain separately exported. The former `/controls` and `/display`
101
- entrypoints are removed; Toggle Group now uses `/toggle-group`. This is an
102
- intentional pre-release breaking import migration, without compatibility aliases.
103
-
104
- Attachment, Calendar, Carousel, Resizable, and Questionnaire are secondary-only;
105
- the root aggregate preserves its historical family boundary.
106
-
107
- ## Accessibility
108
-
109
- Components are authored with keyboard and screen-reader semantics in hand: the dialog
110
- family warns in development when no accessible name is provided, focus is moved and
111
- restored through the CDK, and interactive parts expose their state through ARIA.
112
- Overlay panes render in a CDK overlay; load `@angular/cdk/overlay-prebuilt.css` as
113
- shown above.
114
-
115
- ## Component guides
116
-
117
- Every component page in the docs app pairs a Markdown guide with live examples and
118
- copy-ready code. Browse all 55 pages under
119
- [Raqm-UI-demo/src/app/pages](https://github.com/KeyLitDev/RaqmUI/tree/main/Raqm-UI-demo/src/app/pages).
120
-
121
- ## License
122
-
123
- MIT — see [LICENSE](https://github.com/KeyLitDev/RaqmUI/blob/main/LICENSE).
124
-
125
- For attribution, see
126
- [NOTICE.md](https://github.com/KeyLitDev/RaqmUI/blob/main/NOTICE.md).
1
+ # Raqm UI
2
+
3
+ Standalone Angular UI components with signal-based APIs, light and dark themes,
4
+ and RTL support. Built on the Angular CDK.
5
+
6
+ [Documentation & examples](https://raqmui.meabuelgheit.workers.dev/) ·
7
+ [Getting started](https://raqmui.meabuelgheit.workers.dev/getting-started) ·
8
+ [Component guides](https://raqmui.meabuelgheit.workers.dev/components)
9
+
10
+ ## Install
11
+
12
+ Requires Angular 22.2 and Angular CDK 22.2. Your application must provide
13
+ `@angular/core`, `@angular/common`, and `@angular/forms`.
14
+
15
+ ```sh
16
+ npm install @raqm/ui @angular/cdk
17
+ ```
18
+
19
+ Pre-1.0: minor releases may include breaking API changes. Read the packaged
20
+ `CHANGELOG.md` before upgrading.
21
+
22
+ ## Styles
23
+
24
+ Add the theme before your application styles in `angular.json`:
25
+
26
+ ```json
27
+ "styles": [
28
+ "@raqm/ui/theme.css",
29
+ "src/styles.scss"
30
+ ]
31
+ ```
32
+
33
+ The theme includes CDK overlay styles; no separate overlay stylesheet is needed.
34
+ The aggregate `theme.css` is deprecated but supported during the component-style
35
+ migration. For smaller bundles, use `@raqm/ui/styles/base.css`,
36
+ `@raqm/ui/styles/overlay.css`, and the required component styles.
37
+
38
+ <details>
39
+ <summary>Granular stylesheet order</summary>
40
+
41
+ After `base.css` and `overlay.css`, load the residual styles you need in this order
42
+ (each name is `@raqm/ui/styles/<name>.css`):
43
+
44
+ `sidebar`, `input`, `input-otp`, `checkbox`, `spinner`, `button`, `pagination`, `kbd`,
45
+ `toggle-group`, `switch`, `badge`, `dropdown-menu`, `context-menu`, `radio-group`,
46
+ `textarea`, `input-group-button`, `menubar`, `navigation-menu`, `questionnaire`,
47
+ `avatar`, `combobox`, `field-parts`, `table`, `attachment`, `popover`, `dialog`,
48
+ `alert-dialog`, `sheet`, `drawer`, `command`, `tooltip`, `empty`, `alert`, `item`,
49
+ `tabs`, `accordion`, `resizable`, `native-select`, `field-relationships`,
50
+ `button-group`, `input-group-relationships`, `toggle`.
51
+
52
+ Include `button.css` for Toast/Dialog close controls, `spinner.css` when used inside
53
+ Badge, and `input.css`/`textarea.css` for those controls inside Field.
54
+ Components without a residual stylesheet encapsulate their own styles.
55
+
56
+ </details>
57
+
58
+ ## Usage
59
+
60
+ Import components from their focused entrypoints:
61
+
62
+ ```ts
63
+ import { Component } from '@angular/core';
64
+ import { RaqmButton } from '@raqm/ui/button';
65
+
66
+ @Component({
67
+ selector: 'app-example',
68
+ imports: [RaqmButton],
69
+ template: `<button raqm-button="outline" type="button">Download</button>`,
70
+ })
71
+ export class ExampleComponent {}
72
+ ```
73
+
74
+ Multipart families such as `RaqmCard` export template dependency arrays for
75
+ `imports: [RaqmCard]`. Use the individual `Component`/`Directive` classes for
76
+ queries and injection.
77
+
78
+ ## Themes and RTL
79
+
80
+ Set `data-raqm-theme="dark"` on an ancestor for dark mode, or
81
+ `data-raqm-theme="light"` for an explicit light scope. Override `--raqm-*` CSS
82
+ custom properties after loading the theme. Set `dir="rtl"` for RTL layouts.
83
+
84
+ ## License
85
+
86
+ MIT. License and third-party notices are included in the package as `LICENSE`
87
+ and `NOTICE.md`.
@@ -34,6 +34,7 @@ var RaqmBadge = class RaqmBadge {
34
34
  ngImport: i0,
35
35
  template: "<ng-content />",
36
36
  isInline: true,
37
+ styles: [":where(:host){display:inline-flex;inline-size:fit-content;flex-shrink:0;align-items:center;justify-content:center;overflow:hidden;white-space:nowrap;transition-property:color,background-color,border-color,box-shadow,transform,opacity;transition-duration:var(--raqm-duration-base);transition-timing-function:var(--raqm-ease-standard);box-sizing:border-box;block-size:calc(var(--raqm-spacing) * 5);gap:calc(var(--raqm-spacing) * 1);border-radius:calc(var(--raqm-spacing) * 8);border:1px solid transparent;padding-inline:calc(var(--raqm-spacing) * 2);padding-block:calc(var(--raqm-spacing) * .5);font-size:var(--raqm-font-size-xs);line-height:1rem;font-weight:var(--raqm-font-weight-medium);background-color:var(--raqm-badge-background, var(--raqm-primary));color:var(--raqm-badge-foreground, var(--raqm-primary-foreground));border-color:var(--raqm-badge-border, transparent)}:where(:host([data-raqm-variant=secondary])){background-color:var(--raqm-badge-background, var(--raqm-secondary));color:var(--raqm-badge-foreground, var(--raqm-secondary-foreground))}:where(:host([data-raqm-variant=outline])){background-color:var(--raqm-badge-background, transparent);color:var(--raqm-badge-foreground, var(--raqm-foreground));border-color:var(--raqm-badge-border, var(--raqm-border))}:where(:host([data-raqm-variant=destructive])){background-color:var(--raqm-badge-background, color-mix(in oklch, var(--raqm-destructive) var(--raqm-destructive-bg-alpha, 10%), transparent));color:var(--raqm-badge-foreground, var(--raqm-destructive))}:where(:host([data-raqm-variant=ghost])){background-color:var(--raqm-badge-background, transparent);color:var(--raqm-badge-foreground, inherit)}:where(:host(a[data-raqm-variant=default]):hover){background-color:color-mix(in oklch,var(--raqm-badge-background, var(--raqm-primary)) 80%,transparent)}:where(:host(a[data-raqm-variant=secondary]):hover){background-color:color-mix(in oklch,var(--raqm-badge-background, var(--raqm-secondary)) 80%,transparent)}:where(:host(a[data-raqm-variant=outline]):hover){background-color:var(--raqm-badge-background, var(--raqm-muted));color:var(--raqm-badge-foreground, var(--raqm-muted-foreground))}:where(:host(a[data-raqm-variant=destructive]):hover){background-color:color-mix(in oklch,var(--raqm-destructive) 20%,transparent)}:where(:host([data-raqm-variant=ghost]):hover){background-color:var(--raqm-badge-background, color-mix(in oklch, var(--raqm-muted) var(--raqm-ghost-hover-alpha, 100%), transparent));color:var(--raqm-badge-foreground, var(--raqm-muted-foreground))}:where(:host(:focus-visible)){border-color:var(--raqm-ring);box-shadow:0 0 0 var(--raqm-focus-ring-width) var(--raqm-focus-ring-color)}:where(:host([aria-invalid=true])){border-color:var(--raqm-invalid-border)}:where(:host([aria-invalid=true]):focus-visible){box-shadow:0 0 0 var(--raqm-focus-ring-width) var(--raqm-invalid-ring)}:where(:host([data-raqm-variant=destructive]):focus-visible){box-shadow:0 0 0 var(--raqm-focus-ring-width) color-mix(in oklch,var(--raqm-destructive) var(--raqm-destructive-focus-alpha, 20%),transparent)}\n"],
37
38
  changeDetection: i0.ChangeDetectionStrategy.OnPush
38
39
  });
39
40
  };
@@ -51,7 +52,8 @@ i0.ɵɵngDeclareClassMetadata({
51
52
  host: {
52
53
  class: "raqm-badge",
53
54
  "[attr.data-raqm-variant]": "activeVariant()"
54
- }
55
+ },
56
+ styles: [":where(:host){display:inline-flex;inline-size:fit-content;flex-shrink:0;align-items:center;justify-content:center;overflow:hidden;white-space:nowrap;transition-property:color,background-color,border-color,box-shadow,transform,opacity;transition-duration:var(--raqm-duration-base);transition-timing-function:var(--raqm-ease-standard);box-sizing:border-box;block-size:calc(var(--raqm-spacing) * 5);gap:calc(var(--raqm-spacing) * 1);border-radius:calc(var(--raqm-spacing) * 8);border:1px solid transparent;padding-inline:calc(var(--raqm-spacing) * 2);padding-block:calc(var(--raqm-spacing) * .5);font-size:var(--raqm-font-size-xs);line-height:1rem;font-weight:var(--raqm-font-weight-medium);background-color:var(--raqm-badge-background, var(--raqm-primary));color:var(--raqm-badge-foreground, var(--raqm-primary-foreground));border-color:var(--raqm-badge-border, transparent)}:where(:host([data-raqm-variant=secondary])){background-color:var(--raqm-badge-background, var(--raqm-secondary));color:var(--raqm-badge-foreground, var(--raqm-secondary-foreground))}:where(:host([data-raqm-variant=outline])){background-color:var(--raqm-badge-background, transparent);color:var(--raqm-badge-foreground, var(--raqm-foreground));border-color:var(--raqm-badge-border, var(--raqm-border))}:where(:host([data-raqm-variant=destructive])){background-color:var(--raqm-badge-background, color-mix(in oklch, var(--raqm-destructive) var(--raqm-destructive-bg-alpha, 10%), transparent));color:var(--raqm-badge-foreground, var(--raqm-destructive))}:where(:host([data-raqm-variant=ghost])){background-color:var(--raqm-badge-background, transparent);color:var(--raqm-badge-foreground, inherit)}:where(:host(a[data-raqm-variant=default]):hover){background-color:color-mix(in oklch,var(--raqm-badge-background, var(--raqm-primary)) 80%,transparent)}:where(:host(a[data-raqm-variant=secondary]):hover){background-color:color-mix(in oklch,var(--raqm-badge-background, var(--raqm-secondary)) 80%,transparent)}:where(:host(a[data-raqm-variant=outline]):hover){background-color:var(--raqm-badge-background, var(--raqm-muted));color:var(--raqm-badge-foreground, var(--raqm-muted-foreground))}:where(:host(a[data-raqm-variant=destructive]):hover){background-color:color-mix(in oklch,var(--raqm-destructive) 20%,transparent)}:where(:host([data-raqm-variant=ghost]):hover){background-color:var(--raqm-badge-background, color-mix(in oklch, var(--raqm-muted) var(--raqm-ghost-hover-alpha, 100%), transparent));color:var(--raqm-badge-foreground, var(--raqm-muted-foreground))}:where(:host(:focus-visible)){border-color:var(--raqm-ring);box-shadow:0 0 0 var(--raqm-focus-ring-width) var(--raqm-focus-ring-color)}:where(:host([aria-invalid=true])){border-color:var(--raqm-invalid-border)}:where(:host([aria-invalid=true]):focus-visible){box-shadow:0 0 0 var(--raqm-focus-ring-width) var(--raqm-invalid-ring)}:where(:host([data-raqm-variant=destructive]):focus-visible){box-shadow:0 0 0 var(--raqm-focus-ring-width) color-mix(in oklch,var(--raqm-destructive) var(--raqm-destructive-focus-alpha, 20%),transparent)}\n"]
55
57
  }]
56
58
  }],
57
59
  propDecorators: { appearance: [{
@@ -1 +1 @@
1
- {"version":3,"file":"raqm-ui-badge.mjs","names":[],"sources":["../../../projects/ui/badge/badge.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\r\n\r\ntype BadgeVariant = 'default' | 'secondary' | 'destructive' | 'outline' | 'ghost';\r\n\r\n/**\r\n * Status pill on a native `<span>` or `<a>`; a real anchor keeps native navigation and focus.\r\n * `raqm-badge` selects the appearance; `--raqm-badge-background`/`-foreground`/`-border` override colours.\r\n */\r\n@Component({\r\n selector: 'span[raqm-badge], a[raqm-badge]',\r\n template: '<ng-content />',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'raqm-badge',\r\n '[attr.data-raqm-variant]': 'activeVariant()',\r\n },\r\n})\r\nexport class RaqmBadge {\r\n /** Bare marker uses the default appearance. */\r\n readonly appearance = input<BadgeVariant | ''>('', { alias: 'raqm-badge' });\r\n\r\n protected readonly activeVariant = computed(() => this.appearance() || 'default');\r\n}\r\n"],"mappings":";;AAiBA,IAAa,YAAb,MAAa,UAAS;CAEX,aAAa,MAAyB,IAAE;EAAA,GAAA,YAAA,EAAA,WAAA,aAAA,+BAAA,CAAA;EAAI,OAAO;CAAY,CAAA;CAErD,gBAAgB,eAAe,KAAK,WAAU,KAAM,WAAU,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;CAJtE,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAS,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAT,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAS,cAAA;EAAA,UAAA;EAAA,QAAA,EAAA,YAAA;GAAA,mBAAA;GAAA,YAAA;GAAA,UAAA;GAAA,YAAA;GAAA,mBAAA;EAAA,EAAA;EAAA,MAAA;GAAA,YAAA,EAAA,0BAAA,kBAAA;GAAA,gBAAA;EAAA;EAAA,UAAA;EAAA,UAPV;EAAgB,UAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAOf,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAS,YAAA,CAAA;EATrB,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,UAAU;GACV,iBAAiB,wBAAwB;GACzC,MAAM;IACJ,OAAO;IACP,4BAA4B;GAC7B;EACF,CAAA"}
1
+ {"version":3,"file":"raqm-ui-badge.mjs","names":[],"sources":["../../../projects/ui/badge/badge.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\r\n\r\ntype BadgeVariant = 'default' | 'secondary' | 'destructive' | 'outline' | 'ghost';\r\n\r\n/**\r\n * Status pill on a native `<span>` or `<a>`; a real anchor keeps native navigation and focus.\r\n * `raqm-badge` selects the appearance; `--raqm-badge-background`/`-foreground`/`-border` override colours.\r\n */\r\n@Component({\r\n selector: 'span[raqm-badge], a[raqm-badge]',\r\n template: '<ng-content />',\r\n styleUrl: './badge.component.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'raqm-badge',\r\n '[attr.data-raqm-variant]': 'activeVariant()',\r\n },\r\n})\r\nexport class RaqmBadge {\r\n /** Bare marker uses the default appearance. */\r\n readonly appearance = input<BadgeVariant | ''>('', { alias: 'raqm-badge' });\r\n\r\n protected readonly activeVariant = computed(() => this.appearance() || 'default');\r\n}\r\n"],"mappings":";;AAkBA,IAAa,YAAb,MAAa,UAAS;CAEX,aAAa,MAAyB,IAAE;EAAA,GAAA,YAAA,EAAA,WAAA,aAAA,+BAAA,CAAA;EAAI,OAAO;CAAY,CAAA;CAErD,gBAAgB,eAAe,KAAK,WAAU,KAAM,WAAU,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;CAJtE,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAS,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAT,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAS,cAAA;EAAA,UAAA;EAAA,QAAA,EAAA,YAAA;GAAA,mBAAA;GAAA,YAAA;GAAA,UAAA;GAAA,YAAA;GAAA,mBAAA;EAAA,EAAA;EAAA,MAAA;GAAA,YAAA,EAAA,0BAAA,kBAAA;GAAA,gBAAA;EAAA;EAAA,UAAA;EAAA,UARV;EAAgB,UAAA;EAAA,QAAA,CAAA,mgGAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAQf,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAS,YAAA,CAAA;EAVrB,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAiC,UACjC;GAAgB,iBAET,wBAAwB;GAAM,MACzC;IACJ,OAAO;IACP,4BAA4B;GAC7B;GAAA,QAAA,CAAA,mgGAAA;EAAA,CAAA"}
@@ -179,43 +179,70 @@ function connectCalendarEffects(host) {
179
179
  if (pending) host.setPendingFocus(false);
180
180
  });
181
181
  }
182
+ function optionsKey(options) {
183
+ return JSON.stringify(Object.keys(options).sort().map((name) => {
184
+ const value = options[name];
185
+ return [
186
+ name,
187
+ typeof value,
188
+ value
189
+ ];
190
+ }));
191
+ }
192
+ const DATE_FORMAT_LIMIT = 32;
182
193
  var RaqmCalendarFormat = class {
183
194
  host;
195
+ explicitFormats = /* @__PURE__ */ new Map();
196
+ renderFormats = /* @__PURE__ */ new Map();
197
+ weekNumberFormat;
198
+ cachedLocale;
184
199
  constructor(host) {
185
200
  this.host = host;
186
201
  }
187
202
  format(date, options) {
188
- return new Intl.DateTimeFormat(this.host.locale(), {
189
- ...options,
190
- calendar: "gregory",
191
- numberingSystem: "latn"
192
- }).format(date);
203
+ const locale = this.ensureLocale();
204
+ const effective = this.effectiveOptions(options);
205
+ if (effective.timeZone === void 0) return new Intl.DateTimeFormat(locale, effective).format(date);
206
+ const cacheKey = optionsKey(effective);
207
+ let formatter = this.explicitFormats.get(cacheKey);
208
+ if (formatter === void 0) {
209
+ if (this.explicitFormats.size >= DATE_FORMAT_LIMIT) {
210
+ const oldest = this.explicitFormats.keys().next().value;
211
+ if (oldest !== void 0) this.explicitFormats.delete(oldest);
212
+ }
213
+ formatter = new Intl.DateTimeFormat(locale, effective);
214
+ this.explicitFormats.set(cacheKey, formatter);
215
+ }
216
+ return formatter.format(date);
217
+ }
218
+ clearInternalFormats() {
219
+ this.renderFormats.clear();
193
220
  }
194
221
  caption(date) {
195
- return this.host.formatters().formatCaption?.(date) ?? this.format(date, {
222
+ return this.host.formatters().formatCaption?.(date) ?? this.internal(date, {
196
223
  month: "long",
197
224
  year: "numeric"
198
225
  });
199
226
  }
200
227
  monthLabel(date, month) {
201
228
  const value = civil(date.getFullYear(), month);
202
- return this.host.formatters().formatMonthDropdown?.(value) ?? this.format(value, { month: "short" });
229
+ return this.host.formatters().formatMonthDropdown?.(value) ?? this.internal(value, { month: "short" });
203
230
  }
204
231
  yearLabel(year) {
205
232
  const value = civil(year);
206
- return this.host.formatters().formatYearDropdown?.(value) ?? this.format(value, { year: "numeric" });
233
+ return this.host.formatters().formatYearDropdown?.(value) ?? this.internal(value, { year: "numeric" });
207
234
  }
208
235
  weekday(date) {
209
236
  const custom = this.host.formatters().formatWeekdayName?.(date);
210
237
  if (custom) return custom;
211
- const short = this.format(date, { weekday: "short" });
238
+ const short = this.internal(date, { weekday: "short" });
212
239
  const language = this.host.locale().split("-")[0].toLowerCase();
213
240
  if (language === "ar") return short.replace(/^ال/, "");
214
241
  if (language === "he") return short.replace(/^יום\s+/, "");
215
242
  return Array.from(short).slice(0, 2).join("");
216
243
  }
217
244
  dayLabel(day) {
218
- return this.host.labels().day?.(day.date, day.modifiers) ?? this.format(day.date, {
245
+ return this.host.labels().day?.(day.date, day.modifiers) ?? this.internal(day.date, {
219
246
  weekday: "long",
220
247
  month: "long",
221
248
  day: "numeric",
@@ -223,10 +250,47 @@ var RaqmCalendarFormat = class {
223
250
  });
224
251
  }
225
252
  dayText(date) {
226
- return this.host.formatters().formatDay?.(date) ?? this.format(date, { day: "numeric" });
253
+ return this.host.formatters().formatDay?.(date) ?? this.internal(date, { day: "numeric" });
227
254
  }
228
255
  weekText(week) {
229
- return this.host.formatters().formatWeekNumber?.(week) ?? new Intl.NumberFormat(this.host.locale(), { numberingSystem: "latn" }).format(week);
256
+ return this.host.formatters().formatWeekNumber?.(week) ?? this.numberFormat().format(week);
257
+ }
258
+ internal(date, options) {
259
+ const locale = this.ensureLocale();
260
+ const effective = this.effectiveOptions(options);
261
+ const cacheKey = optionsKey(effective);
262
+ let formatter = this.renderFormats.get(cacheKey);
263
+ if (formatter === void 0) {
264
+ formatter = new Intl.DateTimeFormat(locale, effective);
265
+ this.renderFormats.set(cacheKey, formatter);
266
+ }
267
+ return formatter.format(date);
268
+ }
269
+ effectiveOptions(options) {
270
+ return {
271
+ ...options,
272
+ calendar: "gregory",
273
+ numberingSystem: "latn"
274
+ };
275
+ }
276
+ numberFormat() {
277
+ const locale = this.ensureLocale();
278
+ let formatter = this.weekNumberFormat;
279
+ if (formatter === void 0) {
280
+ formatter = new Intl.NumberFormat(locale, { numberingSystem: "latn" });
281
+ this.weekNumberFormat = formatter;
282
+ }
283
+ return formatter;
284
+ }
285
+ ensureLocale() {
286
+ const locale = this.host.locale();
287
+ if (locale !== this.cachedLocale) {
288
+ this.cachedLocale = locale;
289
+ this.explicitFormats.clear();
290
+ this.renderFormats.clear();
291
+ this.weekNumberFormat = void 0;
292
+ }
293
+ return locale;
230
294
  }
231
295
  };
232
296
  var RaqmCalendarKeyboard = class {
@@ -668,6 +732,9 @@ var RaqmCalendarComponent = class RaqmCalendarComponent {
668
732
  if ("selected" in changes) this.view.markSelectionControlled();
669
733
  if ("month" in changes) this.view.markMonthControlled();
670
734
  }
735
+ ngDoCheck() {
736
+ this.formats.clearInternalFormats();
737
+ }
671
738
  ngOnInit() {
672
739
  this.view.init();
673
740
  }