Skip to content

Commit

Permalink
Refactory DirectiveAction factories and relocate documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
plblum committed Oct 5, 2024
1 parent 6de28b7 commit 908e7e8
Show file tree
Hide file tree
Showing 7 changed files with 1,146 additions and 252 deletions.
File renamed without changes.
335 changes: 335 additions & 0 deletions packages/jivs-angular/Planning/Design for ARIAs.txt

Large diffs are not rendered by default.

66 changes: 61 additions & 5 deletions packages/jivs-angular/Planning/Planning jivs-angular3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,21 +72,23 @@ When generating markdown output that includes HTML, CSS, or TypeScript code, rep

# Notes list for me to work out
1. Provide ARIA attributes that are configurable, and localizable.
This may take adding settings in FivaseServicesHost.
3. FivaseServicesHost:
This may take adding settings in FivaseServices.
2. Provide localizable tooltip strings available for various directives. Will be used by Required, Corrected, and IssueFound Directives so the user knows their purpose.
3. FivaseServices:
- Support a settings service pattern, where each Directive can get:
- global configuration
- css classes, invalidCssClass and validCssClass
- aria attribute values
- Settings changed event to be called after localization has changed the strings so directives can refresh arias and other localization settings
4. We may introduce new DirectiveAction types to allow users to inject appropriate handlers for gainedFocus and lostFocus messages (FivaseForm.sendMessage). This will give users more flexibility in how they manage focus-based interactions.

6. Work on ValidationSummary. It will use PresentationDirectiveActions but needs to show the summaryMessage. It will monitor validation callbacks.
7. Add a directive on a submit button to disable it or handle validation.
8. Developing components
- Provide several prototypes of components that show an error message, required indicator, corrected indicator, validation summary, and a complete field input enclosed in a box.
- Document how to configure any component to support Jivs. Sending input data in. Getting issues out.
- Develop examples of custom components and custom HTML elements. Use the model of a quantity tool on a shopping site with minus and plus commands and the current count. There will be different ways to supply events, including DOM events and Angular listeners. The plan includes using DOM Shadow API and actual Angular components. DirectiveActions will be used to reach into them to get the current value or attach a listener. Custom DOM events will deliver the target element, QuantityHtmlElement, with a Value property that is a number.
9. Error message wrapping tags should identify severity to allow css to change based on that.
9. Error message wrapping tags should identify severity to allow css to change based on that. This belongs in a separate project for Jivs-HTML.
11. Often creating an ErrorMessage component has [showWhenInvalid]="valuehostname" on its outer container
and [validationErrors] inside. This is a good case for validationErrors inheriting valueHostName from showWhenInvalid.

Expand Down Expand Up @@ -144,6 +146,59 @@ interface IValidationServices {
// Placeholder for specific service methods used internally
getService<T>(serviceName): null | T;
setService(serviceName, service): void;

textLocalizerService: ITextLocalizerService;
cultureSerivce: ICultureService;
// NOTE: There are MANY more properties that I've omitted.
}
```

```ts
/**
* A service to offer text alternatives to the default text
* based on cultureId.
*/
export interface ITextLocalizerService extends IServiceWithFallback<ITextLocalizerService>
{
/**
* Returns the localized version of the text for the given culture.
* If nothing is matched, it returns the fallback text.
* @param cultureIdToMatch - The cultureID.
* @param l10nKey - Localization key, which is the text that identifies which word,
* phrase, or other block of text is requested. If null or '', no localization is requested.
* @param fallback - Used when there was no match for the culture.
* Only supply '' if you are sure that registered data will always supply a value.
* @returns The localized text or the fallback text.
*/
localize(cultureIdToMatch: string, l10nKey: string | null, fallback: string | null): string | null;

/**
* Registers a lookup key with the culture specific text.
* Replaces an already registered entry with the same l10nKey.
* @param l10nKey - Localization key, which is the text that identifies which word,
* phrase, or other block of text is requested.
* @param cultureToText - keys are language codes from cultureId, like 'en'.
* values are the actual text to output.
*/
register(l10nKey: string, cultureToText: CultureToText): void;

}

```

```ts
/**
* Service for identifying cultures that you will use in the app,
* by their CultureID ('en', 'en-US', 'en-GB', etc), and provides
* fallbacks for when a requested CultureID is not found.
*/
export interface ICultureService extends IService {
/**
* The culture shown to the user in the app. Its the ISO language-region format.
This value is the starting point to search through localizations.
*/
activeCultureId: string;

}
```

Expand Down Expand Up @@ -177,8 +232,9 @@ export interface IValidatableValueHostBase extends IValueHost {
isValid: boolean;
asyncProcessing?: boolean;
corrected?: boolean;
currentValidationState: ValueHostValidationState;
}
export interface IInputValueHost extends IValueHost {
export interface IInputValueHost extends IValidatableValueHostBase {
setInputValue(nativeValue: any, inputValue: string, options?: SetValueOptions): void;
requiresInput: boolean;
}
Expand Down
300 changes: 300 additions & 0 deletions packages/jivs-angular/Planning/designing indicator directives.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
# **Designing some new directives**

This guide covers the validation-related directives and options that can be customized by users. These directives help control the visibility and display of various UI components such as error messages, required indicators, and completion icons.

## **Directives Overview**

### **`[valueHostName]` Directive**
The `[valueHostName]` directive allows for the inheritance of the `valueHostName` across nested elements. When this directive is applied to an enclosing tag, any validation-related directive within that tag will automatically inherit the `valueHostName`. This applies to the following directives: `[showWhenInvalid]`, `[showWhenRequired]`, `[showWhenCompleted]`, `[validate]`, and `[validationErrors]`.

If `[valueHostName]` is not present, each directive must be assigned a `valueHostName` explicitly.

**Usage Example:**
```html
<div [valueHostName]="FirstName">
<input type="text" [validate] /> <!-- Inherits FirstName -->
<div [showWhenInvalid]></div> <!-- Inherits FirstName -->
<div [validationErrors]></div> <!-- Inherits FirstName -->
</div>
```

---

### **`[showWhenRequired]` Directive**
This directive shows or hides a tag based on whether the associated input requires user input (i.e., whether the `requiresInput` property of the `IInputValueHost` is `true`).

- **Class and Member**: The relevant class is `IInputValueHost`, with the member `requiresInput`. The `valueHostName` is required to locate the input being validated and determine if the input is required (`requiresInput = true`). Without the `valueHostName`, the system cannot access the necessary state to evaluate this condition.

**Usage Example:**
```html
<div class="required-indicator" [showWhenRequired]>This field is required</div>
```

---

### **`[showWhenCompleted]` Directive**
This directive handles showing or hiding a tag based on whether an input's validation state changes from invalid to valid, meaning the error has been corrected.

- **Class and Member**: The relevant class is `ValueHostValidationState`, and the member is `corrected`. The directive uses the `valueHostName` to connect to the correct input and evaluate whether an error has been corrected. Without the `valueHostName`, the validation system cannot identify or track the state changes needed to trigger this behavior.

**Usage Example:**
```html
<div class="completed-indicator" [showWhenCompleted]>✔</div>
```

---

### **`[validate]` Directive**
This directive binds an input field to the validation logic, allowing it to participate in the validation system.

**Usage Example:**
```html
<input type="text" [validate]="FirstName" />
```
With `[valueHostName]`:
```html
<div [valueHostName]="FirstName">
<input type="text" [validate] /> <!-- Inherits FirstName -->
</div>
```

---

### **`[validationErrors]` Directive**
This directive is responsible for displaying validation errors for the associated input.

**Usage Example:**
```html
<div [validationErrors]="FirstName"></div>
```
With `[valueHostName]`:
```html
<div [valueHostName]="FirstName">
<div [validationErrors]></div> <!-- Inherits FirstName -->
</div>
```
---

## **Customization Options**

Each directive allows users to specify custom CSS classes to override the defaults, providing flexibility to match specific UI requirements. **Global defaults** are provided for each directive to ensure a smooth out-of-the-box experience, but users can easily override these defaults where necessary.

### **Custom CSS Classes:**

- **`[val-invalid-class]`**: Customizes the CSS class applied when validation fails. By default, the system applies a global class (e.g., `'invalid'`), but users can override it with their own class.
```html
<input validate="email" [val-invalid-class]="'my-invalid-class'">
```

- [val-valid-class]: Customizes the CSS class applied when validation succeeds. A global default class is provided, but users can specify their own.
```html
<input validate="email" [val-valid-class]="'my-valid-class'">
```
---

## **Callbacks for State Changes**

Each directive can trigger callbacks when validation states change, allowing custom logic to be executed. This works both for components (where the template specifies a function of the component instance) and generic cases (where a default function is triggered).

This feature allows for seamless integration of UI behaviors like fading out completion indicators or handling custom validation displays.

---

## **Preconfigured Templates & Best Practices**

To help users get started quickly, here are several template examples for common validation scenarios, along with suggested CSS. These templates can be easily customized by overriding the provided CSS classes or adding your own.

### **1. Error Messages with Hover Pop-Up**

Display an error icon that reveals detailed error messages on hover.

**Template:**
```html
<div class="error-icon" [showWhenInvalid]>
<span>⚠</span>
<div class="error-messages" [validationErrors]></div>
</div>
```

**CSS:**
```css
.error-icon {
position: relative;
}

.error-messages {
display: none;
position: absolute;
background-color: #f8d7da;
color: #721c24;
padding: 5px;
border-radius: 4px;
}

.error-icon:hover .error-messages {
display: block;
}

```
---

### **2. Required Field Indicator with Custom Image**

Show an image when the field is required.

**Template:**
```html
<div class="required-indicator" [showWhenRequired]>
<img src="required-icon.png" alt="Required">
</div>
```

**CSS:**
```css
.required-indicator img {
width: 16px;
height: 16px;
}

```

---

### **3. Completed Indicator with Fade-Out Effect**

Show a checkmark when validation is completed, which fades out after a short delay.

**Template:**
```html
<div class="completed-indicator" [showWhenCompleted]>✔</div>
```

**CSS:**
```css
.completed-indicator {
opacity: 1;
transition: opacity 2s ease-out;
}

.completed-indicator.fade {
opacity: 0;
}

```

---

### **4. Combined Required and Completed Indicators**

This setup shows both required and completed indicators, where the completed checkmark overlays the required icon.

**Template:**
```html
<div class="field-status">
<span class="required" [showWhenRequired]>*</span>
<span class="completed" [showWhenCompleted]>✔</span>
</div>
```

**CSS:**
```css
.field-status {
position: relative;
}

.required {
color: red;
margin-right: 10px;
}

.completed {
position: absolute;
left: 5px;
color: green;
}

```


---

### **5. Severity-Based Error Icons**

This template shows an icon that represents the highest severity level from the `IssuesFound` array, automatically set by the directive. The `data-severity` attribute is generated and set to "severe" or "warning," but omitted when the severity is "error" (the default case).

**Template:**
```html
<div class="severity-icon" [showWhenInvalid]>
<span class="icon">⚠</span>
</div>
```

**CSS:**
```css
.severity-icon[data-severity="warning"] .icon {
color: yellow;
}

.severity-icon[data-severity="severe"] .icon {
color: red;
}

/* No additional style for error, as it's the default */
```
The data-severity attribute allows users to style the icon or the component based on the highest severity found. If the validation severity is "error," the attribute will not be emitted, allowing for a cleaner default styling approach.

---

### **6. Full Field Component with All Parts**

A more complex template that combines all aspects: label, input, required indicator, error messages, and completion indicator.

**Template:**
```html
<div class="field-wrapper" [valueHostName]="fieldName">
<label for="email">Email</label>
<input id="email" validate [val-invalid-class]="'input-error'" [val-valid-class]="'input-valid'">

<div class="required-indicator" [showWhenRequired]>*</div>
<div class="completed-indicator" [showWhenCompleted]>✔</div>

<div class="error-container" [showWhenInvalid] [validationErrors]></div>
</div>
```

**CSS:**
```css
.field-wrapper {
margin-bottom: 20px;
}

.input-error {
border-color: red;
}

.input-valid {
border-color: green;
}

.required-indicator {
color: red;
}

.completed-indicator {
color: green;
margin-left: 10px;
}

.error-container {
color: red;
font-size: 12px;
}

```
---

## **Visibility Control for UI Elements**

To ensure that elements are hidden or shown correctly, the directives manage the `display` property without directly overriding it. Instead of setting `display:none` followed by `display:block`, the system ensures the original `display` value is respected and uses techniques like removing the inline `display` property or setting it to `inherit`. Additionally, the HTML5 `hidden` attribute is considered for controlling visibility.

---
Loading

0 comments on commit 908e7e8

Please sign in to comment.