@rulecms/source-components-angular 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.
@@ -1846,6 +1846,18 @@ const SIZE_SCALES = {
1846
1846
  * button to differ still override it per column, as before.
1847
1847
  */
1848
1848
  const BUTTON_CSS_VARIABLE_PREFIX = '--rulecms-button';
1849
+ /**
1850
+ * Per-instance slots the library stylesheet reads. The preset writes these on
1851
+ * the element; a column `backgroundColor` rewrite and a future widget-level
1852
+ * token both land on the same names.
1853
+ */
1854
+ const BUTTON_FILL_VARIABLE = `${BUTTON_CSS_VARIABLE_PREFIX}-fill`;
1855
+ const BUTTON_FILL_HOVER_VARIABLE = `${BUTTON_CSS_VARIABLE_PREFIX}-fill-hover`;
1856
+ const BUTTON_FILL_ACTIVE_VARIABLE = `${BUTTON_CSS_VARIABLE_PREFIX}-fill-active`;
1857
+ const BUTTON_INK_VARIABLE = `${BUTTON_CSS_VARIABLE_PREFIX}-ink`;
1858
+ const BUTTON_INK_HOVER_VARIABLE = `${BUTTON_CSS_VARIABLE_PREFIX}-ink-hover`;
1859
+ const BUTTON_BORDER_VARIABLE = `${BUTTON_CSS_VARIABLE_PREFIX}-border`;
1860
+ const BUTTON_RING_VARIABLE = `${BUTTON_CSS_VARIABLE_PREFIX}-ring`;
1849
1861
  const toneCssVariable = (tone, slot = '') => slot === ''
1850
1862
  ? `${BUTTON_CSS_VARIABLE_PREFIX}-${tone}`
1851
1863
  : `${BUTTON_CSS_VARIABLE_PREFIX}-${tone}-${slot}`;
@@ -1857,6 +1869,7 @@ const cssVarWithFallback = (variableName, fallback) => `var(${variableName}, ${f
1857
1869
  /** Shorthand for the common case: one tone slot with its palette default. */
1858
1870
  const toneColor = (tone, slot, fallback) => cssVarWithFallback(toneCssVariable(tone, slot), fallback);
1859
1871
 
1872
+ const asVars = (vars) => vars;
1860
1873
  /**
1861
1874
  * The rules that stop a native `<button>` looking like a native `<button>`.
1862
1875
  *
@@ -1884,9 +1897,7 @@ const structuralStyles = {
1884
1897
  fontFamily: 'inherit',
1885
1898
  fontWeight: 600,
1886
1899
  lineHeight: 1.25,
1887
- // Inert until something changes state. Kept because the host's own `:hover`
1888
- // rule — the only hover mechanism available to a widget today — then eases
1889
- // for free instead of snapping.
1900
+ // Eases the library stylesheet's :hover / :active colour change.
1890
1901
  transition: 'background-color 150ms ease, border-color 150ms ease, color 150ms ease',
1891
1902
  };
1892
1903
  const sizeStyles = (preset) => {
@@ -1957,7 +1968,75 @@ const variantStyles = (preset) => {
1957
1968
  }
1958
1969
  };
1959
1970
  /**
1960
- * The preset's contribution to the button's inline style.
1971
+ * Per-instance colour slots the library stylesheet reads. Tone tokens stay
1972
+ * in the `var(--rulecms-button-brand, fallback)` form so a host `:root`
1973
+ * rebrand still wins.
1974
+ */
1975
+ const variantCssVariables = (preset) => {
1976
+ const palette = TONE_PALETTES[preset.tone];
1977
+ const tone = preset.tone;
1978
+ const ink = toneColor(tone, '', palette.base);
1979
+ const inkHover = toneColor(tone, 'hover', palette.hover);
1980
+ const contrast = toneColor(tone, 'contrast', palette.contrast);
1981
+ switch (preset.variant) {
1982
+ case 'solid':
1983
+ return asVars({
1984
+ [BUTTON_FILL_VARIABLE]: toneColor(tone, '', palette.base),
1985
+ [BUTTON_FILL_HOVER_VARIABLE]: toneColor(tone, 'hover', palette.hover),
1986
+ [BUTTON_FILL_ACTIVE_VARIABLE]: toneColor(tone, 'active', palette.active),
1987
+ [BUTTON_INK_VARIABLE]: contrast,
1988
+ [BUTTON_INK_HOVER_VARIABLE]: contrast,
1989
+ [BUTTON_BORDER_VARIABLE]: toneColor(tone, '', palette.base),
1990
+ [BUTTON_RING_VARIABLE]: ink,
1991
+ });
1992
+ case 'soft':
1993
+ return asVars({
1994
+ [BUTTON_FILL_VARIABLE]: toneColor(tone, 'soft', palette.soft),
1995
+ [BUTTON_FILL_HOVER_VARIABLE]: toneColor(tone, 'soft-hover', palette.softHover),
1996
+ [BUTTON_FILL_ACTIVE_VARIABLE]: `color-mix(in srgb, ${toneColor(tone, 'soft-hover', palette.softHover)} 88%, black)`,
1997
+ [BUTTON_INK_VARIABLE]: toneColor(tone, 'soft-contrast', palette.softContrast),
1998
+ [BUTTON_INK_HOVER_VARIABLE]: toneColor(tone, 'soft-contrast', palette.softContrast),
1999
+ [BUTTON_BORDER_VARIABLE]: 'transparent',
2000
+ [BUTTON_RING_VARIABLE]: ink,
2001
+ });
2002
+ case 'outline':
2003
+ return asVars({
2004
+ [BUTTON_FILL_VARIABLE]: 'transparent',
2005
+ [BUTTON_FILL_HOVER_VARIABLE]: toneColor(tone, 'soft', palette.soft),
2006
+ [BUTTON_FILL_ACTIVE_VARIABLE]: toneColor(tone, 'soft-hover', palette.softHover),
2007
+ [BUTTON_INK_VARIABLE]: ink,
2008
+ [BUTTON_INK_HOVER_VARIABLE]: inkHover,
2009
+ [BUTTON_BORDER_VARIABLE]: toneColor(tone, 'border', palette.border),
2010
+ [BUTTON_RING_VARIABLE]: ink,
2011
+ });
2012
+ case 'ghost':
2013
+ return asVars({
2014
+ [BUTTON_FILL_VARIABLE]: 'transparent',
2015
+ [BUTTON_FILL_HOVER_VARIABLE]: toneColor(tone, 'soft', palette.soft),
2016
+ [BUTTON_FILL_ACTIVE_VARIABLE]: toneColor(tone, 'soft-hover', palette.softHover),
2017
+ [BUTTON_INK_VARIABLE]: ink,
2018
+ [BUTTON_INK_HOVER_VARIABLE]: inkHover,
2019
+ [BUTTON_BORDER_VARIABLE]: 'transparent',
2020
+ [BUTTON_RING_VARIABLE]: ink,
2021
+ });
2022
+ case 'link':
2023
+ default:
2024
+ return asVars({
2025
+ [BUTTON_FILL_VARIABLE]: 'transparent',
2026
+ [BUTTON_FILL_HOVER_VARIABLE]: 'transparent',
2027
+ [BUTTON_FILL_ACTIVE_VARIABLE]: 'transparent',
2028
+ [BUTTON_INK_VARIABLE]: ink,
2029
+ [BUTTON_INK_HOVER_VARIABLE]: inkHover,
2030
+ [BUTTON_BORDER_VARIABLE]: 'transparent',
2031
+ [BUTTON_RING_VARIABLE]: ink,
2032
+ });
2033
+ }
2034
+ };
2035
+ const COLOR_STYLE_KEYS = ['backgroundColor', 'color', 'borderColor'];
2036
+ /**
2037
+ * The preset's contribution to the button's inline style, including resting
2038
+ * colours as real CSS properties. The composer picker uses this so a swatch
2039
+ * looks right without the library stylesheet.
1961
2040
  *
1962
2041
  * Callers spread column `styleProps` *after* this, which is what makes the
1963
2042
  * preset a set of defaults rather than a set of rules: anything the author
@@ -1968,6 +2047,41 @@ function buildButtonPresetStyles(preset) {
1968
2047
  ...structuralStyles,
1969
2048
  ...sizeStyles(preset),
1970
2049
  ...variantStyles(preset),
2050
+ ...variantCssVariables(preset),
2051
+ };
2052
+ }
2053
+ /**
2054
+ * What `RButton` puts on the element. Same as the picker styles, minus the
2055
+ * colour properties the library stylesheet owns — those stay on the element
2056
+ * only as custom properties so `:hover` can change them.
2057
+ */
2058
+ function buildButtonRenderStyles(preset) {
2059
+ const styles = { ...buildButtonPresetStyles(preset) };
2060
+ for (const key of COLOR_STYLE_KEYS) {
2061
+ delete styles[key];
2062
+ }
2063
+ return styles;
2064
+ }
2065
+ /**
2066
+ * Column styles still win on everything except `backgroundColor`, which is
2067
+ * remapped onto the fill slots so hover/active follow the authored colour
2068
+ * instead of the preset's blue-family hover.
2069
+ */
2070
+ function applyButtonColumnStyles(styleProps) {
2071
+ if (!styleProps) {
2072
+ return {};
2073
+ }
2074
+ const { backgroundColor, ...rest } = styleProps;
2075
+ if (backgroundColor === undefined || backgroundColor === '') {
2076
+ return rest;
2077
+ }
2078
+ return {
2079
+ ...rest,
2080
+ ...asVars({
2081
+ [BUTTON_FILL_VARIABLE]: backgroundColor,
2082
+ [BUTTON_FILL_HOVER_VARIABLE]: `color-mix(in srgb, ${backgroundColor} 82%, black)`,
2083
+ [BUTTON_FILL_ACTIVE_VARIABLE]: `color-mix(in srgb, ${backgroundColor} 70%, black)`,
2084
+ }),
1971
2085
  };
1972
2086
  }
1973
2087
  /** Applied on top when the button is disabled, before column styles. */
@@ -2099,9 +2213,9 @@ class RButtonComponent {
2099
2213
  }
2100
2214
  get style() {
2101
2215
  return {
2102
- ...buildButtonPresetStyles(this.preset),
2216
+ ...buildButtonRenderStyles(this.preset),
2103
2217
  ...(this.disabled ? disabledStyles : {}),
2104
- ...this.styleProps,
2218
+ ...applyButtonColumnStyles(this.styleProps),
2105
2219
  };
2106
2220
  }
2107
2221
  get label() {
@@ -2129,7 +2243,16 @@ class RButtonComponent {
2129
2243
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: RButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2130
2244
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.25", type: RButtonComponent, isStandalone: true, selector: "rulecms-r-button", inputs: { componentAttributes: "componentAttributes", styleProps: "styleProps", className: "className", widgetInstanceProps: "widgetInstanceProps" }, host: { styleAttribute: "display: contents" }, ngImport: i0, template: `
2131
2245
  @if (link && disabled) {
2132
- <a [ngStyle]="style" [class]="className || undefined" role="link" aria-disabled="true" [attr.aria-label]="ariaLabel">
2246
+ <a
2247
+ data-rulecms-button
2248
+ [attr.data-rulecms-button-variant]="preset.variant"
2249
+ [attr.data-rulecms-button-tone]="preset.tone"
2250
+ [ngStyle]="style"
2251
+ [class]="className || undefined"
2252
+ role="link"
2253
+ aria-disabled="true"
2254
+ [attr.aria-label]="ariaLabel"
2255
+ >
2133
2256
  @if (iconNode && iconPosition !== 'trailing') {
2134
2257
  <rulecms-svg-icon [iconNode]="iconNode" width="1em" height="1em" [styleProps]="{ flexShrink: 0 }" />
2135
2258
  }
@@ -2140,6 +2263,9 @@ class RButtonComponent {
2140
2263
  </a>
2141
2264
  } @else if (link) {
2142
2265
  <a
2266
+ data-rulecms-button
2267
+ [attr.data-rulecms-button-variant]="preset.variant"
2268
+ [attr.data-rulecms-button-tone]="preset.tone"
2143
2269
  [attr.href]="link.href"
2144
2270
  [attr.target]="link.target"
2145
2271
  [attr.rel]="link.rel"
@@ -2163,6 +2289,9 @@ class RButtonComponent {
2163
2289
  } @else {
2164
2290
  <button
2165
2291
  type="button"
2292
+ data-rulecms-button
2293
+ [attr.data-rulecms-button-variant]="preset.variant"
2294
+ [attr.data-rulecms-button-tone]="preset.tone"
2166
2295
  [disabled]="disabled"
2167
2296
  [ngStyle]="style"
2168
2297
  [class]="className || undefined"
@@ -2188,7 +2317,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
2188
2317
  imports: [NgStyle, SvgIconComponent],
2189
2318
  template: `
2190
2319
  @if (link && disabled) {
2191
- <a [ngStyle]="style" [class]="className || undefined" role="link" aria-disabled="true" [attr.aria-label]="ariaLabel">
2320
+ <a
2321
+ data-rulecms-button
2322
+ [attr.data-rulecms-button-variant]="preset.variant"
2323
+ [attr.data-rulecms-button-tone]="preset.tone"
2324
+ [ngStyle]="style"
2325
+ [class]="className || undefined"
2326
+ role="link"
2327
+ aria-disabled="true"
2328
+ [attr.aria-label]="ariaLabel"
2329
+ >
2192
2330
  @if (iconNode && iconPosition !== 'trailing') {
2193
2331
  <rulecms-svg-icon [iconNode]="iconNode" width="1em" height="1em" [styleProps]="{ flexShrink: 0 }" />
2194
2332
  }
@@ -2199,6 +2337,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
2199
2337
  </a>
2200
2338
  } @else if (link) {
2201
2339
  <a
2340
+ data-rulecms-button
2341
+ [attr.data-rulecms-button-variant]="preset.variant"
2342
+ [attr.data-rulecms-button-tone]="preset.tone"
2202
2343
  [attr.href]="link.href"
2203
2344
  [attr.target]="link.target"
2204
2345
  [attr.rel]="link.rel"
@@ -2222,6 +2363,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
2222
2363
  } @else {
2223
2364
  <button
2224
2365
  type="button"
2366
+ data-rulecms-button
2367
+ [attr.data-rulecms-button-variant]="preset.variant"
2368
+ [attr.data-rulecms-button-tone]="preset.tone"
2225
2369
  [disabled]="disabled"
2226
2370
  [ngStyle]="style"
2227
2371
  [class]="className || undefined"
@@ -3896,6 +4040,49 @@ const getPreviewComponents = () => {
3896
4040
  return cachedPreviewComponents;
3897
4041
  };
3898
4042
 
4043
+ /**
4044
+ * SSR-safe rules for `r-button` pseudo-classes.
4045
+ *
4046
+ * widget-angular injects this once per library via `ComponentLibraryModule.stylesheet`.
4047
+ * The sheet owns `background-color`, `color`, and `border-color` so `:hover`
4048
+ * can win — those properties on an inline style beat any stylesheet rule.
4049
+ * Resting values arrive as `--rulecms-button-fill` / `-ink` / `-border` on
4050
+ * the element. A column background override rewrites the fill slots and
4051
+ * derives hover/active with `color-mix`, so an arbitrary red does not keep
4052
+ * the brand-blue hover.
4053
+ *
4054
+ * Outline is never cleared: the designed ring is a `box-shadow` on
4055
+ * `:focus-visible`, on top of the browser's native focus outline.
4056
+ */
4057
+ const BUTTON_LIBRARY_STYLESHEET = `
4058
+ [data-rulecms-button] {
4059
+ background-color: var(--rulecms-button-fill);
4060
+ color: var(--rulecms-button-ink);
4061
+ border-color: var(--rulecms-button-border, var(--rulecms-button-fill));
4062
+ }
4063
+ [data-rulecms-button]:hover:not(:disabled):not([aria-disabled="true"]) {
4064
+ background-color: var(--rulecms-button-fill-hover);
4065
+ color: var(--rulecms-button-ink-hover, var(--rulecms-button-ink));
4066
+ border-color: var(--rulecms-button-fill-hover);
4067
+ }
4068
+ [data-rulecms-button]:active:not(:disabled):not([aria-disabled="true"]) {
4069
+ background-color: var(--rulecms-button-fill-active);
4070
+ border-color: var(--rulecms-button-fill-active);
4071
+ }
4072
+ [data-rulecms-button][data-rulecms-button-variant="outline"]:hover:not(:disabled):not([aria-disabled="true"]),
4073
+ [data-rulecms-button][data-rulecms-button-variant="ghost"]:hover:not(:disabled):not([aria-disabled="true"]) {
4074
+ border-color: var(--rulecms-button-border, var(--rulecms-button-ink));
4075
+ }
4076
+ [data-rulecms-button][data-rulecms-button-variant="link"]:hover:not(:disabled):not([aria-disabled="true"]),
4077
+ [data-rulecms-button][data-rulecms-button-variant="link"]:active:not(:disabled):not([aria-disabled="true"]) {
4078
+ background-color: transparent;
4079
+ border-color: transparent;
4080
+ }
4081
+ [data-rulecms-button]:focus-visible {
4082
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--rulecms-button-ring, var(--rulecms-button-ink)) 40%, transparent);
4083
+ }
4084
+ `.trim();
4085
+
3899
4086
  /**
3900
4087
  * ComponentLibraryModule conformance (the @rulecms/widget-angular contract).
3901
4088
  *
@@ -3909,11 +4096,17 @@ const getPreviewComponents = () => {
3909
4096
  */
3910
4097
  const manifest = {
3911
4098
  id: 'default',
3912
- version: '0.1.0',
4099
+ version: '0.2.0',
3913
4100
  angularPeerRange: '>=17.0.0',
3914
4101
  };
3915
4102
  /** The render surface: component type → renderable entry. */
3916
4103
  const components = getSourceComponentsPlugin().components;
4104
+ /**
4105
+ * Optional `ComponentLibraryModule.stylesheet`. widget-angular injects this
4106
+ * once per library as an SSR `<style>` tag. v1 is the button hover / focus /
4107
+ * active rules; later interactive cards append here.
4108
+ */
4109
+ const stylesheet = BUTTON_LIBRARY_STYLESHEET;
3917
4110
  /** The editor surface: palette + attribute metadata for the RuleCMS composer. */
3918
4111
  const editor = {
3919
4112
  previewComponents: getPreviewComponents(),
@@ -3975,5 +4168,5 @@ function serializeInlineMarkers(runs) {
3975
4168
  * Generated bundle index. Do not edit.
3976
4169
  */
3977
4170
 
3978
- export { ACCORDION_HEADING_LEVELS, BLOCK_ENCLOSING_TAGS, BUTTON_CLICK_HANDLER_PROP, BUTTON_CSS_VARIABLE_PREFIX, BUTTON_SIZES, BUTTON_TONES, BUTTON_VARIANTS, ComponentIdentifiers, DEFAULT_ACCORDION_HEADING_LEVEL, DEFAULT_BUTTON_LABEL, DEFAULT_BUTTON_PRESET, DEFAULT_EMBED_LOADING, DEFAULT_ICON_POSITION, DEFAULT_LIST_KIND, EMBED_ASPECT_RATIOS, EMBED_LOADING_VALUES, EMBED_PROVIDERS, EMBED_UNSHAPED_HEIGHT, ENCLOSING_TAGS, ICON_POSITIONS, INLINE_ENCLOSING_TAGS, InlineMarkupComponent, LIST_KINDS, LIST_MARKERS, REJECTED_HREF_SCHEMES, SIZE_SCALES, TONE_PALETTES, buildButtonPresetStyles, disabledStyles as buttonDisabledStyles, cardGroups$1 as cardGroups, components, editor, formatInlineMarker, getComponentMetadataForEditing, getPreviewCardGroups, getPreviewComponents, getSourceComponentsPlugin, isAllowedEmbedUrl, isBlockEnclosingTag, isButtonSize, isButtonTone, isButtonVariant, isEnclosingTag, isSafeHref, manifest, normaliseHost, parseInlineLinkMarkers, parseInlineMarkers, resolveButtonPreset, resolveEmbedUrl, resolveLinkAttributes, serializeInlineMarkers, toneCssVariable };
4171
+ export { ACCORDION_HEADING_LEVELS, BLOCK_ENCLOSING_TAGS, BUTTON_BORDER_VARIABLE, BUTTON_CLICK_HANDLER_PROP, BUTTON_CSS_VARIABLE_PREFIX, BUTTON_FILL_ACTIVE_VARIABLE, BUTTON_FILL_HOVER_VARIABLE, BUTTON_FILL_VARIABLE, BUTTON_INK_HOVER_VARIABLE, BUTTON_INK_VARIABLE, BUTTON_LIBRARY_STYLESHEET, BUTTON_RING_VARIABLE, BUTTON_SIZES, BUTTON_TONES, BUTTON_VARIANTS, ComponentIdentifiers, DEFAULT_ACCORDION_HEADING_LEVEL, DEFAULT_BUTTON_LABEL, DEFAULT_BUTTON_PRESET, DEFAULT_EMBED_LOADING, DEFAULT_ICON_POSITION, DEFAULT_LIST_KIND, EMBED_ASPECT_RATIOS, EMBED_LOADING_VALUES, EMBED_PROVIDERS, EMBED_UNSHAPED_HEIGHT, ENCLOSING_TAGS, ICON_POSITIONS, INLINE_ENCLOSING_TAGS, InlineMarkupComponent, LIST_KINDS, LIST_MARKERS, REJECTED_HREF_SCHEMES, SIZE_SCALES, TONE_PALETTES, applyButtonColumnStyles, buildButtonPresetStyles, buildButtonRenderStyles, disabledStyles as buttonDisabledStyles, cardGroups$1 as cardGroups, components, editor, formatInlineMarker, getComponentMetadataForEditing, getPreviewCardGroups, getPreviewComponents, getSourceComponentsPlugin, isAllowedEmbedUrl, isBlockEnclosingTag, isButtonSize, isButtonTone, isButtonVariant, isEnclosingTag, isSafeHref, manifest, normaliseHost, parseInlineLinkMarkers, parseInlineMarkers, resolveButtonPreset, resolveEmbedUrl, resolveLinkAttributes, serializeInlineMarkers, stylesheet, toneCssVariable };
3979
4172
  //# sourceMappingURL=rulecms-source-components-angular.mjs.map